forked from bartvdbraak/blender
Support for arbitrary sized vectors - (was limited by 2-4 previously)
patch http://codereview.appspot.com/5482043 from Andrew Hale * Text from the submission * This patch adds the ability to use arbitrary sized vectors from mathutils. Currently vectors are only of size 2, 3 or 4 since they are generally restricted to geometric applications. However, we can use arbitrary sized vectors for efficient calculations and data manipulation.
This commit is contained in:
parent
bfdaa3b187
commit
414370b8d4
@ -198,6 +198,7 @@ double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int s
|
||||
float normalize_vn_vn(float *array_tar, const float *array_src, const int size);
|
||||
float normalize_vn(float *array_tar, const int size);
|
||||
void range_vn_i(int *array_tar, const int size, const int start);
|
||||
void range_vn_fl(float *array_tar, const int size, const float start, const float step);
|
||||
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_tar, const int size, const float f);
|
||||
|
@ -416,6 +416,15 @@ void range_vn_i(int *array_tar, const int size, const int start)
|
||||
while(i--) { *(array_pt--) = j--; }
|
||||
}
|
||||
|
||||
void range_vn_fl(float *array_tar, const int size, const float start, const float step)
|
||||
{
|
||||
float *array_pt= array_tar + (size-1);
|
||||
int i= size;
|
||||
while(i--) {
|
||||
*(array_pt--) = start + step * (float)(i);
|
||||
}
|
||||
}
|
||||
|
||||
void negate_vn(float *array_tar, const int size)
|
||||
{
|
||||
float *array_pt= array_tar + (size-1);
|
||||
|
@ -40,36 +40,13 @@ PyDoc_STRVAR(M_Mathutils_doc,
|
||||
"This module provides access to matrices, eulers, quaternions and vectors."
|
||||
);
|
||||
static int mathutils_array_parse_fast(float *array,
|
||||
int array_min, int array_max,
|
||||
PyObject *value, const char *error_prefix)
|
||||
int size,
|
||||
PyObject *value_fast,
|
||||
const char *error_prefix)
|
||||
{
|
||||
PyObject *value_fast= NULL;
|
||||
PyObject *item;
|
||||
|
||||
int i, size;
|
||||
|
||||
/* non list/tuple cases */
|
||||
if (!(value_fast=PySequence_Fast(value, error_prefix))) {
|
||||
/* PySequence_Fast sets the error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
size= PySequence_Fast_GET_SIZE(value_fast);
|
||||
|
||||
if (size > array_max || size < array_min) {
|
||||
if (array_max == array_min) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"%.200s: sequence size is %d, expected %d",
|
||||
error_prefix, size, array_max);
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"%.200s: sequence size is %d, expected [%d - %d]",
|
||||
error_prefix, size, array_min, array_max);
|
||||
}
|
||||
Py_DECREF(value_fast);
|
||||
return -1;
|
||||
}
|
||||
int i;
|
||||
|
||||
i= size;
|
||||
do {
|
||||
@ -93,9 +70,10 @@ static int mathutils_array_parse_fast(float *array,
|
||||
/* helper functionm returns length of the 'value', -1 on error */
|
||||
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
|
||||
{
|
||||
#if 1 /* approx 6x speedup for mathutils types */
|
||||
int size;
|
||||
|
||||
#if 1 /* approx 6x speedup for mathutils types */
|
||||
|
||||
if ( (size= VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
|
||||
(size= EulerObject_Check(value) ? 3 : 0) ||
|
||||
(size= QuaternionObject_Check(value) ? 4 : 0) ||
|
||||
@ -125,7 +103,85 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return mathutils_array_parse_fast(array, array_min, array_max, value, error_prefix);
|
||||
PyObject *value_fast= NULL;
|
||||
|
||||
/* non list/tuple cases */
|
||||
if (!(value_fast=PySequence_Fast(value, error_prefix))) {
|
||||
/* PySequence_Fast sets the error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
size= PySequence_Fast_GET_SIZE(value_fast);
|
||||
|
||||
if (size > array_max || size < array_min) {
|
||||
if (array_max == array_min) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"%.200s: sequence size is %d, expected %d",
|
||||
error_prefix, size, array_max);
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"%.200s: sequence size is %d, expected [%d - %d]",
|
||||
error_prefix, size, array_min, array_max);
|
||||
}
|
||||
Py_DECREF(value_fast);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mathutils_array_parse_fast(array, size, value_fast, error_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, const char *error_prefix)
|
||||
{
|
||||
int size;
|
||||
|
||||
#if 1 /* approx 6x speedup for mathutils types */
|
||||
|
||||
if ( (size= VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
|
||||
(size= EulerObject_Check(value) ? 3 : 0) ||
|
||||
(size= QuaternionObject_Check(value) ? 4 : 0) ||
|
||||
(size= ColorObject_Check(value) ? 3 : 0))
|
||||
{
|
||||
if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (size < array_min) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"%.200s: sequence size is %d, expected > %d",
|
||||
error_prefix, size, array_min);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*array= PyMem_Malloc(size * sizeof(float));
|
||||
memcpy(*array, ((BaseMathObject *)value)->data, size * sizeof(float));
|
||||
return size;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
PyObject *value_fast= NULL;
|
||||
//*array= NULL;
|
||||
|
||||
/* non list/tuple cases */
|
||||
if (!(value_fast=PySequence_Fast(value, error_prefix))) {
|
||||
/* PySequence_Fast sets the error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
size= PySequence_Fast_GET_SIZE(value_fast);
|
||||
|
||||
if (size < array_min) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"%.200s: sequence size is %d, expected > %d",
|
||||
error_prefix, size, array_min);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*array= PyMem_Malloc(size * sizeof(float));
|
||||
|
||||
return mathutils_array_parse_fast(*array, size, value_fast, error_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,6 +115,7 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index);
|
||||
|
||||
/* utility func */
|
||||
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix);
|
||||
int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, const char *error_prefix);
|
||||
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
|
||||
|
||||
int column_vector_multiplication(float rvec[4], VectorObject *vec, MatrixObject *mat);
|
||||
|
@ -54,15 +54,29 @@ static int row_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject *v
|
||||
*/
|
||||
static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *UNUSED(kwds))
|
||||
{
|
||||
float vec[4]= {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
float *vec= NULL;
|
||||
int size= 3; /* default to a 3D vector */
|
||||
|
||||
switch(PyTuple_GET_SIZE(args)) {
|
||||
case 0:
|
||||
vec= PyMem_Malloc(size * sizeof(float));
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fill_vn_fl(vec, size, 0.0f);
|
||||
break;
|
||||
case 1:
|
||||
if ((size=mathutils_array_parse(vec, 2, 4, PyTuple_GET_ITEM(args, 0), "mathutils.Vector()")) == -1)
|
||||
if ((size=mathutils_array_parse_alloc(&vec, 2, PyTuple_GET_ITEM(args, 0), "mathutils.Vector()")) == -1) {
|
||||
if (vec) {
|
||||
PyMem_Free(vec);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
@ -87,6 +101,215 @@ static PyObject *vec__apply_to_copy(PyNoArgsFunction vec_func, VectorObject *sel
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------CLASS-METHODS----------------------------*/
|
||||
PyDoc_STRVAR(C_Vector_Fill_doc,
|
||||
".. classmethod:: Fill(size, fill=0.0)\n"
|
||||
"\n"
|
||||
" Create a vector of length size with all values set to fill.\n"
|
||||
"\n"
|
||||
" :arg size: The length of the vector to be created.\n"
|
||||
" :type size: int\n"
|
||||
" :arg fill: The value used to fill the vector.\n"
|
||||
" :type fill: float\n"
|
||||
);
|
||||
static PyObject *C_Vector_Fill(PyObject *cls, PyObject *args)
|
||||
{
|
||||
float *vec;
|
||||
int size;
|
||||
float fill= 0.0f;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|f:Vector.Fill", &size, &fill)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < 2) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Vector(): invalid size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec= PyMem_Malloc(size * sizeof(float));
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector.Fill(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fill_vn_fl(vec, size, fill);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, size, (PyTypeObject *)cls);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(C_Vector_Range_doc,
|
||||
".. classmethod:: Range(start=0, stop, step=1)\n"
|
||||
"\n"
|
||||
" Create a filled with a range of values.\n"
|
||||
"\n"
|
||||
" :arg start: The start of the range used to fill the vector.\n"
|
||||
" :type start: int\n"
|
||||
" :arg stop: The end of the range used to fill the vector.\n"
|
||||
" :type stop: int\n"
|
||||
" :arg step: The step between successive values in the vector.\n"
|
||||
" :type step: int\n"
|
||||
);
|
||||
static PyObject *C_Vector_Range(PyObject *cls, PyObject *args)
|
||||
{
|
||||
float *vec;
|
||||
int stop, size;
|
||||
int start= 0;
|
||||
int step= 1;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|ii:Vector.Range", &start, &stop, &step)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch(PyTuple_GET_SIZE(args)){
|
||||
case 1:
|
||||
size = start;
|
||||
start= 0;
|
||||
break;
|
||||
case 2:
|
||||
if (start >= stop) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Start value is larger"
|
||||
"than the stop value");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size= stop - start;
|
||||
break;
|
||||
default:
|
||||
if (start >= stop) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Start value is larger"
|
||||
"than the stop value");
|
||||
return NULL;
|
||||
}
|
||||
size= (stop - start)/step;
|
||||
if (size%step)
|
||||
size++;
|
||||
break;
|
||||
}
|
||||
|
||||
vec= PyMem_Malloc(size * sizeof(float));
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector.Range(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
range_vn_fl(vec, size, (float)start, (float)step);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, size, (PyTypeObject *)cls);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(C_Vector_Linspace_doc,
|
||||
".. classmethod:: Linspace(start, stop, size)\n"
|
||||
"\n"
|
||||
" Create a vector of the specified size which is filled with linearly spaced values between start and stop values.\n"
|
||||
"\n"
|
||||
" :arg start: The start of the range used to fill the vector.\n"
|
||||
" :type start: int\n"
|
||||
" :arg stop: The end of the range used to fill the vector.\n"
|
||||
" :type stop: int\n"
|
||||
" :arg size: The size of the vector to be created.\n"
|
||||
" :type size: int\n"
|
||||
);
|
||||
static PyObject *C_Vector_Linspace(PyObject *cls, PyObject *args)
|
||||
{
|
||||
float *vec;
|
||||
int size;
|
||||
float start, end, step;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ffi:Vector.Linspace", &start, &end, &size)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < 2) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Vector.Linspace(): invalid size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
step= (end - start)/(float)(size-1);
|
||||
|
||||
vec= PyMem_Malloc(size * sizeof(float));
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector.Linspace(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
range_vn_fl(vec, size, start, step);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, size, (PyTypeObject *)cls);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(C_Vector_Repeat_doc,
|
||||
".. classmethod:: Repeat(vector, size)\n"
|
||||
"\n"
|
||||
" Create a vector by repeating the values in vector until the required size is reached.\n"
|
||||
"\n"
|
||||
" :arg tuple: The vector to draw values from.\n"
|
||||
" :type tuple: :class:`mathutils.Vector`\n"
|
||||
" :arg size: The size of the vector to be created.\n"
|
||||
" :type size: int\n"
|
||||
);
|
||||
static PyObject *C_Vector_Repeat(PyObject *cls, PyObject *args)
|
||||
{
|
||||
float *vec;
|
||||
float *iter_vec= NULL;
|
||||
int i, size, value_size;
|
||||
PyObject *value;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "Oi:Vector.Repeat", &value, &size)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < 2) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Vector.Repeat(): invalid size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((value_size=mathutils_array_parse_alloc(&iter_vec, 2, value, "Vector.Repeat(vector, size), invalid 'vector' arg")) == -1) {
|
||||
PyMem_Free(iter_vec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (iter_vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector.Repeat(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec= PyMem_Malloc(size * sizeof(float));
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector.Repeat(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i= 0;
|
||||
while (i < size) {
|
||||
vec[i]= iter_vec[i % value_size];
|
||||
i++;
|
||||
}
|
||||
|
||||
PyMem_Free(iter_vec);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, size, (PyTypeObject *)cls);
|
||||
}
|
||||
|
||||
/*-----------------------------METHODS---------------------------- */
|
||||
PyDoc_STRVAR(Vector_zero_doc,
|
||||
".. method:: zero()\n"
|
||||
@ -137,6 +360,101 @@ static PyObject *Vector_normalized(VectorObject *self)
|
||||
return vec__apply_to_copy((PyNoArgsFunction)Vector_normalize, self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Vector_resize_doc,
|
||||
".. method:: resize(size=3)\n"
|
||||
"\n"
|
||||
" Resize the vector to have size number of elements.\n"
|
||||
"\n"
|
||||
" :return: an instance of itself\n"
|
||||
" :rtype: :class:`Vector`\n"
|
||||
);
|
||||
static PyObject *Vector_resize(VectorObject *self, PyObject *value)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (self->wrapped==Py_WRAP) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Vector.resize(): "
|
||||
"cannot resize wrapped data - only python vectors");
|
||||
return NULL;
|
||||
}
|
||||
if (self->cb_user) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Vector.resize(): "
|
||||
"cannot resize a vector that has an owner");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((size = PyLong_AsLong(value)) == -1) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Vector.resize(size): "
|
||||
"expected size argument to be an integer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < 2) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Vector.resize(): invalid size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->vec = PyMem_Realloc(self->vec, (size * sizeof(float)));
|
||||
if (self->vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector.resize(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If the vector has increased in length, set all new elements to 0.0f */
|
||||
if (size > self->size) {
|
||||
fill_vn_fl(self->vec + self->size, size - self->size, 0.0f);
|
||||
}
|
||||
|
||||
self->size = size;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Vector_resized_doc,
|
||||
".. method:: resized(size=3)\n"
|
||||
"\n"
|
||||
" Return a resized copy of the vector with size number of elements.\n"
|
||||
"\n"
|
||||
" :return: a new vector\n"
|
||||
" :rtype: :class:`Vector`\n"
|
||||
);
|
||||
static PyObject *Vector_resized(VectorObject *self, PyObject *value)
|
||||
{
|
||||
int size;
|
||||
float *vec;
|
||||
|
||||
/*if (!PyArg_ParseTuple(args, "i:resize", &size))
|
||||
return NULL;*/
|
||||
if ((size = PyLong_AsLong(value)) == -1){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < 2) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Vector.resized(): invalid size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec= PyMem_Malloc(size * sizeof(float));
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector.resized(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fill_vn_fl(vec, size, 0.0f);
|
||||
memcpy(vec, self->vec, self->size * sizeof(float));
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, size, NULL);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Vector_resize_2d_doc,
|
||||
".. method:: resize_2d()\n"
|
||||
"\n"
|
||||
@ -505,6 +823,12 @@ static PyObject *Vector_reflect(VectorObject *self, PyObject *value)
|
||||
if ((value_size= mathutils_array_parse(tvec, 2, 4, value, "Vector.reflect(other), invalid 'other' arg")) == -1)
|
||||
return NULL;
|
||||
|
||||
if (self->size < 2 || self->size > 4) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector must be 2D, 3D or 4D");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mirror[0] = tvec[0];
|
||||
mirror[1] = tvec[1];
|
||||
if (value_size > 2) mirror[2] = tvec[2];
|
||||
@ -544,6 +868,12 @@ static PyObject *Vector_cross(VectorObject *self, PyObject *value)
|
||||
if (mathutils_array_parse(tvec, self->size, self->size, value, "Vector.cross(other), invalid 'other' arg") == -1)
|
||||
return NULL;
|
||||
|
||||
if (self->size != 3) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector must be 3D");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret= (VectorObject *)Vector_CreatePyObject(NULL, 3, Py_NEW, Py_TYPE(self));
|
||||
cross_v3_v3v3(ret->vec, self->vec, tvec);
|
||||
return (PyObject *)ret;
|
||||
@ -561,15 +891,20 @@ PyDoc_STRVAR(Vector_dot_doc,
|
||||
);
|
||||
static PyObject *Vector_dot(VectorObject *self, PyObject *value)
|
||||
{
|
||||
float tvec[MAX_DIMENSIONS];
|
||||
float *tvec;
|
||||
|
||||
if (BaseMath_ReadCallback(self) == -1)
|
||||
return NULL;
|
||||
|
||||
if (mathutils_array_parse(tvec, self->size, self->size, value, "Vector.dot(other), invalid 'other' arg") == -1)
|
||||
return NULL;
|
||||
if (mathutils_array_parse_alloc(&tvec, self->size, value, "Vector.dot(other), invalid 'other' arg") == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return PyFloat_FromDouble(dot_vn_vn(self->vec, tvec, self->size));
|
||||
|
||||
cleanup:
|
||||
PyMem_Free(tvec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Vector_angle_doc,
|
||||
@ -607,6 +942,12 @@ static PyObject *Vector_angle(VectorObject *self, PyObject *args)
|
||||
if (mathutils_array_parse(tvec, self->size, self->size, value, "Vector.angle(other), invalid 'other' arg") == -1)
|
||||
return NULL;
|
||||
|
||||
if (self->size > 4) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector must be 2D, 3D or 4D");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (x = 0; x < size; x++) {
|
||||
dot_self += (double)self->vec[x] * (double)self->vec[x];
|
||||
dot_other += (double)tvec[x] * (double)tvec[x];
|
||||
@ -647,7 +988,7 @@ static PyObject *Vector_rotation_difference(VectorObject *self, PyObject *value)
|
||||
{
|
||||
float quat[4], vec_a[3], vec_b[3];
|
||||
|
||||
if (self->size < 3) {
|
||||
if (self->size < 3 || self->size > 4) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"vec.difference(value): "
|
||||
"expects both vectors to be size 3 or 4");
|
||||
@ -692,6 +1033,12 @@ static PyObject *Vector_project(VectorObject *self, PyObject *value)
|
||||
if (mathutils_array_parse(tvec, size, size, value, "Vector.project(other), invalid 'other' arg") == -1)
|
||||
return NULL;
|
||||
|
||||
if (self->size > 4) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector must be 2D, 3D or 4D");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (BaseMath_ReadCallback(self) == -1)
|
||||
return NULL;
|
||||
|
||||
@ -725,24 +1072,41 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args)
|
||||
const int size= self->size;
|
||||
PyObject *value= NULL;
|
||||
float fac, ifac;
|
||||
float tvec[MAX_DIMENSIONS], vec[MAX_DIMENSIONS];
|
||||
float *tvec, *vec;
|
||||
int x;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "Of:lerp", &value, &fac))
|
||||
return NULL;
|
||||
|
||||
if (mathutils_array_parse(tvec, size, size, value, "Vector.lerp(other), invalid 'other' arg") == -1)
|
||||
return NULL;
|
||||
if (mathutils_array_parse_alloc(&tvec, size, value, "Vector.lerp(other), invalid 'other' arg") == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (BaseMath_ReadCallback(self) == -1)
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
vec= PyMem_Malloc(size * sizeof(float));
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector.lerp(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ifac= 1.0f - fac;
|
||||
|
||||
for (x = 0; x < size; x++) {
|
||||
vec[x] = (ifac * self->vec[x]) + (fac * tvec[x]);
|
||||
}
|
||||
return Vector_CreatePyObject(vec, size, Py_NEW, Py_TYPE(self));
|
||||
|
||||
PyMem_Free(tvec);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, size, Py_TYPE(self));
|
||||
|
||||
cleanup:
|
||||
PyMem_Free(tvec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Vector_rotate_doc,
|
||||
@ -763,7 +1127,7 @@ static PyObject *Vector_rotate(VectorObject *self, PyObject *value)
|
||||
if (mathutils_any_to_rotmat(other_rmat, value, "Vector.rotate(value)") == -1)
|
||||
return NULL;
|
||||
|
||||
if (self->size < 3) {
|
||||
if (self->size < 3 || self->size > 4) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector must be 3D or 4D");
|
||||
return NULL;
|
||||
@ -903,8 +1267,8 @@ static PyObject *Vector_slice(VectorObject *self, int begin, int end)
|
||||
/* sequence slice (set): vector[a:b] = value */
|
||||
static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *seq)
|
||||
{
|
||||
int y, size = 0;
|
||||
float vec[MAX_DIMENSIONS];
|
||||
int size = 0;
|
||||
float *vec= NULL;
|
||||
|
||||
if (BaseMath_ReadCallback(self) == -1)
|
||||
return -1;
|
||||
@ -914,18 +1278,30 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *se
|
||||
begin = MIN2(begin, end);
|
||||
|
||||
size = (end - begin);
|
||||
if (mathutils_array_parse(vec, size, size, seq, "vector[begin:end] = [...]") == -1)
|
||||
if (mathutils_array_parse_alloc(&vec, size, seq, "vector[begin:end] = [...]") == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec[:] = seq: "
|
||||
"problem allocating pointer space");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*parsed well - now set in vector*/
|
||||
for (y = 0; y < size; y++) {
|
||||
self->vec[begin + y] = vec[y];
|
||||
}
|
||||
memcpy(self->vec + begin, vec, size * sizeof(float));
|
||||
|
||||
if (BaseMath_WriteCallback(self) == -1)
|
||||
return -1;
|
||||
|
||||
PyMem_Free(vec);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
PyMem_Free(vec);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Numeric Protocols */
|
||||
@ -933,7 +1309,7 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *se
|
||||
static PyObject *Vector_add(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
float vec[MAX_DIMENSIONS];
|
||||
float *vec= NULL;
|
||||
|
||||
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
@ -956,9 +1332,18 @@ static PyObject *Vector_add(PyObject *v1, PyObject *v2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec= PyMem_Malloc(vec1->size * sizeof(float));
|
||||
|
||||
if (vec == NULL) { /*allocation failure*/
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
add_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->size);
|
||||
|
||||
return Vector_CreatePyObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
|
||||
return Vector_CreatePyObject_alloc(vec, vec1->size, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/* addition in-place: obj += obj */
|
||||
@ -997,7 +1382,7 @@ static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
|
||||
static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
float vec[MAX_DIMENSIONS];
|
||||
float *vec;
|
||||
|
||||
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
@ -1019,9 +1404,18 @@ static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec= PyMem_Malloc(vec1->size * sizeof(float));
|
||||
|
||||
if (vec == NULL) { /*allocation failure*/
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sub_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->size);
|
||||
|
||||
return Vector_CreatePyObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
|
||||
return Vector_CreatePyObject_alloc(vec, vec1->size, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/* subtraction in-place: obj -= obj */
|
||||
@ -1104,9 +1498,18 @@ int column_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject* vec,
|
||||
|
||||
static PyObject *vector_mul_float(VectorObject *vec, const float scalar)
|
||||
{
|
||||
float tvec[MAX_DIMENSIONS];
|
||||
float *tvec= NULL;
|
||||
tvec= PyMem_Malloc(vec->size * sizeof(float));
|
||||
|
||||
if (tvec == NULL) { /*allocation failure*/
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec * float: "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mul_vn_vn_fl(tvec, vec->vec, vec->size, scalar);
|
||||
return Vector_CreatePyObject(tvec, vec->size, Py_NEW, Py_TYPE(vec));
|
||||
return Vector_CreatePyObject_alloc(tvec, vec->size, Py_TYPE(vec));
|
||||
}
|
||||
|
||||
static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
|
||||
@ -1277,8 +1680,7 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
|
||||
/* divid: obj / obj */
|
||||
static PyObject *Vector_div(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
int i;
|
||||
float vec[4], scalar;
|
||||
float *vec= NULL, scalar;
|
||||
VectorObject *vec1 = NULL;
|
||||
|
||||
if (!VectorObject_Check(v1)) { /* not a vector */
|
||||
@ -1287,7 +1689,7 @@ static PyObject *Vector_div(PyObject *v1, PyObject *v2)
|
||||
"Vector must be divided by a float");
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject*)v1; /* vector */
|
||||
vec1 = (VectorObject *)v1; /* vector */
|
||||
|
||||
if (BaseMath_ReadCallback(vec1) == -1)
|
||||
return NULL;
|
||||
@ -1306,16 +1708,23 @@ static PyObject *Vector_div(PyObject *v1, PyObject *v2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < vec1->size; i++) {
|
||||
vec[i] = vec1->vec[i] / scalar;
|
||||
vec= PyMem_Malloc(vec1->size * sizeof(float));
|
||||
|
||||
if (vec == NULL) { /*allocation failure*/
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec / value: "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
return Vector_CreatePyObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
|
||||
|
||||
mul_vn_vn_fl(vec, vec1->vec, vec1->size, 1.0f/scalar);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, vec1->size, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/* divide in-place: obj /= obj */
|
||||
static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
int i;
|
||||
float scalar;
|
||||
VectorObject *vec1 = (VectorObject*)v1;
|
||||
|
||||
@ -1335,9 +1744,8 @@ static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
|
||||
"divide by zero error");
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < vec1->size; i++) {
|
||||
vec1->vec[i] /= scalar;
|
||||
}
|
||||
|
||||
mul_vn_fl(vec1->vec, vec1->size, 1.0f/scalar);
|
||||
|
||||
(void)BaseMath_WriteCallback(vec1);
|
||||
|
||||
@ -1349,29 +1757,24 @@ static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
|
||||
returns the negative of this object*/
|
||||
static PyObject *Vector_neg(VectorObject *self)
|
||||
{
|
||||
float tvec[MAX_DIMENSIONS];
|
||||
float *tvec;
|
||||
|
||||
if (BaseMath_ReadCallback(self) == -1)
|
||||
return NULL;
|
||||
|
||||
tvec= PyMem_Malloc(self->size * sizeof(float));
|
||||
negate_vn_vn(tvec, self->vec, self->size);
|
||||
return Vector_CreatePyObject(tvec, self->size, Py_NEW, Py_TYPE(self));
|
||||
return Vector_CreatePyObject_alloc(tvec, self->size, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/*------------------------vec_magnitude_nosqrt (internal) - for comparing only */
|
||||
static double vec_magnitude_nosqrt(float *data, int size)
|
||||
{
|
||||
double dot = 0.0f;
|
||||
int i;
|
||||
|
||||
for (i=0; i<size; i++) {
|
||||
dot += (double)data[i];
|
||||
}
|
||||
/*return (double)sqrt(dot);*/
|
||||
/* 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 dot;
|
||||
return dot_vn_vn(data, data, size);
|
||||
}
|
||||
|
||||
|
||||
@ -1606,16 +2009,10 @@ static int Vector_setAxis(VectorObject *self, PyObject *value, void *type)
|
||||
/* vector.length */
|
||||
static PyObject *Vector_getLength(VectorObject *self, void *UNUSED(closure))
|
||||
{
|
||||
double dot = 0.0f;
|
||||
int i;
|
||||
|
||||
if (BaseMath_ReadCallback(self) == -1)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < self->size; i++) {
|
||||
dot += (double)(self->vec[i] * self->vec[i]);
|
||||
}
|
||||
return PyFloat_FromDouble(sqrt(dot));
|
||||
return PyFloat_FromDouble(sqrt(dot_vn_vn(self->vec, self->vec, self->size)));
|
||||
}
|
||||
|
||||
static int Vector_setLength(VectorObject *self, PyObject *value)
|
||||
@ -2242,6 +2639,12 @@ static PyObject *Vector_negate(VectorObject *self)
|
||||
}
|
||||
|
||||
static struct PyMethodDef Vector_methods[] = {
|
||||
/* Class Methods */
|
||||
{"Fill", (PyCFunction) C_Vector_Fill, METH_VARARGS | METH_CLASS, C_Vector_Fill_doc},
|
||||
{"Range", (PyCFunction) C_Vector_Range, METH_VARARGS | METH_CLASS, C_Vector_Range_doc},
|
||||
{"Linspace", (PyCFunction) C_Vector_Linspace, METH_VARARGS | METH_CLASS, C_Vector_Linspace_doc},
|
||||
{"Repeat", (PyCFunction) C_Vector_Repeat, METH_VARARGS | METH_CLASS, C_Vector_Repeat_doc},
|
||||
|
||||
/* in place only */
|
||||
{"zero", (PyCFunction) Vector_zero, METH_NOARGS, Vector_zero_doc},
|
||||
{"negate", (PyCFunction) Vector_negate, METH_NOARGS, Vector_negate_doc},
|
||||
@ -2250,6 +2653,8 @@ static struct PyMethodDef Vector_methods[] = {
|
||||
{"normalize", (PyCFunction) Vector_normalize, METH_NOARGS, Vector_normalize_doc},
|
||||
{"normalized", (PyCFunction) Vector_normalized, METH_NOARGS, Vector_normalized_doc},
|
||||
|
||||
{"resize", (PyCFunction) Vector_resize, METH_O, Vector_resize_doc},
|
||||
{"resized", (PyCFunction) Vector_resized, METH_O, Vector_resized_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},
|
||||
@ -2375,7 +2780,7 @@ PyObject *Vector_CreatePyObject(float *vec, const int size, const int type, PyTy
|
||||
{
|
||||
VectorObject *self;
|
||||
|
||||
if (size > 4 || size < 2) {
|
||||
if (size < 2) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Vector(): invalid size");
|
||||
return NULL;
|
||||
@ -2429,3 +2834,12 @@ PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, int cb_type, int
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
PyObject *Vector_CreatePyObject_alloc(float *vec, const int size, PyTypeObject *base_type)
|
||||
{
|
||||
VectorObject *vect_ob;
|
||||
vect_ob= (VectorObject *)Vector_CreatePyObject(vec, size, Py_WRAP, base_type);
|
||||
vect_ob->wrapped= Py_NEW;
|
||||
|
||||
return (PyObject *)vect_ob;
|
||||
}
|
||||
|
@ -41,11 +41,12 @@ extern PyTypeObject vector_Type;
|
||||
typedef struct {
|
||||
BASE_MATH_MEMBERS(vec);
|
||||
|
||||
unsigned char size; /* vec size 2,3 or 4 */
|
||||
int size; /* vec size 2,3 or 4 */
|
||||
} VectorObject;
|
||||
|
||||
/*prototypes*/
|
||||
PyObject *Vector_CreatePyObject(float *vec, const int size, const int type, PyTypeObject *base_type);
|
||||
PyObject *Vector_CreatePyObject_cb(PyObject *user, int size, int callback_type, int subtype);
|
||||
PyObject *Vector_CreatePyObject_alloc(float *vec, const int size, PyTypeObject *base_type);
|
||||
|
||||
#endif /* MATHUTILS_VECTOR_H */
|
||||
|
Loading…
Reference in New Issue
Block a user