2022-02-11 09:07:11 +11:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
2015-07-29 21:16:28 +10:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup mathutils
|
2015-07-29 21:16:28 +10:00
|
|
|
*
|
|
|
|
|
* This file defines the 'mathutils.bvhtree' module, a general purpose module to access
|
|
|
|
|
* blenders bvhtree for mesh surface nearest-element search and ray casting.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <Python.h>
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_ghash.h"
|
2015-07-29 21:16:28 +10:00
|
|
|
#include "BLI_kdopbvh.h"
|
|
|
|
|
#include "BLI_math.h"
|
|
|
|
|
#include "BLI_memarena.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_polyfill_2d.h"
|
|
|
|
|
#include "BLI_utildefines.h"
|
2015-07-29 21:16:28 +10:00
|
|
|
|
|
|
|
|
#include "BKE_bvhutils.h"
|
|
|
|
|
|
|
|
|
|
#include "../generic/py_capi_utils.h"
|
|
|
|
|
#include "../generic/python_utildefines.h"
|
|
|
|
|
|
|
|
|
|
#include "mathutils.h"
|
|
|
|
|
#include "mathutils_bvhtree.h" /* own include */
|
|
|
|
|
|
|
|
|
|
#ifndef MATH_STANDALONE
|
2018-09-27 15:54:10 +02:00
|
|
|
# include "DNA_mesh_types.h"
|
|
|
|
|
# include "DNA_meshdata_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
# include "DNA_object_types.h"
|
2015-07-29 21:16:28 +10:00
|
|
|
|
|
|
|
|
# include "BKE_customdata.h"
|
|
|
|
|
# include "BKE_editmesh_bvh.h"
|
2020-02-10 12:58:59 +01:00
|
|
|
# include "BKE_lib_id.h"
|
2023-03-12 22:29:15 +01:00
|
|
|
# include "BKE_mesh.hh"
|
2018-09-27 15:54:10 +02:00
|
|
|
# include "BKE_mesh_runtime.h"
|
2015-07-29 21:16:28 +10:00
|
|
|
|
2018-12-04 20:47:13 -02:00
|
|
|
# include "DEG_depsgraph_query.h"
|
|
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
# include "bmesh.h"
|
|
|
|
|
|
|
|
|
|
# include "../bmesh/bmesh_py_types.h"
|
|
|
|
|
#endif /* MATH_STANDALONE */
|
|
|
|
|
|
|
|
|
|
#include "BLI_strict_flags.h"
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2019-06-12 09:04:10 +10:00
|
|
|
/** \name Documentation String (snippets)
|
2015-07-29 21:16:28 +10:00
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
#define PYBVH_FIND_GENERIC_DISTANCE_DOC \
|
|
|
|
|
" :arg distance: Maximum distance threshold.\n" \
|
|
|
|
|
" :type distance: float\n"
|
|
|
|
|
|
|
|
|
|
#define PYBVH_FIND_GENERIC_RETURN_DOC \
|
2016-03-19 18:29:47 +11:00
|
|
|
" :return: Returns a tuple\n" \
|
|
|
|
|
" (:class:`Vector` location, :class:`Vector` normal, int index, float distance),\n" \
|
2015-07-29 21:16:28 +10:00
|
|
|
" Values will all be None if no hit is found.\n" \
|
|
|
|
|
" :rtype: :class:`tuple`\n"
|
|
|
|
|
|
2016-03-19 18:29:47 +11:00
|
|
|
#define PYBVH_FIND_GENERIC_RETURN_LIST_DOC \
|
|
|
|
|
" :return: Returns a list of tuples\n" \
|
|
|
|
|
" (:class:`Vector` location, :class:`Vector` normal, int index, float distance),\n" \
|
|
|
|
|
" :rtype: :class:`list`\n"
|
|
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
#define PYBVH_FROM_GENERIC_EPSILON_DOC \
|
|
|
|
|
" :arg epsilon: Increase the threshold for detecting overlap and raycast hits.\n" \
|
|
|
|
|
" :type epsilon: float\n"
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* sqrt(FLT_MAX) */
|
|
|
|
|
#define PYBVH_MAX_DIST_STR "1.84467e+19"
|
|
|
|
|
static const float max_dist_default = 1.844674352395373e+19f;
|
|
|
|
|
|
|
|
|
|
static const char PY_BVH_TREE_TYPE_DEFAULT = 4;
|
|
|
|
|
static const char PY_BVH_AXIS_DEFAULT = 6;
|
|
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
struct PyBVHTree {
|
2021-06-24 17:10:22 +10:00
|
|
|
PyObject_HEAD
|
|
|
|
|
BVHTree *tree;
|
2015-07-29 21:16:28 +10:00
|
|
|
float epsilon;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
float (*coords)[3];
|
2020-02-20 15:38:58 +11:00
|
|
|
uint (*tris)[3];
|
|
|
|
|
uint coords_len, tris_len;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* Optional members */
|
|
|
|
|
/* aligned with 'tris' */
|
|
|
|
|
int *orig_index;
|
|
|
|
|
/* aligned with array that 'orig_index' points to */
|
|
|
|
|
float (*orig_normal)[3];
|
2023-03-02 23:14:33 +01:00
|
|
|
};
|
2015-07-29 21:16:28 +10:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Utility helper functions
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static PyObject *bvhtree_CreatePyObject(BVHTree *tree,
|
|
|
|
|
float epsilon,
|
|
|
|
|
|
|
|
|
|
float (*coords)[3],
|
2020-02-20 15:38:58 +11:00
|
|
|
uint coords_len,
|
|
|
|
|
uint (*tris)[3],
|
|
|
|
|
uint tris_len,
|
2015-07-29 21:16:28 +10:00
|
|
|
|
|
|
|
|
/* optional arrays */
|
|
|
|
|
int *orig_index,
|
|
|
|
|
float (*orig_normal)[3])
|
|
|
|
|
{
|
|
|
|
|
PyBVHTree *result = PyObject_New(PyBVHTree, &PyBVHTree_Type);
|
|
|
|
|
|
|
|
|
|
result->tree = tree;
|
|
|
|
|
result->epsilon = epsilon;
|
|
|
|
|
|
|
|
|
|
result->coords = coords;
|
|
|
|
|
result->tris = tris;
|
|
|
|
|
result->coords_len = coords_len;
|
|
|
|
|
result->tris_len = tris_len;
|
|
|
|
|
|
|
|
|
|
result->orig_index = orig_index;
|
|
|
|
|
result->orig_normal = orig_normal;
|
|
|
|
|
|
|
|
|
|
return (PyObject *)result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name BVHTreeRayHit to Python utilities
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void py_bvhtree_raycast_to_py_tuple(const BVHTreeRayHit *hit, PyObject *py_retval)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(hit->index >= 0);
|
|
|
|
|
BLI_assert(PyTuple_GET_SIZE(py_retval) == 4);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
PyTuple_SET_ITEMS(py_retval,
|
2023-03-02 23:14:33 +01:00
|
|
|
Vector_CreatePyObject(hit->co, 3, nullptr),
|
|
|
|
|
Vector_CreatePyObject(hit->no, 3, nullptr),
|
2015-07-29 21:16:28 +10:00
|
|
|
PyLong_FromLong(hit->index),
|
|
|
|
|
PyFloat_FromDouble(hit->dist));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyObject *py_bvhtree_raycast_to_py(const BVHTreeRayHit *hit)
|
|
|
|
|
{
|
|
|
|
|
PyObject *py_retval = PyTuple_New(4);
|
|
|
|
|
|
|
|
|
|
py_bvhtree_raycast_to_py_tuple(hit, py_retval);
|
|
|
|
|
|
|
|
|
|
return py_retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyObject *py_bvhtree_raycast_to_py_none(void)
|
|
|
|
|
{
|
|
|
|
|
PyObject *py_retval = PyTuple_New(4);
|
|
|
|
|
|
|
|
|
|
PyC_Tuple_Fill(py_retval, Py_None);
|
|
|
|
|
|
|
|
|
|
return py_retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
static PyObject *py_bvhtree_raycast_to_py_and_check(const BVHTreeRayHit *hit)
|
|
|
|
|
{
|
|
|
|
|
PyObject *py_retval;
|
|
|
|
|
|
|
|
|
|
py_retval = PyTuple_New(4);
|
|
|
|
|
|
|
|
|
|
if (hit->index != -1) {
|
|
|
|
|
py_bvhtree_raycast_to_py_tuple(hit, py_retval);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
PyC_Tuple_Fill(py_retval, Py_None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return py_retval;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name BVHTreeNearest to Python utilities
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void py_bvhtree_nearest_to_py_tuple(const BVHTreeNearest *nearest, PyObject *py_retval)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(nearest->index >= 0);
|
|
|
|
|
BLI_assert(PyTuple_GET_SIZE(py_retval) == 4);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
PyTuple_SET_ITEMS(py_retval,
|
2023-03-02 23:14:33 +01:00
|
|
|
Vector_CreatePyObject(nearest->co, 3, nullptr),
|
|
|
|
|
Vector_CreatePyObject(nearest->no, 3, nullptr),
|
2015-07-29 21:16:28 +10:00
|
|
|
PyLong_FromLong(nearest->index),
|
|
|
|
|
PyFloat_FromDouble(sqrtf(nearest->dist_sq)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyObject *py_bvhtree_nearest_to_py(const BVHTreeNearest *nearest)
|
|
|
|
|
{
|
|
|
|
|
PyObject *py_retval = PyTuple_New(4);
|
|
|
|
|
|
|
|
|
|
py_bvhtree_nearest_to_py_tuple(nearest, py_retval);
|
|
|
|
|
|
|
|
|
|
return py_retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyObject *py_bvhtree_nearest_to_py_none(void)
|
|
|
|
|
{
|
|
|
|
|
PyObject *py_retval = PyTuple_New(4);
|
|
|
|
|
|
|
|
|
|
PyC_Tuple_Fill(py_retval, Py_None);
|
|
|
|
|
|
|
|
|
|
return py_retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
static PyObject *py_bvhtree_nearest_to_py_and_check(const BVHTreeNearest *nearest)
|
|
|
|
|
{
|
|
|
|
|
PyObject *py_retval;
|
|
|
|
|
|
|
|
|
|
py_retval = PyTuple_New(4);
|
|
|
|
|
|
|
|
|
|
if (nearest->index != -1) {
|
|
|
|
|
py_bvhtree_nearest_to_py_tuple(nearest, py_retval);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
PyC_Tuple_Fill(py_retval, Py_None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return py_retval;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
static void py_bvhtree__tp_dealloc(PyBVHTree *self)
|
|
|
|
|
{
|
|
|
|
|
if (self->tree) {
|
|
|
|
|
BLI_bvhtree_free(self->tree);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_SAFE_FREE(self->coords);
|
|
|
|
|
MEM_SAFE_FREE(self->tris);
|
|
|
|
|
|
|
|
|
|
MEM_SAFE_FREE(self->orig_index);
|
|
|
|
|
MEM_SAFE_FREE(self->orig_normal);
|
|
|
|
|
|
|
|
|
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Methods
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void py_bvhtree_raycast_cb(void *userdata,
|
|
|
|
|
int index,
|
|
|
|
|
const BVHTreeRay *ray,
|
|
|
|
|
BVHTreeRayHit *hit)
|
|
|
|
|
{
|
2023-03-02 23:14:33 +01:00
|
|
|
const PyBVHTree *self = static_cast<const PyBVHTree *>(userdata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-09-04 01:04:37 +02:00
|
|
|
const float(*coords)[3] = (const float(*)[3])self->coords;
|
2020-02-20 15:38:58 +11:00
|
|
|
const uint *tri = self->tris[index];
|
2015-07-29 21:16:28 +10:00
|
|
|
const float *tri_co[3] = {coords[tri[0]], coords[tri[1]], coords[tri[2]]};
|
|
|
|
|
float dist;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (self->epsilon == 0.0f) {
|
|
|
|
|
dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(tri_co));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
dist = bvhtree_sphereray_tri_intersection(ray, self->epsilon, hit->dist, UNPACK3(tri_co));
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (dist >= 0 && dist < hit->dist) {
|
|
|
|
|
hit->index = self->orig_index ? self->orig_index[index] : index;
|
|
|
|
|
hit->dist = dist;
|
|
|
|
|
madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
|
|
|
|
|
if (self->orig_normal) {
|
|
|
|
|
copy_v3_v3(hit->no, self->orig_normal[hit->index]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
normal_tri_v3(hit->no, UNPACK3(tri_co));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void py_bvhtree_nearest_point_cb(void *userdata,
|
|
|
|
|
int index,
|
|
|
|
|
const float co[3],
|
|
|
|
|
BVHTreeNearest *nearest)
|
|
|
|
|
{
|
2023-03-02 23:14:33 +01:00
|
|
|
PyBVHTree *self = static_cast<PyBVHTree *>(userdata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-09-04 01:04:37 +02:00
|
|
|
const float(*coords)[3] = (const float(*)[3])self->coords;
|
2020-02-20 15:38:58 +11:00
|
|
|
const uint *tri = self->tris[index];
|
2015-07-29 21:16:28 +10:00
|
|
|
const float *tri_co[3] = {coords[tri[0]], coords[tri[1]], coords[tri[2]]};
|
|
|
|
|
float nearest_tmp[3], dist_sq;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(tri_co));
|
|
|
|
|
dist_sq = len_squared_v3v3(co, nearest_tmp);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (dist_sq < nearest->dist_sq) {
|
|
|
|
|
nearest->index = self->orig_index ? self->orig_index[index] : index;
|
|
|
|
|
nearest->dist_sq = dist_sq;
|
|
|
|
|
copy_v3_v3(nearest->co, nearest_tmp);
|
|
|
|
|
if (self->orig_normal) {
|
|
|
|
|
copy_v3_v3(nearest->no, self->orig_normal[nearest->index]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
normal_tri_v3(nearest->no, UNPACK3(tri_co));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyDoc_STRVAR(py_bvhtree_ray_cast_doc,
|
2015-12-02 19:25:08 +11:00
|
|
|
".. method:: ray_cast(origin, direction, distance=sys.float_info.max)\n"
|
2015-07-29 21:16:28 +10:00
|
|
|
"\n"
|
|
|
|
|
" Cast a ray onto the mesh.\n"
|
|
|
|
|
"\n"
|
2021-02-18 09:09:31 +01:00
|
|
|
" :arg origin: Start location of the ray in object space.\n"
|
|
|
|
|
" :type origin: :class:`Vector`\n"
|
2015-07-29 21:16:28 +10:00
|
|
|
" :arg direction: Direction of the ray in object space.\n"
|
|
|
|
|
" :type direction: :class:`Vector`\n" PYBVH_FIND_GENERIC_DISTANCE_DOC
|
|
|
|
|
PYBVH_FIND_GENERIC_RETURN_DOC);
|
|
|
|
|
static PyObject *py_bvhtree_ray_cast(PyBVHTree *self, PyObject *args)
|
|
|
|
|
{
|
|
|
|
|
const char *error_prefix = "ray_cast";
|
|
|
|
|
float co[3], direction[3];
|
|
|
|
|
float max_dist = FLT_MAX;
|
|
|
|
|
BVHTreeRayHit hit;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* parse args */
|
|
|
|
|
{
|
|
|
|
|
PyObject *py_co, *py_direction;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-12-20 10:42:57 +11:00
|
|
|
if (!PyArg_ParseTuple(args, "OO|f:ray_cast", &py_co, &py_direction, &max_dist)) {
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if ((mathutils_array_parse(co, 2, 3 | MU_ARRAY_ZERO, py_co, error_prefix) == -1) ||
|
|
|
|
|
(mathutils_array_parse(direction, 2, 3 | MU_ARRAY_ZERO, py_direction, error_prefix) ==
|
|
|
|
|
-1)) {
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
normalize_v3(direction);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
hit.dist = max_dist;
|
|
|
|
|
hit.index = -1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* may fail if the mesh has no faces, in that case the ray-cast misses */
|
|
|
|
|
if (self->tree) {
|
|
|
|
|
if (BLI_bvhtree_ray_cast(self->tree, co, direction, 0.0f, &hit, py_bvhtree_raycast_cb, self) !=
|
|
|
|
|
-1) {
|
|
|
|
|
return py_bvhtree_raycast_to_py(&hit);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
return py_bvhtree_raycast_to_py_none();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyDoc_STRVAR(py_bvhtree_find_nearest_doc,
|
2015-12-02 19:25:08 +11:00
|
|
|
".. method:: find_nearest(origin, distance=" PYBVH_MAX_DIST_STR
|
|
|
|
|
")\n"
|
2015-07-29 21:16:28 +10:00
|
|
|
"\n"
|
2017-10-27 16:14:24 +11:00
|
|
|
" Find the nearest element (typically face index) to a point.\n"
|
2015-07-29 21:16:28 +10:00
|
|
|
"\n"
|
|
|
|
|
" :arg co: Find nearest element to this point.\n"
|
|
|
|
|
" :type co: :class:`Vector`\n" PYBVH_FIND_GENERIC_DISTANCE_DOC
|
|
|
|
|
PYBVH_FIND_GENERIC_RETURN_DOC);
|
|
|
|
|
static PyObject *py_bvhtree_find_nearest(PyBVHTree *self, PyObject *args)
|
|
|
|
|
{
|
|
|
|
|
const char *error_prefix = "find_nearest";
|
|
|
|
|
float co[3];
|
|
|
|
|
float max_dist = max_dist_default;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
BVHTreeNearest nearest;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* parse args */
|
|
|
|
|
{
|
|
|
|
|
PyObject *py_co;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-12-20 10:42:57 +11:00
|
|
|
if (!PyArg_ParseTuple(args, "O|f:find_nearest", &py_co, &max_dist)) {
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (mathutils_array_parse(co, 2, 3 | MU_ARRAY_ZERO, py_co, error_prefix) == -1) {
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
nearest.index = -1;
|
|
|
|
|
nearest.dist_sq = max_dist * max_dist;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* may fail if the mesh has no faces, in that case the ray-cast misses */
|
|
|
|
|
if (self->tree) {
|
|
|
|
|
if (BLI_bvhtree_find_nearest(self->tree, co, &nearest, py_bvhtree_nearest_point_cb, self) !=
|
|
|
|
|
-1) {
|
|
|
|
|
return py_bvhtree_nearest_to_py(&nearest);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
return py_bvhtree_nearest_to_py_none();
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-19 18:29:47 +11:00
|
|
|
struct PyBVH_RangeData {
|
|
|
|
|
PyBVHTree *self;
|
|
|
|
|
PyObject *result;
|
|
|
|
|
float dist_sq;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void py_bvhtree_nearest_point_range_cb(void *userdata,
|
|
|
|
|
int index,
|
|
|
|
|
const float co[3],
|
2023-03-02 23:14:33 +01:00
|
|
|
float /*dist_sq_bvh*/)
|
2016-03-19 18:29:47 +11:00
|
|
|
{
|
2023-03-02 23:14:33 +01:00
|
|
|
PyBVH_RangeData *data = static_cast<PyBVH_RangeData *>(userdata);
|
2016-03-19 18:29:47 +11:00
|
|
|
PyBVHTree *self = data->self;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-08 00:11:05 +10:00
|
|
|
const float(*coords)[3] = self->coords;
|
2020-02-20 15:38:58 +11:00
|
|
|
const uint *tri = self->tris[index];
|
2016-03-19 18:29:47 +11:00
|
|
|
const float *tri_co[3] = {coords[tri[0]], coords[tri[1]], coords[tri[2]]};
|
|
|
|
|
float nearest_tmp[3], dist_sq;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-19 18:29:47 +11:00
|
|
|
closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(tri_co));
|
|
|
|
|
dist_sq = len_squared_v3v3(co, nearest_tmp);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-19 18:29:47 +11:00
|
|
|
if (dist_sq < data->dist_sq) {
|
|
|
|
|
BVHTreeNearest nearest;
|
|
|
|
|
nearest.index = self->orig_index ? self->orig_index[index] : index;
|
|
|
|
|
nearest.dist_sq = dist_sq;
|
|
|
|
|
copy_v3_v3(nearest.co, nearest_tmp);
|
|
|
|
|
if (self->orig_normal) {
|
|
|
|
|
copy_v3_v3(nearest.no, self->orig_normal[nearest.index]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
normal_tri_v3(nearest.no, UNPACK3(tri_co));
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-19 18:29:47 +11:00
|
|
|
PyList_APPEND(data->result, py_bvhtree_nearest_to_py(&nearest));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyDoc_STRVAR(
|
|
|
|
|
py_bvhtree_find_nearest_range_doc,
|
|
|
|
|
".. method:: find_nearest_range(origin, distance=" PYBVH_MAX_DIST_STR
|
|
|
|
|
")\n"
|
|
|
|
|
"\n"
|
2017-10-27 16:14:24 +11:00
|
|
|
" Find the nearest elements (typically face index) to a point in the distance range.\n"
|
2016-03-19 18:29:47 +11:00
|
|
|
"\n"
|
|
|
|
|
" :arg co: Find nearest elements to this point.\n"
|
|
|
|
|
" :type co: :class:`Vector`\n" PYBVH_FIND_GENERIC_DISTANCE_DOC
|
|
|
|
|
PYBVH_FIND_GENERIC_RETURN_LIST_DOC);
|
|
|
|
|
static PyObject *py_bvhtree_find_nearest_range(PyBVHTree *self, PyObject *args)
|
|
|
|
|
{
|
|
|
|
|
const char *error_prefix = "find_nearest_range";
|
|
|
|
|
float co[3];
|
|
|
|
|
float max_dist = max_dist_default;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-19 18:29:47 +11:00
|
|
|
/* parse args */
|
|
|
|
|
{
|
|
|
|
|
PyObject *py_co;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-12-20 10:42:57 +11:00
|
|
|
if (!PyArg_ParseTuple(args, "O|f:find_nearest_range", &py_co, &max_dist)) {
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2016-03-19 18:29:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-19 18:29:47 +11:00
|
|
|
if (mathutils_array_parse(co, 2, 3 | MU_ARRAY_ZERO, py_co, error_prefix) == -1) {
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2016-03-19 18:29:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-19 18:29:47 +11:00
|
|
|
PyObject *ret = PyList_New(0);
|
|
|
|
|
|
|
|
|
|
if (self->tree) {
|
2023-03-02 23:14:33 +01:00
|
|
|
PyBVH_RangeData data{};
|
|
|
|
|
data.self = self;
|
|
|
|
|
data.result = ret;
|
|
|
|
|
data.dist_sq = square_f(max_dist);
|
2015-08-20 17:32:25 +10:00
|
|
|
BLI_bvhtree_range_query(self->tree, co, max_dist, py_bvhtree_nearest_point_range_cb, &data);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-19 18:29:47 +11:00
|
|
|
return ret;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-03-19 18:29:47 +11:00
|
|
|
|
2020-02-20 15:38:58 +11:00
|
|
|
BLI_INLINE uint overlap_hash(const void *overlap_v)
|
2015-07-29 21:16:28 +10:00
|
|
|
{
|
2023-03-02 23:14:33 +01:00
|
|
|
const BVHTreeOverlap *overlap = static_cast<const BVHTreeOverlap *>(overlap_v);
|
2015-07-29 21:16:28 +10:00
|
|
|
/* same constants as edge-hash */
|
2023-03-02 23:14:33 +01:00
|
|
|
return ((uint(overlap->indexA) * 65) ^ (uint(overlap->indexA) * 31));
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
|
|
|
|
|
{
|
2023-03-02 23:14:33 +01:00
|
|
|
const BVHTreeOverlap *a = static_cast<const BVHTreeOverlap *>(a_v);
|
|
|
|
|
const BVHTreeOverlap *b = static_cast<const BVHTreeOverlap *>(b_v);
|
2015-07-29 21:16:28 +10:00
|
|
|
return (memcmp(a, b, sizeof(*a)) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-20 17:32:25 +10:00
|
|
|
struct PyBVHTree_OverlapData {
|
|
|
|
|
PyBVHTree *tree_pair[2];
|
|
|
|
|
float epsilon;
|
|
|
|
|
};
|
|
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
static bool py_bvhtree_overlap_cb(void *userdata, int index_a, int index_b, int /*thread*/)
|
2015-08-20 17:32:25 +10:00
|
|
|
{
|
2023-03-02 23:14:33 +01:00
|
|
|
PyBVHTree_OverlapData *data = static_cast<PyBVHTree_OverlapData *>(userdata);
|
2015-08-20 17:32:25 +10:00
|
|
|
PyBVHTree *tree_a = data->tree_pair[0];
|
|
|
|
|
PyBVHTree *tree_b = data->tree_pair[1];
|
2020-02-20 15:38:58 +11:00
|
|
|
const uint *tri_a = tree_a->tris[index_a];
|
|
|
|
|
const uint *tri_b = tree_b->tris[index_b];
|
2015-08-20 17:32:25 +10:00
|
|
|
const float *tri_a_co[3] = {
|
|
|
|
|
tree_a->coords[tri_a[0]], tree_a->coords[tri_a[1]], tree_a->coords[tri_a[2]]};
|
|
|
|
|
const float *tri_b_co[3] = {
|
|
|
|
|
tree_b->coords[tri_b[0]], tree_b->coords[tri_b[1]], tree_b->coords[tri_b[2]]};
|
2015-08-24 08:13:58 +10:00
|
|
|
float ix_pair[2][3];
|
|
|
|
|
int verts_shared = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-08-24 08:13:58 +10:00
|
|
|
if (tree_a == tree_b) {
|
|
|
|
|
if (UNLIKELY(index_a == index_b)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-08-24 08:13:58 +10:00
|
|
|
verts_shared = (ELEM(tri_a_co[0], UNPACK3(tri_b_co)) + ELEM(tri_a_co[1], UNPACK3(tri_b_co)) +
|
|
|
|
|
ELEM(tri_a_co[2], UNPACK3(tri_b_co)));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-08-24 08:13:58 +10:00
|
|
|
/* if 2 points are shared, bail out */
|
|
|
|
|
if (verts_shared >= 2) {
|
|
|
|
|
return false;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-08-24 08:13:58 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-13 16:01:38 +10:00
|
|
|
return (isect_tri_tri_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1]) &&
|
2015-08-24 08:13:58 +10:00
|
|
|
((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
|
2015-08-20 17:32:25 +10:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
PyDoc_STRVAR(
|
|
|
|
|
py_bvhtree_overlap_doc,
|
|
|
|
|
".. method:: overlap(other_tree)\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" Find overlapping indices between 2 trees.\n"
|
|
|
|
|
"\n"
|
2018-09-03 16:49:08 +02:00
|
|
|
" :arg other_tree: Other tree to perform overlap test on.\n"
|
2015-07-29 21:16:28 +10:00
|
|
|
" :type other_tree: :class:`BVHTree`\n"
|
|
|
|
|
" :return: Returns a list of unique index pairs,"
|
|
|
|
|
" the first index referencing this tree, the second referencing the **other_tree**.\n"
|
|
|
|
|
" :rtype: :class:`list`\n");
|
|
|
|
|
static PyObject *py_bvhtree_overlap(PyBVHTree *self, PyBVHTree *other)
|
|
|
|
|
{
|
2023-03-02 23:14:33 +01:00
|
|
|
PyBVHTree_OverlapData data;
|
2015-07-29 21:16:28 +10:00
|
|
|
BVHTreeOverlap *overlap;
|
2020-02-20 15:38:58 +11:00
|
|
|
uint overlap_len = 0;
|
2015-07-29 21:16:28 +10:00
|
|
|
PyObject *ret;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (!PyBVHTree_CheckExact(other)) {
|
|
|
|
|
PyErr_SetString(PyExc_ValueError, "Expected a BVHTree argument");
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-08-20 17:32:25 +10:00
|
|
|
data.tree_pair[0] = self;
|
|
|
|
|
data.tree_pair[1] = other;
|
|
|
|
|
data.epsilon = max_ff(self->epsilon, other->epsilon);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-08-20 17:32:25 +10:00
|
|
|
overlap = BLI_bvhtree_overlap(
|
|
|
|
|
self->tree, other->tree, &overlap_len, py_bvhtree_overlap_cb, &data);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
ret = PyList_New(0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
if (overlap == nullptr) {
|
2015-07-29 21:16:28 +10:00
|
|
|
/* pass */
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-08-20 16:10:13 +10:00
|
|
|
const bool use_unique = (self->orig_index || other->orig_index);
|
2015-07-29 21:16:28 +10:00
|
|
|
GSet *pair_test = use_unique ?
|
|
|
|
|
BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, overlap_len) :
|
2023-03-02 23:14:33 +01:00
|
|
|
nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
/* simple case, no index remapping */
|
2020-02-20 15:38:58 +11:00
|
|
|
uint i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
for (i = 0; i < overlap_len; i++) {
|
2015-08-20 17:32:25 +10:00
|
|
|
PyObject *item;
|
|
|
|
|
if (use_unique) {
|
|
|
|
|
if (self->orig_index) {
|
|
|
|
|
overlap[i].indexA = self->orig_index[overlap[i].indexA];
|
|
|
|
|
}
|
|
|
|
|
if (other->orig_index) {
|
|
|
|
|
overlap[i].indexB = other->orig_index[overlap[i].indexB];
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-08-20 17:32:25 +10:00
|
|
|
/* skip if its already added */
|
|
|
|
|
if (!BLI_gset_add(pair_test, &overlap[i])) {
|
|
|
|
|
continue;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2015-08-20 17:32:25 +10:00
|
|
|
item = PyTuple_New(2);
|
|
|
|
|
PyTuple_SET_ITEMS(
|
2015-08-22 21:17:32 +10:00
|
|
|
item, PyLong_FromLong(overlap[i].indexA), PyLong_FromLong(overlap[i].indexB));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-08-20 17:32:25 +10:00
|
|
|
PyList_Append(ret, item);
|
|
|
|
|
Py_DECREF(item);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (pair_test) {
|
2023-03-02 23:14:33 +01:00
|
|
|
BLI_gset_free(pair_test, nullptr);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (overlap) {
|
|
|
|
|
MEM_freeN(overlap);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Class Methods
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
PyDoc_STRVAR(
|
|
|
|
|
C_BVHTree_FromPolygons_doc,
|
|
|
|
|
".. classmethod:: FromPolygons(vertices, polygons, all_triangles=False, epsilon=0.0)\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" BVH tree constructed geometry passed in as arguments.\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" :arg vertices: float triplets each representing ``(x, y, z)``\n"
|
|
|
|
|
" :type vertices: float triplet sequence\n"
|
|
|
|
|
" :arg polygons: Sequence of polyugons, each containing indices to the vertices argument.\n"
|
|
|
|
|
" :type polygons: Sequence of sequences containing ints\n"
|
|
|
|
|
" :arg all_triangles: Use when all **polygons** are triangles for more efficient "
|
|
|
|
|
"conversion.\n"
|
|
|
|
|
" :type all_triangles: bool\n" PYBVH_FROM_GENERIC_EPSILON_DOC);
|
2023-03-02 23:14:33 +01:00
|
|
|
static PyObject *C_BVHTree_FromPolygons(PyObject * /*cls*/, PyObject *args, PyObject *kwargs)
|
2015-07-29 21:16:28 +10:00
|
|
|
{
|
|
|
|
|
const char *error_prefix = "BVHTree.FromPolygons";
|
2023-03-02 23:14:33 +01:00
|
|
|
const char *keywords[] = {"vertices", "polygons", "all_triangles", "epsilon", nullptr};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
PyObject *py_coords, *py_tris;
|
2023-03-02 23:14:33 +01:00
|
|
|
PyObject *py_coords_fast = nullptr, *py_tris_fast = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
MemArena *poly_arena = nullptr;
|
|
|
|
|
MemArena *pf_arena = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
float(*coords)[3] = nullptr;
|
|
|
|
|
uint(*tris)[3] = nullptr;
|
2020-02-20 15:38:58 +11:00
|
|
|
uint coords_len, tris_len;
|
2015-07-29 21:16:28 +10:00
|
|
|
float epsilon = 0.0f;
|
2015-08-03 20:00:16 +10:00
|
|
|
bool all_triangles = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* when all_triangles is False */
|
2023-03-02 23:14:33 +01:00
|
|
|
int *orig_index = nullptr;
|
|
|
|
|
float(*orig_normal)[3] = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-20 15:38:58 +11:00
|
|
|
uint i;
|
2015-07-29 21:16:28 +10:00
|
|
|
bool valid = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (!PyArg_ParseTupleAndKeywords(args,
|
2015-08-03 20:00:16 +10:00
|
|
|
kwargs,
|
2019-12-20 10:42:57 +11:00
|
|
|
"OO|$O&f:BVHTree.FromPolygons",
|
2015-08-03 20:00:16 +10:00
|
|
|
(char **)keywords,
|
|
|
|
|
&py_coords,
|
|
|
|
|
&py_tris,
|
|
|
|
|
PyC_ParseBool,
|
|
|
|
|
&all_triangles,
|
|
|
|
|
&epsilon)) {
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (!(py_coords_fast = PySequence_Fast(py_coords, error_prefix)) ||
|
|
|
|
|
!(py_tris_fast = PySequence_Fast(py_tris, error_prefix))) {
|
|
|
|
|
Py_XDECREF(py_coords_fast);
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (valid) {
|
|
|
|
|
PyObject **py_coords_fast_items = PySequence_Fast_ITEMS(py_coords_fast);
|
2023-03-02 23:14:33 +01:00
|
|
|
coords_len = uint(PySequence_Fast_GET_SIZE(py_coords_fast));
|
|
|
|
|
coords = static_cast<float(*)[3]>(MEM_mallocN(size_t(coords_len) * sizeof(*coords), __func__));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
for (i = 0; i < coords_len; i++) {
|
|
|
|
|
PyObject *py_vert = py_coords_fast_items[i];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (mathutils_array_parse(coords[i], 3, 3, py_vert, "BVHTree vertex: ") == -1) {
|
|
|
|
|
valid = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (valid == false) {
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
|
|
|
|
else if (all_triangles) {
|
|
|
|
|
/* all triangles, simple case */
|
|
|
|
|
PyObject **py_tris_fast_items = PySequence_Fast_ITEMS(py_tris_fast);
|
2023-03-02 23:14:33 +01:00
|
|
|
tris_len = uint(PySequence_Fast_GET_SIZE(py_tris_fast));
|
|
|
|
|
tris = static_cast<uint(*)[3]>(MEM_mallocN(size_t(tris_len) * sizeof(*tris), __func__));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
for (i = 0; i < tris_len; i++) {
|
|
|
|
|
PyObject *py_tricoords = py_tris_fast_items[i];
|
|
|
|
|
PyObject *py_tricoords_fast;
|
|
|
|
|
PyObject **py_tricoords_fast_items;
|
2020-02-20 15:38:58 +11:00
|
|
|
uint *tri = tris[i];
|
2015-07-29 21:16:28 +10:00
|
|
|
int j;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (!(py_tricoords_fast = PySequence_Fast(py_tricoords, error_prefix))) {
|
|
|
|
|
valid = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (PySequence_Fast_GET_SIZE(py_tricoords_fast) != 3) {
|
|
|
|
|
Py_DECREF(py_tricoords_fast);
|
|
|
|
|
PyErr_Format(PyExc_ValueError,
|
|
|
|
|
"%s: non triangle found at index %d with length of %d",
|
|
|
|
|
error_prefix,
|
|
|
|
|
i,
|
|
|
|
|
PySequence_Fast_GET_SIZE(py_tricoords_fast));
|
|
|
|
|
valid = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
py_tricoords_fast_items = PySequence_Fast_ITEMS(py_tricoords_fast);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
for (j = 0; j < 3; j++) {
|
2017-08-20 15:44:54 +10:00
|
|
|
tri[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]);
|
2023-03-02 23:14:33 +01:00
|
|
|
if (UNLIKELY(tri[j] >= uint(coords_len))) {
|
2015-07-29 21:16:28 +10:00
|
|
|
PyErr_Format(PyExc_ValueError,
|
|
|
|
|
"%s: index %d must be less than %d",
|
|
|
|
|
error_prefix,
|
|
|
|
|
tri[j],
|
|
|
|
|
coords_len);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* decref below */
|
|
|
|
|
valid = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
Py_DECREF(py_tricoords_fast);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-07-29 21:16:28 +10:00
|
|
|
else {
|
|
|
|
|
/* ngon support (much more involved) */
|
2023-03-02 23:14:33 +01:00
|
|
|
const uint polys_len = uint(PySequence_Fast_GET_SIZE(py_tris_fast));
|
2015-07-29 21:16:28 +10:00
|
|
|
struct PolyLink {
|
|
|
|
|
struct PolyLink *next;
|
2020-02-20 15:38:58 +11:00
|
|
|
uint len;
|
|
|
|
|
uint poly[0];
|
2023-03-02 23:14:33 +01:00
|
|
|
} *plink_first = nullptr, **p_plink_prev = &plink_first, *plink = nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
int poly_index;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
tris_len = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
poly_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
for (i = 0; i < polys_len; i++) {
|
|
|
|
|
PyObject *py_tricoords = PySequence_Fast_GET_ITEM(py_tris_fast, i);
|
|
|
|
|
PyObject *py_tricoords_fast;
|
|
|
|
|
PyObject **py_tricoords_fast_items;
|
2020-02-20 15:38:58 +11:00
|
|
|
uint py_tricoords_len;
|
|
|
|
|
uint j;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (!(py_tricoords_fast = PySequence_Fast(py_tricoords, error_prefix))) {
|
|
|
|
|
valid = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
py_tricoords_len = uint(PySequence_Fast_GET_SIZE(py_tricoords_fast));
|
2015-07-29 21:16:28 +10:00
|
|
|
py_tricoords_fast_items = PySequence_Fast_ITEMS(py_tricoords_fast);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
plink = static_cast<PolyLink *>(BLI_memarena_alloc(
|
|
|
|
|
poly_arena, sizeof(*plink) + (sizeof(int) * size_t(py_tricoords_len))));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
plink->len = uint(py_tricoords_len);
|
2015-07-29 21:16:28 +10:00
|
|
|
*p_plink_prev = plink;
|
|
|
|
|
p_plink_prev = &plink->next;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
for (j = 0; j < py_tricoords_len; j++) {
|
2017-08-20 15:44:54 +10:00
|
|
|
plink->poly[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]);
|
2023-03-02 23:14:33 +01:00
|
|
|
if (UNLIKELY(plink->poly[j] >= uint(coords_len))) {
|
2015-07-29 21:16:28 +10:00
|
|
|
PyErr_Format(PyExc_ValueError,
|
|
|
|
|
"%s: index %d must be less than %d",
|
|
|
|
|
error_prefix,
|
|
|
|
|
plink->poly[j],
|
|
|
|
|
coords_len);
|
2016-11-29 19:31:46 +11:00
|
|
|
/* decref below */
|
2015-07-29 21:16:28 +10:00
|
|
|
valid = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2016-11-29 19:31:46 +11:00
|
|
|
Py_DECREF(py_tricoords_fast);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (py_tricoords_len >= 3) {
|
|
|
|
|
tris_len += (py_tricoords_len - 2);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2023-03-02 23:14:33 +01:00
|
|
|
*p_plink_prev = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-17 16:43:56 +11:00
|
|
|
/* All NGON's are parsed, now tessellate. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
|
2023-03-02 23:14:33 +01:00
|
|
|
tris = static_cast<uint(*)[3]>(MEM_mallocN(sizeof(*tris) * size_t(tris_len), __func__));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
orig_index = static_cast<int *>(MEM_mallocN(sizeof(*orig_index) * size_t(tris_len), __func__));
|
|
|
|
|
orig_normal = static_cast<float(*)[3]>(
|
|
|
|
|
MEM_mallocN(sizeof(*orig_normal) * size_t(polys_len), __func__));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
for (plink = plink_first, poly_index = 0, i = 0; plink; plink = plink->next, poly_index++) {
|
|
|
|
|
if (plink->len == 3) {
|
2020-02-20 15:38:58 +11:00
|
|
|
uint *tri = tris[i];
|
|
|
|
|
memcpy(tri, plink->poly, sizeof(uint[3]));
|
2015-07-29 21:16:28 +10:00
|
|
|
orig_index[i] = poly_index;
|
|
|
|
|
normal_tri_v3(orig_normal[poly_index], coords[tri[0]], coords[tri[1]], coords[tri[2]]);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
else if (plink->len > 3) {
|
2023-03-02 23:14:33 +01:00
|
|
|
float(*proj_coords)[2] = static_cast<float(*)[2]>(
|
|
|
|
|
BLI_memarena_alloc(pf_arena, sizeof(*proj_coords) * plink->len));
|
2015-07-29 21:16:28 +10:00
|
|
|
float *normal = orig_normal[poly_index];
|
|
|
|
|
const float *co_prev;
|
|
|
|
|
const float *co_curr;
|
|
|
|
|
float axis_mat[3][3];
|
2020-02-20 15:38:58 +11:00
|
|
|
uint(*tris_offset)[3] = &tris[i];
|
|
|
|
|
uint j;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* calc normal and setup 'proj_coords' */
|
|
|
|
|
zero_v3(normal);
|
|
|
|
|
co_prev = coords[plink->poly[plink->len - 1]];
|
|
|
|
|
for (j = 0; j < plink->len; j++) {
|
|
|
|
|
co_curr = coords[plink->poly[j]];
|
|
|
|
|
add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
|
|
|
|
|
co_prev = co_curr;
|
|
|
|
|
}
|
|
|
|
|
normalize_v3(normal);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
axis_dominant_v3_to_m3_negate(axis_mat, normal);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
for (j = 0; j < plink->len; j++) {
|
2016-02-12 19:12:58 +11:00
|
|
|
mul_v2_m3v3(proj_coords[j], axis_mat, coords[plink->poly[j]]);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-20 14:03:22 +11:00
|
|
|
BLI_polyfill_calc_arena(proj_coords, plink->len, 1, tris_offset, pf_arena);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
j = plink->len - 2;
|
|
|
|
|
while (j--) {
|
2020-02-20 15:38:58 +11:00
|
|
|
uint *tri = tris_offset[j];
|
2015-07-29 21:16:28 +10:00
|
|
|
/* remap to global indices */
|
|
|
|
|
tri[0] = plink->poly[tri[0]];
|
|
|
|
|
tri[1] = plink->poly[tri[1]];
|
|
|
|
|
tri[2] = plink->poly[tri[2]];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
orig_index[i] = poly_index;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
BLI_memarena_clear(pf_arena);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
zero_v3(orig_normal[poly_index]);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
Py_DECREF(py_coords_fast);
|
|
|
|
|
Py_DECREF(py_tris_fast);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (pf_arena) {
|
|
|
|
|
BLI_memarena_free(pf_arena);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (poly_arena) {
|
|
|
|
|
BLI_memarena_free(poly_arena);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (valid) {
|
|
|
|
|
BVHTree *tree;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
tree = BLI_bvhtree_new(int(tris_len), epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT);
|
2015-07-29 21:16:28 +10:00
|
|
|
if (tree) {
|
|
|
|
|
for (i = 0; i < tris_len; i++) {
|
|
|
|
|
float co[3][3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
copy_v3_v3(co[0], coords[tris[i][0]]);
|
|
|
|
|
copy_v3_v3(co[1], coords[tris[i][1]]);
|
|
|
|
|
copy_v3_v3(co[2], coords[tris[i][2]]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
BLI_bvhtree_insert(tree, int(i), co[0], 3);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
BLI_bvhtree_balance(tree);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
return bvhtree_CreatePyObject(
|
|
|
|
|
tree, epsilon, coords, coords_len, tris, tris_len, orig_index, orig_normal);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
if (coords) {
|
|
|
|
|
MEM_freeN(coords);
|
|
|
|
|
}
|
|
|
|
|
if (tris) {
|
|
|
|
|
MEM_freeN(tris);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef MATH_STANDALONE
|
|
|
|
|
|
|
|
|
|
PyDoc_STRVAR(C_BVHTree_FromBMesh_doc,
|
2015-08-24 08:12:59 +10:00
|
|
|
".. classmethod:: FromBMesh(bmesh, epsilon=0.0)\n"
|
2015-07-29 21:16:28 +10:00
|
|
|
"\n"
|
|
|
|
|
" BVH tree based on :class:`BMesh` data.\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" :arg bmesh: BMesh data.\n"
|
|
|
|
|
" :type bmesh: :class:`BMesh`\n" PYBVH_FROM_GENERIC_EPSILON_DOC);
|
2023-03-02 23:14:33 +01:00
|
|
|
static PyObject *C_BVHTree_FromBMesh(PyObject * /*cls*/, PyObject *args, PyObject *kwargs)
|
2015-07-29 21:16:28 +10:00
|
|
|
{
|
2023-03-02 23:14:33 +01:00
|
|
|
const char *keywords[] = {"bmesh", "epsilon", nullptr};
|
2015-07-29 21:16:28 +10:00
|
|
|
|
|
|
|
|
BPy_BMesh *py_bm;
|
|
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
float(*coords)[3] = nullptr;
|
|
|
|
|
uint(*tris)[3] = nullptr;
|
2020-02-20 15:38:58 +11:00
|
|
|
uint coords_len, tris_len;
|
2015-07-29 21:16:28 +10:00
|
|
|
float epsilon = 0.0f;
|
|
|
|
|
|
|
|
|
|
BMesh *bm;
|
|
|
|
|
BMLoop *(*looptris)[3];
|
|
|
|
|
|
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args,
|
|
|
|
|
kwargs,
|
2019-12-20 10:42:57 +11:00
|
|
|
"O!|$f:BVHTree.FromBMesh",
|
2015-07-29 21:16:28 +10:00
|
|
|
(char **)keywords,
|
|
|
|
|
&BPy_BMesh_Type,
|
|
|
|
|
&py_bm,
|
|
|
|
|
&epsilon)) {
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bm = py_bm->bm;
|
|
|
|
|
|
|
|
|
|
/* Get data for tessellation */
|
|
|
|
|
{
|
2023-03-02 23:14:33 +01:00
|
|
|
coords_len = uint(bm->totvert);
|
|
|
|
|
tris_len = uint(poly_to_tri_count(bm->totface, bm->totloop));
|
2015-07-29 21:16:28 +10:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
coords = static_cast<float(*)[3]>(MEM_mallocN(sizeof(*coords) * size_t(coords_len), __func__));
|
|
|
|
|
tris = static_cast<uint(*)[3]>(MEM_mallocN(sizeof(*tris) * size_t(tris_len), __func__));
|
2015-07-29 21:16:28 +10:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
looptris = static_cast<BMLoop *(*)[3]>(
|
|
|
|
|
MEM_mallocN(sizeof(*looptris) * size_t(tris_len), __func__));
|
2015-07-29 21:16:28 +10:00
|
|
|
|
2021-06-01 12:49:22 +10:00
|
|
|
BM_mesh_calc_tessellation(bm, looptris);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
BMIter iter;
|
|
|
|
|
BVHTree *tree;
|
2020-02-20 15:38:58 +11:00
|
|
|
uint i;
|
2015-07-29 21:16:28 +10:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
int *orig_index = nullptr;
|
|
|
|
|
float(*orig_normal)[3] = nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
tree = BLI_bvhtree_new(int(tris_len), epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT);
|
2015-07-29 21:16:28 +10:00
|
|
|
if (tree) {
|
|
|
|
|
BMFace *f;
|
|
|
|
|
BMVert *v;
|
|
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
orig_index = static_cast<int *>(
|
|
|
|
|
MEM_mallocN(sizeof(*orig_index) * size_t(tris_len), __func__));
|
|
|
|
|
orig_normal = static_cast<float(*)[3]>(
|
|
|
|
|
MEM_mallocN(sizeof(*orig_normal) * size_t(bm->totface), __func__));
|
2015-07-29 21:16:28 +10:00
|
|
|
|
|
|
|
|
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
|
|
|
|
|
copy_v3_v3(coords[i], v->co);
|
2023-03-02 23:14:33 +01:00
|
|
|
BM_elem_index_set(v, int(i)); /* set_inline */
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
|
|
|
|
|
copy_v3_v3(orig_normal[i], f->no);
|
2023-03-02 23:14:33 +01:00
|
|
|
BM_elem_index_set(f, int(i)); /* set_inline */
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2023-03-03 16:22:49 +11:00
|
|
|
bm->elem_index_dirty &= char(~(BM_VERT | BM_FACE));
|
2015-07-29 21:16:28 +10:00
|
|
|
|
|
|
|
|
for (i = 0; i < tris_len; i++) {
|
|
|
|
|
float co[3][3];
|
|
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
tris[i][0] = uint(BM_elem_index_get(looptris[i][0]->v));
|
|
|
|
|
tris[i][1] = uint(BM_elem_index_get(looptris[i][1]->v));
|
|
|
|
|
tris[i][2] = uint(BM_elem_index_get(looptris[i][2]->v));
|
2015-07-29 21:16:28 +10:00
|
|
|
|
|
|
|
|
copy_v3_v3(co[0], coords[tris[i][0]]);
|
|
|
|
|
copy_v3_v3(co[1], coords[tris[i][1]]);
|
|
|
|
|
copy_v3_v3(co[2], coords[tris[i][2]]);
|
|
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
BLI_bvhtree_insert(tree, int(i), co[0], 3);
|
2015-07-29 21:16:28 +10:00
|
|
|
orig_index[i] = BM_elem_index_get(looptris[i][0]->f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_bvhtree_balance(tree);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_freeN(looptris);
|
|
|
|
|
|
|
|
|
|
return bvhtree_CreatePyObject(
|
|
|
|
|
tree, epsilon, coords, coords_len, tris, tris_len, orig_index, orig_normal);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* return various derived meshes based on requested settings */
|
2018-09-27 15:54:10 +02:00
|
|
|
static Mesh *bvh_get_mesh(const char *funcname,
|
2023-03-02 23:14:33 +01:00
|
|
|
Depsgraph *depsgraph,
|
|
|
|
|
Scene *scene,
|
2018-12-04 20:47:13 -02:00
|
|
|
Object *ob,
|
2018-12-27 17:18:05 +01:00
|
|
|
const bool use_deform,
|
|
|
|
|
const bool use_cage,
|
|
|
|
|
bool *r_free_mesh)
|
2015-07-29 21:16:28 +10:00
|
|
|
{
|
2018-12-27 17:18:05 +01:00
|
|
|
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
|
2015-07-29 21:16:28 +10:00
|
|
|
/* we only need minimum mesh data for topology and vertex locations */
|
2020-08-20 16:10:13 +10:00
|
|
|
const CustomData_MeshMasks data_masks = CD_MASK_BAREMESH;
|
2018-12-07 11:54:24 -02:00
|
|
|
const bool use_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
|
2018-12-27 17:18:05 +01:00
|
|
|
*r_free_mesh = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* Write the display mesh into the dummy mesh */
|
|
|
|
|
if (use_deform) {
|
|
|
|
|
if (use_render) {
|
|
|
|
|
if (use_cage) {
|
|
|
|
|
PyErr_Format(
|
|
|
|
|
PyExc_ValueError,
|
2018-12-07 11:54:24 -02:00
|
|
|
"%s(...): cage arg is unsupported when dependency graph evaluation mode is RENDER",
|
|
|
|
|
funcname);
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
|
|
|
|
*r_free_mesh = true;
|
2020-08-18 12:58:48 +02:00
|
|
|
return mesh_create_eval_final(depsgraph, scene, ob, &data_masks);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2023-03-02 23:14:33 +01:00
|
|
|
if (ob_eval != nullptr) {
|
2015-07-29 21:16:28 +10:00
|
|
|
if (use_cage) {
|
2019-03-27 19:07:16 +01:00
|
|
|
return mesh_get_eval_deform(depsgraph, scene, ob_eval, &data_masks);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
|
|
|
|
return mesh_get_eval_final(depsgraph, scene, ob_eval, &data_masks);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
|
|
|
|
PyErr_Format(PyExc_ValueError,
|
|
|
|
|
"%s(...): Cannot get evaluated data from given dependency graph / object pair",
|
|
|
|
|
funcname);
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2020-08-07 12:41:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* !use_deform */
|
|
|
|
|
if (use_render) {
|
|
|
|
|
if (use_cage) {
|
|
|
|
|
PyErr_Format(
|
|
|
|
|
PyExc_ValueError,
|
|
|
|
|
"%s(...): cage arg is unsupported when dependency graph evaluation mode is RENDER",
|
|
|
|
|
funcname);
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
|
|
|
|
*r_free_mesh = true;
|
|
|
|
|
return mesh_create_eval_no_deform_render(depsgraph, scene, ob, &data_masks);
|
2018-12-27 17:18:05 +01:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
|
|
|
|
if (use_cage) {
|
|
|
|
|
PyErr_Format(PyExc_ValueError,
|
|
|
|
|
"%s(...): cage arg is unsupported when deform=False and dependency graph "
|
|
|
|
|
"evaluation mode is not RENDER",
|
|
|
|
|
funcname);
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
|
|
|
|
*r_free_mesh = true;
|
|
|
|
|
return mesh_create_eval_no_deform(depsgraph, scene, ob, &data_masks);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyDoc_STRVAR(C_BVHTree_FromObject_doc,
|
2018-12-04 20:47:13 -02:00
|
|
|
".. classmethod:: FromObject(object, depsgraph, deform=True, render=False, "
|
|
|
|
|
"cage=False, epsilon=0.0)\n"
|
2015-07-29 21:16:28 +10:00
|
|
|
"\n"
|
|
|
|
|
" BVH tree based on :class:`Object` data.\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" :arg object: Object data.\n"
|
|
|
|
|
" :type object: :class:`Object`\n"
|
2018-12-04 20:47:13 -02:00
|
|
|
" :arg depsgraph: Depsgraph to use for evaluating the mesh.\n"
|
|
|
|
|
" :type depsgraph: :class:`Depsgraph`\n"
|
2015-07-29 21:16:28 +10:00
|
|
|
" :arg deform: Use mesh with deformations.\n"
|
|
|
|
|
" :type deform: bool\n"
|
2018-12-07 11:54:24 -02:00
|
|
|
" :arg cage: Use modifiers cage.\n"
|
2015-07-29 21:16:28 +10:00
|
|
|
" :type cage: bool\n" PYBVH_FROM_GENERIC_EPSILON_DOC);
|
2023-03-02 23:14:33 +01:00
|
|
|
static PyObject *C_BVHTree_FromObject(PyObject * /*cls*/, PyObject *args, PyObject *kwargs)
|
2015-07-29 21:16:28 +10:00
|
|
|
{
|
2021-07-03 23:08:40 +10:00
|
|
|
/* NOTE: options here match #bpy_bmesh_from_object. */
|
2023-03-02 23:14:33 +01:00
|
|
|
const char *keywords[] = {"object", "depsgraph", "deform", "cage", "epsilon", nullptr};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-04 20:47:13 -02:00
|
|
|
PyObject *py_ob, *py_depsgraph;
|
2015-07-29 21:16:28 +10:00
|
|
|
Object *ob;
|
2023-03-02 23:14:33 +01:00
|
|
|
Depsgraph *depsgraph;
|
|
|
|
|
Scene *scene;
|
2018-09-27 15:54:10 +02:00
|
|
|
Mesh *mesh;
|
2015-08-03 20:00:16 +10:00
|
|
|
bool use_deform = true;
|
|
|
|
|
bool use_cage = false;
|
2018-12-27 17:18:05 +01:00
|
|
|
bool free_mesh = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
const MLoopTri *lt;
|
Mesh: Replace MLoop struct with generic attributes
Implements #102359.
Split the `MLoop` struct into two separate integer arrays called
`corner_verts` and `corner_edges`, referring to the vertex each corner
is attached to and the next edge around the face at each corner. These
arrays can be sliced to give access to the edges or vertices in a face.
Then they are often referred to as "poly_verts" or "poly_edges".
The main benefits are halving the necessary memory bandwidth when only
one array is used and simplifications from using regular integer indices
instead of a special-purpose struct.
The commit also starts a renaming from "loop" to "corner" in mesh code.
Like the other mesh struct of array refactors, forward compatibility is
kept by writing files with the older format. This will be done until 4.0
to ease the transition process.
Looking at a small portion of the patch should give a good impression
for the rest of the changes. I tried to make the changes as small as
possible so it's easy to tell the correctness from the diff. Though I
found Blender developers have been very inventive over the last decade
when finding different ways to loop over the corners in a face.
For performance, nearly every piece of code that deals with `Mesh` is
slightly impacted. Any algorithm that is memory bottle-necked should
see an improvement. For example, here is a comparison of interpolating
a vertex float attribute to face corners (Ryzen 3700x):
**Before** (Average: 3.7 ms, Min: 3.4 ms)
```
threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) {
for (const int64_t i : range) {
dst[i] = src[loops[i].v];
}
});
```
**After** (Average: 2.9 ms, Min: 2.6 ms)
```
array_utils::gather(src, corner_verts, dst);
```
That's an improvement of 28% to the average timings, and it's also a
simplification, since an index-based routine can be used instead.
For more examples using the new arrays, see the design task.
Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
|
|
|
const int *corner_verts;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
float(*coords)[3] = nullptr;
|
|
|
|
|
uint(*tris)[3] = nullptr;
|
2020-02-20 15:38:58 +11:00
|
|
|
uint coords_len, tris_len;
|
2015-07-29 21:16:28 +10:00
|
|
|
float epsilon = 0.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
if (!PyArg_ParseTupleAndKeywords(args,
|
2018-12-07 11:54:24 -02:00
|
|
|
kwargs,
|
2019-12-20 10:42:57 +11:00
|
|
|
"OO|$O&O&f:BVHTree.FromObject",
|
2018-12-07 11:54:24 -02:00
|
|
|
(char **)keywords,
|
2018-12-04 20:47:13 -02:00
|
|
|
&py_ob,
|
|
|
|
|
&py_depsgraph,
|
2015-08-03 20:00:16 +10:00
|
|
|
PyC_ParseBool,
|
|
|
|
|
&use_deform,
|
|
|
|
|
PyC_ParseBool,
|
|
|
|
|
&use_cage,
|
|
|
|
|
&epsilon) ||
|
2023-03-02 23:14:33 +01:00
|
|
|
((ob = static_cast<Object *>(PyC_RNA_AsPointer(py_ob, "Object"))) == nullptr) ||
|
|
|
|
|
((depsgraph = static_cast<Depsgraph *>(PyC_RNA_AsPointer(py_depsgraph, "Depsgraph"))) ==
|
|
|
|
|
nullptr)) {
|
|
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-04 20:47:13 -02:00
|
|
|
scene = DEG_get_evaluated_scene(depsgraph);
|
2018-12-27 17:18:05 +01:00
|
|
|
mesh = bvh_get_mesh("BVHTree", depsgraph, scene, ob, use_deform, use_cage, &free_mesh);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
if (mesh == nullptr) {
|
|
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* Get data for tessellation */
|
|
|
|
|
{
|
2018-09-27 15:54:10 +02:00
|
|
|
lt = BKE_mesh_runtime_looptri_ensure(mesh);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
tris_len = uint(BKE_mesh_runtime_looptri_len(mesh));
|
|
|
|
|
coords_len = uint(mesh->totvert);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
coords = static_cast<float(*)[3]>(MEM_mallocN(sizeof(*coords) * size_t(coords_len), __func__));
|
|
|
|
|
tris = static_cast<uint(*)[3]>(MEM_mallocN(sizeof(*tris) * size_t(tris_len), __func__));
|
|
|
|
|
memcpy(coords, BKE_mesh_vert_positions(mesh), sizeof(float[3]) * size_t(mesh->totvert));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Mesh: Replace MLoop struct with generic attributes
Implements #102359.
Split the `MLoop` struct into two separate integer arrays called
`corner_verts` and `corner_edges`, referring to the vertex each corner
is attached to and the next edge around the face at each corner. These
arrays can be sliced to give access to the edges or vertices in a face.
Then they are often referred to as "poly_verts" or "poly_edges".
The main benefits are halving the necessary memory bandwidth when only
one array is used and simplifications from using regular integer indices
instead of a special-purpose struct.
The commit also starts a renaming from "loop" to "corner" in mesh code.
Like the other mesh struct of array refactors, forward compatibility is
kept by writing files with the older format. This will be done until 4.0
to ease the transition process.
Looking at a small portion of the patch should give a good impression
for the rest of the changes. I tried to make the changes as small as
possible so it's easy to tell the correctness from the diff. Though I
found Blender developers have been very inventive over the last decade
when finding different ways to loop over the corners in a face.
For performance, nearly every piece of code that deals with `Mesh` is
slightly impacted. Any algorithm that is memory bottle-necked should
see an improvement. For example, here is a comparison of interpolating
a vertex float attribute to face corners (Ryzen 3700x):
**Before** (Average: 3.7 ms, Min: 3.4 ms)
```
threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) {
for (const int64_t i : range) {
dst[i] = src[loops[i].v];
}
});
```
**After** (Average: 2.9 ms, Min: 2.6 ms)
```
array_utils::gather(src, corner_verts, dst);
```
That's an improvement of 28% to the average timings, and it's also a
simplification, since an index-based routine can be used instead.
For more examples using the new arrays, see the design task.
Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
|
|
|
corner_verts = BKE_mesh_corner_verts(mesh);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
{
|
|
|
|
|
BVHTree *tree;
|
2020-02-20 15:38:58 +11:00
|
|
|
uint i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
int *orig_index = nullptr;
|
2023-03-15 14:00:40 -04:00
|
|
|
blender::float3 *orig_normal = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
tree = BLI_bvhtree_new(int(tris_len), epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT);
|
2015-07-29 21:16:28 +10:00
|
|
|
if (tree) {
|
2023-03-02 23:14:33 +01:00
|
|
|
orig_index = static_cast<int *>(
|
|
|
|
|
MEM_mallocN(sizeof(*orig_index) * size_t(tris_len), __func__));
|
2022-02-21 11:40:59 -05:00
|
|
|
if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
|
2023-03-15 14:00:40 -04:00
|
|
|
const blender::Span<blender::float3> poly_normals = mesh->poly_normals();
|
|
|
|
|
orig_normal = static_cast<blender::float3 *>(
|
|
|
|
|
MEM_malloc_arrayN(size_t(mesh->totpoly), sizeof(blender::float3), __func__));
|
|
|
|
|
blender::MutableSpan(orig_normal, poly_normals.size()).copy_from(poly_normals);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
for (i = 0; i < tris_len; i++, lt++) {
|
|
|
|
|
float co[3][3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-21 19:46:13 +11:00
|
|
|
tris[i][0] = uint(corner_verts[lt->tri[0]]);
|
|
|
|
|
tris[i][1] = uint(corner_verts[lt->tri[1]]);
|
|
|
|
|
tris[i][2] = uint(corner_verts[lt->tri[2]]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
copy_v3_v3(co[0], coords[tris[i][0]]);
|
|
|
|
|
copy_v3_v3(co[1], coords[tris[i][1]]);
|
|
|
|
|
copy_v3_v3(co[2], coords[tris[i][2]]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
BLI_bvhtree_insert(tree, int(i), co[0], 3);
|
|
|
|
|
orig_index[i] = int(lt->poly);
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
BLI_bvhtree_balance(tree);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-27 17:18:05 +01:00
|
|
|
if (free_mesh) {
|
2023-03-02 23:14:33 +01:00
|
|
|
BKE_id_free(nullptr, mesh);
|
2018-12-27 17:18:05 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-15 14:00:40 -04:00
|
|
|
return bvhtree_CreatePyObject(tree,
|
|
|
|
|
epsilon,
|
|
|
|
|
coords,
|
|
|
|
|
coords_len,
|
|
|
|
|
tris,
|
|
|
|
|
tris_len,
|
|
|
|
|
orig_index,
|
|
|
|
|
reinterpret_cast<float(*)[3]>(orig_normal));
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* MATH_STANDALONE */
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Module & Type definition
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2023-03-03 09:53:23 +11:00
|
|
|
#ifdef __GNUC__
|
|
|
|
|
# pragma GCC diagnostic push
|
|
|
|
|
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
static PyMethodDef py_bvhtree_methods[] = {
|
2023-03-03 09:53:23 +11:00
|
|
|
{"ray_cast",
|
|
|
|
|
reinterpret_cast<PyCFunction>(py_bvhtree_ray_cast),
|
|
|
|
|
METH_VARARGS,
|
|
|
|
|
py_bvhtree_ray_cast_doc},
|
2016-02-08 08:26:04 +11:00
|
|
|
{"find_nearest",
|
2023-03-03 09:53:23 +11:00
|
|
|
reinterpret_cast<PyCFunction>(py_bvhtree_find_nearest),
|
2016-02-08 08:26:04 +11:00
|
|
|
METH_VARARGS,
|
|
|
|
|
py_bvhtree_find_nearest_doc},
|
2016-03-19 18:29:47 +11:00
|
|
|
{"find_nearest_range",
|
2023-03-03 09:53:23 +11:00
|
|
|
reinterpret_cast<PyCFunction>(py_bvhtree_find_nearest_range),
|
2016-03-19 18:29:47 +11:00
|
|
|
METH_VARARGS,
|
|
|
|
|
py_bvhtree_find_nearest_range_doc},
|
2023-03-03 09:53:23 +11:00
|
|
|
{"overlap", reinterpret_cast<PyCFunction>(py_bvhtree_overlap), METH_O, py_bvhtree_overlap_doc},
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
/* class methods */
|
|
|
|
|
{"FromPolygons",
|
2023-03-03 09:53:23 +11:00
|
|
|
reinterpret_cast<PyCFunction>(C_BVHTree_FromPolygons),
|
2015-07-29 21:16:28 +10:00
|
|
|
METH_VARARGS | METH_KEYWORDS | METH_CLASS,
|
|
|
|
|
C_BVHTree_FromPolygons_doc},
|
|
|
|
|
#ifndef MATH_STANDALONE
|
|
|
|
|
{"FromBMesh",
|
2023-03-03 09:53:23 +11:00
|
|
|
reinterpret_cast<PyCFunction>(C_BVHTree_FromBMesh),
|
2015-07-29 21:16:28 +10:00
|
|
|
METH_VARARGS | METH_KEYWORDS | METH_CLASS,
|
|
|
|
|
C_BVHTree_FromBMesh_doc},
|
|
|
|
|
{"FromObject",
|
2023-03-03 09:53:23 +11:00
|
|
|
reinterpret_cast<PyCFunction>(C_BVHTree_FromObject),
|
2015-07-29 21:16:28 +10:00
|
|
|
METH_VARARGS | METH_KEYWORDS | METH_CLASS,
|
|
|
|
|
C_BVHTree_FromObject_doc},
|
|
|
|
|
#endif
|
2023-03-02 23:14:33 +01:00
|
|
|
{nullptr, nullptr, 0, nullptr},
|
2015-07-29 21:16:28 +10:00
|
|
|
};
|
|
|
|
|
|
2023-03-03 09:53:23 +11:00
|
|
|
#ifdef __GNUC__
|
|
|
|
|
# pragma GCC diagnostic pop
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-07-29 21:16:28 +10:00
|
|
|
PyTypeObject PyBVHTree_Type = {
|
2023-03-02 23:14:33 +01:00
|
|
|
PyVarObject_HEAD_INIT(nullptr, 0)
|
2022-11-07 22:34:35 +11:00
|
|
|
/*tp_name*/ "BVHTree",
|
|
|
|
|
/*tp_basicsize*/ sizeof(PyBVHTree),
|
|
|
|
|
/*tp_itemsize*/ 0,
|
|
|
|
|
/*tp_dealloc*/ (destructor)py_bvhtree__tp_dealloc,
|
|
|
|
|
/*tp_vectorcall_offset*/ 0,
|
2023-03-02 23:14:33 +01:00
|
|
|
/*tp_getattr*/ nullptr,
|
|
|
|
|
/*tp_setattr*/ nullptr,
|
|
|
|
|
/*tp_as_async*/ nullptr,
|
|
|
|
|
/*tp_repr*/ nullptr,
|
|
|
|
|
/*tp_as_number*/ nullptr,
|
|
|
|
|
/*tp_as_sequence*/ nullptr,
|
|
|
|
|
/*tp_as_mapping*/ nullptr,
|
|
|
|
|
/*tp_hash*/ nullptr,
|
|
|
|
|
/*tp_call*/ nullptr,
|
|
|
|
|
/*tp_str*/ nullptr,
|
|
|
|
|
/*tp_getattro*/ nullptr,
|
|
|
|
|
/*tp_setattro*/ nullptr,
|
|
|
|
|
/*tp_as_buffer*/ nullptr,
|
2022-11-07 22:34:35 +11:00
|
|
|
/*tp_flags*/ Py_TPFLAGS_DEFAULT,
|
2023-03-02 23:14:33 +01:00
|
|
|
/*tp_doc*/ nullptr,
|
|
|
|
|
/*tp_traverse*/ nullptr,
|
|
|
|
|
/*tp_clear*/ nullptr,
|
|
|
|
|
/*tp_richcompare*/ nullptr,
|
2022-11-07 22:34:35 +11:00
|
|
|
/*tp_weaklistoffset*/ 0,
|
2023-03-02 23:14:33 +01:00
|
|
|
/*tp_iter*/ nullptr,
|
|
|
|
|
/*tp_iternext*/ nullptr,
|
2022-11-07 22:34:35 +11:00
|
|
|
/*tp_methods*/ py_bvhtree_methods,
|
2023-03-02 23:14:33 +01:00
|
|
|
/*tp_members*/ nullptr,
|
|
|
|
|
/*tp_getset*/ nullptr,
|
|
|
|
|
/*tp_base*/ nullptr,
|
|
|
|
|
/*tp_dict*/ nullptr,
|
|
|
|
|
/*tp_descr_get*/ nullptr,
|
|
|
|
|
/*tp_descr_set*/ nullptr,
|
2022-11-07 22:34:35 +11:00
|
|
|
/*tp_dictoffset*/ 0,
|
2023-03-02 23:14:33 +01:00
|
|
|
/*tp_init*/ nullptr,
|
2022-11-07 22:34:35 +11:00
|
|
|
/*tp_alloc*/ (allocfunc)PyType_GenericAlloc,
|
|
|
|
|
/*tp_new*/ (newfunc)PyType_GenericNew,
|
|
|
|
|
/*tp_free*/ (freefunc)0,
|
2023-03-02 23:14:33 +01:00
|
|
|
/*tp_is_gc*/ nullptr,
|
|
|
|
|
/*tp_bases*/ nullptr,
|
|
|
|
|
/*tp_mro*/ nullptr,
|
|
|
|
|
/*tp_cache*/ nullptr,
|
|
|
|
|
/*tp_subclasses*/ nullptr,
|
|
|
|
|
/*tp_weaklist*/ nullptr,
|
|
|
|
|
/*tp_del*/ (destructor) nullptr,
|
2022-11-07 22:34:35 +11:00
|
|
|
/*tp_version_tag*/ 0,
|
2023-03-02 23:14:33 +01:00
|
|
|
/*tp_finalize*/ nullptr,
|
|
|
|
|
/*tp_vectorcall*/ nullptr,
|
2015-07-29 21:16:28 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/* Module definition */
|
|
|
|
|
|
|
|
|
|
PyDoc_STRVAR(py_bvhtree_doc,
|
|
|
|
|
"BVH tree structures for proximity searches and ray casts on geometry.");
|
2023-03-02 23:14:33 +01:00
|
|
|
static PyModuleDef bvhtree_moduledef = {
|
2015-07-29 21:16:28 +10:00
|
|
|
PyModuleDef_HEAD_INIT,
|
2022-11-08 11:13:58 +11:00
|
|
|
/*m_name*/ "mathutils.bvhtree",
|
|
|
|
|
/*m_doc*/ py_bvhtree_doc,
|
|
|
|
|
/*m_size*/ 0,
|
2023-03-02 23:14:33 +01:00
|
|
|
/*m_methods*/ nullptr,
|
|
|
|
|
/*m_slots*/ nullptr,
|
|
|
|
|
/*m_traverse*/ nullptr,
|
|
|
|
|
/*m_clear*/ nullptr,
|
|
|
|
|
/*m_free*/ nullptr,
|
2015-07-29 21:16:28 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PyMODINIT_FUNC PyInit_mathutils_bvhtree(void)
|
|
|
|
|
{
|
|
|
|
|
PyObject *m = PyModule_Create(&bvhtree_moduledef);
|
|
|
|
|
|
2023-03-02 23:14:33 +01:00
|
|
|
if (m == nullptr) {
|
|
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Register classes */
|
|
|
|
|
if (PyType_Ready(&PyBVHTree_Type) < 0) {
|
2023-03-02 23:14:33 +01:00
|
|
|
return nullptr;
|
2015-07-29 21:16:28 +10:00
|
|
|
}
|
|
|
|
|
|
2021-02-12 08:08:16 +11:00
|
|
|
PyModule_AddType(m, &PyBVHTree_Type);
|
2015-07-29 21:16:28 +10:00
|
|
|
|
|
|
|
|
return m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|