Anonymous avatar Anonymous committed 82c4a22

Added Lorenz' patch set for the math module, addressing:
* consistently use degrees and not radians
* raise a ValueError rather than a ZeroDivisionError in case the div
zero occurs during an internal calculation.
* SLERP implementation is more robust. check for special cases like
angle=0,180,360 degrees.
* fixed a bug in LERP. t must be in range [0,1]
* in the rotation methods: check if the rotation axis is zero and raise
a ValueError in case it is.
* check for div zero for div, idiv, floor_div
* also check for div zero in the angleto method
* a wrong function signature in basemod.c

Comments (0)

Files changed (9)

src/base/basemod.c

     return 0;
 }
 
-unsigned long
-UlongFromObj (PyObject* obj, long* val)
+int
+UlongFromObj (PyObject* obj, unsigned long* val)
 {
     PyObject* longobj;
     unsigned long tmp;

src/base/internals.h

 int ASCIIFromObj (PyObject *obj, char **text, PyObject **freeme);
 int UTF8FromObj (PyObject *obj, char **text, PyObject **freeme);
 int LongFromObj (PyObject* obj, long* val);
-unsigned long UlongFromObj (PyObject* obj, long* val);
+int UlongFromObj (PyObject* obj, unsigned long* val);
 int ColorFromObj (PyObject *obj, pguint32 *val);
 
 extern PyTypeObject PyColor_Type;

src/math/mathmod.c

 
     if (!PyArg_ParseTuple (args, "dd:vector_from_polar", &r, &phi))
         return NULL;
+    phi = DEG2RAD (phi);
     c1 = r * cos (phi);
     c2 = r * sin (phi);
     return PyVector2_New (c1, c2);
     if (!PyArg_ParseTuple (args, "ddd:vector_from_spherical", &r, &theta, &phi))
         return NULL;
 
+    theta = DEG2RAD (theta);
+    phi = DEG2RAD (phi);
     c1 = r * sin (theta) * cos (phi);
     c2 = r * sin (theta) * sin (phi);
     c3 = r * cos (theta);

src/math/vector.c

 static PyObject* _vector_scaletolength (PyVector *self, PyObject *args);
 static PyObject* _vector_reflect (PyVector *self, PyObject *args);
 static PyObject* _vector_reflect_ip (PyVector *self, PyObject *args);
+
+static double
+_vector_distance_squared_as_double(PyVector *self, PyObject *args);
 static PyObject* _vector_distance (PyVector *self, PyObject *args);
 static PyObject* _vector_distance_squared (PyVector *self, PyObject *args);
 static PyObject* _vector_copy (PyObject *self, PyObject *unused);
 {
     PyVector *v = (PyVector *) self;
     Py_ssize_t i;
-    
+    PyObject *tmp;
     PyObject *tuple = PyTuple_New (v->dim);
     if (!tuple)
         return NULL;
     for (i = 0; i < v->dim; i++)
     {
-        PyTuple_SET_ITEM (tuple, i, PyFloat_FromDouble (v->coords[i]));
-    }
+        tmp = PyFloat_FromDouble (v->coords[i]);
+        if (!tmp)
+        {
+            Py_DECREF (tuple);
+            return NULL;
+        }
+        PyTuple_SET_ITEM (tuple, i, tmp);
+   }
     return tuple;
 }
 
     length = sqrt (_ScalarProduct(self->coords, self->coords, self->dim));
     if (length == 0)
     {
-        PyErr_SetString (PyExc_ZeroDivisionError,
+        PyErr_SetString (PyExc_ValueError,
             "can not normalize vector of length 0");
         return NULL;
     }
     length = sqrt (_ScalarProduct (self->coords, self->coords, self->dim));
     if (length == 0)
     {
-        PyErr_SetString (PyExc_ZeroDivisionError,
+        PyErr_SetString (PyExc_ValueError,
             "can not normalize vector of length 0");
         return NULL;
     }
     PyObject *other;
     PyVector *ret;
     double *othercoords;
-    double angle, t, length1, length2, f0, f1, f2;
+    double angle, t, length1, length2, f0, f1, f2, tmp;
 
     if (!PyArg_ParseTuple(args, "Od:slerp", &other, &t))
         return NULL;
 
     if ((length1 < self->epsilon) || (length2 < self->epsilon))
     {
-        PyErr_SetString (PyExc_ZeroDivisionError,
+        PyErr_SetString (PyExc_ValueError,
             "can not use slerp with zero-Vector");
         PyMem_Free (othercoords);
         return NULL;
     }
-    angle = acos (_ScalarProduct (self->coords, othercoords, self->dim) /
-        (length1 * length2));
+    tmp = _ScalarProduct (self->coords, othercoords, self->dim) /
+        (length1 * length2);
+    /* make sure tmp is in the range [-1:1] so acos won't return NaN */
+    tmp = (tmp < -1 ? -1 : (tmp > 1 ? 1 : tmp));
+    angle = acos (tmp);
+                       
 
     if (t < 0)
     {
         PyMem_Free (othercoords);
         return NULL;
     }
-    f0 = ((length2 - length1) * t + length1) / sin (angle);
-    f1 = sin (angle * (1 - t)) / length1;
-    f2 = sin (angle * t) / length2;
-    for (i = 0; i < self->dim; ++i)
-        ret->coords[i] = (self->coords[i] * f1 + othercoords[i] * f2) * f0;
+    /* special case angle==0 and angle==360 */
+    if ((fabs (angle) < self->epsilon) ||
+        (fabs (fabs (angle) - 2 * M_PI) < self->epsilon))
+    {
+        /* approximate with lerp, because slerp diverges with 1/sin(angle) */
+        for (i = 0; i < self->dim; ++i)
+            ret->coords[i] = self->coords[i] * (1 - t) + othercoords[i] * t;
+    }
+    /* special case angle==180 and angle==-180 */
+    else if (fabs (fabs (angle) - M_PI) < self->epsilon)
+    {
+        PyErr_SetString(PyExc_ValueError,
+            "SLERP with 180 degrees is undefined.");
+        Py_DECREF (ret);
+        PyMem_Free (othercoords);
+        return NULL;
+    }
+    else
+    {
+        f0 = ((length2 - length1) * t + length1) / sin (angle);
+        f1 = sin (angle * (1 - t)) / length1;
+        f2 = sin (angle * t) / length2;
+        for (i = 0; i < self->dim; ++i)
+            ret->coords[i] = (self->coords[i] * f1 + othercoords[i] * f2) * f0;
+    }
 
     PyMem_Free (othercoords);
     return (PyObject*) ret;
         return NULL;
     }
 
-    if (fabs (t) > 1)
+    if (t < 0 || t > 1)
     {
-        PyErr_SetString (PyExc_ValueError, "t must be in range [-1, 1]");
+        PyErr_SetString (PyExc_ValueError, "t must be in range [0, 1]");
         PyMem_Free (othercoords);
         return NULL;
     }
     if (!DoubleFromObj (args, &newlength))
         return NULL;
 
-    for (i = 0; i < self->dim; ++i)
-        oldlength += self->coords[i] * self->coords[i];
-    oldlength = sqrt (oldlength);
+    oldlength = sqrt (_ScalarProduct (self->coords, self->coords, self->dim));
 
     if (oldlength < self->epsilon)
     {
-        PyErr_SetString (PyExc_ZeroDivisionError,
+        PyErr_SetString (PyExc_ValueError,
             "cannot scale a vector with zero length");
         return NULL;
     }
     }
 
     /* Normalize the normal */
-    nlength = 0;
-    for (i = 0; i < ndim; i++)
-        nlength += ncoords[i] * ncoords[i];
+    nlength = _ScalarProduct(ncoords, ncoords, ndim);
     if (nlength < eps)
     {
-        PyErr_SetString (PyExc_ZeroDivisionError,
+        PyErr_SetString (PyExc_ValueError,
             "normal must not be a zero-length vector");
         goto ret;
     }
     }
 
     /* Calculate the dot product for the projection. */
-    dotprod = 0;
-    for (i = 0; i < dim; i++)
-        dotprod += srccoords[i] * ncoords[i];
+    dotprod = _ScalarProduct(srccoords, ncoords, dim);
         
     dstcoords = PyMem_New (double, dim);
     if (!dstcoords)
     Py_RETURN_NONE;
 }
 
-static PyObject*
-_vector_distance (PyVector *self, PyObject *args)
+static double
+_vector_distance_squared_as_double(PyVector *self, PyObject *args)
 {
     Py_ssize_t otherdim, i;
-    double *othercoords, distance, tmp;
+    double *othercoords, distance_squared, tmp;
 
     if (!IsVectorCompatible (args))
     {
         PyErr_SetString (PyExc_TypeError, "other must be a vector compatible");
-        return NULL;
+        return -1;
     }
 
     othercoords = VectorCoordsFromObj (args, &otherdim);
     if (!othercoords)
-        return NULL;
+        return -1;
     if (otherdim != self->dim)
     {
         PyErr_SetString (PyExc_ValueError,
             "must have same the same dimension as vector");
         PyMem_Free (othercoords);
-        return NULL;
+        return -1;
     }
-    distance = 0;
+    distance_squared = 0;
     for (i = 0; i < self->dim; i++)
     {
         tmp = othercoords[i] - self->coords[i];
-        distance += tmp * tmp;
+        distance_squared += tmp * tmp;
     }
     PyMem_Free (othercoords);
-    return PyFloat_FromDouble (sqrt (distance));
+    return distance_squared;
+}
+
+static PyObject*
+_vector_distance (PyVector *self, PyObject *args)
+{
+    double distance_squared = _vector_distance_squared_as_double (self, args);
+    if (distance_squared == -1 && PyErr_Occurred())
+        return NULL;
+    return PyFloat_FromDouble (sqrt (distance_squared));
 }
 
 static PyObject*
 _vector_distance_squared (PyVector *self, PyObject *args)
 {
-    Py_ssize_t otherdim, i;
-    double *othercoords, distance, tmp;
-
-    if (!IsVectorCompatible (args))
-    {
-        PyErr_SetString (PyExc_TypeError, "other must be a vector compatible");
+    double distance_squared = _vector_distance_squared_as_double (self, args);
+    if (distance_squared == -1 && PyErr_Occurred ())
         return NULL;
-    }
-
-    othercoords = VectorCoordsFromObj (args, &otherdim);
-    if (!othercoords)
-        return NULL;
-    if (otherdim != self->dim)
-    {
-        PyErr_SetString (PyExc_ValueError,
-            "must have same the same dimension as vector");
-        PyMem_Free (othercoords);
-        return NULL;
-    }
-    distance = 0;
-    for (i = 0; i < self->dim; i++)
-    {
-        tmp = othercoords[i] - self->coords[i];
-        distance += tmp * tmp;
-    }
-    PyMem_Free (othercoords);
-    return PyFloat_FromDouble (distance);
+    return PyFloat_FromDouble (distance_squared);
 }
 
 static PyObject*
         double tmp;
         if (!DoubleFromObj (other, &tmp))
             break;
+        if (tmp == 0.f)
+        {
+            PyErr_SetString (PyExc_ZeroDivisionError, "division by zero");
+            return NULL;
+        }
         tmp = 1.f / tmp;
         retval = PyVector_NewSpecialized (dim);
         if (!retval)
         double tmp;
         if (!DoubleFromObj (other, &tmp))
             break;
+        if (tmp == 0.f)
+        {
+            PyErr_SetString (PyExc_ZeroDivisionError, "division by zero");
+            return NULL;
+        }
         tmp = 1. / tmp;
         for (i = 0; i < dim; i++)
             vcoords[i] *= tmp;
         double tmp;
         if (!DoubleFromObj (other, &tmp))
             break;
+        if (tmp == 0.f)
+        {
+            PyErr_SetString (PyExc_ZeroDivisionError, "division by zero");
+            return NULL;
+        }
         tmp = 1. / tmp;
         retval = PyVector_NewSpecialized(dim);
         if (!retval)
         double tmp;
         if (!DoubleFromObj (other, &tmp))
             break;
+        if (tmp == 0.f)
+        {
+            PyErr_SetString (PyExc_ZeroDivisionError, "division by zero");
+            return NULL;
+        }
         tmp = 1. / tmp;
         for (i = 0; i < dim; i++)
             v->coords[i] = floor (vcoords[i] * tmp);
 }
 
 /**
- * -vector1, ~vector1
+ * -vector1, +vector1
  */
 static PyObject*
 _vector_neg (PyVector *self)
     Py_ssize_t i;
     for (i = 0; i < self->dim; i++)
     {
-        if (fabs (self->coords[i]) > self->epsilon)
+        if (self->coords[i] != 0.f)
             return 1;
     }
     return 0;
     double diff;
     PyVector *v = NULL, *v2 = NULL;
     PyObject *other = NULL;
-    int swap = 0, retval = 1;
+    int retval = 1;
     
     if (PyVector_Check (o1))
     {
     }
     else if (PyVector_Check (o2))
     {
-        swap = 1;
         v = (PyVector *) o2;
         other = o1;
     }
             }
         }
     }
-    if (swap == 1)
-    {
-        if (retval == 0)
-            retval = 1;
-        else
-            retval = 0;
-    }
 
     switch (op)
     {

src/math/vector2.c

     double r, phi;
     r = sqrt(_ScalarProduct (self->coords, self->coords, self->dim));
     phi = atan2 (self->coords[1], self->coords[0]);
-    return Py_BuildValue ("(dd)", r, phi);
+    return Py_BuildValue ("(dd)", r, RAD2DEG (phi));
 }
 
 /* C API */

src/math/vector3.c

 static PyObject* _vector3_get_z (PyObject *self, void *closure);
 static int _vector3_set_z (PyObject *self, PyObject *value, void *closure);
 
-static void _do_rotate (double *dst_coords, const double *src_coords,
+static int _do_rotate (double *dst_coords, const double *src_coords,
     const double* axis_coords, double angle, double epsilon);
 
 static PyObject* _vector3_rotate (PyObject *self, PyObject *args);
 }
 
 /* Vector3 methods */
-static void
+static int
 _do_rotate (double *dst_coords, const double *src_coords,
     const double* axis_coords, double angle, double epsilon)
 {
         axis[i] = axis_coords[i];
     }
 
+    if (axislen < epsilon)
+    {
+        PyErr_SetString (PyExc_ValueError,
+            "rotation axis is too close to zero.");
+        return 0;
+    }
+    
     /* normalize the axis */
-    if (axislen - 1 > epsilon)
+    if (fabs (axislen - 1) > epsilon)
     {
         nfactor = 1. / sqrt (axislen);
         for (i = 0; i < 3; ++i)
              src_coords[1] * (axis[1] * axis[2] * coscompl + axis[0] * sinv) +
              src_coords[2] * (cosv + axis[2] * axis[2] * coscompl));
     }
+    return 1;
 }
 
 static PyObject*
         return NULL;
     }
     ret = (PyVector*) PyVector3_New (0.f, 0.f, 0.f);
-    _do_rotate (ret->coords, v->coords, axiscoords, angle, v->epsilon);
+    
+    if (!ret ||
+        !_do_rotate (ret->coords, v->coords, axiscoords, angle, v->epsilon))
+    {
+        Py_XDECREF (ret);
+        ret = NULL;
+    }
+
     PyMem_Free (axiscoords);
     return (PyObject*) ret;
 }
     }
 
     memcpy (tmp, v->coords, sizeof (double) * 3);
-    _do_rotate (v->coords, tmp, axiscoords, angle, v->epsilon);
+    if (!_do_rotate (v->coords, tmp, axiscoords, angle, v->epsilon))
+    {
+        PyMem_Free (axiscoords);
+        return NULL;
+    }
     PyMem_Free (axiscoords);
     Py_RETURN_NONE;
 }
 static PyObject*
 _vector3_angleto (PyObject *self, PyObject *args)
 {
-    double angle, tmp1, tmp2;
+    double angle, tmp, squared_length1, squared_length2;
     double *othercoords;
     Py_ssize_t otherdim;
     PyVector* v = (PyVector*)self;
         return NULL;
     }
     
-    tmp1 = _ScalarProduct (v->coords, v->coords, v->dim);
-    tmp2 = _ScalarProduct (othercoords, othercoords, otherdim);
-    angle = acos (_ScalarProduct (v->coords, othercoords, v->dim) /
-        sqrt (tmp1 * tmp2));
+
+    squared_length1 = _ScalarProduct (v->coords, v->coords, v->dim);
+    squared_length2 = _ScalarProduct (othercoords, othercoords, otherdim);
+    tmp = sqrt (squared_length1 * squared_length2);
+    if (tmp == 0.f)
+    {
+        PyErr_SetString (PyExc_ValueError,
+            "angle to zero vector is undefined");
+        PyMem_Free (othercoords);
+        return NULL;
+    }
+    angle = acos (_ScalarProduct (v->coords, othercoords, v->dim) / tmp);
+
     PyMem_Free (othercoords);
-
     return PyFloat_FromDouble (RAD2DEG (angle));
 }
 
     PyVector* v = (PyVector*)self;
     double r, theta, phi;
     r = sqrt (_ScalarProduct (v->coords, v->coords, v->dim));
+    if (r == 0.f)
+        return Py_BuildValue ("(ddd)", 0.f, 0.f, 0.f);
 
     theta = acos (v->coords[2] / r);
     phi = atan2 (v->coords[1], v->coords[0]);
-    return Py_BuildValue ("(ddd)", r, theta, phi);
+    return Py_BuildValue ("(ddd)", r, RAD2DEG (theta), RAD2DEG (phi));
 }
 
 

test/math_test.py

         v = from_polar(*v1.as_polar())
         self.assertEqual(v1, v)
         self.assertEqual(e1.as_polar(), (1, 0))
-        self.assertEqual(e2.as_polar(), (1, math.pi / 2))
-        self.assertEqual((2 * e2).as_polar(),
-                         (2, math.pi / 2))
+        self.assertEqual(e2.as_polar(), (1, 90))
+        self.assertEqual((2 * e2).as_polar(), (2, 90))
         self.assertRaises(TypeError, lambda : from_polar((None, None)))
         self.assertRaises(TypeError, lambda : from_polar("ab"))
         self.assertRaises(TypeError, lambda : from_polar((None, 1)))
         self.assertRaises(TypeError, lambda : from_polar((1, 2, 3)))
         self.assertRaises(TypeError, lambda : from_polar((1,)))
-        v = from_polar(.5, math.pi / 2.)
+        v = from_polar(.5, 90)
         self.assertEqual(v, .5 * e2)
 
     def test_pygame2_math_base_vector_from_spherical(self):
         from_spherical = pmath.vector_from_spherical
         v = from_spherical(*v1.as_spherical())
         self.assertEqual(v1, v)
-        self.assertEqual(e1.as_spherical(), (1, math.pi / 2., 0))
-        self.assertEqual(e2.as_spherical(), (1, math.pi / 2., math.pi / 2))
+        self.assertEqual(e1.as_spherical(), (1, 90, 0))
+        self.assertEqual(e2.as_spherical(), (1, 90, 90))
         self.assertEqual(e3.as_spherical(), (1, 0, 0))
-        self.assertEqual((2 * e2).as_spherical(),
-                         (2, math.pi / 2., math.pi / 2))
+        self.assertEqual((2 * e2).as_spherical(), (2, 90, 90))
         self.assertRaises(TypeError, lambda : from_spherical((None, None, None)))
         self.assertRaises(TypeError, lambda : from_spherical("abc"))
         self.assertRaises(TypeError, lambda : from_spherical((None, 1, 2)))
         self.assertRaises(TypeError, lambda : from_spherical((1, 2, 3, 4)))
         self.assertRaises(TypeError, lambda : from_spherical((1, 2)))
         self.assertRaises(TypeError, lambda : from_spherical((1, 2, 3)))
-        v = from_spherical(.5, math.pi / 2., math.pi / 2.)
+        v = from_spherical(.5, 90, 90)
         self.assertEqual(v, .5 * e2)
 
 if __name__ == "__main__":

test/math_vector2_test.py

         self.assertEqual(self.v1.y, self.l1[1])
         # v2 is paralell to v1
         self.assertAlmostEqual(self.v1.x * v.y - self.v1.y * v.x, 0.)
-        self.assertRaises(ZeroDivisionError, lambda : self.zeroVec.normalize())
+        self.assertRaises(ValueError, lambda : self.zeroVec.normalize())
 
     def test_pygame2_math_base_Vector_normalize_ip(self):
 
         self.assertAlmostEqual(v.x * v.x + v.y * v.y, 1.)
         # v2 is paralell to v1
         self.assertAlmostEqual(self.v1.x * v.y - self.v1.y * v.x, 0.)
-        self.assertRaises(ZeroDivisionError,
-                          lambda : self.zeroVec.normalize_ip())
+        self.assertRaises(ValueError, lambda : self.zeroVec.normalize_ip())
 
     def test_pygame2_math_base_Vector_distance(self):
 
         self.assertEqual(v.reflect(n), Vector2(1, 1))
         self.assertEqual(v.reflect(3*n), v.reflect(n))
         self.assertEqual(v.reflect(-v), -v)
-        self.assertRaises(ZeroDivisionError, lambda : v.reflect(self.zeroVec))
+        self.assertRaises(ValueError, lambda : v.reflect(self.zeroVec))        
 
     def test_pygame2_math_base_Vector_reflect_ip(self):
 
         v2 = Vector2(v1)
         v2.reflect_ip(-v1)
         self.assertEqual(v2, -v1)
-        self.assertRaises(ZeroDivisionError, lambda : v2.reflect_ip(Vector2()))
+        self.assertRaises(ValueError, lambda : v2.reflect_ip(Vector2()))
 
     def test_pygame2_math_base_Vector_scale_to(self):
 
         v = Vector2(1, 1)
         v.scale_to(2.5)
         self.assertEqual(v, Vector2(2.5, 2.5) / math.sqrt(2))
-        self.assertRaises(ZeroDivisionError,
-                          lambda : self.zeroVec.scale_to(1))
+        self.assertRaises(ValueError, lambda : self.zeroVec.scale_to(1))
         self.assertEqual(v.scale_to(0), None)
         self.assertEqual(v, self.zeroVec)
 
         v = from_polar(*self.v1.as_polar())
         self.assertEqual(self.v1, v)
         self.assertEqual(self.e1.as_polar(), (1, 0))
-        self.assertEqual(self.e2.as_polar(), (1, math.pi / 2))
-        self.assertEqual((2 * self.e2).as_polar(),
-                         (2, math.pi / 2))
+        self.assertEqual(self.e2.as_polar(), (1, 90))
+        self.assertEqual((2 * self.e2).as_polar(), (2, 90))
         self.assertRaises(TypeError, lambda : from_polar((None, None)))
         self.assertRaises(TypeError, lambda : from_polar("ab"))
         self.assertRaises(TypeError, lambda : from_polar((None, 1)))
         self.assertRaises(TypeError, lambda : from_polar((1, 2, 3)))
         self.assertRaises(TypeError, lambda : from_polar((1,)))
-        v = from_polar(.5, math.pi / 2.)
+        v = from_polar(.5, 90)
         self.assertEqual(v, .5 * self.e2)
 
     def test_pygame2_math_base_Vector2_cross(self):

test/math_vector3_test.py

                  (self.v1.z * v.x - self.v1.x * v.z) ** 2 +
                  (self.v1.x * v.y - self.v1.y * v.x) ** 2)
         self.assertAlmostEqual(cross, 0.)
-        self.assertRaises(ZeroDivisionError, lambda : self.zeroVec.normalize())
+        self.assertRaises(ValueError, lambda : self.zeroVec.normalize())
         
     def test_normalize_ip(self):
         v = +self.v1
                  (self.v1.z * v.x - self.v1.x * v.z) ** 2 +
                  (self.v1.x * v.y - self.v1.y * v.x) ** 2)
         self.assertAlmostEqual(cross, 0.)
-        self.assertRaises(ZeroDivisionError,
-                          lambda : self.zeroVec.normalize_ip())
+        self.assertRaises(ValueError, lambda : self.zeroVec.normalize_ip())
 
     def test_normalized(self):
         self.assertEqual(self.v1.normalized, False)
         v = Vector3(1, 1, 1)
         v.scale_to(2.5)
         self.assertEqual(v, Vector3(2.5, 2.5, 2.5) / math.sqrt(3))
-        self.assertRaises(ZeroDivisionError, lambda : self.zeroVec.scale_to(1))
+        self.assertRaises(ValueError, lambda : self.zeroVec.scale_to(1))
         self.assertEqual(v.scale_to(0), None)
         self.assertEqual(v, self.zeroVec)
 
         self.assertEqual(v.reflect(n), Vector3(1, 1, 1))
         self.assertEqual(v.reflect(3*n), v.reflect(n))
         self.assertEqual(v.reflect(-v), -v)
-        self.assertRaises(ZeroDivisionError, lambda : v.reflect(self.zeroVec))
+        self.assertRaises(ValueError, lambda : v.reflect(self.zeroVec))
         
     def test_reflect_ip(self):
         v1 = Vector3(1, -1, 1)
         v2 = Vector3(v1)
         v2.reflect_ip(-v1)
         self.assertEqual(v2, -v1)
-        self.assertRaises(ZeroDivisionError, lambda : v2.reflect_ip(self.zeroVec))
+        self.assertRaises(ValueError, lambda : v2.reflect_ip(self.zeroVec))
 
     def test_distance(self):
         diff = self.v1 - self.v2
                                self.v2.distance_squared(self.v1))
     
     def test_slerp(self):
-        self.assertRaises(ZeroDivisionError,
-                          lambda : self.zeroVec.slerp(self.v1, .5))
-        self.assertRaises(ZeroDivisionError,
-                          lambda : self.v1.slerp(self.zeroVec, .5))
-        self.assertRaises(ZeroDivisionError,
+        self.assertRaises(ValueError, lambda : self.zeroVec.slerp(self.v1, .5))
+        self.assertRaises(ValueError, lambda : self.v1.slerp(self.zeroVec, .5))
+        self.assertRaises(ValueError,
                           lambda : self.zeroVec.slerp(self.zeroVec, .5))
         steps = 10
         angle_step = self.e1.angle_to(self.e2) / steps
         from_spherical = pmath.vector_from_spherical
         v = from_spherical(*self.v1.as_spherical ())
         self.assertEqual(self.v1, v)
-        self.assertEqual(self.e1.as_spherical(), (1, math.pi / 2., 0))
-        self.assertEqual(self.e2.as_spherical(), (1, math.pi / 2., math.pi / 2))
+        self.assertEqual(self.e1.as_spherical(), (1, 90, 0))
+        self.assertEqual(self.e2.as_spherical(), (1, 90, 90))
         self.assertEqual(self.e3.as_spherical(), (1, 0, 0))
-        self.assertEqual((2 * self.e2).as_spherical(),
-                         (2, math.pi / 2., math.pi / 2))
+        self.assertEqual((2 * self.e2).as_spherical(), (2, 90, 90))
         self.assertRaises(TypeError, lambda : from_spherical((None, None, None)))
         self.assertRaises(TypeError, lambda : from_spherical("abc"))
         self.assertRaises(TypeError, lambda : from_spherical((None, 1, 2)))
         self.assertRaises(TypeError, lambda : from_spherical((1, 2, 3, 4)))
         self.assertRaises(TypeError, lambda : from_spherical((1, 2)))
         self.assertRaises(TypeError, lambda : from_spherical((1, 2, 3)))
-        v = from_spherical(.5, math.pi / 2., math.pi / 2.)
+        v = from_spherical(.5, 90, 90)
         self.assertEqual(v, .5 * self.e2)
 
 if __name__ == "__main__":
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.