diff options
author | Campbell Barton <ideasman42@gmail.com> | 2013-07-22 18:50:38 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2013-07-22 18:50:38 +0400 |
commit | 57ce6d1470907b283742f45d369b4fe6edcee361 (patch) | |
tree | f0a0cdf436b57dd09020a48cb9fe7a599d353499 /source/blender/bmesh | |
parent | 9634f8f1151740609230c24761ac20fdfe1a9168 (diff) |
old todo, rotate around individual origins now supports connected face/edge islands.
previously this gave very odd/annoying results, see bug reports [#36134], [#35419]
Diffstat (limited to 'source/blender/bmesh')
-rw-r--r-- | source/blender/bmesh/intern/bmesh_queries.c | 205 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_queries.h | 9 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_normals.c | 7 |
3 files changed, 189 insertions, 32 deletions
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 720997fcef8..8f5e25f5fd7 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -1758,20 +1758,27 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed) return vol; } - +/* note, almost duplicate of BM_mesh_calc_edge_groups, keep in sync */ /** - * TODO (as we need) - * - option to walk over faces by verts. - * - option to walk over non manifold edges. + * Calculate isolated groups of faces with optional filtering. * * \param bm the BMesh. - * \param r_groups_array Array of ints to fill in, length of bm->totface. + * \param r_groups_array Array of ints to fill in, length of bm->totface + * (or when hflag_test is set, the number of flagged faces). * \param r_group_index index, length pairs into \a r_groups_array, size of return value - * int pairs: (array_start, array_length). + * int pairs: (array_start, array_length). + * \param filter_fn Filter the edges or verts we step over (depends on \a htype_step) + * as to which types we deal with. + * \param user_data Optional user data for \a filter_fn, can be NULL. + * \param hflag_test Optional flag to test faces, + * use to exclude faces from the calculation, 0 for all faces. + * \param htype_step BM_VERT to walk over face-verts, BM_EDGE to walk over faces edges + * (having both set is supported too). * \return The number of groups found. */ int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2], - bool (*filter_fn)(BMElem *, void *user_data), void *user_data, const char htype) + BMElemFilterFunc filter_fn, void *user_data, + const char hflag_test, const char htype_step) { #ifdef DEBUG int group_index_len = 1; @@ -1786,11 +1793,11 @@ int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde int group_curr = 0; - const unsigned int tot_faces = bm->totface; + unsigned int tot_faces = 0; unsigned int tot_touch = 0; - BMFace **fstack; - STACK_DECLARE(fstack); + BMFace **stack; + STACK_DECLARE(stack); BMIter iter; BMFace *f; @@ -1798,30 +1805,38 @@ int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde STACK_INIT(group_array); - BLI_assert(((htype & ~(BM_VERT | BM_EDGE)) == 0) && (htype != 0)); + BLI_assert(((htype_step & ~(BM_VERT | BM_EDGE)) == 0) && (htype_step != 0)); /* init the array */ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { + if ((hflag_test == 0) || BM_elem_flag_test(f, hflag_test)) { + tot_faces++; + BM_elem_flag_disable(f, BM_ELEM_TAG); + } + else { + /* never walk over tagged */ + BM_elem_flag_enable(f, BM_ELEM_TAG); + } + BM_elem_index_set(f, i); /* set_inline */ - BM_elem_flag_disable(f, BM_ELEM_TAG); } bm->elem_index_dirty &= ~BM_FACE; /* detect groups */ - fstack = MEM_mallocN(sizeof(*fstack) * tot_faces, __func__); + stack = MEM_mallocN(sizeof(*stack) * tot_faces, __func__); while (tot_touch != tot_faces) { - int *fg; + int *group_item; bool ok = false; BLI_assert(tot_touch < tot_faces); - STACK_INIT(fstack); + STACK_INIT(stack); BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(f, BM_ELEM_TAG) == false) { BM_elem_flag_enable(f, BM_ELEM_TAG); - STACK_PUSH(fstack, f); + STACK_PUSH(stack, f); ok = true; break; } @@ -1835,48 +1850,50 @@ int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_index_len); } - fg = group_index[group_curr]; - fg[0] = STACK_SIZE(group_array); - fg[1] = 0; + group_item = group_index[group_curr]; + group_item[0] = STACK_SIZE(group_array); + group_item[1] = 0; - while ((f = STACK_POP(fstack))) { + while ((f = STACK_POP(stack))) { BMLoop *l_iter, *l_first; /* add face */ STACK_PUSH(group_array, BM_elem_index_get(f)); tot_touch++; - fg[1]++; + group_item[1]++; /* done */ - if (htype & BM_EDGE) { + if (htype_step & BM_EDGE) { /* search for other faces */ l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { BMLoop *l_radial_iter = l_iter->radial_next; - if ((l_radial_iter != l_iter) && filter_fn((BMElem *)l_iter->e, user_data)) { + if ((l_radial_iter != l_iter) && + ((filter_fn == NULL) || filter_fn((BMElem *)l_iter->e, user_data))) + { do { BMFace *f_other = l_radial_iter->f; if (BM_elem_flag_test(f_other, BM_ELEM_TAG) == false) { BM_elem_flag_enable(f_other, BM_ELEM_TAG); - STACK_PUSH(fstack, f_other); + STACK_PUSH(stack, f_other); } } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); } } while ((l_iter = l_iter->next) != l_first); } - if (htype & BM_VERT) { + if (htype_step & BM_VERT) { BMIter liter; /* search for other faces */ l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - if (filter_fn((BMElem *)l_iter->v, user_data)) { + if ((filter_fn == NULL) || filter_fn((BMElem *)l_iter->v, user_data)) { BMLoop *l_other; BM_ITER_ELEM (l_other, &liter, l_iter, BM_LOOPS_OF_LOOP) { BMFace *f_other = l_other->f; if (BM_elem_flag_test(f_other, BM_ELEM_TAG) == false) { BM_elem_flag_enable(f_other, BM_ELEM_TAG); - STACK_PUSH(fstack, f_other); + STACK_PUSH(stack, f_other); } } } @@ -1887,7 +1904,139 @@ int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde group_curr++; } - MEM_freeN(fstack); + MEM_freeN(stack); + + /* reduce alloc to required size */ + group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_curr); + *r_group_index = group_index; + + return group_curr; +} + +/* note, almost duplicate of BM_mesh_calc_face_groups, keep in sync */ +/** + * Calculate isolated groups of edges with optional filtering. + * + * \param bm the BMesh. + * \param r_groups_array Array of ints to fill in, length of bm->totedge + * (or when hflag_test is set, the number of flagged edges). + * \param r_group_index index, length pairs into \a r_groups_array, size of return value + * int pairs: (array_start, array_length). + * \param filter_fn Filter the edges or verts we step over (depends on \a htype_step) + * as to which types we deal with. + * \param user_data Optional user data for \a filter_fn, can be NULL. + * \param hflag_test Optional flag to test edges, + * use to exclude edges from the calculation, 0 for all edges. + * \return The number of groups found. + * + * \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument, + * since we always walk over verts. + */ +int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2], + BMElemFilterFunc filter_fn, void *user_data, + const char hflag_test) +{ +#ifdef DEBUG + int group_index_len = 1; +#else + int group_index_len = 32; +#endif + + int (*group_index)[2] = MEM_mallocN(sizeof(*group_index) * group_index_len, __func__); + + int *group_array = r_groups_array; + STACK_DECLARE(group_array); + + int group_curr = 0; + + unsigned int tot_edges = 0; + unsigned int tot_touch = 0; + + BMEdge **stack; + STACK_DECLARE(stack); + + BMIter iter; + BMEdge *e; + int i; + + STACK_INIT(group_array); + + /* init the array */ + BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { + if ((hflag_test == 0) || BM_elem_flag_test(e, hflag_test)) { + tot_edges++; + BM_elem_flag_disable(e, BM_ELEM_TAG); + } + else { + /* never walk over tagged */ + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + + BM_elem_index_set(e, i); /* set_inline */ + } + bm->elem_index_dirty &= ~BM_FACE; + + /* detect groups */ + stack = MEM_mallocN(sizeof(*stack) * tot_edges, __func__); + + while (tot_touch != tot_edges) { + int *group_item; + bool ok = false; + + BLI_assert(tot_touch < tot_edges); + + STACK_INIT(stack); + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + STACK_PUSH(stack, e); + ok = true; + break; + } + } + + BLI_assert(ok == true); + + /* manage arrays */ + if (group_index_len == group_curr) { + group_index_len *= 2; + group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_index_len); + } + + group_item = group_index[group_curr]; + group_item[0] = STACK_SIZE(group_array); + group_item[1] = 0; + + while ((e = STACK_POP(stack))) { + BMIter viter; + BMIter eiter; + BMVert *v; + + /* add edge */ + STACK_PUSH(group_array, BM_elem_index_get(e)); + tot_touch++; + group_item[1]++; + /* done */ + + /* search for other edges */ + BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { + if ((filter_fn == NULL) || filter_fn((BMElem *)v, user_data)) { + BMEdge *e_other; + BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_other, BM_ELEM_TAG) == false) { + BM_elem_flag_enable(e_other, BM_ELEM_TAG); + STACK_PUSH(stack, e_other); + } + } + } + } + } + + group_curr++; + } + + MEM_freeN(stack); /* reduce alloc to required size */ group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_curr); diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index f62de692778..23d89cf92fa 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -27,6 +27,8 @@ * \ingroup bmesh */ +typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data); + bool BM_vert_in_face(BMFace *f, BMVert *v); int BM_verts_in_face_count(BMFace *f, BMVert **varr, int len); bool BM_verts_in_face(BMFace *f, BMVert **varr, int len); @@ -115,8 +117,13 @@ bool BM_face_is_any_vert_flag_test(BMFace *f, const char hflag); bool BM_face_is_any_edge_flag_test(BMFace *f, const char hflag); float BM_mesh_calc_volume(BMesh *bm, bool is_signed); + int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2], - bool (*filter_fn)(BMElem *, void *user_data), void *user_data, const char htype); + BMElemFilterFunc filter_fn, void *user_data, + const char hflag_test, const char htype_step); +int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2], + BMElemFilterFunc filter_fn, void *user_data, + const char hflag_test); /* not really any good place to put this */ float bmesh_subd_falloff_calc(const int falloff, float val); diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c index 9d86e7ab275..025b8557331 100644 --- a/source/blender/bmesh/operators/bmo_normals.c +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -146,14 +146,15 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op) { - int *groups_array = MEM_mallocN(sizeof(groups_array) * bm->totface, __func__); + int *groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totface, __func__); int faces_len; BMFace **faces_arr = BM_iter_as_arrayN(bm, BM_FACES_OF_MESH, NULL, &faces_len, NULL, 0); - BMFace **faces_grp = MEM_mallocN(sizeof(faces_grp) * bm->totface, __func__); + BMFace **faces_grp = MEM_mallocN(sizeof(*faces_grp) * bm->totface, __func__); int (*group_index)[2]; const int group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index, - bmo_recalc_normal_edge_filter_cb, NULL, BM_EDGE); + bmo_recalc_normal_edge_filter_cb, NULL, + 0, BM_EDGE); int i; |