py/mathutils fix for eternal loop with Matrix.Rotation().
authorCampbell Barton <ideasman42@gmail.com>
Tue, 11 Jan 2011 09:41:26 +0000 (09:41 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 11 Jan 2011 09:41:26 +0000 (09:41 +0000)
rotation range clamping used a while loop which would run forever when the value was so big subtracting a full revolution didnt change the value.

Solve by using fmod() and double precision angle.

source/blender/python/generic/mathutils_matrix.c
source/blender/python/generic/mathutils_quat.c

index 2418f746dd055bbb87eb5be0d82900cbbbd7c9c4..c36341269dbc0785c69f612866bc700442ab626d 100644 (file)
@@ -170,11 +170,11 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
        VectorObject *vec= NULL;
        char *axis= NULL;
        int matSize;
-       float angle = 0.0f;
+       double angle; /* use double because of precission problems at high values */
        float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
                0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
 
-       if(!PyArg_ParseTuple(args, "fi|O", &angle, &matSize, &vec)) {
+       if(!PyArg_ParseTuple(args, "di|O", &angle, &matSize, &vec)) {
                PyErr_SetString(PyExc_TypeError, "mathutils.RotationMatrix(angle, size, axis): expected float int and a string or vector");
                return NULL;
        }
@@ -191,11 +191,9 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
                }
        }
 
-       while (angle<-(Py_PI*2))
-               angle+=(Py_PI*2);
-       while (angle>(Py_PI*2))
-               angle-=(Py_PI*2);
-       
+       /* clamp angle between -360 and 360 in radians */
+       angle= fmod(angle + M_PI*2, M_PI*4) - M_PI*2;
+
        if(matSize != 2 && matSize != 3 && matSize != 4) {
                PyErr_SetString(PyExc_AttributeError, "mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix");
                return NULL;
index 18eabcb77a1abf530904fe75ac3032fc7adfb4fb..9d79a86dbccfed47054ef8277b486c73ef863339 100644 (file)
@@ -782,22 +782,24 @@ static int Quaternion_setAngle(QuaternionObject * self, PyObject * value, void *
        float tquat[4];
        float len;
        
-       float axis[3];
-       float angle;
+       float axis[3], angle_dummy;
+       double angle;
 
        if(!BaseMath_ReadCallback(self))
                return -1;
 
        len= normalize_qt_qt(tquat, self->quat);
-       quat_to_axis_angle(axis, &angle, tquat);
+       quat_to_axis_angle(axis, &angle_dummy, tquat);
 
-       angle = PyFloat_AsDouble(value);
+       angle= PyFloat_AsDouble(value);
 
        if(angle==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
                PyErr_SetString(PyExc_TypeError, "quaternion.angle = value: float expected");
                return -1;
        }
 
+       angle= fmod(angle + M_PI*2, M_PI*4) - M_PI*2;
+
        /* If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations */
        if( EXPP_FloatsAreEqual(axis[0], 0.0f, 10) &&
                EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
@@ -878,7 +880,7 @@ static int Quaternion_setAxisVec(QuaternionObject *self, PyObject *value, void *
 static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
        PyObject *seq= NULL;
-       float angle = 0.0f;
+       double angle = 0.0f;
        float quat[QUAT_SIZE]= {0.0f, 0.0f, 0.0f, 0.0f};
 
        if(kwds && PyDict_Size(kwds)) {
@@ -886,7 +888,7 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
                return NULL;
        }
        
-       if(!PyArg_ParseTuple(args, "|Of:mathutils.Quaternion", &seq, &angle))
+       if(!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle))
                return NULL;
 
        switch(PyTuple_GET_SIZE(args)) {
@@ -899,7 +901,7 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
        case 2:
                if (mathutils_array_parse(quat, 3, 3, seq, "mathutils.Quaternion()") == -1)
                        return NULL;
-
+               angle= fmod(angle + M_PI*2, M_PI*4) - M_PI*2; /* clamp because of precission issues */
                axis_angle_to_quat(quat, quat, angle);
                break;
        /* PyArg_ParseTuple assures no more then 2 */