|
Blender
V2.59
|
00001 /* 00002 * $Id: mathutils_Quaternion.c 38674 2011-07-25 01:44:19Z 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 * 00024 * Contributor(s): Joseph Gilbert 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 #include <Python.h> 00035 00036 #include "mathutils.h" 00037 00038 #include "BLI_math.h" 00039 #include "BLI_utildefines.h" 00040 00041 #define QUAT_SIZE 4 00042 00043 static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self); 00044 static PyObject *Quaternion_copy(QuaternionObject *self); 00045 00046 //-----------------------------METHODS------------------------------ 00047 00048 /* note: BaseMath_ReadCallback must be called beforehand */ 00049 static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits) 00050 { 00051 PyObject *ret; 00052 int i; 00053 00054 ret= PyTuple_New(QUAT_SIZE); 00055 00056 if(ndigits >= 0) { 00057 for(i= 0; i < QUAT_SIZE; i++) { 00058 PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->quat[i], ndigits))); 00059 } 00060 } 00061 else { 00062 for(i= 0; i < QUAT_SIZE; i++) { 00063 PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->quat[i])); 00064 } 00065 } 00066 00067 return ret; 00068 } 00069 00070 PyDoc_STRVAR(Quaternion_to_euler_doc, 00071 ".. method:: to_euler(order, euler_compat)\n" 00072 "\n" 00073 " Return Euler representation of the quaternion.\n" 00074 "\n" 00075 " :arg order: Optional rotation order argument in\n" 00076 " ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n" 00077 " :type order: string\n" 00078 " :arg euler_compat: Optional euler argument the new euler will be made\n" 00079 " compatible with (no axis flipping between them).\n" 00080 " Useful for converting a series of matrices to animation curves.\n" 00081 " :type euler_compat: :class:`Euler`\n" 00082 " :return: Euler representation of the quaternion.\n" 00083 " :rtype: :class:`Euler`\n" 00084 ); 00085 static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args) 00086 { 00087 float tquat[4]; 00088 float eul[3]; 00089 const char *order_str= NULL; 00090 short order= EULER_ORDER_XYZ; 00091 EulerObject *eul_compat = NULL; 00092 00093 if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat)) 00094 return NULL; 00095 00096 if(BaseMath_ReadCallback(self) == -1) 00097 return NULL; 00098 00099 if(order_str) { 00100 order= euler_order_from_string(order_str, "Matrix.to_euler()"); 00101 00102 if(order == -1) 00103 return NULL; 00104 } 00105 00106 normalize_qt_qt(tquat, self->quat); 00107 00108 if(eul_compat) { 00109 float mat[3][3]; 00110 00111 if(BaseMath_ReadCallback(eul_compat) == -1) 00112 return NULL; 00113 00114 quat_to_mat3(mat, tquat); 00115 00116 if(order == EULER_ORDER_XYZ) mat3_to_compatible_eul(eul, eul_compat->eul, mat); 00117 else mat3_to_compatible_eulO(eul, eul_compat->eul, order, mat); 00118 } 00119 else { 00120 if(order == EULER_ORDER_XYZ) quat_to_eul(eul, tquat); 00121 else quat_to_eulO(eul, order, tquat); 00122 } 00123 00124 return newEulerObject(eul, order, Py_NEW, NULL); 00125 } 00126 //----------------------------Quaternion.toMatrix()------------------ 00127 PyDoc_STRVAR(Quaternion_to_matrix_doc, 00128 ".. method:: to_matrix()\n" 00129 "\n" 00130 " Return a matrix representation of the quaternion.\n" 00131 "\n" 00132 " :return: A 3x3 rotation matrix representation of the quaternion.\n" 00133 " :rtype: :class:`Matrix`\n" 00134 ); 00135 static PyObject *Quaternion_to_matrix(QuaternionObject *self) 00136 { 00137 float mat[9]; /* all values are set */ 00138 00139 if(BaseMath_ReadCallback(self) == -1) 00140 return NULL; 00141 00142 quat_to_mat3((float (*)[3])mat, self->quat); 00143 return newMatrixObject(mat, 3, 3, Py_NEW, NULL); 00144 } 00145 00146 //----------------------------Quaternion.cross(other)------------------ 00147 PyDoc_STRVAR(Quaternion_cross_doc, 00148 ".. method:: cross(other)\n" 00149 "\n" 00150 " Return the cross product of this quaternion and another.\n" 00151 "\n" 00152 " :arg other: The other quaternion to perform the cross product with.\n" 00153 " :type other: :class:`Quaternion`\n" 00154 " :return: The cross product.\n" 00155 " :rtype: :class:`Quaternion`\n" 00156 ); 00157 static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value) 00158 { 00159 float quat[QUAT_SIZE], tquat[QUAT_SIZE]; 00160 00161 if(BaseMath_ReadCallback(self) == -1) 00162 return NULL; 00163 00164 if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.cross(other), invalid 'other' arg") == -1) 00165 return NULL; 00166 00167 mul_qt_qtqt(quat, self->quat, tquat); 00168 return newQuaternionObject(quat, Py_NEW, Py_TYPE(self)); 00169 } 00170 00171 //----------------------------Quaternion.dot(other)------------------ 00172 PyDoc_STRVAR(Quaternion_dot_doc, 00173 ".. method:: dot(other)\n" 00174 "\n" 00175 " Return the dot product of this quaternion and another.\n" 00176 "\n" 00177 " :arg other: The other quaternion to perform the dot product with.\n" 00178 " :type other: :class:`Quaternion`\n" 00179 " :return: The dot product.\n" 00180 " :rtype: :class:`Quaternion`\n" 00181 ); 00182 static PyObject *Quaternion_dot(QuaternionObject *self, PyObject *value) 00183 { 00184 float tquat[QUAT_SIZE]; 00185 00186 if(BaseMath_ReadCallback(self) == -1) 00187 return NULL; 00188 00189 if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.dot(other), invalid 'other' arg") == -1) 00190 return NULL; 00191 00192 return PyFloat_FromDouble(dot_qtqt(self->quat, tquat)); 00193 } 00194 00195 PyDoc_STRVAR(Quaternion_rotation_difference_doc, 00196 ".. function:: difference(other)\n" 00197 "\n" 00198 " Returns a quaternion representing the rotational difference.\n" 00199 "\n" 00200 " :arg other: second quaternion.\n" 00201 " :type other: :class:`Quaternion`\n" 00202 " :return: the rotational difference between the two quat rotations.\n" 00203 " :rtype: :class:`Quaternion`\n" 00204 ); 00205 static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject *value) 00206 { 00207 float tquat[QUAT_SIZE], quat[QUAT_SIZE]; 00208 00209 if(BaseMath_ReadCallback(self) == -1) 00210 return NULL; 00211 00212 if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.difference(other), invalid 'other' arg") == -1) 00213 return NULL; 00214 00215 rotation_between_quats_to_quat(quat, self->quat, tquat); 00216 00217 return newQuaternionObject(quat, Py_NEW, Py_TYPE(self)); 00218 } 00219 00220 PyDoc_STRVAR(Quaternion_slerp_doc, 00221 ".. function:: slerp(other, factor)\n" 00222 "\n" 00223 " Returns the interpolation of two quaternions.\n" 00224 "\n" 00225 " :arg other: value to interpolate with.\n" 00226 " :type other: :class:`Quaternion`\n" 00227 " :arg factor: The interpolation value in [0.0, 1.0].\n" 00228 " :type factor: float\n" 00229 " :return: The interpolated rotation.\n" 00230 " :rtype: :class:`Quaternion`\n" 00231 ); 00232 static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args) 00233 { 00234 PyObject *value; 00235 float tquat[QUAT_SIZE], quat[QUAT_SIZE], fac; 00236 00237 if(!PyArg_ParseTuple(args, "Of:slerp", &value, &fac)) { 00238 PyErr_SetString(PyExc_TypeError, 00239 "quat.slerp(): " 00240 "expected Quaternion types and float"); 00241 return NULL; 00242 } 00243 00244 if(BaseMath_ReadCallback(self) == -1) 00245 return NULL; 00246 00247 if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.slerp(other), invalid 'other' arg") == -1) 00248 return NULL; 00249 00250 if(fac > 1.0f || fac < 0.0f) { 00251 PyErr_SetString(PyExc_ValueError, 00252 "quat.slerp(): " 00253 "interpolation factor must be between 0.0 and 1.0"); 00254 return NULL; 00255 } 00256 00257 interp_qt_qtqt(quat, self->quat, tquat, fac); 00258 00259 return newQuaternionObject(quat, Py_NEW, Py_TYPE(self)); 00260 } 00261 00262 PyDoc_STRVAR(Quaternion_rotate_doc, 00263 ".. method:: rotate(other)\n" 00264 "\n" 00265 " Rotates the quaternion a by another mathutils value.\n" 00266 "\n" 00267 " :arg other: rotation component of mathutils value\n" 00268 " :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n" 00269 ); 00270 static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value) 00271 { 00272 float self_rmat[3][3], other_rmat[3][3], rmat[3][3]; 00273 float tquat[4], length; 00274 00275 if(BaseMath_ReadCallback(self) == -1) 00276 return NULL; 00277 00278 if(mathutils_any_to_rotmat(other_rmat, value, "quaternion.rotate(value)") == -1) 00279 return NULL; 00280 00281 length= normalize_qt_qt(tquat, self->quat); 00282 quat_to_mat3(self_rmat, tquat); 00283 mul_m3_m3m3(rmat, self_rmat, other_rmat); 00284 00285 mat3_to_quat(self->quat, rmat); 00286 mul_qt_fl(self->quat, length); /* maintain length after rotating */ 00287 00288 (void)BaseMath_WriteCallback(self); 00289 Py_RETURN_NONE; 00290 } 00291 00292 //----------------------------Quaternion.normalize()---------------- 00293 //normalize the axis of rotation of [theta, vector] 00294 PyDoc_STRVAR(Quaternion_normalize_doc, 00295 ".. function:: normalize()\n" 00296 "\n" 00297 " Normalize the quaternion.\n" 00298 ); 00299 static PyObject *Quaternion_normalize(QuaternionObject *self) 00300 { 00301 if(BaseMath_ReadCallback(self) == -1) 00302 return NULL; 00303 00304 normalize_qt(self->quat); 00305 00306 (void)BaseMath_WriteCallback(self); 00307 Py_RETURN_NONE; 00308 } 00309 PyDoc_STRVAR(Quaternion_normalized_doc, 00310 ".. function:: normalized()\n" 00311 "\n" 00312 " Return a new normalized quaternion.\n" 00313 "\n" 00314 " :return: a normalized copy.\n" 00315 " :rtype: :class:`Quaternion`\n" 00316 ); 00317 static PyObject *Quaternion_normalized(QuaternionObject *self) 00318 { 00319 return quat__apply_to_copy((PyNoArgsFunction)Quaternion_normalize, self); 00320 } 00321 00322 //----------------------------Quaternion.invert()------------------ 00323 PyDoc_STRVAR(Quaternion_invert_doc, 00324 ".. function:: invert()\n" 00325 "\n" 00326 " Set the quaternion to its inverse.\n" 00327 ); 00328 static PyObject *Quaternion_invert(QuaternionObject *self) 00329 { 00330 if(BaseMath_ReadCallback(self) == -1) 00331 return NULL; 00332 00333 invert_qt(self->quat); 00334 00335 (void)BaseMath_WriteCallback(self); 00336 Py_RETURN_NONE; 00337 } 00338 PyDoc_STRVAR(Quaternion_inverted_doc, 00339 ".. function:: inverted()\n" 00340 "\n" 00341 " Return a new, inverted quaternion.\n" 00342 "\n" 00343 " :return: the inverted value.\n" 00344 " :rtype: :class:`Quaternion`\n" 00345 ); 00346 static PyObject *Quaternion_inverted(QuaternionObject *self) 00347 { 00348 return quat__apply_to_copy((PyNoArgsFunction)Quaternion_invert, self); 00349 } 00350 00351 //----------------------------Quaternion.identity()----------------- 00352 PyDoc_STRVAR(Quaternion_identity_doc, 00353 ".. function:: identity()\n" 00354 "\n" 00355 " Set the quaternion to an identity quaternion.\n" 00356 "\n" 00357 " :return: an instance of itself.\n" 00358 " :rtype: :class:`Quaternion`\n" 00359 ); 00360 static PyObject *Quaternion_identity(QuaternionObject *self) 00361 { 00362 if(BaseMath_ReadCallback(self) == -1) 00363 return NULL; 00364 00365 unit_qt(self->quat); 00366 00367 (void)BaseMath_WriteCallback(self); 00368 Py_RETURN_NONE; 00369 } 00370 //----------------------------Quaternion.negate()------------------- 00371 PyDoc_STRVAR(Quaternion_negate_doc, 00372 ".. function:: negate()\n" 00373 "\n" 00374 " Set the quaternion to its negative.\n" 00375 "\n" 00376 " :return: an instance of itself.\n" 00377 " :rtype: :class:`Quaternion`\n" 00378 ); 00379 static PyObject *Quaternion_negate(QuaternionObject *self) 00380 { 00381 if(BaseMath_ReadCallback(self) == -1) 00382 return NULL; 00383 00384 mul_qt_fl(self->quat, -1.0f); 00385 00386 (void)BaseMath_WriteCallback(self); 00387 Py_RETURN_NONE; 00388 } 00389 //----------------------------Quaternion.conjugate()---------------- 00390 PyDoc_STRVAR(Quaternion_conjugate_doc, 00391 ".. function:: conjugate()\n" 00392 "\n" 00393 " Set the quaternion to its conjugate (negate x, y, z).\n" 00394 ); 00395 static PyObject *Quaternion_conjugate(QuaternionObject *self) 00396 { 00397 if(BaseMath_ReadCallback(self) == -1) 00398 return NULL; 00399 00400 conjugate_qt(self->quat); 00401 00402 (void)BaseMath_WriteCallback(self); 00403 Py_RETURN_NONE; 00404 } 00405 PyDoc_STRVAR(Quaternion_conjugated_doc, 00406 ".. function:: conjugated()\n" 00407 "\n" 00408 " Return a new conjugated quaternion.\n" 00409 "\n" 00410 " :return: a new quaternion.\n" 00411 " :rtype: :class:`Quaternion`\n" 00412 ); 00413 static PyObject *Quaternion_conjugated(QuaternionObject *self) 00414 { 00415 return quat__apply_to_copy((PyNoArgsFunction)Quaternion_conjugate, self); 00416 } 00417 00418 //----------------------------Quaternion.copy()---------------- 00419 PyDoc_STRVAR(Quaternion_copy_doc, 00420 ".. function:: copy()\n" 00421 "\n" 00422 " Returns a copy of this quaternion.\n" 00423 "\n" 00424 " :return: A copy of the quaternion.\n" 00425 " :rtype: :class:`Quaternion`\n" 00426 "\n" 00427 " .. note:: use this to get a copy of a wrapped quaternion with\n" 00428 " no reference to the original data.\n" 00429 ); 00430 static PyObject *Quaternion_copy(QuaternionObject *self) 00431 { 00432 if(BaseMath_ReadCallback(self) == -1) 00433 return NULL; 00434 00435 return newQuaternionObject(self->quat, Py_NEW, Py_TYPE(self)); 00436 } 00437 00438 //----------------------------print object (internal)-------------- 00439 //print the object to screen 00440 static PyObject *Quaternion_repr(QuaternionObject *self) 00441 { 00442 PyObject *ret, *tuple; 00443 00444 if(BaseMath_ReadCallback(self) == -1) 00445 return NULL; 00446 00447 tuple= Quaternion_to_tuple_ext(self, -1); 00448 00449 ret= PyUnicode_FromFormat("Quaternion(%R)", tuple); 00450 00451 Py_DECREF(tuple); 00452 return ret; 00453 } 00454 00455 static PyObject* Quaternion_richcmpr(PyObject *a, PyObject *b, int op) 00456 { 00457 PyObject *res; 00458 int ok= -1; /* zero is true */ 00459 00460 if (QuaternionObject_Check(a) && QuaternionObject_Check(b)) { 00461 QuaternionObject *quatA= (QuaternionObject *)a; 00462 QuaternionObject *quatB= (QuaternionObject *)b; 00463 00464 if(BaseMath_ReadCallback(quatA) == -1 || BaseMath_ReadCallback(quatB) == -1) 00465 return NULL; 00466 00467 ok= (EXPP_VectorsAreEqual(quatA->quat, quatB->quat, QUAT_SIZE, 1)) ? 0 : -1; 00468 } 00469 00470 switch (op) { 00471 case Py_NE: 00472 ok = !ok; /* pass through */ 00473 case Py_EQ: 00474 res = ok ? Py_False : Py_True; 00475 break; 00476 00477 case Py_LT: 00478 case Py_LE: 00479 case Py_GT: 00480 case Py_GE: 00481 res = Py_NotImplemented; 00482 break; 00483 default: 00484 PyErr_BadArgument(); 00485 return NULL; 00486 } 00487 00488 return Py_INCREF(res), res; 00489 } 00490 00491 //---------------------SEQUENCE PROTOCOLS------------------------ 00492 //----------------------------len(object)------------------------ 00493 //sequence length 00494 static int Quaternion_len(QuaternionObject *UNUSED(self)) 00495 { 00496 return QUAT_SIZE; 00497 } 00498 //----------------------------object[]--------------------------- 00499 //sequence accessor (get) 00500 static PyObject *Quaternion_item(QuaternionObject *self, int i) 00501 { 00502 if(i<0) i= QUAT_SIZE-i; 00503 00504 if(i < 0 || i >= QUAT_SIZE) { 00505 PyErr_SetString(PyExc_IndexError, 00506 "quaternion[attribute]: " 00507 "array index out of range"); 00508 return NULL; 00509 } 00510 00511 if(BaseMath_ReadIndexCallback(self, i) == -1) 00512 return NULL; 00513 00514 return PyFloat_FromDouble(self->quat[i]); 00515 00516 } 00517 //----------------------------object[]------------------------- 00518 //sequence accessor (set) 00519 static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob) 00520 { 00521 float scalar= (float)PyFloat_AsDouble(ob); 00522 if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ 00523 PyErr_SetString(PyExc_TypeError, 00524 "quaternion[index] = x: " 00525 "index argument not a number"); 00526 return -1; 00527 } 00528 00529 if(i<0) i= QUAT_SIZE-i; 00530 00531 if(i < 0 || i >= QUAT_SIZE){ 00532 PyErr_SetString(PyExc_IndexError, 00533 "quaternion[attribute] = x: " 00534 "array assignment index out of range"); 00535 return -1; 00536 } 00537 self->quat[i] = scalar; 00538 00539 if(BaseMath_WriteIndexCallback(self, i) == -1) 00540 return -1; 00541 00542 return 0; 00543 } 00544 //----------------------------object[z:y]------------------------ 00545 //sequence slice (get) 00546 static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end) 00547 { 00548 PyObject *tuple; 00549 int count; 00550 00551 if(BaseMath_ReadCallback(self) == -1) 00552 return NULL; 00553 00554 CLAMP(begin, 0, QUAT_SIZE); 00555 if (end<0) end= (QUAT_SIZE + 1) + end; 00556 CLAMP(end, 0, QUAT_SIZE); 00557 begin= MIN2(begin, end); 00558 00559 tuple= PyTuple_New(end - begin); 00560 for(count= begin; count < end; count++) { 00561 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->quat[count])); 00562 } 00563 00564 return tuple; 00565 } 00566 //----------------------------object[z:y]------------------------ 00567 //sequence slice (set) 00568 static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq) 00569 { 00570 int i, size; 00571 float quat[QUAT_SIZE]; 00572 00573 if(BaseMath_ReadCallback(self) == -1) 00574 return -1; 00575 00576 CLAMP(begin, 0, QUAT_SIZE); 00577 if (end<0) end= (QUAT_SIZE + 1) + end; 00578 CLAMP(end, 0, QUAT_SIZE); 00579 begin = MIN2(begin, end); 00580 00581 if((size=mathutils_array_parse(quat, 0, QUAT_SIZE, seq, "mathutils.Quaternion[begin:end] = []")) == -1) 00582 return -1; 00583 00584 if(size != (end - begin)){ 00585 PyErr_SetString(PyExc_ValueError, 00586 "quaternion[begin:end] = []: " 00587 "size mismatch in slice assignment"); 00588 return -1; 00589 } 00590 00591 /* parsed well - now set in vector */ 00592 for(i= 0; i < size; i++) 00593 self->quat[begin + i] = quat[i]; 00594 00595 (void)BaseMath_WriteCallback(self); 00596 return 0; 00597 } 00598 00599 00600 static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item) 00601 { 00602 if (PyIndex_Check(item)) { 00603 Py_ssize_t i; 00604 i = PyNumber_AsSsize_t(item, PyExc_IndexError); 00605 if (i == -1 && PyErr_Occurred()) 00606 return NULL; 00607 if (i < 0) 00608 i += QUAT_SIZE; 00609 return Quaternion_item(self, i); 00610 } else if (PySlice_Check(item)) { 00611 Py_ssize_t start, stop, step, slicelength; 00612 00613 if (PySlice_GetIndicesEx((void *)item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0) 00614 return NULL; 00615 00616 if (slicelength <= 0) { 00617 return PyTuple_New(0); 00618 } 00619 else if (step == 1) { 00620 return Quaternion_slice(self, start, stop); 00621 } 00622 else { 00623 PyErr_SetString(PyExc_IndexError, 00624 "slice steps not supported with quaternions"); 00625 return NULL; 00626 } 00627 } 00628 else { 00629 PyErr_Format(PyExc_TypeError, 00630 "quaternion indices must be integers, not %.200s", 00631 Py_TYPE(item)->tp_name); 00632 return NULL; 00633 } 00634 } 00635 00636 00637 static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyObject *value) 00638 { 00639 if (PyIndex_Check(item)) { 00640 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); 00641 if (i == -1 && PyErr_Occurred()) 00642 return -1; 00643 if (i < 0) 00644 i += QUAT_SIZE; 00645 return Quaternion_ass_item(self, i, value); 00646 } 00647 else if (PySlice_Check(item)) { 00648 Py_ssize_t start, stop, step, slicelength; 00649 00650 if (PySlice_GetIndicesEx((void *)item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0) 00651 return -1; 00652 00653 if (step == 1) 00654 return Quaternion_ass_slice(self, start, stop, value); 00655 else { 00656 PyErr_SetString(PyExc_IndexError, 00657 "slice steps not supported with quaternion"); 00658 return -1; 00659 } 00660 } 00661 else { 00662 PyErr_Format(PyExc_TypeError, 00663 "quaternion indices must be integers, not %.200s", 00664 Py_TYPE(item)->tp_name); 00665 return -1; 00666 } 00667 } 00668 00669 //------------------------NUMERIC PROTOCOLS---------------------- 00670 //------------------------obj + obj------------------------------ 00671 //addition 00672 static PyObject *Quaternion_add(PyObject *q1, PyObject *q2) 00673 { 00674 float quat[QUAT_SIZE]; 00675 QuaternionObject *quat1 = NULL, *quat2 = NULL; 00676 00677 if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { 00678 PyErr_SetString(PyExc_TypeError, 00679 "Quaternion addition: " 00680 "arguments not valid for this operation"); 00681 return NULL; 00682 } 00683 quat1 = (QuaternionObject*)q1; 00684 quat2 = (QuaternionObject*)q2; 00685 00686 if(BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1) 00687 return NULL; 00688 00689 add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f); 00690 return newQuaternionObject(quat, Py_NEW, Py_TYPE(q1)); 00691 } 00692 //------------------------obj - obj------------------------------ 00693 //subtraction 00694 static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2) 00695 { 00696 int x; 00697 float quat[QUAT_SIZE]; 00698 QuaternionObject *quat1 = NULL, *quat2 = NULL; 00699 00700 if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { 00701 PyErr_SetString(PyExc_TypeError, 00702 "Quaternion addition: " 00703 "arguments not valid for this operation"); 00704 return NULL; 00705 } 00706 00707 quat1 = (QuaternionObject*)q1; 00708 quat2 = (QuaternionObject*)q2; 00709 00710 if(BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1) 00711 return NULL; 00712 00713 for(x = 0; x < QUAT_SIZE; x++) { 00714 quat[x] = quat1->quat[x] - quat2->quat[x]; 00715 } 00716 00717 return newQuaternionObject(quat, Py_NEW, Py_TYPE(q1)); 00718 } 00719 00720 static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar) 00721 { 00722 float tquat[4]; 00723 copy_qt_qt(tquat, quat->quat); 00724 mul_qt_fl(tquat, scalar); 00725 return newQuaternionObject(tquat, Py_NEW, Py_TYPE(quat)); 00726 } 00727 00728 //------------------------obj * obj------------------------------ 00729 //mulplication 00730 static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2) 00731 { 00732 float quat[QUAT_SIZE], scalar; 00733 QuaternionObject *quat1 = NULL, *quat2 = NULL; 00734 00735 if(QuaternionObject_Check(q1)) { 00736 quat1 = (QuaternionObject*)q1; 00737 if(BaseMath_ReadCallback(quat1) == -1) 00738 return NULL; 00739 } 00740 if(QuaternionObject_Check(q2)) { 00741 quat2 = (QuaternionObject*)q2; 00742 if(BaseMath_ReadCallback(quat2) == -1) 00743 return NULL; 00744 } 00745 00746 if(quat1 && quat2) { /* QUAT*QUAT (cross product) */ 00747 mul_qt_qtqt(quat, quat1->quat, quat2->quat); 00748 return newQuaternionObject(quat, Py_NEW, Py_TYPE(q1)); 00749 } 00750 /* the only case this can happen (for a supported type is "FLOAT*QUAT") */ 00751 else if(quat2) { /* FLOAT*QUAT */ 00752 if(((scalar= PyFloat_AsDouble(q1)) == -1.0f && PyErr_Occurred())==0) { 00753 return quat_mul_float(quat2, scalar); 00754 } 00755 } 00756 else if (quat1) { 00757 /* QUAT * VEC */ 00758 if (VectorObject_Check(q2)) { 00759 VectorObject *vec2 = (VectorObject *)q2; 00760 float tvec[3]; 00761 00762 if(vec2->size != 3) { 00763 PyErr_SetString(PyExc_ValueError, 00764 "Vector multiplication: " 00765 "only 3D vector rotations (with quats) " 00766 "currently supported"); 00767 return NULL; 00768 } 00769 if(BaseMath_ReadCallback(vec2) == -1) { 00770 return NULL; 00771 } 00772 00773 copy_v3_v3(tvec, vec2->vec); 00774 mul_qt_v3(quat1->quat, tvec); 00775 00776 return newVectorObject(tvec, 3, Py_NEW, Py_TYPE(vec2)); 00777 } 00778 /* QUAT * FLOAT */ 00779 else if((((scalar= PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred())==0)) { 00780 return quat_mul_float(quat1, scalar); 00781 } 00782 } 00783 else { 00784 BLI_assert(!"internal error"); 00785 } 00786 00787 PyErr_Format(PyExc_TypeError, 00788 "Quaternion multiplication: " 00789 "not supported between '%.200s' and '%.200s' types", 00790 Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name); 00791 return NULL; 00792 } 00793 00794 /* -obj 00795 returns the negative of this object*/ 00796 static PyObject *Quaternion_neg(QuaternionObject *self) 00797 { 00798 float tquat[QUAT_SIZE]; 00799 00800 if(BaseMath_ReadCallback(self) == -1) 00801 return NULL; 00802 00803 negate_v4_v4(tquat, self->quat); 00804 return newQuaternionObject(tquat, Py_NEW, Py_TYPE(self)); 00805 } 00806 00807 00808 //-----------------PROTOCOL DECLARATIONS-------------------------- 00809 static PySequenceMethods Quaternion_SeqMethods = { 00810 (lenfunc) Quaternion_len, /* sq_length */ 00811 (binaryfunc) NULL, /* sq_concat */ 00812 (ssizeargfunc) NULL, /* sq_repeat */ 00813 (ssizeargfunc) Quaternion_item, /* sq_item */ 00814 (ssizessizeargfunc) NULL, /* sq_slice, deprecated */ 00815 (ssizeobjargproc) Quaternion_ass_item, /* sq_ass_item */ 00816 (ssizessizeobjargproc) NULL, /* sq_ass_slice, deprecated */ 00817 (objobjproc) NULL, /* sq_contains */ 00818 (binaryfunc) NULL, /* sq_inplace_concat */ 00819 (ssizeargfunc) NULL, /* sq_inplace_repeat */ 00820 }; 00821 00822 static PyMappingMethods Quaternion_AsMapping = { 00823 (lenfunc)Quaternion_len, 00824 (binaryfunc)Quaternion_subscript, 00825 (objobjargproc)Quaternion_ass_subscript 00826 }; 00827 00828 static PyNumberMethods Quaternion_NumMethods = { 00829 (binaryfunc) Quaternion_add, /*nb_add*/ 00830 (binaryfunc) Quaternion_sub, /*nb_subtract*/ 00831 (binaryfunc) Quaternion_mul, /*nb_multiply*/ 00832 NULL, /*nb_remainder*/ 00833 NULL, /*nb_divmod*/ 00834 NULL, /*nb_power*/ 00835 (unaryfunc) Quaternion_neg, /*nb_negative*/ 00836 (unaryfunc) 0, /*tp_positive*/ 00837 (unaryfunc) 0, /*tp_absolute*/ 00838 (inquiry) 0, /*tp_bool*/ 00839 (unaryfunc) 0, /*nb_invert*/ 00840 NULL, /*nb_lshift*/ 00841 (binaryfunc)0, /*nb_rshift*/ 00842 NULL, /*nb_and*/ 00843 NULL, /*nb_xor*/ 00844 NULL, /*nb_or*/ 00845 NULL, /*nb_int*/ 00846 NULL, /*nb_reserved*/ 00847 NULL, /*nb_float*/ 00848 NULL, /* nb_inplace_add */ 00849 NULL, /* nb_inplace_subtract */ 00850 NULL, /* nb_inplace_multiply */ 00851 NULL, /* nb_inplace_remainder */ 00852 NULL, /* nb_inplace_power */ 00853 NULL, /* nb_inplace_lshift */ 00854 NULL, /* nb_inplace_rshift */ 00855 NULL, /* nb_inplace_and */ 00856 NULL, /* nb_inplace_xor */ 00857 NULL, /* nb_inplace_or */ 00858 NULL, /* nb_floor_divide */ 00859 NULL, /* nb_true_divide */ 00860 NULL, /* nb_inplace_floor_divide */ 00861 NULL, /* nb_inplace_true_divide */ 00862 NULL, /* nb_index */ 00863 }; 00864 00865 static PyObject *Quaternion_getAxis(QuaternionObject *self, void *type) 00866 { 00867 return Quaternion_item(self, GET_INT_FROM_POINTER(type)); 00868 } 00869 00870 static int Quaternion_setAxis(QuaternionObject *self, PyObject *value, void *type) 00871 { 00872 return Quaternion_ass_item(self, GET_INT_FROM_POINTER(type), value); 00873 } 00874 00875 static PyObject *Quaternion_getMagnitude(QuaternionObject *self, void *UNUSED(closure)) 00876 { 00877 if(BaseMath_ReadCallback(self) == -1) 00878 return NULL; 00879 00880 return PyFloat_FromDouble(sqrt(dot_qtqt(self->quat, self->quat))); 00881 } 00882 00883 static PyObject *Quaternion_getAngle(QuaternionObject *self, void *UNUSED(closure)) 00884 { 00885 float tquat[4]; 00886 00887 if(BaseMath_ReadCallback(self) == -1) 00888 return NULL; 00889 00890 normalize_qt_qt(tquat, self->quat); 00891 return PyFloat_FromDouble(2.0f * (saacos(tquat[0]))); 00892 } 00893 00894 static int Quaternion_setAngle(QuaternionObject *self, PyObject *value, void *UNUSED(closure)) 00895 { 00896 float tquat[4]; 00897 float len; 00898 00899 float axis[3], angle_dummy; 00900 double angle; 00901 00902 if(BaseMath_ReadCallback(self) == -1) 00903 return -1; 00904 00905 len= normalize_qt_qt(tquat, self->quat); 00906 quat_to_axis_angle(axis, &angle_dummy, tquat); 00907 00908 angle= PyFloat_AsDouble(value); 00909 00910 if(angle==-1.0 && PyErr_Occurred()) { /* parsed item not a number */ 00911 PyErr_SetString(PyExc_TypeError, 00912 "quaternion.angle = value: float expected"); 00913 return -1; 00914 } 00915 00916 angle= angle_wrap_rad(angle); 00917 00918 /* If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations */ 00919 if( EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && 00920 EXPP_FloatsAreEqual(axis[1], 0.0f, 10) && 00921 EXPP_FloatsAreEqual(axis[2], 0.0f, 10) 00922 ) { 00923 axis[0] = 1.0f; 00924 } 00925 00926 axis_angle_to_quat(self->quat, axis, angle); 00927 mul_qt_fl(self->quat, len); 00928 00929 if(BaseMath_WriteCallback(self) == -1) 00930 return -1; 00931 00932 return 0; 00933 } 00934 00935 static PyObject *Quaternion_getAxisVec(QuaternionObject *self, void *UNUSED(closure)) 00936 { 00937 float tquat[4]; 00938 00939 float axis[3]; 00940 float angle; 00941 00942 if(BaseMath_ReadCallback(self) == -1) 00943 return NULL; 00944 00945 normalize_qt_qt(tquat, self->quat); 00946 quat_to_axis_angle(axis, &angle, tquat); 00947 00948 /* If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations */ 00949 if( EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && 00950 EXPP_FloatsAreEqual(axis[1], 0.0f, 10) && 00951 EXPP_FloatsAreEqual(axis[2], 0.0f, 10) 00952 ) { 00953 axis[0] = 1.0f; 00954 } 00955 00956 return (PyObject *) newVectorObject(axis, 3, Py_NEW, NULL); 00957 } 00958 00959 static int Quaternion_setAxisVec(QuaternionObject *self, PyObject *value, void *UNUSED(closure)) 00960 { 00961 float tquat[4]; 00962 float len; 00963 00964 float axis[3]; 00965 float angle; 00966 00967 if(BaseMath_ReadCallback(self) == -1) 00968 return -1; 00969 00970 len= normalize_qt_qt(tquat, self->quat); 00971 quat_to_axis_angle(axis, &angle, tquat); /* axis value is unused */ 00972 00973 if (mathutils_array_parse(axis, 3, 3, value, "quat.axis = other") == -1) 00974 return -1; 00975 00976 axis_angle_to_quat(self->quat, axis, angle); 00977 mul_qt_fl(self->quat, len); 00978 00979 if(BaseMath_WriteCallback(self) == -1) 00980 return -1; 00981 00982 return 0; 00983 } 00984 00985 //----------------------------------mathutils.Quaternion() -------------- 00986 static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 00987 { 00988 PyObject *seq= NULL; 00989 double angle = 0.0f; 00990 float quat[QUAT_SIZE]= {0.0f, 0.0f, 0.0f, 0.0f}; 00991 00992 if(kwds && PyDict_Size(kwds)) { 00993 PyErr_SetString(PyExc_TypeError, 00994 "mathutils.Quaternion(): " 00995 "takes no keyword args"); 00996 return NULL; 00997 } 00998 00999 if(!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle)) 01000 return NULL; 01001 01002 switch(PyTuple_GET_SIZE(args)) { 01003 case 0: 01004 break; 01005 case 1: 01006 if (mathutils_array_parse(quat, QUAT_SIZE, QUAT_SIZE, seq, "mathutils.Quaternion()") == -1) 01007 return NULL; 01008 break; 01009 case 2: 01010 if (mathutils_array_parse(quat, 3, 3, seq, "mathutils.Quaternion()") == -1) 01011 return NULL; 01012 angle= angle_wrap_rad(angle); /* clamp because of precision issues */ 01013 axis_angle_to_quat(quat, quat, angle); 01014 break; 01015 /* PyArg_ParseTuple assures no more then 2 */ 01016 } 01017 return newQuaternionObject(quat, Py_NEW, type); 01018 } 01019 01020 static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self) 01021 { 01022 PyObject *ret= Quaternion_copy(self); 01023 PyObject *ret_dummy= quat_func(ret); 01024 if(ret_dummy) { 01025 Py_DECREF(ret_dummy); 01026 return (PyObject *)ret; 01027 } 01028 else { /* error */ 01029 Py_DECREF(ret); 01030 return NULL; 01031 } 01032 } 01033 01034 //-----------------------METHOD DEFINITIONS ---------------------- 01035 static struct PyMethodDef Quaternion_methods[] = { 01036 /* in place only */ 01037 {"identity", (PyCFunction) Quaternion_identity, METH_NOARGS, Quaternion_identity_doc}, 01038 {"negate", (PyCFunction) Quaternion_negate, METH_NOARGS, Quaternion_negate_doc}, 01039 01040 /* operate on original or copy */ 01041 {"conjugate", (PyCFunction) Quaternion_conjugate, METH_NOARGS, Quaternion_conjugate_doc}, 01042 {"conjugated", (PyCFunction) Quaternion_conjugated, METH_NOARGS, Quaternion_conjugated_doc}, 01043 01044 {"invert", (PyCFunction) Quaternion_invert, METH_NOARGS, Quaternion_invert_doc}, 01045 {"inverted", (PyCFunction) Quaternion_inverted, METH_NOARGS, Quaternion_inverted_doc}, 01046 01047 {"normalize", (PyCFunction) Quaternion_normalize, METH_NOARGS, Quaternion_normalize_doc}, 01048 {"normalized", (PyCFunction) Quaternion_normalized, METH_NOARGS, Quaternion_normalized_doc}, 01049 01050 /* return converted representation */ 01051 {"to_euler", (PyCFunction) Quaternion_to_euler, METH_VARARGS, Quaternion_to_euler_doc}, 01052 {"to_matrix", (PyCFunction) Quaternion_to_matrix, METH_NOARGS, Quaternion_to_matrix_doc}, 01053 01054 /* operation between 2 or more types */ 01055 {"cross", (PyCFunction) Quaternion_cross, METH_O, Quaternion_cross_doc}, 01056 {"dot", (PyCFunction) Quaternion_dot, METH_O, Quaternion_dot_doc}, 01057 {"rotation_difference", (PyCFunction) Quaternion_rotation_difference, METH_O, Quaternion_rotation_difference_doc}, 01058 {"slerp", (PyCFunction) Quaternion_slerp, METH_VARARGS, Quaternion_slerp_doc}, 01059 {"rotate", (PyCFunction) Quaternion_rotate, METH_O, Quaternion_rotate_doc}, 01060 01061 {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc}, 01062 {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc}, 01063 {NULL, NULL, 0, NULL} 01064 }; 01065 01066 /*****************************************************************************/ 01067 /* Python attributes get/set structure: */ 01068 /*****************************************************************************/ 01069 static PyGetSetDef Quaternion_getseters[] = { 01070 {(char *)"w", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, (char *)"Quaternion W value.\n\n:type: float", (void *)0}, 01071 {(char *)"x", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, (char *)"Quaternion X axis.\n\n:type: float", (void *)1}, 01072 {(char *)"y", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, (char *)"Quaternion Y axis.\n\n:type: float", (void *)2}, 01073 {(char *)"z", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, (char *)"Quaternion Z axis.\n\n:type: float", (void *)3}, 01074 {(char *)"magnitude", (getter)Quaternion_getMagnitude, (setter)NULL, (char *)"Size of the quaternion (readonly).\n\n:type: float", NULL}, 01075 {(char *)"angle", (getter)Quaternion_getAngle, (setter)Quaternion_setAngle, (char *)"angle of the quaternion.\n\n:type: float", NULL}, 01076 {(char *)"axis",(getter)Quaternion_getAxisVec, (setter)Quaternion_setAxisVec, (char *)"quaternion axis as a vector.\n\n:type: :class:`Vector`", NULL}, 01077 {(char *)"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, (char *)BaseMathObject_Wrapped_doc, NULL}, 01078 {(char *)"owner", (getter)BaseMathObject_getOwner, (setter)NULL, (char *)BaseMathObject_Owner_doc, NULL}, 01079 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ 01080 }; 01081 01082 //------------------PY_OBECT DEFINITION-------------------------- 01083 PyDoc_STRVAR(quaternion_doc, 01084 "This object gives access to Quaternions in Blender." 01085 ); 01086 PyTypeObject quaternion_Type = { 01087 PyVarObject_HEAD_INIT(NULL, 0) 01088 "mathutils.Quaternion", //tp_name 01089 sizeof(QuaternionObject), //tp_basicsize 01090 0, //tp_itemsize 01091 (destructor)BaseMathObject_dealloc, //tp_dealloc 01092 NULL, //tp_print 01093 NULL, //tp_getattr 01094 NULL, //tp_setattr 01095 NULL, //tp_compare 01096 (reprfunc) Quaternion_repr, //tp_repr 01097 &Quaternion_NumMethods, //tp_as_number 01098 &Quaternion_SeqMethods, //tp_as_sequence 01099 &Quaternion_AsMapping, //tp_as_mapping 01100 NULL, //tp_hash 01101 NULL, //tp_call 01102 NULL, //tp_str 01103 NULL, //tp_getattro 01104 NULL, //tp_setattro 01105 NULL, //tp_as_buffer 01106 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, //tp_flags 01107 quaternion_doc, //tp_doc 01108 (traverseproc)BaseMathObject_traverse, //tp_traverse 01109 (inquiry)BaseMathObject_clear, //tp_clear 01110 (richcmpfunc)Quaternion_richcmpr, //tp_richcompare 01111 0, //tp_weaklistoffset 01112 NULL, //tp_iter 01113 NULL, //tp_iternext 01114 Quaternion_methods, //tp_methods 01115 NULL, //tp_members 01116 Quaternion_getseters, //tp_getset 01117 NULL, //tp_base 01118 NULL, //tp_dict 01119 NULL, //tp_descr_get 01120 NULL, //tp_descr_set 01121 0, //tp_dictoffset 01122 NULL, //tp_init 01123 NULL, //tp_alloc 01124 Quaternion_new, //tp_new 01125 NULL, //tp_free 01126 NULL, //tp_is_gc 01127 NULL, //tp_bases 01128 NULL, //tp_mro 01129 NULL, //tp_cache 01130 NULL, //tp_subclasses 01131 NULL, //tp_weaklist 01132 NULL, //tp_del 01133 }; 01134 //------------------------newQuaternionObject (internal)------------- 01135 //creates a new quaternion object 01136 /*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER 01137 (i.e. it was allocated elsewhere by MEM_mallocN()) 01138 pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON 01139 (i.e. it must be created here with PyMEM_malloc())*/ 01140 PyObject *newQuaternionObject(float *quat, int type, PyTypeObject *base_type) 01141 { 01142 QuaternionObject *self; 01143 01144 self= base_type ? (QuaternionObject *)base_type->tp_alloc(base_type, 0) : 01145 (QuaternionObject *)PyObject_GC_New(QuaternionObject, &quaternion_Type); 01146 01147 if(self) { 01148 /* init callbacks as NULL */ 01149 self->cb_user= NULL; 01150 self->cb_type= self->cb_subtype= 0; 01151 01152 if(type == Py_WRAP){ 01153 self->quat = quat; 01154 self->wrapped = Py_WRAP; 01155 } 01156 else if (type == Py_NEW){ 01157 self->quat = PyMem_Malloc(QUAT_SIZE * sizeof(float)); 01158 if(!quat) { //new empty 01159 unit_qt(self->quat); 01160 } 01161 else { 01162 QUATCOPY(self->quat, quat); 01163 } 01164 self->wrapped = Py_NEW; 01165 } 01166 else { 01167 Py_FatalError("Quaternion(): invalid type!"); 01168 } 01169 } 01170 return (PyObject *) self; 01171 } 01172 01173 PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype) 01174 { 01175 QuaternionObject *self= (QuaternionObject *)newQuaternionObject(NULL, Py_NEW, NULL); 01176 if(self) { 01177 Py_INCREF(cb_user); 01178 self->cb_user= cb_user; 01179 self->cb_type= (unsigned char)cb_type; 01180 self->cb_subtype= (unsigned char)cb_subtype; 01181 PyObject_GC_Track(self); 01182 } 01183 01184 return (PyObject *)self; 01185 } 01186