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[0]-A[0],2) + math.pow(B[1]-A[1],2) + math.pow(B[2]-A[2],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[0]
triPosY = triPos[1]
triPosZ = triPos[2]
triCenter = [sum(triPosX)/3, sum(triPosY)/3, sum(triPosZ)/3]
# Get Triangle Area with Edges lenght and Semi Perimeter equation
edgeA = distanceBetween2points([triPosX[0], triPosY[0], triPosZ[0]], [triPosX[1], triPosY[1], triPosZ[1]])
edgeB = distanceBetween2points([triPosX[1], triPosY[1], triPosZ[1]], [triPosX[2], triPosY[2], triPosZ[2]])
edgeC = distanceBetween2points([triPosX[2], triPosY[2], triPosZ[2]], [triPosX[0], triPosY[0], triPosZ[0]])
semiPerimeter = (edgeA + edgeB+ edgeC) / 2
area = (semiPerimeter*abs(semiPerimeter-edgeA)*abs(semiPerimeter-edgeB)*abs(semiPerimeter-edgeC)) ** 0.5
sx += triCenter[0] * area
sy += triCenter[1] * area
sz += triCenter[2] * 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[0]
nul.Kinematics.Global.posy = centerOfMass[1]
nul.Kinematics.Global.posz = centerOfMass[2]
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[0], centerOfMass[1], centerOfMass[2], c.siAbsolute, c.siGlobal, c.siCtr, c.siXYZ)