Blender V5.0
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
10
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 calculate. */
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 = MEM_callocN<LinkData>(__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 = MEM_malloc_arrayN<BMEdge *>(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 = MEM_callocN<BMEdgeLoopStore>(__func__);
147
148 /* add both directions */
149 if (bm_loop_build(el_store, e->v1, e->v2, 1) && bm_loop_build(el_store, e->v2, e->v1, -1) &&
150 el_store->len > 1)
151 {
152 BLI_addtail(r_eloops, el_store);
153 count++;
154 }
155 else {
156 BM_edgeloop_free(el_store);
157 }
158 }
159 }
160
161 for (uint i = 0; i < edges_len; i += 1) {
162 e = edges[i];
166 }
167
168 MEM_freeN(edges);
169 return count;
170}
171
172/* -------------------------------------------------------------------- */
173/* BM_mesh_edgeloops_find_path & Util Functions. */
174
183
184static void vs_add(
185 BLI_mempool *vs_pool, ListBase *lb, BMVert *v, BMEdge *e_prev, const int iter_tot)
186{
187 VertStep *vs_new = static_cast<VertStep *>(BLI_mempool_alloc(vs_pool));
188 vs_new->v = v;
189
190 BM_elem_index_set(v, iter_tot); /* set_dirty */
191
192 /* This edge stores a direct path back to the original vertex so we can
193 * backtrack without having to store an array of previous verts. */
194
195 /* WARNING: Setting the edge is not common practice but currently harmless, take care. */
196 BLI_assert(BM_vert_in_edge(e_prev, v));
197 v->e = e_prev;
198
199 BLI_addtail(lb, vs_new);
200}
201
203 ListBase *lb,
204 const int dir,
205 BMVert *v_match[2])
206{
207 ListBase lb_tmp = {nullptr, nullptr};
208 VertStep *vs, *vs_next;
209 BLI_assert(abs(dir) == 1);
210
211 for (vs = static_cast<VertStep *>(lb->first); vs; vs = vs_next) {
212 BMIter iter;
213 BMEdge *e;
214 /* these values will be the same every iteration */
215 const int vs_iter_tot = BM_elem_index_get(vs->v);
216 const int vs_iter_next = vs_iter_tot + dir;
217
218 vs_next = vs->next;
219
220 BM_ITER_ELEM (e, &iter, vs->v, BM_EDGES_OF_VERT) {
222 BMVert *v_next = BM_edge_other_vert(e, vs->v);
223 const int v_next_index = BM_elem_index_get(v_next);
224 /* not essential to clear flag but prevents more checking next time round */
226 if (v_next_index == 0) {
227 vs_add(vs_pool, &lb_tmp, v_next, e, vs_iter_next);
228 }
229 else if ((dir < 0) == (v_next_index < 0)) {
230 /* on the same side - do nothing */
231 }
232 else {
233 /* we have met out match! (vertices from different sides meet) */
234 if (dir == 1) {
235 v_match[0] = vs->v;
236 v_match[1] = v_next;
237 }
238 else {
239 v_match[0] = v_next;
240 v_match[1] = vs->v;
241 }
242 /* normally we would manage memory of remaining items in (lb, lb_tmp),
243 * but search is done, vs_pool will get destroyed immediately */
244 return true;
245 }
246 }
247 }
248
249 BLI_mempool_free(vs_pool, vs);
250 }
251
252 /* Commented because used in a loop, and this flag has already been set. */
253 // bm->elem_index_dirty |= BM_VERT;
254
255 /* `lb` is now full of freed items, overwrite. */
256 *lb = lb_tmp;
257
258 return (BLI_listbase_is_empty(lb) == false);
259}
260
262 ListBase *r_eloops,
263 bool (*test_fn)(BMEdge *, void *user_data),
264 void *user_data,
265 BMVert *v_src,
266 BMVert *v_dst)
267{
268 BMIter iter;
269 BMEdge *e;
270 bool found = false;
271
272 BLI_assert(v_src != v_dst);
273
274 {
275 BMVert *v;
276 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
279 }
280 }
281 bm->elem_index_dirty |= BM_VERT;
282
283 /* first flush edges to tags, and tag verts */
284 int edges_len;
285 BMEdge **edges;
286
287 if (test_fn) {
288 BLI_Stack *edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
289 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
290 if (test_fn(e, user_data)) {
294 BLI_stack_push(edge_stack, (void *)&e);
295 }
296 else {
298 }
299 }
300 edges_len = BLI_stack_count(edge_stack);
301 edges = MEM_malloc_arrayN<BMEdge *>(edges_len, __func__);
302 BLI_stack_pop_n_reverse(edge_stack, edges, BLI_stack_count(edge_stack));
303 BLI_stack_free(edge_stack);
304 }
305 else {
306 int i = 0;
307 edges_len = bm->totedge;
308 edges = MEM_malloc_arrayN<BMEdge *>(edges_len, __func__);
309
314 edges[i] = e;
315 }
316 }
317
318 /* prime the lists and begin search */
319 {
320 BMVert *v_match[2] = {nullptr, nullptr};
321 ListBase lb_src = {nullptr, nullptr};
322 ListBase lb_dst = {nullptr, nullptr};
323 BLI_mempool *vs_pool = BLI_mempool_create(sizeof(VertStep), 0, 512, BLI_MEMPOOL_NOP);
324
325 /* edge args are dummy */
326 vs_add(vs_pool, &lb_src, v_src, v_src->e, 1);
327 vs_add(vs_pool, &lb_dst, v_dst, v_dst->e, -1);
328 bm->elem_index_dirty |= BM_VERT;
329
330 do {
331 if ((bm_loop_path_build_step(vs_pool, &lb_src, 1, v_match) == false) || v_match[0]) {
332 break;
333 }
334 if ((bm_loop_path_build_step(vs_pool, &lb_dst, -1, v_match) == false) || v_match[0]) {
335 break;
336 }
337 } while (true);
338
339 BLI_mempool_destroy(vs_pool);
340
341 if (v_match[0]) {
342 BMEdgeLoopStore *el_store = MEM_callocN<BMEdgeLoopStore>(__func__);
343 BMVert *v;
344
345 /* build loop from edge pointers */
346 v = v_match[0];
347 while (true) {
348 LinkData *node = MEM_callocN<LinkData>(__func__);
349 node->data = v;
350 BLI_addhead(&el_store->verts, node);
351 el_store->len++;
352 if (v == v_src) {
353 break;
354 }
355 v = BM_edge_other_vert(v->e, v);
356 }
357
358 v = v_match[1];
359 while (true) {
360 LinkData *node = MEM_callocN<LinkData>(__func__);
361 node->data = v;
362 BLI_addtail(&el_store->verts, node);
363 el_store->len++;
364 if (v == v_dst) {
365 break;
366 }
367 v = BM_edge_other_vert(v->e, v);
368 }
369
370 BLI_addtail(r_eloops, el_store);
371
372 found = true;
373 }
374 }
375
376 for (uint i = 0; i < edges_len; i += 1) {
377 e = edges[i];
381 }
382 MEM_freeN(edges);
383
384 return found;
385}
386
387/* -------------------------------------------------------------------- */
388/* BM_mesh_edgeloops_xxx utility function */
389
391{
392 while (BMEdgeLoopStore *el_store = static_cast<BMEdgeLoopStore *>(BLI_pophead(eloops))) {
393 BM_edgeloop_free(el_store);
394 }
395}
396
398{
399 LISTBASE_FOREACH (BMEdgeLoopStore *, el_store, eloops) {
400 BM_edgeloop_calc_center(bm, el_store);
401 }
402}
403
405{
406 LISTBASE_FOREACH (BMEdgeLoopStore *, el_store, eloops) {
407 BM_edgeloop_calc_normal(bm, el_store);
408 }
409}
410
411void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm, ListBase *eloops, const float no_align[3])
412{
413 LISTBASE_FOREACH (BMEdgeLoopStore *, el_store, eloops) {
414 BM_edgeloop_calc_normal_aligned(bm, el_store, no_align);
415 }
416}
417
418void BM_mesh_edgeloops_calc_order(BMesh * /*bm*/, ListBase *eloops, const bool use_normals)
419{
420 ListBase eloops_ordered = {nullptr};
421 BMEdgeLoopStore *el_store;
422 float cent[3];
423 int tot = 0;
424 zero_v3(cent);
425 /* assumes we calculated centers already */
426 for (el_store = static_cast<BMEdgeLoopStore *>(eloops->first); el_store;
427 el_store = el_store->next, tot++)
428 {
429 add_v3_v3(cent, el_store->co);
430 }
431 mul_v3_fl(cent, 1.0f / float(tot));
432
433 /* Find the furthest out loop. */
434 {
435 BMEdgeLoopStore *el_store_best = nullptr;
436 float len_best_sq = -1.0f;
437 LISTBASE_FOREACH (BMEdgeLoopStore *, el_store, eloops) {
438 const float len_sq = len_squared_v3v3(cent, el_store->co);
439 if (len_sq > len_best_sq) {
440 len_best_sq = len_sq;
441 el_store_best = el_store;
442 }
443 }
444
445 BLI_remlink(eloops, el_store_best);
446 BLI_addtail(&eloops_ordered, el_store_best);
447 }
448
449 /* not so efficient re-ordering */
450 while (eloops->first) {
451 BMEdgeLoopStore *el_store_best = nullptr;
452 const float *co = ((BMEdgeLoopStore *)eloops_ordered.last)->co;
453 const float *no = ((BMEdgeLoopStore *)eloops_ordered.last)->no;
454 float len_best_sq = FLT_MAX;
455
456 if (use_normals) {
458 }
459
460 LISTBASE_FOREACH (BMEdgeLoopStore *, el_store, eloops) {
461 float len_sq;
462 if (use_normals) {
463 /* Scale the length by how close the loops are to pointing at each other. */
464 float dir[3];
465 sub_v3_v3v3(dir, co, el_store->co);
466 len_sq = normalize_v3(dir);
467 len_sq = len_sq *
468 ((1.0f - fabsf(dot_v3v3(dir, no))) + (1.0f - fabsf(dot_v3v3(dir, el_store->no))));
469 }
470 else {
471 len_sq = len_squared_v3v3(co, el_store->co);
472 }
473
474 if (len_sq < len_best_sq) {
475 len_best_sq = len_sq;
476 el_store_best = el_store;
477 }
478 }
479
480 BLI_remlink(eloops, el_store_best);
481 BLI_addtail(&eloops_ordered, el_store_best);
482 }
483
484 *eloops = eloops_ordered;
485}
486
487/* -------------------------------------------------------------------- */
488/* BM_edgeloop_*** functions */
489
491{
492 BMEdgeLoopStore *el_store_copy = static_cast<BMEdgeLoopStore *>(
493 MEM_mallocN(sizeof(*el_store), __func__));
494 *el_store_copy = *el_store;
495 BLI_duplicatelist(&el_store_copy->verts, &el_store->verts);
496 return el_store_copy;
497}
498
499BMEdgeLoopStore *BM_edgeloop_from_verts(BMVert **v_arr, const int v_arr_tot, bool is_closed)
500{
501 BMEdgeLoopStore *el_store = static_cast<BMEdgeLoopStore *>(
502 MEM_callocN(sizeof(*el_store), __func__));
503 int i;
504 for (i = 0; i < v_arr_tot; i++) {
505 LinkData *node = MEM_callocN<LinkData>(__func__);
506 node->data = v_arr[i];
507 BLI_addtail(&el_store->verts, node);
508 }
509 el_store->len = v_arr_tot;
510 if (is_closed) {
511 el_store->flag |= BM_EDGELOOP_IS_CLOSED;
512 }
513 return el_store;
514}
515
517{
518 BLI_freelistN(&el_store->verts);
519 MEM_freeN(el_store);
520}
521
523{
524 return (el_store->flag & BM_EDGELOOP_IS_CLOSED) != 0;
525}
526
528{
529 return &el_store->verts;
530}
531
533{
534 return el_store->len;
535}
536
538{
539 return el_store->no;
540}
541
543{
544 return el_store->co;
545}
546
547#define NODE_AS_V(n) ((BMVert *)((LinkData *)n)->data)
548#define NODE_AS_CO(n) ((BMVert *)((LinkData *)n)->data)->co
549
551{
552 LinkData *node;
553 int i = 0;
554 for (node = static_cast<LinkData *>(el_store->verts.first); node && node->next;
555 node = node->next)
556 {
557 e_arr[i++] = BM_edge_exists(NODE_AS_V(node), NODE_AS_V(node->next));
558 BLI_assert(e_arr[i - 1] != nullptr);
559 }
560
561 if (el_store->flag & BM_EDGELOOP_IS_CLOSED) {
562 e_arr[i] = BM_edge_exists(NODE_AS_V(el_store->verts.first), NODE_AS_V(el_store->verts.last));
563 BLI_assert(e_arr[i] != nullptr);
564 }
565 BLI_assert(el_store->len == i + 1);
566}
567
569{
570 LinkData *node_curr = static_cast<LinkData *>(el_store->verts.last);
571 LinkData *node_prev = ((LinkData *)el_store->verts.last)->prev;
572 LinkData *node_first = static_cast<LinkData *>(el_store->verts.first);
573 LinkData *node_next = node_first;
574
575 const float *v_prev = NODE_AS_CO(node_prev);
576 const float *v_curr = NODE_AS_CO(node_curr);
577 const float *v_next = NODE_AS_CO(node_next);
578
579 float totw = 0.0f;
580 float w_prev;
581
582 zero_v3(el_store->co);
583
584 w_prev = len_v3v3(v_prev, v_curr);
585 do {
586 const float w_curr = len_v3v3(v_curr, v_next);
587 const float w = (w_curr + w_prev);
588 madd_v3_v3fl(el_store->co, v_curr, w);
589 totw += w;
590 w_prev = w_curr;
591
592 node_prev = node_curr;
593 node_curr = node_next;
594 node_next = node_next->next;
595
596 if (node_next == nullptr) {
597 break;
598 }
599 v_prev = v_curr;
600 v_curr = v_next;
601 v_next = NODE_AS_CO(node_next);
602 } while (true);
603
604 if (totw != 0.0f) {
605 mul_v3_fl(el_store->co, 1.0f / totw);
606 }
607}
608
610{
611 LinkData *node_curr = static_cast<LinkData *>(el_store->verts.first);
612 const float *v_prev = NODE_AS_CO(el_store->verts.last);
613 const float *v_curr = NODE_AS_CO(node_curr);
614
615 zero_v3(el_store->no);
616
617 /* Newell's Method */
618 do {
619 add_newell_cross_v3_v3v3(el_store->no, v_prev, v_curr);
620
621 if ((node_curr = node_curr->next)) {
622 v_prev = v_curr;
623 v_curr = NODE_AS_CO(node_curr);
624 }
625 else {
626 break;
627 }
628 } while (true);
629
630 if (UNLIKELY(normalize_v3(el_store->no) < EDGELOOP_EPS)) {
631 el_store->no[2] = 1.0f; /* other axis set to 0.0 */
632 return false;
633 }
634 return true;
635}
636
638 BMEdgeLoopStore *el_store,
639 const float no_align[3])
640{
641 LinkData *node_curr = static_cast<LinkData *>(el_store->verts.first);
642 const float *v_prev = NODE_AS_CO(el_store->verts.last);
643 const float *v_curr = NODE_AS_CO(node_curr);
644
645 zero_v3(el_store->no);
646
647 /* Own Method */
648 do {
649 float cross[3], no[3], dir[3];
650 sub_v3_v3v3(dir, v_curr, v_prev);
651 cross_v3_v3v3(cross, no_align, dir);
652 cross_v3_v3v3(no, dir, cross);
653 add_v3_v3(el_store->no, no);
654
655 if ((node_curr = node_curr->next)) {
656 v_prev = v_curr;
657 v_curr = NODE_AS_CO(node_curr);
658 }
659 else {
660 break;
661 }
662 } while (true);
663
664 if (UNLIKELY(normalize_v3(el_store->no) < EDGELOOP_EPS)) {
665 el_store->no[2] = 1.0f; /* other axis set to 0.0 */
666 return false;
667 }
668 return true;
669}
670
671void BM_edgeloop_flip(BMesh * /*bm*/, BMEdgeLoopStore *el_store)
672{
673 negate_v3(el_store->no);
674 BLI_listbase_reverse(&el_store->verts);
675}
676
678 BMesh *bm, BMEdgeLoopStore *el_store, int el_store_len, bool split, GSet *split_edges)
679{
680 bool split_swap = true;
681
682#define EDGE_SPLIT(node_copy, node_other) \
683 { \
684 BMVert *v_split, *v_other = static_cast<BMVert *>((node_other)->data); \
685 BMEdge *e_split, \
686 *e_other = BM_edge_exists(static_cast<BMVert *>((node_copy)->data), v_other); \
687 v_split = BM_edge_split(bm, \
688 e_other, \
689 static_cast<BMVert *>(split_swap ? (node_copy)->data : v_other), \
690 &e_split, \
691 0.0f); \
692 v_split->e = e_split; \
693 BLI_assert(v_split == e_split->v2); \
694 BLI_gset_insert(split_edges, e_split); \
695 (node_copy)->data = v_split; \
696 } \
697 ((void)0)
698
699 /* first double until we are more than half as big */
700 while ((el_store->len * 2) < el_store_len) {
701 LinkData *node_curr = static_cast<LinkData *>(el_store->verts.first);
702 while (node_curr) {
703 LinkData *node_curr_copy = static_cast<LinkData *>(MEM_dupallocN(node_curr));
704 if (split == false) {
705 BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
706 node_curr = node_curr_copy->next;
707 }
708 else {
709 if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) {
710 EDGE_SPLIT(node_curr_copy,
711 node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first);
712 BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
713 node_curr = node_curr_copy->next;
714 }
715 else {
716 EDGE_SPLIT(node_curr_copy, node_curr->prev);
717 BLI_insertlinkbefore(&el_store->verts, node_curr, node_curr_copy);
718 node_curr = node_curr->next;
719 }
720 split_swap = !split_swap;
721 }
722 el_store->len++;
723 }
724 split_swap = !split_swap;
725 }
726
727 if (el_store->len < el_store_len) {
728 LinkData *node_curr = static_cast<LinkData *>(el_store->verts.first);
729
730 int iter_prev = 0;
731 BLI_FOREACH_SPARSE_RANGE (el_store->len, (el_store_len - el_store->len), iter) {
732 while (iter_prev < iter) {
733 node_curr = node_curr->next;
734 iter_prev += 1;
735 }
736
737 LinkData *node_curr_copy;
738 node_curr_copy = static_cast<LinkData *>(MEM_dupallocN(node_curr));
739 if (split == false) {
740 BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
741 node_curr = node_curr_copy->next;
742 }
743 else {
744 if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) {
745 EDGE_SPLIT(node_curr_copy,
746 node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first);
747 BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
748 node_curr = node_curr_copy->next;
749 }
750 else {
751 EDGE_SPLIT(node_curr_copy, node_curr->prev);
752 BLI_insertlinkbefore(&el_store->verts, node_curr, node_curr_copy);
753 node_curr = node_curr->next;
754 }
755 split_swap = !split_swap;
756 }
757 el_store->len++;
758 iter_prev += 1;
759 }
760 }
761
762#undef BKE_FOREACH_SUBSET_OF_RANGE
763#undef EDGE_SPLIT
764
765 BLI_assert(el_store->len == el_store_len);
766}
767
769{
770 /* A little more efficient if 'a' as smaller. */
771 if (el_store_a->len > el_store_b->len) {
772 std::swap(el_store_a, el_store_b);
773 }
774
775 /* init */
776 LISTBASE_FOREACH (LinkData *, node, &el_store_a->verts) {
778 }
779 LISTBASE_FOREACH (LinkData *, node, &el_store_b->verts) {
781 }
782
783 /* Check 'a' (clear as we go). */
784 LISTBASE_FOREACH (LinkData *, node, &el_store_a->verts) {
785 if (!BM_elem_flag_test((BMVert *)node->data, BM_ELEM_INTERNAL_TAG)) {
786 /* Finish clearing 'a', leave tag clean. */
787 while ((node = node->next)) {
789 }
790 return true;
791 }
793 }
794 return false;
795}
#define BLI_assert(a)
Definition BLI_assert.h:46
struct GSet GSet
Definition BLI_ghash.h:337
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:332
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
void void void void void void void BLI_listbase_reverse(ListBase *lb) ATTR_NONNULL(1)
Definition listbase.cc:836
void void void void void void BLI_duplicatelist(ListBase *dst, const ListBase *src) ATTR_NONNULL(1
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:252
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:371
#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)
@ BLI_MEMPOOL_NOP
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
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.cc:157
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:228
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
Definition stack.cc:132
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.cc:96
#define BLI_stack_new(esize, descr)
unsigned int uint
#define UNLIKELY(x)
#define BLI_FOREACH_SPARSE_RANGE(src, dst, i)
static void split(const char *text, const char *seps, char ***str, int *count)
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
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
#define abs
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
int count
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define fabsf
#define FLT_MAX
Definition stdcycles.h:14
BMEdgeLoopStore * next
BMEdgeLoopStore * prev
struct BMEdge * e
void * data
struct LinkData * next
struct LinkData * prev
void * last
void * first
VertStep * next
VertStep * prev
i
Definition text_draw.cc:230