Blender  V2.59
mathutils.c
Go to the documentation of this file.
00001 /* 
00002  * $Id: mathutils.c 38409 2011-07-15 04:01:47Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * This is a new part of Blender.
00024  *
00025  * Contributor(s): Joseph Gilbert, Campbell Barton
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00034 #include <Python.h>
00035 
00036 #include "mathutils.h"
00037 
00038 #include "BLI_math.h"
00039 #include "BLI_utildefines.h"
00040 
00041 PyDoc_STRVAR(M_Mathutils_doc,
00042 "This module provides access to matrices, eulers, quaternions and vectors."
00043 );
00044 static int mathutils_array_parse_fast(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
00045 {
00046         PyObject *value_fast= NULL;
00047         PyObject *item;
00048 
00049         int i, size;
00050 
00051         /* non list/tuple cases */
00052         if(!(value_fast=PySequence_Fast(value, error_prefix))) {
00053                 /* PySequence_Fast sets the error */
00054                 return -1;
00055         }
00056 
00057         size= PySequence_Fast_GET_SIZE(value_fast);
00058 
00059         if(size > array_max || size < array_min) {
00060                 if (array_max == array_min)     {
00061                         PyErr_Format(PyExc_ValueError,
00062                                      "%.200s: sequence size is %d, expected %d",
00063                                      error_prefix, size, array_max);
00064                 }
00065                 else {
00066                         PyErr_Format(PyExc_ValueError,
00067                                      "%.200s: sequence size is %d, expected [%d - %d]",
00068                                      error_prefix, size, array_min, array_max);
00069                 }
00070                 Py_DECREF(value_fast);
00071                 return -1;
00072         }
00073 
00074         i= size;
00075         do {
00076                 i--;
00077                 if(((array[i]= PyFloat_AsDouble((item= PySequence_Fast_GET_ITEM(value_fast, i)))) == -1.0f) && PyErr_Occurred()) {
00078                         PyErr_Format(PyExc_TypeError,
00079                                      "%.200s: sequence index %d expected a number, "
00080                                      "found '%.200s' type, ",
00081                                      error_prefix, i, Py_TYPE(item)->tp_name);
00082                         Py_DECREF(value_fast);
00083                         return -1;
00084                 }
00085         } while(i);
00086 
00087         Py_XDECREF(value_fast);
00088         return size;
00089 }
00090 
00091 /* helper functionm returns length of the 'value', -1 on error */
00092 int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
00093 {
00094 #if 1 /* approx 6x speedup for mathutils types */
00095         int size;
00096 
00097         if(     (VectorObject_Check(value) && (size= ((VectorObject *)value)->size)) ||
00098                 (EulerObject_Check(value) && (size= 3)) ||
00099                 (QuaternionObject_Check(value) && (size= 4)) ||
00100                 (ColorObject_Check(value) && (size= 3))
00101         ) {
00102                 if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
00103                         return -1;
00104                 }
00105 
00106                 if(size > array_max || size < array_min) {
00107                         if (array_max == array_min)     {
00108                                 PyErr_Format(PyExc_ValueError,
00109                                              "%.200s: sequence size is %d, expected %d",
00110                                              error_prefix, size, array_max);
00111                         }
00112                         else {
00113                                 PyErr_Format(PyExc_ValueError,
00114                                              "%.200s: sequence size is %d, expected [%d - %d]",
00115                                              error_prefix, size, array_min, array_max);
00116                         }
00117                         return -1;
00118                 }
00119 
00120                 memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float));
00121                 return size;
00122         }
00123         else
00124 #endif
00125         {
00126                 return mathutils_array_parse_fast(array, array_min, array_max, value, error_prefix);
00127         }
00128 }
00129 
00130 int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
00131 {
00132         if(EulerObject_Check(value)) {
00133                 if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
00134                         return -1;
00135                 }
00136                 else {
00137                         eulO_to_mat3(rmat, ((EulerObject *)value)->eul, ((EulerObject *)value)->order);
00138                         return 0;
00139                 }
00140         }
00141         else if (QuaternionObject_Check(value)) {
00142                 if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
00143                         return -1;
00144                 }
00145                 else {
00146                         float tquat[4];
00147                         normalize_qt_qt(tquat, ((QuaternionObject *)value)->quat);
00148                         quat_to_mat3(rmat, tquat);
00149                         return 0;
00150                 }
00151         }
00152         else if (MatrixObject_Check(value)) {
00153                 if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
00154                         return -1;
00155                 }
00156                 else if(((MatrixObject *)value)->col_size < 3 || ((MatrixObject *)value)->row_size < 3) {
00157                         PyErr_Format(PyExc_ValueError,
00158                                      "%.200s: matrix must have minimum 3x3 dimensions",
00159                                      error_prefix);
00160                         return -1;
00161                 }
00162                 else {
00163                         matrix_as_3x3(rmat, (MatrixObject *)value);
00164                         normalize_m3(rmat);
00165                         return 0;
00166                 }
00167         }
00168         else {
00169                 PyErr_Format(PyExc_TypeError,
00170                              "%.200s: expected a Euler, Quaternion or Matrix type, "
00171                              "found %.200s", error_prefix, Py_TYPE(value)->tp_name);
00172                 return -1;
00173         }
00174 }
00175 
00176 
00177 //----------------------------------MATRIX FUNCTIONS--------------------
00178 
00179 
00180 /* Utility functions */
00181 
00182 // LomontRRDCompare4, Ever Faster Float Comparisons by Randy Dillon
00183 #define SIGNMASK(i) (-(int)(((unsigned int)(i))>>31))
00184 
00185 int EXPP_FloatsAreEqual(float af, float bf, int maxDiff)
00186 {       // solid, fast routine across all platforms
00187         // with constant time behavior
00188         int ai = *(int *)(&af);
00189         int bi = *(int *)(&bf);
00190         int test = SIGNMASK(ai^bi);
00191         int diff, v1, v2;
00192 
00193         assert((0 == test) || (0xFFFFFFFF == test));
00194         diff = (ai ^ (test & 0x7fffffff)) - bi;
00195         v1 = maxDiff + diff;
00196         v2 = maxDiff - diff;
00197         return (v1|v2) >= 0;
00198 }
00199 
00200 /*---------------------- EXPP_VectorsAreEqual -------------------------
00201   Builds on EXPP_FloatsAreEqual to test vectors */
00202 int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps)
00203 {
00204         int x;
00205         for (x=0; x< size; x++){
00206                 if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0)
00207                         return 0;
00208         }
00209         return 1;
00210 }
00211 
00212 
00213 /* Mathutils Callbacks */
00214 
00215 /* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */
00216 static Mathutils_Callback *mathutils_callbacks[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
00217 
00218 int Mathutils_RegisterCallback(Mathutils_Callback *cb)
00219 {
00220         int i;
00221         
00222         /* find the first free slot */
00223         for(i= 0; mathutils_callbacks[i]; i++) {
00224                 if(mathutils_callbacks[i]==cb) /* already registered? */
00225                         return i;
00226         }
00227         
00228         mathutils_callbacks[i] = cb;
00229         return i;
00230 }
00231 
00232 /* use macros to check for NULL */
00233 int _BaseMathObject_ReadCallback(BaseMathObject *self)
00234 {
00235         Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
00236         if(cb->get(self, self->cb_subtype) != -1)
00237                 return 0;
00238 
00239         if(!PyErr_Occurred()) {
00240                 PyErr_Format(PyExc_RuntimeError,
00241                              "%s read, user has become invalid",
00242                              Py_TYPE(self)->tp_name);
00243         }
00244         return -1;
00245 }
00246 
00247 int _BaseMathObject_WriteCallback(BaseMathObject *self)
00248 {
00249         Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
00250         if(cb->set(self, self->cb_subtype) != -1)
00251                 return 0;
00252 
00253         if(!PyErr_Occurred()) {
00254                 PyErr_Format(PyExc_RuntimeError,
00255                              "%s write, user has become invalid",
00256                              Py_TYPE(self)->tp_name);
00257         }
00258         return -1;
00259 }
00260 
00261 int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index)
00262 {
00263         Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
00264         if(cb->get_index(self, self->cb_subtype, index) != -1)
00265                 return 0;
00266 
00267         if(!PyErr_Occurred()) {
00268                 PyErr_Format(PyExc_RuntimeError,
00269                              "%s read index, user has become invalid",
00270                              Py_TYPE(self)->tp_name);
00271         }
00272         return -1;
00273 }
00274 
00275 int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index)
00276 {
00277         Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
00278         if(cb->set_index(self, self->cb_subtype, index) != -1)
00279                 return 0;
00280 
00281         if(!PyErr_Occurred()) {
00282                 PyErr_Format(PyExc_RuntimeError,
00283                              "%s write index, user has become invalid",
00284                              Py_TYPE(self)->tp_name);
00285         }
00286         return -1;
00287 }
00288 
00289 /* BaseMathObject generic functions for all mathutils types */
00290 char BaseMathObject_Owner_doc[] = "The item this is wrapping or None  (readonly).";
00291 PyObject *BaseMathObject_getOwner(BaseMathObject *self, void *UNUSED(closure))
00292 {
00293         PyObject *ret= self->cb_user ? self->cb_user : Py_None;
00294         Py_INCREF(ret);
00295         return ret;
00296 }
00297 
00298 char BaseMathObject_Wrapped_doc[] = "True when this object wraps external data (readonly).\n\n:type: boolean";
00299 PyObject *BaseMathObject_getWrapped(BaseMathObject *self, void *UNUSED(closure))
00300 {
00301         return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1:0);
00302 }
00303 
00304 int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
00305 {
00306         Py_VISIT(self->cb_user);
00307         return 0;
00308 }
00309 
00310 int BaseMathObject_clear(BaseMathObject *self)
00311 {
00312         Py_CLEAR(self->cb_user);
00313         return 0;
00314 }
00315 
00316 void BaseMathObject_dealloc(BaseMathObject *self)
00317 {
00318         /* only free non wrapped */
00319         if(self->wrapped != Py_WRAP) {
00320                 PyMem_Free(self->data);
00321         }
00322 
00323         if(self->cb_user) {
00324                 PyObject_GC_UnTrack(self);
00325                 BaseMathObject_clear(self);
00326         }
00327 
00328         Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes
00329 }
00330 
00331 /*----------------------------MODULE INIT-------------------------*/
00332 static struct PyMethodDef M_Mathutils_methods[] = {
00333         {NULL, NULL, 0, NULL}
00334 };
00335 
00336 static struct PyModuleDef M_Mathutils_module_def = {
00337         PyModuleDef_HEAD_INIT,
00338         "mathutils",  /* m_name */
00339         M_Mathutils_doc,  /* m_doc */
00340         0,  /* m_size */
00341         M_Mathutils_methods,  /* m_methods */
00342         NULL,  /* m_reload */
00343         NULL,  /* m_traverse */
00344         NULL,  /* m_clear */
00345         NULL,  /* m_free */
00346 };
00347 
00348 PyMODINIT_FUNC PyInit_mathutils(void)
00349 {
00350         PyObject *submodule;
00351         PyObject *item;
00352 
00353         if(PyType_Ready(&vector_Type) < 0)
00354                 return NULL;
00355         if(PyType_Ready(&matrix_Type) < 0)
00356                 return NULL;    
00357         if(PyType_Ready(&euler_Type) < 0)
00358                 return NULL;
00359         if(PyType_Ready(&quaternion_Type) < 0)
00360                 return NULL;
00361         if(PyType_Ready(&color_Type) < 0)
00362                 return NULL;
00363 
00364         submodule = PyModule_Create(&M_Mathutils_module_def);
00365         
00366         /* each type has its own new() function */
00367         PyModule_AddObject(submodule, "Vector",         (PyObject *)&vector_Type);
00368         PyModule_AddObject(submodule, "Matrix",         (PyObject *)&matrix_Type);
00369         PyModule_AddObject(submodule, "Euler",          (PyObject *)&euler_Type);
00370         PyModule_AddObject(submodule, "Quaternion",     (PyObject *)&quaternion_Type);
00371         PyModule_AddObject(submodule, "Color",          (PyObject *)&color_Type);
00372         
00373         /* submodule */
00374         PyModule_AddObject(submodule, "geometry",               (item=PyInit_mathutils_geometry()));
00375         /* XXX, python doesnt do imports with this usefully yet
00376          * 'from mathutils.geometry import PolyFill'
00377          * ...fails without this. */
00378         PyDict_SetItemString(PyThreadState_GET()->interp->modules, "mathutils.geometry", item);
00379         Py_INCREF(item);
00380 
00381         mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb);
00382 
00383         return submodule;
00384 }