Blender V5.0
bmesh_intersect.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
21
22#include "MEM_guardedalloc.h"
23
24#include "BLI_alloca.h"
25#include "BLI_linklist.h"
26#include "BLI_math_geom.h"
27#include "BLI_math_vector.h"
28#include "BLI_memarena.h"
29#include "BLI_sort_utils.h"
30#include "BLI_utildefines.h"
31#include "BLI_vector.hh"
32
34
35#include "BLI_kdopbvh.hh"
36
37#include "bmesh.hh"
39
40#include "bmesh_intersect.hh" /* own include */
41
43
44#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
45
46/*
47 * Some of these depend on each other:
48 */
49
50/* splice verts into existing edges */
51#define USE_SPLICE
52/* split faces by intersecting edges */
53#define USE_NET
54/* split resulting edges */
55#define USE_SEPARATE
56/* remove verts created by intersecting triangles */
57#define USE_DISSOLVE
58/* detect isolated holes and fill them */
59#define USE_NET_ISLAND_CONNECT
60
61/* strict asserts that may fail in practice (handy for debugging cases which should succeed) */
62// #define USE_PARANOID
63/* use accelerated overlap check */
64#define USE_BVH
65
66// #define USE_DUMP
67
68static void tri_v3_scale(float v1[3], float v2[3], float v3[3], const float t)
69{
70 float p[3];
71
72 mid_v3_v3v3v3(p, v1, v2, v3);
73
74 interp_v3_v3v3(v1, p, v1, t);
75 interp_v3_v3v3(v2, p, v2, t);
76 interp_v3_v3v3(v3, p, v3, t);
77}
78
79#ifdef USE_DISSOLVE
80/* other edge when a vert only has 2 edges */
82{
85
86 if (v->e != e) {
87 return v->e;
88 }
89 return BM_DISK_EDGE_NEXT(v->e, v);
90}
91#endif
92
101
107
110 GHash *edgetri_cache; /* int[4]: BMVert */
111 GHash *edge_verts; /* BMEdge: LinkList(of verts), new and original edges */
112 GHash *face_edges; /* BMFace-index: LinkList(of edges), only original faces */
113 GSet *wire_edges; /* BMEdge (could use tags instead) */
114 LinkNode *vert_dissolve; /* BMVert's */
115
117
119};
120
129
130static bool ghash_insert_link(GHash *gh, void *key, void *val, bool use_test, MemArena *mem_arena)
131{
132 void **ls_base_p;
133 LinkBase *ls_base;
134 LinkNode *ls;
135
136 if (!BLI_ghash_ensure_p(gh, key, &ls_base_p)) {
137 ls_base = static_cast<LinkBase *>(*ls_base_p = BLI_memarena_alloc(mem_arena,
138 sizeof(*ls_base)));
139 ls_base->list = nullptr;
140 ls_base->list_len = 0;
141 }
142 else {
143 ls_base = static_cast<LinkBase *>(*ls_base_p);
144 if (use_test && (BLI_linklist_index(ls_base->list, val) != -1)) {
145 return false;
146 }
147 }
148
149 ls = static_cast<LinkNode *>(BLI_memarena_alloc(mem_arena, sizeof(*ls)));
150 ls->next = ls_base->list;
151 ls->link = val;
152 ls_base->list = ls;
153 ls_base->list_len += 1;
154
155 return true;
156}
157
158struct VertSort {
159 float val;
161};
162
163#ifdef USE_SPLICE
164static void edge_verts_sort(const float co[3], LinkBase *v_ls_base)
165{
166 /* not optimal but list will be typically < 5 */
167 uint i;
168 VertSort *vert_sort = BLI_array_alloca(vert_sort, v_ls_base->list_len);
169 LinkNode *node;
170
171 BLI_assert(v_ls_base->list_len > 1);
172
173 for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) {
174 BMVert *v = static_cast<BMVert *>(node->link);
175 BLI_assert(v->head.htype == BM_VERT);
176 vert_sort[i].val = len_squared_v3v3(co, v->co);
177 vert_sort[i].v = v;
178 }
179
180 qsort(vert_sort, v_ls_base->list_len, sizeof(*vert_sort), BLI_sortutil_cmp_float);
181
182 for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) {
183 node->link = vert_sort[i].v;
184 }
185}
186#endif
187
188static void edge_verts_add(ISectState *s, BMEdge *e, BMVert *v, const bool use_test)
189{
190 BLI_assert(e->head.htype == BM_EDGE);
191 BLI_assert(v->head.htype == BM_VERT);
192 ghash_insert_link(s->edge_verts, (void *)e, v, use_test, s->mem_arena);
193}
194
195static void face_edges_add(ISectState *s, const int f_index, BMEdge *e, const bool use_test)
196{
197 void *f_index_key = POINTER_FROM_INT(f_index);
198 BLI_assert(e->head.htype == BM_EDGE);
199 BLI_assert(BM_edge_in_face(e, s->bm->ftable[f_index]) == false);
200 BLI_assert(BM_elem_index_get(s->bm->ftable[f_index]) == f_index);
201
202 ghash_insert_link(s->face_edges, f_index_key, e, use_test, s->mem_arena);
203}
204
205#ifdef USE_NET
207 BMFace *f,
208 LinkBase *e_ls_base,
209 bool use_island_connect,
210 bool use_partial_connect,
211 MemArena *mem_arena_edgenet)
212{
213 uint i;
214 uint edge_arr_len = e_ls_base->list_len;
215 BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len);
216 LinkNode *node;
218
219 for (i = 0, node = e_ls_base->list; i < e_ls_base->list_len; i++, node = node->next) {
220 edge_arr[i] = static_cast<BMEdge *>(node->link);
221 }
222 BLI_assert(node == nullptr);
223
224# ifdef USE_DUMP
225 printf("# %s: %d %u\n", __func__, BM_elem_index_get(f), e_ls_base->list_len);
226# endif
227
228# ifdef USE_NET_ISLAND_CONNECT
229 if (use_island_connect) {
230 uint edge_arr_holes_len;
231 BMEdge **edge_arr_holes;
233 f,
234 edge_arr,
235 edge_arr_len,
236 use_partial_connect,
237 mem_arena_edgenet,
238 &edge_arr_holes,
239 &edge_arr_holes_len))
240 {
241 edge_arr_len = edge_arr_holes_len;
242 edge_arr = edge_arr_holes; /* owned by the arena */
243 }
244 }
245# else
246 UNUSED_VARS(use_island_connect, mem_arena_edgenet);
247# endif
248
249 BM_face_split_edgenet(bm, f, edge_arr, int(edge_arr_len), nullptr);
250}
251#endif
252
253#ifdef USE_DISSOLVE
263#endif
264
265static enum ISectType intersect_line_tri(const float p0[3],
266 const float p1[3],
267 const float *t_cos[3],
268 const float t_nor[3],
269 float r_ix[3],
270 const ISectEpsilon *e)
271{
272 float p_dir[3];
273 uint i_t0;
274 float fac;
275
276 sub_v3_v3v3(p_dir, p0, p1);
277 normalize_v3(p_dir);
278
279 for (i_t0 = 0; i_t0 < 3; i_t0++) {
280 const uint i_t1 = (i_t0 + 1) % 3;
281 float te_dir[3];
282
283 sub_v3_v3v3(te_dir, t_cos[i_t0], t_cos[i_t1]);
284 normalize_v3(te_dir);
285 if (fabsf(dot_v3v3(p_dir, te_dir)) >= 1.0f - e->eps) {
286 /* co-linear */
287 }
288 else {
289 float ix_pair[2][3];
290 int ix_pair_type;
291
292 ix_pair_type = isect_line_line_epsilon_v3(
293 p0, p1, t_cos[i_t0], t_cos[i_t1], ix_pair[0], ix_pair[1], 0.0f);
294
295 if (ix_pair_type != 0) {
296 if (ix_pair_type == 1) {
297 copy_v3_v3(ix_pair[1], ix_pair[0]);
298 }
299
300 if ((ix_pair_type == 1) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) <= e->eps_margin_sq))
301 {
302 fac = line_point_factor_v3(ix_pair[1], t_cos[i_t0], t_cos[i_t1]);
303 if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
304 fac = line_point_factor_v3(ix_pair[0], p0, p1);
305 if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
306 copy_v3_v3(r_ix, ix_pair[0]);
307 return ISectType(IX_EDGE_TRI_EDGE0 + (enum ISectType)i_t0);
308 }
309 }
310 }
311 }
312 }
313 }
314
315 /* check ray isn't planar with tri */
316 if (fabsf(dot_v3v3(p_dir, t_nor)) >= e->eps) {
318 p0, p1, t_cos[0], t_cos[1], t_cos[2], &fac, nullptr, 0.0f))
319 {
320 if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
321 interp_v3_v3v3(r_ix, p0, p1, fac);
322 if (min_fff(len_squared_v3v3(t_cos[0], r_ix),
323 len_squared_v3v3(t_cos[1], r_ix),
324 len_squared_v3v3(t_cos[2], r_ix)) >= e->eps_margin_sq)
325 {
326 return IX_EDGE_TRI;
327 }
328 }
329 }
330 }
331
332 /* r_ix may be unset */
333 return IX_NONE;
334}
335
337 BMVert *e_v0,
338 BMVert *e_v1,
339 BMVert *t[3],
340 const int t_index,
341 const float *t_cos[3],
342 const float t_nor[3],
343 enum ISectType *r_side)
344{
345 BMesh *bm = s->bm;
346 int k_arr[IX_TOT][4];
347 uint i;
348 const int ti[3] = {UNPACK3_EX(BM_elem_index_get, t, )};
349 float ix[3];
350
351 if (BM_elem_index_get(e_v0) > BM_elem_index_get(e_v1)) {
352 std::swap(e_v0, e_v1);
353 }
354
355#ifdef USE_PARANOID
356 BLI_assert(len_squared_v3v3(e_v0->co, t[0]->co) >= s->epsilon.eps_sq);
357 BLI_assert(len_squared_v3v3(e_v0->co, t[1]->co) >= s->epsilon.eps_sq);
358 BLI_assert(len_squared_v3v3(e_v0->co, t[2]->co) >= s->epsilon.eps_sq);
359 BLI_assert(len_squared_v3v3(e_v1->co, t[0]->co) >= s->epsilon.eps_sq);
360 BLI_assert(len_squared_v3v3(e_v1->co, t[1]->co) >= s->epsilon.eps_sq);
361 BLI_assert(len_squared_v3v3(e_v1->co, t[2]->co) >= s->epsilon.eps_sq);
362#endif
363
364#define KEY_SET(k, i0, i1, i2, i3) \
365 { \
366 (k)[0] = i0; \
367 (k)[1] = i1; \
368 (k)[2] = i2; \
369 (k)[3] = i3; \
370 } \
371 (void)0
372
373/* Order tri, then order (1-2, 2-3). */
374#define KEY_EDGE_TRI_ORDER(k) \
375 { \
376 if (k[2] > k[3]) { \
377 std::swap(k[2], k[3]); \
378 } \
379 if (k[0] > k[2]) { \
380 std::swap(k[0], k[2]); \
381 std::swap(k[1], k[3]); \
382 } \
383 } \
384 (void)0
385
386 KEY_SET(k_arr[IX_EDGE_TRI], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), t_index, -1);
387 /* need to order here */
388 KEY_SET(
389 k_arr[IX_EDGE_TRI_EDGE0], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[0], ti[1]);
390 KEY_SET(
391 k_arr[IX_EDGE_TRI_EDGE1], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[1], ti[2]);
392 KEY_SET(
393 k_arr[IX_EDGE_TRI_EDGE2], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[2], ti[0]);
394
398
399#undef KEY_SET
400#undef KEY_EDGE_TRI_ORDER
401
402 for (i = 0; i < ARRAY_SIZE(k_arr); i++) {
403 BMVert *iv;
404
405 iv = static_cast<BMVert *>(BLI_ghash_lookup(s->edgetri_cache, k_arr[i]));
406
407 if (iv) {
408#ifdef USE_DUMP
409 printf("# cache hit (%d, %d, %d, %d)\n", UNPACK4(k_arr[i]));
410#endif
411 *r_side = (enum ISectType)i;
412 return iv;
413 }
414 }
415
416 *r_side = intersect_line_tri(e_v0->co, e_v1->co, t_cos, t_nor, ix, &s->epsilon);
417 if (*r_side != IX_NONE) {
418 BMVert *iv;
419 BMEdge *e;
420#ifdef USE_DUMP
421 printf("# new vertex (%.6f, %.6f, %.6f) %d\n", UNPACK3(ix), *r_side);
422#endif
423
424#ifdef USE_PARANOID
427 BLI_assert(len_squared_v3v3(ix, t[0]->co) > s->epsilon.eps_sq);
428 BLI_assert(len_squared_v3v3(ix, t[1]->co) > s->epsilon.eps_sq);
429 BLI_assert(len_squared_v3v3(ix, t[2]->co) > s->epsilon.eps_sq);
430#endif
431 iv = BM_vert_create(bm, ix, nullptr, eBMCreateFlag(0));
432
433 e = BM_edge_exists(e_v0, e_v1);
434 if (e) {
435#ifdef USE_DUMP
436 printf("# adding to edge %d\n", BM_elem_index_get(e));
437#endif
438 edge_verts_add(s, e, iv, false);
439 }
440 else {
441#ifdef USE_DISSOLVE
442 vert_dissolve_add(s, iv);
443#endif
444 }
445
446 if ((*r_side >= IX_EDGE_TRI_EDGE0) && (*r_side <= IX_EDGE_TRI_EDGE2)) {
447 i = uint(*r_side - IX_EDGE_TRI_EDGE0);
448 e = BM_edge_exists(t[i], t[(i + 1) % 3]);
449 if (e) {
450 edge_verts_add(s, e, iv, false);
451 }
452 }
453
454 {
455 int *k = static_cast<int *>(BLI_memarena_alloc(s->mem_arena, sizeof(int[4])));
456 memcpy(k, k_arr[*r_side], sizeof(int[4]));
458 }
459
460 return iv;
461 }
462
463 *r_side = IX_NONE;
464
465 return nullptr;
466}
467
469 int (*test_fn)(BMFace *f, void *user_data);
471};
472
473static bool bm_loop_filter_fn(const BMLoop *l, void *user_data)
474{
476 return false;
477 }
478
479 if (l->radial_next != l) {
480 LoopFilterWrap *data = static_cast<LoopFilterWrap *>(user_data);
481 BMLoop *l_iter = l->radial_next;
482 const int face_side = data->test_fn(l->f, data->user_data);
483 do {
484 const int face_side_other = data->test_fn(l_iter->f, data->user_data);
485 if (UNLIKELY(face_side_other == -1)) {
486 /* pass */
487 }
488 else if (face_side_other != face_side) {
489 return false;
490 }
491 } while ((l_iter = l_iter->radial_next) != l);
492 return true;
493 }
494 return false;
495}
496
501 int a_index,
502 int b_index,
503 const std::array<BMLoop *, 3> &a,
504 const std::array<BMLoop *, 3> &b,
505 bool no_shared)
506{
507 BMFace *f_a = a[0]->f;
508 BMFace *f_b = b[0]->f;
509 BMVert *fv_a[3] = {UNPACK3_EX(, a, ->v)};
510 BMVert *fv_b[3] = {UNPACK3_EX(, b, ->v)};
511 const float *f_a_cos[3] = {UNPACK3_EX(, fv_a, ->co)};
512 const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)};
513 float f_a_nor[3];
514 float f_b_nor[3];
515 uint i;
516
517 /* should be enough but may need to bump */
518 BMVert *iv_ls_a[8];
519 BMVert *iv_ls_b[8];
520 STACK_DECLARE(iv_ls_a);
521 STACK_DECLARE(iv_ls_b);
522
523 if (no_shared) {
524 if (UNLIKELY(ELEM(fv_a[0], UNPACK3(fv_b)) || ELEM(fv_a[1], UNPACK3(fv_b)) ||
525 ELEM(fv_a[2], UNPACK3(fv_b))))
526 {
527 return;
528 }
529 }
530 else {
531 if (UNLIKELY(BM_face_share_edge_check(f_a, f_b))) {
532 return;
533 }
534 }
535
536 STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a));
537 STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b));
538
539#define VERT_VISIT_A _FLAG_WALK
540#define VERT_VISIT_B _FLAG_WALK_ALT
541
542#define STACK_PUSH_TEST_A(ele) \
543 if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_A) == 0) { \
544 BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_A); \
545 STACK_PUSH(iv_ls_a, ele); \
546 } \
547 ((void)0)
548
549#define STACK_PUSH_TEST_B(ele) \
550 if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_B) == 0) { \
551 BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_B); \
552 STACK_PUSH(iv_ls_b, ele); \
553 } \
554 ((void)0)
555
556 /* vert-vert
557 * --------- */
558 {
559 /* first check if any verts are touching
560 * (any case where we won't create new verts)
561 */
562 uint i_a;
563 for (i_a = 0; i_a < 3; i_a++) {
564 uint i_b;
565 for (i_b = 0; i_b < 3; i_b++) {
566 if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
567#ifdef USE_DUMP
568 if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) {
569 printf(" ('VERT-VERT-A') %u, %d),\n", i_a, BM_elem_index_get(fv_a[i_a]));
570 }
571 if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) {
572 printf(" ('VERT-VERT-B') %u, %d),\n", i_b, BM_elem_index_get(fv_b[i_b]));
573 }
574#endif
575 STACK_PUSH_TEST_A(fv_a[i_a]);
576 STACK_PUSH_TEST_B(fv_b[i_b]);
577 }
578 }
579 }
580 }
581
582 /* vert-edge
583 * --------- */
584 {
585 uint i_a;
586 for (i_a = 0; i_a < 3; i_a++) {
587 if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) {
588 uint i_b_e0;
589 for (i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
590 uint i_b_e1 = (i_b_e0 + 1) % 3;
591
592 if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
593 BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B))
594 {
595 continue;
596 }
597
598 const float fac = line_point_factor_v3(
599 fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co);
600 if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
601 float ix[3];
602 interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac);
603 if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
604 BMEdge *e;
605 STACK_PUSH_TEST_B(fv_a[i_a]);
606 // STACK_PUSH_TEST_A(fv_a[i_a]);
607 e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]);
608#ifdef USE_DUMP
609 printf(" ('VERT-EDGE-A', %d, %d),\n",
610 BM_elem_index_get(fv_b[i_b_e0]),
611 BM_elem_index_get(fv_b[i_b_e1]));
612#endif
613 if (e) {
614#ifdef USE_DUMP
615 printf("# adding to edge %d\n", BM_elem_index_get(e));
616#endif
617 edge_verts_add(s, e, fv_a[i_a], true);
618 }
619 break;
620 }
621 }
622 }
623 }
624 }
625 }
626
627 {
628 uint i_b;
629 for (i_b = 0; i_b < 3; i_b++) {
630 if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) {
631 uint i_a_e0;
632 for (i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
633 uint i_a_e1 = (i_a_e0 + 1) % 3;
634
635 if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
636 BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A))
637 {
638 continue;
639 }
640
641 const float fac = line_point_factor_v3(
642 fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co);
643 if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
644 float ix[3];
645 interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac);
646 if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
647 BMEdge *e;
648 STACK_PUSH_TEST_A(fv_b[i_b]);
649 // STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
650 e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]);
651#ifdef USE_DUMP
652 printf(" ('VERT-EDGE-B', %d, %d),\n",
653 BM_elem_index_get(fv_a[i_a_e0]),
654 BM_elem_index_get(fv_a[i_a_e1]));
655#endif
656 if (e) {
657#ifdef USE_DUMP
658 printf("# adding to edge %d\n", BM_elem_index_get(e));
659#endif
660 edge_verts_add(s, e, fv_b[i_b], true);
661 }
662 break;
663 }
664 }
665 }
666 }
667 }
668 }
669
670 /* vert-tri
671 * -------- */
672 {
673
674 float t_scale[3][3];
675 uint i_a;
676
677 copy_v3_v3(t_scale[0], fv_b[0]->co);
678 copy_v3_v3(t_scale[1], fv_b[1]->co);
679 copy_v3_v3(t_scale[2], fv_b[2]->co);
680 tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x);
681
682 /* second check for verts intersecting the triangle */
683 for (i_a = 0; i_a < 3; i_a++) {
684 if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A)) {
685 continue;
686 }
687
688 float ix[3];
689 if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) {
690 if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
691 STACK_PUSH_TEST_A(fv_a[i_a]);
692 STACK_PUSH_TEST_B(fv_a[i_a]);
693#ifdef USE_DUMP
694 printf(" 'VERT TRI-A',\n");
695#endif
696 }
697 }
698 }
699 }
700
701 {
702 float t_scale[3][3];
703 uint i_b;
704
705 copy_v3_v3(t_scale[0], fv_a[0]->co);
706 copy_v3_v3(t_scale[1], fv_a[1]->co);
707 copy_v3_v3(t_scale[2], fv_a[2]->co);
708 tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x);
709
710 for (i_b = 0; i_b < 3; i_b++) {
711 if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B)) {
712 continue;
713 }
714
715 float ix[3];
716 if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) {
717 if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
718 STACK_PUSH_TEST_A(fv_b[i_b]);
719 STACK_PUSH_TEST_B(fv_b[i_b]);
720#ifdef USE_DUMP
721 printf(" 'VERT TRI-B',\n");
722#endif
723 }
724 }
725 }
726 }
727
728 if ((STACK_SIZE(iv_ls_a) >= 3) && (STACK_SIZE(iv_ls_b) >= 3)) {
729#ifdef USE_DUMP
730 printf("# OVERLAP\n");
731#endif
732 goto finally;
733 }
734
735 normal_tri_v3(f_a_nor, UNPACK3(f_a_cos));
736 normal_tri_v3(f_b_nor, UNPACK3(f_b_cos));
737
738 /* edge-tri & edge-edge
739 * -------------------- */
740 {
741 for (uint i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
742 uint i_a_e1 = (i_a_e0 + 1) % 3;
743 enum ISectType side;
744 BMVert *iv;
745
746 if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
747 BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A))
748 {
749 continue;
750 }
751
753 s, fv_a[i_a_e0], fv_a[i_a_e1], fv_b, b_index, f_b_cos, f_b_nor, &side);
754 if (iv) {
757#ifdef USE_DUMP
758 printf(" ('EDGE-TRI-A', %d),\n", side);
759#endif
760 }
761 }
762
763 for (uint i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
764 uint i_b_e1 = (i_b_e0 + 1) % 3;
765 enum ISectType side;
766 BMVert *iv;
767
768 if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
769 BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B))
770 {
771 continue;
772 }
773
775 s, fv_b[i_b_e0], fv_b[i_b_e1], fv_a, a_index, f_a_cos, f_a_nor, &side);
776 if (iv) {
779#ifdef USE_DUMP
780 printf(" ('EDGE-TRI-B', %d),\n", side);
781#endif
782 }
783 }
784 }
785
786 {
787 for (i = 0; i < 2; i++) {
788 BMVert **ie_vs;
789 BMFace *f;
790 bool ie_exists;
791 BMEdge *ie;
792
793 if (i == 0) {
794 if (STACK_SIZE(iv_ls_a) != 2) {
795 continue;
796 }
797 ie_vs = iv_ls_a;
798 f = f_a;
799 }
800 else {
801 if (STACK_SIZE(iv_ls_b) != 2) {
802 continue;
803 }
804 ie_vs = iv_ls_b;
805 f = f_b;
806 }
807
808 /* possible but unlikely we get this - for edge-edge intersection */
809 ie = BM_edge_exists(UNPACK2(ie_vs));
810 if (ie == nullptr) {
811 ie_exists = false;
812 /* one of the verts must be new if we are making an edge
813 * ...no, we need this in case 2x quads intersect at either ends.
814 * if not (ie_vs[0].index == -1 or ie_vs[1].index == -1):
815 * continue */
816 ie = BM_edge_create(s->bm, UNPACK2(ie_vs), nullptr, eBMCreateFlag(0));
818 }
819 else {
820 ie_exists = true;
821 /* may already exist */
822 BLI_gset_add(s->wire_edges, ie);
823
824 if (BM_edge_in_face(ie, f)) {
825 continue;
826 }
827 }
828
829 face_edges_add(s, BM_elem_index_get(f), ie, ie_exists);
830 // BLI_assert(len(ie_vs) <= 2)
831 }
832 }
833
834finally:
835 for (i = 0; i < STACK_SIZE(iv_ls_a); i++) {
837 }
838 for (i = 0; i < STACK_SIZE(iv_ls_b); i++) {
840 }
841}
842
843#ifdef USE_BVH
844
849
850# ifdef USE_KDOPBVH_WATERTIGHT
851static const IsectRayPrecalc isect_precalc_x = {1, 2, 0, 0, 0, 1};
852# endif
853
854static void raycast_callback(void *userdata,
855 int index,
856 const BVHTreeRay *ray,
857 BVHTreeRayHit * /*hit*/)
858{
859 RaycastData *raycast_data = static_cast<RaycastData *>(userdata);
860 const float **looptris = raycast_data->looptris;
861 const float *v0 = looptris[index * 3 + 0];
862 const float *v1 = looptris[index * 3 + 1];
863 const float *v2 = looptris[index * 3 + 2];
864 float dist;
865
866 if (
868 isect_ray_tri_watertight_v3(ray->origin, &isect_precalc_x, v0, v1, v2, &dist, nullptr)
869# else
871 ray->origin, ray->direction, v0, v1, v2, &dist, nullptr, FLT_EPSILON)
872# endif
873 )
874 {
875 if (dist >= 0.0f) {
876# ifdef USE_DUMP
877 printf("%s:\n", __func__);
878 print_v3(" origin", ray->origin);
879 print_v3(" direction", ray->direction);
880 printf(" dist %f\n", dist);
881 print_v3(" v0", v0);
882 print_v3(" v1", v1);
883 print_v3(" v2", v2);
884# endif
885
886# ifdef USE_DUMP
887 printf("%s: Adding depth %f\n", __func__, dist);
888# endif
889 raycast_data->z_buffer->append(dist);
890 }
891 }
892}
893
894static int isect_bvhtree_point_v3(BVHTree *tree, const float **looptris, const float co[3])
895{
897
898 RaycastData raycast_data = {
899 looptris,
900 &z_buffer,
901 };
902 BVHTreeRayHit hit = {0};
903 const float dir[3] = {1.0f, 0.0f, 0.0f};
904
905 /* Need to initialize hit even tho it's not used.
906 * This is to make it so KD-tree believes we didn't intersect anything and
907 * keeps calling the intersect callback.
908 */
909 hit.index = -1;
911
912 BLI_bvhtree_ray_cast(tree, co, dir, 0.0f, &hit, raycast_callback, &raycast_data);
913
914# ifdef USE_DUMP
915 printf("%s: Total intersections: %zu\n", __func__, z_buffer.count);
916# endif
917
918 int num_isect;
919
920 if (z_buffer.is_empty()) {
921 num_isect = 0;
922 }
923 else if (z_buffer.size() == 1) {
924 num_isect = 1;
925 }
926 else {
927 /* 2 or more */
928 const float eps = FLT_EPSILON * 10;
929 num_isect = 1; /* always count first */
930
931 std::sort(z_buffer.begin(), z_buffer.end());
932
933 const float *depth_arr = z_buffer.data();
934 float depth_last = depth_arr[0];
935
936 for (uint i = 1; i < z_buffer.size(); i++) {
937 if (depth_arr[i] - depth_last > eps) {
938 depth_last = depth_arr[i];
939 num_isect++;
940 }
941 }
942 }
943
944 // return (num_isect & 1) == 1;
945 return num_isect;
946}
947
948#endif /* USE_BVH */
949
951 const blender::Span<std::array<BMLoop *, 3>> looptris,
952 int (*test_fn)(BMFace *f, void *user_data),
953 void *user_data,
954 const bool use_self,
955 const bool use_separate,
956 const bool use_dissolve,
957 const bool use_island_connect,
958 const bool use_partial_connect,
959 const bool use_edge_tag,
960 const int boolean_mode,
961 const float eps)
962{
963 ISectState s;
964 const int totface_orig = bm->totface;
965
966 /* use to check if we made any changes */
967 bool has_edit_isect = false, has_edit_boolean = false;
968
969 /* needed for boolean, since cutting up faces moves the loops within the face */
970 const float **looptri_coords = nullptr;
971
972#ifdef USE_BVH
973 BVHTree *tree_a, *tree_b;
974 uint tree_overlap_tot;
975 BVHTreeOverlap *overlap;
976#else
977 int i_a, i_b;
978#endif
979
980 s.bm = bm;
981
984
985 s.edge_verts = BLI_ghash_ptr_new(__func__);
986 s.face_edges = BLI_ghash_int_new(__func__);
987 s.wire_edges = BLI_gset_ptr_new(__func__);
988 s.vert_dissolve = nullptr;
989
991
992 /* setup epsilon from base */
993 s.epsilon.eps = eps;
994 s.epsilon.eps2x = eps * 2.0f;
995 s.epsilon.eps_margin = s.epsilon.eps2x * 10.0f;
996
1000
1002 BM_VERT | BM_EDGE |
1003#ifdef USE_NET
1004 BM_FACE |
1005#endif
1006 0);
1007
1009#ifdef USE_SPLICE
1010 BM_EDGE |
1011#endif
1012#ifdef USE_NET
1013 BM_FACE |
1014#endif
1015 0);
1016
1017#ifdef USE_DISSOLVE
1018 if (use_dissolve) {
1020 }
1021#else
1022 UNUSED_VARS(use_dissolve);
1023#endif
1024
1025#ifdef USE_DUMP
1026 printf("data = [\n");
1027#endif
1028
1029 if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
1030 /* Keep original geometry for ray-cast callbacks. */
1031 float **cos;
1032 int i, j;
1033
1034 cos = static_cast<float **>(
1035 MEM_mallocN(size_t(looptris.size()) * sizeof(*looptri_coords) * 3, __func__));
1036 for (i = 0, j = 0; i < int(looptris.size()); i++) {
1037 cos[j++] = looptris[i][0]->v->co;
1038 cos[j++] = looptris[i][1]->v->co;
1039 cos[j++] = looptris[i][2]->v->co;
1040 }
1041 looptri_coords = (const float **)cos;
1042 }
1043
1044#ifdef USE_BVH
1045 {
1046 int i;
1047 tree_a = BLI_bvhtree_new(int(looptris.size()), s.epsilon.eps_margin, 8, 8);
1048 for (i = 0; i < int(looptris.size()); i++) {
1049 if (test_fn(looptris[i][0]->f, user_data) == 0) {
1050 const float t_cos[3][3] = {
1051 {UNPACK3(looptris[i][0]->v->co)},
1052 {UNPACK3(looptris[i][1]->v->co)},
1053 {UNPACK3(looptris[i][2]->v->co)},
1054 };
1055
1056 BLI_bvhtree_insert(tree_a, i, (const float *)t_cos, 3);
1057 }
1058 }
1059 BLI_bvhtree_balance(tree_a);
1060 }
1061
1062 if (use_self == false) {
1063 int i;
1064 tree_b = BLI_bvhtree_new(int(looptris.size()), s.epsilon.eps_margin, 8, 8);
1065 for (i = 0; i < int(looptris.size()); i++) {
1066 if (test_fn(looptris[i][0]->f, user_data) == 1) {
1067 const float t_cos[3][3] = {
1068 {UNPACK3(looptris[i][0]->v->co)},
1069 {UNPACK3(looptris[i][1]->v->co)},
1070 {UNPACK3(looptris[i][2]->v->co)},
1071 };
1072
1073 BLI_bvhtree_insert(tree_b, i, (const float *)t_cos, 3);
1074 }
1075 }
1076 BLI_bvhtree_balance(tree_b);
1077 }
1078 else {
1079 tree_b = tree_a;
1080 }
1081
1082 /* For self intersection this can be useful, sometimes users generate geometry
1083 * where surfaces that seem disconnected happen to share an edge.
1084 * So when performing intersection calculation allow shared vertices,
1085 * just not shared edges. See #75946. */
1086 const bool isect_tri_tri_no_shared = (boolean_mode != BMESH_ISECT_BOOLEAN_NONE);
1087
1089# ifndef NDEBUG
1090 /* The overlap result must match that obtained in Release to succeed
1091 * in the `bmesh_boolean` test. */
1092 if (looptris.size() < 1024) {
1094 }
1095# endif
1096 overlap = BLI_bvhtree_overlap_ex(tree_b, tree_a, &tree_overlap_tot, nullptr, nullptr, 0, flag);
1097
1098 if (overlap) {
1099 uint i;
1100
1101 for (i = 0; i < tree_overlap_tot; i++) {
1102# ifdef USE_DUMP
1103 printf(" ((%d, %d), (\n", overlap[i].indexA, overlap[i].indexB);
1104# endif
1106 overlap[i].indexA,
1107 overlap[i].indexB,
1108 looptris[overlap[i].indexA],
1109 looptris[overlap[i].indexB],
1110 isect_tri_tri_no_shared);
1111# ifdef USE_DUMP
1112 printf(")),\n");
1113# endif
1114 }
1115 MEM_freeN(overlap);
1116 }
1117
1118 if (boolean_mode == BMESH_ISECT_BOOLEAN_NONE) {
1119 /* no booleans, just free immediate */
1120 BLI_bvhtree_free(tree_a);
1121 if (tree_a != tree_b) {
1122 BLI_bvhtree_free(tree_b);
1123 }
1124 }
1125
1126#else
1127 {
1128 for (i_a = 0; i_a < looptris.size(); i_a++) {
1129 const int t_a = test_fn(looptris[i_a][0]->f, user_data);
1130 for (i_b = i_a + 1; i_b < looptris.size(); i_b++) {
1131 const int t_b = test_fn(looptris[i_b][0]->f, user_data);
1132
1133 if (use_self) {
1134 if ((t_a != 0) || (t_b != 0)) {
1135 continue;
1136 }
1137 }
1138 else {
1139 if ((t_a != t_b) && !ELEM(-1, t_a, t_b)) {
1140 continue;
1141 }
1142 }
1143
1144# ifdef USE_DUMP
1145 printf(" ((%d, %d), (", i_a, i_b);
1146# endif
1147 bm_isect_tri_tri(&s, i_a, i_b, looptris[i_a], looptris[i_b], isect_tri_tri_no_shared);
1148# ifdef USE_DUMP
1149 printf(")),\n");
1150# endif
1151 }
1152 }
1153 }
1154#endif /* USE_BVH */
1155
1156#ifdef USE_DUMP
1157 printf("]\n");
1158#endif
1159
1160 /* --------- */
1161
1162#ifdef USE_SPLICE
1163 {
1164 GHashIterator gh_iter;
1165
1166 GHASH_ITER (gh_iter, s.edge_verts) {
1167 BMEdge *e = static_cast<BMEdge *>(BLI_ghashIterator_getKey(&gh_iter));
1168 LinkBase *v_ls_base = static_cast<LinkBase *>(BLI_ghashIterator_getValue(&gh_iter));
1169
1170 BMVert *v_start;
1171 BMVert *v_end;
1172 BMVert *v_prev;
1173 bool is_wire;
1174
1175 LinkNode *node;
1176
1177 /* direction is arbitrary, could be swapped */
1178 v_start = e->v1;
1179 v_end = e->v2;
1180
1181 if (v_ls_base->list_len > 1) {
1182 edge_verts_sort(v_start->co, v_ls_base);
1183 }
1184
1185# ifdef USE_DUMP
1186 printf("# SPLITTING EDGE: %d, %u\n", BM_elem_index_get(e), v_ls_base->list_len);
1187# endif
1188 /* intersect */
1189 is_wire = BLI_gset_haskey(s.wire_edges, e);
1190
1191# ifdef USE_PARANOID
1192 for (node = v_ls_base->list; node; node = node->next) {
1193 BMVert *_v = node->link;
1194 BLI_assert(len_squared_v3v3(_v->co, e->v1->co) > s.epsilon.eps_sq);
1195 BLI_assert(len_squared_v3v3(_v->co, e->v2->co) > s.epsilon.eps_sq);
1196 }
1197# endif
1198
1199 v_prev = v_start;
1200
1201 for (node = v_ls_base->list; node; node = node->next) {
1202 BMVert *vi = static_cast<BMVert *>(node->link);
1203 const float fac = line_point_factor_v3(vi->co, e->v1->co, e->v2->co);
1204
1205 if (BM_vert_in_edge(e, v_prev)) {
1206 BMEdge *e_split;
1207 v_prev = BM_edge_split(bm, e, v_prev, &e_split, clamp_f(fac, 0.0f, 1.0f));
1208 BLI_assert(BM_vert_in_edge(e, v_end));
1209
1210 if (!BM_edge_exists(v_prev, vi) && !BM_vert_splice_check_double(v_prev, vi) &&
1211 !BM_vert_pair_share_face_check(v_prev, vi))
1212 {
1213 BM_vert_splice(bm, vi, v_prev);
1214 }
1215 else {
1216 copy_v3_v3(v_prev->co, vi->co);
1217 }
1218 v_prev = vi;
1219 if (is_wire) {
1220 BLI_gset_insert(s.wire_edges, e_split);
1221 }
1222 }
1223 }
1224 UNUSED_VARS_NDEBUG(v_end);
1225 }
1226 }
1227#endif
1228
1229/* important to handle before edgenet */
1230#ifdef USE_DISSOLVE
1231 if (use_dissolve && (boolean_mode == BMESH_ISECT_BOOLEAN_NONE)) {
1232 /* first pass */
1233 BMVert *(*splice_ls)[2];
1234 STACK_DECLARE(splice_ls);
1235 LinkNode *node;
1236
1237 for (node = s.vert_dissolve; node; node = node->next) {
1238 BMVert *v = static_cast<BMVert *>(node->link);
1240 if (!BM_vert_is_edge_pair(v)) {
1242 }
1243 }
1244 }
1245
1246 splice_ls = static_cast<BMVert *(*)[2]>(
1247 MEM_mallocN(BLI_gset_len(s.wire_edges) * sizeof(*splice_ls), __func__));
1248 STACK_INIT(splice_ls, BLI_gset_len(s.wire_edges));
1249
1250 for (node = s.vert_dissolve; node; node = node->next) {
1251 BMEdge *e_pair[2];
1252 BMVert *v = static_cast<BMVert *>(node->link);
1253 BMVert *v_a, *v_b;
1254
1256 continue;
1257 }
1258
1259 /* get chain */
1260 e_pair[0] = v->e;
1261 e_pair[1] = BM_DISK_EDGE_NEXT(v->e, v);
1262
1263 if (BM_elem_flag_test(e_pair[0], BM_ELEM_TAG) || BM_elem_flag_test(e_pair[1], BM_ELEM_TAG)) {
1264 continue;
1265 }
1266
1267 /* It's possible the vertex to dissolve is an edge on an existing face
1268 * that doesn't divide the face, therefor the edges are not wire
1269 * and shouldn't be handled here, see: #63787. */
1270 if (!BLI_gset_haskey(s.wire_edges, e_pair[0]) || !BLI_gset_haskey(s.wire_edges, e_pair[1])) {
1271 continue;
1272 }
1273
1274 v_a = BM_edge_other_vert(e_pair[0], v);
1275 v_b = BM_edge_other_vert(e_pair[1], v);
1276
1277 /* simple case */
1279 /* only start on an edge-case */
1280 /* pass */
1281 }
1282 else if (!BM_elem_flag_test(v_a, BM_ELEM_TAG) && !BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
1283 /* simple case, single edge spans face */
1284 BMVert **splice_pair;
1285 BM_elem_flag_enable(e_pair[1], BM_ELEM_TAG);
1286 splice_pair = STACK_PUSH_RET(splice_ls);
1287 splice_pair[0] = v;
1288 splice_pair[1] = v_b;
1289# ifdef USE_DUMP
1290 printf("# Simple Case!\n");
1291# endif
1292 }
1293 else {
1294# ifdef USE_PARANOID
1295 BMEdge *e_keep;
1296# endif
1297 BMEdge *e;
1298 BMEdge *e_step;
1299 BMVert *v_step;
1300
1301 /* walk the chain! */
1302 if (BM_elem_flag_test(v_a, BM_ELEM_TAG)) {
1303 e = e_pair[0];
1304# ifdef USE_PARANOID
1305 e_keep = e_pair[1];
1306# endif
1307 }
1308 else {
1309 std::swap(v_a, v_b);
1310 e = e_pair[1];
1311# ifdef USE_PARANOID
1312 e_keep = e_pair[0];
1313# endif
1314 }
1315
1316 /* WALK */
1317 v_step = v;
1318 e_step = e;
1319
1320 while (true) {
1321 BMEdge *e_next;
1322 BMVert *v_next;
1323
1324 v_next = BM_edge_other_vert(e_step, v_step);
1326 if (!BM_elem_flag_test(v_next, BM_ELEM_TAG)) {
1327 BMVert **splice_pair;
1328# ifdef USE_PARANOID
1329 BLI_assert(e_step != e_keep);
1330# endif
1331 splice_pair = STACK_PUSH_RET(splice_ls);
1332 splice_pair[0] = v;
1333 splice_pair[1] = v_next;
1334 break;
1335 }
1336
1337 e_next = bm_vert_other_edge(v_next, e_step);
1338 e_step = e_next;
1339 v_step = v_next;
1341# ifdef USE_PARANOID
1342 BLI_assert(e_step != e_keep);
1343# endif
1344# ifdef USE_DUMP
1345 printf("# walk step %p %p\n", e_next, v_next);
1346# endif
1347 }
1348# ifdef USE_PARANOID
1350# endif
1351 }
1352 }
1353
1354 /* Remove edges! */
1355 {
1356 GHashIterator gh_iter;
1357
1358 GHASH_ITER (gh_iter, s.face_edges) {
1359 LinkBase *e_ls_base = static_cast<LinkBase *>(BLI_ghashIterator_getValue(&gh_iter));
1360 LinkNode **node_prev_p;
1361
1362 node_prev_p = &e_ls_base->list;
1363 for (node = e_ls_base->list; node; node = node->next) {
1364 BMEdge *e = static_cast<BMEdge *>(node->link);
1366 /* allocated by arena, don't free */
1367 *node_prev_p = node->next;
1368 e_ls_base->list_len--;
1369 }
1370 else {
1371 node_prev_p = &node->next;
1372 }
1373 }
1374 }
1375 }
1376
1377 {
1378 BMIter eiter;
1379 BMEdge *e, *e_next;
1380
1381 BM_ITER_MESH_MUTABLE (e, e_next, &eiter, bm, BM_EDGES_OF_MESH) {
1383
1384 /* in rare and annoying cases,
1385 * there can be faces from 's.face_edges' removed by the edges.
1386 * These are degenerate cases, so just make sure we don't reference the faces again. */
1387 if (e->l) {
1388 BMLoop *l_iter = e->l;
1389 BMFace **faces;
1390
1391 faces = bm->ftable;
1392
1393 do {
1394 const int f_index = BM_elem_index_get(l_iter->f);
1395 if (f_index >= 0) {
1396 BLI_assert(f_index < totface_orig);
1397 /* we could check if these are in: 's.face_edges', but easier just to remove */
1398 faces[f_index] = nullptr;
1399 }
1400 } while ((l_iter = l_iter->radial_next) != e->l);
1401 }
1402
1403 BLI_gset_remove(s.wire_edges, e, nullptr);
1404 BM_edge_kill(bm, e);
1405 }
1406 }
1407 }
1408
1409 /* Remove verts! */
1410 {
1411 GSet *verts_invalid = BLI_gset_ptr_new(__func__);
1412
1413 for (node = s.vert_dissolve; node; node = node->next) {
1414 /* arena allocated, don't free */
1415 BMVert *v = static_cast<BMVert *>(node->link);
1417 if (!v->e) {
1418 BLI_gset_add(verts_invalid, v);
1419 BM_vert_kill(bm, v);
1420 }
1421 }
1422 }
1423
1424 {
1425 uint i;
1426 for (i = 0; i < STACK_SIZE(splice_ls); i++) {
1427 if (!BLI_gset_haskey(verts_invalid, splice_ls[i][0]) &&
1428 !BLI_gset_haskey(verts_invalid, splice_ls[i][1]))
1429 {
1430 if (!BM_edge_exists(UNPACK2(splice_ls[i])) &&
1432 {
1433 BM_vert_splice(bm, splice_ls[i][1], splice_ls[i][0]);
1434 }
1435 }
1436 }
1437 }
1438
1439 BLI_gset_free(verts_invalid, nullptr);
1440 }
1441
1442 MEM_freeN(splice_ls);
1443 }
1444#endif /* USE_DISSOLVE */
1445
1446/* now split faces */
1447#ifdef USE_NET
1448 {
1449 GHashIterator gh_iter;
1450 BMFace **faces;
1451
1452 MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
1453
1454 faces = bm->ftable;
1455
1456 GHASH_ITER (gh_iter, s.face_edges) {
1457 const int f_index = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter));
1458 BMFace *f;
1459 LinkBase *e_ls_base = static_cast<LinkBase *>(BLI_ghashIterator_getValue(&gh_iter));
1460
1461 BLI_assert(f_index >= 0 && f_index < totface_orig);
1462
1463 f = faces[f_index];
1464 if (UNLIKELY(f == nullptr)) {
1465 continue;
1466 }
1467
1468 BLI_assert(BM_elem_index_get(f) == f_index);
1469
1471 bm, f, e_ls_base, use_island_connect, use_partial_connect, mem_arena_edgenet);
1472
1473 BLI_memarena_clear(mem_arena_edgenet);
1474 }
1475
1476 BLI_memarena_free(mem_arena_edgenet);
1477 }
1478#else
1479 UNUSED_VARS(use_island_connect);
1480#endif /* USE_NET */
1481 (void)totface_orig;
1482
1483#ifdef USE_SEPARATE
1484 if (use_separate) {
1485 GSetIterator gs_iter;
1486
1488
1489 GSET_ITER (gs_iter, s.wire_edges) {
1490 BMEdge *e = static_cast<BMEdge *>(BLI_gsetIterator_getKey(&gs_iter));
1492 }
1493
1494 BM_mesh_edgesplit(bm, false, true, false);
1495 }
1496 else if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE || use_edge_tag) {
1497 GSetIterator gs_iter;
1498
1499 /* no need to clear for boolean */
1500
1501 GSET_ITER (gs_iter, s.wire_edges) {
1502 BMEdge *e = static_cast<BMEdge *>(BLI_gsetIterator_getKey(&gs_iter));
1504 }
1505 }
1506#else
1507 (void)use_separate;
1508#endif /* USE_SEPARATE */
1509
1510 if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
1511 BVHTree *tree_pair[2] = {tree_a, tree_b};
1512
1513 /* group vars */
1514 int *groups_array;
1515 int (*group_index)[2];
1516 int group_tot;
1517 int i;
1518 BMFace **ftable;
1519
1521 ftable = bm->ftable;
1522
1523 /* wrap the face-test callback to make it into an edge-loop delimiter */
1524 LoopFilterWrap user_data_wrap{};
1525 user_data_wrap.test_fn = test_fn;
1526 user_data_wrap.user_data = user_data;
1527
1528 groups_array = MEM_malloc_arrayN<int>(size_t(bm->totface), __func__);
1529 group_tot = BM_mesh_calc_face_groups(
1530 bm, groups_array, &group_index, bm_loop_filter_fn, nullptr, &user_data_wrap, 0, BM_EDGE);
1531
1532#ifdef USE_DUMP
1533 printf("%s: Total face-groups: %d\n", __func__, group_tot);
1534#endif
1535
1536 /* Check if island is inside/outside */
1537 for (i = 0; i < group_tot; i++) {
1538 int fg = group_index[i][0];
1539 int fg_end = group_index[i][1] + fg;
1540 bool do_remove, do_flip;
1541
1542 {
1543 /* For now assume this is an OK face to test with (not degenerate!) */
1544 BMFace *f = ftable[groups_array[fg]];
1545 float co[3];
1546 int hits;
1547 int side = test_fn(f, user_data);
1548
1549 if (side == -1) {
1550 continue;
1551 }
1552 BLI_assert(ELEM(side, 0, 1));
1553 side = !side;
1554
1555 // BM_face_calc_center_median(f, co);
1557
1558 hits = isect_bvhtree_point_v3(tree_pair[side], looptri_coords, co);
1559
1560 switch (boolean_mode) {
1562 do_remove = ((hits & 1) != 1);
1563 do_flip = false;
1564 break;
1566 do_remove = ((hits & 1) == 1);
1567 do_flip = false;
1568 break;
1570 do_remove = ((hits & 1) == 1) == side;
1571 do_flip = (side == 0);
1572 break;
1573 }
1574 }
1575
1576 if (do_remove) {
1577 for (; fg != fg_end; fg++) {
1578 /* postpone killing the face since we access below, mark instead */
1579 // BM_face_kill_loose(bm, ftable[groups_array[fg]]);
1580 ftable[groups_array[fg]]->mat_nr = -1;
1581 }
1582 }
1583 else if (do_flip) {
1584 for (; fg != fg_end; fg++) {
1585 BM_face_normal_flip(bm, ftable[groups_array[fg]]);
1586 }
1587 }
1588
1589 has_edit_boolean |= (do_flip || do_remove);
1590 }
1591
1592 MEM_freeN(groups_array);
1593 MEM_freeN(group_index);
1594
1595#ifdef USE_DISSOLVE
1596 /* We have dissolve code above, this is alternative logic,
1597 * we need to do it after the boolean is executed. */
1598 if (use_dissolve) {
1599 LinkNode *node;
1600 for (node = s.vert_dissolve; node; node = node->next) {
1601 BMVert *v = static_cast<BMVert *>(node->link);
1602 if (BM_vert_is_edge_pair(v)) {
1603 /* we won't create degenerate faces from this */
1604 bool ok = true;
1605
1606 /* would we create a 2-sided-face?
1607 * if so, don't dissolve this since we may */
1608 if (v->e->l) {
1609 BMLoop *l_iter = v->e->l;
1610 do {
1611 if (l_iter->f->len == 3) {
1612 ok = false;
1613 break;
1614 }
1615 } while ((l_iter = l_iter->radial_next) != v->e->l);
1616 }
1617
1618 if (ok) {
1619 BM_vert_collapse_edge(bm, v->e, v, true, false, false);
1620 }
1621 }
1622 }
1623 }
1624#endif
1625
1626 {
1627 int tot = bm->totface;
1628 for (i = 0; i < tot; i++) {
1629 if (ftable[i]->mat_nr == -1) {
1630 BM_face_kill_loose(bm, ftable[i]);
1631 }
1632 }
1633 }
1634 }
1635
1636 if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
1637 MEM_freeN(looptri_coords);
1638
1639 /* no booleans, just free immediate */
1640 BLI_bvhtree_free(tree_a);
1641 if (tree_a != tree_b) {
1642 BLI_bvhtree_free(tree_b);
1643 }
1644 }
1645
1646 has_edit_isect = (BLI_ghash_len(s.face_edges) != 0);
1647
1648 /* cleanup */
1649 BLI_ghash_free(s.edgetri_cache, nullptr, nullptr);
1650
1651 BLI_ghash_free(s.edge_verts, nullptr, nullptr);
1652 BLI_ghash_free(s.face_edges, nullptr, nullptr);
1653 BLI_gset_free(s.wire_edges, nullptr);
1654
1656
1657 /* It's unlikely the selection history is useful at this point,
1658 * if this is not called this array would need to be validated, see: #86799. */
1660
1661 return (has_edit_isect || has_edit_boolean);
1662}
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:18
#define BLI_assert(a)
Definition BLI_assert.h:46
struct GSet GSet
Definition BLI_ghash.h:337
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:295
GSet * BLI_gset_ptr_new(const char *info)
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
#define BLI_ghashutil_inthash_v4_cmp
Definition BLI_ghash.h:598
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
#define GHASH_ITER(gh_iter_, ghash_)
Definition BLI_ghash.h:318
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:686
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:954
void BLI_gset_insert(GSet *gs, void *key)
Definition BLI_ghash.cc:959
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition BLI_ghash.h:455
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:702
#define GSET_ITER(gs_iter_, gset_)
Definition BLI_ghash.h:468
#define BLI_ghashutil_inthash_v4_p
Definition BLI_ghash.h:589
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
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
GHash * BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:752
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.cc:966
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.cc:999
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
#define BVH_RAYCAST_DIST_MAX
#define USE_KDOPBVH_WATERTIGHT
@ BVH_OVERLAP_USE_THREADING
@ BVH_OVERLAP_RETURN_PAIRS
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_ray_cast(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_fff(float a, float b, float c)
bool isect_line_segment_tri_epsilon_v3(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2], float epsilon)
int isect_line_line_epsilon_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float r_i1[3], float r_i2[3], float epsilon)
bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3], float r_isect_co[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])
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:41
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)
void print_v3(const char *str, const float v[3])
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
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE float normalize_v3(float n[3])
void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3])
#define BLI_MEMARENA_STD_BUFSIZE
MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
void BLI_memarena_free(MemArena *ma) ATTR_NONNULL(1)
void * BLI_memarena_alloc(MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
int BLI_sortutil_cmp_float(const void *a_, const void *b_)
Definition sort_utils.cc:25
unsigned int uint
#define UNPACK2(a)
#define UNPACK3_EX(pre, a, post)
#define UNPACK4(a)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define POINTER_FROM_INT(i)
#define UNUSED_VARS_NDEBUG(...)
#define POINTER_AS_INT(i)
#define UNPACK3(a)
#define UNLIKELY(x)
#define ELEM(...)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
#define STACK_PUSH_RET(stack)
Read Guarded memory(de)allocation.
#define BM_DISK_EDGE_NEXT(e, v)
@ BM_ELEM_TAG
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
void BM_vert_kill(BMesh *bm, BMVert *v)
void BM_face_kill_loose(BMesh *bm, BMFace *f)
void BM_edge_kill(BMesh *bm, BMEdge *e)
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition bmesh_core.cc:41
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.
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
eBMCreateFlag
Definition bmesh_core.hh:27
void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, const bool copy_select)
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
#define KEY_EDGE_TRI_ORDER(k)
static bool bm_loop_filter_fn(const BMLoop *l, void *user_data)
static void raycast_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *)
static BMVert * bm_isect_edge_tri(ISectState *s, BMVert *e_v0, BMVert *e_v1, BMVert *t[3], const int t_index, const float *t_cos[3], const float t_nor[3], enum ISectType *r_side)
static void bm_isect_tri_tri(ISectState *s, int a_index, int b_index, const std::array< BMLoop *, 3 > &a, const std::array< BMLoop *, 3 > &b, bool no_shared)
static bool ghash_insert_link(GHash *gh, void *key, void *val, bool use_test, MemArena *mem_arena)
#define KEY_SET(k, i0, i1, i2, i3)
bool BM_mesh_intersect(BMesh *bm, const blender::Span< std::array< BMLoop *, 3 > > looptris, int(*test_fn)(BMFace *f, void *user_data), void *user_data, const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect, const bool use_partial_connect, const bool use_edge_tag, const int boolean_mode, const float eps)
#define STACK_PUSH_TEST_B(ele)
static void face_edges_add(ISectState *s, const int f_index, BMEdge *e, const bool use_test)
#define VERT_VISIT_B
#define USE_SPLICE
static enum ISectType intersect_line_tri(const float p0[3], const float p1[3], const float *t_cos[3], const float t_nor[3], float r_ix[3], const ISectEpsilon *e)
#define STACK_PUSH_TEST_A(ele)
static void face_edges_split(BMesh *bm, BMFace *f, LinkBase *e_ls_base, bool use_island_connect, bool use_partial_connect, MemArena *mem_arena_edgenet)
static void tri_v3_scale(float v1[3], float v2[3], float v3[3], const float t)
ISectType
@ IX_EDGE_TRI_EDGE2
@ IX_EDGE_TRI_EDGE1
@ IX_EDGE_TRI_EDGE0
@ IX_TOT
@ IX_EDGE_TRI
@ IX_NONE
#define USE_NET
#define VERT_VISIT_A
static void edge_verts_sort(const float co[3], LinkBase *v_ls_base)
static void edge_verts_add(ISectState *s, BMEdge *e, BMVert *v, const bool use_test)
static void vert_dissolve_add(ISectState *s, BMVert *v)
static int isect_bvhtree_point_v3(BVHTree *tree, const float **looptris, const float co[3])
static BMEdge * bm_vert_other_edge(BMVert *v, BMEdge *e)
@ BMESH_ISECT_BOOLEAN_DIFFERENCE
@ BMESH_ISECT_BOOLEAN_NONE
@ BMESH_ISECT_BOOLEAN_UNION
@ BMESH_ISECT_BOOLEAN_ISECT
@ BM_EDGES_OF_MESH
#define BM_ITER_MESH_MUTABLE(ele, ele_next, iter, bm, itype)
BMesh const char void * data
BMesh * bm
void BM_select_history_clear(BMesh *bm)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
BMEdge * BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces, const bool kill_duplicate_faces)
Vert Collapse Faces.
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
void BM_face_normal_flip(BMesh *bm, BMFace *f)
bool BM_face_split_edgenet_connect_islands(BMesh *bm, BMFace *f, BMEdge **edge_net_init, const uint edge_net_init_len, bool use_partial_connect, MemArena *mem_arena, BMEdge ***r_edge_net_new, uint *r_edge_net_new_len)
bool BM_face_split_edgenet(BMesh *bm, BMFace *f, BMEdge **edge_net, const int edge_net_len, blender::Vector< BMFace * > *r_face_arr)
#define BM_ELEM_API_FLAG_DISABLE(element, f)
#define BM_ELEM_API_FLAG_TEST(element, f)
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b)
int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int(**r_group_index)[2], BMLoopFilterFunc filter_fn, BMLoopPairFilterFunc filter_pair_fn, void *user_data, const char hflag_test, const char htype_step)
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
bool BM_face_share_edge_check(BMFace *f_a, BMFace *f_b)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
bool BM_vert_is_edge_pair(const BMVert *v)
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
void append(const T &value)
int64_t size() const
bool is_empty() const
KDTree_3d * tree
#define printf(...)
#define cos
static MemArena * mem_arena
Definition makesdna.cc:62
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static char faces[256]
const btScalar eps
Definition poly34.cpp:11
#define fabsf
short mat_nr
BMHeader head
struct BMLoop * radial_next
struct BMFace * f
float co[3]
BMFace ** ftable
float origin[3]
float direction[3]
ISectEpsilon epsilon
MemArena * mem_arena
GHash * edgetri_cache
LinkNode * vert_dissolve
LinkNode * list
void * link
struct LinkNode * next
int(* test_fn)(BMFace *f, void *user_data)
blender::Vector< float, 64 > * z_buffer
const float ** looptris
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:145