| #include <u.h> |
| #include <libc.h> |
| #include "map.h" |
| |
| /* For Albers formulas see Deetz and Adams "Elements of Map Projection", */ |
| /* USGS Special Publication No. 68, GPO 1921 */ |
| |
| static double r0sq, r1sq, d2, n, den, sinb1, sinb2; |
| static struct coord plat1, plat2; |
| static int southpole; |
| |
| static double num(double s) |
| { |
| if(d2==0) |
| return(1); |
| s = d2*s*s; |
| return(1+s*(2./3+s*(3./5+s*(4./7+s*5./9)))); |
| } |
| |
| /* Albers projection for a spheroid, good only when N pole is fixed */ |
| |
| static int |
| Xspalbers(struct place *place, double *x, double *y) |
| { |
| double r = sqrt(r0sq-2*(1-d2)*place->nlat.s*num(place->nlat.s)/n); |
| double t = n*place->wlon.l; |
| *y = r*cos(t); |
| *x = -r*sin(t); |
| if(!southpole) |
| *y = -*y; |
| else |
| *x = -*x; |
| return(1); |
| } |
| |
| /* lat1, lat2: std parallels; e2: squared eccentricity */ |
| |
| static proj albinit(double lat1, double lat2, double e2) |
| { |
| double r1; |
| double t; |
| for(;;) { |
| if(lat1 < -90) |
| lat1 = -180 - lat1; |
| if(lat2 > 90) |
| lat2 = 180 - lat2; |
| if(lat1 <= lat2) |
| break; |
| t = lat1; lat1 = lat2; lat2 = t; |
| } |
| if(lat2-lat1 < 1) { |
| if(lat1 > 89) |
| return(azequalarea()); |
| return(0); |
| } |
| if(fabs(lat2+lat1) < 1) |
| return(cylequalarea(lat1)); |
| d2 = e2; |
| den = num(1.); |
| deg2rad(lat1,&plat1); |
| deg2rad(lat2,&plat2); |
| sinb1 = plat1.s*num(plat1.s)/den; |
| sinb2 = plat2.s*num(plat2.s)/den; |
| n = (plat1.c*plat1.c/(1-e2*plat1.s*plat1.s) - |
| plat2.c*plat2.c/(1-e2*plat2.s*plat2.s)) / |
| (2*(1-e2)*den*(sinb2-sinb1)); |
| r1 = plat1.c/(n*sqrt(1-e2*plat1.s*plat1.s)); |
| r1sq = r1*r1; |
| r0sq = r1sq + 2*(1-e2)*den*sinb1/n; |
| southpole = lat1<0 && plat2.c>plat1.c; |
| return(Xspalbers); |
| } |
| |
| proj |
| sp_albers(double lat1, double lat2) |
| { |
| return(albinit(lat1,lat2,EC2)); |
| } |
| |
| proj |
| albers(double lat1, double lat2) |
| { |
| return(albinit(lat1,lat2,0.)); |
| } |
| |
| static double scale = 1; |
| static double twist = 0; |
| |
| void |
| albscale(double x, double y, double lat, double lon) |
| { |
| struct place place; |
| double alat, alon, x1,y1; |
| scale = 1; |
| twist = 0; |
| invalb(x,y,&alat,&alon); |
| twist = lon - alon; |
| deg2rad(lat,&place.nlat); |
| deg2rad(lon,&place.wlon); |
| Xspalbers(&place,&x1,&y1); |
| scale = sqrt((x1*x1+y1*y1)/(x*x+y*y)); |
| } |
| |
| void |
| invalb(double x, double y, double *lat, double *lon) |
| { |
| int i; |
| double sinb_den, sinp; |
| x *= scale; |
| y *= scale; |
| *lon = atan2(-x,fabs(y))/(RAD*n) + twist; |
| sinb_den = (r0sq - x*x - y*y)*n/(2*(1-d2)); |
| sinp = sinb_den; |
| for(i=0; i<5; i++) |
| sinp = sinb_den/num(sinp); |
| *lat = asin(sinp)/RAD; |
| } |