Rename python mathutils functions and split in-place methods from those that return...
authorCampbell Barton <ideasman42@gmail.com>
Sat, 5 Feb 2011 06:14:50 +0000 (06:14 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 5 Feb 2011 06:14:50 +0000 (06:14 +0000)
http://wiki.blender.org/index.php/Dev:2.5/Source/Python/Mathutils
This completes the changes proposed.

This will break scripts (fixing coming up next), for full list of changes see mathutils.c comments.

source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/intern/math_vector.c
source/blender/python/generic/mathutils.c
source/blender/python/generic/mathutils_euler.c
source/blender/python/generic/mathutils_matrix.c
source/blender/python/generic/mathutils_quat.c
source/blender/python/generic/mathutils_vector.c

index 4d8a4f2bbafa774efe01a713be57d65dfeaba769..d6d9c0a1c2292c76e1a2461ae879f76b7d150e8a 100644 (file)
@@ -173,6 +173,8 @@ void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]);
 /***************************** Array Functions *******************************/
 /* attempted to follow fixed length vertex functions. names could be improved*/
 void range_vni(int *array, const int size, const int start);
+void negate_vn(float *array_tar, const int size);
+void negate_vn_vn(float *array_tar, const float *array_src, const int size);
 void mul_vn_fl(float *array, const int size, const float f);
 void mul_vn_vn_fl(float *array_tar, const float *array_src, const int size, const float f);
 void add_vn_vn(float *array_tar, const float *array_src, const int size);
index 37a68cb0fca65bb3e4aaaf24d40e0f4906df3c92..bcad7894e860e1fdbaca8734879d0b6cc9b202d1 100644 (file)
@@ -375,6 +375,21 @@ void range_vni(int *array_tar, const int size, const int start)
        while(i--) { *(array_pt--) = j--; }
 }
 
+void negate_vn(float *array_tar, const int size)
+{
+       float *array_pt= array_tar + (size-1);
+       int i= size;
+       while(i--) { *(array_pt--) *= -1.0f; }
+}
+
+void negate_vn_vn(float *array_tar, const float *array_src, const int size)
+{
+       float *tar= array_tar + (size-1);
+       const float *src= array_src + (size-1);
+       int i= size;
+       while(i--) { *(tar--) = - *(src--); }
+}
+
 void mul_vn_fl(float *array_tar, const int size, const float f)
 {
        float *array_pt= array_tar + (size-1);
index 49cd5d2f53e4947adc48e3c25e85f08eb8f0596c..25b1e458ae8ce29735cc3a5c361294304268653c 100644 (file)
  * - Quaternion * Quaternion --> cross product (not dot product)
  * - Euler.rotate(angle, axis) --> Euler.rotate_axis(axis, angle)
  * - Euler.unique() *removed*, not a standard function only toggled different rotations.
- *
+ * - Matrix.rotation_part() -> to_3x3()
+ * - Matrix.scale_part() -> to_scale()
+ * - Matrix.translation_part() -> to_translation()
+ * - Matrix.resize4x4() -> resize_4x4()
+ * - Euler.to_quat() -> to_quaternion()
+ * - Matrix.to_quat() -> to_quaternion()
+ * resizing nolonger returns the resized value.
+ * - Vector.resize2D -> resize_2d
+ * - Vector.resize3D -> resize_3d
+ * - Vector.resize4D -> resize_4d
+ * added new functions.
+ * - Vector.to_2d()
+ * - Vector.to_3d()
+ * - Vector.to_4d()
  * moved into class functions.
  * - Mathutils.RotationMatrix -> mathutils.Matrix.Rotation
  * - Mathutils.ScaleMatrix -> mathutils.Matrix.Scale
index 0294cfd72e9cc86bae00304d0decc2f3695e1b1c..8f6d7e8a182f545770abaa92dbe81a7bcffdc049 100644 (file)
@@ -146,7 +146,7 @@ static char Euler_to_matrix_doc[] =
 ;
 static PyObject *Euler_to_matrix(EulerObject * self)
 {
-       float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+       float mat[9];
 
        if(!BaseMath_ReadCallback(self))
                return NULL;
@@ -162,19 +162,13 @@ static char Euler_zero_doc[] =
 ".. method:: zero()\n"
 "\n"
 "   Set all values to zero.\n"
-"\n"
-"   :return: an instance of itself\n"
-"   :rtype: :class:`Euler`\n"
 ;
 static PyObject *Euler_zero(EulerObject * self)
 {
-       self->eul[0] = 0.0;
-       self->eul[1] = 0.0;
-       self->eul[2] = 0.0;
+       zero_v3(self->eul);
 
        (void)BaseMath_WriteCallback(self);
-       Py_INCREF(self);
-       return (PyObject *)self;
+       Py_RETURN_NONE;
 }
 
 static char Euler_rotate_axis_doc[] =
@@ -568,7 +562,7 @@ static PyGetSetDef Euler_getseters[] = {
 static struct PyMethodDef Euler_methods[] = {
        {"zero", (PyCFunction) Euler_zero, METH_NOARGS, Euler_zero_doc},
        {"to_matrix", (PyCFunction) Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc},
-       {"to_quat", (PyCFunction) Euler_to_quaternion, METH_NOARGS, Euler_to_quaternion_doc},
+       {"to_quaternion", (PyCFunction) Euler_to_quaternion, METH_NOARGS, Euler_to_quaternion_doc},
        {"rotate_axis", (PyCFunction) Euler_rotate_axis, METH_VARARGS, Euler_rotate_axis_doc},
        {"make_compatible", (PyCFunction) Euler_make_compatible, METH_O, Euler_make_compatible_doc},
        {"__copy__", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc},
index 1cec0536cc87f24f641292fa4b07353bba76439c..8f8d3267cc6e74895779ab22ca26ce84b03308ea 100644 (file)
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
 
+#define MATRIX_APPLY_TO_COPY(matrix_meth_noargs, _self) \
+       MatrixObject *ret= (MatrixObject *)Matrix_copy(_self); \
+       PyObject *ret_dummy= matrix_meth_noargs(ret); \
+       if(ret_dummy) { \
+               Py_DECREF(ret_dummy); \
+               return (PyObject *)ret; \
+       } \
+       else { /* error */ \
+               Py_DECREF(ret); \
+               return NULL; \
+       } \
+
+
+static PyObject *Matrix_copy(MatrixObject *self);
+
 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value);
 
 /* matrix vector callbacks */
@@ -661,7 +676,7 @@ static char Matrix_to_euler_doc[] =
 "   :return: Euler representation of the matrix.\n"
 "   :rtype: :class:`Euler`\n"
 ;
-PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
+static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
 {
        const char *order_str= NULL;
        short order= EULER_ORDER_XYZ;
@@ -713,16 +728,16 @@ PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
 
        return newEulerObject(eul, order, Py_NEW, NULL);
 }
-/*---------------------------Matrix.resize4x4() ------------------*/
-static char Matrix_resize4x4_doc[] =
-".. method:: resize4x4()\n"
+
+static char Matrix_resize_4x4_doc[] =
+".. method:: resize_4x4()\n"
 "\n"
 "   Resize the matrix to 4x4.\n"
 "\n"
 "   :return: an instance of itself.\n"
 "   :rtype: :class:`Matrix`\n"
 ;
-PyObject *Matrix_resize4x4(MatrixObject *self)
+static PyObject *Matrix_resize_4x4(MatrixObject *self)
 {
        int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index;
 
@@ -737,7 +752,7 @@ PyObject *Matrix_resize4x4(MatrixObject *self)
 
        self->contigPtr = PyMem_Realloc(self->contigPtr, (sizeof(float) * 16));
        if(self->contigPtr == NULL) {
-               PyErr_SetString(PyExc_MemoryError, "matrix.resize4x4(): problem allocating pointer space");
+               PyErr_SetString(PyExc_MemoryError, "matrix.resize_4x4(): problem allocating pointer space");
                return NULL;
        }
        /*set row pointers*/
@@ -782,7 +797,7 @@ static char Matrix_to_4x4_doc[] =
 "   :return: a new matrix.\n"
 "   :rtype: :class:`Matrix`\n"
 ;
-PyObject *Matrix_to_4x4(MatrixObject *self)
+static PyObject *Matrix_to_4x4(MatrixObject *self)
 {
        if(!BaseMath_ReadCallback(self))
                return NULL;
@@ -809,7 +824,7 @@ static char Matrix_to_3x3_doc[] =
 "   :return: a new matrix.\n"
 "   :rtype: :class:`Matrix`\n"
 ;
-PyObject *Matrix_to_3x3(MatrixObject *self)
+static PyObject *Matrix_to_3x3(MatrixObject *self)
 {
        float mat[3][3];
 
@@ -826,57 +841,29 @@ PyObject *Matrix_to_3x3(MatrixObject *self)
        return newMatrixObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
 }
 
-/*---------------------------Matrix.translationPart() ------------*/
-static char Matrix_translation_part_doc[] =
-".. method:: translation_part()\n"
+static char Matrix_to_translation_doc[] =
+".. method:: to_translation()\n"
 "\n"
 "   Return a the translation part of a 4 row matrix.\n"
 "\n"
 "   :return: Return a the translation of a matrix.\n"
 "   :rtype: :class:`Vector`\n"
 ;
-PyObject *Matrix_translation_part(MatrixObject *self)
+static PyObject *Matrix_to_translation(MatrixObject *self)
 {
        if(!BaseMath_ReadCallback(self))
                return NULL;
 
        if((self->colSize < 3) || self->rowSize < 4){
-               PyErr_SetString(PyExc_AttributeError, "Matrix.translation_part(): inappropriate matrix size");
+               PyErr_SetString(PyExc_AttributeError, "Matrix.to_translation(): inappropriate matrix size");
                return NULL;
        }
 
        return newVectorObject(self->matrix[3], 3, Py_NEW, NULL);
 }
-/*---------------------------Matrix.rotationPart() ---------------*/
-static char Matrix_rotation_part_doc[] =
-".. method:: rotation_part()\n"
-"\n"
-"   Return the 3d submatrix corresponding to the linear term of the embedded affine transformation in 3d. This matrix represents rotation and scale.\n"
-"\n"
-"   :return: Return the 3d matrix for rotation and scale.\n"
-"   :rtype: :class:`Matrix`\n"
-"\n"
-"   .. note:: Note that the (4,4) element of a matrix can be used for uniform scaling too.\n"
-;
-PyObject *Matrix_rotation_part(MatrixObject *self)
-{
-       float mat[3][3];
-
-       if(!BaseMath_ReadCallback(self))
-               return NULL;
-
-       if((self->colSize < 3) || (self->rowSize < 3)) {
-               PyErr_SetString(PyExc_AttributeError, "Matrix.rotation_part(): inappropriate matrix size");
-               return NULL;
-       }
-
-       matrix_as_3x3(mat, self);
 
-       return newMatrixObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
-}
-/*---------------------------Matrix.scalePart() --------------------*/
-static char Matrix_scale_part_doc[] =
-".. method:: scale_part()\n"
+static char Matrix_to_scale_doc[] =
+".. method:: to_scale()\n"
 "\n"
 "   Return a the scale part of a 3x3 or 4x4 matrix.\n"
 "\n"
@@ -885,7 +872,7 @@ static char Matrix_scale_part_doc[] =
 "\n"
 "   .. 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"
 ;
-PyObject *Matrix_scale_part(MatrixObject *self)
+static PyObject *Matrix_to_scale(MatrixObject *self)
 {
        float rot[3][3];
        float mat[3][3];
@@ -896,7 +883,7 @@ PyObject *Matrix_scale_part(MatrixObject *self)
 
        /*must be 3-4 cols, 3-4 rows, square matrix*/
        if((self->colSize < 3) || (self->rowSize < 3)) {
-               PyErr_SetString(PyExc_AttributeError, "Matrix.scale_part(): inappropriate matrix size, 3x3 minimum size");
+               PyErr_SetString(PyExc_AttributeError, "Matrix.to_scale(): inappropriate matrix size, 3x3 minimum size");
                return NULL;
        }
 
@@ -921,7 +908,7 @@ static char Matrix_invert_doc[] =
 "\n"
 "   .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
 ;
-PyObject *Matrix_invert(MatrixObject *self)
+static PyObject *Matrix_invert(MatrixObject *self)
 {
 
        int x, y, z = 0;
@@ -971,8 +958,22 @@ PyObject *Matrix_invert(MatrixObject *self)
        }
 
        (void)BaseMath_WriteCallback(self);
-       Py_INCREF(self);
-       return (PyObject *)self;
+       Py_RETURN_NONE;
+}
+
+static char Matrix_inverted_doc[] =
+".. method:: invert()\n"
+"\n"
+"   Return an inverted copy of the matrix.\n"
+"\n"
+"   :return: the  inverted matrix.\n"
+"   :rtype: :class:`Matrix`\n"
+"\n"
+"   .. note:: :exc:`ValueError` exception is raised.\n"
+;
+static PyObject *Matrix_inverted(MatrixObject *self)
+{
+       MATRIX_APPLY_TO_COPY(Matrix_invert, self);
 }
 
 /*---------------------------Matrix.decompose() ---------------------*/
@@ -1067,7 +1068,7 @@ static char Matrix_determinant_doc[] =
 "\n"
 "   .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
 ;
-PyObject *Matrix_determinant(MatrixObject *self)
+static PyObject *Matrix_determinant(MatrixObject *self)
 {
        if(!BaseMath_ReadCallback(self))
                return NULL;
@@ -1085,12 +1086,9 @@ static char Matrix_transpose_doc[] =
 "\n"
 "   Set the matrix to its transpose.\n"
 "\n"
-"   :return: an instance of itself\n"
-"   :rtype: :class:`Matrix`\n"
-"\n"
 "   .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"
 ;
-PyObject *Matrix_transpose(MatrixObject *self)
+static PyObject *Matrix_transpose(MatrixObject *self)
 {
        float t = 0.0f;
 
@@ -1113,10 +1111,21 @@ PyObject *Matrix_transpose(MatrixObject *self)
        }
 
        (void)BaseMath_WriteCallback(self);
-       Py_INCREF(self);
-       return (PyObject *)self;
+       Py_RETURN_NONE;
 }
 
+static char Matrix_transposed_doc[] =
+".. method:: transposed()\n"
+"\n"
+"   Return a new, transposed matrix.\n"
+"\n"
+"   :return: a transposed matrix\n"
+"   :rtype: :class:`Matrix`\n"
+;
+static PyObject *Matrix_transposed(MatrixObject *self)
+{
+       MATRIX_APPLY_TO_COPY(Matrix_transpose, self);
+}
 
 /*---------------------------Matrix.zero() -----------------------*/
 static char Matrix_zero_doc[] =
@@ -1127,21 +1136,14 @@ static char Matrix_zero_doc[] =
 "   :return: an instance of itself\n"
 "   :rtype: :class:`Matrix`\n"
 ;
-PyObject *Matrix_zero(MatrixObject *self)
+static PyObject *Matrix_zero(MatrixObject *self)
 {
-       int row, col;
-
-       for(row = 0; row < self->rowSize; row++) {
-               for(col = 0; col < self->colSize; col++) {
-                       self->matrix[row][col] = 0.0f;
-               }
-       }
+       fill_vn(self->contigPtr, self->rowSize * self->colSize, 0.0f);
 
        if(!BaseMath_WriteCallback(self))
                return NULL;
 
-       Py_INCREF(self);
-       return (PyObject *)self;
+       Py_RETURN_NONE;
 }
 /*---------------------------Matrix.identity(() ------------------*/
 static char Matrix_identity_doc[] =
@@ -1149,14 +1151,11 @@ static char Matrix_identity_doc[] =
 "\n"
 "   Set the matrix to the identity matrix.\n"
 "\n"
-"   :return: an instance of itself\n"
-"   :rtype: :class:`Matrix`\n"
-"\n"
 "   .. note:: An object with zero location and rotation, a scale of one, will have an identity matrix.\n"
 "\n"
 "   .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"
 ;
-PyObject *Matrix_identity(MatrixObject *self)
+static PyObject *Matrix_identity(MatrixObject *self)
 {
        if(!BaseMath_ReadCallback(self))
                return NULL;
@@ -1180,8 +1179,7 @@ PyObject *Matrix_identity(MatrixObject *self)
        if(!BaseMath_WriteCallback(self))
                return NULL;
 
-       Py_INCREF(self);
-       return (PyObject *)self;
+       Py_RETURN_NONE;
 }
 
 /*---------------------------Matrix.copy() ------------------*/
@@ -1193,7 +1191,7 @@ static char Matrix_copy_doc[] =
 "   :return: an instance of itself\n"
 "   :rtype: :class:`Matrix`\n"
 ;
-PyObject *Matrix_copy(MatrixObject *self)
+static PyObject *Matrix_copy(MatrixObject *self)
 {
        if(!BaseMath_ReadCallback(self))
                return NULL;
@@ -1718,21 +1716,32 @@ static PyGetSetDef Matrix_getseters[] = {
 
 /*-----------------------METHOD DEFINITIONS ----------------------*/
 static struct PyMethodDef Matrix_methods[] = {
+       /* derived values */
+       {"determinant", (PyCFunction) Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
+       {"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
+
+       /* in place only */
        {"zero", (PyCFunction) Matrix_zero, METH_NOARGS, Matrix_zero_doc},
        {"identity", (PyCFunction) Matrix_identity, METH_NOARGS, Matrix_identity_doc},
+
+       /* operate on original or copy */
        {"transpose", (PyCFunction) Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
-       {"lerp", (PyCFunction) Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
-       {"determinant", (PyCFunction) Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
+       {"transposed", (PyCFunction) Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
        {"invert", (PyCFunction) Matrix_invert, METH_NOARGS, Matrix_invert_doc},
-       {"translation_part", (PyCFunction) Matrix_translation_part, METH_NOARGS, Matrix_translation_part_doc},
-       {"rotation_part", (PyCFunction) Matrix_rotation_part, METH_NOARGS, Matrix_rotation_part_doc},
-       {"scale_part", (PyCFunction) Matrix_scale_part, METH_NOARGS, Matrix_scale_part_doc},
-       {"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
-       {"resize4x4", (PyCFunction) Matrix_resize4x4, METH_NOARGS, Matrix_resize4x4_doc},
-       {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
+       {"inverted", (PyCFunction) Matrix_inverted, METH_NOARGS, Matrix_inverted_doc},
        {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
+       // TODO. {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc},
+       {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
+       {"resize_4x4", (PyCFunction) Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
+
+       /* return converted representation */
        {"to_euler", (PyCFunction) Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
-       {"to_quat", (PyCFunction) Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc},
+       {"to_quaternion", (PyCFunction) Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc},
+       {"to_scale", (PyCFunction) Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
+       {"to_translation", (PyCFunction) Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc},
+
+       /* operation between 2 or more types  */
+       {"lerp", (PyCFunction) Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
        {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
        {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
 
@@ -1860,8 +1869,8 @@ PyObject *newMatrixObject(float *mat, const unsigned short rowSize, const unsign
                                }
                        }
                } else if (rowSize == colSize ) { /*or if no arguments are passed return identity matrix for square matrices */
-                       Matrix_identity(self);
-                       Py_DECREF(self);
+                       PyObject *ret_dummy= Matrix_identity(self);
+                       Py_DECREF(ret_dummy);
                }
                self->wrapped = Py_NEW;
        }else{ /*bad type*/
index 1b571742cda0545d82c5aa403eb3e42f8dcdfb5a..c7d4fd186a424f2f5fbe52cea8e84c16ca3dc5e1 100644 (file)
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
 
+#define QUAT_SIZE 4
 
+#define QUAT_APPLY_TO_COPY(quat_meth_noargs, _self) \
+       QuaternionObject *ret= (QuaternionObject *)Quaternion_copy(_self); \
+       PyObject *ret_dummy= quat_meth_noargs(ret); \
+       if(ret_dummy) { \
+               Py_DECREF(ret_dummy); \
+               return (PyObject *)ret; \
+       } \
+       else { /* error */ \
+               Py_DECREF(ret); \
+               return NULL; \
+       } \
 
-#define QUAT_SIZE 4
+static PyObject *Quaternion_copy(QuaternionObject *self);
 
 //-----------------------------METHODS------------------------------
 
@@ -250,9 +262,6 @@ static char Quaternion_normalize_doc[] =
 ".. function:: normalize()\n"
 "\n"
 "   Normalize the quaternion.\n"
-"\n"
-"   :return: an instance of itself.\n"
-"   :rtype: :class:`Quaternion`\n"
 ;
 static PyObject *Quaternion_normalize(QuaternionObject *self)
 {
@@ -262,19 +271,28 @@ static PyObject *Quaternion_normalize(QuaternionObject *self)
        normalize_qt(self->quat);
 
        (void)BaseMath_WriteCallback(self);
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
 }
-//----------------------------Quaternion.inverse()------------------
-static char Quaternion_inverse_doc[] =
-".. function:: inverse()\n"
+static char Quaternion_normalized_doc[] =
+".. function:: normalized()\n"
 "\n"
-"   Set the quaternion to its inverse.\n"
+"   Return a new normalized quaternion.\n"
 "\n"
-"   :return: an instance of itself.\n"
+"   :return: a normalized copy.\n"
 "   :rtype: :class:`Quaternion`\n"
 ;
-static PyObject *Quaternion_inverse(QuaternionObject *self)
+static PyObject *Quaternion_normalized(QuaternionObject *self)
+{
+       QUAT_APPLY_TO_COPY(Quaternion_normalize, self);
+}
+
+//----------------------------Quaternion.invert()------------------
+static char Quaternion_invert_doc[] =
+".. function:: invert()\n"
+"\n"
+"   Set the quaternion to its inverse.\n"
+;
+static PyObject *Quaternion_invert(QuaternionObject *self)
 {
        if(!BaseMath_ReadCallback(self))
                return NULL;
@@ -282,9 +300,21 @@ static PyObject *Quaternion_inverse(QuaternionObject *self)
        invert_qt(self->quat);
 
        (void)BaseMath_WriteCallback(self);
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
+}
+static char Quaternion_inverted_doc[] =
+".. function:: inverted()\n"
+"\n"
+"   Return a new, inverted quaternion.\n"
+"\n"
+"   :return: the inverted value.\n"
+"   :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_inverted(QuaternionObject *self)
+{
+       QUAT_APPLY_TO_COPY(Quaternion_invert, self);
 }
+
 //----------------------------Quaternion.identity()-----------------
 static char Quaternion_identity_doc[] =
 ".. function:: identity()\n"
@@ -302,8 +332,7 @@ static PyObject *Quaternion_identity(QuaternionObject *self)
        unit_qt(self->quat);
 
        (void)BaseMath_WriteCallback(self);
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
 }
 //----------------------------Quaternion.negate()-------------------
 static char Quaternion_negate_doc[] =
@@ -322,17 +351,13 @@ static PyObject *Quaternion_negate(QuaternionObject *self)
        mul_qt_fl(self->quat, -1.0f);
 
        (void)BaseMath_WriteCallback(self);
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
 }
 //----------------------------Quaternion.conjugate()----------------
 static char Quaternion_conjugate_doc[] =
 ".. function:: conjugate()\n"
 "\n"
 "   Set the quaternion to its conjugate (negate x, y, z).\n"
-"\n"
-"   :return: an instance of itself.\n"
-"   :rtype: :class:`Quaternion`\n"
 ;
 static PyObject *Quaternion_conjugate(QuaternionObject *self)
 {
@@ -342,9 +367,21 @@ static PyObject *Quaternion_conjugate(QuaternionObject *self)
        conjugate_qt(self->quat);
 
        (void)BaseMath_WriteCallback(self);
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
+}
+static char Quaternion_conjugated_doc[] =
+".. function:: conjugated()\n"
+"\n"
+"   Return a new conjugated quaternion.\n"
+"\n"
+"   :return: a new quaternion.\n"
+"   :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_conjugated(QuaternionObject *self)
+{
+       QUAT_APPLY_TO_COPY(Quaternion_conjugate, self);
 }
+
 //----------------------------Quaternion.copy()----------------
 static char Quaternion_copy_doc[] =
 ".. function:: copy()\n"
@@ -902,17 +939,30 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
 
 //-----------------------METHOD DEFINITIONS ----------------------
 static struct PyMethodDef Quaternion_methods[] = {
+       /* in place only */
        {"identity", (PyCFunction) Quaternion_identity, METH_NOARGS, Quaternion_identity_doc},
        {"negate", (PyCFunction) Quaternion_negate, METH_NOARGS, Quaternion_negate_doc},
+
+       /* operate on original or copy */
        {"conjugate", (PyCFunction) Quaternion_conjugate, METH_NOARGS, Quaternion_conjugate_doc},
-       {"inverse", (PyCFunction) Quaternion_inverse, METH_NOARGS, Quaternion_inverse_doc},
+       {"conjugated", (PyCFunction) Quaternion_conjugated, METH_NOARGS, Quaternion_conjugated_doc},
+
+       {"invert", (PyCFunction) Quaternion_invert, METH_NOARGS, Quaternion_invert_doc},
+       {"inverted", (PyCFunction) Quaternion_inverted, METH_NOARGS, Quaternion_inverted_doc},
+
        {"normalize", (PyCFunction) Quaternion_normalize, METH_NOARGS, Quaternion_normalize_doc},
+       {"normalized", (PyCFunction) Quaternion_normalized, METH_NOARGS, Quaternion_normalized_doc},
+
+       /* return converted representation */
        {"to_euler", (PyCFunction) Quaternion_to_euler, METH_VARARGS, Quaternion_to_euler_doc},
        {"to_matrix", (PyCFunction) Quaternion_to_matrix, METH_NOARGS, Quaternion_to_matrix_doc},
+
+       /* operation between 2 or more types  */
        {"cross", (PyCFunction) Quaternion_cross, METH_O, Quaternion_cross_doc},
        {"dot", (PyCFunction) Quaternion_dot, METH_O, Quaternion_dot_doc},
        {"difference", (PyCFunction) Quaternion_difference, METH_O, Quaternion_difference_doc},
        {"slerp", (PyCFunction) Quaternion_slerp, METH_VARARGS, Quaternion_slerp_doc},
+
        {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
        {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
        {NULL, NULL, 0, NULL}
index ba5cf4bb317b2db50db225b2a9e0f502f1557567..c39d42e31df848cbdef1bf6bb28ae43af5a5197b 100644 (file)
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
 
+#define MAX_DIMENSIONS 4
 
+#define VEC_APPLY_TO_COPY(vec_meth_noargs, _self) \
+       VectorObject *ret= (VectorObject *)Vector_copy(_self); \
+       PyObject *ret_dummy= vec_meth_noargs(ret); \
+       if(ret_dummy) { \
+               Py_DECREF(ret_dummy); \
+               return (PyObject *)ret; \
+       } \
+       else { /* error */ \
+               Py_DECREF(ret); \
+               return NULL; \
+       } \
 
-#define MAX_DIMENSIONS 4
 /* Swizzle axes get packed into a single value that is used as a closure. Each
    axis uses SWIZZLE_BITS_PER_AXIS bits. The first bit (SWIZZLE_VALID_AXIS) is
    used as a sentinel: if it is unset, the axis is not valid. */
 #define SWIZZLE_VALID_AXIS 0x4
 #define SWIZZLE_AXIS       0x3
 
+static PyObject *Vector_copy(VectorObject *self);
 static PyObject *Vector_to_tuple_ext(VectorObject *self, int ndigits);
 
-//----------------------------------mathutils.Vector() ------------------
-// Supports 2D, 3D, and 4D vector objects both int and float values
-// accepted. Mixed float and int values accepted. Ints are parsed to float 
+/* Supports 2D, 3D, and 4D vector objects both int and float values
+ * accepted. Mixed float and int values accepted. Ints are parsed to float
+ */
 static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *UNUSED(kwds))
 {
        float vec[4]= {0.0f, 0.0f, 0.0f, 0.0f};
@@ -70,27 +82,20 @@ static char Vector_zero_doc[] =
 ".. method:: zero()\n"
 "\n"
 "   Set all values to zero.\n"
-"\n"
-"   :return: an instance of itself\n"
-"   :rtype: :class:`Vector`\n"
 ;
 static PyObject *Vector_zero(VectorObject *self)
 {
        fill_vn(self->vec, self->size, 0.0f);
 
        (void)BaseMath_WriteCallback(self);
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
 }
-/*----------------------------Vector.normalize() ----------------- */
+
 static char Vector_normalize_doc[] =
 ".. method:: normalize()\n"
 "\n"
 "   Normalize the vector, making the length of the vector always 1.0.\n"
 "\n"
-"   :return: an instance of itself\n"
-"   :rtype: :class:`Vector`\n"
-"\n"
 "   .. warning:: Normalizing a vector where all values are zero results in all axis having a nan value (not a number).\n"
 "\n"
 "   .. note:: Normalize works for vectors of all sizes, however 4D Vectors w axis is left untouched.\n"
@@ -112,64 +117,72 @@ static PyObject *Vector_normalize(VectorObject *self)
        }
        
        (void)BaseMath_WriteCallback(self);
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
+}
+static char Vector_normalized_doc[] =
+".. method:: normalized()\n"
+"\n"
+"   Return a new, normalized vector.\n"
+"\n"
+"   :return: a normalized copy of the vector\n"
+"   :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_normalized(VectorObject *self)
+{
+       VEC_APPLY_TO_COPY(Vector_normalize, self);
 }
 
-
-/*----------------------------Vector.resize2D() ------------------ */
-static char Vector_resize2D_doc[] =
-".. method:: resize2D()\n"
+static char Vector_resize_2d_doc[] =
+".. method:: resize_2d()\n"
 "\n"
 "   Resize the vector to 2D  (x, y).\n"
 "\n"
 "   :return: an instance of itself\n"
 "   :rtype: :class:`Vector`\n"
 ;
-static PyObject *Vector_resize2D(VectorObject *self)
+static PyObject *Vector_resize_2d(VectorObject *self)
 {
        if(self->wrapped==Py_WRAP) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize2D(): cannot resize wrapped data - only python vectors");
+               PyErr_SetString(PyExc_TypeError, "vector.resize_2d(): cannot resize wrapped data - only python vectors");
                return NULL;
        }
        if(self->cb_user) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize2D(): cannot resize a vector that has an owner");
+               PyErr_SetString(PyExc_TypeError, "vector.resize_2d(): cannot resize a vector that has an owner");
                return NULL;
        }
        
        self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 2));
        if(self->vec == NULL) {
-               PyErr_SetString(PyExc_MemoryError, "vector.resize2D(): problem allocating pointer space");
+               PyErr_SetString(PyExc_MemoryError, "vector.resize_2d(): problem allocating pointer space");
                return NULL;
        }
        
        self->size = 2;
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
 }
-/*----------------------------Vector.resize3D() ------------------ */
-static char Vector_resize3D_doc[] =
-".. method:: resize3D()\n"
+
+static char Vector_resize_3d_doc[] =
+".. method:: resize_3d()\n"
 "\n"
 "   Resize the vector to 3D  (x, y, z).\n"
 "\n"
 "   :return: an instance of itself\n"
 "   :rtype: :class:`Vector`\n"
 ;
-static PyObject *Vector_resize3D(VectorObject *self)
+static PyObject *Vector_resize_3d(VectorObject *self)
 {
        if (self->wrapped==Py_WRAP) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize3D(): cannot resize wrapped data - only python vectors");
+               PyErr_SetString(PyExc_TypeError, "vector.resize_3d(): cannot resize wrapped data - only python vectors");
                return NULL;
        }
        if(self->cb_user) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize3D(): cannot resize a vector that has an owner");
+               PyErr_SetString(PyExc_TypeError, "vector.resize_3d(): cannot resize a vector that has an owner");
                return NULL;
        }
        
        self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 3));
        if(self->vec == NULL) {
-               PyErr_SetString(PyExc_MemoryError, "vector.resize3D(): problem allocating pointer space");
+               PyErr_SetString(PyExc_MemoryError, "vector.resize_3d(): problem allocating pointer space");
                return NULL;
        }
        
@@ -177,32 +190,31 @@ static PyObject *Vector_resize3D(VectorObject *self)
                self->vec[2] = 0.0f;
        
        self->size = 3;
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
 }
-/*----------------------------Vector.resize4D() ------------------ */
-static char Vector_resize4D_doc[] =
-".. method:: resize4D()\n"
+
+static char Vector_resize_4d_doc[] =
+".. method:: resize_4d()\n"
 "\n"
 "   Resize the vector to 4D (x, y, z, w).\n"
 "\n"
 "   :return: an instance of itself\n"
 "   :rtype: :class:`Vector`\n"
 ;
-static PyObject *Vector_resize4D(VectorObject *self)
+static PyObject *Vector_resize_4d(VectorObject *self)
 {
        if(self->wrapped==Py_WRAP) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize4D(): cannot resize wrapped data - only python vectors");
+               PyErr_SetString(PyExc_TypeError, "vector.resize_4d(): cannot resize wrapped data - only python vectors");
                return NULL;
        }
        if(self->cb_user) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize4D(): cannot resize a vector that has an owner");
+               PyErr_SetString(PyExc_TypeError, "vector.resize_4d(): cannot resize a vector that has an owner");
                return NULL;
        }
        
        self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 4));
        if(self->vec == NULL) {
-               PyErr_SetString(PyExc_MemoryError, "vector.resize4D(): problem allocating pointer space");
+               PyErr_SetString(PyExc_MemoryError, "vector.resize_4d(): problem allocating pointer space");
                return NULL;
        }
        if(self->size == 2){
@@ -212,11 +224,60 @@ static PyObject *Vector_resize4D(VectorObject *self)
                self->vec[3] = 1.0f;
        }
        self->size = 4;
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
+}
+static char Vector_to_2d_doc[] =
+".. method:: to_2d()\n"
+"\n"
+"   Return a 2d copy of the vector.\n"
+"\n"
+"   :return: a new vector\n"
+"   :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_to_2d(VectorObject *self)
+{
+       if(!BaseMath_ReadCallback(self))
+               return NULL;
+
+       return newVectorObject(self->vec, 2, Py_NEW, Py_TYPE(self));
+}
+static char Vector_to_3d_doc[] =
+".. method:: to_3d()\n"
+"\n"
+"   Return a 3d copy of the vector.\n"
+"\n"
+"   :return: a new vector\n"
+"   :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_to_3d(VectorObject *self)
+{
+       float tvec[3]= {0.0f};
+
+       if(!BaseMath_ReadCallback(self))
+               return NULL;
+
+       memcpy(tvec, self->vec, sizeof(float) * MIN2(self->size, 3));
+       return newVectorObject(tvec, 3, Py_NEW, Py_TYPE(self));
+}
+static char Vector_to_4d_doc[] =
+".. method:: to_4d()\n"
+"\n"
+"   Return a 4d copy of the vector.\n"
+"\n"
+"   :return: a new vector\n"
+"   :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_to_4d(VectorObject *self)
+{
+       float tvec[4]= {0.0f, 0.0f, 0.0f, 1.0f};
+
+       if(!BaseMath_ReadCallback(self))
+               return NULL;
+
+       memcpy(tvec, self->vec, sizeof(float) * MIN2(self->size, 4));
+       return newVectorObject(tvec, 4, Py_NEW, Py_TYPE(self));
 }
 
-/*----------------------------Vector.toTuple() ------------------ */
 static char Vector_to_tuple_doc[] =
 ".. method:: to_tuple(precision=-1)\n"
 "\n"
@@ -270,7 +331,6 @@ static PyObject *Vector_to_tuple(VectorObject *self, PyObject *args)
        return Vector_to_tuple_ext(self, ndigits);
 }
 
-/*----------------------------Vector.toTrackQuat(track, up) ---------------------- */
 static char Vector_to_track_quat_doc[] =
 ".. method:: to_track_quat(track, up)\n"
 "\n"
@@ -385,10 +445,10 @@ static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args )
        return newQuaternionObject(quat, Py_NEW, NULL);
 }
 
-/*----------------------------Vector.reflect(mirror) ----------------------
-  return a reflected vector on the mirror normal
-   vec - ((2 * DotVecs(vec, mirror)) * mirror)
-*/
+/*
* Vector.reflect(mirror): return a reflected vector on the mirror normal
*  vec - ((2 * DotVecs(vec, mirror)) * mirror)
+ */
 static char Vector_reflect_doc[] =
 ".. method:: reflect(mirror)\n"
 "\n"
@@ -654,7 +714,6 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args)
        return newVectorObject(vec, size, Py_NEW, Py_TYPE(self));
 }
 
-/*---------------------------- Vector.rotate(angle, axis) ----------------------*/
 static char Vector_rotate_doc[] =
 ".. function:: rotate(axis, angle)\n"
 "\n"
@@ -696,7 +755,6 @@ static PyObject *Vector_rotate(VectorObject *self, PyObject *args)
        return (PyObject *)self;
 }
 
-/*----------------------------Vector.copy() -------------------------------------- */
 static char Vector_copy_doc[] =
 ".. function:: copy()\n"
 "\n"
@@ -715,8 +773,6 @@ static PyObject *Vector_copy(VectorObject *self)
        return newVectorObject(self->vec, self->size, Py_NEW, Py_TYPE(self));
 }
 
-/*----------------------------print object (internal)-------------
-  print the object to screen */
 static PyObject *Vector_repr(VectorObject *self)
 {
        PyObject *ret, *tuple;
@@ -730,15 +786,13 @@ static PyObject *Vector_repr(VectorObject *self)
        return ret;
 }
 
-/*---------------------SEQUENCE PROTOCOLS------------------------
-  ----------------------------len(object)------------------------
-  sequence length*/
+/* Sequence Protocol */
+/* sequence length len(vector) */
 static int Vector_len(VectorObject *self)
 {
        return self->size;
 }
-/*----------------------------object[]---------------------------
-  sequence accessor (get)*/
+/* sequence accessor (get): vector[index] */
 static PyObject *Vector_item(VectorObject *self, int i)
 {
        if(i<0) i= self->size-i;
@@ -753,8 +807,7 @@ static PyObject *Vector_item(VectorObject *self, int i)
        
        return PyFloat_FromDouble(self->vec[i]);
 }
-/*----------------------------object[]-------------------------
-  sequence accessor (set)*/
+/* sequence accessor (set): vector[index] = value */
 static int Vector_ass_item(VectorObject *self, int i, PyObject * ob)
 {
        float scalar;
@@ -776,8 +829,7 @@ static int Vector_ass_item(VectorObject *self, int i, PyObject * ob)
        return 0;
 }
 
-/*----------------------------object[z:y]------------------------
-  sequence slice (get) */
+/* sequence slice (get): vector[a:b] */
 static PyObject *Vector_slice(VectorObject *self, int begin, int end)
 {
        PyObject *tuple;
@@ -798,8 +850,7 @@ static PyObject *Vector_slice(VectorObject *self, int begin, int end)
 
        return tuple;
 }
-/*----------------------------object[z:y]------------------------
-  sequence slice (set) */
+/* sequence slice (set): vector[a:b] = value */
 static int Vector_ass_slice(VectorObject *self, int begin, int end,
                                 PyObject * seq)
 {
@@ -827,9 +878,9 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end,
 
        return 0;
 }
-/*------------------------NUMERIC PROTOCOLS----------------------
-  ------------------------obj + obj------------------------------
-  addition*/
+
+/* Numeric Protocols */
+/* addition: obj + obj */
 static PyObject *Vector_add(PyObject * v1, PyObject * v2)
 {
        VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -856,8 +907,7 @@ static PyObject *Vector_add(PyObject * v1, PyObject * v2)
        return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
 }
 
-/*  ------------------------obj += obj------------------------------
-  addition in place */
+/* addition in-place: obj += obj */
 static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
 {
        VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -884,8 +934,7 @@ static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
        return v1;
 }
 
-/*------------------------obj - obj------------------------------
-  subtraction*/
+/* subtraction: obj - obj */
 static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
 {
        VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -911,8 +960,7 @@ static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
        return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
 }
 
-/*------------------------obj -= obj------------------------------
-  subtraction*/
+/* subtraction in-place: obj -= obj */
 static PyObject *Vector_isub(PyObject * v1, PyObject * v2)
 {
        VectorObject *vec1= NULL, *vec2= NULL;
@@ -1067,8 +1115,7 @@ static PyObject *Vector_mul(PyObject * v1, PyObject * v2)
        return NULL;
 }
 
-/*------------------------obj *= obj------------------------------
-  in place mulplication */
+/* mulplication in-place: obj *= obj */
 static PyObject *Vector_imul(PyObject * v1, PyObject * v2)
 {
        VectorObject *vec = (VectorObject *)v1;
@@ -1116,8 +1163,7 @@ static PyObject *Vector_imul(PyObject * v1, PyObject * v2)
        return v1;
 }
 
-/*------------------------obj / obj------------------------------
-  divide*/
+/* divid: obj / obj */
 static PyObject *Vector_div(PyObject * v1, PyObject * v2)
 {
        int i;
@@ -1149,8 +1195,7 @@ static PyObject *Vector_div(PyObject * v1, PyObject * v2)
        return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
 }
 
-/*------------------------obj /= obj------------------------------
-  divide*/
+/* divide in-place: obj /= obj */
 static PyObject *Vector_idiv(PyObject * v1, PyObject * v2)
 {
        int i;
@@ -1179,21 +1224,17 @@ static PyObject *Vector_idiv(PyObject * v1, PyObject * v2)
        return v1;
 }
 
-/*-------------------------- -obj -------------------------------
+/* -obj
   returns the negative of this object*/
 static PyObject *Vector_neg(VectorObject *self)
 {
-       int i;
-       float vec[4];
+       float tvec[MAX_DIMENSIONS];
        
        if(!BaseMath_ReadCallback(self))
                return NULL;
        
-       for(i = 0; i < self->size; i++){
-               vec[i] = -self->vec[i];
-       }
-
-       return newVectorObject(vec, self->size, Py_NEW, Py_TYPE(self));
+       negate_vn_vn(tvec, self->vec, self->size);
+       return newVectorObject(tvec, self->size, Py_NEW, Py_TYPE(self));
 }
 
 /*------------------------vec_magnitude_nosqrt (internal) - for comparing only */
@@ -1209,7 +1250,7 @@ static double vec_magnitude_nosqrt(float *data, int size)
        /* warning, line above removed because we are not using the length,
           rather the comparing the sizes and for this we do not need the sqrt
           for the actual length, the dot must be sqrt'd */
-       return (double)dot;
+       return dot;
 }
 
 
@@ -2043,28 +2084,34 @@ static char Vector_negate_doc[] =
 ;
 static PyObject *Vector_negate(VectorObject *self)
 {
-       int i;
        if(!BaseMath_ReadCallback(self))
                return NULL;
        
-       for(i = 0; i < self->size; i++)
-               self->vec[i] = -(self->vec[i]);
-       
+       negate_vn(self->vec, self->size);
+
        (void)BaseMath_WriteCallback(self); // already checked for error
-       
-       Py_INCREF(self);
-       return (PyObject*)self;
+       Py_RETURN_NONE;
 }
 
 static struct PyMethodDef Vector_methods[] = {
+       /* in place only */
        {"zero", (PyCFunction) Vector_zero, METH_NOARGS, Vector_zero_doc},
-       {"normalize", (PyCFunction) Vector_normalize, METH_NOARGS, Vector_normalize_doc},
        {"negate", (PyCFunction) Vector_negate, METH_NOARGS, Vector_negate_doc},
-       {"resize2D", (PyCFunction) Vector_resize2D, METH_NOARGS, Vector_resize2D_doc},
-       {"resize3D", (PyCFunction) Vector_resize3D, METH_NOARGS, Vector_resize3D_doc},
-       {"resize4D", (PyCFunction) Vector_resize4D, METH_NOARGS, Vector_resize4D_doc},
+
+       /* operate on original or copy */
+       {"normalize", (PyCFunction) Vector_normalize, METH_NOARGS, Vector_normalize_doc},
+       {"normalized", (PyCFunction) Vector_normalized, METH_NOARGS, Vector_normalized_doc},
+
+       {"to_2d", (PyCFunction) Vector_to_2d, METH_NOARGS, Vector_to_2d_doc},
+       {"resize_2d", (PyCFunction) Vector_resize_2d, METH_NOARGS, Vector_resize_2d_doc},
+       {"to_3d", (PyCFunction) Vector_to_3d, METH_NOARGS, Vector_to_3d_doc},
+       {"resize_3d", (PyCFunction) Vector_resize_3d, METH_NOARGS, Vector_resize_3d_doc},
+       {"to_4d", (PyCFunction) Vector_to_4d, METH_NOARGS, Vector_to_4d_doc},
+       {"resize_4d", (PyCFunction) Vector_resize_4d, METH_NOARGS, Vector_resize_4d_doc},
        {"to_tuple", (PyCFunction) Vector_to_tuple, METH_VARARGS, Vector_to_tuple_doc},
        {"to_track_quat", (PyCFunction) Vector_to_track_quat, METH_VARARGS, Vector_to_track_quat_doc},
+
+       /* operation between 2 or more types  */
        {"reflect", (PyCFunction) Vector_reflect, METH_O, Vector_reflect_doc},
        {"cross", (PyCFunction) Vector_cross, METH_O, Vector_cross_doc},
        {"dot", (PyCFunction) Vector_dot, METH_O, Vector_dot_doc},
@@ -2073,6 +2120,7 @@ static struct PyMethodDef Vector_methods[] = {
        {"project", (PyCFunction) Vector_project, METH_O, Vector_project_doc},
        {"lerp", (PyCFunction) Vector_lerp, METH_VARARGS, Vector_lerp_doc},
        {"rotate", (PyCFunction) Vector_rotate, METH_VARARGS, Vector_rotate_doc},
+
        {"copy", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc},
        {"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL},
        {NULL, NULL, 0, NULL}