aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/map/libmap/albers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/map/libmap/albers.c')
-rw-r--r--src/cmd/map/libmap/albers.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/cmd/map/libmap/albers.c b/src/cmd/map/libmap/albers.c
new file mode 100644
index 00000000..56e3e9f5
--- /dev/null
+++ b/src/cmd/map/libmap/albers.c
@@ -0,0 +1,117 @@
+#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;
+}