Hexagonal tilling of hemi-sphere

2019-03-01 08:17发布

问题:

I need to have hexagonal grid on a spherical surface. like shown here.

Right now I am doing a hexagonal flattened grid. and the projecting it onto the surface of a hemisphere. Like here, But as you can see, the funny artifact is hexagons on the edge are disproportionately large. There should be a better way to do this so that all the hexagons are near equal in their size.

I had tried the solution like @spektre had suggested but my code was producing following plot.

i was using the a=sqrt(x*x+y*y)/r * (pi/2) because i wanted to scale a that goes from [0,r] to z [0,r] so angle a has bounds of [0,pi/2].

But with just a=sqrt(x*x+y*y)/r it works well.

New Development with the task, New problem

I have the problem that now, the hexagons are not equal through out the shapes. I want a uniform shape (area wise) for them across the dome and cylinder. I am confused on how to manage this?

回答1:

Here is what I have in mind:

  1. create planar hex grid on XY plane

    center of your grid must be the center of your sphere I chose (0,0,0) and size of the grid should be at least the 2*radius of your sphere big.

  2. convert planar coordinates to spherical

    so distance from (0,0,0) to point coordinate in XY plane is arclength traveling on surface of your sphere so if processed point is (x,y,z) and sphere radius is r then latitude position on sphere is:

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

    so we can directly compute z coordinate:

    z=r*cos(a);
    

    and scale x,y to surface of sphere:

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

    If the z coordinate is negative then you have crossed half sphere and should handle differently (skip hex or convert to cylinder or whatever)

Here Small OpenGL/C++ example for this:

//---------------------------------------------------------------------------
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();
    }
//---------------------------------------------------------------------------

And usage:

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);

And preview:

For more info and ideas see related:

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