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