Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/lib/euclid.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/euclid.py')
-rw-r--r--lib/euclid.py516
1 files changed, 0 insertions, 516 deletions
diff --git a/lib/euclid.py b/lib/euclid.py
deleted file mode 100644
index b3834d6..0000000
--- a/lib/euclid.py
+++ /dev/null
@@ -1,516 +0,0 @@
-#!/usr/bin/env python
-#
-# euclid graphics maths module
-#
-# Copyright (c) 2006 Alex Holkner
-# Alex.Holkner@mail.google.com
-#
-# This library is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by the
-# Free Software Foundation; either version 2.1 of the License, or (at your
-# option) any later version.
-#
-# This library is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
-# for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this library; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-'''euclid graphics maths module
-
-Documentation and tests are included in the file "euclid.txt", or online
-at http://code.google.com/p/pyeuclid
-'''
-
-__docformat__ = 'restructuredtext'
-__version__ = '$Id$'
-__revision__ = '$Revision$'
-
-import math
-import operator
-import types
-
-
-
-class Vector2(object):
- __slots__ = ['x', 'y']
-
- def __init__(self, x=0, y=0):
- self.x = x
- self.y = y
-
- def __copy__(self):
- return self.__class__(self.x, self.y)
-
- copy = __copy__
-
- def __repr__(self):
- return 'Vector2(%.2f, %.2f)' % (self.x, self.y)
-
- def __eq__(self, other):
- if not other: return False
-
- if isinstance(other, Vector2):
- return self.x == other.x and \
- self.y == other.y
- else:
- if hasattr(other, '__len__') and len(other) == 2:
- return self.x == other[0] and \
- self.y == other[1]
- else:
- return False
-
- def __neq__(self, other):
- return not self.__eq__(other)
-
- def __nonzero__(self):
- return self.x != 0 or self.y != 0
-
- def __len__(self):
- return 2
-
- def __getitem__(self, key):
- return (self.x, self.y)[key]
-
- def __setitem__(self, key, value):
- l = [self.x, self.y]
- l[key] = value
- self.x, self.y = l
-
- def __iter__(self):
- return iter((self.x, self.y))
-
- def __getattr__(self, name):
- try:
- return tuple([(self.x, self.y)['xy'.index(c)] \
- for c in name])
- except ValueError:
- raise AttributeError, name
-
- def __add__(self, other):
- return Vector2(self.x + other.x, self.y + other.y)
-
- __radd__ = __add__
-
- def __iadd__(self, other):
- self.x += other.x
- self.y += other.y
- return self
-
- def __sub__(self, other):
- return Vector2(self.x - other.x, self.y - other.y)
-
- def __rsub__(self, other):
- return Vector2(other.x - self.x, other.y - self.y)
-
- def __mul__(self, other):
- return Vector2(self.x * other, self.y * other)
-
- __rmul__ = __mul__
-
- def __imul__(self, other):
- self.x *= other
- self.y *= other
- return self
-
- def __div__(self, other):
- return Vector2(operator.div(self.x, other),
- operator.div(self.y, other))
-
-
- def __rdiv__(self, other):
- return Vector2(operator.div(other, self.x),
- operator.div(other, self.y))
-
- def __floordiv__(self, other):
- return Vector2(operator.floordiv(self.x, other),
- operator.floordiv(self.y, other))
-
-
- def __rfloordiv__(self, other):
- return Vector2(operator.floordiv(other, self.x),
- operator.floordiv(other, self.y))
-
- def __truediv__(self, other):
- return Vector2(operator.truediv(self.x, other),
- operator.truediv(self.y, other))
-
- def __rtruediv__(self, other):
- return Vector2(operator.truediv(other, self.x),
- operator.truediv(other, self.y))
-
- def __neg__(self):
- return Vector2(-self.x, -self.y)
-
- __pos__ = __copy__
-
- def __abs__(self):
- return math.sqrt(self.x * self.x + self.y * self.y)
-
- magnitude = __abs__
-
- def magnitude_squared(self):
- return self.x * self.x + self.y * self.y
-
- def normalize(self):
- d = self.magnitude()
- if d:
- self.x /= d
- self.y /= d
- return self
-
- def normalized(self):
- d = self.magnitude()
- if d:
- return Vector2(self.x / d, self.y / d)
- return self.copy()
-
- def dot(self, other):
- assert isinstance(other, Vector2)
- return self.x * other.x + \
- self.y * other.y
-
- def cross(self):
- return Vector2(self.y, -self.x)
-
- def product(self, v2):
- # product of our vector and the other vector's perpendicular
- return self.x * v2.y - self.y * v2.x
-
- def reflect(self, normal):
- # assume normal is normalized
- assert isinstance(normal, Vector2)
- d = 2 * (self.x * normal.x + self.y * normal.y)
- return Vector2(self.x - d * normal.x,
- self.y - d * normal.y)
-
- def limit(self, max_magnitude):
- if self.magnitude() > max_magnitude:
- self.normalize()
- self *= max_magnitude
-
- def heading(self):
- return math.atan2(self.y, self.x)
-
- def angle(self, other):
- """angle between this and the other vector in radians"""
- if self == -other: # same vector facing the opposite way will kill acos on float precision
- return math.pi
-
- return math.acos(self.normalized().dot(other.normalized()))
-
-
-# Geometry
-# Much maths thanks to Paul Bourke, http://astronomy.swin.edu.au/~pbourke
-# ---------------------------------------------------------------------------
-
-class Geometry(object):
- def _connect_unimplemented(self, other):
- raise AttributeError, 'Cannot connect %s to %s' % \
- (self.__class__, other.__class__)
-
- def _intersect_unimplemented(self, other):
- raise AttributeError, 'Cannot intersect %s and %s' % \
- (self.__class__, other.__class__)
-
- _intersect_point2 = _intersect_unimplemented
- _intersect_line2 = _intersect_unimplemented
- _intersect_circle = _intersect_unimplemented
- _connect_point2 = _connect_unimplemented
- _connect_line2 = _connect_unimplemented
- _connect_circle = _connect_unimplemented
-
-
- def intersect(self, other):
- raise NotImplementedError
-
- def connect(self, other):
- raise NotImplementedError
-
- def distance(self, other):
- c = self.connect(other)
- if c:
- return c.length
- return 0.0
-
-def _intersect_point2_circle(P, C):
- return (P - C.c).magnitude_squared() <= C.r * C.r
-
-def _intersect_line2_line2(A, B):
- d = B.v.y * A.v.x - B.v.x * A.v.y
- if d == 0:
- return None
-
- dy = A.p.y - B.p.y
- dx = A.p.x - B.p.x
- ua = (B.v.x * dy - B.v.y * dx) / d
- if not A._u_in(ua):
- return None
- ub = (A.v.x * dy - A.v.y * dx) / d
- if not B._u_in(ub):
- return None
-
- return Point2(A.p.x + ua * A.v.x,
- A.p.y + ua * A.v.y)
-
-def _intersect_line2_circle(L, C):
- a = L.v.magnitude_squared()
- b = 2 * (L.v.x * (L.p.x - C.c.x) + \
- L.v.y * (L.p.y - C.c.y))
- c = C.c.magnitude_squared() + \
- L.p.magnitude_squared() - \
- 2 * C.c.dot(L.p) - \
- C.r * C.r
- det = b * b - 4 * a * c
- if det < 0:
- return None
- sq = math.sqrt(det)
- u1 = (-b + sq) / (2 * a)
- u2 = (-b - sq) / (2 * a)
- if not L._u_in(u1):
- u1 = max(min(u1, 1.0), 0.0)
- if not L._u_in(u2):
- u2 = max(min(u2, 1.0), 0.0)
-
- # Tangent
- if u1 == u2:
- return Point2(L.p.x + u1 * L.v.x,
- L.p.y + u1 * L.v.y)
-
- return LineSegment2(Point2(L.p.x + u1 * L.v.x,
- L.p.y + u1 * L.v.y),
- Point2(L.p.x + u2 * L.v.x,
- L.p.y + u2 * L.v.y))
-
-def _connect_point2_line2(P, L):
- d = L.v.magnitude_squared()
- assert d != 0
- u = ((P.x - L.p.x) * L.v.x + \
- (P.y - L.p.y) * L.v.y) / d
- if not L._u_in(u):
- u = max(min(u, 1.0), 0.0)
- return LineSegment2(P,
- Point2(L.p.x + u * L.v.x,
- L.p.y + u * L.v.y))
-
-def _connect_point2_circle(P, C):
- v = P - C.c
- v.normalize()
- v *= C.r
- return LineSegment2(P, Point2(C.c.x + v.x, C.c.y + v.y))
-
-def _connect_line2_line2(A, B):
- d = B.v.y * A.v.x - B.v.x * A.v.y
- if d == 0:
- # Parallel, connect an endpoint with a line
- if isinstance(B, Ray2) or isinstance(B, LineSegment2):
- p1, p2 = _connect_point2_line2(B.p, A)
- return p2, p1
- # No endpoint (or endpoint is on A), possibly choose arbitrary point
- # on line.
- return _connect_point2_line2(A.p, B)
-
- dy = A.p.y - B.p.y
- dx = A.p.x - B.p.x
- ua = (B.v.x * dy - B.v.y * dx) / d
- if not A._u_in(ua):
- ua = max(min(ua, 1.0), 0.0)
- ub = (A.v.x * dy - A.v.y * dx) / d
- if not B._u_in(ub):
- ub = max(min(ub, 1.0), 0.0)
-
- return LineSegment2(Point2(A.p.x + ua * A.v.x, A.p.y + ua * A.v.y),
- Point2(B.p.x + ub * B.v.x, B.p.y + ub * B.v.y))
-
-def _connect_circle_line2(C, L):
- d = L.v.magnitude_squared()
- assert d != 0
- u = ((C.c.x - L.p.x) * L.v.x + (C.c.y - L.p.y) * L.v.y) / d
- if not L._u_in(u):
- u = max(min(u, 1.0), 0.0)
- point = Point2(L.p.x + u * L.v.x, L.p.y + u * L.v.y)
- v = (point - C.c)
- v.normalize()
- v *= C.r
- return LineSegment2(Point2(C.c.x + v.x, C.c.y + v.y), point)
-
-def _connect_circle_circle(A, B):
- v = B.c - A.c
- v.normalize()
- return LineSegment2(Point2(A.c.x + v.x * A.r, A.c.y + v.y * A.r),
- Point2(B.c.x - v.x * B.r, B.c.y - v.y * B.r))
-
-
-class Point2(Vector2, Geometry):
- def __repr__(self):
- return 'Point2(%.2f, %.2f)' % (self.x, self.y)
-
- def intersect(self, other):
- return other._intersect_point2(self)
-
- def _intersect_circle(self, other):
- return _intersect_point2_circle(self, other)
-
- def connect(self, other):
- return other._connect_point2(self)
-
- def _connect_point2(self, other):
- return LineSegment2(other, self)
-
- def _connect_line2(self, other):
- c = _connect_point2_line2(self, other)
- if c:
- return c._swap()
-
- def _connect_circle(self, other):
- c = _connect_point2_circle(self, other)
- if c:
- return c._swap()
-
-class Line2(Geometry):
- __slots__ = ['p', 'v']
-
- def __init__(self, *args):
- if len(args) == 3:
- assert isinstance(args[0], Point2) and \
- isinstance(args[1], Vector2) and \
- type(args[2]) == float
- self.p = args[0].copy()
- self.v = args[1] * args[2] / abs(args[1])
- elif len(args) == 2:
- if isinstance(args[0], Point2) and isinstance(args[1], Point2):
- self.p = args[0].copy()
- self.v = args[1] - args[0]
- elif isinstance(args[0], Point2) and isinstance(args[1], Vector2):
- self.p = args[0].copy()
- self.v = args[1].copy()
- else:
- raise AttributeError, '%r' % (args,)
- elif len(args) == 1:
- if isinstance(args[0], Line2):
- self.p = args[0].p.copy()
- self.v = args[0].v.copy()
- else:
- raise AttributeError, '%r' % (args,)
- else:
- raise AttributeError, '%r' % (args,)
-
- if not self.v:
- raise AttributeError, 'Line has zero-length vector'
-
- def __copy__(self):
- return self.__class__(self.p, self.v)
-
- copy = __copy__
-
- def __repr__(self):
- return 'Line2(<%.2f, %.2f> + u<%.2f, %.2f>)' % \
- (self.p.x, self.p.y, self.v.x, self.v.y)
-
- p1 = property(lambda self: self.p)
- p2 = property(lambda self: Point2(self.p.x + self.v.x,
- self.p.y + self.v.y))
-
- def _apply_transform(self, t):
- self.p = t * self.p
- self.v = t * self.v
-
- def _u_in(self, u):
- return True
-
- def intersect(self, other):
- return other._intersect_line2(self)
-
- def _intersect_line2(self, other):
- return _intersect_line2_line2(self, other)
-
- def _intersect_circle(self, other):
- return _intersect_line2_circle(self, other)
-
- def connect(self, other):
- return other._connect_line2(self)
-
- def _connect_point2(self, other):
- return _connect_point2_line2(other, self)
-
- def _connect_line2(self, other):
- return _connect_line2_line2(other, self)
-
- def _connect_circle(self, other):
- return _connect_circle_line2(other, self)
-
-class Ray2(Line2):
- def __repr__(self):
- return 'Ray2(<%.2f, %.2f> + u<%.2f, %.2f>)' % \
- (self.p.x, self.p.y, self.v.x, self.v.y)
-
- def _u_in(self, u):
- return u >= 0.0
-
-class LineSegment2(Line2):
- def __repr__(self):
- return 'LineSegment2(<%.2f, %.2f> to <%.2f, %.2f>)' % \
- (self.p.x, self.p.y, self.p.x + self.v.x, self.p.y + self.v.y)
-
- def _u_in(self, u):
- return u >= 0.0 and u <= 1.0
-
- def __abs__(self):
- return abs(self.v)
-
- def magnitude_squared(self):
- return self.v.magnitude_squared()
-
- def _swap(self):
- # used by connect methods to switch order of points
- self.p = self.p2
- self.v *= -1
- return self
-
- length = property(lambda self: abs(self.v))
-
-class Circle(Geometry):
- __slots__ = ['c', 'r']
-
- def __init__(self, center, radius):
- assert isinstance(center, Vector2) and type(radius) == float
- self.c = center.copy()
- self.r = radius
-
- def __copy__(self):
- return self.__class__(self.c, self.r)
-
- copy = __copy__
-
- def __repr__(self):
- return 'Circle(<%.2f, %.2f>, radius=%.2f)' % \
- (self.c.x, self.c.y, self.r)
-
- def _apply_transform(self, t):
- self.c = t * self.c
-
- def intersect(self, other):
- return other._intersect_circle(self)
-
- def _intersect_point2(self, other):
- return _intersect_point2_circle(other, self)
-
- def _intersect_line2(self, other):
- return _intersect_line2_circle(other, self)
-
- def connect(self, other):
- return other._connect_circle(self)
-
- def _connect_point2(self, other):
- return _connect_point2_circle(other, self)
-
- def _connect_line2(self, other):
- c = _connect_circle_line2(self, other)
- if c:
- return c._swap()
-
- def _connect_circle(self, other):
- return _connect_circle_circle(other, self)