commit 65350ebdfc88e462dcc1e8b6c83db75a7c7b8fe3 Author: cecilkorik Date: Thu Nov 15 19:44:58 2007 +0000 consolidated pyvec3d and pyobarr into new "py3dutil" added cgrid for collision added quaternion class (not working yet) --HG-- branch : py3dutil diff --git a/cgrid.c b/cgrid.c new file mode 100644 index 0000000..f54ba7d --- /dev/null +++ b/cgrid.c @@ -0,0 +1,356 @@ +#include "cgrid.h" +#include "obarr.h" +#include "red_black_tree.h" + +void cgrid_unroll(CgridObject* self) +{ + long i = 0; + rb_red_blk_node* nil = self->pTree->nil; + rb_red_blk_node* x = self->pTree->root->left; + rb_red_blk_node* last = nil; + + if (!self->bUnrollDirty) + return; + + if (self->pUnrolled) + { + Py_DECREF(self->pUnrolled); + } + self->pUnrolled = PyObject_New(ObarrObject, &ObarrObjectType); + obarr_set_size(self->pUnrolled, self->nCells); + + while(nil != x) { + last = x; + x = x->right; + } + while (last != nil) { + if (i == self->nCells) + { + printf("SizeError in Unroll!\n"); + break; + } + obarr_set_element(self->pUnrolled, i++, (PyObject*)last->info); + last = TreePredecessor(self->pTree,last); + } + self->bUnrollDirty = 0; +} + +int cgrid_compare(const void* a, const void* b) +{ + const CgridKey* sa = (const CgridKey*)a; + const CgridKey* sb = (const CgridKey*)b; + int rv; + + rv = (sa->x > sb->x) - (sa->x < sb->x); + if (rv != 0) + { + return rv; + } + else + { + rv = (sa->y > sb->y) - (sa->y < sb->y); + if (rv != 0) + { + return rv; + } + else + { + rv = (sa->z > sb->z) - (sa->z < sb->z); + return rv; + } + } + return 0; +} + + +CgridKey* cgrid_newkey() +{ + CgridKey* ptr; + + ptr = (CgridKey*)malloc(sizeof(CgridKey)); + return ptr; +} +CgridInfo* cgrid_newinfo() +{ + CgridInfo* ptr; + + ptr = (CgridInfo*)malloc(sizeof(CgridInfo)); + return ptr; +} + + +void cgrid_destroykey(void* a) +{ + free(a); +} + +void cgrid_destroyinfo(void* a) +{ + const CgridInfo* sa = (const CgridInfo*)a; + PyObject** other = sa->pContents->pData; + + for (;other - sa->pContents->pData < sa->pContents->nSize; other++) + { + if (*other == Py_None) + continue; + PyObject_DelAttrString(*other, "_cgrid_internal_key_x"); + PyObject_DelAttrString(*other, "_cgrid_internal_key_y"); + PyObject_DelAttrString(*other, "_cgrid_internal_key_z"); + } + + obarr_empty(sa->pContents); + Py_DECREF(sa->pContents); + free(a); +} + +void cgrid_printkey(const void* a) +{ + const CgridKey* sa = (const CgridKey*)a; + + printf("", sa->x, sa->y, sa->z); +} + +void cgrid_printinfo(void* a) +{ + ObarrObject* arr = (ObarrObject*)a; + + printf("", arr->nSize); +} + + +int Cgrid_init(CgridObject *self, PyObject *args, PyObject *kwds) +{ + double fCell; + + if (!PyArg_ParseTuple(args, "d", &fCell)) + { + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return 1; + } + + self->pTree = RBTreeCreate(cgrid_compare, cgrid_destroykey, cgrid_destroyinfo, cgrid_printkey, cgrid_printinfo); + self->nSize = 0; + self->nCells = 0; + self->fCellSize = fCell; + self->pUnrolled = NULL; + self->bUnrollDirty = 1; + + return 0; +} + +void Cgrid_dealloc(PyObject* self_in) +{ + CgridObject* self = (CgridObject*)self_in; + + RBTreeDestroy(self->pTree); +} + +PyObject* Cgrid_repr(PyObject *self_in) +{ + CgridObject *self; + PyObject *tuple, *fmtstring, *reprstring; + + if (!Cgrid_Check(self_in)) + return PyString_FromString(""); + + self = (CgridObject*)self_in; + tuple = Py_BuildValue("(ii)", self->nCells, self->nSize); + fmtstring = PyString_FromString(""); + reprstring = PyString_Format(fmtstring, tuple); + Py_DECREF(tuple); + Py_DECREF(fmtstring); + return reprstring; +} + +/* +PyObject * +Cgrid_copy(PyObject *self_in, PyObject *unused) +{ + if (!Cgrid_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + CgridObject* self = (CgridObject*)self_in; + CgridObject* rv = NULL; + rv = PyObject_New(CgridObject, &CgridObjectType); + int i; + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i]; + + return (PyObject*)rv; +} +*/ +Py_ssize_t Cgrid_len(PyObject *self_in) +{ + CgridObject* self = (CgridObject*)self_in; + + return self->nCells; +} + +PyObject* Cgrid_item(PyObject *self_in, Py_ssize_t index) +{ + CgridObject* self = (CgridObject*)self_in; + + cgrid_unroll(self); + if (!obarr_valid_index(self->pUnrolled, index)) + { + PyErr_SetString(PyExc_IndexError, "invalid index"); + return NULL; + } + return obarr_get_element(self->pUnrolled, index); +} + +int Cgrid_contains(PyObject* self_in, PyObject* other_in) +{ + CgridObject* self = (CgridObject*)self_in; + rb_red_blk_node* pNode = NULL; + CgridKey k; + + if (!PyArg_ParseTuple(other_in, "lll", &k.x, &k.y, &k.z)) + { + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return 0; + } + + pNode = RBExactQuery(self->pTree, &k); + return !!pNode; +} + +PyObject* Cgrid_insert(PyObject *self_in, PyObject *args) +{ + CgridObject* self = (CgridObject*)self_in; + PyObject* other = NULL; + CgridKey* pK = NULL; + CgridInfo* pV = NULL; + rb_red_blk_node* pNode = NULL; + + pK = cgrid_newkey(); + if (!PyArg_ParseTuple(args, "(lll)O", &pK->x, &pK->y, &pK->z, &other)) + { + free(pK); + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return NULL; + } + + PyObject_SetAttrString(other, "_cgrid_internal_key_x", PyInt_FromLong(pK->x)); + PyObject_SetAttrString(other, "_cgrid_internal_key_y", PyInt_FromLong(pK->y)); + PyObject_SetAttrString(other, "_cgrid_internal_key_z", PyInt_FromLong(pK->z)); + + pNode = RBExactQuery(self->pTree, pK); + if (pNode) + { + pV = (CgridInfo*)pNode->info; + } + else + { + pV = cgrid_newinfo(); + pV->pSelf = self; + pV->pContents = PyObject_New(ObarrObject, &ObarrObjectType); + COPY_KEY(pK, &(pV->k)); + + RBTreeInsert(self->pTree, pK, pV); + self->nCells++; + } + obarr_set_size(pV->pContents, pV->pContents->nSize + 1); + obarr_set_element(pV->pContents, pV->pContents->nSize - 1, other); + + self->nSize++; + self->bUnrollDirty = 1; + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* Cgrid_delete(PyObject *self_in, PyObject *args) +{ + CgridObject* self = (CgridObject*)self_in; + rb_red_blk_node* pNode = NULL; + CgridInfo* pV; + CgridKey k; + + if (!PyArg_ParseTuple(args, "(lll)", &k.x, &k.y, &k.z)) + { + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return NULL; + } + + pNode = RBExactQuery(self->pTree, &k); + if (!pNode) + { + PyErr_SetString(PyExc_ValueError, "supplied argument not found in grid (no such cell)"); + return NULL; + } + pV = (CgridInfo*)pNode->info; + self->nSize = self->nSize - pV->pContents->nSize; + RBDelete(self->pTree, pNode); + self->nCells--; + + self->bUnrollDirty = 1; + + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* Cgrid_remove(PyObject *self_in, PyObject *args) +{ + CgridObject* self = (CgridObject*)self_in; + PyObject *other, *element; + CgridKey k; + CgridInfo* pV; + PyObject *pX, *pY, *pZ; + rb_red_blk_node* pNode = NULL; + long i; + + if (!PyArg_ParseTuple(args, "O", &other)) + { + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return NULL; + } + + pX = PyObject_GetAttrString(other, "_cgrid_internal_key_x"); + pY = PyObject_GetAttrString(other, "_cgrid_internal_key_y"); + pZ = PyObject_GetAttrString(other, "_cgrid_internal_key_z"); + if (!pX || !pY || !pZ) + { + PyErr_SetString(PyExc_ValueError, "supplied argument not found in grid (missing _cgrid_internal_key attributes)"); + return NULL; + } + k.x = PyInt_AsLong(pX); + k.y = PyInt_AsLong(pY); + k.z = PyInt_AsLong(pZ); + + pNode = RBExactQuery(self->pTree, &k); + if (!pNode) + { + PyErr_SetString(PyExc_ValueError, "supplied argument not found in grid (no such cell)"); + return NULL; + } + pV = (CgridInfo*)pNode->info; + i = obarr_find(pV->pContents, other); + if (i == -1) + { + PyErr_SetString(PyExc_ValueError, "supplied argument not found in grid (not in cell)"); + return NULL; + } + + element = obarr_get_element(pV->pContents, i); + + PyObject_DelAttrString(element, "_cgrid_internal_key_x"); + PyObject_DelAttrString(element, "_cgrid_internal_key_y"); + PyObject_DelAttrString(element, "_cgrid_internal_key_z"); + + obarr_del_index(pV->pContents, i); + self->nSize--; + self->bUnrollDirty = 1; + + if (pV->pContents->nSize == 0) + { + RBDelete(self->pTree, pNode); + self->nCells--; + } + Py_INCREF(Py_None); + return Py_None; + +} diff --git a/cgrid.h b/cgrid.h new file mode 100644 index 0000000..58f62ba --- /dev/null +++ b/cgrid.h @@ -0,0 +1,128 @@ +#include +#include + +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +#endif + +typedef struct rb_red_blk_tree rb_red_blk_tree; +typedef struct ObarrObject ObarrObject; + +typedef struct CgridObject { + PyObject_HEAD + rb_red_blk_tree* pTree; + long nSize; + long nCells; + double fCellSize; + ObarrObject* pUnrolled; + int bUnrollDirty; +} CgridObject; + +staticforward PyTypeObject CgridObjectType; + +#define Cgrid_Check(op) PyObject_TypeCheck(op, &CgridObjectType) +#define COPY_KEY(a, b) (b)->x = (a)->x; (b)->y = (a)->y; (b)->z = (a)->z; + +typedef struct CgridKey { + long x; + long y; + long z; +} CgridKey; +typedef struct CgridInfo { + CgridObject* pSelf; + CgridKey k; + ObarrObject* pContents; + +} CgridInfo; + + +/* internal functions */ +void cgrid_unroll(CgridObject* self); +int cgrid_compare(const void* a, const void* b); +CgridKey* cgrid_newkey(); +CgridInfo* cgrid_newinfo(); +void cgrid_destroykey(void* a); +void cgrid_destroyinfo(void* a); +void cgrid_printkey(const void* a); +void cgrid_printinfo(void* a); + +/* exported API functions */ +int Cgrid_init(CgridObject *self, PyObject *args, PyObject *kwds); +void Cgrid_dealloc(PyObject* self_in); +int Cgrid_contains(PyObject* self_in, PyObject* other_in); +PyObject * Cgrid_item(PyObject *self_in, Py_ssize_t index); +Py_ssize_t Cgrid_len(PyObject *self_in); +PyObject* Cgrid_repr(PyObject *self_in); +PyObject* Cgrid_insert(PyObject *self_in, PyObject *args); +PyObject* Cgrid_delete(PyObject *self_in, PyObject *args); +PyObject* Cgrid_remove(PyObject *self_in, PyObject *args); +/*PyObject* Cgrid_remove(PyObject *self_in, PyObject *args);*/ + + +static PySequenceMethods Cgrid_as_seq[] = { + Cgrid_len, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + Cgrid_item, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + Cgrid_contains, /* sq_contains */ +}; + +static PyMethodDef Cgrid_methods[] = { + {"insert", (PyCFunction)Cgrid_insert, METH_VARARGS, "allocate the array to a new size"}, + {"delete", (PyCFunction)Cgrid_delete, METH_VARARGS, "remove a grid cell"}, + {"remove", (PyCFunction)Cgrid_remove, METH_VARARGS, "remove an object from its grid cell"}, + {NULL} +}; + +static struct PyMemberDef Cgrid_members[] = { + /*{"x", T_OBJECT_EX, offsetof(CgridObject, x), 0, "x"}, + {"y", T_OBJECT_EX, offsetof(CgridObject, y), 0, "y"}, + {"z", T_OBJECT_EX, offsetof(CgridObject, z), 0, "z"},*/ + {NULL} /* Sentinel */ +}; + + +static PyTypeObject CgridObjectType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "pyobarr.cgrid", /* tp_name */ + sizeof(CgridObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + Cgrid_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + Cgrid_repr, /* tp_repr */ + 0, /* tp_as_number */ + Cgrid_as_seq, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + "Vector objects are simple.", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Cgrid_methods, /* tp_methods */ + Cgrid_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Cgrid_init, /* tp_init */ +}; \ No newline at end of file diff --git a/misc.c b/misc.c new file mode 100644 index 0000000..cf4941c --- /dev/null +++ b/misc.c @@ -0,0 +1,60 @@ +#include "misc.h" + +/***********************************************************************/ +/* FUNCTION: void Assert(int assertion, char* error) */ +/**/ +/* INPUTS: assertion should be a predicated that the programmer */ +/* assumes to be true. If this assumption is not true the message */ +/* error is printed and the program exits. */ +/**/ +/* OUTPUT: None. */ +/**/ +/* Modifies input: none */ +/**/ +/* Note: If DEBUG_ASSERT is not defined then assertions should not */ +/* be in use as they will slow down the code. Therefore the */ +/* compiler will complain if an assertion is used when */ +/* DEBUG_ASSERT is undefined. */ +/***********************************************************************/ + + +void Assert(int assertion, char* error) { + if(!assertion) { + printf("Assertion Failed: %s\n",error); + exit(-1); + } +} + + + +/***********************************************************************/ +/* FUNCTION: SafeMalloc */ +/**/ +/* INPUTS: size is the size to malloc */ +/**/ +/* OUTPUT: returns pointer to allocated memory if succesful */ +/**/ +/* EFFECT: mallocs new memory. If malloc fails, prints error message */ +/* and terminates program. */ +/**/ +/* Modifies Input: none */ +/**/ +/***********************************************************************/ + +void * SafeMalloc(size_t size) { + void * result; + + if ( (result = malloc(size)) ) { /* assignment intentional */ + return(result); + } else { + printf("memory overflow: malloc failed in SafeMalloc."); + printf(" Exiting Program.\n"); + exit(-1); + return(0); + } +} +/* NullFunction does nothing it is included so that it can be passed */ +/* as a function to RBTreeCreate when no other suitable function has */ +/* been defined */ + +void NullFunction(void * junk) { ; } diff --git a/misc.h b/misc.h new file mode 100644 index 0000000..0a87d21 --- /dev/null +++ b/misc.h @@ -0,0 +1,34 @@ +#include +#include + +#ifndef INC_E_MISC_ +#define INC_E_MISC_ + + +/* CONVENTIONS: All data structures for red-black trees have the prefix */ +/* "rb_" to prevent name conflicts. */ +/* */ +/* Function names: Each word in a function name begins with */ +/* a capital letter. An example funcntion name is */ +/* CreateRedTree(a,b,c). Furthermore, each function name */ +/* should begin with a capital letter to easily distinguish */ +/* them from variables. */ +/* */ +/* Variable names: Each word in a variable name begins with */ +/* a capital letter EXCEPT the first letter of the variable */ +/* name. For example, int newLongInt. Global variables have */ +/* names beginning with "g". An example of a global */ +/* variable name is gNewtonsConstant. */ + +void Assert(int assertion, char* error); +void * SafeMalloc(size_t size); + +#endif + + + + + + + + diff --git a/obarr.c b/obarr.c new file mode 100644 index 0000000..2ec996f --- /dev/null +++ b/obarr.c @@ -0,0 +1,424 @@ +#define NEED_STATIC +#include "obarr.h" +#undef NEED_STATIC + +PyObject* obarr_get_element(ObarrObject* self, long index) +{ + return self->pData[index]; +} + +int obarr_find(ObarrObject* self, PyObject* other_in) +{ + long i; + for (i = 0; i < self->nSize; i++) + { + if (self->pData[i] == other_in) + return i; + + } + return -1; +} + + +void obarr_set_element(ObarrObject* self, long index, PyObject* new_in) +{ + PyObject* old = obarr_get_element(self, index); + Py_INCREF(new_in); + self->pData[index] = new_in; + Py_DECREF(old); +} + +void obarr_empty(ObarrObject* self) +{ + long i; + for (i = 0; i < self->nAllocSize; i++) + { + Py_DECREF(self->pData[i]); + } + if (self->pData != NULL) + free(self->pData); + self->nAllocSize = 0; + self->nSize = 0; + self->pData = NULL; +} + +void obarr_del_index(ObarrObject* self, long i) +{ + Py_DECREF(self->pData[i]); + + if ((self->nSize - i - 1) > 0) + { + /* slide the tail end of the array up so we don't have a hole in the middle */ + self->pData[i] = self->pData[self->nSize - 1]; + + /* fill the end of the array with a None before we reduce the size to cover that up */ + /* to turn it back into "allocated but unused" space */ + self->pData[self->nSize - 1] = Py_None; + Py_INCREF(Py_None); + } + else + { + self->pData[i] = Py_None; + Py_INCREF(Py_None); + } + self->nSize = self->nSize - 1; +} + +int obarr_valid_index(ObarrObject* self, long i) +{ + if (i >= 0 && i < self->nSize) + return 1; + return 0; +} + +int obarr_set_size(ObarrObject* self, long size) +{ + long i, newsize; + void* tmp; + + if (size == 0) + { + obarr_empty(self); + return 1; + } + else if (size > self->nAllocSize) + { + newsize = self->nChunkSize * (size / self->nChunkSize); + if ((size % self->nChunkSize) != 0) + newsize = newsize + self->nChunkSize; + if (self->pData == NULL) + { + self->pData = (PyObject**)malloc(newsize * sizeof(void*)); + if (self->pData == NULL) + { + return 0; + } + for (i = 0; i < newsize; i++) + { + Py_INCREF(Py_None); + self->pData[i] = Py_None; + } + } + else + { + tmp = realloc(self->pData, newsize * sizeof(void*)); + if (tmp == NULL) + return 0; + self->pData = (PyObject**)tmp; + for (i = self->nAllocSize; i < newsize; i++) + { + Py_INCREF(Py_None); + self->pData[i] = Py_None; + } + } + self->nAllocSize = newsize; + } + else + { + for (i = size; i < self->nAllocSize; i++) + { + if (self->pData[i] != Py_None) + { + Py_DECREF(self->pData[i]); + Py_INCREF(Py_None); + self->pData[i] = Py_None; + } + } + } + self->nSize = size; + return 1; +} + +int Obarr_init(ObarrObject *self, PyObject *args, PyObject *kwds) +{ + self->nSize = 0; + self->nChunkSize = 64; + self->nAllocSize = 0; + self->pData = NULL; + + return 0; +} + +void Obarr_dealloc(PyObject* self_in) +{ + ObarrObject* self = (ObarrObject*)self_in; + obarr_empty(self); +} + +PyObject* Obarr_repr(PyObject *self_in) +{ + ObarrObject *self; + PyObject *tuple, *fmtstring, *reprstring; + if (!Obarr_Check(self_in)) + return PyString_FromString(""); + + self = (ObarrObject*)self_in; + tuple = Py_BuildValue("(l)", self->nSize); + fmtstring = PyString_FromString(""); + reprstring = PyString_Format(fmtstring, tuple); + Py_DECREF(tuple); + Py_DECREF(fmtstring); + return reprstring; +} + +Py_ssize_t Obarr_len(PyObject *self_in) +{ + ObarrObject* self = (ObarrObject*)self_in; + return self->nSize; +} + + +PyObject * Obarr_item(PyObject *self_in, Py_ssize_t index) +{ + ObarrObject* self = (ObarrObject*)self_in; + PyObject* ob; + if (!obarr_valid_index(self, index)) + { + PyErr_SetString(PyExc_IndexError, "index not in range"); + return NULL; + } + + ob = obarr_get_element(self, index); + Py_INCREF(ob); + return ob; + +} + +int Obarr_setitem(PyObject* self_in, Py_ssize_t index, PyObject* new_in) +{ + ObarrObject* self = (ObarrObject*)self_in; + if (!obarr_valid_index(self, index)) + { + PyErr_SetString(PyExc_IndexError, "index not in range"); + return -1; + } + obarr_set_element(self, index, new_in); + + return 0; +} + +PyObject* Obarr_remove(PyObject* self_in, PyObject* args) +{ + ObarrObject* self = (ObarrObject*)self_in; + long i; + PyObject* other_in = NULL; + if (!PyArg_ParseTuple(args, "O", &other_in)) + { + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return NULL; + } + i = obarr_find(self, other_in); + if (i == -1) + { + PyErr_SetString(PyExc_ValueError, "supplied argument not found in list"); + return NULL; + } + obarr_del_index(self, i); + + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* Obarr_delete(PyObject* self_in, PyObject* args) +{ + ObarrObject* self = (ObarrObject*)self_in; + long i; + if (!PyArg_ParseTuple(args, "l", &i)) + { + PyErr_SetString(PyExc_TypeError, "must be called with an index as an argument"); + return NULL; + } + if (!obarr_valid_index(self, i)) + { + PyErr_SetString(PyExc_IndexError, "index not in range"); + return NULL; + } + + obarr_del_index(self, i); + + Py_INCREF(Py_None); + return Py_None; +} + +int Obarr_contains(PyObject* self_in, PyObject* other_in) +{ + ObarrObject* self = (ObarrObject*)self_in; + long i; + i = obarr_find(self, other_in); + if (i == -1) + return 0; + return 1; +} + +PyObject* Obarr_index(PyObject* self_in, PyObject* args) +{ + ObarrObject* self = (ObarrObject*)self_in; + long i; + PyObject* other_in = NULL; + if (!PyArg_ParseTuple(args, "O", &other_in)) + { + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return NULL; + } + i = obarr_find(self, other_in); + if (i == -1) + { + PyErr_SetString(PyExc_ValueError, "not found"); + return NULL; + } + return PyInt_FromLong(i); +} + +PyObject* Obarr_find(PyObject* self_in, PyObject* args) +{ + ObarrObject* self = (ObarrObject*)self_in; + long i; + PyObject* other_in = NULL; + if (!PyArg_ParseTuple(args, "O", &other_in)) + { + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return NULL; + } + + i = obarr_find(self, other_in); + return PyInt_FromLong(i); +} + +int compare_doubles(const void *a, const void *b) +{ + const sortkey *sa = (const sortkey*)a; + const sortkey *sb = (const sortkey*)b; + + return (sa->d > sb->d) - (sa->d < sb->d); +} + +PyObject* Obarr_sort(PyObject* self_in, PyObject* args) +{ + ObarrObject* self = (ObarrObject*)self_in; + ObarrObject* other = NULL; + PyObject* other_in = NULL; + PyObject* pyfloat = NULL; + sortkey* pSortkeys = NULL; + PyObject** pNewData = NULL; + long i; + + if (!PyArg_ParseTuple(args, "O!", &ObarrObjectType, &other_in)) + { + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return NULL; + } + other = (ObarrObject*)other_in; + + if (other->nSize != self->nSize) + { + PyErr_SetString(PyExc_ValueError, "array to sort by must be the same size"); + return NULL; + } + + pSortkeys = malloc(sizeof(sortkey) * self->nSize); + if (!pSortkeys) + { + PyErr_SetString(PyExc_MemoryError, "insufficient free memory"); + return NULL; + } + + for (i = 0; i < self->nSize; i++) + { + pyfloat = other->pData[i]; + if (!PyFloat_Check(pyfloat)) + { + PyErr_SetString(PyExc_TypeError, "array to sort by must contain only floats"); + return NULL; + } + pSortkeys[i].d = PyFloat_AsDouble(pyfloat); + pSortkeys[i].i = i; + } + + qsort(pSortkeys, self->nSize, sizeof(sortkey), compare_doubles); + + pNewData = malloc(self->nAllocSize * sizeof(void*)); + if (!pNewData) + { + PyErr_SetString(PyExc_MemoryError, "insufficient free memory"); + return NULL; + } + + memcpy(pNewData, self->pData, self->nAllocSize * sizeof(void*)); + for (i = 0; i < self->nSize; i++) + { + pNewData[i] = self->pData[pSortkeys[i].i]; + } + free(pSortkeys); + free(self->pData); + self->pData = pNewData; + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* Obarr_append(PyObject* self_in, PyObject* args) +{ + ObarrObject* self = (ObarrObject*)self_in; + PyObject* other_in = NULL; + long index; + int r; + if (!PyArg_ParseTuple(args, "O", &other_in)) + { + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return NULL; + } + index = self->nSize; + r = obarr_set_size(self, self->nSize + 1); + if (!r) + { + PyErr_SetString(PyExc_MemoryError, "insufficient free memory"); + return NULL; + } + + obarr_set_element(self, index, other_in); + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* Obarr_resize(PyObject* self_in, PyObject* args) +{ + ObarrObject* self = (ObarrObject*)self_in; + long newsize; + int r; + if (!PyArg_ParseTuple(args, "l", &newsize)) + { + PyErr_SetString(PyExc_TypeError, "wrong arguments"); + return NULL; + } + r = obarr_set_size(self, newsize); + if (!r) + { + PyErr_SetString(PyExc_MemoryError, "insufficient free memory"); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + + + +PyObject* Obarr_clear(PyObject* self_in, PyObject* args) +{ + ObarrObject* self = (ObarrObject*)self_in; + obarr_empty(self); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* Obarr_debug(PyObject* self_in, PyObject* args) +{ + ObarrObject* self = (ObarrObject*)self_in; + printf("AllocSize: %d\n", self->nAllocSize); + printf("Chunk: %d\n", self->nChunkSize); + printf("Size: %d\n", self->nSize); + Py_INCREF(Py_None); + return Py_None; + +} diff --git a/obarr.h b/obarr.h new file mode 100644 index 0000000..18dac9f --- /dev/null +++ b/obarr.h @@ -0,0 +1,130 @@ +#include +#include + +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +#endif + +typedef struct ObarrObject { + PyObject_HEAD + PyObject** pData; + long nSize; + long nChunkSize; + long nAllocSize; + void* pInternal_; +} ObarrObject; + +#define Obarr_Check(op) PyObject_TypeCheck(op, &ObarrObjectType) + +/* internal functions (note lowercase obarr) */ +PyObject* obarr_get_element(ObarrObject* self, long index); +long obarr_find(ObarrObject* self, PyObject* other_in); +void obarr_set_element(ObarrObject* self, long index, PyObject* new_in); +void obarr_empty(ObarrObject* self); +void obarr_del_index(ObarrObject* self, long i); +int obarr_valid_index(ObarrObject* self, long i); +int obarr_set_size(ObarrObject* self, long size); + +/* exposed API functions (note uppercase Obarr) */ +int Obarr_init(ObarrObject *self, PyObject *args, PyObject *kwds); +void Obarr_dealloc(PyObject* self_in); +PyObject* Obarr_repr(PyObject *self_in); +Py_ssize_t Obarr_len(PyObject *self_in); +PyObject * Obarr_item(PyObject *self_in, Py_ssize_t index); +int Obarr_setitem(PyObject* self_in, Py_ssize_t index, PyObject* new_in); +PyObject* Obarr_remove(PyObject* self_in, PyObject* args); +PyObject* Obarr_delete(PyObject* self_in, PyObject* args); +int Obarr_contains(PyObject* self_in, PyObject* other_in); +PyObject* Obarr_index(PyObject* self_in, PyObject* args); +PyObject* Obarr_find(PyObject* self_in, PyObject* args); +PyObject* Obarr_sort(PyObject* self_in, PyObject* args); +PyObject* Obarr_append(PyObject* self_in, PyObject* args); +PyObject* Obarr_resize(PyObject* self_in, PyObject* args); +PyObject* Obarr_clear(PyObject* self_in, PyObject* args); +PyObject* Obarr_debug(PyObject* self_in, PyObject* args); + +/* sorting tools */ +typedef struct _sortkey +{ + double d; + long i; +} sortkey; +int compare_doubles(const void *a, const void *b); + + +/* Python object definition structures */ +static PySequenceMethods Obarr_as_seq[] = { + Obarr_len, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + Obarr_item, /* sq_item */ + 0, /* sq_slice */ + Obarr_setitem, /* sq_ass_item */ + 0, /* sq_ass_slice */ + Obarr_contains, /* sq_contains */ +}; + +static PyMethodDef Obarr_methods[] = { + {"resize", (PyCFunction)Obarr_resize, METH_VARARGS, "allocate the array to a new size"}, + {"clear", (PyCFunction)Obarr_clear, METH_NOARGS, "delete everything in the array"}, + {"append", (PyCFunction)Obarr_append, METH_VARARGS, "append the object to the array"}, + {"find", (PyCFunction)Obarr_find, METH_VARARGS, "find the index of an object in the array"}, + {"index", (PyCFunction)Obarr_index, METH_VARARGS, "find the index of an object in the array"}, + {"debug", (PyCFunction)Obarr_debug, METH_NOARGS, "debug"}, + {"delete", (PyCFunction)Obarr_delete, METH_VARARGS, "delete a specific index in the array"}, + {"remove", (PyCFunction)Obarr_remove, METH_VARARGS, "remove an object from the array"}, + {"sort", (PyCFunction)Obarr_sort, METH_VARARGS, "sorts the array using another obarr of floats as sortkeys"}, + {NULL} +}; + +static struct PyMemberDef Obarr_members[] = { + /*{"x", T_OBJECT_EX, offsetof(ObarrObject, x), 0, "x"}, + {"y", T_OBJECT_EX, offsetof(ObarrObject, y), 0, "y"}, + {"z", T_OBJECT_EX, offsetof(ObarrObject, z), 0, "z"},*/ + {NULL} /* Sentinel */ +}; + + +static PyTypeObject ObarrObjectType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "pyobarr.obarr", /* tp_name */ + sizeof(ObarrObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + Obarr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + Obarr_repr, /* tp_repr */ + 0, /* tp_as_number */ + Obarr_as_seq, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + "Vector objects are simple.", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Obarr_methods, /* tp_methods */ + Obarr_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Obarr_init, /* tp_init */ +}; + + diff --git a/pyobarr.c b/pyobarr.c new file mode 100644 index 0000000..64935e5 --- /dev/null +++ b/pyobarr.c @@ -0,0 +1,31 @@ +#include "obarr.h" +#include "cgrid.h" + + +static PyMethodDef ModMethods[] = { + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +PyMODINIT_FUNC +initpy3dutil(void) +{ + PyObject* m; + + ObarrObjectType.tp_new = PyType_GenericNew; + CgridObjectType.tp_new = PyType_GenericNew; + if (PyType_Ready(&ObarrObjectType) < 0) + return; + if (PyType_Ready(&CgridObjectType) < 0) + return; + + (void) Py_InitModule("py3dutil", ModMethods); + m = Py_InitModule3("py3dutil", NULL, + "Example module that creates an extension type."); + if (m == NULL) + return; + + Py_INCREF(&ObarrObjectType); + Py_INCREF(&CgridObjectType); + PyModule_AddObject(m, "obarr", (PyObject *)&ObarrObjectType); + PyModule_AddObject(m, "cgrid", (PyObject *)&CgridObjectType); +} diff --git a/quat.c b/quat.c new file mode 100644 index 0000000..970efcd --- /dev/null +++ b/quat.c @@ -0,0 +1,598 @@ + +#include + +#ifdef _MSC_VER +#define isnan(x) ((x) != (x)) +#define isinf(x) ((x) != (x)) +#endif + +#define VECLEN 4 + +#define MATH_PI (atan(1.0)*4.0) +#define RAD2DEG (180.0 / MATH_PI) +#define DEG2RAD (MATH_PI / 180.0) + + + +staticforward PyTypeObject QuatObjectType; + +int Quat_init(VectObject *self, PyObject *args, PyObject *kwds) +{ +#if defined (VEC3D) + double inx, iny, inz, inw; + if (!PyArg_ParseTuple(args, "dddd", &inx, &iny, &inz, &inw)) + return -1; + + self->elements[0] = inx; + self->elements[1] = iny; + self->elements[2] = inz; + self->elements[3] = inw; + + return 0; +} + +PyObject* Quat_get_element(PyObject* self_in, int index) +{ + VectObject* self = (VectObject*)self_in; + return PyFloat_FromDouble(self->elements[index]); +} + +PyObject* Quat_getx(PyObject* self_in, void* closure) +{ + return Quat_get_element(self_in, 0); +} + +PyObject* Quat_gety(PyObject* self_in, void* closure) +{ + return Quat_get_element(self_in, 1); +} + +#if defined (VEC3D) +PyObject* Quat_getz(PyObject* self_in, void* closure) +{ + return Quat_get_element(self_in, 2); +} +#endif + +int +Quat_set_notallowed(PyObject* self_in, PyObject* value, void* closure) +{ + PyErr_SetString(PyExc_TypeError, "Vectors cannot be set directly"); + return -1; +} + + + +PyObject* Quat_repr(PyObject *self_in) +{ + VectObject *self; + PyObject *tuple, *fmtstring, *reprstring; + + if (!Quat_Check(self_in)) + return PyString_FromString(""); + self = (VectObject*)self_in; + +#if defined (VEC3D) + tuple = Py_BuildValue("(ddd)", self->elements[0], self->elements[1], self->elements[2]); + fmtstring = PyString_FromString("vect(%f, %f, %f)"); + reprstring = PyString_Format(fmtstring, tuple); + Py_DECREF(tuple); + Py_DECREF(fmtstring); + return reprstring; +#else + return PyString_FromString(""); +#endif +} + + +int Quat_true(PyObject *self_in) +{ + VectObject *self = (VectObject*)self_in; + int b = 1; + int i; + double x; + for (i = 0; i < VECLEN; i++) + { + x = self->elements[i]; + b = b && (x == 0.0 || isnan(x) || isinf(x)); + } + + return !b; +} + +PyObject* Quat_add(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *other, *rv; + int i; + if (!Quat_Check(self_in) || !Quat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "both arguments must be of type 'vect'"); + return NULL; + } + self = (VectObject*)self_in; + other = (VectObject*)other_in; + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i] + other->elements[i]; + + return (PyObject*)rv; +} + +PyObject* Quat_sub(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *other, *rv; + int i; + if (!Quat_Check(self_in) || !Quat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "both arguments must be of type 'vect'"); + return NULL; + } + self = (VectObject*)self_in; + other = (VectObject*)other_in; + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i] - other->elements[i]; + + return (PyObject*)rv; +} + +PyObject* Quat_mul(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *rv; + int i; + double scalar; + if (!Quat_Check(self_in) || !PyFloat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "'vect' can only be multiplied by a scalar"); + return NULL; + } + + self = (VectObject*)self_in; + scalar = PyFloat_AsDouble(other_in); + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i] * scalar; + + return (PyObject*)rv; +} + +PyObject* Quat_div(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *rv; + int i; + double scalar; + if (!Quat_Check(self_in) || !PyFloat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "'vect' can only be divided by a scalar"); + return NULL; + } + self = (VectObject*)self_in; + scalar = PyFloat_AsDouble(other_in); + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i] / scalar; + + return (PyObject*)rv; +} + +PyObject* Quat_ip_add(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *other; + int i; + if (!Quat_Check(self_in) || !Quat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "both arguments must be of type 'vect'"); + return NULL; + } + self = (VectObject*)self_in; + other = (VectObject*)other_in; + for (i = 0; i < VECLEN; i++) + self->elements[i] += other->elements[i]; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Quat_ip_sub(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *other; + int i; + + if (!Quat_Check(self_in) || !Quat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "both arguments must be of type 'vect'"); + return NULL; + } + self = (VectObject*)self_in; + other = (VectObject*)other_in; + for (i = 0; i < VECLEN; i++) + self->elements[i] -= other->elements[i]; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Quat_ip_mul(PyObject *self_in, PyObject *other_in) +{ + VectObject *self; + int i; + double scalar; + if (!Quat_Check(self_in) || !PyFloat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "'vect' can only be multiplied by a scalar"); + return NULL; + } + self = (VectObject*)self_in; + scalar = PyFloat_AsDouble(other_in); + for (i = 0; i < VECLEN; i++) + self->elements[i] *= scalar; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Quat_ip_div(PyObject *self_in, PyObject *other_in) +{ + VectObject *self; + int i; + double scalar; + if (!Quat_Check(self_in) || !PyFloat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "'vect' can only be divided by a scalar"); + return NULL; + } + self = (VectObject*)self_in; + scalar = PyFloat_AsDouble(other_in); + for (i = 0; i < VECLEN; i++) + self->elements[i] /= scalar; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Quat_negate(PyObject *self_in) +{ + VectObject *self, *rv; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = -self->elements[i]; + + return (PyObject*)rv; +} + +PyObject* Quat_ip_negate(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + for (i = 0; i < VECLEN; i++) + self->elements[i] = -self->elements[i]; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Quat_ip_zero(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + for (i = 0; i < VECLEN; i++) + self->elements[i] = 0.0; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Quat_ip_normalize(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + double mag, mag2; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + mag2 = 0.0; + for (i = 0; i < VECLEN; i++) + mag2 += self->elements[i] * self->elements[i]; + if ((1.0 - mag2) < -0.001 || (1.0 - mag2) > 0.001) + { + mag = sqrt(mag2); + for (i = 0; i < VECLEN; i++) + self->elements[i] /= mag; + } + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Quat_mag(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + double d; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + d = 0.0; + for (i = 0; i < VECLEN; i++) + d += self->elements[i] * self->elements[i]; + d = sqrt(d); + + return PyFloat_FromDouble(d); +} + +PyObject* Quat_mag2(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + double d; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + d = 0.0; + for (i = 0; i < VECLEN; i++) + d += self->elements[i] * self->elements[i]; + + return PyFloat_FromDouble(d); +} + +PyObject* Quat_dotprod(PyObject *self_in, PyObject *args) +{ + VectObject *self, *other; + double d; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + if (!PyArg_ParseTuple(args, "O!", &VectObjectType, &other)) + { + PyErr_SetString(PyExc_TypeError, "argument is not a vector"); + return NULL; + } +/* Python code is: + value = sum([self[i] * other[i] for i in range(3)]) + if value >= 1.0: + return 0.0 + return math.acos(value) * 180.0 / math.pi +*/ + + d = 0.0; + for (i = 0; i < VECLEN; i++) + d += self->elements[i] * other->elements[i]; + if (d >= 1.0) + return PyFloat_FromDouble(0.0); + + return PyFloat_FromDouble(acos(d) * RAD2DEG); +} + +PyObject * +Quat_crossprod(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + double d; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + d = 0.0; + for (i = 0; i < VECLEN; i++) + d += self->elements[i] * self->elements[i]; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Quat_average(PyObject *self_in, PyObject *args) +{ + VectObject *self, *other, *rv; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + if (!PyArg_ParseTuple(args, "O!", &VectObjectType, &other)) + { + PyErr_SetString(PyExc_TypeError, "argument is not a vector"); + return NULL; + } + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = (self->elements[i] + other->elements[i]) / 2.0; + + return (PyObject*)rv; +} + +PyObject* Quat_dir(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + double d; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + d = 0.0; + for (i = 0; i < VECLEN; i++) + d += self->elements[i] * self->elements[i]; + + return PyFloat_FromDouble(d); +} + +PyObject* Quat_copy(PyObject *self_in, PyObject *unused) +{ + VectObject *self, *rv; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i]; + + return (PyObject*)rv; +} + +PyObject* Quat_dist(PyObject *self_in, PyObject *args) +{ + VectObject *self, *other; + double d, dd; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + if (!PyArg_ParseTuple(args, "O!", &VectObjectType, &other)) + { + PyErr_SetString(PyExc_TypeError, "argument is not a vector"); + return NULL; + } + d = 0.0; + dd = 0.0; + for (i = 0; i < VECLEN; i++) + { + dd = self->elements[i] - other->elements[i]; + d += dd * dd; + } + + return PyFloat_FromDouble(sqrt(d)); +} + +PyObject* Quat_slerp(PyObject *self_in, PyObject *args) +{ + VectObject *self, *other, *rv; + double amt, oamt; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + amt = 0.0; + if (!PyArg_ParseTuple(args, "O!d", &VectObjectType, &other, &amt)) + { + PyErr_SetString(PyExc_TypeError, "arguments must be a vector and a float"); + return NULL; + } + oamt = 1.0 - amt; + rv = PyObject_New(VectObject, &VectObjectType); + + for (i = 0; i < VECLEN; i++) + { + rv->elements[i] = (self->elements[i] * oamt) + (other->elements[i] * amt); + } + + return (PyObject*)rv; +} + +PyObject* Quat_sserp(PyObject *self_in, PyObject *args) +{ + VectObject *self, *other, *rv, *norm; + double amt, oamt, smag, omag; + int i; + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + amt = 0.0; + if (!PyArg_ParseTuple(args, "O!d", &VectObjectType, &other, &amt)) + { + PyErr_SetString(PyExc_TypeError, "arguments must be a vector and a float"); + return NULL; + } + oamt = 1.0 - amt; + rv = PyObject_New(VectObject, &VectObjectType); + smag = 0.0; + omag = 0.0; + for (i = 0; i < VECLEN; i++) + { + smag += self->elements[i] * self->elements[i]; + omag += other->elements[i] * other->elements[i]; + rv->elements[i] = (self->elements[i] * oamt) + (other->elements[i] * amt); + } + smag = sqrt(smag); + omag = sqrt(omag); + + norm = (VectObject*)Quat_ip_normalize((PyObject*)rv, NULL); + Py_XDECREF(norm); + + for (i = 0; i < VECLEN; i++) + rv->elements[i] *= (smag + omag) / 2.0; + return (PyObject*)rv; +} + + +int Quat_len(PyObject *self_in) +{ + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return -1; + } + return VECLEN; +} + + +PyObject* Quat_item(PyObject *self_in, int index) +{ + if (!Quat_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + if (index < 0 || index >= VECLEN) + { + PyErr_SetString(PyExc_IndexError, "index not in range"); + return NULL; + } + + return Quat_get_element(self_in, index); + +} + + + diff --git a/red_black_tree.c b/red_black_tree.c new file mode 100644 index 0000000..7216df4 --- /dev/null +++ b/red_black_tree.c @@ -0,0 +1,672 @@ +#include "red_black_tree.h" + +/***********************************************************************/ +/* FUNCTION: RBTreeCreate */ +/**/ +/* INPUTS: All the inputs are names of functions. CompFunc takes to */ +/* void pointers to keys and returns 1 if the first arguement is */ +/* "greater than" the second. DestFunc takes a pointer to a key and */ +/* destroys it in the appropriate manner when the node containing that */ +/* key is deleted. InfoDestFunc is similiar to DestFunc except it */ +/* recieves a pointer to the info of a node and destroys it. */ +/* PrintFunc recieves a pointer to the key of a node and prints it. */ +/* PrintInfo recieves a pointer to the info of a node and prints it. */ +/* If RBTreePrint is never called the print functions don't have to be */ +/* defined and NullFunction can be used. */ +/**/ +/* OUTPUT: This function returns a pointer to the newly created */ +/* red-black tree. */ +/**/ +/* Modifies Input: none */ +/***********************************************************************/ + +rb_red_blk_tree* RBTreeCreate( int (*CompFunc) (const void*,const void*), + void (*DestFunc) (void*), + void (*InfoDestFunc) (void*), + void (*PrintFunc) (const void*), + void (*PrintInfo)(void*)) { + rb_red_blk_tree* newTree; + rb_red_blk_node* temp; + + newTree=(rb_red_blk_tree*) SafeMalloc(sizeof(rb_red_blk_tree)); + newTree->Compare= CompFunc; + newTree->DestroyKey= DestFunc; + newTree->PrintKey= PrintFunc; + newTree->PrintInfo= PrintInfo; + newTree->DestroyInfo= InfoDestFunc; + + /* see the comment in the rb_red_blk_tree structure in red_black_tree.h */ + /* for information on nil and root */ + temp=newTree->nil= (rb_red_blk_node*) SafeMalloc(sizeof(rb_red_blk_node)); + temp->parent=temp->left=temp->right=temp; + temp->red=0; + temp->key=0; + temp=newTree->root= (rb_red_blk_node*) SafeMalloc(sizeof(rb_red_blk_node)); + temp->parent=temp->left=temp->right=newTree->nil; + temp->key=0; + temp->red=0; + return(newTree); +} + +/***********************************************************************/ +/* FUNCTION: LeftRotate */ +/**/ +/* INPUTS: This takes a tree so that it can access the appropriate */ +/* root and nil pointers, and the node to rotate on. */ +/**/ +/* OUTPUT: None */ +/**/ +/* Modifies Input: tree, x */ +/**/ +/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ +/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ +/* makes the parent of x be to the left of x, x the parent of */ +/* its parent before the rotation and fixes other pointers */ +/* accordingly. */ +/***********************************************************************/ + +void LeftRotate(rb_red_blk_tree* tree, rb_red_blk_node* x) { + rb_red_blk_node* y; + rb_red_blk_node* nil=tree->nil; + + /* I originally wrote this function to use the sentinel for */ + /* nil to avoid checking for nil. However this introduces a */ + /* very subtle bug because sometimes this function modifies */ + /* the parent pointer of nil. This can be a problem if a */ + /* function which calls LeftRotate also uses the nil sentinel */ + /* and expects the nil sentinel's parent pointer to be unchanged */ + /* after calling this function. For example, when RBDeleteFixUP */ + /* calls LeftRotate it expects the parent pointer of nil to be */ + /* unchanged. */ + + y=x->right; + x->right=y->left; + + if (y->left != nil) y->left->parent=x; /* used to use sentinel here */ + /* and do an unconditional assignment instead of testing for nil */ + + y->parent=x->parent; + + /* instead of checking if x->parent is the root as in the book, we */ + /* count on the root sentinel to implicitly take care of this case */ + if( x == x->parent->left) { + x->parent->left=y; + } else { + x->parent->right=y; + } + y->left=x; + x->parent=y; + +#ifdef DEBUG_ASSERT + Assert(!tree->nil->red,"nil not red in LeftRotate"); +#endif +} + + +/***********************************************************************/ +/* FUNCTION: RighttRotate */ +/**/ +/* INPUTS: This takes a tree so that it can access the appropriate */ +/* root and nil pointers, and the node to rotate on. */ +/**/ +/* OUTPUT: None */ +/**/ +/* Modifies Input?: tree, y */ +/**/ +/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ +/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ +/* makes the parent of x be to the left of x, x the parent of */ +/* its parent before the rotation and fixes other pointers */ +/* accordingly. */ +/***********************************************************************/ + +void RightRotate(rb_red_blk_tree* tree, rb_red_blk_node* y) { + rb_red_blk_node* x; + rb_red_blk_node* nil=tree->nil; + + /* I originally wrote this function to use the sentinel for */ + /* nil to avoid checking for nil. However this introduces a */ + /* very subtle bug because sometimes this function modifies */ + /* the parent pointer of nil. This can be a problem if a */ + /* function which calls LeftRotate also uses the nil sentinel */ + /* and expects the nil sentinel's parent pointer to be unchanged */ + /* after calling this function. For example, when RBDeleteFixUP */ + /* calls LeftRotate it expects the parent pointer of nil to be */ + /* unchanged. */ + + x=y->left; + y->left=x->right; + + if (nil != x->right) x->right->parent=y; /*used to use sentinel here */ + /* and do an unconditional assignment instead of testing for nil */ + + /* instead of checking if x->parent is the root as in the book, we */ + /* count on the root sentinel to implicitly take care of this case */ + x->parent=y->parent; + if( y == y->parent->left) { + y->parent->left=x; + } else { + y->parent->right=x; + } + x->right=y; + y->parent=x; + +#ifdef DEBUG_ASSERT + Assert(!tree->nil->red,"nil not red in RightRotate"); +#endif +} + +/***********************************************************************/ +/* FUNCTION: TreeInsertHelp */ +/**/ +/* INPUTS: tree is the tree to insert into and z is the node to insert */ +/**/ +/* OUTPUT: none */ +/**/ +/* Modifies Input: tree, z */ +/**/ +/* EFFECTS: Inserts z into the tree as if it were a regular binary tree */ +/* using the algorithm described in _Introduction_To_Algorithms_ */ +/* by Cormen et al. This funciton is only intended to be called */ +/* by the RBTreeInsert function and not by the user */ +/***********************************************************************/ + +void TreeInsertHelp(rb_red_blk_tree* tree, rb_red_blk_node* z) { + /* This function should only be called by InsertRBTree (see above) */ + rb_red_blk_node* x; + rb_red_blk_node* y; + rb_red_blk_node* nil=tree->nil; + + z->left=z->right=nil; + y=tree->root; + x=tree->root->left; + while( x != nil) { + y=x; + if (1 == tree->Compare(x->key,z->key)) { /* x.key > z.key */ + x=x->left; + } else { /* x,key <= z.key */ + x=x->right; + } + } + z->parent=y; + if ( (y == tree->root) || + (1 == tree->Compare(y->key,z->key))) { /* y.key > z.key */ + y->left=z; + } else { + y->right=z; + } + +#ifdef DEBUG_ASSERT + Assert(!tree->nil->red,"nil not red in TreeInsertHelp"); +#endif +} + +/* Before calling Insert RBTree the node x should have its key set */ + +/***********************************************************************/ +/* FUNCTION: RBTreeInsert */ +/**/ +/* INPUTS: tree is the red-black tree to insert a node which has a key */ +/* pointed to by key and info pointed to by info. */ +/**/ +/* OUTPUT: This function returns a pointer to the newly inserted node */ +/* which is guarunteed to be valid until this node is deleted. */ +/* What this means is if another data structure stores this */ +/* pointer then the tree does not need to be searched when this */ +/* is to be deleted. */ +/**/ +/* Modifies Input: tree */ +/**/ +/* EFFECTS: Creates a node node which contains the appropriate key and */ +/* info pointers and inserts it into the tree. */ +/***********************************************************************/ + +rb_red_blk_node * RBTreeInsert(rb_red_blk_tree* tree, void* key, void* info) { + rb_red_blk_node * y; + rb_red_blk_node * x; + rb_red_blk_node * newNode; + + x=(rb_red_blk_node*) SafeMalloc(sizeof(rb_red_blk_node)); + x->key=key; + x->info=info; + + TreeInsertHelp(tree,x); + newNode=x; + x->red=1; + while(x->parent->red) { /* use sentinel instead of checking for root */ + if (x->parent == x->parent->parent->left) { + y=x->parent->parent->right; + if (y->red) { + x->parent->red=0; + y->red=0; + x->parent->parent->red=1; + x=x->parent->parent; + } else { + if (x == x->parent->right) { + x=x->parent; + LeftRotate(tree,x); + } + x->parent->red=0; + x->parent->parent->red=1; + RightRotate(tree,x->parent->parent); + } + } else { /* case for x->parent == x->parent->parent->right */ + y=x->parent->parent->left; + if (y->red) { + x->parent->red=0; + y->red=0; + x->parent->parent->red=1; + x=x->parent->parent; + } else { + if (x == x->parent->left) { + x=x->parent; + RightRotate(tree,x); + } + x->parent->red=0; + x->parent->parent->red=1; + LeftRotate(tree,x->parent->parent); + } + } + } + tree->root->left->red=0; + return(newNode); + +#ifdef DEBUG_ASSERT + Assert(!tree->nil->red,"nil not red in RBTreeInsert"); + Assert(!tree->root->red,"root not red in RBTreeInsert"); +#endif +} + +/***********************************************************************/ +/* FUNCTION: TreeSuccessor */ +/**/ +/* INPUTS: tree is the tree in question, and x is the node we want the */ +/* the successor of. */ +/**/ +/* OUTPUT: This function returns the successor of x or NULL if no */ +/* successor exists. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: uses the algorithm in _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +rb_red_blk_node* TreeSuccessor(rb_red_blk_tree* tree,rb_red_blk_node* x) { + rb_red_blk_node* y; + rb_red_blk_node* nil=tree->nil; + rb_red_blk_node* root=tree->root; + + if (nil != (y = x->right)) { /* assignment to y is intentional */ + while(y->left != nil) { /* returns the minium of the right subtree of x */ + y=y->left; + } + return(y); + } else { + y=x->parent; + while(x == y->right) { /* sentinel used instead of checking for nil */ + x=y; + y=y->parent; + } + if (y == root) return(nil); + return(y); + } +} + +/***********************************************************************/ +/* FUNCTION: Treepredecessor */ +/**/ +/* INPUTS: tree is the tree in question, and x is the node we want the */ +/* the predecessor of. */ +/**/ +/* OUTPUT: This function returns the predecessor of x or NULL if no */ +/* predecessor exists. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: uses the algorithm in _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +rb_red_blk_node* TreePredecessor(rb_red_blk_tree* tree, rb_red_blk_node* x) { + rb_red_blk_node* y; + rb_red_blk_node* nil=tree->nil; + rb_red_blk_node* root=tree->root; + + if (nil != (y = x->left)) { /* assignment to y is intentional */ + while(y->right != nil) { /* returns the maximum of the left subtree of x */ + y=y->right; + } + return(y); + } else { + y=x->parent; + while(x == y->left) { + if (y == root) return(nil); + x=y; + y=y->parent; + } + return(y); + } +} + +/***********************************************************************/ +/* FUNCTION: InorderTreePrint */ +/**/ +/* INPUTS: tree is the tree to print and x is the current inorder node */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECTS: This function recursively prints the nodes of the tree */ +/* inorder using the PrintKey and PrintInfo functions. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: This function should only be called from RBTreePrint */ +/***********************************************************************/ + +void InorderTreePrint(rb_red_blk_tree* tree, rb_red_blk_node* x) { + rb_red_blk_node* nil=tree->nil; + rb_red_blk_node* root=tree->root; + if (x != tree->nil) { + InorderTreePrint(tree,x->left); + printf("info="); + tree->PrintInfo(x->info); + printf(" key="); + tree->PrintKey(x->key); + printf(" l->key="); + if( x->left == nil) printf("NULL"); else tree->PrintKey(x->left->key); + printf(" r->key="); + if( x->right == nil) printf("NULL"); else tree->PrintKey(x->right->key); + printf(" p->key="); + if( x->parent == root) printf("NULL"); else tree->PrintKey(x->parent->key); + printf(" red=%i\n",x->red); + InorderTreePrint(tree,x->right); + } +} + + +/***********************************************************************/ +/* FUNCTION: TreeDestHelper */ +/**/ +/* INPUTS: tree is the tree to destroy and x is the current node */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECTS: This function recursively destroys the nodes of the tree */ +/* postorder using the DestroyKey and DestroyInfo functions. */ +/**/ +/* Modifies Input: tree, x */ +/**/ +/* Note: This function should only be called by RBTreeDestroy */ +/***********************************************************************/ + +void TreeDestHelper(rb_red_blk_tree* tree, rb_red_blk_node* x) { + rb_red_blk_node* nil=tree->nil; + if (x != nil) { + TreeDestHelper(tree,x->left); + TreeDestHelper(tree,x->right); + tree->DestroyKey(x->key); + tree->DestroyInfo(x->info); + free(x); + } +} + + +/***********************************************************************/ +/* FUNCTION: RBTreeDestroy */ +/**/ +/* INPUTS: tree is the tree to destroy */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: Destroys the key and frees memory */ +/**/ +/* Modifies Input: tree */ +/**/ +/***********************************************************************/ + +void RBTreeDestroy(rb_red_blk_tree* tree) { + TreeDestHelper(tree,tree->root->left); + free(tree->root); + free(tree->nil); + free(tree); +} + + +/***********************************************************************/ +/* FUNCTION: RBTreePrint */ +/**/ +/* INPUTS: tree is the tree to print */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: This function recursively prints the nodes of the tree */ +/* inorder using the PrintKey and PrintInfo functions. */ +/**/ +/* Modifies Input: none */ +/**/ +/***********************************************************************/ + +void RBTreePrint(rb_red_blk_tree* tree) { + InorderTreePrint(tree,tree->root->left); +} + + +/***********************************************************************/ +/* FUNCTION: RBExactQuery */ +/**/ +/* INPUTS: tree is the tree to print and q is a pointer to the key */ +/* we are searching for */ +/**/ +/* OUTPUT: returns the a node with key equal to q. If there are */ +/* multiple nodes with key equal to q this function returns */ +/* the one highest in the tree */ +/**/ +/* Modifies Input: none */ +/**/ +/***********************************************************************/ + +rb_red_blk_node* RBExactQuery(rb_red_blk_tree* tree, void* q) { + rb_red_blk_node* x=tree->root->left; + rb_red_blk_node* nil=tree->nil; + int compVal; + if (x == nil) return(0); + compVal=tree->Compare(x->key,(int*) q); + while(0 != compVal) {/*assignemnt*/ + if (1 == compVal) { /* x->key > q */ + x=x->left; + } else { + x=x->right; + } + if ( x == nil) return(0); + compVal=tree->Compare(x->key,(int*) q); + } + return(x); +} + + +/***********************************************************************/ +/* FUNCTION: RBDeleteFixUp */ +/**/ +/* INPUTS: tree is the tree to fix and x is the child of the spliced */ +/* out node in RBTreeDelete. */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: Performs rotations and changes colors to restore red-black */ +/* properties after a node is deleted */ +/**/ +/* Modifies Input: tree, x */ +/**/ +/* The algorithm from this function is from _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +void RBDeleteFixUp(rb_red_blk_tree* tree, rb_red_blk_node* x) { + rb_red_blk_node* root=tree->root->left; + rb_red_blk_node* w; + + while( (!x->red) && (root != x)) { + if (x == x->parent->left) { + w=x->parent->right; + if (w->red) { + w->red=0; + x->parent->red=1; + LeftRotate(tree,x->parent); + w=x->parent->right; + } + if ( (!w->right->red) && (!w->left->red) ) { + w->red=1; + x=x->parent; + } else { + if (!w->right->red) { + w->left->red=0; + w->red=1; + RightRotate(tree,w); + w=x->parent->right; + } + w->red=x->parent->red; + x->parent->red=0; + w->right->red=0; + LeftRotate(tree,x->parent); + x=root; /* this is to exit while loop */ + } + } else { /* the code below is has left and right switched from above */ + w=x->parent->left; + if (w->red) { + w->red=0; + x->parent->red=1; + RightRotate(tree,x->parent); + w=x->parent->left; + } + if ( (!w->right->red) && (!w->left->red) ) { + w->red=1; + x=x->parent; + } else { + if (!w->left->red) { + w->right->red=0; + w->red=1; + LeftRotate(tree,w); + w=x->parent->left; + } + w->red=x->parent->red; + x->parent->red=0; + w->left->red=0; + RightRotate(tree,x->parent); + x=root; /* this is to exit while loop */ + } + } + } + x->red=0; + +#ifdef DEBUG_ASSERT + Assert(!tree->nil->red,"nil not black in RBDeleteFixUp"); +#endif +} + + +/***********************************************************************/ +/* FUNCTION: RBDelete */ +/**/ +/* INPUTS: tree is the tree to delete node z from */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: Deletes z from tree and frees the key and info of z */ +/* using DestoryKey and DestoryInfo. Then calls */ +/* RBDeleteFixUp to restore red-black properties */ +/**/ +/* Modifies Input: tree, z */ +/**/ +/* The algorithm from this function is from _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +void RBDelete(rb_red_blk_tree* tree, rb_red_blk_node* z){ + rb_red_blk_node* y; + rb_red_blk_node* x; + rb_red_blk_node* nil=tree->nil; + rb_red_blk_node* root=tree->root; + + y= ((z->left == nil) || (z->right == nil)) ? z : TreeSuccessor(tree,z); + x= (y->left == nil) ? y->right : y->left; + if (root == (x->parent = y->parent)) { /* assignment of y->p to x->p is intentional */ + root->left=x; + } else { + if (y == y->parent->left) { + y->parent->left=x; + } else { + y->parent->right=x; + } + } + if (y != z) { /* y should not be nil in this case */ + +#ifdef DEBUG_ASSERT + Assert( (y!=tree->nil),"y is nil in RBDelete\n"); +#endif + /* y is the node to splice out and x is its child */ + + if (!(y->red)) RBDeleteFixUp(tree,x); + + tree->DestroyKey(z->key); + tree->DestroyInfo(z->info); + y->left=z->left; + y->right=z->right; + y->parent=z->parent; + y->red=z->red; + z->left->parent=z->right->parent=y; + if (z == z->parent->left) { + z->parent->left=y; + } else { + z->parent->right=y; + } + free(z); + } else { + tree->DestroyKey(y->key); + tree->DestroyInfo(y->info); + if (!(y->red)) RBDeleteFixUp(tree,x); + free(y); + } + +#ifdef DEBUG_ASSERT + Assert(!tree->nil->red,"nil not black in RBDelete"); +#endif +} + + +/***********************************************************************/ +/* FUNCTION: RBDEnumerate */ +/**/ +/* INPUTS: tree is the tree to look for keys >= low */ +/* and <= high with respect to the Compare function */ +/**/ +/* OUTPUT: stack containing pointers to the nodes between [low,high] */ +/**/ +/* Modifies Input: none */ +/***********************************************************************/ + +#ifdef HAS_STACK +stk_stack* RBEnumerate(rb_red_blk_tree* tree, void* low, void* high) { + stk_stack* enumResultStack; + rb_red_blk_node* nil=tree->nil; + rb_red_blk_node* x=tree->root->left; + rb_red_blk_node* lastBest=nil; + + enumResultStack=StackCreate(); + while(nil != x) { + if ( 1 == (tree->Compare(x->key,high)) ) { /* x->key > high */ + x=x->left; + } else { + lastBest=x; + x=x->right; + } + } + while ( (lastBest != nil) && (1 != tree->Compare(low,lastBest->key))) { + StackPush(enumResultStack,lastBest); + lastBest=TreePredecessor(tree,lastBest); + } + return(enumResultStack); +} + + +#endif + + + + diff --git a/red_black_tree.h b/red_black_tree.h new file mode 100644 index 0000000..a7d490b --- /dev/null +++ b/red_black_tree.h @@ -0,0 +1,71 @@ +#ifdef DMALLOC +#include +#endif +#include"misc.h" +#ifdef HAS_STACK +#include"stack.h" +#endif + +/* CONVENTIONS: All data structures for red-black trees have the prefix */ +/* "rb_" to prevent name conflicts. */ +/* */ +/* Function names: Each word in a function name begins with */ +/* a capital letter. An example funcntion name is */ +/* CreateRedTree(a,b,c). Furthermore, each function name */ +/* should begin with a capital letter to easily distinguish */ +/* them from variables. */ +/* */ +/* Variable names: Each word in a variable name begins with */ +/* a capital letter EXCEPT the first letter of the variable */ +/* name. For example, int newLongInt. Global variables have */ +/* names beginning with "g". An example of a global */ +/* variable name is gNewtonsConstant. */ + +/* comment out the line below to remove all the debugging assertion */ +/* checks from the compiled code. */ +#define DEBUG_ASSERT 1 + +typedef struct rb_red_blk_node { + void* key; + void* info; + int red; /* if red=0 then the node is black */ + struct rb_red_blk_node* left; + struct rb_red_blk_node* right; + struct rb_red_blk_node* parent; +} rb_red_blk_node; + + +/* Compare(a,b) should return 1 if *a > *b, -1 if *a < *b, and 0 otherwise */ +/* Destroy(a) takes a pointer to whatever key might be and frees it accordingly */ +typedef struct rb_red_blk_tree { + int (*Compare)(const void* a, const void* b); + void (*DestroyKey)(void* a); + void (*DestroyInfo)(void* a); + void (*PrintKey)(const void* a); + void (*PrintInfo)(void* a); + /* A sentinel is used for root and for nil. These sentinels are */ + /* created when RBTreeCreate is caled. root->left should always */ + /* point to the node which is the root of the tree. nil points to a */ + /* node which should always be black but has aribtrary children and */ + /* parent and no key or info. The point of using these sentinels is so */ + /* that the root and nil nodes do not require special cases in the code */ + rb_red_blk_node* root; + rb_red_blk_node* nil; +} rb_red_blk_tree; + +rb_red_blk_tree* RBTreeCreate(int (*CompFunc)(const void*, const void*), + void (*DestFunc)(void*), + void (*InfoDestFunc)(void*), + void (*PrintFunc)(const void*), + void (*PrintInfo)(void*)); +rb_red_blk_node * RBTreeInsert(rb_red_blk_tree*, void* key, void* info); +void RBTreePrint(rb_red_blk_tree*); +void RBDelete(rb_red_blk_tree* , rb_red_blk_node* ); +void RBTreeDestroy(rb_red_blk_tree*); +rb_red_blk_node* TreePredecessor(rb_red_blk_tree*,rb_red_blk_node*); +rb_red_blk_node* TreeSuccessor(rb_red_blk_tree*,rb_red_blk_node*); +rb_red_blk_node* RBExactQuery(rb_red_blk_tree*, void*); +#ifdef HAS_STACK +stk_stack * RBEnumerate(rb_red_blk_tree* tree,void* low, void* high); +#endif +void NullFunction(void*); diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..cdce28e --- /dev/null +++ b/setup.py @@ -0,0 +1,22 @@ +from distutils.core import setup, Extension +from cPickle import load, dump +import os + +module1 = Extension('pyobarr', sources = ['pyobarr.c', 'obarr.c', 'cgrid.c', 'red_black_tree.c', 'misc.c']) + +buildno = 0 +if os.path.exists('buildno'): + buildno = load(open('buildno', 'rb')) + buildno += 1 +dump(buildno, open('buildno', 'wb')) + +setup (name = 'py3dutil', + version = '0.1.%.4d' % (buildno,), + description = 'Accelerator library for 3d games', + author = 'Bradley Lawrence', + author_email = 'py3dutil@iambitter.org', + long_description = ''' +Does arrays, vectors, and collision. Does them fast. Oh my yes. +''', + ext_modules = [module1]) + diff --git a/test.py b/test.py new file mode 100644 index 0000000..ccfe6d7 --- /dev/null +++ b/test.py @@ -0,0 +1,34 @@ +#!/usr/bin/python +import time + +from pyobarr import * + +class testclass(object): + def __init__(self): + self.teststr = 'abcdef' + self.otherstr = 'xzlksdf' + def funcfun(self, other): + return other +a = obarr() +a.append('xxx') +for x in range(1000000): + a.append(testclass()) + +for i in range(0, 50000): + a.delete(i) +print "Done" +for x in range(1000000): + a[x] = testclass() +print "Reallocated" + +time.sleep(10) +a.clear() +print "Deallocated" +for x in range(1000000): + a.append(testclass()) +print "Reallocated" +time.sleep(10) + + +time.sleep(100) + diff --git a/vect.c b/vect.c new file mode 100644 index 0000000..24a8b21 --- /dev/null +++ b/vect.c @@ -0,0 +1,611 @@ + +#include + +#ifdef _MSC_VER +#define isnan(x) ((x) != (x)) +#define isinf(x) ((x) != (x)) +#endif + +#define VEC3D + +#ifdef VEC3D +#define VECLEN 3 +#endif + +#ifdef VEC2D +#define VECLEN 2 +#endif + +#define MATH_PI (atan(1.0)*4.0) +#define RAD2DEG (180.0 / MATH_PI) +#define DEG2RAD (MATH_PI / 180.0) + + + +staticforward PyTypeObject VectObjectType; + +int Vect_init(VectObject *self, PyObject *args, PyObject *kwds) +{ +#if defined (VEC3D) + double inx, iny, inz; + if (!PyArg_ParseTuple(args, "ddd", &inx, &iny, &inz)) + return -1; + + self->elements[0] = inx; + self->elements[1] = iny; + self->elements[2] = inz; +#elif defined (VEC2D) + double inx, iny; + if (!PyArg_ParseTuple(args, "dd", &inx, &iny)) + return -1; + + self->elements[0] = inx; + self->elements[1] = iny; +#endif + + return 0; +} + +PyObject* vect_get_element(PyObject* self_in, int index) +{ + VectObject* self = (VectObject*)self_in; + return PyFloat_FromDouble(self->elements[index]); +} + +PyObject* Vect_getx(PyObject* self_in, void* closure) +{ + return vect_get_element(self_in, 0); +} + +PyObject* Vect_gety(PyObject* self_in, void* closure) +{ + return vect_get_element(self_in, 1); +} + +#if defined (VEC3D) +PyObject* Vect_getz(PyObject* self_in, void* closure) +{ + return vect_get_element(self_in, 2); +} +#endif + +int Vect_set_notallowed(PyObject* self_in, PyObject* value, void* closure) +{ + PyErr_SetString(PyExc_TypeError, "Vectors cannot be set directly"); + return -1; +} + + + +PyObject* Vect_repr(PyObject *self_in) +{ + VectObject *self; + PyObject *tuple, *fmtstring, *reprstring; + + if (!Vect_Check(self_in)) + return PyString_FromString(""); + self = (VectObject*)self_in; + +#if defined (VEC3D) + tuple = Py_BuildValue("(ddd)", self->elements[0], self->elements[1], self->elements[2]); + fmtstring = PyString_FromString("vect(%f, %f, %f)"); + reprstring = PyString_Format(fmtstring, tuple); + Py_DECREF(tuple); + Py_DECREF(fmtstring); + return reprstring; +#else + return PyString_FromString(""); +#endif +} + + +int Vect_true(PyObject *self_in) +{ + VectObject *self = (VectObject*)self_in; + int b = 1; + int i; + double x; + for (i = 0; i < VECLEN; i++) + { + x = self->elements[i]; + b = b && (x == 0.0 || isnan(x) || isinf(x)); + } + + return !b; +} + +PyObject* Vect_add(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *other, *rv; + int i; + if (!Vect_Check(self_in) || !Vect_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "both arguments must be of type 'vect'"); + return NULL; + } + self = (VectObject*)self_in; + other = (VectObject*)other_in; + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i] + other->elements[i]; + + return (PyObject*)rv; +} + +PyObject* Vect_sub(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *other, *rv; + int i; + if (!Vect_Check(self_in) || !Vect_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "both arguments must be of type 'vect'"); + return NULL; + } + self = (VectObject*)self_in; + other = (VectObject*)other_in; + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i] - other->elements[i]; + + return (PyObject*)rv; +} + +PyObject* Vect_mul(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *rv; + int i; + double scalar; + if (!Vect_Check(self_in) || !PyFloat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "'vect' can only be multiplied by a scalar"); + return NULL; + } + + self = (VectObject*)self_in; + scalar = PyFloat_AsDouble(other_in); + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i] * scalar; + + return (PyObject*)rv; +} + +PyObject* Vect_div(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *rv; + int i; + double scalar; + if (!Vect_Check(self_in) || !PyFloat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "'vect' can only be divided by a scalar"); + return NULL; + } + self = (VectObject*)self_in; + scalar = PyFloat_AsDouble(other_in); + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i] / scalar; + + return (PyObject*)rv; +} + +PyObject* Vect_ip_add(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *other; + int i; + if (!Vect_Check(self_in) || !Vect_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "both arguments must be of type 'vect'"); + return NULL; + } + self = (VectObject*)self_in; + other = (VectObject*)other_in; + for (i = 0; i < VECLEN; i++) + self->elements[i] += other->elements[i]; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Vect_ip_sub(PyObject *self_in, PyObject *other_in) +{ + VectObject *self, *other; + int i; + + if (!Vect_Check(self_in) || !Vect_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "both arguments must be of type 'vect'"); + return NULL; + } + self = (VectObject*)self_in; + other = (VectObject*)other_in; + for (i = 0; i < VECLEN; i++) + self->elements[i] -= other->elements[i]; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Vect_ip_mul(PyObject *self_in, PyObject *other_in) +{ + VectObject *self; + int i; + double scalar; + if (!Vect_Check(self_in) || !PyFloat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "'vect' can only be multiplied by a scalar"); + return NULL; + } + self = (VectObject*)self_in; + scalar = PyFloat_AsDouble(other_in); + for (i = 0; i < VECLEN; i++) + self->elements[i] *= scalar; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Vect_ip_div(PyObject *self_in, PyObject *other_in) +{ + VectObject *self; + int i; + double scalar; + if (!Vect_Check(self_in) || !PyFloat_Check(other_in)) + { + PyErr_SetString(PyExc_TypeError, "'vect' can only be divided by a scalar"); + return NULL; + } + self = (VectObject*)self_in; + scalar = PyFloat_AsDouble(other_in); + for (i = 0; i < VECLEN; i++) + self->elements[i] /= scalar; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Vect_negate(PyObject *self_in) +{ + VectObject *self, *rv; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = -self->elements[i]; + + return (PyObject*)rv; +} + +PyObject* Vect_ip_negate(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + for (i = 0; i < VECLEN; i++) + self->elements[i] = -self->elements[i]; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Vect_ip_zero(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + for (i = 0; i < VECLEN; i++) + self->elements[i] = 0.0; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Vect_ip_normalize(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + double mag, mag2; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + mag2 = 0.0; + for (i = 0; i < VECLEN; i++) + mag2 += self->elements[i] * self->elements[i]; + if ((1.0 - mag2) < -0.001 || (1.0 - mag2) > 0.001) + { + mag = sqrt(mag2); + for (i = 0; i < VECLEN; i++) + self->elements[i] /= mag; + } + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Vect_mag(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + double d; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + d = 0.0; + for (i = 0; i < VECLEN; i++) + d += self->elements[i] * self->elements[i]; + d = sqrt(d); + + return PyFloat_FromDouble(d); +} + +PyObject* Vect_mag2(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + double d; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + d = 0.0; + for (i = 0; i < VECLEN; i++) + d += self->elements[i] * self->elements[i]; + + return PyFloat_FromDouble(d); +} + +PyObject* Vect_dotprod(PyObject *self_in, PyObject *args) +{ + VectObject *self, *other; + double d; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + if (!PyArg_ParseTuple(args, "O!", &VectObjectType, &other)) + { + PyErr_SetString(PyExc_TypeError, "argument is not a vector"); + return NULL; + } +/* Python code is: + value = sum([self[i] * other[i] for i in range(3)]) + if value >= 1.0: + return 0.0 + return math.acos(value) * 180.0 / math.pi +*/ + + d = 0.0; + for (i = 0; i < VECLEN; i++) + d += self->elements[i] * other->elements[i]; + if (d >= 1.0) + return PyFloat_FromDouble(0.0); + + return PyFloat_FromDouble(acos(d) * RAD2DEG); +} + +PyObject* Vect_crossprod(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + double d; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + d = 0.0; + for (i = 0; i < VECLEN; i++) + d += self->elements[i] * self->elements[i]; + + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* Vect_average(PyObject *self_in, PyObject *args) +{ + VectObject *self, *other, *rv; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + if (!PyArg_ParseTuple(args, "O!", &VectObjectType, &other)) + { + PyErr_SetString(PyExc_TypeError, "argument is not a vector"); + return NULL; + } + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = (self->elements[i] + other->elements[i]) / 2.0; + + return (PyObject*)rv; +} + +PyObject* Vect_dir(PyObject *self_in, PyObject *unused) +{ + VectObject *self; + double d; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + d = 0.0; + for (i = 0; i < VECLEN; i++) + d += self->elements[i] * self->elements[i]; + + return PyFloat_FromDouble(d); +} + +PyObject* Vect_copy(PyObject *self_in, PyObject *unused) +{ + VectObject *self, *rv; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + rv = PyObject_New(VectObject, &VectObjectType); + for (i = 0; i < VECLEN; i++) + rv->elements[i] = self->elements[i]; + + return (PyObject*)rv; +} + +PyObject* Vect_dist(PyObject *self_in, PyObject *args) +{ + VectObject *self, *other; + double d, dd; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + if (!PyArg_ParseTuple(args, "O!", &VectObjectType, &other)) + { + PyErr_SetString(PyExc_TypeError, "argument is not a vector"); + return NULL; + } + d = 0.0; + dd = 0.0; + for (i = 0; i < VECLEN; i++) + { + dd = self->elements[i] - other->elements[i]; + d += dd * dd; + } + + return PyFloat_FromDouble(sqrt(d)); +} + +PyObject* Vect_slerp(PyObject *self_in, PyObject *args) +{ + VectObject *self, *other, *rv; + double amt, oamt; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + amt = 0.0; + if (!PyArg_ParseTuple(args, "O!d", &VectObjectType, &other, &amt)) + { + PyErr_SetString(PyExc_TypeError, "arguments must be a vector and a float"); + return NULL; + } + oamt = 1.0 - amt; + rv = PyObject_New(VectObject, &VectObjectType); + + for (i = 0; i < VECLEN; i++) + { + rv->elements[i] = (self->elements[i] * oamt) + (other->elements[i] * amt); + } + + return (PyObject*)rv; +} + +PyObject* Vect_sserp(PyObject *self_in, PyObject *args) +{ + VectObject *self, *other, *rv, *norm; + double amt, oamt, smag, omag; + int i; + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + self = (VectObject*)self_in; + amt = 0.0; + if (!PyArg_ParseTuple(args, "O!d", &VectObjectType, &other, &amt)) + { + PyErr_SetString(PyExc_TypeError, "arguments must be a vector and a float"); + return NULL; + } + oamt = 1.0 - amt; + rv = PyObject_New(VectObject, &VectObjectType); + smag = 0.0; + omag = 0.0; + for (i = 0; i < VECLEN; i++) + { + smag += self->elements[i] * self->elements[i]; + omag += other->elements[i] * other->elements[i]; + rv->elements[i] = (self->elements[i] * oamt) + (other->elements[i] * amt); + } + smag = sqrt(smag); + omag = sqrt(omag); + + norm = (VectObject*)Vect_ip_normalize((PyObject*)rv, NULL); + Py_XDECREF(norm); + + for (i = 0; i < VECLEN; i++) + rv->elements[i] *= (smag + omag) / 2.0; + return (PyObject*)rv; +} + + +int Vect_len(PyObject *self_in) +{ + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return -1; + } + return VECLEN; +} + + +PyObject* Vect_item(PyObject *self_in, int index) +{ + if (!Vect_Check(self_in)) + { + PyErr_SetString(PyExc_TypeError, "not a vector"); + return NULL; + } + if (index < 0 || index >= VECLEN) + { + PyErr_SetString(PyExc_IndexError, "index not in range"); + return NULL; + } + + return vect_get_element(self_in, index); + +} + + + diff --git a/vect.h b/vect.h new file mode 100644 index 0000000..9b42d60 --- /dev/null +++ b/vect.h @@ -0,0 +1,201 @@ +#include +#include + +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +#endif + +typedef struct { + PyObject_HEAD + double elements[VECLEN]; +} VectObject; + + +#define Vect_Check(op) PyObject_TypeCheck(op, &VectObjectType) +#define VEC3D + +#ifdef VEC3D +#define VECLEN 3 +#endif + +#ifdef VEC2D +#define VECLEN 2 +#endif + + +// internal functions +PyObject* vect_get_element(PyObject* self_in, int index); + +// Python API functions +int Vect_init(VectObject *self, PyObject *args, PyObject *kwds); +PyObject* Vect_getx(PyObject* self_in, void* closure); +PyObject* Vect_gety(PyObject* self_in, void* closure); +#ifdef VEC3D +PyObject* Vect_getz(PyObject* self_in, void* closure); +#endif +int Vect_set_notallowed(PyObject* self_in, PyObject* value, void* closure); +PyObject* Vect_repr(PyObject *self_in); +int Vect_true(PyObject *self_in); +PyObject* Vect_add(PyObject *self_in, PyObject *other_in); +PyObject* Vect_sub(PyObject *self_in, PyObject *other_in); +PyObject* Vect_mul(PyObject *self_in, PyObject *other_in); +PyObject* Vect_div(PyObject *self_in, PyObject *other_in); +PyObject* Vect_ip_add(PyObject *self_in, PyObject *other_in); +PyObject* Vect_ip_sub(PyObject *self_in, PyObject *other_in); +PyObject* Vect_ip_mul(PyObject *self_in, PyObject *other_in); +PyObject* Vect_ip_div(PyObject *self_in, PyObject *other_in); +PyObject* Vect_negate(PyObject *self_in); +PyObject* Vect_ip_negate(PyObject *self_in, PyObject *unused); +PyObject* Vect_ip_zero(PyObject *self_in, PyObject *unused); +PyObject* Vect_ip_normalize(PyObject *self_in, PyObject *unused); +PyObject* Vect_mag(PyObject *self_in, PyObject *unused); +PyObject* Vect_mag2(PyObject *self_in, PyObject *unused); +PyObject* Vect_dotprod(PyObject *self_in, PyObject *args); +PyObject* Vect_crossprod(PyObject *self_in, PyObject *unused); +PyObject* Vect_average(PyObject *self_in, PyObject *args); +PyObject* Vect_dir(PyObject *self_in, PyObject *unused); +PyObject* Vect_copy(PyObject *self_in, PyObject *unused); +PyObject* Vect_dist(PyObject *self_in, PyObject *args); +PyObject* Vect_slerp(PyObject *self_in, PyObject *args); +PyObject* Vect_sserp(PyObject *self_in, PyObject *args); +int Vect_len(PyObject *self_in); +PyObject* Vect_item(PyObject *self_in, int index); + + + + + + +static PyNumberMethods Vect_as_number[] = { + Vect_add, /* nb_add */ + Vect_sub, /* nb_subtract */ + Vect_mul, /* nb_multiply */ + Vect_div, /* nb_divide */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + Vect_negate, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + Vect_true, /* nb_nonzero */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ + 0, /* nb_and */ + 0, /* nb_xor */ + 0, /* nb_or */ + 0, /* nb_coerce */ + 0, /* nb_int */ + 0, /* nb_long */ + 0, /* nb_float */ + 0, /* nb_oct */ + 0, /* nb_hex */ + Vect_ip_add, /* nb_inplace_add */ + Vect_ip_sub, /* nb_inplace_subtract */ + Vect_ip_mul, /* nb_inplace_multiply */ + Vect_ip_div, /* nb_inplace_divide */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + 0, /* nb_floordiv */ + 0, /* nb_truediv */ + 0, /* nb_inplace_floordiv */ + 0, /* nb_inplace_truediv */ + +}; + +static PySequenceMethods Vect_as_seq[] = { + Vect_len, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + Vect_item, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + 0, /* sq_contains */ +}; + +static PyGetSetDef Vect_getset[] = { + {"x", Vect_getx, Vect_set_notallowed, "x", NULL}, + {"y", Vect_gety, Vect_set_notallowed, "y", NULL}, +#if defined (VEC3D) + {"z", Vect_getz, Vect_set_notallowed, "z", NULL}, +#endif + {NULL} +}; + +static PyMethodDef Vect_methods[] = { + {"__add__", (PyCFunction)Vect_add, METH_O|METH_COEXIST, "add two vectors"}, + {"__sub__", (PyCFunction)Vect_sub, METH_O|METH_COEXIST, "subtract two vectors"}, + {"__mul__", (PyCFunction)Vect_mul, METH_O|METH_COEXIST, "multiply a vector by a scalar"}, + {"__div__", (PyCFunction)Vect_div, METH_O|METH_COEXIST, "divide a vector by a scalar"}, + {"__neg__", (PyCFunction)Vect_negate, METH_O|METH_COEXIST, "negate (reverse) a vector"}, + {"zero", (PyCFunction)Vect_ip_zero, METH_NOARGS, "sets all vector components to 0"}, + {"negate", (PyCFunction)Vect_ip_negate, METH_NOARGS, "negate (reverse) a vector in place"}, + {"normalize", (PyCFunction)Vect_ip_normalize, METH_NOARGS, "normalize a vector in place"}, + {"avg", (PyCFunction)Vect_average, METH_VARARGS, "find halfway between this and another vector"}, + {"dot", (PyCFunction)Vect_dotprod, METH_VARARGS, "compute the dot product of this and another vector"}, + {"cross", (PyCFunction)Vect_crossprod, METH_VARARGS, "compute the cross product of this and another vector"}, + {"dist", (PyCFunction)Vect_dist, METH_VARARGS, "compute the distance between this and another vector"}, + {"mag", (PyCFunction)Vect_mag, METH_NOARGS, "compute the vector magnitude"}, + {"mag2", (PyCFunction)Vect_mag2, METH_NOARGS, "compute the squared vector magnitude"}, + {"dir", (PyCFunction)Vect_dir, METH_NOARGS, "compute the vector direction (in Euler angles)"}, + {"copy", (PyCFunction)Vect_copy, METH_NOARGS, "makes a copy"}, + {"slerp", (PyCFunction)Vect_slerp, METH_VARARGS, "spherical linear interpolation"}, + {"sserp", (PyCFunction)Vect_sserp, METH_VARARGS, "spherical spherical interpolation"}, + {NULL} +}; + +static struct PyMemberDef Vect_members[] = { + /*{"x", T_OBJECT_EX, offsetof(VectObject, x), 0, "x"}, + {"y", T_OBJECT_EX, offsetof(VectObject, y), 0, "y"}, + {"z", T_OBJECT_EX, offsetof(VectObject, z), 0, "z"},*/ + {NULL} /* Sentinel */ +}; + + +static PyTypeObject VectObjectType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "py3dutil.vect", /* tp_name */ + sizeof(VectObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + Vect_repr, /* tp_repr */ + Vect_as_number, /* tp_as_number */ + Vect_as_seq, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + "Vector objects are simple.", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Vect_methods, /* tp_methods */ + Vect_members, /* tp_members */ + Vect_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Vect_init, /* tp_init */ +}; \ No newline at end of file