| #include <u.h> |
| #include <libc.h> |
| #include "map.h" |
| |
| /* |
| * conformal map of earth onto tetrahedron |
| * the stages of mapping are |
| * (a) stereo projection of tetrahedral face onto |
| * isosceles curvilinear triangle with 3 120-degree |
| * angles and one straight side |
| * (b) map of this triangle onto half plane cut along |
| * 3 rays from the roots of unity to infinity |
| * formula (z^4+2*3^.5*z^2-1)/(z^4-2*3^.5*z^2-1) |
| * (c) do 3 times for each sector of plane: |
| * map of |arg z|<=pi/6, cut along z>1 into |
| * triangle |arg z|<=pi/6, Re z<=const, |
| * with upper side of cut going into upper half of |
| * of vertical side of triangle and lowere into lower |
| * formula int from 0 to z dz/sqrt(1-z^3) |
| * |
| * int from u to 1 3^.25*du/sqrt(1-u^3) = |
| F(acos((rt3-1+u)/(rt3+1-u)),sqrt(1/2+rt3/4)) |
| * int from 1 to u 3^.25*du/sqrt(u^3-1) = |
| * F(acos((rt3+1-u)/(rt3-1+u)),sqrt(1/2-rt3/4)) |
| * this latter formula extends analytically down to |
| * u=0 and is the basis of this routine, with the |
| * argument of complex elliptic integral elco2 |
| * being tan(acos...) |
| * the formula F(pi-x,k) = 2*F(pi/2,k)-F(x,k) is |
| * used to cross over into the region where Re(acos...)>pi/2 |
| * f0 and fpi are suitably scaled complete integrals |
| */ |
| |
| #define TFUZZ 0.00001 |
| |
| static struct place tpole[4]; /* point of tangency of tetrahedron face*/ |
| static double tpoleinit[4][2] = { |
| 1., 0., |
| 1., 180., |
| -1., 90., |
| -1., -90. |
| }; |
| static struct tproj { |
| double tlat,tlon; /* center of stereo projection*/ |
| double ttwist; /* rotatn before stereo*/ |
| double trot; /*rotate after projection*/ |
| struct place projpl; /*same as tlat,tlon*/ |
| struct coord projtw; /*same as ttwist*/ |
| struct coord postrot; /*same as trot*/ |
| } tproj[4][4] = { |
| {/*00*/ {0.}, |
| /*01*/ {90., 0., 90., -90.}, |
| /*02*/ {0., 45., -45., 150.}, |
| /*03*/ {0., -45., -135., 30.} |
| }, |
| {/*10*/ {90., 0., -90., 90.}, |
| /*11*/ {0.}, |
| /*12*/ {0., 135., -135., -150.}, |
| /*13*/ {0., -135., -45., -30.} |
| }, |
| {/*20*/ {0., 45., 135., -30.}, |
| /*21*/ {0., 135., 45., -150.}, |
| /*22*/ {0.}, |
| /*23*/ {-90., 0., 180., 90.} |
| }, |
| {/*30*/ {0., -45., 45., -150.}, |
| /*31*/ {0., -135., 135., -30.}, |
| /*32*/ {-90., 0., 0., 90.}, |
| /*33*/ {0.} |
| }}; |
| static double tx[4] = { /*where to move facet after final rotation*/ |
| 0., 0., -1., 1. /*-1,1 to be sqrt(3)*/ |
| }; |
| static double ty[4] = { |
| 0., 2., -1., -1. |
| }; |
| static double root3; |
| static double rt3inv; |
| static double two_rt3; |
| static double tkc,tk,tcon; |
| static double f0r,f0i,fpir,fpii; |
| |
| static void |
| twhichp(struct place *g, int *p, int *q) |
| { |
| int i,j,k; |
| double cosdist[4]; |
| struct place *tp; |
| for(i=0;i<4;i++) { |
| tp = &tpole[i]; |
| cosdist[i] = g->nlat.s*tp->nlat.s + |
| g->nlat.c*tp->nlat.c*( |
| g->wlon.s*tp->wlon.s + |
| g->wlon.c*tp->wlon.c); |
| } |
| j = 0; |
| for(i=1;i<4;i++) |
| if(cosdist[i] > cosdist[j]) |
| j = i; |
| *p = j; |
| k = j==0?1:0; |
| for(i=0;i<4;i++) |
| if(i!=j&&cosdist[i]>cosdist[k]) |
| k = i; |
| *q = k; |
| } |
| |
| int |
| Xtetra(struct place *place, double *x, double *y) |
| { |
| int i,j; |
| struct place pl; |
| register struct tproj *tpp; |
| double vr, vi; |
| double br, bi; |
| double zr,zi,z2r,z2i,z4r,z4i,sr,si,tr,ti; |
| twhichp(place,&i,&j); |
| copyplace(place,&pl); |
| norm(&pl,&tproj[i][j].projpl,&tproj[i][j].projtw); |
| Xstereographic(&pl,&vr,&vi); |
| zr = vr/2; |
| zi = vi/2; |
| if(zr<=TFUZZ) |
| zr = TFUZZ; |
| csq(zr,zi,&z2r,&z2i); |
| csq(z2r,z2i,&z4r,&z4i); |
| z2r *= two_rt3; |
| z2i *= two_rt3; |
| cdiv(z4r+z2r-1,z4i+z2i,z4r-z2r-1,z4i-z2i,&sr,&si); |
| csqrt(sr-1,si,&tr,&ti); |
| cdiv(tcon*tr,tcon*ti,root3+1-sr,-si,&br,&bi); |
| if(br<0) { |
| br = -br; |
| bi = -bi; |
| if(!elco2(br,bi,tk,1.,1.,&vr,&vi)) |
| return 0; |
| vr = fpir - vr; |
| vi = fpii - vi; |
| } else |
| if(!elco2(br,bi,tk,1.,1.,&vr,&vi)) |
| return 0; |
| if(si>=0) { |
| tr = f0r - vi; |
| ti = f0i + vr; |
| } else { |
| tr = f0r + vi; |
| ti = f0i - vr; |
| } |
| tpp = &tproj[i][j]; |
| *x = tr*tpp->postrot.c + |
| ti*tpp->postrot.s + tx[i]; |
| *y = ti*tpp->postrot.c - |
| tr*tpp->postrot.s + ty[i]; |
| return(1); |
| } |
| |
| int |
| tetracut(struct place *g, struct place *og, double *cutlon) |
| { |
| int i,j,k; |
| if((g->nlat.s<=-rt3inv&&og->nlat.s<=-rt3inv) && |
| (ckcut(g,og,*cutlon=0.)==2||ckcut(g,og,*cutlon=PI)==2)) |
| return(2); |
| twhichp(g,&i,&k); |
| twhichp(og,&j,&k); |
| if(i==j||i==0||j==0) |
| return(1); |
| return(0); |
| } |
| |
| proj |
| tetra(void) |
| { |
| int i; |
| int j; |
| register struct place *tp; |
| register struct tproj *tpp; |
| double t; |
| root3 = sqrt(3.); |
| rt3inv = 1/root3; |
| two_rt3 = 2*root3; |
| tkc = sqrt(.5-.25*root3); |
| tk = sqrt(.5+.25*root3); |
| tcon = 2*sqrt(root3); |
| elco2(tcon/(root3-1),0.,tkc,1.,1.,&f0r,&f0i); |
| elco2(1.e15,0.,tk,1.,1.,&fpir,&fpii); |
| fpir *= 2; |
| fpii *= 2; |
| for(i=0;i<4;i++) { |
| tx[i] *= f0r*root3; |
| ty[i] *= f0r; |
| tp = &tpole[i]; |
| t = tp->nlat.s = tpoleinit[i][0]/root3; |
| tp->nlat.c = sqrt(1 - t*t); |
| tp->nlat.l = atan2(tp->nlat.s,tp->nlat.c); |
| deg2rad(tpoleinit[i][1],&tp->wlon); |
| for(j=0;j<4;j++) { |
| tpp = &tproj[i][j]; |
| latlon(tpp->tlat,tpp->tlon,&tpp->projpl); |
| deg2rad(tpp->ttwist,&tpp->projtw); |
| deg2rad(tpp->trot,&tpp->postrot); |
| } |
| } |
| return(Xtetra); |
| } |
| |