diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/bmesh/intern/bmesh_mods.c | 49 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_mods.h | 1 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_queries.c | 71 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_queries.h | 2 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_utils.c | 35 |
5 files changed, 143 insertions, 15 deletions
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index ae53d5f83e4..29e6de5db0e 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -709,6 +709,43 @@ int BM_face_validate(BMesh *bm, BMFace *face, FILE *err) } /** + * \brief Check if Rotate Edge is OK + * + * Quick check to see if we could rotate the edge, + * use this to avoid calling exceptions on common cases. + */ +int BM_edge_rotate_check(BMesh *UNUSED(bm), BMEdge *e) +{ + BMFace *fa, *fb; + if (BM_edge_face_pair(e, &fa, &fb)) { + BMLoop *la, *lb; + + la = BM_face_other_vert_loop(e->v2, fa, e->v1); + lb = BM_face_other_vert_loop(e->v2, fb, e->v1); + + /* check that the next vert in both faces isnt the same + * (ie - the next edge doesnt sharwe the same faces). + * since we can't rotate usefully in this case. */ + if (la->v == lb->v) { + return FALSE; + } + + /* mirror of the check above but in the opposite direction */ + la = BM_face_other_vert_loop(e->v1, fa, e->v2); + lb = BM_face_other_vert_loop(e->v1, fb, e->v2); + + if (la->v == lb->v) { + return FALSE; + } + + return TRUE; + } + else { + return FALSE; + } +} + +/** * \brief Rotate Edge * * Spins an edge topologically, @@ -727,16 +764,12 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, int ccw) BMFace *f; BMIter liter; - v1 = e->v1; - v2 = e->v2; - - if (BM_edge_face_count(e) != 2) + if (!BM_edge_rotate_check(bm, e)) { return NULL; + } - /* If either of e's vertices has valence 2, then - * dissolving the edge would leave a spur, so not allowed */ - if (BM_vert_edge_count(e->v1) == 2 || BM_vert_edge_count(e->v2) == 2) - return NULL; + v1 = e->v1; + v2 = e->v2; f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e); diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h index 6d4b1333549..d530e9d8666 100644 --- a/source/blender/bmesh/intern/bmesh_mods.h +++ b/source/blender/bmesh/intern/bmesh_mods.h @@ -53,6 +53,7 @@ BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts); int BM_face_validate(BMesh *bm, BMFace *face, FILE *err); +int BM_edge_rotate_check(BMesh *UNUSED(bm), BMEdge *e); BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, int ccw); BMVert *BM_vert_rip(BMesh *bm, BMFace *sf, BMVert *sv); diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index e597145a54c..ad7300e1c21 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -65,7 +65,7 @@ int BM_vert_in_edge(BMEdge *e, BMVert *v) /** * \brief BMESH OTHER EDGE IN FACE SHARING A VERTEX * - * Finds the other loop that shares 'v' with 'e's loop in 'f'. + * Finds the other loop that shares \a v with \a e loop in \a f. */ BMLoop *BM_face_other_loop(BMEdge *e, BMFace *f, BMVert *v) { @@ -84,6 +84,50 @@ BMLoop *BM_face_other_loop(BMEdge *e, BMFace *f, BMVert *v) } /** + * \brief BMESH NEXT LOOP IN FACE SHARING A VERTEX + * + * Finds the other loop in a face. + * + * This function returns a loop in \a f that shares an edge with \v + * The direction is defined by \a v_prev, where the return value is + * the loop of what would be 'v_next' + * + * \note \a v_prev and \a v _implicitly_ define an edge. + */ +BMLoop *BM_face_other_vert_loop(BMVert *v_prev, BMFace *f, BMVert *v) +{ + BMIter liter; + BMLoop *l_iter; + + BLI_assert(BM_edge_exists(v_prev, v) != NULL); + + BM_ITER(l_iter, &liter, NULL, BM_LOOPS_OF_VERT, v) { + if (l_iter->f == f) { + break; + } + } + + if (l_iter) { + if (l_iter->prev->v == v_prev) { + return l_iter->next; + } + else if (l_iter->next->v == v_prev) { + return l_iter->prev; + } + else { + /* invalid args */ + BLI_assert(0); + return NULL; + } + } + else { + /* invalid args */ + BLI_assert(0); + return NULL; + } +} + +/** * Returns TRUE if the vertex is used in a given face. */ @@ -191,6 +235,31 @@ BMVert *BM_edge_other_vert(BMEdge *e, BMVert *v) } /** + * Utility function, since enough times we have an edge + * and want to access 2 connected faces. + * + * \return TRUE when only 2 faces are found. + */ +int BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb) +{ + BMLoop *la, *lb; + + if ((la = e->l) && + (lb = la->radial_next) && + (lb->radial_next == la)) + { + *r_fa = la->f; + *r_fb = lb->f; + return TRUE; + } + else { + *r_fa = NULL; + *r_fb = NULL; + return FALSE; + } +} + +/** * Returns the number of edges around this vertex. */ int BM_vert_edge_count(BMVert *v) diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 1fb0df7e2af..8c366d213d7 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -37,8 +37,10 @@ int BM_edge_in_face(BMFace *f, BMEdge *e); int BM_vert_in_edge(BMEdge *e, BMVert *v); int BM_verts_in_edge(BMVert *v1, BMVert *v2, BMEdge *e); +int BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb); BMVert *BM_edge_other_vert(BMEdge *e, BMVert *v); BMLoop *BM_face_other_loop(BMEdge *e, BMFace *f, BMVert *v); +BMLoop *BM_face_other_vert_loop(BMVert *v_prev, BMFace *f, BMVert *v); int BM_vert_edge_count(BMVert *v); int BM_edge_face_count(BMEdge *e); diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index b7418e428ed..64e530ca52a 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -125,16 +125,39 @@ void bmo_edgerotate_exec(BMesh *bm, BMOperator *op) BMEdge *e, *e2; int ccw = BMO_slot_bool_get(op, "ccw"); +#define EDGE_OUT 1 +#define FACE_TAINT 1 + BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) { - if (!(e2 = BM_edge_rotate(bm, e, ccw))) { - BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge"); - return; - } + if (BM_edge_rotate_check(bm, e)) { + BMFace *fa, *fb; + if (BM_edge_face_pair(e, &fa, &fb)) { + + /* check we're untouched */ + if (BMO_elem_flag_test(bm, fa, FACE_TAINT) == FALSE && + BMO_elem_flag_test(bm, fb, FACE_TAINT) == FALSE) + { + + if (!(e2 = BM_edge_rotate(bm, e, ccw))) { + BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge"); + return; + } - BMO_elem_flag_enable(bm, e2, 1); + BMO_elem_flag_enable(bm, e2, EDGE_OUT); + + /* dont touch again */ + BMO_elem_flag_enable(bm, fa, FACE_TAINT); + BMO_elem_flag_enable(bm, fb, FACE_TAINT); + } + } + } } - BMO_slot_buffer_from_flag(bm, op, "edgeout", 1, BM_EDGE); + BMO_slot_buffer_from_flag(bm, op, "edgeout", EDGE_OUT, BM_EDGE); + +#undef EDGE_OUT +#undef FACE_TAINT + } #define SEL_FLAG 1 |