Blender V4.3
bmesh_walkers_impl.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <cstring>
12
13#include "BLI_utildefines.h"
14
15#include "BKE_customdata.hh"
16
17#include "bmesh.hh"
19
20/* Pop into stack memory (common operation). */
21#define BMW_state_remove_r(walker, owalk) \
22 { \
23 memcpy(owalk, BMW_current_state(walker), sizeof(*(owalk))); \
24 BMW_state_remove(walker); \
25 } \
26 (void)0
27
28/* -------------------------------------------------------------------- */
32static bool bmw_mask_check_vert(BMWalker *walker, BMVert *v)
33{
35 return false;
36 }
37 if (walker->mask_vert && !BMO_vert_flag_test(walker->bm, v, walker->mask_vert)) {
38 return false;
39 }
40 return true;
41}
42
43static bool bmw_mask_check_edge(BMWalker *walker, BMEdge *e)
44{
46 return false;
47 }
48 if (walker->mask_edge && !BMO_edge_flag_test(walker->bm, e, walker->mask_edge)) {
49 return false;
50 }
51 return true;
52}
53
54static bool bmw_mask_check_face(BMWalker *walker, BMFace *f)
55{
57 return false;
58 }
59 if (walker->mask_face && !BMO_face_flag_test(walker->bm, f, walker->mask_face)) {
60 return false;
61 }
62 return true;
63}
64
67/* -------------------------------------------------------------------- */
74static bool bmw_edge_is_wire(const BMWalker *walker, const BMEdge *e)
75{
76 if (walker->flag & BMW_FLAG_TEST_HIDDEN) {
77 /* Check if this is a wire edge, ignoring hidden faces. */
78 if (BM_edge_is_wire(e)) {
79 return true;
80 }
82 }
83 return BM_edge_is_wire(e);
84}
85
88/* -------------------------------------------------------------------- */
101{
102 BMwShellWalker *shellWalk = nullptr;
103
104 if (BLI_gset_haskey(walker->visit_set, e)) {
105 return;
106 }
107
108 if (!bmw_mask_check_edge(walker, e)) {
109 return;
110 }
111
112 shellWalk = static_cast<BMwShellWalker *>(BMW_state_add(walker));
113 shellWalk->curedge = e;
114 BLI_gset_insert(walker->visit_set, e);
115}
116
117static void bmw_VertShellWalker_begin(BMWalker *walker, void *data)
118{
119 BMIter eiter;
120 BMHeader *h = static_cast<BMHeader *>(data);
121 BMEdge *e;
122 BMVert *v;
123
124 if (UNLIKELY(h == nullptr)) {
125 return;
126 }
127
128 switch (h->htype) {
129 case BM_VERT: {
130 /* Starting the walk at a vert, add all the edges to the work-list. */
131 v = (BMVert *)h;
132 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
134 }
135 break;
136 }
137
138 case BM_EDGE: {
139 /* Starting the walk at an edge, add the single edge to the work-list. */
140 e = (BMEdge *)h;
142 break;
143 }
144 default:
145 BLI_assert(0);
146 }
147}
148
150{
151 BMwShellWalker *shellWalk = static_cast<BMwShellWalker *>(BMW_current_state(walker));
152 return shellWalk->curedge;
153}
154
156{
157 BMwShellWalker *swalk, owalk;
158 BMEdge *e, *e2;
159 BMVert *v;
160 BMIter iter;
161 int i;
162
163 BMW_state_remove_r(walker, &owalk);
164 swalk = &owalk;
165
166 e = swalk->curedge;
167
168 for (i = 0; i < 2; i++) {
169 v = i ? e->v2 : e->v1;
170 BM_ITER_ELEM (e2, &iter, v, BM_EDGES_OF_VERT) {
172 }
173 }
174
175 return e;
176}
177
178#if 0
179static void *bmw_VertShellWalker_step(BMWalker *walker)
180{
181 BMEdge *curedge, *next = nullptr;
182 BMVert *v_old = nullptr;
183 bool restrictpass = true;
184 BMwShellWalker shellWalk = *((BMwShellWalker *)BMW_current_state(walker));
185
186 if (!BLI_gset_haskey(walker->visit_set, shellWalk.base)) {
187 BLI_gset_insert(walker->visit_set, shellWalk.base);
188 }
189
190 BMW_state_remove(walker);
191
192 /* Find the next edge whose other vertex has not been visited. */
193 curedge = shellWalk.curedge;
194 do {
195 if (!BLI_gset_haskey(walker->visit_set, curedge)) {
196 if (!walker->visibility_flag ||
197 (walker->visibility_flag &&
198 BMO_edge_flag_test(walker->bm, curedge, walker->visibility_flag)))
199 {
200 BMwShellWalker *newstate;
201
202 v_old = BM_edge_other_vert(curedge, shellWalk.base);
203
204 /* Push a new state onto the stack. */
205 newState = BMW_state_add(walker);
206 BLI_gset_insert(walker->visit_set, curedge);
207
208 /* Populate the new state. */
209
210 newState->base = v_old;
211 newState->curedge = curedge;
212 }
213 }
214 } while ((curedge = bmesh_disk_edge_next(curedge, shellWalk.base)) != shellWalk.curedge);
215
216 return shellWalk.curedge;
217}
218#endif
219
222/* -------------------------------------------------------------------- */
232{
233 BMwLoopShellWalker *shellWalk = nullptr;
234
235 if (BLI_gset_haskey(walker->visit_set, l)) {
236 return;
237 }
238
239 if (!bmw_mask_check_face(walker, l->f)) {
240 return;
241 }
242
243 shellWalk = static_cast<BMwLoopShellWalker *>(BMW_state_add(walker));
244 shellWalk->curloop = l;
245 BLI_gset_insert(walker->visit_set, l);
246}
247
248static void bmw_LoopShellWalker_begin(BMWalker *walker, void *data)
249{
250 BMIter iter;
251 BMHeader *h = static_cast<BMHeader *>(data);
252
253 if (UNLIKELY(h == nullptr)) {
254 return;
255 }
256
257 switch (h->htype) {
258 case BM_LOOP: {
259 /* Starting the walk at a vert, add all the edges to the work-list. */
260 BMLoop *l = (BMLoop *)h;
262 break;
263 }
264
265 case BM_VERT: {
266 BMVert *v = (BMVert *)h;
267 BMLoop *l;
268 BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
270 }
271 break;
272 }
273 case BM_EDGE: {
274 BMEdge *e = (BMEdge *)h;
275 BMLoop *l;
276 BM_ITER_ELEM (l, &iter, e, BM_LOOPS_OF_EDGE) {
278 }
279 break;
280 }
281 case BM_FACE: {
282 BMFace *f = (BMFace *)h;
284 /* Walker will handle other loops within the face. */
286 break;
287 }
288 default:
289 BLI_assert(0);
290 }
291}
292
294{
295 BMwLoopShellWalker *shellWalk = static_cast<BMwLoopShellWalker *>(BMW_current_state(walker));
296 return shellWalk->curloop;
297}
298
300{
301 BMEdge *e_edj_pair[2];
302 int i;
303
304 /* Seems paranoid, but one caller also walks edges. */
306
309
310 e_edj_pair[0] = l->e;
311 e_edj_pair[1] = l->prev->e;
312
313 for (i = 0; i < 2; i++) {
314 BMEdge *e = e_edj_pair[i];
315 if (bmw_mask_check_edge(walker, e)) {
316 BMLoop *l_iter, *l_first;
317
318 l_iter = l_first = e->l;
319 do {
320 BMLoop *l_radial = (l_iter->v == l->v) ? l_iter : l_iter->next;
321 BLI_assert(l_radial->v == l->v);
322 if (l != l_radial) {
323 bmw_LoopShellWalker_visitLoop(walker, l_radial);
324 }
325 } while ((l_iter = l_iter->radial_next) != l_first);
326 }
327 }
328}
329
331{
332 BMwLoopShellWalker *swalk, owalk;
333 BMLoop *l;
334
335 BMW_state_remove_r(walker, &owalk);
336 swalk = &owalk;
337
338 l = swalk->curloop;
340
341 return l;
342}
343
346/* -------------------------------------------------------------------- */
360{
361 BMwLoopShellWireWalker *shellWalk = nullptr;
362
363 BLI_assert(bmw_edge_is_wire(walker, e));
364
365 if (BLI_gset_haskey(walker->visit_set_alt, e)) {
366 return;
367 }
368
369 if (!bmw_mask_check_edge(walker, e)) {
370 return;
371 }
372
373 shellWalk = static_cast<BMwLoopShellWireWalker *>(BMW_state_add(walker));
374 shellWalk->curelem = (BMElem *)e;
376}
377
378static void bmw_LoopShellWireWalker_visitVert(BMWalker *walker, BMVert *v, const BMEdge *e_from)
379{
380 BMEdge *e;
381
383
384 if (BLI_gset_haskey(walker->visit_set_alt, v)) {
385 return;
386 }
387
388 if (!bmw_mask_check_vert(walker, v)) {
389 return;
390 }
391
392 e = v->e;
393 do {
394 if (bmw_edge_is_wire(walker, e) && (e != e_from)) {
395 BMVert *v_other;
396 BMIter iter;
397 BMLoop *l;
398
400
401 /* Check if we step onto a non-wire vertex. */
402 v_other = BM_edge_other_vert(e, v);
403 BM_ITER_ELEM (l, &iter, v_other, BM_LOOPS_OF_VERT) {
404
406 }
407 }
408 } while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
409
411}
412
413static void bmw_LoopShellWireWalker_begin(BMWalker *walker, void *data)
414{
415 BMHeader *h = static_cast<BMHeader *>(data);
416
417 if (UNLIKELY(h == nullptr)) {
418 return;
419 }
420
421 bmw_LoopShellWalker_begin(walker, data);
422
423 switch (h->htype) {
424 case BM_LOOP: {
425 BMLoop *l = (BMLoop *)h;
426 bmw_LoopShellWireWalker_visitVert(walker, l->v, nullptr);
427 break;
428 }
429
430 case BM_VERT: {
431 BMVert *v = (BMVert *)h;
432 if (v->e) {
433 bmw_LoopShellWireWalker_visitVert(walker, v, nullptr);
434 }
435 break;
436 }
437 case BM_EDGE: {
438 BMEdge *e = (BMEdge *)h;
439 if (bmw_mask_check_edge(walker, e)) {
440 bmw_LoopShellWireWalker_visitVert(walker, e->v1, nullptr);
441 bmw_LoopShellWireWalker_visitVert(walker, e->v2, nullptr);
442 }
443 else if (e->l) {
444 BMLoop *l_iter, *l_first;
445
446 l_iter = l_first = e->l;
447 do {
448 bmw_LoopShellWalker_visitLoop(walker, l_iter);
449 bmw_LoopShellWalker_visitLoop(walker, l_iter->next);
450 } while ((l_iter = l_iter->radial_next) != l_first);
451 }
452 break;
453 }
454 case BM_FACE: {
455 /* Wire verts will be walked over. */
456 break;
457 }
458 default:
459 BLI_assert(0);
460 }
461}
462
464{
465 BMwLoopShellWireWalker *shellWalk = static_cast<BMwLoopShellWireWalker *>(
466 BMW_current_state(walker));
467 return shellWalk->curelem;
468}
469
471{
472 BMwLoopShellWireWalker *swalk, owalk;
473
474 BMW_state_remove_r(walker, &owalk);
475 swalk = &owalk;
476
477 if (swalk->curelem->head.htype == BM_LOOP) {
478 BMLoop *l = (BMLoop *)swalk->curelem;
479
481
482 bmw_LoopShellWireWalker_visitVert(walker, l->v, nullptr);
483
484 return l;
485 }
486
487 BMEdge *e = (BMEdge *)swalk->curelem;
488
490
493
494 return e;
495}
496
499/* -------------------------------------------------------------------- */
507{
508 BMwShellWalker *shellWalk = nullptr;
509
510 if (BLI_gset_haskey(walker->visit_set, e)) {
511 return;
512 }
513
514 if (!bmw_mask_check_edge(walker, e)) {
515 return;
516 }
517
518 shellWalk = static_cast<BMwShellWalker *>(BMW_state_add(walker));
519 shellWalk->curedge = e;
520 BLI_gset_insert(walker->visit_set, e);
521}
522
523static void bmw_FaceShellWalker_begin(BMWalker *walker, void *data)
524{
525 BMEdge *e = static_cast<BMEdge *>(data);
527}
528
530{
531 BMwShellWalker *shellWalk = static_cast<BMwShellWalker *>(BMW_current_state(walker));
532 return shellWalk->curedge;
533}
534
536{
537 BMwShellWalker *swalk, owalk;
538 BMEdge *e, *e2;
539 BMIter iter;
540
541 BMW_state_remove_r(walker, &owalk);
542 swalk = &owalk;
543
544 e = swalk->curedge;
545
546 if (e->l) {
547 BMLoop *l_iter, *l_first;
548
549 l_iter = l_first = e->l;
550 do {
551 BM_ITER_ELEM (e2, &iter, l_iter->f, BM_EDGES_OF_FACE) {
552 if (e2 != e) {
554 }
555 }
556 } while ((l_iter = l_iter->radial_next) != l_first);
557 }
558
559 return e;
560}
561
564/* -------------------------------------------------------------------- */
573{
575
576 if (BLI_gset_haskey(walker->visit_set, v)) {
577 /* Already visited. */
578 return;
579 }
580
581 if (!bmw_mask_check_vert(walker, v)) {
582 /* Not flagged for walk. */
583 return;
584 }
585
586 vwalk = static_cast<BMwConnectedVertexWalker *>(BMW_state_add(walker));
587 vwalk->curvert = v;
588 BLI_gset_insert(walker->visit_set, v);
589}
590
591static void bmw_ConnectedVertexWalker_begin(BMWalker *walker, void *data)
592{
593 BMVert *v = static_cast<BMVert *>(data);
595}
596
598{
600 BMW_current_state(walker));
601 return vwalk->curvert;
602}
603
605{
606 BMwConnectedVertexWalker *vwalk, owalk;
607 BMVert *v, *v2;
608 BMEdge *e;
609 BMIter iter;
610
611 BMW_state_remove_r(walker, &owalk);
612 vwalk = &owalk;
613
614 v = vwalk->curvert;
615
616 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
618 if (!BLI_gset_haskey(walker->visit_set, v2)) {
620 }
621 }
622
623 return v;
624}
625
628/* -------------------------------------------------------------------- */
641static void bmw_IslandboundWalker_begin(BMWalker *walker, void *data)
642{
643 BMLoop *l = static_cast<BMLoop *>(data);
644 BMwIslandboundWalker *iwalk = nullptr;
645
646 iwalk = static_cast<BMwIslandboundWalker *>(BMW_state_add(walker));
647
648 iwalk->base = iwalk->curloop = l;
649 iwalk->lastv = l->v;
650
651 BLI_gset_insert(walker->visit_set, data);
652}
653
655{
656 BMwIslandboundWalker *iwalk = static_cast<BMwIslandboundWalker *>(BMW_current_state(walker));
657
658 return iwalk->curloop;
659}
660
662{
663 BMwIslandboundWalker *iwalk, owalk;
664 BMVert *v;
665 BMEdge *e;
666 BMFace *f;
667 BMLoop *l;
668
669 memcpy(&owalk, BMW_current_state(walker), sizeof(owalk));
670 /* Normally we'd remove here, but delay until after error checking. */
671 iwalk = &owalk;
672
673 l = iwalk->curloop;
674 e = l->e;
675
676 v = BM_edge_other_vert(e, iwalk->lastv);
677
678 /* Pop off current state. */
679 BMW_state_remove(walker);
680
681 f = l->f;
682
683 while (true) {
685 if (BM_loop_is_manifold(l)) {
686 l = l->radial_next;
687 f = l->f;
688 e = l->e;
689
690 if (!bmw_mask_check_face(walker, f)) {
691 l = l->radial_next;
692 break;
693 }
694 }
695 else {
696 /* Treat non-manifold edges as boundaries. */
697 f = l->f;
698 e = l->e;
699 break;
700 }
701 }
702
703 if (l == owalk.curloop) {
704 return nullptr;
705 }
706 if (BLI_gset_haskey(walker->visit_set, l)) {
707 return owalk.curloop;
708 }
709
710 BLI_gset_insert(walker->visit_set, l);
711 iwalk = static_cast<BMwIslandboundWalker *>(BMW_state_add(walker));
712 iwalk->base = owalk.base;
713
714#if 0
715 if (!BMO_face_flag_test(walker->bm, l->f, walker->visibility_flag)) {
716 iwalk->curloop = l->radial_next;
717 }
718 else {
719 iwalk->curloop = l;
720 }
721#else
722 iwalk->curloop = l;
723#endif
724 iwalk->lastv = v;
725
726 return owalk.curloop;
727}
728
729/* -------------------------------------------------------------------- */
737static void bmw_IslandWalker_begin(BMWalker *walker, void *data)
738{
739 BMwIslandWalker *iwalk = nullptr;
740
741 if (!bmw_mask_check_face(walker, static_cast<BMFace *>(data))) {
742 return;
743 }
744
745 iwalk = static_cast<BMwIslandWalker *>(BMW_state_add(walker));
746 BLI_gset_insert(walker->visit_set, data);
747
748 iwalk->cur = static_cast<BMFace *>(data);
749}
750
751static void *bmw_IslandWalker_yield(BMWalker *walker)
752{
753 BMwIslandWalker *iwalk = static_cast<BMwIslandWalker *>(BMW_current_state(walker));
754
755 return iwalk->cur;
756}
757
758static void *bmw_IslandWalker_step_ex(BMWalker *walker, bool only_manifold)
759{
760 BMwIslandWalker *iwalk, owalk;
761 BMLoop *l_iter, *l_first;
762
763 BMW_state_remove_r(walker, &owalk);
764 iwalk = &owalk;
765
766 l_iter = l_first = BM_FACE_FIRST_LOOP(iwalk->cur);
767 do {
768 /* Could skip loop here too, but don't add unless we need it. */
769 if (!bmw_mask_check_edge(walker, l_iter->e)) {
770 continue;
771 }
772
773 BMLoop *l_radial_iter;
774
775 if (only_manifold && (l_iter->radial_next != l_iter)) {
776 int face_count = 1;
777 /* Check other faces (not this one), ensure only one other Can be walked onto. */
778 l_radial_iter = l_iter->radial_next;
779 do {
780 if (bmw_mask_check_face(walker, l_radial_iter->f)) {
781 face_count++;
782 if (face_count == 3) {
783 break;
784 }
785 }
786 } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
787
788 if (face_count != 2) {
789 continue;
790 }
791 }
792
793 l_radial_iter = l_iter;
794 while ((l_radial_iter = l_radial_iter->radial_next) != l_iter) {
795 BMFace *f = l_radial_iter->f;
796
797 if (!bmw_mask_check_face(walker, f)) {
798 continue;
799 }
800
801 /* Saves checking #BLI_gset_haskey below (manifold edges there's a 50% chance). */
802 if (f == iwalk->cur) {
803 continue;
804 }
805
806 if (BLI_gset_haskey(walker->visit_set, f)) {
807 continue;
808 }
809
810 iwalk = static_cast<BMwIslandWalker *>(BMW_state_add(walker));
811 iwalk->cur = f;
812 BLI_gset_insert(walker->visit_set, f);
813 break;
814 }
815 } while ((l_iter = l_iter->next) != l_first);
816
817 return owalk.cur;
818}
819
820static void *bmw_IslandWalker_step(BMWalker *walker)
821{
822 return bmw_IslandWalker_step_ex(walker, false);
823}
824
829{
830 return bmw_IslandWalker_step_ex(walker, true);
831}
832
835/* -------------------------------------------------------------------- */
841/* utility function to see if an edge is a part of an ngon boundary */
843{
844 return (BM_edge_is_boundary(e) && (e->l->f->len > 4) &&
845 (BM_edge_is_boundary(e->l->next->e) || BM_edge_is_boundary(e->l->prev->e)));
846}
847
848static void bmw_EdgeLoopWalker_begin(BMWalker *walker, void *data)
849{
850 BMwEdgeLoopWalker *lwalk = nullptr, owalk, *owalk_pt;
851 BMEdge *e = static_cast<BMEdge *>(data);
852 BMVert *v;
853 const int vert_edge_count[2] = {
856 };
857 const int vert_face_count[2] = {
860 };
861
862 v = e->v1;
863
864 lwalk = static_cast<BMwEdgeLoopWalker *>(BMW_state_add(walker));
865 BLI_gset_insert(walker->visit_set, e);
866
867 lwalk->cur = lwalk->start = e;
868 lwalk->lastv = lwalk->startv = v;
870 lwalk->is_single = (lwalk->is_boundary && bm_edge_is_single(e));
871
936 if ((lwalk->is_boundary == false) &&
937 /* Without checking the face count, the 3 edges could be this edge
938 * plus two boundary edges (which would not be stepped over), see #84906. */
939 ((vert_edge_count[0] == 3 && vert_face_count[0] == 3) ||
940 (vert_edge_count[1] == 3 && vert_face_count[1] == 3)))
941 {
942 BMIter iter;
943 BMFace *f_iter;
944 BMFace *f_best = nullptr;
945
946 BM_ITER_ELEM (f_iter, &iter, e, BM_FACES_OF_EDGE) {
947 if (f_best == nullptr || f_best->len < f_iter->len) {
948 f_best = f_iter;
949 }
950 }
951
952 if (f_best) {
953 /* Only use hub selection for 5+ sides else this could
954 * conflict with normal edge loop selection. */
955 lwalk->f_hub = f_best->len > 4 ? f_best : nullptr;
956 }
957 else {
958 /* Edge doesn't have any faces connected to it. */
959 lwalk->f_hub = nullptr;
960 }
961 }
962 else {
963 lwalk->f_hub = nullptr;
964 }
965
966 /* Rewind. */
967 while ((owalk_pt = static_cast<BMwEdgeLoopWalker *>(BMW_current_state(walker)))) {
968 owalk = *((BMwEdgeLoopWalker *)owalk_pt);
969 BMW_walk(walker);
970 }
971
972 lwalk = static_cast<BMwEdgeLoopWalker *>(BMW_state_add(walker));
973 *lwalk = owalk;
974
975 lwalk->lastv = lwalk->startv = BM_edge_other_vert(owalk.cur, lwalk->lastv);
976
977 BLI_gset_clear(walker->visit_set, nullptr);
978 BLI_gset_insert(walker->visit_set, owalk.cur);
979}
980
982{
983 BMwEdgeLoopWalker *lwalk = static_cast<BMwEdgeLoopWalker *>(BMW_current_state(walker));
984
985 return lwalk->cur;
986}
987
989{
990 BMwEdgeLoopWalker *lwalk, owalk;
991 BMEdge *e, *nexte = nullptr;
992 BMLoop *l;
993 BMVert *v;
994
995 BMW_state_remove_r(walker, &owalk);
996 lwalk = &owalk;
997
998 e = lwalk->cur;
999 l = e->l;
1000
1001 if (owalk.f_hub) { /* NGON EDGE */
1002 int vert_edge_tot;
1003
1004 v = BM_edge_other_vert(e, lwalk->lastv);
1005
1006 vert_edge_tot = BM_vert_edge_count_nonwire(v);
1007
1008 if (vert_edge_tot == 3) {
1009 l = BM_face_other_vert_loop(owalk.f_hub, lwalk->lastv, v);
1010 nexte = BM_edge_exists(v, l->v);
1011
1012 if (bmw_mask_check_edge(walker, nexte) && !BLI_gset_haskey(walker->visit_set, nexte) &&
1013 /* Never step onto a boundary edge, this gives odd-results. */
1014 (BM_edge_is_boundary(nexte) == false))
1015 {
1016 lwalk = static_cast<BMwEdgeLoopWalker *>(BMW_state_add(walker));
1017 lwalk->cur = nexte;
1018 lwalk->lastv = v;
1019
1020 lwalk->is_boundary = owalk.is_boundary;
1021 lwalk->is_single = owalk.is_single;
1022 lwalk->f_hub = owalk.f_hub;
1023
1024 BLI_gset_insert(walker->visit_set, nexte);
1025 }
1026 }
1027 }
1028 else if (l == nullptr) { /* WIRE EDGE */
1029 BMIter eiter;
1030
1031 /* Match trunk: mark all connected wire edges. */
1032 for (int i = 0; i < 2; i++) {
1033 v = i ? e->v2 : e->v1;
1034
1035 BM_ITER_ELEM (nexte, &eiter, v, BM_EDGES_OF_VERT) {
1036 if ((nexte->l == nullptr) && bmw_mask_check_edge(walker, nexte) &&
1037 !BLI_gset_haskey(walker->visit_set, nexte))
1038 {
1039 lwalk = static_cast<BMwEdgeLoopWalker *>(BMW_state_add(walker));
1040 lwalk->cur = nexte;
1041 lwalk->lastv = v;
1042
1043 lwalk->is_boundary = owalk.is_boundary;
1044 lwalk->is_single = owalk.is_single;
1045 lwalk->f_hub = owalk.f_hub;
1046
1047 BLI_gset_insert(walker->visit_set, nexte);
1048 }
1049 }
1050 }
1051 }
1052 else if (owalk.is_boundary == false) { /* NORMAL EDGE WITH FACES */
1053 int vert_edge_tot;
1054
1055 v = BM_edge_other_vert(e, lwalk->lastv);
1056
1057 vert_edge_tot = BM_vert_edge_count_nonwire(v);
1058
1059 /* Typical looping over edges in the middle of a mesh.
1060 * Why use 2 here at all? - for internal ngon loops it can be useful. */
1061 if (ELEM(vert_edge_tot, 4, 2)) {
1062 int i_opposite = vert_edge_tot / 2;
1063 int i = 0;
1064 do {
1066 if (BM_edge_is_manifold(l->e)) {
1067 l = l->radial_next;
1068 }
1069 else {
1070 l = nullptr;
1071 break;
1072 }
1073 } while (++i != i_opposite);
1074 }
1075 else {
1076 l = nullptr;
1077 }
1078
1079 if (l != nullptr) {
1080 if (l != e->l && bmw_mask_check_edge(walker, l->e) &&
1081 !BLI_gset_haskey(walker->visit_set, l->e))
1082 {
1083 lwalk = static_cast<BMwEdgeLoopWalker *>(BMW_state_add(walker));
1084 lwalk->cur = l->e;
1085 lwalk->lastv = v;
1086
1087 lwalk->is_boundary = owalk.is_boundary;
1088 lwalk->is_single = owalk.is_single;
1089 lwalk->f_hub = owalk.f_hub;
1090
1091 BLI_gset_insert(walker->visit_set, l->e);
1092 }
1093 }
1094 }
1095 else if (owalk.is_boundary == true) { /* BOUNDARY EDGE WITH FACES */
1096 int vert_edge_tot;
1097
1098 v = BM_edge_other_vert(e, lwalk->lastv);
1099
1100 vert_edge_tot = BM_vert_edge_count_nonwire(v);
1101
1102 /* Check if we should step, this is fairly involved. */
1103 if (
1104 /* Walk over boundary of faces but stop at corners. */
1105 (owalk.is_single == false && vert_edge_tot > 2) ||
1106
1107 /* Initial edge was a boundary, so is this edge and vertex is only a part of this face
1108 * this lets us walk over the boundary of an ngon which is handy. */
1109 (owalk.is_single == true && vert_edge_tot == 2 && BM_edge_is_boundary(e)))
1110 {
1111 /* Find next boundary edge in the fan. */
1112 do {
1114 if (BM_edge_is_manifold(l->e)) {
1115 l = l->radial_next;
1116 }
1117 else if (BM_edge_is_boundary(l->e)) {
1118 break;
1119 }
1120 else {
1121 l = nullptr;
1122 break;
1123 }
1124 } while (true);
1125 }
1126
1127 if (owalk.is_single == false && l && bm_edge_is_single(l->e)) {
1128 l = nullptr;
1129 }
1130
1131 if (l != nullptr) {
1132 if (l != e->l && bmw_mask_check_edge(walker, l->e) &&
1133 !BLI_gset_haskey(walker->visit_set, l->e))
1134 {
1135 lwalk = static_cast<BMwEdgeLoopWalker *>(BMW_state_add(walker));
1136 lwalk->cur = l->e;
1137 lwalk->lastv = v;
1138
1139 lwalk->is_boundary = owalk.is_boundary;
1140 lwalk->is_single = owalk.is_single;
1141 lwalk->f_hub = owalk.f_hub;
1142
1143 BLI_gset_insert(walker->visit_set, l->e);
1144 }
1145 }
1146 }
1147
1148 return owalk.cur;
1149}
1150
1153/* -------------------------------------------------------------------- */
1166{
1167 /* Face must have degree 4. */
1168 if (l->f->len != 4) {
1169 return false;
1170 }
1171
1172 if (!bmw_mask_check_face(walker, l->f)) {
1173 return false;
1174 }
1175
1176 /* The face must not have been already visited. */
1177 if (BLI_gset_haskey(walker->visit_set, l->f) && BLI_gset_haskey(walker->visit_set_alt, l->e)) {
1178 return false;
1179 }
1180
1181 return true;
1182}
1183
1184/* Check whether the face loop can start from the given edge. */
1186{
1187 /* There is no face loop starting from a wire edge. */
1188 if (BM_edge_is_wire(e)) {
1189 return false;
1190 }
1191
1192 /* Don't start a loop from a boundary edge if it cannot be extended to cover any faces. */
1193 if (BM_edge_is_boundary(e)) {
1194 if (!bmw_FaceLoopWalker_include_face(walker, e->l)) {
1195 return false;
1196 }
1197 }
1198
1199 /* Don't start a face loop from non-manifold edges. */
1200 if (!BM_edge_is_manifold(e)) {
1201 return false;
1202 }
1203
1204 return true;
1205}
1206
1207static void bmw_FaceLoopWalker_begin(BMWalker *walker, void *data)
1208{
1209 BMwFaceLoopWalker *lwalk, owalk, *owalk_pt;
1210 BMEdge *e = static_cast<BMEdge *>(data);
1211 // BMesh *bm = walker->bm; /* UNUSED */
1212 // int fcount = BM_edge_face_count(e); /* UNUSED */
1213
1214 if (!bmw_FaceLoopWalker_edge_begins_loop(walker, e)) {
1215 return;
1216 }
1217
1218 lwalk = static_cast<BMwFaceLoopWalker *>(BMW_state_add(walker));
1219 lwalk->l = e->l;
1220 lwalk->no_calc = false;
1221 BLI_gset_insert(walker->visit_set, lwalk->l->f);
1222
1223 /* Rewind. */
1224 while ((owalk_pt = static_cast<BMwFaceLoopWalker *>(BMW_current_state(walker)))) {
1225 owalk = *((BMwFaceLoopWalker *)owalk_pt);
1226 BMW_walk(walker);
1227 }
1228
1229 lwalk = static_cast<BMwFaceLoopWalker *>(BMW_state_add(walker));
1230 *lwalk = owalk;
1231 lwalk->no_calc = false;
1232
1233 BLI_gset_clear(walker->visit_set_alt, nullptr);
1234 BLI_gset_insert(walker->visit_set_alt, lwalk->l->e);
1235
1236 BLI_gset_clear(walker->visit_set, nullptr);
1237 BLI_gset_insert(walker->visit_set, lwalk->l->f);
1238}
1239
1241{
1242 BMwFaceLoopWalker *lwalk = static_cast<BMwFaceLoopWalker *>(BMW_current_state(walker));
1243
1244 if (!lwalk) {
1245 return nullptr;
1246 }
1247
1248 return lwalk->l->f;
1249}
1250
1252{
1253 BMwFaceLoopWalker *lwalk, owalk;
1254 BMFace *f;
1255 BMLoop *l;
1256
1257 BMW_state_remove_r(walker, &owalk);
1258 lwalk = &owalk;
1259
1260 f = lwalk->l->f;
1261 l = lwalk->l->radial_next;
1262
1263 if (lwalk->no_calc) {
1264 return f;
1265 }
1266
1267 if (!bmw_FaceLoopWalker_include_face(walker, l)) {
1268 l = lwalk->l;
1269 l = l->next->next;
1270 if (!BM_edge_is_manifold(l->e)) {
1271 l = l->prev->prev;
1272 }
1273 l = l->radial_next;
1274 }
1275
1276 if (bmw_FaceLoopWalker_include_face(walker, l)) {
1277 lwalk = static_cast<BMwFaceLoopWalker *>(BMW_state_add(walker));
1278 lwalk->l = l;
1279
1280 if (l->f->len != 4) {
1281 lwalk->no_calc = true;
1282 lwalk->l = owalk.l;
1283 }
1284 else {
1285 lwalk->no_calc = false;
1286 }
1287
1288 /* Both may already exist. */
1289 BLI_gset_add(walker->visit_set_alt, l->e);
1290 BLI_gset_add(walker->visit_set, l->f);
1291 }
1292
1293 return f;
1294}
1295
1298// #define BMW_EDGERING_NGON
1299
1300/* -------------------------------------------------------------------- */
1308static void bmw_EdgeringWalker_begin(BMWalker *walker, void *data)
1309{
1310 BMwEdgeringWalker *lwalk, owalk, *owalk_pt;
1311 BMEdge *e = static_cast<BMEdge *>(data);
1312
1313 lwalk = static_cast<BMwEdgeringWalker *>(BMW_state_add(walker));
1314 lwalk->l = e->l;
1315
1316 if (!lwalk->l) {
1317 lwalk->wireedge = e;
1318 return;
1319 }
1320 lwalk->wireedge = nullptr;
1321
1322 BLI_gset_insert(walker->visit_set, lwalk->l->e);
1323
1324 /* Rewind. */
1325 while ((owalk_pt = static_cast<BMwEdgeringWalker *>(BMW_current_state(walker)))) {
1326 owalk = *((BMwEdgeringWalker *)owalk_pt);
1327 BMW_walk(walker);
1328 }
1329
1330 lwalk = static_cast<BMwEdgeringWalker *>(BMW_state_add(walker));
1331 *lwalk = owalk;
1332
1333#ifdef BMW_EDGERING_NGON
1334 if (lwalk->l->f->len % 2 != 0)
1335#else
1336 if (lwalk->l->f->len != 4)
1337#endif
1338 {
1339 lwalk->l = lwalk->l->radial_next;
1340 }
1341
1342 BLI_gset_clear(walker->visit_set, nullptr);
1343 BLI_gset_insert(walker->visit_set, lwalk->l->e);
1344}
1345
1347{
1348 BMwEdgeringWalker *lwalk = static_cast<BMwEdgeringWalker *>(BMW_current_state(walker));
1349
1350 if (!lwalk) {
1351 return nullptr;
1352 }
1353
1354 if (lwalk->l) {
1355 return lwalk->l->e;
1356 }
1357 return lwalk->wireedge;
1358}
1359
1361{
1362 BMwEdgeringWalker *lwalk, owalk;
1363 BMEdge *e;
1364 BMLoop *l;
1365#ifdef BMW_EDGERING_NGON
1366 int i, len;
1367#endif
1368
1369#define EDGE_CHECK(e) \
1370 (bmw_mask_check_edge(walker, e) && (BM_edge_is_boundary(e) || BM_edge_is_manifold(e)))
1371
1372 BMW_state_remove_r(walker, &owalk);
1373 lwalk = &owalk;
1374
1375 l = lwalk->l;
1376 if (!l) {
1377 return lwalk->wireedge;
1378 }
1379
1380 e = l->e;
1381 if (!EDGE_CHECK(e)) {
1382 /* Walker won't traverse to a non-manifold edge, but may
1383 * be started on one, and should not traverse *away* from
1384 * a non-manifold edge (non-manifold edges are never in an
1385 * edge ring with manifold edges. */
1386 return e;
1387 }
1388
1389#ifdef BMW_EDGERING_NGON
1390 l = l->radial_next;
1391
1392 i = len = l->f->len;
1393 while (i > 0) {
1394 l = l->next;
1395 i -= 2;
1396 }
1397
1398 if ((len <= 0) || (len % 2 != 0) || !EDGE_CHECK(l->e) || !bmw_mask_check_face(walker, l->f)) {
1399 l = owalk.l;
1400 i = len;
1401 while (i > 0) {
1402 l = l->next;
1403 i -= 2;
1404 }
1405 }
1406 /* Only walk to manifold edge. */
1407 if ((l->f->len % 2 == 0) && EDGE_CHECK(l->e) && !BLI_gset_haskey(walker->visit_set, l->e))
1408#else
1409
1410 l = l->radial_next;
1411 l = l->next->next;
1412
1413 if ((l->f->len != 4) || !EDGE_CHECK(l->e) || !bmw_mask_check_face(walker, l->f)) {
1414 l = owalk.l->next->next;
1415 }
1416 /* Only walk to manifold edge. */
1417 if ((l->f->len == 4) && EDGE_CHECK(l->e) && !BLI_gset_haskey(walker->visit_set, l->e))
1418#endif
1419 {
1420 lwalk = static_cast<BMwEdgeringWalker *>(BMW_state_add(walker));
1421 lwalk->l = l;
1422 lwalk->wireedge = nullptr;
1423
1424 BLI_gset_insert(walker->visit_set, l->e);
1425 }
1426
1427 return e;
1428
1429#undef EDGE_CHECK
1430}
1431
1434/* -------------------------------------------------------------------- */
1438static void bmw_EdgeboundaryWalker_begin(BMWalker *walker, void *data)
1439{
1440 BMwEdgeboundaryWalker *lwalk;
1441 BMEdge *e = static_cast<BMEdge *>(data);
1442
1444
1445 if (BLI_gset_haskey(walker->visit_set, e)) {
1446 return;
1447 }
1448
1449 lwalk = static_cast<BMwEdgeboundaryWalker *>(BMW_state_add(walker));
1450 lwalk->e = e;
1451 BLI_gset_insert(walker->visit_set, e);
1452}
1453
1455{
1456 BMwEdgeboundaryWalker *lwalk = static_cast<BMwEdgeboundaryWalker *>(BMW_current_state(walker));
1457
1458 if (!lwalk) {
1459 return nullptr;
1460 }
1461
1462 return lwalk->e;
1463}
1464
1466{
1467 BMwEdgeboundaryWalker *lwalk, owalk;
1468 BMEdge *e, *e_other;
1469 BMVert *v;
1470 BMIter eiter;
1471 BMIter viter;
1472
1473 BMW_state_remove_r(walker, &owalk);
1474 lwalk = &owalk;
1475
1476 e = lwalk->e;
1477
1478 if (!bmw_mask_check_edge(walker, e)) {
1479 return e;
1480 }
1481
1482 BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
1483 BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) {
1484 if (e != e_other && BM_edge_is_boundary(e_other)) {
1485 if (BLI_gset_haskey(walker->visit_set, e_other)) {
1486 continue;
1487 }
1488
1489 if (!bmw_mask_check_edge(walker, e_other)) {
1490 continue;
1491 }
1492
1493 lwalk = static_cast<BMwEdgeboundaryWalker *>(BMW_state_add(walker));
1494 BLI_gset_insert(walker->visit_set, e_other);
1495
1496 lwalk->e = e_other;
1497 }
1498 }
1499 }
1500
1501 return e;
1502}
1503
1506/* -------------------------------------------------------------------- */
1516static void bmw_UVEdgeWalker_begin(BMWalker *walker, void *data)
1517{
1518 BMwUVEdgeWalker *lwalk;
1519 BMLoop *l = static_cast<BMLoop *>(data);
1520
1521 if (BLI_gset_haskey(walker->visit_set, l)) {
1522 return;
1523 }
1524
1525 lwalk = static_cast<BMwUVEdgeWalker *>(BMW_state_add(walker));
1526 lwalk->l = l;
1527 BLI_gset_insert(walker->visit_set, l);
1528}
1529
1531{
1532 BMwUVEdgeWalker *lwalk = static_cast<BMwUVEdgeWalker *>(BMW_current_state(walker));
1533
1534 if (!lwalk) {
1535 return nullptr;
1536 }
1537
1538 return lwalk->l;
1539}
1540
1541static void *bmw_UVEdgeWalker_step(BMWalker *walker)
1542{
1543 const int type = walker->bm->ldata.layers[walker->layer].type;
1544 const int offset = walker->bm->ldata.layers[walker->layer].offset;
1545
1546 BMwUVEdgeWalker *lwalk, owalk;
1547 BMLoop *l;
1548 int i;
1549
1550 BMW_state_remove_r(walker, &owalk);
1551 lwalk = &owalk;
1552
1553 l = lwalk->l;
1554
1555 if (!bmw_mask_check_edge(walker, l->e)) {
1556 return l;
1557 }
1558
1559 /* Go over loops around `l->v` and `l->next->v` and see which ones share `l` and `l->next`
1560 * UV coordinates. in addition, push on `l->next` if necessary. */
1561 for (i = 0; i < 2; i++) {
1562 BMIter liter;
1563 BMLoop *l_pivot, *l_radial;
1564
1565 l_pivot = i ? l->next : l;
1566 BM_ITER_ELEM (l_radial, &liter, l_pivot->v, BM_LOOPS_OF_VERT) {
1567 BMLoop *l_radial_first = l_radial;
1568 void *data_pivot = BM_ELEM_CD_GET_VOID_P(l_pivot, offset);
1569
1570 do {
1571 BMLoop *l_other;
1572 void *data_other;
1573
1574 if (BLI_gset_haskey(walker->visit_set, l_radial)) {
1575 continue;
1576 }
1577
1578 if (l_radial->v != l_pivot->v) {
1579 if (!bmw_mask_check_edge(walker, l_radial->e)) {
1580 continue;
1581 }
1582 }
1583
1584 l_other = (l_radial->v != l_pivot->v) ? l_radial->next : l_radial;
1585 data_other = BM_ELEM_CD_GET_VOID_P(l_other, offset);
1586
1587 if (!CustomData_data_equals(eCustomDataType(type), data_pivot, data_other)) {
1588 continue;
1589 }
1590
1591 lwalk = static_cast<BMwUVEdgeWalker *>(BMW_state_add(walker));
1592 BLI_gset_insert(walker->visit_set, l_radial);
1593
1594 lwalk->l = l_radial;
1595
1596 } while ((l_radial = l_radial->radial_next) != l_radial_first);
1597 }
1598 }
1599
1600 return l;
1601}
1602
1605/* -------------------------------------------------------------------- */
1609static void bmw_NonManifoldedgeWalker_begin(BMWalker *walker, void *data)
1610{
1612 BMEdge *e = static_cast<BMEdge *>(data);
1613
1614 if (BLI_gset_haskey(walker->visit_set, e)) {
1615 return;
1616 }
1617
1618 lwalk = static_cast<BMwNonManifoldEdgeLoopWalker *>(BMW_state_add(walker));
1619 lwalk->start = e;
1620 lwalk->cur = e;
1621 lwalk->startv = e->v1;
1622 lwalk->lastv = e->v1;
1624 BLI_gset_insert(walker->visit_set, e);
1625}
1626
1628{
1630 BMW_current_state(walker));
1631
1632 if (!lwalk) {
1633 return nullptr;
1634 }
1635 return lwalk->cur;
1636}
1637
1643{
1644 BLI_assert(!BM_loop_is_manifold(l));
1645 do {
1647 if (BM_loop_is_manifold(l)) {
1648 l = l->radial_next;
1649 }
1650 else if (BM_edge_face_count_is_equal(l->e, face_count)) {
1651 return l;
1652 }
1653 else {
1654 break;
1655 }
1656 } while (true);
1657 return nullptr;
1658}
1659
1661{
1662 BMwNonManifoldEdgeLoopWalker *lwalk, owalk;
1663 BMW_state_remove_r(walker, &owalk);
1664 lwalk = &owalk;
1665 BMLoop *l_cur = nullptr;
1666 const int face_count = lwalk->face_count;
1667
1668 BMVert *v = nullptr;
1669
1670 /* Use the second pass is unlikely, only needed to walk back in the opposite direction. */
1671 for (int pass = 0; pass < 2; pass++) {
1672
1673 BMEdge *e = lwalk->cur;
1674 v = BM_edge_other_vert(e, lwalk->lastv);
1675
1676 /* If `lwalk.lastv` can't be walked along, start walking in the opposite direction
1677 * on the initial edge, do this at most one time during this walk operation. */
1678 if (UNLIKELY(pass == 1)) {
1679 e = lwalk->start;
1680 v = lwalk->startv;
1681 }
1682
1683 BMLoop *l = e->l;
1684 do {
1685 BMLoop *l_next = bmw_NonManifoldLoop_find_next_around_vertex(l, v, face_count);
1686 if ((l_next != nullptr) && !BLI_gset_haskey(walker->visit_set, l_next->e)) {
1687 if (l_cur == nullptr) {
1688 l_cur = l_next;
1689 }
1690 else if (l_cur->e != l_next->e) {
1691 /* If there are more than one possible edge to step onto (unlikely but possible),
1692 * treat as a junction and stop walking as there is no correct answer in this case. */
1693 l_cur = nullptr;
1694 break;
1695 }
1696 }
1697 } while ((l = l->radial_next) != e->l);
1698
1699 if (l_cur != nullptr) {
1700 break;
1701 }
1702 }
1703
1704 if (l_cur != nullptr) {
1705 BLI_assert(!BLI_gset_haskey(walker->visit_set, l_cur->e));
1706 BLI_assert(BM_edge_face_count(l_cur->e) == face_count);
1707 lwalk = static_cast<BMwNonManifoldEdgeLoopWalker *>(BMW_state_add(walker));
1708 lwalk->lastv = v;
1709 lwalk->cur = l_cur->e;
1710 lwalk->face_count = face_count;
1711 BLI_gset_insert(walker->visit_set, l_cur->e);
1712 }
1713 return owalk.cur;
1714}
1715
1727
1737
1747
1749 BM_EDGE,
1753 sizeof(BMwShellWalker),
1755 BM_EDGE, /* Valid restrict masks. */
1756};
1757
1767
1769 BM_FACE,
1773 sizeof(BMwIslandWalker),
1775 BM_EDGE | BM_FACE, /* Valid restrict masks. */
1776};
1777
1779 BM_FACE,
1781 bmw_IslandManifoldWalker_step, /* Only difference with #BMW_ISLAND. */
1783 sizeof(BMwIslandWalker),
1785 BM_EDGE | BM_FACE, /* Valid restrict masks. */
1786};
1787
1789 BM_EDGE,
1793 sizeof(BMwEdgeLoopWalker),
1795 0,
1796 /* Valid restrict masks. */ /* Could add flags here but so far none are used. */
1797};
1798
1800 BM_EDGE,
1804 sizeof(BMwFaceLoopWalker),
1806 0,
1807 /* Valid restrict masks. */ /* Could add flags here but so far none are used. */
1808};
1809
1811 BM_EDGE,
1815 sizeof(BMwEdgeringWalker),
1817 BM_EDGE, /* Valid restrict masks. */
1818};
1819
1829
1839
1841 BM_LOOP,
1845 sizeof(BMwUVEdgeWalker),
1847 BM_EDGE, /* Valid restrict masks. */
1848};
1849
1859
1862/* -------------------------------------------------------------------- */
1867 &bmw_VertShellWalker_Type, /* #BMW_VERT_SHELL */
1868 &bmw_LoopShellWalker_Type, /* #BMW_LOOP_SHELL */
1869 &bmw_LoopShellWireWalker_Type, /* #BMW_LOOP_SHELL_WIRE */
1870 &bmw_FaceShellWalker_Type, /* #BMW_FACE_SHELL */
1871 &bmw_EdgeLoopWalker_Type, /* #BMW_EDGELOOP */
1872 &bmw_FaceLoopWalker_Type, /* #BMW_FACELOOP */
1873 &bmw_EdgeringWalker_Type, /* #BMW_EDGERING */
1874 &bmw_EdgeboundaryWalker_Type, /* #BMW_EDGEBOUNDARY */
1875 &bmw_NonManifoldedgeWalker_type, /* #BMW_EDGELOOP_NONMANIFOLD */
1876 &bmw_UVEdgeWalker_Type, /* #BMW_LOOPDATA_ISLAND */
1877 &bmw_IslandboundWalker_Type, /* #BMW_ISLANDBOUND */
1878 &bmw_IslandWalker_Type, /* #BMW_ISLAND */
1879 &bmw_IslandManifoldWalker_Type, /* #BMW_ISLAND_MANIFOLD */
1880 &bmw_ConnectedVertexWalker_Type, /* #BMW_CONNECTED_VERTEX */
1881};
1882
1884
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_data_equals(eCustomDataType type, const void *data1, const void *data2)
#define BLI_assert(a)
Definition BLI_assert.h:50
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:1004
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1029
void BLI_gset_insert(GSet *gs, void *key)
Definition BLI_ghash.c:959
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.c:966
#define ARRAY_SIZE(arr)
#define UNLIKELY(x)
#define ELEM(...)
@ BM_LOOP
#define BM_DISK_EDGE_NEXT(e, v)
@ BM_ELEM_HIDDEN
#define BM_FACE_FIRST_LOOP(p)
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BM_elem_flag_test(ele, hflag)
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_FACES_OF_EDGE
@ BM_VERTS_OF_EDGE
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
@ BM_EDGES_OF_FACE
#define BM_FACE
#define BM_EDGE
#define BM_VERT
#define BMO_edge_flag_test(bm, e, oflag)
#define BMO_vert_flag_test(bm, e, oflag)
#define BMO_face_flag_test(bm, e, oflag)
BMLoop * BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
int BM_vert_face_count(const BMVert *v)
int BM_edge_face_count(const BMEdge *e)
BMLoop * BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
Other Loop in Face Sharing a Vertex.
int BM_vert_edge_count_nonwire(const BMVert *v)
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_edge_face_count_is_equal(e, n)
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void * BMW_state_add(BMWalker *walker)
Add a new Walker State.
void * BMW_current_state(BMWalker *walker)
Current Walker State.
void * BMW_walk(BMWalker *walker)
Main Walking Function.
void BMW_state_remove(BMWalker *walker)
Remove Current Walker State.
@ BMW_DEPTH_FIRST
@ BMW_BREADTH_FIRST
@ BMW_FLAG_TEST_HIDDEN
static void bmw_FaceLoopWalker_begin(BMWalker *walker, void *data)
static void bmw_VertShellWalker_begin(BMWalker *walker, void *data)
static bool bmw_edge_is_wire(const BMWalker *walker, const BMEdge *e)
static void * bmw_VertShellWalker_yield(BMWalker *walker)
static BMWalker bmw_UVEdgeWalker_Type
static void * bmw_IslandWalker_step_ex(BMWalker *walker, bool only_manifold)
static void bmw_ConnectedVertexWalker_begin(BMWalker *walker, void *data)
static void * bmw_NonManifoldedgeWalker_step(BMWalker *walker)
static void * bmw_IslandboundWalker_yield(BMWalker *walker)
static bool bmw_FaceLoopWalker_edge_begins_loop(BMWalker *walker, BMEdge *e)
static void bmw_FaceShellWalker_begin(BMWalker *walker, void *data)
static bool bmw_FaceLoopWalker_include_face(BMWalker *walker, BMLoop *l)
static void * bmw_LoopShellWalker_step(BMWalker *walker)
static bool bm_edge_is_single(BMEdge *e)
static BMWalker bmw_FaceLoopWalker_Type
static void * bmw_FaceLoopWalker_yield(BMWalker *walker)
static void * bmw_VertShellWalker_step(BMWalker *walker)
static void * bmw_IslandboundWalker_step(BMWalker *walker)
static void bmw_IslandboundWalker_begin(BMWalker *walker, void *data)
static void * bmw_EdgeringWalker_step(BMWalker *walker)
static void * bmw_IslandManifoldWalker_step(BMWalker *walker)
static void * bmw_EdgeLoopWalker_step(BMWalker *walker)
static void bmw_LoopShellWalker_step_impl(BMWalker *walker, BMLoop *l)
static void bmw_IslandWalker_begin(BMWalker *walker, void *data)
static void bmw_EdgeboundaryWalker_begin(BMWalker *walker, void *data)
static BMWalker bmw_ConnectedVertexWalker_Type
static BMWalker bmw_FaceShellWalker_Type
static void * bmw_IslandWalker_step(BMWalker *walker)
static BMWalker bmw_EdgeboundaryWalker_Type
static void bmw_EdgeringWalker_begin(BMWalker *walker, void *data)
static void * bmw_ConnectedVertexWalker_step(BMWalker *walker)
static void bmw_VertShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
#define EDGE_CHECK(e)
static void bmw_LoopShellWalker_visitLoop(BMWalker *walker, BMLoop *l)
static void * bmw_UVEdgeWalker_step(BMWalker *walker)
#define BMW_state_remove_r(walker, owalk)
static void * bmw_EdgeLoopWalker_yield(BMWalker *walker)
const int bm_totwalkers
static bool bmw_mask_check_edge(BMWalker *walker, BMEdge *e)
static BMWalker bmw_LoopShellWireWalker_Type
static void bmw_NonManifoldedgeWalker_begin(BMWalker *walker, void *data)
static void bmw_LoopShellWalker_visitEdgeWire(BMWalker *walker, BMEdge *e)
static BMLoop * bmw_NonManifoldLoop_find_next_around_vertex(BMLoop *l, BMVert *v, int face_count)
static void bmw_ConnectedVertexWalker_visitVertex(BMWalker *walker, BMVert *v)
static BMWalker bmw_IslandboundWalker_Type
static bool bmw_mask_check_face(BMWalker *walker, BMFace *f)
static void bmw_LoopShellWireWalker_visitVert(BMWalker *walker, BMVert *v, const BMEdge *e_from)
static void * bmw_UVEdgeWalker_yield(BMWalker *walker)
static void bmw_EdgeLoopWalker_begin(BMWalker *walker, void *data)
static BMWalker bmw_EdgeringWalker_Type
static bool bmw_mask_check_vert(BMWalker *walker, BMVert *v)
static void bmw_FaceShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
static void * bmw_FaceLoopWalker_step(BMWalker *walker)
static void * bmw_EdgeboundaryWalker_yield(BMWalker *walker)
static void * bmw_NonManifoldedgeWalker_yield(BMWalker *walker)
static void * bmw_LoopShellWalker_yield(BMWalker *walker)
static void bmw_LoopShellWireWalker_begin(BMWalker *walker, void *data)
static void bmw_UVEdgeWalker_begin(BMWalker *walker, void *data)
static void * bmw_LoopShellWireWalker_step(BMWalker *walker)
static BMWalker bmw_LoopShellWalker_Type
static void * bmw_EdgeboundaryWalker_step(BMWalker *walker)
static void * bmw_ConnectedVertexWalker_yield(BMWalker *walker)
static void * bmw_IslandWalker_yield(BMWalker *walker)
static void * bmw_FaceShellWalker_yield(BMWalker *walker)
static BMWalker bmw_EdgeLoopWalker_Type
static BMWalker bmw_VertShellWalker_Type
static void * bmw_FaceShellWalker_step(BMWalker *walker)
static void * bmw_EdgeringWalker_yield(BMWalker *walker)
static BMWalker bmw_IslandManifoldWalker_Type
static void bmw_LoopShellWalker_begin(BMWalker *walker, void *data)
static BMWalker bmw_NonManifoldedgeWalker_type
static BMWalker bmw_IslandWalker_Type
static void * bmw_LoopShellWireWalker_yield(BMWalker *walker)
BMWalker * bm_walker_types[]
struct BMwNonManifoldEdgeLoopWalker BMwNonManifoldEdgeLoopWalker
struct BMwIslandWalker BMwIslandWalker
struct BMwFaceLoopWalker BMwFaceLoopWalker
struct BMwEdgeLoopWalker BMwEdgeLoopWalker
struct BMwIslandboundWalker BMwIslandboundWalker
struct BMwEdgeringWalker BMwEdgeringWalker
struct BMwConnectedVertexWalker BMwConnectedVertexWalker
struct BMwLoopShellWalker BMwLoopShellWalker
struct BMwEdgeboundaryWalker BMwEdgeboundaryWalker
struct BMwLoopShellWireWalker BMwLoopShellWireWalker
struct BMwShellWalker BMwShellWalker
struct BMwUVEdgeWalker BMwUVEdgeWalker
int len
static ulong * next
struct BMLoop * l
BMHeader head
BMHeader head
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
struct BMEdge * e
BMHeader head
struct GSet * visit_set_alt
BMWFlag flag
short mask_face
struct GSet * visit_set
BMesh * bm
short mask_edge
short mask_vert
CustomData ldata
CustomDataLayer * layers