Blender  V2.93
bmesh_core.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 
23 #include "MEM_guardedalloc.h"
24 
25 #include "BLI_alloca.h"
26 #include "BLI_array.h"
27 #include "BLI_linklist_stack.h"
28 #include "BLI_math_vector.h"
29 #include "BLI_utildefines_stack.h"
30 
31 #include "BLT_translation.h"
32 
33 #include "DNA_meshdata_types.h"
34 
35 #include "BKE_customdata.h"
36 #include "BKE_mesh.h"
37 
38 #include "bmesh.h"
39 #include "intern/bmesh_private.h"
40 
41 /* use so valgrinds memcheck alerts us when undefined index is used.
42  * TESTING ONLY! */
43 // #define USE_DEBUG_INDEX_MEMCHECK
44 
45 #ifdef USE_DEBUG_INDEX_MEMCHECK
46 # define DEBUG_MEMCHECK_INDEX_INVALIDATE(ele) \
47  { \
48  int undef_idx; \
49  BM_elem_index_set(ele, undef_idx); /* set_ok_invalid */ \
50  } \
51  (void)0
52 
53 #endif
54 
59  const float co[3],
60  const BMVert *v_example,
61  const eBMCreateFlag create_flag)
62 {
64 
65  BLI_assert((v_example == NULL) || (v_example->head.htype == BM_VERT));
66  BLI_assert(!(create_flag & 1));
67 
68  /* --- assign all members --- */
69  v->head.data = NULL;
70 
71 #ifdef USE_DEBUG_INDEX_MEMCHECK
72  DEBUG_MEMCHECK_INDEX_INVALIDATE(v);
73 #else
74  BM_elem_index_set(v, -1); /* set_ok_invalid */
75 #endif
76 
77  v->head.htype = BM_VERT;
78  v->head.hflag = 0;
79  v->head.api_flag = 0;
80 
81  /* allocate flags */
82  if (bm->use_toolflags) {
84  }
85 
86  /* 'v->no' is handled by BM_elem_attrs_copy */
87  if (co) {
88  copy_v3_v3(v->co, co);
89  }
90  else {
91  zero_v3(v->co);
92  }
93  /* 'v->no' set below */
94 
95  v->e = NULL;
96  /* --- done --- */
97 
98  /* disallow this flag for verts - its meaningless */
99  BLI_assert((create_flag & BM_CREATE_NO_DOUBLE) == 0);
100 
101  /* may add to middle of the pool */
105 
106  bm->totvert++;
107 
108  if (!(create_flag & BM_CREATE_SKIP_CD)) {
109  if (v_example) {
110  int *keyi;
111 
112  /* handles 'v->no' too */
113  BM_elem_attrs_copy(bm, bm, v_example, v);
114 
115  /* exception: don't copy the original shapekey index */
117  if (keyi) {
118  *keyi = ORIGINDEX_NONE;
119  }
120  }
121  else {
123  zero_v3(v->no);
124  }
125  }
126  else {
127  if (v_example) {
128  copy_v3_v3(v->no, v_example->no);
129  }
130  else {
131  zero_v3(v->no);
132  }
133  }
134 
136 
137  return v;
138 }
139 
148  BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
149 {
150  BMEdge *e;
151 
152  BLI_assert(v1 != v2);
153  BLI_assert(v1->head.htype == BM_VERT && v2->head.htype == BM_VERT);
154  BLI_assert((e_example == NULL) || (e_example->head.htype == BM_EDGE));
155  BLI_assert(!(create_flag & 1));
156 
157  if ((create_flag & BM_CREATE_NO_DOUBLE) && (e = BM_edge_exists(v1, v2))) {
158  return e;
159  }
160 
162 
163  /* --- assign all members --- */
164  e->head.data = NULL;
165 
166 #ifdef USE_DEBUG_INDEX_MEMCHECK
167  DEBUG_MEMCHECK_INDEX_INVALIDATE(e);
168 #else
169  BM_elem_index_set(e, -1); /* set_ok_invalid */
170 #endif
171 
172  e->head.htype = BM_EDGE;
174  e->head.api_flag = 0;
175 
176  /* allocate flags */
177  if (bm->use_toolflags) {
179  }
180 
181  e->v1 = v1;
182  e->v2 = v2;
183  e->l = NULL;
184 
185  memset(&e->v1_disk_link, 0, sizeof(BMDiskLink[2]));
186  /* --- done --- */
187 
188  bmesh_disk_edge_append(e, e->v1);
189  bmesh_disk_edge_append(e, e->v2);
190 
191  /* may add to middle of the pool */
195 
196  bm->totedge++;
197 
198  if (!(create_flag & BM_CREATE_SKIP_CD)) {
199  if (e_example) {
200  BM_elem_attrs_copy(bm, bm, e_example, e);
201  }
202  else {
204  }
205  }
206 
208 
209  return e;
210 }
211 
218  BMVert *v,
219  BMEdge *e,
220  BMFace *f,
221  const BMLoop *l_example,
222  const eBMCreateFlag create_flag)
223 {
224  BMLoop *l = NULL;
225 
227 
228  BLI_assert((l_example == NULL) || (l_example->head.htype == BM_LOOP));
229  BLI_assert(!(create_flag & 1));
230 
231 #ifndef NDEBUG
232  if (l_example) {
233  /* ensure passing a loop is either sharing the same vertex, or entirely disconnected
234  * use to catch mistake passing in loop offset-by-one. */
235  BLI_assert((v == l_example->v) || !ELEM(v, l_example->prev->v, l_example->next->v));
236  }
237 #endif
238 
239  /* --- assign all members --- */
240  l->head.data = NULL;
241 
242 #ifdef USE_DEBUG_INDEX_MEMCHECK
243  DEBUG_MEMCHECK_INDEX_INVALIDATE(l);
244 #else
245  BM_elem_index_set(l, -1); /* set_ok_invalid */
246 #endif
247 
248  l->head.htype = BM_LOOP;
249  l->head.hflag = 0;
250  l->head.api_flag = 0;
251 
252  l->v = v;
253  l->e = e;
254  l->f = f;
255 
256  l->radial_next = NULL;
257  l->radial_prev = NULL;
258  l->next = NULL;
259  l->prev = NULL;
260  /* --- done --- */
261 
262  /* may add to middle of the pool */
265 
266  bm->totloop++;
267 
268  if (!(create_flag & BM_CREATE_SKIP_CD)) {
269  if (l_example) {
270  /* no need to copy attrs, just handle customdata */
271  // BM_elem_attrs_copy(bm, bm, l_example, l);
273  CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_example->head.data, &l->head.data);
274  }
275  else {
277  }
278  }
279 
280  return l;
281 }
282 
284  BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte, const eBMCreateFlag create_flag)
285 {
286 #ifdef USE_BMESH_HOLES
287  BMLoopList *lst = BLI_mempool_calloc(bm->looplistpool);
288 #endif
289  BMLoop *l = bm_loop_create(bm, startv, starte, f, NULL /* starte->l */, create_flag);
290 
291  bmesh_radial_loop_append(starte, l);
292 
293 #ifdef USE_BMESH_HOLES
294  lst->first = lst->last = l;
295  BLI_addtail(&f->loops, lst);
296 #else
297  f->l_first = l;
298 #endif
299 
300  return l;
301 }
302 
304  BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges)
305 {
307  BMEdge **edges = BLI_array_alloca(edges, f->len);
308  BMLoop *l_iter;
309  BMLoop *l_first;
310  BMLoop *l_copy;
311  BMFace *f_copy;
312  int i;
313 
314  BLI_assert((bm_dst == bm_src) || (copy_verts && copy_edges));
315 
316  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
317  i = 0;
318  do {
319  if (copy_verts) {
320  verts[i] = BM_vert_create(bm_dst, l_iter->v->co, l_iter->v, BM_CREATE_NOP);
321  }
322  else {
323  verts[i] = l_iter->v;
324  }
325  i++;
326  } while ((l_iter = l_iter->next) != l_first);
327 
328  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
329  i = 0;
330  do {
331  if (copy_edges) {
332  BMVert *v1, *v2;
333 
334  if (l_iter->e->v1 == verts[i]) {
335  v1 = verts[i];
336  v2 = verts[(i + 1) % f->len];
337  }
338  else {
339  v2 = verts[i];
340  v1 = verts[(i + 1) % f->len];
341  }
342 
343  edges[i] = BM_edge_create(bm_dst, v1, v2, l_iter->e, BM_CREATE_NOP);
344  }
345  else {
346  edges[i] = l_iter->e;
347  }
348  i++;
349  } while ((l_iter = l_iter->next) != l_first);
350 
351  f_copy = BM_face_create(bm_dst, verts, edges, f->len, NULL, BM_CREATE_SKIP_CD);
352 
353  BM_elem_attrs_copy(bm_src, bm_dst, f, f_copy);
354 
355  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
356  l_copy = BM_FACE_FIRST_LOOP(f_copy);
357  do {
358  BM_elem_attrs_copy(bm_src, bm_dst, l_iter, l_copy);
359  l_copy = l_copy->next;
360  } while ((l_iter = l_iter->next) != l_first);
361 
362  return f_copy;
363 }
364 
372 {
373  BMFace *f;
374 
375  f = BLI_mempool_alloc(bm->fpool);
376 
377  /* --- assign all members --- */
378  f->head.data = NULL;
379 #ifdef USE_DEBUG_INDEX_MEMCHECK
380  DEBUG_MEMCHECK_INDEX_INVALIDATE(f);
381 #else
382  BM_elem_index_set(f, -1); /* set_ok_invalid */
383 #endif
384 
385  f->head.htype = BM_FACE;
386  f->head.hflag = 0;
387  f->head.api_flag = 0;
388 
389  /* allocate flags */
390  if (bm->use_toolflags) {
392  }
393 
394 #ifdef USE_BMESH_HOLES
395  BLI_listbase_clear(&f->loops);
396 #else
397  f->l_first = NULL;
398 #endif
399  f->len = 0;
400  /* caller must initialize */
401  // zero_v3(f->no);
402  f->mat_nr = 0;
403  /* --- done --- */
404 
405  /* may add to middle of the pool */
409 
410  bm->totface++;
411 
412 #ifdef USE_BMESH_HOLES
413  f->totbounds = 0;
414 #endif
415 
416  return f;
417 }
418 
429  BMVert **verts,
430  BMEdge **edges,
431  const int len,
432  const BMFace *f_example,
433  const eBMCreateFlag create_flag)
434 {
435  BMFace *f = NULL;
436  BMLoop *l, *startl, *lastl;
437  int i;
438 
439  BLI_assert((f_example == NULL) || (f_example->head.htype == BM_FACE));
440  BLI_assert(!(create_flag & 1));
441 
442  if (len == 0) {
443  /* just return NULL for now */
444  return NULL;
445  }
446 
447  if (create_flag & BM_CREATE_NO_DOUBLE) {
448  /* Check if face already exists */
449  f = BM_face_exists(verts, len);
450  if (f != NULL) {
451  return f;
452  }
453  }
454 
456 
457  startl = lastl = bm_face_boundary_add(bm, f, verts[0], edges[0], create_flag);
458 
459  for (i = 1; i < len; i++) {
460  l = bm_loop_create(bm, verts[i], edges[i], f, NULL /* edges[i]->l */, create_flag);
461 
462  bmesh_radial_loop_append(edges[i], l);
463 
464  l->prev = lastl;
465  lastl->next = l;
466  lastl = l;
467  }
468 
469  startl->prev = lastl;
470  lastl->next = startl;
471 
472  f->len = len;
473 
474  if (!(create_flag & BM_CREATE_SKIP_CD)) {
475  if (f_example) {
476  BM_elem_attrs_copy(bm, bm, f_example, f);
477  }
478  else {
480  zero_v3(f->no);
481  }
482  }
483  else {
484  if (f_example) {
485  copy_v3_v3(f->no, f_example->no);
486  }
487  else {
488  zero_v3(f->no);
489  }
490  }
491 
492  BM_CHECK_ELEMENT(f);
493 
494  return f;
495 }
496 
501  BMVert **vert_arr,
502  const int len,
503  const BMFace *f_example,
504  const eBMCreateFlag create_flag,
505  const bool create_edges)
506 {
507  BMEdge **edge_arr = BLI_array_alloca(edge_arr, len);
508 
509  if (create_edges) {
510  BM_edges_from_verts_ensure(bm, edge_arr, vert_arr, len);
511  }
512  else {
513  if (BM_edges_from_verts(edge_arr, vert_arr, len) == false) {
514  return NULL;
515  }
516  }
517 
518  return BM_face_create(bm, vert_arr, edge_arr, len, f_example, create_flag);
519 }
520 
521 #ifndef NDEBUG
522 
529 int bmesh_elem_check(void *element, const char htype)
530 {
531  BMHeader *head = element;
532  enum {
533  IS_NULL = (1 << 0),
534  IS_WRONG_TYPE = (1 << 1),
535 
536  IS_VERT_WRONG_EDGE_TYPE = (1 << 2),
537 
538  IS_EDGE_NULL_DISK_LINK = (1 << 3),
539  IS_EDGE_WRONG_LOOP_TYPE = (1 << 4),
540  IS_EDGE_WRONG_FACE_TYPE = (1 << 5),
541  IS_EDGE_NULL_RADIAL_LINK = (1 << 6),
542  IS_EDGE_ZERO_FACE_LENGTH = (1 << 7),
543 
544  IS_LOOP_WRONG_FACE_TYPE = (1 << 8),
545  IS_LOOP_WRONG_EDGE_TYPE = (1 << 9),
546  IS_LOOP_WRONG_VERT_TYPE = (1 << 10),
547  IS_LOOP_VERT_NOT_IN_EDGE = (1 << 11),
548  IS_LOOP_NULL_CYCLE_LINK = (1 << 12),
549  IS_LOOP_ZERO_FACE_LENGTH = (1 << 13),
550  IS_LOOP_WRONG_FACE_LENGTH = (1 << 14),
551  IS_LOOP_WRONG_RADIAL_LENGTH = (1 << 15),
552 
553  IS_FACE_NULL_LOOP = (1 << 16),
554  IS_FACE_WRONG_LOOP_FACE = (1 << 17),
555  IS_FACE_NULL_EDGE = (1 << 18),
556  IS_FACE_NULL_VERT = (1 << 19),
557  IS_FACE_LOOP_VERT_NOT_IN_EDGE = (1 << 20),
558  IS_FACE_LOOP_WRONG_RADIAL_LENGTH = (1 << 21),
559  IS_FACE_LOOP_WRONG_DISK_LENGTH = (1 << 22),
560  IS_FACE_LOOP_DUPE_LOOP = (1 << 23),
561  IS_FACE_LOOP_DUPE_VERT = (1 << 24),
562  IS_FACE_LOOP_DUPE_EDGE = (1 << 25),
563  IS_FACE_WRONG_LENGTH = (1 << 26),
564  } err = 0;
565 
566  if (!element) {
567  return IS_NULL;
568  }
569 
570  if (head->htype != htype) {
571  return IS_WRONG_TYPE;
572  }
573 
574  switch (htype) {
575  case BM_VERT: {
576  BMVert *v = element;
577  if (v->e && v->e->head.htype != BM_EDGE) {
578  err |= IS_VERT_WRONG_EDGE_TYPE;
579  }
580  break;
581  }
582  case BM_EDGE: {
583  BMEdge *e = element;
584  if (e->v1_disk_link.prev == NULL || e->v2_disk_link.prev == NULL ||
585  e->v1_disk_link.next == NULL || e->v2_disk_link.next == NULL) {
586  err |= IS_EDGE_NULL_DISK_LINK;
587  }
588 
589  if (e->l && e->l->head.htype != BM_LOOP) {
590  err |= IS_EDGE_WRONG_LOOP_TYPE;
591  }
592  if (e->l && e->l->f->head.htype != BM_FACE) {
593  err |= IS_EDGE_WRONG_FACE_TYPE;
594  }
595  if (e->l && (e->l->radial_next == NULL || e->l->radial_prev == NULL)) {
596  err |= IS_EDGE_NULL_RADIAL_LINK;
597  }
598  if (e->l && e->l->f->len <= 0) {
599  err |= IS_EDGE_ZERO_FACE_LENGTH;
600  }
601  break;
602  }
603  case BM_LOOP: {
604  BMLoop *l = element, *l2;
605  int i;
606 
607  if (l->f->head.htype != BM_FACE) {
608  err |= IS_LOOP_WRONG_FACE_TYPE;
609  }
610  if (l->e->head.htype != BM_EDGE) {
611  err |= IS_LOOP_WRONG_EDGE_TYPE;
612  }
613  if (l->v->head.htype != BM_VERT) {
614  err |= IS_LOOP_WRONG_VERT_TYPE;
615  }
616  if (!BM_vert_in_edge(l->e, l->v)) {
617  fprintf(stderr,
618  "%s: fatal bmesh error (vert not in edge)! (bmesh internal error)\n",
619  __func__);
620  err |= IS_LOOP_VERT_NOT_IN_EDGE;
621  }
622 
623  if (l->radial_next == NULL || l->radial_prev == NULL) {
624  err |= IS_LOOP_NULL_CYCLE_LINK;
625  }
626  if (l->f->len <= 0) {
627  err |= IS_LOOP_ZERO_FACE_LENGTH;
628  }
629 
630  /* validate boundary loop -- invalid for hole loops, of course,
631  * but we won't be allowing those for a while yet */
632  l2 = l;
633  i = 0;
634  do {
635  if (i >= BM_NGON_MAX) {
636  break;
637  }
638 
639  i++;
640  } while ((l2 = l2->next) != l);
641 
642  if (i != l->f->len || l2 != l) {
643  err |= IS_LOOP_WRONG_FACE_LENGTH;
644  }
645 
647  err |= IS_LOOP_WRONG_RADIAL_LENGTH;
648  }
649 
650  break;
651  }
652  case BM_FACE: {
653  BMFace *f = element;
654  BMLoop *l_iter;
655  BMLoop *l_first;
656  int len = 0;
657 
658 # ifdef USE_BMESH_HOLES
659  if (!f->loops.first)
660 # else
661  if (!f->l_first)
662 # endif
663  {
664  err |= IS_FACE_NULL_LOOP;
665  }
666  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
667  do {
668  if (l_iter->f != f) {
669  fprintf(stderr,
670  "%s: loop inside one face points to another! (bmesh internal error)\n",
671  __func__);
672  err |= IS_FACE_WRONG_LOOP_FACE;
673  }
674 
675  if (!l_iter->e) {
676  err |= IS_FACE_NULL_EDGE;
677  }
678  if (!l_iter->v) {
679  err |= IS_FACE_NULL_VERT;
680  }
681  if (l_iter->e && l_iter->v) {
682  if (!BM_vert_in_edge(l_iter->e, l_iter->v) ||
683  !BM_vert_in_edge(l_iter->e, l_iter->next->v)) {
684  err |= IS_FACE_LOOP_VERT_NOT_IN_EDGE;
685  }
686 
687  if (!bmesh_radial_validate(bmesh_radial_length(l_iter), l_iter)) {
688  err |= IS_FACE_LOOP_WRONG_RADIAL_LENGTH;
689  }
690 
691  if (bmesh_disk_count_at_most(l_iter->v, 2) < 2) {
692  err |= IS_FACE_LOOP_WRONG_DISK_LENGTH;
693  }
694  }
695 
696  /* check for duplicates */
698  err |= IS_FACE_LOOP_DUPE_LOOP;
699  }
701  if (l_iter->v) {
702  if (BM_ELEM_API_FLAG_TEST(l_iter->v, _FLAG_ELEM_CHECK)) {
703  err |= IS_FACE_LOOP_DUPE_VERT;
704  }
706  }
707  if (l_iter->e) {
708  if (BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_ELEM_CHECK)) {
709  err |= IS_FACE_LOOP_DUPE_EDGE;
710  }
712  }
713 
714  len++;
715  } while ((l_iter = l_iter->next) != l_first);
716 
717  /* cleanup duplicates flag */
718  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
719  do {
721  if (l_iter->v) {
723  }
724  if (l_iter->e) {
726  }
727  } while ((l_iter = l_iter->next) != l_first);
728 
729  if (len != f->len) {
730  err |= IS_FACE_WRONG_LENGTH;
731  }
732  break;
733  }
734  default:
735  BLI_assert(0);
736  break;
737  }
738 
739  BMESH_ASSERT(err == 0);
740 
741  return err;
742 }
743 
744 #endif /* NDEBUG */
745 
751 {
752  bm->totvert--;
756 
758 
759  if (v->head.data) {
761  }
762 
763  if (bm->vtoolflagpool) {
765  }
767 }
768 
774 {
775  bm->totedge--;
779 
781 
782  if (e->head.data) {
784  }
785 
786  if (bm->etoolflagpool) {
788  }
790 }
791 
796 static void bm_kill_only_face(BMesh *bm, BMFace *f)
797 {
798  if (bm->act_face == f) {
799  bm->act_face = NULL;
800  }
801 
802  bm->totface--;
806 
808 
809  if (f->head.data) {
811  }
812 
813  if (bm->ftoolflagpool) {
814  BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f)->oflags);
815  }
817 }
818 
824 {
825  bm->totloop--;
828 
829  if (l->head.data) {
831  }
832 
834 }
835 
841 {
842  BMEdge **edges = BLI_array_alloca(edges, f->len);
843  BMLoop *l_iter;
844  BMLoop *l_first;
845  int i = 0;
846 
847  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
848  do {
849  edges[i++] = l_iter->e;
850  } while ((l_iter = l_iter->next) != l_first);
851 
852  for (i = 0; i < f->len; i++) {
853  BM_edge_kill(bm, edges[i]);
854  }
855 }
856 
862 {
864  BMLoop *l_iter;
865  BMLoop *l_first;
866  int i = 0;
867 
868  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
869  do {
870  verts[i++] = l_iter->v;
871  } while ((l_iter = l_iter->next) != l_first);
872 
873  for (i = 0; i < f->len; i++) {
874  BM_vert_kill(bm, verts[i]);
875  }
876 }
877 
882 {
883 #ifdef USE_BMESH_HOLES
884  BMLoopList *ls, *ls_next;
885 #endif
886 
887 #ifdef NDEBUG
888  /* check length since we may be removing degenerate faces */
889  if (f->len >= 3) {
890  BM_CHECK_ELEMENT(f);
891  }
892 #endif
893 
894 #ifdef USE_BMESH_HOLES
895  for (ls = f->loops.first; ls; ls = ls_next)
896 #else
897  if (f->l_first)
898 #endif
899  {
900  BMLoop *l_iter, *l_next, *l_first;
901 
902 #ifdef USE_BMESH_HOLES
903  ls_next = ls->next;
904  l_iter = l_first = ls->first;
905 #else
906  l_iter = l_first = f->l_first;
907 #endif
908 
909  do {
910  l_next = l_iter->next;
911 
912  bmesh_radial_loop_remove(l_iter->e, l_iter);
913  bm_kill_only_loop(bm, l_iter);
914 
915  } while ((l_iter = l_next) != l_first);
916 
917 #ifdef USE_BMESH_HOLES
918  BLI_mempool_free(bm->looplistpool, ls);
919 #endif
920  }
921 
922  bm_kill_only_face(bm, f);
923 }
924 
930 {
931 #ifdef USE_BMESH_HOLES
932  BMLoopList *ls, *ls_next;
933 #endif
934 
935  BM_CHECK_ELEMENT(f);
936 
937 #ifdef USE_BMESH_HOLES
938  for (ls = f->loops.first; ls; ls = ls_next)
939 #else
940  if (f->l_first)
941 #endif
942  {
943  BMLoop *l_iter, *l_next, *l_first;
944 
945 #ifdef USE_BMESH_HOLES
946  ls_next = ls->next;
947  l_iter = l_first = ls->first;
948 #else
949  l_iter = l_first = f->l_first;
950 #endif
951 
952  do {
953  BMEdge *e;
954  l_next = l_iter->next;
955 
956  e = l_iter->e;
957  bmesh_radial_loop_remove(e, l_iter);
958  bm_kill_only_loop(bm, l_iter);
959 
960  if (e->l == NULL) {
961  BMVert *v1 = e->v1, *v2 = e->v2;
962 
963  bmesh_disk_edge_remove(e, e->v1);
964  bmesh_disk_edge_remove(e, e->v2);
966 
967  if (v1->e == NULL) {
969  }
970  if (v2->e == NULL) {
972  }
973  }
974  } while ((l_iter = l_next) != l_first);
975 
976 #ifdef USE_BMESH_HOLES
977  BLI_mempool_free(bm->looplistpool, ls);
978 #endif
979  }
980 
981  bm_kill_only_face(bm, f);
982 }
983 
988 {
989  while (e->l) {
990  BM_face_kill(bm, e->l->f);
991  }
992 
993  bmesh_disk_edge_remove(e, e->v1);
994  bmesh_disk_edge_remove(e, e->v2);
995 
997 }
998 
1003 {
1004  while (v->e) {
1005  BM_edge_kill(bm, v->e);
1006  }
1007 
1009 }
1010 
1011 /********** private disk and radial cycle functions ********** */
1012 
1017 {
1018  BMLoop *l_first = l;
1019  int i = 0;
1020 
1021  do {
1022  i++;
1023  } while ((l = l->next) != l_first);
1024 
1025  return i;
1026 }
1027 
1038  BMFace *f,
1039  const int cd_loop_mdisp_offset,
1040  const bool use_loop_mdisp_flip)
1041 {
1042  BMLoop *l_first = f->l_first;
1043 
1044  /* track previous cycles radial state */
1045  BMEdge *e_prev = l_first->prev->e;
1046  BMLoop *l_prev_radial_next = l_first->prev->radial_next;
1047  BMLoop *l_prev_radial_prev = l_first->prev->radial_prev;
1048  bool is_prev_boundary = l_prev_radial_next == l_prev_radial_next->radial_next;
1049 
1050  BMLoop *l_iter = l_first;
1051  do {
1052  BMEdge *e_iter = l_iter->e;
1053  BMLoop *l_iter_radial_next = l_iter->radial_next;
1054  BMLoop *l_iter_radial_prev = l_iter->radial_prev;
1055  bool is_iter_boundary = l_iter_radial_next == l_iter_radial_next->radial_next;
1056 
1057 #if 0
1058  bmesh_radial_loop_remove(e_iter, l_iter);
1059  bmesh_radial_loop_append(e_prev, l_iter);
1060 #else
1061  /* inline loop reversal */
1062  if (is_prev_boundary) {
1063  /* boundary */
1064  l_iter->radial_next = l_iter;
1065  l_iter->radial_prev = l_iter;
1066  }
1067  else {
1068  /* non-boundary, replace radial links */
1069  l_iter->radial_next = l_prev_radial_next;
1070  l_iter->radial_prev = l_prev_radial_prev;
1071  l_prev_radial_next->radial_prev = l_iter;
1072  l_prev_radial_prev->radial_next = l_iter;
1073  }
1074 
1075  if (e_iter->l == l_iter) {
1076  e_iter->l = l_iter->next;
1077  }
1078  l_iter->e = e_prev;
1079 #endif
1080 
1081  SWAP(BMLoop *, l_iter->next, l_iter->prev);
1082 
1083  if (cd_loop_mdisp_offset != -1) {
1084  MDisps *md = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset);
1085  BKE_mesh_mdisp_flip(md, use_loop_mdisp_flip);
1086  }
1087 
1088  e_prev = e_iter;
1089  l_prev_radial_next = l_iter_radial_next;
1090  l_prev_radial_prev = l_iter_radial_prev;
1091  is_prev_boundary = is_iter_boundary;
1092 
1093  /* step to next (now swapped) */
1094  } while ((l_iter = l_iter->prev) != l_first);
1095 
1096 #ifndef NDEBUG
1097  /* validate radial */
1098  int i;
1099  for (i = 0, l_iter = l_first; i < f->len; i++, l_iter = l_iter->next) {
1100  BM_CHECK_ELEMENT(l_iter);
1101  BM_CHECK_ELEMENT(l_iter->e);
1102  BM_CHECK_ELEMENT(l_iter->v);
1103  BM_CHECK_ELEMENT(l_iter->f);
1104  }
1105 
1106  BM_CHECK_ELEMENT(f);
1107 #endif
1108 
1109  /* Loop indices are no more valid! */
1111 }
1112 
1113 static void bm_elements_systag_enable(void *veles, int tot, const char api_flag)
1114 {
1115  BMHeader **eles = veles;
1116  int i;
1117 
1118  for (i = 0; i < tot; i++) {
1119  BM_ELEM_API_FLAG_ENABLE((BMElemF *)eles[i], api_flag);
1120  }
1121 }
1122 
1123 static void bm_elements_systag_disable(void *veles, int tot, const char api_flag)
1124 {
1125  BMHeader **eles = veles;
1126  int i;
1127 
1128  for (i = 0; i < tot; i++) {
1129  BM_ELEM_API_FLAG_DISABLE((BMElemF *)eles[i], api_flag);
1130  }
1131 }
1132 
1133 static int bm_loop_systag_count_radial(BMLoop *l, const char api_flag)
1134 {
1135  BMLoop *l_iter = l;
1136  int i = 0;
1137  do {
1138  i += BM_ELEM_API_FLAG_TEST(l_iter->f, api_flag) ? 1 : 0;
1139  } while ((l_iter = l_iter->radial_next) != l);
1140 
1141  return i;
1142 }
1143 
1144 static int UNUSED_FUNCTION(bm_vert_systag_count_disk)(BMVert *v, const char api_flag)
1145 {
1146  BMEdge *e = v->e;
1147  int i = 0;
1148 
1149  if (!e) {
1150  return 0;
1151  }
1152 
1153  do {
1154  i += BM_ELEM_API_FLAG_TEST(e, api_flag) ? 1 : 0;
1155  } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
1156 
1157  return i;
1158 }
1159 
1164 static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag)
1165 {
1166  BMEdge *e = v->e;
1167 
1168  if (!e) {
1169  return false;
1170  }
1171 
1172  do {
1173  BMLoop *l = e->l;
1174 
1175  if (!l) {
1176  return false;
1177  }
1178 
1179  if (BM_edge_is_boundary(l->e)) {
1180  return false;
1181  }
1182 
1183  do {
1184  if (!BM_ELEM_API_FLAG_TEST(l->f, api_flag)) {
1185  return false;
1186  }
1187  } while ((l = l->radial_next) != e->l);
1188  } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
1189 
1190  return true;
1191 }
1192 
1193 /* Mid-level Topology Manipulation Functions */
1194 
1209 BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
1210 {
1211  BMFace *f, *f_new;
1212 #ifdef USE_BMESH_HOLES
1213  BMLoopList *lst;
1214  ListBase holes = {NULL, NULL};
1215 #endif
1216  BMLoop *l_iter;
1217  BMLoop *l_first;
1218  BMEdge **edges = NULL;
1219  BMEdge **deledges = NULL;
1220  BMVert **delverts = NULL;
1224  BMVert *v1 = NULL, *v2 = NULL;
1225  int i;
1226  const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
1227 
1228  if (UNLIKELY(!totface)) {
1229  BMESH_ASSERT(0);
1230  return NULL;
1231  }
1232 
1233  if (totface == 1) {
1234  return faces[0];
1235  }
1236 
1238 
1239  for (i = 0; i < totface; i++) {
1240  f = faces[i];
1241  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1242  do {
1243  int rlen = bm_loop_systag_count_radial(l_iter, _FLAG_JF);
1244 
1245  if (rlen > 2) {
1246  /* Input faces do not form a contiguous manifold region */
1247  goto error;
1248  }
1249  else if (rlen == 1) {
1250  BLI_array_append(edges, l_iter->e);
1251 
1252  if (!v1) {
1253  v1 = l_iter->v;
1254  v2 = BM_edge_other_vert(l_iter->e, l_iter->v);
1255  }
1256  }
1257  else if (rlen == 2) {
1258  const bool d1 = bm_vert_is_manifold_flagged(l_iter->e->v1, _FLAG_JF);
1259  const bool d2 = bm_vert_is_manifold_flagged(l_iter->e->v2, _FLAG_JF);
1260 
1261  if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) {
1262  /* don't remove an edge it makes up the side of another face
1263  * else this will remove the face as well - campbell */
1264  if (!BM_edge_face_count_is_over(l_iter->e, 2)) {
1265  if (do_del) {
1266  BLI_array_append(deledges, l_iter->e);
1267  }
1269  }
1270  }
1271  else {
1272  if (d1 && !BM_ELEM_API_FLAG_TEST(l_iter->e->v1, _FLAG_JF)) {
1273  if (do_del) {
1274  BLI_array_append(delverts, l_iter->e->v1);
1275  }
1276  BM_ELEM_API_FLAG_ENABLE(l_iter->e->v1, _FLAG_JF);
1277  }
1278 
1279  if (d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e->v2, _FLAG_JF)) {
1280  if (do_del) {
1281  BLI_array_append(delverts, l_iter->e->v2);
1282  }
1283  BM_ELEM_API_FLAG_ENABLE(l_iter->e->v2, _FLAG_JF);
1284  }
1285  }
1286  }
1287  } while ((l_iter = l_iter->next) != l_first);
1288 
1289 #ifdef USE_BMESH_HOLES
1290  for (lst = f->loops.first; lst; lst = lst->next) {
1291  if (lst == f->loops.first) {
1292  continue;
1293  }
1294 
1295  BLI_remlink(&f->loops, lst);
1296  BLI_addtail(&holes, lst);
1297  }
1298 #endif
1299  }
1300 
1301  /* create region face */
1302  f_new = BLI_array_len(edges) ?
1304  bm, v1, v2, edges, BLI_array_len(edges), faces[0], BM_CREATE_NOP) :
1305  NULL;
1306  if (UNLIKELY(f_new == NULL)) {
1307  /* Invalid boundary region to join faces */
1308  goto error;
1309  }
1310 
1311  /* copy over loop data */
1312  l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
1313  do {
1314  BMLoop *l2 = l_iter->radial_next;
1315 
1316  do {
1317  if (BM_ELEM_API_FLAG_TEST(l2->f, _FLAG_JF)) {
1318  break;
1319  }
1320  l2 = l2->radial_next;
1321  } while (l2 != l_iter);
1322 
1323  if (l2 != l_iter) {
1324  /* loops share an edge, shared vert depends on winding */
1325  if (l2->v != l_iter->v) {
1326  l2 = l2->next;
1327  }
1328  BLI_assert(l_iter->v == l2->v);
1329 
1330  BM_elem_attrs_copy(bm, bm, l2, l_iter);
1331  }
1332  } while ((l_iter = l_iter->next) != l_first);
1333 
1334 #ifdef USE_BMESH_HOLES
1335  /* add holes */
1336  BLI_movelisttolist(&f_new->loops, &holes);
1337 
1338  /* update loop face pointer */
1339  for (lst = f_new->loops.first; lst; lst = lst->next) {
1340  l_iter = l_first = lst->first;
1341  do {
1342  l_iter->f = f_new;
1343  } while ((l_iter = l_iter->next) != l_first);
1344  }
1345 #endif
1346 
1349 
1350  /* handle multi-res data */
1351  if (cd_loop_mdisp_offset != -1) {
1352  float f_center[3];
1353  float(*faces_center)[3] = BLI_array_alloca(faces_center, totface);
1354 
1355  BM_face_calc_center_median(f_new, f_center);
1356  for (i = 0; i < totface; i++) {
1357  BM_face_calc_center_median(faces[i], faces_center[i]);
1358  }
1359 
1360  l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
1361  do {
1362  for (i = 0; i < totface; i++) {
1364  bm, l_iter, faces[i], f_center, faces_center[i], cd_loop_mdisp_offset);
1365  }
1366  } while ((l_iter = l_iter->next) != l_first);
1367  }
1368 
1369  /* delete old geometry */
1370  if (do_del) {
1371  for (i = 0; i < BLI_array_len(deledges); i++) {
1372  BM_edge_kill(bm, deledges[i]);
1373  }
1374 
1375  for (i = 0; i < BLI_array_len(delverts); i++) {
1376  BM_vert_kill(bm, delverts[i]);
1377  }
1378  }
1379  else {
1380  /* otherwise we get both old and new faces */
1381  for (i = 0; i < totface; i++) {
1382  BM_face_kill(bm, faces[i]);
1383  }
1384  }
1385 
1386  BLI_array_free(edges);
1387  BLI_array_free(deledges);
1388  BLI_array_free(delverts);
1389 
1390  BM_CHECK_ELEMENT(f_new);
1391  return f_new;
1392 
1393 error:
1395  BLI_array_free(edges);
1396  BLI_array_free(deledges);
1397  BLI_array_free(delverts);
1398 
1399  return NULL;
1400 }
1401 
1403 {
1404  BMFace *f;
1405 #ifdef USE_BMESH_HOLES
1406  BMLoopList *lst;
1407 #endif
1408 
1410 
1411 #ifdef USE_BMESH_HOLES
1412  lst = BLI_mempool_calloc(bm->looplistpool);
1413  BLI_addtail(&f->loops, lst);
1414 #endif
1415 
1416 #ifdef USE_BMESH_HOLES
1417  f->totbounds = 1;
1418 #endif
1419 
1420  BM_elem_attrs_copy(bm, bm, f_example, f);
1421 
1422  return f;
1423 }
1424 
1464  BMFace *f,
1465  BMLoop *l_v1,
1466  BMLoop *l_v2,
1467  BMLoop **r_l,
1468 #ifdef USE_BMESH_HOLES
1469  ListBase *holes,
1470 #endif
1471  BMEdge *e_example,
1472  const bool no_double)
1473 {
1474 #ifdef USE_BMESH_HOLES
1475  BMLoopList *lst, *lst2;
1476 #else
1477  int first_loop_f1;
1478 #endif
1479 
1480  BMFace *f2;
1481  BMLoop *l_iter, *l_first;
1482  BMLoop *l_f1 = NULL, *l_f2 = NULL;
1483  BMEdge *e;
1484  BMVert *v1 = l_v1->v, *v2 = l_v2->v;
1485  int f1len, f2len;
1486 
1487  BLI_assert(f == l_v1->f && f == l_v2->f);
1488 
1489  /* allocate new edge between v1 and v2 */
1490  e = BM_edge_create(bm, v1, v2, e_example, no_double ? BM_CREATE_NO_DOUBLE : BM_CREATE_NOP);
1491 
1492  f2 = bm_face_create__sfme(bm, f);
1493  l_f1 = bm_loop_create(bm, v2, e, f, l_v2, 0);
1494  l_f2 = bm_loop_create(bm, v1, e, f2, l_v1, 0);
1495 
1496  l_f1->prev = l_v2->prev;
1497  l_f2->prev = l_v1->prev;
1498  l_v2->prev->next = l_f1;
1499  l_v1->prev->next = l_f2;
1500 
1501  l_f1->next = l_v1;
1502  l_f2->next = l_v2;
1503  l_v1->prev = l_f1;
1504  l_v2->prev = l_f2;
1505 
1506 #ifdef USE_BMESH_HOLES
1507  lst = f->loops.first;
1508  lst2 = f2->loops.first;
1509 
1510  lst2->first = lst2->last = l_f2;
1511  lst->first = lst->last = l_f1;
1512 #else
1513  /* find which of the faces the original first loop is in */
1514  l_iter = l_first = l_f1;
1515  first_loop_f1 = 0;
1516  do {
1517  if (l_iter == f->l_first) {
1518  first_loop_f1 = 1;
1519  }
1520  } while ((l_iter = l_iter->next) != l_first);
1521 
1522  if (first_loop_f1) {
1523  /* original first loop was in f1, find a suitable first loop for f2
1524  * which is as similar as possible to f1. the order matters for tools
1525  * such as duplifaces. */
1526  if (f->l_first->prev == l_f1) {
1527  f2->l_first = l_f2->prev;
1528  }
1529  else if (f->l_first->next == l_f1) {
1530  f2->l_first = l_f2->next;
1531  }
1532  else {
1533  f2->l_first = l_f2;
1534  }
1535  }
1536  else {
1537  /* original first loop was in f2, further do same as above */
1538  f2->l_first = f->l_first;
1539 
1540  if (f->l_first->prev == l_f2) {
1541  f->l_first = l_f1->prev;
1542  }
1543  else if (f->l_first->next == l_f2) {
1544  f->l_first = l_f1->next;
1545  }
1546  else {
1547  f->l_first = l_f1;
1548  }
1549  }
1550 #endif
1551 
1552  /* validate both loop */
1553  /* I don't know how many loops are supposed to be in each face at this point! FIXME */
1554 
1555  /* go through all of f2's loops and make sure they point to it properly */
1556  l_iter = l_first = BM_FACE_FIRST_LOOP(f2);
1557  f2len = 0;
1558  do {
1559  l_iter->f = f2;
1560  f2len++;
1561  } while ((l_iter = l_iter->next) != l_first);
1562 
1563  /* link up the new loops into the new edges radial */
1564  bmesh_radial_loop_append(e, l_f1);
1565  bmesh_radial_loop_append(e, l_f2);
1566 
1567  f2->len = f2len;
1568 
1569  f1len = 0;
1570  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1571  do {
1572  f1len++;
1573  } while ((l_iter = l_iter->next) != l_first);
1574 
1575  f->len = f1len;
1576 
1577  if (r_l) {
1578  *r_l = l_f2;
1579  }
1580 
1581 #ifdef USE_BMESH_HOLES
1582  if (holes) {
1583  BLI_movelisttolist(&f2->loops, holes);
1584  }
1585  else {
1586  /* this code is not significant until holes actually work */
1587  // printf("warning: call to split face euler without holes argument; holes will be tossed.\n");
1588  for (lst = f->loops.last; lst != f->loops.first; lst = lst2) {
1589  lst2 = lst->prev;
1590  BLI_mempool_free(bm->looplistpool, lst);
1591  }
1592  }
1593 #endif
1594 
1596  BM_CHECK_ELEMENT(f);
1597  BM_CHECK_ELEMENT(f2);
1598 
1599  return f2;
1600 }
1601 
1621 {
1622  BMLoop *l_next;
1623  BMEdge *e_new;
1624  BMVert *v_new, *v_old;
1625 #ifndef NDEBUG
1626  int valence1, valence2;
1627  bool edok;
1628  int i;
1629 #endif
1630 
1631  BLI_assert(BM_vert_in_edge(e, tv) != false);
1632 
1633  v_old = BM_edge_other_vert(e, tv);
1634 
1635 #ifndef NDEBUG
1636  valence1 = bmesh_disk_count(v_old);
1637  valence2 = bmesh_disk_count(tv);
1638 #endif
1639 
1640  /* order of 'e_new' verts should match 'e'
1641  * (so extruded faces don't flip) */
1642  v_new = BM_vert_create(bm, tv->co, tv, BM_CREATE_NOP);
1643  e_new = BM_edge_create(bm, tv, v_new, e, BM_CREATE_NOP);
1644 
1645  bmesh_disk_edge_remove(e_new, tv);
1646  bmesh_disk_edge_remove(e_new, v_new);
1647 
1648  bmesh_disk_vert_replace(e, v_new, tv);
1649 
1650  /* add e_new to v_new's disk cycle */
1651  bmesh_disk_edge_append(e_new, v_new);
1652 
1653  /* add e_new to tv's disk cycle */
1654  bmesh_disk_edge_append(e_new, tv);
1655 
1656 #ifndef NDEBUG
1657  /* verify disk cycles */
1658  edok = bmesh_disk_validate(valence1, v_old->e, v_old);
1659  BMESH_ASSERT(edok != false);
1660  edok = bmesh_disk_validate(valence2, tv->e, tv);
1661  BMESH_ASSERT(edok != false);
1662  edok = bmesh_disk_validate(2, v_new->e, v_new);
1663  BMESH_ASSERT(edok != false);
1664 #endif
1665 
1666  /* Split the radial cycle if present */
1667  l_next = e->l;
1668  e->l = NULL;
1669  if (l_next) {
1670  BMLoop *l_new, *l;
1671 #ifndef NDEBUG
1672  int radlen = bmesh_radial_length(l_next);
1673 #endif
1674  bool is_first = true;
1675 
1676  /* Take the next loop. Remove it from radial. Split it. Append to appropriate radials */
1677  while (l_next) {
1678  l = l_next;
1679  l->f->len++;
1680  l_next = l_next != l_next->radial_next ? l_next->radial_next : NULL;
1682 
1683  l_new = bm_loop_create(bm, NULL, NULL, l->f, l, 0);
1684  l_new->prev = l;
1685  l_new->next = l->next;
1686  l_new->prev->next = l_new;
1687  l_new->next->prev = l_new;
1688  l_new->v = v_new;
1689 
1690  /* assign the correct edge to the correct loop */
1691  if (BM_verts_in_edge(l_new->v, l_new->next->v, e)) {
1692  l_new->e = e;
1693  l->e = e_new;
1694 
1695  /* append l into e_new's rad cycle */
1696  if (is_first) {
1697  is_first = false;
1698  l->radial_next = l->radial_prev = NULL;
1699  }
1700 
1701  bmesh_radial_loop_append(l_new->e, l_new);
1703  }
1704  else if (BM_verts_in_edge(l_new->v, l_new->next->v, e_new)) {
1705  l_new->e = e_new;
1706  l->e = e;
1707 
1708  /* append l into e_new's rad cycle */
1709  if (is_first) {
1710  is_first = false;
1711  l->radial_next = l->radial_prev = NULL;
1712  }
1713 
1714  bmesh_radial_loop_append(l_new->e, l_new);
1716  }
1717  }
1718 
1719 #ifndef NDEBUG
1720  /* verify length of radial cycle */
1721  edok = bmesh_radial_validate(radlen, e->l);
1722  BMESH_ASSERT(edok != false);
1723  edok = bmesh_radial_validate(radlen, e_new->l);
1724  BMESH_ASSERT(edok != false);
1725 
1726  /* verify loop->v and loop->next->v pointers for e */
1727  for (i = 0, l = e->l; i < radlen; i++, l = l->radial_next) {
1728  BMESH_ASSERT(l->e == e);
1729  // BMESH_ASSERT(l->radial_next == l);
1730  BMESH_ASSERT(!(l->prev->e != e_new && l->next->e != e_new));
1731 
1732  edok = BM_verts_in_edge(l->v, l->next->v, e);
1733  BMESH_ASSERT(edok != false);
1734  BMESH_ASSERT(l->v != l->next->v);
1735  BMESH_ASSERT(l->e != l->next->e);
1736 
1737  /* verify loop cycle for kloop->f */
1739  BM_CHECK_ELEMENT(l->v);
1740  BM_CHECK_ELEMENT(l->e);
1741  BM_CHECK_ELEMENT(l->f);
1742  }
1743  /* verify loop->v and loop->next->v pointers for e_new */
1744  for (i = 0, l = e_new->l; i < radlen; i++, l = l->radial_next) {
1745  BMESH_ASSERT(l->e == e_new);
1746  // BMESH_ASSERT(l->radial_next == l);
1747  BMESH_ASSERT(!(l->prev->e != e && l->next->e != e));
1748  edok = BM_verts_in_edge(l->v, l->next->v, e_new);
1749  BMESH_ASSERT(edok != false);
1750  BMESH_ASSERT(l->v != l->next->v);
1751  BMESH_ASSERT(l->e != l->next->e);
1752 
1754  BM_CHECK_ELEMENT(l->v);
1755  BM_CHECK_ELEMENT(l->e);
1756  BM_CHECK_ELEMENT(l->f);
1757  }
1758 #endif
1759  }
1760 
1761  BM_CHECK_ELEMENT(e_new);
1762  BM_CHECK_ELEMENT(v_new);
1763  BM_CHECK_ELEMENT(v_old);
1765  BM_CHECK_ELEMENT(tv);
1766 
1767  if (r_e) {
1768  *r_e = e_new;
1769  }
1770  return v_new;
1771 }
1772 
1804  BMEdge *e_kill,
1805  BMVert *v_kill,
1806  const bool do_del,
1807  const bool check_edge_exists,
1808  const bool kill_degenerate_faces,
1809  const bool kill_duplicate_faces)
1810 {
1811  BMEdge *e_old;
1812  BMVert *v_old, *v_target;
1813  BMLoop *l_kill;
1814 #ifndef NDEBUG
1815  int radlen, i;
1816  bool edok;
1817 #endif
1818 
1819  BLI_assert(BM_vert_in_edge(e_kill, v_kill));
1820 
1821  if (BM_vert_in_edge(e_kill, v_kill) == 0) {
1822  return NULL;
1823  }
1824 
1825  if (bmesh_disk_count_at_most(v_kill, 3) == 2) {
1826 #ifndef NDEBUG
1827  int valence1, valence2;
1828  BMLoop *l;
1829 #endif
1830 
1831  e_old = bmesh_disk_edge_next(e_kill, v_kill);
1832  v_target = BM_edge_other_vert(e_kill, v_kill);
1833  v_old = BM_edge_other_vert(e_old, v_kill);
1834 
1835  /* check for double edges */
1836  if (BM_verts_in_edge(v_kill, v_target, e_old)) {
1837  return NULL;
1838  }
1839 
1840  BMEdge *e_splice;
1841  BLI_SMALLSTACK_DECLARE(faces_degenerate, BMFace *);
1842  BMLoop *l_kill_next;
1843 
1844  /* Candidates for being duplicate. */
1845  BLI_SMALLSTACK_DECLARE(faces_duplicate_candidate, BMFace *);
1846 
1847 #ifndef NDEBUG
1848  /* For verification later, count valence of 'v_old' and 'v_target' */
1849  valence1 = bmesh_disk_count(v_old);
1850  valence2 = bmesh_disk_count(v_target);
1851 #endif
1852 
1853  if (check_edge_exists) {
1854  e_splice = BM_edge_exists(v_target, v_old);
1855  }
1856 
1857  bmesh_disk_vert_replace(e_old, v_target, v_kill);
1858 
1859  /* remove e_kill from 'v_target's disk cycle */
1860  bmesh_disk_edge_remove(e_kill, v_target);
1861 
1862 #ifndef NDEBUG
1863  /* deal with radial cycle of e_kill */
1864  radlen = bmesh_radial_length(e_kill->l);
1865 #endif
1866  if (e_kill->l) {
1867 
1868  /* fix the neighboring loops of all loops in e_kill's radial cycle */
1869  l_kill = e_kill->l;
1870  do {
1871  /* relink loops and fix vertex pointer */
1872  if (l_kill->next->v == v_kill) {
1873  l_kill->next->v = v_target;
1874  }
1875 
1876  l_kill->next->prev = l_kill->prev;
1877  l_kill->prev->next = l_kill->next;
1878  if (BM_FACE_FIRST_LOOP(l_kill->f) == l_kill) {
1879  BM_FACE_FIRST_LOOP(l_kill->f) = l_kill->next;
1880  }
1881 
1882  /* fix len attribute of face */
1883  l_kill->f->len--;
1884  if (kill_degenerate_faces && (l_kill->f->len < 3)) {
1885  BLI_SMALLSTACK_PUSH(faces_degenerate, l_kill->f);
1886  }
1887  else {
1888  /* The duplicate test isn't reliable at this point as `e_splice` might be set,
1889  * so the duplicate test needs to run once the edge has been spliced. */
1890  if (kill_duplicate_faces) {
1891  BLI_SMALLSTACK_PUSH(faces_duplicate_candidate, l_kill->f);
1892  }
1893  }
1894  l_kill_next = l_kill->radial_next;
1895 
1896  bm_kill_only_loop(bm, l_kill);
1897 
1898  } while ((l_kill = l_kill_next) != e_kill->l);
1899  /* `e_kill->l` is invalid but the edge is freed next. */
1900 #ifndef NDEBUG
1901  /* Validate radial cycle of e_old */
1902  edok = bmesh_radial_validate(radlen, e_old->l);
1903  BMESH_ASSERT(edok != false);
1904 #endif
1905  }
1906  /* deallocate edge */
1907  bm_kill_only_edge(bm, e_kill);
1908 
1909  /* deallocate vertex */
1910  if (do_del) {
1911  bm_kill_only_vert(bm, v_kill);
1912  }
1913  else {
1914  v_kill->e = NULL;
1915  }
1916 
1917 #ifndef NDEBUG
1918  /* Validate disk cycle lengths of 'v_old', 'v_target' are unchanged */
1919  edok = bmesh_disk_validate(valence1, v_old->e, v_old);
1920  BMESH_ASSERT(edok != false);
1921  edok = bmesh_disk_validate(valence2, v_target->e, v_target);
1922  BMESH_ASSERT(edok != false);
1923 
1924  /* Validate loop cycle of all faces attached to 'e_old' */
1925  for (i = 0, l = e_old->l; i < radlen; i++, l = l->radial_next) {
1926  BMESH_ASSERT(l->e == e_old);
1927  edok = BM_verts_in_edge(l->v, l->next->v, e_old);
1928  BMESH_ASSERT(edok != false);
1929  edok = bmesh_loop_validate(l->f);
1930  BMESH_ASSERT(edok != false);
1931 
1933  BM_CHECK_ELEMENT(l->v);
1934  BM_CHECK_ELEMENT(l->e);
1935  BM_CHECK_ELEMENT(l->f);
1936  }
1937 #endif
1938  if (check_edge_exists) {
1939  if (e_splice) {
1940  /* removes e_splice */
1941  BM_edge_splice(bm, e_old, e_splice);
1942  }
1943  }
1944 
1945  if (kill_degenerate_faces) {
1946  BMFace *f_kill;
1947  while ((f_kill = BLI_SMALLSTACK_POP(faces_degenerate))) {
1948  BM_face_kill(bm, f_kill);
1949  }
1950  }
1951 
1952  if (kill_duplicate_faces) {
1953  BMFace *f_kill;
1954  while ((f_kill = BLI_SMALLSTACK_POP(faces_duplicate_candidate))) {
1955  if (BM_face_find_double(f_kill)) {
1956  BM_face_kill(bm, f_kill);
1957  }
1958  }
1959  }
1960 
1961  BM_CHECK_ELEMENT(v_old);
1962  BM_CHECK_ELEMENT(v_target);
1963  BM_CHECK_ELEMENT(e_old);
1964 
1965  return e_old;
1966  }
1967  return NULL;
1968 }
1969 
1989  BMEdge *e_kill,
1990  BMVert *v_kill,
1991  const bool do_del,
1992  const bool check_edge_exists,
1993  const bool kill_degenerate_faces)
1994 {
1995  BLI_SMALLSTACK_DECLARE(faces_degenerate, BMFace *);
1996  BMVert *v_target = BM_edge_other_vert(e_kill, v_kill);
1997 
1998  BLI_assert(BM_vert_in_edge(e_kill, v_kill));
1999 
2000  if (e_kill->l) {
2001  BMLoop *l_kill, *l_first, *l_kill_next;
2002  l_kill = l_first = e_kill->l;
2003  do {
2004  /* relink loops and fix vertex pointer */
2005  if (l_kill->next->v == v_kill) {
2006  l_kill->next->v = v_target;
2007  }
2008 
2009  l_kill->next->prev = l_kill->prev;
2010  l_kill->prev->next = l_kill->next;
2011  if (BM_FACE_FIRST_LOOP(l_kill->f) == l_kill) {
2012  BM_FACE_FIRST_LOOP(l_kill->f) = l_kill->next;
2013  }
2014 
2015  /* fix len attribute of face */
2016  l_kill->f->len--;
2017  if (kill_degenerate_faces) {
2018  if (l_kill->f->len < 3) {
2019  BLI_SMALLSTACK_PUSH(faces_degenerate, l_kill->f);
2020  }
2021  }
2022  l_kill_next = l_kill->radial_next;
2023 
2024  bm_kill_only_loop(bm, l_kill);
2025 
2026  } while ((l_kill = l_kill_next) != l_first);
2027 
2028  e_kill->l = NULL;
2029  }
2030 
2031  BM_edge_kill(bm, e_kill);
2032  BM_CHECK_ELEMENT(v_kill);
2033  BM_CHECK_ELEMENT(v_target);
2034 
2035  if (v_target->e && v_kill->e) {
2036  /* inline BM_vert_splice(bm, v_target, v_kill); */
2037  BMEdge *e;
2038  while ((e = v_kill->e)) {
2039  BMEdge *e_target;
2040 
2041  if (check_edge_exists) {
2042  e_target = BM_edge_exists(v_target, BM_edge_other_vert(e, v_kill));
2043  }
2044 
2045  bmesh_edge_vert_swap(e, v_target, v_kill);
2046  BLI_assert(e->v1 != e->v2);
2047 
2048  if (check_edge_exists) {
2049  if (e_target) {
2050  BM_edge_splice(bm, e_target, e);
2051  }
2052  }
2053  }
2054  }
2055 
2056  if (kill_degenerate_faces) {
2057  BMFace *f_kill;
2058  while ((f_kill = BLI_SMALLSTACK_POP(faces_degenerate))) {
2059  BM_face_kill(bm, f_kill);
2060  }
2061  }
2062 
2063  if (do_del) {
2064  BLI_assert(v_kill->e == NULL);
2065  bm_kill_only_vert(bm, v_kill);
2066  }
2067 
2068  return v_target;
2069 }
2070 
2103 {
2104  BMLoop *l_iter, *l_f1 = NULL, *l_f2 = NULL;
2105  int newlen = 0, i, f1len = 0, f2len = 0;
2106  bool edok;
2107  /* can't join a face to itself */
2108  if (f1 == f2) {
2109  return NULL;
2110  }
2111 
2112  /* validate that edge is 2-manifold edge */
2113  if (!BM_edge_is_manifold(e)) {
2114  return NULL;
2115  }
2116 
2117  /* verify that e is in both f1 and f2 */
2118  f1len = f1->len;
2119  f2len = f2->len;
2120 
2121  if (!((l_f1 = BM_face_edge_share_loop(f1, e)) && (l_f2 = BM_face_edge_share_loop(f2, e)))) {
2122  return NULL;
2123  }
2124 
2125  /* validate direction of f2's loop cycle is compatible */
2126  if (l_f1->v == l_f2->v) {
2127  return NULL;
2128  }
2129 
2130  /* validate that for each face, each vertex has another edge in its disk cycle that is
2131  * not e, and not shared. */
2132  if (BM_edge_in_face(l_f1->next->e, f2) || BM_edge_in_face(l_f1->prev->e, f2) ||
2133  BM_edge_in_face(l_f2->next->e, f1) || BM_edge_in_face(l_f2->prev->e, f1)) {
2134  return NULL;
2135  }
2136 
2137  /* validate only one shared edge */
2138  if (BM_face_share_edge_count(f1, f2) > 1) {
2139  return NULL;
2140  }
2141 
2142  /* validate no internal join */
2143  {
2144  bool is_dupe = false;
2145 
2146  /* TODO: skip clearing once this is ensured. */
2147  for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f2); i < f2len; i++, l_iter = l_iter->next) {
2149  }
2150 
2151  for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f1); i < f1len; i++, l_iter = l_iter->next) {
2152  BM_elem_flag_set(l_iter->v, BM_ELEM_INTERNAL_TAG, l_iter != l_f1);
2153  }
2154  for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f2); i < f2len; i++, l_iter = l_iter->next) {
2155  if (l_iter != l_f2) {
2156  /* as soon as a duplicate is found, bail out */
2157  if (BM_elem_flag_test(l_iter->v, BM_ELEM_INTERNAL_TAG)) {
2158  is_dupe = true;
2159  break;
2160  }
2161  }
2162  }
2163  /* Cleanup tags. */
2164  for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f1); i < f1len; i++, l_iter = l_iter->next) {
2166  }
2167  if (is_dupe) {
2168  return NULL;
2169  }
2170  }
2171 
2172  /* join the two loop */
2173  l_f1->prev->next = l_f2->next;
2174  l_f2->next->prev = l_f1->prev;
2175 
2176  l_f1->next->prev = l_f2->prev;
2177  l_f2->prev->next = l_f1->next;
2178 
2179  /* If `l_f1` was base-loop, make `l_f1->next` the base. */
2180  if (BM_FACE_FIRST_LOOP(f1) == l_f1) {
2181  BM_FACE_FIRST_LOOP(f1) = l_f1->next;
2182  }
2183 
2184  /* increase length of f1 */
2185  f1->len += (f2->len - 2);
2186 
2187  /* make sure each loop points to the proper face */
2188  newlen = f1->len;
2189  for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f1); i < newlen; i++, l_iter = l_iter->next) {
2190  l_iter->f = f1;
2191  }
2192 
2193  /* remove edge from the disk cycle of its two vertices */
2194  bmesh_disk_edge_remove(l_f1->e, l_f1->e->v1);
2195  bmesh_disk_edge_remove(l_f1->e, l_f1->e->v2);
2196 
2197  /* deallocate edge and its two loops as well as f2 */
2198  if (bm->etoolflagpool) {
2199  BLI_mempool_free(bm->etoolflagpool, ((BMEdge_OFlag *)l_f1->e)->oflags);
2200  }
2201  BLI_mempool_free(bm->epool, l_f1->e);
2202  bm->totedge--;
2203  BLI_mempool_free(bm->lpool, l_f1);
2204  bm->totloop--;
2205  BLI_mempool_free(bm->lpool, l_f2);
2206  bm->totloop--;
2207  if (bm->ftoolflagpool) {
2208  BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f2)->oflags);
2209  }
2210  BLI_mempool_free(bm->fpool, f2);
2211  bm->totface--;
2212  /* account for both above */
2214 
2215  BM_CHECK_ELEMENT(f1);
2216 
2217  /* validate the new loop cycle */
2218  edok = bmesh_loop_validate(f1);
2219  BMESH_ASSERT(edok != false);
2220 
2221  return f1;
2222 }
2223 
2230 {
2231  bool is_double = false;
2232 
2233  BLI_assert(BM_edge_exists(v_a, v_b) == false);
2234 
2235  if (v_a->e && v_b->e) {
2236  BMEdge *e, *e_first;
2237 
2238 #define VERT_VISIT _FLAG_WALK
2239 
2240  /* tag 'v_a' */
2241  e = e_first = v_a->e;
2242  do {
2243  BMVert *v_other = BM_edge_other_vert(e, v_a);
2246  } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != e_first);
2247 
2248  /* check 'v_b' connects to 'v_a' edges */
2249  e = e_first = v_b->e;
2250  do {
2251  BMVert *v_other = BM_edge_other_vert(e, v_b);
2252  if (BM_ELEM_API_FLAG_TEST(v_other, VERT_VISIT)) {
2253  is_double = true;
2254  break;
2255  }
2256  } while ((e = BM_DISK_EDGE_NEXT(e, v_b)) != e_first);
2257 
2258  /* cleanup */
2259  e = e_first = v_a->e;
2260  do {
2261  BMVert *v_other = BM_edge_other_vert(e, v_a);
2264  } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != e_first);
2265 
2266 #undef VERT_VISIT
2267  }
2268 
2269  return is_double;
2270 }
2271 
2284 bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
2285 {
2286  BMEdge *e;
2287 
2288  /* verts already spliced */
2289  if (v_src == v_dst) {
2290  return false;
2291  }
2292 
2293  BLI_assert(BM_vert_pair_share_face_check(v_src, v_dst) == false);
2294 
2295  /* move all the edges from 'v_src' disk to 'v_dst' */
2296  while ((e = v_src->e)) {
2297  bmesh_edge_vert_swap(e, v_dst, v_src);
2298  BLI_assert(e->v1 != e->v2);
2299  }
2300 
2301  BM_CHECK_ELEMENT(v_src);
2302  BM_CHECK_ELEMENT(v_dst);
2303 
2304  /* 'v_src' is unused now, and can be killed */
2305  BM_vert_kill(bm, v_src);
2306 
2307  return true;
2308 }
2309 
2310 /* -------------------------------------------------------------------- */
2314 /* BM_edge_face_count(e) >= 1 */
2316 {
2317  return (e->l && e->l->radial_next != e->l);
2318 }
2319 
2332  BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select)
2333 {
2334  int v_edges_num = 0;
2335 
2336  /* Detailed notes on array use since this is stack memory, we have to be careful */
2337 
2338  /* newly created vertices, only use when 'r_vout' is set
2339  * (total size will be number of fans) */
2340  BLI_SMALLSTACK_DECLARE(verts_new, BMVert *);
2341  /* fill with edges from the face-fan, clearing on completion
2342  * (total size will be max fan edge count) */
2343  BLI_SMALLSTACK_DECLARE(edges, BMEdge *);
2344  /* temp store edges to walk over when filling 'edges',
2345  * (total size will be max radial edges of any edge) */
2346  BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *);
2347 
2348  /* number of resulting verts, include self */
2349  int verts_num = 1;
2350  /* track the total number of edges handled, so we know when we've found the last fan */
2351  int edges_found = 0;
2352 
2353 #define EDGE_VISIT _FLAG_WALK
2354 
2355  /* count and flag at once */
2356  if (v->e) {
2357  BMEdge *e_first, *e_iter;
2358  e_iter = e_first = v->e;
2359  do {
2360  v_edges_num += 1;
2361 
2364  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
2365 
2366  while (true) {
2367  /* Considering only edges and faces incident on vertex v, walk
2368  * the edges & collect in the 'edges' list for splitting */
2369 
2370  BMEdge *e = v->e;
2372 
2373  do {
2375  BLI_SMALLSTACK_PUSH(edges, e);
2376  edges_found += 1;
2377 
2378  if (e->l) {
2379  BMLoop *l_iter, *l_first;
2380  l_iter = l_first = e->l;
2381  do {
2382  BMLoop *l_adjacent = (l_iter->v == v) ? l_iter->prev : l_iter->next;
2383  BLI_assert(BM_vert_in_edge(l_adjacent->e, v));
2384  if (BM_ELEM_API_FLAG_TEST(l_adjacent->e, EDGE_VISIT)) {
2385  BM_ELEM_API_FLAG_DISABLE(l_adjacent->e, EDGE_VISIT);
2386  BLI_SMALLSTACK_PUSH(edges_search, l_adjacent->e);
2387  }
2388  } while ((l_iter = l_iter->radial_next) != l_first);
2389  }
2390  } while ((e = BLI_SMALLSTACK_POP(edges_search)));
2391 
2392  /* now we have all edges connected to 'v->e' */
2393 
2394  BLI_assert(edges_found <= v_edges_num);
2395 
2396  if (edges_found == v_edges_num) {
2397  /* We're done! The remaining edges in 'edges' form the last fan,
2398  * which can be left as is.
2399  * if 'edges' were alloc'd it'd be freed here. */
2400  break;
2401  }
2402 
2403  BMVert *v_new;
2404 
2405  v_new = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
2406  if (copy_select) {
2407  BM_elem_select_copy(bm, v_new, v);
2408  }
2409 
2410  while ((e = BLI_SMALLSTACK_POP(edges))) {
2411  bmesh_edge_vert_swap(e, v_new, v);
2412  }
2413 
2414  if (r_vout) {
2415  BLI_SMALLSTACK_PUSH(verts_new, v_new);
2416  }
2417  verts_num += 1;
2418  }
2419  }
2420 
2421 #undef EDGE_VISIT
2422 
2423  /* flags are clean now, handle return values */
2424 
2425  if (r_vout_len != NULL) {
2426  *r_vout_len = verts_num;
2427  }
2428 
2429  if (r_vout != NULL) {
2430  BMVert **verts;
2431 
2432  verts = MEM_mallocN(sizeof(BMVert *) * verts_num, __func__);
2433  *r_vout = verts;
2434 
2435  verts[0] = v;
2436  BLI_SMALLSTACK_AS_TABLE(verts_new, &verts[1]);
2437  }
2438 }
2439 
2460 {
2461  do {
2462  LinkNode *n_orig = edges_separate->link;
2463  do {
2464  LinkNode *n_prev = n_orig;
2465  LinkNode *n_step = n_orig->next;
2466  BMEdge *e_orig = n_orig->link;
2467  do {
2468  BMEdge *e = n_step->link;
2469  BLI_assert(e != e_orig);
2470  if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2) && BM_edge_splice(bm, e_orig, e)) {
2471  /* don't visit again */
2472  n_prev->next = n_step->next;
2473  }
2474  else {
2475  n_prev = n_step;
2476  }
2477  } while ((n_step = n_step->next));
2478 
2479  } while ((n_orig = n_orig->next) && n_orig->next);
2480  } while ((edges_separate = edges_separate->next));
2481 }
2482 
2487  BMVert *v,
2488  BMEdge **e_in,
2489  int e_in_len,
2490  const bool copy_select,
2491  BMVert ***r_vout,
2492  int *r_vout_len)
2493 {
2494  LinkNode *edges_separate = NULL;
2495  int i;
2496 
2497  for (i = 0; i < e_in_len; i++) {
2498  BMEdge *e = e_in[i];
2500  LinkNode *edges_orig = NULL;
2501  do {
2502  BMLoop *l_sep = e->l;
2503  bmesh_kernel_edge_separate(bm, e, l_sep, copy_select);
2504  BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
2505  BLI_assert(e != l_sep->e);
2506  } while (bm_edge_supports_separate(e));
2507  BLI_linklist_prepend_alloca(&edges_orig, e);
2508  BLI_linklist_prepend_alloca(&edges_separate, edges_orig);
2509  }
2510  }
2511 
2512  bmesh_kernel_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
2513 
2514  if (edges_separate) {
2515  bmesh_kernel_vert_separate__cleanup(bm, edges_separate);
2516  }
2517 }
2518 
2523  BMVert *v,
2524  const char hflag,
2525  const bool copy_select,
2526  BMVert ***r_vout,
2527  int *r_vout_len)
2528 {
2529  LinkNode *edges_separate = NULL;
2530  BMEdge *e_iter, *e_first;
2531 
2532  e_iter = e_first = v->e;
2533  do {
2534  if (BM_elem_flag_test(e_iter, hflag)) {
2535  BMEdge *e = e_iter;
2537  LinkNode *edges_orig = NULL;
2538  do {
2539  BMLoop *l_sep = e->l;
2540  bmesh_kernel_edge_separate(bm, e, l_sep, copy_select);
2541  /* trick to avoid looping over separated edges */
2542  if (edges_separate == NULL && edges_orig == NULL) {
2543  e_first = l_sep->e;
2544  }
2545  BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
2546  BLI_assert(e != l_sep->e);
2547  } while (bm_edge_supports_separate(e));
2548  BLI_linklist_prepend_alloca(&edges_orig, e);
2549  BLI_linklist_prepend_alloca(&edges_separate, edges_orig);
2550  }
2551  }
2552  } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
2553 
2554  bmesh_kernel_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
2555 
2556  if (edges_separate) {
2557  bmesh_kernel_vert_separate__cleanup(bm, edges_separate);
2558  }
2559 }
2560 
2562  BMVert *v_dst,
2563  BMVert *v_src,
2564  bool (*testfn)(BMEdge *, void *arg),
2565  void *arg)
2566 {
2567  LinkNode *edges_hflag = NULL;
2568  BMEdge *e_iter, *e_first;
2569 
2570  e_iter = e_first = v_src->e;
2571  do {
2572  if (testfn(e_iter, arg)) {
2573  BLI_linklist_prepend_alloca(&edges_hflag, e_iter);
2574  }
2575  } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_src)) != e_first);
2576 
2577  if (edges_hflag) {
2578  do {
2579  e_iter = edges_hflag->link;
2580  bmesh_disk_vert_replace(e_iter, v_dst, v_src);
2581  } while ((edges_hflag = edges_hflag->next));
2582  }
2583 }
2584 
2597 bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
2598 {
2599  BMLoop *l;
2600 
2601  if (!BM_vert_in_edge(e_src, e_dst->v1) || !BM_vert_in_edge(e_src, e_dst->v2)) {
2602  /* not the same vertices can't splice */
2603 
2604  /* the caller should really make sure this doesn't happen ever
2605  * so assert on release builds */
2606  BLI_assert(0);
2607 
2608  return false;
2609  }
2610 
2611  while (e_src->l) {
2612  l = e_src->l;
2613  BLI_assert(BM_vert_in_edge(e_dst, l->v));
2614  BLI_assert(BM_vert_in_edge(e_dst, l->next->v));
2615  bmesh_radial_loop_remove(e_src, l);
2616  bmesh_radial_loop_append(e_dst, l);
2617  }
2618 
2619  BLI_assert(bmesh_radial_length(e_src->l) == 0);
2620 
2621  BM_CHECK_ELEMENT(e_src);
2622  BM_CHECK_ELEMENT(e_dst);
2623 
2624  /* removes from disks too */
2625  BM_edge_kill(bm, e_src);
2626 
2627  return true;
2628 }
2629 
2641 void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select)
2642 {
2643  BMEdge *e_new;
2644 #ifndef NDEBUG
2645  const int radlen = bmesh_radial_length(e->l);
2646 #endif
2647 
2648  BLI_assert(l_sep->e == e);
2649  BLI_assert(e->l);
2650 
2651  if (BM_edge_is_boundary(e)) {
2652  BLI_assert(0); /* no cut required */
2653  return;
2654  }
2655 
2656  if (l_sep == e->l) {
2657  e->l = l_sep->radial_next;
2658  }
2659 
2660  e_new = BM_edge_create(bm, e->v1, e->v2, e, BM_CREATE_NOP);
2661  bmesh_radial_loop_remove(e, l_sep);
2662  bmesh_radial_loop_append(e_new, l_sep);
2663  l_sep->e = e_new;
2664 
2665  if (copy_select) {
2666  BM_elem_select_copy(bm, e_new, e);
2667  }
2668 
2669  BLI_assert(bmesh_radial_length(e->l) == radlen - 1);
2670  BLI_assert(bmesh_radial_length(e_new->l) == 1);
2671 
2672  BM_CHECK_ELEMENT(e_new);
2674 }
2675 
2686 {
2687  BMVert *v_new = NULL;
2688  BMVert *v_sep = l_sep->v;
2689  BMEdge *e_iter;
2690  BMEdge *edges[2];
2691  int i;
2692 
2693  /* peel the face from the edge radials on both sides of the
2694  * loop vert, disconnecting the face from its fan */
2695  if (!BM_edge_is_boundary(l_sep->e)) {
2696  bmesh_kernel_edge_separate(bm, l_sep->e, l_sep, false);
2697  }
2698  if (!BM_edge_is_boundary(l_sep->prev->e)) {
2699  bmesh_kernel_edge_separate(bm, l_sep->prev->e, l_sep->prev, false);
2700  }
2701 
2702  /* do inline, below */
2703 #if 0
2704  if (BM_vert_edge_count_is_equal(v_sep, 2)) {
2705  return v_sep;
2706  }
2707 #endif
2708 
2709  /* Search for an edge unattached to this loop */
2710  e_iter = v_sep->e;
2711  while (!ELEM(e_iter, l_sep->e, l_sep->prev->e)) {
2712  e_iter = bmesh_disk_edge_next(e_iter, v_sep);
2713 
2714  /* We've come back around to the initial edge, all touch this loop.
2715  * If there are still only two edges out of v_sep,
2716  * then this whole URMV was just a no-op, so exit now. */
2717  if (e_iter == v_sep->e) {
2719  return v_sep;
2720  }
2721  }
2722 
2723  v_sep->e = l_sep->e;
2724 
2725  v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP);
2726 
2727  edges[0] = l_sep->e;
2728  edges[1] = l_sep->prev->e;
2729 
2730  for (i = 0; i < ARRAY_SIZE(edges); i++) {
2731  BMEdge *e = edges[i];
2732  bmesh_edge_vert_swap(e, v_new, v_sep);
2733  }
2734 
2735  BLI_assert(v_sep != l_sep->v);
2736  BLI_assert(v_sep->e != l_sep->v->e);
2737 
2738  BM_CHECK_ELEMENT(l_sep);
2739  BM_CHECK_ELEMENT(v_sep);
2740  BM_CHECK_ELEMENT(edges[0]);
2741  BM_CHECK_ELEMENT(edges[1]);
2742  BM_CHECK_ELEMENT(v_new);
2743 
2744  return v_new;
2745 }
2746 
2755 {
2756  BMVert *v_sep = larr[0]->v;
2757  BMVert *v_new;
2758  int edges_len = 0;
2759  int i;
2760  /* any edges not owned by 'larr' loops connected to 'v_sep'? */
2761  bool is_mixed_edge_any = false;
2762  /* any loops not owned by 'larr' radially connected to 'larr' loop edges? */
2763  bool is_mixed_loop_any = false;
2764 
2765 #define LOOP_VISIT _FLAG_WALK
2766 #define EDGE_VISIT _FLAG_WALK
2767 
2768  for (i = 0; i < larr_len; i++) {
2769  BMLoop *l_sep = larr[i];
2770 
2771  /* all must be from the same vert! */
2772  BLI_assert(v_sep == l_sep->v);
2773 
2776 
2777  /* weak! but it makes it simpler to check for edges to split
2778  * while doing a radial loop (where loops may be adjacent) */
2781 
2782  BMLoop *loop_pair[2] = {l_sep, l_sep->prev};
2783  for (int j = 0; j < ARRAY_SIZE(loop_pair); j++) {
2784  BMEdge *e = loop_pair[j]->e;
2787  edges_len += 1;
2788  }
2789  }
2790  }
2791 
2792  BMEdge **edges = BLI_array_alloca(edges, edges_len);
2793  STACK_DECLARE(edges);
2794 
2795  STACK_INIT(edges, edges_len);
2796 
2797  {
2798  BMEdge *e_first, *e_iter;
2799  e_iter = e_first = v_sep->e;
2800  do {
2801  if (BM_ELEM_API_FLAG_TEST(e_iter, EDGE_VISIT)) {
2802  BMLoop *l_iter, *l_first;
2803  bool is_mixed_loop = false;
2804 
2805  l_iter = l_first = e_iter->l;
2806  do {
2807  if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
2808  is_mixed_loop = true;
2809  break;
2810  }
2811  } while ((l_iter = l_iter->radial_next) != l_first);
2812 
2813  if (is_mixed_loop) {
2814  /* ensure the first loop is one we don't own so we can do a quick check below
2815  * on the edge's loop-flag to see if the edge is mixed or not. */
2816  e_iter->l = l_iter;
2817 
2818  is_mixed_loop_any = true;
2819  }
2820 
2821  STACK_PUSH(edges, e_iter);
2822  }
2823  else {
2824  /* at least one edge attached isn't connected to our loops */
2825  is_mixed_edge_any = true;
2826  }
2827  } while ((e_iter = bmesh_disk_edge_next(e_iter, v_sep)) != e_first);
2828  }
2829 
2830  BLI_assert(edges_len == STACK_SIZE(edges));
2831 
2832  if (is_mixed_loop_any == false && is_mixed_edge_any == false) {
2833  /* all loops in 'larr' are the sole owners of their edges.
2834  * nothing to split away from, this is a no-op */
2835  v_new = v_sep;
2836  }
2837  else {
2838  v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP);
2839 
2840  for (i = 0; i < STACK_SIZE(edges); i++) {
2841  BMEdge *e = edges[i];
2842  BMLoop *l_iter, *l_first, *l_next;
2843  BMEdge *e_new;
2844 
2845  /* disable so copied edge isn't left dirty (loop edges are cleared last too) */
2847 
2848  /* will always be false when (is_mixed_loop_any == false) */
2849  if (!BM_ELEM_API_FLAG_TEST(e->l, LOOP_VISIT)) {
2850  /* edge has some loops owned by us, some owned by other loops */
2851  BMVert *e_new_v_pair[2];
2852 
2853  if (e->v1 == v_sep) {
2854  e_new_v_pair[0] = v_new;
2855  e_new_v_pair[1] = e->v2;
2856  }
2857  else {
2858  BLI_assert(v_sep == e->v2);
2859  e_new_v_pair[0] = e->v1;
2860  e_new_v_pair[1] = v_new;
2861  }
2862 
2863  e_new = BM_edge_create(bm, UNPACK2(e_new_v_pair), e, BM_CREATE_NOP);
2864 
2865  /* now moved all loops from 'larr' to this newly created edge */
2866  l_iter = l_first = e->l;
2867  do {
2868  l_next = l_iter->radial_next;
2869  if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
2870  bmesh_radial_loop_remove(e, l_iter);
2871  bmesh_radial_loop_append(e_new, l_iter);
2872  l_iter->e = e_new;
2873  }
2874  } while ((l_iter = l_next) != l_first);
2875  }
2876  else {
2877  /* we own the edge entirely, replace the vert */
2878  bmesh_disk_vert_replace(e, v_new, v_sep);
2879  }
2880 
2881  /* loop vert is handled last! */
2882  }
2883  }
2884 
2885  for (i = 0; i < larr_len; i++) {
2886  BMLoop *l_sep = larr[i];
2887 
2888  l_sep->v = v_new;
2889 
2896 
2899  }
2900 
2901 #undef LOOP_VISIT
2902 #undef EDGE_VISIT
2903 
2904  return v_new;
2905 }
2906 
2908 {
2909  BMLoop *l_iter, *l_first;
2910 
2911  BLI_assert(ELEM(v_src, e->v1, e->v2));
2912  bmesh_disk_vert_replace(e, v_dst, v_src);
2913 
2914  l_iter = l_first = e->l;
2915  do {
2916  if (l_iter->v == v_src) {
2917  l_iter->v = v_dst;
2918  if (BM_vert_in_edge(l_iter->prev->e, v_src)) {
2919  bmesh_edge_vert_swap__recursive(l_iter->prev->e, v_dst, v_src);
2920  }
2921  }
2922  else if (l_iter->next->v == v_src) {
2923  l_iter->next->v = v_dst;
2924  if (BM_vert_in_edge(l_iter->next->e, v_src)) {
2925  bmesh_edge_vert_swap__recursive(l_iter->next->e, v_dst, v_src);
2926  }
2927  }
2928  else {
2929  BLI_assert(l_iter->prev->v != v_src);
2930  }
2931  } while ((l_iter = l_iter->radial_next) != l_first);
2932 }
2933 
2939 {
2940  BMVert *v_new = BM_vert_create(bm, l_sep->v->co, l_sep->v, BM_CREATE_NOP);
2941  /* passing either 'l_sep->e', 'l_sep->prev->e' will work */
2942  bmesh_edge_vert_swap__recursive(l_sep->e, v_new, l_sep->v);
2943  BLI_assert(l_sep->v == v_new);
2944  return v_new;
2945 }
2946 
2953 {
2954  BMLoop *l_iter, *l_first;
2955 
2956  BLI_assert(f_a != f_b);
2957 
2958  l_iter = l_first = BM_FACE_FIRST_LOOP(f_a);
2959  do {
2960  l_iter->f = f_b;
2961  } while ((l_iter = l_iter->next) != l_first);
2962 
2963  l_iter = l_first = BM_FACE_FIRST_LOOP(f_b);
2964  do {
2965  l_iter->f = f_a;
2966  } while ((l_iter = l_iter->next) != l_first);
2967 
2968  SWAP(BMFace, (*f_a), (*f_b));
2969 
2970  /* swap back */
2971  SWAP(void *, f_a->head.data, f_b->head.data);
2972  SWAP(int, f_a->head.index, f_b->head.index);
2973 }
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
void CustomData_bmesh_set_default(struct CustomData *data, void **block)
Definition: customdata.c:3703
#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.c:3633
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.c:3606
void BKE_mesh_mdisp_flip(struct MDisps *md, const bool use_loop_mdisp_flip)
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:104
#define BLI_array_staticdeclare(arr, maxstatic)
Definition: BLI_array.h:69
#define BLI_array_len(arr)
Definition: BLI_array.h:74
#define BLI_array_free(arr)
Definition: BLI_array.h:116
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
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:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v3(float r[3])
void * BLI_mempool_calloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_mempool.c:362
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_NONNULL(1)
Definition: BLI_mempool.c:334
#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_INIT(stack, tot)
#define STACK_SIZE(stack)
@ 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:556
#define BM_DEFAULT_NGON_STACK_SIZE
Definition: bmesh_class.h:571
#define BM_NGON_MAX
Definition: bmesh_class.h:581
@ 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_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
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:2952
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
Join Connected Faces.
Definition: bmesh_core.c:1209
static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_src)
Definition: bmesh_core.c:2907
void BM_face_verts_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:861
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
Splice Edge.
Definition: bmesh_core.c:2597
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
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:2486
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:217
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:500
BMVert * bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep)
Definition: bmesh_core.c:2938
static void bm_elements_systag_disable(void *veles, int tot, const char api_flag)
Definition: bmesh_core.c:1123
static void bm_kill_only_loop(BMesh *bm, BMLoop *l)
Definition: bmesh_core.c:823
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select)
Separate Edge.
Definition: bmesh_core.c:2641
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
Definition: bmesh_core.c:2284
BMFace * bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
Join Face Kill Edge (JFKE)
Definition: bmesh_core.c:2102
#define LOOP_VISIT
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:1002
static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
Definition: bmesh_core.c:2459
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:1463
void BM_face_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:881
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:1803
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:2522
void BM_face_kill_loose(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:929
static void bm_kill_only_vert(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:750
static BMFace * bm_face_create__sfme(BMesh *bm, BMFace *f_example)
Definition: bmesh_core.c:1402
BLI_INLINE BMFace * bm_face_create__internal(BMesh *bm)
Definition: bmesh_core.c:371
BMVert * bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
Un-glue Region Make Vert (URMV)
Definition: bmesh_core.c:2685
static void bm_kill_only_edge(BMesh *bm, BMEdge *e)
Definition: bmesh_core.c:773
static int UNUSED_FUNCTION() bm_loop_length(BMLoop *l)
Definition: bmesh_core.c:1016
void BM_face_edges_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:840
static int UNUSED_FUNCTION() bm_vert_systag_count_disk(BMVert *v, const char api_flag)
Definition: bmesh_core.c:1144
BMVert * bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len)
Definition: bmesh_core.c:2754
#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:2561
static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag)
Definition: bmesh_core.c:1164
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:1037
void BM_edge_kill(BMesh *bm, BMEdge *e)
Definition: bmesh_core.c:987
BMFace * BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges)
Definition: bmesh_core.c:303
int bmesh_elem_check(void *element, const char htype)
Definition: bmesh_core.c:529
static void bm_elements_systag_enable(void *veles, int tot, const char api_flag)
Definition: bmesh_core.c:1113
static BMLoop * bm_face_boundary_add(BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte, const eBMCreateFlag create_flag)
Definition: bmesh_core.c:283
#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:428
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:1620
static int bm_loop_systag_count_radial(BMLoop *l, const char api_flag)
Definition: bmesh_core.c:1133
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:2331
BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
Definition: bmesh_core.c:2315
static void bm_kill_only_face(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:796
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:1988
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
eBMCreateFlag
Definition: bmesh_core.h:26
@ BM_CREATE_NOP
Definition: bmesh_core.h:27
@ BM_CREATE_SKIP_CD
Definition: bmesh_core.h:33
@ BM_CREATE_NO_DOUBLE
Definition: bmesh_core.h:29
#define BMESH_ASSERT(a)
Definition: bmesh_error.h:76
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:125
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
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:516
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])
#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
#define BM_CHECK_ELEMENT(el)
Definition: bmesh_private.h:38
int bmesh_radial_length(const BMLoop *l)
int bmesh_disk_count_at_most(const BMVert *v, const int count_max)
@ _FLAG_JF
Definition: bmesh_private.h:61
@ _FLAG_ELEM_CHECK
Definition: bmesh_private.h:68
#define BM_ELEM_API_FLAG_ENABLE(element, f)
Definition: bmesh_private.h:71
int bmesh_disk_count(const BMVert *v)
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
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
Definition: bmesh_query.c:555
BMFace * BM_face_find_double(BMFace *f)
Definition: bmesh_query.c:2121
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
Definition: bmesh_query.c:1231
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
Definition: bmesh_query.c:1426
BMFace * BM_face_exists(BMVert **varr, int len)
Definition: bmesh_query.c:2070
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:97
#define BM_vert_edge_count_is_equal(v, n)
Definition: bmesh_query.h:91
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()
static FT_Error err
Definition: freetypefont.c:52
static float verts[][3]
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static char faces[256]
static void error(const char *str)
Definition: meshlaplacian.c:65
BMHeader head
Definition: bmesh_class.h:123
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
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
float no[3]
Definition: bmesh_class.h:280
BMLoop * l_first
Definition: bmesh_class.h:273
char htype
Definition: bmesh_class.h:76
int index
Definition: bmesh_class.h:73
char hflag
Definition: bmesh_class.h:78
void * data
Definition: bmesh_class.h:63
char api_flag
Definition: bmesh_class.h:86
BMHeader head
Definition: bmesh_class.h:157
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_prev
Definition: bmesh_class.h:216
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
float no[3]
Definition: bmesh_class.h:100
BMHeader head
Definition: bmesh_class.h:97
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:40
struct LinkNode * next
Definition: BLI_linklist.h:39
uint len