diff options
author | Joseph Gilbert <ascotan@gmail.com> | 2004-02-29 16:20:34 +0300 |
---|---|---|
committer | Joseph Gilbert <ascotan@gmail.com> | 2004-02-29 16:20:34 +0300 |
commit | 8f3a9815baafb6f8fe00659cf6390a8c4092ef8b (patch) | |
tree | 9a69af7bffd6fd0d7da8e998d74a37dc273628a2 /source/blender/python/api2_2x/vector.c | |
parent | 2255ac3b19ec3b2aa0e884ad5960f34c9c0efa23 (diff) |
Mathutils library for the python API
- support for quaternions, euler, vector, matrix operations.
- euler supports unique rotation calculation
- new matrix memory construction and internal functions
- quaternion slerp and diff calculation
- 2d, 3d, 4d vector construction and handling
- full conversion support between types
- update to object/window to reflect to matrix type
- update to types/blender/module to reflect new module
Diffstat (limited to 'source/blender/python/api2_2x/vector.c')
-rw-r--r-- | source/blender/python/api2_2x/vector.c | 583 |
1 files changed, 483 insertions, 100 deletions
diff --git a/source/blender/python/api2_2x/vector.c b/source/blender/python/api2_2x/vector.c index d08775aa6a7..efb13787204 100644 --- a/source/blender/python/api2_2x/vector.c +++ b/source/blender/python/api2_2x/vector.c @@ -1,5 +1,4 @@ -/* - * + /* * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -23,19 +22,162 @@ * All rights reserved. * * - * Contributor(s): Willian P. Germano + * Contributor(s): Willian P. Germano & Joseph Gilbert * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -/* This file is the old bpython opy_vector.c with minor modifications */ - #include "vector.h" +//doc strings +char Vector_Zero_doc[] = +"() - set all values in the vector to 0"; +char Vector_Normalize_doc[] = +"() - normalize the vector"; +char Vector_Negate_doc[] = +"() - changes vector to it's additive inverse"; +char Vector_Resize2D_doc[] = +"() - resize a vector to [x,y]"; +char Vector_Resize3D_doc[] = +"() - resize a vector to [x,y,z]"; +char Vector_Resize4D_doc[] = +"() - resize a vector to [x,y,z,w]"; + +//method table +struct PyMethodDef Vector_methods[] = { + {"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_Resize2D_doc}, + {"resize4D",(PyCFunction)Vector_Resize4D, METH_NOARGS, + Vector_Resize2D_doc}, + {NULL, NULL, 0, NULL} +}; + /*****************************/ -/* Vector Python Object */ +// Vector Python Object /*****************************/ -#define VectorObject_Check(v) ((v)->ob_type == &vector_Type) + +//object methods +PyObject *Vector_Zero(VectorObject *self) +{ + int x; + for(x = 0; x < self->size; x++){ + self->vec[x] = 0.0f; + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Vector_Normalize(VectorObject *self) +{ + float norm; + int x; + + norm = 0.0f; + for(x = 0; x < self->size; x++){ + norm += self->vec[x] * self->vec[x]; + } + norm = (float)sqrt(norm); + for(x = 0; x < self->size; x++){ + self->vec[x] /= norm; + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Vector_Negate(VectorObject *self) +{ + int x; + for(x = 0; x < self->size; x++){ + self->vec[x] = -(self->vec[x]); + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Vector_Resize2D(VectorObject *self) +{ + float x, y; + + if(self->size == 4 || self->size == 3){ + x = self->vec[0]; + y = self->vec[1]; + PyMem_Free(self->vec); + self->vec = PyMem_Malloc(2*sizeof (float)); + self->vec[0] = x; + self->vec[1] = y; + self->size = 2; + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Vector_Resize3D(VectorObject *self) +{ + float x, y, z; + + if(self->size == 2){ + x = self->vec[0]; + y = self->vec[1]; + PyMem_Free(self->vec); + self->vec = PyMem_Malloc(3*sizeof (float)); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = 0.0f; + self->size = 3; + } + else if (self->size == 4){ + x = self->vec[0]; + y = self->vec[1]; + z = self->vec[2]; + PyMem_Free(self->vec); + self->vec = PyMem_Malloc(3*sizeof (float)); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = z; + self->size = 3; + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Vector_Resize4D(VectorObject *self) +{ + float x, y, z; + + if(self->size == 2){ + x = self->vec[0]; + y = self->vec[1]; + PyMem_Free(self->vec); + self->vec = PyMem_Malloc(4*sizeof (float)); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = 0.0f; + self->vec[3] = 1.0f; + self->size = 4; + } + else if (self->size == 3){ + x = self->vec[0]; + y = self->vec[1]; + z = self->vec[2]; + PyMem_Free(self->vec); + self->vec = PyMem_Malloc(4*sizeof (float)); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = z; + self->vec[3] = 1.0f; + self->size = 4; + } + + return EXPP_incr_ret(Py_None); +} static void Vector_dealloc(VectorObject *self) { @@ -44,144 +186,374 @@ static void Vector_dealloc(VectorObject *self) static PyObject *Vector_getattr(VectorObject *self, char *name) { - if (self->size==3 && ELEM3(name[0], 'x', 'y', 'z') && name[1]==0) - return PyFloat_FromDouble(self->vec[ name[0]-'x' ]); - - return EXPP_ReturnPyObjError(PyExc_AttributeError, "attribute not found"); + if (self->size==4 && ELEM4(name[0], 'x', 'y', 'z', 'w') && name[1]==0){ + if ((name[0]) == ('w')){ + return PyFloat_FromDouble(self->vec[3]); + }else{ + return PyFloat_FromDouble(self->vec[name[0]-'x']); + } + } + else if (self->size==3 && ELEM3(name[0], 'x', 'y', 'z') && name[1]==0) + return PyFloat_FromDouble(self->vec[name[0]-'x']); + else if (self->size==2 && ELEM(name[0], 'x', 'y') && name[1]==0) + return PyFloat_FromDouble(self->vec[name[0]-'x']); + + if ((strcmp(name,"length") == 0)){ + if(self->size == 4){ + return PyFloat_FromDouble(sqrt(self->vec[0] * self->vec[0] + + self->vec[1] * self->vec[1] + + self->vec[2] * self->vec[2] + + self->vec[3] * self->vec[3])); + } + else if(self->size == 3){ + return PyFloat_FromDouble(sqrt(self->vec[0] * self->vec[0] + + self->vec[1] * self->vec[1] + + self->vec[2] * self->vec[2])); + }else if (self->size == 2){ + return PyFloat_FromDouble(sqrt(self->vec[0] * self->vec[0] + + self->vec[1] * self->vec[1])); + }else EXPP_ReturnPyObjError(PyExc_AttributeError, + "can only return the length of a 2D ,3D or 4D vector\n"); + } + + return Py_FindMethod(Vector_methods, (PyObject*)self, name); } static int Vector_setattr(VectorObject *self, char *name, PyObject *v) { - float val; - - if (!PyArg_Parse(v, "f", &val)) - return EXPP_ReturnIntError(PyExc_TypeError, - "expected float argument"); - - if (self->size==3 && ELEM3(name[0], 'x', 'y', 'z') && name[1]==0) - self->vec[ name[0]-'x' ]= val; - else - return -1; - - return 0; + float val; + int valTemp; + + if(!PyFloat_Check(v)){ + if(!PyInt_Check(v)){ + return EXPP_ReturnIntError(PyExc_TypeError,"int or float expected\n"); + }else{ + if (!PyArg_Parse(v, "i", &valTemp)) + return EXPP_ReturnIntError(PyExc_TypeError, "unable to parse int argument\n"); + val = (float)valTemp; + } + }else{ + if (!PyArg_Parse(v, "f", &val)) + return EXPP_ReturnIntError(PyExc_TypeError, "unable to parse float argument\n"); + } + if (self->size==4 && ELEM4(name[0], 'x', 'y', 'z', 'w') && name[1]==0){ + if ((name[0]) == ('w')){ + self->vec[3]= val; + }else{ + self->vec[name[0]-'x']= val; + } + } + else if (self->size==3 && ELEM3(name[0], 'x', 'y', 'z') && name[1]==0) + self->vec[name[0]-'x']= val; + else if (self->size==2 && ELEM(name[0], 'x', 'y') && name[1]==0) + self->vec[name[0]-'x']= val; + else return -1; + + return 0; } /* Vectors Sequence methods */ - static int Vector_len(VectorObject *self) { - return self->size; + return self->size; } static PyObject *Vector_item(VectorObject *self, int i) { - if (i < 0 || i >= self->size) - return EXPP_ReturnPyObjError (PyExc_IndexError, - "array index out of range"); + if (i < 0 || i >= self->size) + return EXPP_ReturnPyObjError (PyExc_IndexError, "array index out of range\n"); + + return Py_BuildValue("f", self->vec[i]); - return Py_BuildValue("f", self->vec[i]); } static PyObject *Vector_slice(VectorObject *self, int begin, int end) { - PyObject *list; - int count; + PyObject *list; + int count; - if (begin < 0) begin= 0; - if (end > self->size) end= self->size; - if (begin > end) begin= end; + if (begin < 0) begin= 0; + if (end > self->size) end= self->size; + if (begin > end) begin= end; - list= PyList_New(end-begin); + list= PyList_New(end-begin); - for (count = begin; count < end; count++) - PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->vec[count])); + for (count = begin; count < end; count++){ + PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->vec[count])); + } - return list; + return list; } static int Vector_ass_item(VectorObject *self, int i, PyObject *ob) { - if (i < 0 || i >= self->size) - return EXPP_ReturnIntError(PyExc_IndexError, - "array assignment index out of range"); + if (i < 0 || i >= self->size) + return EXPP_ReturnIntError(PyExc_IndexError, + "array assignment index out of range\n"); + if (!PyInt_Check(ob) && !PyFloat_Check(ob)) + return EXPP_ReturnIntError(PyExc_IndexError, + "vector member must be a number\n"); - if (!PyNumber_Check(ob)) - return EXPP_ReturnIntError(PyExc_IndexError, - "vector member must be a number"); + self->vec[i]= (float)PyFloat_AsDouble(ob); - self->vec[i]= PyFloat_AsDouble(ob); - - return 0; + return 0; } static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *seq) { - int count; - - if (begin < 0) begin= 0; - if (end > self->size) end= self->size; - if (begin > end) begin= end; - - if (!PySequence_Check(seq)) - return EXPP_ReturnIntError(PyExc_TypeError, - "illegal argument type for built-in operation"); - - if (PySequence_Length(seq) != (end - begin)) - return EXPP_ReturnIntError(PyExc_TypeError, - "size mismatch in slice assignment"); - - for (count = begin; count < end; count++) { - PyObject *ob = PySequence_GetItem(seq, count); - - if (!PyArg_Parse(ob, "f", &self->vec[count])) { - Py_DECREF(ob); - return -1; - } - - Py_DECREF(ob); - } + int count, z; + + if (begin < 0) begin= 0; + if (end > self->size) end= self->size; + if (begin > end) begin= end; + + if (!PySequence_Check(seq)) + return EXPP_ReturnIntError(PyExc_TypeError, + "illegal argument type for built-in operation\n"); + if (PySequence_Length(seq) != (end - begin)) + return EXPP_ReturnIntError(PyExc_TypeError, + "size mismatch in slice assignment\n"); + + z = 0; + for (count = begin; count < end; count++) { + PyObject *ob = PySequence_GetItem(seq, z); z++; + if (!PyInt_Check(ob) && !PyFloat_Check(ob)) + return EXPP_ReturnIntError(PyExc_IndexError, + "list member must be a number\n"); + + if (!PyArg_Parse(ob, "f", &self->vec[count])){ + Py_DECREF(ob); + return -1; + } + } return 0; } static PyObject *Vector_repr (VectorObject *self) { - int i, maxindex = self->size - 1; - char ftoa[24]; - PyObject *str1, *str2; + int i, maxindex = self->size - 1; + char ftoa[24]; + PyObject *str1, *str2; - str1 = PyString_FromString ("["); + str1 = PyString_FromString ("["); - for (i = 0; i < maxindex; i++) { - sprintf(ftoa, "%.3f, ", self->vec[i]); - str2 = PyString_FromString (ftoa); - if (!str1 || !str2) goto error; /* my first goto : ) */ - PyString_ConcatAndDel (&str1, str2); - } + for (i = 0; i < maxindex; i++) { + sprintf(ftoa, "%.4f, ", self->vec[i]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); + } - sprintf(ftoa, "%.3f]\n", self->vec[maxindex]); - str2 = PyString_FromString (ftoa); - if (!str1 || !str2) goto error; /* uh-oh, became a habit */ - PyString_ConcatAndDel (&str1, str2); + sprintf(ftoa, "%.4f]\n", self->vec[maxindex]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); - if (str1) return str1; + if (str1) return str1; error: - Py_XDECREF (str1); - Py_XDECREF (str2); - return EXPP_ReturnPyObjError (PyExc_MemoryError, - "couldn't create PyString!"); + Py_XDECREF (str1); + Py_XDECREF (str2); + return EXPP_ReturnPyObjError (PyExc_MemoryError, + "couldn't create PyString!\n"); +} + + +PyObject * Vector_add(PyObject *v1, PyObject *v2) +{ + float * vec; + int x; + + if((!VectorObject_Check(v1)) || (!VectorObject_Check(v2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((VectorObject*)v1)->flag != 0 || ((VectorObject*)v2)->flag != 0) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "cannot add a scalar to a vector\n"); + if(((VectorObject*)v1)->size != ((VectorObject*)v2)->size) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "vectors must have the same dimensions for this operation\n"); + + vec = PyMem_Malloc ((((VectorObject*)v1)->size)*sizeof (float)); + + for(x = 0; x < ((VectorObject*)v1)->size; x++){ + vec[x] = ((VectorObject*)v1)->vec[x] + ((VectorObject*)v2)->vec[x]; + } + + return (PyObject*)newVectorObject(vec, (((VectorObject*)v1)->size)); +} + +PyObject * Vector_sub(PyObject *v1, PyObject *v2) +{ + float * vec; + int x; + + if((!VectorObject_Check(v1)) || (!VectorObject_Check(v2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((VectorObject*)v1)->flag != 0 || ((VectorObject*)v2)->flag != 0) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "cannot subtract a scalar from a vector\n"); + if(((VectorObject*)v1)->size != ((VectorObject*)v2)->size) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "vectors must have the same dimensions for this operation\n"); + + vec = PyMem_Malloc ((((VectorObject*)v1)->size)*sizeof (float)); + + for(x = 0; x < ((VectorObject*)v1)->size; x++){ + vec[x] = ((VectorObject*)v1)->vec[x] - ((VectorObject*)v2)->vec[x]; + } + + return (PyObject*)newVectorObject(vec, (((VectorObject*)v1)->size)); +} + +PyObject * Vector_mul(PyObject *v1, PyObject * v2) +{ + float * vec; + int x; + + if((!VectorObject_Check(v1)) || (!VectorObject_Check(v2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((VectorObject*)v1)->flag == 0 && ((VectorObject*)v2)->flag == 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "please use the dot product or the cross product to multiply vectors\n"); + if(((VectorObject*)v1)->size != ((VectorObject*)v2)->size) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "vector dimension error during Vector_mul\n"); + + vec = PyMem_Malloc ((((VectorObject*)v1)->size)*sizeof(float)); + + for(x = 0; x < ((VectorObject*)v1)->size; x++){ + vec[x] = ((VectorObject*)v1)->vec[x] * ((VectorObject*)v2)->vec[x]; + } + + return (PyObject*)newVectorObject(vec, (((VectorObject*)v1)->size)); +} + +PyObject * Vector_div(PyObject *v1, PyObject * v2) +{ + float * vec; + int x; + + if((!VectorObject_Check(v1)) || (!VectorObject_Check(v2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((VectorObject*)v1)->flag == 0 && ((VectorObject*)v2)->flag == 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "cannot divide two vectors\n"); + if(((VectorObject*)v1)->flag != 0 && ((VectorObject*)v2)->flag == 0) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "cannot divide a scalar by a vector\n"); + if(((VectorObject*)v1)->size != ((VectorObject*)v2)->size) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "vector dimension error during Vector_mul\n"); + + vec = PyMem_Malloc ((((VectorObject*)v1)->size)*sizeof(float)); + + for(x = 0; x < ((VectorObject*)v1)->size; x++){ + vec[x] = ((VectorObject*)v1)->vec[x] / ((VectorObject*)v2)->vec[x]; + } + + return (PyObject*)newVectorObject(vec, (((VectorObject*)v1)->size)); } +//coercion of unknown types to type VectorObject for numeric protocols +int Vector_coerce(PyObject **v1, PyObject **v2) +{ + long *tempI; + double *tempF; + float *vec; + int x; + + if (VectorObject_Check(*v1)) { + if (VectorObject_Check(*v2)) { //two vectors + Py_INCREF(*v1); + Py_INCREF(*v2); + return 0; + }else{ + if(Matrix_CheckPyObject(*v2)){ + printf("vector/matrix numeric protocols unsupported...\n"); + Py_INCREF(*v1); + return 0; //operation will type check + }else if(PyNumber_Check(*v2)){ + if(PyInt_Check(*v2)){ //cast scalar to vector + tempI = PyMem_Malloc(1*sizeof(long)); + *tempI = PyInt_AsLong(*v2); + vec = PyMem_Malloc ((((VectorObject*)*v1)->size)*sizeof (float)); + for(x = 0; x < (((VectorObject*)*v1)->size); x++){ + vec[x] = (float)*tempI; + } + PyMem_Free(tempI); + *v2 = newVectorObject(vec, (((VectorObject*)*v1)->size)); + ((VectorObject*)*v2)->flag = 1; //int coercion + Py_INCREF(*v1); + return 0; + }else if(PyFloat_Check(*v2)){ //cast scalar to vector + tempF = PyMem_Malloc(1*sizeof(double)); + *tempF = PyFloat_AsDouble(*v2); + vec = PyMem_Malloc ((((VectorObject*)*v1)->size)*sizeof (float)); + for(x = 0; x < (((VectorObject*)*v1)->size); x++){ + vec[x] = (float)*tempF; + } + PyMem_Free(tempF); + *v2 = newVectorObject(vec, (((VectorObject*)*v1)->size)); + ((VectorObject*)*v2)->flag = 2; //float coercion + Py_INCREF(*v1); + return 0; + } + } + //unknown type or numeric cast failure + printf("attempting vector operation with unsupported type...\n"); + Py_INCREF(*v1); + return 0; //operation will type check + } + }else{ + printf("numeric protocol failure...\n"); + return -1; //this should not occur - fail + } + return -1; +} + + static PySequenceMethods Vector_SeqMethods = { - (inquiry) Vector_len, /* sq_length */ - (binaryfunc) 0, /* sq_concat */ - (intargfunc) 0, /* sq_repeat */ - (intargfunc) Vector_item, /* sq_item */ - (intintargfunc) Vector_slice, /* sq_slice */ - (intobjargproc) Vector_ass_item, /* sq_ass_item */ - (intintobjargproc) Vector_ass_slice, /* sq_ass_slice */ + (inquiry) Vector_len, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (intargfunc) 0, /* sq_repeat */ + (intargfunc) Vector_item, /* sq_item */ + (intintargfunc) Vector_slice, /* sq_slice */ + (intobjargproc) Vector_ass_item, /* sq_ass_item */ + (intintobjargproc) Vector_ass_slice, /* sq_ass_slice */ +}; + +static PyNumberMethods Vector_NumMethods = +{ + (binaryfunc) Vector_add, /* __add__ */ + (binaryfunc) Vector_sub, /* __sub__ */ + (binaryfunc) Vector_mul, /* __mul__ */ + (binaryfunc) Vector_div, /* __div__ */ + (binaryfunc) 0, /* __mod__ */ + (binaryfunc) 0, /* __divmod__ */ + (ternaryfunc) 0, /* __pow__ */ + (unaryfunc) 0, /* __neg__ */ + (unaryfunc) 0, /* __pos__ */ + (unaryfunc) 0, /* __abs__ */ + (inquiry) 0, /* __nonzero__ */ + (unaryfunc) 0, /* __invert__ */ + (binaryfunc) 0, /* __lshift__ */ + (binaryfunc) 0, /* __rshift__ */ + (binaryfunc) 0, /* __and__ */ + (binaryfunc) 0, /* __xor__ */ + (binaryfunc) 0, /* __or__ */ + (coercion) Vector_coerce, /* __coerce__ */ + (unaryfunc) 0, /* __int__ */ + (unaryfunc) 0, /* __long__ */ + (unaryfunc) 0, /* __float__ */ + (unaryfunc) 0, /* __oct__ */ + (unaryfunc) 0, /* __hex__ */ + }; PyTypeObject vector_Type = @@ -191,27 +563,38 @@ PyTypeObject vector_Type = "vector", /*tp_name*/ sizeof(VectorObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ - /* methods */ (destructor) Vector_dealloc, /*tp_dealloc*/ (printfunc) 0, /*tp_print*/ (getattrfunc) Vector_getattr, /*tp_getattr*/ (setattrfunc) Vector_setattr, /*tp_setattr*/ 0, /*tp_compare*/ (reprfunc) Vector_repr, /*tp_repr*/ - 0, /*tp_as_number*/ + &Vector_NumMethods, /*tp_as_number*/ &Vector_SeqMethods, /*tp_as_sequence*/ }; PyObject *newVectorObject(float *vec, int size) { VectorObject *self; + int x; vector_Type.ob_type = &PyType_Type; self = PyObject_NEW(VectorObject, &vector_Type); - self->vec = vec; + if(!vec){ + self->vec = PyMem_Malloc (size *sizeof (float)); + for(x = 0; x < size; x++){ + self->vec[x] = 0.0f; + } + if(size == 4) self->vec[3] = 1.0f; + }else{ + self->vec = vec; + } + self->size = size; + self->flag = 0; return (PyObject*) self; } + |