[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [27029] trunk/blender: Mathutils API: Euler support for rotation order.

Campbell Barton ideasman42 at gmail.com
Sat Feb 20 20:49:05 CET 2010


Revision: 27029
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=27029
Author:   campbellbarton
Date:     2010-02-20 20:49:04 +0100 (Sat, 20 Feb 2010)

Log Message:
-----------
Mathutils API: Euler support for rotation order.

Examples.
 euler = Euler(1, 2, 3)
 euler.order = 'ZXY'
 
 euler = matrix.to_euler('XZY')


Still missing rna support. this still wont give the right order, defaulting to XYZ.
 eul = object.rotation_euler

Modified Paths:
--------------
    trunk/blender/release/scripts/io/export_fbx.py
    trunk/blender/source/blender/blenlib/intern/math_rotation.c
    trunk/blender/source/blender/python/generic/Mathutils.c
    trunk/blender/source/blender/python/generic/Mathutils.h
    trunk/blender/source/blender/python/generic/euler.c
    trunk/blender/source/blender/python/generic/euler.h
    trunk/blender/source/blender/python/generic/matrix.c
    trunk/blender/source/blender/python/generic/quat.c
    trunk/blender/source/blender/python/generic/vector.c
    trunk/blender/source/blender/python/intern/bpy_rna.c

Modified: trunk/blender/release/scripts/io/export_fbx.py
===================================================================
--- trunk/blender/release/scripts/io/export_fbx.py	2010-02-20 15:27:38 UTC (rev 27028)
+++ trunk/blender/release/scripts/io/export_fbx.py	2010-02-20 19:49:04 UTC (rev 27029)
@@ -2876,7 +2876,7 @@
                                 context_bone_anim_vecs = []
                                 prev_eul = None
                                 for mtx in context_bone_anim_mats:
-                                    if prev_eul:	prev_eul = mtx[1].to_euler(prev_eul)
+                                    if prev_eul:	prev_eul = mtx[1].to_euler('XYZ', prev_eul)
                                     else:			prev_eul = mtx[1].to_euler()
                                     context_bone_anim_vecs.append(eulerRadToDeg(prev_eul))
 # 									context_bone_anim_vecs.append(prev_eul)

Modified: trunk/blender/source/blender/blenlib/intern/math_rotation.c
===================================================================
--- trunk/blender/source/blender/blenlib/intern/math_rotation.c	2010-02-20 15:27:38 UTC (rev 27028)
+++ trunk/blender/source/blender/blenlib/intern/math_rotation.c	2010-02-20 19:49:04 UTC (rev 27029)
@@ -1052,7 +1052,7 @@
 	{{1, 0, 2}, 1}, // YXZ
 	{{1, 2, 0}, 0}, // YZX
 	{{2, 0, 1}, 0}, // ZXY
-	{{2, 1, 0}, 1}  // ZYZ
+	{{2, 1, 0}, 1}  // ZYX
 };
 
 /* Get relevant pointer to rotation order set from the array 

Modified: trunk/blender/source/blender/python/generic/Mathutils.c
===================================================================
--- trunk/blender/source/blender/python/generic/Mathutils.c	2010-02-20 15:27:38 UTC (rev 27028)
+++ trunk/blender/source/blender/python/generic/Mathutils.c	2010-02-20 19:49:04 UTC (rev 27029)
@@ -170,18 +170,10 @@
 		}
 	}
 
-#ifdef USE_MATHUTILS_DEG
-	/* Clamp to -360:360 */
-	while (angle<-360.0f)
-		angle+=360.0;
-	while (angle>360.0f)
-		angle-=360.0;
-#else
 	while (angle<-(Py_PI*2))
 		angle+=(Py_PI*2);
 	while (angle>(Py_PI*2))
 		angle-=(Py_PI*2);
-#endif
 	
 	if(matSize != 2 && matSize != 3 && matSize != 4) {
 		PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
@@ -205,10 +197,6 @@
 			return NULL;
 		
 	}
-#ifdef USE_MATHUTILS_DEG
-	//convert to radians
-	angle = angle * (float) (Py_PI / 180);
-#endif
 
 	/* check for valid vector/axis above */
 	if(vec) {

Modified: trunk/blender/source/blender/python/generic/Mathutils.h
===================================================================
--- trunk/blender/source/blender/python/generic/Mathutils.h	2010-02-20 15:27:38 UTC (rev 27028)
+++ trunk/blender/source/blender/python/generic/Mathutils.h	2010-02-20 19:49:04 UTC (rev 27029)
@@ -37,8 +37,6 @@
 #include "quat.h"
 #include "euler.h"
 
-/* #define USE_MATHUTILS_DEG - for backwards compat */
-
 /* Can cast different mathutils types to this, use for generic funcs */
 
 extern char BaseMathObject_Wrapped_doc[];

Modified: trunk/blender/source/blender/python/generic/euler.c
===================================================================
--- trunk/blender/source/blender/python/generic/euler.c	2010-02-20 15:27:38 UTC (rev 27028)
+++ trunk/blender/source/blender/python/generic/euler.c	2010-02-20 19:49:04 UTC (rev 27029)
@@ -41,6 +41,7 @@
 	int size, i;
 	float eul[3];
 	PyObject *e;
+	short order= 0;  // TODO, add order option
 
 	size = PyTuple_GET_SIZE(args);
 	if (size == 1) {
@@ -53,7 +54,7 @@
 		}
 	} else if (size == 0) {
 		//returns a new empty 3d euler
-		return newEulerObject(NULL, Py_NEW, NULL);
+		return newEulerObject(NULL, order, Py_NEW, NULL);
 	} else {
 		listObject = args;
 	}
@@ -79,9 +80,26 @@
 			return NULL;
 		}
 	}
-	return newEulerObject(eul, Py_NEW, NULL);
+	return newEulerObject(eul, order, Py_NEW, NULL);
 }
 
+short euler_order_from_string(const char *str, const char *error_prefix)
+{
+	if((str[0] && str[1] && str[2] && str[3]=='\0')) {
+		switch(*((int32_t *)str)) {
+			case 'X'|'Y'<<8|'Z'<<16:	return 0;
+			case 'X'|'Z'<<8|'Y'<<16:	return 1;
+			case 'Y'|'X'<<8|'Z'<<16:	return 2;
+			case 'Y'|'Z'<<8|'X'<<16:	return 3;
+			case 'Z'|'X'<<8|'Y'<<16:	return 4;
+			case 'Z'|'Y'<<8|'X'<<16:	return 5;
+		}
+	}
+
+	PyErr_Format(PyExc_TypeError, "%s: invalid euler order '%s'", error_prefix, str);
+	return -1;
+}
+
 //-----------------------------METHODS----------------------------
 //----------------------------Euler.toQuat()----------------------
 //return a quaternion representation of the euler
@@ -97,22 +115,12 @@
 static PyObject *Euler_ToQuat(EulerObject * self)
 {
 	float quat[4];
-#ifdef USE_MATHUTILS_DEG
-	float eul[3];
-	int x;
-#endif
 
 	if(!BaseMath_ReadCallback(self))
 		return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-	for(x = 0; x < 3; x++) {
-		eul[x] = self->eul[x] * ((float)Py_PI / 180);
-	}
-	eul_to_quat( quat,eul);
-#else
-	eul_to_quat( quat,self->eul);
-#endif
+	if(self->order==0)	eul_to_quat(quat, self->eul);
+	else				eulO_to_quat(quat, self->eul, self->order);
 
 	return newQuaternionObject(quat, Py_NEW, NULL);
 }
@@ -133,24 +141,14 @@
 	if(!BaseMath_ReadCallback(self))
 		return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-	{
-		float eul[3];
-		int x;
-		
-		for(x = 0; x < 3; x++) {
-			eul[x] = self->eul[x] * ((float)Py_PI / 180);
-		}
-		eul_to_mat3( (float (*)[3]) mat,eul);
-	}
-#else
-	eul_to_mat3( (float (*)[3]) mat,self->eul);
-#endif
+	if(self->order==0)	eul_to_mat3((float (*)[3])mat, self->eul);
+	else				eulO_to_mat3((float (*)[3])mat, self->eul, self->order);
+
 	return newMatrixObject(mat, 3, 3 , Py_NEW, NULL);
 }
 //----------------------------Euler.unique()-----------------------
 //sets the x,y,z values to a unique euler rotation
-
+// TODO, check if this works with rotation order!!!
 static char Euler_Unique_doc[] =
 ".. method:: unique()\n"
 "\n"
@@ -170,16 +168,9 @@
 	if(!BaseMath_ReadCallback(self))
 		return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-	//radians
-	heading = self->eul[0] * (float)Py_PI / 180;
-	pitch = self->eul[1] * (float)Py_PI / 180;
-	bank = self->eul[2] * (float)Py_PI / 180;
-#else
 	heading = self->eul[0];
 	pitch = self->eul[1];
 	bank = self->eul[2];
-#endif
 
 	//wrap heading in +180 / -180
 	pitch += Py_PI;
@@ -210,13 +201,6 @@
 	heading -= (floor(heading * PI_INV)) * PI_2;
 	heading -= Py_PI;
 
-#ifdef USE_MATHUTILS_DEG
-	//back to degrees
-	self->eul[0] = (float)(heading * 180 / (float)Py_PI);
-	self->eul[1] = (float)(pitch * 180 / (float)Py_PI);
-	self->eul[2] = (float)(bank * 180 / (float)Py_PI);
-#endif
-
 	BaseMath_WriteCallback(self);
 	Py_INCREF(self);
 	return (PyObject *)self;
@@ -261,29 +245,9 @@
 	if(!BaseMath_ReadCallback(self))
 		return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-	{
-		int x;
+	if(self->order == 0)	rotate_eul(self->eul, *axis, angle);
+	else					rotate_eulO(self->eul, self->order, *axis, angle);
 
-		//covert to radians
-		angle *= ((float)Py_PI / 180);
-		for(x = 0; x < 3; x++) {
-			self->eul[x] *= ((float)Py_PI / 180);
-		}
-	}
-#endif
-	rotate_eul(self->eul, *axis, angle);
-
-#ifdef USE_MATHUTILS_DEG
-	{
-		int x;
-		//convert back from radians
-		for(x = 0; x < 3; x++) {
-			self->eul[x] *= (180 / (float)Py_PI);
-		}
-	}
-#endif
-
 	BaseMath_WriteCallback(self);
 	Py_INCREF(self);
 	return (PyObject *)self;
@@ -297,40 +261,27 @@
 "   :arg other: make compatible with this rotation.\n"
 "   :type other: :class:`Euler`\n"
 "   :return: an instance of itself.\n"
-"   :rtype: :class:`Euler`\n";
+"   :rtype: :class:`Euler`\n"
+"\n"
+"   .. note:: the order of eulers must match or an exception is raised.\n";
 
 static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value)
 {
-#ifdef USE_MATHUTILS_DEG
-	float eul_from_rad[3];
-	int x;
-#endif
-	
 	if(!EulerObject_Check(value)) {
-		PyErr_SetString(PyExc_TypeError, "euler.makeCompatible(euler):expected a single euler argument.");
+		PyErr_SetString(PyExc_TypeError, "euler.make_compatible(euler): expected a single euler argument.");
 		return NULL;
 	}
 	
 	if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
 		return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-	//covert to radians
-	for(x = 0; x < 3; x++) {
-		self->eul[x] = self->eul[x] * ((float)Py_PI / 180);
-		eul_from_rad[x] = value->eul[x] * ((float)Py_PI / 180);
+	if(self->order != value->order) {
+		PyErr_SetString(PyExc_ValueError, "euler.make_compatible(euler): rotation orders don't match\n");
+		return NULL;
 	}
-	compatible_eul(self->eul, eul_from_rad);
-#else
+
 	compatible_eul(self->eul, value->eul);
-#endif
 
-#ifdef USE_MATHUTILS_DEG
-	//convert back from radians
-	for(x = 0; x < 3; x++) {
-		self->eul[x] *= (180 / (float)Py_PI);
-	}
-#endif
 	BaseMath_WriteCallback(self);
 	Py_INCREF(self);
 	return (PyObject *)self;
@@ -354,7 +305,7 @@
 	if(!BaseMath_ReadCallback(self))
 		return NULL;
 
-	return newEulerObject(self->eul, Py_NEW, Py_TYPE(self));
+	return newEulerObject(self->eul, self->order, Py_NEW, Py_TYPE(self));
 }
 
 //----------------------------print object (internal)--------------
@@ -402,12 +353,7 @@
 			result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1);
 			break;
 		case Py_NE:
-			result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1);
-			if (result == 0){
-				result = 1;
-			}else{
-				result = 0;
-			}
+			result = !EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1);
 			break;
 		default:
 			printf("The result of the comparison could not be evaluated");
@@ -563,6 +509,30 @@
 	return Euler_ass_item(self, GET_INT_FROM_POINTER(type), value);
 }
 
+/* rotation order */
+static PyObject *Euler_getOrder(EulerObject *self, void *type)
+{
+	static char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
+	return PyUnicode_FromString(order[self->order]);
+}
+
+static int Euler_setOrder( EulerObject * self, PyObject * value, void * type )
+{
+	char *order_str= _PyUnicode_AsString(value);
+	short order= euler_order_from_string(order_str, "euler.order");
+
+	if(order < 0)
+		return -1;
+
+	if(self->cb_user) {
+		PyErr_SetString(PyExc_TypeError, "euler.order: assignment is not allowed on eulers with an owner");
+		return -1;
+	}
+
+	self->order= order;
+	return 0;
+}
+
 /*****************************************************************************/
 /* Python attributes get/set structure:                                      */
 /*****************************************************************************/
@@ -570,6 +540,7 @@
 	{"x", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler X axis in radians. **type** float", (void *)0},

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list