Add option to set object origin to the center of mass
authorSergej Reich <sergej.reich@googlemail.com>
Sat, 20 Oct 2012 16:48:54 +0000 (16:48 +0000)
committerSergej Reich <sergej.reich@googlemail.com>
Sat, 20 Oct 2012 16:48:54 +0000 (16:48 +0000)
This uses the weighted average of polygon centroids based on area
It work well in most cases but will be slightly wrong when polygons have
many vertices.

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

index 9fffb71785b8fdfebed63101e35e118a59e70fea..2f889084d0e55f6d934db07d2ef444b3321b17e3 100644 (file)
@@ -292,6 +292,7 @@ void create_vert_edge_map(MeshElemMap **map, int **mem,
 int BKE_mesh_minmax(struct Mesh *me, float r_min[3], float r_max[3]);
 int BKE_mesh_center_median(struct Mesh *me, float cent[3]);
 int BKE_mesh_center_bounds(struct Mesh *me, float cent[3]);
+int BKE_mesh_center_centroid(struct Mesh *me, float cent[3]);
 void BKE_mesh_translate(struct Mesh *me, float offset[3], int do_keys);
 
 /* mesh_validate.c */
index c244317ccb7a619ca327487ecc829380a6071c68..30eaf461430b0a630a75a8d31a3d3f12ad6d57fd 100644 (file)
@@ -3175,6 +3175,32 @@ int BKE_mesh_center_bounds(Mesh *me, float cent[3])
        return 0;
 }
 
+int BKE_mesh_center_centroid(Mesh *me, float cent[3])
+{
+       int i = me->totpoly;
+       MPoly *mpoly;
+       float poly_area;
+       float total_area = 0.0f;
+       float poly_cent[3];
+       
+       zero_v3(cent);
+       
+       /* calculate a weighted average of polygon centroids */
+       for (mpoly = me->mpoly; i--; mpoly++) {
+               BKE_mesh_calc_poly_center(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+               poly_area = BKE_mesh_calc_poly_area(mpoly, me->mloop + mpoly->loopstart, me->mvert, NULL);
+               
+               madd_v3_v3fl(cent, poly_cent, poly_area);
+               total_area += poly_area;
+       }
+       /* otherwise we get NAN for 0 polys */
+       if (me->totpoly) {
+               mul_v3_fl(cent, 1.0f / total_area);
+       }
+
+       return (me->totpoly != 0);
+}
+
 void BKE_mesh_translate(Mesh *me, float offset[3], int do_keys)
 {
        int i = me->totvert;
index 4c95884a51a2751616e36a596b8f91cc4faac7e5..9bf1bbfa1025b1700af44b6ab1c3ad70fa561136 100644 (file)
@@ -654,7 +654,8 @@ void OBJECT_OT_transform_apply(wmOperatorType *ot)
 enum {
        GEOMETRY_TO_ORIGIN = 0,
        ORIGIN_TO_GEOMETRY,
-       ORIGIN_TO_CURSOR
+       ORIGIN_TO_CURSOR,
+       ORIGIN_TO_CENTER_OF_MASS
 };
 
 static int object_origin_set_exec(bContext *C, wmOperator *op)
@@ -785,6 +786,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
                                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_CENTROID) { BKE_mesh_center_median(me, cent); }
                                else { BKE_mesh_center_bounds(me, cent); }
 
@@ -980,6 +982,8 @@ void OBJECT_OT_origin_set(wmOperatorType *ot)
                                     "Move object origin to center of object geometry"},
                {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)"},
                {0, NULL, 0, NULL, NULL}
        };
        
@@ -1006,4 +1010,3 @@ void OBJECT_OT_origin_set(wmOperatorType *ot)
        ot->prop = RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", "");
        RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_CENTROID, "Center", "");
 }
-