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