BMesh optimize face splitting by taking loops rather then verts
authorCampbell Barton <ideasman42@gmail.com>
Tue, 24 Dec 2013 00:04:03 +0000 (11:04 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 24 Dec 2013 00:13:58 +0000 (11:13 +1100)
- add BM_vert_pair_share_face
- add BM_loop_is_adjacent
- remove BM_verts_connect

20 files changed:
source/blender/bmesh/intern/bmesh_core.c
source/blender/bmesh/intern/bmesh_core.h
source/blender/bmesh/intern/bmesh_mods.c
source/blender/bmesh/intern/bmesh_mods.h
source/blender/bmesh/intern/bmesh_polygon.c
source/blender/bmesh/intern/bmesh_queries.c
source/blender/bmesh/intern/bmesh_queries.h
source/blender/bmesh/intern/bmesh_queries_inline.h
source/blender/bmesh/operators/bmo_connect.c
source/blender/bmesh/operators/bmo_connect_nonplanar.c
source/blender/bmesh/operators/bmo_dissolve.c
source/blender/bmesh/operators/bmo_removedoubles.c
source/blender/bmesh/operators/bmo_subdivide.c
source/blender/bmesh/operators/bmo_subdivide_edgering.c
source/blender/bmesh/tools/bmesh_bevel.c
source/blender/bmesh/tools/bmesh_bisect_plane.c
source/blender/bmesh/tools/bmesh_decimate_collapse.c
source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
source/blender/editors/mesh/editmesh_knife.c
source/blender/python/bmesh/bmesh_py_utils.c

index cbaffe2da1a227c59a612ec3ad8ecb766932d3fd..7b3ca89871805bc6454ab4c93b9ca604d76d2302 100644 (file)
@@ -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);
index e9fd4e650cb50787842f97c7d6fdb94766ad1b1b..654698da3c6fc259e32ee096bcdd8ae139a51330 100644 (file)
@@ -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);
index 49c8c987956996b51e979841009c8fbdbc82fde3..6d8dc531a3276b3e1f3d8f1e505c141006ded0f5 100644 (file)
@@ -251,48 +251,6 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const
        return BM_faces_join(bm, faces, 2, do_del);
 }
 
-/**
- * \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
  *
@@ -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;
 }
index ca281c13f2112a81c23ef15c24ee099490e73d88..f3ed99230d7861d52ceadd4e0996753927fd0b78 100644 (file)
@@ -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);
 
index 7a625840891295e113bd6988aaa8d8fcccd518f6..a3aaea9e257a876cab333e9fcff86ca98511b201 100644 (file)
@@ -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) {
index 16785778883e9dca7b4e0f9f69dd05e7bff65ecc..968ca5f3102cf390d09733c674d94be5a8ce5a09 100644 (file)
@@ -181,6 +181,37 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
 #endif
 }
 
+/**
+ * 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
index 17c14310191d63125a6277c19fd53339a8ca3fb3..d4b6cd0e061a95a7883519b27c3bb9620f32512d 100644 (file)
@@ -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]);
index c3ee363f247e5097a6dc60dff177a1e13d8d1dc0..a2a0a15faad23a745779304f947cc05fe4b5d332 100644 (file)
@@ -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__ */
index d0f64eb28924ebb3e5e00e9b7deb52bb3a54d7a4..3d2c8c3d020e8f515552d4b9be275c7e8da607c4 100644 (file)
@@ -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) {
index bd7a625406cfab5eb953f4f1df237450350a1ee7..334647fc68c680404b7e2b4d37e94391d5cb644b 100644 (file)
@@ -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;
index ae645b978744296478e2656bd49a5b3c87f46803..60b96e35057bffa07f7c703626ef126e5b73b1e8 100644 (file)
@@ -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);
                                                }
                                        }
                                }
index cc5a635092a9d84efff03c56db621f15bee7c3dc..8eb94b9a743b89cdddb3f178ca239d53360d09f5 100644 (file)
 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);
        }
 }
 
index b3b9cecf389bf72ed7eb9b8b18518cbb454581a1..723595771a162ac3dbc22668201b7632d8e8bf51 100644 (file)
@@ -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);
                                        }
index d1ec06c548671c7999190a774ade74d7b247e841..182bf0518efbfc658e5d0bf50970f4a6bf889441 100644 (file)
@@ -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;
                }
index 7f39cbee2c5488af9a1345bae8a6a48a5e855bc8..b10f162f2b07b0c1e8125e9935428a3b4534c49f 100644 (file)
@@ -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 */
index 6aeb26435acdde9fc0fa645f4ae8be41dbdb2848..7001cfa40619b6ccf634e0d54e3583c62e10cd9b 100644 (file)
@@ -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);
index 3ee238ad54f05212e0e43ba352ea2ae0596de213..292978cd247651f53e1c48176f7282af5cb60065 100644 (file)
@@ -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 */
index 868caa49ec75e1273883b97ccad32d0b2365503e..092a004aecee7f88a7b6c958fe12d3135bae47b9 100644 (file)
@@ -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);
                        }
                }
index 64175c133eafea66cf9fffb42e8f11c8c094c076..0d1e43a709b5dcd28ca345b791fb587e3dbdf287 100644 (file)
@@ -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) {
index d228e1a0646730aacee4365b35615a6287121557..236d6badd55a02a7e05859f9cfc6e825564583dc 100644 (file)
@@ -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);
        }