static int isea_ptdi(ref isea_dgg g, int tri, isea_pt pt, out isea_pt di) { isea_pt v = pt; int quad = isea_ptdd(tri, ref v); quad = isea_dddi(ref g, quad, v, out di); return(quad); }
// fuller's at 5.2454 west, 2.3009 N, adjacent at 7.46658 deg static void isea_grid_init(ref isea_dgg g) { g.polyhedron = isea_poly.ISEA_ICOSAHEDRON; g.o_lat = ISEA_STD_LAT; g.o_lon = ISEA_STD_LON; g.o_az = 0.0; g.aperture = 4; g.resolution = 6; g.radius = 1.0; g.topology = isea_topology.ISEA_HEXAGON; }
static isea_pt isea_forward(isea_dgg g, isea_geo @in) { isea_pt @out, coord; int tri = isea_transform(ref g, @in, out @out); if (g.output == isea_address_form.ISEA_PLANE) { isea_tri_plane(tri, ref @out, g.radius); return(@out); } // convert to isea standard triangle size @out.x = @out.x / g.radius * ISEA_SCALE; @out.y = @out.y / g.radius * ISEA_SCALE; @out.x += 0.5; @out.y += 2.0 * .14433756729740644112; switch (g.output) { case isea_address_form.ISEA_PROJTRI: // nothing to do, already in projected triangle break; case isea_address_form.ISEA_VERTEX2DD: g.quad = isea_ptdd(tri, ref @out); break; case isea_address_form.ISEA_Q2DD: // Same as above, we just don't print as much g.quad = isea_ptdd(tri, ref @out); break; case isea_address_form.ISEA_Q2DI: g.quad = isea_ptdi(ref g, tri, @out, out coord); return(coord); case isea_address_form.ISEA_SEQNUM: isea_ptdi(ref g, tri, @out, out coord); // disn will set g->serial isea_disn(ref g, g.quad, coord); return(coord); case isea_address_form.ISEA_HEX: isea_hex(ref g, tri, @out, out coord); return(coord); } return(@out); }
static int isea_transform(ref isea_dgg g, isea_geo @in, out isea_pt @out) { isea_geo pole; pole.lat = g.o_lat; pole.lon = g.o_lon; isea_geo i = isea_ctran(ref pole, @in, g.o_az); int tri = isea_snyder_forward(i, out @out); @out.x *= g.radius; @out.y *= g.radius; g.triangle = tri; return(tri); }
// q2di to seqnum static int isea_disn(ref isea_dgg g, int quad, isea_pt di) { if (quad == 0) { g.serial = 1; return(1); } // hexes in a quad int hexes = (int)(Math.Pow(g.aperture, g.resolution) + 0.5); if (quad == 11) { g.serial = (ulong)(1 + 10 * hexes + 1); return((int)g.serial); } int sn; if (g.aperture == 3 && g.resolution % 2 == 1) { int height = (int)(Math.Pow(g.aperture, (g.resolution - 1) / 2.0)); sn = ((int)di.x) * height; sn += ((int)di.y) / height; sn += (quad - 1) * hexes; sn += 2; } else { int sidelength = (int)(Math.Pow(g.aperture, g.resolution / 2.0) + 0.5); sn = (int)((quad - 1) * hexes + sidelength * di.x + di.y + 2); } g.serial = (ulong)sn; return(sn); }
// TODO just encode the quad in the d or i coordinate // quad is 0-11, which can be four bits. // d' = d << 4 + q, d = d' >> 4, q = d' & 0xf // convert a q2di to global hex coord static int isea_hex(ref isea_dgg g, int tri, isea_pt pt, out isea_pt hex) { isea_pt v; int quad=isea_ptdi(ref g, tri, pt, out v); hex.x=((int)v.x<<4)+quad; hex.y=v.y; return 1; // silence the compiler #if false double d=v.x; double i=v.y; // Aperture 3 odd resolutions if(g.aperture==3&&g.resolution%2!=0) { int offset=(int)(Math.Pow(3.0, g.resolution-1)+0.5); d+=offset*((g.quad-1)%5); i+=offset*((g.quad-1)%5); if(quad==0) { d=0; i=offset; } else if(quad==11) { d=2*offset; i=0; } else if(quad>5) { d+=offset; } double x=(2*d-i)/3; double y=(2*i-d)/3; hex.x=x+offset/3; hex.y=y+2*offset/3; return 1; } // aperture 3 even resolutions and aperture 4 double sidelength=(int)(Math.Pow(g.aperture, g.resolution/2.0)+0.5); if(g.quad==0) { hex.x=0; hex.y=sidelength; } else if(g.quad==11) { hex.x=sidelength*2; hex.y=0; } else { hex.x=d+sidelength*((g.quad-1)%5); if(g.quad>5) hex.x+=sidelength; hex.y=i+sidelength*((g.quad-1)%5); } return 1; #endif }
// fuller's at 5.2454 west, 2.3009 N, adjacent at 7.46658 deg static void isea_grid_init(ref isea_dgg g) { g.polyhedron=isea_poly.ISEA_ICOSAHEDRON; g.o_lat=ISEA_STD_LAT; g.o_lon=ISEA_STD_LON; g.o_az=0.0; g.aperture=4; g.resolution=6; g.radius=1.0; g.topology=isea_topology.ISEA_HEXAGON; }
static isea_pt isea_forward(isea_dgg g, isea_geo @in) { isea_pt @out, coord; int tri=isea_transform(ref g, @in, out @out); if(g.output==isea_address_form.ISEA_PLANE) { isea_tri_plane(tri, ref @out, g.radius); return @out; } // convert to isea standard triangle size @[email protected]/g.radius*ISEA_SCALE; @[email protected]/g.radius*ISEA_SCALE; @out.x+=0.5; @out.y+=2.0*.14433756729740644112; switch(g.output) { case isea_address_form.ISEA_PROJTRI: // nothing to do, already in projected triangle break; case isea_address_form.ISEA_VERTEX2DD: g.quad=isea_ptdd(tri, ref @out); break; case isea_address_form.ISEA_Q2DD: // Same as above, we just don't print as much g.quad=isea_ptdd(tri, ref @out); break; case isea_address_form.ISEA_Q2DI: g.quad=isea_ptdi(ref g, tri, @out, out coord); return coord; case isea_address_form.ISEA_SEQNUM: isea_ptdi(ref g, tri, @out, out coord); // disn will set g->serial isea_disn(ref g, g.quad, coord); return coord; case isea_address_form.ISEA_HEX: isea_hex(ref g, tri, @out, out coord); return coord; } return @out; }
// q2di to seqnum static int isea_disn(ref isea_dgg g, int quad, isea_pt di) { if(quad==0) { g.serial=1; return 1; } // hexes in a quad int hexes=(int)(Math.Pow(g.aperture, g.resolution)+0.5); if(quad==11) { g.serial=(ulong)(1+10*hexes+1); return (int)g.serial; } int sn; if(g.aperture==3&&g.resolution%2==1) { int height=(int)(Math.Pow(g.aperture, (g.resolution-1)/2.0)); sn=((int)di.x)*height; sn+=((int)di.y)/height; sn+=(quad-1)*hexes; sn+=2; } else { int sidelength=(int)(Math.Pow(g.aperture, g.resolution/2.0)+0.5); sn=(int)((quad-1)*hexes+sidelength*di.x+di.y+2); } g.serial=(ulong)sn; return sn; }
static int isea_dddi_ap3odd(ref isea_dgg g, int quad, isea_pt pt, out isea_pt di) { // This is the number of hexes from apex to base of a triangle double sidelength=(Math.Pow(2.0, g.resolution)+1.0)/2.0; // in hexes // apex to base is cos(30deg) double hexwidth=Math.Cos(Math.PI/6.0)/sidelength; // TODO I think sidelength is always x.5, so // (int)sidelength * 2 + 1 might be just as good int maxcoord=(int)(sidelength*2.0+0.5); isea_pt v=pt; hex h; h.z=0; hexbin2(hexwidth, v.x, v.y, out h.x, out h.y); h.iso=false; hex_iso(ref h); int d=h.x-h.z; int i=h.x+h.y+h.y; // you want to test for max coords for the next quad in the same // "row" first to get the case where both are max if(quad<=5) { if(d==0&&i==maxcoord) { // north pole quad=0; d=0; i=0; } else if(i==maxcoord) { // upper right in next quad quad+=1; if(quad==6) quad=1; i=maxcoord-d; d=0; } else if(d==maxcoord) { // lower right in quad to lower right quad+=5; d=0; } } else if(quad>=6) { if(i==0&&d==maxcoord) { // south pole quad=11; d=0; i=0; } else if(d==maxcoord) { // lower right in next quad quad+=1; if(quad==11) quad=6; d=maxcoord-i; i=0; } else if(i==maxcoord) { // upper right in quad to upper right quad=(quad-4)%5; i=0; } } di.x=d; di.y=i; g.quad=quad; return quad; }
static int isea_ptdi(ref isea_dgg g, int tri, isea_pt pt, out isea_pt di) { isea_pt v=pt; int quad=isea_ptdd(tri, ref v); quad=isea_dddi(ref g, quad, v, out di); return quad; }
static int isea_dddi(ref isea_dgg g, int quad, isea_pt pt, out isea_pt di) { if (g.aperture == 3 && g.resolution % 2 != 0) { return(isea_dddi_ap3odd(ref g, quad, pt, out di)); } // todo might want to do this as an iterated loop int sidelength; // in hexes if (g.aperture > 0) { sidelength = (int)(Math.Pow(g.aperture, g.resolution / 2.0) + 0.5); } else { sidelength = g.resolution; } double hexwidth = 1.0 / sidelength; isea_pt v = pt; hex h; h.z = 0; isea_rotate(ref v, -30.0); hexbin2(hexwidth, v.x, v.y, out h.x, out h.y); h.iso = false; hex_iso(ref h); // we may actually be on another quad if (quad <= 5) { if (h.x == 0 && h.z == -sidelength) { // north pole quad = 0; h.z = 0; h.y = 0; h.x = 0; } else if (h.z == -sidelength) { quad = quad + 1; if (quad == 6) { quad = 1; } h.y = sidelength - h.x; h.z = h.x - sidelength; h.x = 0; } else if (h.x == sidelength) { quad += 5; h.y = -h.z; h.x = 0; } } else if (quad >= 6) { if (h.z == 0 && h.x == sidelength) { // south pole quad = 11; h.x = 0; h.y = 0; h.z = 0; } else if (h.x == sidelength) { quad = quad + 1; if (quad == 11) { quad = 6; } h.x = h.y + sidelength; h.y = 0; h.z = -h.x; } else if (h.y == -sidelength) { quad -= 4; h.y = 0; h.z = -h.x; } } di.x = h.x; di.y = -h.z; g.quad = quad; return(quad); }
static int isea_dddi_ap3odd(ref isea_dgg g, int quad, isea_pt pt, out isea_pt di) { // This is the number of hexes from apex to base of a triangle double sidelength = (Math.Pow(2.0, g.resolution) + 1.0) / 2.0; // in hexes // apex to base is cos(30deg) double hexwidth = Math.Cos(Math.PI / 6.0) / sidelength; // TODO I think sidelength is always x.5, so // (int)sidelength * 2 + 1 might be just as good int maxcoord = (int)(sidelength * 2.0 + 0.5); isea_pt v = pt; hex h; h.z = 0; hexbin2(hexwidth, v.x, v.y, out h.x, out h.y); h.iso = false; hex_iso(ref h); int d = h.x - h.z; int i = h.x + h.y + h.y; // you want to test for max coords for the next quad in the same // "row" first to get the case where both are max if (quad <= 5) { if (d == 0 && i == maxcoord) { // north pole quad = 0; d = 0; i = 0; } else if (i == maxcoord) { // upper right in next quad quad += 1; if (quad == 6) { quad = 1; } i = maxcoord - d; d = 0; } else if (d == maxcoord) { // lower right in quad to lower right quad += 5; d = 0; } } else if (quad >= 6) { if (i == 0 && d == maxcoord) { // south pole quad = 11; d = 0; i = 0; } else if (d == maxcoord) { // lower right in next quad quad += 1; if (quad == 11) { quad = 6; } d = maxcoord - i; i = 0; } else if (i == maxcoord) { // upper right in quad to upper right quad = (quad - 4) % 5; i = 0; } } di.x = d; di.y = i; g.quad = quad; return(quad); }
static void isea_orient_pole(ref isea_dgg g) { g.o_lat = Math.PI / 2.0; g.o_lon = 0.0; g.o_az = 0; }
static void isea_orient_isea(ref isea_dgg g) { g.o_lat = ISEA_STD_LAT; g.o_lon = ISEA_STD_LON; g.o_az = 0.0; }
static void isea_orient_isea(ref isea_dgg g) { g.o_lat=ISEA_STD_LAT; g.o_lon=ISEA_STD_LON; g.o_az=0.0; }
static void isea_orient_pole(ref isea_dgg g) { g.o_lat=Math.PI/2.0; g.o_lon=0.0; g.o_az=0; }
static int isea_dddi(ref isea_dgg g, int quad, isea_pt pt, out isea_pt di) { if(g.aperture==3&&g.resolution%2!=0) return isea_dddi_ap3odd(ref g, quad, pt, out di); // todo might want to do this as an iterated loop int sidelength; // in hexes if(g.aperture>0) sidelength=(int)(Math.Pow(g.aperture, g.resolution/2.0)+0.5); else sidelength=g.resolution; double hexwidth=1.0/sidelength; isea_pt v=pt; hex h; h.z=0; isea_rotate(ref v, -30.0); hexbin2(hexwidth, v.x, v.y, out h.x, out h.y); h.iso=false; hex_iso(ref h); // we may actually be on another quad if(quad<=5) { if(h.x==0&&h.z==-sidelength) { // north pole quad=0; h.z=0; h.y=0; h.x=0; } else if(h.z==-sidelength) { quad=quad+1; if(quad==6) quad=1; h.y=sidelength-h.x; h.z=h.x-sidelength; h.x=0; } else if(h.x==sidelength) { quad+=5; h.y=-h.z; h.x=0; } } else if(quad>=6) { if(h.z==0&&h.x==sidelength) { // south pole quad=11; h.x=0; h.y=0; h.z=0; } else if(h.x==sidelength) { quad=quad+1; if(quad==11) quad=6; h.x=h.y+sidelength; h.y=0; h.z=-h.x; } else if(h.y==-sidelength) { quad-=4; h.y=0; h.z=-h.x; } } di.x=h.x; di.y=-h.z; g.quad=quad; return quad; }
static int isea_transform(ref isea_dgg g, isea_geo @in, out isea_pt @out) { isea_geo pole; pole.lat=g.o_lat; pole.lon=g.o_lon; isea_geo i=isea_ctran(ref pole, @in, g.o_az); int tri=isea_snyder_forward(i, out @out); @out.x*=g.radius; @out.y*=g.radius; g.triangle=tri; return tri; }
// TODO just encode the quad in the d or i coordinate // quad is 0-11, which can be four bits. // d' = d << 4 + q, d = d' >> 4, q = d' & 0xf // convert a q2di to global hex coord static int isea_hex(ref isea_dgg g, int tri, isea_pt pt, out isea_pt hex) { isea_pt v; int quad = isea_ptdi(ref g, tri, pt, out v); hex.x = ((int)v.x << 4) + quad; hex.y = v.y; return(1); // silence the compiler #if false double d = v.x; double i = v.y; // Aperture 3 odd resolutions if (g.aperture == 3 && g.resolution % 2 != 0) { int offset = (int)(Math.Pow(3.0, g.resolution - 1) + 0.5); d += offset * ((g.quad - 1) % 5); i += offset * ((g.quad - 1) % 5); if (quad == 0) { d = 0; i = offset; } else if (quad == 11) { d = 2 * offset; i = 0; } else if (quad > 5) { d += offset; } double x = (2 * d - i) / 3; double y = (2 * i - d) / 3; hex.x = x + offset / 3; hex.y = y + 2 * offset / 3; return(1); } // aperture 3 even resolutions and aperture 4 double sidelength = (int)(Math.Pow(g.aperture, g.resolution / 2.0) + 0.5); if (g.quad == 0) { hex.x = 0; hex.y = sidelength; } else if (g.quad == 11) { hex.x = sidelength * 2; hex.y = 0; } else { hex.x = d + sidelength * ((g.quad - 1) % 5); if (g.quad > 5) { hex.x += sidelength; } hex.y = i + sidelength * ((g.quad - 1) % 5); } return(1); #endif }