Blender V2.61 - r43446

KX_PyMath.h

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #ifndef __KX_PYMATH_H__
00034 #define __KX_PYMATH_H__
00035 
00036 #include "MT_Point2.h"
00037 #include "MT_Point3.h"
00038 #include "MT_Vector2.h"
00039 #include "MT_Vector3.h"
00040 #include "MT_Vector4.h"
00041 #include "MT_Matrix3x3.h"
00042 #include "MT_Matrix4x4.h"
00043 
00044 #include "KX_Python.h"
00045 #include "PyObjectPlus.h"
00046 
00047 #ifdef WITH_PYTHON
00048 #ifdef USE_MATHUTILS
00049 extern "C" {
00050 #include "../../blender/python/mathutils/mathutils.h" /* so we can have mathutils callbacks */
00051 }
00052 #endif
00053 
00054 inline unsigned int Size(const MT_Matrix4x4&)          { return 4; }
00055 inline unsigned int Size(const MT_Matrix3x3&)          { return 3; }
00056 inline unsigned int Size(const MT_Tuple2&)                { return 2; }
00057 inline unsigned int Size(const MT_Tuple3&)                { return 3; }
00058 inline unsigned int Size(const MT_Tuple4&)                { return 4; }
00059 
00063 template<class T>
00064 bool PyMatTo(PyObject* pymat, T& mat)
00065 {
00066     bool noerror = true;
00067     mat.setIdentity();
00068 
00069 
00070 #ifdef USE_MATHUTILS
00071 
00072     if (MatrixObject_Check(pymat))
00073     {
00074         MatrixObject *pymatrix = (MatrixObject *)pymat;
00075 
00076         if (BaseMath_ReadCallback(pymatrix) == -1)
00077             return false;
00078 
00079         if (pymatrix->num_col != Size(mat) || pymatrix->num_row != Size(mat))
00080             return false;
00081 
00082         for (unsigned int row = 0; row < Size(mat); row++)
00083         {
00084             for (unsigned int col = 0; col < Size(mat); col++)
00085             {
00086                 mat[row][col] = *(pymatrix->matrix + col * pymatrix->num_row + row);
00087             }
00088         }
00089     }
00090     else
00091 
00092 #endif /* USE_MATHUTILS */
00093 
00094 
00095     if (PySequence_Check(pymat))
00096     {
00097         unsigned int rows = PySequence_Size(pymat);
00098         if (rows != Size(mat))
00099             return false;
00100             
00101         for (unsigned int row = 0; noerror && row < rows; row++)
00102         {
00103             PyObject *pyrow = PySequence_GetItem(pymat, row); /* new ref */
00104             if (!PyErr_Occurred() && PySequence_Check(pyrow))
00105             {
00106                 unsigned int cols = PySequence_Size(pyrow);
00107                 if (cols != Size(mat))
00108                     noerror = false;
00109                 else
00110                 {
00111                     for( unsigned int col = 0; col < cols; col++)
00112                     {
00113                         PyObject *item = PySequence_GetItem(pyrow, col); /* new ref */
00114                         mat[row][col] = PyFloat_AsDouble(item);
00115                         Py_DECREF(item);
00116                     }
00117                 }
00118             } else 
00119                 noerror = false;
00120             Py_DECREF(pyrow);
00121         }
00122     } else 
00123         noerror = false;
00124     
00125     if (noerror==false)
00126         PyErr_SetString(PyExc_TypeError, "could not be converted to a matrix (sequence of sequences)");
00127     
00128     return noerror;
00129 }
00130 
00134 template<class T>
00135 bool PyVecTo(PyObject* pyval, T& vec)
00136 {
00137 #ifdef USE_MATHUTILS
00138     /* no need for BaseMath_ReadCallback() here, reading the sequences will do this */
00139     
00140     if(VectorObject_Check(pyval)) {
00141         VectorObject *pyvec= (VectorObject *)pyval;
00142         if(BaseMath_ReadCallback(pyvec) == -1) {
00143             return false; /* exception raised */
00144         }
00145         if (pyvec->size != Size(vec)) {
00146             PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", pyvec->size, Size(vec));
00147             return false;
00148         }
00149         vec.setValue((float *) pyvec->vec);
00150         return true;
00151     }
00152     else if(QuaternionObject_Check(pyval)) {
00153         QuaternionObject *pyquat= (QuaternionObject *)pyval;
00154         if(BaseMath_ReadCallback(pyquat) == -1) {
00155             return false; /* exception raised */
00156         }
00157         if (4 != Size(vec)) {
00158             PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", 4, Size(vec));
00159             return false;
00160         }
00161         /* xyzw -> wxyz reordering is done by PyQuatTo */
00162         vec.setValue((float *) pyquat->quat);
00163         return true;
00164     }
00165     else if(EulerObject_Check(pyval)) {
00166         EulerObject *pyeul= (EulerObject *)pyval;
00167         if(BaseMath_ReadCallback(pyeul) == -1) {
00168             return false; /* exception raised */
00169         }
00170         if (3 != Size(vec)) {
00171             PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", 3, Size(vec));
00172             return false;
00173         }
00174         vec.setValue((float *) pyeul->eul);
00175         return true;
00176     } else
00177 #endif
00178     if(PyTuple_Check(pyval))
00179     {
00180         unsigned int numitems = PyTuple_GET_SIZE(pyval);
00181         if (numitems != Size(vec)) {
00182             PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", numitems, Size(vec));
00183             return false;
00184         }
00185         
00186         for (unsigned int x = 0; x < numitems; x++)
00187             vec[x] = PyFloat_AsDouble(PyTuple_GET_ITEM(pyval, x)); /* borrow ref */
00188         
00189         if (PyErr_Occurred()) {
00190             PyErr_SetString(PyExc_AttributeError, "one or more of the items in the sequence was not a float");
00191             return false;
00192         }
00193         
00194         return true;
00195     }
00196     else if (PyObject_TypeCheck(pyval, (PyTypeObject *)&PyObjectPlus::Type))
00197     {   /* note, include this check because PySequence_Check does too much introspection
00198          * on the PyObject (like getting its __class__, on a BGE type this means searching up
00199          * the parent list each time only to discover its not a sequence.
00200          * GameObjects are often used as an alternative to vectors so this is a common case
00201          * better to do a quick check for it, likely the error below will be ignored.
00202          * 
00203          * This is not 'correct' since we have proxy type CListValues's which could
00204          * contain floats/ints but there no cases of CValueLists being this way
00205          */
00206         PyErr_Format(PyExc_AttributeError, "expected a sequence type");
00207         return false;
00208     }
00209     else if (PySequence_Check(pyval))
00210     {
00211         unsigned int numitems = PySequence_Size(pyval);
00212         if (numitems != Size(vec)) {
00213             PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", numitems, Size(vec));
00214             return false;
00215         }
00216         
00217         for (unsigned int x = 0; x < numitems; x++)
00218         {
00219             PyObject *item = PySequence_GetItem(pyval, x); /* new ref */
00220             vec[x] = PyFloat_AsDouble(item);
00221             Py_DECREF(item);
00222         }
00223         
00224         if (PyErr_Occurred()) {
00225             PyErr_SetString(PyExc_AttributeError, "one or more of the items in the sequence was not a float");
00226             return false;
00227         }
00228         
00229         return true;
00230     } else
00231     {
00232         PyErr_Format(PyExc_AttributeError, "not a sequence type, expected a sequence of numbers size %d", Size(vec));
00233     }
00234     
00235     return false;
00236 }
00237 
00238 
00239 bool PyQuatTo(PyObject* pyval, MT_Quaternion &qrot);
00240 
00241 bool PyOrientationTo(PyObject* pyval, MT_Matrix3x3 &mat, const char *error_prefix);
00242 
00246 PyObject* PyObjectFrom(const MT_Matrix4x4 &mat);
00247 
00251 PyObject* PyObjectFrom(const MT_Matrix3x3 &mat);
00252 
00256 PyObject* PyObjectFrom(const MT_Tuple2 &vec);
00257 
00261 PyObject* PyObjectFrom(const MT_Tuple3 &vec);
00262 
00263 #ifdef USE_MATHUTILS
00264 
00267 PyObject* PyObjectFrom(const MT_Quaternion &qrot);
00268 #endif
00269 
00273 PyObject* PyObjectFrom(const MT_Tuple4 &pos);
00274 
00275 #endif
00276 
00277 #endif // WITH_PYTHON