Blender  V3.3
bmesh_core.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
9 #include "MEM_guardedalloc.h"
10 
11 #include "BLI_alloca.h"
12 #include "BLI_array.h"
13 #include "BLI_linklist_stack.h"
14 #include "BLI_math_vector.h"
15 #include "BLI_utildefines_stack.h"
16 
17 #include "BLT_translation.h"
18 
19 #include "DNA_meshdata_types.h"
20 
21 #include "BKE_customdata.h"
22 #include "BKE_mesh.h"
23 
24 #include "bmesh.h"
25 #include "intern/bmesh_private.h"
26 
27 /* use so valgrinds memcheck alerts us when undefined index is used.
28  * TESTING ONLY! */
29 // #define USE_DEBUG_INDEX_MEMCHECK
30 
31 #ifdef USE_DEBUG_INDEX_MEMCHECK
32 # define DEBUG_MEMCHECK_INDEX_INVALIDATE(ele) \
33  { \
34  int undef_idx; \
35  BM_elem_index_set(ele, undef_idx); /* set_ok_invalid */ \
36  } \
37  (void)0
38 
39 #endif
40 
42  const float co[3],
43  const BMVert *v_example,
44  const eBMCreateFlag create_flag)
45 {
47 
48  BLI_assert((v_example == NULL) || (v_example->head.htype == BM_VERT));
49  BLI_assert(!(create_flag & 1));
50 
51  /* --- assign all members --- */
52  v->head.data = NULL;
53 
54 #ifdef USE_DEBUG_INDEX_MEMCHECK
55  DEBUG_MEMCHECK_INDEX_INVALIDATE(v);
56 #else
57  BM_elem_index_set(v, -1); /* set_ok_invalid */
58 #endif
59 
60  v->head.htype = BM_VERT;
61  v->head.hflag = 0;
62  v->head.api_flag = 0;
63 
64  /* allocate flags */
65  if (bm->use_toolflags) {
67  }
68 
69  /* 'v->no' is handled by BM_elem_attrs_copy */
70  if (co) {
71  copy_v3_v3(v->co, co);
72  }
73  else {
74  zero_v3(v->co);
75  }
76  /* 'v->no' set below */
77 
78  v->e = NULL;
79  /* --- done --- */
80 
81  /* disallow this flag for verts - its meaningless */
82  BLI_assert((create_flag & BM_CREATE_NO_DOUBLE) == 0);
83 
84  /* may add to middle of the pool */
88 
89  bm->totvert++;
90 
91  if (!(create_flag & BM_CREATE_SKIP_CD)) {
92  if (v_example) {
93  int *keyi;
94 
95  /* handles 'v->no' too */
96  BM_elem_attrs_copy(bm, bm, v_example, v);
97 
98  /* exception: don't copy the original shapekey index */
100  if (keyi) {
101  *keyi = ORIGINDEX_NONE;
102  }
103  }
104  else {
106  zero_v3(v->no);
107  }
108  }
109  else {
110  if (v_example) {
111  copy_v3_v3(v->no, v_example->no);
112  }
113  else {
114  zero_v3(v->no);
115  }
116  }
117 
119 
120  return v;
121 }
122 
124  BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
125 {
126  BMEdge *e;
127 
128  BLI_assert(v1 != v2);
129  BLI_assert(v1->head.htype == BM_VERT && v2->head.htype == BM_VERT);
130  BLI_assert((e_example == NULL) || (e_example->head.htype == BM_EDGE));
131  BLI_assert(!(create_flag & 1));
132 
133  if ((create_flag & BM_CREATE_NO_DOUBLE) && (e = BM_edge_exists(v1, v2))) {
134  return e;
135  }
136 
138 
139  /* --- assign all members --- */
140  e->head.data = NULL;
141 
142 #ifdef USE_DEBUG_INDEX_MEMCHECK
143  DEBUG_MEMCHECK_INDEX_INVALIDATE(e);
144 #else
145  BM_elem_index_set(e, -1); /* set_ok_invalid */
146 #endif
147 
148  e->head.htype = BM_EDGE;
150  e->head.api_flag = 0;
151 
152  /* allocate flags */
153  if (bm->use_toolflags) {
155  }
156 
157  e->v1 = v1;
158  e->v2 = v2;
159  e->l = NULL;
160 
161  memset(&e->v1_disk_link, 0, sizeof(BMDiskLink[2]));
162  /* --- done --- */
163 
164  bmesh_disk_edge_append(e, e->v1);
165  bmesh_disk_edge_append(e, e->v2);
166 
167  /* may add to middle of the pool */
171 
172  bm->totedge++;
173 
174  if (!(create_flag & BM_CREATE_SKIP_CD)) {
175  if (e_example) {
176  BM_elem_attrs_copy(bm, bm, e_example, e);
177  }
178  else {
180  }
181  }
182 
184 
185  return e;
186 }
187 
194  BMVert *v,
195  BMEdge *e,
196  BMFace *f,
197  const BMLoop *l_example,
198  const eBMCreateFlag create_flag)
199 {
200  BMLoop *l = NULL;
201 
203 
204  BLI_assert((l_example == NULL) || (l_example->head.htype == BM_LOOP));
205  BLI_assert(!(create_flag & 1));
206 
207 #ifndef NDEBUG
208  if (l_example) {
209  /* ensure passing a loop is either sharing the same vertex, or entirely disconnected
210  * use to catch mistake passing in loop offset-by-one. */
211  BLI_assert((v == l_example->v) || !ELEM(v, l_example->prev->v, l_example->next->v));
212  }
213 #endif
214 
215  /* --- assign all members --- */
216  l->head.data = NULL;
217 
218 #ifdef USE_DEBUG_INDEX_MEMCHECK
219  DEBUG_MEMCHECK_INDEX_INVALIDATE(l);
220 #else
221  BM_elem_index_set(l, -1); /* set_ok_invalid */
222 #endif
223 
224  l->head.htype = BM_LOOP;
225  l->head.hflag = 0;
226  l->head.api_flag = 0;
227 
228  l->v = v;
229  l->e = e;
230  l->f = f;
231 
232  l->radial_next = NULL;
233  l->radial_prev = NULL;
234  l->next = NULL;
235  l->prev = NULL;
236  /* --- done --- */
237 
238  /* may add to middle of the pool */
241 
242  bm->totloop++;
243 
244  if (!(create_flag & BM_CREATE_SKIP_CD)) {
245  if (l_example) {
246  /* no need to copy attrs, just handle customdata */
247  // BM_elem_attrs_copy(bm, bm, l_example, l);
249  CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_example->head.data, &l->head.data);
250  }
251  else {
253  }
254  }
255 
256  return l;
257 }
258 
260  BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte, const eBMCreateFlag create_flag)
261 {
262 #ifdef USE_BMESH_HOLES
263  BMLoopList *lst = BLI_mempool_calloc(bm->looplistpool);
264 #endif
265  BMLoop *l = bm_loop_create(bm, startv, starte, f, NULL /* starte->l */, create_flag);
266 
267  bmesh_radial_loop_append(starte, l);
268 
269 #ifdef USE_BMESH_HOLES
270  lst->first = lst->last = l;
271  BLI_addtail(&f->loops, lst);
272 #else
273  f->l_first = l;
274 #endif
275 
276  return l;
277 }
278 
280  BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges)
281 {
283  BMEdge **edges = BLI_array_alloca(edges, f->len);
284  BMLoop *l_iter;
285  BMLoop *l_first;
286  BMLoop *l_copy;
287  BMFace *f_copy;
288  int i;
289 
290  BLI_assert((bm_dst == bm_src) || (copy_verts && copy_edges));
291 
292  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
293  i = 0;
294  do {
295  if (copy_verts) {
296  verts[i] = BM_vert_create(bm_dst, l_iter->v->co, l_iter->v, BM_CREATE_NOP);
297  }
298  else {
299  verts[i] = l_iter->v;
300  }
301  i++;
302  } while ((l_iter = l_iter->next) != l_first);
303 
304  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
305  i = 0;
306  do {
307  if (copy_edges) {
308  BMVert *v1, *v2;
309 
310  if (l_iter->e->v1 == verts[i]) {
311  v1 = verts[i];
312  v2 = verts[(i + 1) % f->len];
313  }
314  else {
315  v2 = verts[i];
316  v1 = verts[(i + 1) % f->len];
317  }
318 
319  edges[i] = BM_edge_create(bm_dst, v1, v2, l_iter->e, BM_CREATE_NOP);
320  }
321  else {
322  edges[i] = l_iter->e;
323  }
324  i++;
325  } while ((l_iter = l_iter->next) != l_first);
326 
327  f_copy = BM_face_create(bm_dst, verts, edges, f->len, NULL, BM_CREATE_SKIP_CD);
328 
329  BM_elem_attrs_copy(bm_src, bm_dst, f, f_copy);
330 
331  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
332  l_copy = BM_FACE_FIRST_LOOP(f_copy);
333  do {
334  BM_elem_attrs_copy(bm_src, bm_dst, l_iter, l_copy);
335  l_copy = l_copy->next;
336  } while ((l_iter = l_iter->next) != l_first);
337 
338  return f_copy;
339 }
340 
348 {
349  BMFace *f;
350 
351  f = BLI_mempool_alloc(bm->fpool);
352 
353  /* --- assign all members --- */
354  f->head.data = NULL;
355 #ifdef USE_DEBUG_INDEX_MEMCHECK
356  DEBUG_MEMCHECK_INDEX_INVALIDATE(f);
357 #else
358  BM_elem_index_set(f, -1); /* set_ok_invalid */
359 #endif
360 
361  f->head.htype = BM_FACE;
362  f->head.hflag = 0;
363  f->head.api_flag = 0;
364 
365  /* allocate flags */
366  if (bm->use_toolflags) {
368  }
369 
370 #ifdef USE_BMESH_HOLES
371  BLI_listbase_clear(&f->loops);
372 #else
373  f->l_first = NULL;
374 #endif
375  f->len = 0;
376  /* caller must initialize */
377  // zero_v3(f->no);
378  f->mat_nr = 0;
379  /* --- done --- */
380 
381  /* may add to middle of the pool */
385 
386  bm->totface++;
387 
388 #ifdef USE_BMESH_HOLES
389  f->totbounds = 0;
390 #endif
391 
392  return f;
393 }
394 
396  BMVert **verts,
397  BMEdge **edges,
398  const int len,
399  const BMFace *f_example,
400  const eBMCreateFlag create_flag)
401 {
402  BMFace *f = NULL;
403  BMLoop *l, *startl, *lastl;
404  int i;
405 
406  BLI_assert((f_example == NULL) || (f_example->head.htype == BM_FACE));
407  BLI_assert(!(create_flag & 1));
408 
409  if (len == 0) {
410  /* just return NULL for now */
411  return NULL;
412  }
413 
414  if (create_flag & BM_CREATE_NO_DOUBLE) {
415  /* Check if face already exists */
416  f = BM_face_exists(verts, len);
417  if (f != NULL) {
418  return f;
419  }
420  }
421 
423 
424  startl = lastl = bm_face_boundary_add(bm, f, verts[0], edges[0], create_flag);
425 
426  for (i = 1; i < len; i++) {
427  l = bm_loop_create(bm, verts[i], edges[i], f, NULL /* edges[i]->l */, create_flag);
428 
429  bmesh_radial_loop_append(edges[i], l);
430 
431  l->prev = lastl;
432  lastl->next = l;
433  lastl = l;
434  }
435 
436  startl->prev = lastl;
437  lastl->next = startl;
438 
439  f->len = len;
440 
441  if (!(create_flag & BM_CREATE_SKIP_CD)) {
442  if (f_example) {
443  BM_elem_attrs_copy(bm, bm, f_example, f);
444  }
445  else {
447  zero_v3(f->no);
448  }
449  }
450  else {
451  if (f_example) {
452  copy_v3_v3(f->no, f_example->no);
453  }
454  else {
455  zero_v3(f->no);
456  }
457  }
458 
459  BM_CHECK_ELEMENT(f);
460 
461  return f;
462 }
463 
465  BMVert **vert_arr,
466  const int len,
467  const BMFace *f_example,
468  const eBMCreateFlag create_flag,
469  const bool create_edges)
470 {
471  BMEdge **edge_arr = BLI_array_alloca(edge_arr, len);
472 
473  if (create_edges) {
474  BM_edges_from_verts_ensure(bm, edge_arr, vert_arr, len);
475  }
476  else {
477  if (BM_edges_from_verts(edge_arr, vert_arr, len) == false) {
478  return NULL;
479  }
480  }
481 
482  return BM_face_create(bm, vert_arr, edge_arr, len, f_example, create_flag);
483 }
484 
485 #ifndef NDEBUG
486 
487 int bmesh_elem_check(void *element, const char htype)
488 {
489  BMHeader *head = element;
490  enum {
491  IS_NULL = (1 << 0),
492  IS_WRONG_TYPE = (1 << 1),
493 
494  IS_VERT_WRONG_EDGE_TYPE = (1 << 2),
495 
496  IS_EDGE_NULL_DISK_LINK = (1 << 3),
497  IS_EDGE_WRONG_LOOP_TYPE = (1 << 4),
498  IS_EDGE_WRONG_FACE_TYPE = (1 << 5),
499  IS_EDGE_NULL_RADIAL_LINK = (1 << 6),
500  IS_EDGE_ZERO_FACE_LENGTH = (1 << 7),
501 
502  IS_LOOP_WRONG_FACE_TYPE = (1 << 8),
503  IS_LOOP_WRONG_EDGE_TYPE = (1 << 9),
504  IS_LOOP_WRONG_VERT_TYPE = (1 << 10),
505  IS_LOOP_VERT_NOT_IN_EDGE = (1 << 11),
506  IS_LOOP_NULL_CYCLE_LINK = (1 << 12),
507  IS_LOOP_ZERO_FACE_LENGTH = (1 << 13),
508  IS_LOOP_WRONG_FACE_LENGTH = (1 << 14),
509  IS_LOOP_WRONG_RADIAL_LENGTH = (1 << 15),
510 
511  IS_FACE_NULL_LOOP = (1 << 16),
512  IS_FACE_WRONG_LOOP_FACE = (1 << 17),
513  IS_FACE_NULL_EDGE = (1 << 18),
514  IS_FACE_NULL_VERT = (1 << 19),
515  IS_FACE_LOOP_VERT_NOT_IN_EDGE = (1 << 20),
516  IS_FACE_LOOP_WRONG_RADIAL_LENGTH = (1 << 21),
517  IS_FACE_LOOP_WRONG_DISK_LENGTH = (1 << 22),
518  IS_FACE_LOOP_DUPE_LOOP = (1 << 23),
519  IS_FACE_LOOP_DUPE_VERT = (1 << 24),
520  IS_FACE_LOOP_DUPE_EDGE = (1 << 25),
521  IS_FACE_WRONG_LENGTH = (1 << 26),
522  } err = 0;
523 
524  if (!element) {
525  return IS_NULL;
526  }
527 
528  if (head->htype != htype) {
529  return IS_WRONG_TYPE;
530  }
531 
532  switch (htype) {
533  case BM_VERT: {
534  BMVert *v = element;
535  if (v->e && v->e->head.htype != BM_EDGE) {
536  err |= IS_VERT_WRONG_EDGE_TYPE;
537  }
538  break;
539  }
540  case BM_EDGE: {
541  BMEdge *e = element;
542  if (e->v1_disk_link.prev == NULL || e->v2_disk_link.prev == NULL ||
543  e->v1_disk_link.next == NULL || e->v2_disk_link.next == NULL) {
544  err |= IS_EDGE_NULL_DISK_LINK;
545  }
546 
547  if (e->l && e->l->head.htype != BM_LOOP) {
548  err |= IS_EDGE_WRONG_LOOP_TYPE;
549  }
550  if (e->l && e->l->f->head.htype != BM_FACE) {
551  err |= IS_EDGE_WRONG_FACE_TYPE;
552  }
553  if (e->l && (e->l->radial_next == NULL || e->l->radial_prev == NULL)) {
554  err |= IS_EDGE_NULL_RADIAL_LINK;
555  }
556  if (e->l && e->l->f->len <= 0) {
557  err |= IS_EDGE_ZERO_FACE_LENGTH;
558  }
559  break;
560  }
561  case BM_LOOP: {
562  BMLoop *l = element, *l2;
563  int i;
564 
565  if (l->f->head.htype != BM_FACE) {
566  err |= IS_LOOP_WRONG_FACE_TYPE;
567  }
568  if (l->e->head.htype != BM_EDGE) {
569  err |= IS_LOOP_WRONG_EDGE_TYPE;
570  }
571  if (l->v->head.htype != BM_VERT) {
572  err |= IS_LOOP_WRONG_VERT_TYPE;
573  }
574  if (!BM_vert_in_edge(l->e, l->v)) {
575  fprintf(stderr,
576  "%s: fatal bmesh error (vert not in edge)! (bmesh internal error)\n",
577  __func__);
578  err |= IS_LOOP_VERT_NOT_IN_EDGE;
579  }
580 
581  if (l->radial_next == NULL || l->radial_prev == NULL) {
582  err |= IS_LOOP_NULL_CYCLE_LINK;
583  }
584  if (l->f->len <= 0) {
585  err |= IS_LOOP_ZERO_FACE_LENGTH;
586  }
587 
588  /* validate boundary loop -- invalid for hole loops, of course,
589  * but we won't be allowing those for a while yet */
590  l2 = l;
591  i = 0;
592  do {
593  if (i >= BM_NGON_MAX) {
594  break;
595  }
596 
597  i++;
598  } while ((l2 = l2->next) != l);
599 
600  if (i != l->f->len || l2 != l) {
601  err |= IS_LOOP_WRONG_FACE_LENGTH;
602  }
603 
605  err |= IS_LOOP_WRONG_RADIAL_LENGTH;
606  }
607 
608  break;
609  }
610  case BM_FACE: {
611  BMFace *f = element;
612  BMLoop *l_iter;
613  BMLoop *l_first;
614  int len = 0;
615 
616 # ifdef USE_BMESH_HOLES
617  if (!f->loops.first)
618 # else
619  if (!f->l_first)
620 # endif
621  {
622  err |= IS_FACE_NULL_LOOP;
623  }
624  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
625  do {
626  if (l_iter->f != f) {
627  fprintf(stderr,
628  "%s: loop inside one face points to another! (bmesh internal error)\n",
629  __func__);
630  err |= IS_FACE_WRONG_LOOP_FACE;
631  }
632 
633  if (!l_iter->e) {
634  err |= IS_FACE_NULL_EDGE;
635  }
636  if (!l_iter->v) {
637  err |= IS_FACE_NULL_VERT;
638  }
639  if (l_iter->e && l_iter->v) {
640  if (!BM_vert_in_edge(l_iter->e, l_iter->v) ||
641  !BM_vert_in_edge(l_iter->e, l_iter->next->v)) {
642  err |= IS_FACE_LOOP_VERT_NOT_IN_EDGE;
643  }
644 
645  if (!bmesh_radial_validate(bmesh_radial_length(l_iter), l_iter)) {
646  err |= IS_FACE_LOOP_WRONG_RADIAL_LENGTH;
647  }
648 
649  if (bmesh_disk_count_at_most(l_iter->v, 2) < 2) {
650  err |= IS_FACE_LOOP_WRONG_DISK_LENGTH;
651  }
652  }
653 
654  /* check for duplicates */
656  err |= IS_FACE_LOOP_DUPE_LOOP;
657  }
659  if (l_iter->v) {
660  if (BM_ELEM_API_FLAG_TEST(l_iter->v, _FLAG_ELEM_CHECK)) {
661  err |= IS_FACE_LOOP_DUPE_VERT;
662  }
664  }
665  if (l_iter->e) {
666  if (BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_ELEM_CHECK)) {
667  err |= IS_FACE_LOOP_DUPE_EDGE;
668  }
670  }
671 
672  len++;
673  } while ((l_iter = l_iter->next) != l_first);
674 
675  /* cleanup duplicates flag */
676  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
677  do {
679  if (l_iter->v) {
681  }
682  if (l_iter->e) {
684  }
685  } while ((l_iter = l_iter->next) != l_first);
686 
687  if (len != f->len) {
688  err |= IS_FACE_WRONG_LENGTH;
689  }
690  break;
691  }
692  default:
693  BLI_assert(0);
694  break;
695  }
696 
697  BMESH_ASSERT(err == 0);
698 
699  return err;
700 }
701 
702 #endif /* NDEBUG */
703 
709 {
710  bm->totvert--;
714 
716 
717  if (v->head.data) {
719  }
720 
721  if (bm->vtoolflagpool) {
723  }
725 }
726 
732 {
733  bm->totedge--;
737 
739 
740  if (e->head.data) {
742  }
743 
744  if (bm->etoolflagpool) {
746  }
748 }
749 
754 static void bm_kill_only_face(BMesh *bm, BMFace *f)
755 {
756  if (bm->act_face == f) {
757  bm->act_face = NULL;
758  }
759 
760  bm->totface--;
764 
766 
767  if (f->head.data) {
769  }
770 
771  if (bm->ftoolflagpool) {
772  BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f)->oflags);
773  }
775 }
776 
782 {
783  bm->totloop--;
786 
787  if (l->head.data) {
789  }
790 
792 }
793 
795 {
796  BMEdge **edges = BLI_array_alloca(edges, f->len);
797  BMLoop *l_iter;
798  BMLoop *l_first;
799  int i = 0;
800 
801  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
802  do {
803  edges[i++] = l_iter->e;
804  } while ((l_iter = l_iter->next) != l_first);
805 
806  for (i = 0; i < f->len; i++) {
807  BM_edge_kill(bm, edges[i]);
808  }
809 }
810 
812 {
814  BMLoop *l_iter;
815  BMLoop *l_first;
816  int i = 0;
817 
818  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
819  do {
820  verts[i++] = l_iter->v;
821  } while ((l_iter = l_iter->next) != l_first);
822 
823  for (i = 0; i < f->len; i++) {
824  BM_vert_kill(bm, verts[i]);
825  }
826 }
827 
829 {
830 #ifdef USE_BMESH_HOLES
831  BMLoopList *ls, *ls_next;
832 #endif
833 
834 #ifdef NDEBUG
835  /* check length since we may be removing degenerate faces */
836  if (f->len >= 3) {
837  BM_CHECK_ELEMENT(f);
838  }
839 #endif
840 
841 #ifdef USE_BMESH_HOLES
842  for (ls = f->loops.first; ls; ls = ls_next)
843 #else
844  if (f->l_first)
845 #endif
846  {
847  BMLoop *l_iter, *l_next, *l_first;
848 
849 #ifdef USE_BMESH_HOLES
850  ls_next = ls->next;
851  l_iter = l_first = ls->first;
852 #else
853  l_iter = l_first = f->l_first;
854 #endif
855 
856  do {
857  l_next = l_iter->next;
858 
859  bmesh_radial_loop_remove(l_iter->e, l_iter);
860  bm_kill_only_loop(bm, l_iter);
861 
862  } while ((l_iter = l_next) != l_first);
863 
864 #ifdef USE_BMESH_HOLES
865  BLI_mempool_free(bm->looplistpool, ls);
866 #endif
867  }
868 
869  bm_kill_only_face(bm, f);
870 }
871 
873 {
874 #ifdef USE_BMESH_HOLES
875  BMLoopList *ls, *ls_next;
876 #endif
877 
878  BM_CHECK_ELEMENT(f);
879 
880 #ifdef USE_BMESH_HOLES
881  for (ls = f->loops.first; ls; ls = ls_next)
882 #else
883  if (f->l_first)
884 #endif
885  {
886  BMLoop *l_iter, *l_next, *l_first;
887 
888 #ifdef USE_BMESH_HOLES
889  ls_next = ls->next;
890  l_iter = l_first = ls->first;
891 #else
892  l_iter = l_first = f->l_first;
893 #endif
894 
895  do {
896  BMEdge *e;
897  l_next = l_iter->next;
898 
899  e = l_iter->e;
900  bmesh_radial_loop_remove(e, l_iter);
901  bm_kill_only_loop(bm, l_iter);
902 
903  if (e->l == NULL) {
904  BMVert *v1 = e->v1, *v2 = e->v2;
905 
906  bmesh_disk_edge_remove(e, e->v1);
907  bmesh_disk_edge_remove(e, e->v2);
909 
910  if (v1->e == NULL) {
912  }
913  if (v2->e == NULL) {
915  }
916  }
917  } while ((l_iter = l_next) != l_first);
918 
919 #ifdef USE_BMESH_HOLES
920  BLI_mempool_free(bm->looplistpool, ls);
921 #endif
922  }
923 
924  bm_kill_only_face(bm, f);
925 }
926 
928 {
929  while (e->l) {
930  BM_face_kill(bm, e->l->f);
931  }
932 
933  bmesh_disk_edge_remove(e, e->v1);
934  bmesh_disk_edge_remove(e, e->v2);
935 
937 }
938 
940 {
941  while (v->e) {
942  BM_edge_kill(bm, v->e);
943  }
944 
946 }
947 
948 /********** private disk and radial cycle functions ********** */
949 
954 {
955  BMLoop *l_first = l;
956  int i = 0;
957 
958  do {
959  i++;
960  } while ((l = l->next) != l_first);
961 
962  return i;
963 }
964 
966  BMFace *f,
967  const int cd_loop_mdisp_offset,
968  const bool use_loop_mdisp_flip)
969 {
970  BMLoop *l_first = f->l_first;
971 
972  /* track previous cycles radial state */
973  BMEdge *e_prev = l_first->prev->e;
974  BMLoop *l_prev_radial_next = l_first->prev->radial_next;
975  BMLoop *l_prev_radial_prev = l_first->prev->radial_prev;
976  bool is_prev_boundary = l_prev_radial_next == l_prev_radial_next->radial_next;
977 
978  BMLoop *l_iter = l_first;
979  do {
980  BMEdge *e_iter = l_iter->e;
981  BMLoop *l_iter_radial_next = l_iter->radial_next;
982  BMLoop *l_iter_radial_prev = l_iter->radial_prev;
983  bool is_iter_boundary = l_iter_radial_next == l_iter_radial_next->radial_next;
984 
985 #if 0
986  bmesh_radial_loop_remove(e_iter, l_iter);
987  bmesh_radial_loop_append(e_prev, l_iter);
988 #else
989  /* inline loop reversal */
990  if (is_prev_boundary) {
991  /* boundary */
992  l_iter->radial_next = l_iter;
993  l_iter->radial_prev = l_iter;
994  }
995  else {
996  /* non-boundary, replace radial links */
997  l_iter->radial_next = l_prev_radial_next;
998  l_iter->radial_prev = l_prev_radial_prev;
999  l_prev_radial_next->radial_prev = l_iter;
1000  l_prev_radial_prev->radial_next = l_iter;
1001  }
1002 
1003  if (e_iter->l == l_iter) {
1004  e_iter->l = l_iter->next;
1005  }
1006  l_iter->e = e_prev;
1007 #endif
1008 
1009  SWAP(BMLoop *, l_iter->next, l_iter->prev);
1010 
1011  if (cd_loop_mdisp_offset != -1) {
1012  MDisps *md = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset);
1013  BKE_mesh_mdisp_flip(md, use_loop_mdisp_flip);
1014  }
1015 
1016  e_prev = e_iter;
1017  l_prev_radial_next = l_iter_radial_next;
1018  l_prev_radial_prev = l_iter_radial_prev;
1019  is_prev_boundary = is_iter_boundary;
1020 
1021  /* step to next (now swapped) */
1022  } while ((l_iter = l_iter->prev) != l_first);
1023 
1024 #ifndef NDEBUG
1025  /* validate radial */
1026  int i;
1027  for (i = 0, l_iter = l_first; i < f->len; i++, l_iter = l_iter->next) {
1028  BM_CHECK_ELEMENT(l_iter);
1029  BM_CHECK_ELEMENT(l_iter->e);
1030  BM_CHECK_ELEMENT(l_iter->v);
1031  BM_CHECK_ELEMENT(l_iter->f);
1032  }
1033 
1034  BM_CHECK_ELEMENT(f);
1035 #endif
1036 
1037  /* Loop indices are no more valid! */
1039 }
1040 
1041 static void bm_elements_systag_enable(void *veles, int tot, const char api_flag)
1042 {
1043  BMHeader **eles = veles;
1044  int i;
1045 
1046  for (i = 0; i < tot; i++) {
1047  BM_ELEM_API_FLAG_ENABLE((BMElemF *)eles[i], api_flag);
1048  }
1049 }
1050 
1051 static void bm_elements_systag_disable(void *veles, int tot, const char api_flag)
1052 {
1053  BMHeader **eles = veles;
1054  int i;
1055 
1056  for (i = 0; i < tot; i++) {
1057  BM_ELEM_API_FLAG_DISABLE((BMElemF *)eles[i], api_flag);
1058  }
1059 }
1060 
1061 static int bm_loop_systag_count_radial(BMLoop *l, const char api_flag)
1062 {
1063  BMLoop *l_iter = l;
1064  int i = 0;
1065  do {
1066  i += BM_ELEM_API_FLAG_TEST(l_iter->f, api_flag) ? 1 : 0;
1067  } while ((l_iter = l_iter->radial_next) != l);
1068 
1069  return i;
1070 }
1071 
1072 static int UNUSED_FUNCTION(bm_vert_systag_count_disk)(BMVert *v, const char api_flag)
1073 {
1074  BMEdge *e = v->e;
1075  int i = 0;
1076 
1077  if (!e) {
1078  return 0;
1079  }
1080 
1081  do {
1082  i += BM_ELEM_API_FLAG_TEST(e, api_flag) ? 1 : 0;
1083  } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
1084 
1085  return i;
1086 }
1087 
1092 static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag)
1093 {
1094  BMEdge *e = v->e;
1095 
1096  if (!e) {
1097  return false;
1098  }
1099 
1100  do {
1101  BMLoop *l = e->l;
1102 
1103  if (!l) {
1104  return false;
1105  }
1106 
1107  if (BM_edge_is_boundary(l->e)) {
1108  return false;
1109  }
1110 
1111  do {
1112  if (!BM_ELEM_API_FLAG_TEST(l->f, api_flag)) {
1113  return false;
1114  }
1115  } while ((l = l->radial_next) != e->l);
1116  } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
1117 
1118  return true;
1119 }
1120 
1121 /* Mid-level Topology Manipulation Functions */
1122 
1123 BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
1124 {
1125  BMFace *f, *f_new;
1126 #ifdef USE_BMESH_HOLES
1127  BMLoopList *lst;
1128  ListBase holes = {NULL, NULL};
1129 #endif
1130  BMLoop *l_iter;
1131  BMLoop *l_first;
1132  BMEdge **edges = NULL;
1133  BMEdge **deledges = NULL;
1134  BMVert **delverts = NULL;
1138  BMVert *v1 = NULL, *v2 = NULL;
1139  int i;
1140  const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
1141 
1142  if (UNLIKELY(!totface)) {
1143  BMESH_ASSERT(0);
1144  return NULL;
1145  }
1146 
1147  if (totface == 1) {
1148  return faces[0];
1149  }
1150 
1152 
1153  for (i = 0; i < totface; i++) {
1154  f = faces[i];
1155  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1156  do {
1157  int rlen = bm_loop_systag_count_radial(l_iter, _FLAG_JF);
1158 
1159  if (rlen > 2) {
1160  /* Input faces do not form a contiguous manifold region */
1161  goto error;
1162  }
1163  else if (rlen == 1) {
1164  BLI_array_append(edges, l_iter->e);
1165 
1166  if (!v1) {
1167  v1 = l_iter->v;
1168  v2 = BM_edge_other_vert(l_iter->e, l_iter->v);
1169  }
1170  }
1171  else if (rlen == 2) {
1172  const bool d1 = bm_vert_is_manifold_flagged(l_iter->e->v1, _FLAG_JF);
1173  const bool d2 = bm_vert_is_manifold_flagged(l_iter->e->v2, _FLAG_JF);
1174 
1175  if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) {
1176  /* don't remove an edge it makes up the side of another face
1177  * else this will remove the face as well - campbell */
1178  if (!BM_edge_face_count_is_over(l_iter->e, 2)) {
1179  if (do_del) {
1180  BLI_array_append(deledges, l_iter->e);
1181  }
1183  }
1184  }
1185  else {
1186  if (d1 && !BM_ELEM_API_FLAG_TEST(l_iter->e->v1, _FLAG_JF)) {
1187  if (do_del) {
1188  BLI_array_append(delverts, l_iter->e->v1);
1189  }
1190  BM_ELEM_API_FLAG_ENABLE(l_iter->e->v1, _FLAG_JF);
1191  }
1192 
1193  if (d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e->v2, _FLAG_JF)) {
1194  if (do_del) {
1195  BLI_array_append(delverts, l_iter->e->v2);
1196  }
1197  BM_ELEM_API_FLAG_ENABLE(l_iter->e->v2, _FLAG_JF);
1198  }
1199  }
1200  }
1201  } while ((l_iter = l_iter->next) != l_first);
1202 
1203 #ifdef USE_BMESH_HOLES
1204  for (lst = f->loops.first; lst; lst = lst->next) {
1205  if (lst == f->loops.first) {
1206  continue;
1207  }
1208 
1209  BLI_remlink(&f->loops, lst);
1210  BLI_addtail(&holes, lst);
1211  }
1212 #endif
1213  }
1214 
1215  /* create region face */
1216  f_new = BLI_array_len(edges) ?
1218  bm, v1, v2, edges, BLI_array_len(edges), faces[0], BM_CREATE_NOP) :
1219  NULL;
1220  if (UNLIKELY(f_new == NULL)) {
1221  /* Invalid boundary region to join faces */
1222  goto error;
1223  }
1224 
1225  /* copy over loop data */
1226  l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
1227  do {
1228  BMLoop *l2 = l_iter->radial_next;
1229 
1230  do {
1231  if (BM_ELEM_API_FLAG_TEST(l2->f, _FLAG_JF)) {
1232  break;
1233  }
1234  l2 = l2->radial_next;
1235  } while (l2 != l_iter);
1236 
1237  if (l2 != l_iter) {
1238  /* loops share an edge, shared vert depends on winding */
1239  if (l2->v != l_iter->v) {
1240  l2 = l2->next;
1241  }
1242  BLI_assert(l_iter->v == l2->v);
1243 
1244  BM_elem_attrs_copy(bm, bm, l2, l_iter);
1245  }
1246  } while ((l_iter = l_iter->next) != l_first);
1247 
1248 #ifdef USE_BMESH_HOLES
1249  /* add holes */
1250  BLI_movelisttolist(&f_new->loops, &holes);
1251 
1252  /* update loop face pointer */
1253  for (lst = f_new->loops.first; lst; lst = lst->next) {
1254  l_iter = l_first = lst->first;
1255  do {
1256  l_iter->f = f_new;
1257  } while ((l_iter = l_iter->next) != l_first);
1258  }
1259 #endif
1260 
1263 
1264  /* handle multi-res data */
1265  if (cd_loop_mdisp_offset != -1) {
1266  float f_center[3];
1267  float(*faces_center)[3] = BLI_array_alloca(faces_center, totface);
1268 
1269  BM_face_calc_center_median(f_new, f_center);
1270  for (i = 0; i < totface; i++) {
1271  BM_face_calc_center_median(faces[i], faces_center[i]);
1272  }
1273 
1274  l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
1275  do {
1276  for (i = 0; i < totface; i++) {
1278  bm, l_iter, faces[i], f_center, faces_center[i], cd_loop_mdisp_offset);
1279  }
1280  } while ((l_iter = l_iter->next) != l_first);
1281  }
1282 
1283  /* delete old geometry */
1284  if (do_del) {
1285  for (i = 0; i < BLI_array_len(deledges); i++) {
1286  BM_edge_kill(bm, deledges[i]);
1287  }
1288 
1289  for (i = 0; i < BLI_array_len(delverts); i++) {
1290  BM_vert_kill(bm, delverts[i]);
1291  }
1292  }
1293  else {
1294  /* otherwise we get both old and new faces */
1295  for (i = 0; i < totface; i++) {
1296  BM_face_kill(bm, faces[i]);
1297  }
1298  }
1299 
1300  BLI_array_free(edges);
1301  BLI_array_free(deledges);
1302  BLI_array_free(delverts);
1303 
1304  BM_CHECK_ELEMENT(f_new);
1305  return f_new;
1306 
1307 error:
1309  BLI_array_free(edges);
1310  BLI_array_free(deledges);
1311  BLI_array_free(delverts);
1312 
1313  return NULL;
1314 }
1315 
1317 {
1318  BMFace *f;
1319 #ifdef USE_BMESH_HOLES
1320  BMLoopList *lst;
1321 #endif
1322 
1324 
1325 #ifdef USE_BMESH_HOLES
1326  lst = BLI_mempool_calloc(bm->looplistpool);
1327  BLI_addtail(&f->loops, lst);
1328 #endif
1329 
1330 #ifdef USE_BMESH_HOLES
1331  f->totbounds = 1;
1332 #endif
1333 
1334  BM_elem_attrs_copy(bm, bm, f_example, f);
1335 
1336  return f;
1337 }
1338 
1340  BMFace *f,
1341  BMLoop *l_v1,
1342  BMLoop *l_v2,
1343  BMLoop **r_l,
1344 #ifdef USE_BMESH_HOLES
1345  ListBase *holes,
1346 #endif
1347  BMEdge *e_example,
1348  const bool no_double)
1349 {
1350 #ifdef USE_BMESH_HOLES
1351  BMLoopList *lst, *lst2;
1352 #else
1353  int first_loop_f1;
1354 #endif
1355 
1356  BMFace *f2;
1357  BMLoop *l_iter, *l_first;
1358  BMLoop *l_f1 = NULL, *l_f2 = NULL;
1359  BMEdge *e;
1360  BMVert *v1 = l_v1->v, *v2 = l_v2->v;
1361  int f1len, f2len;
1362 
1363  BLI_assert(f == l_v1->f && f == l_v2->f);
1364 
1365  /* allocate new edge between v1 and v2 */
1366  e = BM_edge_create(bm, v1, v2, e_example, no_double ? BM_CREATE_NO_DOUBLE : BM_CREATE_NOP);
1367 
1368  f2 = bm_face_create__sfme(bm, f);
1369  l_f1 = bm_loop_create(bm, v2, e, f, l_v2, 0);
1370  l_f2 = bm_loop_create(bm, v1, e, f2, l_v1, 0);
1371 
1372  l_f1->prev = l_v2->prev;
1373  l_f2->prev = l_v1->prev;
1374  l_v2->prev->next = l_f1;
1375  l_v1->prev->next = l_f2;
1376 
1377  l_f1->next = l_v1;
1378  l_f2->next = l_v2;
1379  l_v1->prev = l_f1;
1380  l_v2->prev = l_f2;
1381 
1382 #ifdef USE_BMESH_HOLES
1383  lst = f->loops.first;
1384  lst2 = f2->loops.first;
1385 
1386  lst2->first = lst2->last = l_f2;
1387  lst->first = lst->last = l_f1;
1388 #else
1389  /* find which of the faces the original first loop is in */
1390  l_iter = l_first = l_f1;
1391  first_loop_f1 = 0;
1392  do {
1393  if (l_iter == f->l_first) {
1394  first_loop_f1 = 1;
1395  }
1396  } while ((l_iter = l_iter->next) != l_first);
1397 
1398  if (first_loop_f1) {
1399  /* original first loop was in f1, find a suitable first loop for f2
1400  * which is as similar as possible to f1. the order matters for tools
1401  * such as duplifaces. */
1402  if (f->l_first->prev == l_f1) {
1403  f2->l_first = l_f2->prev;
1404  }
1405  else if (f->l_first->next == l_f1) {
1406  f2->l_first = l_f2->next;
1407  }
1408  else {
1409  f2->l_first = l_f2;
1410  }
1411  }
1412  else {
1413  /* original first loop was in f2, further do same as above */
1414  f2->l_first = f->l_first;
1415 
1416  if (f->l_first->prev == l_f2) {
1417  f->l_first = l_f1->prev;
1418  }
1419  else if (f->l_first->next == l_f2) {
1420  f->l_first = l_f1->next;
1421  }
1422  else {
1423  f->l_first = l_f1;
1424  }
1425  }
1426 #endif
1427 
1428  /* validate both loop */
1429  /* I don't know how many loops are supposed to be in each face at this point! FIXME */
1430 
1431  /* go through all of f2's loops and make sure they point to it properly */
1432  l_iter = l_first = BM_FACE_FIRST_LOOP(f2);
1433  f2len = 0;
1434  do {
1435  l_iter->f = f2;
1436  f2len++;
1437  } while ((l_iter = l_iter->next) != l_first);
1438 
1439  /* link up the new loops into the new edges radial */
1440  bmesh_radial_loop_append(e, l_f1);
1441  bmesh_radial_loop_append(e, l_f2);
1442 
1443  f2->len = f2len;
1444 
1445  f1len = 0;
1446  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1447  do {
1448  f1len++;
1449  } while ((l_iter = l_iter->next) != l_first);
1450 
1451  f->len = f1len;
1452 
1453  if (r_l) {
1454  *r_l = l_f2;
1455  }
1456 
1457 #ifdef USE_BMESH_HOLES
1458  if (holes) {
1459  BLI_movelisttolist(&f2->loops, holes);
1460  }
1461  else {
1462  /* this code is not significant until holes actually work */
1463  // printf("WARNING: call to split face euler without holes argument; holes will be tossed.\n");
1464  for (lst = f->loops.last; lst != f->loops.first; lst = lst2) {
1465  lst2 = lst->prev;
1466  BLI_mempool_free(bm->looplistpool, lst);
1467  }
1468  }
1469 #endif
1470 
1472  BM_CHECK_ELEMENT(f);
1473  BM_CHECK_ELEMENT(f2);
1474 
1475  return f2;
1476 }
1477 
1479 {
1480  BMLoop *l_next;
1481  BMEdge *e_new;
1482  BMVert *v_new, *v_old;
1483 #ifndef NDEBUG
1484  int valence1, valence2;
1485  bool edok;
1486  int i;
1487 #endif
1488 
1489  BLI_assert(BM_vert_in_edge(e, tv) != false);
1490 
1491  v_old = BM_edge_other_vert(e, tv);
1492 
1493 #ifndef NDEBUG
1494  valence1 = bmesh_disk_count(v_old);
1495  valence2 = bmesh_disk_count(tv);
1496 #endif
1497 
1498  /* order of 'e_new' verts should match 'e'
1499  * (so extruded faces don't flip) */
1500  v_new = BM_vert_create(bm, tv->co, tv, BM_CREATE_NOP);
1501  e_new = BM_edge_create(bm, tv, v_new, e, BM_CREATE_NOP);
1502 
1503  bmesh_disk_edge_remove(e_new, tv);
1504  bmesh_disk_edge_remove(e_new, v_new);
1505 
1506  bmesh_disk_vert_replace(e, v_new, tv);
1507 
1508  /* add e_new to v_new's disk cycle */
1509  bmesh_disk_edge_append(e_new, v_new);
1510 
1511  /* add e_new to tv's disk cycle */
1512  bmesh_disk_edge_append(e_new, tv);
1513 
1514 #ifndef NDEBUG
1515  /* verify disk cycles */
1516  edok = bmesh_disk_validate(valence1, v_old->e, v_old);
1517  BMESH_ASSERT(edok != false);
1518  edok = bmesh_disk_validate(valence2, tv->e, tv);
1519  BMESH_ASSERT(edok != false);
1520  edok = bmesh_disk_validate(2, v_new->e, v_new);
1521  BMESH_ASSERT(edok != false);
1522 #endif
1523 
1524  /* Split the radial cycle if present */
1525  l_next = e->l;
1526  e->l = NULL;
1527  if (l_next) {
1528  BMLoop *l_new, *l;
1529 #ifndef NDEBUG
1530  int radlen = bmesh_radial_length(l_next);
1531 #endif
1532  bool is_first = true;
1533 
1534  /* Take the next loop. Remove it from radial. Split it. Append to appropriate radials */
1535  while (l_next) {
1536  l = l_next;
1537  l->f->len++;
1538  l_next = l_next != l_next->radial_next ? l_next->radial_next : NULL;
1540 
1541  l_new = bm_loop_create(bm, NULL, NULL, l->f, l, 0);
1542  l_new->prev = l;
1543  l_new->next = l->next;
1544  l_new->prev->next = l_new;
1545  l_new->next->prev = l_new;
1546  l_new->v = v_new;
1547 
1548  /* assign the correct edge to the correct loop */
1549  if (BM_verts_in_edge(l_new->v, l_new->next->v, e)) {
1550  l_new->e = e;
1551  l->e = e_new;
1552 
1553  /* append l into e_new's rad cycle */
1554  if (is_first) {
1555  is_first = false;
1556  l->radial_next = l->radial_prev = NULL;
1557  }
1558 
1559  bmesh_radial_loop_append(l_new->e, l_new);
1561  }
1562  else if (BM_verts_in_edge(l_new->v, l_new->next->v, e_new)) {
1563  l_new->e = e_new;
1564  l->e = e;
1565 
1566  /* append l into e_new's rad cycle */
1567  if (is_first) {
1568  is_first = false;
1569  l->radial_next = l->radial_prev = NULL;
1570  }
1571 
1572  bmesh_radial_loop_append(l_new->e, l_new);
1574  }
1575  }
1576 
1577 #ifndef NDEBUG
1578  /* verify length of radial cycle */
1579  edok = bmesh_radial_validate(radlen, e->l);
1580  BMESH_ASSERT(edok != false);
1581  edok = bmesh_radial_validate(radlen, e_new->l);
1582  BMESH_ASSERT(edok != false);
1583 
1584  /* verify loop->v and loop->next->v pointers for e */
1585  for (i = 0, l = e->l; i < radlen; i++, l = l->radial_next) {
1586  BMESH_ASSERT(l->e == e);
1587  // BMESH_ASSERT(l->radial_next == l);
1588  BMESH_ASSERT(!(l->prev->e != e_new && l->next->e != e_new));
1589 
1590  edok = BM_verts_in_edge(l->v, l->next->v, e);
1591  BMESH_ASSERT(edok != false);
1592  BMESH_ASSERT(l->v != l->next->v);
1593  BMESH_ASSERT(l->e != l->next->e);
1594 
1595  /* verify loop cycle for kloop->f */
1597  BM_CHECK_ELEMENT(l->v);
1598  BM_CHECK_ELEMENT(l->e);
1599  BM_CHECK_ELEMENT(l->f);
1600  }
1601  /* verify loop->v and loop->next->v pointers for e_new */
1602  for (i = 0, l = e_new->l; i < radlen; i++, l = l->radial_next) {
1603  BMESH_ASSERT(l->e == e_new);
1604  // BMESH_ASSERT(l->radial_next == l);
1605  BMESH_ASSERT(!(l->prev->e != e && l->next->e != e));
1606  edok = BM_verts_in_edge(l->v, l->next->v, e_new);
1607  BMESH_ASSERT(edok != false);
1608  BMESH_ASSERT(l->v != l->next->v);
1609  BMESH_ASSERT(l->e != l->next->e);
1610 
1612  BM_CHECK_ELEMENT(l->v);
1613  BM_CHECK_ELEMENT(l->e);
1614  BM_CHECK_ELEMENT(l->f);
1615  }
1616 #endif
1617  }
1618 
1619  BM_CHECK_ELEMENT(e_new);
1620  BM_CHECK_ELEMENT(v_new);
1621  BM_CHECK_ELEMENT(v_old);
1623  BM_CHECK_ELEMENT(tv);
1624 
1625  if (r_e) {
1626  *r_e = e_new;
1627  }
1628  return v_new;
1629 }
1630 
1632  BMEdge *e_kill,
1633  BMVert *v_kill,
1634  const bool do_del,
1635  const bool check_edge_exists,
1636  const bool kill_degenerate_faces,
1637  const bool kill_duplicate_faces)
1638 {
1639  BMEdge *e_old;
1640  BMVert *v_old, *v_target;
1641  BMLoop *l_kill;
1642 #ifndef NDEBUG
1643  int radlen, i;
1644  bool edok;
1645 #endif
1646 
1647  BLI_assert(BM_vert_in_edge(e_kill, v_kill));
1648 
1649  if (BM_vert_in_edge(e_kill, v_kill) == 0) {
1650  return NULL;
1651  }
1652 
1653  if (bmesh_disk_count_at_most(v_kill, 3) == 2) {
1654 #ifndef NDEBUG
1655  int valence1, valence2;
1656  BMLoop *l;
1657 #endif
1658 
1659  e_old = bmesh_disk_edge_next(e_kill, v_kill);
1660  v_target = BM_edge_other_vert(e_kill, v_kill);
1661  v_old = BM_edge_other_vert(e_old, v_kill);
1662 
1663  /* check for double edges */
1664  if (BM_verts_in_edge(v_kill, v_target, e_old)) {
1665  return NULL;
1666  }
1667 
1668  BMEdge *e_splice;
1669  BLI_SMALLSTACK_DECLARE(faces_degenerate, BMFace *);
1670  BMLoop *l_kill_next;
1671 
1672  /* Candidates for being duplicate. */
1673  BLI_SMALLSTACK_DECLARE(faces_duplicate_candidate, BMFace *);
1674 
1675 #ifndef NDEBUG
1676  /* For verification later, count valence of 'v_old' and 'v_target' */
1677  valence1 = bmesh_disk_count(v_old);
1678  valence2 = bmesh_disk_count(v_target);
1679 #endif
1680 
1681  if (check_edge_exists) {
1682  e_splice = BM_edge_exists(v_target, v_old);
1683  }
1684 
1685  bmesh_disk_vert_replace(e_old, v_target, v_kill);
1686 
1687  /* remove e_kill from 'v_target's disk cycle */
1688  bmesh_disk_edge_remove(e_kill, v_target);
1689 
1690 #ifndef NDEBUG
1691  /* deal with radial cycle of e_kill */
1692  radlen = bmesh_radial_length(e_kill->l);
1693 #endif
1694  if (e_kill->l) {
1695 
1696  /* fix the neighboring loops of all loops in e_kill's radial cycle */
1697  l_kill = e_kill->l;
1698  do {
1699  /* relink loops and fix vertex pointer */
1700  if (l_kill->next->v == v_kill) {
1701  l_kill->next->v = v_target;
1702  }
1703 
1704  l_kill->next->prev = l_kill->prev;
1705  l_kill->prev->next = l_kill->next;
1706  if (BM_FACE_FIRST_LOOP(l_kill->f) == l_kill) {
1707  BM_FACE_FIRST_LOOP(l_kill->f) = l_kill->next;
1708  }
1709 
1710  /* fix len attribute of face */
1711  l_kill->f->len--;
1712  if (kill_degenerate_faces && (l_kill->f->len < 3)) {
1713  BLI_SMALLSTACK_PUSH(faces_degenerate, l_kill->f);
1714  }
1715  else {
1716  /* The duplicate test isn't reliable at this point as `e_splice` might be set,
1717  * so the duplicate test needs to run once the edge has been spliced. */
1718  if (kill_duplicate_faces) {
1719  BLI_SMALLSTACK_PUSH(faces_duplicate_candidate, l_kill->f);
1720  }
1721  }
1722  l_kill_next = l_kill->radial_next;
1723 
1724  bm_kill_only_loop(bm, l_kill);
1725 
1726  } while ((l_kill = l_kill_next) != e_kill->l);
1727  /* `e_kill->l` is invalid but the edge is freed next. */
1728 #ifndef NDEBUG
1729  /* Validate radial cycle of e_old */
1730  edok = bmesh_radial_validate(radlen, e_old->l);
1731  BMESH_ASSERT(edok != false);
1732 #endif
1733  }
1734  /* deallocate edge */
1735  bm_kill_only_edge(bm, e_kill);
1736 
1737  /* deallocate vertex */
1738  if (do_del) {
1739  bm_kill_only_vert(bm, v_kill);
1740  }
1741  else {
1742  v_kill->e = NULL;
1743  }
1744 
1745 #ifndef NDEBUG
1746  /* Validate disk cycle lengths of 'v_old', 'v_target' are unchanged */
1747  edok = bmesh_disk_validate(valence1, v_old->e, v_old);
1748  BMESH_ASSERT(edok != false);
1749  edok = bmesh_disk_validate(valence2, v_target->e, v_target);
1750  BMESH_ASSERT(edok != false);
1751 
1752  /* Validate loop cycle of all faces attached to 'e_old' */
1753  for (i = 0, l = e_old->l; i < radlen; i++, l = l->radial_next) {
1754  BMESH_ASSERT(l->e == e_old);
1755  edok = BM_verts_in_edge(l->v, l->next->v, e_old);
1756  BMESH_ASSERT(edok != false);
1757  edok = bmesh_loop_validate(l->f);
1758  BMESH_ASSERT(edok != false);
1759 
1761  BM_CHECK_ELEMENT(l->v);
1762  BM_CHECK_ELEMENT(l->e);
1763  BM_CHECK_ELEMENT(l->f);
1764  }
1765 #endif
1766  if (check_edge_exists) {
1767  if (e_splice) {
1768  /* removes e_splice */
1769  BM_edge_splice(bm, e_old, e_splice);
1770  }
1771  }
1772 
1773  if (kill_degenerate_faces) {
1774  BMFace *f_kill;
1775  while ((f_kill = BLI_SMALLSTACK_POP(faces_degenerate))) {
1776  BM_face_kill(bm, f_kill);
1777  }
1778  }
1779 
1780  if (kill_duplicate_faces) {
1781  BMFace *f_kill;
1782  while ((f_kill = BLI_SMALLSTACK_POP(faces_duplicate_candidate))) {
1783  if (BM_face_find_double(f_kill)) {
1784  BM_face_kill(bm, f_kill);
1785  }
1786  }
1787  }
1788 
1789  BM_CHECK_ELEMENT(v_old);
1790  BM_CHECK_ELEMENT(v_target);
1791  BM_CHECK_ELEMENT(e_old);
1792 
1793  return e_old;
1794  }
1795  return NULL;
1796 }
1797 
1799  BMEdge *e_kill,
1800  BMVert *v_kill,
1801  const bool do_del,
1802  const bool check_edge_exists,
1803  const bool kill_degenerate_faces)
1804 {
1805  BLI_SMALLSTACK_DECLARE(faces_degenerate, BMFace *);
1806  BMVert *v_target = BM_edge_other_vert(e_kill, v_kill);
1807 
1808  BLI_assert(BM_vert_in_edge(e_kill, v_kill));
1809 
1810  if (e_kill->l) {
1811  BMLoop *l_kill, *l_first, *l_kill_next;
1812  l_kill = l_first = e_kill->l;
1813  do {
1814  /* relink loops and fix vertex pointer */
1815  if (l_kill->next->v == v_kill) {
1816  l_kill->next->v = v_target;
1817  }
1818 
1819  l_kill->next->prev = l_kill->prev;
1820  l_kill->prev->next = l_kill->next;
1821  if (BM_FACE_FIRST_LOOP(l_kill->f) == l_kill) {
1822  BM_FACE_FIRST_LOOP(l_kill->f) = l_kill->next;
1823  }
1824 
1825  /* fix len attribute of face */
1826  l_kill->f->len--;
1827  if (kill_degenerate_faces) {
1828  if (l_kill->f->len < 3) {
1829  BLI_SMALLSTACK_PUSH(faces_degenerate, l_kill->f);
1830  }
1831  }
1832  l_kill_next = l_kill->radial_next;
1833 
1834  bm_kill_only_loop(bm, l_kill);
1835 
1836  } while ((l_kill = l_kill_next) != l_first);
1837 
1838  e_kill->l = NULL;
1839  }
1840 
1841  BM_edge_kill(bm, e_kill);
1842  BM_CHECK_ELEMENT(v_kill);
1843  BM_CHECK_ELEMENT(v_target);
1844 
1845  if (v_target->e && v_kill->e) {
1846  /* inline BM_vert_splice(bm, v_target, v_kill); */
1847  BMEdge *e;
1848  while ((e = v_kill->e)) {
1849  BMEdge *e_target;
1850 
1851  if (check_edge_exists) {
1852  e_target = BM_edge_exists(v_target, BM_edge_other_vert(e, v_kill));
1853  }
1854 
1855  bmesh_edge_vert_swap(e, v_target, v_kill);
1856  BLI_assert(e->v1 != e->v2);
1857 
1858  if (check_edge_exists) {
1859  if (e_target) {
1860  BM_edge_splice(bm, e_target, e);
1861  }
1862  }
1863  }
1864  }
1865 
1866  if (kill_degenerate_faces) {
1867  BMFace *f_kill;
1868  while ((f_kill = BLI_SMALLSTACK_POP(faces_degenerate))) {
1869  BM_face_kill(bm, f_kill);
1870  }
1871  }
1872 
1873  if (do_del) {
1874  BLI_assert(v_kill->e == NULL);
1875  bm_kill_only_vert(bm, v_kill);
1876  }
1877 
1878  return v_target;
1879 }
1880 
1882 {
1883  BMLoop *l_iter, *l_f1 = NULL, *l_f2 = NULL;
1884  int newlen = 0, i, f1len = 0, f2len = 0;
1885  bool edok;
1886  /* can't join a face to itself */
1887  if (f1 == f2) {
1888  return NULL;
1889  }
1890 
1891  /* validate that edge is 2-manifold edge */
1892  if (!BM_edge_is_manifold(e)) {
1893  return NULL;
1894  }
1895 
1896  /* verify that e is in both f1 and f2 */
1897  f1len = f1->len;
1898  f2len = f2->len;
1899 
1900  if (!((l_f1 = BM_face_edge_share_loop(f1, e)) && (l_f2 = BM_face_edge_share_loop(f2, e)))) {
1901  return NULL;
1902  }
1903 
1904  /* validate direction of f2's loop cycle is compatible */
1905  if (l_f1->v == l_f2->v) {
1906  return NULL;
1907  }
1908 
1909  /* validate that for each face, each vertex has another edge in its disk cycle that is
1910  * not e, and not shared. */
1911  if (BM_edge_in_face(l_f1->next->e, f2) || BM_edge_in_face(l_f1->prev->e, f2) ||
1912  BM_edge_in_face(l_f2->next->e, f1) || BM_edge_in_face(l_f2->prev->e, f1)) {
1913  return NULL;
1914  }
1915 
1916  /* validate only one shared edge */
1917  if (BM_face_share_edge_count(f1, f2) > 1) {
1918  return NULL;
1919  }
1920 
1921  /* validate no internal join */
1922  {
1923  bool is_dupe = false;
1924 
1925  /* TODO: skip clearing once this is ensured. */
1926  for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f2); i < f2len; i++, l_iter = l_iter->next) {
1928  }
1929 
1930  for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f1); i < f1len; i++, l_iter = l_iter->next) {
1931  BM_elem_flag_set(l_iter->v, BM_ELEM_INTERNAL_TAG, l_iter != l_f1);
1932  }
1933  for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f2); i < f2len; i++, l_iter = l_iter->next) {
1934  if (l_iter != l_f2) {
1935  /* as soon as a duplicate is found, bail out */
1936  if (BM_elem_flag_test(l_iter->v, BM_ELEM_INTERNAL_TAG)) {
1937  is_dupe = true;
1938  break;
1939  }
1940  }
1941  }
1942  /* Cleanup tags. */
1943  for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f1); i < f1len; i++, l_iter = l_iter->next) {
1945  }
1946  if (is_dupe) {
1947  return NULL;
1948  }
1949  }
1950 
1951  /* join the two loop */
1952  l_f1->prev->next = l_f2->next;
1953  l_f2->next->prev = l_f1->prev;
1954 
1955  l_f1->next->prev = l_f2->prev;
1956  l_f2->prev->next = l_f1->next;
1957 
1958  /* If `l_f1` was base-loop, make `l_f1->next` the base. */
1959  if (BM_FACE_FIRST_LOOP(f1) == l_f1) {
1960  BM_FACE_FIRST_LOOP(f1) = l_f1->next;
1961  }
1962 
1963  /* increase length of f1 */
1964  f1->len += (f2->len - 2);
1965 
1966  /* make sure each loop points to the proper face */
1967  newlen = f1->len;
1968  for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f1); i < newlen; i++, l_iter = l_iter->next) {
1969  l_iter->f = f1;
1970  }
1971 
1972  /* remove edge from the disk cycle of its two vertices */
1973  bmesh_disk_edge_remove(l_f1->e, l_f1->e->v1);
1974  bmesh_disk_edge_remove(l_f1->e, l_f1->e->v2);
1975 
1976  /* deallocate edge and its two loops as well as f2 */
1977  if (bm->etoolflagpool) {
1978  BLI_mempool_free(bm->etoolflagpool, ((BMEdge_OFlag *)l_f1->e)->oflags);
1979  }
1980  BLI_mempool_free(bm->epool, l_f1->e);
1981  bm->totedge--;
1982  BLI_mempool_free(bm->lpool, l_f1);
1983  bm->totloop--;
1984  BLI_mempool_free(bm->lpool, l_f2);
1985  bm->totloop--;
1986  if (bm->ftoolflagpool) {
1987  BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f2)->oflags);
1988  }
1989  BLI_mempool_free(bm->fpool, f2);
1990  bm->totface--;
1991  /* account for both above */
1993 
1994  BM_CHECK_ELEMENT(f1);
1995 
1996  /* validate the new loop cycle */
1997  edok = bmesh_loop_validate(f1);
1998  BMESH_ASSERT(edok != false);
1999 
2000  return f1;
2001 }
2002 
2004 {
2005  bool is_double = false;
2006 
2007  BLI_assert(BM_edge_exists(v_a, v_b) == false);
2008 
2009  if (v_a->e && v_b->e) {
2010  BMEdge *e, *e_first;
2011 
2012 #define VERT_VISIT _FLAG_WALK
2013 
2014  /* tag 'v_a' */
2015  e = e_first = v_a->e;
2016  do {
2017  BMVert *v_other = BM_edge_other_vert(e, v_a);
2020  } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != e_first);
2021 
2022  /* check 'v_b' connects to 'v_a' edges */
2023  e = e_first = v_b->e;
2024  do {
2025  BMVert *v_other = BM_edge_other_vert(e, v_b);
2026  if (BM_ELEM_API_FLAG_TEST(v_other, VERT_VISIT)) {
2027  is_double = true;
2028  break;
2029  }
2030  } while ((e = BM_DISK_EDGE_NEXT(e, v_b)) != e_first);
2031 
2032  /* cleanup */
2033  e = e_first = v_a->e;
2034  do {
2035  BMVert *v_other = BM_edge_other_vert(e, v_a);
2038  } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != e_first);
2039 
2040 #undef VERT_VISIT
2041  }
2042 
2043  return is_double;
2044 }
2045 
2046 bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
2047 {
2048  BMEdge *e;
2049 
2050  /* verts already spliced */
2051  if (v_src == v_dst) {
2052  return false;
2053  }
2054 
2055  BLI_assert(BM_vert_pair_share_face_check(v_src, v_dst) == false);
2056 
2057  /* move all the edges from 'v_src' disk to 'v_dst' */
2058  while ((e = v_src->e)) {
2059  bmesh_edge_vert_swap(e, v_dst, v_src);
2060  BLI_assert(e->v1 != e->v2);
2061  }
2062 
2063  BM_CHECK_ELEMENT(v_src);
2064  BM_CHECK_ELEMENT(v_dst);
2065 
2066  /* 'v_src' is unused now, and can be killed */
2067  BM_vert_kill(bm, v_src);
2068 
2069  return true;
2070 }
2071 
2072 /* -------------------------------------------------------------------- */
2076 /* BM_edge_face_count(e) >= 1 */
2078 {
2079  return (e->l && e->l->radial_next != e->l);
2080 }
2081 
2083  BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select)
2084 {
2085  int v_edges_num = 0;
2086 
2087  /* Detailed notes on array use since this is stack memory, we have to be careful */
2088 
2089  /* newly created vertices, only use when 'r_vout' is set
2090  * (total size will be number of fans) */
2091  BLI_SMALLSTACK_DECLARE(verts_new, BMVert *);
2092  /* fill with edges from the face-fan, clearing on completion
2093  * (total size will be max fan edge count) */
2094  BLI_SMALLSTACK_DECLARE(edges, BMEdge *);
2095  /* temp store edges to walk over when filling 'edges',
2096  * (total size will be max radial edges of any edge) */
2097  BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *);
2098 
2099  /* number of resulting verts, include self */
2100  int verts_num = 1;
2101  /* track the total number of edges handled, so we know when we've found the last fan */
2102  int edges_found = 0;
2103 
2104 #define EDGE_VISIT _FLAG_WALK
2105 
2106  /* count and flag at once */
2107  if (v->e) {
2108  BMEdge *e_first, *e_iter;
2109  e_iter = e_first = v->e;
2110  do {
2111  v_edges_num += 1;
2112 
2115  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
2116 
2117  while (true) {
2118  /* Considering only edges and faces incident on vertex v, walk
2119  * the edges & collect in the 'edges' list for splitting */
2120 
2121  BMEdge *e = v->e;
2123 
2124  do {
2126  BLI_SMALLSTACK_PUSH(edges, e);
2127  edges_found += 1;
2128 
2129  if (e->l) {
2130  BMLoop *l_iter, *l_first;
2131  l_iter = l_first = e->l;
2132  do {
2133  BMLoop *l_adjacent = (l_iter->v == v) ? l_iter->prev : l_iter->next;
2134  BLI_assert(BM_vert_in_edge(l_adjacent->e, v));
2135  if (BM_ELEM_API_FLAG_TEST(l_adjacent->e, EDGE_VISIT)) {
2136  BM_ELEM_API_FLAG_DISABLE(l_adjacent->e, EDGE_VISIT);
2137  BLI_SMALLSTACK_PUSH(edges_search, l_adjacent->e);
2138  }
2139  } while ((l_iter = l_iter->radial_next) != l_first);
2140  }
2141  } while ((e = BLI_SMALLSTACK_POP(edges_search)));
2142 
2143  /* now we have all edges connected to 'v->e' */
2144 
2145  BLI_assert(edges_found <= v_edges_num);
2146 
2147  if (edges_found == v_edges_num) {
2148  /* We're done! The remaining edges in 'edges' form the last fan,
2149  * which can be left as is.
2150  * if 'edges' were alloc'd it'd be freed here. */
2151  break;
2152  }
2153 
2154  BMVert *v_new;
2155 
2156  v_new = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
2157  if (copy_select) {
2158  BM_elem_select_copy(bm, v_new, v);
2159  }
2160 
2161  while ((e = BLI_SMALLSTACK_POP(edges))) {
2162  bmesh_edge_vert_swap(e, v_new, v);
2163  }
2164 
2165  if (r_vout) {
2166  BLI_SMALLSTACK_PUSH(verts_new, v_new);
2167  }
2168  verts_num += 1;
2169  }
2170  }
2171 
2172 #undef EDGE_VISIT
2173 
2174  /* flags are clean now, handle return values */
2175 
2176  if (r_vout_len != NULL) {
2177  *r_vout_len = verts_num;
2178  }
2179 
2180  if (r_vout != NULL) {
2181  BMVert **verts;
2182 
2183  verts = MEM_mallocN(sizeof(BMVert *) * verts_num, __func__);
2184  *r_vout = verts;
2185 
2186  verts[0] = v;
2187  BLI_SMALLSTACK_AS_TABLE(verts_new, &verts[1]);
2188  }
2189 }
2190 
2211 {
2212  do {
2213  LinkNode *n_orig = edges_separate->link;
2214  do {
2215  LinkNode *n_prev = n_orig;
2216  LinkNode *n_step = n_orig->next;
2217  BMEdge *e_orig = n_orig->link;
2218  do {
2219  BMEdge *e = n_step->link;
2220  BLI_assert(e != e_orig);
2221  if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2) && BM_edge_splice(bm, e_orig, e)) {
2222  /* don't visit again */
2223  n_prev->next = n_step->next;
2224  }
2225  else {
2226  n_prev = n_step;
2227  }
2228  } while ((n_step = n_step->next));
2229 
2230  } while ((n_orig = n_orig->next) && n_orig->next);
2231  } while ((edges_separate = edges_separate->next));
2232 }
2233 
2235  BMVert *v,
2236  BMEdge **e_in,
2237  int e_in_len,
2238  const bool copy_select,
2239  BMVert ***r_vout,
2240  int *r_vout_len)
2241 {
2242  LinkNode *edges_separate = NULL;
2243  int i;
2244 
2245  for (i = 0; i < e_in_len; i++) {
2246  BMEdge *e = e_in[i];
2248  LinkNode *edges_orig = NULL;
2249  do {
2250  BMLoop *l_sep = e->l;
2251  bmesh_kernel_edge_separate(bm, e, l_sep, copy_select);
2252  BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
2253  BLI_assert(e != l_sep->e);
2254  } while (bm_edge_supports_separate(e));
2255  BLI_linklist_prepend_alloca(&edges_orig, e);
2256  BLI_linklist_prepend_alloca(&edges_separate, edges_orig);
2257  }
2258  }
2259 
2260  bmesh_kernel_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
2261 
2262  if (edges_separate) {
2263  bmesh_kernel_vert_separate__cleanup(bm, edges_separate);
2264  }
2265 }
2266 
2268  BMVert *v,
2269  const char hflag,
2270  const bool copy_select,
2271  BMVert ***r_vout,
2272  int *r_vout_len)
2273 {
2274  LinkNode *edges_separate = NULL;
2275  BMEdge *e_iter, *e_first;
2276 
2277  e_iter = e_first = v->e;
2278  do {
2279  if (BM_elem_flag_test(e_iter, hflag)) {
2280  BMEdge *e = e_iter;
2282  LinkNode *edges_orig = NULL;
2283  do {
2284  BMLoop *l_sep = e->l;
2285  bmesh_kernel_edge_separate(bm, e, l_sep, copy_select);
2286  /* trick to avoid looping over separated edges */
2287  if (edges_separate == NULL && edges_orig == NULL) {
2288  e_first = l_sep->e;
2289  }
2290  BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
2291  BLI_assert(e != l_sep->e);
2292  } while (bm_edge_supports_separate(e));
2293  BLI_linklist_prepend_alloca(&edges_orig, e);
2294  BLI_linklist_prepend_alloca(&edges_separate, edges_orig);
2295  }
2296  }
2297  } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
2298 
2299  bmesh_kernel_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
2300 
2301  if (edges_separate) {
2302  bmesh_kernel_vert_separate__cleanup(bm, edges_separate);
2303  }
2304 }
2305 
2307  BMVert *v_dst,
2308  BMVert *v_src,
2309  bool (*testfn)(BMEdge *, void *arg),
2310  void *arg)
2311 {
2312  LinkNode *edges_hflag = NULL;
2313  BMEdge *e_iter, *e_first;
2314 
2315  e_iter = e_first = v_src->e;
2316  do {
2317  if (testfn(e_iter, arg)) {
2318  BLI_linklist_prepend_alloca(&edges_hflag, e_iter);
2319  }
2320  } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_src)) != e_first);
2321 
2322  if (edges_hflag) {
2323  do {
2324  e_iter = edges_hflag->link;
2325  bmesh_disk_vert_replace(e_iter, v_dst, v_src);
2326  } while ((edges_hflag = edges_hflag->next));
2327  }
2328 }
2329 
2332 bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
2333 {
2334  BMLoop *l;
2335 
2336  if (!BM_vert_in_edge(e_src, e_dst->v1) || !BM_vert_in_edge(e_src, e_dst->v2)) {
2337  /* not the same vertices can't splice */
2338 
2339  /* the caller should really make sure this doesn't happen ever
2340  * so assert on release builds */
2341  BLI_assert(0);
2342 
2343  return false;
2344  }
2345 
2346  while (e_src->l) {
2347  l = e_src->l;
2348  BLI_assert(BM_vert_in_edge(e_dst, l->v));
2349  BLI_assert(BM_vert_in_edge(e_dst, l->next->v));
2350  bmesh_radial_loop_remove(e_src, l);
2351  bmesh_radial_loop_append(e_dst, l);
2352  }
2353 
2354  BLI_assert(bmesh_radial_length(e_src->l) == 0);
2355 
2356  BM_CHECK_ELEMENT(e_src);
2357  BM_CHECK_ELEMENT(e_dst);
2358 
2359  /* removes from disks too */
2360  BM_edge_kill(bm, e_src);
2361 
2362  return true;
2363 }
2364 
2365 void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select)
2366 {
2367  BMEdge *e_new;
2368 #ifndef NDEBUG
2369  const int radlen = bmesh_radial_length(e->l);
2370 #endif
2371 
2372  BLI_assert(l_sep->e == e);
2373  BLI_assert(e->l);
2374 
2375  if (BM_edge_is_boundary(e)) {
2376  BLI_assert(0); /* no cut required */
2377  return;
2378  }
2379 
2380  if (l_sep == e->l) {
2381  e->l = l_sep->radial_next;
2382  }
2383 
2384  e_new = BM_edge_create(bm, e->v1, e->v2, e, BM_CREATE_NOP);
2385  bmesh_radial_loop_remove(e, l_sep);
2386  bmesh_radial_loop_append(e_new, l_sep);
2387  l_sep->e = e_new;
2388 
2389  if (copy_select) {
2390  BM_elem_select_copy(bm, e_new, e);
2391  }
2392 
2393  BLI_assert(bmesh_radial_length(e->l) == radlen - 1);
2394  BLI_assert(bmesh_radial_length(e_new->l) == 1);
2395 
2396  BM_CHECK_ELEMENT(e_new);
2398 }
2399 
2401 {
2402  BMVert *v_new = NULL;
2403  BMVert *v_sep = l_sep->v;
2404  BMEdge *e_iter;
2405  BMEdge *edges[2];
2406  int i;
2407 
2408  /* peel the face from the edge radials on both sides of the
2409  * loop vert, disconnecting the face from its fan */
2410  if (!BM_edge_is_boundary(l_sep->e)) {
2411  bmesh_kernel_edge_separate(bm, l_sep->e, l_sep, false);
2412  }
2413  if (!BM_edge_is_boundary(l_sep->prev->e)) {
2414  bmesh_kernel_edge_separate(bm, l_sep->prev->e, l_sep->prev, false);
2415  }
2416 
2417  /* do inline, below */
2418 #if 0
2419  if (BM_vert_edge_count_is_equal(v_sep, 2)) {
2420  return v_sep;
2421  }
2422 #endif
2423 
2424  /* Search for an edge unattached to this loop */
2425  e_iter = v_sep->e;
2426  while (!ELEM(e_iter, l_sep->e, l_sep->prev->e)) {
2427  e_iter = bmesh_disk_edge_next(e_iter, v_sep);
2428 
2429  /* We've come back around to the initial edge, all touch this loop.
2430  * If there are still only two edges out of v_sep,
2431  * then this whole URMV was just a no-op, so exit now. */
2432  if (e_iter == v_sep->e) {
2434  return v_sep;
2435  }
2436  }
2437 
2438  v_sep->e = l_sep->e;
2439 
2440  v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP);
2441 
2442  edges[0] = l_sep->e;
2443  edges[1] = l_sep->prev->e;
2444 
2445  for (i = 0; i < ARRAY_SIZE(edges); i++) {
2446  BMEdge *e = edges[i];
2447  bmesh_edge_vert_swap(e, v_new, v_sep);
2448  }
2449 
2450  BLI_assert(v_sep != l_sep->v);
2451  BLI_assert(v_sep->e != l_sep->v->e);
2452 
2453  BM_CHECK_ELEMENT(l_sep);
2454  BM_CHECK_ELEMENT(v_sep);
2455  BM_CHECK_ELEMENT(edges[0]);
2456  BM_CHECK_ELEMENT(edges[1]);
2457  BM_CHECK_ELEMENT(v_new);
2458 
2459  return v_new;
2460 }
2461 
2463 {
2464  BMVert *v_sep = larr[0]->v;
2465  BMVert *v_new;
2466  int edges_len = 0;
2467  int i;
2468  /* any edges not owned by 'larr' loops connected to 'v_sep'? */
2469  bool is_mixed_edge_any = false;
2470  /* any loops not owned by 'larr' radially connected to 'larr' loop edges? */
2471  bool is_mixed_loop_any = false;
2472 
2473 #define LOOP_VISIT _FLAG_WALK
2474 #define EDGE_VISIT _FLAG_WALK
2475 
2476  for (i = 0; i < larr_len; i++) {
2477  BMLoop *l_sep = larr[i];
2478 
2479  /* all must be from the same vert! */
2480  BLI_assert(v_sep == l_sep->v);
2481 
2484 
2485  /* weak! but it makes it simpler to check for edges to split
2486  * while doing a radial loop (where loops may be adjacent) */
2489 
2490  BMLoop *loop_pair[2] = {l_sep, l_sep->prev};
2491  for (int j = 0; j < ARRAY_SIZE(loop_pair); j++) {
2492  BMEdge *e = loop_pair[j]->e;
2495  edges_len += 1;
2496  }
2497  }
2498  }
2499 
2500  BMEdge **edges = BLI_array_alloca(edges, edges_len);
2501  STACK_DECLARE(edges);
2502 
2503  STACK_INIT(edges, edges_len);
2504 
2505  {
2506  BMEdge *e_first, *e_iter;
2507  e_iter = e_first = v_sep->e;
2508  do {
2509  if (BM_ELEM_API_FLAG_TEST(e_iter, EDGE_VISIT)) {
2510  BMLoop *l_iter, *l_first;
2511  bool is_mixed_loop = false;
2512 
2513  l_iter = l_first = e_iter->l;
2514  do {
2515  if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
2516  is_mixed_loop = true;
2517  break;
2518  }
2519  } while ((l_iter = l_iter->radial_next) != l_first);
2520 
2521  if (is_mixed_loop) {
2522  /* ensure the first loop is one we don't own so we can do a quick check below
2523  * on the edge's loop-flag to see if the edge is mixed or not. */
2524  e_iter->l = l_iter;
2525 
2526  is_mixed_loop_any = true;
2527  }
2528 
2529  STACK_PUSH(edges, e_iter);
2530  }
2531  else {
2532  /* at least one edge attached isn't connected to our loops */
2533  is_mixed_edge_any = true;
2534  }
2535  } while ((e_iter = bmesh_disk_edge_next(e_iter, v_sep)) != e_first);
2536  }
2537 
2538  BLI_assert(edges_len == STACK_SIZE(edges));
2539 
2540  if (is_mixed_loop_any == false && is_mixed_edge_any == false) {
2541  /* all loops in 'larr' are the sole owners of their edges.
2542  * nothing to split away from, this is a no-op */
2543  v_new = v_sep;
2544  }
2545  else {
2546  v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP);
2547 
2548  for (i = 0; i < STACK_SIZE(edges); i++) {
2549  BMEdge *e = edges[i];
2550  BMLoop *l_iter, *l_first, *l_next;
2551  BMEdge *e_new;
2552 
2553  /* disable so copied edge isn't left dirty (loop edges are cleared last too) */
2555 
2556  /* will always be false when (is_mixed_loop_any == false) */
2557  if (!BM_ELEM_API_FLAG_TEST(e->l, LOOP_VISIT)) {
2558  /* edge has some loops owned by us, some owned by other loops */
2559  BMVert *e_new_v_pair[2];
2560 
2561  if (e->v1 == v_sep) {
2562  e_new_v_pair[0] = v_new;
2563  e_new_v_pair[1] = e->v2;
2564  }
2565  else {
2566  BLI_assert(v_sep == e->v2);
2567  e_new_v_pair[0] = e->v1;
2568  e_new_v_pair[1] = v_new;
2569  }
2570 
2571  e_new = BM_edge_create(bm, UNPACK2(e_new_v_pair), e, BM_CREATE_NOP);
2572 
2573  /* now moved all loops from 'larr' to this newly created edge */
2574  l_iter = l_first = e->l;
2575  do {
2576  l_next = l_iter->radial_next;
2577  if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
2578  bmesh_radial_loop_remove(e, l_iter);
2579  bmesh_radial_loop_append(e_new, l_iter);
2580  l_iter->e = e_new;
2581  }
2582  } while ((l_iter = l_next) != l_first);
2583  }
2584  else {
2585  /* we own the edge entirely, replace the vert */
2586  bmesh_disk_vert_replace(e, v_new, v_sep);
2587  }
2588 
2589  /* loop vert is handled last! */
2590  }
2591  }
2592 
2593  for (i = 0; i < larr_len; i++) {
2594  BMLoop *l_sep = larr[i];
2595 
2596  l_sep->v = v_new;
2597 
2604 
2607  }
2608 
2609 #undef LOOP_VISIT
2610 #undef EDGE_VISIT
2611 
2612  return v_new;
2613 }
2614 
2616 {
2617  BMLoop *l_iter, *l_first;
2618 
2619  BLI_assert(ELEM(v_src, e->v1, e->v2));
2620  bmesh_disk_vert_replace(e, v_dst, v_src);
2621 
2622  l_iter = l_first = e->l;
2623  do {
2624  if (l_iter->v == v_src) {
2625  l_iter->v = v_dst;
2626  if (BM_vert_in_edge(l_iter->prev->e, v_src)) {
2627  bmesh_edge_vert_swap__recursive(l_iter->prev->e, v_dst, v_src);
2628  }
2629  }
2630  else if (l_iter->next->v == v_src) {
2631  l_iter->next->v = v_dst;
2632  if (BM_vert_in_edge(l_iter->next->e, v_src)) {
2633  bmesh_edge_vert_swap__recursive(l_iter->next->e, v_dst, v_src);
2634  }
2635  }
2636  else {
2637  BLI_assert(l_iter->prev->v != v_src);
2638  }
2639  } while ((l_iter = l_iter->radial_next) != l_first);
2640 }
2641 
2643 {
2644  BMVert *v_new = BM_vert_create(bm, l_sep->v->co, l_sep->v, BM_CREATE_NOP);
2645  /* passing either 'l_sep->e', 'l_sep->prev->e' will work */
2646  bmesh_edge_vert_swap__recursive(l_sep->e, v_new, l_sep->v);
2647  BLI_assert(l_sep->v == v_new);
2648  return v_new;
2649 }
2650 
2652 {
2653  BMLoop *l_iter, *l_first;
2654 
2655  BLI_assert(f_a != f_b);
2656 
2657  l_iter = l_first = BM_FACE_FIRST_LOOP(f_a);
2658  do {
2659  l_iter->f = f_b;
2660  } while ((l_iter = l_iter->next) != l_first);
2661 
2662  l_iter = l_first = BM_FACE_FIRST_LOOP(f_b);
2663  do {
2664  l_iter->f = f_a;
2665  } while ((l_iter = l_iter->next) != l_first);
2666 
2667  SWAP(BMFace, (*f_a), (*f_b));
2668 
2669  /* swap back */
2670  SWAP(void *, f_a->head.data, f_b->head.data);
2671  SWAP(int, f_a->head.index, f_b->head.index);
2672 }
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
void CustomData_bmesh_set_default(struct CustomData *data, void **block)
Definition: customdata.cc:3756
#define ORIGINDEX_NONE
void CustomData_bmesh_copy_data(const struct CustomData *source, struct CustomData *dest, void *src_block, void **dest_block)
void CustomData_bmesh_free_block_data(struct CustomData *data, void *block)
Definition: customdata.cc:3689
void * CustomData_bmesh_get(const struct CustomData *data, void *block, int type)
int CustomData_get_offset(const struct CustomData *data, int type)
void CustomData_bmesh_free_block(struct CustomData *data, void **block)
Definition: customdata.cc:3665
void BKE_mesh_mdisp_flip(struct MDisps *md, bool use_loop_mdisp_flip)
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:98
#define BLI_array_staticdeclare(arr, maxstatic)
Definition: BLI_array.h:58
#define BLI_array_len(arr)
Definition: BLI_array.h:63
#define BLI_array_free(arr)
Definition: BLI_array.h:113
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v3(float r[3])
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
Definition: BLI_mempool.c:319
void * BLI_mempool_calloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
Definition: BLI_mempool.c:347
#define UNPACK2(a)
#define UNUSED_FUNCTION(x)
#define ARRAY_SIZE(arr)
#define SWAP(type, a, b)
#define UNUSED(x)
#define UNLIKELY(x)
#define ELEM(...)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
@ CD_SHAPE_KEYINDEX
_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.
@ BM_SPACEARR_DIRTY_ALL
Definition: bmesh_class.h:416
#define BM_DISK_EDGE_NEXT(e, v)
Definition: bmesh_class.h:625
#define BM_DEFAULT_NGON_STACK_SIZE
Definition: bmesh_class.h:640
#define BM_NGON_MAX
Definition: bmesh_class.h:650
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_LOOP
Definition: bmesh_class.h:385
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
@ BM_ELEM_INTERNAL_TAG
Definition: bmesh_class.h:496
@ BM_ELEM_DRAW
Definition: bmesh_class.h:486
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v)
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void *ele_dst)
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len)
BMFace * BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len, const BMFace *f_example, const eBMCreateFlag create_flag)
Make NGon.
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b)
Definition: bmesh_core.c:2651
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
Join Connected Faces.
Definition: bmesh_core.c:1123
static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_src)
Definition: bmesh_core.c:2615
void BM_face_verts_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:811
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
Splice Edge.
Definition: bmesh_core.c:2332
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:41
void BM_vert_separate(BMesh *bm, BMVert *v, BMEdge **e_in, int e_in_len, const bool copy_select, BMVert ***r_vout, int *r_vout_len)
Definition: bmesh_core.c:2234
static BMLoop * bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f, const BMLoop *l_example, const eBMCreateFlag create_flag)
Definition: bmesh_core.c:193
BMFace * BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
Definition: bmesh_core.c:464
BMVert * bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep)
Definition: bmesh_core.c:2642
static void bm_elements_systag_disable(void *veles, int tot, const char api_flag)
Definition: bmesh_core.c:1051
static void bm_kill_only_loop(BMesh *bm, BMLoop *l)
Definition: bmesh_core.c:781
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select)
Separate Edge.
Definition: bmesh_core.c:2365
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
Definition: bmesh_core.c:2046
BMFace * bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
Join Face Kill Edge (JFKE)
Definition: bmesh_core.c:1881
#define LOOP_VISIT
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:939
static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
Definition: bmesh_core.c:2210
BMFace * bmesh_kernel_split_face_make_edge(BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2, BMLoop **r_l, BMEdge *e_example, const bool no_double)
Split Face Make Edge (SFME)
Definition: bmesh_core.c:1339
void BM_face_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:828
BMEdge * bmesh_kernel_join_edge_kill_vert(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool check_edge_exists, const bool kill_degenerate_faces, const bool kill_duplicate_faces)
Join Edge Kill Vert (JEKV)
Definition: bmesh_core.c:1631
void BM_vert_separate_hflag(BMesh *bm, BMVert *v, const char hflag, const bool copy_select, BMVert ***r_vout, int *r_vout_len)
Definition: bmesh_core.c:2267
void BM_face_kill_loose(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:872
static void bm_kill_only_vert(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:708
static BMFace * bm_face_create__sfme(BMesh *bm, BMFace *f_example)
Definition: bmesh_core.c:1316
BLI_INLINE BMFace * bm_face_create__internal(BMesh *bm)
Definition: bmesh_core.c:347
BMVert * bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
Un-glue Region Make Vert (URMV)
Definition: bmesh_core.c:2400
static void bm_kill_only_edge(BMesh *bm, BMEdge *e)
Definition: bmesh_core.c:731
static int UNUSED_FUNCTION() bm_loop_length(BMLoop *l)
Definition: bmesh_core.c:953
void BM_face_edges_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:794
static int UNUSED_FUNCTION() bm_vert_systag_count_disk(BMVert *v, const char api_flag)
Definition: bmesh_core.c:1072
BMVert * bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len)
Definition: bmesh_core.c:2462
#define EDGE_VISIT
void BM_vert_separate_tested_edges(BMesh *UNUSED(bm), BMVert *v_dst, BMVert *v_src, bool(*testfn)(BMEdge *, void *arg), void *arg)
Definition: bmesh_core.c:2306
static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag)
Definition: bmesh_core.c:1092
void bmesh_kernel_loop_reverse(BMesh *bm, BMFace *f, const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
Loop Reverse.
Definition: bmesh_core.c:965
void BM_edge_kill(BMesh *bm, BMEdge *e)
Definition: bmesh_core.c:927
BMFace * BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges)
Definition: bmesh_core.c:279
int bmesh_elem_check(void *element, const char htype)
Definition: bmesh_core.c:487
static void bm_elements_systag_enable(void *veles, int tot, const char api_flag)
Definition: bmesh_core.c:1041
static BMLoop * bm_face_boundary_add(BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte, const eBMCreateFlag create_flag)
Definition: bmesh_core.c:259
#define VERT_VISIT
BMFace * BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, const BMFace *f_example, const eBMCreateFlag create_flag)
Definition: bmesh_core.c:395
BMVert * bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
Split Edge Make Vert (SEMV)
Definition: bmesh_core.c:1478
static int bm_loop_systag_count_radial(BMLoop *l, const char api_flag)
Definition: bmesh_core.c:1061
void bmesh_kernel_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select)
Separate Vert.
Definition: bmesh_core.c:2082
BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
Definition: bmesh_core.c:2077
static void bm_kill_only_face(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:754
BMVert * bmesh_kernel_join_vert_kill_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool check_edge_exists, const bool kill_degenerate_faces)
Join Vert Kill Edge (JVKE)
Definition: bmesh_core.c:1798
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:123
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
Definition: bmesh_core.c:2003
eBMCreateFlag
Definition: bmesh_core.h:11
@ BM_CREATE_NOP
Definition: bmesh_core.h:12
@ BM_CREATE_SKIP_CD
Definition: bmesh_core.h:20
@ BM_CREATE_NO_DOUBLE
Definition: bmesh_core.h:14
#define BMESH_ASSERT(a)
Definition: bmesh_error.h:80
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:15
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:111
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
void BM_loop_interp_multires_ex(BMesh *UNUSED(bm), BMLoop *l_dst, const BMFace *f_src, const float f_dst_center[3], const float f_src_center[3], const int cd_loop_mdisp_offset)
Definition: bmesh_interp.c:472
ATTR_WARN_UNUSED_RESULT BMesh * bm
#define BM_select_history_remove(bm, ele)
ATTR_WARN_UNUSED_RESULT const void * element
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
@ _FLAG_JF
Definition: bmesh_private.h:56
@ _FLAG_ELEM_CHECK
Definition: bmesh_private.h:63
#define BM_ELEM_API_FLAG_DISABLE(element, f)
Definition: bmesh_private.h:71
#define BM_ELEM_API_FLAG_TEST(element, f)
Definition: bmesh_private.h:76
#define BM_CHECK_ELEMENT(el)
Definition: bmesh_private.h:32
int bmesh_radial_length(const BMLoop *l)
int bmesh_disk_count_at_most(const BMVert *v, int count_max)
#define BM_ELEM_API_FLAG_ENABLE(element, f)
Definition: bmesh_private.h:66
int bmesh_disk_count(const BMVert *v)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1553
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:100
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
Definition: bmesh_query.c:420
BMFace * BM_face_find_double(BMFace *f)
Definition: bmesh_query.c:1660
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
Definition: bmesh_query.c:968
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
Definition: bmesh_query.c:1115
BMFace * BM_face_exists(BMVert **varr, int len)
Definition: bmesh_query.c:1612
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_edge_face_count_is_over(e, n)
Definition: bmesh_query.h:248
#define BM_vert_edge_count_is_equal(v, n)
Definition: bmesh_query.h:239
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_verts_in_edge(const BMVert *v1, const BMVert *v2, const BMEdge *e) 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 bmesh_disk_edge_remove(BMEdge *e, BMVert *v)
bool bmesh_loop_validate(BMFace *f)
void bmesh_disk_edge_append(BMEdge *e, BMVert *v)
void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src)
void bmesh_radial_loop_unlink(BMLoop *l)
void bmesh_radial_loop_append(BMEdge *e, BMLoop *l)
void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
BMESH RADIAL REMOVE LOOP.
bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
bool bmesh_radial_validate(int radlen, BMLoop *l)
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int len
Definition: draw_manager.c:108
static float verts[][3]
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static char faces[256]
static void error(const char *str)
Definition: meshlaplacian.c:51
BMHeader head
Definition: bmesh_class.h:111
BMVert * v1
Definition: bmesh_class.h:122
BMVert * v2
Definition: bmesh_class.h:122
struct BMLoop * l
Definition: bmesh_class.h:128
short mat_nr
Definition: bmesh_class.h:281
int len
Definition: bmesh_class.h:267
BMHeader head
Definition: bmesh_class.h:255
float no[3]
Definition: bmesh_class.h:271
BMLoop * l_first
Definition: bmesh_class.h:261
char htype
Definition: bmesh_class.h:64
int index
Definition: bmesh_class.h:61
char hflag
Definition: bmesh_class.h:66
void * data
Definition: bmesh_class.h:51
char api_flag
Definition: bmesh_class.h:74
BMHeader head
Definition: bmesh_class.h:145
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * radial_prev
Definition: bmesh_class.h:204
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMLoop * prev
Definition: bmesh_class.h:233
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
float co[3]
Definition: bmesh_class.h:87
struct BMEdge * e
Definition: bmesh_class.h:97
float no[3]
Definition: bmesh_class.h:88
BMHeader head
Definition: bmesh_class.h:85
int totvert
Definition: bmesh_class.h:297
struct BLI_mempool * epool
Definition: bmesh_class.h:314
char elem_index_dirty
Definition: bmesh_class.h:305
CustomData vdata
Definition: bmesh_class.h:337
int totedge
Definition: bmesh_class.h:297
char elem_table_dirty
Definition: bmesh_class.h:311
struct BLI_mempool * vtoolflagpool
Definition: bmesh_class.h:331
CustomData edata
Definition: bmesh_class.h:337
uint use_toolflags
Definition: bmesh_class.h:333
int totloop
Definition: bmesh_class.h:297
struct BLI_mempool * etoolflagpool
Definition: bmesh_class.h:331
BMFace * act_face
Definition: bmesh_class.h:366
struct BLI_mempool * ftoolflagpool
Definition: bmesh_class.h:331
char spacearr_dirty
Definition: bmesh_class.h:344
CustomData pdata
Definition: bmesh_class.h:337
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
struct BLI_mempool * fpool
Definition: bmesh_class.h:314
struct BLI_mempool * vpool
Definition: bmesh_class.h:314
struct BLI_mempool * lpool
Definition: bmesh_class.h:314
void * link
Definition: BLI_linklist.h:24
struct LinkNode * next
Definition: BLI_linklist.h:23
static FT_Error err