Blender V5.0
bmesh_query.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
15
16#include "MEM_guardedalloc.h"
17
18#include "BLI_alloca.h"
19#include "BLI_linklist.h"
20#include "BLI_math_base.h"
21#include "BLI_math_geom.h"
22#include "BLI_math_matrix.h"
23#include "BLI_math_rotation.h"
24#include "BLI_math_vector.h"
26
27#include "BKE_customdata.hh"
28
29#include "bmesh.hh"
31
38
40{
42 return l->v == v ? l->prev : l->next;
43}
44
46{
47 BMLoop *l_iter = BM_face_vert_share_loop(f, v);
48
49 BLI_assert(BM_edge_exists(v_prev, v) != nullptr);
50
51 if (l_iter) {
52 if (l_iter->prev->v == v_prev) {
53 return l_iter->next;
54 }
55 if (l_iter->next->v == v_prev) {
56 return l_iter->prev;
57 }
58 /* invalid args */
59 BLI_assert(0);
60 return nullptr;
61 }
62 /* invalid args */
63 BLI_assert(0);
64 return nullptr;
65}
66
68{
69#if 0 /* works but slow */
71#else
72 BMEdge *e = l->e;
73 BMVert *v_prev = BM_edge_other_vert(e, v);
74 if (l->v == v) {
75 if (l->prev->v == v_prev) {
76 return l->next;
77 }
78 BLI_assert(l->next->v == v_prev);
79
80 return l->prev;
81 }
82 BLI_assert(l->v == v_prev);
83
84 if (l->prev->v == v) {
85 return l->prev->prev;
86 }
87 BLI_assert(l->next->v == v);
88 return l->next->next;
89#endif
90}
91
93{
95 if (l->e == e) {
96 return l->next;
97 }
98 if (l->prev->e == e) {
99 return l->prev;
100 }
101
102 BLI_assert(0);
103 return nullptr;
104}
105
107{
108 if (v_a->e && v_b->e) {
109 BMIter iter;
110 BMFace *f;
111
112 BM_ITER_ELEM (f, &iter, v_a, BM_FACES_OF_VERT) {
113 if (BM_vert_in_face(v_b, f)) {
114 return true;
115 }
116 }
117 }
118
119 return false;
120}
121
123 BMVert *v_b,
124 bool (*test_fn)(BMFace *, void *user_data),
125 void *user_data)
126{
127 if (v_a->e && v_b->e) {
128 BMIter iter;
129 BMFace *f;
130
131 BM_ITER_ELEM (f, &iter, v_a, BM_FACES_OF_VERT) {
132 if (test_fn(f, user_data)) {
133 if (BM_vert_in_face(v_b, f)) {
134 return true;
135 }
136 }
137 }
138 }
139
140 return false;
141}
142
144 BMVert *v_b,
145 const bool allow_adjacent,
146 bool (*callback)(BMFace *, BMLoop *, BMLoop *, void *userdata),
147 void *user_data,
148 BMLoop **r_l_a,
149 BMLoop **r_l_b)
150{
151 if (v_a->e && v_b->e) {
152 BMIter iter;
153 BMLoop *l_a, *l_b;
154
155 BM_ITER_ELEM (l_a, &iter, v_a, BM_LOOPS_OF_VERT) {
156 BMFace *f = l_a->f;
158 if (l_b && (allow_adjacent || !BM_loop_is_adjacent(l_a, l_b)) &&
159 callback(f, l_a, l_b, user_data))
160 {
161 *r_l_a = l_a;
162 *r_l_b = l_b;
163
164 return f;
165 }
166 }
167 }
168
169 return nullptr;
170}
171
173 BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
174{
175 BMLoop *l_cur_a = nullptr, *l_cur_b = nullptr;
176 BMFace *f_cur = nullptr;
177
178 if (v_a->e && v_b->e) {
179 BMIter iter;
180 BMLoop *l_a, *l_b;
181
182 BM_ITER_ELEM (l_a, &iter, v_a, BM_LOOPS_OF_VERT) {
183 if ((f_cur == nullptr) || (l_a->f->len < f_cur->len)) {
184 l_b = BM_face_vert_share_loop(l_a->f, v_b);
185 if (l_b && (allow_adjacent || !BM_loop_is_adjacent(l_a, l_b))) {
186 f_cur = l_a->f;
187 l_cur_a = l_a;
188 l_cur_b = l_b;
189 }
190 }
191 }
192 }
193
194 *r_l_a = l_cur_a;
195 *r_l_b = l_cur_b;
196
197 return f_cur;
198}
199
201 BMEdge *e_a, BMEdge *e_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
202{
203 BMLoop *l_cur_a = nullptr, *l_cur_b = nullptr;
204 BMFace *f_cur = nullptr;
205
206 if (e_a->l && e_b->l) {
207 BMIter iter;
208 BMLoop *l_a, *l_b;
209
210 BM_ITER_ELEM (l_a, &iter, e_a, BM_LOOPS_OF_EDGE) {
211 if ((f_cur == nullptr) || (l_a->f->len < f_cur->len)) {
212 l_b = BM_face_edge_share_loop(l_a->f, e_b);
213 if (l_b && (allow_adjacent || !BM_loop_is_adjacent(l_a, l_b))) {
214 f_cur = l_a->f;
215 l_cur_a = l_a;
216 l_cur_b = l_b;
217 }
218 }
219 }
220 }
221
222 *r_l_a = l_cur_a;
223 *r_l_b = l_cur_b;
224
225 return f_cur;
226}
227
229{
230 float no[2][3];
231
232 if ((BM_face_calc_normal_subset(l_a, l_b, no[0]) != 0.0f) &&
233 (BM_face_calc_normal_subset(l_b, l_a, no[1]) != 0.0f))
234 {
235 return dot_v3v3(no[0], no[1]);
236 }
237 return -1.0f;
238}
239
240float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3])
241{
242 const float *axis = l->f->no;
243 return dist_signed_squared_to_corner_v3v3v3(co, l->prev->v->co, l->v->co, l->next->v->co, axis);
244}
245
246float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
247{
248 const float *axis = l->f->no;
249 float dir[3];
250 float plane[4];
251
252 sub_v3_v3v3(dir, l->next->v->co, l->v->co);
253 cross_v3_v3v3(plane, axis, dir);
254
255 plane[3] = -dot_v3v3(plane, l->v->co);
256 return dist_signed_squared_to_plane_v3(co, plane);
257}
258
260 BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
261{
262 BMLoop *l_cur_a = nullptr, *l_cur_b = nullptr;
263 BMFace *f_cur = nullptr;
264
265 if (v_a->e && v_b->e) {
266 BMIter iter;
267 BMLoop *l_a, *l_b;
268 float dot_best = -1.0f;
269
270 BM_ITER_ELEM (l_a, &iter, v_a, BM_LOOPS_OF_VERT) {
271 l_b = BM_face_vert_share_loop(l_a->f, v_b);
272 if (l_b && (allow_adjacent || !BM_loop_is_adjacent(l_a, l_b))) {
273
274 if (f_cur == nullptr) {
275 f_cur = l_a->f;
276 l_cur_a = l_a;
277 l_cur_b = l_b;
278 }
279 else {
280 /* avoid expensive calculations if we only ever find one face */
281 float dot;
282 if (dot_best == -1.0f) {
283 dot_best = bm_face_calc_split_dot(l_cur_a, l_cur_b);
284 }
285
287 if (dot > dot_best) {
288 dot_best = dot;
289
290 f_cur = l_a->f;
291 l_cur_a = l_a;
292 l_cur_b = l_b;
293 }
294 }
295 }
296 }
297 }
298
299 *r_l_a = l_cur_a;
300 *r_l_b = l_cur_b;
301
302 return f_cur;
303}
304
306{
307 return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : nullptr;
308}
313
315{
316 BMLoop *l_iter, *l_first;
317
318#ifdef USE_BMESH_HOLES
319 BMLoopList *lst;
320 for (lst = f->loops.first; lst; lst = lst->next)
321#endif
322 {
323#ifdef USE_BMESH_HOLES
324 l_iter = l_first = lst->first;
325#else
326 l_iter = l_first = f->l_first;
327#endif
328 do {
329 if (l_iter->v == v) {
330 return true;
331 }
332 } while ((l_iter = l_iter->next) != l_first);
333 }
334
335 return false;
336}
337
339{
340 BMLoop *l_iter, *l_first;
341
342#ifdef USE_BMESH_HOLES
343 BMLoopList *lst;
344#endif
345
346 int i, count = 0;
347
348 for (i = 0; i < len; i++) {
350 }
351
352#ifdef USE_BMESH_HOLES
353 for (lst = f->loops.first; lst; lst = lst->next)
354#endif
355 {
356
357#ifdef USE_BMESH_HOLES
358 l_iter = l_first = lst->first;
359#else
360 l_iter = l_first = f->l_first;
361#endif
362
363 do {
364 if (BM_ELEM_API_FLAG_TEST(l_iter->v, _FLAG_OVERLAP)) {
365 count++;
366 }
367
368 } while ((l_iter = l_iter->next) != l_first);
369 }
370
371 for (i = 0; i < len; i++) {
373 }
374
375 return count;
376}
377
378bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
379{
380 BMLoop *l_iter, *l_first;
381
382#ifdef USE_BMESH_HOLES
383 BMLoopList *lst;
384#endif
385
386 int i;
387 bool ok = true;
388
389 /* simple check, we know can't succeed */
390 if (f->len < len) {
391 return false;
392 }
393
394 for (i = 0; i < len; i++) {
396 }
397
398#ifdef USE_BMESH_HOLES
399 for (lst = f->loops.first; lst; lst = lst->next)
400#endif
401 {
402
403#ifdef USE_BMESH_HOLES
404 l_iter = l_first = lst->first;
405#else
406 l_iter = l_first = f->l_first;
407#endif
408
409 do {
410 if (BM_ELEM_API_FLAG_TEST(l_iter->v, _FLAG_OVERLAP)) {
411 /* pass */
412 }
413 else {
414 ok = false;
415 break;
416 }
417
418 } while ((l_iter = l_iter->next) != l_first);
419 }
420
421 for (i = 0; i < len; i++) {
423 }
424
425 return ok;
426}
427
428bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
429{
430 if (e->l) {
431 const BMLoop *l_iter, *l_first;
432
433 l_iter = l_first = e->l;
434 do {
435 if (l_iter->f == f) {
436 return true;
437 }
438 } while ((l_iter = l_iter->radial_next) != l_first);
439 }
440
441 return false;
442}
443
445{
446 BMLoop *l_other;
447
448 // BLI_assert(BM_edge_is_manifold(e)); /* Too strict, just check there is another radial face. */
449 BLI_assert(e->l && e->l->radial_next != e->l);
451
452 l_other = (l->e == e) ? l : l->prev;
453 l_other = l_other->radial_next;
454 BLI_assert(l_other->e == e);
455
456 if (l_other->v == l->v) {
457 /* pass */
458 }
459 else if (l_other->next->v == l->v) {
460 l_other = l_other->next;
461 }
462 else {
463 BLI_assert(0);
464 }
465
466 return l_other;
467}
468
470{
471 BMEdge *e_prev = *e_step;
472 BMEdge *e_next;
473 if (l->e == e_prev) {
474 e_next = l->prev->e;
475 }
476 else if (l->prev->e == e_prev) {
477 e_next = l->e;
478 }
479 else {
480 BLI_assert(0);
481 return nullptr;
482 }
483
484 if (BM_edge_is_manifold(e_next)) {
485 return BM_edge_other_loop((*e_step = e_next), l);
486 }
487 return nullptr;
488}
489
491{
492 BMLoop *l_a;
493 int tot = 0;
494 int i;
495
496 BLI_assert(BM_vert_in_edge(e_first, v));
497
498 l_a = e_first->l;
499 do {
500 l_a = BM_loop_other_vert_loop(l_a, v);
501 l_a = BM_vert_in_edge(l_a->e, v) ? l_a : l_a->prev;
502 if (BM_edge_is_manifold(l_a->e)) {
503 l_a = l_a->radial_next;
504 }
505 else {
506 return nullptr;
507 }
508
509 tot++;
510 } while (l_a != e_first->l);
511
512 /* we know the total, now loop half way */
513 tot /= 2;
514 i = 0;
515
516 l_a = e_first->l;
517 do {
518 if (i == tot) {
519 l_a = BM_vert_in_edge(l_a->e, v) ? l_a : l_a->prev;
520 return l_a->e;
521 }
522
523 l_a = BM_loop_other_vert_loop(l_a, v);
524 l_a = BM_vert_in_edge(l_a->e, v) ? l_a : l_a->prev;
525 if (BM_edge_is_manifold(l_a->e)) {
526 l_a = l_a->radial_next;
527 }
528 /* this won't have changed from the previous loop */
529
530 i++;
531 } while (l_a != e_first->l);
532
533 return nullptr;
534}
535
537{
538 return len_v3v3(e->v1->co, e->v2->co);
539}
540
542{
543 return len_squared_v3v3(e->v1->co, e->v2->co);
544}
545
546bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
547{
548 BMLoop *la, *lb;
549
550 if ((la = e->l) && (lb = la->radial_next) && (la != lb) && (lb->radial_next == la)) {
551 *r_fa = la->f;
552 *r_fb = lb->f;
553 return true;
554 }
555
556 *r_fa = nullptr;
557 *r_fb = nullptr;
558 return false;
559}
560
561bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
562{
563 BMLoop *la, *lb;
564
565 if ((la = e->l) && (lb = la->radial_next) && (la != lb) && (lb->radial_next == la)) {
566 *r_la = la;
567 *r_lb = lb;
568 return true;
569 }
570
571 *r_la = nullptr;
572 *r_lb = nullptr;
573 return false;
574}
575
577{
578 const BMEdge *e = v->e;
579 if (e) {
580 BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v);
581 return ((e_other != e) && (BM_DISK_EDGE_NEXT(e_other, v) == e));
582 }
583 return false;
584}
585
587{
588 const BMEdge *e = v->e;
589 if (e) {
590 BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v);
591 if ((e_other != e) && (BM_DISK_EDGE_NEXT(e_other, v) == e)) {
592 return BM_edge_is_manifold(e) && BM_edge_is_manifold(e_other);
593 }
594 }
595 return false;
596}
597
598bool BM_vert_edge_pair(const BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
599{
600 BMEdge *e_a = v->e;
601 if (e_a) {
602 BMEdge *e_b = BM_DISK_EDGE_NEXT(e_a, v);
603 if ((e_b != e_a) && (BM_DISK_EDGE_NEXT(e_b, v) == e_a)) {
604 *r_e_a = e_a;
605 *r_e_b = e_b;
606 return true;
607 }
608 }
609
610 *r_e_a = nullptr;
611 *r_e_b = nullptr;
612 return false;
613}
614
616{
617 return bmesh_disk_count(v);
618}
619
620int BM_vert_edge_count_at_most(const BMVert *v, const int count_max)
621{
622 return bmesh_disk_count_at_most(v, count_max);
623}
624
626{
627 int count = 0;
628 BMIter eiter;
629 BMEdge *edge;
630 BM_ITER_ELEM (edge, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) {
631 if (edge->l) {
632 count++;
633 }
634 }
635 return count;
636}
638{
639 int count = 0;
640
641 if (e->l) {
642 BMLoop *l_iter, *l_first;
643
644 l_iter = l_first = e->l;
645 do {
646 count++;
647 } while ((l_iter = l_iter->radial_next) != l_first);
648 }
649
650 return count;
651}
652
653int BM_edge_face_count_at_most(const BMEdge *e, const int count_max)
654{
655 int count = 0;
656
657 if (e->l) {
658 BMLoop *l_iter, *l_first;
659
660 l_iter = l_first = e->l;
661 do {
662 count++;
663 if (count == count_max) {
664 break;
665 }
666 } while ((l_iter = l_iter->radial_next) != l_first);
667 }
668
669 return count;
670}
671
673{
675}
676
677int BM_vert_face_count_at_most(const BMVert *v, int count_max)
678{
679 return bmesh_disk_facevert_count_at_most(v, count_max);
680}
681
683{
684 if (v->e != nullptr) {
685 const BMEdge *e_iter, *e_first;
686 e_first = e_iter = v->e;
687 do {
688 if (e_iter->l != nullptr) {
689 return true;
690 }
691 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
692 }
693 return false;
694}
695
697{
698 if (v->e) {
699 BMEdge *e_first, *e_iter;
700
701 e_first = e_iter = v->e;
702 do {
703 if (e_iter->l) {
704 return false;
705 }
706 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
707
708 return true;
709 }
710 return false;
711}
712
714{
715 BMEdge *e_iter, *e_first, *e_prev;
716 BMLoop *l_iter, *l_first;
717 int loop_num = 0, loop_num_region = 0, boundary_num = 0;
718
719 if (v->e == nullptr) {
720 /* loose vert */
721 return false;
722 }
723
724 /* count edges while looking for non-manifold edges */
725 e_first = e_iter = v->e;
726 /* may be null */
727 l_first = e_iter->l;
728 do {
729 /* loose edge or edge shared by more than two faces,
730 * edges with 1 face user are OK, otherwise we could
731 * use BM_edge_is_manifold() here */
732 if (e_iter->l == nullptr || (e_iter->l != e_iter->l->radial_next->radial_next)) {
733 return false;
734 }
735
736 /* count radial loops */
737 if (e_iter->l->v == v) {
738 loop_num += 1;
739 }
740
741 if (!BM_edge_is_boundary(e_iter)) {
742 /* non boundary check opposite loop */
743 if (e_iter->l->radial_next->v == v) {
744 loop_num += 1;
745 }
746 }
747 else {
748 /* start at the boundary */
749 l_first = e_iter->l;
750 boundary_num += 1;
751 /* >2 boundaries can't be manifold */
752 if (boundary_num == 3) {
753 return false;
754 }
755 }
756 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
757
758 e_first = l_first->e;
759 l_first = (l_first->v == v) ? l_first : l_first->next;
760 BLI_assert(l_first->v == v);
761
762 l_iter = l_first;
763 e_prev = e_first;
764
765 do {
766 loop_num_region += 1;
767 } while (((l_iter = BM_vert_step_fan_loop(l_iter, &e_prev)) != l_first) && (l_iter != nullptr));
768
769 return (loop_num == loop_num_region);
770}
771
772#define LOOP_VISIT _FLAG_WALK
773#define EDGE_VISIT _FLAG_WALK
774
776{
777 BMLoop *l_iter, *l_first;
778 int count = 0;
779
782
783 l_iter = l_first = e->l;
784 do {
785 if (l_iter->v == v) {
786 BMEdge *e_other = l_iter->prev->e;
787 if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
789 count += 1;
790 }
791 if (!BM_ELEM_API_FLAG_TEST(e_other, EDGE_VISIT)) {
793 }
794 }
795 else if (l_iter->next->v == v) {
796 BMEdge *e_other = l_iter->next->e;
797 if (!BM_ELEM_API_FLAG_TEST(l_iter->next, LOOP_VISIT)) {
799 count += 1;
800 }
801 if (!BM_ELEM_API_FLAG_TEST(e_other, EDGE_VISIT)) {
803 }
804 }
805 else {
806 BLI_assert(0);
807 }
808 } while ((l_iter = l_iter->radial_next) != l_first);
809
810 return count;
811}
812
814{
815 int count = 0;
816 BMEdge *e_iter, *e_first;
817
818 /* clear flags */
819 e_iter = e_first = l->e;
820 do {
822 if (e_iter->l) {
823 BMLoop *l_iter, *l_first;
824 l_iter = l_first = e_iter->l;
825 do {
826 if (l_iter->v == l->v) {
828 count += 1;
829 }
830 } while ((l_iter = l_iter->radial_next) != l_first);
831 }
832 } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != e_first);
833
834 return count;
835}
836
838{
839 const int count = bm_loop_region_count__recursive(l->e, l->v);
840 const int count_total = bm_loop_region_count__clear(l);
841 if (r_loop_total) {
842 *r_loop_total = count_total;
843 }
844 return count;
845}
846
847#undef LOOP_VISIT
848#undef EDGE_VISIT
849
854
856{
857 BMLoop *l_first = BM_vert_find_first_loop((BMVert *)v);
858 if (l_first) {
859 int count, count_total;
860 count = BM_loop_region_loops_count_at_most(l_first, &count_total);
861 return (count == count_total);
862 }
863 return true;
864}
865
867{
868 if (BM_edge_is_manifold(e)) {
869 BMLoop *l1 = e->l;
870 BMLoop *l2 = e->l->radial_next;
871 if (!equals_v3v3(l1->f->no, l2->f->no)) {
872 float cross[3];
873 float l_dir[3];
874 cross_v3_v3v3(cross, l1->f->no, l2->f->no);
875 /* we assume contiguous normals, otherwise the result isn't meaningful */
876 sub_v3_v3v3(l_dir, l1->next->v->co, l1->v->co);
877 return (dot_v3v3(l_dir, cross) > 0.0f);
878 }
879 }
880 return true;
881}
882
884 const int cd_loop_type,
885 const int cd_loop_offset)
886{
887 BLI_assert(cd_loop_offset != -1);
888
889 if (e->l && e->l->radial_next != e->l) {
890 const BMLoop *l_base_v1 = e->l;
891 const BMLoop *l_base_v2 = e->l->next;
892 const void *l_base_cd_v1 = BM_ELEM_CD_GET_VOID_P(l_base_v1, cd_loop_offset);
893 const void *l_base_cd_v2 = BM_ELEM_CD_GET_VOID_P(l_base_v2, cd_loop_offset);
894 const BMLoop *l_iter = e->l->radial_next;
895 do {
896 const BMLoop *l_iter_v1;
897 const BMLoop *l_iter_v2;
898 const void *l_iter_cd_v1;
899 const void *l_iter_cd_v2;
900
901 if (l_iter->v == l_base_v1->v) {
902 l_iter_v1 = l_iter;
903 l_iter_v2 = l_iter->next;
904 }
905 else {
906 l_iter_v1 = l_iter->next;
907 l_iter_v2 = l_iter;
908 }
909 BLI_assert((l_iter_v1->v == l_base_v1->v) && (l_iter_v2->v == l_base_v2->v));
910
911 l_iter_cd_v1 = BM_ELEM_CD_GET_VOID_P(l_iter_v1, cd_loop_offset);
912 l_iter_cd_v2 = BM_ELEM_CD_GET_VOID_P(l_iter_v2, cd_loop_offset);
913
914 if ((CustomData_data_equals(eCustomDataType(cd_loop_type), l_base_cd_v1, l_iter_cd_v1) ==
915 0) ||
916 (CustomData_data_equals(eCustomDataType(cd_loop_type), l_base_cd_v2, l_iter_cd_v2) == 0))
917 {
918 return false;
919 }
920
921 } while ((l_iter = l_iter->radial_next) != e->l);
922 }
923 return true;
924}
925
927{
928 if (v->e) {
929 BMEdge *e_first, *e_iter;
930
931 e_first = e_iter = v->e;
932 do {
933 if (BM_edge_is_boundary(e_iter)) {
934 return true;
935 }
936 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
937
938 return false;
939 }
940 return false;
941}
942
944{
945 BMIter iter1, iter2;
946 BMEdge *e;
947 BMFace *f;
948 int count = 0;
949
950 BM_ITER_ELEM (e, &iter1, f_a, BM_EDGES_OF_FACE) {
951 BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) {
952 if (f != f_a && f != f_b && BM_face_share_edge_check(f, f_b)) {
953 count++;
954 }
955 }
956 }
957
958 return count;
959}
960
962{
963 BMIter iter1, iter2;
964 BMEdge *e;
965 BMFace *f;
966
967 BM_ITER_ELEM (e, &iter1, f_a, BM_EDGES_OF_FACE) {
968 BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) {
969 if (f != f_a && f != f_b && BM_face_share_edge_check(f, f_b)) {
970 return true;
971 }
972 }
973 }
974
975 return false;
976}
977
979{
980 BMLoop *l_iter;
981 BMLoop *l_first;
982 int count = 0;
983
984 l_iter = l_first = BM_FACE_FIRST_LOOP(f_a);
985 do {
986 if (BM_edge_in_face(l_iter->e, f_b)) {
987 count++;
988 }
989 } while ((l_iter = l_iter->next) != l_first);
990
991 return count;
992}
993
995{
996 BMLoop *l_iter;
997 BMLoop *l_first;
998
999 l_iter = l_first = BM_FACE_FIRST_LOOP(f_a);
1000 do {
1001 if (BM_edge_in_face(l_iter->e, f_b)) {
1002 return true;
1003 }
1004 } while ((l_iter = l_iter->next) != l_first);
1005
1006 return false;
1007}
1008
1010{
1011 BMLoop *l_iter;
1012 BMLoop *l_first;
1013 int count = 0;
1014
1015 l_iter = l_first = BM_FACE_FIRST_LOOP(f_a);
1016 do {
1017 if (BM_vert_in_face(l_iter->v, f_b)) {
1018 count++;
1019 }
1020 } while ((l_iter = l_iter->next) != l_first);
1021
1022 return count;
1023}
1024
1026{
1027 BMLoop *l_iter;
1028 BMLoop *l_first;
1029
1030 l_iter = l_first = BM_FACE_FIRST_LOOP(f_a);
1031 do {
1032 if (BM_vert_in_face(l_iter->v, f_b)) {
1033 return true;
1034 }
1035 } while ((l_iter = l_iter->next) != l_first);
1036
1037 return false;
1038}
1039
1041{
1042 BLI_assert(l_a->v == l_b->v);
1043 return (ELEM(l_a->e, l_b->e, l_b->prev->e) || ELEM(l_b->e, l_a->e, l_a->prev->e));
1044}
1045
1047{
1048 BMLoop *l;
1049 BMFace *f;
1050
1051 if (e1->l && e2->l) {
1052 l = e1->l;
1053 do {
1054 f = l->f;
1055 if (BM_edge_in_face(e2, f)) {
1056 return true;
1057 }
1058 l = l->radial_next;
1059 } while (l != e1->l);
1060 }
1061 return false;
1062}
1063
1065{
1066 BMLoop *l;
1067 BMFace *f;
1068
1069 if (e1->l && e2->l) {
1070 l = e1->l;
1071 do {
1072 f = l->f;
1073 if (f->len == 4) {
1074 if (BM_edge_in_face(e2, f)) {
1075 return true;
1076 }
1077 }
1078 l = l->radial_next;
1079 } while (l != e1->l);
1080 }
1081 return false;
1082}
1083
1085{
1086 return (e1->v1 == e2->v1 || e1->v1 == e2->v2 || e1->v2 == e2->v1 || e1->v2 == e2->v2);
1087}
1088
1090{
1091 BLI_assert(e1 != e2);
1092 if (BM_vert_in_edge(e2, e1->v1)) {
1093 return e1->v1;
1094 }
1095 if (BM_vert_in_edge(e2, e1->v2)) {
1096 return e1->v2;
1097 }
1098 return nullptr;
1099}
1100
1102{
1104 if (l->v == v) {
1105 return l;
1106 }
1107 return l->next;
1108}
1109
1111{
1112 BMLoop *l_first;
1113 BMLoop *l_iter;
1114
1115 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1116 do {
1117 if (l_iter->v == v) {
1118 return l_iter;
1119 }
1120 } while ((l_iter = l_iter->next) != l_first);
1121
1122 return nullptr;
1123}
1124
1126{
1127 BMLoop *l_first;
1128 BMLoop *l_iter;
1129
1130 l_iter = l_first = e->l;
1131 do {
1132 if (l_iter->f == f) {
1133 return l_iter;
1134 }
1135 } while ((l_iter = l_iter->radial_next) != l_first);
1136
1137 return nullptr;
1138}
1139
1141 BMVert **r_v1,
1142 BMVert **r_v2,
1143 const BMLoop *edge_loop)
1144{
1145 BLI_assert(edge_loop->e == edge);
1146 (void)edge; /* quiet warning in release build */
1147 *r_v1 = edge_loop->v;
1148 *r_v2 = edge_loop->next->v;
1149}
1150
1151void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
1152{
1153 BM_edge_ordered_verts_ex(edge, r_v1, r_v2, edge->l);
1154}
1155
1156BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
1157{
1158 BMLoop *l_step = l->prev;
1159
1160 BLI_assert(!ELEM(l_stop, nullptr, l));
1161
1162 while (UNLIKELY(len_squared_v3v3(l->v->co, l_step->v->co) < eps_sq)) {
1163 l_step = l_step->prev;
1164 BLI_assert(l_step != l);
1165 if (UNLIKELY(l_step == l_stop)) {
1166 return nullptr;
1167 }
1168 }
1169
1170 return l_step;
1171}
1172
1173BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
1174{
1175 BMLoop *l_step = l->next;
1176
1177 BLI_assert(!ELEM(l_stop, nullptr, l));
1178
1179 while (UNLIKELY(len_squared_v3v3(l->v->co, l_step->v->co) < eps_sq)) {
1180 l_step = l_step->next;
1181 BLI_assert(l_step != l);
1182 if (UNLIKELY(l_step == l_stop)) {
1183 return nullptr;
1184 }
1185 }
1186
1187 return l_step;
1188}
1189
1191{
1192 float e_dir_prev[3];
1193 float e_dir_next[3];
1194 float l_no[3];
1195
1196 sub_v3_v3v3(e_dir_prev, l->prev->v->co, l->v->co);
1197 sub_v3_v3v3(e_dir_next, l->next->v->co, l->v->co);
1198 cross_v3_v3v3(l_no, e_dir_next, e_dir_prev);
1199 return dot_v3v3(l_no, l->f->no) > 0.0f;
1200}
1201
1203{
1204 return angle_v3v3v3(l->prev->v->co, l->v->co, l->next->v->co);
1205}
1206
1207float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
1208{
1209 /* NOTE: we cannot use result of normal_tri_v3 here to detect colinear vectors
1210 * (vertex on a straight line) from zero value,
1211 * because it does not normalize both vectors before making cross-product.
1212 * Instead of adding two costly normalize computations,
1213 * just check ourselves for colinear case. */
1214 /* NOTE: FEPSILON might need some finer tweaking at some point?
1215 * Seems to be working OK for now though. */
1216 float v1[3], v2[3], v_tmp[3];
1217 sub_v3_v3v3(v1, l->prev->v->co, l->v->co);
1218 sub_v3_v3v3(v2, l->next->v->co, l->v->co);
1219
1220 const float fac = ((v2[0] == 0.0f) ?
1221 ((v2[1] == 0.0f) ? ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) :
1222 v1[1] / v2[1]) :
1223 v1[0] / v2[0]);
1224
1225 mul_v3_v3fl(v_tmp, v2, fac);
1226 sub_v3_v3(v_tmp, v1);
1227 if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) {
1228 /* Not co-linear, we can compute cross-product and normalize it into normal. */
1229 cross_v3_v3v3(r_normal, v1, v2);
1230 return normalize_v3(r_normal);
1231 }
1232 copy_v3_v3(r_normal, l->f->no);
1233 return 0.0f;
1234}
1235
1237 const float normal_fallback[3],
1238 float const (*vertexCos)[3],
1239 const float epsilon_sq,
1240 float r_normal[3])
1241{
1242 const int i_prev = BM_elem_index_get(l->prev->v);
1243 const int i_next = BM_elem_index_get(l->next->v);
1244 const int i = BM_elem_index_get(l->v);
1245
1246 float v1[3], v2[3], v_tmp[3];
1247 sub_v3_v3v3(v1, vertexCos[i_prev], vertexCos[i]);
1248 sub_v3_v3v3(v2, vertexCos[i_next], vertexCos[i]);
1249
1250 const float fac = ((v2[0] == 0.0f) ?
1251 ((v2[1] == 0.0f) ? ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) :
1252 v1[1] / v2[1]) :
1253 v1[0] / v2[0]);
1254
1255 mul_v3_v3fl(v_tmp, v2, fac);
1256 sub_v3_v3(v_tmp, v1);
1257 if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) {
1258 /* Not co-linear, we can compute cross-product and normalize it into normal. */
1259 cross_v3_v3v3(r_normal, v1, v2);
1260 return normalize_v3(r_normal);
1261 }
1262 copy_v3_v3(r_normal, normal_fallback);
1263 return 0.0f;
1264}
1265
1266float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
1267{
1268 return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal);
1269}
1270
1272 const float normal_fallback[3],
1273 float const (*vertexCos)[3],
1274 float r_normal[3])
1275
1276{
1277 return BM_loop_calc_face_normal_safe_vcos_ex(l, normal_fallback, vertexCos, 1e-5f, r_normal);
1278}
1279
1280float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
1281{
1282 float v1[3], v2[3];
1283 sub_v3_v3v3(v1, l->prev->v->co, l->v->co);
1284 sub_v3_v3v3(v2, l->next->v->co, l->v->co);
1285
1286 cross_v3_v3v3(r_normal, v1, v2);
1287 const float len = normalize_v3(r_normal);
1288 if (UNLIKELY(len == 0.0f)) {
1289 copy_v3_v3(r_normal, l->f->no);
1290 }
1291 return len;
1292}
1293
1294void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
1295{
1296 float v_prev[3];
1297 float v_next[3];
1298
1299 sub_v3_v3v3(v_prev, l->v->co, l->prev->v->co);
1300 sub_v3_v3v3(v_next, l->next->v->co, l->v->co);
1301
1302 normalize_v3(v_prev);
1303 normalize_v3(v_next);
1304
1305 add_v3_v3v3(r_dir, v_prev, v_next);
1306 normalize_v3(r_dir);
1307}
1308
1309void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
1310{
1311 float v_prev[3];
1312 float v_next[3];
1313 float dir[3];
1314
1315 sub_v3_v3v3(v_prev, l->prev->v->co, l->v->co);
1316 sub_v3_v3v3(v_next, l->v->co, l->next->v->co);
1317
1318 normalize_v3(v_prev);
1319 normalize_v3(v_next);
1320 add_v3_v3v3(dir, v_prev, v_next);
1321
1322 if (compare_v3v3(v_prev, v_next, FLT_EPSILON * 10.0f) == false) {
1323 float nor[3]; /* for this purpose doesn't need to be normalized */
1324 cross_v3_v3v3(nor, v_prev, v_next);
1325 /* concave face check */
1326 if (UNLIKELY(dot_v3v3(nor, l->f->no) < 0.0f)) {
1327 negate_v3(nor);
1328 }
1329 cross_v3_v3v3(r_tangent, dir, nor);
1330 }
1331 else {
1332 /* prev/next are the same - compare with face normal since we don't have one */
1333 cross_v3_v3v3(r_tangent, dir, l->f->no);
1334 }
1335
1336 normalize_v3(r_tangent);
1337}
1338
1339float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
1340{
1341 if (BM_edge_is_manifold(e)) {
1342 const BMLoop *l1 = e->l;
1343 const BMLoop *l2 = e->l->radial_next;
1344 return angle_normalized_v3v3(l1->f->no, l2->f->no);
1345 }
1346 return fallback;
1347}
1349{
1350 return BM_edge_calc_face_angle_ex(e, DEG2RADF(90.0f));
1351}
1352
1354 const float imat3[3][3],
1355 const float fallback)
1356{
1357 if (BM_edge_is_manifold(e)) {
1358 const BMLoop *l1 = e->l;
1359 const BMLoop *l2 = e->l->radial_next;
1360 float no1[3], no2[3];
1361 copy_v3_v3(no1, l1->f->no);
1362 copy_v3_v3(no2, l2->f->no);
1363
1364 mul_transposed_m3_v3(imat3, no1);
1365 mul_transposed_m3_v3(imat3, no2);
1366
1367 normalize_v3(no1);
1368 normalize_v3(no2);
1369
1370 return angle_normalized_v3v3(no1, no2);
1371 }
1372 return fallback;
1373}
1374float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, const float imat3[3][3])
1375{
1376 return BM_edge_calc_face_angle_with_imat3_ex(e, imat3, DEG2RADF(90.0f));
1377}
1378
1379float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback)
1380{
1381 if (BM_edge_is_manifold(e)) {
1382 BMLoop *l1 = e->l;
1383 BMLoop *l2 = e->l->radial_next;
1384 const float angle = angle_normalized_v3v3(l1->f->no, l2->f->no);
1385 return BM_edge_is_convex(e) ? angle : -angle;
1386 }
1387 return fallback;
1388}
1393
1394void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
1395{
1396 float tvec[3];
1397 BMVert *v1, *v2;
1398 BM_edge_ordered_verts_ex(e, &v1, &v2, e_loop);
1399
1400 sub_v3_v3v3(tvec, v1->co, v2->co); /* use for temp storage */
1401 /* NOTE: we could average the tangents of both loops,
1402 * for non flat ngons it will give a better direction */
1403 cross_v3_v3v3(r_tangent, tvec, e_loop->f->no);
1404 normalize_v3(r_tangent);
1405}
1406
1407float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback)
1408{
1409 BMEdge *e1, *e2;
1410
1411 /* Saves `BM_vert_edge_count(v)` and edge iterator,
1412 * get the edges and count them both at once. */
1413
1414 if ((e1 = v->e) && (e2 = bmesh_disk_edge_next(e1, v)) && (e1 != e2) &&
1415 /* make sure we come full circle and only have 2 connected edges */
1416 (e1 == bmesh_disk_edge_next(e2, v)))
1417 {
1418 BMVert *v1 = BM_edge_other_vert(e1, v);
1419 BMVert *v2 = BM_edge_other_vert(e2, v);
1420
1421 return float(M_PI) - angle_v3v3v3(v1->co, v->co, v2->co);
1422 }
1423 return fallback;
1424}
1425
1427{
1428 return BM_vert_calc_edge_angle_ex(v, DEG2RADF(90.0f));
1429}
1430
1432{
1433 BMIter iter;
1434 BMLoop *l;
1435 float accum_shell = 0.0f;
1436 float accum_angle = 0.0f;
1437
1438 BM_ITER_ELEM (l, &iter, (BMVert *)v, BM_LOOPS_OF_VERT) {
1439 const float face_angle = BM_loop_calc_face_angle(l);
1440 accum_shell += shell_v3v3_normalized_to_dist(v->no, l->f->no) * face_angle;
1441 accum_angle += face_angle;
1442 }
1443
1444 if (accum_angle != 0.0f) {
1445 return accum_shell / accum_angle;
1446 }
1447 return 1.0f;
1448}
1449float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag)
1450{
1451 BMIter iter;
1452 const BMLoop *l;
1453 float accum_shell = 0.0f;
1454 float accum_angle = 0.0f;
1455 int tot_sel = 0, tot = 0;
1456
1457 BM_ITER_ELEM (l, &iter, (BMVert *)v, BM_LOOPS_OF_VERT) {
1458 if (BM_elem_flag_test(l->f, hflag)) { /* <-- main difference to BM_vert_calc_shell_factor! */
1459 const float face_angle = BM_loop_calc_face_angle(l);
1460 accum_shell += shell_v3v3_normalized_to_dist(no, l->f->no) * face_angle;
1461 accum_angle += face_angle;
1462 tot_sel++;
1463 }
1464 tot++;
1465 }
1466
1467 if (accum_angle != 0.0f) {
1468 return accum_shell / accum_angle;
1469 }
1470 /* other main difference from BM_vert_calc_shell_factor! */
1471 if (tot != 0 && tot_sel == 0) {
1472 /* none selected, so use all */
1474 }
1475 return 1.0f;
1476}
1477
1479{
1480 BMIter iter;
1481 BMEdge *e;
1482 int tot;
1483 float length = 0.0f;
1484
1485 BM_ITER_ELEM_INDEX (e, &iter, (BMVert *)v, BM_EDGES_OF_VERT, tot) {
1486 const BMVert *v_other = BM_edge_other_vert(e, v);
1487 if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
1489 }
1490 }
1491
1492 if (tot) {
1493 return length / float(tot);
1494 }
1495 return 0.0f;
1496}
1497
1499{
1500 float shortest_len = FLT_MAX;
1501
1502 BMLoop *l_iter;
1503 BMLoop *l_first;
1504
1505 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1506 BMLoop *shortest_loop = l_first; /* Fallback for non-finite coordinates, see #108658. */
1507
1508 do {
1509 const float len_sq = len_squared_v3v3(l_iter->v->co, l_iter->next->v->co);
1510 if (len_sq <= shortest_len) {
1511 shortest_loop = l_iter;
1512 shortest_len = len_sq;
1513 }
1514 } while ((l_iter = l_iter->next) != l_first);
1515
1516 return shortest_loop;
1517}
1518
1520{
1521 float len_max_sq = 0.0f;
1522
1523 BMLoop *l_iter;
1524 BMLoop *l_first;
1525
1526 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1527 BMLoop *longest_loop = l_first; /* Fallback for non-finite coordinates, see #108658. */
1528
1529 do {
1530 const float len_sq = len_squared_v3v3(l_iter->v->co, l_iter->next->v->co);
1531 if (len_sq >= len_max_sq) {
1532 longest_loop = l_iter;
1533 len_max_sq = len_sq;
1534 }
1535 } while ((l_iter = l_iter->next) != l_first);
1536
1537 return longest_loop;
1538}
1539
1546#if 0
1548{
1549 BMIter iter;
1550 BMEdge *e;
1551
1552 BLI_assert(v_a != v_b);
1553 BLI_assert(v_a->head.htype == BM_VERT && v_b->head.htype == BM_VERT);
1554
1555 BM_ITER_ELEM (e, &iter, v_a, BM_EDGES_OF_VERT) {
1556 if (e->v1 == v_b || e->v2 == v_b) {
1557 return e;
1558 }
1559 }
1560
1561 return nullptr;
1562}
1563#else
1565{
1566 /* speedup by looping over both edges verts
1567 * where one vert may connect to many edges but not the other. */
1568
1569 BMEdge *e_a, *e_b;
1570
1571 BLI_assert(v_a != v_b);
1572 BLI_assert(v_a->head.htype == BM_VERT && v_b->head.htype == BM_VERT);
1573
1574 if ((e_a = v_a->e) && (e_b = v_b->e)) {
1575 BMEdge *e_a_iter = e_a, *e_b_iter = e_b;
1576
1577 do {
1578 if (BM_vert_in_edge(e_a_iter, v_b)) {
1579 return e_a_iter;
1580 }
1581 if (BM_vert_in_edge(e_b_iter, v_a)) {
1582 return e_b_iter;
1583 }
1584 } while (((e_a_iter = bmesh_disk_edge_next(e_a_iter, v_a)) != e_a) &&
1585 ((e_b_iter = bmesh_disk_edge_next(e_b_iter, v_b)) != e_b));
1586 }
1587
1588 return nullptr;
1589}
1590#endif
1591
1593{
1594 BMVert *v = e->v1;
1595 BMVert *v_other = e->v2;
1596
1597 BMEdge *e_iter;
1598
1599 e_iter = e;
1600 while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e) {
1601 if (UNLIKELY(BM_vert_in_edge(e_iter, v_other))) {
1602 return e_iter;
1603 }
1604 }
1605
1606 return nullptr;
1607}
1608
1610{
1611 if (e->l != nullptr) {
1612 BMLoop *l_iter, *l_first;
1613 l_iter = l_first = e->l;
1614 do {
1615 if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
1616 return l_iter;
1617 }
1618 } while ((l_iter = l_iter->radial_next) != l_first);
1619 }
1620 return nullptr;
1621}
1622
1623BMFace *BM_face_exists(BMVert *const *varr, int len)
1624{
1625 if (varr[0]->e) {
1626 BMEdge *e_iter, *e_first;
1627 e_iter = e_first = varr[0]->e;
1628
1629 /* would normally use BM_LOOPS_OF_VERT, but this runs so often,
1630 * its faster to iterate on the data directly */
1631 do {
1632 if (e_iter->l) {
1633 BMLoop *l_iter_radial, *l_first_radial;
1634 l_iter_radial = l_first_radial = e_iter->l;
1635
1636 do {
1637 if ((l_iter_radial->v == varr[0]) && (l_iter_radial->f->len == len)) {
1638 /* the fist 2 verts match, now check the remaining (len - 2) faces do too
1639 * winding isn't known, so check in both directions */
1640 int i_walk = 2;
1641
1642 if (l_iter_radial->next->v == varr[1]) {
1643 BMLoop *l_walk = l_iter_radial->next->next;
1644 do {
1645 if (l_walk->v != varr[i_walk]) {
1646 break;
1647 }
1648 } while ((void)(l_walk = l_walk->next), ++i_walk != len);
1649 }
1650 else if (l_iter_radial->prev->v == varr[1]) {
1651 BMLoop *l_walk = l_iter_radial->prev->prev;
1652 do {
1653 if (l_walk->v != varr[i_walk]) {
1654 break;
1655 }
1656 } while ((void)(l_walk = l_walk->prev), ++i_walk != len);
1657 }
1658
1659 if (i_walk == len) {
1660 return l_iter_radial->f;
1661 }
1662 }
1663 } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
1664 }
1665 } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, varr[0])) != e_first);
1666 }
1667
1668 return nullptr;
1669}
1670
1672{
1673 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1674 for (BMLoop *l_iter = l_first->radial_next; l_first != l_iter; l_iter = l_iter->radial_next) {
1675 if (l_iter->f->len == l_first->f->len) {
1676 if (l_iter->v == l_first->v) {
1677 BMLoop *l_a = l_first, *l_b = l_iter, *l_b_init = l_iter;
1678 do {
1679 if (l_a->e != l_b->e) {
1680 break;
1681 }
1682 } while (((void)(l_a = l_a->next), (l_b = l_b->next)) != l_b_init);
1683 if (l_b == l_b_init) {
1684 return l_iter->f;
1685 }
1686 }
1687 else {
1688 BMLoop *l_a = l_first, *l_b = l_iter, *l_b_init = l_iter;
1689 do {
1690 if (l_a->e != l_b->e) {
1691 break;
1692 }
1693 } while (((void)(l_a = l_a->prev), (l_b = l_b->next)) != l_b_init);
1694 if (l_b == l_b_init) {
1695 return l_iter->f;
1696 }
1697 }
1698 }
1699 }
1700 return nullptr;
1701}
1702
1703bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len)
1704{
1705 BMFace *f;
1706 BMEdge *e;
1707 BMVert *v;
1708 bool ok;
1709 int tot_tag;
1710
1711 BMIter fiter;
1712 BMIter viter;
1713
1714 int i;
1715
1716 for (i = 0; i < len; i++) {
1717 /* save some time by looping over edge faces rather than vert faces
1718 * will still loop over some faces twice but not as many */
1719 BM_ITER_ELEM (f, &fiter, earr[i], BM_FACES_OF_EDGE) {
1721 BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) {
1723 }
1724 }
1725
1726 /* clear all edge tags */
1727 BM_ITER_ELEM (e, &fiter, varr[i], BM_EDGES_OF_VERT) {
1729 }
1730 }
1731
1732 /* now tag all verts and edges in the boundary array as true so
1733 * we can know if a face-vert is from our array */
1734 for (i = 0; i < len; i++) {
1737 }
1738
1739 /* so! boundary is tagged, everything else cleared */
1740
1741 /* 1) tag all faces connected to edges - if all their verts are boundary */
1742 tot_tag = 0;
1743 for (i = 0; i < len; i++) {
1744 BM_ITER_ELEM (f, &fiter, earr[i], BM_FACES_OF_EDGE) {
1746 ok = true;
1747 BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) {
1749 ok = false;
1750 break;
1751 }
1752 }
1753
1754 if (ok) {
1755 /* we only use boundary verts */
1757 tot_tag++;
1758 }
1759 }
1760 else {
1761 /* we already found! */
1762 }
1763 }
1764 }
1765
1766 if (tot_tag == 0) {
1767 /* no faces use only boundary verts, quit early */
1768 ok = false;
1769 goto finally;
1770 }
1771
1772 /* 2) loop over non-boundary edges that use boundary verts,
1773 * check each have 2 tagged faces connected (faces that only use 'varr' verts) */
1774 ok = true;
1775 for (i = 0; i < len; i++) {
1776 BM_ITER_ELEM (e, &fiter, varr[i], BM_EDGES_OF_VERT) {
1777
1778 if (/* non-boundary edge */
1780 /* ...using boundary verts */
1783 {
1784 int tot_face_tag = 0;
1785 BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
1787 tot_face_tag++;
1788 }
1789 }
1790
1791 if (tot_face_tag != 2) {
1792 ok = false;
1793 break;
1794 }
1795 }
1796 }
1797
1798 if (ok == false) {
1799 break;
1800 }
1801 }
1802
1803finally:
1804 /* Cleanup */
1805 for (i = 0; i < len; i++) {
1808 }
1809 return ok;
1810}
1811
1813{
1814 BMVert **varr = BLI_array_alloca(varr, len);
1815
1816 /* first check if verts have edges, if not we can bail out early */
1817 if (!BM_verts_from_edges(varr, earr, len)) {
1818 BMESH_ASSERT(0);
1819 return false;
1820 }
1821
1822 return BM_face_exists_multi(varr, earr, len);
1823}
1824
1826{
1827 BMIter viter;
1828 BMFace *f;
1829 int i;
1830 BMFace *f_overlap = nullptr;
1831 LinkNode *f_lnk = nullptr;
1832
1833#ifndef NDEBUG
1834 /* check flag isn't already set */
1835 for (i = 0; i < len; i++) {
1836 BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
1838 }
1839 }
1840#endif
1841
1842 for (i = 0; i < len; i++) {
1843 BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
1844 if (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0) {
1845 if (len <= BM_verts_in_face_count(varr, len, f)) {
1846 f_overlap = f;
1847 break;
1848 }
1849
1851 BLI_linklist_prepend_alloca(&f_lnk, f);
1852 }
1853 }
1854 }
1855
1856 for (; f_lnk; f_lnk = f_lnk->next) {
1858 }
1859
1860 return f_overlap;
1861}
1862
1864{
1865 BMIter viter;
1866 BMFace *f;
1867 bool is_init = false;
1868 bool is_overlap = false;
1869 LinkNode *f_lnk = nullptr;
1870
1871#ifndef NDEBUG
1872 /* check flag isn't already set */
1873 for (int i = 0; i < len; i++) {
1875 BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
1877 }
1878 }
1879#endif
1880
1881 for (int i = 0; i < len; i++) {
1882 BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
1883 if ((f->len <= len) && (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0)) {
1884 /* Check if all verts in this face are flagged. */
1885 BMLoop *l_iter, *l_first;
1886
1887 if (is_init == false) {
1888 is_init = true;
1889 for (int j = 0; j < len; j++) {
1891 }
1892 }
1893
1894 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1895 is_overlap = true;
1896 do {
1897 if (BM_ELEM_API_FLAG_TEST(l_iter->v, _FLAG_OVERLAP) == 0) {
1898 is_overlap = false;
1899 break;
1900 }
1901 } while ((l_iter = l_iter->next) != l_first);
1902
1903 if (is_overlap) {
1904 break;
1905 }
1906
1908 BLI_linklist_prepend_alloca(&f_lnk, f);
1909 }
1910 }
1911 }
1912
1913 if (is_init == true) {
1914 for (int i = 0; i < len; i++) {
1916 }
1917 }
1918
1919 for (; f_lnk; f_lnk = f_lnk->next) {
1921 }
1922
1923 return is_overlap;
1924}
1925
1926bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide)
1927{
1928 if (v->e) {
1929 BMEdge *e_other;
1930 BMIter eiter;
1931
1932 BM_ITER_ELEM (e_other, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) {
1933 if (!respect_hide || !BM_elem_flag_test(e_other, BM_ELEM_HIDDEN)) {
1934 if (!BM_elem_flag_test(e_other, hflag)) {
1935 return false;
1936 }
1937 }
1938 }
1939 }
1940
1941 return true;
1942}
1943
1944bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide)
1945{
1946 if (v->e) {
1947 BMEdge *f_other;
1948 BMIter fiter;
1949
1950 BM_ITER_ELEM (f_other, &fiter, (BMVert *)v, BM_FACES_OF_VERT) {
1951 if (!respect_hide || !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) {
1952 if (!BM_elem_flag_test(f_other, hflag)) {
1953 return false;
1954 }
1955 }
1956 }
1957 }
1958
1959 return true;
1960}
1961
1962bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide)
1963{
1964 if (e->l) {
1965 BMLoop *l_iter, *l_first;
1966
1967 l_iter = l_first = e->l;
1968 do {
1969 if (!respect_hide || !BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
1970 if (!BM_elem_flag_test(l_iter->f, hflag)) {
1971 return false;
1972 }
1973 }
1974 } while ((l_iter = l_iter->radial_next) != l_first);
1975 }
1976
1977 return true;
1978}
1979
1980bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag)
1981{
1982 if (e->l) {
1983 BMLoop *l_iter, *l_first;
1984
1985 l_iter = l_first = e->l;
1986 do {
1987 if (BM_elem_flag_test(l_iter->f, hflag)) {
1988 return true;
1989 }
1990 } while ((l_iter = l_iter->radial_next) != l_first);
1991 }
1992
1993 return false;
1994}
1995
1996bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag)
1997{
1998 return (BM_elem_flag_test(e->v1, hflag) || BM_elem_flag_test(e->v2, hflag));
1999}
2000
2001bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag)
2002{
2003 BMLoop *l_iter;
2004 BMLoop *l_first;
2005
2006 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2007 do {
2008 if (BM_elem_flag_test(l_iter->v, hflag)) {
2009 return true;
2010 }
2011 } while ((l_iter = l_iter->next) != l_first);
2012 return false;
2013}
2014
2015bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag)
2016{
2017 BMLoop *l_iter;
2018 BMLoop *l_first;
2019
2020 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2021 do {
2022 if (BM_elem_flag_test(l_iter->e, hflag)) {
2023 return true;
2024 }
2025 } while ((l_iter = l_iter->next) != l_first);
2026 return false;
2027}
2028
2030{
2031 if (e->l) {
2032 BMLoop *l_iter, *l_first;
2033
2034 l_iter = l_first = e->l;
2035 do {
2036 if (l_iter->f->len == len) {
2037 return true;
2038 }
2039 } while ((l_iter = l_iter->radial_next) != l_first);
2040 }
2041
2042 return false;
2043}
2044
2046{
2047 const float eps = 0.0001f;
2048 float no[3];
2049
2050 BM_face_calc_normal(f, no);
2051 return len_squared_v3v3(no, f->no) < (eps * eps);
2052}
2053
2059static double bm_mesh_calc_volume_face(const BMFace *f)
2060{
2061 const int tottri = f->len - 2;
2062 BMLoop **loops = BLI_array_alloca(loops, f->len);
2063 uint(*index)[3] = BLI_array_alloca(index, tottri);
2064 double vol = 0.0;
2065
2066 BM_face_calc_tessellation(f, false, loops, index);
2067
2068 for (int j = 0; j < tottri; j++) {
2069 const float *p1 = loops[index[j][0]]->v->co;
2070 const float *p2 = loops[index[j][1]]->v->co;
2071 const float *p3 = loops[index[j][2]]->v->co;
2072
2073 double p1_db[3];
2074 double p2_db[3];
2075 double p3_db[3];
2076
2077 copy_v3db_v3fl(p1_db, p1);
2078 copy_v3db_v3fl(p2_db, p2);
2079 copy_v3db_v3fl(p3_db, p3);
2080
2081 /* co1.dot(co2.cross(co3)) / 6.0 */
2082 double cross[3];
2083 cross_v3_v3v3_db(cross, p2_db, p3_db);
2084 vol += dot_v3v3_db(p1_db, cross);
2085 }
2086 return (1.0 / 6.0) * vol;
2087}
2088double BM_mesh_calc_volume(BMesh *bm, bool is_signed)
2089{
2090 /* warning, calls its own tessellation function, may be slow */
2091 double vol = 0.0;
2092 BMFace *f;
2093 BMIter fiter;
2094
2095 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
2096 vol += bm_mesh_calc_volume_face(f);
2097 }
2098
2099 if (is_signed == false) {
2100 vol = fabs(vol);
2101 }
2102
2103 return vol;
2104}
2105
2107 int *r_groups_array,
2108 int (**r_group_index)[2],
2109 BMLoopFilterFunc filter_fn,
2110 BMLoopPairFilterFunc filter_pair_fn,
2111 void *user_data,
2112 const char hflag_test,
2113 const char htype_step)
2114{
2115 /* NOTE: almost duplicate of #BM_mesh_calc_edge_groups, keep in sync. */
2116
2117#ifndef NDEBUG
2118 int group_index_len = 1;
2119#else
2120 int group_index_len = 32;
2121#endif
2122
2123 int (*group_index)[2] = static_cast<int (*)[2]>(
2124 MEM_mallocN(sizeof(*group_index) * group_index_len, __func__));
2125
2126 int *group_array = r_groups_array;
2127 STACK_DECLARE(group_array);
2128
2129 int group_curr = 0;
2130
2131 uint tot_faces = 0;
2132 uint tot_touch = 0;
2133
2134 BMFace **stack;
2135 STACK_DECLARE(stack);
2136
2137 BMIter iter;
2138 BMFace *f, *f_next;
2139 int i;
2140
2141 STACK_INIT(group_array, bm->totface);
2142
2143 BLI_assert(((htype_step & ~(BM_VERT | BM_EDGE)) == 0) && (htype_step != 0));
2144
2145 /* init the array */
2146 BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
2147 if ((hflag_test == 0) || BM_elem_flag_test(f, hflag_test)) {
2148 tot_faces++;
2150 }
2151 else {
2152 /* never walk over tagged */
2154 }
2155
2156 BM_elem_index_set(f, i); /* set_inline */
2157 }
2158 bm->elem_index_dirty &= ~BM_FACE;
2159
2160 /* detect groups */
2161 stack = MEM_malloc_arrayN<BMFace *>(tot_faces, __func__);
2162
2163 f_next = static_cast<BMFace *>(BM_iter_new(&iter, bm, BM_FACES_OF_MESH, nullptr));
2164
2165 while (tot_touch != tot_faces) {
2166 int *group_item;
2167 bool ok = false;
2168
2169 BLI_assert(tot_touch < tot_faces);
2170
2171 STACK_INIT(stack, tot_faces);
2172
2173 for (; f_next; f_next = static_cast<BMFace *>(BM_iter_step(&iter))) {
2174 if (BM_elem_flag_test(f_next, BM_ELEM_TAG) == false) {
2176 STACK_PUSH(stack, f_next);
2177 ok = true;
2178 break;
2179 }
2180 }
2181
2182 BLI_assert(ok == true);
2184
2185 /* manage arrays */
2186 if (group_index_len == group_curr) {
2187 group_index_len *= 2;
2188 group_index = static_cast<int (*)[2]>(
2189 MEM_reallocN(group_index, sizeof(*group_index) * group_index_len));
2190 }
2191
2192 group_item = group_index[group_curr];
2193 group_item[0] = STACK_SIZE(group_array);
2194 group_item[1] = 0;
2195
2196 while ((f = STACK_POP(stack))) {
2197 BMLoop *l_iter, *l_first;
2198
2199 /* add face */
2200 STACK_PUSH(group_array, BM_elem_index_get(f));
2201 tot_touch++;
2202 group_item[1]++;
2203 /* done */
2204
2205 if (htype_step & BM_EDGE) {
2206 /* search for other faces */
2207 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2208 do {
2209 BMLoop *l_radial_iter = l_iter->radial_next;
2210 if ((l_radial_iter != l_iter) &&
2211 ((filter_fn == nullptr) || filter_fn(l_iter, user_data)))
2212 {
2213 do {
2214 if ((filter_pair_fn == nullptr) || filter_pair_fn(l_iter, l_radial_iter, user_data))
2215 {
2216 BMFace *f_other = l_radial_iter->f;
2217 if (BM_elem_flag_test(f_other, BM_ELEM_TAG) == false) {
2219 STACK_PUSH(stack, f_other);
2220 }
2221 }
2222 } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
2223 }
2224 } while ((l_iter = l_iter->next) != l_first);
2225 }
2226
2227 if (htype_step & BM_VERT) {
2228 BMIter liter;
2229 /* search for other faces */
2230 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2231 do {
2232 if ((filter_fn == nullptr) || filter_fn(l_iter, user_data)) {
2233 BMLoop *l_other;
2234 BM_ITER_ELEM (l_other, &liter, l_iter, BM_LOOPS_OF_LOOP) {
2235 if ((filter_pair_fn == nullptr) || filter_pair_fn(l_iter, l_other, user_data)) {
2236 BMFace *f_other = l_other->f;
2237 if (BM_elem_flag_test(f_other, BM_ELEM_TAG) == false) {
2239 STACK_PUSH(stack, f_other);
2240 }
2241 }
2242 }
2243 }
2244 } while ((l_iter = l_iter->next) != l_first);
2245 }
2246 }
2247
2248 group_curr++;
2249 }
2250
2251 MEM_freeN(stack);
2252
2253 /* reduce alloc to required size */
2254 if (group_index_len != group_curr) {
2255 group_index = static_cast<int (*)[2]>(
2256 MEM_reallocN(group_index, sizeof(*group_index) * group_curr));
2257 }
2258 *r_group_index = group_index;
2259
2260 return group_curr;
2261}
2262
2264 int *r_groups_array,
2265 int (**r_group_index)[2],
2266 BMVertFilterFunc filter_fn,
2267 void *user_data,
2268 const char hflag_test)
2269{
2270 /* NOTE: almost duplicate of #BM_mesh_calc_face_groups, keep in sync. */
2271
2272#ifndef NDEBUG
2273 int group_index_len = 1;
2274#else
2275 int group_index_len = 32;
2276#endif
2277
2278 int (*group_index)[2] = static_cast<int (*)[2]>(
2279 MEM_mallocN(sizeof(*group_index) * group_index_len, __func__));
2280
2281 int *group_array = r_groups_array;
2282 STACK_DECLARE(group_array);
2283
2284 int group_curr = 0;
2285
2286 uint tot_edges = 0;
2287 uint tot_touch = 0;
2288
2289 BMEdge **stack;
2290 STACK_DECLARE(stack);
2291
2292 BMIter iter;
2293 BMEdge *e, *e_next;
2294 int i;
2295 STACK_INIT(group_array, bm->totedge);
2296
2297 /* init the array */
2299 if ((hflag_test == 0) || BM_elem_flag_test(e, hflag_test)) {
2300 tot_edges++;
2302 }
2303 else {
2304 /* never walk over tagged */
2306 }
2307
2308 BM_elem_index_set(e, i); /* set_inline */
2309 }
2310 bm->elem_index_dirty &= ~BM_EDGE;
2311
2312 /* detect groups */
2313 stack = MEM_malloc_arrayN<BMEdge *>(tot_edges, __func__);
2314
2315 e_next = static_cast<BMEdge *>(BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, nullptr));
2316
2317 while (tot_touch != tot_edges) {
2318 int *group_item;
2319 bool ok = false;
2320
2321 BLI_assert(tot_touch < tot_edges);
2322
2323 STACK_INIT(stack, tot_edges);
2324
2325 for (; e_next; e_next = static_cast<BMEdge *>(BM_iter_step(&iter))) {
2326 if (BM_elem_flag_test(e_next, BM_ELEM_TAG) == false) {
2328 STACK_PUSH(stack, e_next);
2329 ok = true;
2330 break;
2331 }
2332 }
2333
2334 BLI_assert(ok == true);
2336
2337 /* manage arrays */
2338 if (group_index_len == group_curr) {
2339 group_index_len *= 2;
2340 group_index = static_cast<int (*)[2]>(
2341 MEM_reallocN(group_index, sizeof(*group_index) * group_index_len));
2342 }
2343
2344 group_item = group_index[group_curr];
2345 group_item[0] = STACK_SIZE(group_array);
2346 group_item[1] = 0;
2347
2348 while ((e = STACK_POP(stack))) {
2349 BMIter viter;
2350 BMIter eiter;
2351 BMVert *v;
2352
2353 /* add edge */
2354 STACK_PUSH(group_array, BM_elem_index_get(e));
2355 tot_touch++;
2356 group_item[1]++;
2357 /* done */
2358
2359 /* search for other edges */
2360 BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
2361 if ((filter_fn == nullptr) || filter_fn(v, user_data)) {
2362 BMEdge *e_other;
2363 BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) {
2364 if (BM_elem_flag_test(e_other, BM_ELEM_TAG) == false) {
2366 STACK_PUSH(stack, e_other);
2367 }
2368 }
2369 }
2370 }
2371 }
2372
2373 group_curr++;
2374 }
2375
2376 MEM_freeN(stack);
2377
2378 /* reduce alloc to required size */
2379 if (group_index_len != group_curr) {
2380 group_index = static_cast<int (*)[2]>(
2381 MEM_reallocN(group_index, sizeof(*group_index) * group_curr));
2382 }
2383 *r_group_index = group_index;
2384
2385 return group_curr;
2386}
2387
2389 BMesh *bm, BMVert **verts, BMEdge **edges, BMFace **faces, int (**r_groups)[3])
2390{
2391 int (*groups)[3] = MEM_malloc_arrayN<int[3]>(bm->totvert, __func__);
2392 STACK_DECLARE(groups);
2393 STACK_INIT(groups, bm->totvert);
2394
2395 /* Clear all selected vertices */
2397
2398 BMVert **stack = MEM_malloc_arrayN<BMVert *>(bm->totvert, __func__);
2399 STACK_DECLARE(stack);
2400 STACK_INIT(stack, bm->totvert);
2401
2403 STACK_INIT(verts, bm->totvert);
2404
2405 STACK_DECLARE(edges);
2406 STACK_INIT(edges, bm->totedge);
2407
2409 STACK_INIT(faces, bm->totface);
2410
2411 BMIter iter;
2412 BMVert *v_stack_init;
2413 BM_ITER_MESH (v_stack_init, &iter, bm, BM_VERTS_OF_MESH) {
2414 if (BM_elem_flag_test(v_stack_init, BM_ELEM_TAG)) {
2415 continue;
2416 }
2417
2418 const uint verts_init = STACK_SIZE(verts);
2419 const uint edges_init = STACK_SIZE(edges);
2420 const uint faces_init = STACK_SIZE(faces);
2421
2422 /* Initialize stack. */
2423 BM_elem_flag_enable(v_stack_init, BM_ELEM_TAG);
2424 STACK_PUSH(verts, v_stack_init);
2425
2426 if (v_stack_init->e != nullptr) {
2427 BMVert *v_iter = v_stack_init;
2428 do {
2429 BMEdge *e_iter, *e_first;
2430 e_iter = e_first = v_iter->e;
2431 do {
2432 if (!BM_elem_flag_test(e_iter, BM_ELEM_TAG)) {
2434 STACK_PUSH(edges, e_iter);
2435
2436 if (e_iter->l != nullptr) {
2437 BMLoop *l_iter, *l_first;
2438 l_iter = l_first = e_iter->l;
2439 do {
2440 if (!BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
2442 STACK_PUSH(faces, l_iter->f);
2443 }
2444 } while ((l_iter = l_iter->radial_next) != l_first);
2445 }
2446
2447 BMVert *v_other = BM_edge_other_vert(e_iter, v_iter);
2448 if (!BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
2450 STACK_PUSH(verts, v_other);
2451
2452 STACK_PUSH(stack, v_other);
2453 }
2454 }
2455 } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_iter)) != e_first);
2456 } while ((v_iter = STACK_POP(stack)));
2457 }
2458
2459 int *g = STACK_PUSH_RET(groups);
2460 g[0] = STACK_SIZE(verts) - verts_init;
2461 g[1] = STACK_SIZE(edges) - edges_init;
2462 g[2] = STACK_SIZE(faces) - faces_init;
2463 }
2464
2465 MEM_freeN(stack);
2466
2467 /* Reduce alloc to required size. */
2468 groups = static_cast<int (*)[3]>(MEM_reallocN(groups, sizeof(*groups) * STACK_SIZE(groups)));
2469 *r_groups = groups;
2470 return STACK_SIZE(groups);
2471}
2472
2473float bmesh_subd_falloff_calc(const int falloff, float val)
2474{
2475 switch (falloff) {
2477 val = 3.0f * val * val - 2.0f * val * val * val;
2478 break;
2480 val = sqrtf(2.0f * val - val * val);
2481 break;
2482 case SUBD_FALLOFF_ROOT:
2483 val = sqrtf(val);
2484 break;
2485 case SUBD_FALLOFF_SHARP:
2486 val = val * val;
2487 break;
2488 case SUBD_FALLOFF_LIN:
2489 break;
2491 val = val * (2.0f - val);
2492 break;
2493 default:
2494 BLI_assert(0);
2495 break;
2496 }
2497
2498 return val;
2499}
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_data_equals(eCustomDataType type, const void *data1, const void *data2)
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:18
#define BLI_assert(a)
Definition BLI_assert.h:46
#define DEG2RADF(_deg)
#define M_PI
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
float dist_signed_squared_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:463
float dist_signed_squared_to_corner_v3v3v3(const float p[3], const float v1[3], const float v2[3], const float v3[3], const float axis_ref[3])
Definition math_geom.cc:546
void mul_transposed_m3_v3(const float M[3][3], float r[3])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE double dot_v3v3_db(const double a[3], const double b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE void copy_v3db_v3fl(double r[3], const float a[3])
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3])
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float n[3])
unsigned int uint
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define STACK_POP(stack)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
#define STACK_PUSH_RET(stack)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
#define BM_DISK_EDGE_NEXT(e, v)
bool(*)(const BMLoop *, void *user_data) BMLoopFilterFunc
#define BM_FACE_FIRST_LOOP(p)
@ BM_ELEM_HIDDEN
@ BM_ELEM_INTERNAL_TAG
@ BM_ELEM_TAG
bool(*)(const BMVert *, void *user_data) BMVertFilterFunc
bool(*)(const BMLoop *, const BMLoop *, void *user_data) BMLoopPairFilterFunc
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
#define LOOP_VISIT
#define EDGE_VISIT
#define BMESH_ASSERT(a)
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_LOOPS_OF_LOOP
@ BM_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_EDGE
@ BM_VERTS_OF_FACE
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
@ BM_EDGES_OF_FACE
#define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar)
#define BM_iter_new(iter, bm, itype, data)
BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
@ SUBD_FALLOFF_SHARP
@ SUBD_FALLOFF_SMOOTH
@ SUBD_FALLOFF_INVSQUARE
@ SUBD_FALLOFF_SPHERE
@ SUBD_FALLOFF_LIN
@ SUBD_FALLOFF_ROOT
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
float BM_face_calc_normal(const BMFace *f, float r_no[3])
BMESH UPDATE FACE NORMAL.
void BM_face_calc_tessellation(const BMFace *f, const bool use_fixed_quad, BMLoop **r_loops, uint(*r_index)[3])
#define BM_ELEM_API_FLAG_DISABLE(element, f)
#define BM_ELEM_API_FLAG_TEST(element, f)
int bmesh_disk_count_at_most(const BMVert *v, int count_max)
#define BM_ELEM_API_FLAG_ENABLE(element, f)
@ _FLAG_OVERLAP
int bmesh_disk_count(const BMVert *v)
BMLoop * BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b)
float BM_vert_calc_edge_angle(const BMVert *v)
BMVert * BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm, BMVert **verts, BMEdge **edges, BMFace **faces, int(**r_groups)[3])
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
int BM_edge_face_count_at_most(const BMEdge *e, const int count_max)
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3])
void BM_edge_ordered_verts_ex(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2, const BMLoop *edge_loop)
bool BM_vert_is_wire(const BMVert *v)
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e, const int cd_loop_type, const int cd_loop_offset)
bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide)
BMLoop * BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v)
Other Loop in Face Sharing an Edge.
BMFace * BM_edge_pair_share_face_by_len(BMEdge *e_a, BMEdge *e_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
int BM_vert_edge_count_at_most(const BMVert *v, const int count_max)
float BM_edge_calc_face_angle(const BMEdge *e)
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len)
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b)
int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int(**r_group_index)[2], BMLoopFilterFunc filter_fn, BMLoopPairFilterFunc filter_pair_fn, void *user_data, const char hflag_test, const char htype_step)
float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag)
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag)
float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l, const float normal_fallback[3], float const (*vertexCos)[3], float r_normal[3])
bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len)
bool BM_face_exists_multi_edge(BMEdge **earr, int len)
bool BM_face_share_edge_check(BMFace *f_a, BMFace *f_b)
bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b)
bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag)
BMLoop * BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
float BM_vert_calc_median_tagged_edge_length(const BMVert *v)
BMLoop * BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
static int bm_loop_region_count__recursive(BMEdge *e, BMVert *v)
bool BM_vert_is_manifold_region(const BMVert *v)
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
BM_loop_calc_face_tangent.
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide)
BMFace * BM_face_exists(BMVert *const *varr, int len)
bool BM_vert_is_manifold(const BMVert *v)
BMLoop * BM_face_find_shortest_loop(BMFace *f)
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l, const float normal_fallback[3], float const (*vertexCos)[3], const float epsilon_sq, float r_normal[3])
int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b)
float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e, const float imat3[3][3], const float fallback)
BMESH EDGE/FACE ANGLE.
float BM_edge_calc_length_squared(const BMEdge *e)
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
float BM_edge_calc_face_angle_signed(const BMEdge *e)
float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
BM_loop_calc_face_normal.
BMEdge * BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
BMLoop * BM_edge_vert_share_loop(BMLoop *l, BMVert *v)
Return the Loop Shared by Edge and Vert.
float bmesh_subd_falloff_calc(const int falloff, float val)
BMEdge * BM_edge_find_double(BMEdge *e)
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2)
float BM_vert_calc_shell_factor(const BMVert *v)
bool BM_face_is_normal_valid(const BMFace *f)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
BMFace * BM_vert_pair_shared_face_cb(BMVert *v_a, BMVert *v_b, const bool allow_adjacent, bool(*callback)(BMFace *, BMLoop *, BMLoop *, void *userdata), void *user_data, BMLoop **r_l_a, BMLoop **r_l_b)
BMFace * BM_face_find_double(BMFace *f)
int BM_vert_face_count(const BMVert *v)
BMLoop * BM_vert_find_first_loop(BMVert *v)
int BM_edge_face_count(const BMEdge *e)
BMLoop * BM_edge_find_first_loop_visible(BMEdge *e)
BMLoop * BM_edge_other_loop(BMEdge *e, BMLoop *l)
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback)
BMESH VERT/EDGE ANGLE.
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
BMFace * BM_vert_pair_share_face_by_angle(BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
static float bm_face_calc_split_dot(BMLoop *l_a, BMLoop *l_b)
BMLoop * BM_face_find_longest_loop(BMFace *f)
BMLoop * BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
Other Loop in Face Sharing a Vertex.
void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
BM_loop_calc_face_direction.
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
int BM_loop_region_loops_count(BMLoop *l)
int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int(**r_group_index)[2], BMVertFilterFunc filter_fn, void *user_data, const char hflag_test)
int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total)
bool BM_vert_in_face(BMVert *v, BMFace *f)
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag)
BMFace * BM_vert_pair_share_face_by_len(BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
BMLoop * BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e)
float BM_edge_calc_length(const BMEdge *e)
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
BMESH EDGE/FACE ANGLE.
int BM_vert_edge_count(const BMVert *v)
bool BM_loop_is_convex(const BMLoop *l)
double BM_mesh_calc_volume(BMesh *bm, bool is_signed)
static int bm_loop_region_count__clear(BMLoop *l)
float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, const float imat3[3][3])
float BM_loop_calc_face_angle(const BMLoop *l)
bool BM_vert_face_check(const BMVert *v)
static double bm_mesh_calc_volume_face(const BMFace *f)
bool BM_vert_is_edge_pair(const BMVert *v)
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
int BM_vert_face_count_at_most(const BMVert *v, int count_max)
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback)
BMESH EDGE/FACE ANGLE.
BMLoop * BM_vert_find_first_loop_visible(BMVert *v)
bool BM_vert_is_edge_pair_manifold(const BMVert *v)
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b)
BMFace * BM_face_exists_overlap(BMVert **varr, const int len)
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
BMESH EDGE/FACE TANGENT.
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
BM_loop_calc_face_normal.
bool BM_vert_is_boundary(const BMVert *v)
int BM_vert_edge_count_nonwire(const BMVert *v)
bool BM_edge_is_convex(const BMEdge *e)
bool BM_vert_edge_pair(const BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
BMLoop * BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
Other Loop in Face Sharing a Vert.
bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide)
BMLoop * BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f)
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag)
bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
bool BM_vert_pair_share_face_check_cb(BMVert *v_a, BMVert *v_b, bool(*test_fn)(BMFace *, void *user_data), void *user_data)
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()
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) 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_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 BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
BMLoop * bmesh_disk_faceloop_find_first_visible(const BMEdge *e, const BMVert *v)
BMLoop * bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
int bmesh_disk_facevert_count(const BMVert *v)
DISK COUNT FACE VERT.
int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max)
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
nullptr float
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
static float verts[][3]
uint nor
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
float length(VecOp< float, D >) RET
int count
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 fabs(const float2 a)
static char faces[256]
const btScalar eps
Definition poly34.cpp:11
#define sqrtf
#define FLT_MAX
Definition stdcycles.h:14
BMVert * v1
BMVert * v2
struct BMLoop * l
float no[3]
BMLoop * l_first
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
float co[3]
struct BMEdge * e
BMHeader head
void * link
struct LinkNode * next
i
Definition text_draw.cc:230
uint len