## Center of Mass

Discussions regarding modelling with SOFTIMAGE© mc_axe
Posts: 405
Joined: 12 Mar 2013, 18:44

### Center of Mass

Hello evryone, anyone knows if we already have a tool to calculate center of mass for a closed mesh for example a rock ( assuming uniform density - same material everywhere) ?

Transform > 'Move center to vertices' preety much averages the possitions of vertices, so it depends on the topology,
A ball that has its top part subdivided a few times will have a center close to the top, while real center of mass should remain pretty mcuh in the same place.

I tried also rigid bodies where there is inertal properties > center of mass, but is litterally the same algorithm.

Here is a response that i found on google groups:
To find the center of gravity (or "centroid") of a polygonal mesh:
convert all of its faces to triangles, and average the centroids of
all of the triangles, weighted by the doubled area of each face.
Wikipedia calls it <a href="http://en.wikipedia.org/wiki/
Centroid#Centroid_by_geometric_decomposition">Centroid by Geometric
Decomposition</a>.

C = Centroid <vector>, A = (area of a face * 2)
R = face centroid = average of vertices making the face <vector>
C = [sum of all (A*R)] / [sum of all R]
Thx mc_axe
Posts: 405
Joined: 12 Mar 2013, 18:44

### Re: Center of Mass

Hi all, tried to figure this out in ICE. I sumed up all the polygon possitions of a mesh factored by their coresponding area, then i divided the result by the sum of total area of all polygons.
Then i fed the result on a null (host of the tree) as possition to visualize the new center (center of mass) but the null wont move for a reason (i can only showcase the value of Center of Mass).

^^The above is abit different to the proposed method (as seen in first post), i did not tried to implement centroids or something crazy that can solve evrything, my ICE knowledge is super limited. In the example i added a few loops in the right side of a 2x2x2 cube (with 2 subs in all axes) and i split once the top left then triangulate.
Move center to vertices would have taken the center at x: -0,0227 y: 0,0455 z: 1,1591, but the compound yields (0,0,1) which is the actual center of mass for a 2x2x2 cube positioned at (0,0,1). So regarldless of topology and dencity of components we can still find the "real" center.

*Requires freeze tranformations.
*Assumes a closed mesh no interiors and crazy stuff.
*Requires a triangulated mesh as input, that is because polygon possitions for triangles is their actual centroid which is not the case for example on a very random ngon

If anyone can help me so i can get the null to move that would be cool, thnx. Kolya
Posts: 5
Joined: 03 Oct 2017, 19:17

### Re: Center of Mass

to move the null, you need to change null.kine.global attribute.
You do not have the required permissions to view the files attached to this post. mc_axe
Posts: 405
Joined: 12 Mar 2013, 18:44

### Re: Center of Mass

Thx alot Kolya you the best! Next Ill try to figure out how it can work without a need to freeze translations , to update soon. myara
Posts: 389
Joined: 28 Sep 2011, 10:33

### Re: Center of Mass

I gave it a try and this is what I've got. It calculates the center of mass of the selected polygon mesh, creates a null and put the coordinates on it.

It calculates from the internal triangles so you don't need to triangulaze it, and it converts the values to global coordinates so you don't need to freeze the object either.

Code: Select all

``````#Python
xsi = Application
log = LogMessage

import math

def distanceBetween2points(A,B):
'''
Return Distance between 2 points in 3D Space
distanceBetween2points([x,y,z],[x,y,z])
'''
return abs(math.sqrt(math.pow(B-A,2) + math.pow(B-A,2) + math.pow(B-A,2)))

def getCenterOfMass(obj):
geo = obj.ActivePrimitive.Geometry
tris = geo.Triangles
totalArea = 0
sx=0
sy=0
sz=0
for tri in tris:
# Get Position of Triangle
triPos = tri.PositionArray
triPosX = triPos
triPosY = triPos
triPosZ = triPos

# Convert Position to Global and get Global Centroid of the triangle
triPos_A = XSIMath.CreateVector3(triPosX, triPosY, triPosZ)
triPos_B = XSIMath.CreateVector3(triPosX, triPosY, triPosZ)
triPos_C = XSIMath.CreateVector3(triPosX, triPosY, triPosZ)
triPos_A_G = XSIMath.MapObjectPositionToWorldSpace(obj.Kinematics.Global.Transform, triPos_A)
triPos_B_G = XSIMath.MapObjectPositionToWorldSpace(obj.Kinematics.Global.Transform, triPos_B)
triPos_C_G = XSIMath.MapObjectPositionToWorldSpace(obj.Kinematics.Global.Transform, triPos_C)

triCenter_G = [(triPos_A_G.X + triPos_B_G.X + triPos_C_G.X)/3, (triPos_A_G.Y + triPos_B_G.Y + triPos_C_G.Y)/3, (triPos_A_G.Z + triPos_B_G.Z + triPos_C_G.Z)/3]

# Get Triangle Area with Edges lenght and Semi Perimeter equation
edgeA = distanceBetween2points([triPosX, triPosY, triPosZ], [triPosX, triPosY, triPosZ])
edgeB = distanceBetween2points([triPosX, triPosY, triPosZ], [triPosX, triPosY, triPosZ])
edgeC = distanceBetween2points([triPosX, triPosY, triPosZ], [triPosX, triPosY, triPosZ])
semiPerimeter = (edgeA + edgeB+ edgeC) / 2
area = (semiPerimeter*abs(semiPerimeter-edgeA)*abs(semiPerimeter-edgeB)*abs(semiPerimeter-edgeC)) ** 0.5

sx += triCenter_G * area
sy += triCenter_G * area
sz += triCenter_G * area

totalArea += area

# Calculate Center of Mass
nulx = sx/totalArea
nuly = sy/totalArea
nulz = sz/totalArea

return [nulx, nuly, nulz]

#------------------

# Selection
obj = xsi.Selection(0)

# Create Null, and Assign coordinates
nul = xsi.ActiveSceneRoot.AddNull('nul')
centerOfMass = getCenterOfMass(obj)
nul.Kinematics.Global.posx = centerOfMass
nul.Kinematics.Global.posy = centerOfMass
nul.Kinematics.Global.posz = centerOfMass
``````
M.Yara
Character Modeler | Softimage Generalist (sort of) rray
Moderator
Posts: 1684
Joined: 26 Sep 2009, 15:51
Location: Bonn, Germany

### Re: Center of Mass

Nice! For solid bodies then you would probably convert the mesh into tetrahedrons then use the same algorithm.

I looked a bit into it.. always thought that would be something almost as simple as triangulation, but it seems more complicated.
softimage resources section updated Feb 7 2019 mc_axe
Posts: 405
Joined: 12 Mar 2013, 18:44

### Re: Center of Mass

Kudos @Martin you are beyond awesome!  @rray incredible idea to break down the mesh in to tiny bits in order to solve all kinds of solid meshes, im going to try a voxelizer just out of curiosity at the weekend to see wat kind of resolution i can get  myara
Posts: 389
Joined: 28 Sep 2011, 10:33

### Re: Center of Mass

Thanks, I hope you find it useful.

Well, although I think I'm right, I'm not completely sure about my math here, because it's not really my expertise.

A little break down of what I did.

Since you can access the internal triangle data from the object and the triangles positions (vertices positions), you don't need to triangulaze the object. You can do it even with Ngons.
So I did that with obj.ActivePrimitive.Geometry.Triangles and it's PositionArray.

I based my code from the physics equation where you calculate the center of mass between multiple bodies with different mass :
center of mass = sum ( position N * mass N ) / sum (mass N)

Each triangle will be considered an object, so we will have to find the center of mass of those triangles.

So to use that we need :
- centroid of each triangle (to have the position of each triangle)
- area of each triangle (to have the mass of the object)

For the centroid, I just used the average position ([(x+x+x)/3, ...].

To calculate the area I used the formula using the edges and semi perimeter because I though it was the simplest formula for this case:
area = square ( semi perimeter * ( semi perimeter - edge A) * ( semi perimeter - edge B) * ( semi perimeter - edge B) )

note : each semi perimeter - edge length must be positive, so I used abs() to convert it to an absolute number.

To have the edge I'm using calculating the distance between 2 vertices with this formula:
square ( (x2 - x1)**2 + (y2 -y1)**2 + (z2 - z1)**2 )

With that, I gather the " sum( position in 1 axis of the centroid * area of the triangle) " of all of the triangles in the object, and then divide it with the total area of the object.
And do it 3 times, 1 per axis.

To convert local position to global position I'm just using XSIMath.

I think it's really simple to get, but with getCenterOfMass(obj) you'll have the 3 coordinates, you use it as you want (make it the center of the object, creating a null, making it a vector, etc).
M.Yara
Character Modeler | Softimage Generalist (sort of) myara
Posts: 389
Joined: 28 Sep 2011, 10:33

### Re: Center of Mass

While I was writing my explanation, I realized I did something stupid.
Since we are working with only 1 object, I shouldn't be converting the position to global before doing the calculations, that would make it slower (converting to global is not a very fast operation, and this exponentially increase depending on the triangle cout).

Instead, the fastest approach would be working in local, and convert the result to global at the very end.

This should be much faster

Code: Select all

``````xsi = Application
log = LogMessage

import math

def distanceBetween2points(A,B):
'''
Return Distance between 2 points in 3D Space
distanceBetween2points([x,y,z],[x,y,z])
'''
return abs(math.sqrt(math.pow(B-A,2) + math.pow(B-A,2) + math.pow(B-A,2)))

def getCenterOfMass(obj):
geo = obj.ActivePrimitive.Geometry
tris = geo.Triangles
totalArea = 0
sx=0
sy=0
sz=0
for tri in tris:
# Get Position of Triangle
triPos = tri.PositionArray
triPosX = triPos
triPosY = triPos
triPosZ = triPos

triCenter = [sum(triPosX)/3, sum(triPosY)/3, sum(triPosZ)/3]

# Get Triangle Area with Edges lenght and Semi Perimeter equation
edgeA = distanceBetween2points([triPosX, triPosY, triPosZ], [triPosX, triPosY, triPosZ])
edgeB = distanceBetween2points([triPosX, triPosY, triPosZ], [triPosX, triPosY, triPosZ])
edgeC = distanceBetween2points([triPosX, triPosY, triPosZ], [triPosX, triPosY, triPosZ])
semiPerimeter = (edgeA + edgeB+ edgeC) / 2
area = (semiPerimeter*abs(semiPerimeter-edgeA)*abs(semiPerimeter-edgeB)*abs(semiPerimeter-edgeC)) ** 0.5

sx += triCenter * area
sy += triCenter * area
sz += triCenter * area

totalArea += area

# Calculate Center of Mass
nulx = sx/totalArea
nuly = sy/totalArea
nulz = sz/totalArea

# Convert the local position to Global
nulpos = XSIMath.CreateVector3(nulx, nuly, nulz)
nulpos_G = XSIMath.MapObjectPositionToWorldSpace(obj.Kinematics.Global.Transform, nulpos)

return [nulpos_G.X, nulpos_G.Y, nulpos_G.Z]

#------------------

# Selection
obj = xsi.Selection(0)

centerOfMass = getCenterOfMass(obj)

# Create Null, and Assign coordinates
nul = xsi.ActiveSceneRoot.AddNull('nul')
nul.Kinematics.Global.posx = centerOfMass
nul.Kinematics.Global.posy = centerOfMass
nul.Kinematics.Global.posz = centerOfMass``````
PS: sorry for the double post, I though it would be easier to understand this way.

If you want to change the Center of the Object change the last part of the #Create Null... with this code:

Code: Select all

``````from win32com.client import constants as c
xsi.Translate(obj, centerOfMass, centerOfMass, centerOfMass, c.siAbsolute, c.siGlobal, c.siCtr, c.siXYZ)
``````
M.Yara
Character Modeler | Softimage Generalist (sort of)