【问题标题】:General formula to calculate Polyhedron volume计算多面体体积的通用公式
【发布时间】:2010-12-22 17:50:53
【问题描述】:

给定一个顶点列表 (v),以及连接顶点的边列表 (e),以及连接边的曲面列表 (s),如何计算多面体?

【问题讨论】:

    标签: math


    【解决方案1】:

    与多边形类似,我们可以将其分成三角形并对面积求和,
    您可以将多面体拆分为金字塔并将它们的体积相加。但我不确定为此实现算法有多难。

    (我相信有一种数学方式/公式,例如使用向量和矩阵。
    我建议您也将您的问题发布到http://mathoverflow.net)

    【讨论】:

      【解决方案2】:

      首先,通过绘制新边将每个面分成三角形。

      现在看一个三角形,假设它位于“上”表面(其中一些细节稍后会变得不重要)。查看三角形下方的体积,直至多面体下方的某个水平面。如果 {h1, h2, h3} 是三个点的高,A 是底面积,那么立体的体积将为 A(h1+h2+h3)/3。现在我们必须将 面的这些实体的体积相加,并为 面减去它们以获得多面体的体积。

      玩一下代数,您会发现水平面上方的多面体高度无关紧要。平面可以在多面体之上,也可以穿过它,结果还是正确的。

      所以我们需要的是 (1) 一种计算底面积的方法,以及 (2) 一种区分“上”面和“下”面的方法。如果你有点的笛卡尔坐标,第一个很容易,如果点是有序的,第二个很容易,你可以将它们组合起来,用一块石头杀死两只鸟。假设每个面都有一个角列表,按逆时针顺序排列。然后这些点在 x-y 平面上的投影将逆时针用于上表面,顺时针用于下表面。如果你用this method计算底面的面积,上面的面积是正的,下面的面积是负的,所以你可以把它们加在一起得到答案。

      那么如何获得角的有序列表?从一个三角形开始,选择一个顺序,对于每条边,共享该边的邻居应该以相反的顺序列出这两个点。从一个邻居移动到另一个邻居,直到你有每个三角形的列表。如果多面体的体积为负,只需乘以 -1(这意味着您为第一个三角形选择了错误的顺序,并且多面体是由内向外的)。

      编辑: 我忘记了最好的部分!如果您检查代数以将这些体积相加,您会发现很多项都被抵消了,尤其是在将三角形组合回原始面时。我还没有详细解决这个问题,但看起来最终结果可能是一个非常简单的函数。

      【讨论】:

        【解决方案3】:

        我以前做过,但我使用的表面网格总是有三角形面。如果您的网格有非三角形刻面,您可以先轻松地将它们分解为三角形刻面。然后我把它喂给TetGen 以获得内部的四面体化。最后,我把四面体的所有体积加起来。 TetGen 相当容易使用,并且是除CGAL 之外唯一可以处理复杂网格的库。如果您不介意安装一个庞大的库并疯狂使用模板,那么 CGAL 非常易于使用。

        【讨论】:

          【解决方案4】:
          1. 取多边形并将它们分成三角形。
          2. 考虑由每个三角形和任意点(原点)形成的四面体。
          3. 对这些四面体的有符号体积求和。

          注意事项:

          1. 仅当您可以从外部观察三角形时保持一致的 CW 或 CCW 顺序时,这才有效。
          2. 四面体的有符号体积等于以下矩阵行列式的 1/6:

          [ 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。

          【讨论】:

          • 你是什么意思“即使形状没有通过减去该体积以及添加它来包围原点,它也可以工作,但这取决于具有一致的顺序。” ??这怎么能通过数学来完成??
          • 它将每个三角形连接到原点形成的四面体的体积相加。如果原点在形状之外,背向原点的三角形将产生一个符号与面向原点的三角形相反的体积。这会导致原点和形状之间的体积包含在总数中,然后再减去,从而得到正确的体积。
          • 这适用于非凸多面体conceptdraw.com/a1942c3/p12/preview/640/… 吗?而且你的算法也适用于不规则的多面体,因为多边形被分解成三角形,对吧?
          【解决方案5】:

          这是 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()
          

          【讨论】:

            猜你喜欢
            • 2013-06-12
            • 2023-03-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-07-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多