Blender  V2.59
KX_PyMath.h
Go to the documentation of this file.
00001 /*
00002  * $Id: KX_PyMath.h 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  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #ifndef __KX_PYMATH_H__
00036 #define __KX_PYMATH_H__
00037 
00038 #include "MT_Point2.h"
00039 #include "MT_Point3.h"
00040 #include "MT_Vector2.h"
00041 #include "MT_Vector3.h"
00042 #include "MT_Vector4.h"
00043 #include "MT_Matrix3x3.h"
00044 #include "MT_Matrix4x4.h"
00045 
00046 #include "KX_Python.h"
00047 #include "PyObjectPlus.h"
00048 
00049 #ifdef WITH_PYTHON
00050 #ifdef USE_MATHUTILS
00051 extern "C" {
00052 #include "../../blender/python/mathutils/mathutils.h" /* so we can have mathutils callbacks */
00053 }
00054 #endif
00055 
00056 inline unsigned int Size(const MT_Matrix4x4&)          { return 4; }
00057 inline unsigned int Size(const MT_Matrix3x3&)          { return 3; }
00058 inline unsigned int Size(const MT_Tuple2&)                { return 2; }
00059 inline unsigned int Size(const MT_Tuple3&)                { return 3; }
00060 inline unsigned int Size(const MT_Tuple4&)                { return 4; }
00061 
00065 template<class T>
00066 bool PyMatTo(PyObject* pymat, T& mat)
00067 {
00068         bool noerror = true;
00069         mat.setIdentity();
00070         if (PySequence_Check(pymat))
00071         {
00072                 unsigned int cols = PySequence_Size(pymat);
00073                 if (cols != Size(mat))
00074                         return false;
00075                         
00076                 for (unsigned int x = 0; noerror && x < cols; x++)
00077                 {
00078                         PyObject *pycol = PySequence_GetItem(pymat, x); /* new ref */
00079                         if (!PyErr_Occurred() && PySequence_Check(pycol))
00080                         {
00081                                 unsigned int rows = PySequence_Size(pycol);
00082                                 if (rows != Size(mat))
00083                                         noerror = false;
00084                                 else
00085                                 {
00086                                         for( unsigned int y = 0; y < rows; y++)
00087                                         {
00088                                                 PyObject *item = PySequence_GetItem(pycol, y); /* new ref */
00089                                                 mat[y][x] = PyFloat_AsDouble(item);
00090                                                 Py_DECREF(item);
00091                                         }
00092                                 }
00093                         } else 
00094                                 noerror = false;
00095                         Py_DECREF(pycol);
00096                 }
00097         } else 
00098                 noerror = false;
00099         
00100         if (noerror==false)
00101                 PyErr_SetString(PyExc_TypeError, "could not be converted to a matrix (sequence of sequences)");
00102         
00103         return noerror;
00104 }
00105 
00109 template<class T>
00110 bool PyVecTo(PyObject* pyval, T& vec)
00111 {
00112 #ifdef USE_MATHUTILS
00113         /* no need for BaseMath_ReadCallback() here, reading the sequences will do this */
00114         
00115         if(VectorObject_Check(pyval)) {
00116                 VectorObject *pyvec= (VectorObject *)pyval;
00117                 if(BaseMath_ReadCallback(pyvec) == -1) {
00118                         return false; /* exception raised */
00119                 }
00120                 if (pyvec->size != Size(vec)) {
00121                         PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", pyvec->size, Size(vec));
00122                         return false;
00123                 }
00124                 vec.setValue((float *) pyvec->vec);
00125                 return true;
00126         }
00127         else if(QuaternionObject_Check(pyval)) {
00128                 QuaternionObject *pyquat= (QuaternionObject *)pyval;
00129                 if(BaseMath_ReadCallback(pyquat) == -1) {
00130                         return false; /* exception raised */
00131                 }
00132                 if (4 != Size(vec)) {
00133                         PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", 4, Size(vec));
00134                         return false;
00135                 }
00136                 /* xyzw -> wxyz reordering is done by PyQuatTo */
00137                 vec.setValue((float *) pyquat->quat);
00138                 return true;
00139         }
00140         else if(EulerObject_Check(pyval)) {
00141                 EulerObject *pyeul= (EulerObject *)pyval;
00142                 if(BaseMath_ReadCallback(pyeul) == -1) {
00143                         return false; /* exception raised */
00144                 }
00145                 if (3 != Size(vec)) {
00146                         PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", 3, Size(vec));
00147                         return false;
00148                 }
00149                 vec.setValue((float *) pyeul->eul);
00150                 return true;
00151         } else
00152 #endif
00153         if(PyTuple_Check(pyval))
00154         {
00155                 unsigned int numitems = PyTuple_GET_SIZE(pyval);
00156                 if (numitems != Size(vec)) {
00157                         PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", numitems, Size(vec));
00158                         return false;
00159                 }
00160                 
00161                 for (unsigned int x = 0; x < numitems; x++)
00162                         vec[x] = PyFloat_AsDouble(PyTuple_GET_ITEM(pyval, x)); /* borrow ref */
00163                 
00164                 if (PyErr_Occurred()) {
00165                         PyErr_SetString(PyExc_AttributeError, "one or more of the items in the sequence was not a float");
00166                         return false;
00167                 }
00168                 
00169                 return true;
00170         }
00171         else if (PyObject_TypeCheck(pyval, (PyTypeObject *)&PyObjectPlus::Type))
00172         {       /* note, include this check because PySequence_Check does too much introspection
00173                  * on the PyObject (like getting its __class__, on a BGE type this means searching up
00174                  * the parent list each time only to discover its not a sequence.
00175                  * GameObjects are often used as an alternative to vectors so this is a common case
00176                  * better to do a quick check for it, likely the error below will be ignored.
00177                  * 
00178                  * This is not 'correct' since we have proxy type CListValues's which could
00179                  * contain floats/ints but there no cases of CValueLists being this way
00180                  */
00181                 PyErr_Format(PyExc_AttributeError, "expected a sequence type");
00182                 return false;
00183         }
00184         else if (PySequence_Check(pyval))
00185         {
00186                 unsigned int numitems = PySequence_Size(pyval);
00187                 if (numitems != Size(vec)) {
00188                         PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", numitems, Size(vec));
00189                         return false;
00190                 }
00191                 
00192                 for (unsigned int x = 0; x < numitems; x++)
00193                 {
00194                         PyObject *item = PySequence_GetItem(pyval, x); /* new ref */
00195                         vec[x] = PyFloat_AsDouble(item);
00196                         Py_DECREF(item);
00197                 }
00198                 
00199                 if (PyErr_Occurred()) {
00200                         PyErr_SetString(PyExc_AttributeError, "one or more of the items in the sequence was not a float");
00201                         return false;
00202                 }
00203                 
00204                 return true;
00205         } else
00206         {
00207                 PyErr_Format(PyExc_AttributeError, "not a sequence type, expected a sequence of numbers size %d", Size(vec));
00208         }
00209         
00210         return false;
00211 }
00212 
00213 
00214 bool PyQuatTo(PyObject* pyval, MT_Quaternion &qrot);
00215 
00216 bool PyOrientationTo(PyObject* pyval, MT_Matrix3x3 &mat, const char *error_prefix);
00217 
00221 PyObject* PyObjectFrom(const MT_Matrix4x4 &mat);
00222 
00226 PyObject* PyObjectFrom(const MT_Matrix3x3 &mat);
00227 
00231 PyObject* PyObjectFrom(const MT_Tuple2 &vec);
00232 
00236 PyObject* PyObjectFrom(const MT_Tuple3 &vec);
00237 
00238 #ifdef USE_MATHUTILS
00239 
00242 PyObject* PyObjectFrom(const MT_Quaternion &qrot);
00243 #endif
00244 
00248 PyObject* PyObjectFrom(const MT_Tuple4 &pos);
00249 
00250 #endif
00251 
00252 #endif // WITH_PYTHON