45 PyLong_FromLong(nearest->index),
46 PyFloat_FromDouble(nearest->dist));
53 py_retval = PyTuple_New(3);
64 py_retval = PyTuple_New(3);
66 if (nearest->index != -1) {
80#define UINT_IS_NEG(n) ((n) > INT_MAX)
85 const char *keywords[] = {
"size",
nullptr};
87 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"I:KDTree", (
char **)keywords, &maxsize)) {
92 PyErr_SetString(PyExc_ValueError,
"negative 'size' given");
96 self->obj = BLI_kdtree_3d_new(maxsize);
97 self->maxsize = maxsize;
99 self->count_balance = 0;
106 BLI_kdtree_3d_free(
self->obj);
107 Py_TYPE(
self)->tp_free((PyObject *)
self);
112 py_kdtree_insert_doc,
113 ".. method:: insert(co, index)\n"
115 " Insert a point into the KDTree.\n"
117 " :arg co: Point 3d position.\n"
118 " :type co: Sequence[float]\n"
119 " :arg index: The index of the point.\n"
120 " :type index: int\n");
126 const char *keywords[] = {
"co",
"index",
nullptr};
128 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"Oi:insert", (
char **)keywords, &py_co, &index)) {
137 PyErr_SetString(PyExc_ValueError,
"negative index given");
142 PyErr_SetString(PyExc_RuntimeError,
"Trying to insert more items than KDTree has room for");
146 BLI_kdtree_3d_insert(
self->obj, index, co);
154 py_kdtree_balance_doc,
155 ".. method:: balance()\n"
157 " Balance the tree.\n"
161 " This builds the entire tree, avoid calling after each insertion.\n");
164 BLI_kdtree_3d_balance(
self->obj);
180 PyObject *py_args = PyTuple_New(1);
181 PyTuple_SET_ITEM(py_args, 0, PyLong_FromLong(index));
182 PyObject *result = PyObject_CallObject(data->py_filter, py_args);
190 return int(use_node);
194 data->is_error =
true;
201 ".. method:: find(co, filter=None)\n"
203 " Find nearest point to ``co``.\n"
205 " :arg co: 3D coordinates.\n"
206 " :type co: Sequence[float]\n"
207 " :arg filter: function which takes an index and returns True for indices to "
208 "include in the search.\n"
209 " :type filter: Callable[[int], bool]\n"
210 " :return: Returns (position, index, distance).\n"
211 " :rtype: tuple[:class:`Vector`, int, float]\n");
214 PyObject *py_co, *py_filter =
nullptr;
216 KDTreeNearest_3d nearest;
217 const char *keywords[] = {
"co",
"filter",
nullptr};
219 if (!PyArg_ParseTupleAndKeywords(
220 args, kwargs,
"O|$O:find", (
char **)keywords, &py_co, &py_filter))
229 if (
self->count !=
self->count_balance) {
230 PyErr_SetString(PyExc_RuntimeError,
"KDTree must be balanced before calling find()");
236 if (py_filter ==
nullptr) {
237 BLI_kdtree_3d_find_nearest(
self->obj, co, &nearest);
243 data.is_error =
false;
257 py_kdtree_find_n_doc,
258 ".. method:: find_n(co, n)\n"
260 " Find nearest ``n`` points to ``co``.\n"
262 " :arg co: 3D coordinates.\n"
263 " :type co: Sequence[float]\n"
264 " :arg n: Number of points to find.\n"
266 " :return: Returns a list of tuples (position, index, distance).\n"
267 " :rtype: list[tuple[:class:`Vector`, int, float]]\n");
273 KDTreeNearest_3d *nearest;
276 const char *keywords[] = {
"co",
"n",
nullptr};
278 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"OI:find_n", (
char **)keywords, &py_co, &n)) {
287 PyErr_SetString(PyExc_RuntimeError,
"negative 'n' given");
291 if (
self->count !=
self->count_balance) {
292 PyErr_SetString(PyExc_RuntimeError,
"KDTree must be balanced before calling find_n()");
296 nearest =
static_cast<KDTreeNearest_3d *
>(
MEM_mallocN(
sizeof(KDTreeNearest_3d) * n, __func__));
298 found = BLI_kdtree_3d_find_nearest_n(
self->obj, co, nearest, n);
300 py_list = PyList_New(found);
302 for (i = 0; i < found; i++) {
313 py_kdtree_find_range_doc,
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: Sequence[float]\n"
320 " :arg radius: Distance to search for points.\n"
321 " :type radius: float\n"
322 " :return: Returns a list of tuples (position, index, distance).\n"
323 " :rtype: list[tuple[:class:`Vector`, int, float]]\n");
329 KDTreeNearest_3d *nearest =
nullptr;
333 const char *keywords[] = {
"co",
"radius",
nullptr};
335 if (!PyArg_ParseTupleAndKeywords(
336 args, kwargs,
"Of:find_range", (
char **)keywords, &py_co, &radius))
346 PyErr_SetString(PyExc_RuntimeError,
"negative radius given");
350 if (
self->count !=
self->count_balance) {
351 PyErr_SetString(PyExc_RuntimeError,
"KDTree must be balanced before calling find_range()");
355 found = BLI_kdtree_3d_range_search(
self->obj, co, &nearest, radius);
357 py_list = PyList_New(found);
359 for (i = 0; i < found; i++) {
370#if (defined(__GNUC__) && !defined(__clang__))
371# pragma GCC diagnostic push
372# pragma GCC diagnostic ignored "-Wcast-function-type"
376 {
"insert", (PyCFunction)
py_kdtree_insert, METH_VARARGS | METH_KEYWORDS, py_kdtree_insert_doc},
378 {
"find", (PyCFunction)
py_kdtree_find, METH_VARARGS | METH_KEYWORDS, py_kdtree_find_doc},
379 {
"find_n", (PyCFunction)
py_kdtree_find_n, METH_VARARGS | METH_KEYWORDS, py_kdtree_find_n_doc},
382 METH_VARARGS | METH_KEYWORDS,
383 py_kdtree_find_range_doc},
384 {
nullptr,
nullptr, 0,
nullptr},
387#if (defined(__GNUC__) && !defined(__clang__))
388# pragma GCC diagnostic pop
394 "KdTree(size) -> new kd-tree initialized to hold ``size`` items.\n"
398 " :class:`KDTree.balance` must have been called before using any of the ``find`` "
402 PyVarObject_HEAD_INIT(
nullptr, 0)
438 (allocfunc)PyType_GenericAlloc,
439 (newfunc)PyType_GenericNew,
447 (destructor)
nullptr,
456 "Generic 3-dimensional kd-tree to perform spatial searches.");
458 PyModuleDef_HEAD_INIT,
A KD-tree for nearest neighbor search.
Read Guarded memory(de)allocation.
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void *(* MEM_mallocN)(size_t len, const char *str)
void MEM_freeN(void *vmemh)
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
PyObject * Vector_CreatePyObject(const float *vec, const int vec_num, 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_find(PyKDTree *self, PyObject *args, PyObject *kwargs)
PyTypeObject PyKDTree_Type
static PyObject * py_kdtree_find_n(PyKDTree *self, PyObject *args, PyObject *kwargs)
static PyObject * kdtree_nearest_to_py(const KDTreeNearest_3d *nearest)
static PyObject * py_kdtree_find_range(PyKDTree *self, PyObject *args, PyObject *kwargs)
static void PyKDTree__tp_dealloc(PyKDTree *self)
static PyObject * py_kdtree_insert(PyKDTree *self, PyObject *args, PyObject *kwargs)
static PyMethodDef PyKDTree_methods[]
static int py_find_nearest_cb(void *user_data, int index, const float co[3], float dist_sq)
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: Sequence[float]\n" " :arg index: The index of the point.\n" " :type index: int\n")
static PyObject * py_kdtree_balance(PyKDTree *self)
static PyModuleDef kdtree_moduledef
PyMODINIT_FUNC PyInit_mathutils_kdtree()
static PyObject * kdtree_nearest_to_py_and_check(const KDTreeNearest_3d *nearest)
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