py3dutil/cgrid.c
cecilkorik aff2400534 --HG--
branch : py3dutil
2008-02-17 20:44:49 +00:00

557 lines
No EOL
13 KiB
C

#include "cgrid.h"
#include "obarr.h"
#include "red_black_tree.h"
#include <math.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);
}
long cgrid_coord_to_gridcoord(CgridObject* self, double coord)
{
return long(floor(coord / self->dCellSize));
}
ObarrObject* cgrid_get_radius(CgridObject *self, PyObject *other, double dRadius)
{
ObarrObject *pNeighbors;
pNeighbors = PyObject_New(ObarrObject, &ObarrObjectType);
if (!cgrid_get_radius_append(pNeighbors))
{
Py_DECREF(pNeighbors);
return NULL;
}
return pNeighbors;
}
void* cgrid_get_radius_append(CgridObject *self, PyObject *other, double dRadius, ObarrObject *pNeighbors)
{
PyObject *el = NULL;
rb_red_blk_node* pNode = NULL;
PyObject *pAttr;
CgridInfo *pV;
CgridKey k;
double dRe;
double dX, dY, dZ;
double dXi, dYi, dZi;
double dXs, dYs, dZs;
double dXe, dYe, dZe;
long x, y, r, i;
if (!PyArg_ParseTuple(args, "Od", &other, &dRadius))
{
PyErr_SetString(PyExc_TypeError, "wrong arguments");
return NULL;
}
pAttr = PyObject_GetAttrString(other, "pos")
if (!pAttr)
{
PyErr_SetString(PyExc_TypeError, "missing 'pos' attribute of input object");
return NULL;
}
if (!PyArg_ParseTuple(pAttr, "ddd", &dX, &dY, &dZ))
{
Py_DECREF(pAttr);
PyErr_SetString(PyExc_TypeError, "invalid 'pos' attribute of input object");
return NULL;
}
Py_DECREF(pAttr);
dXs = dX + dRadius + (self->dCellSize * 0.1);
dYs = dY + dRadius + (self->dCellSize * 0.1);
dZs = dZ + dRadius + (self->dCellSize * 0.1);
for (dXi = (dX - dRadius); dXi <= dXs; dXi += self->dCellSize)
{
for (dYi = (dY - dRadius); dYi <= dYs; dYi += self->dCellSize)
{
for (dZi = (dZ - dRadius); dZi <= dZs; dZi += self->dCellSize)
{
k.x = cgrid_coord_to_gridcoord(dXi);
k.y = cgrid_coord_to_gridcoord(dYi);
k.z = cgrid_coord_to_gridcoord(dZi);
pNode = RBExactQuery(self->pTree, &k);
if (pNode)
{
pV = (CgridInfo*)pNode->info;
for (i = 0; i < pV->pContents->nSize; i++)
{
el = obarr_get_element(pV->pContents, i);
pAttr = PyObject_GetAttrString(other, "pos");
if (!pAttr)
{
PyErr_SetString(PyExc_TypeError, "missing 'pos' attribute of object in grid");
return NULL;
}
if (!PyArg_ParseTuple(pAttr, "ddd", &dXe, &dYe, &dZe))
{
Py_DECREF(pAttr);
PyErr_SetString(PyExc_TypeError, "invalid 'pos' attribute of object in grid");
return NULL;
}
Py_DECREF(pAttr);
pAttr = PyObject_GetAttrString(other, "radius");
if (!pAttr)
dRe = 0.0;
else if (!PyFloat_Check(pAttr))
{
Py_DECREF(pAttr);
PyErr_SetString(PyExc_TypeError, "invalid 'radius' attribute of object in grid");
return NULL;
}
else
dRe = PyFloat_AsDouble(pAttr);
Py_DECREF(pAttr);
dDist = sqrt(SQR(dXe - dX) + SQR(dYe - dY) + SQR(dZe - dZ)) - dRe;
if (dDist > dRadius)
continue;
if (!obarr_append(pNeighbors, el))
{
PyErr_SetString(PyExc_MemoryError, "out of memory");
return NULL;
}
}
}
}
}
}
return pNeighbors;
}
int Cgrid_init(CgridObject *self, PyObject *args, PyObject *kwds)
{
double dCell;
if (!PyArg_ParseTuple(args, "d", &dCell))
{
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->dCellSize = dCell;
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;
}
PyObject* Cgrid_get_radius(PyObject *self_in, PyObject *args)
{
CgridObject *self = (CgridObject*)self_in;
PyObject *other = NULL;
double dRadius;
if (!PyArg_ParseTuple(args, "Od", &other, &dRadius))
{
PyErr_SetString(PyExc_TypeError, "wrong arguments");
return NULL;
}
return cgrid_get_radius(self, other, dRadius);
}
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 */
};
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}
};
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 */
};
PyTypeObject CgridObjectType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"py3dutil.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 */
};