7

我有一个封闭的凸多面体,它由一组凸多边形(面)定义,这些凸多边形(面)由 3D 空间中的顶点数组定义。假设密度均匀,我试图找到多面体的质心。目前我用这个伪代码中的算法计算它。

public Vector3 getCentroid() {
    Vector3 centroid = (0, 0, 0);
    for (face in faces) {
        Vector3 point = face.centroid;
        point.multiply(face.area());
        centroid.add(point);
    }
    centroid.divide(faces.size());
    return centroid;
}

这实质上是取面部质心的加权平均值。我不能 100% 确定这是正确的,因为我无法在网上找到正确的算法。如果有人可以确认我的算法或将我推荐给正确的算法,我将不胜感激。

谢谢。


[编辑]

所以这是我用来查找质心的实际 Java 代码。它将多面体分解成金字塔,这些金字塔会聚在多面体内部的任意点上。金字塔形心的加权平均值基于以下公式。

C all = SUM所有金字塔(C pyramid * volume pyramid)/volume all

这是(大量注释的代码):

    // Compute the average of the facial centroids.
    // This gives an arbitrary point inside the polyhedron.
    Vector3 avgPoint = new Vector3(0, 0, 0);
    for (int i = 0; i < faces.size(); i++) {
        avgPoint.add(faces.get(i).centroid);
    }
    avgPoint.divide(faces.size());

    // Initialise the centroid and the volume.
    centroid = new Vector3(0, 0, 0);
    volume = 0;

    // Loop through each face.
    for (int i = 0; i < faces.size(); i++) {
        Face face = faces.get(i);

        // Find a vector from avgPoint to the centroid of the face.
        Vector3 avgToCentroid = face.centroid.clone();
        avgToCentroid.sub(avgPoint);

        // Gives the unsigned minimum distance between the face and a parallel plane on avgPoint.
        float distance = avgToCentroid.scalarProjection(face.getNormal());

        // Finds the volume of the pyramid using V = 1/3 * B * h
        // where:   B = area of the pyramid base.
        //          h = pyramid height.
        float pyramidVolume = face.getArea() * distance / 3;

        // Centroid of a pyramid is 1/4 of the height up from the base.
        // Using 3/4 here because vector is travelling 'down' the pyramid.
        avgToCentroid.multiply(0.75f);
        avgToCentroid.add(avgPoint);
        // avgToCentroid is now the centroid of the pyramid.

        // Weight it by the volume of the pyramid.
        avgToCentroid.multiply(pyramidVolume);

        volume += pyramidVolume;
    }

    // Average the weighted sum of pyramid centroids.
    centroid.divide(volume);

请随时问我您对此可能有的任何问题或指出您看到的任何错误。

4

2 回答 2

8

通常,这取决于多面体的结构。有4种可能的情况:

  • 只有顶点有权重,即你的多面体是点系统。然后你可以计算所有点的加权和的平均值:

    r_c = sum(r_i * m_i) / sum(m_i)
    

    r_i是表示第 i 个顶点的向量m_i- 它的质量。质量相等的情况给我们留下了更简单的公式:

    r_c = sum(r_i) / n
    

    哪里n是顶点数。请注意,两个总和都是矢量化的。

  • 只有边有重量,多面体本质上是一个尸体。这种情况可以通过将每个边替换为位于边中间的顶点并具有整个边的权重来减少到前一种情况。

  • 只有脸有重量。这种情况也可以简化为第一种情况。每个面都是一个二维凸图,可以找到其质心。用其质心替换每个面将这种情况带到第一个情况。

  • 实心多面体(您的情况,从“假设均匀密度”推断)。这个问题需要更复杂的方法。第一步是将多面体拆分为四面体。这是有关如何执行此操作的简短说明。因为四面体的质心位于其所有中线相交的点。(四面体的中值是连接其顶点和对面质心的线。)下一步是将分区中的每个四面体替换为其质心。最后一步是找到所得到的一组加权点的质心,这正是第一种情况。

于 2012-02-17T09:32:39.150 回答
2

对于实体情况,有一种比尝试四面体化多面体(有缺陷)更简单的方法

这是伪 java-ish 代码(假设体面的 Vector3 实现):

// running sum for total volume
double vol = 0;
// running sum for centroid
Vector3 centroid = (0, 0, 0);
for each triangle (a,b,c)
{
  // Compute area-magnitude normal
  Vector3 n = (b-a).cross(c-a);
  vol += a.dot(n)/6.;
  // Compute contribution to centroid integral for each dimension
  for(int d = 0;d<3;d++)
    centroid[d] += n[d] * ((a[d]+b[d])^2 + (b[d]+c[d])^2 + (c[d]+a[d])^2);
}
// final scale by inverse volume
centroid *= 1./(24.*2.*vol);

请注意,如果您的面的度数高于三角形,则可以用扇子进行简单的三角测量,这仍然有效。

即使多面体不是凸面,这也很方便。

我还发布了matlab代码

于 2014-02-18T20:36:33.933 回答