From 3ef27ec807bc89eed5b3a10ae9041c607ff4eacb Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 30 Apr 2015 05:52:48 +1000 Subject: BMesh: add BM_face_loop_separate_multi New utility function to handle splitting off multiple loops from a face at once. --- source/blender/bmesh/intern/bmesh_core.c | 145 +++++++++++++++++++++++++++++++ source/blender/bmesh/intern/bmesh_core.h | 2 + source/blender/bmesh/intern/bmesh_mods.c | 6 ++ source/blender/bmesh/intern/bmesh_mods.h | 2 + 4 files changed, 155 insertions(+) (limited to 'source/blender') diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index abeecf596ba..81cc9727965 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -2359,6 +2359,151 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep) return v_new; } +/** + * A version of #bmesh_urmv_loop that disconnects multiple loops at once. + * + * Handles the task of finding fans boundaris. + */ +BMVert *bmesh_urmv_loop_multi( + BMesh *bm, BMLoop **larr, int larr_len) +{ + BMVert *v_sep = larr[0]->v; + BMVert *v_new; + int i; + bool is_mixed_any = false; + + BLI_SMALLSTACK_DECLARE(edges, BMEdge *); + +#define LOOP_VISIT _FLAG_WALK +#define EDGE_VISIT _FLAG_WALK + + for (i = 0; i < larr_len; i++) { + BMLoop *l_sep = larr[i]; + + /* all must be from the same vert! */ + BLI_assert(v_sep == l_sep->v); + + BLI_assert(!BM_ELEM_API_FLAG_TEST(l_sep, LOOP_VISIT)); + BM_ELEM_API_FLAG_ENABLE(l_sep, LOOP_VISIT); + + /* weak! but it makes it simpler to check for edges to split + * while doing a radial loop (where loops may be adjacent) */ + BM_ELEM_API_FLAG_ENABLE(l_sep->next, LOOP_VISIT); + BM_ELEM_API_FLAG_ENABLE(l_sep->prev, LOOP_VISIT); + } + + for (i = 0; i < larr_len; i++) { + BMLoop *l_sep = larr[i]; + + BMLoop *loop_pair[2] = {l_sep, l_sep->prev}; + int j; + for (j = 0; j < ARRAY_SIZE(loop_pair); j++) { + BMEdge *e = loop_pair[j]->e; + if (!BM_ELEM_API_FLAG_TEST(e, EDGE_VISIT)) { + BMLoop *l_iter, *l_first; + bool is_mixed = false; + + BM_ELEM_API_FLAG_ENABLE(e, EDGE_VISIT); + + l_iter = l_first = e->l; + do { + if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) { + is_mixed = true; + is_mixed_any = true; + break; + } + } while ((l_iter = l_iter->radial_next) != l_first); + + if (is_mixed) { + /* ensure the first loop is one we don't own so we can do a quick check below + * on the edge's loop-flag to see if the edge is mixed or not. */ + e->l = l_iter; + } + BLI_SMALLSTACK_PUSH(edges, e); + } + } + } + + if (is_mixed_any == false) { + /* all loops in 'larr' are the soul owners of their edges. + * nothing to split away from, this is a no-op */ + v_new = v_sep; + } + else { + BMEdge *e; + + BLI_assert(!BLI_SMALLSTACK_IS_EMPTY(edges)); + + v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP); + while ((e = BLI_SMALLSTACK_POP(edges))) { + BMLoop *l_iter, *l_first, *l_next; + BMEdge *e_new; + + /* disable so copied edge isn't left dirty (loop edges are cleared last too) */ + BM_ELEM_API_FLAG_DISABLE(e, EDGE_VISIT); + + if (!BM_ELEM_API_FLAG_TEST(e->l, LOOP_VISIT)) { + /* edge has some loops owned by us, some owned by other loops */ + BMVert *e_new_v_pair[2]; + + if (e->v1 == v_sep) { + e_new_v_pair[0] = v_new; + e_new_v_pair[1] = e->v2; + } + else { + BLI_assert(v_sep == e->v2); + e_new_v_pair[0] = e->v1; + e_new_v_pair[1] = v_new; + } + + e_new = BM_edge_create(bm, UNPACK2(e_new_v_pair), e, BM_CREATE_NOP); + + /* now moved all loops from 'larr' to this newly created edge */ + l_iter = l_first = e->l; + do { + l_next = l_iter->radial_next; + if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) { + bmesh_radial_loop_remove(l_iter, e); + bmesh_radial_append(e_new, l_iter); + l_iter->e = e_new; + } + } while ((l_iter = l_next) != l_first); + } + else { + /* we own the edge entirely, replace the vert */ + bmesh_disk_edge_remove(e, v_sep); + bmesh_disk_vert_swap(e, v_new, v_sep); + bmesh_disk_edge_append(e, v_new); + } + + /* loop vert is handled last! */ + } + } + + for (i = 0; i < larr_len; i++) { + BMLoop *l_sep = larr[i]; + + l_sep->v = v_new; + + BLI_assert(BM_ELEM_API_FLAG_TEST(l_sep, LOOP_VISIT)); + BLI_assert(BM_ELEM_API_FLAG_TEST(l_sep->prev, LOOP_VISIT)); + BLI_assert(BM_ELEM_API_FLAG_TEST(l_sep->next, LOOP_VISIT)); + BM_ELEM_API_FLAG_DISABLE(l_sep, LOOP_VISIT); + BM_ELEM_API_FLAG_DISABLE(l_sep->prev, LOOP_VISIT); + BM_ELEM_API_FLAG_DISABLE(l_sep->next, LOOP_VISIT); + + + BM_ELEM_API_FLAG_DISABLE(l_sep->prev->e, EDGE_VISIT); + BM_ELEM_API_FLAG_DISABLE(l_sep->e, EDGE_VISIT); + } + +#undef LOOP_VISIT +#undef EDGE_VISIT + + return v_new; +} + + /** * \brief Unglue Region Make Vert (URMV) * diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h index 55bc6a62a88..85dd1de0ef5 100644 --- a/source/blender/bmesh/intern/bmesh_core.h +++ b/source/blender/bmesh/intern/bmesh_core.h @@ -99,6 +99,8 @@ BMEdge *bmesh_jekv( BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e); BMVert *bmesh_urmv(BMesh *bm, BMFace *f_sep, BMVert *v_sep); BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep); +BMVert *bmesh_urmv_loop_multi( + BMesh *bm, BMLoop **larr, int larr_len); void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b); diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index ab6d21de7e8..5891876c22c 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -1650,3 +1650,9 @@ BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl) { return bmesh_urmv_loop(bm, sl); } + +BMVert *BM_face_loop_separate_multi( + BMesh *bm, BMLoop **larr, int larr_len) +{ + return bmesh_urmv_loop_multi(bm, larr, larr_len); +} diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h index 2ef836a14a5..1b826b1e0b2 100644 --- a/source/blender/bmesh/intern/bmesh_mods.h +++ b/source/blender/bmesh/intern/bmesh_mods.h @@ -89,5 +89,7 @@ enum { BMVert *BM_face_vert_separate(BMesh *bm, BMFace *sf, BMVert *sv); BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl); +BMVert *BM_face_loop_separate_multi( + BMesh *bm, BMLoop **larr, int larr_len); #endif /* __BMESH_MODS_H__ */ -- cgit v1.2.3