bmesh edge rotate
* improve check to see if edge rotate can be done, was checking if both edges verts have an edge count of 2, which is really a meaningless test since the verts can have stray edges connected and the result wont work right. instead check if the next verts in both faces share a vertex. * add utility function BM_face_other_vert_loop() which gets the next loop in a face. * add convenience function BM_edge_face_pair() which returns 2 faces for edges that have exactly 2 face users. (saves ugly e->l->radial_next ... in code) and is more readable.
This commit is contained in:
@@ -708,6 +708,43 @@ int BM_face_validate(BMesh *bm, BMFace *face, FILE *err)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \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
|
||||
*
|
||||
@@ -727,17 +764,13 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, int ccw)
|
||||
BMFace *f;
|
||||
BMIter liter;
|
||||
|
||||
if (!BM_edge_rotate_check(bm, e)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
v1 = e->v1;
|
||||
v2 = e->v2;
|
||||
|
||||
if (BM_edge_face_count(e) != 2)
|
||||
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;
|
||||
|
||||
f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e);
|
||||
|
||||
if (f == NULL)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -83,6 +83,50 @@ BMLoop *BM_face_other_loop(BMEdge *e, BMFace *f, BMVert *v)
|
||||
return l_iter->v == v ? l_iter->prev : l_iter->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* \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.
|
||||
*/
|
||||
@@ -190,6 +234,31 @@ BMVert *BM_edge_other_vert(BMEdge *e, BMVert *v)
|
||||
return bmesh_edge_other_vert_get(e, 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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -125,16 +125,39 @@ void bmo_edgerotate_exec(BMesh *bm, BMOperator *op)
|
||||
BMEdge *e, *e2;
|
||||
int ccw = BMO_slot_bool_get(op, "ccw");
|
||||
|
||||
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;
|
||||
}
|
||||
#define EDGE_OUT 1
|
||||
#define FACE_TAINT 1
|
||||
|
||||
BMO_elem_flag_enable(bm, e2, 1);
|
||||
BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
|
||||
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, 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
|
||||
|
||||
Reference in New Issue
Block a user