Cleanup: Move bvhutils.c to C++

This will be useful when adding a utility to create a BVH tree from a
`CurveEval` for the attribute proximity and attribute transfer nodes.
This commit is contained in:
Hans Goudey 2021-07-01 16:46:55 -05:00
parent 7eecf77f0b
commit 0ff1c38fcc
Notes: blender-bot 2023-02-14 05:16:25 +01:00
Referenced by issue #89604, Booleans don't work if there is an empty object in the collection.
Referenced by issue #89583, Particles do not react to collision objects anymore
Referenced by issue #89431, mantaflow instability on high timesteps
2 changed files with 103 additions and 78 deletions

View File

@ -93,7 +93,7 @@ set(SRC
intern/boids.c
intern/bpath.c
intern/brush.c
intern/bvhutils.c
intern/bvhutils.cc
intern/cachefile.c
intern/callbacks.c
intern/camera.c

View File

@ -21,9 +21,9 @@
* \ingroup bke
*/
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <cmath>
#include <cstdio>
#include <cstring>
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@ -46,15 +46,15 @@
/** \name BVHCache
* \{ */
typedef struct BVHCacheItem {
struct BVHCacheItem {
bool is_filled;
BVHTree *tree;
} BVHCacheItem;
};
typedef struct BVHCache {
struct BVHCache {
BVHCacheItem items[BVHTREE_MAX_ITEM];
ThreadMutex mutex;
} BVHCache;
};
/**
* Queries a bvhcache for the cache bvhtree of the request type
@ -74,14 +74,14 @@ static bool bvhcache_find(BVHCache **bvh_cache_p,
if (r_locked) {
*r_locked = false;
}
if (*bvh_cache_p == NULL) {
if (*bvh_cache_p == nullptr) {
if (!do_lock) {
/* Cache does not exist and no lock is requested. */
return false;
}
/* Lazy initialization of the bvh_cache using the `mesh_eval_mutex`. */
BLI_mutex_lock(mesh_eval_mutex);
if (*bvh_cache_p == NULL) {
if (*bvh_cache_p == nullptr) {
*bvh_cache_p = bvhcache_init();
}
BLI_mutex_unlock(mesh_eval_mutex);
@ -94,7 +94,7 @@ static bool bvhcache_find(BVHCache **bvh_cache_p,
}
if (do_lock) {
BLI_mutex_lock(&bvh_cache->mutex);
bool in_cache = bvhcache_find(bvh_cache_p, type, r_tree, NULL, NULL);
bool in_cache = bvhcache_find(bvh_cache_p, type, r_tree, nullptr, nullptr);
if (in_cache) {
BLI_mutex_unlock(&bvh_cache->mutex);
return in_cache;
@ -113,11 +113,11 @@ static void bvhcache_unlock(BVHCache *bvh_cache, bool lock_started)
bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
{
if (bvh_cache == NULL) {
if (bvh_cache == nullptr) {
return false;
}
for (BVHCacheType i = 0; i < BVHTREE_MAX_ITEM; i++) {
for (int i = 0; i < BVHTREE_MAX_ITEM; i++) {
if (bvh_cache->items[i].tree == tree) {
return true;
}
@ -127,7 +127,7 @@ bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
BVHCache *bvhcache_init(void)
{
BVHCache *cache = MEM_callocN(sizeof(BVHCache), __func__);
BVHCache *cache = (BVHCache *)MEM_callocN(sizeof(BVHCache), __func__);
BLI_mutex_init(&cache->mutex);
return cache;
}
@ -137,7 +137,7 @@ BVHCache *bvhcache_init(void)
* as that will be done when the cache is freed.
*
* A call to this assumes that there was no previous cached tree of the given type
* \warning The #BVHTree can be NULL.
* \warning The #BVHTree can be nullptr.
*/
static void bvhcache_insert(BVHCache *bvh_cache, BVHTree *tree, BVHCacheType type)
{
@ -152,10 +152,10 @@ static void bvhcache_insert(BVHCache *bvh_cache, BVHTree *tree, BVHCacheType typ
*/
void bvhcache_free(BVHCache *bvh_cache)
{
for (BVHCacheType index = 0; index < BVHTREE_MAX_ITEM; index++) {
for (int index = 0; index < BVHTREE_MAX_ITEM; index++) {
BVHCacheItem *item = &bvh_cache->items[index];
BLI_bvhtree_free(item->tree);
item->tree = NULL;
item->tree = nullptr;
}
BLI_mutex_end(&bvh_cache->mutex);
MEM_freeN(bvh_cache);
@ -197,9 +197,10 @@ float bvhtree_ray_tri_intersection(const BVHTreeRay *ray,
float dist;
#ifdef USE_KDOPBVH_WATERTIGHT
if (isect_ray_tri_watertight_v3(ray->origin, ray->isect_precalc, v0, v1, v2, &dist, NULL))
if (isect_ray_tri_watertight_v3(ray->origin, ray->isect_precalc, v0, v1, v2, &dist, nullptr))
#else
if (isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON))
if (isect_ray_tri_epsilon_v3(
ray->origin, ray->direction, v0, v1, v2, &dist, nullptr, FLT_EPSILON))
#endif
{
return dist;
@ -247,7 +248,7 @@ static void mesh_faces_nearest_point(void *userdata,
t0 = vert[face->v1].co;
t1 = vert[face->v2].co;
t2 = vert[face->v3].co;
t3 = face->v4 ? vert[face->v4].co : NULL;
t3 = face->v4 ? vert[face->v4].co : nullptr;
do {
float nearest_tmp[3], dist_sq;
@ -264,7 +265,7 @@ static void mesh_faces_nearest_point(void *userdata,
t1 = t2;
t2 = t3;
t3 = NULL;
t3 = nullptr;
} while (t2);
}
@ -300,7 +301,7 @@ static void editmesh_looptri_nearest_point(void *userdata,
const float co[3],
BVHTreeNearest *nearest)
{
const BVHTreeFromEditMesh *data = userdata;
const BVHTreeFromEditMesh *data = (const BVHTreeFromEditMesh *)userdata;
BMEditMesh *em = data->em;
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
@ -339,7 +340,7 @@ static void mesh_faces_spherecast(void *userdata,
t0 = vert[face->v1].co;
t1 = vert[face->v2].co;
t2 = vert[face->v3].co;
t3 = face->v4 ? vert[face->v4].co : NULL;
t3 = face->v4 ? vert[face->v4].co : nullptr;
do {
float dist;
@ -360,7 +361,7 @@ static void mesh_faces_spherecast(void *userdata,
t1 = t2;
t2 = t3;
t3 = NULL;
t3 = nullptr;
} while (t2);
}
@ -484,7 +485,7 @@ static void editmesh_verts_spherecast(void *userdata,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
{
const BVHTreeFromEditMesh *data = userdata;
const BVHTreeFromEditMesh *data = (const BVHTreeFromEditMesh *)userdata;
BMVert *eve = BM_vert_at_index(data->em->bm, index);
mesh_verts_spherecast_do(index, eve->co, ray, hit);
@ -600,7 +601,7 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon,
const BLI_bitmap *verts_mask,
int verts_num_active)
{
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (verts_mask) {
BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
@ -637,9 +638,9 @@ static void bvhtree_from_mesh_verts_setup_data(BVHTreeFromMesh *data,
data->tree = tree;
data->cached = is_cached;
/* a NULL nearest callback works fine
/* a nullptr nearest callback works fine
* remember the min distance to point is the same as the min distance to BV of point */
data->nearest_callback = NULL;
data->nearest_callback = nullptr;
data->raycast_callback = mesh_verts_spherecast;
data->vert = vert;
@ -658,7 +659,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (bvh_cache_p) {
bool lock_started = false;
@ -687,9 +688,9 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
memset(data, 0, sizeof(*data));
data->tree = tree;
data->em = em;
data->nearest_callback = NULL;
data->nearest_callback = nullptr;
data->raycast_callback = editmesh_verts_spherecast;
data->cached = bvh_cache_p != NULL;
data->cached = bvh_cache_p != nullptr;
}
return tree;
@ -699,7 +700,7 @@ BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
return bvhtree_from_editmesh_verts_ex(
data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
/**
@ -724,7 +725,7 @@ BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
{
bool in_cache = false;
bool lock_started = false;
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (bvh_cache_p) {
in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
@ -732,7 +733,7 @@ BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
if (in_cache == false) {
tree = bvhtree_from_mesh_verts_create_tree(
epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
bvhtree_balance(tree, bvh_cache_p != NULL);
bvhtree_balance(tree, bvh_cache_p != nullptr);
if (bvh_cache_p) {
/* Save on cache for later use */
@ -807,7 +808,7 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(const MVert *vert,
int tree_type,
int axis)
{
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (edges_mask) {
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
@ -871,7 +872,7 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (bvh_cache_p) {
bool lock_started = false;
@ -899,9 +900,9 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
memset(data, 0, sizeof(*data));
data->tree = tree;
data->em = em;
data->nearest_callback = NULL; /* TODO */
data->raycast_callback = NULL; /* TODO */
data->cached = bvh_cache_p != NULL;
data->nearest_callback = nullptr; /* TODO */
data->raycast_callback = nullptr; /* TODO */
data->cached = bvh_cache_p != nullptr;
}
return tree;
@ -911,7 +912,7 @@ BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
return bvhtree_from_editmesh_edges_ex(
data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
/**
@ -939,7 +940,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
{
bool in_cache = false;
bool lock_started = false;
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (bvh_cache_p) {
in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
@ -988,7 +989,7 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
const BLI_bitmap *faces_mask,
int faces_num_active)
{
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (faces_num) {
if (faces_mask) {
@ -1074,7 +1075,7 @@ BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
{
bool in_cache = false;
bool lock_started = false;
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (bvh_cache_p) {
in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
@ -1082,7 +1083,7 @@ BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
if (in_cache == false) {
tree = bvhtree_from_mesh_faces_create_tree(
epsilon, tree_type, axis, vert, face, numFaces, faces_mask, faces_num_active);
bvhtree_balance(tree, bvh_cache_p != NULL);
bvhtree_balance(tree, bvh_cache_p != nullptr);
if (bvh_cache_p) {
/* Save on cache for later use */
@ -1117,7 +1118,7 @@ static BVHTree *bvhtree_from_editmesh_looptri_create_tree(float epsilon,
const BLI_bitmap *looptri_mask,
int looptri_num_active)
{
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
const int looptri_num = em->tottri;
if (looptri_num) {
@ -1132,7 +1133,7 @@ static BVHTree *bvhtree_from_editmesh_looptri_create_tree(float epsilon,
/* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
if (tree) {
const struct BMLoop *(*looptris)[3] = (void *)em->looptris;
const BMLoop *(*looptris)[3] = (const BMLoop *(*)[3])em->looptris;
/* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden
* and/or selected. Even if the faces themselves are not selected for the snapped
@ -1169,7 +1170,7 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
const BLI_bitmap *looptri_mask,
int looptri_num_active)
{
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (looptri_mask) {
BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
@ -1247,7 +1248,7 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
/* BMESH specific check that we have tessfaces,
* we _could_ tessellate here but rather not - campbell */
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (bvh_cache_p) {
bool lock_started = false;
bool in_cache = bvhcache_find(
@ -1276,7 +1277,7 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
data->nearest_callback = editmesh_looptri_nearest_point;
data->raycast_callback = editmesh_looptri_spherecast;
data->em = em;
data->cached = bvh_cache_p != NULL;
data->cached = bvh_cache_p != nullptr;
}
return tree;
}
@ -1285,7 +1286,7 @@ BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
return bvhtree_from_editmesh_looptri_ex(
data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
/**
@ -1312,7 +1313,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
{
bool in_cache = false;
bool lock_started = false;
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
if (bvh_cache_p) {
in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
@ -1329,7 +1330,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
looptri_mask,
looptri_num_active);
bvhtree_balance(tree, bvh_cache_p != NULL);
bvhtree_balance(tree, bvh_cache_p != nullptr);
if (bvh_cache_p) {
BVHCache *bvh_cache = *bvh_cache_p;
@ -1443,13 +1444,13 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const BVHCacheType bvh_cache_type,
const int tree_type)
{
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime.bvh_cache;
ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
bool is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, NULL, NULL);
bool is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, nullptr, nullptr);
if (is_cached && tree == NULL) {
if (is_cached && tree == nullptr) {
memset(data, 0, sizeof(*data));
return tree;
}
@ -1458,7 +1459,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
case BVHTREE_FROM_VERTS:
case BVHTREE_FROM_LOOSEVERTS:
if (is_cached == false) {
BLI_bitmap *loose_verts_mask = NULL;
BLI_bitmap *loose_verts_mask = nullptr;
int loose_vert_len = -1;
int verts_len = mesh->totvert;
@ -1480,7 +1481,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
bvh_cache_p,
mesh_eval_mutex);
if (loose_verts_mask != NULL) {
if (loose_verts_mask != nullptr) {
MEM_freeN(loose_verts_mask);
}
}
@ -1493,7 +1494,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
case BVHTREE_FROM_EDGES:
case BVHTREE_FROM_LOOSEEDGES:
if (is_cached == false) {
BLI_bitmap *loose_edges_mask = NULL;
BLI_bitmap *loose_edges_mask = nullptr;
int loose_edges_len = -1;
int edges_len = mesh->totedge;
@ -1516,7 +1517,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
bvh_cache_p,
mesh_eval_mutex);
if (loose_edges_mask != NULL) {
if (loose_edges_mask != nullptr) {
MEM_freeN(loose_edges_mask);
}
}
@ -1538,7 +1539,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
mesh->mface,
num_faces,
false,
NULL,
nullptr,
-1,
0.0,
tree_type,
@ -1561,7 +1562,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
int looptri_len = BKE_mesh_runtime_looptri_len(mesh);
int looptri_mask_active_len = -1;
BLI_bitmap *looptri_mask = NULL;
BLI_bitmap *looptri_mask = nullptr;
if (bvh_cache_type == BVHTREE_FROM_LOOPTRI_NO_HIDDEN) {
looptri_mask = looptri_no_hidden_map_get(
mesh->mpoly, looptri_len, &looptri_mask_active_len);
@ -1584,7 +1585,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
bvh_cache_p,
mesh_eval_mutex);
if (looptri_mask != NULL) {
if (looptri_mask != nullptr) {
MEM_freeN(looptri_mask);
}
}
@ -1603,7 +1604,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
break;
}
if (data->tree != NULL) {
if (data->tree != nullptr) {
#ifdef DEBUG
if (BLI_bvhtree_get_tree_type(data->tree) != tree_type) {
printf("tree_type %d obtained instead of %d\n",
@ -1631,15 +1632,15 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
BVHTree *tree = nullptr;
bool is_cached = false;
memset(data, 0, sizeof(*data));
if (bvh_cache_p) {
is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, NULL, NULL);
is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, nullptr, nullptr);
if (is_cached && tree == NULL) {
if (is_cached && tree == nullptr) {
return tree;
}
}
@ -1650,31 +1651,55 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
switch (bvh_cache_type) {
case BVHTREE_FROM_EM_VERTS:
if (is_cached == false) {
tree = bvhtree_from_editmesh_verts_ex(
data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
tree = bvhtree_from_editmesh_verts_ex(data,
em,
nullptr,
-1,
0.0f,
tree_type,
6,
bvh_cache_type,
bvh_cache_p,
mesh_eval_mutex);
}
else {
data->nearest_callback = NULL;
data->nearest_callback = nullptr;
data->raycast_callback = editmesh_verts_spherecast;
}
break;
case BVHTREE_FROM_EM_EDGES:
if (is_cached == false) {
tree = bvhtree_from_editmesh_edges_ex(
data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
tree = bvhtree_from_editmesh_edges_ex(data,
em,
nullptr,
-1,
0.0f,
tree_type,
6,
bvh_cache_type,
bvh_cache_p,
mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
data->nearest_callback = NULL; /* TODO */
data->raycast_callback = NULL; /* TODO */
data->nearest_callback = nullptr; /* TODO */
data->raycast_callback = nullptr; /* TODO */
}
break;
case BVHTREE_FROM_EM_LOOPTRI:
if (is_cached == false) {
tree = bvhtree_from_editmesh_looptri_ex(
data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
tree = bvhtree_from_editmesh_looptri_ex(data,
em,
nullptr,
-1,
0.0f,
tree_type,
6,
bvh_cache_type,
bvh_cache_p,
mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@ -1694,7 +1719,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
break;
}
if (data->tree != NULL) {
if (data->tree != nullptr) {
#ifdef DEBUG
if (BLI_bvhtree_get_tree_type(data->tree) != tree_type) {
printf("tree_type %d obtained instead of %d\n",
@ -1763,7 +1788,7 @@ BVHTree *BKE_bvhtree_from_pointcloud_get(BVHTreeFromPointCloud *data,
{
BVHTree *tree = BLI_bvhtree_new(pointcloud->totpoint, 0.0f, tree_type, 6);
if (!tree) {
return NULL;
return nullptr;
}
for (int i = 0; i < pointcloud->totpoint; i++) {
@ -1774,7 +1799,7 @@ BVHTree *BKE_bvhtree_from_pointcloud_get(BVHTreeFromPointCloud *data,
data->coords = pointcloud->co;
data->tree = tree;
data->nearest_callback = NULL;
data->nearest_callback = nullptr;
return tree;
}