如何索引二十面体的面?

时间:2015-06-18 10:28:55

标签: c++ math geometry

我正在编写一个模拟作用于横跨球体表面的网格。网格本身是一个细分的Icosahedron(然而事先不知道细分的级别)

使用正方形网格,很容易找到相邻的单元格,因为它们沿x轴或y轴都是正负1。但是对于这些三角形来说情况并非如此,我的思绪很难想象一种索引细胞的方法。

我是否可以使用任何类型的坐标系来寻址二十面体的面,这至少可以让3个单元格与二十面体中的任意单元相邻?

4 个答案:

答案 0 :(得分:5)

基本上,您希望将几何体预处理为特定的数据结构,以便快速查找三角形的邻居。

如果这是您唯一的要求,那么很容易“推出自己的”。例如,对于每个三角形,您将存储其三个边,作为指向边结构的指针或作为边表的索引。然后,对于每个边,您将存储其两个相邻的三角形(再次作为指针或三角形索引)。

此设置允许您轻松地从三角形到每个边缘,然后从边缘结构中找到另一个相邻的三角形。

三角形曲面有更多高级数据结构,可以进行更有趣的操作,例如doubly connected edge listwinged edge data structure

如果您想使用预制图书馆,GTS library将会满足您的需求。

答案 1 :(得分:2)

对于二十面体的每一面,您可以将三角形映射到网格,每个网格方块分为两个,例如(格式方便的索引的十六进制编号):

 A
 +
 |\
 |0\
 +--+
 |\2|\
 |1\|3\
 +--+--+
 |\5|\7|\
 |4\|6\|8\
 +--+--+--+
 |\A|\C|\E|\
 |9\|B\|D\|F\
 +--+--+--+--+
B             C

对于经过n次细分的边,边上有4个 n 三角形,因此您可以为二十面体的每一边创建一个该尺寸的数组,以存储任何每个三角形数据为你的模拟。

对三角形的引用可以存储为(边,行,列)

行和列索引从0开始。列索引基于行中三角形的数量(即每个网格方格2个)。

如果你有侧面,行和列,你可以像这样计算一边的数组索引:

index = (row * row) + column

因此,您可以将数据存储在2d数组中,并按如下方式访问它:

value = data[side][(row * row) + column]

具有偶数列的三角形的相邻三角形:

(side, row, column - 1)
(side, row, column + 1)
(side, row + 1, column + 1)

具有奇数列的三角形的相邻三角形:

(side, row, column - 1)
(side, row, column + 1)
(side, row - 1, column - 1)

这使您可以轻松地在细分的三角形网格中引用三角形,而无需显式存储邻接信息。

当涉及到将其组织成二十面体时,问题就在于此。在计算对相邻三角形的引用之后,您需要验证新引用是否在边的范围内:

int rows = 1 << subdivision_count;
if(row >= rows)
{
    // compute (side, row, column) in adjacent side of icosahedron to B-C edge
}
else if(column < 0)
{
    // compute (side, row, column) in adjacent side of icosahedron to A-B edge
}
else if(column >= ((row * 2) + 1))
{
    // compute (side, row, column) in adjacent side of icosahedron to A-C edge
}

你必须存储每一方的邻接信息,以及它的边缘类型(AB,BC,AC)。

您将需要确定9种不同的可能映射,每种边缘类型组合一种。例如,如果相邻三角形与AC边缘交叉,并且此边缘与相邻边的AB边缘匹配,则

side = adjacent side (from table)
row = row
column = column - ((row * 2) + 1)

在某些方面,这是一种更复杂的方法,但在其他方面则更简单。所有这些的好处是:

  • 无需存储单个三角形的邻接信息,仅适用于二十面体边
  • 如果为每一侧存储A,B,C的3D位置,则可以为给定(侧,行,列)参考的三角形计算三角形坐标,因此不需要存储每个三角形的那些< / LI>

答案 2 :(得分:2)

这是一个有趣的问题。确切的答案取决于你如何细分二十面体的面部,你不会说。但是我会给出一个攻击问题的框架。

首先,让我说一下我认为在方形网格的情况下使问题变得容易:有一个反映网格对称性的数学组结构。确切地说,有一对简单的变换(向上移动;向右移动),它们与它们的反转一起产生一个网格单元到另一个网格单元的每次变换。此外,升档和右移操作通勤:您应用一系列操作的顺序不会改变结果。向上和向右操作在单元网格上生成可交换的变换组。该组与ZxZ同构,因此整数对(m,n)给出了很好的坐标。

二十面体上缺少这样的结构是你问题的问题之一。二十面体上有一个群体结构,有两个发生器,有时被称为&#34; a&#34;和&#34; b&#34;,其中&#34; a&#34;是180度旋转,它将给定边缘映射到自身上,反转,b是给定面部的120度旋转。问题是该组不是可交换的,所以ab!= ba。这使得与组生成器的计算严重复杂化。另一个问题是这种方法三重覆盖每个面(每次旋转一次)。二十面体旋转对称组A5中有60个元素,但二十面体上只有20个面。

威廉·汉密尔顿在Icosian calculus中发现了一种解决这些问题的非常有趣的方法,并在Icosian Game中得到了普及。值得注意的是,汉密尔顿为二十面体旋转组(他用希腊语iota和kappa而不是a和b代表)提供了生成器,然后才真正发明了(或至少很好理解)组和生成器的概念。然后汉密尔顿使用他的Icosian演算在十二面体的顶点图上找到哈密顿电路(或者等效地,二十面体的面图,因为十二面体和二十面体彼此是双重的)。见图here

该图可用于以0到19的循环次序对二十面体的面进行索引。将十二面体顶点图中的点沿哈密顿循环编号为0到19;这也对应于二十面体的相邻面的编号也沿着哈密顿循环。给定一个面m,它的两个相邻面是m-1模20和m + 1模20;第三个相邻面由graph中的虚线给出。也许第三个相邻面的索引有一个很好的公式或模式,但我不能随便看到它;它很容易存放在一张桌子里。

如果以某种方式细分脸部,可以将哈密顿循环继续进入脸部。通过在脸部中心引入新点,将每个脸部细分为三个脸部。然后你可以通过一个面上的三个新三角形找到一条汉密尔顿路径(顺时针或逆时针穿过它们,这取决于入口边缘和出口边缘之间的关系)。如果以这种方式进一步细分面,则会以空间填充曲线的方式获得通过其他细分三角形的哈密顿路径。面部细分的问题在于三角形边长的最大值不会减小。

对于更细分三角形的方法(通过细分边,而不是在面的中心引入新点),我找不到将二十面体上的哈密顿循环扩展到汉密尔顿路径的方法新的数字。因此,您可能更容易使用建议用于索引三角形面的其他方法之一来查找面内的相邻三角形,并将其与我建议的用于索引二十面体的面的方法相结合,以便在另一个中找到相邻的三角形面。

<强>更新

我一直在考虑索引面部。使用Triangular tilings上维基百科页面中的图像,一张脸将由无限平铺的大三角形部分组成

Equilateral triangle tiling

仿射变换(不会影响索引编制)将图像转换为

Right triangle tiling

然而,后一个图像包含正方形,因此三角形很容易通过正方形底角的x坐标,正方形底角的y坐标和单个位(0或1)指示三角形是黄色还是绿色。黄色三角形(m,n,0)旁边的三个三角形是(m-1,n,1),(m,n-1,1)和(m,n,1),绿色三角形旁边的三个三角形(m,n,1)是(m,n,0),(m + 1,n,0)和(m,n + 1,0);所有这些操作都是快速递减,递增或位翻转。通过将(m,n)处的正方形分成四个较小的正方形(坐标为(2m + 0,2n + 0),(2m + 1,2n + 0),(2m + 0,2n)来实现三角形数量的加倍。 +1)和(2m + 1,2n + 1),因此(m,n,0)处的黄色三角形在(2m,2n,0),(2m + 1,2n,0)处被分成黄色三角形,(2m,2n + 1,0),和(2m,2n,1)处的绿色三角形,(m,n,1)处的绿色三角形在(2m + 1,2n,1)处被分成绿色三角形),(2m,2n + 1,1),(2m + 1,2n + 1,1)和(2m + 1,2n + 1,0)处的黄色三角形;所有这些操作都是快速移位,没有携带,并且位翻转。最后,如果y坐标变为负数,我们可以判断三角形(x,y,c)是否在底部超出界限,如果x坐标为负,则三角形超出界限,如果x + y则超出对角线界限+ c&gt;无论三角形的大小如何,另一个快速操作。没有倍增。

我们的意思是&#34;底部&#34;对于三维人物的脸?汉密尔顿循环也回答了这个问题:&#34;底部&#34;任何面孔都是(定向)哈密顿循环进入的一侧。这使我们对每张脸都有明确的定位。

所以每个子三角形现在都有一个很好的坐标:(f,x,y,c)其中f是沿汉密尔顿循环计算的二十面体的面,x是包含三角形的平行四边形的x坐标, y是平行四边形的y坐标,c是颜色(左下角为0(黄色),右上角为1(绿色))。邻居可以通过三个快速操作加上简单的超出界限测试来计算,细分可以通过一些移位完成,并且无需携带即可。如果邻居测试越界,你只需减去f mod 20,增加f mod 20,或查找&#34;虚线&#34;面对一边。您还可以以简单的方式迭代每个三角形,首先遍历面,然后通过每个面中x + y + c =常数的三角形。

答案 3 :(得分:1)

为每个三角形分配一个元组{s,x,y},其中s表示边,x,y表示该边内的位置,这是微不足道的:

   /\ /Y
  /__\
 /\  /\
/__\/__\ ->X

这将有三角形{0,0},{1,1}(中间),{2,0}和{0,2}。在一个平面内,(相同的s),x&amp; y坐标告诉你哪些三角形边界。您需要一个表格来表示30个边缘,这表示每个边缘的两边都是三角形,以及它们的X,Y坐标是如何排序的。

(你可能会想出一个智能编号而不是表格;我不能。)