consolidated pyvec3d and pyobarr into new "py3dutil"

added cgrid for collision
added quaternion class (not working yet)

--HG--
branch : py3dutil
This commit is contained in:
cecilkorik 2007-11-15 19:44:58 +00:00
commit 65350ebdfc
14 changed files with 3372 additions and 0 deletions

356
cgrid.c Normal file
View file

@ -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("<GridKey(%d, %d, %d)>", sa->x, sa->y, sa->z);
}
void cgrid_printinfo(void* a)
{
ObarrObject* arr = (ObarrObject*)a;
printf("<Obarr size %d>", 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("<unknown object type>");
self = (CgridObject*)self_in;
tuple = Py_BuildValue("(ii)", self->nCells, self->nSize);
fmtstring = PyString_FromString("<cgrid of %d cells, %d objects>");
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;
}

128
cgrid.h Normal file
View file

@ -0,0 +1,128 @@
#include <Python.h>
#include <structmember.h>
#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 */
};

60
misc.c Normal file
View file

@ -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) { ; }

34
misc.h Normal file
View file

@ -0,0 +1,34 @@
#include<stdio.h>
#include<stdlib.h>
#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

424
obarr.c Normal file
View file

@ -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("<unknown object type>");
self = (ObarrObject*)self_in;
tuple = Py_BuildValue("(l)", self->nSize);
fmtstring = PyString_FromString("<array of %d objects>");
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;
}

130
obarr.h Normal file
View file

@ -0,0 +1,130 @@
#include <Python.h>
#include <structmember.h>
#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 */
};

31
pyobarr.c Normal file
View file

@ -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);
}

598
quat.c Normal file
View file

@ -0,0 +1,598 @@
#include <math.h>
#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("<unknown object type>");
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("<unknown object type>");
#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);
}

672
red_black_tree.c Normal file
View file

@ -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

71
red_black_tree.h Normal file
View file

@ -0,0 +1,71 @@
#ifdef DMALLOC
#include <dmalloc.h>
#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*);

22
setup.py Normal file
View file

@ -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])

34
test.py Normal file
View file

@ -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)

611
vect.c Normal file
View file

@ -0,0 +1,611 @@
#include <math.h>
#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("<unknown object type>");
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("<unknown object type>");
#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);
}

201
vect.h Normal file
View file

@ -0,0 +1,201 @@
#include <Python.h>
#include <structmember.h>
#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 */
};