Blender V4.3
bmesh_edgeloop.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 by Campbell Barton. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include "MEM_guardedalloc.h"
12
13#include "BLI_listbase.h"
14#include "BLI_math_vector.h"
15#include "BLI_mempool.h"
16#include "BLI_stack.h"
18
19#include "bmesh.hh"
20
21#include "bmesh_edgeloop.hh" /* own include */
22
26 int flag;
27 int len;
28 /* optional values to calc */
29 float co[3], no[3];
30};
31
32#define BM_EDGELOOP_IS_CLOSED (1 << 0)
33
34/* Use a small value since we need normals even for very small loops. */
35#define EDGELOOP_EPS 1e-10f
36
37/* -------------------------------------------------------------------- */
38/* BM_mesh_edgeloops_find & Utility Functions. */
39
40static int bm_vert_other_tag(BMVert *v, BMVert *v_prev, BMEdge **r_e)
41{
42 BMIter iter;
43 BMEdge *e, *e_next = nullptr;
44 uint count = 0;
45
46 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
48 BMVert *v_other = BM_edge_other_vert(e, v);
49 if (v_other != v_prev) {
50 e_next = e;
51 count++;
52 }
53 }
54 }
55
56 *r_e = e_next;
57 return count;
58}
59
63static bool bm_loop_build(BMEdgeLoopStore *el_store, BMVert *v_prev, BMVert *v, int dir)
64{
65 void (*add_fn)(ListBase *, void *) = dir == 1 ? BLI_addhead : BLI_addtail;
66 BMEdge *e_next;
67 BMVert *v_next;
68 BMVert *v_first = v;
69
70 BLI_assert(abs(dir) == 1);
71
73 return true;
74 }
75
76 while (v) {
77 LinkData *node = static_cast<LinkData *>(MEM_callocN(sizeof(*node), __func__));
78 int count;
79 node->data = v;
80 add_fn(&el_store->verts, node);
81 el_store->len++;
83
84 count = bm_vert_other_tag(v, v_prev, &e_next);
85 if (count == 1) {
86 v_next = BM_edge_other_vert(e_next, v);
88 if (UNLIKELY(v_next == v_first)) {
89 el_store->flag |= BM_EDGELOOP_IS_CLOSED;
90 v_next = nullptr;
91 }
92 }
93 else if (count == 0) {
94 /* pass */
95 v_next = nullptr;
96 }
97 else {
98 v_next = nullptr;
99 return false;
100 }
101
102 v_prev = v;
103 v = v_next;
104 }
105
106 return true;
107}
108
110 ListBase *r_eloops,
111 bool (*test_fn)(BMEdge *, void *user_data),
112 void *user_data)
113{
114 BMIter iter;
115 BMEdge *e;
116 BMVert *v;
117 int count = 0;
118
119 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
121 }
122
123 /* first flush edges to tags, and tag verts */
124 BLI_Stack *edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
125 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
127 if (test_fn(e, user_data)) {
131 BLI_stack_push(edge_stack, (void *)&e);
132 }
133 else {
135 }
136 }
137
138 const uint edges_len = BLI_stack_count(edge_stack);
139 BMEdge **edges = static_cast<BMEdge **>(MEM_mallocN(sizeof(*edges) * edges_len, __func__));
140 BLI_stack_pop_n_reverse(edge_stack, edges, BLI_stack_count(edge_stack));
141 BLI_stack_free(edge_stack);
142
143 for (uint i = 0; i < edges_len; i += 1) {
144 e = edges[i];
146 BMEdgeLoopStore *el_store = static_cast<BMEdgeLoopStore *>(
147 MEM_callocN(sizeof(BMEdgeLoopStore), __func__));
148
149 /* add both directions */
150 if (bm_loop_build(el_store, e->v1, e->v2, 1) && bm_loop_build(el_store, e->v2, e->v1, -1) &&
151 el_store->len > 1)
152 {
153 BLI_addtail(r_eloops, el_store);
154 count++;
155 }
156 else {
157 BM_edgeloop_free(el_store);
158 }
159 }
160 }
161
162 for (uint i = 0; i < edges_len; i += 1) {
163 e = edges[i];
167 }
168
169 MEM_freeN(edges);
170 return count;
171}
172
173/* -------------------------------------------------------------------- */
174/* BM_mesh_edgeloops_find_path & Util Functions. */
175
184
185static void vs_add(
186 BLI_mempool *vs_pool, ListBase *lb, BMVert *v, BMEdge *e_prev, const int iter_tot)
187{
188 VertStep *vs_new = static_cast<VertStep *>(BLI_mempool_alloc(vs_pool));
189 vs_new->v = v;
190
191 BM_elem_index_set(v, iter_tot); /* set_dirty */
192
193 /* This edge stores a direct path back to the original vertex so we can
194 * backtrack without having to store an array of previous verts. */
195
196 /* WARNING: Setting the edge is not common practice but currently harmless, take care. */
197 BLI_assert(BM_vert_in_edge(e_prev, v));
198 v->e = e_prev;
199
200 BLI_addtail(lb, vs_new);
201}
202
204 ListBase *lb,
205 const int dir,
206 BMVert *v_match[2])
207{
208 ListBase lb_tmp = {nullptr, nullptr};
209 VertStep *vs, *vs_next;
210 BLI_assert(abs(dir) == 1);
211
212 for (vs = static_cast<VertStep *>(lb->first); vs; vs = vs_next) {
213 BMIter iter;
214 BMEdge *e;
215 /* these values will be the same every iteration */
216 const int vs_iter_tot = BM_elem_index_get(vs->v);
217 const int vs_iter_next = vs_iter_tot + dir;
218
219 vs_next = vs->next;
220
221 BM_ITER_ELEM (e, &iter, vs->v, BM_EDGES_OF_VERT) {
223 BMVert *v_next = BM_edge_other_vert(e, vs->v);
224 const int v_next_index = BM_elem_index_get(v_next);
225 /* not essential to clear flag but prevents more checking next time round */
227 if (v_next_index == 0) {
228 vs_add(vs_pool, &lb_tmp, v_next, e, vs_iter_next);
229 }
230 else if ((dir < 0) == (v_next_index < 0)) {
231 /* on the same side - do nothing */
232 }
233 else {
234 /* we have met out match! (vertices from different sides meet) */
235 if (dir == 1) {
236 v_match[0] = vs->v;
237 v_match[1] = v_next;
238 }
239 else {
240 v_match[0] = v_next;
241 v_match[1] = vs->v;
242 }
243 /* normally we would manage memory of remaining items in (lb, lb_tmp),
244 * but search is done, vs_pool will get destroyed immediately */
245 return true;
246 }
247 }
248 }
249
250 BLI_mempool_free(vs_pool, vs);
251 }
252
253 /* Commented because used in a loop, and this flag has already been set. */
254 // bm->elem_index_dirty |= BM_VERT;
255
256 /* `lb` is now full of freed items, overwrite. */
257 *lb = lb_tmp;
258
259 return (BLI_listbase_is_empty(lb) == false);
260}
261
263 ListBase *r_eloops,
264 bool (*test_fn)(BMEdge *, void *user_data),
265 void *user_data,
266 BMVert *v_src,
267 BMVert *v_dst)
268{
269 BMIter iter;
270 BMEdge *e;
271 bool found = false;
272
273 BLI_assert(v_src != v_dst);
274
275 {
276 BMVert *v;
277 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
280 }
281 }
283
284 /* first flush edges to tags, and tag verts */
285 int edges_len;
286 BMEdge **edges;
287
288 if (test_fn) {
289 BLI_Stack *edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
290 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
291 if (test_fn(e, user_data)) {
295 BLI_stack_push(edge_stack, (void *)&e);
296 }
297 else {
299 }
300 }
301 edges_len = BLI_stack_count(edge_stack);
302 edges = static_cast<BMEdge **>(MEM_mallocN(sizeof(*edges) * edges_len, __func__));
303 BLI_stack_pop_n_reverse(edge_stack, edges, BLI_stack_count(edge_stack));
304 BLI_stack_free(edge_stack);
305 }
306 else {
307 int i = 0;
308 edges_len = bm->totedge;
309 edges = static_cast<BMEdge **>(MEM_mallocN(sizeof(*edges) * edges_len, __func__));
310
315 edges[i] = e;
316 }
317 }
318
319 /* prime the lists and begin search */
320 {
321 BMVert *v_match[2] = {nullptr, nullptr};
322 ListBase lb_src = {nullptr, nullptr};
323 ListBase lb_dst = {nullptr, nullptr};
324 BLI_mempool *vs_pool = BLI_mempool_create(sizeof(VertStep), 0, 512, BLI_MEMPOOL_NOP);
325
326 /* edge args are dummy */
327 vs_add(vs_pool, &lb_src, v_src, v_src->e, 1);
328 vs_add(vs_pool, &lb_dst, v_dst, v_dst->e, -1);
330
331 do {
332 if ((bm_loop_path_build_step(vs_pool, &lb_src, 1, v_match) == false) || v_match[0]) {
333 break;
334 }
335 if ((bm_loop_path_build_step(vs_pool, &lb_dst, -1, v_match) == false) || v_match[0]) {
336 break;
337 }
338 } while (true);
339
340 BLI_mempool_destroy(vs_pool);
341
342 if (v_match[0]) {
343 BMEdgeLoopStore *el_store = static_cast<BMEdgeLoopStore *>(
344 MEM_callocN(sizeof(BMEdgeLoopStore), __func__));
345 BMVert *v;
346
347 /* build loop from edge pointers */
348 v = v_match[0];
349 while (true) {
350 LinkData *node = static_cast<LinkData *>(MEM_callocN(sizeof(*node), __func__));
351 node->data = v;
352 BLI_addhead(&el_store->verts, node);
353 el_store->len++;
354 if (v == v_src) {
355 break;
356 }
357 v = BM_edge_other_vert(v->e, v);
358 }
359
360 v = v_match[1];
361 while (true) {
362 LinkData *node = static_cast<LinkData *>(MEM_callocN(sizeof(*node), __func__));
363 node->data = v;
364 BLI_addtail(&el_store->verts, node);
365 el_store->len++;
366 if (v == v_dst) {
367 break;
368 }
369 v = BM_edge_other_vert(v->e, v);
370 }
371
372 BLI_addtail(r_eloops, el_store);
373
374 found = true;
375 }
376 }
377
378 for (uint i = 0; i < edges_len; i += 1) {
379 e = edges[i];
383 }
384 MEM_freeN(edges);
385
386 return found;
387}
388
389/* -------------------------------------------------------------------- */
390/* BM_mesh_edgeloops_xxx utility function */
391
393{
394 while (BMEdgeLoopStore *el_store = static_cast<BMEdgeLoopStore *>(BLI_pophead(eloops))) {
395 BM_edgeloop_free(el_store);
396 }
397}
398
400{
401 LISTBASE_FOREACH (BMEdgeLoopStore *, el_store, eloops) {
402 BM_edgeloop_calc_center(bm, el_store);
403 }
404}
405
407{
408 LISTBASE_FOREACH (BMEdgeLoopStore *, el_store, eloops) {
409 BM_edgeloop_calc_normal(bm, el_store);
410 }
411}
412
413void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm, ListBase *eloops, const float no_align[3])
414{
415 LISTBASE_FOREACH (BMEdgeLoopStore *, el_store, eloops) {
416 BM_edgeloop_calc_normal_aligned(bm, el_store, no_align);
417 }
418}
419
420void BM_mesh_edgeloops_calc_order(BMesh * /*bm*/, ListBase *eloops, const bool use_normals)
421{
422 ListBase eloops_ordered = {nullptr};
423 BMEdgeLoopStore *el_store;
424 float cent[3];
425 int tot = 0;
426 zero_v3(cent);
427 /* assumes we calculated centers already */
428 for (el_store = static_cast<BMEdgeLoopStore *>(eloops->first); el_store;
429 el_store = el_store->next, tot++)
430 {
431 add_v3_v3(cent, el_store->co);
432 }
433 mul_v3_fl(cent, 1.0f / float(tot));
434
435 /* Find the furthest out loop. */
436 {
437 BMEdgeLoopStore *el_store_best = nullptr;
438 float len_best_sq = -1.0f;
439 LISTBASE_FOREACH (BMEdgeLoopStore *, el_store, eloops) {
440 const float len_sq = len_squared_v3v3(cent, el_store->co);
441 if (len_sq > len_best_sq) {
442 len_best_sq = len_sq;
443 el_store_best = el_store;
444 }
445 }
446
447 BLI_remlink(eloops, el_store_best);
448 BLI_addtail(&eloops_ordered, el_store_best);
449 }
450
451 /* not so efficient re-ordering */
452 while (eloops->first) {
453 BMEdgeLoopStore *el_store_best = nullptr;
454 const float *co = ((BMEdgeLoopStore *)eloops_ordered.last)->co;
455 const float *no = ((BMEdgeLoopStore *)eloops_ordered.last)->no;
456 float len_best_sq = FLT_MAX;
457
458 if (use_normals) {
460 }
461
462 LISTBASE_FOREACH (BMEdgeLoopStore *, el_store, eloops) {
463 float len_sq;
464 if (use_normals) {
465 /* Scale the length by how close the loops are to pointing at each other. */
466 float dir[3];
467 sub_v3_v3v3(dir, co, el_store->co);
468 len_sq = normalize_v3(dir);
469 len_sq = len_sq *
470 ((1.0f - fabsf(dot_v3v3(dir, no))) + (1.0f - fabsf(dot_v3v3(dir, el_store->no))));
471 }
472 else {
473 len_sq = len_squared_v3v3(co, el_store->co);
474 }
475
476 if (len_sq < len_best_sq) {
477 len_best_sq = len_sq;
478 el_store_best = el_store;
479 }
480 }
481
482 BLI_remlink(eloops, el_store_best);
483 BLI_addtail(&eloops_ordered, el_store_best);
484 }
485
486 *eloops = eloops_ordered;
487}
488
489/* -------------------------------------------------------------------- */
490/* BM_edgeloop_*** functions */
491
493{
494 BMEdgeLoopStore *el_store_copy = static_cast<BMEdgeLoopStore *>(
495 MEM_mallocN(sizeof(*el_store), __func__));
496 *el_store_copy = *el_store;
497 BLI_duplicatelist(&el_store_copy->verts, &el_store->verts);
498 return el_store_copy;
499}
500
501BMEdgeLoopStore *BM_edgeloop_from_verts(BMVert **v_arr, const int v_arr_tot, bool is_closed)
502{
503 BMEdgeLoopStore *el_store = static_cast<BMEdgeLoopStore *>(
504 MEM_callocN(sizeof(*el_store), __func__));
505 int i;
506 for (i = 0; i < v_arr_tot; i++) {
507 LinkData *node = static_cast<LinkData *>(MEM_callocN(sizeof(*node), __func__));
508 node->data = v_arr[i];
509 BLI_addtail(&el_store->verts, node);
510 }
511 el_store->len = v_arr_tot;
512 if (is_closed) {
513 el_store->flag |= BM_EDGELOOP_IS_CLOSED;
514 }
515 return el_store;
516}
517
519{
520 BLI_freelistN(&el_store->verts);
521 MEM_freeN(el_store);
522}
523
525{
526 return (el_store->flag & BM_EDGELOOP_IS_CLOSED) != 0;
527}
528
530{
531 return &el_store->verts;
532}
533
535{
536 return el_store->len;
537}
538
540{
541 return el_store->no;
542}
543
545{
546 return el_store->co;
547}
548
549#define NODE_AS_V(n) ((BMVert *)((LinkData *)n)->data)
550#define NODE_AS_CO(n) ((BMVert *)((LinkData *)n)->data)->co
551
553{
554 LinkData *node;
555 int i = 0;
556 for (node = static_cast<LinkData *>(el_store->verts.first); node && node->next;
557 node = node->next)
558 {
559 e_arr[i++] = BM_edge_exists(NODE_AS_V(node), NODE_AS_V(node->next));
560 BLI_assert(e_arr[i - 1] != nullptr);
561 }
562
563 if (el_store->flag & BM_EDGELOOP_IS_CLOSED) {
564 e_arr[i] = BM_edge_exists(NODE_AS_V(el_store->verts.first), NODE_AS_V(el_store->verts.last));
565 BLI_assert(e_arr[i] != nullptr);
566 }
567 BLI_assert(el_store->len == i + 1);
568}
569
571{
572 LinkData *node_curr = static_cast<LinkData *>(el_store->verts.last);
573 LinkData *node_prev = ((LinkData *)el_store->verts.last)->prev;
574 LinkData *node_first = static_cast<LinkData *>(el_store->verts.first);
575 LinkData *node_next = node_first;
576
577 const float *v_prev = NODE_AS_CO(node_prev);
578 const float *v_curr = NODE_AS_CO(node_curr);
579 const float *v_next = NODE_AS_CO(node_next);
580
581 float totw = 0.0f;
582 float w_prev;
583
584 zero_v3(el_store->co);
585
586 w_prev = len_v3v3(v_prev, v_curr);
587 do {
588 const float w_curr = len_v3v3(v_curr, v_next);
589 const float w = (w_curr + w_prev);
590 madd_v3_v3fl(el_store->co, v_curr, w);
591 totw += w;
592 w_prev = w_curr;
593
594 node_prev = node_curr;
595 node_curr = node_next;
596 node_next = node_next->next;
597
598 if (node_next == nullptr) {
599 break;
600 }
601 v_prev = v_curr;
602 v_curr = v_next;
603 v_next = NODE_AS_CO(node_next);
604 } while (true);
605
606 if (totw != 0.0f) {
607 mul_v3_fl(el_store->co, 1.0f / float(totw));
608 }
609}
610
612{
613 LinkData *node_curr = static_cast<LinkData *>(el_store->verts.first);
614 const float *v_prev = NODE_AS_CO(el_store->verts.last);
615 const float *v_curr = NODE_AS_CO(node_curr);
616
617 zero_v3(el_store->no);
618
619 /* Newell's Method */
620 do {
621 add_newell_cross_v3_v3v3(el_store->no, v_prev, v_curr);
622
623 if ((node_curr = node_curr->next)) {
624 v_prev = v_curr;
625 v_curr = NODE_AS_CO(node_curr);
626 }
627 else {
628 break;
629 }
630 } while (true);
631
632 if (UNLIKELY(normalize_v3(el_store->no) < EDGELOOP_EPS)) {
633 el_store->no[2] = 1.0f; /* other axis set to 0.0 */
634 return false;
635 }
636 return true;
637}
638
640 BMEdgeLoopStore *el_store,
641 const float no_align[3])
642{
643 LinkData *node_curr = static_cast<LinkData *>(el_store->verts.first);
644 const float *v_prev = NODE_AS_CO(el_store->verts.last);
645 const float *v_curr = NODE_AS_CO(node_curr);
646
647 zero_v3(el_store->no);
648
649 /* Own Method */
650 do {
651 float cross[3], no[3], dir[3];
652 sub_v3_v3v3(dir, v_curr, v_prev);
653 cross_v3_v3v3(cross, no_align, dir);
654 cross_v3_v3v3(no, dir, cross);
655 add_v3_v3(el_store->no, no);
656
657 if ((node_curr = node_curr->next)) {
658 v_prev = v_curr;
659 v_curr = NODE_AS_CO(node_curr);
660 }
661 else {
662 break;
663 }
664 } while (true);
665
666 if (UNLIKELY(normalize_v3(el_store->no) < EDGELOOP_EPS)) {
667 el_store->no[2] = 1.0f; /* other axis set to 0.0 */
668 return false;
669 }
670 return true;
671}
672
673void BM_edgeloop_flip(BMesh * /*bm*/, BMEdgeLoopStore *el_store)
674{
675 negate_v3(el_store->no);
676 BLI_listbase_reverse(&el_store->verts);
677}
678
680 BMesh *bm, BMEdgeLoopStore *el_store, int el_store_len, bool split, GSet *split_edges)
681{
682 bool split_swap = true;
683
684#define EDGE_SPLIT(node_copy, node_other) \
685 { \
686 BMVert *v_split, *v_other = static_cast<BMVert *>((node_other)->data); \
687 BMEdge *e_split, \
688 *e_other = BM_edge_exists(static_cast<BMVert *>((node_copy)->data), v_other); \
689 v_split = BM_edge_split(bm, \
690 e_other, \
691 static_cast<BMVert *>(split_swap ? (node_copy)->data : v_other), \
692 &e_split, \
693 0.0f); \
694 v_split->e = e_split; \
695 BLI_assert(v_split == e_split->v2); \
696 BLI_gset_insert(split_edges, e_split); \
697 (node_copy)->data = v_split; \
698 } \
699 ((void)0)
700
701 /* first double until we are more than half as big */
702 while ((el_store->len * 2) < el_store_len) {
703 LinkData *node_curr = static_cast<LinkData *>(el_store->verts.first);
704 while (node_curr) {
705 LinkData *node_curr_copy = static_cast<LinkData *>(MEM_dupallocN(node_curr));
706 if (split == false) {
707 BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
708 node_curr = node_curr_copy->next;
709 }
710 else {
711 if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) {
712 EDGE_SPLIT(node_curr_copy,
713 node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first);
714 BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
715 node_curr = node_curr_copy->next;
716 }
717 else {
718 EDGE_SPLIT(node_curr_copy, node_curr->prev);
719 BLI_insertlinkbefore(&el_store->verts, node_curr, node_curr_copy);
720 node_curr = node_curr->next;
721 }
722 split_swap = !split_swap;
723 }
724 el_store->len++;
725 }
726 split_swap = !split_swap;
727 }
728
729 if (el_store->len < el_store_len) {
730 LinkData *node_curr = static_cast<LinkData *>(el_store->verts.first);
731
732 int iter_prev = 0;
733 BLI_FOREACH_SPARSE_RANGE (el_store->len, (el_store_len - el_store->len), iter) {
734 while (iter_prev < iter) {
735 node_curr = node_curr->next;
736 iter_prev += 1;
737 }
738
739 LinkData *node_curr_copy;
740 node_curr_copy = static_cast<LinkData *>(MEM_dupallocN(node_curr));
741 if (split == false) {
742 BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
743 node_curr = node_curr_copy->next;
744 }
745 else {
746 if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) {
747 EDGE_SPLIT(node_curr_copy,
748 node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first);
749 BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
750 node_curr = node_curr_copy->next;
751 }
752 else {
753 EDGE_SPLIT(node_curr_copy, node_curr->prev);
754 BLI_insertlinkbefore(&el_store->verts, node_curr, node_curr_copy);
755 node_curr = node_curr->next;
756 }
757 split_swap = !split_swap;
758 }
759 el_store->len++;
760 iter_prev += 1;
761 }
762 }
763
764#undef BKE_FOREACH_SUBSET_OF_RANGE
765#undef EDGE_SPLIT
766
767 BLI_assert(el_store->len == el_store_len);
768}
769
771{
772 /* A little more efficient if 'a' as smaller. */
773 if (el_store_a->len > el_store_b->len) {
774 std::swap(el_store_a, el_store_b);
775 }
776
777 /* init */
778 LISTBASE_FOREACH (LinkData *, node, &el_store_a->verts) {
780 }
781 LISTBASE_FOREACH (LinkData *, node, &el_store_b->verts) {
783 }
784
785 /* Check 'a' (clear as we go). */
786 LISTBASE_FOREACH (LinkData *, node, &el_store_a->verts) {
787 if (!BM_elem_flag_test((BMVert *)node->data, BM_ELEM_INTERNAL_TAG)) {
788 /* Finish clearing 'a', leave tag clean. */
789 while ((node = node->next)) {
791 }
792 return true;
793 }
795 }
796 return false;
797}
#define BLI_assert(a)
Definition BLI_assert.h:50
struct GSet GSet
Definition BLI_ghash.h:341
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
#define LISTBASE_FOREACH(type, var, list)
void void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
void void void void void void void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1)
Definition listbase.cc:823
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:251
#define BLI_ASSERT_UNIT_V3(v)
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
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 zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
@ BLI_MEMPOOL_NOP
Definition BLI_mempool.h:86
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL()
Definition stack.c:156
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.c:227
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
Definition stack.c:131
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.c:96
#define BLI_stack_new(esize, descr)
unsigned int uint
#define UNLIKELY(x)
#define BLI_FOREACH_SPARSE_RANGE(src, dst, i)
Read Guarded memory(de)allocation.
@ BM_ELEM_INTERNAL_TAG
#define BM_EDGELOOP_IS_CLOSED
void BM_mesh_edgeloops_calc_order(BMesh *, ListBase *eloops, const bool use_normals)
static bool bm_loop_path_build_step(BLI_mempool *vs_pool, ListBase *lb, const int dir, BMVert *v_match[2])
#define NODE_AS_CO(n)
void BM_edgeloop_expand(BMesh *bm, BMEdgeLoopStore *el_store, int el_store_len, bool split, GSet *split_edges)
void BM_mesh_edgeloops_free(ListBase *eloops)
void BM_edgeloop_free(BMEdgeLoopStore *el_store)
bool BM_edgeloop_overlap_check(BMEdgeLoopStore *el_store_a, BMEdgeLoopStore *el_store_b)
void BM_edgeloop_flip(BMesh *, BMEdgeLoopStore *el_store)
BMEdgeLoopStore * BM_edgeloop_copy(BMEdgeLoopStore *el_store)
bool BM_edgeloop_calc_normal(BMesh *, BMEdgeLoopStore *el_store)
int BM_mesh_edgeloops_find(BMesh *bm, ListBase *r_eloops, bool(*test_fn)(BMEdge *, void *user_data), void *user_data)
#define NODE_AS_V(n)
void BM_edgeloop_calc_center(BMesh *, BMEdgeLoopStore *el_store)
BMEdgeLoopStore * BM_edgeloop_from_verts(BMVert **v_arr, const int v_arr_tot, bool is_closed)
bool BM_mesh_edgeloops_find_path(BMesh *bm, ListBase *r_eloops, bool(*test_fn)(BMEdge *, void *user_data), void *user_data, BMVert *v_src, BMVert *v_dst)
#define EDGELOOP_EPS
int BM_edgeloop_length_get(BMEdgeLoopStore *el_store)
const float * BM_edgeloop_normal_get(BMEdgeLoopStore *el_store)
bool BM_edgeloop_calc_normal_aligned(BMesh *, BMEdgeLoopStore *el_store, const float no_align[3])
static bool bm_loop_build(BMEdgeLoopStore *el_store, BMVert *v_prev, BMVert *v, int dir)
bool BM_edgeloop_is_closed(BMEdgeLoopStore *el_store)
void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm, ListBase *eloops, const float no_align[3])
void BM_edgeloop_edges_get(BMEdgeLoopStore *el_store, BMEdge **e_arr)
static int bm_vert_other_tag(BMVert *v, BMVert *v_prev, BMEdge **r_e)
const float * BM_edgeloop_center_get(BMEdgeLoopStore *el_store)
static void vs_add(BLI_mempool *vs_pool, ListBase *lb, BMVert *v, BMEdge *e_prev, const int iter_tot)
void BM_mesh_edgeloops_calc_normal(BMesh *bm, ListBase *eloops)
ListBase * BM_edgeloop_verts_get(BMEdgeLoopStore *el_store)
#define EDGE_SPLIT(node_copy, node_other)
void BM_mesh_edgeloops_calc_center(BMesh *bm, ListBase *eloops)
#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_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
#define BM_VERT
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
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 const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
OperationNode * node
#define fabsf(x)
int count
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
ccl_device_inline float cross(const float2 a, const float2 b)
#define FLT_MAX
Definition stdcycles.h:14
BMEdgeLoopStore * next
BMEdgeLoopStore * prev
struct BMEdge * e
char elem_index_dirty
int totedge
void * data
struct LinkData * next
struct LinkData * prev
void * last
void * first
VertStep * next
VertStep * prev
ccl_device_inline int abs(int x)
Definition util/math.h:120