31 #include "../generic/py_capi_utils.h"
32 #include "../generic/python_utildefines.h"
40 PyObject_HEAD KDTree_3d *
obj;
56 PyLong_FromLong(nearest->index),
57 PyFloat_FromDouble(nearest->dist));
64 py_retval = PyTuple_New(3);
75 py_retval = PyTuple_New(3);
77 if (nearest->index != -1) {
91 #define UINT_IS_NEG(n) ((n) > INT_MAX)
96 const char *keywords[] = {
"size",
NULL};
98 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"I:KDTree", (
char **)keywords, &maxsize)) {
103 PyErr_SetString(PyExc_ValueError,
"negative 'size' given");
107 self->obj = BLI_kdtree_3d_new(maxsize);
108 self->maxsize = maxsize;
110 self->count_balance = 0;
117 BLI_kdtree_3d_free(
self->obj);
118 Py_TYPE(
self)->tp_free((PyObject *)
self);
122 ".. method:: insert(co, index)\n"
124 " Insert a point into the KDTree.\n"
126 " :arg co: Point 3d position.\n"
127 " :type co: float triplet\n"
128 " :arg index: The index of the point.\n"
129 " :type index: int\n");
135 const char *keywords[] = {
"co",
"index",
NULL};
137 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"Oi:insert", (
char **)keywords, &py_co, &index)) {
146 PyErr_SetString(PyExc_ValueError,
"negative index given");
151 PyErr_SetString(PyExc_RuntimeError,
"Trying to insert more items than KDTree has room for");
155 BLI_kdtree_3d_insert(
self->obj, index, co);
162 ".. method:: balance()\n"
164 " Balance the tree.\n"
168 " This builds the entire tree, avoid calling after each insertion.\n");
171 BLI_kdtree_3d_balance(
self->obj);
172 self->count_balance =
self->count;
187 PyObject *py_args = PyTuple_New(1);
188 PyTuple_SET_ITEM(py_args, 0, PyLong_FromLong(index));
189 PyObject *
result = PyObject_CallObject(
data->py_filter, py_args);
197 return (
int)use_node;
201 data->is_error =
true;
206 ".. method:: find(co, filter=None)\n"
208 " Find nearest point to ``co``.\n"
210 " :arg co: 3d coordinates.\n"
211 " :type co: float triplet\n"
212 " :arg filter: function which takes an index and returns True for indices to "
213 "include in the search.\n"
214 " :type filter: callable\n"
215 " :return: Returns (:class:`Vector`, index, distance).\n"
216 " :rtype: :class:`tuple`\n");
221 KDTreeNearest_3d nearest;
222 const char *keywords[] = {
"co",
"filter",
NULL};
224 if (!PyArg_ParseTupleAndKeywords(
225 args, kwargs,
"O|O:find", (
char **)keywords, &py_co, &
py_filter)) {
233 if (
self->count !=
self->count_balance) {
234 PyErr_SetString(PyExc_RuntimeError,
"KDTree must be balanced before calling find()");
241 BLI_kdtree_3d_find_nearest(
self->obj, co, &nearest);
247 data.is_error =
false;
260 ".. method:: find_n(co, n)\n"
262 " Find nearest ``n`` points to ``co``.\n"
264 " :arg co: 3d coordinates.\n"
265 " :type co: float triplet\n"
266 " :arg n: Number of points to find.\n"
268 " :return: Returns a list of tuples (:class:`Vector`, index, distance).\n"
269 " :rtype: :class:`list`\n");
275 KDTreeNearest_3d *nearest;
278 const char *keywords[] = {
"co",
"n",
NULL};
280 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"OI:find_n", (
char **)keywords, &py_co, &n)) {
289 PyErr_SetString(PyExc_RuntimeError,
"negative 'n' given");
293 if (
self->count !=
self->count_balance) {
294 PyErr_SetString(PyExc_RuntimeError,
"KDTree must be balanced before calling find_n()");
298 nearest =
MEM_mallocN(
sizeof(KDTreeNearest_3d) * n, __func__);
300 found = BLI_kdtree_3d_find_nearest_n(
self->obj, co, nearest, n);
302 py_list = PyList_New(found);
304 for (i = 0; i < found; i++) {
314 ".. method:: find_range(co, radius)\n"
316 " Find all points within ``radius`` of ``co``.\n"
318 " :arg co: 3d coordinates.\n"
319 " :type co: float triplet\n"
320 " :arg radius: Distance to search for points.\n"
321 " :type radius: float\n"
322 " :return: Returns a list of tuples (:class:`Vector`, index, distance).\n"
323 " :rtype: :class:`list`\n");
329 KDTreeNearest_3d *nearest =
NULL;
333 const char *keywords[] = {
"co",
"radius",
NULL};
335 if (!PyArg_ParseTupleAndKeywords(
336 args, kwargs,
"Of:find_range", (
char **)keywords, &py_co, &radius)) {
345 PyErr_SetString(PyExc_RuntimeError,
"negative radius given");
349 if (
self->count !=
self->count_balance) {
350 PyErr_SetString(PyExc_RuntimeError,
"KDTree must be balanced before calling find_range()");
354 found = BLI_kdtree_3d_range_search(
self->obj, co, &nearest, radius);
356 py_list = PyList_New(found);
358 for (i = 0; i < found; i++) {
370 {
"insert", (PyCFunction)
py_kdtree_insert, METH_VARARGS | METH_KEYWORDS, py_kdtree_insert_doc},
372 {
"find", (PyCFunction)
py_kdtree_find, METH_VARARGS | METH_KEYWORDS, py_kdtree_find_doc},
373 {
"find_n", (PyCFunction)
py_kdtree_find_n, METH_VARARGS | METH_KEYWORDS, py_kdtree_find_n_doc},
376 METH_VARARGS | METH_KEYWORDS,
377 py_kdtree_find_range_doc},
382 "KdTree(size) -> new kd-tree initialized to hold ``size`` items.\n"
386 " :class:`KDTree.balance` must have been called before using any of the ``find`` "
389 PyVarObject_HEAD_INIT(
NULL, 0)
"KDTree",
425 (allocfunc)PyType_GenericAlloc,
426 (newfunc)PyType_GenericNew,
437 PyDoc_STRVAR(py_kdtree_doc,
"Generic 3-dimensional kd-tree to perform spatial searches.");
439 PyModuleDef_HEAD_INIT,
A kd-tree for nearest neighbor search.
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
Read Guarded memory(de)allocation.
void(* MEM_freeN)(void *vmemh)
void *(* MEM_mallocN)(size_t len, const char *str)
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
PyObject * Vector_CreatePyObject(const float *vec, const int size, PyTypeObject *base_type)
static int PyKDTree__tp_init(PyKDTree *self, PyObject *args, PyObject *kwargs)
static void kdtree_nearest_to_py_tuple(const KDTreeNearest_3d *nearest, PyObject *py_retval)
static PyObject * py_kdtree_balance(PyKDTree *self)
PyTypeObject PyKDTree_Type
PyMODINIT_FUNC PyInit_mathutils_kdtree(void)
static PyObject * py_kdtree_find_range(PyKDTree *self, PyObject *args, PyObject *kwargs)
static PyObject * kdtree_nearest_to_py_and_check(const KDTreeNearest_3d *nearest)
static struct PyModuleDef kdtree_moduledef
static void PyKDTree__tp_dealloc(PyKDTree *self)
static PyMethodDef PyKDTree_methods[]
static int py_find_nearest_cb(void *user_data, int index, const float co[3], float dist_sq)
static PyObject * py_kdtree_find_n(PyKDTree *self, PyObject *args, PyObject *kwargs)
static PyObject * py_kdtree_find(PyKDTree *self, PyObject *args, PyObject *kwargs)
PyDoc_STRVAR(py_kdtree_insert_doc, ".. method:: insert(co, index)\n" "\n" " Insert a point into the KDTree.\n" "\n" " :arg co: Point 3d position.\n" " :type co: float triplet\n" " :arg index: The index of the point.\n" " :type index: int\n")
static PyObject * kdtree_nearest_to_py(const KDTreeNearest_3d *nearest)
static PyObject * py_kdtree_insert(PyKDTree *self, PyObject *args, PyObject *kwargs)
int PyC_ParseBool(PyObject *o, void *p)
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value)
#define PyTuple_SET_ITEMS(op_arg,...)
PyObject_HEAD KDTree_3d * obj