Blender V2.61 - r43446
|
00001 /* 00002 * 00003 * ***** BEGIN GPL LICENSE BLOCK ***** 00004 * 00005 * This program is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU General Public License 00007 * as published by the Free Software Foundation; either version 2 00008 * of the License, or (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software Foundation, 00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 * 00019 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00020 * All rights reserved. 00021 * 00022 * Contributor(s): Michel Selten & 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_string.h" 00039 #include "BLI_dynstr.h" 00040 00041 typedef enum eMatrixAccess_t { 00042 MAT_ACCESS_ROW, 00043 MAT_ACCESS_COL 00044 } eMatrixAccess_t; 00045 00046 static PyObject *Matrix_copy(MatrixObject *self); 00047 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value); 00048 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self); 00049 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type); 00050 00051 static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row) 00052 { 00053 if ((vec->size != mat->num_col) || (row >= mat->num_row)) { 00054 PyErr_SetString(PyExc_AttributeError, 00055 "Matrix(): " 00056 "owner matrix has been resized since this row vector was created"); 00057 return 0; 00058 } 00059 else { 00060 return 1; 00061 } 00062 } 00063 00064 static int matrix_col_vector_check(MatrixObject *mat, VectorObject *vec, int col) 00065 { 00066 if ((vec->size != mat->num_row) || (col >= mat->num_col)) { 00067 PyErr_SetString(PyExc_AttributeError, 00068 "Matrix(): " 00069 "owner matrix has been resized since this column vector was created"); 00070 return 0; 00071 } 00072 else { 00073 return 1; 00074 } 00075 } 00076 00077 /* ---------------------------------------------------------------------------- 00078 * matrix row callbacks 00079 * this is so you can do matrix[i][j] = val OR matrix.row[i][j] = val */ 00080 00081 int mathutils_matrix_row_cb_index = -1; 00082 00083 static int mathutils_matrix_row_check(BaseMathObject *bmo) 00084 { 00085 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00086 return BaseMath_ReadCallback(self); 00087 } 00088 00089 static int mathutils_matrix_row_get(BaseMathObject *bmo, int row) 00090 { 00091 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00092 int col; 00093 00094 if (BaseMath_ReadCallback(self) == -1) 00095 return -1; 00096 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row)) 00097 return -1; 00098 00099 for (col = 0; col < self->num_col; col++) { 00100 bmo->data[col] = MATRIX_ITEM(self, row, col); 00101 } 00102 00103 return 0; 00104 } 00105 00106 static int mathutils_matrix_row_set(BaseMathObject *bmo, int row) 00107 { 00108 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00109 int col; 00110 00111 if (BaseMath_ReadCallback(self) == -1) 00112 return -1; 00113 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row)) 00114 return -1; 00115 00116 for (col = 0; col < self->num_col; col++) { 00117 MATRIX_ITEM(self, row, col) = bmo->data[col]; 00118 } 00119 00120 (void)BaseMath_WriteCallback(self); 00121 return 0; 00122 } 00123 00124 static int mathutils_matrix_row_get_index(BaseMathObject *bmo, int row, int col) 00125 { 00126 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00127 00128 if (BaseMath_ReadCallback(self) == -1) 00129 return -1; 00130 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row)) 00131 return -1; 00132 00133 bmo->data[col] = MATRIX_ITEM(self, row, col); 00134 return 0; 00135 } 00136 00137 static int mathutils_matrix_row_set_index(BaseMathObject *bmo, int row, int col) 00138 { 00139 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00140 00141 if (BaseMath_ReadCallback(self) == -1) 00142 return -1; 00143 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row)) 00144 return -1; 00145 00146 MATRIX_ITEM(self, row, col) = bmo->data[col]; 00147 00148 (void)BaseMath_WriteCallback(self); 00149 return 0; 00150 } 00151 00152 Mathutils_Callback mathutils_matrix_row_cb = { 00153 mathutils_matrix_row_check, 00154 mathutils_matrix_row_get, 00155 mathutils_matrix_row_set, 00156 mathutils_matrix_row_get_index, 00157 mathutils_matrix_row_set_index 00158 }; 00159 00160 00161 /* ---------------------------------------------------------------------------- 00162 * matrix row callbacks 00163 * this is so you can do matrix.col[i][j] = val */ 00164 00165 int mathutils_matrix_col_cb_index = -1; 00166 00167 static int mathutils_matrix_col_check(BaseMathObject *bmo) 00168 { 00169 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00170 return BaseMath_ReadCallback(self); 00171 } 00172 00173 static int mathutils_matrix_col_get(BaseMathObject *bmo, int col) 00174 { 00175 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00176 int num_row; 00177 int row; 00178 00179 if (BaseMath_ReadCallback(self) == -1) 00180 return -1; 00181 if (!matrix_col_vector_check(self, (VectorObject *)bmo, col)) 00182 return -1; 00183 00184 /* for 'translation' size will always be '3' even on 4x4 vec */ 00185 num_row = MIN2(self->num_row, ((VectorObject *)bmo)->size); 00186 00187 for (row = 0; row < num_row; row++) { 00188 bmo->data[row] = MATRIX_ITEM(self, row, col); 00189 } 00190 00191 return 0; 00192 } 00193 00194 static int mathutils_matrix_col_set(BaseMathObject *bmo, int col) 00195 { 00196 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00197 int num_row; 00198 int row; 00199 00200 if (BaseMath_ReadCallback(self) == -1) 00201 return -1; 00202 if (!matrix_col_vector_check(self, (VectorObject *)bmo, col)) 00203 return -1; 00204 00205 /* for 'translation' size will always be '3' even on 4x4 vec */ 00206 num_row = MIN2(self->num_row, ((VectorObject *)bmo)->size); 00207 00208 for (row = 0; row < num_row; row++) { 00209 MATRIX_ITEM(self, row, col) = bmo->data[row]; 00210 } 00211 00212 (void)BaseMath_WriteCallback(self); 00213 return 0; 00214 } 00215 00216 static int mathutils_matrix_col_get_index(BaseMathObject *bmo, int col, int row) 00217 { 00218 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00219 00220 if (BaseMath_ReadCallback(self) == -1) 00221 return -1; 00222 if (!matrix_col_vector_check(self, (VectorObject *)bmo, col)) 00223 return -1; 00224 00225 bmo->data[row] = MATRIX_ITEM(self, row, col); 00226 return 0; 00227 } 00228 00229 static int mathutils_matrix_col_set_index(BaseMathObject *bmo, int col, int row) 00230 { 00231 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00232 00233 if (BaseMath_ReadCallback(self) == -1) 00234 return -1; 00235 if (!matrix_col_vector_check(self, (VectorObject *)bmo, col)) 00236 return -1; 00237 00238 MATRIX_ITEM(self, row, col) = bmo->data[row]; 00239 00240 (void)BaseMath_WriteCallback(self); 00241 return 0; 00242 } 00243 00244 Mathutils_Callback mathutils_matrix_col_cb = { 00245 mathutils_matrix_col_check, 00246 mathutils_matrix_col_get, 00247 mathutils_matrix_col_set, 00248 mathutils_matrix_col_get_index, 00249 mathutils_matrix_col_set_index 00250 }; 00251 00252 00253 /* ---------------------------------------------------------------------------- 00254 * matrix row callbacks 00255 * this is so you can do matrix.translation = val 00256 * note, this is _exactly like matrix.col except the 4th component is always omitted */ 00257 00258 int mathutils_matrix_translation_cb_index = -1; 00259 00260 static int mathutils_matrix_translation_check(BaseMathObject *bmo) 00261 { 00262 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00263 return BaseMath_ReadCallback(self); 00264 } 00265 00266 static int mathutils_matrix_translation_get(BaseMathObject *bmo, int col) 00267 { 00268 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00269 int row; 00270 00271 if (BaseMath_ReadCallback(self) == -1) 00272 return -1; 00273 00274 for (row = 0; row < 3; row++) { 00275 bmo->data[row] = MATRIX_ITEM(self, row, col); 00276 } 00277 00278 return 0; 00279 } 00280 00281 static int mathutils_matrix_translation_set(BaseMathObject *bmo, int col) 00282 { 00283 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00284 int row; 00285 00286 if (BaseMath_ReadCallback(self) == -1) 00287 return -1; 00288 00289 for (row = 0; row < 3; row++) { 00290 MATRIX_ITEM(self, row, col) = bmo->data[row]; 00291 } 00292 00293 (void)BaseMath_WriteCallback(self); 00294 return 0; 00295 } 00296 00297 static int mathutils_matrix_translation_get_index(BaseMathObject *bmo, int col, int row) 00298 { 00299 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00300 00301 if (BaseMath_ReadCallback(self) == -1) 00302 return -1; 00303 00304 bmo->data[row] = MATRIX_ITEM(self, row, col); 00305 return 0; 00306 } 00307 00308 static int mathutils_matrix_translation_set_index(BaseMathObject *bmo, int col, int row) 00309 { 00310 MatrixObject *self = (MatrixObject *)bmo->cb_user; 00311 00312 if (BaseMath_ReadCallback(self) == -1) 00313 return -1; 00314 00315 MATRIX_ITEM(self, row, col) = bmo->data[row]; 00316 00317 (void)BaseMath_WriteCallback(self); 00318 return 0; 00319 } 00320 00321 Mathutils_Callback mathutils_matrix_translation_cb = { 00322 mathutils_matrix_translation_check, 00323 mathutils_matrix_translation_get, 00324 mathutils_matrix_translation_set, 00325 mathutils_matrix_translation_get_index, 00326 mathutils_matrix_translation_set_index 00327 }; 00328 00329 00330 /* matrix column callbacks, this is so you can do matrix.translation = Vector() */ 00331 00332 //----------------------------------mathutils.Matrix() ----------------- 00333 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. 00334 //create a new matrix type 00335 static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 00336 { 00337 if (kwds && PyDict_Size(kwds)) { 00338 PyErr_SetString(PyExc_TypeError, 00339 "Matrix(): " 00340 "takes no keyword args"); 00341 return NULL; 00342 } 00343 00344 switch (PyTuple_GET_SIZE(args)) { 00345 case 0: 00346 return Matrix_CreatePyObject(NULL, 4, 4, Py_NEW, type); 00347 case 1: 00348 { 00349 PyObject *arg = PyTuple_GET_ITEM(args, 0); 00350 00351 /* Input is now as a sequence of rows so length of sequence 00352 * is the number of rows */ 00353 /* -1 is an error, size checks will accunt for this */ 00354 const unsigned short num_row = PySequence_Size(arg); 00355 00356 if (num_row >= 2 && num_row <= 4) { 00357 PyObject *item = PySequence_GetItem(arg, 0); 00358 /* Since each item is a row, number of items is the 00359 * same as the number of columns */ 00360 const unsigned short num_col = PySequence_Size(item); 00361 Py_XDECREF(item); 00362 00363 if (num_col >= 2 && num_col <= 4) { 00364 /* sane row & col size, new matrix and assign as slice */ 00365 PyObject *matrix = Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, type); 00366 if (Matrix_ass_slice((MatrixObject *)matrix, 0, INT_MAX, arg) == 0) { 00367 return matrix; 00368 } 00369 else { /* matrix ok, slice assignment not */ 00370 Py_DECREF(matrix); 00371 } 00372 } 00373 } 00374 } 00375 } 00376 00377 /* will overwrite error */ 00378 PyErr_SetString(PyExc_TypeError, 00379 "Matrix(): " 00380 "expects no args or 2-4 numeric sequences"); 00381 return NULL; 00382 } 00383 00384 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self) 00385 { 00386 PyObject *ret = Matrix_copy(self); 00387 PyObject *ret_dummy = matrix_func(ret); 00388 if (ret_dummy) { 00389 Py_DECREF(ret_dummy); 00390 return (PyObject *)ret; 00391 } 00392 else { /* error */ 00393 Py_DECREF(ret); 00394 return NULL; 00395 } 00396 } 00397 00398 /* when a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4 */ 00399 static void matrix_3x3_as_4x4(float mat[16]) 00400 { 00401 mat[10] = mat[8]; 00402 mat[9] = mat[7]; 00403 mat[8] = mat[6]; 00404 mat[7] = 0.0f; 00405 mat[6] = mat[5]; 00406 mat[5] = mat[4]; 00407 mat[4] = mat[3]; 00408 mat[3] = 0.0f; 00409 } 00410 00411 /*-----------------------CLASS-METHODS----------------------------*/ 00412 00413 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. 00414 PyDoc_STRVAR(C_Matrix_Rotation_doc, 00415 ".. classmethod:: Rotation(angle, size, axis)\n" 00416 "\n" 00417 " Create a matrix representing a rotation.\n" 00418 "\n" 00419 " :arg angle: The angle of rotation desired, in radians.\n" 00420 " :type angle: float\n" 00421 " :arg size: The size of the rotation matrix to construct [2, 4].\n" 00422 " :type size: int\n" 00423 " :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object\n" 00424 " (optional when size is 2).\n" 00425 " :type axis: string or :class:`Vector`\n" 00426 " :return: A new rotation matrix.\n" 00427 " :rtype: :class:`Matrix`\n" 00428 ); 00429 static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args) 00430 { 00431 PyObject *vec = NULL; 00432 const char *axis = NULL; 00433 int matSize; 00434 double angle; /* use double because of precision problems at high values */ 00435 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 00436 0.0f, 0.0f, 0.0f, 0.0f, 00437 0.0f, 0.0f, 0.0f, 0.0f, 00438 0.0f, 0.0f, 0.0f, 1.0f}; 00439 00440 if (!PyArg_ParseTuple(args, "di|O:Matrix.Rotation", &angle, &matSize, &vec)) { 00441 return NULL; 00442 } 00443 00444 if (vec && PyUnicode_Check(vec)) { 00445 axis = _PyUnicode_AsString((PyObject *)vec); 00446 if (axis == NULL || axis[0] == '\0' || axis[1] != '\0' || axis[0] < 'X' || axis[0] > 'Z') { 00447 PyErr_SetString(PyExc_ValueError, 00448 "Matrix.Rotation(): " 00449 "3rd argument axis value must be a 3D vector " 00450 "or a string in 'X', 'Y', 'Z'"); 00451 return NULL; 00452 } 00453 else { 00454 /* use the string */ 00455 vec = NULL; 00456 } 00457 } 00458 00459 angle = angle_wrap_rad(angle); 00460 00461 if (matSize != 2 && matSize != 3 && matSize != 4) { 00462 PyErr_SetString(PyExc_ValueError, 00463 "Matrix.Rotation(): " 00464 "can only return a 2x2 3x3 or 4x4 matrix"); 00465 return NULL; 00466 } 00467 if (matSize == 2 && (vec != NULL)) { 00468 PyErr_SetString(PyExc_ValueError, 00469 "Matrix.Rotation(): " 00470 "cannot create a 2x2 rotation matrix around arbitrary axis"); 00471 return NULL; 00472 } 00473 if ((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) { 00474 PyErr_SetString(PyExc_ValueError, 00475 "Matrix.Rotation(): " 00476 "axis of rotation for 3d and 4d matrices is required"); 00477 return NULL; 00478 } 00479 00480 /* check for valid vector/axis above */ 00481 if (vec) { 00482 float tvec[3]; 00483 00484 if (mathutils_array_parse(tvec, 3, 3, vec, "Matrix.Rotation(angle, size, axis), invalid 'axis' arg") == -1) 00485 return NULL; 00486 00487 axis_angle_to_mat3((float (*)[3])mat, tvec, angle); 00488 } 00489 else if (matSize == 2) { 00490 const float angle_cos = cosf(angle); 00491 const float angle_sin = sinf(angle); 00492 00493 //2D rotation matrix 00494 mat[0] = angle_cos; 00495 mat[1] = angle_sin; 00496 mat[2] = -angle_sin; 00497 mat[3] = angle_cos; 00498 } 00499 else { 00500 /* valid axis checked above */ 00501 single_axis_angle_to_mat3((float (*)[3])mat, axis[0], angle); 00502 } 00503 00504 if (matSize == 4) { 00505 matrix_3x3_as_4x4(mat); 00506 } 00507 //pass to matrix creation 00508 return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); 00509 } 00510 00511 00512 PyDoc_STRVAR(C_Matrix_Translation_doc, 00513 ".. classmethod:: Translation(vector)\n" 00514 "\n" 00515 " Create a matrix representing a translation.\n" 00516 "\n" 00517 " :arg vector: The translation vector.\n" 00518 " :type vector: :class:`Vector`\n" 00519 " :return: An identity matrix with a translation.\n" 00520 " :rtype: :class:`Matrix`\n" 00521 ); 00522 static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value) 00523 { 00524 float mat[4][4]= MAT4_UNITY; 00525 00526 if (mathutils_array_parse(mat[3], 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1) 00527 return NULL; 00528 00529 return Matrix_CreatePyObject(&mat[0][0], 4, 4, Py_NEW, (PyTypeObject *)cls); 00530 } 00531 //----------------------------------mathutils.Matrix.Scale() ------------- 00532 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. 00533 PyDoc_STRVAR(C_Matrix_Scale_doc, 00534 ".. classmethod:: Scale(factor, size, axis)\n" 00535 "\n" 00536 " Create a matrix representing a scaling.\n" 00537 "\n" 00538 " :arg factor: The factor of scaling to apply.\n" 00539 " :type factor: float\n" 00540 " :arg size: The size of the scale matrix to construct [2, 4].\n" 00541 " :type size: int\n" 00542 " :arg axis: Direction to influence scale. (optional).\n" 00543 " :type axis: :class:`Vector`\n" 00544 " :return: A new scale matrix.\n" 00545 " :rtype: :class:`Matrix`\n" 00546 ); 00547 static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args) 00548 { 00549 PyObject *vec = NULL; 00550 int vec_size; 00551 float tvec[3]; 00552 float factor; 00553 int matSize; 00554 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 00555 0.0f, 0.0f, 0.0f, 0.0f, 00556 0.0f, 0.0f, 0.0f, 0.0f, 00557 0.0f, 0.0f, 0.0f, 1.0f}; 00558 00559 if (!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) { 00560 return NULL; 00561 } 00562 if (matSize != 2 && matSize != 3 && matSize != 4) { 00563 PyErr_SetString(PyExc_ValueError, 00564 "Matrix.Scale(): " 00565 "can only return a 2x2 3x3 or 4x4 matrix"); 00566 return NULL; 00567 } 00568 if (vec) { 00569 vec_size = (matSize == 2 ? 2 : 3); 00570 if (mathutils_array_parse(tvec, vec_size, vec_size, vec, 00571 "Matrix.Scale(factor, size, axis), invalid 'axis' arg") == -1) 00572 { 00573 return NULL; 00574 } 00575 } 00576 if (vec == NULL) { //scaling along axis 00577 if (matSize == 2) { 00578 mat[0] = factor; 00579 mat[3] = factor; 00580 } 00581 else { 00582 mat[0] = factor; 00583 mat[4] = factor; 00584 mat[8] = factor; 00585 } 00586 } 00587 else { //scaling in arbitrary direction 00588 //normalize arbitrary axis 00589 float norm = 0.0f; 00590 int x; 00591 for (x = 0; x < vec_size; x++) { 00592 norm += tvec[x] * tvec[x]; 00593 } 00594 norm = (float) sqrt(norm); 00595 for (x = 0; x < vec_size; x++) { 00596 tvec[x] /= norm; 00597 } 00598 if (matSize == 2) { 00599 mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0])); 00600 mat[1] = ((factor - 1) *(tvec[0] * tvec[1])); 00601 mat[2] = ((factor - 1) *(tvec[0] * tvec[1])); 00602 mat[3] = 1 + ((factor - 1) *(tvec[1] * tvec[1])); 00603 } 00604 else { 00605 mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0])); 00606 mat[1] = ((factor - 1) *(tvec[0] * tvec[1])); 00607 mat[2] = ((factor - 1) *(tvec[0] * tvec[2])); 00608 mat[3] = ((factor - 1) *(tvec[0] * tvec[1])); 00609 mat[4] = 1 + ((factor - 1) *(tvec[1] * tvec[1])); 00610 mat[5] = ((factor - 1) *(tvec[1] * tvec[2])); 00611 mat[6] = ((factor - 1) *(tvec[0] * tvec[2])); 00612 mat[7] = ((factor - 1) *(tvec[1] * tvec[2])); 00613 mat[8] = 1 + ((factor - 1) *(tvec[2] * tvec[2])); 00614 } 00615 } 00616 if (matSize == 4) { 00617 matrix_3x3_as_4x4(mat); 00618 } 00619 //pass to matrix creation 00620 return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); 00621 } 00622 //----------------------------------mathutils.Matrix.OrthoProjection() --- 00623 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. 00624 PyDoc_STRVAR(C_Matrix_OrthoProjection_doc, 00625 ".. classmethod:: OrthoProjection(axis, size)\n" 00626 "\n" 00627 " Create a matrix to represent an orthographic projection.\n" 00628 "\n" 00629 " :arg axis: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n" 00630 " where a single axis is for a 2D matrix.\n" 00631 " Or a vector for an arbitrary axis\n" 00632 " :type axis: string or :class:`Vector`\n" 00633 " :arg size: The size of the projection matrix to construct [2, 4].\n" 00634 " :type size: int\n" 00635 " :return: A new projection matrix.\n" 00636 " :rtype: :class:`Matrix`\n" 00637 ); 00638 static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args) 00639 { 00640 PyObject *axis; 00641 00642 int matSize, x; 00643 float norm = 0.0f; 00644 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 00645 0.0f, 0.0f, 0.0f, 0.0f, 00646 0.0f, 0.0f, 0.0f, 0.0f, 00647 0.0f, 0.0f, 0.0f, 1.0f}; 00648 00649 if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) { 00650 return NULL; 00651 } 00652 if (matSize != 2 && matSize != 3 && matSize != 4) { 00653 PyErr_SetString(PyExc_ValueError, 00654 "Matrix.OrthoProjection(): " 00655 "can only return a 2x2 3x3 or 4x4 matrix"); 00656 return NULL; 00657 } 00658 00659 if (PyUnicode_Check(axis)) { //ortho projection onto cardinal plane 00660 Py_ssize_t plane_len; 00661 const char *plane = _PyUnicode_AsStringAndSize(axis, &plane_len); 00662 if (matSize == 2) { 00663 if (plane_len == 1 && plane[0] == 'X') { 00664 mat[0] = 1.0f; 00665 } 00666 else if (plane_len == 1 && plane[0] == 'Y') { 00667 mat[3] = 1.0f; 00668 } 00669 else { 00670 PyErr_Format(PyExc_ValueError, 00671 "Matrix.OrthoProjection(): " 00672 "unknown plane, expected: X, Y, not '%.200s'", 00673 plane); 00674 return NULL; 00675 } 00676 } 00677 else { 00678 if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Y') { 00679 mat[0] = 1.0f; 00680 mat[4] = 1.0f; 00681 } 00682 else if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Z') { 00683 mat[0] = 1.0f; 00684 mat[8] = 1.0f; 00685 } 00686 else if (plane_len == 2 && plane[0] == 'Y' && plane[1] == 'Z') { 00687 mat[4] = 1.0f; 00688 mat[8] = 1.0f; 00689 } 00690 else { 00691 PyErr_Format(PyExc_ValueError, 00692 "Matrix.OrthoProjection(): " 00693 "unknown plane, expected: XY, XZ, YZ, not '%.200s'", 00694 plane); 00695 return NULL; 00696 } 00697 } 00698 } 00699 else { 00700 //arbitrary plane 00701 00702 int vec_size = (matSize == 2 ? 2 : 3); 00703 float tvec[4]; 00704 00705 if (mathutils_array_parse(tvec, vec_size, vec_size, axis, 00706 "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1) 00707 { 00708 return NULL; 00709 } 00710 00711 //normalize arbitrary axis 00712 for (x = 0; x < vec_size; x++) { 00713 norm += tvec[x] * tvec[x]; 00714 } 00715 norm = (float) sqrt(norm); 00716 for (x = 0; x < vec_size; x++) { 00717 tvec[x] /= norm; 00718 } 00719 if (matSize == 2) { 00720 mat[0] = 1 - (tvec[0] * tvec[0]); 00721 mat[1] = - (tvec[0] * tvec[1]); 00722 mat[2] = - (tvec[0] * tvec[1]); 00723 mat[3] = 1 - (tvec[1] * tvec[1]); 00724 } 00725 else if (matSize > 2) { 00726 mat[0] = 1 - (tvec[0] * tvec[0]); 00727 mat[1] = - (tvec[0] * tvec[1]); 00728 mat[2] = - (tvec[0] * tvec[2]); 00729 mat[3] = - (tvec[0] * tvec[1]); 00730 mat[4] = 1 - (tvec[1] * tvec[1]); 00731 mat[5] = - (tvec[1] * tvec[2]); 00732 mat[6] = - (tvec[0] * tvec[2]); 00733 mat[7] = - (tvec[1] * tvec[2]); 00734 mat[8] = 1 - (tvec[2] * tvec[2]); 00735 } 00736 } 00737 if (matSize == 4) { 00738 matrix_3x3_as_4x4(mat); 00739 } 00740 //pass to matrix creation 00741 return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); 00742 } 00743 00744 PyDoc_STRVAR(C_Matrix_Shear_doc, 00745 ".. classmethod:: Shear(plane, size, factor)\n" 00746 "\n" 00747 " Create a matrix to represent an shear transformation.\n" 00748 "\n" 00749 " :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n" 00750 " where a single axis is for a 2D matrix only.\n" 00751 " :type plane: string\n" 00752 " :arg size: The size of the shear matrix to construct [2, 4].\n" 00753 " :type size: int\n" 00754 " :arg factor: The factor of shear to apply. For a 3 or 4 *size* matrix\n" 00755 " pass a pair of floats corrasponding with the *plane* axis.\n" 00756 " :type factor: float or float pair\n" 00757 " :return: A new shear matrix.\n" 00758 " :rtype: :class:`Matrix`\n" 00759 ); 00760 static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args) 00761 { 00762 int matSize; 00763 const char *plane; 00764 PyObject *fac; 00765 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 00766 0.0f, 0.0f, 0.0f, 0.0f, 00767 0.0f, 0.0f, 0.0f, 0.0f, 00768 0.0f, 0.0f, 0.0f, 1.0f}; 00769 00770 if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) { 00771 return NULL; 00772 } 00773 if (matSize != 2 && matSize != 3 && matSize != 4) { 00774 PyErr_SetString(PyExc_ValueError, 00775 "Matrix.Shear(): " 00776 "can only return a 2x2 3x3 or 4x4 matrix"); 00777 return NULL; 00778 } 00779 00780 if (matSize == 2) { 00781 float const factor = PyFloat_AsDouble(fac); 00782 00783 if (factor == -1.0f && PyErr_Occurred()) { 00784 PyErr_SetString(PyExc_TypeError, 00785 "Matrix.Shear(): " 00786 "the factor to be a float"); 00787 return NULL; 00788 } 00789 00790 /* unit */ 00791 mat[0] = 1.0f; 00792 mat[3] = 1.0f; 00793 00794 if (strcmp(plane, "X") == 0) { 00795 mat[2] = factor; 00796 } 00797 else if (strcmp(plane, "Y") == 0) { 00798 mat[1] = factor; 00799 } 00800 else { 00801 PyErr_SetString(PyExc_ValueError, 00802 "Matrix.Shear(): " 00803 "expected: X, Y or wrong matrix size for shearing plane"); 00804 return NULL; 00805 } 00806 } 00807 else { 00808 /* 3 or 4, apply as 3x3, resize later if needed */ 00809 float factor[2]; 00810 00811 if (mathutils_array_parse(factor, 2, 2, fac, "Matrix.Shear()") < 0) { 00812 return NULL; 00813 } 00814 00815 /* unit */ 00816 mat[0] = 1.0f; 00817 mat[4] = 1.0f; 00818 mat[8] = 1.0f; 00819 00820 if (strcmp(plane, "XY") == 0) { 00821 mat[6] = factor[0]; 00822 mat[7] = factor[1]; 00823 } 00824 else if (strcmp(plane, "XZ") == 0) { 00825 mat[3] = factor[0]; 00826 mat[5] = factor[1]; 00827 } 00828 else if (strcmp(plane, "YZ") == 0) { 00829 mat[1] = factor[0]; 00830 mat[2] = factor[1]; 00831 } 00832 else { 00833 PyErr_SetString(PyExc_ValueError, 00834 "Matrix.Shear(): " 00835 "expected: X, Y, XY, XZ, YZ"); 00836 return NULL; 00837 } 00838 } 00839 00840 if (matSize == 4) { 00841 matrix_3x3_as_4x4(mat); 00842 } 00843 //pass to matrix creation 00844 return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); 00845 } 00846 00847 void matrix_as_3x3(float mat[3][3], MatrixObject *self) 00848 { 00849 copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0)); 00850 copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1)); 00851 copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2)); 00852 } 00853 00854 /* assumes rowsize == colsize is checked and the read callback has run */ 00855 static float matrix_determinant_internal(MatrixObject *self) 00856 { 00857 if (self->num_col == 2) { 00858 return determinant_m2(MATRIX_ITEM(self, 0, 0), MATRIX_ITEM(self, 0, 1), 00859 MATRIX_ITEM(self, 1, 0), MATRIX_ITEM(self, 1, 1)); 00860 } 00861 else if (self->num_col == 3) { 00862 return determinant_m3(MATRIX_ITEM(self, 0, 0), MATRIX_ITEM(self, 0, 1), MATRIX_ITEM(self, 0, 2), 00863 MATRIX_ITEM(self, 1, 0), MATRIX_ITEM(self, 1, 1), MATRIX_ITEM(self, 1, 2), 00864 MATRIX_ITEM(self, 2, 0), MATRIX_ITEM(self, 2, 1), MATRIX_ITEM(self, 2, 2)); 00865 } 00866 else { 00867 return determinant_m4((float (*)[4])self->matrix); 00868 } 00869 } 00870 00871 00872 /*-----------------------------METHODS----------------------------*/ 00873 PyDoc_STRVAR(Matrix_to_quaternion_doc, 00874 ".. method:: to_quaternion()\n" 00875 "\n" 00876 " Return a quaternion representation of the rotation matrix.\n" 00877 "\n" 00878 " :return: Quaternion representation of the rotation matrix.\n" 00879 " :rtype: :class:`Quaternion`\n" 00880 ); 00881 static PyObject *Matrix_to_quaternion(MatrixObject *self) 00882 { 00883 float quat[4]; 00884 00885 if (BaseMath_ReadCallback(self) == -1) 00886 return NULL; 00887 00888 /* must be 3-4 cols, 3-4 rows, square matrix */ 00889 if ((self->num_row < 3) || (self->num_col < 3) || (self->num_row != self->num_col)) { 00890 PyErr_SetString(PyExc_ValueError, 00891 "Matrix.to_quat(): " 00892 "inappropriate matrix size - expects 3x3 or 4x4 matrix"); 00893 return NULL; 00894 } 00895 if (self->num_row == 3) { 00896 mat3_to_quat(quat, (float (*)[3])self->matrix); 00897 } 00898 else { 00899 mat4_to_quat(quat, (float (*)[4])self->matrix); 00900 } 00901 00902 return Quaternion_CreatePyObject(quat, Py_NEW, NULL); 00903 } 00904 00905 /*---------------------------matrix.toEuler() --------------------*/ 00906 PyDoc_STRVAR(Matrix_to_euler_doc, 00907 ".. method:: to_euler(order, euler_compat)\n" 00908 "\n" 00909 " Return an Euler representation of the rotation matrix\n" 00910 " (3x3 or 4x4 matrix only).\n" 00911 "\n" 00912 " :arg order: Optional rotation order argument in\n" 00913 " ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n" 00914 " :type order: string\n" 00915 " :arg euler_compat: Optional euler argument the new euler will be made\n" 00916 " compatible with (no axis flipping between them).\n" 00917 " Useful for converting a series of matrices to animation curves.\n" 00918 " :type euler_compat: :class:`Euler`\n" 00919 " :return: Euler representation of the matrix.\n" 00920 " :rtype: :class:`Euler`\n" 00921 ); 00922 static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args) 00923 { 00924 const char *order_str = NULL; 00925 short order = EULER_ORDER_XYZ; 00926 float eul[3], eul_compatf[3]; 00927 EulerObject *eul_compat = NULL; 00928 00929 float tmat[3][3]; 00930 float (*mat)[3]; 00931 00932 if (BaseMath_ReadCallback(self) == -1) 00933 return NULL; 00934 00935 if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat)) 00936 return NULL; 00937 00938 if (eul_compat) { 00939 if (BaseMath_ReadCallback(eul_compat) == -1) 00940 return NULL; 00941 00942 copy_v3_v3(eul_compatf, eul_compat->eul); 00943 } 00944 00945 /*must be 3-4 cols, 3-4 rows, square matrix */ 00946 if (self->num_row ==3 && self->num_col ==3) { 00947 mat = (float (*)[3])self->matrix; 00948 } 00949 else if (self->num_row ==4 && self->num_col ==4) { 00950 copy_m3_m4(tmat, (float (*)[4])self->matrix); 00951 mat = tmat; 00952 } 00953 else { 00954 PyErr_SetString(PyExc_ValueError, 00955 "Matrix.to_euler(): " 00956 "inappropriate matrix size - expects 3x3 or 4x4 matrix"); 00957 return NULL; 00958 } 00959 00960 if (order_str) { 00961 order = euler_order_from_string(order_str, "Matrix.to_euler()"); 00962 00963 if (order == -1) 00964 return NULL; 00965 } 00966 00967 if (eul_compat) { 00968 if (order == 1) mat3_to_compatible_eul(eul, eul_compatf, mat); 00969 else mat3_to_compatible_eulO(eul, eul_compatf, order, mat); 00970 } 00971 else { 00972 if (order == 1) mat3_to_eul(eul, mat); 00973 else mat3_to_eulO(eul, order, mat); 00974 } 00975 00976 return Euler_CreatePyObject(eul, order, Py_NEW, NULL); 00977 } 00978 00979 PyDoc_STRVAR(Matrix_resize_4x4_doc, 00980 ".. method:: resize_4x4()\n" 00981 "\n" 00982 " Resize the matrix to 4x4.\n" 00983 ); 00984 static PyObject *Matrix_resize_4x4(MatrixObject *self) 00985 { 00986 float mat[4][4] = MAT4_UNITY; 00987 int col; 00988 00989 if (self->wrapped == Py_WRAP) { 00990 PyErr_SetString(PyExc_TypeError, 00991 "Matrix.resize_4x4(): " 00992 "cannot resize wrapped data - make a copy and resize that"); 00993 return NULL; 00994 } 00995 if (self->cb_user) { 00996 PyErr_SetString(PyExc_TypeError, 00997 "Matrix.resize_4x4(): " 00998 "cannot resize owned data - make a copy and resize that"); 00999 return NULL; 01000 } 01001 01002 self->matrix = PyMem_Realloc(self->matrix, (sizeof(float) * 16)); 01003 if (self->matrix == NULL) { 01004 PyErr_SetString(PyExc_MemoryError, 01005 "Matrix.resize_4x4(): " 01006 "problem allocating pointer space"); 01007 return NULL; 01008 } 01009 01010 for (col = 0; col < self->num_col; col++) { 01011 memcpy(mat[col], MATRIX_COL_PTR(self, col), self->num_row * sizeof(float)); 01012 } 01013 01014 copy_m4_m4((float (*)[4])self->matrix, (float (*)[4])mat); 01015 01016 self->num_col = 4; 01017 self->num_row = 4; 01018 01019 Py_RETURN_NONE; 01020 } 01021 01022 PyDoc_STRVAR(Matrix_to_4x4_doc, 01023 ".. method:: to_4x4()\n" 01024 "\n" 01025 " Return a 4x4 copy of this matrix.\n" 01026 "\n" 01027 " :return: a new matrix.\n" 01028 " :rtype: :class:`Matrix`\n" 01029 ); 01030 static PyObject *Matrix_to_4x4(MatrixObject *self) 01031 { 01032 if (BaseMath_ReadCallback(self) == -1) 01033 return NULL; 01034 01035 if (self->num_row == 4 && self->num_col == 4) { 01036 return Matrix_CreatePyObject(self->matrix, 4, 4, Py_NEW, Py_TYPE(self)); 01037 } 01038 else if (self->num_row == 3 && self->num_col == 3) { 01039 float mat[4][4]; 01040 copy_m4_m3(mat, (float (*)[3])self->matrix); 01041 return Matrix_CreatePyObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self)); 01042 } 01043 /* TODO, 2x2 matrix */ 01044 01045 PyErr_SetString(PyExc_TypeError, 01046 "Matrix.to_4x4(): " 01047 "inappropriate matrix size"); 01048 return NULL; 01049 } 01050 01051 PyDoc_STRVAR(Matrix_to_3x3_doc, 01052 ".. method:: to_3x3()\n" 01053 "\n" 01054 " Return a 3x3 copy of this matrix.\n" 01055 "\n" 01056 " :return: a new matrix.\n" 01057 " :rtype: :class:`Matrix`\n" 01058 ); 01059 static PyObject *Matrix_to_3x3(MatrixObject *self) 01060 { 01061 float mat[3][3]; 01062 01063 if (BaseMath_ReadCallback(self) == -1) 01064 return NULL; 01065 01066 if ((self->num_row < 3) || (self->num_col < 3)) { 01067 PyErr_SetString(PyExc_TypeError, 01068 "Matrix.to_3x3(): inappropriate matrix size"); 01069 return NULL; 01070 } 01071 01072 matrix_as_3x3(mat, self); 01073 01074 return Matrix_CreatePyObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self)); 01075 } 01076 01077 PyDoc_STRVAR(Matrix_to_translation_doc, 01078 ".. method:: to_translation()\n" 01079 "\n" 01080 " Return a the translation part of a 4 row matrix.\n" 01081 "\n" 01082 " :return: Return a the translation of a matrix.\n" 01083 " :rtype: :class:`Vector`\n" 01084 ); 01085 static PyObject *Matrix_to_translation(MatrixObject *self) 01086 { 01087 if (BaseMath_ReadCallback(self) == -1) 01088 return NULL; 01089 01090 if ((self->num_row < 3) || self->num_col < 4) { 01091 PyErr_SetString(PyExc_TypeError, 01092 "Matrix.to_translation(): " 01093 "inappropriate matrix size"); 01094 return NULL; 01095 } 01096 01097 return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, Py_NEW, NULL); 01098 } 01099 01100 PyDoc_STRVAR(Matrix_to_scale_doc, 01101 ".. method:: to_scale()\n" 01102 "\n" 01103 " Return a the scale part of a 3x3 or 4x4 matrix.\n" 01104 "\n" 01105 " :return: Return a the scale of a matrix.\n" 01106 " :rtype: :class:`Vector`\n" 01107 "\n" 01108 " .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n" 01109 ); 01110 static PyObject *Matrix_to_scale(MatrixObject *self) 01111 { 01112 float rot[3][3]; 01113 float mat[3][3]; 01114 float size[3]; 01115 01116 if (BaseMath_ReadCallback(self) == -1) 01117 return NULL; 01118 01119 /*must be 3-4 cols, 3-4 rows, square matrix */ 01120 if ((self->num_row < 3) || (self->num_col < 3)) { 01121 PyErr_SetString(PyExc_TypeError, 01122 "Matrix.to_scale(): " 01123 "inappropriate matrix size, 3x3 minimum size"); 01124 return NULL; 01125 } 01126 01127 matrix_as_3x3(mat, self); 01128 01129 /* compatible mat4_to_loc_rot_size */ 01130 mat3_to_rot_size(rot, size, mat); 01131 01132 return Vector_CreatePyObject(size, 3, Py_NEW, NULL); 01133 } 01134 01135 /*---------------------------matrix.invert() ---------------------*/ 01136 PyDoc_STRVAR(Matrix_invert_doc, 01137 ".. method:: invert()\n" 01138 "\n" 01139 " Set the matrix to its inverse.\n" 01140 "\n" 01141 " .. note:: :exc:`ValueError` exception is raised.\n" 01142 "\n" 01143 " .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n" 01144 ); 01145 static PyObject *Matrix_invert(MatrixObject *self) 01146 { 01147 01148 int x, y, z = 0; 01149 float det = 0.0f; 01150 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 01151 0.0f, 0.0f, 0.0f, 0.0f, 01152 0.0f, 0.0f, 0.0f, 0.0f, 01153 0.0f, 0.0f, 0.0f, 1.0f}; 01154 01155 if (BaseMath_ReadCallback(self) == -1) 01156 return NULL; 01157 01158 if (self->num_col != self->num_row) { 01159 PyErr_SetString(PyExc_TypeError, 01160 "Matrix.invert(ed): " 01161 "only square matrices are supported"); 01162 return NULL; 01163 } 01164 01165 /* calculate the determinant */ 01166 det = matrix_determinant_internal(self); 01167 01168 if (det != 0) { 01169 /* calculate the classical adjoint */ 01170 if (self->num_col == 2) { 01171 mat[0] = MATRIX_ITEM(self, 1, 1); 01172 mat[1] = -MATRIX_ITEM(self, 0, 1); 01173 mat[2] = -MATRIX_ITEM(self, 1, 0); 01174 mat[3] = MATRIX_ITEM(self, 0, 0); 01175 } 01176 else if (self->num_col == 3) { 01177 adjoint_m3_m3((float (*)[3]) mat,(float (*)[3])self->matrix); 01178 } 01179 else if (self->num_col == 4) { 01180 adjoint_m4_m4((float (*)[4]) mat, (float (*)[4])self->matrix); 01181 } 01182 /* divide by determinate */ 01183 for (x = 0; x < (self->num_col * self->num_row); x++) { 01184 mat[x] /= det; 01185 } 01186 /* set values */ 01187 for (x = 0; x < self->num_col; x++) { 01188 for (y = 0; y < self->num_row; y++) { 01189 MATRIX_ITEM(self, y, x) = mat[z]; 01190 z++; 01191 } 01192 } 01193 /*transpose 01194 Matrix_transpose(self);*/ 01195 } 01196 else { 01197 PyErr_SetString(PyExc_ValueError, 01198 "Matrix.invert(ed): " 01199 "matrix does not have an inverse"); 01200 return NULL; 01201 } 01202 01203 (void)BaseMath_WriteCallback(self); 01204 Py_RETURN_NONE; 01205 } 01206 01207 PyDoc_STRVAR(Matrix_inverted_doc, 01208 ".. method:: inverted()\n" 01209 "\n" 01210 " Return an inverted copy of the matrix.\n" 01211 "\n" 01212 " :return: the inverted matrix.\n" 01213 " :rtype: :class:`Matrix`\n" 01214 "\n" 01215 " .. note:: :exc:`ValueError` exception is raised.\n" 01216 ); 01217 static PyObject *Matrix_inverted(MatrixObject *self) 01218 { 01219 return matrix__apply_to_copy((PyNoArgsFunction)Matrix_invert, self); 01220 } 01221 01222 PyDoc_STRVAR(Matrix_rotate_doc, 01223 ".. method:: rotate(other)\n" 01224 "\n" 01225 " Rotates the matrix a by another mathutils value.\n" 01226 "\n" 01227 " :arg other: rotation component of mathutils value\n" 01228 " :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n" 01229 "\n" 01230 " .. note:: If any of the columns are not unit length this may not have desired results.\n" 01231 ); 01232 static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value) 01233 { 01234 float self_rmat[3][3], other_rmat[3][3], rmat[3][3]; 01235 01236 if (BaseMath_ReadCallback(self) == -1) 01237 return NULL; 01238 01239 if (mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1) 01240 return NULL; 01241 01242 if (self->num_row != 3 || self->num_col != 3) { 01243 PyErr_SetString(PyExc_TypeError, 01244 "Matrix.rotate(): " 01245 "must have 3x3 dimensions"); 01246 return NULL; 01247 } 01248 01249 matrix_as_3x3(self_rmat, self); 01250 mul_m3_m3m3(rmat, other_rmat, self_rmat); 01251 01252 copy_m3_m3((float (*)[3])(self->matrix), rmat); 01253 01254 (void)BaseMath_WriteCallback(self); 01255 Py_RETURN_NONE; 01256 } 01257 01258 /*---------------------------matrix.decompose() ---------------------*/ 01259 PyDoc_STRVAR(Matrix_decompose_doc, 01260 ".. method:: decompose()\n" 01261 "\n" 01262 " Return the location, rotaion and scale components of this matrix.\n" 01263 "\n" 01264 " :return: loc, rot, scale triple.\n" 01265 " :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)" 01266 ); 01267 static PyObject *Matrix_decompose(MatrixObject *self) 01268 { 01269 PyObject *ret; 01270 float loc[3]; 01271 float rot[3][3]; 01272 float quat[4]; 01273 float size[3]; 01274 01275 if (self->num_row != 4 || self->num_col != 4) { 01276 PyErr_SetString(PyExc_TypeError, 01277 "Matrix.decompose(): " 01278 "inappropriate matrix size - expects 4x4 matrix"); 01279 return NULL; 01280 } 01281 01282 if (BaseMath_ReadCallback(self) == -1) 01283 return NULL; 01284 01285 mat4_to_loc_rot_size(loc, rot, size, (float (*)[4])self->matrix); 01286 mat3_to_quat(quat, rot); 01287 01288 ret = PyTuple_New(3); 01289 PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(loc, 3, Py_NEW, NULL)); 01290 PyTuple_SET_ITEM(ret, 1, Quaternion_CreatePyObject(quat, Py_NEW, NULL)); 01291 PyTuple_SET_ITEM(ret, 2, Vector_CreatePyObject(size, 3, Py_NEW, NULL)); 01292 01293 return ret; 01294 } 01295 01296 01297 01298 PyDoc_STRVAR(Matrix_lerp_doc, 01299 ".. function:: lerp(other, factor)\n" 01300 "\n" 01301 " Returns the interpolation of two matrices.\n" 01302 "\n" 01303 " :arg other: value to interpolate with.\n" 01304 " :type other: :class:`Matrix`\n" 01305 " :arg factor: The interpolation value in [0.0, 1.0].\n" 01306 " :type factor: float\n" 01307 " :return: The interpolated rotation.\n" 01308 " :rtype: :class:`Matrix`\n" 01309 ); 01310 static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args) 01311 { 01312 MatrixObject *mat2 = NULL; 01313 float fac, mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM]; 01314 01315 if (!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac)) 01316 return NULL; 01317 01318 if (self->num_col != mat2->num_col || self->num_row != mat2->num_row) { 01319 PyErr_SetString(PyExc_ValueError, 01320 "Matrix.lerp(): " 01321 "expects both matrix objects of the same dimensions"); 01322 return NULL; 01323 } 01324 01325 if (BaseMath_ReadCallback(self) == -1 || BaseMath_ReadCallback(mat2) == -1) 01326 return NULL; 01327 01328 /* TODO, different sized matrix */ 01329 if (self->num_col == 4 && self->num_row == 4) { 01330 blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac); 01331 } 01332 else if (self->num_col == 3 && self->num_row == 3) { 01333 blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac); 01334 } 01335 else { 01336 PyErr_SetString(PyExc_ValueError, 01337 "Matrix.lerp(): " 01338 "only 3x3 and 4x4 matrices supported"); 01339 return NULL; 01340 } 01341 01342 return Matrix_CreatePyObject(mat, self->num_col, self->num_row, Py_NEW, Py_TYPE(self)); 01343 } 01344 01345 /*---------------------------matrix.determinant() ----------------*/ 01346 PyDoc_STRVAR(Matrix_determinant_doc, 01347 ".. method:: determinant()\n" 01348 "\n" 01349 " Return the determinant of a matrix.\n" 01350 "\n" 01351 " :return: Return a the determinant of a matrix.\n" 01352 " :rtype: float\n" 01353 "\n" 01354 " .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n" 01355 ); 01356 static PyObject *Matrix_determinant(MatrixObject *self) 01357 { 01358 if (BaseMath_ReadCallback(self) == -1) 01359 return NULL; 01360 01361 if (self->num_col != self->num_row) { 01362 PyErr_SetString(PyExc_TypeError, 01363 "Matrix.determinant(): " 01364 "only square matrices are supported"); 01365 return NULL; 01366 } 01367 01368 return PyFloat_FromDouble((double)matrix_determinant_internal(self)); 01369 } 01370 /*---------------------------matrix.transpose() ------------------*/ 01371 PyDoc_STRVAR(Matrix_transpose_doc, 01372 ".. method:: transpose()\n" 01373 "\n" 01374 " Set the matrix to its transpose.\n" 01375 "\n" 01376 " .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n" 01377 ); 01378 static PyObject *Matrix_transpose(MatrixObject *self) 01379 { 01380 if (BaseMath_ReadCallback(self) == -1) 01381 return NULL; 01382 01383 if (self->num_col != self->num_row) { 01384 PyErr_SetString(PyExc_TypeError, 01385 "Matrix.transpose(d): " 01386 "only square matrices are supported"); 01387 return NULL; 01388 } 01389 01390 if (self->num_col == 2) { 01391 const float t = MATRIX_ITEM(self, 1, 0); 01392 MATRIX_ITEM(self, 1, 0) = MATRIX_ITEM(self, 0, 1); 01393 MATRIX_ITEM(self, 0, 1) = t; 01394 } 01395 else if (self->num_col == 3) { 01396 transpose_m3((float (*)[3])self->matrix); 01397 } 01398 else { 01399 transpose_m4((float (*)[4])self->matrix); 01400 } 01401 01402 (void)BaseMath_WriteCallback(self); 01403 Py_RETURN_NONE; 01404 } 01405 01406 PyDoc_STRVAR(Matrix_transposed_doc, 01407 ".. method:: transposed()\n" 01408 "\n" 01409 " Return a new, transposed matrix.\n" 01410 "\n" 01411 " :return: a transposed matrix\n" 01412 " :rtype: :class:`Matrix`\n" 01413 ); 01414 static PyObject *Matrix_transposed(MatrixObject *self) 01415 { 01416 return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self); 01417 } 01418 01419 /*---------------------------matrix.zero() -----------------------*/ 01420 PyDoc_STRVAR(Matrix_zero_doc, 01421 ".. method:: zero()\n" 01422 "\n" 01423 " Set all the matrix values to zero.\n" 01424 "\n" 01425 " :return: an instance of itself\n" 01426 " :rtype: :class:`Matrix`\n" 01427 ); 01428 static PyObject *Matrix_zero(MatrixObject *self) 01429 { 01430 fill_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f); 01431 01432 if (BaseMath_WriteCallback(self) == -1) 01433 return NULL; 01434 01435 Py_RETURN_NONE; 01436 } 01437 /*---------------------------matrix.identity(() ------------------*/ 01438 PyDoc_STRVAR(Matrix_identity_doc, 01439 ".. method:: identity()\n" 01440 "\n" 01441 " Set the matrix to the identity matrix.\n" 01442 "\n" 01443 " .. note:: An object with zero location and rotation, a scale of one,\n" 01444 " will have an identity matrix.\n" 01445 "\n" 01446 " .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n" 01447 ); 01448 static PyObject *Matrix_identity(MatrixObject *self) 01449 { 01450 if (BaseMath_ReadCallback(self) == -1) 01451 return NULL; 01452 01453 if (self->num_col != self->num_row) { 01454 PyErr_SetString(PyExc_TypeError, 01455 "Matrix.identity(): " 01456 "only square matrices are supported"); 01457 return NULL; 01458 } 01459 01460 if (self->num_col == 2) { 01461 MATRIX_ITEM(self, 0, 0) = 1.0f; 01462 MATRIX_ITEM(self, 0, 1) = 0.0f; 01463 MATRIX_ITEM(self, 1, 0) = 0.0f; 01464 MATRIX_ITEM(self, 1, 1) = 1.0f; 01465 } 01466 else if (self->num_col == 3) { 01467 unit_m3((float (*)[3])self->matrix); 01468 } 01469 else { 01470 unit_m4((float (*)[4])self->matrix); 01471 } 01472 01473 if (BaseMath_WriteCallback(self) == -1) 01474 return NULL; 01475 01476 Py_RETURN_NONE; 01477 } 01478 01479 /*---------------------------Matrix.copy() ------------------*/ 01480 PyDoc_STRVAR(Matrix_copy_doc, 01481 ".. method:: copy()\n" 01482 "\n" 01483 " Returns a copy of this matrix.\n" 01484 "\n" 01485 " :return: an instance of itself\n" 01486 " :rtype: :class:`Matrix`\n" 01487 ); 01488 static PyObject *Matrix_copy(MatrixObject *self) 01489 { 01490 if (BaseMath_ReadCallback(self) == -1) 01491 return NULL; 01492 01493 return Matrix_CreatePyObject((float (*))self->matrix, self->num_col, self->num_row, Py_NEW, Py_TYPE(self)); 01494 } 01495 01496 /*----------------------------print object (internal)-------------*/ 01497 /* print the object to screen */ 01498 static PyObject *Matrix_repr(MatrixObject *self) 01499 { 01500 int col, row; 01501 PyObject *rows[MATRIX_MAX_DIM] = {NULL}; 01502 01503 if (BaseMath_ReadCallback(self) == -1) 01504 return NULL; 01505 01506 for (row = 0; row < self->num_row; row++) { 01507 rows[row] = PyTuple_New(self->num_col); 01508 for (col = 0; col < self->num_col; col++) { 01509 PyTuple_SET_ITEM(rows[row], col, PyFloat_FromDouble(MATRIX_ITEM(self, row, col))); 01510 } 01511 } 01512 switch (self->num_row) { 01513 case 2: return PyUnicode_FromFormat("Matrix((%R,\n" 01514 " %R))", rows[0], rows[1]); 01515 01516 case 3: return PyUnicode_FromFormat("Matrix((%R,\n" 01517 " %R,\n" 01518 " %R))", rows[0], rows[1], rows[2]); 01519 01520 case 4: return PyUnicode_FromFormat("Matrix((%R,\n" 01521 " %R,\n" 01522 " %R,\n" 01523 " %R))", rows[0], rows[1], rows[2], rows[3]); 01524 } 01525 01526 Py_FatalError("Matrix(): invalid row size!"); 01527 return NULL; 01528 } 01529 01530 static PyObject *Matrix_str(MatrixObject *self) 01531 { 01532 DynStr *ds; 01533 01534 int maxsize[MATRIX_MAX_DIM]; 01535 int row, col; 01536 01537 char dummy_buf[1]; 01538 01539 if (BaseMath_ReadCallback(self) == -1) 01540 return NULL; 01541 01542 ds = BLI_dynstr_new(); 01543 01544 /* First determine the maximum width for each column */ 01545 for (col = 0; col < self->num_col; col++) { 01546 maxsize[col] = 0; 01547 for (row = 0; row < self->num_row; row++) { 01548 int size = BLI_snprintf(dummy_buf, sizeof(dummy_buf), "%.4f", MATRIX_ITEM(self, row, col)); 01549 maxsize[col] = MAX2(maxsize[col], size); 01550 } 01551 } 01552 01553 /* Now write the unicode string to be printed */ 01554 BLI_dynstr_appendf(ds, "<Matrix %dx%d (", self->num_row, self->num_col); 01555 for (row = 0; row < self->num_row; row++) { 01556 for (col = 0; col < self->num_col; col++) { 01557 BLI_dynstr_appendf(ds, col ? ", %*.4f" : "%*.4f", maxsize[col], MATRIX_ITEM(self, row, col)); 01558 } 01559 BLI_dynstr_append(ds, row + 1 != self->num_row ? ")\n " : ")"); 01560 } 01561 BLI_dynstr_append(ds, ">"); 01562 01563 return mathutils_dynstr_to_py(ds); /* frees ds */ 01564 } 01565 01566 static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op) 01567 { 01568 PyObject *res; 01569 int ok = -1; /* zero is true */ 01570 01571 if (MatrixObject_Check(a) && MatrixObject_Check(b)) { 01572 MatrixObject *matA = (MatrixObject *)a; 01573 MatrixObject *matB = (MatrixObject *)b; 01574 01575 if (BaseMath_ReadCallback(matA) == -1 || BaseMath_ReadCallback(matB) == -1) 01576 return NULL; 01577 01578 ok = ( (matA->num_row == matB->num_row) && 01579 (matA->num_col == matB->num_col) && 01580 EXPP_VectorsAreEqual(matA->matrix, matB->matrix, (matA->num_col * matA->num_row), 1) 01581 ) ? 0 : -1; 01582 } 01583 01584 switch (op) { 01585 case Py_NE: 01586 ok = !ok; /* pass through */ 01587 case Py_EQ: 01588 res = ok ? Py_False : Py_True; 01589 break; 01590 01591 case Py_LT: 01592 case Py_LE: 01593 case Py_GT: 01594 case Py_GE: 01595 res = Py_NotImplemented; 01596 break; 01597 default: 01598 PyErr_BadArgument(); 01599 return NULL; 01600 } 01601 01602 return Py_INCREF(res), res; 01603 } 01604 01605 /*---------------------SEQUENCE PROTOCOLS------------------------ 01606 ----------------------------len(object)------------------------ 01607 sequence length */ 01608 static int Matrix_len(MatrixObject *self) 01609 { 01610 return (self->num_row); 01611 } 01612 /*----------------------------object[]--------------------------- 01613 sequence accessor (get) 01614 the wrapped vector gives direct access to the matrix data */ 01615 static PyObject *Matrix_item_row(MatrixObject *self, int row) 01616 { 01617 if (BaseMath_ReadCallback(self) == -1) 01618 return NULL; 01619 01620 if (row < 0 || row >= self->num_row) { 01621 PyErr_SetString(PyExc_IndexError, 01622 "matrix[attribute]: " 01623 "array index out of range"); 01624 return NULL; 01625 } 01626 return Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, row); 01627 } 01628 /* same but column access */ 01629 static PyObject *Matrix_item_col(MatrixObject *self, int col) 01630 { 01631 if (BaseMath_ReadCallback(self) == -1) 01632 return NULL; 01633 01634 if (col < 0 || col >= self->num_col) { 01635 PyErr_SetString(PyExc_IndexError, 01636 "matrix[attribute]: " 01637 "array index out of range"); 01638 return NULL; 01639 } 01640 return Vector_CreatePyObject_cb((PyObject *)self, self->num_row, mathutils_matrix_col_cb_index, col); 01641 } 01642 01643 /*----------------------------object[]------------------------- 01644 sequence accessor (set) */ 01645 01646 static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value) 01647 { 01648 int col; 01649 float vec[4]; 01650 if (BaseMath_ReadCallback(self) == -1) 01651 return -1; 01652 01653 if (row >= self->num_row || row < 0) { 01654 PyErr_SetString(PyExc_IndexError, 01655 "matrix[attribute] = x: bad row"); 01656 return -1; 01657 } 01658 01659 if (mathutils_array_parse(vec, self->num_col, self->num_col, value, "matrix[i] = value assignment") < 0) { 01660 return -1; 01661 } 01662 01663 /* Since we are assigning a row we cannot memcpy */ 01664 for (col = 0; col < self->num_col; col++) { 01665 MATRIX_ITEM(self, row, col) = vec[col]; 01666 } 01667 01668 (void)BaseMath_WriteCallback(self); 01669 return 0; 01670 } 01671 static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value) 01672 { 01673 int row; 01674 float vec[4]; 01675 if (BaseMath_ReadCallback(self) == -1) 01676 return -1; 01677 01678 if (col >= self->num_col || col < 0) { 01679 PyErr_SetString(PyExc_IndexError, 01680 "matrix[attribute] = x: bad col"); 01681 return -1; 01682 } 01683 01684 if (mathutils_array_parse(vec, self->num_row, self->num_row, value, "matrix[i] = value assignment") < 0) { 01685 return -1; 01686 } 01687 01688 /* Since we are assigning a row we cannot memcpy */ 01689 for (row = 0; row < self->num_row; row++) { 01690 MATRIX_ITEM(self, row, col) = vec[row]; 01691 } 01692 01693 (void)BaseMath_WriteCallback(self); 01694 return 0; 01695 } 01696 01697 01698 /*----------------------------object[z:y]------------------------ 01699 sequence slice (get)*/ 01700 static PyObject *Matrix_slice(MatrixObject *self, int begin, int end) 01701 { 01702 01703 PyObject *tuple; 01704 int count; 01705 01706 if (BaseMath_ReadCallback(self) == -1) 01707 return NULL; 01708 01709 CLAMP(begin, 0, self->num_row); 01710 CLAMP(end, 0, self->num_row); 01711 begin = MIN2(begin, end); 01712 01713 tuple = PyTuple_New(end - begin); 01714 for (count = begin; count < end; count++) { 01715 PyTuple_SET_ITEM(tuple, count - begin, 01716 Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, count)); 01717 01718 } 01719 01720 return tuple; 01721 } 01722 /*----------------------------object[z:y]------------------------ 01723 sequence slice (set)*/ 01724 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value) 01725 { 01726 PyObject *value_fast = NULL; 01727 01728 if (BaseMath_ReadCallback(self) == -1) 01729 return -1; 01730 01731 CLAMP(begin, 0, self->num_row); 01732 CLAMP(end, 0, self->num_row); 01733 begin = MIN2(begin, end); 01734 01735 /* non list/tuple cases */ 01736 if (!(value_fast = PySequence_Fast(value, "matrix[begin:end] = value"))) { 01737 /* PySequence_Fast sets the error */ 01738 return -1; 01739 } 01740 else { 01741 const int size = end - begin; 01742 int row, col; 01743 float mat[16]; 01744 float vec[4]; 01745 01746 if (PySequence_Fast_GET_SIZE(value_fast) != size) { 01747 Py_DECREF(value_fast); 01748 PyErr_SetString(PyExc_ValueError, 01749 "matrix[begin:end] = []: " 01750 "size mismatch in slice assignment"); 01751 return -1; 01752 } 01753 01754 memcpy(mat, self->matrix, self->num_col * self->num_row * sizeof(float)); 01755 01756 /* parse sub items */ 01757 for (row = begin; row < end; row++) { 01758 /* parse each sub sequence */ 01759 PyObject *item = PySequence_Fast_GET_ITEM(value_fast, row - begin); 01760 01761 if (mathutils_array_parse(vec, self->num_col, self->num_col, item, 01762 "matrix[begin:end] = value assignment") < 0) 01763 { 01764 return -1; 01765 } 01766 01767 for (col = 0; col < self->num_col; col++) { 01768 mat[col * self->num_row + row] = vec[col]; 01769 } 01770 } 01771 01772 Py_DECREF(value_fast); 01773 01774 /*parsed well - now set in matrix*/ 01775 memcpy(self->matrix, mat, self->num_col * self->num_row * sizeof(float)); 01776 01777 (void)BaseMath_WriteCallback(self); 01778 return 0; 01779 } 01780 } 01781 /*------------------------NUMERIC PROTOCOLS---------------------- 01782 ------------------------obj + obj------------------------------*/ 01783 static PyObject *Matrix_add(PyObject *m1, PyObject *m2) 01784 { 01785 float mat[16]; 01786 MatrixObject *mat1 = NULL, *mat2 = NULL; 01787 01788 mat1 = (MatrixObject *)m1; 01789 mat2 = (MatrixObject *)m2; 01790 01791 if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) { 01792 PyErr_Format(PyExc_TypeError, 01793 "Matrix addition: (%s + %s) " 01794 "invalid type for this operation", 01795 Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name); 01796 return NULL; 01797 } 01798 01799 if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1) 01800 return NULL; 01801 01802 if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) { 01803 PyErr_SetString(PyExc_TypeError, 01804 "Matrix addition: " 01805 "matrices must have the same dimensions for this operation"); 01806 return NULL; 01807 } 01808 01809 add_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row); 01810 01811 return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1)); 01812 } 01813 /*------------------------obj - obj------------------------------ 01814 subtraction*/ 01815 static PyObject *Matrix_sub(PyObject *m1, PyObject *m2) 01816 { 01817 float mat[16]; 01818 MatrixObject *mat1 = NULL, *mat2 = NULL; 01819 01820 mat1 = (MatrixObject *)m1; 01821 mat2 = (MatrixObject *)m2; 01822 01823 if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) { 01824 PyErr_Format(PyExc_TypeError, 01825 "Matrix subtraction: (%s - %s) " 01826 "invalid type for this operation", 01827 Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name 01828 ); 01829 return NULL; 01830 } 01831 01832 if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1) 01833 return NULL; 01834 01835 if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) { 01836 PyErr_SetString(PyExc_TypeError, 01837 "Matrix addition: " 01838 "matrices must have the same dimensions for this operation"); 01839 return NULL; 01840 } 01841 01842 sub_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row); 01843 01844 return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1)); 01845 } 01846 /*------------------------obj * obj------------------------------ 01847 mulplication*/ 01848 static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar) 01849 { 01850 float tmat[16]; 01851 mul_vn_vn_fl(tmat, mat->matrix, mat->num_col * mat->num_row, scalar); 01852 return Matrix_CreatePyObject(tmat, mat->num_col, mat->num_row, Py_NEW, Py_TYPE(mat)); 01853 } 01854 01855 static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) 01856 { 01857 float scalar; 01858 int vec_size; 01859 01860 MatrixObject *mat1 = NULL, *mat2 = NULL; 01861 01862 if (MatrixObject_Check(m1)) { 01863 mat1 = (MatrixObject *)m1; 01864 if (BaseMath_ReadCallback(mat1) == -1) 01865 return NULL; 01866 } 01867 if (MatrixObject_Check(m2)) { 01868 mat2 = (MatrixObject *)m2; 01869 if (BaseMath_ReadCallback(mat2) == -1) 01870 return NULL; 01871 } 01872 01873 if (mat1 && mat2) { 01874 /* MATRIX * MATRIX */ 01875 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 01876 0.0f, 0.0f, 0.0f, 0.0f, 01877 0.0f, 0.0f, 0.0f, 0.0f, 01878 0.0f, 0.0f, 0.0f, 1.0f}; 01879 01880 int col, row, item; 01881 01882 if (mat1->num_col != mat2->num_row) { 01883 PyErr_SetString(PyExc_ValueError, 01884 "matrix1 * matrix2: matrix1 number of columns " 01885 "and the matrix2 number of rows must be the same"); 01886 return NULL; 01887 } 01888 01889 for (col = 0; col < mat2->num_col; col++) { 01890 for (row = 0; row < mat1->num_row; row++) { 01891 double dot = 0.0f; 01892 for (item = 0; item < mat1->num_col; item++) { 01893 dot += MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col); 01894 } 01895 mat[(col * mat1->num_row) + row] = (float)dot; 01896 } 01897 } 01898 01899 return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1)); 01900 } 01901 else if (mat2) { 01902 /*FLOAT/INT * MATRIX */ 01903 if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) { 01904 return matrix_mul_float(mat2, scalar); 01905 } 01906 } 01907 else if (mat1) { 01908 /* MATRIX * VECTOR */ 01909 if (VectorObject_Check(m2)) { 01910 VectorObject *vec2 = (VectorObject *)m2; 01911 float tvec[4]; 01912 if (BaseMath_ReadCallback(vec2) == -1) 01913 return NULL; 01914 if (column_vector_multiplication(tvec, vec2, mat1) == -1) { 01915 return NULL; 01916 } 01917 01918 if (mat1->num_col == 4 && vec2->size == 3) { 01919 vec_size = 3; 01920 } 01921 else { 01922 vec_size = mat1->num_row; 01923 } 01924 01925 return Vector_CreatePyObject(tvec, vec_size, Py_NEW, Py_TYPE(m2)); 01926 } 01927 /*FLOAT/INT * MATRIX */ 01928 else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) { 01929 return matrix_mul_float(mat1, scalar); 01930 } 01931 } 01932 else { 01933 BLI_assert(!"internal error"); 01934 } 01935 01936 PyErr_Format(PyExc_TypeError, 01937 "Matrix multiplication: " 01938 "not supported between '%.200s' and '%.200s' types", 01939 Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name); 01940 return NULL; 01941 } 01942 01943 /*-----------------PROTOCOL DECLARATIONS--------------------------*/ 01944 static PySequenceMethods Matrix_SeqMethods = { 01945 (lenfunc) Matrix_len, /* sq_length */ 01946 (binaryfunc) NULL, /* sq_concat */ 01947 (ssizeargfunc) NULL, /* sq_repeat */ 01948 (ssizeargfunc) Matrix_item_row, /* sq_item */ 01949 (ssizessizeargfunc) NULL, /* sq_slice, deprecated */ 01950 (ssizeobjargproc) Matrix_ass_item_row, /* sq_ass_item */ 01951 (ssizessizeobjargproc) NULL, /* sq_ass_slice, deprecated */ 01952 (objobjproc) NULL, /* sq_contains */ 01953 (binaryfunc) NULL, /* sq_inplace_concat */ 01954 (ssizeargfunc) NULL, /* sq_inplace_repeat */ 01955 }; 01956 01957 01958 static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item) 01959 { 01960 if (PyIndex_Check(item)) { 01961 Py_ssize_t i; 01962 i = PyNumber_AsSsize_t(item, PyExc_IndexError); 01963 if (i == -1 && PyErr_Occurred()) 01964 return NULL; 01965 if (i < 0) 01966 i += self->num_row; 01967 return Matrix_item_row(self, i); 01968 } 01969 else if (PySlice_Check(item)) { 01970 Py_ssize_t start, stop, step, slicelength; 01971 01972 if (PySlice_GetIndicesEx((void *)item, self->num_row, &start, &stop, &step, &slicelength) < 0) 01973 return NULL; 01974 01975 if (slicelength <= 0) { 01976 return PyTuple_New(0); 01977 } 01978 else if (step == 1) { 01979 return Matrix_slice(self, start, stop); 01980 } 01981 else { 01982 PyErr_SetString(PyExc_IndexError, 01983 "slice steps not supported with matrices"); 01984 return NULL; 01985 } 01986 } 01987 else { 01988 PyErr_Format(PyExc_TypeError, 01989 "matrix indices must be integers, not %.200s", 01990 Py_TYPE(item)->tp_name); 01991 return NULL; 01992 } 01993 } 01994 01995 static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value) 01996 { 01997 if (PyIndex_Check(item)) { 01998 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); 01999 if (i == -1 && PyErr_Occurred()) 02000 return -1; 02001 if (i < 0) 02002 i += self->num_row; 02003 return Matrix_ass_item_row(self, i, value); 02004 } 02005 else if (PySlice_Check(item)) { 02006 Py_ssize_t start, stop, step, slicelength; 02007 02008 if (PySlice_GetIndicesEx((void *)item, self->num_row, &start, &stop, &step, &slicelength) < 0) 02009 return -1; 02010 02011 if (step == 1) 02012 return Matrix_ass_slice(self, start, stop, value); 02013 else { 02014 PyErr_SetString(PyExc_IndexError, 02015 "slice steps not supported with matrices"); 02016 return -1; 02017 } 02018 } 02019 else { 02020 PyErr_Format(PyExc_TypeError, 02021 "matrix indices must be integers, not %.200s", 02022 Py_TYPE(item)->tp_name); 02023 return -1; 02024 } 02025 } 02026 02027 static PyMappingMethods Matrix_AsMapping = { 02028 (lenfunc)Matrix_len, 02029 (binaryfunc)Matrix_subscript, 02030 (objobjargproc)Matrix_ass_subscript 02031 }; 02032 02033 02034 static PyNumberMethods Matrix_NumMethods = { 02035 (binaryfunc) Matrix_add, /*nb_add*/ 02036 (binaryfunc) Matrix_sub, /*nb_subtract*/ 02037 (binaryfunc) Matrix_mul, /*nb_multiply*/ 02038 NULL, /*nb_remainder*/ 02039 NULL, /*nb_divmod*/ 02040 NULL, /*nb_power*/ 02041 (unaryfunc) 0, /*nb_negative*/ 02042 (unaryfunc) 0, /*tp_positive*/ 02043 (unaryfunc) 0, /*tp_absolute*/ 02044 (inquiry) 0, /*tp_bool*/ 02045 (unaryfunc) Matrix_inverted, /*nb_invert*/ 02046 NULL, /*nb_lshift*/ 02047 (binaryfunc)0, /*nb_rshift*/ 02048 NULL, /*nb_and*/ 02049 NULL, /*nb_xor*/ 02050 NULL, /*nb_or*/ 02051 NULL, /*nb_int*/ 02052 NULL, /*nb_reserved*/ 02053 NULL, /*nb_float*/ 02054 NULL, /* nb_inplace_add */ 02055 NULL, /* nb_inplace_subtract */ 02056 NULL, /* nb_inplace_multiply */ 02057 NULL, /* nb_inplace_remainder */ 02058 NULL, /* nb_inplace_power */ 02059 NULL, /* nb_inplace_lshift */ 02060 NULL, /* nb_inplace_rshift */ 02061 NULL, /* nb_inplace_and */ 02062 NULL, /* nb_inplace_xor */ 02063 NULL, /* nb_inplace_or */ 02064 NULL, /* nb_floor_divide */ 02065 NULL, /* nb_true_divide */ 02066 NULL, /* nb_inplace_floor_divide */ 02067 NULL, /* nb_inplace_true_divide */ 02068 NULL, /* nb_index */ 02069 }; 02070 02071 PyDoc_STRVAR(Matrix_translation_doc, 02072 "The translation component of the matrix.\n\n:type: Vector" 02073 ); 02074 static PyObject *Matrix_translation_get(MatrixObject *self, void *UNUSED(closure)) 02075 { 02076 PyObject *ret; 02077 02078 if (BaseMath_ReadCallback(self) == -1) 02079 return NULL; 02080 02081 /*must be 4x4 square matrix*/ 02082 if (self->num_row != 4 || self->num_col != 4) { 02083 PyErr_SetString(PyExc_AttributeError, 02084 "Matrix.translation: " 02085 "inappropriate matrix size, must be 4x4"); 02086 return NULL; 02087 } 02088 02089 ret = (PyObject *)Vector_CreatePyObject_cb((PyObject *)self, 3, mathutils_matrix_translation_cb_index, 3); 02090 02091 return ret; 02092 } 02093 02094 static int Matrix_translation_set(MatrixObject *self, PyObject *value, void *UNUSED(closure)) 02095 { 02096 float tvec[3]; 02097 02098 if (BaseMath_ReadCallback(self) == -1) 02099 return -1; 02100 02101 /*must be 4x4 square matrix*/ 02102 if (self->num_row != 4 || self->num_col != 4) { 02103 PyErr_SetString(PyExc_AttributeError, 02104 "Matrix.translation: " 02105 "inappropriate matrix size, must be 4x4"); 02106 return -1; 02107 } 02108 02109 if ((mathutils_array_parse(tvec, 3, 3, value, "Matrix.translation")) == -1) { 02110 return -1; 02111 } 02112 02113 copy_v3_v3(((float (*)[4])self->matrix)[3], tvec); 02114 02115 (void)BaseMath_WriteCallback(self); 02116 02117 return 0; 02118 } 02119 02120 PyDoc_STRVAR(Matrix_row_doc, 02121 "Access the matix by rows (default), (readonly).\n\n:type: Matrix Access" 02122 ); 02123 static PyObject *Matrix_row_get(MatrixObject *self, void *UNUSED(closure)) 02124 { 02125 return MatrixAccess_CreatePyObject(self, MAT_ACCESS_ROW); 02126 } 02127 02128 PyDoc_STRVAR(Matrix_col_doc, 02129 "Access the matix by colums, 3x3 and 4x4 only, (readonly).\n\n:type: Matrix Access" 02130 ); 02131 static PyObject *Matrix_col_get(MatrixObject *self, void *UNUSED(closure)) 02132 { 02133 return MatrixAccess_CreatePyObject(self, MAT_ACCESS_COL); 02134 } 02135 02136 PyDoc_STRVAR(Matrix_median_scale_doc, 02137 "The average scale applied to each axis (readonly).\n\n:type: float" 02138 ); 02139 static PyObject *Matrix_median_scale_get(MatrixObject *self, void *UNUSED(closure)) 02140 { 02141 float mat[3][3]; 02142 02143 if (BaseMath_ReadCallback(self) == -1) 02144 return NULL; 02145 02146 /*must be 3-4 cols, 3-4 rows, square matrix*/ 02147 if ((self->num_row < 3) || (self->num_col < 3)) { 02148 PyErr_SetString(PyExc_AttributeError, 02149 "Matrix.median_scale: " 02150 "inappropriate matrix size, 3x3 minimum"); 02151 return NULL; 02152 } 02153 02154 matrix_as_3x3(mat, self); 02155 02156 return PyFloat_FromDouble(mat3_to_scale(mat)); 02157 } 02158 02159 PyDoc_STRVAR(Matrix_is_negative_doc, 02160 "True if this matrix results in a negative scale, 3x3 and 4x4 only, (readonly).\n\n:type: bool" 02161 ); 02162 static PyObject *Matrix_is_negative_get(MatrixObject *self, void *UNUSED(closure)) 02163 { 02164 if (BaseMath_ReadCallback(self) == -1) 02165 return NULL; 02166 02167 /*must be 3-4 cols, 3-4 rows, square matrix*/ 02168 if (self->num_row == 4 && self->num_col == 4) 02169 return PyBool_FromLong(is_negative_m4((float (*)[4])self->matrix)); 02170 else if (self->num_row == 3 && self->num_col == 3) 02171 return PyBool_FromLong(is_negative_m3((float (*)[3])self->matrix)); 02172 else { 02173 PyErr_SetString(PyExc_AttributeError, 02174 "Matrix.is_negative: " 02175 "inappropriate matrix size - expects 3x3 or 4x4 matrix"); 02176 return NULL; 02177 } 02178 } 02179 02180 PyDoc_STRVAR(Matrix_is_orthogonal_doc, 02181 "True if this matrix is orthogonal, 3x3 and 4x4 only, (readonly).\n\n:type: bool" 02182 ); 02183 static PyObject *Matrix_is_orthogonal_get(MatrixObject *self, void *UNUSED(closure)) 02184 { 02185 if (BaseMath_ReadCallback(self) == -1) 02186 return NULL; 02187 02188 /*must be 3-4 cols, 3-4 rows, square matrix*/ 02189 if (self->num_row == 4 && self->num_col == 4) 02190 return PyBool_FromLong(is_orthogonal_m4((float (*)[4])self->matrix)); 02191 else if (self->num_row == 3 && self->num_col == 3) 02192 return PyBool_FromLong(is_orthogonal_m3((float (*)[3])self->matrix)); 02193 else { 02194 PyErr_SetString(PyExc_AttributeError, 02195 "Matrix.is_orthogonal: " 02196 "inappropriate matrix size - expects 3x3 or 4x4 matrix"); 02197 return NULL; 02198 } 02199 } 02200 02201 /*****************************************************************************/ 02202 /* Python attributes get/set structure: */ 02203 /*****************************************************************************/ 02204 static PyGetSetDef Matrix_getseters[] = { 02205 {(char *)"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, Matrix_median_scale_doc, NULL}, 02206 {(char *)"translation", (getter)Matrix_translation_get, (setter)Matrix_translation_set, Matrix_translation_doc, NULL}, 02207 {(char *)"row", (getter)Matrix_row_get, (setter)NULL, Matrix_row_doc, NULL}, 02208 {(char *)"col", (getter)Matrix_col_get, (setter)NULL, Matrix_col_doc, NULL}, 02209 {(char *)"is_negative", (getter)Matrix_is_negative_get, (setter)NULL, Matrix_is_negative_doc, NULL}, 02210 {(char *)"is_orthogonal", (getter)Matrix_is_orthogonal_get, (setter)NULL, Matrix_is_orthogonal_doc, NULL}, 02211 {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL}, 02212 {(char *)"owner",(getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL}, 02213 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ 02214 }; 02215 02216 /*-----------------------METHOD DEFINITIONS ----------------------*/ 02217 static struct PyMethodDef Matrix_methods[] = { 02218 /* derived values */ 02219 {"determinant", (PyCFunction) Matrix_determinant, METH_NOARGS, Matrix_determinant_doc}, 02220 {"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc}, 02221 02222 /* in place only */ 02223 {"zero", (PyCFunction) Matrix_zero, METH_NOARGS, Matrix_zero_doc}, 02224 {"identity", (PyCFunction) Matrix_identity, METH_NOARGS, Matrix_identity_doc}, 02225 02226 /* operate on original or copy */ 02227 {"transpose", (PyCFunction) Matrix_transpose, METH_NOARGS, Matrix_transpose_doc}, 02228 {"transposed", (PyCFunction) Matrix_transposed, METH_NOARGS, Matrix_transposed_doc}, 02229 {"invert", (PyCFunction) Matrix_invert, METH_NOARGS, Matrix_invert_doc}, 02230 {"inverted", (PyCFunction) Matrix_inverted, METH_NOARGS, Matrix_inverted_doc}, 02231 {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc}, 02232 // TODO. {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc}, 02233 {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc}, 02234 {"resize_4x4", (PyCFunction) Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc}, 02235 {"rotate", (PyCFunction) Matrix_rotate, METH_O, Matrix_rotate_doc}, 02236 02237 /* return converted representation */ 02238 {"to_euler", (PyCFunction) Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc}, 02239 {"to_quaternion", (PyCFunction) Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc}, 02240 {"to_scale", (PyCFunction) Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc}, 02241 {"to_translation", (PyCFunction) Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc}, 02242 02243 /* operation between 2 or more types */ 02244 {"lerp", (PyCFunction) Matrix_lerp, METH_VARARGS, Matrix_lerp_doc}, 02245 {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc}, 02246 {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc}, 02247 02248 /* class methods */ 02249 {"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc}, 02250 {"Scale", (PyCFunction) C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc}, 02251 {"Shear", (PyCFunction) C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc}, 02252 {"Translation", (PyCFunction) C_Matrix_Translation, METH_O | METH_CLASS, C_Matrix_Translation_doc}, 02253 {"OrthoProjection", (PyCFunction) C_Matrix_OrthoProjection, METH_VARARGS | METH_CLASS, C_Matrix_OrthoProjection_doc}, 02254 {NULL, NULL, 0, NULL} 02255 }; 02256 02257 /*------------------PY_OBECT DEFINITION--------------------------*/ 02258 PyDoc_STRVAR(matrix_doc, 02259 "This object gives access to Matrices in Blender." 02260 ); 02261 PyTypeObject matrix_Type = { 02262 PyVarObject_HEAD_INIT(NULL, 0) 02263 "mathutils.Matrix", /*tp_name*/ 02264 sizeof(MatrixObject), /*tp_basicsize*/ 02265 0, /*tp_itemsize*/ 02266 (destructor)BaseMathObject_dealloc, /*tp_dealloc*/ 02267 NULL, /*tp_print*/ 02268 NULL, /*tp_getattr*/ 02269 NULL, /*tp_setattr*/ 02270 NULL, /*tp_compare*/ 02271 (reprfunc) Matrix_repr, /*tp_repr*/ 02272 &Matrix_NumMethods, /*tp_as_number*/ 02273 &Matrix_SeqMethods, /*tp_as_sequence*/ 02274 &Matrix_AsMapping, /*tp_as_mapping*/ 02275 NULL, /*tp_hash*/ 02276 NULL, /*tp_call*/ 02277 (reprfunc) Matrix_str, /*tp_str*/ 02278 NULL, /*tp_getattro*/ 02279 NULL, /*tp_setattro*/ 02280 NULL, /*tp_as_buffer*/ 02281 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ 02282 matrix_doc, /*tp_doc*/ 02283 (traverseproc)BaseMathObject_traverse, //tp_traverse 02284 (inquiry)BaseMathObject_clear, //tp_clear 02285 (richcmpfunc)Matrix_richcmpr, /*tp_richcompare*/ 02286 0, /*tp_weaklistoffset*/ 02287 NULL, /*tp_iter*/ 02288 NULL, /*tp_iternext*/ 02289 Matrix_methods, /*tp_methods*/ 02290 NULL, /*tp_members*/ 02291 Matrix_getseters, /*tp_getset*/ 02292 NULL, /*tp_base*/ 02293 NULL, /*tp_dict*/ 02294 NULL, /*tp_descr_get*/ 02295 NULL, /*tp_descr_set*/ 02296 0, /*tp_dictoffset*/ 02297 NULL, /*tp_init*/ 02298 NULL, /*tp_alloc*/ 02299 Matrix_new, /*tp_new*/ 02300 NULL, /*tp_free*/ 02301 NULL, /*tp_is_gc*/ 02302 NULL, /*tp_bases*/ 02303 NULL, /*tp_mro*/ 02304 NULL, /*tp_cache*/ 02305 NULL, /*tp_subclasses*/ 02306 NULL, /*tp_weaklist*/ 02307 NULL /*tp_del*/ 02308 }; 02309 02310 /* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER 02311 * (i.e. it was allocated elsewhere by MEM_mallocN()) 02312 * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON 02313 * (i.e. it must be created here with PyMEM_malloc()) */ 02314 PyObject *Matrix_CreatePyObject(float *mat, 02315 const unsigned short num_col, const unsigned short num_row, 02316 int type, PyTypeObject *base_type) 02317 { 02318 MatrixObject *self; 02319 02320 /* matrix objects can be any 2-4row x 2-4col matrix */ 02321 if (num_col < 2 || num_col > 4 || num_row < 2 || num_row > 4) { 02322 PyErr_SetString(PyExc_RuntimeError, 02323 "Matrix(): " 02324 "row and column sizes must be between 2 and 4"); 02325 return NULL; 02326 } 02327 02328 self = base_type ? (MatrixObject *)base_type->tp_alloc(base_type, 0) : 02329 (MatrixObject *)PyObject_GC_New(MatrixObject, &matrix_Type); 02330 02331 if (self) { 02332 self->num_col = num_col; 02333 self->num_row = num_row; 02334 02335 /* init callbacks as NULL */ 02336 self->cb_user = NULL; 02337 self->cb_type = self->cb_subtype = 0; 02338 02339 if (type == Py_WRAP) { 02340 self->matrix = mat; 02341 self->wrapped = Py_WRAP; 02342 } 02343 else if (type == Py_NEW) { 02344 self->matrix = PyMem_Malloc(num_col * num_row * sizeof(float)); 02345 if (self->matrix == NULL) { /*allocation failure*/ 02346 PyErr_SetString(PyExc_MemoryError, 02347 "Matrix(): " 02348 "problem allocating pointer space"); 02349 return NULL; 02350 } 02351 02352 if (mat) { /*if a float array passed*/ 02353 memcpy(self->matrix, mat, num_col * num_row * sizeof(float)); 02354 } 02355 else if (num_col == num_row) { 02356 /* or if no arguments are passed return identity matrix for square matrices */ 02357 PyObject *ret_dummy = Matrix_identity(self); 02358 Py_DECREF(ret_dummy); 02359 } 02360 else { 02361 /* otherwise zero everything */ 02362 memset(self->matrix, 0, num_col * num_row * sizeof(float)); 02363 } 02364 self->wrapped = Py_NEW; 02365 } 02366 else { 02367 Py_FatalError("Matrix(): invalid type!"); 02368 return NULL; 02369 } 02370 } 02371 return (PyObject *) self; 02372 } 02373 02374 PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user, 02375 const unsigned short num_col, const unsigned short num_row, 02376 int cb_type, int cb_subtype) 02377 { 02378 MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, NULL); 02379 if (self) { 02380 Py_INCREF(cb_user); 02381 self->cb_user = cb_user; 02382 self->cb_type = (unsigned char)cb_type; 02383 self->cb_subtype = (unsigned char)cb_subtype; 02384 PyObject_GC_Track(self); 02385 } 02386 return (PyObject *) self; 02387 } 02388 02389 02390 /* ---------------------------------------------------------------------------- 02391 * special type for alaternate access */ 02392 02393 typedef struct { 02394 PyObject_HEAD /* required python macro */ 02395 MatrixObject *matrix_user; 02396 eMatrixAccess_t type; 02397 } MatrixAccessObject; 02398 02399 static int MatrixAccess_traverse(MatrixAccessObject *self, visitproc visit, void *arg) 02400 { 02401 Py_VISIT(self->matrix_user); 02402 return 0; 02403 } 02404 02405 static int MatrixAccess_clear(MatrixAccessObject *self) 02406 { 02407 Py_CLEAR(self->matrix_user); 02408 return 0; 02409 } 02410 02411 static void MatrixAccess_dealloc(MatrixAccessObject *self) 02412 { 02413 if (self->matrix_user) { 02414 PyObject_GC_UnTrack(self); 02415 MatrixAccess_clear(self); 02416 } 02417 02418 Py_TYPE(self)->tp_free(self); 02419 } 02420 02421 /* sequence access */ 02422 02423 static int MatrixAccess_len(MatrixAccessObject *self) 02424 { 02425 return (self->type == MAT_ACCESS_ROW) ? 02426 self->matrix_user->num_row : 02427 self->matrix_user->num_col; 02428 } 02429 02430 static PyObject *MatrixAccess_slice(MatrixAccessObject *self, int begin, int end) 02431 { 02432 PyObject *tuple; 02433 int count; 02434 02435 /* row/col access */ 02436 MatrixObject *matrix_user = self->matrix_user; 02437 int matrix_access_len; 02438 PyObject *(*Matrix_item_new)(MatrixObject *, int); 02439 02440 if (self->type == MAT_ACCESS_ROW) { 02441 matrix_access_len = matrix_user->num_row; 02442 Matrix_item_new = Matrix_item_row; 02443 } 02444 else { /* MAT_ACCESS_ROW */ 02445 matrix_access_len = matrix_user->num_col; 02446 Matrix_item_new = Matrix_item_col; 02447 } 02448 02449 CLAMP(begin, 0, matrix_access_len); 02450 if (end < 0) end = (matrix_access_len + 1) + end; 02451 CLAMP(end, 0, matrix_access_len); 02452 begin = MIN2(begin, end); 02453 02454 tuple = PyTuple_New(end - begin); 02455 for (count = begin; count < end; count++) { 02456 PyTuple_SET_ITEM(tuple, count - begin, Matrix_item_new(matrix_user, count)); 02457 } 02458 02459 return tuple; 02460 } 02461 02462 static PyObject *MatrixAccess_subscript(MatrixAccessObject *self, PyObject *item) 02463 { 02464 MatrixObject *matrix_user = self->matrix_user; 02465 02466 if (PyIndex_Check(item)) { 02467 Py_ssize_t i; 02468 i = PyNumber_AsSsize_t(item, PyExc_IndexError); 02469 if (i == -1 && PyErr_Occurred()) 02470 return NULL; 02471 if (self->type == MAT_ACCESS_ROW) { 02472 if (i < 0) 02473 i += matrix_user->num_row; 02474 return Matrix_item_row(matrix_user, i); 02475 } 02476 else { /* MAT_ACCESS_ROW */ 02477 if (i < 0) 02478 i += matrix_user->num_col; 02479 return Matrix_item_col(matrix_user, i); 02480 } 02481 } 02482 else if (PySlice_Check(item)) { 02483 Py_ssize_t start, stop, step, slicelength; 02484 02485 if (PySlice_GetIndicesEx((void *)item, MatrixAccess_len(self), &start, &stop, &step, &slicelength) < 0) 02486 return NULL; 02487 02488 if (slicelength <= 0) { 02489 return PyTuple_New(0); 02490 } 02491 else if (step == 1) { 02492 return MatrixAccess_slice(self, start, stop); 02493 } 02494 else { 02495 PyErr_SetString(PyExc_IndexError, 02496 "slice steps not supported with matrix accessors"); 02497 return NULL; 02498 } 02499 } 02500 else { 02501 PyErr_Format(PyExc_TypeError, 02502 "matrix indices must be integers, not %.200s", 02503 Py_TYPE(item)->tp_name); 02504 return NULL; 02505 } 02506 } 02507 02508 static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item, PyObject *value) 02509 { 02510 MatrixObject *matrix_user = self->matrix_user; 02511 02512 if (PyIndex_Check(item)) { 02513 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); 02514 if (i == -1 && PyErr_Occurred()) 02515 return -1; 02516 02517 if (self->type == MAT_ACCESS_ROW) { 02518 if (i < 0) 02519 i += matrix_user->num_row; 02520 return Matrix_ass_item_row(matrix_user, i, value); 02521 } 02522 else { /* MAT_ACCESS_ROW */ 02523 if (i < 0) 02524 i += matrix_user->num_col; 02525 return Matrix_ass_item_col(matrix_user, i, value); 02526 } 02527 02528 } 02529 /* TODO, slice */ 02530 else { 02531 PyErr_Format(PyExc_TypeError, 02532 "matrix indices must be integers, not %.200s", 02533 Py_TYPE(item)->tp_name); 02534 return -1; 02535 } 02536 } 02537 02538 static PyObject *MatrixAccess_iter(MatrixAccessObject *self) 02539 { 02540 /* Try get values from a collection */ 02541 PyObject *ret; 02542 PyObject *iter = NULL; 02543 ret = MatrixAccess_slice(self, 0, MATRIX_MAX_DIM); 02544 02545 /* we know this is a tuple so no need to PyIter_Check 02546 * otherwise it could be NULL (unlikely) if conversion failed */ 02547 if (ret) { 02548 iter = PyObject_GetIter(ret); 02549 Py_DECREF(ret); 02550 } 02551 02552 return iter; 02553 } 02554 02555 static PyMappingMethods MatrixAccess_AsMapping = { 02556 (lenfunc)MatrixAccess_len, 02557 (binaryfunc)MatrixAccess_subscript, 02558 (objobjargproc) MatrixAccess_ass_subscript 02559 }; 02560 02561 PyTypeObject matrix_access_Type = { 02562 PyVarObject_HEAD_INIT(NULL, 0) 02563 "MatrixAccess", /*tp_name*/ 02564 sizeof(MatrixAccessObject), /*tp_basicsize*/ 02565 0, /*tp_itemsize*/ 02566 (destructor)MatrixAccess_dealloc, /*tp_dealloc*/ 02567 NULL, /*tp_print*/ 02568 NULL, /*tp_getattr*/ 02569 NULL, /*tp_setattr*/ 02570 NULL, /*tp_compare*/ 02571 NULL, /*tp_repr*/ 02572 NULL, /*tp_as_number*/ 02573 NULL /*&MatrixAccess_SeqMethods*/ /* TODO */, /*tp_as_sequence*/ 02574 &MatrixAccess_AsMapping, /*tp_as_mapping*/ 02575 NULL, /*tp_hash*/ 02576 NULL, /*tp_call*/ 02577 NULL, /*tp_str*/ 02578 NULL, /*tp_getattro*/ 02579 NULL, /*tp_setattro*/ 02580 NULL, /*tp_as_buffer*/ 02581 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ 02582 NULL, /*tp_doc*/ 02583 (traverseproc)MatrixAccess_traverse, //tp_traverse 02584 (inquiry)MatrixAccess_clear, //tp_clear 02585 NULL /* (richcmpfunc)MatrixAccess_richcmpr */ /* TODO*/, /*tp_richcompare*/ 02586 0, /*tp_weaklistoffset*/ 02587 (getiterfunc)MatrixAccess_iter, /* getiterfunc tp_iter; */ 02588 }; 02589 02590 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type) 02591 { 02592 MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject, &matrix_access_Type); 02593 02594 matrix_access->matrix_user = matrix; 02595 Py_INCREF(matrix); 02596 02597 matrix_access->type = type; 02598 02599 return (PyObject *)matrix_access; 02600 } 02601 02602 /* end special access 02603 * -------------------------------------------------------------------------- */