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:
commit
65350ebdfc
14 changed files with 3372 additions and 0 deletions
356
cgrid.c
Normal file
356
cgrid.c
Normal 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
128
cgrid.h
Normal 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
60
misc.c
Normal 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
34
misc.h
Normal 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
424
obarr.c
Normal 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
130
obarr.h
Normal 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
31
pyobarr.c
Normal 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
598
quat.c
Normal 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
672
red_black_tree.c
Normal 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
71
red_black_tree.h
Normal 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
22
setup.py
Normal 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
34
test.py
Normal 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
611
vect.c
Normal 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
201
vect.h
Normal 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 */
|
||||
};
|
Loading…
Add table
Reference in a new issue