From 741a177a74057b9baaae17640205017ca393ed89 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Apr 2012 21:47:32 +0000 Subject: bmesh: improve rip tool - When the rip extends into a fan, pick the opposite edge in the fan (rather then 2 along) - When stepping over the fan to find the rip edge, walk in the direction closest to the mouse (generally works nicer) --- source/blender/bmesh/intern/bmesh_core.c | 3 +- source/blender/bmesh/intern/bmesh_queries.c | 53 +++++++++++++++++++++++ source/blender/bmesh/intern/bmesh_queries.h | 1 + source/blender/editors/mesh/editmesh_rip.c | 65 ++++++++++++++++++++++------- 4 files changed, 105 insertions(+), 17 deletions(-) (limited to 'source') diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 76095728d5a..51ca11b0898 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -814,8 +814,7 @@ static int UNUSED_FUNCTION(count_flagged_disk)(BMVert *v, int flag) do { i += BM_ELEM_API_FLAG_TEST(e, flag) ? 1 : 0; - e = bmesh_disk_edge_next(e, v); - } while (e != v->e); + } while ((e = bmesh_disk_edge_next(e, v)) != v->e); return i; } diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 09cd6a2f96b..3561092b1cf 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -308,6 +308,59 @@ BMVert *BM_edge_other_vert(BMEdge *e, BMVert *v) return bmesh_edge_other_vert_get(e, v); } +/** + * The function takes a vertex at the center of a fan and returns the opposite edge in the fan. + * All edges in the fan must be manifold, otherwise return NULL. + * + * \note This could (probably) be done more effieiently. + */ +BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first) +{ + BMLoop *l_a; + int tot = 0; + int i; + + BLI_assert(BM_vert_in_edge(e_first, v)); + + l_a = e_first->l; + do { + l_a = BM_loop_other_vert_loop(l_a, v); + l_a = BM_vert_in_edge(l_a->e, v) ? l_a : l_a->prev; + if (BM_edge_is_manifold(l_a->e)) { + l_a = l_a->radial_next; + } + else { + return NULL; + } + + tot++; + } while (l_a != e_first->l); + + /* we know the total, now loop half way */ + tot /= 2; + i = 0; + + l_a = e_first->l; + do { + if (i == tot) { + l_a = BM_vert_in_edge(l_a->e, v) ? l_a : l_a->prev; + return l_a->e; + } + + l_a = BM_loop_other_vert_loop(l_a, v); + l_a = BM_vert_in_edge(l_a->e, v) ? l_a : l_a->prev; + if (BM_edge_is_manifold(l_a->e)) { + l_a = l_a->radial_next; + } + /* this wont have changed from the previous loop */ + + + i++; + } while (l_a != e_first->l); + + return NULL; +} + /** * Returms edge length */ diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index d69a57bdb40..5178311eea4 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -49,6 +49,7 @@ int BM_vert_edge_count_nonwire(BMVert *v); int BM_vert_edge_count(BMVert *v); int BM_edge_face_count(BMEdge *e); int BM_vert_face_count(BMVert *v); +BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e); int BM_vert_is_wire(BMVert *v); int BM_edge_is_wire(BMEdge *e); diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 34666c2cb7a..3d310e5ea90 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -66,7 +66,7 @@ static float edbm_rip_rip_edgedist(ARegion *ar, float mat[][4], float *co1, floa return dist_to_line_segment_v2(mvalf, vec1, vec2); } -static float edbm_rip_edge_side_measure(BMEdge *e, +static float edbm_rip_edge_side_measure(BMEdge *e, BMLoop *e_l, ARegion *ar, float projectMat[4][4], const float fmval[2]) { @@ -80,6 +80,8 @@ static float edbm_rip_edge_side_measure(BMEdge *e, BMVert *v1_other; BMVert *v2_other; + BLI_assert(BM_vert_in_edge(e, e_l->v)); + /* method for calculating distance: * * for each edge: calculate face center, then made a vector @@ -88,8 +90,8 @@ static float edbm_rip_edge_side_measure(BMEdge *e, /* rather then the face center, get the middle of * both edge verts connected to this one */ - v1_other = BM_face_other_vert_loop(e->l->f, e->v2, e->v1)->v; - v2_other = BM_face_other_vert_loop(e->l->f, e->v1, e->v2)->v; + v1_other = BM_face_other_vert_loop(e_l->f, e->v2, e->v1)->v; + v2_other = BM_face_other_vert_loop(e_l->f, e->v1, e->v2)->v; mid_v3_v3v3(cent, v1_other->co, v2_other->co); mid_v3_v3v3(mid, e->v1->co, e->v2->co); @@ -323,12 +325,12 @@ static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs, e = lp->l_a->e; v_prev = edbm_ripsel_edloop_pair_start_vert(e); for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { - score_a += edbm_rip_edge_side_measure(e, ar, projectMat, fmval); + score_a += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval); } e = lp->l_b->e; v_prev = edbm_ripsel_edloop_pair_start_vert(e); for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { - score_b += edbm_rip_edge_side_measure(e, ar, projectMat, fmval); + score_b += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval); } e = (score_a > score_b) ? lp->l_a->e : lp->l_b->e; @@ -538,26 +540,59 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) dist = FLT_MAX; } else { + int totedge; + int all_minifold; /* expand edge selection */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { e2 = NULL; i = 0; + totedge = 0; + all_minifold = TRUE; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - /* important to check selection rather then tag here - * else we get feedback loop */ - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - e2 = e; - i++; + + if (!BM_edge_is_wire(e) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { + /* important to check selection rather then tag here + * else we get feedback loop */ + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + e2 = e; + i++; + } + totedge++; + } + + /** #BM_vert_other_disk_edge has no hidden checks so don't check hidden here */ + if ((all_minifold == TRUE) && (BM_edge_is_manifold(e) == FALSE)) { + all_minifold = FALSE; } } + /* single edge, extend */ if (i == 1 && e2->l) { - l = BM_face_other_edge_loop(e2->l->f, e2, v); - l = l->radial_next; - l = BM_face_other_edge_loop(l->f, l->e, v); + if ((totedge == 4) || (all_minifold == FALSE)) { + BMLoop *l_a = e2->l; + BMLoop *l_b = l_a->radial_next; + + /* find the best face to follow, this wat the edge won't point away from + * the mouse when there are more then 4 (takes the shortest face fan around) */ + l = (edbm_rip_edge_side_measure(e2, l_a, ar, projectMat, fmval) < + edbm_rip_edge_side_measure(e2, l_b, ar, projectMat, fmval)) ? l_a : l_b; - if (l) { - BM_elem_flag_enable(l->e, BM_ELEM_TAG); + l = BM_face_other_edge_loop(l->f, e2, v); + l = l->radial_next; + l = BM_face_other_edge_loop(l->f, l->e, v); + + if (l) { + BM_elem_flag_enable(l->e, BM_ELEM_TAG); + } + } + else { + e = BM_vert_other_disk_edge(v, e2); + + if (e) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + } } } } -- cgit v1.2.3