The depsgraph was always created within a fixed evaluation context. Passing both risks the depsgraph and evaluation context not matching, and it complicates the Python API where we'd have to expose both which is not so easy to understand. This also removes the global evaluation context in main, which assumed there to be a single active scene and view layer. Differential Revision: https://developer.blender.org/D3152
1333 lines
36 KiB
C
1333 lines
36 KiB
C
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* 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.
|
|
*
|
|
* Contributor(s): Lukas Toenne, Campbell Barton
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/python/mathutils/mathutils_bvhtree.c
|
|
* \ingroup mathutils
|
|
*
|
|
* 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"
|
|
|
|
#include "BLI_utildefines.h"
|
|
#include "BLI_kdopbvh.h"
|
|
#include "BLI_polyfill_2d.h"
|
|
#include "BLI_math.h"
|
|
#include "BLI_ghash.h"
|
|
#include "BLI_memarena.h"
|
|
|
|
#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
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "BKE_customdata.h"
|
|
#include "BKE_DerivedMesh.h"
|
|
#include "BKE_editmesh_bvh.h"
|
|
|
|
#include "bmesh.h"
|
|
|
|
#include "../bmesh/bmesh_py_types.h"
|
|
#endif /* MATH_STANDALONE */
|
|
|
|
|
|
#include "BLI_strict_flags.h"
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Docstring (snippets)
|
|
* \{ */
|
|
|
|
#define PYBVH_FIND_GENERIC_DISTANCE_DOC \
|
|
" :arg distance: Maximum distance threshold.\n" \
|
|
" :type distance: float\n"
|
|
|
|
#define PYBVH_FIND_GENERIC_RETURN_DOC \
|
|
" :return: Returns a tuple\n" \
|
|
" (:class:`Vector` location, :class:`Vector` normal, int index, float distance),\n" \
|
|
" Values will all be None if no hit is found.\n" \
|
|
" :rtype: :class:`tuple`\n"
|
|
|
|
#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"
|
|
|
|
#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;
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
BVHTree *tree;
|
|
float epsilon;
|
|
|
|
float (*coords)[3];
|
|
unsigned int (*tris)[3];
|
|
unsigned int coords_len, tris_len;
|
|
|
|
/* Optional members */
|
|
/* aligned with 'tris' */
|
|
int *orig_index;
|
|
/* aligned with array that 'orig_index' points to */
|
|
float (*orig_normal)[3];
|
|
} PyBVHTree;
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Utility helper functions
|
|
* \{ */
|
|
|
|
static PyObject *bvhtree_CreatePyObject(
|
|
BVHTree *tree, float epsilon,
|
|
|
|
float (*coords)[3], unsigned int coords_len,
|
|
unsigned int (*tris)[3], unsigned int tris_len,
|
|
|
|
/* 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);
|
|
|
|
PyTuple_SET_ITEMS(py_retval,
|
|
Vector_CreatePyObject(hit->co, 3, NULL),
|
|
Vector_CreatePyObject(hit->no, 3, NULL),
|
|
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);
|
|
|
|
PyTuple_SET_ITEMS(py_retval,
|
|
Vector_CreatePyObject(nearest->co, 3, NULL),
|
|
Vector_CreatePyObject(nearest->no, 3, NULL),
|
|
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)
|
|
{
|
|
const PyBVHTree *self = userdata;
|
|
|
|
const float (*coords)[3] = (const float (*)[3])self->coords;
|
|
const unsigned int *tri = self->tris[index];
|
|
const float *tri_co[3] = {coords[tri[0]], coords[tri[1]], coords[tri[2]]};
|
|
float dist;
|
|
|
|
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));
|
|
}
|
|
|
|
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)
|
|
{
|
|
PyBVHTree *self = userdata;
|
|
|
|
const float (*coords)[3] = (const float (*)[3])self->coords;
|
|
const unsigned int *tri = self->tris[index];
|
|
const float *tri_co[3] = {coords[tri[0]], coords[tri[1]], coords[tri[2]]};
|
|
float nearest_tmp[3], dist_sq;
|
|
|
|
closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(tri_co));
|
|
dist_sq = len_squared_v3v3(co, nearest_tmp);
|
|
|
|
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,
|
|
".. method:: ray_cast(origin, direction, distance=sys.float_info.max)\n"
|
|
"\n"
|
|
" Cast a ray onto the mesh.\n"
|
|
"\n"
|
|
" :arg co: Start location of the ray in object space.\n"
|
|
" :type co: :class:`Vector`\n"
|
|
" :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;
|
|
|
|
/* parse args */
|
|
{
|
|
PyObject *py_co, *py_direction;
|
|
|
|
if (!PyArg_ParseTuple(
|
|
args, (char *)"OO|f:ray_cast",
|
|
&py_co, &py_direction, &max_dist))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
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))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
normalize_v3(direction);
|
|
}
|
|
|
|
hit.dist = max_dist;
|
|
hit.index = -1;
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
return py_bvhtree_raycast_to_py_none();
|
|
}
|
|
|
|
PyDoc_STRVAR(py_bvhtree_find_nearest_doc,
|
|
".. method:: find_nearest(origin, distance=" PYBVH_MAX_DIST_STR ")\n"
|
|
"\n"
|
|
" Find the nearest element (typically face index) to a point.\n"
|
|
"\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;
|
|
|
|
BVHTreeNearest nearest;
|
|
|
|
/* parse args */
|
|
{
|
|
PyObject *py_co;
|
|
|
|
if (!PyArg_ParseTuple(
|
|
args, (char *)"O|f:find_nearest",
|
|
&py_co, &max_dist))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (mathutils_array_parse(co, 2, 3 | MU_ARRAY_ZERO, py_co, error_prefix) == -1) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
nearest.index = -1;
|
|
nearest.dist_sq = max_dist * max_dist;
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
return py_bvhtree_nearest_to_py_none();
|
|
}
|
|
|
|
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], float UNUSED(dist_sq_bvh))
|
|
{
|
|
struct PyBVH_RangeData *data = userdata;
|
|
PyBVHTree *self = data->self;
|
|
|
|
const float (*coords)[3] = (const float (*)[3])self->coords;
|
|
const unsigned int *tri = self->tris[index];
|
|
const float *tri_co[3] = {coords[tri[0]], coords[tri[1]], coords[tri[2]]};
|
|
float nearest_tmp[3], dist_sq;
|
|
|
|
closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(tri_co));
|
|
dist_sq = len_squared_v3v3(co, nearest_tmp);
|
|
|
|
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));
|
|
}
|
|
|
|
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"
|
|
" Find the nearest elements (typically face index) to a point in the distance range.\n"
|
|
"\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;
|
|
|
|
/* parse args */
|
|
{
|
|
PyObject *py_co;
|
|
|
|
if (!PyArg_ParseTuple(
|
|
args, (char *)"O|f:find_nearest_range",
|
|
&py_co, &max_dist))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (mathutils_array_parse(co, 2, 3 | MU_ARRAY_ZERO, py_co, error_prefix) == -1) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
PyObject *ret = PyList_New(0);
|
|
|
|
if (self->tree) {
|
|
struct PyBVH_RangeData data = {
|
|
.self = self,
|
|
.result = ret,
|
|
.dist_sq = SQUARE(max_dist),
|
|
};
|
|
|
|
BLI_bvhtree_range_query(
|
|
self->tree, co, max_dist,
|
|
py_bvhtree_nearest_point_range_cb, &data);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
BLI_INLINE unsigned int overlap_hash(const void *overlap_v)
|
|
{
|
|
const BVHTreeOverlap *overlap = overlap_v;
|
|
/* same constants as edge-hash */
|
|
return (((unsigned int)overlap->indexA * 65) ^ ((unsigned int)overlap->indexA * 31));
|
|
}
|
|
|
|
BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
|
|
{
|
|
const BVHTreeOverlap *a = a_v;
|
|
const BVHTreeOverlap *b = b_v;
|
|
return (memcmp(a, b, sizeof(*a)) != 0);
|
|
}
|
|
|
|
struct PyBVHTree_OverlapData {
|
|
PyBVHTree *tree_pair[2];
|
|
float epsilon;
|
|
};
|
|
|
|
static bool py_bvhtree_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
|
|
{
|
|
struct PyBVHTree_OverlapData *data = userdata;
|
|
PyBVHTree *tree_a = data->tree_pair[0];
|
|
PyBVHTree *tree_b = data->tree_pair[1];
|
|
const unsigned int *tri_a = tree_a->tris[index_a];
|
|
const unsigned int *tri_b = tree_b->tris[index_b];
|
|
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]]};
|
|
float ix_pair[2][3];
|
|
int verts_shared = 0;
|
|
|
|
if (tree_a == tree_b) {
|
|
if (UNLIKELY(index_a == index_b)) {
|
|
return false;
|
|
}
|
|
|
|
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)));
|
|
|
|
/* if 2 points are shared, bail out */
|
|
if (verts_shared >= 2) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return (isect_tri_tri_epsilon_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1], data->epsilon) &&
|
|
((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
|
|
}
|
|
|
|
PyDoc_STRVAR(py_bvhtree_overlap_doc,
|
|
".. method:: overlap(other_tree)\n"
|
|
"\n"
|
|
" Find overlapping indices between 2 trees.\n"
|
|
"\n"
|
|
" :arg other_tree: Other tree to preform overlap test on.\n"
|
|
" :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)
|
|
{
|
|
struct PyBVHTree_OverlapData data;
|
|
BVHTreeOverlap *overlap;
|
|
unsigned int overlap_len = 0;
|
|
PyObject *ret;
|
|
|
|
if (!PyBVHTree_CheckExact(other)) {
|
|
PyErr_SetString(PyExc_ValueError, "Expected a BVHTree argument");
|
|
return NULL;
|
|
}
|
|
|
|
data.tree_pair[0] = self;
|
|
data.tree_pair[1] = other;
|
|
data.epsilon = max_ff(self->epsilon, other->epsilon);
|
|
|
|
overlap = BLI_bvhtree_overlap(self->tree, other->tree, &overlap_len, py_bvhtree_overlap_cb, &data);
|
|
|
|
ret = PyList_New(0);
|
|
|
|
if (overlap == NULL) {
|
|
/* pass */
|
|
}
|
|
else {
|
|
bool use_unique = (self->orig_index || other->orig_index);
|
|
GSet *pair_test = use_unique ? BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, overlap_len) : NULL;
|
|
/* simple case, no index remapping */
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < overlap_len; i++) {
|
|
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];
|
|
}
|
|
|
|
/* skip if its already added */
|
|
if (!BLI_gset_add(pair_test, &overlap[i])) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
item = PyTuple_New(2);
|
|
PyTuple_SET_ITEMS(item,
|
|
PyLong_FromLong(overlap[i].indexA),
|
|
PyLong_FromLong(overlap[i].indexB));
|
|
|
|
PyList_Append(ret, item);
|
|
Py_DECREF(item);
|
|
}
|
|
|
|
if (pair_test) {
|
|
BLI_gset_free(pair_test, NULL);
|
|
}
|
|
}
|
|
|
|
if (overlap) {
|
|
MEM_freeN(overlap);
|
|
}
|
|
|
|
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
|
|
);
|
|
static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, PyObject *kwargs)
|
|
{
|
|
const char *error_prefix = "BVHTree.FromPolygons";
|
|
const char *keywords[] = {"vertices", "polygons", "all_triangles", "epsilon", NULL};
|
|
|
|
PyObject *py_coords, *py_tris;
|
|
PyObject *py_coords_fast = NULL, *py_tris_fast = NULL;
|
|
|
|
MemArena *poly_arena = NULL;
|
|
MemArena *pf_arena = NULL;
|
|
|
|
float (*coords)[3] = NULL;
|
|
unsigned int (*tris)[3] = NULL;
|
|
unsigned int coords_len, tris_len;
|
|
float epsilon = 0.0f;
|
|
bool all_triangles = false;
|
|
|
|
/* when all_triangles is False */
|
|
int *orig_index = NULL;
|
|
float (*orig_normal)[3] = NULL;
|
|
|
|
unsigned int i;
|
|
bool valid = true;
|
|
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(
|
|
args, kwargs, (char *)"OO|$O&f:BVHTree.FromPolygons", (char **)keywords,
|
|
&py_coords, &py_tris,
|
|
PyC_ParseBool, &all_triangles,
|
|
&epsilon))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (!(py_coords_fast = PySequence_Fast(py_coords, error_prefix)) ||
|
|
!(py_tris_fast = PySequence_Fast(py_tris, error_prefix)))
|
|
{
|
|
Py_XDECREF(py_coords_fast);
|
|
return NULL;
|
|
}
|
|
|
|
if (valid) {
|
|
PyObject **py_coords_fast_items = PySequence_Fast_ITEMS(py_coords_fast);
|
|
coords_len = (unsigned int)PySequence_Fast_GET_SIZE(py_coords_fast);
|
|
coords = MEM_mallocN((size_t)coords_len * sizeof(*coords), __func__);
|
|
|
|
for (i = 0; i < coords_len; i++) {
|
|
PyObject *py_vert = py_coords_fast_items[i];
|
|
|
|
if (mathutils_array_parse(coords[i], 3, 3, py_vert, "BVHTree vertex: ") == -1) {
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (valid == false) {
|
|
/* pass */
|
|
}
|
|
else if (all_triangles) {
|
|
/* all triangles, simple case */
|
|
PyObject **py_tris_fast_items = PySequence_Fast_ITEMS(py_tris_fast);
|
|
tris_len = (unsigned int)PySequence_Fast_GET_SIZE(py_tris_fast);
|
|
tris = MEM_mallocN((size_t)tris_len * sizeof(*tris), __func__);
|
|
|
|
for (i = 0; i < tris_len; i++) {
|
|
PyObject *py_tricoords = py_tris_fast_items[i];
|
|
PyObject *py_tricoords_fast;
|
|
PyObject **py_tricoords_fast_items;
|
|
unsigned int *tri = tris[i];
|
|
int j;
|
|
|
|
if (!(py_tricoords_fast = PySequence_Fast(py_tricoords, error_prefix))) {
|
|
valid = false;
|
|
break;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
py_tricoords_fast_items = PySequence_Fast_ITEMS(py_tricoords_fast);
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
tri[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]);
|
|
if (UNLIKELY(tri[j] >= (unsigned int)coords_len)) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"%s: index %d must be less than %d",
|
|
error_prefix, tri[j], coords_len);
|
|
|
|
/* decref below */
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Py_DECREF(py_tricoords_fast);
|
|
}
|
|
}
|
|
else {
|
|
/* ngon support (much more involved) */
|
|
const unsigned int polys_len = (unsigned int)PySequence_Fast_GET_SIZE(py_tris_fast);
|
|
struct PolyLink {
|
|
struct PolyLink *next;
|
|
unsigned int len;
|
|
unsigned int poly[0];
|
|
} *plink_first = NULL, **p_plink_prev = &plink_first, *plink = NULL;
|
|
int poly_index;
|
|
|
|
tris_len = 0;
|
|
|
|
poly_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
|
|
|
|
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;
|
|
unsigned int py_tricoords_len;
|
|
unsigned int j;
|
|
|
|
if (!(py_tricoords_fast = PySequence_Fast(py_tricoords, error_prefix))) {
|
|
valid = false;
|
|
break;
|
|
}
|
|
|
|
py_tricoords_len = (unsigned int)PySequence_Fast_GET_SIZE(py_tricoords_fast);
|
|
py_tricoords_fast_items = PySequence_Fast_ITEMS(py_tricoords_fast);
|
|
|
|
plink = BLI_memarena_alloc(poly_arena, sizeof(*plink) + (sizeof(int) * (size_t)py_tricoords_len));
|
|
|
|
plink->len = (unsigned int)py_tricoords_len;
|
|
*p_plink_prev = plink;
|
|
p_plink_prev = &plink->next;
|
|
|
|
for (j = 0; j < py_tricoords_len; j++) {
|
|
plink->poly[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]);
|
|
if (UNLIKELY(plink->poly[j] >= (unsigned int)coords_len)) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"%s: index %d must be less than %d",
|
|
error_prefix, plink->poly[j], coords_len);
|
|
/* decref below */
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Py_DECREF(py_tricoords_fast);
|
|
|
|
if (py_tricoords_len >= 3) {
|
|
tris_len += (py_tricoords_len - 2);
|
|
}
|
|
}
|
|
*p_plink_prev = NULL;
|
|
|
|
/* all ngon's are parsed, now tessellate */
|
|
|
|
pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
|
|
tris = MEM_mallocN(sizeof(*tris) * (size_t)tris_len, __func__);
|
|
|
|
orig_index = MEM_mallocN(sizeof(*orig_index) * (size_t)tris_len, __func__);
|
|
orig_normal = MEM_mallocN(sizeof(*orig_normal) * (size_t)polys_len, __func__);
|
|
|
|
for (plink = plink_first, poly_index = 0, i = 0; plink; plink = plink->next, poly_index++) {
|
|
if (plink->len == 3) {
|
|
unsigned int *tri = tris[i];
|
|
memcpy(tri, plink->poly, sizeof(unsigned int[3]));
|
|
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) {
|
|
float (*proj_coords)[2] = BLI_memarena_alloc(pf_arena, sizeof(*proj_coords) * plink->len);
|
|
float *normal = orig_normal[poly_index];
|
|
const float *co_prev;
|
|
const float *co_curr;
|
|
float axis_mat[3][3];
|
|
unsigned int (*tris_offset)[3] = &tris[i];
|
|
unsigned int j;
|
|
|
|
/* 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);
|
|
|
|
axis_dominant_v3_to_m3_negate(axis_mat, normal);
|
|
|
|
for (j = 0; j < plink->len; j++) {
|
|
mul_v2_m3v3(proj_coords[j], axis_mat, coords[plink->poly[j]]);
|
|
}
|
|
|
|
BLI_polyfill_calc_arena(proj_coords, plink->len, 1, tris_offset, pf_arena);
|
|
|
|
j = plink->len - 2;
|
|
while (j--) {
|
|
unsigned int *tri = tris_offset[j];
|
|
/* remap to global indices */
|
|
tri[0] = plink->poly[tri[0]];
|
|
tri[1] = plink->poly[tri[1]];
|
|
tri[2] = plink->poly[tri[2]];
|
|
|
|
orig_index[i] = poly_index;
|
|
i++;
|
|
}
|
|
|
|
BLI_memarena_clear(pf_arena);
|
|
}
|
|
else {
|
|
zero_v3(orig_normal[poly_index]);
|
|
}
|
|
}
|
|
}
|
|
|
|
Py_DECREF(py_coords_fast);
|
|
Py_DECREF(py_tris_fast);
|
|
|
|
if (pf_arena) {
|
|
BLI_memarena_free(pf_arena);
|
|
}
|
|
|
|
if (poly_arena) {
|
|
BLI_memarena_free(poly_arena);
|
|
}
|
|
|
|
if (valid) {
|
|
BVHTree *tree;
|
|
|
|
tree = BLI_bvhtree_new((int)tris_len, epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT);
|
|
if (tree) {
|
|
for (i = 0; i < tris_len; i++) {
|
|
float co[3][3];
|
|
|
|
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]]);
|
|
|
|
BLI_bvhtree_insert(tree, (int)i, co[0], 3);
|
|
}
|
|
|
|
BLI_bvhtree_balance(tree);
|
|
}
|
|
|
|
return bvhtree_CreatePyObject(
|
|
tree, epsilon,
|
|
coords, coords_len,
|
|
tris, tris_len,
|
|
orig_index, orig_normal);
|
|
}
|
|
else {
|
|
if (coords)
|
|
MEM_freeN(coords);
|
|
if (tris)
|
|
MEM_freeN(tris);
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef MATH_STANDALONE
|
|
|
|
PyDoc_STRVAR(C_BVHTree_FromBMesh_doc,
|
|
".. classmethod:: FromBMesh(bmesh, epsilon=0.0)\n"
|
|
"\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
|
|
);
|
|
static PyObject *C_BVHTree_FromBMesh(PyObject *UNUSED(cls), PyObject *args, PyObject *kwargs)
|
|
{
|
|
const char *keywords[] = {"bmesh", "epsilon", NULL};
|
|
|
|
BPy_BMesh *py_bm;
|
|
|
|
float (*coords)[3] = NULL;
|
|
unsigned int (*tris)[3] = NULL;
|
|
unsigned int coords_len, tris_len;
|
|
float epsilon = 0.0f;
|
|
|
|
BMesh *bm;
|
|
BMLoop *(*looptris)[3];
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(
|
|
args, kwargs, (char *)"O!|$f:BVHTree.FromBMesh", (char **)keywords,
|
|
&BPy_BMesh_Type, &py_bm, &epsilon))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
bm = py_bm->bm;
|
|
|
|
/* Get data for tessellation */
|
|
{
|
|
int tris_len_dummy;
|
|
|
|
coords_len = (unsigned int)bm->totvert;
|
|
tris_len = (unsigned int)poly_to_tri_count(bm->totface, bm->totloop);
|
|
|
|
coords = MEM_mallocN(sizeof(*coords) * (size_t)coords_len, __func__);
|
|
tris = MEM_mallocN(sizeof(*tris) * (size_t)tris_len, __func__);
|
|
|
|
looptris = MEM_mallocN(sizeof(*looptris) * (size_t)tris_len, __func__);
|
|
|
|
BM_mesh_calc_tessellation(bm, looptris, &tris_len_dummy);
|
|
BLI_assert(tris_len_dummy == (int)tris_len);
|
|
}
|
|
|
|
{
|
|
BMIter iter;
|
|
BVHTree *tree;
|
|
unsigned int i;
|
|
|
|
int *orig_index = NULL;
|
|
float (*orig_normal)[3] = NULL;
|
|
|
|
tree = BLI_bvhtree_new((int)tris_len, epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT);
|
|
if (tree) {
|
|
BMFace *f;
|
|
BMVert *v;
|
|
|
|
orig_index = MEM_mallocN(sizeof(*orig_index) * (size_t)tris_len, __func__);
|
|
orig_normal = MEM_mallocN(sizeof(*orig_normal) * (size_t)bm->totface, __func__);
|
|
|
|
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
|
|
copy_v3_v3(coords[i], v->co);
|
|
BM_elem_index_set(v, (int)i); /* set_inline */
|
|
}
|
|
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
|
|
copy_v3_v3(orig_normal[i], f->no);
|
|
BM_elem_index_set(f, (int)i); /* set_inline */
|
|
}
|
|
bm->elem_index_dirty &= (char)~(BM_VERT | BM_FACE);
|
|
|
|
for (i = 0; i < tris_len; i++) {
|
|
float co[3][3];
|
|
|
|
tris[i][0] = (unsigned int)BM_elem_index_get(looptris[i][0]->v);
|
|
tris[i][1] = (unsigned int)BM_elem_index_get(looptris[i][1]->v);
|
|
tris[i][2] = (unsigned int)BM_elem_index_get(looptris[i][2]->v);
|
|
|
|
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]]);
|
|
|
|
BLI_bvhtree_insert(tree, (int)i, co[0], 3);
|
|
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 */
|
|
static DerivedMesh *bvh_get_derived_mesh(
|
|
const char *funcname, struct Scene *scene, Object *ob,
|
|
bool use_deform, bool use_render, bool use_cage)
|
|
{
|
|
/* TODO: This doesn't work currently because of missing depsgraph. */
|
|
#if 0
|
|
/* we only need minimum mesh data for topology and vertex locations */
|
|
CustomDataMask mask = CD_MASK_BAREMESH;
|
|
|
|
/* Write the display mesh into the dummy mesh */
|
|
if (use_deform) {
|
|
if (use_render) {
|
|
if (use_cage) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"%s(...): cage arg is unsupported when (render=True)", funcname);
|
|
return NULL;
|
|
}
|
|
else {
|
|
return mesh_create_derived_render(scene, ob, mask);
|
|
}
|
|
}
|
|
else {
|
|
if (use_cage) {
|
|
return mesh_get_derived_deform(scene, ob, mask); /* ob->derivedDeform */
|
|
}
|
|
else {
|
|
return mesh_get_derived_final(scene, ob, mask); /* ob->derivedFinal */
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* !use_deform */
|
|
if (use_render) {
|
|
if (use_cage) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"%s(...): cage arg is unsupported when (render=True)", funcname);
|
|
return NULL;
|
|
}
|
|
else {
|
|
return mesh_create_derived_no_deform_render(scene, ob, NULL, mask);
|
|
}
|
|
}
|
|
else {
|
|
if (use_cage) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"%s(...): cage arg is unsupported when (deform=False, render=False)", funcname);
|
|
return NULL;
|
|
}
|
|
else {
|
|
return mesh_create_derived_no_deform(scene, ob, NULL, mask);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
UNUSED_VARS(funcname, scene, ob, use_deform, use_render, use_cage);
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(C_BVHTree_FromObject_doc,
|
|
".. classmethod:: FromObject(object, scene, deform=True, render=False, cage=False, epsilon=0.0)\n"
|
|
"\n"
|
|
" BVH tree based on :class:`Object` data.\n"
|
|
"\n"
|
|
" :arg object: Object data.\n"
|
|
" :type object: :class:`Object`\n"
|
|
" :arg scene: Scene data to use for evaluating the mesh.\n"
|
|
" :type scene: :class:`Scene`\n"
|
|
" :arg deform: Use mesh with deformations.\n"
|
|
" :type deform: bool\n"
|
|
" :arg render: Use render settings.\n"
|
|
" :type render: bool\n"
|
|
" :arg cage: Use render settings.\n"
|
|
" :type cage: bool\n"
|
|
PYBVH_FROM_GENERIC_EPSILON_DOC
|
|
);
|
|
static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyObject *kwargs)
|
|
{
|
|
/* note, options here match 'bpy_bmesh_from_object' */
|
|
const char *keywords[] = {"object", "scene", "deform", "render", "cage", "epsilon", NULL};
|
|
|
|
PyObject *py_ob, *py_scene;
|
|
Object *ob;
|
|
struct Scene *scene;
|
|
DerivedMesh *dm;
|
|
bool use_deform = true;
|
|
bool use_render = false;
|
|
bool use_cage = false;
|
|
|
|
const MLoopTri *lt;
|
|
const MLoop *mloop;
|
|
|
|
float (*coords)[3] = NULL;
|
|
unsigned int (*tris)[3] = NULL;
|
|
unsigned int coords_len, tris_len;
|
|
float epsilon = 0.0f;
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(
|
|
args, kwargs, (char *)"OO|$O&O&O&f:BVHTree.FromObject", (char **)keywords,
|
|
&py_ob, &py_scene,
|
|
PyC_ParseBool, &use_deform,
|
|
PyC_ParseBool, &use_render,
|
|
PyC_ParseBool, &use_cage,
|
|
&epsilon) ||
|
|
((ob = PyC_RNA_AsPointer(py_ob, "Object")) == NULL) ||
|
|
((scene = PyC_RNA_AsPointer(py_scene, "Scene")) == NULL))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
dm = bvh_get_derived_mesh("BVHTree", scene, ob, use_deform, use_render, use_cage);
|
|
if (dm == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Get data for tessellation */
|
|
{
|
|
lt = dm->getLoopTriArray(dm);
|
|
|
|
tris_len = (unsigned int)dm->getNumLoopTri(dm);
|
|
coords_len = (unsigned int)dm->getNumVerts(dm);
|
|
|
|
coords = MEM_mallocN(sizeof(*coords) * (size_t)coords_len, __func__);
|
|
tris = MEM_mallocN(sizeof(*tris) * (size_t)tris_len, __func__);
|
|
|
|
dm->getVertCos(dm, coords);
|
|
|
|
mloop = dm->getLoopArray(dm);
|
|
}
|
|
|
|
{
|
|
BVHTree *tree;
|
|
unsigned int i;
|
|
|
|
int *orig_index = NULL;
|
|
float (*orig_normal)[3] = NULL;
|
|
|
|
tree = BLI_bvhtree_new((int)tris_len, epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT);
|
|
if (tree) {
|
|
orig_index = MEM_mallocN(sizeof(*orig_index) * (size_t)tris_len, __func__);
|
|
orig_normal = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */
|
|
if (orig_normal) {
|
|
orig_normal = MEM_dupallocN(orig_normal);
|
|
}
|
|
|
|
for (i = 0; i < tris_len; i++, lt++) {
|
|
float co[3][3];
|
|
|
|
tris[i][0] = mloop[lt->tri[0]].v;
|
|
tris[i][1] = mloop[lt->tri[1]].v;
|
|
tris[i][2] = mloop[lt->tri[2]].v;
|
|
|
|
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]]);
|
|
|
|
BLI_bvhtree_insert(tree, (int)i, co[0], 3);
|
|
orig_index[i] = (int)lt->poly;
|
|
}
|
|
|
|
BLI_bvhtree_balance(tree);
|
|
}
|
|
|
|
dm->release(dm);
|
|
|
|
return bvhtree_CreatePyObject(
|
|
tree, epsilon,
|
|
coords, coords_len,
|
|
tris, tris_len,
|
|
orig_index, orig_normal);
|
|
}
|
|
}
|
|
#endif /* MATH_STANDALONE */
|
|
|
|
/** \} */
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Module & Type definition
|
|
* \{ */
|
|
|
|
static PyMethodDef py_bvhtree_methods[] = {
|
|
{"ray_cast", (PyCFunction)py_bvhtree_ray_cast, METH_VARARGS, py_bvhtree_ray_cast_doc},
|
|
{"find_nearest", (PyCFunction)py_bvhtree_find_nearest, METH_VARARGS, py_bvhtree_find_nearest_doc},
|
|
{"find_nearest_range", (PyCFunction)py_bvhtree_find_nearest_range, METH_VARARGS, py_bvhtree_find_nearest_range_doc},
|
|
{"overlap", (PyCFunction)py_bvhtree_overlap, METH_O, py_bvhtree_overlap_doc},
|
|
|
|
/* class methods */
|
|
{"FromPolygons", (PyCFunction) C_BVHTree_FromPolygons, METH_VARARGS | METH_KEYWORDS | METH_CLASS, C_BVHTree_FromPolygons_doc},
|
|
#ifndef MATH_STANDALONE
|
|
{"FromBMesh", (PyCFunction) C_BVHTree_FromBMesh, METH_VARARGS | METH_KEYWORDS | METH_CLASS, C_BVHTree_FromBMesh_doc},
|
|
{"FromObject", (PyCFunction) C_BVHTree_FromObject, METH_VARARGS | METH_KEYWORDS | METH_CLASS, C_BVHTree_FromObject_doc},
|
|
#endif
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
|
|
PyTypeObject PyBVHTree_Type = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"BVHTree", /* tp_name */
|
|
sizeof(PyBVHTree), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)py_bvhtree__tp_dealloc, /* tp_dealloc */
|
|
NULL, /* tp_print */
|
|
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 */
|
|
NULL, /* Documentation string */
|
|
NULL, /* tp_traverse */
|
|
NULL, /* tp_clear */
|
|
NULL, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
NULL, /* tp_iter */
|
|
NULL, /* tp_iternext */
|
|
py_bvhtree_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 */
|
|
NULL, /* 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 */
|
|
};
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Module definition */
|
|
|
|
PyDoc_STRVAR(py_bvhtree_doc,
|
|
"BVH tree structures for proximity searches and ray casts on geometry."
|
|
);
|
|
static struct PyModuleDef bvhtree_moduledef = {
|
|
PyModuleDef_HEAD_INIT,
|
|
"mathutils.bvhtree", /* m_name */
|
|
py_bvhtree_doc, /* m_doc */
|
|
0, /* m_size */
|
|
NULL, /* m_methods */
|
|
NULL, /* m_reload */
|
|
NULL, /* m_traverse */
|
|
NULL, /* m_clear */
|
|
NULL /* m_free */
|
|
};
|
|
|
|
PyMODINIT_FUNC PyInit_mathutils_bvhtree(void)
|
|
{
|
|
PyObject *m = PyModule_Create(&bvhtree_moduledef);
|
|
|
|
if (m == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Register classes */
|
|
if (PyType_Ready(&PyBVHTree_Type) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
PyModule_AddObject(m, "BVHTree", (PyObject *)&PyBVHTree_Type);
|
|
|
|
return m;
|
|
}
|
|
|
|
/** \} */
|