Git Product home page Git Product logo

euclid's People

Contributors

aholkner avatar paulo-raca avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

euclid's Issues

Avoid Square Roots Of Powers; Use math.hypot Where Available

This should be more efficient.

diff --git a/euclid.py b/euclid.py
index 66a1d6e..1a1f97d 100644
--- a/euclid.py
+++ b/euclid.py
@@ -222,8 +222,7 @@ class Vector2:
     __pos__ = __copy__

     def __abs__(self):
-        return math.sqrt(self.x ** 2 + \
-                         self.y ** 2)
+        return math.hypot(self.x, self.y)

     magnitude = __abs__

@@ -474,9 +473,7 @@ class Vector3:
     __pos__ = __copy__

     def __abs__(self):
-        return math.sqrt(self.x ** 2 + \
-                         self.y ** 2 + \
-                         self.z ** 2)
+        return math.sqrt(self.x * self.x, self.y * self.y, self.z * self.z)

     magnitude = __abs__

@@ -1286,10 +1283,7 @@ class Quaternion:
         return self

     def __abs__(self):
-        return math.sqrt(self.w ** 2 + \
-                         self.x ** 2 + \
-                         self.y ** 2 + \
-                         self.z ** 2)
+        return math.hypot(self.w * self.w, self.x * self.x, self.y * self.y, self.z * self.z)

     magnitude = __abs__

Actually math.hypot can be used for 3 or 4 components as well, but only in Python 3.8 or later.

Use Recommended “@” Operator For Dot Product

Code looks a bit cleaner, don’t you think:

diff --git a/euclid.py b/euclid.py
index 21da55f..52a32b4 100644
--- a/euclid.py
+++ b/euclid.py
@@ -247,6 +247,7 @@ class Vector2:
         assert isinstance(other, Vector2)
         return self.x * other.x + \
                self.y * other.y
+    __matmul__ = dot

     def cross(self):
         return Vector2(self.y, -self.x)
@@ -260,12 +261,12 @@ class Vector2:

     def angle(self, other):
         """Return the angle to the vector other"""
-        return math.acos(self.dot(other) / (self.magnitude()*other.magnitude()))
+        return math.acos(self @ other / (self.magnitude()*other.magnitude()))

     def project(self, other):
         """Return one vector projected on the vector other"""
         n = other.normalized()
-        return self.dot(n)*n
+        return (self @ n)*n

 class Vector3:
     __slots__ = ['x', 'y', 'z']
@@ -502,6 +503,7 @@ class Vector3:
         return self.x * other.x + \
                self.y * other.y + \
                self.z * other.z
+    __matmul__ = dot

     def cross(self, other):
         assert isinstance(other, Vector3)
@@ -537,12 +539,12 @@ class Vector3:

     def angle(self, other):
         """Return the angle to the vector other"""
-        return math.acos(self.dot(other) / (self.magnitude()*other.magnitude()))
+        return math.acos(self @ other / (self.magnitude()*other.magnitude()))

     def project(self, other):
         """Return one vector projected on the vector other"""
         n = other.normalized()
-        return self.dot(n)*n
+        return (self @ n)*n

 # a b c
 # e f g
@@ -1576,7 +1578,7 @@ def _intersect_line2_circle(L, C):
              L.v.y * (L.p.y - C.c.y))
     c = C.c.magnitude_squared() + \
         L.p.magnitude_squared() - \
-        2 * C.c.dot(L.p) - \
+        2 * C.c @ L.p - \
         C.r ** 2
     det = b ** 2 - 4 * a * c
     if det < 0:
@@ -1861,15 +1863,15 @@ def _connect_point3_sphere(P, S):

 def _connect_point3_plane(p, plane):
     n = plane.n.normalized()
-    d = p.dot(plane.n) - plane.k
+    d = p @ plane.n - plane.k
     return LineSegment3(p, Point3(p.x - n.x * d, p.y - n.y * d, p.z - n.z * d))

 def _connect_line3_line3(A, B):
     assert A.v and B.v
     p13 = A.p - B.p
-    d1343 = p13.dot(B.v)
-    d4321 = B.v.dot(A.v)
-    d1321 = p13.dot(A.v)
+    d1343 = p13 @ B.v
+    d4321 = B.v @ A.v
+    d1321 = p13 @ A.v
     d4343 = B.v.magnitude_squared()
     denom = A.v.magnitude_squared() * d4343 - d4321 ** 2
     if denom == 0:
@@ -1894,11 +1896,11 @@ def _connect_line3_line3(A, B):
                                B.p.z + ub * B.v.z))

 def _connect_line3_plane(L, P):
-    d = P.n.dot(L.v)
+    d = P.n @ L.v
     if not d:
         # Parallel, choose an endpoint
         return _connect_point3_plane(L.p, P)
-    u = (P.k - P.n.dot(L.p)) / d
+    u = (P.k - P.n @ L.p) / d
     if not L._u_in(u):
         # intersects out of range, choose nearest endpoint
         u = max(min(u, 1.0), 0.0)
@@ -1972,7 +1974,7 @@ def _intersect_line3_sphere(L, S):
              L.v.z * (L.p.z - S.c.z))
     c = S.c.magnitude_squared() + \
         L.p.magnitude_squared() - \
-        2 * S.c.dot(L.p) - \
+        2 * S.c @ L.p - \
         S.r ** 2
     det = b ** 2 - 4 * a * c
     if det < 0:
@@ -1992,11 +1994,11 @@ def _intersect_line3_sphere(L, S):
                                L.p.z + u2 * L.v.z))

 def _intersect_line3_plane(L, P):
-    d = P.n.dot(L.v)
+    d = P.n @ L.v
     if not d:
         # Parallel
         return None
-    u = (P.k - P.n.dot(L.p)) / d
+    u = (P.k - P.n @ L.p) / d
     if not L._u_in(u):
         return None
     return Point3(L.p.x + u * L.v.x,
@@ -2006,7 +2008,7 @@ def _intersect_line3_plane(L, P):
 def _intersect_plane_plane(A, B):
     n1_m = A.n.magnitude_squared()
     n2_m = B.n.magnitude_squared()
-    n1d2 = A.n.dot(B.n)
+    n1d2 = A.n @ B.n
     det = n1_m * n2_m - n1d2 ** 2
     if det == 0:
         # Parallel
@@ -2220,11 +2222,11 @@ class Plane:
                    isinstance(args[2], Point3)
             self.n = (args[1] - args[0]).cross(args[2] - args[0])
             self.n.normalize()
-            self.k = self.n.dot(args[0])
+            self.k = self.n @ args[0]
         elif len(args) == 2:
             if isinstance(args[0], Point3) and isinstance(args[1], Vector3):
                 self.n = args[1].normalized()
-                self.k = self.n.dot(args[0])
+                self.k = self.n @ args[0]
             elif isinstance(args[0], Vector3) and isinstance(args[1], float):
                 self.n = args[0].normalized()
                 self.k = args[1]
@@ -2258,7 +2260,7 @@ class Plane:
     def _apply_transform(self, t):
         p = t * self._get_point()
         self.n = t * self.n
-        self.k = self.n.dot(p)
+        self.k = self.n @ p

     def intersect(self, other):
         return other._intersect_plane(self)

Use isinstance() Instead Of Type Comparisons, And numbers.Real Instead Of Specific Numeric Types

Makes the code slightly simpler and more general:

diff --git a/euclid.py b/euclid.py
index cd75766..21da55f 100644
--- a/euclid.py
+++ b/euclid.py
@@ -40,7 +40,8 @@ __revision__ = '$Revision: 37 $'

 import math
 import operator
-import types
+from numbers import \
+    Real

 # If True, allows components of Vector2 and Vector3 to be set via swizzling;
 # e.g.  v.xyz = (1, 2, 3).  This is much, much slower than the more verbose
@@ -168,48 +169,48 @@ class Vector2:
                            other.y - self[1])

     def __mul__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector2(self.x * other,
                        self.y * other)

     __rmul__ = __mul__

     def __imul__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         self.x *= other
         self.y *= other
         return self

     def __div__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector2(operator.div(self.x, other),
                        operator.div(self.y, other))


     def __rdiv__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector2(operator.div(other, self.x),
                        operator.div(other, self.y))

     def __floordiv__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector2(operator.floordiv(self.x, other),
                        operator.floordiv(self.y, other))


     def __rfloordiv__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector2(operator.floordiv(other, self.x),
                        operator.floordiv(other, self.y))

     def __truediv__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector2(operator.truediv(self.x, other),
                        operator.truediv(self.y, other))


     def __rtruediv__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector2(operator.truediv(other, self.x),
                        operator.truediv(other, self.y))

@@ -410,7 +411,7 @@ class Vector3:
                           self.y * other.y,
                           self.z * other.z)
         else:
-            assert type(other) in (int, float)
+            assert isinstance(other, Real)
             return Vector3(self.x * other,
                            self.y * other,
                            self.z * other)
@@ -418,47 +419,47 @@ class Vector3:
     __rmul__ = __mul__

     def __imul__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         self.x *= other
         self.y *= other
         self.z *= other
         return self

     def __div__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector3(operator.div(self.x, other),
                        operator.div(self.y, other),
                        operator.div(self.z, other))


     def __rdiv__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector3(operator.div(other, self.x),
                        operator.div(other, self.y),
                        operator.div(other, self.z))

     def __floordiv__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector3(operator.floordiv(self.x, other),
                        operator.floordiv(self.y, other),
                        operator.floordiv(self.z, other))


     def __rfloordiv__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector3(operator.floordiv(other, self.x),
                        operator.floordiv(other, self.y),
                        operator.floordiv(other, self.z))

     def __truediv__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector3(operator.truediv(self.x, other),
                        operator.truediv(self.y, other),
                        operator.truediv(self.z, other))


     def __rtruediv__(self, other):
-        assert type(other) in (int, float)
+        assert isinstance(other, Real)
         return Vector3(operator.truediv(other, self.x),
                        operator.truediv(other, self.y),
                        operator.truediv(other, self.z))
@@ -1699,7 +1700,7 @@ class Line2(Geometry):
         if len(args) == 3:
             assert isinstance(args[0], Point2) and \
                    isinstance(args[1], Vector2) and \
-                   type(args[2]) == float
+                   isinstance(args[2], float)
             self.p = args[0].copy()
             self.v = args[1] * args[2] / abs(args[1])
         elif len(args) == 2:
@@ -1798,7 +1799,7 @@ class Circle(Geometry):
     __slots__ = ['c', 'r']

     def __init__(self, center, radius):
-        assert isinstance(center, Vector2) and type(radius) == float
+        assert isinstance(center, Vector2) and isinstance(radius, float)
         self.c = center.copy()
         self.r = radius

@@ -2057,7 +2058,7 @@ class Line3:
         if len(args) == 3:
             assert isinstance(args[0], Point3) and \
                    isinstance(args[1], Vector3) and \
-                   type(args[2]) == float
+                   isinstance(args[2], float)
             self.p = args[0].copy()
             self.v = args[1] * args[2] / abs(args[1])
         elif len(args) == 2:
@@ -2164,7 +2165,7 @@ class Sphere:
     __slots__ = ['c', 'r']

     def __init__(self, center, radius):
-        assert isinstance(center, Vector3) and type(radius) == float
+        assert isinstance(center, Vector3) and isinstance(radius, float)
         self.c = center.copy()
         self.r = radius

@@ -2224,7 +2225,7 @@ class Plane:
             if isinstance(args[0], Point3) and isinstance(args[1], Vector3):
                 self.n = args[1].normalized()
                 self.k = self.n.dot(args[0])
-            elif isinstance(args[0], Vector3) and type(args[1]) == float:
+            elif isinstance(args[0], Vector3) and isinstance(args[1], float):
                 self.n = args[0].normalized()
                 self.k = args[1]
             else:

I think cases of isinstance(val, float) should be replaced with isinstance(val, Real) as well.

Get Rid Of Python 2 Compatibility

Should have posted this first, since some of my other patches might not apply cleanly without it. But nobody should be doing new development in Python 2 any more.

diff --git a/euclid.py b/euclid.py
index 7f09de8..c8b99d8 100644
--- a/euclid.py
+++ b/euclid.py
@@ -44,57 +44,12 @@ import math
 import operator
 import types

-# Some magic here.  If _use_slots is True, the classes will derive from
-# object and will define a __slots__ class variable.  If _use_slots is
-# False, classes will be old-style and will not define __slots__.
-#
-# _use_slots = True:   Memory efficient, probably faster in future versions
-#                      of Python, "better".
-# _use_slots = False:  Ordinary classes, much faster than slots in current
-#                      versions of Python (2.4 and 2.5).
-_use_slots = True
-
 # If True, allows components of Vector2 and Vector3 to be set via swizzling;
 # e.g.  v.xyz = (1, 2, 3).  This is much, much slower than the more verbose
 # v.x = 1; v.y = 2; v.z = 3,  and slows down ordinary element setting as
 # well.  Recommended setting is False.
 _enable_swizzle_set = False

-# Requires class to derive from object.
-if _enable_swizzle_set:
-    _use_slots = True
-
-# Implement _use_slots magic.
-class _EuclidMetaclass(type):
-    def __new__(cls, name, bases, dct):
-        if '__slots__' in dct:
-            dct['__getstate__'] = cls._create_getstate(dct['__slots__'])
-            dct['__setstate__'] = cls._create_setstate(dct['__slots__'])
-        if _use_slots:
-            return type.__new__(cls, name, bases + (object,), dct)
-        else:
-            if '__slots__' in dct:
-                del dct['__slots__']
-            return types.ClassType.__new__(types.ClassType, name, bases, dct)
-
-    @classmethod
-    def _create_getstate(cls, slots):
-        def __getstate__(self):
-            d = {}
-            for slot in slots:
-                d[slot] = getattr(self, slot)
-            return d
-        return __getstate__
-
-    @classmethod
-    def _create_setstate(cls, slots):
-        def __setstate__(self, state):
-            for name, value in state.items():
-                setattr(self, name, value)
-        return __setstate__
-
-__metaclass__ = _EuclidMetaclass
-
 class Vector2:
     __slots__ = ['x', 'y']
     __hash__ = None

Better Way Of Defining Swizzle Properties

How about defining the swizzle methods this way. It should have less run-time overhead than the __setitem__ technique, at the cost of a proliferation of properties in the affected classes.

diff --git a/euclid.py b/euclid.py
index 5fdc285..824ce8a 100644
--- a/euclid.py
+++ b/euclid.py
@@ -43,12 +43,64 @@ import operator
 from numbers import \
     Real

-# If True, allows components of Vector2 and Vector3 to be set via swizzling;
-# e.g.  v.xyz = (1, 2, 3).  This is much, much slower than the more verbose
-# v.x = 1; v.y = 2; v.z = 3,  and slows down ordinary element setting as
-# well.  Recommended setting is False.
-_enable_swizzle_set = False
-
+def add_swizzle(components) :
+
+    def do_swizzle(Vec) :
+
+        def defprop(components) :
+
+            def getter(self) :
+                return \
+                    tuple(getattr(self, c) for c in components)
+            #end getter
+
+            def setter(self, values) :
+                if len(values) != len(components) :
+                    raise ValueError \
+                      (
+                            "need %d components for setting %s"
+                        %
+                            (len(components), repr(components))
+                      )
+                #end if
+                for c, v in zip(components, values) :
+                    setattr(self, c, v)
+                #end for
+            #end setter
+
+        #begin defprop
+            name = "".join(components)
+            getter.__doc__ = "components %s" % repr(components)
+            getter.__name__ = name
+            return name, property(getter, setter)
+        #end defprop
+
+        def permute_components(components) :
+            for i in range(len(components)) :
+                this = components[i]
+                rest = components[:i] + components[i + 1:]
+                yield (this,)
+                for permrest in permute_components(rest) :
+                    yield (this,) + permrest
+                #end for
+            #end for
+        #end permute_components
+
+    #begin do_swizzle
+        for perm in permute_components(components) :
+            if len(perm) > 1 :
+                name, prop = defprop(perm)
+                setattr(Vec, name, prop)
+            #end if
+        #end for
+        return Vec
+    #end do_swizzle
+
+#begin add_swizzle
+    return do_swizzle
+#end add_swizzle
+
+@add_swizzle(("x", "y"))
 class Vector2:
     __slots__ = ['x', 'y']
     __hash__ = None
@@ -101,21 +153,6 @@ class Vector2:
         except ValueError:
             raise AttributeError(name)

-    if _enable_swizzle_set:
-        # This has detrimental performance on ordinary setattr as well
-        # if enabled
-        def __setattr__(self, name, value):
-            if len(name) == 1:
-                object.__setattr__(self, name, value)
-            else:
-                try:
-                    l = [self.x, self.y]
-                    for c, v in map(None, name, value):
-                        l['xy'.index(c)] = v
-                    self.x, self.y = l
-                except ValueError:
-                    raise AttributeError(name)
-
     def __add__(self, other):
         if isinstance(other, Vector2):
             # Vector + Vector -> Vector
@@ -268,6 +305,7 @@ class Vector2:
         n = other.normalized()
         return (self @ n)*n

+@add_swizzle(("x", "y", "z"))
 class Vector3:
     __slots__ = ['x', 'y', 'z']
     __hash__ = None
@@ -325,22 +363,6 @@ class Vector3:
         except ValueError:
             raise AttributeError(name)

-    if _enable_swizzle_set:
-        # This has detrimental performance on ordinary setattr as well
-        # if enabled
-        def __setattr__(self, name, value):
-            if len(name) == 1:
-                object.__setattr__(self, name, value)
-            else:
-                try:
-                    l = [self.x, self.y, self.z]
-                    for c, v in map(None, name, value):
-                        l['xyz'.index(c)] = v
-                    self.x, self.y, self.z = l
-                except ValueError:
-                    raise AttributeError(name)
-
-
     def __add__(self, other):
         if isinstance(other, Vector3):
             # Vector + Vector -> Vector
@@ -1188,7 +1210,7 @@ class Matrix4:

         return tmp;

-
+@add_swizzle(("w", "x", "y", "z"))
 class Quaternion:
     # All methods and naming conventions based off
     # http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions
@@ -1511,6 +1533,8 @@ class Quaternion:
         Q.z = q1.z * ratio1 + q2.z * ratio2
         return Q

+del add_swizzle # your work is done
+
 # Geometry
 # Much maths thanks to Paul Bourke, http://astronomy.swin.edu.au/~pbourke
 # ---------------------------------------------------------------------------

Replace classmethod() Calls With Decorators

Cleaner to use the decorator syntax for this:

diff --git a/euclid.py b/euclid.py
index 2f3209a..cd75766 100644
--- a/euclid.py
+++ b/euclid.py
@@ -689,25 +689,26 @@ class Matrix3:
         return self

     # Static constructors
+    @classmethod
     def new_identity(cls):
         self = cls()
         return self
-    new_identity = classmethod(new_identity)

+    @classmethod
     def new_scale(cls, x, y):
         self = cls()
         self.a = x
         self.f = y
         return self
-    new_scale = classmethod(new_scale)

+    @classmethod
     def new_translate(cls, x, y):
         self = cls()
         self.c = x
         self.g = y
         return self
-    new_translate = classmethod(new_translate)

+    @classmethod
     def new_rotate(cls, angle):
         self = cls()
         s = math.sin(angle)
@@ -716,7 +717,6 @@ class Matrix3:
         self.b = -s
         self.e = s
         return self
-    new_rotate = classmethod(new_rotate)

     def determinant(self):
         return (self.a*self.f*self.k
@@ -1001,33 +1001,34 @@ class Matrix4:
         return M

     # Static constructors
+    @classmethod
     def new(cls, *values):
         M = cls()
         M[:] = values
         return M
-    new = classmethod(new)

+    @classmethod
     def new_identity(cls):
         self = cls()
         return self
-    new_identity = classmethod(new_identity)

+    @classmethod
     def new_scale(cls, x, y, z):
         self = cls()
         self.a = x
         self.f = y
         self.k = z
         return self
-    new_scale = classmethod(new_scale)

+    @classmethod
     def new_translate(cls, x, y, z):
         self = cls()
         self.d = x
         self.h = y
         self.l = z
         return self
-    new_translate = classmethod(new_translate)

+    @classmethod
     def new_rotatex(cls, angle):
         self = cls()
         s = math.sin(angle)
@@ -1036,8 +1037,8 @@ class Matrix4:
         self.g = -s
         self.j = s
         return self
-    new_rotatex = classmethod(new_rotatex)

+    @classmethod
     def new_rotatey(cls, angle):
         self = cls()
         s = math.sin(angle)
@@ -1046,8 +1047,8 @@ class Matrix4:
         self.c = s
         self.i = -s
         return self
-    new_rotatey = classmethod(new_rotatey)

+    @classmethod
     def new_rotatez(cls, angle):
         self = cls()
         s = math.sin(angle)
@@ -1056,8 +1057,8 @@ class Matrix4:
         self.b = -s
         self.e = s
         return self
-    new_rotatez = classmethod(new_rotatez)

+    @classmethod
     def new_rotate_axis(cls, angle, axis):
         assert(isinstance(axis, Vector3))
         vector = axis.normalized()
@@ -1081,8 +1082,8 @@ class Matrix4:
         self.j = y * z * c1 + x * s
         self.k = z * z * c1 + c
         return self
-    new_rotate_axis = classmethod(new_rotate_axis)

+    @classmethod
     def new_rotate_euler(cls, heading, attitude, bank):
         # from http://www.euclideanspace.com/
         ch = math.cos(heading)
@@ -1103,8 +1104,8 @@ class Matrix4:
         self.j = sh * sa * cb + ch * sb
         self.k = -sh * sa * sb + ch * cb
         return self
-    new_rotate_euler = classmethod(new_rotate_euler)

+    @classmethod
     def new_rotate_triple_axis(cls, x, y, z):
       m = cls()

@@ -1113,8 +1114,8 @@ class Matrix4:
       m.i, m.j, m.k = x.z, y.z, z.z

       return m
-    new_rotate_triple_axis = classmethod(new_rotate_triple_axis)

+    @classmethod
     def new_look_at(cls, eye, at, up):
       z = (eye - at).normalized()
       x = up.cross(z).normalized()
@@ -1123,8 +1124,8 @@ class Matrix4:
       m = cls.new_rotate_triple_axis(x, y, z)
       m.d, m.h, m.l = eye.x, eye.y, eye.z
       return m
-    new_look_at = classmethod(new_look_at)

+    @classmethod
     def new_perspective(cls, fov_y, aspect, near, far):
         # from the gluPerspective man page
         f = 1 / math.tan(fov_y / 2)
@@ -1137,7 +1138,6 @@ class Matrix4:
         self.o = -1
         self.p = 0
         return self
-    new_perspective = classmethod(new_perspective)

     def determinant(self):
         return ((self.a * self.f - self.e * self.b)
@@ -1393,10 +1393,11 @@ class Quaternion:
         return M

     # Static constructors
+    @classmethod
     def new_identity(cls):
         return cls()
-    new_identity = classmethod(new_identity)

+    @classmethod
     def new_rotate_axis(cls, angle, axis):
         assert(isinstance(axis, Vector3))
         axis = axis.normalized()
@@ -1407,8 +1408,8 @@ class Quaternion:
         Q.y = axis.y * s
         Q.z = axis.z * s
         return Q
-    new_rotate_axis = classmethod(new_rotate_axis)

+    @classmethod
     def new_rotate_euler(cls, heading, attitude, bank):
         Q = cls()
         c1 = math.cos(heading / 2)
@@ -1423,8 +1424,8 @@ class Quaternion:
         Q.y = s1 * c2 * c3 + c1 * s2 * s3
         Q.z = c1 * s2 * c3 - s1 * c2 * s3
         return Q
-    new_rotate_euler = classmethod(new_rotate_euler)

+    @classmethod
     def new_rotate_matrix(cls, m):
       if m[0*4 + 0] + m[1*4 + 1] + m[2*4 + 2] > 0.00000001:
         t = m[0*4 + 0] + m[1*4 + 1] + m[2*4 + 2] + 1.0
@@ -1469,8 +1470,8 @@ class Quaternion:
           (m[1*4 + 2] + m[2*4 + 1])*s,
           s*t
           )
-    new_rotate_matrix = classmethod(new_rotate_matrix)

+    @classmethod
     def new_interpolate(cls, q1, q2, t):
         assert isinstance(q1, Quaternion) and isinstance(q2, Quaternion)
         Q = cls()
@@ -1506,7 +1507,6 @@ class Quaternion:
         Q.y = q1.y * ratio1 + q2.y * ratio2
         Q.z = q1.z * ratio1 + q2.z * ratio2
         return Q
-    new_interpolate = classmethod(new_interpolate)

 # Geometry
 # Much maths thanks to Paul Bourke, http://astronomy.swin.edu.au/~pbourke

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.