半球六边形拼贴

Hexagonal tilling of hemi-sphere

我需要在球面上有六边形网格。就像这里显示的那样。

现在我正在做一个六边形的扁平网格。 并将其投影到半球的表面上。像这儿, 但正如您所见,有趣的神器是边缘的六边形大得不成比例。应该有更好的方法来做到这一点,以便所有六边形的大小几乎相等。

我已经尝试过@spektre 建议的解决方案,但我的代码产生了以下情节。

我正在使用 a=sqrt(x*x+y*y)/r * (pi/2) 因为我想缩放从 [0,r]z [0,r]a 所以角度 a[0,pi/2]

但仅 a=sqrt(x*x+y*y)/r 效果很好。

任务的新开发,新问题

我现在遇到的问题是,六边形在所有形状中都不相等。我希望它们在整个圆顶和圆柱体上具有统一的形状(区域方面)。我对如何管理这个感到困惑?

这是我的想法:

  1. 在 XY 平面上创建平面六角网格

    你的网格中心 必须是 我选择的你的球体的中心 (0,0,0) 并且网格的大小应该至少是你的球体半径的 2* 大.

  2. 将平面坐标转换为球面坐标

    所以从 (0,0,0)XY 平面中的点坐标的距离是在球体表面上移动的弧长所以如果处理的点是 (x,y,z) 和球体半径是 r 那么球体上的纬度位置是:

    a=sqrt(x*x+y*y)/r;
    

    所以我们可以直接计算z坐标:

    z=r*cos(a);
    

    并缩放 x,y 到球体表面:

    a=r*sin(a)/sqrt(x*x+y*y);
    x*=a; y*=a;
    

    如果 z 坐标为负,那么您已经越过了半个球体,应该以不同的方式处理(跳过十六进制或转换为圆柱体或其他)

这里是小OpenGL/C++例子:

//---------------------------------------------------------------------------
const int _gx=15;           // hex grid size
const int _gy=15;
const int _hy=(_gy+1)<<1;   // hex points size
const int _hx=(_gx+1);
double hex[_hy][_hx][3];    // hex grid points
//---------------------------------------------------------------------------
void hexgrid_init(double r) // set hex[][][] to planar hex grid points at xy plane
    {
    double x0,y0,x,y,z,dx,dy,dz;
    double sx,sy,sz;
    int i,j;
    // hex sizes
    sz=sqrt(8.0)*r/double(_hy);
    sx=sz*cos(60.0*deg);
    sy=sz*sin(60.0*deg);

    // center points arrounf (0,0)
    x0=(0.5*sz)-double(_hy/4)*(sz+sx);
    y0=-double(_hx)*(sy);
    if (int(_gx&1)==0) x0-=sz+sx;
    if (int(_gy&1)==0) y0-=sy; else y0+=sy;

    for (y=y0,i=0;i<_hy;i+=2,y+=sy+sy)
     for (x=x0,j=0;j<_hx;j++,x+=sz)
        {
        hex[i][j][0]=x;
        hex[i][j][1]=y;
        hex[i][j][2]=0.0;
        x+=sz+sx+sx; j++; if (j>=_hx) break;
        hex[i][j][0]=x;
        hex[i][j][1]=y;
        hex[i][j][2]=0.0;
        }

    for (y=y0+sy,i=1;i<_hy;i+=2,y+=sy+sy)
     for (x=x0+sx,j=0;j<_hx;j++,x+=sx+sx+sz)
        {
        hex[i][j][0]=x;
        hex[i][j][1]=y;
        hex[i][j][2]=0.0;
        x+=sz; j++; if (j>=_hx) break;
        hex[i][j][0]=x;
        hex[i][j][1]=y;
        hex[i][j][2]=0.0;
        }

    }
//---------------------------------------------------------------------------
void hexgrid_half_sphere(double r0) // convert planar hex grid to half sphere at (0,0,0) with radius r0
    {
    int i,j;
    double x,y,z,a,l;
    for (i=0;i<_hy;i++)
     for (j=0;j<_hx;j++)
        {
        x=hex[i][j][0];
        y=hex[i][j][1];
        z=hex[i][j][2];
        l=sqrt(x*x+y*y);    // distance from center on xy plane (arclength)
        a=l/r0;             // convert arclength to angle
        z=r0*cos(a);        // compute z coordinate (sphere)
        if (z>=0.0)         // half sphere
            {
            a=r0*sin(a)/l;
            }
        else{               // turn hexes above half sphere to cylinder
            z=0.5*pi*r0-l;
            a=r0/l;
            }
        x*=a;
        y*=a;
        hex[i][j][0]=x;
        hex[i][j][1]=y;
        hex[i][j][2]=z;
        }
    }
//---------------------------------------------------------------------------
void hex_draw(int x,int y,GLuint style)     // draw hex x = <0,_gx) , y = <0,_gy)
    {
    y<<=1;
    if ((x&1)==0) y++;
    if ((x<0)||(x+1>=_hx)) return;
    if ((y<0)||(y+2>=_hy)) return;
    glBegin(style);
    glVertex3dv(hex[y+1][x  ]);
    glVertex3dv(hex[y  ][x  ]);
    glVertex3dv(hex[y  ][x+1]);
    glVertex3dv(hex[y+1][x+1]);
    glVertex3dv(hex[y+2][x+1]);
    glVertex3dv(hex[y+2][x  ]);
    glEnd();
    }
//---------------------------------------------------------------------------

和用法:

hexgrid_init(1.5);
hexgrid_half_sphere(1.0);

int x,y;
glColor3f(0.0,0.2,0.3);
for (y=0;y<_gy;y++)
 for (x=0;x<_gx;x++)
  hex_draw(x,y,GL_POLYGON);
glLineWidth(2);
glColor3f(1.0,1.0,1.0);
for (y=0;y<_gy;y++)
 for (x=0;x<_gx;x++)
  hex_draw(x,y,GL_LINE_LOOP);
glLineWidth(1);

预览:

有关更多信息和想法,请参阅相关内容:

  • Make a sphere with equidistant vertices
  • Turning a cylinder into a sphere without pinching at the poles