我有一个封闭的凸多面体,它是由一个凸多边形(面)数组定义的,这些凸多边形是由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 金字塔 * volume 金字塔)/ volume 全部子>
以下是(重度注释代码):
// 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);
如果您有任何问题,请随时向我询问或指出您看到的任何错误。
答案 0 :(得分:7)
通常,这取决于多面体的结构。有4种可能的情况:
只有顶点具有权重,即您的多面体是点系统。然后你可以计算所有点的加权和的平均值:
r_c = sum(r_i * m_i) / sum(m_i)
此处r_i
是表示第i个顶点的矢量m_i
- 其质量。等质量的情况给我们留下了更简单的公式:
r_c = sum(r_i) / n
其中n
是顶点数。请注意,两个总和都是矢量化的。
只有边缘有重量,多面体基本上是一个胴体。通过用位于边缘中间的顶点替换每个边并且具有整个边的权重,可以将这种情况简化为前一个边。
只有脸有重量。这种情况也可以减少到第一种情况。每个面都是2D凸面图,其中可以找到质心。用它的质心代替每个面将这个案例带到第一个面。
实心多面体(您的情况,从推断“假定均匀密度”)。这个问题需要更复杂的方法。第一步是将多面体分割成四面体。以下是关于如何执行此操作的short description。对于四面体质心位于其所有中位数相交的点。 (四面体的中位数是连接其顶点和相对面的质心的线。)下一步是用分区中心替换分区中的每个四面体。最后一步是找到所得加权点集的质心,这正是第一种情况。
答案 1 :(得分:2)
对于实例,有多simpler method而不是试图对多面体进行四面体化(具有pitfalls)。
这是伪ish 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 code