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.
This commit is contained in:
parent
43a6cf1504
commit
361c7cbbc5
Notes:
blender-bot
2023-02-14 08:47:25 +01:00
Referenced by issue #65986, Set Origin to center of mass has to be performed several times Referenced by issue #52434, Setting origin to Center of Mass on zero-volume objects produces wrong results now in 2.79
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue