Blender V5.0
bmesh_intersect_edges.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_math_geom.h"
14#include "BLI_math_vector.h"
15#include "BLI_sort.h"
16#include "BLI_stack.h"
17#include "BLI_vector.hh"
18
19#include "BKE_bvhutils.hh"
20
21#include "atomic_ops.h"
22
23#include "bmesh.hh"
24
25#include "bmesh_intersect_edges.hh" /* own include */
26
27// #define INTERSECT_EDGES_DEBUG
28
29#define KDOP_TREE_TYPE 4
30#define KDOP_AXIS_LEN 14
31#define BLI_STACK_PAIR_LEN (2 * KDOP_TREE_TYPE)
32
33/* -------------------------------------------------------------------- */
38
39/* Callbacks for `BM_vert_pair_shared_face_cb` */
40
52
54 BMLoop *l_a,
55 BMLoop *l_b,
56 void *userdata)
57{
58 EDBMSplitBestFaceData *data = static_cast<EDBMSplitBestFaceData *>(userdata);
59 float no[3];
60 copy_v3_v3(no, f->no);
61
62 float min = dot_v3v3(l_a->v->co, no);
63 float max = dot_v3v3(l_b->v->co, no);
64 if (min > max) {
65 std::swap(min, max);
66 }
67
68 BMEdge **e_iter = &data->edgenet[0];
69 BMEdge *e_next = data->edgenet[1];
70 BMVert *v_test = ELEM((*e_iter)->v1, e_next->v1, e_next->v2) ? (*e_iter)->v2 : (*e_iter)->v1;
71
72 int verts_len = data->edgenet_len - 1;
73 for (int i = verts_len; i--; e_iter++) {
74 v_test = BM_edge_other_vert(*e_iter, v_test);
75 BLI_assert(v_test != nullptr);
76 if (!BM_face_point_inside_test(f, v_test->co)) {
77 return false;
78 }
79 float dot = dot_v3v3(v_test->co, no);
80 min = std::min(dot, min);
81 max = std::max(dot, max);
82 }
83
84 const float test_edgenet_range_on_face_normal = max - min;
85 if (test_edgenet_range_on_face_normal < data->best_edgenet_range_on_face_normal) {
86 data->best_edgenet_range_on_face_normal = test_edgenet_range_on_face_normal;
87 data->r_best_face = f;
88 }
89
90 return false;
91}
92
93/* find the best splittable face between the two vertices. */
95 BMLoop *l_a,
96 BMLoop *l_b,
97 void *userdata)
98{
99 float (*data)[3] = static_cast<float (*)[3]>(userdata);
100 float *v_a_co = data[0];
101 float *v_a_b_dir = data[1];
102 const float range_min = -FLT_EPSILON;
103 const float range_max = 1.0f + FLT_EPSILON;
104
105 float co[3];
106 float dir[3];
107 float lambda_b;
108
109 copy_v3_v3(co, l_a->prev->v->co);
110 sub_v3_v3v3(dir, l_a->next->v->co, co);
111 if (isect_ray_ray_v3(v_a_co, v_a_b_dir, co, dir, nullptr, &lambda_b)) {
112 if (IN_RANGE(lambda_b, range_min, range_max)) {
113 return true;
114 }
115 copy_v3_v3(co, l_b->prev->v->co);
116 sub_v3_v3v3(dir, l_b->next->v->co, co);
117 if (isect_ray_ray_v3(v_a_co, v_a_b_dir, co, dir, nullptr, &lambda_b)) {
118 return IN_RANGE(lambda_b, range_min, range_max);
119 }
120 }
121 return false;
122}
123
125 BMVert *v_a, BMVert *v_b, BMEdge **edgenet, const int edgenet_len, const float epsilon)
126{
127 BMFace *best_face = nullptr;
128
129 BLI_assert(v_a != v_b);
130
131 BMLoop *dummy;
132 if (edgenet_len == 1) {
133 float data[2][3];
134 copy_v3_v3(data[0], v_b->co);
135 sub_v3_v3v3(data[1], v_a->co, data[0]);
136 best_face = BM_vert_pair_shared_face_cb(
137 v_a, v_b, false, bm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy);
138 BLI_assert(!best_face || BM_edge_in_face(edgenet[0], best_face) == false);
139 }
140 else {
142 data.edgenet = edgenet;
143 data.edgenet_len = edgenet_len;
144 data.best_edgenet_range_on_face_normal = FLT_MAX;
145 data.r_best_face = nullptr;
146
148 v_a, v_b, true, bm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy);
149
150 if (data.r_best_face) {
151 /* Check if the edgenet's range is smaller than the face's range. */
152 float no[3], min = FLT_MAX, max = -FLT_MAX;
153 copy_v3_v3(no, data.r_best_face->no);
154 BMVert *v_test;
155 BMIter f_iter;
156 BM_ITER_ELEM (v_test, &f_iter, data.r_best_face, BM_VERTS_OF_FACE) {
157 float dot = dot_v3v3(v_test->co, no);
158 min = std::min(dot, min);
159 max = std::max(dot, max);
160 }
161 float face_range_on_normal = max - min + 2 * epsilon;
162 if (face_range_on_normal < data.best_edgenet_range_on_face_normal) {
163 data.r_best_face = nullptr;
164 }
165 }
166 best_face = data.r_best_face;
167 }
168
169 return best_face;
170}
171
173
174/* -------------------------------------------------------------------- */
179
181 union {
184 struct {
186 float lambda;
187 };
188 };
189};
190
191/* -------------------------------------------------------------------- */
192/* Overlap Callbacks */
193
201
202/* Utils */
203
205{
206 r_pair_elem->vert = v;
207}
208
210 float lambda,
211 int *r_data_cut_edges_len,
212 EDBMSplitElem *r_pair_elem)
213{
214 r_pair_elem->edge = e;
215 r_pair_elem->lambda = lambda;
216
217 /* Even though we have multiple atomic operations, this is fine here, since
218 * there is no dependency on order.
219 * The `e->head.index` check + atomic increment will ever be true once, as
220 * expected. We don't care which instance of the code actually ends up
221 * incrementing `r_data_cut_edge_len`, so there is no race condition here. */
222 if (atomic_fetch_and_add_int32(&e->head.index, 1) == 0) {
223 atomic_fetch_and_add_int32(r_data_cut_edges_len, 1);
224 }
225}
226
227/* Util for Vert x Edge and Edge x Edge callbacks */
229 BMEdge *e,
230 const float co[3],
231 const float dir[3],
232 float lambda,
233 float data_dist_sq,
234 int *data_cut_edges_len,
235 EDBMSplitElem r_pair[2])
236{
237 BMVert *e_v;
238 float dist_sq_vert_factor;
239
240 if (!IN_RANGE_INCL(lambda, 0.0f, 1.0f)) {
241 /* Vert x Vert is already handled elsewhere. */
242 return false;
243 }
244
245 if (lambda < 0.5f) {
246 e_v = e->v1;
247 dist_sq_vert_factor = lambda;
248 }
249 else {
250 e_v = e->v2;
251 dist_sq_vert_factor = 1.0f - lambda;
252 }
253
254 if (v != e_v) {
255 float dist_sq_vert = square_f(dist_sq_vert_factor) * len_squared_v3(dir);
256 if (dist_sq_vert < data_dist_sq) {
257 /* Vert x Vert is already handled elsewhere. */
258 return false;
259 }
260
261 float closest[3];
262 madd_v3_v3v3fl(closest, co, dir, lambda);
263
264 float dist_sq = len_squared_v3v3(v->co, closest);
265 if (dist_sq < data_dist_sq) {
266 bm_edge_pair_elem_setup(e, lambda, data_cut_edges_len, &r_pair[0]);
267 bm_vert_pair_elem_setup_ex(v, &r_pair[1]);
268 return true;
269 }
270 }
271
272 return false;
273}
274
275/* Vertex x Vertex Callback */
276
277static bool bm_vertxvert_isect_cb(void *userdata, int index_a, int index_b, int thread)
278{
279 EDBMSplitData *data = static_cast<EDBMSplitData *>(userdata);
280 BMVert *v_a = BM_vert_at_index(data->bm, index_a);
281 BMVert *v_b = BM_vert_at_index(data->bm, index_b);
282
283 EDBMSplitElem *pair = static_cast<EDBMSplitElem *>(BLI_stack_push_r(data->pair_stack[thread]));
284
285 bm_vert_pair_elem_setup_ex(v_a, &pair[0]);
286 bm_vert_pair_elem_setup_ex(v_b, &pair[1]);
287
288 return true;
289}
290
291static bool bm_vertxvert_self_isect_cb(void *userdata, int index_a, int index_b, int thread)
292{
293 if (index_a < index_b) {
294 return bm_vertxvert_isect_cb(userdata, index_a, index_b, thread);
295 }
296 return false;
297}
298
299/* Vertex x Edge and Edge x Vertex Callbacks */
300
301static bool bm_edgexvert_isect_cb(void *userdata, int index_a, int index_b, int thread)
302{
303 EDBMSplitData *data = static_cast<EDBMSplitData *>(userdata);
304 BMEdge *e = BM_edge_at_index(data->bm, index_a);
305 BMVert *v = BM_vert_at_index(data->bm, index_b);
306
307 float co[3], dir[3], lambda;
308 copy_v3_v3(co, e->v1->co);
309 sub_v3_v3v3(dir, e->v2->co, co);
310 lambda = ray_point_factor_v3_ex(v->co, co, dir, 0.0f, -1.0f);
311
312 EDBMSplitElem pair_tmp[2];
314 v, e, co, dir, lambda, data->dist_sq, &data->cut_edges_len, pair_tmp))
315 {
316 EDBMSplitElem *pair = static_cast<EDBMSplitElem *>(BLI_stack_push_r(data->pair_stack[thread]));
317 pair[0] = pair_tmp[0];
318 pair[1] = pair_tmp[1];
319 }
320
321 /* Always return false with edges. */
322 return false;
323}
324
325/* Edge x Edge Callbacks */
326
328 BMEdge *e_a,
329 BMEdge *e_b,
330 const float co_a[3],
331 const float dir_a[3],
332 const float co_b[3],
333 const float dir_b[3],
334 float lambda_a,
335 float lambda_b,
336 EDBMSplitElem r_pair[2])
337{
338 float dist_sq_va_factor, dist_sq_vb_factor;
339 BMVert *e_a_v, *e_b_v;
340 if (lambda_a < 0.5f) {
341 e_a_v = e_a->v1;
342 dist_sq_va_factor = lambda_a;
343 }
344 else {
345 e_a_v = e_a->v2;
346 dist_sq_va_factor = 1.0f - lambda_a;
347 }
348
349 if (lambda_b < 0.5f) {
350 e_b_v = e_b->v1;
351 dist_sq_vb_factor = lambda_b;
352 }
353 else {
354 e_b_v = e_b->v2;
355 dist_sq_vb_factor = 1.0f - lambda_b;
356 }
357
358 if (e_a_v != e_b_v) {
359 if (!IN_RANGE_INCL(lambda_a, 0.0f, 1.0f) || !IN_RANGE_INCL(lambda_b, 0.0f, 1.0f)) {
360 /* Vert x Edge is already handled elsewhere. */
361 return false;
362 }
363
364 float dist_sq_va = square_f(dist_sq_va_factor) * len_squared_v3(dir_a);
365 float dist_sq_vb = square_f(dist_sq_vb_factor) * len_squared_v3(dir_b);
366
367 if (dist_sq_va < data->dist_sq || dist_sq_vb < data->dist_sq) {
368 /* Vert x Edge is already handled elsewhere. */
369 return false;
370 }
371
372 float near_a[3], near_b[3];
373 madd_v3_v3v3fl(near_a, co_a, dir_a, lambda_a);
374 madd_v3_v3v3fl(near_b, co_b, dir_b, lambda_b);
375
376 float dist_sq = len_squared_v3v3(near_a, near_b);
377 if (dist_sq < data->dist_sq) {
378 bm_edge_pair_elem_setup(e_a, lambda_a, &data->cut_edges_len, &r_pair[0]);
379 bm_edge_pair_elem_setup(e_b, lambda_b, &data->cut_edges_len, &r_pair[1]);
380 return true;
381 }
382 }
383 return false;
384}
385
386static bool bm_edgexedge_isect_cb(void *userdata, int index_a, int index_b, int thread)
387{
388 EDBMSplitData *data = static_cast<EDBMSplitData *>(userdata);
389 BMEdge *e_a = BM_edge_at_index(data->bm, index_a);
390 BMEdge *e_b = BM_edge_at_index(data->bm, index_b);
391
392 if (BM_edge_share_vert_check(e_a, e_b)) {
393 /* The other vertices may intersect but Vert x Edge is already handled elsewhere. */
394 return false;
395 }
396
397 float co_a[3], dir_a[3], co_b[3], dir_b[3];
398 copy_v3_v3(co_a, e_a->v1->co);
399 sub_v3_v3v3(dir_a, e_a->v2->co, co_a);
400
401 copy_v3_v3(co_b, e_b->v1->co);
402 sub_v3_v3v3(dir_b, e_b->v2->co, co_b);
403
404 float lambda_a, lambda_b;
405 /* Using with dist^4 as `epsilon` is not the best solution, but it fits in most cases. */
406 if (isect_ray_ray_epsilon_v3(co_a, dir_a, co_b, dir_b, data->dist_sq_sq, &lambda_a, &lambda_b)) {
407 EDBMSplitElem pair_tmp[2];
409 data, e_a, e_b, co_a, dir_a, co_b, dir_b, lambda_a, lambda_b, pair_tmp))
410 {
411 EDBMSplitElem *pair = static_cast<EDBMSplitElem *>(
412 BLI_stack_push_r(data->pair_stack[thread]));
413 pair[0] = pair_tmp[0];
414 pair[1] = pair_tmp[1];
415 }
416 }
417
418 /* Edge x Edge returns always false. */
419 return false;
420}
421
422static bool bm_edgexedge_self_isect_cb(void *userdata, int index_a, int index_b, int thread)
423{
424 if (index_a < index_b) {
425 return bm_edgexedge_isect_cb(userdata, index_a, index_b, thread);
426 }
427 return false;
428}
429
430/* -------------------------------------------------------------------- */
431/* BVHTree Overlap Function */
432
433static void bm_elemxelem_bvhtree_overlap(const BVHTree *tree1,
434 const BVHTree *tree2,
437 BLI_Stack **pair_stack)
438{
439 int parallel_tasks_num = BLI_bvhtree_overlap_thread_num(tree1);
440 for (int i = 0; i < parallel_tasks_num; i++) {
441 if (pair_stack[i] == nullptr) {
442 pair_stack[i] = BLI_stack_new(sizeof(const EDBMSplitElem[2]), __func__);
443 }
444 }
445 data->pair_stack = pair_stack;
446 BLI_bvhtree_overlap_ex(tree1, tree2, nullptr, callback, data, 1, BVH_OVERLAP_USE_THREADING);
447}
448
449/* -------------------------------------------------------------------- */
450/* Callbacks for `BLI_qsort_r` */
451
452static int sort_cmp_by_lambda_cb(const void *index1_v, const void *index2_v, void *keys_v)
453{
454 const EDBMSplitElem *pair_flat = static_cast<const EDBMSplitElem *>(keys_v);
455 const int index1 = *(int *)index1_v;
456 const int index2 = *(int *)index2_v;
457
458 if (pair_flat[index1].lambda > pair_flat[index2].lambda) {
459 return 1;
460 }
461 return -1;
462}
463
464/* -------------------------------------------------------------------- */
465/* Main API */
466
467#define INTERSECT_EDGES
468
470 BMesh *bm, const char hflag, const float dist, const bool split_faces, GHash *r_targetmap)
471{
472 bool ok = false;
473
474 BMIter iter;
475 BMVert *v;
476 BMEdge *e;
477 int i;
478
479 /* Store all intersections in this array. */
480 EDBMSplitElem(*pair_iter)[2], (*pair_array)[2] = nullptr;
481 int pair_len = 0;
482
483 BLI_Stack *pair_stack[BLI_STACK_PAIR_LEN] = {nullptr};
484 BLI_Stack **pair_stack_vertxvert = pair_stack;
485 BLI_Stack **pair_stack_edgexelem = &pair_stack[KDOP_TREE_TYPE];
486
487 const float dist_sq = square_f(dist);
488 const float dist_half = dist / 2;
489
491 data.bm = bm;
492 data.pair_stack = pair_stack;
493 data.cut_edges_len = 0;
494 data.dist_sq = dist_sq;
495 data.dist_sq_sq = square_f(dist_sq);
496
498
499 /* tag and count the verts to be tested. */
500 int verts_act_len = 0, verts_remain_len = 0;
501 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
502 if (BM_elem_flag_test(v, hflag)) {
504 verts_act_len++;
505 }
506 else {
509 verts_remain_len++;
510 }
511 }
512
513 /* The index will indicate which cut in pair_array this vertex belongs to. */
514 BM_elem_index_set(v, -1);
515 }
516 bm->elem_index_dirty |= BM_VERT;
517
518 /* Start the creation of BVHTrees. */
519 BVHTree *tree_verts_act = nullptr, *tree_verts_remain = nullptr;
520 if (verts_act_len) {
521 tree_verts_act = BLI_bvhtree_new(verts_act_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
522 }
523 if (verts_remain_len) {
524 tree_verts_remain = BLI_bvhtree_new(
525 verts_remain_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
526 }
527
528 if (tree_verts_act || tree_verts_remain) {
531 if (tree_verts_act) {
532 BLI_bvhtree_insert(tree_verts_act, i, v->co, 1);
533 }
534 }
535 else if (tree_verts_remain && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
536 BLI_bvhtree_insert(tree_verts_remain, i, v->co, 1);
537 }
538 }
539
540 if (tree_verts_act) {
541 BLI_bvhtree_balance(tree_verts_act);
542 /* First pair search. */
544 tree_verts_act, tree_verts_act, bm_vertxvert_self_isect_cb, &data, pair_stack_vertxvert);
545 }
546
547 if (tree_verts_remain) {
548 BLI_bvhtree_balance(tree_verts_remain);
549 }
550
551 if (tree_verts_act && tree_verts_remain) {
553 tree_verts_remain, tree_verts_act, bm_vertxvert_isect_cb, &data, pair_stack_vertxvert);
554 }
555 }
556
557 for (i = KDOP_TREE_TYPE; i--;) {
558 if (pair_stack_vertxvert[i]) {
559 pair_len += BLI_stack_count(pair_stack_vertxvert[i]);
560 }
561 }
562
563#ifdef INTERSECT_EDGES
564 uint vertxvert_pair_len = pair_len;
565
566# define EDGE_ACT_TO_TEST 1
567# define EDGE_REMAIN_TO_TEST 2
568 /* Tag and count the edges. */
569 int edges_act_len = 0, edges_remain_len = 0;
570 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
571 if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) || (len_squared_v3v3(e->v1->co, e->v2->co) < dist_sq))
572 {
573 /* Don't test hidden edges or smaller than the minimum distance.
574 * These have already been handled in the vertices overlap. */
576 if (split_faces) {
577 /* Tag to be ignored. */
579 }
580 continue;
581 }
582
585 edges_act_len++;
586 }
587 else {
589 edges_remain_len++;
590 if (split_faces) {
591 /* Tag to be ignored. */
593 }
594 }
595 }
596
597 BVHTree *tree_edges_act = nullptr, *tree_edges_remain = nullptr;
598 if (edges_act_len) {
599 tree_edges_act = BLI_bvhtree_new(edges_act_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
600 }
601
602 if (edges_remain_len && (tree_edges_act || tree_verts_act)) {
603 tree_edges_remain = BLI_bvhtree_new(
604 edges_remain_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
605 }
606
607 if (tree_edges_act || tree_edges_remain) {
609 int edge_test = BM_elem_index_get(e);
610 float co[2][3];
611 if (edge_test == EDGE_ACT_TO_TEST) {
612 BLI_assert(tree_edges_act);
613 e->head.index = 0;
614 copy_v3_v3(co[0], e->v1->co);
615 copy_v3_v3(co[1], e->v2->co);
616 BLI_bvhtree_insert(tree_edges_act, i, co[0], 2);
617 }
618 else if (edge_test == EDGE_REMAIN_TO_TEST) {
619 BLI_assert(tree_edges_remain);
620 e->head.index = 0;
621 copy_v3_v3(co[0], e->v1->co);
622 copy_v3_v3(co[1], e->v2->co);
623 BLI_bvhtree_insert(tree_edges_remain, i, co[0], 2);
624 }
625# ifdef INTERSECT_EDGES_DEBUG
626 else {
627 e->head.index = 0;
628 }
629# endif
630 /* Tag used when converting pairs to vert x vert. */
632 }
633# undef EDGE_ACT_TO_TEST
634# undef EDGE_REMAIN_TO_TEST
635
636 /* Use `e->head.index` to count intersections. */
637 bm->elem_index_dirty |= BM_EDGE;
638
639 if (tree_edges_act) {
640 BLI_bvhtree_balance(tree_edges_act);
641 }
642
643 if (tree_edges_remain) {
644 BLI_bvhtree_balance(tree_edges_remain);
645 }
646
647 int edgexedge_pair_len = 0;
648 if (tree_edges_act) {
649 /* Edge x Edge */
651 tree_edges_act, tree_edges_act, bm_edgexedge_self_isect_cb, &data, pair_stack_edgexelem);
652
653 if (tree_edges_remain) {
655 tree_edges_remain, tree_edges_act, bm_edgexedge_isect_cb, &data, pair_stack_edgexelem);
656 }
657
658 for (i = KDOP_TREE_TYPE; i--;) {
659 if (pair_stack_edgexelem[i]) {
660 edgexedge_pair_len += BLI_stack_count(pair_stack_edgexelem[i]);
661 }
662 }
663
664 if (tree_verts_act) {
665 /* Edge v Vert */
667 tree_edges_act, tree_verts_act, bm_edgexvert_isect_cb, &data, pair_stack_edgexelem);
668 }
669
670 if (tree_verts_remain) {
671 /* Edge v Vert */
673 tree_edges_act, tree_verts_remain, bm_edgexvert_isect_cb, &data, pair_stack_edgexelem);
674 }
675
676 BLI_bvhtree_free(tree_edges_act);
677 }
678
679 if (tree_verts_act && tree_edges_remain) {
680 /* Edge v Vert */
682 tree_edges_remain, tree_verts_act, bm_edgexvert_isect_cb, &data, pair_stack_edgexelem);
683 }
684
685 BLI_bvhtree_free(tree_edges_remain);
686
687 int edgexelem_pair_len = 0;
688 for (i = KDOP_TREE_TYPE; i--;) {
689 if (pair_stack_edgexelem[i]) {
690 edgexelem_pair_len += BLI_stack_count(pair_stack_edgexelem[i]);
691 }
692 }
693
694 pair_len += edgexelem_pair_len;
695 int edgexvert_pair_len = edgexelem_pair_len - edgexedge_pair_len;
696
697 if (edgexelem_pair_len) {
698 pair_array = static_cast<EDBMSplitElem(*)[2]>(
699 MEM_mallocN(sizeof(*pair_array) * pair_len, __func__));
700
701 pair_iter = pair_array;
702 for (i = 0; i < BLI_STACK_PAIR_LEN; i++) {
703 if (pair_stack[i]) {
704 uint count = uint(BLI_stack_count(pair_stack[i]));
705 BLI_stack_pop_n_reverse(pair_stack[i], pair_iter, count);
706 pair_iter += count;
707 }
708 }
709
710 /* Map intersections per edge. */
711 union EdgeIntersectionsMap {
712 struct {
713 int cuts_len;
714 int cuts_index[];
715 };
716 int as_int[0];
717 } *e_map_iter, *e_map;
718
719# ifdef INTERSECT_EDGES_DEBUG
720 int cut_edges_len = 0;
721 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
722 if (e->head.index != 0) {
723 cut_edges_len++;
724 }
725 }
726 BLI_assert(cut_edges_len == data.cut_edges_len);
727# endif
728
729 size_t e_map_size = (data.cut_edges_len * sizeof(*e_map)) +
730 ((size_t(2) * edgexedge_pair_len + edgexvert_pair_len) *
731 sizeof(*(e_map->cuts_index)));
732
733 e_map = static_cast<EdgeIntersectionsMap *>(MEM_mallocN(e_map_size, __func__));
734 int map_len = 0;
735
736 /* Convert every pair to Vert x Vert. */
737
738 /* The list of pairs starts with [vert x vert] followed by [edge x edge]
739 * and finally [edge x vert].
740 * Ignore the [vert x vert] pairs */
741 EDBMSplitElem *pair_flat, *pair_flat_iter;
742 pair_flat = (EDBMSplitElem *)&pair_array[vertxvert_pair_len];
743 pair_flat_iter = &pair_flat[0];
744 uint pair_flat_len = 2 * edgexelem_pair_len;
745 for (i = 0; i < pair_flat_len; i++, pair_flat_iter++) {
746 if (pair_flat_iter->elem->head.htype != BM_EDGE) {
747 continue;
748 }
749
750 e = pair_flat_iter->edge;
753 int e_cuts_len = e->head.index;
754
755 e_map_iter = (EdgeIntersectionsMap *)&e_map->as_int[map_len];
756 e_map_iter->cuts_len = e_cuts_len;
757 e_map_iter->cuts_index[0] = i;
758
759 /* Use `e->head.index` to indicate which slot to fill with the `cut` index. */
760 e->head.index = map_len + 1;
761 map_len += 1 + e_cuts_len;
762 }
763 else {
764 e_map->as_int[++e->head.index] = i;
765 }
766 }
767
768 /* Split Edges A to set all Vert x Edge. */
769 for (i = 0; i < map_len;
770 e_map_iter = (EdgeIntersectionsMap *)&e_map->as_int[i], i += 1 + e_map_iter->cuts_len)
771 {
772
773 /* sort by lambda. */
774 BLI_qsort_r(e_map_iter->cuts_index,
775 e_map_iter->cuts_len,
776 sizeof(*(e_map->cuts_index)),
778 pair_flat);
779
780 float lambda, lambda_prev = 0.0f;
781 for (int j = 0; j < e_map_iter->cuts_len; j++) {
782 uint index = e_map_iter->cuts_index[j];
783
784 EDBMSplitElem *pair_elem = &pair_flat[index];
785 lambda = (pair_elem->lambda - lambda_prev) / (1.0f - lambda_prev);
786 lambda_prev = pair_elem->lambda;
787 e = pair_elem->edge;
788 if (split_faces) {
789 /* Tagged edges are ignored when split faces.
790 * Un-tag these. */
792 }
793
794 BMVert *v_new = BM_edge_split(bm, e, e->v1, nullptr, lambda);
795 pair_elem->vert = v_new;
796 }
797 }
798
799 MEM_freeN(e_map);
800 }
801 }
802#endif
803
804 BLI_bvhtree_free(tree_verts_act);
805 BLI_bvhtree_free(tree_verts_remain);
806
807 if (r_targetmap) {
808 if (pair_len && pair_array == nullptr) {
809 pair_array = static_cast<EDBMSplitElem(*)[2]>(
810 MEM_mallocN(sizeof(*pair_array) * pair_len, __func__));
811 pair_iter = pair_array;
812 for (i = 0; i < BLI_STACK_PAIR_LEN; i++) {
813 if (pair_stack[i]) {
814 uint count = uint(BLI_stack_count(pair_stack[i]));
815 BLI_stack_pop_n_reverse(pair_stack[i], pair_iter, count);
816 pair_iter += count;
817 }
818 }
819 }
820
821 if (pair_array) {
822 BMVert *v_key, *v_val;
823 pair_iter = &pair_array[0];
824 for (i = 0; i < pair_len; i++, pair_iter++) {
825 BLI_assert((*pair_iter)[0].elem->head.htype == BM_VERT);
826 BLI_assert((*pair_iter)[1].elem->head.htype == BM_VERT);
827 BLI_assert((*pair_iter)[0].elem != (*pair_iter)[1].elem);
828 v_key = (*pair_iter)[0].vert;
829 v_val = (*pair_iter)[1].vert;
830 BLI_ghash_insert(r_targetmap, v_key, v_val);
831 }
832
841 pair_iter = &pair_array[0];
842 for (i = 0; i < pair_len; i++, pair_iter++) {
843 v_key = (*pair_iter)[0].vert;
844 v_val = (*pair_iter)[1].vert;
845 BMVert *v_target;
846 while ((v_target = static_cast<BMVert *>(BLI_ghash_lookup(r_targetmap, v_val)))) {
847 v_val = v_target;
848 }
849 if (v_val != (*pair_iter)[1].vert) {
850 BMVert **v_val_p = (BMVert **)BLI_ghash_lookup_p(r_targetmap, v_key);
851 *v_val_p = (*pair_iter)[1].vert = v_val;
852 }
853 if (split_faces) {
854 /* The vertex index indicates its position in the pair_array flat. */
855 BM_elem_index_set(v_key, i * 2);
856 BM_elem_index_set(v_val, i * 2 + 1);
857 }
858 }
859
860 if (split_faces) {
861 BMEdge **edgenet = nullptr;
862 int edgenet_alloc_len = 0;
863
864 EDBMSplitElem *pair_flat = (EDBMSplitElem *)&pair_array[0];
865 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
867 /* Edge out of context or already tested. */
868 continue;
869 }
870
871 BMVert *va, *vb, *va_dest = nullptr;
872 va = e->v1;
873 vb = e->v2;
874
875 int v_cut = BM_elem_index_get(va);
876 int v_cut_other = BM_elem_index_get(vb);
877 if (v_cut == -1 && v_cut_other == -1) {
879 /* Edge out of context. */
881 }
882 continue;
883 }
884
885 /* Tag to avoid testing again. */
887
888 if (v_cut == -1) {
889 std::swap(va, vb);
890 v_cut = v_cut_other;
891 v_cut_other = -1;
892 }
893
894 /* `v_cut` indicates the other vertex within the `pair_array`. */
895 v_cut += v_cut % 2 ? -1 : 1;
896 va_dest = pair_flat[v_cut].vert;
897
898 if (BM_vert_pair_share_face_check(va, va_dest)) {
899 /* Vert par acts on the same face.
900 * Although there are cases like this where the face can be split,
901 * for efficiency it is better to ignore then. */
902 continue;
903 }
904
905 BMFace *best_face = nullptr;
906 BMVert *v_other_dest, *v_other = vb;
907 BMEdge *e_net = e;
908 int edgenet_len = 0;
909 while (true) {
910 if (v_cut_other != -1) {
911 v_cut_other += v_cut_other % 2 ? -1 : 1;
912 v_other_dest = pair_flat[v_cut_other].vert;
913
914 if (BM_vert_pair_share_face_check(v_other, v_other_dest)) {
915 /* Vert par acts on the same face.
916 * Although there are cases like this where the face can be split,
917 * for efficiency and to avoid complications, it is better to ignore these cases.
918 */
919 break;
920 }
921 }
922 else {
923 v_other_dest = v_other;
924 }
925
926 if (va_dest == v_other_dest) {
927 /* Edge/Edge-net to vertex - we can't split the face. */
928 break;
929 }
930 if (edgenet_len == 0 && BM_edge_exists(va_dest, v_other_dest)) {
931 /* Edge to edge - no need to detect face. */
932 break;
933 }
934
935 if (edgenet_alloc_len == edgenet_len) {
936 edgenet_alloc_len = (edgenet_alloc_len + 1) * 2;
937 edgenet = static_cast<BMEdge **>(
938 MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet)));
939 }
940 edgenet[edgenet_len++] = e_net;
941
942 best_face = bm_vert_pair_best_face_get(
943 va_dest, v_other_dest, edgenet, edgenet_len, dist);
944
945 if (best_face) {
946 if ((va_dest != va) && !BM_edge_exists(va_dest, va)) {
954 e_net = edgenet[0];
955 if (edgenet_len > 1) {
956 vb = BM_edge_other_vert(e_net, va);
957 }
958 else {
959 vb = v_other_dest;
960 }
961 edgenet[0] = BM_edge_create(bm, va_dest, vb, e_net, BM_CREATE_NOP);
962 }
963 if ((edgenet_len > 1) && (v_other_dest != v_other) &&
964 !BM_edge_exists(v_other_dest, v_other))
965 {
973 e_net = edgenet[edgenet_len - 1];
974 edgenet[edgenet_len - 1] = BM_edge_create(
975 bm, v_other_dest, BM_edge_other_vert(e_net, v_other), e_net, BM_CREATE_NOP);
976 }
977 break;
978 }
979
980 BMEdge *e_test = e_net, *e_next = nullptr;
981 while ((e_test = BM_DISK_EDGE_NEXT(e_test, v_other)) != (e_net)) {
982 if (!BM_edge_is_wire(e_test)) {
983 if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
984 continue;
985 }
986 if (!BM_elem_flag_test(e_test->v1, BM_ELEM_TAG) &&
988 {
989 continue;
990 }
991 /* Avoids endless loop. */
993 }
994 else if (!BM_edge_is_wire(e_net)) {
995 continue;
996 }
997 e_next = e_test;
998 break;
999 }
1000
1001 if (e_next == nullptr) {
1002 break;
1003 }
1004
1005 e_net = e_next;
1006 v_other = BM_edge_other_vert(e_net, v_other);
1007 if (v_other == va) {
1008 /* Endless loop. */
1009 break;
1010 }
1011 v_cut_other = BM_elem_index_get(v_other);
1012 }
1013
1014 if (best_face) {
1016 BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, &face_arr);
1017 /* Update the new faces normal.
1018 * Normal is necessary to obtain the best face for edgenet */
1019 for (BMFace *face : face_arr) {
1021 }
1022 }
1023 }
1024
1025 if (edgenet) {
1026 MEM_freeN(edgenet);
1027 }
1028 }
1029 ok = true;
1030 }
1031 }
1032
1033 for (i = BLI_STACK_PAIR_LEN; i--;) {
1034 if (pair_stack[i]) {
1035 BLI_stack_free(pair_stack[i]);
1036 }
1037 }
1038 if (pair_array) {
1039 MEM_freeN(pair_array);
1040 }
1041
1042 return ok;
1043}
1044
#define BLI_assert(a)
Definition BLI_assert.h:46
void ** BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:745
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
bool(*)(void *userdata, int index_a, int index_b, int thread) BVHTree_OverlapCallback
@ BVH_OVERLAP_USE_THREADING
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)
BVHTreeOverlap * BLI_bvhtree_overlap_ex(const BVHTree *tree1, const BVHTree *tree2, uint *r_overlap_num, BVHTree_OverlapCallback callback, void *userdata, uint max_interactions, int flag)
int BLI_bvhtree_overlap_thread_num(const BVHTree *tree)
MINLINE float square_f(float a)
bool isect_ray_ray_v3(const float ray_origin_a[3], const float ray_direction_a[3], const float ray_origin_b[3], const float ray_direction_b[3], float *r_lambda_a, float *r_lambda_b)
float ray_point_factor_v3_ex(const float p[3], const float ray_origin[3], const float ray_direction[3], float epsilon, float fallback)
bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3], const float ray_direction_a[3], const float ray_origin_b[3], const float ray_direction_b[3], float epsilon, float *r_lambda_a, float *r_lambda_b)
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
Definition sort.cc:77
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL()
Definition stack.cc:157
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:228
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.cc:96
void * BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:103
#define BLI_stack_new(esize, descr)
unsigned int uint
#define IN_RANGE(a, b, c)
#define ELEM(...)
#define IN_RANGE_INCL(a, b, c)
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE int32_t atomic_fetch_and_add_int32(int32_t *p, int32_t x)
#define BM_DISK_EDGE_NEXT(e, v)
@ BM_ELEM_HIDDEN
@ BM_ELEM_TAG
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
@ BM_CREATE_NOP
Definition bmesh_core.hh:28
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
#define KDOP_TREE_TYPE
bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, const bool split_faces, GHash *r_targetmap)
static bool bm_vertxvert_self_isect_cb(void *userdata, int index_a, int index_b, int thread)
static bool bm_vert_pair_share_best_splittable_face_cb(BMFace *f, BMLoop *l_a, BMLoop *l_b, void *userdata)
static bool bm_edgexvert_isect_impl(BMVert *v, BMEdge *e, const float co[3], const float dir[3], float lambda, float data_dist_sq, int *data_cut_edges_len, EDBMSplitElem r_pair[2])
static bool bm_edgexedge_isect_impl(EDBMSplitData *data, BMEdge *e_a, BMEdge *e_b, const float co_a[3], const float dir_a[3], const float co_b[3], const float dir_b[3], float lambda_a, float lambda_b, EDBMSplitElem r_pair[2])
static void bm_edge_pair_elem_setup(BMEdge *e, float lambda, int *r_data_cut_edges_len, EDBMSplitElem *r_pair_elem)
static void bm_elemxelem_bvhtree_overlap(const BVHTree *tree1, const BVHTree *tree2, BVHTree_OverlapCallback callback, EDBMSplitData *data, BLI_Stack **pair_stack)
static bool bm_edgexedge_self_isect_cb(void *userdata, int index_a, int index_b, int thread)
static BMFace * bm_vert_pair_best_face_get(BMVert *v_a, BMVert *v_b, BMEdge **edgenet, const int edgenet_len, const float epsilon)
#define KDOP_AXIS_LEN
static int sort_cmp_by_lambda_cb(const void *index1_v, const void *index2_v, void *keys_v)
#define EDGE_REMAIN_TO_TEST
#define BLI_STACK_PAIR_LEN
static bool bm_vertxvert_isect_cb(void *userdata, int index_a, int index_b, int thread)
#define EDGE_ACT_TO_TEST
static bool bm_vert_pair_share_splittable_face_cb(BMFace *, BMLoop *l_a, BMLoop *l_b, void *userdata)
static void bm_vert_pair_elem_setup_ex(BMVert *v, EDBMSplitElem *r_pair_elem)
static bool bm_edgexedge_isect_cb(void *userdata, int index_a, int index_b, int thread)
static bool bm_edgexvert_isect_cb(void *userdata, int index_a, int index_b, int thread)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_FACE
BMesh const char void * data
BMesh * bm
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
BLI_INLINE BMEdge * BM_edge_at_index(BMesh *bm, const int index)
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
#define BM_EDGE
#define BM_VERT
bool BM_face_point_inside_test(const BMFace *f, const float co[3])
void BM_face_normal_update(BMFace *f)
bool BM_face_split_edgenet(BMesh *bm, BMFace *f, BMEdge **edge_net, const int edge_net_len, blender::Vector< BMFace * > *r_face_arr)
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b)
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
BMFace * BM_vert_pair_shared_face_cb(BMVert *v_a, BMVert *v_b, const bool allow_adjacent, bool(*callback)(BMFace *, BMLoop *, BMLoop *, void *userdata), void *user_data, BMLoop **r_l_a, BMLoop **r_l_b)
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
bool closest(btVector3 &v)
nullptr float
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
int count
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline int as_int(const uint i)
Definition math_base.h:226
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
BMVert * v1
BMVert * v2
BMHeader head
float no[3]
struct BMVert * v
struct BMLoop * prev
struct BMLoop * next
float co[3]
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251