我正在尝试创建一个类似于此形状的,具有12个五边形的六边形,并具有任意大小。

algorithm - 数学产生的球形六角形网格-LMLPHP

(Image Source)

唯一的是,我完全不知道需要哪种代码来生成它!

目的是能够在3D空间中获取一个点并将其转换为网格上的位置坐标,反之亦然,并获取网格位置并获得用于绘制网格的相关顶点。

我什至不知道该如何存储网格位置。 3个五边形之间的每个“三角形部分”是否都有自己的2D坐标集?

我很可能会为此使用C#,但是我对使用哪种算法以及如何工作的解释更感兴趣,而不是有人给我一段代码。

最佳答案

首先对问题中的图像进行一些分析:由相邻五边形中心跨越的球形三角形似乎是等边的。当五个等边三角形在一个角处相交并覆盖整个球体时,这只能是icosahedron引起的构型。因此,有12个五边形和映射到球体的六边形网格的三角形切口的20个补丁。

因此,这是在球体上构造这种六边形网格的方法:

  • 创建六边形网格的三角形切口:一个固定的三角形(我选择了(-0.5,0),(0.5,0),(0,sqrt(3)/ 2))叠加到具有所需分辨率n s.t的六边形网格上。三角形的角与六角形的中心重合,请参见n = 0,1,2,20的示例:
    algorithm - 数学产生的球形六角形网格-LMLPHP
  • 计算icosahedron的角并定义它的20个三角形面(请参见下面的代码)。二十面体的角定义五边形的中心,二十面体的面定义映射的六边形网格的面片。 (二十面体将球体表面的最佳规则划分为三角形,即划分为相等的等边三角形。其他此类划分可以从四面体或八面体得出;然后在三角形的角处将有三角形或正方形,此外,三角形的越来越小将使在平面网格到曲面上的任何映射中不可避免的变形更加明显。因此,选择二十面体作为三角形斑块的基础有助于最大程度地减少六边形的变形。
  • 将六角形网格的三角形切口映射到对应于二十面体面的球形三角形:基于slerp的double-barycentric coordinates可以解决问题。以下是将分辨率为n = 10的六边形网格的三角形切口映射到一个球形三角形(由二十面体的一个面定义)的图示,以及将网格映射到覆盖整个球体的所有这些球形三角形的图示(不同不同映射的颜色):

  • algorithm - 数学产生的球形六角形网格-LMLPHP algorithm - 数学产生的球形六角形网格-LMLPHP

    这是Python代码,用于生成二十面体的角(坐标)和三角形(点索引):
    from math import sin,cos,acos,sqrt,pi
    s,c = 2/sqrt(5),1/sqrt(5)
    topPoints = [(0,0,1)] + [(s*cos(i*2*pi/5.), s*sin(i*2*pi/5.), c) for i in range(5)]
    bottomPoints = [(-x,y,-z) for (x,y,z) in topPoints]
    icoPoints = topPoints + bottomPoints
    icoTriangs = [(0,i+1,(i+1)%5+1) for i in range(5)] +\
                 [(6,i+7,(i+1)%5+7) for i in range(5)] +\
                 [(i+1,(i+1)%5+1,(7-i)%5+7) for i in range(5)] +\
                 [(i+1,(7-i)%5+7,(8-i)%5+7) for i in range(5)]
    

    这是Python代码,使用双slerp将固定三角形映射(的点)到球形三角形:
    # barycentric coords for triangle (-0.5,0),(0.5,0),(0,sqrt(3)/2)
    def barycentricCoords(p):
      x,y = p
      # l3*sqrt(3)/2 = y
      l3 = y*2./sqrt(3.)
      # l1 + l2 + l3 = 1
      # 0.5*(l2 - l1) = x
      l2 = x + 0.5*(1 - l3)
      l1 = 1 - l2 - l3
      return l1,l2,l3
    
    from math import atan2
    def scalProd(p1,p2):
      return sum([p1[i]*p2[i] for i in range(len(p1))])
    # uniform interpolation of arc defined by p0, p1 (around origin)
    # t=0 -> p0, t=1 -> p1
    def slerp(p0,p1,t):
      assert abs(scalProd(p0,p0) - scalProd(p1,p1)) < 1e-7
      ang0Cos = scalProd(p0,p1)/scalProd(p0,p0)
      ang0Sin = sqrt(1 - ang0Cos*ang0Cos)
      ang0 = atan2(ang0Sin,ang0Cos)
      l0 = sin((1-t)*ang0)
      l1 = sin(t    *ang0)
      return tuple([(l0*p0[i] + l1*p1[i])/ang0Sin for i in range(len(p0))])
    
    # map 2D point p to spherical triangle s1,s2,s3 (3D vectors of equal length)
    def mapGridpoint2Sphere(p,s1,s2,s3):
      l1,l2,l3 = barycentricCoords(p)
      if abs(l3-1) < 1e-10: return s3
      l2s = l2/(l1+l2)
      p12 = slerp(s1,s2,l2s)
      return slerp(p12,s3,l3)
    

    09-07 00:03