[Bf-blender-cvs] [361c7cbbc57] master: Fix T52434: Restore mesh center of mass calculation

Campbell Barton noreply at git.blender.org
Mon Aug 21 07:15:06 CEST 2017


Commit: 361c7cbbc57720db3b04698c7e45fe72297e2b24
Author: Campbell Barton
Date:   Mon Aug 21 15:06:07 2017 +1000
Branches: master
https://developer.blender.org/rB361c7cbbc57720db3b04698c7e45fe72297e2b24

Fix T52434: Restore mesh center of mass calculation

The new method while improved for solid objects
doesn't work for non-manifold meshes, keep both.

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

M	source/blender/blenkernel/BKE_mesh.h
M	source/blender/blenkernel/intern/mesh_evaluate.c
M	source/blender/editors/object/object_transform.c

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

diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 9480679f817..f3b2b653e3d 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -280,7 +280,8 @@ void BKE_mesh_poly_edgebitmap_insert(
 
 bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]);
 bool BKE_mesh_center_bounds(const struct Mesh *me, float r_cent[3]);
-bool BKE_mesh_center_centroid(const struct Mesh *me, float r_cent[3]);
+bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]);
+bool BKE_mesh_center_of_volume(const struct Mesh *me, float r_cent[3]);
 
 void BKE_mesh_calc_volume(
         const struct MVert *mverts, const int mverts_num,
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 5dfcef9f9bf..643ca3ee536 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -2002,11 +2002,14 @@ float BKE_mesh_calc_poly_area(
  * - http://forums.cgsociety.org/archive/index.php?t-756235.html
  * - http://www.globalspec.com/reference/52702/203279/4-8-the-centroid-of-a-tetrahedron
  *
- * \note volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid
- * (so division can be done once at the end)
- * \note results will have bias if polygon is non-planar.
+ * \note
+ * - Volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid
+ *   (so division can be done once at the end).
+ * - Results will have bias if polygon is non-planar.
+ * - The resulting volume will only be correct if the mesh is manifold and has consistent face winding
+ *   (non-contiguous face normals or holes in the mesh surface).
  */
-static float mesh_calc_poly_volume_and_weighted_centroid(
+static float mesh_calc_poly_volume_centroid(
         const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray,
         float r_cent[3])
 {
@@ -2043,6 +2046,43 @@ static float mesh_calc_poly_volume_and_weighted_centroid(
 	return total_volume;
 }
 
+/**
+ * \note
+ * - Results won't be correct if polygon is non-planar.
+ * - This has the advantage over #mesh_calc_poly_volume_centroid
+ *   that it doesn't depend on solid geometry, instead it weights the surface by volume.
+ */
+static float mesh_calc_poly_area_centroid(
+        const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray,
+        float r_cent[3])
+{
+	int i;
+	float tri_area;
+	float total_area = 0.0f;
+	float v1[3], v2[3], v3[3], normal[3], tri_cent[3];
+
+	BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, normal);
+	copy_v3_v3(v1, mvarray[loopstart[0].v].co);
+	copy_v3_v3(v2, mvarray[loopstart[1].v].co);
+	zero_v3(r_cent);
+
+	for (i = 2; i < mpoly->totloop; i++) {
+		copy_v3_v3(v3, mvarray[loopstart[i].v].co);
+
+		tri_area = area_tri_signed_v3(v1, v2, v3, normal);
+		total_area += tri_area;
+
+		mid_v3_v3v3v3(tri_cent, v1, v2, v3);
+		madd_v3_v3fl(r_cent, tri_cent, tri_area);
+
+		copy_v3_v3(v2, v3);
+	}
+
+	mul_v3_fl(r_cent, 1.0f / total_area);
+
+	return total_area;
+}
+
 #if 0 /* slow version of the function below */
 void BKE_mesh_calc_poly_angles(MPoly *mpoly, MLoop *loopstart,
                                MVert *mvarray, float angles[])
@@ -2157,7 +2197,40 @@ bool BKE_mesh_center_bounds(const Mesh *me, float r_cent[3])
 	return false;
 }
 
-bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3])
+bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
+{
+	int i = me->totpoly;
+	MPoly *mpoly;
+	float poly_area;
+	float total_area = 0.0f;
+	float poly_cent[3];
+
+	zero_v3(r_cent);
+
+	/* calculate a weighted average of polygon centroids */
+	for (mpoly = me->mpoly; i--; mpoly++) {
+		poly_area = mesh_calc_poly_area_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+
+		madd_v3_v3fl(r_cent, poly_cent, poly_area);
+		total_area += poly_area;
+	}
+	/* otherwise we get NAN for 0 polys */
+	if (me->totpoly) {
+		mul_v3_fl(r_cent, 1.0f / total_area);
+	}
+
+	/* zero area faces cause this, fallback to median */
+	if (UNLIKELY(!is_finite_v3(r_cent))) {
+		return BKE_mesh_center_median(me, r_cent);
+	}
+
+	return (me->totpoly != 0);
+}
+
+/**
+ * \note Mesh must be manifold with consistent face-winding, see #mesh_calc_poly_volume_centroid for details.
+ */
+bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3])
 {
 	int i = me->totpoly;
 	MPoly *mpoly;
@@ -2169,7 +2242,7 @@ bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3])
 
 	/* calculate a weighted average of polyhedron centroids */
 	for (mpoly = me->mpoly; i--; mpoly++) {
-		poly_volume = mesh_calc_poly_volume_and_weighted_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+		poly_volume = mesh_calc_poly_volume_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
 
 		/* poly_cent is already volume-weighted, so no need to multiply by the volume */
 		add_v3_v3(r_cent, poly_cent);
@@ -2189,6 +2262,7 @@ bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3])
 
 	return (me->totpoly != 0);
 }
+
 /** \} */
 
 
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index ccbfc3a4f29..04d8a65e043 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -720,7 +720,8 @@ enum {
 	GEOMETRY_TO_ORIGIN = 0,
 	ORIGIN_TO_GEOMETRY,
 	ORIGIN_TO_CURSOR,
-	ORIGIN_TO_CENTER_OF_MASS
+	ORIGIN_TO_CENTER_OF_MASS_SURFACE,
+	ORIGIN_TO_CENTER_OF_MASS_VOLUME,
 };
 
 static int object_origin_set_exec(bContext *C, wmOperator *op)
@@ -874,10 +875,21 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
 			if (obedit == NULL && ob->type == OB_MESH) {
 				Mesh *me = ob->data;
 
-				if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
-				else if (centermode == ORIGIN_TO_CENTER_OF_MASS)    { BKE_mesh_center_centroid(me, cent); }
-				else if (around == V3D_AROUND_CENTER_MEAN)          { BKE_mesh_center_median(me, cent); }
-				else                                                { BKE_mesh_center_bounds(me, cent); }
+				if (centermode == ORIGIN_TO_CURSOR) {
+					/* done */
+				}
+				else if (centermode == ORIGIN_TO_CENTER_OF_MASS_SURFACE) {
+					BKE_mesh_center_of_surface(me, cent);
+				}
+				else if (centermode == ORIGIN_TO_CENTER_OF_MASS_VOLUME) {
+					BKE_mesh_center_of_volume(me, cent);
+				}
+				else if (around == V3D_AROUND_CENTER_MEAN) {
+					BKE_mesh_center_median(me, cent);
+				}
+				else {
+					BKE_mesh_center_bounds(me, cent);
+				}
 
 				negate_v3_v3(cent_neg, cent);
 				BKE_mesh_translate(me, cent_neg, 1);
@@ -1085,11 +1097,14 @@ void OBJECT_OT_origin_set(wmOperatorType *ot)
 	static EnumPropertyItem prop_set_center_types[] = {
 		{GEOMETRY_TO_ORIGIN, "GEOMETRY_ORIGIN", 0, "Geometry to Origin", "Move object geometry to object origin"},
 		{ORIGIN_TO_GEOMETRY, "ORIGIN_GEOMETRY", 0, "Origin to Geometry",
-		                     "Move object origin to center of object geometry"},
+		 "Calculate the center of geometry based on the current pivot point (median, otherwise bounding-box)"},
 		{ORIGIN_TO_CURSOR, "ORIGIN_CURSOR", 0, "Origin to 3D Cursor",
-		                   "Move object origin to position of the 3D cursor"},
-		{ORIGIN_TO_CENTER_OF_MASS, "ORIGIN_CENTER_OF_MASS", 0, "Origin to Center of Mass",
-		                           "Move object origin to the object center of mass (assuming uniform density)"},
+		 "Move object origin to position of the 3D cursor"},
+		/* Intentional naming mismatch since some scripts refer to this. */
+		{ORIGIN_TO_CENTER_OF_MASS_SURFACE, "ORIGIN_CENTER_OF_MASS", 0, "Origin to Center of Mass (Surface)",
+		 "Calculate the center of mass calculated from the surface area"},
+		{ORIGIN_TO_CENTER_OF_MASS_VOLUME, "ORIGIN_CENTER_OF_VOLUME", 0, "Origin to Center of Mass (Volume)",
+		 "Calculate the center of mass from the volume (must be manifold geometry with consistent normals)"},
 		{0, NULL, 0, NULL, NULL}
 	};



More information about the Bf-blender-cvs mailing list