如何计算 3D 质心?
是否存在 3D 质心这样的东西?让我非常清楚 - 过去 2 天我一直在这个网站和整个网络上阅读有关质心的内容,因此我完全了解有关该主题的现有帖子,包括 维基百科。
也就是说,让我解释一下我想要做什么。基本上,我想选择边缘和/或顶点,但不是面。然后,我想将一个对象放置在 3D 质心位置。
我会告诉你我不想要什么:
- 顶点平均,这会在具有更详细网格的任何方向上拉得太远。
- 边界框中心,因为我已经有一些适用于此场景的东西。
我愿意接受有关质心的建议,但我不知道这是如何工作的,因为单独的顶点或边并不能定义任何类型的质量,特别是当我只选择了边循环时。
为了好玩,我将向您展示一些我使用PyMEL ="https://stackoverflow.com/questions/2792443/finding-the-centroid-of-a-polygon/2792459#2792459">@Emile的代码作为参考,但我认为它不起作用应该这样:
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)
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
理论上,
centroid = SUM(pos*volume)/SUM(volume)
,当您将零件分割为有限体积时,每个体积都有一个位置pos
和体积值volume< /代码>。
这正是为寻找复合材料零件的重心而进行的计算。
In theory
centroid = SUM(pos*volume)/SUM(volume)
when you split the part into finite volumes each with a locationpos
and volume valuevolume
.This is precisely the calculation done for finding the center of gravity of a composite part.
不仅有一个 3D 质心,还有一个 n 维质心,其公式在您引用的维基百科文章的“按积分公式”部分中给出。
也许您在设置此积分时遇到困难?你还没有定义你的形状。
[编辑]我将根据您的评论加强这个答案。既然您已经用边和顶点描述了您的形状,那么我假设它是一个 多面体。您可以将多面体划分为金字塔,找到金字塔的质心,然后形状的质心就是质心的质心(最后一个计算是使用 ja72 的公式完成的)。
我假设你的形状是凸的(没有空心部分——如果不是这种情况,那么就把它分成凸块)。您可以通过在内部选取一个点并将边绘制到顶点来将其划分为金字塔(将其三角化)。那么你的形状的每个面都是金字塔的底部。有金字塔质心的公式(你可以查一下,它是从面质心到内点的 1/4)。然后,正如前面所说,形状的质心是质心的质心——ja72 的有限计算,而不是积分——如另一个答案中给出的。
这与 Hugh Bothwell 的答案中的算法相同,但我相信 1/4 是正确的,而不是 1/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.
我喜欢这个问题。质心听起来不错,但问题就变成了,每个顶点的质量是多少?
为什么不使用包含顶点的每条边的平均长度?这应该可以很好地补偿具有密集网格的区域。
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.
您将必须从顶点重新创建面信息(本质上是德劳尼三角剖分)。
如果您的顶点定义了凸包,您可以选取对象内的任意点 A。将您的对象视为具有顶点 A 且每个面作为底面的金字塔棱柱的集合。
对于每个面,找到面积Fa和2d质心Fc;那么棱镜的质量与体积成正比(== 1/3 底面 * 高度(Fc-A 垂直于面的分量)),只要对所有棱镜执行相同的操作,您就可以忽略比例常数;质心为 (2/3 A + 1/3 Fc),或从顶点到底部 2d 质心的三分之一距离。
然后,您可以对质心点进行质量加权平均值,以找到整个对象的 3d 质心。
相同的过程应该适用于非凸壳 - 甚至适用于壳外的 A - 但面计算可能是个问题;您需要注意自己脸部的惯用手习惯。
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.