[Bf-blender-cvs] [22bbd1c] master: BMesh: improve rip tool /w mon-manifold verts

Campbell Barton noreply at git.blender.org
Mon May 4 23:23:15 CEST 2015


Commit: 22bbd1c51219aafb40adb3e9a206f660a621fd70
Author: Campbell Barton
Date:   Tue May 5 07:11:31 2015 +1000
Branches: master
https://developer.blender.org/rB22bbd1c51219aafb40adb3e9a206f660a621fd70

BMesh: improve rip tool /w mon-manifold verts

Can now rip from multiple fans (mixed single faces or larger regions)

Also add BM_vert_is_manifold_region which only checks if a vert has disconnected fans.

===================================================================

M	source/blender/bmesh/intern/bmesh_queries.c
M	source/blender/bmesh/intern/bmesh_queries.h
M	source/blender/editors/mesh/editmesh_rip.c

===================================================================

diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 031fc68..63e3617 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -917,6 +917,105 @@ bool BM_vert_is_manifold(const BMVert *v)
 	return (loop_num == loop_num_region);
 }
 
+#define LOOP_VISIT _FLAG_WALK
+#define EDGE_VISIT _FLAG_WALK
+
+static int bm_loop_region_count__recursive(BMEdge *e, BMVert *v)
+{
+	BMLoop *l_iter, *l_first;
+	int count = 0;
+
+	BLI_assert(!BM_ELEM_API_FLAG_TEST(e, EDGE_VISIT));
+	BM_ELEM_API_FLAG_ENABLE(e, EDGE_VISIT);
+
+	l_iter = l_first = e->l;
+	do {
+		if (l_iter->v == v) {
+			BMEdge *e_other = l_iter->prev->e;
+			if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
+				BM_ELEM_API_FLAG_ENABLE(l_iter, LOOP_VISIT);
+				count += 1;
+			}
+			if (!BM_ELEM_API_FLAG_TEST(e_other, EDGE_VISIT)) {
+				count += bm_loop_region_count__recursive(e_other, v);
+			}
+		}
+		else if (l_iter->next->v == v) {
+			BMEdge *e_other = l_iter->next->e;
+			if (!BM_ELEM_API_FLAG_TEST(l_iter->next, LOOP_VISIT)) {
+				BM_ELEM_API_FLAG_ENABLE(l_iter->next, LOOP_VISIT);
+				count += 1;
+			}
+			if (!BM_ELEM_API_FLAG_TEST(e_other, EDGE_VISIT)) {
+				count += bm_loop_region_count__recursive(e_other, v);
+			}
+		}
+		else {
+			BLI_assert(0);
+		}
+	} while ((l_iter = l_iter->radial_next) != l_first);
+
+	return count;
+}
+
+static int bm_loop_region_count__clear(BMLoop *l)
+{
+	int count = 0;
+	BMEdge *e_iter, *e_first;
+
+	/* clear flags */
+	e_iter = e_first = l->e;
+	do {
+		BM_ELEM_API_FLAG_DISABLE(e_iter, EDGE_VISIT);
+		if (e_iter->l) {
+			BMLoop *l_iter, *l_first;
+			l_iter = l_first = e_iter->l;
+			do {
+				if (l_iter->v == l->v) {
+					BM_ELEM_API_FLAG_DISABLE(l_iter, LOOP_VISIT);
+					count += 1;
+				}
+			} while ((l_iter = l_iter->radial_next) != l_first);
+		}
+	} while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != e_first);
+
+	return count;
+}
+
+/**
+ * The number of loops connected to this loop (not including disconnected regions).
+ */
+int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total)
+{
+	const int count       = bm_loop_region_count__recursive(l->e, l->v);
+	const int count_total = bm_loop_region_count__clear(l);
+	if (r_loop_total) {
+		*r_loop_total = count_total;
+	}
+	return count;
+}
+
+#undef LOOP_VISIT
+#undef EDGE_VISIT
+
+int BM_loop_region_loops_count(BMLoop *l)
+{
+	return BM_loop_region_loops_count_ex(l, NULL);
+}
+
+/**
+ * A version of #BM_vert_is_manifold
+ * which only checks if we're connected to multiple isolated regions.
+ */
+bool BM_vert_is_manifold_region(const BMVert *v)
+{
+	BMLoop *l_first = BM_vert_find_first_loop((BMVert *)v);
+	int count, count_total;
+
+	count = BM_loop_region_loops_count_ex(l_first, &count_total);
+	return (count == count_total);
+}
+
 /**
  * Check if the edge is convex or concave
  * (depends on face winding)
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index e4f7c78..f0a348d 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -85,12 +85,15 @@ bool    BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 BLI_INLINE bool    BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 
 bool    BM_vert_is_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool    BM_vert_is_manifold_region(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 BLI_INLINE bool    BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 bool    BM_vert_is_boundary(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 BLI_INLINE bool    BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 BLI_INLINE bool    BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 bool    BM_edge_is_convex(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 
+int     BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+int     BM_loop_region_loops_count(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
 bool    BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 float   BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index abd88ae..1e207a8 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -532,14 +532,14 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
 	BMesh *bm = em->bm;
 	BMIter iter, liter;
 	BMLoop *l;
-	BMEdge *e, *e2;
+	BMEdge *e2;
 	BMVert *v;
 	const int totvert_orig = bm->totvert;
 	int i;
 	float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
 	float dist_sq = FLT_MAX;
 	float d;
-	bool is_wire;
+	bool is_wire, is_manifold_region;
 
 	BMEditSelection ese;
 	int totboundary_edge = 0;
@@ -565,17 +565,19 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
 	}
 
 	is_wire = BM_vert_is_wire(v);
+	is_manifold_region = BM_vert_is_manifold_region(v);
 
 	e2 = NULL;
 
-	if (v->e) {
+	{
+		BMEdge *e;
 		/* find closest edge to mouse cursor */
 		BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
 			/* consider wire as boundary for this purpose,
 			 * otherwise we can't a face away from a wire edge */
 			totboundary_edge += (BM_edge_is_boundary(e) || BM_edge_is_wire(e));
 			if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
-				if (BM_edge_is_manifold(e)) {
+				if ((is_manifold_region == false) || BM_edge_is_manifold(e)) {
 					d = edbm_rip_edgedist_squared(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT);
 					if ((e2 == NULL) || (d < dist_sq)) {
 						dist_sq = d;
@@ -584,67 +586,60 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
 				}
 			}
 		}
-
-		/* if we are ripping a single vertex from 3 faces,
-		 * then measure the distance to the face corner as well as the edge */
-		if (BM_vert_face_count_is_equal(v, 3) &&
-		    BM_vert_edge_count_is_equal(v, 3))
-		{
-			BMEdge *e_all[3];
-			BMLoop *l_all[3];
-			int i1, i2;
-
-			BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
-			BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
-
-			/* not do a loop similar to the one above, but test against loops */
-			for (i1 = 0; i1 < 3; i1++) {
-				/* consider wire as boundary for this purpose,
-				 * otherwise we can't a face away from a wire edge */
-				float l_mid_co[3];
-				l = l_all[i1];
-				edbm_calc_loop_co(l, l_mid_co);
-				d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
-				if ((e2 == NULL) || (d < dist_sq)) {
-					dist_sq = d;
-
-					/* find the edge that is not in this loop */
-					e2 = NULL;
-					for (i2 = 0; i2 < 3; i2++) {
-						if (!BM_edge_in_loop(e_all[i2], l)) {
-							e2 = e_all[i2];
-							break;
-						}
-					}
-					BLI_assert(e2 != NULL);
-				}
-			}
-		}
 	}
 
-	if (e2) {
+	if (e2 && (is_manifold_region == false)) {
 		/* Try to split off a non-manifold fan (when we have multiple disconnected fans) */
-
-		/* note: we're lazy here and first split then check there are any faces remaining,
-		 * this isn't good practice, however its less hassle then checking for multiple-disconnected regions */
 		BMLoop *l_sep = e2->l->v == v ? e2->l : e2->l->next;
 		BMVert *v_new;
+
 		BLI_assert(l_sep->v == v);
 		v_new = bmesh_urmv_loop_region(bm, l_sep);
-		if (BM_vert_find_first_loop(v)) {
-			BM_vert_select_set(bm, v, false);
-			BM_select_history_remove(bm, v);
+		BLI_assert(BM_vert_find_first_loop(v));
 
-			BM_vert_select_set(bm, v_new, true);
-			if (ese.ele) {
-				BM_select_history_store(bm, v_new);
-			}
+		BM_vert_select_set(bm, v, false);
+		BM_select_history_remove(bm, v);
 
-			return OPERATOR_FINISHED;
+		BM_vert_select_set(bm, v_new, true);
+		if (ese.ele) {
+			BM_select_history_store(bm, v_new);
 		}
-		else {
-			/* rewind */
-			BM_vert_splice(bm, v, v_new);
+		return OPERATOR_FINISHED;
+	}
+
+	/* if we are ripping a single vertex from 3 faces,
+	 * then measure the distance to the face corner as well as the edge */
+	if (BM_vert_face_count_is_equal(v, 3) &&
+	    BM_vert_edge_count_is_equal(v, 3))
+	{
+		BMEdge *e_all[3];
+		BMLoop *l_all[3];
+		int i1, i2;
+
+		BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
+		BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
+
+		/* not do a loop similar to the one above, but test against loops */
+		for (i1 = 0; i1 < 3; i1++) {
+			/* consider wire as boundary for this purpose,
+			 * otherwise we can't a face away from a wire edge */
+			float l_mid_co[3];
+			l = l_all[i1];
+			edbm_calc_loop_co(l, l_mid_co);
+			d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
+			if ((e2 == NULL) || (d < dist_sq)) {
+				dist_sq = d;
+
+				/* find the edge that is not in this loop */
+				e2 = NULL;
+				for (i2 = 0; i2 < 3; i2++) {
+					if (!BM_edge_in_loop(e_all[i2], l)) {
+						e2 = e_all[i2];
+						break;
+					}
+				}
+				BLI_assert(e2 != NULL);
+			}
 		}
 	}
 
@@ -703,6 +698,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
 					}
 				}
 				else {
+					BMEdge *e;
 					/* a wire vert, find the best edge */
 					BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) {
 						if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {




More information about the Bf-blender-cvs mailing list