def _circle_tangents(self, other, invert_second_radius): "compute tangents as explained in \ https://en.wikipedia.org/wiki/Tangent_lines_to_circles#Analytic_geometry" dx = other.pos.pos_x - self.pos.pos_x dy = other.pos.pos_y - self.pos.pos_y if not invert_second_radius: dr = other.radius - self.radius else: dr = -other.radius - self.radius d = sqrt(dx * dx + dy * dy) x = dx / d y = dy / d r = dr / d a1 = r * x - y * sqrt(1 - r * r) b1 = r * y + x * sqrt(1 - r * r) c1 = self.radius - (a1 * self.pos.pos_x + b1 * self.pos.pos_y) a2 = r * x + y * sqrt(1 - r * r) b2 = r * y - x * sqrt(1 - r * r) c2 = self.radius - (a2 * self.pos.pos_x + b2 * self.pos.pos_y) x11 = (b1 * (b1 * self.pos.pos_x - a1 * self.pos.pos_y) - a1 * c1) y11 = (a1 * (-b1 * self.pos.pos_x + a1 * self.pos.pos_y) - b1 * c1) x12 = (b1 * (b1 * other.pos.pos_x - a1 * other.pos.pos_y) - a1 * c1) y12 = (a1 * (-b1 * other.pos.pos_x + a1 * other.pos.pos_y) - b1 * c1) x21 = (b2 * (b2 * self.pos.pos_x - a2 * self.pos.pos_y) - a2 * c2) y21 = (a2 * (-b2 * self.pos.pos_x + a2 * self.pos.pos_y) - b2 * c2) x22 = (b2 * (b2 * other.pos.pos_x - a2 * other.pos.pos_y) - a2 * c2) y22 = (a2 * (-b2 * other.pos.pos_x + a2 * other.pos.pos_y) - b2 * c2) start1 = Vec2D(x11, y11) end1 = Vec2D(x12, y12) orient11 = Vec2D.orientation(end1, start1, self.pos) orient12 = Vec2D.orientation(start1, end1, other.pos) start2 = Vec2D(x21, y21) end2 = Vec2D(x22, y22) orient21 = Vec2D.orientation(end2, start2, self.pos) orient22 = Vec2D.orientation(start2, end2, other.pos) tan1 = Tangent(start1, self, orient11, end1, other, orient12) tan2 = Tangent(start2, self, orient21, end2, other, orient22) return [tan1, tan2]
def _circle_tangents(self, other, invert_second_radius): "compute tangents as explained in \ https://en.wikipedia.org/wiki/Tangent_lines_to_circles#Analytic_geometry" dx = other.pos.pos_x - self.pos.pos_x dy = other.pos.pos_y - self.pos.pos_y if not invert_second_radius: dr = other.radius - self.radius else: dr = - other.radius - self.radius d = sqrt(dx*dx + dy*dy) x = dx/d y = dy/d r = dr/d a1 = r*x - y*sqrt(1 - r*r) b1 = r*y + x*sqrt(1 - r*r) c1 = self.radius - (a1*self.pos.pos_x + b1*self.pos.pos_y) a2 = r*x + y*sqrt(1 - r*r) b2 = r*y - x*sqrt(1 - r*r) c2 = self.radius - (a2*self.pos.pos_x + b2*self.pos.pos_y) x11 = (b1*(b1*self.pos.pos_x - a1*self.pos.pos_y) - a1*c1) y11 = (a1*(-b1*self.pos.pos_x + a1*self.pos.pos_y) - b1*c1) x12 = (b1*(b1*other.pos.pos_x - a1*other.pos.pos_y) - a1*c1) y12 = (a1*(-b1*other.pos.pos_x + a1*other.pos.pos_y) - b1*c1) x21 = (b2*(b2*self.pos.pos_x - a2*self.pos.pos_y) - a2*c2) y21 = (a2*(-b2*self.pos.pos_x + a2*self.pos.pos_y) - b2*c2) x22 = (b2*(b2*other.pos.pos_x - a2*other.pos.pos_y) - a2*c2) y22 = (a2*(-b2*other.pos.pos_x + a2*other.pos.pos_y) - b2*c2) start1 = Vec2D(x11, y11) end1 = Vec2D(x12, y12) orient11 = Vec2D.orientation(end1, start1, self.pos) orient12 = Vec2D.orientation(start1, end1, other.pos) start2 = Vec2D(x21, y21) end2 = Vec2D(x22, y22) orient21 = Vec2D.orientation(end2, start2, self.pos) orient22 = Vec2D.orientation(start2, end2, other.pos) tan1 = Tangent(start1, self, orient11, end1, other, orient12) tan2 = Tangent(start2, self, orient21, end2, other, orient22) return [tan1, tan2]
def test_orientation_colinear(self): "test that orientation returns (almost) zero for colinear points" vec1 = Vec2D(0, 0) vec2 = Vec2D(1, 0) vec3 = Vec2D(2, 0) self.assertAlmostEqual(0, Vec2D.orientation(vec1, vec2, vec3))
def test_negative_orientation(self): "test that orientation returns postive value for positively oriented \ points" vec1 = Vec2D(0, 0) vec2 = Vec2D(0, 1) vec3 = Vec2D(1, 0) self.assertTrue(Vec2D.orientation(vec1, vec2, vec3) < 0)
def sort_points_on_circle(points, circle): "sort points by their angle on the circle" if not points: return [] reference = points[0] rest = points[1:len(points)] sorted_points = sorted( rest, key=lambda p: Vec2D.orientation(reference, circle.pos, p)) return [reference] + sorted_points
def sort_points_on_circle(points, circle): "sort points by their angle on the circle" if not points: return [] reference = points[0] rest = points[1: len(points)] sorted_points = sorted(rest, key=lambda p: Vec2D.orientation(reference, circle.pos, p)) return [reference] + sorted_points