| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup mathutils | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This file defines the 'mathutils.kdtree' module, a general purpose module to access | 
					
						
							|  |  |  |  * blenders kdtree for 3d spatial lookups. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <Python.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_utildefines.h"
 | 
					
						
							|  |  |  | #include "BLI_kdtree.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "../generic/py_capi_utils.h"
 | 
					
						
							| 
									
										
										
										
											2015-01-06 16:42:22 +11:00
										 |  |  | #include "../generic/python_utildefines.h"
 | 
					
						
							| 
									
										
										
										
											2014-01-07 00:53:52 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | #include "mathutils.h"
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | #include "mathutils_kdtree.h" /* own include */
 | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_strict_flags.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PyObject_HEAD KDTree_3d *obj; | 
					
						
							|  |  |  |   unsigned int maxsize; | 
					
						
							|  |  |  |   unsigned int count; | 
					
						
							|  |  |  |   unsigned int count_balance; /* size when we last balanced */ | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } PyKDTree; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | /* Utility helper functions */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-20 00:46:33 +11:00
										 |  |  | static void kdtree_nearest_to_py_tuple(const KDTreeNearest_3d *nearest, PyObject *py_retval) | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_assert(nearest->index >= 0); | 
					
						
							|  |  |  |   BLI_assert(PyTuple_GET_SIZE(py_retval) == 3); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PyTuple_SET_ITEMS(py_retval, | 
					
						
							|  |  |  |                     Vector_CreatePyObject((float *)nearest->co, 3, NULL), | 
					
						
							|  |  |  |                     PyLong_FromLong(nearest->index), | 
					
						
							|  |  |  |                     PyFloat_FromDouble(nearest->dist)); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-20 00:46:33 +11:00
										 |  |  | static PyObject *kdtree_nearest_to_py(const KDTreeNearest_3d *nearest) | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PyObject *py_retval; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   py_retval = PyTuple_New(3); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   kdtree_nearest_to_py_tuple(nearest, py_retval); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return py_retval; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-20 00:46:33 +11:00
										 |  |  | static PyObject *kdtree_nearest_to_py_and_check(const KDTreeNearest_3d *nearest) | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PyObject *py_retval; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   py_retval = PyTuple_New(3); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (nearest->index != -1) { | 
					
						
							|  |  |  |     kdtree_nearest_to_py_tuple(nearest, py_retval); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     PyC_Tuple_Fill(py_retval, Py_None); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return py_retval; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | /* KDTree */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* annoying since arg parsing won't check overflow */ | 
					
						
							|  |  |  | #define UINT_IS_NEG(n) ((n) > INT_MAX)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int PyKDTree__tp_init(PyKDTree *self, PyObject *args, PyObject *kwargs) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   unsigned int maxsize; | 
					
						
							|  |  |  |   const char *keywords[] = {"size", NULL}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "I:KDTree", (char **)keywords, &maxsize)) { | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (UINT_IS_NEG(maxsize)) { | 
					
						
							|  |  |  |     PyErr_SetString(PyExc_ValueError, "negative 'size' given"); | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   self->obj = BLI_kdtree_3d_new(maxsize); | 
					
						
							|  |  |  |   self->maxsize = maxsize; | 
					
						
							|  |  |  |   self->count = 0; | 
					
						
							|  |  |  |   self->count_balance = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 0; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void PyKDTree__tp_dealloc(PyKDTree *self) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_kdtree_3d_free(self->obj); | 
					
						
							|  |  |  |   Py_TYPE(self)->tp_free((PyObject *)self); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(py_kdtree_insert_doc, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |              ".. 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"); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | static PyObject *py_kdtree_insert(PyKDTree *self, PyObject *args, PyObject *kwargs) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PyObject *py_co; | 
					
						
							|  |  |  |   float co[3]; | 
					
						
							|  |  |  |   int index; | 
					
						
							|  |  |  |   const char *keywords[] = {"co", "index", NULL}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!PyArg_ParseTupleAndKeywords( | 
					
						
							|  |  |  |           args, kwargs, (char *)"Oi:insert", (char **)keywords, &py_co, &index)) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (mathutils_array_parse(co, 3, 3, py_co, "insert: invalid 'co' arg") == -1) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (index < 0) { | 
					
						
							|  |  |  |     PyErr_SetString(PyExc_ValueError, "negative index given"); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (self->count >= self->maxsize) { | 
					
						
							|  |  |  |     PyErr_SetString(PyExc_RuntimeError, "Trying to insert more items than KDTree has room for"); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   BLI_kdtree_3d_insert(self->obj, index, co); | 
					
						
							|  |  |  |   self->count++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Py_RETURN_NONE; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(py_kdtree_balance_doc, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |              ".. method:: balance()\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              "   Balance the tree.\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              ".. note::\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              "   This builds the entire tree, avoid calling after each insertion.\n"); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | static PyObject *py_kdtree_balance(PyKDTree *self) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_kdtree_3d_balance(self->obj); | 
					
						
							|  |  |  |   self->count_balance = self->count; | 
					
						
							|  |  |  |   Py_RETURN_NONE; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-06 21:33:39 +11:00
										 |  |  | struct PyKDTree_NearestData { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PyObject *py_filter; | 
					
						
							|  |  |  |   bool is_error; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:33:39 +11:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int py_find_nearest_cb(void *user_data, int index, const float co[3], float dist_sq) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   UNUSED_VARS(co, dist_sq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   struct PyKDTree_NearestData *data = user_data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   PyObject *py_args = PyTuple_New(1); | 
					
						
							|  |  |  |   PyTuple_SET_ITEM(py_args, 0, PyLong_FromLong(index)); | 
					
						
							|  |  |  |   PyObject *result = PyObject_CallObject(data->py_filter, py_args); | 
					
						
							|  |  |  |   Py_DECREF(py_args); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (result) { | 
					
						
							|  |  |  |     bool use_node; | 
					
						
							|  |  |  |     int ok = PyC_ParseBool(result, &use_node); | 
					
						
							|  |  |  |     Py_DECREF(result); | 
					
						
							|  |  |  |     if (ok) { | 
					
						
							|  |  |  |       return (int)use_node; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   data->is_error = true; | 
					
						
							|  |  |  |   return -1; | 
					
						
							| 
									
										
										
										
											2015-12-06 21:33:39 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | PyDoc_STRVAR(py_kdtree_find_doc, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |              ".. method:: find(co, filter=None)\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              "   Find nearest point to ``co``.\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              "   :arg co: 3d coordinates.\n" | 
					
						
							|  |  |  |              "   :type co: float triplet\n" | 
					
						
							|  |  |  |              "   :arg filter: function which takes an index and returns True for indices to " | 
					
						
							|  |  |  |              "include in the search.\n" | 
					
						
							|  |  |  |              "   :type filter: callable\n" | 
					
						
							|  |  |  |              "   :return: Returns (:class:`Vector`, index, distance).\n" | 
					
						
							|  |  |  |              "   :rtype: :class:`tuple`\n"); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | static PyObject *py_kdtree_find(PyKDTree *self, PyObject *args, PyObject *kwargs) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PyObject *py_co, *py_filter = NULL; | 
					
						
							|  |  |  |   float co[3]; | 
					
						
							|  |  |  |   KDTreeNearest_3d nearest; | 
					
						
							|  |  |  |   const char *keywords[] = {"co", "filter", NULL}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!PyArg_ParseTupleAndKeywords( | 
					
						
							|  |  |  |           args, kwargs, (char *)"O|O:find", (char **)keywords, &py_co, &py_filter)) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (mathutils_array_parse(co, 3, 3, py_co, "find: invalid 'co' arg") == -1) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (self->count != self->count_balance) { | 
					
						
							|  |  |  |     PyErr_SetString(PyExc_RuntimeError, "KDTree must be balanced before calling find()"); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   nearest.index = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (py_filter == NULL) { | 
					
						
							|  |  |  |     BLI_kdtree_3d_find_nearest(self->obj, co, &nearest); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     struct PyKDTree_NearestData data = {0}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data.py_filter = py_filter; | 
					
						
							|  |  |  |     data.is_error = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     BLI_kdtree_3d_find_nearest_cb(self->obj, co, py_find_nearest_cb, &data, &nearest); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (data.is_error) { | 
					
						
							|  |  |  |       return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return kdtree_nearest_to_py_and_check(&nearest); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(py_kdtree_find_n_doc, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |              ".. method:: find_n(co, n)\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              "   Find nearest ``n`` points to ``co``.\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              "   :arg co: 3d coordinates.\n" | 
					
						
							|  |  |  |              "   :type co: float triplet\n" | 
					
						
							|  |  |  |              "   :arg n: Number of points to find.\n" | 
					
						
							|  |  |  |              "   :type n: int\n" | 
					
						
							|  |  |  |              "   :return: Returns a list of tuples (:class:`Vector`, index, distance).\n" | 
					
						
							|  |  |  |              "   :rtype: :class:`list`\n"); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | static PyObject *py_kdtree_find_n(PyKDTree *self, PyObject *args, PyObject *kwargs) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PyObject *py_list; | 
					
						
							|  |  |  |   PyObject *py_co; | 
					
						
							|  |  |  |   float co[3]; | 
					
						
							|  |  |  |   KDTreeNearest_3d *nearest; | 
					
						
							|  |  |  |   unsigned int n; | 
					
						
							|  |  |  |   int i, found; | 
					
						
							|  |  |  |   const char *keywords[] = {"co", "n", NULL}; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (!PyArg_ParseTupleAndKeywords( | 
					
						
							|  |  |  |           args, kwargs, (char *)"OI:find_n", (char **)keywords, &py_co, &n)) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (mathutils_array_parse(co, 3, 3, py_co, "find_n: invalid 'co' arg") == -1) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (UINT_IS_NEG(n)) { | 
					
						
							|  |  |  |     PyErr_SetString(PyExc_RuntimeError, "negative 'n' given"); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (self->count != self->count_balance) { | 
					
						
							|  |  |  |     PyErr_SetString(PyExc_RuntimeError, "KDTree must be balanced before calling find_n()"); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   nearest = MEM_mallocN(sizeof(KDTreeNearest_3d) * n, __func__); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   found = BLI_kdtree_3d_find_nearest_n(self->obj, co, nearest, n); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   py_list = PyList_New(found); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (i = 0; i < found; i++) { | 
					
						
							|  |  |  |     PyList_SET_ITEM(py_list, i, kdtree_nearest_to_py(&nearest[i])); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MEM_freeN(nearest); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return py_list; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(py_kdtree_find_range_doc, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |              ".. method:: find_range(co, radius)\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              "   Find all points within ``radius`` of ``co``.\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              "   :arg co: 3d coordinates.\n" | 
					
						
							|  |  |  |              "   :type co: float triplet\n" | 
					
						
							|  |  |  |              "   :arg radius: Distance to search for points.\n" | 
					
						
							|  |  |  |              "   :type radius: float\n" | 
					
						
							|  |  |  |              "   :return: Returns a list of tuples (:class:`Vector`, index, distance).\n" | 
					
						
							|  |  |  |              "   :rtype: :class:`list`\n"); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | static PyObject *py_kdtree_find_range(PyKDTree *self, PyObject *args, PyObject *kwargs) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PyObject *py_list; | 
					
						
							|  |  |  |   PyObject *py_co; | 
					
						
							|  |  |  |   float co[3]; | 
					
						
							|  |  |  |   KDTreeNearest_3d *nearest = NULL; | 
					
						
							|  |  |  |   float radius; | 
					
						
							|  |  |  |   int i, found; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const char *keywords[] = {"co", "radius", NULL}; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (!PyArg_ParseTupleAndKeywords( | 
					
						
							|  |  |  |           args, kwargs, (char *)"Of:find_range", (char **)keywords, &py_co, &radius)) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (mathutils_array_parse(co, 3, 3, py_co, "find_range: invalid 'co' arg") == -1) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (radius < 0.0f) { | 
					
						
							|  |  |  |     PyErr_SetString(PyExc_RuntimeError, "negative radius given"); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (self->count != self->count_balance) { | 
					
						
							|  |  |  |     PyErr_SetString(PyExc_RuntimeError, "KDTree must be balanced before calling find_range()"); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   found = BLI_kdtree_3d_range_search(self->obj, co, &nearest, radius); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   py_list = PyList_New(found); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (i = 0; i < found; i++) { | 
					
						
							|  |  |  |     PyList_SET_ITEM(py_list, i, kdtree_nearest_to_py(&nearest[i])); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (nearest) { | 
					
						
							|  |  |  |     MEM_freeN(nearest); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return py_list; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyMethodDef PyKDTree_methods[] = { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     {"insert", (PyCFunction)py_kdtree_insert, METH_VARARGS | METH_KEYWORDS, py_kdtree_insert_doc}, | 
					
						
							|  |  |  |     {"balance", (PyCFunction)py_kdtree_balance, METH_NOARGS, py_kdtree_balance_doc}, | 
					
						
							|  |  |  |     {"find", (PyCFunction)py_kdtree_find, METH_VARARGS | METH_KEYWORDS, py_kdtree_find_doc}, | 
					
						
							|  |  |  |     {"find_n", (PyCFunction)py_kdtree_find_n, METH_VARARGS | METH_KEYWORDS, py_kdtree_find_n_doc}, | 
					
						
							|  |  |  |     {"find_range", | 
					
						
							|  |  |  |      (PyCFunction)py_kdtree_find_range, | 
					
						
							|  |  |  |      METH_VARARGS | METH_KEYWORDS, | 
					
						
							|  |  |  |      py_kdtree_find_range_doc}, | 
					
						
							|  |  |  |     {NULL, NULL, 0, NULL}, | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(py_KDtree_doc, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |              "KdTree(size) -> new kd-tree initialized to hold ``size`` items.\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              ".. note::\n" | 
					
						
							|  |  |  |              "\n" | 
					
						
							|  |  |  |              "   :class:`KDTree.balance` must have been called before using any of the ``find`` " | 
					
						
							|  |  |  |              "methods.\n"); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | PyTypeObject PyKDTree_Type = { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     PyVarObject_HEAD_INIT(NULL, 0) "KDTree", /* tp_name */ | 
					
						
							|  |  |  |     sizeof(PyKDTree),                        /* tp_basicsize */ | 
					
						
							|  |  |  |     0,                                       /* tp_itemsize */ | 
					
						
							|  |  |  |     /* methods */ | 
					
						
							|  |  |  |     (destructor)PyKDTree__tp_dealloc,       /* tp_dealloc */ | 
					
						
							| 
									
										
										
										
											2019-10-16 14:44:36 +11:00
										 |  |  |     (printfunc)NULL,                        /* tp_print */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     NULL,                                   /* tp_getattr */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_setattr */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_compare */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_repr */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_as_number */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_as_sequence */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_as_mapping */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_hash */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_call */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_str */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_getattro */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_setattro */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_as_buffer */ | 
					
						
							|  |  |  |     Py_TPFLAGS_DEFAULT,                     /* tp_flags */ | 
					
						
							|  |  |  |     py_KDtree_doc,                          /* Documentation string */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_traverse */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_clear */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_richcompare */ | 
					
						
							|  |  |  |     0,                                      /* tp_weaklistoffset */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_iter */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_iternext */ | 
					
						
							|  |  |  |     (struct PyMethodDef *)PyKDTree_methods, /* tp_methods */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_members */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_getset */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_base */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_dict */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_descr_get */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_descr_set */ | 
					
						
							|  |  |  |     0,                                      /* tp_dictoffset */ | 
					
						
							|  |  |  |     (initproc)PyKDTree__tp_init,            /* tp_init */ | 
					
						
							|  |  |  |     (allocfunc)PyType_GenericAlloc,         /* tp_alloc */ | 
					
						
							|  |  |  |     (newfunc)PyType_GenericNew,             /* tp_new */ | 
					
						
							|  |  |  |     (freefunc)0,                            /* tp_free */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_is_gc */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_bases */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_mro */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_cache */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_subclasses */ | 
					
						
							|  |  |  |     NULL,                                   /* tp_weaklist */ | 
					
						
							|  |  |  |     (destructor)NULL,                       /* tp_del */ | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-17 12:19:59 +11:00
										 |  |  | PyDoc_STRVAR(py_kdtree_doc, "Generic 3-dimensional kd-tree to perform spatial searches."); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | static struct PyModuleDef kdtree_moduledef = { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     "mathutils.kdtree", /* m_name */ | 
					
						
							|  |  |  |     py_kdtree_doc,      /* m_doc */ | 
					
						
							|  |  |  |     0,                  /* m_size */ | 
					
						
							|  |  |  |     NULL,               /* m_methods */ | 
					
						
							|  |  |  |     NULL,               /* m_reload */ | 
					
						
							|  |  |  |     NULL,               /* m_traverse */ | 
					
						
							|  |  |  |     NULL,               /* m_clear */ | 
					
						
							|  |  |  |     NULL,               /* m_free */ | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC PyInit_mathutils_kdtree(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PyObject *m = PyModule_Create(&kdtree_moduledef); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (m == NULL) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Register the 'KDTree' class */ | 
					
						
							|  |  |  |   if (PyType_Ready(&PyKDTree_Type)) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   PyModule_AddObject(m, "KDTree", (PyObject *)&PyKDTree_Type); | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return m; | 
					
						
							| 
									
										
										
										
											2014-01-06 20:32:34 +11:00
										 |  |  | } |