332 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			332 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * | ||
|  |  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** | ||
|  |  * | ||
|  |  * This program is free software; you can redistribute it and/or | ||
|  |  * modify it under the terms of the GNU General Public License | ||
|  |  * as published by the Free Software Foundation; either version 2 | ||
|  |  * of the License, or (at your option) any later version. The Blender | ||
|  |  * Foundation also sells licenses for use in proprietary software under | ||
|  |  * the Blender License.  See http://www.blender.org/BL/ for information
 | ||
|  |  * about this. | ||
|  |  * | ||
|  |  * This program is distributed in the hope that it will be useful, | ||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||
|  |  * GNU General Public License for more details. | ||
|  |  * | ||
|  |  * You should have received a copy of the GNU General Public License | ||
|  |  * along with this program; if not, write to the Free Software Foundation, | ||
|  |  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. | ||
|  |  * | ||
|  |  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. | ||
|  |  * All rights reserved. | ||
|  |  * | ||
|  |  *  | ||
|  |  * Contributor(s): Joseph Gilbert | ||
|  |  * | ||
|  |  * ***** END GPL/BL DUAL LICENSE BLOCK ***** | ||
|  |  */ | ||
|  | 
 | ||
|  | #include "euler.h"
 | ||
|  | 
 | ||
|  | //doc strings
 | ||
|  | char Euler_Zero_doc[] = | ||
|  | "() - set all values in the euler to 0"; | ||
|  | char Euler_Unique_doc[] = | ||
|  | "() - sets the euler rotation a unique shortest arc rotation - tests for gimbal lock"; | ||
|  | char Euler_ToMatrix_doc[] = | ||
|  | "() - returns a rotation matrix representing the euler rotation"; | ||
|  | char Euler_ToQuat_doc[] = | ||
|  | "() - returns a quaternion representing the euler rotation"; | ||
|  | 
 | ||
|  | //methods table
 | ||
|  | struct PyMethodDef Euler_methods[] = { | ||
|  | 	{"zero",(PyCFunction)Euler_Zero, METH_NOARGS, | ||
|  | 				Euler_Zero_doc}, | ||
|  | 	{"unique",(PyCFunction)Euler_Unique, METH_NOARGS, | ||
|  | 				Euler_Unique_doc}, | ||
|  | 	{"toMatrix",(PyCFunction)Euler_ToMatrix, METH_NOARGS, | ||
|  | 				Euler_ToMatrix_doc}, | ||
|  | 	{"toQuat",(PyCFunction)Euler_ToQuat, METH_NOARGS, | ||
|  | 				Euler_ToQuat_doc}, | ||
|  | 	{NULL, NULL, 0, NULL} | ||
|  | }; | ||
|  | 
 | ||
|  | /*****************************/ | ||
|  | //    Euler Python Object   
 | ||
|  | /*****************************/ | ||
|  | 
 | ||
|  | //euler methods
 | ||
|  | PyObject *Euler_ToQuat(EulerObject *self) | ||
|  | { | ||
|  | 	float *quat; | ||
|  | 	int x; | ||
|  | 
 | ||
|  | 	for(x = 0; x < 3; x++){ | ||
|  | 		self->eul[x] *= (float)(Py_PI/180); | ||
|  | 	} | ||
|  | 	quat = PyMem_Malloc(4*sizeof(float)); | ||
|  | 	EulToQuat(self->eul, quat);	 | ||
|  | 	for(x = 0; x < 3; x++){ | ||
|  | 		self->eul[x] *= (float)(180/Py_PI); | ||
|  | 	} | ||
|  | 	return (PyObject*)newQuaternionObject(quat); | ||
|  | } | ||
|  | 
 | ||
|  | PyObject *Euler_ToMatrix(EulerObject *self) | ||
|  | { | ||
|  | 	float *mat; | ||
|  | 	int x; | ||
|  | 
 | ||
|  | 	for(x = 0; x < 3; x++){ | ||
|  | 		self->eul[x] *= (float)(Py_PI/180); | ||
|  | 	} | ||
|  | 	mat = PyMem_Malloc(3*3*sizeof(float)); | ||
|  | 	EulToMat3(self->eul, (float(*)[3])mat); | ||
|  | 	for(x = 0; x < 3; x++){ | ||
|  | 		self->eul[x] *= (float)(180/Py_PI); | ||
|  | 	} | ||
|  | 	return (PyObject*)newMatrixObject(mat,3,3); | ||
|  | } | ||
|  | 
 | ||
|  | PyObject *Euler_Unique(EulerObject *self) | ||
|  | { | ||
|  | 	float heading, pitch, bank; | ||
|  | 	float pi2  = (float)Py_PI * 2.0f; | ||
|  | 	float piO2 = (float)Py_PI / 2.0f; | ||
|  | 	float Opi2 = 1.0f / pi2; | ||
|  | 
 | ||
|  | 	//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); | ||
|  | 	 | ||
|  | 	//wrap heading in +180 / -180
 | ||
|  | 	pitch += (float)Py_PI; | ||
|  | 	pitch -= (float)floor(pitch * Opi2) * pi2; | ||
|  | 	pitch -= (float)Py_PI; | ||
|  | 
 | ||
|  | 
 | ||
|  | 	if(pitch < -piO2){ | ||
|  | 		pitch = (float)-Py_PI - pitch; | ||
|  | 		heading += (float)Py_PI; | ||
|  | 		bank += (float)Py_PI; | ||
|  | 	}else if (pitch > piO2){ | ||
|  | 		pitch = (float)Py_PI - pitch; | ||
|  | 		heading += (float)Py_PI; | ||
|  | 		bank += (float)Py_PI; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	//gimbal lock test
 | ||
|  | 	if(fabs(pitch) > piO2 - 1e-4){ | ||
|  | 		heading += bank; | ||
|  | 		bank = 0.0f; | ||
|  | 	}else{ | ||
|  | 		bank += (float)Py_PI; | ||
|  | 		bank -= (float)(floor(bank * Opi2)) * pi2; | ||
|  | 		bank -= (float)Py_PI; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	heading += (float)Py_PI; | ||
|  | 	heading -= (float)(floor(heading * Opi2)) * pi2; | ||
|  | 	heading -= (float)Py_PI; | ||
|  | 	 | ||
|  | 	//back to degrees
 | ||
|  | 	self->eul[0] = heading * (float)(180/Py_PI); | ||
|  | 	self->eul[1] = pitch * (float)(180/Py_PI); | ||
|  | 	self->eul[2] = bank * (float)(180/Py_PI); | ||
|  | 
 | ||
|  | 	return EXPP_incr_ret(Py_None); | ||
|  | } | ||
|  | 
 | ||
|  | PyObject *Euler_Zero(EulerObject *self) | ||
|  | { | ||
|  | 	self->eul[0] = 0.0; | ||
|  | 	self->eul[1] = 0.0; | ||
|  | 	self->eul[2] = 0.0; | ||
|  | 
 | ||
|  | 	return EXPP_incr_ret(Py_None); | ||
|  | } | ||
|  | 
 | ||
|  | static void Euler_dealloc(EulerObject *self) | ||
|  | { | ||
|  |   PyObject_DEL (self); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject *Euler_getattr(EulerObject *self, char *name) | ||
|  | { | ||
|  | 	if (ELEM3(name[0], 'x', 'y', 'z') && name[1]==0){ | ||
|  | 		return PyFloat_FromDouble(self->eul[name[0]-'x']); | ||
|  | 	} | ||
|  | 	return Py_FindMethod(Euler_methods, (PyObject*)self, name); | ||
|  | } | ||
|  | 
 | ||
|  | static int Euler_setattr(EulerObject *self, char *name, PyObject *e) | ||
|  | { | ||
|  | 	float val; | ||
|  | 
 | ||
|  | 	if (!PyArg_Parse(e, "f", &val)) | ||
|  | 		return EXPP_ReturnIntError(PyExc_TypeError,	 | ||
|  | 		"unable to parse float argument\n"); | ||
|  | 
 | ||
|  | 	if (ELEM3(name[0], 'x', 'y', 'z') && name[1]==0){ | ||
|  | 		self->eul[name[0]-'x']= val; | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 	else return -1; | ||
|  | } | ||
|  | 
 | ||
|  | /* Eulers Sequence methods */ | ||
|  | static PyObject *Euler_item(EulerObject *self, int i) | ||
|  | { | ||
|  | 	if (i < 0 || i >= 3) | ||
|  | 	  return EXPP_ReturnPyObjError (PyExc_IndexError, "array index out of range\n"); | ||
|  | 
 | ||
|  | 	return Py_BuildValue("f", self->eul[i]); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject *Euler_slice(EulerObject *self, int begin, int end) | ||
|  | { | ||
|  | 	PyObject *list; | ||
|  | 	int count; | ||
|  |    | ||
|  | 	if (begin < 0) begin= 0; | ||
|  | 	if (end > 3) end= 3; | ||
|  | 	if (begin > end) begin= end; | ||
|  | 
 | ||
|  | 	list= PyList_New(end-begin); | ||
|  | 
 | ||
|  | 	for (count = begin; count < end; count++){ | ||
|  | 		PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->eul[count])); | ||
|  | 	} | ||
|  | 	return list; | ||
|  | } | ||
|  | 
 | ||
|  | static int Euler_ass_item(EulerObject *self, int i, PyObject *ob) | ||
|  | { | ||
|  | 	if (i < 0 || i >= 3) | ||
|  | 		return EXPP_ReturnIntError(PyExc_IndexError, | ||
|  | 					"array assignment index out of range\n"); | ||
|  | 
 | ||
|  | 	if (!PyNumber_Check(ob)) | ||
|  | 		return EXPP_ReturnIntError(PyExc_IndexError, | ||
|  | 					"Euler member must be a number\n"); | ||
|  | 
 | ||
|  | 	if(!PyFloat_Check(ob) && !PyInt_Check(ob)){ | ||
|  | 		return EXPP_ReturnIntError(PyExc_TypeError,"int or float expected\n"); | ||
|  | 	}else{ | ||
|  | 		self->eul[i]= (float)PyFloat_AsDouble(ob); | ||
|  | 	} | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq) | ||
|  | { | ||
|  | 	int count, z; | ||
|  | 
 | ||
|  | 	if (begin < 0) begin= 0; | ||
|  | 	if (end > 3) end= 3; | ||
|  | 	if (begin > end) begin= end; | ||
|  | 
 | ||
|  | 	if (!PySequence_Check(seq)) | ||
|  | 		return EXPP_ReturnIntError(PyExc_TypeError, | ||
|  | 					"illegal argument type for built-in operation\n"); | ||
|  | 	if (PySequence_Length(seq) != (end - begin)) | ||
|  | 		return EXPP_ReturnIntError(PyExc_TypeError, | ||
|  | 					"size mismatch in slice assignment\n"); | ||
|  | 
 | ||
|  | 	z = 0; | ||
|  | 	for (count = begin; count < end; count++) { | ||
|  | 		PyObject *ob = PySequence_GetItem(seq, z); z++; | ||
|  | 
 | ||
|  | 		if(!PyFloat_Check(ob) && !PyInt_Check(ob)){ | ||
|  | 			Py_DECREF(ob); | ||
|  | 			return -1; | ||
|  | 		}else{ | ||
|  | 			if (!PyArg_Parse(ob, "f", &self->eul[count])) { | ||
|  | 				Py_DECREF(ob); | ||
|  | 				return -1; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  |   return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject *Euler_repr (EulerObject *self) | ||
|  | { | ||
|  | 	int i, maxindex = 3 - 1; | ||
|  | 	char ftoa[24]; | ||
|  | 	PyObject *str1, *str2; | ||
|  | 
 | ||
|  | 	str1 = PyString_FromString ("["); | ||
|  | 
 | ||
|  | 	for (i = 0; i < maxindex; i++) { | ||
|  | 		sprintf(ftoa, "%.4f, ", self->eul[i]); | ||
|  | 		str2 = PyString_FromString (ftoa); | ||
|  | 		if (!str1 || !str2) goto error; | ||
|  | 		PyString_ConcatAndDel (&str1, str2); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	sprintf(ftoa, "%.4f]\n", self->eul[maxindex]); | ||
|  | 	str2 = PyString_FromString (ftoa); | ||
|  | 	if (!str1 || !str2) goto error;  | ||
|  | 	PyString_ConcatAndDel (&str1, str2); | ||
|  | 
 | ||
|  | 	if (str1) return str1; | ||
|  | 
 | ||
|  | error: | ||
|  | 	Py_XDECREF (str1); | ||
|  | 	Py_XDECREF (str2); | ||
|  | 	return EXPP_ReturnPyObjError (PyExc_MemoryError, | ||
|  | 			"couldn't create PyString!\n"); | ||
|  | } | ||
|  | 
 | ||
|  | static PySequenceMethods Euler_SeqMethods = | ||
|  | { | ||
|  | 	(inquiry)       0,                     /* sq_length */ | ||
|  | 	(binaryfunc)    0,                     /* sq_concat */ | ||
|  | 	(intargfunc)    0,                     /* sq_repeat */ | ||
|  | 	(intargfunc)    Euler_item,            /* sq_item */ | ||
|  | 	(intintargfunc)   Euler_slice,         /* sq_slice */ | ||
|  | 	(intobjargproc)   Euler_ass_item,      /* sq_ass_item */ | ||
|  | 	(intintobjargproc)  Euler_ass_slice,   /* sq_ass_slice */ | ||
|  | }; | ||
|  | 
 | ||
|  | PyTypeObject euler_Type = | ||
|  | { | ||
|  |   PyObject_HEAD_INIT(NULL) | ||
|  |   0,                           /*ob_size*/ | ||
|  |   "euler",                     /*tp_name*/ | ||
|  |   sizeof(EulerObject),         /*tp_basicsize*/ | ||
|  |   0,                           /*tp_itemsize*/ | ||
|  |   (destructor)  Euler_dealloc,  /*tp_dealloc*/ | ||
|  |   (printfunc)   0,              /*tp_print*/ | ||
|  |   (getattrfunc) Euler_getattr, /*tp_getattr*/ | ||
|  |   (setattrfunc) Euler_setattr, /*tp_setattr*/ | ||
|  |   0,                           /*tp_compare*/ | ||
|  |   (reprfunc)    Euler_repr,    /*tp_repr*/ | ||
|  |   0,                           /*tp_as_number*/ | ||
|  |   &Euler_SeqMethods,           /*tp_as_sequence*/ | ||
|  | }; | ||
|  | 
 | ||
|  | PyObject *newEulerObject(float *eul) | ||
|  | { | ||
|  |   EulerObject *self; | ||
|  |   int x; | ||
|  | 
 | ||
|  |   euler_Type.ob_type = &PyType_Type; | ||
|  | 
 | ||
|  |   self = PyObject_NEW(EulerObject, &euler_Type); | ||
|  | 
 | ||
|  |   if(!eul){ | ||
|  | 	  self->eul = PyMem_Malloc (3*sizeof (float)); | ||
|  | 	  for(x = 0; x < 3; x++){ | ||
|  | 		  self->eul[x] = 0.0f; | ||
|  | 	  } | ||
|  |   }else	self->eul = eul; | ||
|  |   | ||
|  |   return (PyObject*) self; | ||
|  | } | ||
|  | 
 |