[Bf-blender-cvs] [cc7cfd6] master: Mesh Tool: removes degenerate edges, faces and face ears.

Campbell Barton noreply at git.blender.org
Mon Feb 17 01:41:59 CET 2014


Commit: cc7cfd661736f67d3f97108c38998b159d87ec9b
Author: Campbell Barton
Date:   Mon Feb 17 11:32:35 2014 +1100
https://developer.blender.org/rBcc7cfd661736f67d3f97108c38998b159d87ec9b

Mesh Tool: removes degenerate edges, faces and face ears.

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

M	release/scripts/startup/bl_ui/space_view3d.py
M	source/blender/bmesh/intern/bmesh_opdefines.c
M	source/blender/bmesh/intern/bmesh_operators_private.h
M	source/blender/bmesh/operators/bmo_dissolve.c
M	source/blender/editors/mesh/editmesh_tools.c
M	source/blender/editors/mesh/mesh_intern.h
M	source/blender/editors/mesh/mesh_ops.c

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

diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 1ebe9aa..c79ad56 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2318,8 +2318,10 @@ class VIEW3D_MT_edit_mesh_clean(Menu):
 
         layout.separator()
 
-        layout.operator("mesh.fill_holes")
+        layout.operator("mesh.dissolve_degenerate")
+        layout.operator("mesh.dissolve_limited")
         layout.operator("mesh.vert_connect_nonplanar")
+        layout.operator("mesh.fill_holes")
 
 
 class VIEW3D_MT_edit_mesh_delete(Menu):
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 0c75597..0c8347f 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1022,6 +1022,25 @@ static BMOpDefine bmo_dissolve_limit_def = {
 };
 
 /*
+ * Degenerate Dissolve.
+ *
+ * Dissolve edges with no length, faces with no area.
+ */
+static BMOpDefine bmo_dissolve_degenerate_def = {
+	"dissolve_degenerate",
+	/* slots_in */
+	{{"dist", BMO_OP_SLOT_FLT}, /* minimum distance to consider degenerate */
+	 {"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}},
+	 {{'\0'}},
+	},
+	/* slots_out */
+	{{"verts.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}},  /* output vertices */
+	 {{'\0'}}},
+	bmo_dissolve_degenerate_exec,
+	BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+};
+
+/*
  * Triangulate.
  */
 static BMOpDefine bmo_triangulate_def = {
@@ -1828,8 +1847,9 @@ const BMOpDefine *bmo_opdefines[] = {
 	&bmo_delete_def,
 	&bmo_dissolve_edges_def,
 	&bmo_dissolve_faces_def,
-	&bmo_dissolve_limit_def,
 	&bmo_dissolve_verts_def,
+	&bmo_dissolve_limit_def,
+	&bmo_dissolve_degenerate_def,
 	&bmo_duplicate_def,
 	&bmo_holes_fill_def,
 	&bmo_face_attribute_fill_def,
diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h
index 517a2c4..9c1b708 100644
--- a/source/blender/bmesh/intern/bmesh_operators_private.h
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -56,8 +56,9 @@ void bmo_create_vert_exec(BMesh *bm, BMOperator *op);
 void bmo_delete_exec(BMesh *bm, BMOperator *op);
 void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op);
 void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op);
-void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op);
 void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op);
+void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op);
+void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op);
 void bmo_duplicate_exec(BMesh *bm, BMOperator *op);
 void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op);
 void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op);
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 60b96e3..334242f 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -474,3 +474,144 @@ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
 
 	BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "region.out", BM_FACE, FACE_NEW);
 }
+
+
+#define EDGE_MARK 1
+#define EDGE_COLLAPSE 2
+
+static void bm_mesh_edge_collapse_flagged(BMesh *bm, const int flag, const short oflag)
+{
+	BMO_op_callf(bm, flag, "collapse edges=%fe", oflag);
+}
+
+void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
+{
+	const float dist = BMO_slot_float_get(op->slots_in, "dist");
+	const float dist_sq = dist * dist;
+
+	bool found;
+	BMIter eiter;
+	BMEdge *e;
+
+
+	BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK);
+
+	/* collapse zero length edges, this accounts for zero area faces too */
+	found = false;
+	BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+		if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+			if (BM_edge_calc_length_squared(e) < dist_sq) {
+				BMO_elem_flag_enable(bm, e, EDGE_COLLAPSE);
+				found = true;
+			}
+		}
+
+		/* clear all loop tags (checked later) */
+		if (e->l) {
+			BMLoop *l_iter, *l_first;
+			l_iter = l_first = e->l;
+			do {
+				BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
+			} while ((l_iter = l_iter->radial_next) != l_first);
+		}
+	}
+
+	if (found) {
+		bm_mesh_edge_collapse_flagged(bm, op->flag, EDGE_COLLAPSE);
+	}
+
+
+	/* clip degenerate ears from the face */
+	found = false;
+	BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+		if (e->l && BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+			BMLoop *l_iter, *l_first;
+			l_iter = l_first = e->l;
+			do {
+				if (
+				    /* check the loop hasn't already been tested (and flag not to test again) */
+				    !BM_elem_flag_test(l_iter, BM_ELEM_TAG) &&
+				    (BM_elem_flag_enable(l_iter, BM_ELEM_TAG),
+
+				     /* check we're marked to tested (radial edge already tested) */
+				     BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_MARK) &&
+
+				     /* check edges are not already going to be collapsed */
+				     !BMO_elem_flag_test(bm, l_iter->e, EDGE_COLLAPSE) &&
+				     !BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE)))
+				{
+					/* test if the faces loop (ear) is degenerate */
+					float dir_prev[3], len_prev;
+					float dir_next[3], len_next;
+
+
+					sub_v3_v3v3(dir_prev, l_iter->prev->v->co, l_iter->v->co);
+					sub_v3_v3v3(dir_next, l_iter->next->v->co, l_iter->v->co);
+
+					len_prev = normalize_v3(dir_prev);
+					len_next = normalize_v3(dir_next);
+
+					if ((len_v3v3(dir_prev, dir_next) * min_ff(len_prev, len_next)) <= dist) {
+						bool reset = false;
+
+						if (fabsf(len_prev - len_next) <= dist) {
+							/* both edges the same length */
+							if (l_iter->f->len == 3) {
+								/* ideally this would have been discovered with short edge test above */
+								BMO_elem_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE);
+								found = true;
+							}
+							else {
+								/* add a joining edge and tag for removal */
+								BMLoop *l_split;
+								if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
+									BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
+									found = true;
+									reset = true;
+								}
+							}
+						}
+						else if (len_prev < len_next) {
+							/* split 'l_iter->e', then join the vert with next */
+							BMVert *v_new;
+							BMEdge *e_new;
+							BMLoop *l_split;
+							v_new = BM_edge_split(bm, l_iter->e, l_iter->v, &e_new, len_prev / len_next);
+							BLI_assert(v_new == l_iter->next->v);
+							(void)v_new;
+							if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
+								BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
+								found = true;
+							}
+							reset = true;
+						}
+						else if (len_next < len_prev) {
+							/* split 'l_iter->prev->e', then join the vert with next */
+							BMVert *v_new;
+							BMEdge *e_new;
+							BMLoop *l_split;
+							v_new = BM_edge_split(bm, l_iter->prev->e, l_iter->v, &e_new, len_next / len_prev);
+							BLI_assert(v_new == l_iter->prev->v);
+							(void)v_new;
+							if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
+								BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
+								found = true;
+							}
+							reset = true;
+						}
+
+						if (reset) {
+							/* we can't easily track where we are on the radial edge, reset! */
+							l_first = l_iter;
+						}
+					}
+				}
+			} while ((l_iter = l_iter->radial_next) != l_first);
+		}
+	}
+
+	if (found) {
+		bm_mesh_edge_collapse_flagged(bm, op->flag, EDGE_COLLAPSE);
+	}
+
+}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index dbb1552..f8b50d4 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -313,6 +313,12 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
 	}
 }
 
+static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int totelem[3])
+{
+	BKE_reportf(reports, RPT_INFO,
+	            "Removed: %d vertices, %d edges, %d faces",
+	            totelem[0] - bm->totvert, totelem[1] - bm->totedge, totelem[2] - bm->totface);
+}
 
 /* Note, these values must match delete_mesh() event values */
 static EnumPropertyItem prop_mesh_delete_types[] = {
@@ -453,9 +459,7 @@ static int edbm_delete_loose_exec(bContext *C, wmOperator *op)
 
 	EDBM_update_generic(em, true, true);
 
-	BKE_reportf(op->reports, RPT_INFO,
-	            "Removed: %d vertices, %d edges, %d faces",
-	            totelem[0] - bm->totvert, totelem[1] - bm->totedge, totelem[2] - bm->totface);
+	edbm_report_delete_info(op->reports, bm, totelem);
 
 	return OPERATOR_FINISHED;
 }
@@ -3676,6 +3680,51 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
 	                  "Delimit dissolve operation");
 }
 
+static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
+{
+	Object *obedit = CTX_data_edit_object(C);
+	BMEditMesh *em = BKE_editmesh_from_object(obedit);
+	const float thresh = RNA_float_get(op->ptr, "threshold");
+	BMesh *bm = em->bm;
+	const int totelem[3] = {bm->totvert, bm->totedge, bm->totface};
+
+	if (!EDBM_op_callf(
+	        em, op,
+	        "dissolve_degenerate edges=%he dist=%f",
+	        BM_ELEM_SELECT, thresh))
+	{
+		return OPERATOR_CANCELLED;
+	}
+
+	/* tricky to maintain correct selection here, so just flush up from verts */
+	EDBM_select_flush(em);
+
+	EDBM_update_generic(em, true, true);
+
+	edbm_report_delete_info(op->reports, bm, totelem);
+
+	return OPERATOR_FINISHED;
+}
+
+void MESH_OT_dissolve_degenerate(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Degenerate Dissolve";
+	ot->idname = "MESH_OT_dissolve_degenerate";
+	ot->description = "Dissolve zero area faces and zero length edges";
+
+	/* api callbacks */
+	ot->exec = edbm_dissolve_degenerate_exec;
+	ot->poll = ED_operator_editmesh;
+
+	/* flags */
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+	RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f,  "Merge Distance",
+	              "Minimum distance between elements to merge", 0.00001, 10.0);
+}
+
+
 /* internall

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list