关于算法:数学生成球形六角形网格

Mathematically producing sphere-shaped hexagonal grid

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

https://i.stack.imgur.com/F35J0.png

(图片来源)

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

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

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

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


您拥有的形状是所谓的" Goldberg多面体"之一,也是测地线多面体。

可以(称为Conway多面体表示法)简洁地编码用于生成此(以及更多)的(相当优雅的)算法。

施工过程很容易逐步进行,您可以点击下面的图片进行实时预览。

  • 您要查找的多面体可以从等面体生成-使用等面体初始化网格。
    isosahedron

  • 我们对网格应用"截断"操作(Conway表示法t)(此网格的立体映射是足球)。
    enter image description here

  • 我们应用"双"运算符(Conway表示法d)。
    enter image description here

  • 我们再次应用"截断"操作。此时,配方为tdtI(从右侧读取!)。您已经可以看到前进的方向。
    enter image description here

  • 重复执行步骤3和4,直到满意为止。

  • 例如,下面是dtdtdtdtI的网格。
    enter image description here

    这很容易实现。我建议使用一种易于遍历邻域的数据结构,以给出顶点,边等,例如网格的有翼边或半边的数据结构。您只需要为所需的形状实现截断和双重运算符即可。


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

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

  • 创建六边形网格的三角形切口:固定三角形(我选择了(-0.5,0),(0.5,0),(0,sqrt(3)/ 2))叠加在具有所需分辨率n s.t的六边形网格上。三角形的角与六边形的中心重合,请参见n = 0,1,2,20的示例:
    enter image description here

  • 计算二十面体的角并定义其二十个三角形面(请参见下面的代码)。二十面体的角定义五边形的中心,二十面体的面定义映射的六边形网格的面片。 (二十面体将球体表面最好的规则划分为三角形,即划分为等边的等边三角形。其他这样的划分可以从四面体或八面体得出;然后在三角形的角处将有三角形或正方形,此外,三角形的越来越小将使在平面网格到曲面上的任何映射中不可避免的变形更加明显。因此,选择二十面体作为三角形斑块的基础有助于最大程度地减少六边形的变形。

  • 将六边形网格的三角形切口映射到对应于二十面体面的球形三角形:基于重心坐标的双刀齿就可以解决问题。下图说明了将分辨率为n = 10的六边形网格的三角形切口映射到一个球面三角形(由二十面体的一个面定义)的情况,并且将网格图映射到覆盖了整个球体的所有这些球面三角形上(不同的映射使用不同的颜色):

  • enter image description here enter image description here

    这是Python代码,用于生成二十面体的角(坐标)和三角形(点索引):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    # 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)


    [完成重新编辑18.10.2017]

    几何存储就在您身上。您可以将其存储在某种网格中,也可以即时生成它。我喜欢存储它。以2张桌子的形式。一个拥有所有顶点(无重复),另一个拥有每个获得的十六进制的6个已使用点索引,以及一些辅助信息(例如球形位置)以简化后期处理。

    现在如何生成它:

  • 创建六角形三角形

    大小应为球体的半径。不包括转角点,也跳过三角形的最后一条线(在径向和轴向上,因此球体上相邻三角形之间有1个十六进制的间隙),因为在连接三角形线段时会重叠。

  • 60deg六角形三角形转换为72deg饼图

    因此,只需将其转换为极坐标Coordiantes(radius,angle),即围绕0 deg的中心三角形。然后将半径乘以cos(angle)/cos(30);,这会将三角形转换为Pie。然后按比例72/60重新缩放角度。那将使我们的三角形成为可连接的...

  • 复制并旋转三角形以填充5个五边形段

    只需旋转第一个三角形的点并存储为新的点即可。

  • 计算z

    基于此半球形的六边形修整,您可以将2D贴图中的距离转换为弧长,以最大程度地限制变形。

    但是,当我尝试使用它(下面的示例)时,六边形有些扭曲,因此深度和缩放比例需要进行一些调整。或后期处理。

  • 复制半球形成一个球

    只需复制点/轴,并抵消z轴(或如果要保留绕组,则旋转180度)。

  • 添加赤道以及所有缺失的五边形和六边形

    您应该使用相邻十六进制的坐标,这样就不会在网格上添加更多的失真和重叠。这里预览:

    img

    蓝色是起始三角形。深蓝色是其副本。红色是极五边形。深绿色是赤道,浅绿色是三角形之间的连接线。在淡黄色中,深橙色五边形附近缺少赤道六边形。

  • 这里是简单的C ++ OpenGL示例(由#4中的链接答案制成):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    //$$---- Form CPP ----
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #include <math.h>
    #pragma hdrstop
    #include"win_main.h"
    #include"gl/OpenGL3D_double.cpp"
    #include"PolyLine.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource"*.dfm"
    TMain *Main;
    OpenGLscreen scr;
    bool _redraw=true;
    double animx=  0.0,danimx=0.0;
    double animy=  0.0,danimy=0.0;
    //---------------------------------------------------------------------------
    PointTab     pnt;   // (x,y,z)

    struct _hexagon
        {
        int ix[6];      // index of 6 points, last point duplicate for pentagon
        int a,b;        // spherical coordinate
        DWORD col;      // color

        // inline
        _hexagon()      {}
        _hexagon(_hexagon& a)   { *this=a; }
        ~_hexagon() {}
        _hexagon* operator = (const _hexagon *a) { *this=*a; return this; }
        //_hexagon* operator = (const _hexagon &a) { ...copy... return this; }
        };
    List<_hexagon> hex;
    //---------------------------------------------------------------------------
    // https://stackoverflow.com/a/46787885/2521214
    //---------------------------------------------------------------------------
    void hex_sphere(int N,double R)
        {
        const double c=cos(60.0*deg);
        const double s=sin(60.0*deg);
        const double sy=       R/(N+N-2);
        const double sz=sy/s;
        const double sx=sz*c;
        const double sz2=0.5*sz;

        const int na=5*(N-2);
        const int nb=  N;
        const int b0=  N;
        double *q,p[3],ang,len,l,l0,ll;
        int i,j,n,a,b,ix;
        _hexagon h,*ph;

        hex.allocate(na*nb);
        hex.num=0;
        pnt.reset3D(N*N);
        b=0; a=0; ix=0;

        // generate triangle hex grid
        h.col=0x00804000;
        for (b=1;b<N-1;b++)                             // skip first line b=0
         for (a=1;a<b;a++)                              // skip first and last line
            {
            p[0]=double(a       )*(sx+sz);
            p[1]=double(b-(a>>1))*(sy*2.0);
            p[2]=0.0;
            if (int(a&1)!=0) p[1]-=sy;
            ix=pnt.add(p[0]+sz2+sx,p[1]   ,p[2]); h.ix[0]=ix; //  2 1
            ix=pnt.add(p[0]+sz2   ,p[1]+sy,p[2]); h.ix[1]=ix; // 3   0
            ix=pnt.add(p[0]-sz2   ,p[1]+sy,p[2]); h.ix[2]=ix; //  4 5
            ix=pnt.add(p[0]-sz2-sx,p[1]   ,p[2]); h.ix[3]=ix;
            ix=pnt.add(p[0]-sz2   ,p[1]-sy,p[2]); h.ix[4]=ix;
            ix=pnt.add(p[0]+sz2   ,p[1]-sy,p[2]); h.ix[5]=ix;
            h.a=a;
            h.b=N-1-b;
            hex.add(h);
            } n=hex.num; // remember number of hexs for the first triangle

        // distort points to match area
        for (ix=0;ix<pnt.nn;ix+=3)
            {
            // point pointer
            q=pnt.pnt.dat+ix;
            // convert to polar coordinates
            ang=atan2(q[1],q[0]);
            len=vector_len(q);
            // match area of pentagon (72deg) triangle as we got hexagon (60deg) triangle
            ang-=60.0*deg;  // rotate so center of generated triangle is angle 0deg
            while (ang>+60.0*deg) ang-=pi2;
            while (ang<-60.0*deg) ang+=pi2;
            len*=cos(ang)/cos(30.0*deg);        // scale radius so triangle converts to pie
            ang*=72.0/60.0;                     // scale up angle so rotated triangles merge
            // convert back to cartesian
            q[0]=len*cos(ang);
            q[1]=len*sin(ang);
            }

        // copy and rotate the triangle to cover pentagon
        h.col=0x00404000;
        for (ang=72.0*deg,a=1;a<5;a++,ang+=72.0*deg)
         for (ph=hex.dat,i=0;i<n;i++,ph++)
            {
            for (j=0;j<6;j++)
                {
                vector_copy(p,pnt.pnt.dat+ph->ix[j]);
                rotate2d(-ang,p[0],p[1]);
                h.ix[j]=pnt.add(p[0],p[1],p[2]);
                }
            h.a=ph->a+(a*(N-2));
            h.b=ph->b;
            hex.add(h);
            }

        // compute z
        for (q=pnt.pnt.dat,ix=0;ix<pnt.nn;ix+=pnt.dn,q+=pnt.dn)
            {
            q[2]=0.0;
            ang=vector_len(q)*0.5*pi/R;
            q[2]=R*cos(ang);
            ll=fabs(R*sin(ang)/sqrt((q[0]*q[0])+(q[1]*q[1])));
            q[0]*=ll;
            q[1]*=ll;
            }

        // copy and mirror the other half-sphere
        n=hex.num;
        for (ph=hex.dat,i=0;i<n;i++,ph++)
            {
            for (j=0;j<6;j++)
                {
                vector_copy(p,pnt.pnt.dat+ph->ix[j]);
                p[2]=-p[2];
                h.ix[j]=pnt.add(p[0],p[1],p[2]);
                }
            h.a= ph->a;
            h.b=-ph->b;
            hex.add(h);
            }

        // create index search table
        int i0,i1,j0,j1,a0,a1,ii[5];
        int **ab=new int*[na];
        for (a=0;a<na;a++)
            {
            ab[a]=new int[nb+nb+1];
            for (b=-nb;b<=nb;b++) ab[a][b0+b]=-1;
            }
        n=hex.num;
        for (ph=hex.dat,i=0;i<n;i++,ph++) ab[ph->a][b0+ph->b]=i;

        // add join ring
        h.col=0x00408000;
        for (a=0;a<na;a++)
            {
            h.a=a;
            h.b=0;
            a0=a;
            a1=a+1; if (a1>=na) a1-=na;
            i0=ab[a0][b0+1];
            i1=ab[a1][b0+1];
            j0=ab[a0][b0-1];
            j1=ab[a1][b0-1];
            if ((i0>=0)&&(i1>=0))
             if ((j0>=0)&&(j1>=0))
                {
                h.ix[0]=hex[i1].ix[1];
                h.ix[1]=hex[i0].ix[0];
                h.ix[2]=hex[i0].ix[1];
                h.ix[3]=hex[j0].ix[1];
                h.ix[4]=hex[j0].ix[0];
                h.ix[5]=hex[j1].ix[1];
                hex.add(h);
                ab[h.a][b0+h.b]=hex.num-1;
                }
            }

        // add 2x5 join lines
        h.col=0x00008040;
        for (a=0;a<na;a+=N-2)
         for (b=1;b<N-3;b++)
            {
            // +b hemisphere
            h.a= a;
            h.b=+b;
            a0=a-b; if (a0<  0) a0+=na; i0=ab[a0][b0+b+0];
            a0--;   if (a0<  0) a0+=na; i1=ab[a0][b0+b+1];
            a1=a+1; if (a1>=na) a1-=na; j0=ab[a1][b0+b+0];
                                        j1=ab[a1][b0+b+1];
            if ((i0>=0)&&(i1>=0))
             if ((j0>=0)&&(j1>=0))
                {
                h.ix[0]=hex[i0].ix[5];
                h.ix[1]=hex[i0].ix[4];
                h.ix[2]=hex[i1].ix[5];
                h.ix[3]=hex[j1].ix[3];
                h.ix[4]=hex[j0].ix[4];
                h.ix[5]=hex[j0].ix[3];
                hex.add(h);
                }
            // -b hemisphere
            h.a= a;
            h.b=-b;
            a0=a-b; if (a0<  0) a0+=na; i0=ab[a0][b0-b+0];
            a0--;   if (a0<  0) a0+=na; i1=ab[a0][b0-b-1];
            a1=a+1; if (a1>=na) a1-=na; j0=ab[a1][b0-b+0];
                                        j1=ab[a1][b0-b-1];
            if ((i0>=0)&&(i1>=0))
             if ((j0>=0)&&(j1>=0))
                {
                h.ix[0]=hex[i0].ix[5];
                h.ix[1]=hex[i0].ix[4];
                h.ix[2]=hex[i1].ix[5];
                h.ix[3]=hex[j1].ix[3];
                h.ix[4]=hex[j0].ix[4];
                h.ix[5]=hex[j0].ix[3];
                hex.add(h);
                }
            }

        // add pentagons at poles
        _hexagon h0,h1;
        h0.col=0x00000080;
        h0.a=0; h0.b=N-1; h1=h0; h1.b=-h1.b;
        p[2]=sqrt((R*R)-(sz*sz));
        for (ang=0.0,a=0;a<5;a++,ang+=72.0*deg)
            {
            p[0]=2.0*sz*cos(ang);
            p[1]=2.0*sz*sin(ang);
            h0.ix[a]=pnt.add(p[0],p[1],+p[2]);
            h1.ix[a]=pnt.add(p[0],p[1],-p[2]);
            }
        h0.ix[5]=h0.ix[4]; hex.add(h0);
        h1.ix[5]=h1.ix[4]; hex.add(h1);

        // add 5 missing hexagons at poles
        h.col=0x00600060;
        for (ph=&h0,b=N-3,h.b=N-2,i=0;i<2;i++,b=-b,ph=&h1,h.b=-h.b)
            {
            a =  1; if (a>=na) a-=na; ii[0]=ab[a][b0+b];
            a+=N-2; if (a>=na) a-=na; ii[1]=ab[a][b0+b];
            a+=N-2; if (a>=na) a-=na; ii[2]=ab[a][b0+b];
            a+=N-2; if (a>=na) a-=na; ii[3]=ab[a][b0+b];
            a+=N-2; if (a>=na) a-=na; ii[4]=ab[a][b0+b];
            for (j=0;j<5;j++)
                {
                h.a=((4+j)%5)*(N-2)+1;
                h.ix[0]=ph->ix[ (5-j)%5 ];
                h.ix[1]=ph->ix[ (6-j)%5 ];
                h.ix[2]=hex[ii[(j+4)%5]].ix[4];
                h.ix[3]=hex[ii[(j+4)%5]].ix[5];
                h.ix[4]=hex[ii[ j     ]].ix[3];
                h.ix[5]=hex[ii[ j     ]].ix[4];
                hex.add(h);
                }
            }

        // add 2*5 pentagons and 2*5 missing hexagons at equator
        h0.a=0; h0.b=N-1; h1=h0; h1.b=-h1.b;
        for (ang=36.0*deg,a=0;a<na;a+=N-2,ang-=72.0*deg)
            {
            p[0]=R*cos(ang);
            p[1]=R*sin(ang);
            p[2]=sz;
            i0=pnt.add(p[0],p[1],+p[2]);
            i1=pnt.add(p[0],p[1],-p[2]);
            a0=a-1;if (a0<  0) a0+=na;
            a1=a+1;if (a1>=na) a1-=na;
            ii[0]=ab[a0][b0-1]; ii[2]=ab[a1][b0-1];
            ii[1]=ab[a0][b0+1]; ii[3]=ab[a1][b0+1];
            // hexagons
            h.col=0x00008080;
            h.a=a; h.b=0;
            h.ix[0]=hex[ii[0]].ix[0];
            h.ix[1]=hex[ii[0]].ix[1];
            h.ix[2]=hex[ii[1]].ix[1];
            h.ix[3]=hex[ii[1]].ix[0];
            h.ix[4]=i0;
            h.ix[5]=i1;
            hex.add(h);
            h.a=a; h.b=0;
            h.ix[0]=hex[ii[2]].ix[2];
            h.ix[1]=hex[ii[2]].ix[1];
            h.ix[2]=hex[ii[3]].ix[1];
            h.ix[3]=hex[ii[3]].ix[2];
            h.ix[4]=i0;
            h.ix[5]=i1;
            hex.add(h);
            // pentagons
            h.col=0x000040A0;
            h.a=a; h.b=0;
            h.ix[0]=hex[ii[0]].ix[0];
            h.ix[1]=hex[ii[0]].ix[5];
            h.ix[2]=hex[ii[2]].ix[3];
            h.ix[3]=hex[ii[2]].ix[2];
            h.ix[4]=i1;
            h.ix[5]=i1;
            hex.add(h);
            h.a=a; h.b=0;
            h.ix[0]=hex[ii[1]].ix[0];
            h.ix[1]=hex[ii[1]].ix[5];
            h.ix[2]=hex[ii[3]].ix[3];
            h.ix[3]=hex[ii[3]].ix[2];
            h.ix[4]=i0;
            h.ix[5]=i0;
            hex.add(h);
            }

        // release index search table
        for (a=0;a<na;a++) delete[] ab[a];
        delete[] ab;
        }
    //---------------------------------------------------------------------------
    void hex_draw(GLuint style)     // draw hex
        {
        int i,j;
        _hexagon *h;
        for (h=hex.dat,i=0;i<hex.num;i++,h++)
            {
            if (style==GL_POLYGON) glColor4ubv((BYTE*)&h->col);
            glBegin(style);
            for (j=0;j<6;j++) glVertex3dv(pnt.pnt.dat+h->ix[j]);
            glEnd();
            }
        if (0)
        if (style==GL_POLYGON)
            {
            scr.text_init_pixel(0.1,-0.2);
            glColor3f(1.0,1.0,1.0);
            for (h=hex.dat,i=0;i<hex.num;i++,h++)
             if (abs(h->b)<2)
                {
                double p[3];
                vector_ld(p,0.0,0.0,0.0);
                for (j=0;j<6;j++)
                 vector_add(p,p,pnt.pnt.dat+h->ix[j]);
                vector_mul(p,p,1.0/6.0);
                scr.text(p[0],p[1],p[2],AnsiString().sprintf("%i,%i",h->a,h->b));
                }
            scr.text_exit_pixel();
            }
        }
    //---------------------------------------------------------------------------
    void TMain::draw()
        {
        scr.cls();
        int x,y;

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.0,0.0,-5.0);
        glRotated(animx,1.0,0.0,0.0);
        glRotated(animy,0.0,1.0,0.0);

        hex_draw(GL_POLYGON);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.0,0.0,-5.0+0.01);
        glRotated(animx,1.0,0.0,0.0);
        glRotated(animy,0.0,1.0,0.0);

        glColor3f(1.0,1.0,1.0);
        glLineWidth(2);
        hex_draw(GL_LINE_LOOP);
        glCirclexy(0.0,0.0,0.0,1.5);
        glLineWidth(1);

        scr.exe();
        scr.rfs();
        }
    //---------------------------------------------------------------------------
    __fastcall TMain::TMain(TComponent* Owner) : TForm(Owner)
        {
        scr.init(this);
        hex_sphere(10,1.5);
        _redraw=true;
        }
    //---------------------------------------------------------------------------
    void __fastcall TMain::FormDestroy(TObject *Sender)
        {
        scr.exit();
        }
    //---------------------------------------------------------------------------
    void __fastcall TMain::FormPaint(TObject *Sender)
        {
        _redraw=true;
        }
    //---------------------------------------------------------------------------
    void __fastcall TMain::FormResize(TObject *Sender)
        {
        scr.resize();
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(60,float(scr.xs)/float(scr.ys),0.1,100.0);
        _redraw=true;
        }
    //-----------------------------------------------------------------------
    void __fastcall TMain::Timer1Timer(TObject *Sender)
        {
        animx+=danimx; if (animx>=360.0) animx-=360.0; _redraw=true;
        animy+=danimy; if (animy>=360.0) animy-=360.0; _redraw=true;
        if (_redraw) { draw(); _redraw=false; }
        }
    //---------------------------------------------------------------------------
    void __fastcall TMain::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
        {
        Caption=Key;
        if (Key==40){ animx+=2.0; _redraw=true; }
        if (Key==38){ animx-=2.0; _redraw=true; }
        if (Key==39){ animy+=2.0; _redraw=true; }
        if (Key==37){ animy-=2.0; _redraw=true; }
        }
    //---------------------------------------------------------------------------

    我知道这有点索引混乱,而且由于我懒于进行统一索引,因此无法保证缠绕规则。请注意,每个十六进制的a索引都不是线性的,如果要使用它们映射到2D映射,则需要使用其中心点位置x,y上的atan2重新计算它。

    这里预览:

    preview preview

    仍然存在一些失真。它们是由以下事实造成的:我们使用5个三角形在赤道处进行连接(因此可以保证连接)。这意味着周长是5*R而不是6.28*R。现场模拟仍然可以改善这一点。只需取所有点,并根据它们的距离并绑定到球体表面添加回弹力即可。运行模拟,当振荡降低到阈值以下时,您得到了球体网格...

    另一个选择是找出一些方程式以重新映射网格点(类似于我对三角形到饼形转换所做的操作),这样可以得到更好的结果。