[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[pygame] pgreloaded patches
Hi,
I did a review of the math module in the pgreloaded branch and compiled some patches.
The patches address the following problems:
* 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
I tried to seperate these issues in different patches. The "00_all.patch" is a combination of the others.
Hope you find this usefull.
cheers
//Lorenz
diff -r fb31d86448f9 -r 8eafbb955d09 src/base/basemod.c
--- a/src/base/basemod.c Mon Apr 12 15:51:01 2010 +0200
+++ b/src/base/basemod.c Mon Apr 12 17:44:30 2010 +0200
@@ -109,8 +109,8 @@
return 0;
}
-unsigned long
-UlongFromObj (PyObject* obj, long* val)
+int
+UlongFromObj (PyObject* obj, unsigned long* val)
{
PyObject* longobj;
unsigned long tmp;
diff -r fb31d86448f9 -r 8eafbb955d09 src/base/internals.h
--- a/src/base/internals.h Mon Apr 12 15:51:01 2010 +0200
+++ b/src/base/internals.h Mon Apr 12 17:44:30 2010 +0200
@@ -60,7 +60,7 @@
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;
diff -r fb31d86448f9 -r 8eafbb955d09 src/math/mathmod.c
--- a/src/math/mathmod.c Mon Apr 12 15:51:01 2010 +0200
+++ b/src/math/mathmod.c Mon Apr 12 17:44:30 2010 +0200
@@ -42,6 +42,7 @@
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);
@@ -54,7 +55,8 @@
if (!PyArg_ParseTuple (args, "ddd:vector_from_spherical", &r, &theta, &phi))
return NULL;
-
+ phi = DEG2RAD(phi);
+ theta = DEG2RAD(theta);
c1 = r * sin (theta) * cos (phi);
c2 = r * sin (theta) * sin (phi);
c3 = r * cos (theta);
diff -r fb31d86448f9 -r 8eafbb955d09 src/math/vector.c
--- a/src/math/vector.c Mon Apr 12 15:51:01 2010 +0200
+++ b/src/math/vector.c Mon Apr 12 17:44:30 2010 +0200
@@ -538,12 +538,18 @@
PyVector *v = (PyVector *) self;
Py_ssize_t i;
- PyObject *tuple = PyTuple_New (v->dim);
+ PyObject *tmp, *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;
}
@@ -632,7 +638,7 @@
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;
}
@@ -652,7 +658,7 @@
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;
}
@@ -669,7 +675,7 @@
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;
@@ -703,13 +709,16 @@
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)
{
@@ -726,12 +735,28 @@
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;
}
@@ -765,9 +790,9 @@
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;
}
@@ -822,13 +847,11 @@
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;
}
@@ -869,12 +892,10 @@
}
/* 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;
}
@@ -887,9 +908,7 @@
}
/* 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)
@@ -935,68 +954,54 @@
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*
@@ -1139,6 +1144,11 @@
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)
@@ -1152,6 +1162,11 @@
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;
@@ -1164,6 +1179,11 @@
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)
@@ -1177,6 +1197,11 @@
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);
@@ -1287,7 +1312,7 @@
}
/**
- * -vector1, ~vector1
+ * -vector1, +vector1
*/
static PyObject*
_vector_neg (PyVector *self)
@@ -1317,7 +1342,7 @@
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;
@@ -1597,7 +1622,7 @@
double diff;
PyVector *v = NULL, *v2 = NULL;
PyObject *other = NULL;
- int swap = 0, retval = 1;
+ int retval = 1;
if (PyVector_Check (o1))
{
@@ -1606,7 +1631,6 @@
}
else if (PyVector_Check (o2))
{
- swap = 1;
v = (PyVector *) o2;
other = o1;
}
@@ -1647,13 +1671,6 @@
}
}
}
- if (swap == 1)
- {
- if (retval == 0)
- retval = 1;
- else
- retval = 0;
- }
switch (op)
{
diff -r fb31d86448f9 -r 8eafbb955d09 src/math/vector2.c
--- a/src/math/vector2.c Mon Apr 12 15:51:01 2010 +0200
+++ b/src/math/vector2.c Mon Apr 12 17:44:30 2010 +0200
@@ -360,7 +360,7 @@
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 */
diff -r fb31d86448f9 -r 8eafbb955d09 src/math/vector3.c
--- a/src/math/vector3.c Mon Apr 12 15:51:01 2010 +0200
+++ b/src/math/vector3.c Mon Apr 12 17:44:30 2010 +0200
@@ -34,7 +34,7 @@
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);
@@ -261,7 +261,7 @@
}
/* Vector3 methods */
-static void
+static int
_do_rotate (double *dst_coords, const double *src_coords,
const double* axis_coords, double angle, double epsilon)
{
@@ -282,8 +282,15 @@
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)
@@ -353,6 +360,7 @@
src_coords[1] * (axis[1] * axis[2] * coscompl + axis[0] * sinv) +
src_coords[2] * (cosv + axis[2] * axis[2] * coscompl));
}
+ return 1;
}
static PyObject*
@@ -384,7 +392,12 @@
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;
}
@@ -418,7 +431,11 @@
}
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;
}
@@ -606,7 +623,7 @@
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;
@@ -628,10 +645,17 @@
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));
@@ -643,10 +667,12 @@
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));
}
diff -r fb31d86448f9 -r 8eafbb955d09 test/math_test.py
--- a/test/math_test.py Mon Apr 12 15:51:01 2010 +0200
+++ b/test/math_test.py Mon Apr 12 17:44:30 2010 +0200
@@ -24,15 +24,14 @@
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):
@@ -49,18 +48,17 @@
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__":
diff -r fb31d86448f9 -r 8eafbb955d09 test/math_vector2_test.py
--- a/test/math_vector2_test.py Mon Apr 12 15:51:01 2010 +0200
+++ b/test/math_vector2_test.py Mon Apr 12 17:44:30 2010 +0200
@@ -413,7 +413,7 @@
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):
@@ -429,8 +429,7 @@
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):
@@ -501,7 +500,7 @@
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):
@@ -519,7 +518,7 @@
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):
@@ -529,8 +528,7 @@
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)
@@ -564,15 +562,15 @@
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(self.e2.as_polar(), (1, 90))
self.assertEqual((2 * self.e2).as_polar(),
- (2, math.pi / 2))
+ (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):
diff -r fb31d86448f9 -r 8eafbb955d09 test/math_vector3_test.py
--- a/test/math_vector3_test.py Mon Apr 12 15:51:01 2010 +0200
+++ b/test/math_vector3_test.py Mon Apr 12 17:44:30 2010 +0200
@@ -162,7 +162,7 @@
self.assertEqual(type(b), type(self.v1))
self.assertEqual(type(c), type(self.v1))
def bogus_subscript_ass():
- v = Vector2()
+ v = Vector3()
v["spam"] = 3
self.assertRaises(TypeError, bogus_subscript_ass)
self.assertRaises(TypeError, lambda : v["spam"])
@@ -629,7 +629,7 @@
(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
@@ -644,8 +644,7 @@
(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)
@@ -668,7 +667,7 @@
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)
@@ -688,7 +687,7 @@
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)
@@ -702,7 +701,7 @@
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
@@ -723,11 +722,9 @@
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
@@ -748,18 +745,17 @@
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__":
diff -r fb31d86448f9 -r 836db69eedd1 src/math/vector.c
--- a/src/math/vector.c Mon Apr 12 15:51:01 2010 +0200
+++ b/src/math/vector.c Mon Apr 12 16:29:16 2010 +0200
@@ -632,7 +632,7 @@
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;
}
@@ -652,7 +652,7 @@
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;
}
@@ -703,7 +703,7 @@
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;
@@ -828,7 +828,7 @@
if (oldlength < self->epsilon)
{
- PyErr_SetString (PyExc_ZeroDivisionError,
+ PyErr_SetString (PyExc_ValueError,
"cannot scale a vector with zero length");
return NULL;
}
@@ -874,7 +874,7 @@
nlength += ncoords[i] * ncoords[i];
if (nlength < eps)
{
- PyErr_SetString (PyExc_ZeroDivisionError,
+ PyErr_SetString (PyExc_ValueError,
"normal must not be a zero-length vector");
goto ret;
}
@@ -1139,6 +1139,11 @@
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)
@@ -1152,6 +1157,11 @@
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;
@@ -1164,6 +1174,11 @@
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)
@@ -1177,6 +1192,11 @@
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);
@@ -1317,7 +1337,7 @@
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;
diff -r fb31d86448f9 -r 836db69eedd1 src/math/vector3.c
--- a/src/math/vector3.c Mon Apr 12 15:51:01 2010 +0200
+++ b/src/math/vector3.c Mon Apr 12 16:29:16 2010 +0200
@@ -34,7 +34,7 @@
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);
@@ -261,7 +261,7 @@
}
/* Vector3 methods */
-static void
+static int
_do_rotate (double *dst_coords, const double *src_coords,
const double* axis_coords, double angle, double epsilon)
{
@@ -282,6 +282,13 @@
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)
{
@@ -353,6 +360,7 @@
src_coords[1] * (axis[1] * axis[2] * coscompl + axis[0] * sinv) +
src_coords[2] * (cosv + axis[2] * axis[2] * coscompl));
}
+ return 1;
}
static PyObject*
@@ -384,7 +392,12 @@
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;
}
@@ -418,7 +431,11 @@
}
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;
}
@@ -606,7 +623,7 @@
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;
@@ -628,10 +645,17 @@
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));
@@ -643,6 +667,8 @@
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]);
diff -r 631736a6ae2b -r 5efe286b0f07 src/math/vector.c
--- a/src/math/vector.c Mon Apr 12 16:32:39 2010 +0200
+++ b/src/math/vector.c Mon Apr 12 17:01:19 2010 +0200
@@ -669,7 +669,7 @@
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;
@@ -708,8 +708,11 @@
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)
{
@@ -726,12 +729,28 @@
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;
}
@@ -765,9 +784,9 @@
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;
}
diff -r 631736a6ae2b -r 5efe286b0f07 src/math/vector2.c
--- a/src/math/vector2.c Mon Apr 12 16:32:39 2010 +0200
+++ b/src/math/vector2.c Mon Apr 12 17:01:19 2010 +0200
@@ -360,7 +360,7 @@
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 */
diff -r 631736a6ae2b -r 5efe286b0f07 src/math/vector3.c
--- a/src/math/vector3.c Mon Apr 12 16:32:39 2010 +0200
+++ b/src/math/vector3.c Mon Apr 12 17:01:19 2010 +0200
@@ -672,7 +672,7 @@
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));
}
diff -r 631736a6ae2b -r 5efe286b0f07 test/math_test.py
--- a/test/math_test.py Mon Apr 12 16:32:39 2010 +0200
+++ b/test/math_test.py Mon Apr 12 17:01:19 2010 +0200
@@ -24,15 +24,14 @@
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):
@@ -49,18 +48,17 @@
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__":
diff -r 631736a6ae2b -r 5efe286b0f07 test/math_vector2_test.py
--- a/test/math_vector2_test.py Mon Apr 12 16:32:39 2010 +0200
+++ b/test/math_vector2_test.py Mon Apr 12 17:01:19 2010 +0200
@@ -413,7 +413,7 @@
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):
@@ -429,8 +429,7 @@
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):
@@ -501,7 +500,7 @@
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):
@@ -519,7 +518,7 @@
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):
@@ -529,8 +528,7 @@
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)
@@ -564,15 +562,15 @@
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(self.e2.as_polar(), (1, 90))
self.assertEqual((2 * self.e2).as_polar(),
- (2, math.pi / 2))
+ (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):
diff -r 631736a6ae2b -r 5efe286b0f07 test/math_vector3_test.py
--- a/test/math_vector3_test.py Mon Apr 12 16:32:39 2010 +0200
+++ b/test/math_vector3_test.py Mon Apr 12 17:01:19 2010 +0200
@@ -162,7 +162,7 @@
self.assertEqual(type(b), type(self.v1))
self.assertEqual(type(c), type(self.v1))
def bogus_subscript_ass():
- v = Vector2()
+ v = Vector3()
v["spam"] = 3
self.assertRaises(TypeError, bogus_subscript_ass)
self.assertRaises(TypeError, lambda : v["spam"])
@@ -629,7 +629,7 @@
(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
@@ -644,8 +644,7 @@
(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)
@@ -668,7 +667,7 @@
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)
@@ -688,7 +687,7 @@
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)
@@ -702,7 +701,7 @@
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
@@ -723,11 +722,9 @@
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
@@ -748,18 +745,17 @@
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__":
diff -r 5efe286b0f07 -r 8eafbb955d09 src/base/basemod.c
--- a/src/base/basemod.c Mon Apr 12 17:01:19 2010 +0200
+++ b/src/base/basemod.c Mon Apr 12 17:44:30 2010 +0200
@@ -109,8 +109,8 @@
return 0;
}
-unsigned long
-UlongFromObj (PyObject* obj, long* val)
+int
+UlongFromObj (PyObject* obj, unsigned long* val)
{
PyObject* longobj;
unsigned long tmp;
diff -r 5efe286b0f07 -r 8eafbb955d09 src/base/internals.h
--- a/src/base/internals.h Mon Apr 12 17:01:19 2010 +0200
+++ b/src/base/internals.h Mon Apr 12 17:44:30 2010 +0200
@@ -60,7 +60,7 @@
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;
diff -r 5efe286b0f07 -r 8eafbb955d09 src/math/vector.c
--- a/src/math/vector.c Mon Apr 12 17:01:19 2010 +0200
+++ b/src/math/vector.c Mon Apr 12 17:44:30 2010 +0200
@@ -538,12 +538,18 @@
PyVector *v = (PyVector *) self;
Py_ssize_t i;
- PyObject *tuple = PyTuple_New (v->dim);
+ PyObject *tmp, *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;
}
@@ -841,9 +847,7 @@
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)
{
@@ -888,9 +892,7 @@
}
/* 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_ValueError,
@@ -906,9 +908,7 @@
}
/* 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)
@@ -954,68 +954,54 @@
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*
@@ -1326,7 +1312,7 @@
}
/**
- * -vector1, ~vector1
+ * -vector1, +vector1
*/
static PyObject*
_vector_neg (PyVector *self)
@@ -1636,7 +1622,7 @@
double diff;
PyVector *v = NULL, *v2 = NULL;
PyObject *other = NULL;
- int swap = 0, retval = 1;
+ int retval = 1;
if (PyVector_Check (o1))
{
@@ -1645,7 +1631,6 @@
}
else if (PyVector_Check (o2))
{
- swap = 1;
v = (PyVector *) o2;
other = o1;
}
@@ -1686,13 +1671,6 @@
}
}
}
- if (swap == 1)
- {
- if (retval == 0)
- retval = 1;
- else
- retval = 0;
- }
switch (op)
{
diff -r 5efe286b0f07 -r 8eafbb955d09 src/math/vector3.c
--- a/src/math/vector3.c Mon Apr 12 17:01:19 2010 +0200
+++ b/src/math/vector3.c Mon Apr 12 17:44:30 2010 +0200
@@ -290,7 +290,7 @@
}
/* normalize the axis */
- if (axislen - 1 > epsilon)
+ if (fabs(axislen - 1) > epsilon)
{
nfactor = 1. / sqrt (axislen);
for (i = 0; i < 3; ++i)