Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c49
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c71
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h2
-rw-r--r--source/blender/bmesh/operators/bmo_utils.c35
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