【发布时间】:2010-12-22 17:50:53
【问题描述】:
给定一个顶点列表 (v),以及连接顶点的边列表 (e),以及连接边的曲面列表 (s),如何计算多面体?
【问题讨论】:
标签: math
给定一个顶点列表 (v),以及连接顶点的边列表 (e),以及连接边的曲面列表 (s),如何计算多面体?
【问题讨论】:
标签: math
与多边形类似,我们可以将其分成三角形并对面积求和,
您可以将多面体拆分为金字塔并将它们的体积相加。但我不确定为此实现算法有多难。
(我相信有一种数学方式/公式,例如使用向量和矩阵。
我建议您也将您的问题发布到http://mathoverflow.net)
【讨论】:
首先,通过绘制新边将每个面分成三角形。
现在看一个三角形,假设它位于“上”表面(其中一些细节稍后会变得不重要)。查看三角形下方的体积,直至多面体下方的某个水平面。如果 {h1, h2, h3} 是三个点的高,A 是底面积,那么立体的体积将为 A(h1+h2+h3)/3。现在我们必须将 上 面的这些实体的体积相加,并为 下 面减去它们以获得多面体的体积。
玩一下代数,您会发现水平面上方的多面体高度无关紧要。平面可以在多面体之上,也可以穿过它,结果还是正确的。
所以我们需要的是 (1) 一种计算底面积的方法,以及 (2) 一种区分“上”面和“下”面的方法。如果你有点的笛卡尔坐标,第一个很容易,如果点是有序的,第二个很容易,你可以将它们组合起来,用一块石头杀死两只鸟。假设每个面都有一个角列表,按逆时针顺序排列。然后这些点在 x-y 平面上的投影将逆时针用于上表面,顺时针用于下表面。如果你用this method计算底面的面积,上面的面积是正的,下面的面积是负的,所以你可以把它们加在一起得到答案。
那么如何获得角的有序列表?从一个三角形开始,选择一个顺序,对于每条边,共享该边的邻居应该以相反的顺序列出这两个点。从一个邻居移动到另一个邻居,直到你有每个三角形的列表。如果多面体的体积为负,只需乘以 -1(这意味着您为第一个三角形选择了错误的顺序,并且多面体是由内向外的)。
编辑: 我忘记了最好的部分!如果您检查代数以将这些体积相加,您会发现很多项都被抵消了,尤其是在将三角形组合回原始面时。我还没有详细解决这个问题,但看起来最终结果可能是一个非常简单的函数。
【讨论】:
注意事项:
[ x1 x2 x3 x4 ]
[ y1 y2 y3 y4 ]
[ z1 z2 z3 z4 ]
[ 1 1 1 1 ]
其中列是顶点 (x,y,z,1) 的齐次坐标。
即使形状没有通过减去该体积以及添加它来包围原点,它也可以工作,但这取决于具有一致的顺序。
如果您不能保留顺序,您仍然可以找到某种方法将其分解为四面体,并将每个行列式的 1/6 绝对值相加。
编辑: 我想补充一点,对于四面体的一个顶点(例如 V4)为(0,0,0)的三角形网格,4x4 矩阵的行列式可以简化为左上角 3x3(沿 0,0 展开, 0,1 列),可以简化为 Vol = V1xV2.V3,其中“x”是叉积,“.”是点积。因此,计算每个三角形的表达式,将这些体积相加并除以 6。
【讨论】:
这是 Python 中的一个潜在实现。 任何人都可以检查它是否正确? 我相信我错过了点的排列,因为我的第二次测试(立方体)给出了 0.666 而不是 1。有想法吗?
干杯 艾尔
class Simplex(object):
'''
Simplex
'''
def __init__(self,coordinates):
'''
Constructor
'''
if not len(coordinates) == 4:
raise RuntimeError('You must provide only 4 coordinates!')
self.coordinates = coordinates
def volume(self):
'''
volume: Return volume of simplex. Formula from http://de.wikipedia.org/wiki/Tetraeder
'''
import numpy
vA = numpy.array(self.coordinates[1]) - numpy.array(self.coordinates[0])
vB = numpy.array(self.coordinates[2]) - numpy.array(self.coordinates[0])
vC = numpy.array(self.coordinates[3]) - numpy.array(self.coordinates[0])
return numpy.abs(numpy.dot(numpy.cross(vA,vB),vC)) / 6.0
class Polyeder(object):
def __init__(self,coordinates):
'''
Constructor
'''
if len(coordinates) < 4:
raise RuntimeError('You must provide at least 4 coordinates!')
self.coordinates = coordinates
def volume(self):
pivotCoordinate = self.coordinates[0]
volumeSum = 0
for i in xrange(1,len(self.coordinates)-3):
newCoordinates = [pivotCoordinate]
for j in xrange(i,i+3):
newCoordinates.append(self.coordinates[j])
simplex = Simplex(newCoordinates)
volumeSum += simplex.volume()
return volumeSum
coords = []
coords.append([0,0,0])
coords.append([1,0,0])
coords.append([0,1,0])
coords.append([0,0,1])
s = Simplex(coords)
print s.volume()
coords.append([0,1,1])
coords.append([1,0,1])
coords.append([1,1,0])
coords.append([1,1,1])
p = Polyeder(coords)
print p.volume()
【讨论】: