diff options
author | Campbell Barton <ideasman42@gmail.com> | 2013-12-24 04:04:03 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2013-12-24 04:13:58 +0400 |
commit | 04a902965e5e226e69c5c6e912dd2f513448d2ac (patch) | |
tree | c65a2c9613f5a336f6c2739b5dabc5fbad348230 /source/blender | |
parent | d94db03ac8ef9f6a10e42f01d622421fe3f216bb (diff) |
BMesh optimize face splitting by taking loops rather then verts
- add BM_vert_pair_share_face
- add BM_loop_is_adjacent
- remove BM_verts_connect
Diffstat (limited to 'source/blender')
20 files changed, 232 insertions, 180 deletions
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index cbaffe2da1a..7b3ca898718 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -1258,7 +1258,7 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *UNUSED(example)) * * \return A BMFace pointer */ -BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, +BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2, BMLoop **r_l, #ifdef USE_BMESH_HOLES ListBase *holes, @@ -1275,21 +1275,12 @@ BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMFace *f2; BMLoop *l_iter, *l_first; - BMLoop *l_v1 = NULL, *l_v2 = NULL, *l_f1 = NULL, *l_f2 = NULL; + BMLoop *l_f1 = NULL, *l_f2 = NULL; BMEdge *e; - int i, len, f1len, f2len; + BMVert *v1 = l_v1->v, *v2 = l_v2->v; + int f1len, f2len; - /* verify that v1 and v2 are in face */ - len = f->len; - for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < len; i++, l_iter = l_iter->next) { - if (l_iter->v == v1) l_v1 = l_iter; - else if (l_iter->v == v2) l_v2 = l_iter; - } - - if (!l_v1 || !l_v2) { - BLI_assert(0); - return NULL; - } + BLI_assert(f == l_v1->f && f == l_v2->f); /* allocate new edge between v1 and v2 */ e = BM_edge_create(bm, v1, v2, example, no_double ? BM_CREATE_NO_DOUBLE : BM_CREATE_NOP); diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h index e9fd4e650cb..654698da3c6 100644 --- a/source/blender/bmesh/intern/bmesh_core.h +++ b/source/blender/bmesh/intern/bmesh_core.h @@ -72,14 +72,15 @@ void BM_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len BMEdge **e_in, int e_in_len); /* EULER API - For modifying structure */ -BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, - BMVert *v2, BMLoop **r_l, +BMFace *bmesh_sfme(BMesh *bm, BMFace *f, + BMLoop *l1, BMLoop *l2, + BMLoop **r_l, #ifdef USE_BMESH_HOLES - ListBase *holes, + ListBase *holes, #endif - BMEdge *example, - const bool no_double - ); + BMEdge *example, + const bool no_double + ); BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e); BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool check_edge_splice); diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 49c8c987956..6d8dc531a32 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -252,48 +252,6 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const } /** - * \brief Connect Verts, Split Face - * - * connects two verts together, automatically (if very naively) finding the - * face they both share (if there is one) and splitting it. Use this at your - * own risk, as it doesn't handle the many complex cases it should (like zero-area faces, - * multiple faces, etc). - * - * this is really only meant for cases where you don't know before hand the face - * the two verts belong to for splitting (e.g. the subdivision operator). - * - * \return The newly created edge. - */ -BMEdge *BM_verts_connect(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **r_f) -{ - BMIter fiter; - BMIter viter; - BMVert *v_iter; - BMFace *f_iter; - - /* be warned: this can do weird things in some ngon situation, see BM_face_legal_splits */ - BM_ITER_ELEM (f_iter, &fiter, v1, BM_FACES_OF_VERT) { - BM_ITER_ELEM (v_iter, &viter, f_iter, BM_FACES_OF_VERT) { - if (v_iter == v2) { - BMLoop *l_new; - - f_iter = BM_face_split(bm, f_iter, v1, v2, &l_new, NULL, false); - - if (r_f) { - *r_f = f_iter; - } - return l_new->e; - } - } - } - - if (r_f) { - *r_f = NULL; - } - return NULL; -} - -/** * \brief Face Split * * Split a face along two vertices. returns the newly made face, and sets @@ -310,13 +268,26 @@ BMEdge *BM_verts_connect(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **r_f) * if the split is successful (and the original original face will be the * other side). NULL if the split fails. */ -BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l, - BMEdge *example, const bool no_double) +BMFace *BM_face_split(BMesh *bm, BMFace *f, + BMLoop *l_a, BMLoop *l_b, + BMLoop **r_l, BMEdge *example, + const bool no_double) { const bool has_mdisp = CustomData_has_layer(&bm->ldata, CD_MDISPS); BMFace *f_new, *f_tmp; - BLI_assert(v1 != v2); + BLI_assert(l_a != l_b); + BLI_assert(f == l_a->f && f == l_b->f); + BLI_assert(!BM_loop_is_adjacent(l_a, l_b)); + + /* could be an assert */ + if (UNLIKELY(BM_loop_is_adjacent(l_a, l_b))) { + return NULL; + } + + if (f != l_a->f || f != l_b->f) { + return NULL; + } /* do we have a multires layer? */ if (has_mdisp) { @@ -324,9 +295,9 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l } #ifdef USE_BMESH_HOLES - f_new = bmesh_sfme(bm, f, v1, v2, r_l, NULL, example, no_double); + f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, no_double); #else - f_new = bmesh_sfme(bm, f, v1, v2, r_l, example, no_double); + f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, no_double); #endif if (f_new) { @@ -369,7 +340,7 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l * * \param bm The bmesh * \param f the original face - * \param v1, v2 vertices which define the split edge, must be different + * \param l_a, l_b vertices which define the split edge, must be different * \param cos Array of coordinates for intermediate points * \param n Length of \a cos (must be > 0) * \param r_l pointer which will receive the BMLoop for the first split edge (from \a v1) in the new face @@ -379,16 +350,31 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l * if the split is successful (and the original original face will be the * other side). NULL if the split fails. */ -BMFace *BM_face_split_n(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, float cos[][3], int n, +BMFace *BM_face_split_n(BMesh *bm, BMFace *f, + BMLoop *l_a, BMLoop *l_b, + float cos[][3], int n, BMLoop **r_l, BMEdge *example) { BMFace *f_new, *f_tmp; BMLoop *l_dummy; BMEdge *e, *e_new; BMVert *v_new; + // BMVert *v_a = l_a->v; /* UNUSED */ + BMVert *v_b = l_b->v; int i, j; - BLI_assert(v1 != v2); + BLI_assert(l_a != l_b); + BLI_assert(f == l_a->f && f == l_b->f); + BLI_assert(!BM_loop_is_adjacent(l_a, l_b)); + + /* could be an assert */ + if (UNLIKELY(BM_loop_is_adjacent(l_a, l_b))) { + return NULL; + } + + if (l_a->f != l_b->f) { + return NULL; + } f_tmp = BM_face_copy(bm, bm, f, true, true); @@ -396,12 +382,12 @@ BMFace *BM_face_split_n(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, float cos[ r_l = &l_dummy; #ifdef USE_BMESH_HOLES - f_new = bmesh_sfme(bm, f, v1, v2, r_l, NULL, example, false); + f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, false); #else - f_new = bmesh_sfme(bm, f, v1, v2, r_l, example, false); + f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, false); #endif - /* bmesh_sfme returns in r_l a Loop for f_new going from v1 to v2. - * The radial_next is for f and goes from v2 to v1 */ + /* bmesh_sfme returns in r_l a Loop for f_new going from v_a to v_b. + * The radial_next is for f and goes from v_b to v_a */ if (f_new) { BM_elem_attrs_copy(bm, bm, f, f_new); @@ -409,7 +395,7 @@ BMFace *BM_face_split_n(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, float cos[ e = (*r_l)->e; for (i = 0; i < n; i++) { - v_new = bmesh_semv(bm, v2, e, &e_new); + v_new = bmesh_semv(bm, v_b, e, &e_new); BLI_assert(v_new != NULL); /* bmesh_semv returns in e_new the edge going from v_new to tv */ copy_v3_v3(v_new->co, cos[i]); @@ -510,8 +496,14 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float BMFace *f2 = BM_faces_join(bm, faces, BLI_array_count(faces), true); if (f2) { BMLoop *l_new = NULL; - if (BM_face_split(bm, f2, tv, tv2, &l_new, NULL, false)) { - e_new = l_new->e; + BMLoop *l_a, *l_b; + + if ((l_a = BM_face_vert_share_loop(f2, tv)) && + (l_b = BM_face_vert_share_loop(f2, tv2))) + { + if (BM_face_split(bm, f2, l_a, l_b, &l_new, NULL, false)) { + e_new = l_new->e; + } } } } @@ -1058,10 +1050,10 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f /* note, this assumes joining the faces _didnt_ also remove the verts. * the #BM_edge_rotate_check will ensure this, but its possibly corrupt state or future edits * break this */ - if (!BM_face_split(bm, f, v1, v2, NULL, NULL, true)) { - return NULL; - } - else { + if ((l1 = BM_face_vert_share_loop(f, v1)) && + (l2 = BM_face_vert_share_loop(f, v2)) && + BM_face_split(bm, f, l1, l2, NULL, NULL, true)) + { /* we should really be able to know the faces some other way, * rather then fetching them back from the edge, but this is predictable * where using the return values from face split isn't. - campbell */ @@ -1071,6 +1063,9 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f fb->head.hflag = f_hflag_prev_2; } } + else { + return NULL; + } return e_new; } diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h index ca281c13f21..f3ed99230d7 100644 --- a/source/blender/bmesh/intern/bmesh_mods.h +++ b/source/blender/bmesh/intern/bmesh_mods.h @@ -35,15 +35,13 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v); BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del); -BMEdge *BM_verts_connect(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **r_f); - BMFace *BM_face_split(BMesh *bm, BMFace *f, - BMVert *v1, BMVert *v2, + BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, const bool no_double); BMFace *BM_face_split_n(BMesh *bm, BMFace *f, - BMVert *v1, BMVert *v2, + BMLoop *l_a, BMLoop *l_b, float cos[][3], int n, BMLoop **r_l, BMEdge *example); diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index 7a625840891..a3aaea9e257 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -800,67 +800,67 @@ void BM_face_triangulate(BMesh *bm, BMFace *f, BLI_assert((r_faces_new == NULL) == (r_faces_new_tot == NULL)); if (f->len == 4) { - BMVert *v1, *v2; + BMLoop *l_v1, *l_v2; l_first = BM_FACE_FIRST_LOOP(f); switch (quad_method) { case MOD_TRIANGULATE_QUAD_FIXED: { - v1 = l_first->v; - v2 = l_first->next->next->v; + l_v1 = l_first; + l_v2 = l_first->next->next; break; } case MOD_TRIANGULATE_QUAD_ALTERNATE: { - v1 = l_first->next->v; - v2 = l_first->prev->v; + l_v1 = l_first->next; + l_v2 = l_first->prev; break; } case MOD_TRIANGULATE_QUAD_SHORTEDGE: { - BMVert *v3, *v4; + BMLoop *l_v3, *l_v4; float d1, d2; - v1 = l_first->v; - v2 = l_first->next->next->v; - v3 = l_first->next->v; - v4 = l_first->prev->v; + l_v1 = l_first; + l_v2 = l_first->next->next; + l_v3 = l_first->next; + l_v4 = l_first->prev; - d1 = len_squared_v3v3(v1->co, v2->co); - d2 = len_squared_v3v3(v3->co, v4->co); + d1 = len_squared_v3v3(l_v1->v->co, l_v2->v->co); + d2 = len_squared_v3v3(l_v3->v->co, l_v4->v->co); if (d2 < d1) { - v1 = v3; - v2 = v4; + l_v1 = l_v3; + l_v2 = l_v4; } break; } case MOD_TRIANGULATE_QUAD_BEAUTY: default: { - BMVert *v3, *v4; + BMLoop *l_v3, *l_v4; float cost; - v1 = l_first->next->v; - v2 = l_first->next->next->v; - v3 = l_first->prev->v; - v4 = l_first->v; + l_v1 = l_first->next; + l_v2 = l_first->next->next; + l_v3 = l_first->prev; + l_v4 = l_first; - cost = BM_verts_calc_rotate_beauty(v1, v2, v3, v4, 0, 0); + cost = BM_verts_calc_rotate_beauty(l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0); if (cost < 0.0f) { - v1 = v4; - //v2 = v2; + l_v1 = l_v4; + //l_v2 = l_v2; } else { - //v1 = v1; - v2 = v3; + //l_v1 = l_v1; + l_v2 = l_v3; } break; } } - f_new = BM_face_split(bm, f, v1, v2, &l_new, NULL, false); + f_new = BM_face_split(bm, f, l_v1, l_v2, &l_new, NULL, false); copy_v3_v3(f_new->no, f->no); if (use_tag) { diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 16785778883..968ca5f3102 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -182,6 +182,37 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) } /** + * Given 2 verts, find the smallest face they share and give back both loops. + */ +BMFace *BM_vert_pair_share_face(BMVert *v_a, BMVert *v_b, + BMLoop **r_l_a, BMLoop **r_l_b) +{ + BMLoop *l_cur_a = NULL, *l_cur_b = NULL; + BMFace *f_cur = NULL; + + if (v_a->e && v_b->e) { + BMIter iter; + BMLoop *l_a, *l_b; + + BM_ITER_ELEM (l_a, &iter, v_a, BM_LOOPS_OF_VERT) { + if ((f_cur == NULL) || (l_a->f->len < f_cur->len)) { + l_b = BM_face_vert_share_loop(l_a->f, v_b); + if (l_b) { + f_cur = l_a->f; + l_cur_a = l_a; + l_cur_b = l_b; + } + } + } + } + + if (r_l_a) *r_l_a = l_cur_a; + if (r_l_b) *r_l_b = l_cur_b; + + return f_cur; +} + +/** * Get the first loop of a vert. Uses the same initialization code for the first loop of the * iterator API */ diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 17c14310191..d4b6cd0e061 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -49,6 +49,8 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v); BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v); BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step); BMLoop *BM_vert_find_first_loop(BMVert *v); +BMFace *BM_vert_pair_share_face(BMVert *v_a, BMVert *v_b, + BMLoop **r_l_a, BMLoop **r_l_b); int BM_vert_edge_count_nonwire(BMVert *v); int BM_vert_edge_count(BMVert *v); @@ -67,6 +69,7 @@ BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e); bool BM_edge_is_convex(const BMEdge *e); bool BM_loop_is_convex(const BMLoop *l); +BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b); float BM_loop_calc_face_angle(BMLoop *l); void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3]); diff --git a/source/blender/bmesh/intern/bmesh_queries_inline.h b/source/blender/bmesh/intern/bmesh_queries_inline.h index c3ee363f247..a2a0a15faad 100644 --- a/source/blender/bmesh/intern/bmesh_queries_inline.h +++ b/source/blender/bmesh/intern/bmesh_queries_inline.h @@ -127,5 +127,14 @@ BLI_INLINE int BM_edge_is_boundary(BMEdge *e) } #endif +/** + * Tests whether one loop is next to another within the same face. + */ +BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) +{ + BLI_assert(l_a->f == l_b->f); + BLI_assert(l_a != l_b); + return (ELEM(l_b, l_a->next, l_a->prev)); +} #endif /* __BMESH_QUERIES_INLINE_H__ */ diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index d0f64eb2892..3d2c8c3d020 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -63,7 +63,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f) continue; } - if (l_last != l->prev && l_last != l->next) { + if (!BM_loop_is_adjacent(l_last, l)) { BMLoop **l_pair = STACK_PUSH_RET(loops_split); l_pair[0] = l_last; l_pair[1] = l; @@ -96,7 +96,17 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f) } for (i = 0; i < STACK_SIZE(verts_pair); i++) { - f_new = BM_face_split(bm, f, verts_pair[i][0], verts_pair[i][1], &l_new, NULL, false); + BMLoop *l_a, *l_b; + + if ((l_a = BM_face_vert_share_loop(f, verts_pair[i][0])) && + (l_b = BM_face_vert_share_loop(f, verts_pair[i][1]))) + { + f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false); + } + else { + f_new = NULL; + } + f = f_new; if (!l_new || !f_new) { diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c index bd7a625406c..334647fc68c 100644 --- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c +++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c @@ -86,7 +86,7 @@ static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const f return delta_z; } -static bool bm_face_split_find(BMFace *f, BMVert *v_pair[2], float *r_angle) +static bool bm_face_split_find(BMFace *f, BMLoop *l_pair[2], float *r_angle) { BMLoop *l_iter, *l_first; BMLoop **l_arr = BLI_array_alloca(l_arr, f->len); @@ -111,9 +111,7 @@ static bool bm_face_split_find(BMFace *f, BMVert *v_pair[2], float *r_angle) BMLoop *l_b = l_arr[i_b]; /* check these are not touching * (we could be smarter here) */ - if ((l_a->next != l_b) && - (l_a->prev != l_b)) - { + if (!BM_loop_is_adjacent(l_a, l_b)) { /* first calculate normals */ float no_a[3], no_b[3]; @@ -130,8 +128,8 @@ static bool bm_face_split_find(BMFace *f, BMVert *v_pair[2], float *r_angle) BM_face_legal_splits(f, &l_split, 1); if (l_split[0]) { err_best = err_test; - v_pair[0] = l_a->v; - v_pair[1] = l_b->v; + l_pair[0] = l_a; + l_pair[1] = l_b; angle_best = angle_normalized_v3v3(no_a, no_b); found = true; @@ -151,13 +149,14 @@ static bool bm_face_split_find(BMFace *f, BMVert *v_pair[2], float *r_angle) static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit) { - BMVert *v_pair[2]; + BMLoop *l_pair[2]; float angle; - if (bm_face_split_find(f, v_pair, &angle) && (angle > angle_limit)) { + if (bm_face_split_find(f, l_pair, &angle) && (angle > angle_limit)) { BMFace *f_new; BMLoop *l_new; - f_new = BM_face_split(bm, f, v_pair[0], v_pair[1], &l_new, NULL, false); + + f_new = BM_face_split(bm, f, l_pair[0], l_pair[1], &l_new, NULL, false); if (f_new) { r_f_pair[0] = f; r_f_pair[1] = f_new; diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index ae645b97874..60b96e35057 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -99,7 +99,7 @@ static void bm_face_split(BMesh *bm, const short oflag) if (BMO_elem_flag_test(bm, l->next->v, oflag) == 0 && BMO_elem_flag_test(bm, l->prev->v, oflag) == 0) { - BM_face_split(bm, l->f, l->next->v, l->prev->v, NULL, NULL, true); + BM_face_split(bm, l->f, l->next, l->prev, NULL, NULL, true); } } } diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index cc5a635092a..8eb94b9a743 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -40,30 +40,32 @@ static void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op, BMOpSlot *slot_targetmap) { BMIter liter; - BMLoop *l; - BMVert *v2, *v_double; + BMLoop *l, *l_tar, *l_double; bool split = false; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - v2 = BMO_slot_map_elem_get(slot_targetmap, l->v); - /* ok: if v2 is NULL (e.g. not in the map) then it's + BMVert *v_tar = BMO_slot_map_elem_get(slot_targetmap, l->v); + /* ok: if v_tar is NULL (e.g. not in the map) then it's * a target vert, otherwise it's a double */ - if ((v2 && BM_vert_in_face(f, v2)) && - (v2 != l->prev->v) && - (v2 != l->next->v)) - { - v_double = l->v; - split = true; - break; + if (v_tar) { + BMLoop *l_tar = BM_face_vert_share_loop(f, v_tar); + + if (l_tar && (l_tar != l) && !BM_loop_is_adjacent(l_tar, l)) { + l_double = l; + split = true; + break; + } } } - if (split && v_double != v2) { + if (split) { BMLoop *l_new; - BMFace *f2 = BM_face_split(bm, f, v_double, v2, &l_new, NULL, false); + BMFace *f_new; - remdoubles_splitface(f, bm, op, slot_targetmap); - remdoubles_splitface(f2, bm, op, slot_targetmap); + f_new = BM_face_split(bm, f, l_double, l_tar, &l_new, NULL, false); + + remdoubles_splitface(f, bm, op, slot_targetmap); + remdoubles_splitface(f_new, bm, op, slot_targetmap); } } diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c index b3b9cecf389..723595771a1 100644 --- a/source/blender/bmesh/operators/bmo_subdivide.c +++ b/source/blender/bmesh/operators/bmo_subdivide.c @@ -133,28 +133,23 @@ typedef struct SubDPattern { /* connects face with smallest len, which I think should always be correct for * edge subdivision */ -static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **r_f_new) +static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace **r_f_new) { - BMIter iter, iter2; - BMVert *v; BMLoop *l_new; - BMFace *f, *f_cur = NULL; + BMLoop *l_a, *l_b; + BMFace *f; /* this isn't the best thing in the world. it doesn't handle cases where there's * multiple faces yet. that might require a convexity test to figure out which * face is "best" and who knows what for non-manifold conditions. */ - for (f = BM_iter_new(&iter, bm, BM_FACES_OF_VERT, v1); f; f = BM_iter_step(&iter)) { - for (v = BM_iter_new(&iter2, bm, BM_VERTS_OF_FACE, f); v; v = BM_iter_step(&iter2)) { - if (v == v2) { - if (!f_cur || f->len < f_cur->len) f_cur = f; - } - } - } + f = BM_vert_pair_share_face(v_a, v_b, &l_a, &l_b); + + if (f) { + BMFace *f_new; - if (f_cur) { - f = BM_face_split(bm, f_cur, v1, v2, &l_new, NULL, false); + f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false); - if (r_f_new) *r_f_new = f; + if (r_f_new) *r_f_new = f_new; return l_new ? l_new->e : NULL; } @@ -1118,7 +1113,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) if (loops_split[j][0]) { BMFace *f_new; BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL); - f_new = BM_face_split(bm, face, loops_split[j][0]->v, loops_split[j][1]->v, &l_new, NULL, false); + f_new = BM_face_split(bm, face, loops_split[j][0], loops_split[j][1], &l_new, NULL, false); if (f_new) { BMO_elem_flag_enable(bm, l_new->e, ELE_INNER); } diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index d1ec06c5486..182bf0518ef 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -828,7 +828,7 @@ static void bm_face_slice(BMesh *bm, BMLoop *l, const int cuts) for (i = 0; i < cuts; i++) { /* no chance of double */ - BM_face_split(bm, l_new->f, l_new->prev->v, l_new->next->next->v, &l_new, NULL, false); + BM_face_split(bm, l_new->f, l_new->prev, l_new->next->next, &l_new, NULL, false); if (l_new->f->len < l_new->radial_next->f->len) { l_new = l_new->radial_next; } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 7f39cbee2c5..b10f162f2b0 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -2095,7 +2095,7 @@ static void bevel_build_trifan(BMesh *bm, BevVert *bv) BMLoop *l_new; BMFace *f_new; BLI_assert(v_fan == l_fan->v); - f_new = BM_face_split(bm, f, l_fan->v, l_fan->next->next->v, &l_new, NULL, FALSE); + f_new = BM_face_split(bm, f, l_fan, l_fan->next->next, &l_new, NULL, FALSE); if (f_new->len > f->len) { f = f_new; @@ -2140,7 +2140,7 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) l_b = l_b->next; } else { - BM_face_split(bm, f, l_a->v, l_b->v, &l_new, NULL, FALSE); + BM_face_split(bm, f, l_a, l_b, &l_new, NULL, FALSE); f = l_new->f; /* walk around the new face to get the next verts to split */ diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c index 6aeb26435ac..7001cfa4061 100644 --- a/source/blender/bmesh/tools/bmesh_bisect_plane.c +++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c @@ -139,9 +139,14 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con BMLoop *l_new; if (LIKELY(STACK_SIZE(vert_split_arr) == 2)) { + BMLoop *l_a, *l_b; + + l_a = BM_face_vert_share_loop(f, vert_split_arr[0]); + l_b = BM_face_vert_share_loop(f, vert_split_arr[1]); + /* common case, just cut the face once */ l_new = NULL; - BM_face_split(bm, f, vert_split_arr[0], vert_split_arr[1], &l_new, NULL, true); + BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true); if (l_new) { if (oflag_center) { BMO_elem_flag_enable(bm, l_new->e, oflag_center); @@ -254,9 +259,9 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con /* in fact this simple test is good enough, * test if the loops are adjacent */ - if (found && (l_a->next != l_b && l_a->prev != l_b)) { + if (found && !BM_loop_is_adjacent(l_a, l_b)) { BMFace *f_tmp; - f_tmp = BM_face_split(bm, face_split_arr[j], l_a->v, l_b->v, NULL, NULL, true); + f_tmp = BM_face_split(bm, face_split_arr[j], l_a, l_b, NULL, NULL, true); if (f_tmp) { if (f_tmp != face_split_arr[j]) { STACK_PUSH(face_split_arr, f_tmp); diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index 3ee238ad54f..292978cd247 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -358,7 +358,7 @@ static bool bm_decim_triangulate_begin(BMesh *bm) * - if there is a quad that has a free standing edge joining it along * where we want to split the face, there isnt a good way we can handle this. * currently that edge will get removed when joining the tris back into a quad. */ - f_new = BM_face_split(bm, f, l_a->v, l_b->v, &l_new, NULL, false); + f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false); if (f_new) { /* the value of this doesn't matter, only that the 2 loops match and have unique values */ diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c index 868caa49ec7..092a004aece 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c +++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c @@ -144,7 +144,7 @@ static bool bm_vert_dissolve_fan(BMesh *bm, BMVert *v) if (l->f->len > 3) { BMLoop *l_new; BLI_assert(l->prev->v != l->next->v); - BM_face_split(bm, l->f, l->prev->v, l->next->v, &l_new, NULL, true); + BM_face_split(bm, l->f, l->prev, l->next, &l_new, NULL, true); BM_elem_flag_merge_into(l_new->e, l->e, l->prev->e); } } diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 64175c133ea..0d1e43a709b 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -2237,6 +2237,7 @@ static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *cha BMesh *bm = kcd->em->bm; KnifeEdge *kfe, *kfelast; BMVert *v1, *v2; + BMLoop *l_v1, *l_v2; BMFace *f_new; Ref *ref; KnifeVert *kfv, *kfvprev; @@ -2262,28 +2263,36 @@ static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *cha } BLI_assert(i == nco); l_new = NULL; - if (nco == 0) { - /* Want to prevent creating two-sided polygons */ - if (v1 == v2 || BM_edge_exists(v1, v2)) { - f_new = NULL; + + if ((l_v1 = BM_face_vert_share_loop(f, v1)) && + (l_v2 = BM_face_vert_share_loop(f, v2))) + { + if (nco == 0) { + /* Want to prevent creating two-sided polygons */ + if (v1 == v2 || BM_edge_exists(v1, v2)) { + f_new = NULL; + } + else { + f_new = BM_face_split(bm, f, l_v1, l_v2, &l_new, NULL, true); + } } else { - f_new = BM_face_split(bm, f, v1, v2, &l_new, NULL, true); - } - } - else { - f_new = BM_face_split_n(bm, f, v1, v2, cos, nco, &l_new, NULL); - if (f_new) { - /* Now go through lnew chain matching up chain kv's and assign real v's to them */ - for (l_iter = l_new->next, i = 0; i < nco; l_iter = l_iter->next, i++) { - BLI_assert(equals_v3v3(cos[i], l_iter->v->co)); - if (kcd->select_result) { - BM_edge_select_set(bm, l_iter->e, true); + f_new = BM_face_split_n(bm, f, l_v1, l_v2, cos, nco, &l_new, NULL); + if (f_new) { + /* Now go through lnew chain matching up chain kv's and assign real v's to them */ + for (l_iter = l_new->next, i = 0; i < nco; l_iter = l_iter->next, i++) { + BLI_assert(equals_v3v3(cos[i], l_iter->v->co)); + if (kcd->select_result) { + BM_edge_select_set(bm, l_iter->e, true); + } + kverts[i]->v = l_iter->v; } - kverts[i]->v = l_iter->v; } } } + else { + f_new = NULL; + } /* the select chain above doesnt account for the first loop */ if (kcd->select_result) { diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c index d228e1a0646..236d6badd55 100644 --- a/source/blender/python/bmesh/bmesh_py_utils.c +++ b/source/blender/python/bmesh/bmesh_py_utils.c @@ -401,6 +401,7 @@ static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args, BMesh *bm; BMFace *f_new = NULL; BMLoop *l_new = NULL; + BMLoop *l_a, *l_b; if (!PyArg_ParseTupleAndKeywords(args, kw, "O!O!O!|OiO!:face_split", (char **)kwlist, &BPy_BMFace_Type, &py_face, @@ -422,9 +423,12 @@ static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args, } /* this doubles for checking that the verts are in the same mesh */ - if (BM_vert_in_face(py_face->f, py_vert_a->v) == false || - BM_vert_in_face(py_face->f, py_vert_b->v) == false) + if ((l_a = BM_face_vert_share_loop(py_face->f, py_vert_a->v)) && + (l_b = BM_face_vert_share_loop(py_face->f, py_vert_b->v))) { + /* pass */ + } + else { PyErr_SetString(PyExc_ValueError, "face_split(...): one of the verts passed is not found in the face"); return NULL; @@ -448,14 +452,14 @@ static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args, if (ncoords) { f_new = BM_face_split_n(bm, py_face->f, - py_vert_a->v, py_vert_b->v, + l_a, l_b, (float (*)[3])coords, ncoords, &l_new, py_edge_example ? py_edge_example->e : NULL); PyMem_Free(coords); } else { f_new = BM_face_split(bm, py_face->f, - py_vert_a->v, py_vert_b->v, + l_a, l_b, &l_new, py_edge_example ? py_edge_example->e : NULL, edge_exists); } |