Blender V4.3
bmesh_iterators.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
13#include "MEM_guardedalloc.h"
14
15#include "BLI_utildefines.h"
16
17#include "bmesh.hh"
19
21 '\0',
22 BM_VERT, /* BM_VERTS_OF_MESH */
23 BM_EDGE, /* BM_EDGES_OF_MESH */
24 BM_FACE, /* BM_FACES_OF_MESH */
25 BM_EDGE, /* BM_EDGES_OF_VERT */
26 BM_FACE, /* BM_FACES_OF_VERT */
27 BM_LOOP, /* BM_LOOPS_OF_VERT */
28 BM_VERT, /* BM_VERTS_OF_EDGE */
29 BM_FACE, /* BM_FACES_OF_EDGE */
30 BM_VERT, /* BM_VERTS_OF_FACE */
31 BM_EDGE, /* BM_EDGES_OF_FACE */
32 BM_LOOP, /* BM_LOOPS_OF_FACE */
33 BM_LOOP, /* BM_LOOPS_OF_LOOP */
34 BM_LOOP, /* BM_LOOPS_OF_EDGE */
35};
36
38{
39 int count;
40
41 switch (itype) {
43 count = bm->totvert;
44 break;
46 count = bm->totedge;
47 break;
49 count = bm->totface;
50 break;
51 default:
52 count = 0;
53 BLI_assert(0);
54 break;
55 }
56
57 return count;
58}
59
60void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
61{
62 BMIter iter;
63 void *val;
64 int i;
65
66 /* sanity check */
67 if (index < 0) {
68 return nullptr;
69 }
70
71 val = BM_iter_new(&iter, bm, itype, data);
72
73 i = 0;
74 while (i < index) {
75 val = BM_iter_step(&iter);
76 i++;
77 }
78
79 return val;
80}
81
82int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
83{
84 int i = 0;
85
86 /* sanity check */
87 if (len > 0) {
88 BMIter iter;
89 void *ele;
90
91 for (ele = BM_iter_new(&iter, bm, itype, data); ele; ele = BM_iter_step(&iter)) {
92 array[i] = ele;
93 i++;
94 if (i == len) {
95 return len;
96 }
97 }
98 }
99
100 return i;
101}
103 const char *slot_name,
104 const char restrictmask,
105 void **array,
106 const int len)
107{
108 int i = 0;
109
110 /* sanity check */
111 if (len > 0) {
112 BMOIter oiter;
113 void *ele;
114
115 for (ele = BMO_iter_new(&oiter, slot_args, slot_name, restrictmask); ele;
116 ele = BMO_iter_step(&oiter))
117 {
118 array[i] = ele;
119 i++;
120 if (i == len) {
121 return len;
122 }
123 }
124 }
125
126 return i;
127}
128
130 const char itype,
131 void *data,
132 int *r_len,
133 /* optional args to avoid an alloc (normally stack array) */
134 void **stack_array,
135 int stack_array_size)
136{
137 BMIter iter;
138
139 BLI_assert(stack_array_size == 0 || (stack_array_size && stack_array));
140
141 /* We can't rely on #BMIter.count being set. */
142 switch (itype) {
143 case BM_VERTS_OF_MESH:
144 iter.count = bm->totvert;
145 break;
146 case BM_EDGES_OF_MESH:
147 iter.count = bm->totedge;
148 break;
149 case BM_FACES_OF_MESH:
150 iter.count = bm->totface;
151 break;
152 default:
153 break;
154 }
155
156 if (BM_iter_init(&iter, bm, itype, data) && iter.count > 0) {
157 BMElem *ele;
158 BMElem **array = iter.count > stack_array_size ?
159 static_cast<BMElem **>(MEM_mallocN(sizeof(ele) * iter.count, __func__)) :
160 reinterpret_cast<BMElem **>(stack_array);
161 int i = 0;
162
163 *r_len = iter.count; /* set before iterating */
164
165 while ((ele = static_cast<BMElem *>(BM_iter_step(&iter)))) {
166 array[i++] = ele;
167 }
168 return array;
169 }
170
171 *r_len = 0;
172 return nullptr;
173}
174
176 const char *slot_name,
177 const char restrictmask,
178 int *r_len,
179 /* optional args to avoid an alloc (normally stack array) */
180 void **stack_array,
181 int stack_array_size)
182{
183 BMOIter iter;
184 BMElem *ele;
185 const int slot_len = BMO_slot_buffer_len(slot_args, slot_name);
186
187 BLI_assert(stack_array_size == 0 || (stack_array_size && stack_array));
188
189 if ((ele = static_cast<BMElem *>(BMO_iter_new(&iter, slot_args, slot_name, restrictmask))) &&
190 slot_len > 0)
191 {
192 BMElem **array = slot_len > stack_array_size ?
193 static_cast<BMElem **>(MEM_mallocN(sizeof(ele) * slot_len, __func__)) :
194 reinterpret_cast<BMElem **>(stack_array);
195 int i = 0;
196
197 do {
198 array[i++] = ele;
199 } while ((ele = static_cast<BMElem *>(BMO_iter_step(&iter))));
200 BLI_assert(i <= slot_len);
201
202 if (i != slot_len) {
203 if ((void **)array != stack_array) {
204 array = static_cast<BMElem **>(MEM_reallocN(array, sizeof(ele) * i));
205 }
206 }
207 *r_len = i;
208 return array;
209 }
210
211 *r_len = 0;
212 return nullptr;
213}
214
216 BMesh *bm,
218 bool (*test_fn)(BMElem *, void *user_data),
219 void *user_data)
220{
221 BMIter iter;
222 BMElem *ele;
223 int i;
224 int bitmap_enabled = 0;
225
226 BM_ITER_MESH_INDEX (ele, &iter, bm, itype, i) {
227 if (test_fn(ele, user_data)) {
228 bitmap[i].set();
229 bitmap_enabled++;
230 }
231 else {
232 bitmap[i].reset();
233 }
234 }
235
236 return bitmap_enabled;
237}
238
241 bool (*test_fn)(BMFace *, void *user_data),
242 void *user_data)
243{
244 BMIter iter;
245 BMFace *f;
246 int i;
247 int j = 0;
248 int bitmap_enabled = 0;
249
250 BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
251 if (test_fn(f, user_data)) {
252 for (int tri = 2; tri < f->len; tri++) {
253 bitmap[j].set();
254 bitmap_enabled++;
255 j++;
256 }
257 }
258 else {
259 for (int tri = 2; tri < f->len; tri++) {
260 bitmap[j].reset();
261 j++;
262 }
263 }
264 }
265
266 return bitmap_enabled;
267}
268
269int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
270{
271 BMIter iter;
272 BMElem *ele;
273 int count = 0;
274
275 BM_ITER_ELEM (ele, &iter, data, itype) {
276 if (BM_elem_flag_test_bool(ele, hflag) == value) {
277 count++;
278 }
279 }
280
281 return count;
282}
283
285 BMesh *bm, const char itype, void *data, const short oflag, const bool value)
286{
287 BMIter iter;
288 int count = 0;
289
290 /* loops have no header flags */
292
294 case BM_VERT: {
295 BMVert *ele;
296 BM_ITER_ELEM (ele, &iter, data, itype) {
297 if (BMO_vert_flag_test_bool(bm, ele, oflag) == value) {
298 count++;
299 }
300 }
301 break;
302 }
303 case BM_EDGE: {
304 BMEdge *ele;
305 BM_ITER_ELEM (ele, &iter, data, itype) {
306 if (BMO_edge_flag_test_bool(bm, ele, oflag) == value) {
307 count++;
308 }
309 }
310 break;
311 }
312 case BM_FACE: {
313 BMFace *ele;
314 BM_ITER_ELEM (ele, &iter, data, itype) {
315 if (BMO_face_flag_test_bool(bm, ele, oflag) == value) {
316 count++;
317 }
318 }
319 break;
320 }
321 }
322 return count;
323}
324
325int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
326{
327 BMIter iter;
328 BMElem *ele;
329 int count = 0;
330
331 BM_ITER_MESH (ele, &iter, bm, itype) {
332 if (BM_elem_flag_test_bool(ele, hflag) == value) {
333 count++;
334 }
335 }
336
337 return count;
338}
339
354/*
355 * VERT OF MESH CALLBACKS
356 */
357
358/* see bug #36923 for why we need this,
359 * allow adding but not removing, this isn't _totally_ safe since
360 * you could add/remove within the same loop, but catches common cases
361 */
362#ifndef NDEBUG
363# define USE_IMMUTABLE_ASSERT
364#endif
365
367{
368#ifdef USE_IMMUTABLE_ASSERT
369 ((BMIter *)iter)->count = BLI_mempool_len(iter->pooliter.pool);
370#endif
372}
373
375{
376#ifdef USE_IMMUTABLE_ASSERT
377 BLI_assert(((BMIter *)iter)->count <= BLI_mempool_len(iter->pooliter.pool));
378#endif
379 return BLI_mempool_iterstep(&iter->pooliter);
380}
381
382#ifdef USE_IMMUTABLE_ASSERT
383# undef USE_IMMUTABLE_ASSERT
384#endif
385
386/*
387 * EDGE OF VERT CALLBACKS
388 */
389
391{
392 if (iter->vdata->e) {
393 iter->e_first = iter->vdata->e;
394 iter->e_next = iter->vdata->e;
395 }
396 else {
397 iter->e_first = nullptr;
398 iter->e_next = nullptr;
399 }
400}
401
403{
404 BMEdge *e_curr = iter->e_next;
405
406 if (iter->e_next) {
407 iter->e_next = bmesh_disk_edge_next(iter->e_next, iter->vdata);
408 if (iter->e_next == iter->e_first) {
409 iter->e_next = nullptr;
410 }
411 }
412
413 return e_curr;
414}
415
416/*
417 * FACE OF VERT CALLBACKS
418 */
419
421{
422 ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
423 if (((BMIter *)iter)->count) {
424 iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
425 iter->e_first = iter->l_first->e;
426 iter->e_next = iter->e_first;
427 iter->l_next = iter->l_first;
428 }
429 else {
430 iter->l_first = iter->l_next = nullptr;
431 iter->e_first = iter->e_next = nullptr;
432 }
433}
435{
436 BMLoop *l_curr = iter->l_next;
437
438 if (((BMIter *)iter)->count && iter->l_next) {
439 ((BMIter *)iter)->count--;
441 if (iter->l_next == iter->l_first) {
442 iter->e_next = bmesh_disk_faceedge_find_next(iter->e_next, iter->vdata);
444 iter->l_next = iter->l_first;
445 }
446 }
447
448 if (!((BMIter *)iter)->count) {
449 iter->l_next = nullptr;
450 }
451
452 return l_curr ? l_curr->f : nullptr;
453}
454
455/*
456 * LOOP OF VERT CALLBACKS
457 */
458
460{
461 ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
462 if (((BMIter *)iter)->count) {
463 iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
464 iter->e_first = iter->l_first->e;
465 iter->e_next = iter->e_first;
466 iter->l_next = iter->l_first;
467 }
468 else {
469 iter->l_first = iter->l_next = nullptr;
470 iter->e_first = iter->e_next = nullptr;
471 }
472}
474{
475 BMLoop *l_curr = iter->l_next;
476
477 if (((BMIter *)iter)->count) {
478 ((BMIter *)iter)->count--;
480 if (iter->l_next == iter->l_first) {
481 iter->e_next = bmesh_disk_faceedge_find_next(iter->e_next, iter->vdata);
483 iter->l_next = iter->l_first;
484 }
485 }
486
487 if (!((BMIter *)iter)->count) {
488 iter->l_next = nullptr;
489 }
490
491 /* nullptr on finish */
492 return l_curr;
493}
494
495/*
496 * LOOP OF EDGE CALLBACKS
497 */
498
500{
501 iter->l_first = iter->l_next = iter->edata->l;
502}
503
505{
506 BMLoop *l_curr = iter->l_next;
507
508 if (iter->l_next) {
509 iter->l_next = iter->l_next->radial_next;
510 if (iter->l_next == iter->l_first) {
511 iter->l_next = nullptr;
512 }
513 }
514
515 /* nullptr on finish */
516 return l_curr;
517}
518
519/*
520 * LOOP OF LOOP CALLBACKS
521 */
522
524{
525 iter->l_first = iter->ldata;
526 iter->l_next = iter->l_first->radial_next;
527
528 if (iter->l_next == iter->l_first) {
529 iter->l_next = nullptr;
530 }
531}
532
534{
535 BMLoop *l_curr = iter->l_next;
536
537 if (iter->l_next) {
538 iter->l_next = iter->l_next->radial_next;
539 if (iter->l_next == iter->l_first) {
540 iter->l_next = nullptr;
541 }
542 }
543
544 /* nullptr on finish */
545 return l_curr;
546}
547
548/*
549 * FACE OF EDGE CALLBACKS
550 */
551
553{
554 iter->l_first = iter->l_next = iter->edata->l;
555}
556
558{
559 BMLoop *current = iter->l_next;
560
561 if (iter->l_next) {
562 iter->l_next = iter->l_next->radial_next;
563 if (iter->l_next == iter->l_first) {
564 iter->l_next = nullptr;
565 }
566 }
567
568 return current ? current->f : nullptr;
569}
570
571/*
572 * VERTS OF EDGE CALLBACKS
573 */
574
576{
577 ((BMIter *)iter)->count = 0;
578}
579
581{
582 switch (((BMIter *)iter)->count++) {
583 case 0:
584 return iter->edata->v1;
585 case 1:
586 return iter->edata->v2;
587 default:
588 return nullptr;
589 }
590}
591
592/*
593 * VERT OF FACE CALLBACKS
594 */
595
600
602{
603 BMLoop *l_curr = iter->l_next;
604
605 if (iter->l_next) {
606 iter->l_next = iter->l_next->next;
607 if (iter->l_next == iter->l_first) {
608 iter->l_next = nullptr;
609 }
610 }
611
612 return l_curr ? l_curr->v : nullptr;
613}
614
615/*
616 * EDGE OF FACE CALLBACKS
617 */
618
623
625{
626 BMLoop *l_curr = iter->l_next;
627
628 if (iter->l_next) {
629 iter->l_next = iter->l_next->next;
630 if (iter->l_next == iter->l_first) {
631 iter->l_next = nullptr;
632 }
633 }
634
635 return l_curr ? l_curr->e : nullptr;
636}
637
638/*
639 * LOOP OF FACE CALLBACKS
640 */
641
646
648{
649 BMLoop *l_curr = iter->l_next;
650
651 if (iter->l_next) {
652 iter->l_next = iter->l_next->next;
653 if (iter->l_next == iter->l_first) {
654 iter->l_next = nullptr;
655 }
656 }
657
658 return l_curr;
659}
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL()
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1)
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
@ BM_LOOP
#define BM_FACE_FIRST_LOOP(p)
#define BM_elem_flag_test_bool(ele, hflag)
int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data, const short oflag, const bool value)
Elem Iter Tool Flag Count.
void * BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
void * bmiter__elem_of_mesh_step(BMIter__elem_of_mesh *iter)
void * bmiter__vert_of_edge_step(BMIter__vert_of_edge *iter)
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask, void **array, const int len)
Operator Iterator as Array.
void bmiter__edge_of_face_begin(BMIter__edge_of_face *iter)
void * BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask, int *r_len, void **stack_array, int stack_array_size)
const char bm_iter_itype_htype_map[BM_ITYPE_MAX]
void * bmiter__face_of_vert_step(BMIter__face_of_vert *iter)
void bmiter__face_of_vert_begin(BMIter__face_of_vert *iter)
void * bmiter__loop_of_face_step(BMIter__loop_of_face *iter)
void bmiter__loop_of_edge_begin(BMIter__loop_of_edge *iter)
void bmiter__face_of_edge_begin(BMIter__face_of_edge *iter)
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm, blender::MutableBitSpan bitmap, bool(*test_fn)(BMFace *, void *user_data), void *user_data)
void bmiter__loop_of_face_begin(BMIter__loop_of_face *iter)
void * bmiter__edge_of_face_step(BMIter__edge_of_face *iter)
void bmiter__edge_of_vert_begin(BMIter__edge_of_vert *iter)
void bmiter__elem_of_mesh_begin(BMIter__elem_of_mesh *iter)
void * BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len, void **stack_array, int stack_array_size)
Iterator as Array.
void * bmiter__face_of_edge_step(BMIter__face_of_edge *iter)
void * bmiter__loop_of_edge_step(BMIter__loop_of_edge *iter)
void bmiter__vert_of_face_begin(BMIter__vert_of_face *iter)
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
Mesh Iter Flag Count.
void * bmiter__loop_of_vert_step(BMIter__loop_of_vert *iter)
int BM_iter_mesh_bitmap_from_filter(const char itype, BMesh *bm, blender::MutableBitSpan bitmap, bool(*test_fn)(BMElem *, void *user_data), void *user_data)
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
Iterator as Array.
void * bmiter__loop_of_loop_step(BMIter__loop_of_loop *iter)
void bmiter__loop_of_loop_begin(BMIter__loop_of_loop *iter)
int BM_iter_mesh_count(const char itype, BMesh *bm)
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
Elem Iter Flag Count.
void * bmiter__vert_of_face_step(BMIter__vert_of_face *iter)
void * bmiter__edge_of_vert_step(BMIter__edge_of_vert *iter)
void bmiter__loop_of_vert_begin(BMIter__loop_of_vert *iter)
void bmiter__vert_of_edge_begin(BMIter__vert_of_edge *iter)
#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)
#define BM_iter_init(iter, bm, itype, data)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
#define BM_iter_new(iter, bm, itype, data)
#define BM_ITYPE_MAX
ATTR_WARN_UNUSED_RESULT BMesh const char itype
ATTR_WARN_UNUSED_RESULT BMesh * bm
#define BM_FACE
#define BM_EDGE
#define BM_VERT
#define BMO_edge_flag_test_bool(bm, e, oflag)
#define BMO_face_flag_test_bool(bm, e, oflag)
void * BMO_iter_new(BMOIter *iter, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char restrictmask)
New Iterator.
#define BMO_OP_MAX_SLOTS
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_vert_flag_test_bool(bm, e, oflag)
void * BMO_iter_step(BMOIter *iter)
ATTR_WARN_UNUSED_RESULT const BMFlagLayer const short oflag
BMLoop * bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
BMLoop * bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v)
BME RADIAL FIND FIRST FACE VERT.
BMLoop * bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v)
int bmesh_disk_facevert_count(const BMVert *v)
DISK COUNT FACE VERT.
BMEdge * bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v)
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int len
int count
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
BLI_mempool * pool
Definition BLI_mempool.h:79
BMVert * v1
BMVert * v2
struct BMLoop * l
BLI_mempool_iter pooliter
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMFace * f
struct BMLoop * next
struct BMEdge * e
int totvert
int totedge
int totface