8

Is there even such a thing as a 3D centroid? Let me be perfectly clear—I've been reading and reading about centroids for the last 2 days both on this site and across the web, so I'm perfectly aware at the existing posts on the topic, including Wikipedia.

That said, let me explain what I'm trying to do. Basically, I want to take a selection of edges and/or vertices, but NOT faces. Then, I want to place an object at the 3D centroid position.

I'll tell you what I don't want:

  • The vertices average, which would pull too far in any direction that has a more high-detailed mesh.
  • The bounding box center, because I already have something working for this scenario.

I'm open to suggestions about center of mass, but I don't see how this would work, because vertices or edges alone don't define any sort of mass, especially when I just have an edge loop selected.

For kicks, I'll show you some PyMEL that I worked up, using @Emile's code as reference, but I don't think it's working the way it should:

from pymel.core import ls, spaceLocator
from pymel.core.datatypes import Vector
from pymel.core.nodetypes import NurbsCurve

def get_centroid(node):
    if not isinstance(node, NurbsCurve):
        raise TypeError("Requires NurbsCurve.")
    centroid = Vector(0, 0, 0)
    signed_area = 0.0
    cvs = node.getCVs(space='world')
    v0 = cvs[len(cvs) - 1]
    for i, cv in enumerate(cvs[:-1]):
        v1 = cv
        a = v0.x * v1.y - v1.x * v0.y
        signed_area += a
        centroid += sum([v0, v1]) * a
        v0 = v1
    signed_area *= 0.5
    centroid /= 6 * signed_area
    return centroid

texas = ls(selection=True)[0]
centroid = get_centroid(texas)
print(centroid)
spaceLocator(position=centroid)
Community
  • 1
  • 1
jedmao
  • 10,224
  • 11
  • 59
  • 65

4 Answers4

8

In theory centroid = SUM(pos*volume)/SUM(volume) when you split the part into finite volumes each with a location pos and volume value volume.

This is precisely the calculation done for finding the center of gravity of a composite part.

John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • I'm going to accept this answer for simplicity, but I won't be able to test it until later. I'll keep you posted. – jedmao Feb 02 '11 at 07:54
3

There is not just a 3D centroid, there is an n-dimensional centroid, and the formula for it is given in the "By integral formula" section of the Wikipedia article you cite.

Perhaps you are having trouble setting up this integral? You have not defined your shape.

[Edit] I'll beef up this answer in response to your comment. Since you have described your shape in terms of edges and vertices, then I'll assume it is a polyhedron. You can partition a polyedron into pyramids, find the centroids of the pyramids, and then the centroid of your shape is the centroid of the centroids (this last calculation is done using ja72's formula).

I'll assume your shape is convex (no hollow parts---if this is not the case then break it into convex chunks). You can partition it into pyramids (triangulate it) by picking a point in the interior and drawing edges to the vertices. Then each face of your shape is the base of a pyramid. There are formulas for the centroid of a pyramid (you can look this up, it's 1/4 the way from the centroid of the face to your interior point). Then as was said, the centroid of your shape is the centroid of the centroids---ja72's finite calculation, not an integral---as given in the other answer.

This is the same algorithm as in Hugh Bothwell's answer, however I believe that 1/4 is correct instead of 1/3. Perhaps you can find some code for it lurking around somewhere using the search terms in this description.

Glenn
  • 6,455
  • 4
  • 33
  • 42
  • Yeah, well... embarrassingly, I don't even know what an integral is. I get lost when I don't see actual code. I don't understand the formulas. And you're right. My shape isn't necessarily defined when I just have a collection of vertices. How would you know how to connect the dots correctly? – jedmao Jan 28 '11 at 11:12
2

I like the question. Centre of mass sounds right, but the question then becomes, what mass for each vertex?

Why not use the average length of each edge that includes the vertex? This should compensate nicely areas with a dense mesh.

Keith
  • 6,756
  • 19
  • 23
  • You know, I was just thinking the same thing minutes before you posted this. I wonder what the result would be. Because the math would be so extremely simple in that case because it'd just be a weighted-average. I need to sleep now, but I'll look into this tomorrow. – jedmao Jan 28 '11 at 11:10
  • Still working on this solution. I'll try to keep you updated. – jedmao Feb 02 '11 at 07:52
  • I'll be interested to see the result. It will clearly work for some simple test cases. E.g. A cylinder with a lot of vertices defining one end and fewer on the other. If it does not work, what test cases are a problem? – Keith Feb 03 '11 at 02:51
1

You will have to recreate face information from the vertices (essentially a Delauney triangulation).

If your vertices define a convex hull, you can pick any arbitrary point A inside the object. Treat your object as a collection of pyramidal prisms having apex A and each face as a base.

For each face, find the area Fa and the 2d centroid Fc; then the prism's mass is proportional to the volume (== 1/3 base * height (component of Fc-A perpendicular to the face)) and you can disregard the constant of proportionality so long as you do the same for all prisms; the center of mass is (2/3 A + 1/3 Fc), or a third of the way from the apex to the 2d centroid of the base.

You can then do a mass-weighted average of the center-of-mass points to find the 3d centroid of the object as a whole.

The same process should work for non-convex hulls - or even for A outside the hull - but the face-calculation may be a problem; you will need to be careful about the handedness of your faces.

Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99
  • I've been trying to leverage some Delauney code I found (and simplified) to get this working, but I'm not 100% sure it's working properly. Unfortunately, I can't rely on numpy for this one. Still working on this solution. I'll keep you updated. – jedmao Feb 02 '11 at 07:52