我该如何计算3D重心?

8

是否存在3D质心这样的东西?让我非常清楚地说明一下-我已经在这个网站和整个网络上阅读了有关质心的文章两天了,所以我非常清楚有关该主题的现有帖子,包括维基百科

话虽如此,让我解释一下我的意图。基本上,我想选择边和/或顶点,但不是面。然后,我想将一个物体放置在3D质心位置。

我告诉你我不想要什么:

  • 顶点平均值,因为它会在具有更高详细网格的任何方向上拉得太远。
  • 边界框中心,因为我已经为这种情况有了可行的解决方案。

我可以接受关于重心的建议,但我不明白这怎么可能起作用,因为单独的顶点或边并不定义任何形式的质量,特别是当我只选择一个边环时。

为了好玩,我会展示一些我写的PyMEL代码,参考了@Emile's code,但我认为它的工作方式不正确:

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)
4个回答

8

理论上,当您将零件分成具有位置pos和体积值volume的有限体积时,质心=SUM(pos * volume)/SUM(volume)

这正是计算复合部件重心所做的精确计算。


我会接受这个答案,因为它很简单,但是我要等到稍后才能测试它。我会随时通知你的。 - jedmao

3

不仅存在3D重心,还存在n维重心,其公式在你引用的维基百科文章的“通过积分公式”部分中给出。

也许您在设置这个积分时遇到了麻烦?您尚未定义您的形状。

[编辑] 我会根据您的评论加强这个答案。由于您已经用边缘和顶点描述了您的形状,那么我假设它是一个多面体。您可以将多面体划分成金字塔,找到金字塔的重心,然后您的形状的重心就是重心的重心(最后一次计算使用ja72的公式)。

我假设你的形状是凸的(没有空洞 - 如果不是这种情况,则将其分成凸块)。您可以通过选择内部点并将边缘连接到顶点来将其分割成金字塔(三角化)。然后,您的形状的每个面都是一个金字塔的底部。有关金字塔重心的公式(您可以查找此内容,它距离面的重心到您的内部点的距离为1/4)。然后,正如之前所说,您的形状的重心是重心的重心 - ja72的有限计算,而不是积分 - 如其他答案中所述。
这与Hugh Bothwell的答案中的相同算法相同,但我认为1/4是正确的,而不是1/3。也许您可以使用本描述中的搜索词在某处找到一些代码。

是的,唔...有点尴尬,我甚至不知道什么是积分。当我看不到实际的代码时,我就会迷失方向。我不理解公式。而且你说得对。当我只有一堆顶点时,我的形状并没有被明确定义。你怎么知道如何正确地连接这些点呢? - jedmao

2

我喜欢这个问题。质心听起来不错,但问题是,每个顶点的质量是多少?

为什么不使用包括该顶点的每条边的平均长度呢?这应该可以很好地弥补具有密集网格的区域。


你知道吗,就在你发帖之前的几分钟,我也在想同样的事情。我想知道结果会是什么样子。因为如果是这种情况,数学计算会非常简单,只需要加权平均即可。我现在需要睡觉了,但我明天会研究一下这个问题。 - jedmao
仍在研究解决方案。我会尽量让你保持更新。 - jedmao
我很想看到结果。它显然适用于一些简单的测试案例,例如一个顶点定义一个端口的圆柱体,而在另一端则较少。如果它不能正常工作,那么哪些测试案例会出现问题? - Keith

1

您需要从顶点重新创建面部信息(本质上是 Delauney 三角剖分)。

如果您的顶点定义了一个凸包,您可以选择任意一个点 A 在对象内部。将您的对象视为具有顶点 A 和每个面作为底部的金字塔形棱柱的集合。

对于每个面,找到面积 Fa 和二维重心 Fc;然后棱柱的质量与体积成比例(== 1/3 底面 * 高度(Fc-A 垂直于面的分量)),只要对所有棱柱执行相同的操作,就可以忽略比例常数;质心是(2/3 A + 1/3 Fc),或者从顶点到底面二维重心的路程的三分之一。

然后,您可以对质心点进行质量加权平均,以找到整个对象的三维重心。

相同的过程应该适用于非凸包 - 甚至适用于 A 在凸包外部 - 但面计算可能会有问题;您需要注意面的左右手性。


我一直在尝试利用我找到的(并简化的)Delauney代码来实现这个功能,但我不确定它是否正常工作。不幸的是,我不能依赖numpy来完成这个任务。我仍在努力解决这个问题。我会随时向您更新。 - jedmao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接