Blender V4.3
editmesh_bvh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2010 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "BLI_kdopbvh.h"
12#include "BLI_math_geom.h"
13#include "BLI_math_vector.h"
14
15#include "BKE_editmesh.hh"
16
17#include "BKE_editmesh_bvh.hh" /* own include */
18
19using blender::Span;
20
33
35 int flag,
36 const blender::float3 *cos_cage,
37 const bool cos_cage_free)
38{
39 return BKE_bmbvh_new(em->bm, em->looptris, flag, cos_cage, cos_cage_free);
40}
41
43 const Span<std::array<BMLoop *, 3>> looptris,
44 int flag,
45 const blender::float3 *cos_cage,
46 const bool cos_cage_free,
47 bool (*test_fn)(BMFace *, void *user_data),
48 void *user_data)
49{
50 /* could become argument */
51 const float epsilon = FLT_EPSILON * 2.0f;
52
53 BMBVHTree *bmtree = static_cast<BMBVHTree *>(MEM_callocN(sizeof(*bmtree), "BMBVHTree"));
54 float cos[3][3];
55 int tottri;
56
57 /* avoid testing every tri */
58 BMFace *f_test, *f_test_prev;
59 bool test_fn_ret;
60
61 /* BKE_editmesh_looptris_calc() must be called already */
62 BLI_assert(looptris.size() != 0 || bm->totface == 0);
63
64 if (cos_cage) {
66 }
67
68 bmtree->looptris = looptris;
69 bmtree->bm = bm;
70 bmtree->cos_cage = cos_cage;
71 bmtree->cos_cage_free = cos_cage_free;
72 bmtree->flag = flag;
73
74 if (test_fn) {
75 /* callback must do... */
77
78 f_test_prev = nullptr;
79 test_fn_ret = false;
80
81 tottri = 0;
82 for (const int i : looptris.index_range()) {
83 f_test = looptris[i][0]->f;
84 if (f_test != f_test_prev) {
85 test_fn_ret = test_fn(f_test, user_data);
86 f_test_prev = f_test;
87 }
88
89 if (test_fn_ret) {
90 tottri++;
91 }
92 }
93 }
94 else {
95 tottri = looptris.size();
96 }
97
98 bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8);
99
100 f_test_prev = nullptr;
101 test_fn_ret = false;
102
103 for (const int i : looptris.index_range()) {
104 if (test_fn) {
105 /* NOTE: the arrays won't align now! Take care. */
106 f_test = looptris[i][0]->f;
107 if (f_test != f_test_prev) {
108 test_fn_ret = test_fn(f_test, user_data);
109 f_test_prev = f_test;
110 }
111
112 if (!test_fn_ret) {
113 continue;
114 }
115 }
116
117 if (cos_cage) {
118 copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]);
119 copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]);
120 copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]);
121 }
122 else {
123 copy_v3_v3(cos[0], looptris[i][0]->v->co);
124 copy_v3_v3(cos[1], looptris[i][1]->v->co);
125 copy_v3_v3(cos[2], looptris[i][2]->v->co);
126 }
127
128 BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3);
129 }
130
131 BLI_bvhtree_balance(bmtree->tree);
132
133 return bmtree;
134}
135
136static bool bm_face_is_select(BMFace *f, void * /*user_data*/)
137{
138 return (BM_elem_flag_test(f, BM_ELEM_SELECT) != 0);
139}
140
141static bool bm_face_is_not_hidden(BMFace *f, void * /*user_data*/)
142{
143 return (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == 0);
144}
145
147 const Span<std::array<BMLoop *, 3>> looptris,
148 int flag,
149 const blender::float3 *cos_cage,
150 const bool cos_cage_free)
151{
152 bool (*test_fn)(BMFace *, void *user_data);
153
155 test_fn = bm_face_is_select;
156 }
157 else if (flag & BMBVH_RESPECT_HIDDEN) {
158 test_fn = bm_face_is_not_hidden;
159 }
160 else {
161 test_fn = nullptr;
162 }
163
165
166 return BKE_bmbvh_new_ex(bm, looptris, flag, cos_cage, cos_cage_free, test_fn, nullptr);
167}
168
170{
171 BLI_bvhtree_free(bmtree->tree);
172
173 if (bmtree->cos_cage && bmtree->cos_cage_free) {
174 MEM_freeN((void *)bmtree->cos_cage);
175 }
176
177 MEM_freeN(bmtree);
178}
179
181{
182 return bmtree->tree;
183}
184
185/* -------------------------------------------------------------------- */
186/* Utility BMesh cast/intersect functions */
187
191static void bmbvh_tri_from_face(const float *cos[3],
192 const std::array<BMLoop *, 3> &ltri,
193 const blender::float3 *cos_cage)
194{
195 if (cos_cage == nullptr) {
196 cos[0] = ltri[0]->v->co;
197 cos[1] = ltri[1]->v->co;
198 cos[2] = ltri[2]->v->co;
199 }
200 else {
201 cos[0] = cos_cage[BM_elem_index_get(ltri[0]->v)];
202 cos[1] = cos_cage[BM_elem_index_get(ltri[1]->v)];
203 cos[2] = cos_cage[BM_elem_index_get(ltri[2]->v)];
204 }
205}
206
207/* Taken from `bvhutils.cc`. */
208
209/* -------------------------------------------------------------------- */
210/* BKE_bmbvh_ray_cast */
211
213 /* from the bmtree */
216
217 /* from the hit */
218 float uv[2];
219};
220
222 RayCastUserData *bmcb_data,
223 const BVHTreeRayHit *hit,
224 float *r_dist,
225 float r_hitout[3],
226 float r_cagehit[3])
227{
228 if (r_hitout) {
229 if (bmtree->flag & BMBVH_RETURN_ORIG) {
230 const std::array<BMLoop *, 3> &ltri = bmtree->looptris[hit->index];
231 interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data->uv);
232 }
233 else {
234 copy_v3_v3(r_hitout, hit->co);
235 }
236
237 if (r_cagehit) {
238 copy_v3_v3(r_cagehit, hit->co);
239 }
240 }
241
242 if (r_dist) {
243 *r_dist = hit->dist;
244 }
245
246 return bmtree->looptris[hit->index][0]->f;
247}
248
249static void bmbvh_ray_cast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
250{
251 RayCastUserData *bmcb_data = static_cast<RayCastUserData *>(userdata);
252 const std::array<BMLoop *, 3> &ltri = bmcb_data->looptris[index];
253 float dist, uv[2];
254 const float *tri_cos[3];
255 bool isect;
256
257 bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
258
259 isect =
260 (ray->radius > 0.0f ?
261 isect_ray_tri_epsilon_v3(ray->origin,
262 ray->direction,
263 tri_cos[0],
264 tri_cos[1],
265 tri_cos[2],
266 &dist,
267 uv,
268 ray->radius) :
269#ifdef USE_KDOPBVH_WATERTIGHT
271 ray->origin, ray->isect_precalc, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
272#else
274 ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
275#endif
276
277 if (isect && dist < hit->dist) {
278 hit->dist = dist;
279 hit->index = index;
280
281 copy_v3_v3(hit->no, ltri[0]->f->no);
282
283 madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
284
285 copy_v2_v2(bmcb_data->uv, uv);
286 }
287}
288
290 const float co[3],
291 const float dir[3],
292 const float radius,
293 float *r_dist,
294 float r_hitout[3],
295 float r_cagehit[3])
296{
297 BVHTreeRayHit hit;
298 RayCastUserData bmcb_data;
299 const float dist = r_dist ? *r_dist : FLT_MAX;
300
301 if (bmtree->cos_cage) {
302 BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
303 }
304
305 hit.dist = dist;
306 hit.index = -1;
307
308 /* ok to leave 'uv' uninitialized */
309 bmcb_data.looptris = bmtree->looptris;
310 bmcb_data.cos_cage = bmtree->cos_cage;
311
312 BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb, &bmcb_data);
313
314 if (hit.index != -1 && hit.dist != dist) {
315 return bmbvh_ray_cast_handle_hit(bmtree, &bmcb_data, &hit, r_dist, r_hitout, r_cagehit);
316 }
317
318 return nullptr;
319}
320
321/* -------------------------------------------------------------------- */
322/* bmbvh_ray_cast_cb_filter */
323
324/* Same as BKE_bmbvh_ray_cast but takes a callback to filter out faces.
325 */
326
333
334static void bmbvh_ray_cast_cb_filter(void *userdata,
335 int index,
336 const BVHTreeRay *ray,
337 BVHTreeRayHit *hit)
338{
339 RayCastUserData_Filter *bmcb_data_filter = static_cast<RayCastUserData_Filter *>(userdata);
340 RayCastUserData *bmcb_data = &bmcb_data_filter->bmcb_data;
341 const std::array<BMLoop *, 3> &ltri = bmcb_data->looptris[index];
342 if (bmcb_data_filter->filter_cb(ltri[0]->f, bmcb_data_filter->filter_userdata)) {
343 bmbvh_ray_cast_cb(bmcb_data, index, ray, hit);
344 }
345}
346
348 const float co[3],
349 const float dir[3],
350 const float radius,
351 float *r_dist,
352 float r_hitout[3],
353 float r_cagehit[3],
354 BMBVHTree_FaceFilter filter_cb,
355 void *filter_userdata)
356{
357 BVHTreeRayHit hit;
358 RayCastUserData_Filter bmcb_data_filter;
359 RayCastUserData *bmcb_data = &bmcb_data_filter.bmcb_data;
360
361 const float dist = r_dist ? *r_dist : FLT_MAX;
362
363 bmcb_data_filter.filter_cb = filter_cb;
364 bmcb_data_filter.filter_userdata = filter_userdata;
365
366 if (bmtree->cos_cage) {
367 BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
368 }
369
370 hit.dist = dist;
371 hit.index = -1;
372
373 /* ok to leave 'uv' uninitialized */
374 bmcb_data->looptris = bmtree->looptris;
375 bmcb_data->cos_cage = bmtree->cos_cage;
376
378 bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb_filter, &bmcb_data_filter);
379 if (hit.index != -1 && hit.dist != dist) {
380 return bmbvh_ray_cast_handle_hit(bmtree, bmcb_data, &hit, r_dist, r_hitout, r_cagehit);
381 }
382
383 return nullptr;
384}
385
386/* -------------------------------------------------------------------- */
387/* BKE_bmbvh_find_vert_closest */
388
390 /* from the bmtree */
393
394 /* from the hit */
397};
398
399static void bmbvh_find_vert_closest_cb(void *userdata,
400 int index,
401 const float co[3],
402 BVHTreeNearest *hit)
403{
404 VertSearchUserData *bmcb_data = static_cast<VertSearchUserData *>(userdata);
405 const std::array<BMLoop *, 3> &ltri = bmcb_data->looptris[index];
406 const float dist_max_sq = bmcb_data->dist_max_sq;
407
408 const float *tri_cos[3];
409 bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
410
411 for (int i = 0; i < 3; i++) {
412 const float dist_sq = len_squared_v3v3(co, tri_cos[i]);
413 if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
414 copy_v3_v3(hit->co, tri_cos[i]);
415 /* XXX, normal ignores cage */
416 copy_v3_v3(hit->no, ltri[i]->v->no);
417 hit->dist_sq = dist_sq;
418 hit->index = index;
419 bmcb_data->index_tri = i;
420 }
421 }
422}
423
425 const float co[3],
426 const float dist_max)
427{
428 BVHTreeNearest hit;
429 VertSearchUserData bmcb_data;
430 const float dist_max_sq = dist_max * dist_max;
431
432 if (bmtree->cos_cage) {
433 BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
434 }
435
436 hit.dist_sq = dist_max_sq;
437 hit.index = -1;
438
439 bmcb_data.looptris = bmtree->looptris;
440 bmcb_data.cos_cage = bmtree->cos_cage;
441 bmcb_data.dist_max_sq = dist_max_sq;
442
443 BLI_bvhtree_find_nearest(bmtree->tree, co, &hit, bmbvh_find_vert_closest_cb, &bmcb_data);
444 if (hit.index != -1) {
445 const std::array<BMLoop *, 3> &ltri = bmtree->looptris[hit.index];
446 return ltri[bmcb_data.index_tri]->v;
447 }
448
449 return nullptr;
450}
451
453 /* from the bmtree */
456
457 /* from the hit */
459};
460
461static void bmbvh_find_face_closest_cb(void *userdata,
462 int index,
463 const float co[3],
464 BVHTreeNearest *hit)
465{
466 FaceSearchUserData *bmcb_data = static_cast<FaceSearchUserData *>(userdata);
467 const std::array<BMLoop *, 3> &ltri = bmcb_data->looptris[index];
468 const float dist_max_sq = bmcb_data->dist_max_sq;
469
470 const float *tri_cos[3];
471
472 bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
473
474 float co_close[3];
475 closest_on_tri_to_point_v3(co_close, co, UNPACK3(tri_cos));
476 const float dist_sq = len_squared_v3v3(co, co_close);
477 if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
478 /* XXX, normal ignores cage */
479 copy_v3_v3(hit->no, ltri[0]->f->no);
480 hit->dist_sq = dist_sq;
481 hit->index = index;
482 }
483}
484
486 const float co[3],
487 const float dist_max)
488{
489 BVHTreeNearest hit;
490 FaceSearchUserData bmcb_data;
491 const float dist_max_sq = dist_max * dist_max;
492
493 if (bmtree->cos_cage) {
494 BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
495 }
496
497 hit.dist_sq = dist_max_sq;
498 hit.index = -1;
499
500 bmcb_data.looptris = bmtree->looptris;
501 bmcb_data.cos_cage = bmtree->cos_cage;
502 bmcb_data.dist_max_sq = dist_max_sq;
503
504 BLI_bvhtree_find_nearest(bmtree->tree, co, &hit, bmbvh_find_face_closest_cb, &bmcb_data);
505 if (hit.index != -1) {
506 const std::array<BMLoop *, 3> &ltri = bmtree->looptris[hit.index];
507 return ltri[0]->f;
508 }
509
510 return nullptr;
511}
512
513/* -------------------------------------------------------------------- */
514/* BKE_bmbvh_overlap */
515
520
521static bool bmbvh_overlap_cb(void *userdata, int index_a, int index_b, int /*thread*/)
522{
523 BMBVHTree_OverlapData *data = static_cast<BMBVHTree_OverlapData *>(userdata);
524 const BMBVHTree *bmtree_a = data->tree_pair[0];
525 const BMBVHTree *bmtree_b = data->tree_pair[1];
526
527 const std::array<BMLoop *, 3> &ltri_a = bmtree_a->looptris[index_a];
528 const std::array<BMLoop *, 3> &ltri_b = bmtree_b->looptris[index_b];
529 const float *tri_a_co[3] = {ltri_a[0]->v->co, ltri_a[1]->v->co, ltri_a[2]->v->co};
530 const float *tri_b_co[3] = {ltri_b[0]->v->co, ltri_b[1]->v->co, ltri_b[2]->v->co};
531 float ix_pair[2][3];
532 int verts_shared = 0;
533
534 if (bmtree_a->looptris == bmtree_b->looptris) {
535 if (UNLIKELY(ltri_a[0]->f == ltri_b[0]->f)) {
536 return false;
537 }
538
539 verts_shared = (ELEM(tri_a_co[0], UNPACK3(tri_b_co)) + ELEM(tri_a_co[1], UNPACK3(tri_b_co)) +
540 ELEM(tri_a_co[2], UNPACK3(tri_b_co)));
541
542 /* if 2 points are shared, bail out */
543 if (verts_shared >= 2) {
544 return false;
545 }
546 }
547
548 return (isect_tri_tri_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1]) &&
549 /* if we share a vertex, check the intersection isn't a 'point' */
550 ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
551}
552
554 const BMBVHTree *bmtree_b,
555 uint *r_overlap_tot)
556{
558
559 data.tree_pair[0] = bmtree_a;
560 data.tree_pair[1] = bmtree_b;
561 data.epsilon = max_ff(BLI_bvhtree_get_epsilon(bmtree_a->tree),
562 BLI_bvhtree_get_epsilon(bmtree_b->tree));
563
564 return BLI_bvhtree_overlap(
565 bmtree_a->tree, bmtree_b->tree, r_overlap_tot, bmbvh_overlap_cb, &data);
566}
567
568static bool bmbvh_overlap_self_cb(void *userdata, int index_a, int index_b, int thread)
569{
570 if (index_a < index_b) {
571 return bmbvh_overlap_cb(userdata, index_a, index_b, thread);
572 }
573 return false;
574}
575
577{
579
580 data.tree_pair[0] = bmtree;
581 data.tree_pair[1] = bmtree;
582 data.epsilon = BLI_bvhtree_get_epsilon(bmtree->tree);
583
584 return BLI_bvhtree_overlap(
585 bmtree->tree, bmtree->tree, r_overlap_tot, bmbvh_overlap_self_cb, &data);
586}
bool(* BMBVHTree_FaceFilter)(struct BMFace *f, void *userdata)
@ BMBVH_RETURN_ORIG
@ BMBVH_RESPECT_HIDDEN
@ BMBVH_RESPECT_SELECT
#define BLI_assert(a)
Definition BLI_assert.h:50
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
void BLI_bvhtree_balance(BVHTree *tree)
void BLI_bvhtree_free(BVHTree *tree)
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
int BLI_bvhtree_find_nearest(const BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
float BLI_bvhtree_get_epsilon(const BVHTree *tree)
int BLI_bvhtree_ray_cast(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
BVHTreeOverlap * BLI_bvhtree_overlap(const BVHTree *tree1, const BVHTree *tree2, unsigned int *r_overlap_num, BVHTree_OverlapCallback callback, void *userdata)
MINLINE float max_ff(float a, float b)
bool isect_ray_tri_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
void closest_on_tri_to_point_v3(float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
bool isect_tri_tri_v3(const float t_a0[3], const float t_a1[3], const float t_a2[3], const float t_b0[3], const float t_b1[3], const float t_b2[3], float r_i1[3], float r_i2[3])
bool isect_ray_tri_watertight_v3(const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc, const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
bool isect_ray_tri_epsilon_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2], float epsilon)
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
void interp_v3_v3v3v3_uv(float p[3], const float v1[3], const float v2[3], const float v3[3], const float uv[2])
unsigned int uint
#define UNPACK3(a)
#define UNLIKELY(x)
#define ELEM(...)
Read Guarded memory(de)allocation.
@ BM_ELEM_HIDDEN
@ BM_ELEM_SELECT
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
#define BM_VERT
ATTR_WARN_UNUSED_RESULT const BMVert * v
void BKE_bmbvh_free(BMBVHTree *bmtree)
BMBVHTree * BKE_bmbvh_new(BMesh *bm, const Span< std::array< BMLoop *, 3 > > looptris, int flag, const blender::float3 *cos_cage, const bool cos_cage_free)
BMFace * BKE_bmbvh_ray_cast(const BMBVHTree *bmtree, const float co[3], const float dir[3], const float radius, float *r_dist, float r_hitout[3], float r_cagehit[3])
static bool bm_face_is_select(BMFace *f, void *)
BMBVHTree * BKE_bmbvh_new_from_editmesh(BMEditMesh *em, int flag, const blender::float3 *cos_cage, const bool cos_cage_free)
static void bmbvh_ray_cast_cb_filter(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
static bool bm_face_is_not_hidden(BMFace *f, void *)
static bool bmbvh_overlap_cb(void *userdata, int index_a, int index_b, int)
BMVert * BKE_bmbvh_find_vert_closest(const BMBVHTree *bmtree, const float co[3], const float dist_max)
static BMFace * bmbvh_ray_cast_handle_hit(const BMBVHTree *bmtree, RayCastUserData *bmcb_data, const BVHTreeRayHit *hit, float *r_dist, float r_hitout[3], float r_cagehit[3])
BVHTree * BKE_bmbvh_tree_get(BMBVHTree *bmtree)
BVHTreeOverlap * BKE_bmbvh_overlap_self(const BMBVHTree *bmtree, uint *r_overlap_tot)
static bool bmbvh_overlap_self_cb(void *userdata, int index_a, int index_b, int thread)
static void bmbvh_tri_from_face(const float *cos[3], const std::array< BMLoop *, 3 > &ltri, const blender::float3 *cos_cage)
BMFace * BKE_bmbvh_find_face_closest(const BMBVHTree *bmtree, const float co[3], const float dist_max)
BMFace * BKE_bmbvh_ray_cast_filter(const BMBVHTree *bmtree, const float co[3], const float dir[3], const float radius, float *r_dist, float r_hitout[3], float r_cagehit[3], BMBVHTree_FaceFilter filter_cb, void *filter_userdata)
static void bmbvh_ray_cast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
static void bmbvh_find_face_closest_cb(void *userdata, int index, const float co[3], BVHTreeNearest *hit)
BVHTreeOverlap * BKE_bmbvh_overlap(const BMBVHTree *bmtree_a, const BMBVHTree *bmtree_b, uint *r_overlap_tot)
BMBVHTree * BKE_bmbvh_new_ex(BMesh *bm, const Span< std::array< BMLoop *, 3 > > looptris, int flag, const blender::float3 *cos_cage, const bool cos_cage_free, bool(*test_fn)(BMFace *, void *user_data), void *user_data)
static void bmbvh_find_vert_closest_cb(void *userdata, int index, const float co[3], BVHTreeNearest *hit)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float3 cos(float3 v)
#define FLT_MAX
Definition stdcycles.h:14
const BMBVHTree * tree_pair[2]
bool cos_cage_free
BMesh * bm
Span< std::array< BMLoop *, 3 > > looptris
const blender::float3 * cos_cage
BVHTree * tree
blender::Array< std::array< BMLoop *, 3 > > looptris
float co[3]
char elem_index_dirty
int totface
Span< std::array< BMLoop *, 3 > > looptris
const blender::float3 * cos_cage
RayCastUserData bmcb_data
BMBVHTree_FaceFilter filter_cb
const blender::float3 * cos_cage
Span< std::array< BMLoop *, 3 > > looptris
const blender::float3 * cos_cage
Span< std::array< BMLoop *, 3 > > looptris
uint8_t flag
Definition wm_window.cc:138