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