BMesh: rewrite edge split code (used by edge split modifier and rip tool)
authorCampbell Barton <ideasman42@gmail.com>
Fri, 9 Mar 2012 03:16:39 +0000 (03:16 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 9 Mar 2012 03:16:39 +0000 (03:16 +0000)
this fixes but [#30461] where the same vertex was added to some faces twice.

Previous code rebuilt all faces around the split edges, replace this with much simpler code that uses existing bmesh API for splitting.

This also gives a performance boost to the modifier (over 30x faster in the bug-report file).

source/blender/bmesh/intern/bmesh_core.c
source/blender/bmesh/intern/bmesh_core.h
source/blender/bmesh/intern/bmesh_opdefines.c
source/blender/bmesh/operators/bmo_edgesplit.c
source/blender/editors/mesh/bmesh_tools.c

index 3ca7750f5718bb4c195a11c18543958fc8f7c757..133e446f891eadc5135810217b1d143908115cda 100644 (file)
@@ -41,8 +41,6 @@
  * TESTING ONLY! */
 // #define USE_DEBUG_INDEX_MEMCHECK
 
-static int bm_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep);
-
 #ifdef USE_DEBUG_INDEX_MEMCHECK
 #define DEBUG_MEMCHECK_INDEX_INVALIDATE(ele)               \
        {                                                      \
@@ -1748,7 +1746,7 @@ static int bm_vert_splice(BMesh *bm, BMVert *v, BMVert *vtarget)
  *
  * \return Success
  */
-int bm_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len)
+int bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len)
 {
        BMEdge **stack = NULL;
        BLI_array_declare(stack);
@@ -1856,11 +1854,11 @@ int BM_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
        for (i = 0; i < e_in_len; i++) {
                BMEdge *e = e_in[i];
                if (e->l && BM_vert_in_edge(e, v)) {
-                       bm_edge_separate(bm, e, e->l);
+                       bmesh_edge_separate(bm, e, e->l);
                }
        }
 
-       return bm_vert_separate(bm, v, r_vout, r_vout_len);
+       return bmesh_vert_separate(bm, v, r_vout, r_vout_len);
 }
 
 /**
@@ -1911,7 +1909,7 @@ int BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *etarget)
  * \note Does nothing if \a l_sep is already the only loop in the
  * edge radial.
  */
-static int bm_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep)
+int bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep)
 {
        BMEdge *ne;
        int radlen;
@@ -1959,8 +1957,8 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *sl)
 
        /* peel the face from the edge radials on both sides of the
         * loop vert, disconnecting the face from its fan */
-       bm_edge_separate(bm, sl->e, sl);
-       bm_edge_separate(bm, sl->prev->e, sl->prev);
+       bmesh_edge_separate(bm, sl->e, sl);
+       bmesh_edge_separate(bm, sl->prev->e, sl->prev);
 
        if (bmesh_disk_count(sv) == 2) {
                /* If there are still only two edges out of sv, then
@@ -1978,7 +1976,7 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *sl)
 
        /* Split all fans connected to the vert, duplicating it for
         * each fans. */
-       bm_vert_separate(bm, sv, &vtar, &len);
+       bmesh_vert_separate(bm, sv, &vtar, &len);
 
        /* There should have been at least two fans cut apart here,
         * otherwise the early exit would have kicked in. */
index 11f3e052bff4b820e51e288356885873ab973866..e10222dc29a9c23f99daefaa66fecb6365c803a0 100644 (file)
@@ -41,6 +41,9 @@ void    BM_edge_kill(BMesh *bm, BMEdge *e);
 void    BM_vert_kill(BMesh *bm, BMVert *v);
 
 int     BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *etarget);
+int     bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep);
+
+int     bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len);
 
 int     bmesh_loop_reverse(BMesh *bm, BMFace *f);
 
index 97990c614d55173ac069a031552cd6ca0acfce40..f2dcaded8caba0aa450472565fce13b582897ec6 100644 (file)
@@ -890,8 +890,7 @@ static BMOpDefine bmo_vertexshortestpath_def = {
 static BMOpDefine bmo_edgesplit_def = {
        "edgesplit",
        {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edges */
-        {BMO_OP_SLOT_ELEMENT_BUF, "edgeout1"}, /* old output disconnected edges */
-        {BMO_OP_SLOT_ELEMENT_BUF, "edgeout2"}, /* new output disconnected edges */
+        {BMO_OP_SLOT_ELEMENT_BUF, "edgeout"}, /* old output disconnected edges */
         {0} /* null-terminating sentine */},
        bmo_edgesplit_exec,
        BMO_OP_FLAG_UNTAN_MULTIRES
index f1d3fbeb6afc4716194ef52a4e9a573eb2eac13c..44d0ad4ff940e4801fa3fa872ca10961b1fb2f87 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
- * Contributor(s): Joseph Eagar
+ * Contributor(s): Campbell Barton
  *
  * ***** END GPL LICENSE BLOCK *****
  */
 
-#include <string.h> /* for memcpy */
-
 #include "MEM_guardedalloc.h"
 
-#include "BLI_array.h"
-
 #include "bmesh.h"
 
 #include "intern/bmesh_operators_private.h" /* own include */
 
-typedef struct EdgeTag {
-       BMVert *newv1, *newv2;
-       BMEdge *newe1, *newe2;
-} EdgeTag;
-
-/* (EDGE_DEL == FACE_DEL) - this must be the case */
-enum {
-       EDGE_DEL   = 1,
-       EDGE_SEAM  = 2,
-       EDGE_MARK  = 4,
-       EDGE_RET1  = 8,
-       EDGE_RET2  = 16
-};
-
 enum {
-       FACE_DEL  = EDGE_DEL,
-       FACE_NEW  = 2
+       EDGE_SEAM  = 1
 };
 
-static BMFace *remake_face(BMesh *bm, EdgeTag *etags, BMFace *f, BMVert **f_verts, BMEdge **edges_tmp)
-{
-       BMIter liter1, liter2;
-       EdgeTag *et;
-       BMFace *f2;
-       BMLoop *l, *l2;
-       BMEdge *e;
-       BMVert *lastv1, *lastv2 /* , *v1, *v2 */ /* UNUSED */;
-       int i;
-
-       /* we do final edge last */
-       lastv1 = f_verts[f->len - 1];
-       lastv2 = f_verts[0];
-       /* v1 = f_verts[0]; */ /* UNUSED */
-       /* v2 = f_verts[1]; */ /* UNUSED */
-       for (i = 0; i < f->len - 1; i++) {
-               e = BM_edge_create(bm, f_verts[i], f_verts[i + 1], NULL, TRUE);
-               if (!e) {
-                       return NULL;
-               }
-               edges_tmp[i] = e;
-       }
-
-       edges_tmp[i] = BM_edge_create(bm, lastv1, lastv2, NULL, TRUE);
-
-       f2 = BM_face_create(bm, f_verts, edges_tmp, f->len, FALSE);
-       if (!f2) {
-               return NULL;
-       }
-
-       BM_elem_attrs_copy(bm, bm, f, f2);
-
-       l = BM_iter_new(&liter1, bm, BM_LOOPS_OF_FACE, f);
-       l2 = BM_iter_new(&liter2, bm, BM_LOOPS_OF_FACE, f2);
-       for ( ; l && l2; l = BM_iter_step(&liter1), l2 = BM_iter_step(&liter2)) {
-               BM_elem_attrs_copy(bm, bm, l, l2);
-               if (l->e != l2->e) {
-                       /* set up data for figuring out the two sides of
-                        * the split */
-
-                       /* set edges index as dirty after running all */
-                       BM_elem_index_set(l2->e, BM_elem_index_get(l->e)); /* set_dirty! */
-                       et = &etags[BM_elem_index_get(l->e)];
-                       
-                       if (!et->newe1) {
-                               et->newe1 = l2->e;
-                       }
-                       else if (!et->newe2) {
-                               et->newe2 = l2->e;
-                       }
-                       else {
-                               /* Only two new edges should be created from each original edge
-                                *  for edge split operation */
-
-                               //BLI_assert(et->newe1 == l2->e || et->newe2 == l2->e);
-                               et->newe2 = l2->e;
-                       }
-
-                       if (BMO_elem_flag_test(bm, l->e, EDGE_SEAM)) {
-                               BMO_elem_flag_enable(bm, l2->e, EDGE_SEAM);
-                       }
-
-                       BM_elem_attrs_copy(bm, bm, l->e, l2->e);
-               }
-
-               BMO_elem_flag_enable(bm, l->e, EDGE_MARK);
-               BMO_elem_flag_enable(bm, l2->e, EDGE_MARK);
-       }
-
-       return f2;
-}
-
-static void tag_out_edges(BMesh *bm, EdgeTag *etags, BMOperator *UNUSED(op))
-{
-       EdgeTag *et;
-       BMIter iter;
-       BMLoop *l, *l_start, *l_prev;
-       BMEdge *e;
-       BMVert *v;
-       int i, ok;
-       
-       ok = 0;
-       while (ok++ < 100000) {
-               BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
-                       if (!BMO_elem_flag_test(bm, e, EDGE_SEAM))
-                               continue;
-
-                       if (e->l) {
-                               break;
-                       }
-               }
-               
-               if (!e) {
-                       break;
-               }
-
-               /* ok we found an edge, part of a region of splits we need
-                * to identify.  now walk along it */
-               for (i = 0; i < 2; i++) {
-                       l = e->l;
-                       
-                       v = i ? l->next->v : l->v;
-
-                       while (1) {
-                               et = &etags[BM_elem_index_get(l->e)];
-                               if (et->newe1 == l->e) {
-                                       if (et->newe1) {
-                                               BMO_elem_flag_enable(bm, et->newe1, EDGE_RET1);
-                                               BMO_elem_flag_disable(bm, et->newe1, EDGE_SEAM);
-                                       }
-                                       if (et->newe2) {
-                                               BMO_elem_flag_enable(bm, et->newe2, EDGE_RET2);
-                                               BMO_elem_flag_disable(bm, et->newe2, EDGE_SEAM);
-                                       }
-                               }
-                               else {
-                                       if (et->newe1) {
-                                               BMO_elem_flag_enable(bm, et->newe1, EDGE_RET2);
-                                               BMO_elem_flag_disable(bm, et->newe1, EDGE_SEAM);
-                                       }
-                                       if (et->newe2) {
-                                               BMO_elem_flag_enable(bm, et->newe2, EDGE_RET1);
-                                               BMO_elem_flag_disable(bm, et->newe2, EDGE_SEAM);
-                                       }
-                               }
-
-                               /* If the original edge was non-manifold edges, then it is
-                                * possible l->e is not et->newe1 or et->newe2. So always clear
-                                * the flag on l->e as well, to prevent infinite looping. */
-                               BMO_elem_flag_disable(bm, l->e, EDGE_SEAM);
-                               l_start = l;
-
-                               do {
-                                       /* l_prev checks stops us from looping over the same edge forever [#30459] */
-                                       l_prev = l;
-                                       l = BM_face_other_edge_loop(l->f, l->e, v);
-                                       if (l == l_start || BM_edge_face_count(l->e) != 2) {
-                                               break;
-                                       }
-                                       l = l->radial_next;
-                               } while (l != l_start && l != l_prev && !BMO_elem_flag_test(bm, l->e, EDGE_SEAM));
-                               
-                               if (l == l_start || !BMO_elem_flag_test(bm, l->e, EDGE_SEAM)) {
-                                       break;
-                               }
-
-                               v = (l->v == v) ? l->next->v : l->v;
-                       }
-               }
-       }
-}
-
-/* helper functions for edge tag's */
-BM_INLINE BMVert *bm_edge_tag_vert_get(EdgeTag *et, BMVert *v, BMLoop *l)
-{
-       return (l->e->v1 == v) ? et->newv1 : et->newv2;
-}
-
-BM_INLINE void bm_edge_tag_vert_set(EdgeTag *et, BMVert *v, BMLoop *l, BMVert *vset)
-{
-       if (l->e->v1 == v) {
-               et->newv1 = vset;
-       }
-       else {
-               et->newv2 = vset;
-       }
-}
-
 /**
  * Remove the EDGE_SEAM flag for edges we cant split
  *
@@ -238,6 +51,11 @@ static void bm_edgesplit_validate_seams(BMesh *bm, BMOperator *op)
 
        /* tag all boundry verts so as not to untag an edge which is inbetween only 2 faces [] */
        BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+
+               /* unrelated to flag assignment in this function - since this is the
+                * only place we loop over all edges, disable tag */
+               BM_elem_flag_disable(e, BM_ELEM_INTERNAL_TAG);
+
                if (BM_edge_is_boundary(e)) {
                        vt = &vtouch[BM_elem_index_get(e->v1)]; if (*vt < 2) (*vt)++;
                        vt = &vtouch[BM_elem_index_get(e->v2)]; if (*vt < 2) (*vt)++;
@@ -270,202 +88,36 @@ static void bm_edgesplit_validate_seams(BMesh *bm, BMOperator *op)
 
 void bmo_edgesplit_exec(BMesh *bm, BMOperator *op)
 {
-       EdgeTag *etags, *et; /* edge aligned array of tags */
-       BMIter iter, liter;
-       BMFace *f, *f2;
-       BMLoop *l, *l2, *l3;
-       BMLoop *l_next, *l_prev;
+       BMOIter siter;
        BMEdge *e;
-       BMVert *v, *v2;
-
-       /* face/vert aligned vert array */
-       BMVert **f_verts = NULL;
-       BLI_array_declare(f_verts);
-
-       BMEdge **edges_tmp = NULL;
-       BLI_array_declare(edges_tmp);
-       int i, j;
 
        BMO_slot_buffer_flag_enable(bm, op, "edges", EDGE_SEAM, BM_EDGE);
 
        bm_edgesplit_validate_seams(bm, op);
 
-       etags = MEM_callocN(sizeof(EdgeTag) * bm->totedge, "EdgeTag");
-
-       BM_mesh_elem_index_ensure(bm, BM_EDGE);
-
-       BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
-
-               if (BMO_elem_flag_test(bm, f, FACE_NEW)) {
-                       continue;
-               }
-
-               BLI_array_empty(f_verts);
-               BLI_array_growitems(f_verts, f->len);
-               memset(f_verts, 0, sizeof(BMVert *) * f->len);
-
-               /* this is passed onto remake_face() so it doesnt need to allocate
-                * a new array on each call. */
-               BLI_array_empty(edges_tmp);
-               BLI_array_growitems(edges_tmp, f->len);
-
-               i = 0;
-               BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
-                       if (!BMO_elem_flag_test(bm, l->e, EDGE_SEAM)) {
-                               if (!f_verts[i]) {
-
-                                       et = &etags[BM_elem_index_get(l->e)];
-                                       if (bm_edge_tag_vert_get(et, l->v, l)) {
-                                               f_verts[i] = bm_edge_tag_vert_get(et, l->v, l);
-                                       }
-                                       else {
-                                               f_verts[i] = l->v;
-                                       }
-                               }
-                               i++;
-                               continue;
-                       }
-
-                       l_next = l->next;
-                       l_prev = l->prev;
-                       
-                       for (j = 0; j < 2; j++) {
-                               /* correct as long as i & j dont change during the loop */
-                               const int fv_index = j ? (i + 1) % f->len : i; /* face vert index */
-                               l2 = j ? l_next : l_prev;
-                               v = j ? l2->v : l->v;
-
-                               if (BMO_elem_flag_test(bm, l2->e, EDGE_SEAM)) {
-                                       if (f_verts[fv_index] == NULL) {
-                                               /* make unique vert here for this face only */
-                                               v2 = BM_vert_create(bm, v->co, v);
-                                               f_verts[fv_index] = v2;
-                                       }
-                                       else {
-                                               v2 = f_verts[fv_index];
-                                       }
-                               }
-                               else {
-                                       /* generate unique vert for non-seam edge(s)
-                                        * around the manifold vert fan if necessary */
-
-                                       /* first check that we have two seam edges
-                                        * somewhere within this fa */
-                                       l3 = l2;
-                                       do {
-                                               if (BM_edge_face_count(l3->e) != 2) {
-                                                       /* if we hit a boundary edge, tag
-                                                        * l3 as null so we know to disconnect
-                                                        * it */
-                                                       if (BM_edge_face_count(l3->e) == 1) {
-                                                               l3 = NULL;
-                                                       }
-                                                       break;
-                                               }
-
-                                               l3 = l3->radial_next;
-                                               l3 = BM_face_other_edge_loop(l3->f, l3->e, v);
-                                       } while (l3 != l2 && !BMO_elem_flag_test(bm, l3->e, EDGE_SEAM));
-
-                                       if (l3 == NULL || (BMO_elem_flag_test(bm, l3->e, EDGE_SEAM) && l3->e != l->e)) {
-                                               et = &etags[BM_elem_index_get(l2->e)];
-                                               if (bm_edge_tag_vert_get(et, v, l2) == NULL) {
-                                                       v2 = BM_vert_create(bm, v->co, v);
-                                                       
-                                                       l3 = l2;
-                                                       do {
-                                                               bm_edge_tag_vert_set(et, v, l3, v2);
-                                                               if (BM_edge_face_count(l3->e) != 2) {
-                                                                       break;
-                                                               }
-
-                                                               l3 = l3->radial_next;
-                                                               l3 = BM_face_other_edge_loop(l3->f, l3->e, v);
-                                                               
-                                                               et = &etags[BM_elem_index_get(l3->e)];
-                                                       } while (l3 != l2 && !BMO_elem_flag_test(bm, l3->e, EDGE_SEAM));
-                                               }
-                                               else {
-                                                       v2 = bm_edge_tag_vert_get(et, v, l2);
-                                               }
-
-                                               f_verts[fv_index] = v2;
-                                       }
-                                       else {
-                                               f_verts[fv_index] = v;
-                                       }
-                               }
-                       }
-
-                       i++;
-               }
-
-               /* debugging code, quick way to find the face/vert combination
-                * which is failing assuming quads start planer - campbell */
-#if 0
-               if (f->len == 4) {
-                       float no1[3];
-                       float no2[3];
-                       float angle_error;
-                       printf(" ** found QUAD\n");
-                       normal_tri_v3(no1, f_verts[0]->co, f_verts[1]->co, f_verts[2]->co);
-                       normal_tri_v3(no2, f_verts[0]->co, f_verts[2]->co, f_verts[3]->co);
-                       if ((angle_error = angle_v3v3(no1, no2)) > 0.05) {
-                               printf("     ERROR %.4f\n", angle_error);
-                               print_v3("0", f_verts[0]->co);
-                               print_v3("1", f_verts[1]->co);
-                               print_v3("2", f_verts[2]->co);
-                               print_v3("3", f_verts[3]->co);
-
-                       }
-               }
-               else {
-                       printf(" ** fount %d len face\n", f->len);
-               }
-#endif
+       BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+               if (BMO_elem_flag_test(bm, e, EDGE_SEAM)) {
+                       /* this flag gets copied so we can be sure duplicate edges get it too (important) */
+                       BM_elem_flag_enable(e, BM_ELEM_INTERNAL_TAG);
 
-               f2 = remake_face(bm, etags, f, f_verts, edges_tmp);
-               if (f2) {
-                       BMO_elem_flag_enable(bm, f, FACE_DEL);
-                       BMO_elem_flag_enable(bm, f2, FACE_NEW);
+                       bmesh_edge_separate(bm, e, e->l);
+                       BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
+                       BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
                }
-               /* else { ... should we raise an error here, or an assert? - campbell */
        }
-       
-       /* remake_face() sets invalid indices,
-        * likely these will be corrected on operator exit anyway */
-       bm->elem_index_dirty &= ~BM_EDGE;
-
-       /* cant call the operator because 'tag_out_edges'
-        * relies on original index values, from before editing geometry */
 
-#if 0
-       BMO_op_callf(bm, "del geom=%ff context=%i", FACE_DEL, DEL_ONLYFACES);
-#else
-       BMO_remove_tagged_context(bm, FACE_DEL, DEL_ONLYFACES);
-#endif
-
-       /* test EDGE_MARK'd edges if we need to delete them, EDGE_MARK
-        * is set in remake_face */
-       BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
-               if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
-                       if (!e->l) {
-                               BMO_elem_flag_enable(bm, e, EDGE_DEL);
+       BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+               if (BMO_elem_flag_test(bm, e, EDGE_SEAM)) {
+                       if (BM_elem_flag_test(e->v1, BM_ELEM_TAG)) {
+                               BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
+                               bmesh_vert_separate(bm, e->v1, NULL, NULL);
+                       }
+                       if (BM_elem_flag_test(e->v2, BM_ELEM_TAG)) {
+                               BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
+                               bmesh_vert_separate(bm, e->v2, NULL, NULL);
                        }
                }
        }
 
-#if 0
-       BMO_op_callf(bm, "del geom=%fe context=%i", EDGE_DEL, DEL_EDGES);
-#else
-       BMO_remove_tagged_context(bm, EDGE_DEL, DEL_EDGES);
-#endif
-       
-       tag_out_edges(bm, etags, op);
-       BMO_slot_buffer_from_flag(bm, op, "edgeout1", EDGE_RET1, BM_EDGE);
-       BMO_slot_buffer_from_flag(bm, op, "edgeout2", EDGE_RET2, BM_EDGE);
-
-       BLI_array_free(f_verts);
-       BLI_array_free(edges_tmp);
-       if (etags) MEM_freeN(etags);
+       BMO_slot_buffer_from_hflag(bm, op, "edgeout", BM_ELEM_INTERNAL_TAG, BM_EDGE);
 }
index 924e1fbf339ef8656e485dddf07f11d2d4cc35f0..022e94e8209fa710e0decb5b01e97fb6eb337790 100644 (file)
@@ -2325,17 +2325,11 @@ static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *c
        return dist_to_line_segment_v2(mvalf, vec1, vec2);
 }
 
-/* #define USE_BVH_VISIBILITY */
-
 /* based on mouse cursor position, it defines how is being ripped */
 static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        Object *obedit = CTX_data_edit_object(C);
        ARegion *ar = CTX_wm_region(C);
-#ifdef USE_BVH_VISIBILITY
-       BMBVHTree *bvhtree;
-       View3D *v3d = CTX_wm_view3d(C);
-#endif
        RegionView3D *rv3d = CTX_wm_region_view3d(C);
        BMEditMesh *em = BMEdit_FromObject(obedit);
        BMesh *bm = em->bm;
@@ -2345,9 +2339,10 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
        BMLoop *l;
        BMEdge *e, *e2;
        BMVert *v, *ripvert = NULL;
-       int side = 0, i, singlesel = FALSE;
+       int i, singlesel = FALSE;
        float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
-       float dist = FLT_MAX, d;
+       float dist = FLT_MAX;
+       float d, d_a, d_b;
 
        /* note on selection:
         * When calling edge split we operate on tagged edges rather then selected
@@ -2465,44 +2460,47 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
        bvhtree = BMBVH_NewBVH(em, 0, NULL, NULL);
 #endif
 
-       for (i = 0; i < 2; i++) {
-               BMO_ITER(e, &siter, bm, &bmop, i ? "edgeout2":"edgeout1", BM_EDGE) {
-                       float cent[3] = {0, 0, 0}, mid[3];
-                       float vec[3];
-                       float fmval_tweak[3];
-                       BMVert *v1_other;
-                       BMVert *v2_other;
+       BMO_ITER(e, &siter, bm, &bmop, "edgeout", BM_EDGE) {
+               float cent[3] = {0, 0, 0}, mid[3];
+               float vec[3];
+               float fmval_tweak[3];
+               BMVert *v1_other;
+               BMVert *v2_other;
 
 #ifdef USE_BVH_VISIBILITY
-                       if (!BMBVH_EdgeVisible(bvhtree, e, ar, v3d, obedit) || !e->l)
-                               continue;
+               if (!BMBVH_EdgeVisible(bvhtree, e, ar, v3d, obedit) || !e->l)
+                       continue;
 #endif
 
-                       /* method for calculating distance:
-                        *
-                        * for each edge: calculate face center, then made a vector
-                        * from edge midpoint to face center.  offset edge midpoint
-                        * by a small amount along this vector. */
-
-                       /* 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;
-                       mid_v3_v3v3(cent, v1_other->co, v2_other->co);
-                       mid_v3_v3v3(mid, e->v1->co, e->v2->co);
-                       sub_v3_v3v3(vec, cent, mid);
-                       normalize_v3(vec);
-                       mul_v3_fl(vec, 0.01f);
+               /* method for calculating distance:
+                *
+                * for each edge: calculate face center, then made a vector
+                * from edge midpoint to face center.  offset edge midpoint
+                * by a small amount along this vector. */
 
-                       /* ratrher then adding to both verts, subtract from the mouse */
-                       sub_v2_v2v2(fmval_tweak, fmval, vec);
+               /* 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;
+               mid_v3_v3v3(cent, v1_other->co, v2_other->co);
+               mid_v3_v3v3(mid, e->v1->co, e->v2->co);
 
-                       d = mesh_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, fmval_tweak);
+               ED_view3d_project_float_v2(ar, cent, cent, projectMat);
+               ED_view3d_project_float_v2(ar, mid, mid, projectMat);
 
-                       if (d < dist) {
-                               side = i;
-                               dist = d;
-                       }
+               sub_v2_v2v2(vec, cent, mid);
+               normalize_v2(vec);
+               mul_v2_fl(vec, 0.1f);
+
+
+               /* ratrher then adding to both verts, subtract from the mouse */
+               sub_v2_v2v2(fmval_tweak, fmval, vec);
+
+               d_a = mesh_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, fmval_tweak);
+               d_b = mesh_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, fmval);
+
+               if (d_a > d_b) {
+                       BM_elem_select_set(bm, e, FALSE);
                }
        }
 
@@ -2553,11 +2551,6 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
                        BM_elem_select_set(bm, v_best, TRUE);
                }
 #endif
-
-       }
-       else {
-               /* de-select one of the sides */
-               BMO_slot_buffer_hflag_disable(bm, &bmop, side ? "edgeout1" : "edgeout2", BM_ELEM_SELECT, BM_EDGE, TRUE);
        }
 
        EDBM_selectmode_flush(em);