def test_vector(): for _ in xrange(1000): v = random_vector() x, y = v assert v + (2, 0) == Vector(x+2, y) assert v - (2, 0) == Vector(x-2, y) assert +v == Vector(x, y) assert -v == Vector(-x, -y) assert v * 2 == Vector(2*x, 2*y) assert v / 2 == Vector(x/2, y/2) v = Vector(1, 0) assert v.angle == 0 v.angle = pi/2 v.x, v.y = map(Approx, v) assert v == Vector(0, 1) v.length = 2 v.x, v.y = map(Approx, v) assert v == Vector(0, 2) v.move(2, 2) assert v == Vector(2, 4) v.scale(2, 2, pivot=(1, 1)) assert v == Vector(3, 7) v.rotate(pi/2, pivot=(3, 3)) v.x, v.y = [Approx(n) for n in v] assert v == Vector(-1, 3)
class Circle(Shape): def __init__(self, center=(0, 0), radius=1.0): self.center = Vector(*center) self.radius = radius def __info__(self): return "c=%s, r=%s" % (self.center, self.radius) # -------------------------------------------------------------------------- # Geometry interface def move(self, dx=0.0, dy=0.0): if dx == 0.0 and dy == 0.0: return self.center.move(dx, dy) def scale(self, factor, pivot=None): if factor == 1.0: return if pivot is not None: self.center.scale(factor, pivot) self.radius *= factor def rotate(self, alpha, pivot=None): if alpha == 0.0: return if pivot is not None: self.center.rotate(alpha, pivot) # -------------------------------------------------------------------------- # Shape interface def contains_point(self, point): radius = self.radius delta = point - self.center return delta.squared_length <= radius * radius def segment_intersections(self, segment): points = [] cx, cy = self.center r = self.radius m = segment.slope if m is None: # vertical segment if cx - r <= segment.a.x <= cx + r: pass else: b = segment.y_at(0.0) A = 1 + m*m B = -2*cx + 2*m*b -2*m*cy C = cx*cx + cy*cy + b*b - r*r - 2*b*cy x0, x1 = solve_quadratic(A, B, C) xinterval = segment.xrange if x0 in xinterval: points.append(Vector(x0, segment.y_at(x0))) if x1 in xinterval: points.append(Vector(x1, segment.y_at(x1))) return points