Blender V5.0
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
10
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/* -------------------------------------------------------------------- */
31
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
66
67/* -------------------------------------------------------------------- */
70
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
87
88/* -------------------------------------------------------------------- */
99
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
221
222/* -------------------------------------------------------------------- */
230
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. */
305 BLI_assert(l->head.htype == BM_LOOP);
306
307 bmw_LoopShellWalker_visitLoop(walker, l->next);
308 bmw_LoopShellWalker_visitLoop(walker, l->prev);
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
345
346/* -------------------------------------------------------------------- */
358
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
382 BLI_assert(v->head.htype == BM_VERT);
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
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
489 BLI_assert(e->head.htype == BM_EDGE);
490
493
494 return e;
495}
496
498
499/* -------------------------------------------------------------------- */
505
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
563
564/* -------------------------------------------------------------------- */
571
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
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
627
628/* -------------------------------------------------------------------- */
640
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
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/* -------------------------------------------------------------------- */
736
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));
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
834
835/* -------------------------------------------------------------------- */
840
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 = *(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
1152
1153/* -------------------------------------------------------------------- */
1160
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 = *(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
1297
1298// #define BMW_EDGERING_NGON
1299
1300/* -------------------------------------------------------------------- */
1307
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 = *(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
1433
1434/* -------------------------------------------------------------------- */
1437
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
1505
1506/* -------------------------------------------------------------------- */
1515
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
1604
1605/* -------------------------------------------------------------------- */
1608
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
1717
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
1861
1862/* -------------------------------------------------------------------- */
1865
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:46
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp)
void BLI_gset_insert(GSet *gs, void *key)
Definition BLI_ghash.cc:959
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.cc:966
#define ARRAY_SIZE(arr)
#define UNLIKELY(x)
#define ELEM(...)
#define BM_DISK_EDGE_NEXT(e, v)
#define BM_FACE_FIRST_LOOP(p)
@ BM_ELEM_HIDDEN
@ BM_LOOP
#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
BMesh const char void * data
#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[]
static ulong * next
struct BMLoop * l
BMHeader head
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMFace * f
struct BMLoop * next
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
i
Definition text_draw.cc:230
uint len