home *** CD-ROM | disk | FTP | other *** search
- /*
- Albers Equal-Area Conic Map Projection
- by Paul Bame
- from "Graphics Gems", Academic Press, 1990
- */
-
- /*
- * Albers Conic Equal-Area Projection
- * Formulae taken from "Map Projections Used by the U.S.
- * Geological Survey" Bulletin #1532
- *
- * Equation reference numbers and some variable names taken
- * from the reference.
- * To use, call albers setup() once and then albers_project()
- * for each coordinate pair of interest.
- */
-
- #include "GraphicsGems.h"
- #include <stdio.h>
- #include <math.h>
-
- /*
- * This is the Clarke 1866 Earth spheroid data which is often
- * used by the USGS - there are other spheroids however - see the
- * book.
- */
-
- /*
- * Earth radii in different units */
- #define CONST_EradiusKM (6378.2064) /* Kilometers */
- #define CONST_EradiusMI (CONST_EradiusKM/1.609) /* Miles */
- #define CONST_Ec (0.082271854) /* Eccentricity */
- #define CONST_Ecsq (0.006768658) /* Eccentricity squared */
-
-
-
- /*
- * To keep things simple, assume Earth radius is 1.0. Projected
- * coordinates (X and Y obtained from albers project ()) are
- * dimensionless and may be multiplied by any desired radius
- * to convert to desired units (usually Kilometers or Miles).
- */
- #define CONST_Eradius 1.0
-
- /* Pre-computed variables */
- static double middlelon; /* longitude at center of map */
- static double bigC, cone_const, r0; /* See the reference */
-
- static
- calc_q_msq(lat, qp, msqp)
- double lat;
- double *qp;
- double *msqp;
- /*
- * Given latitude, calculate 'q' [eq 3-12]
- * if msqp is != NULL, m^2 [eq. 12-15].
- */
- {
- double s, c, es;
-
- s = sin(lat);
- es = s * CONST_Ec;
-
- *qp = (1.0 - CONST_Ecsq) * ((s / (1 - es * es))-
- (1 / (2 * CONST_Ec)) * log((1 - es) / (1 + es)));
-
- if (msqp != NULL)
- {
- c = cos(lat);
- *msqp = c * c/ (1 - es * es);
- }
- }
-
-
-
-
- albers_setup(southlat, northlat, originlon, originlat)
- double southlat, northlat;
- double originlon;
- double originlat;
- /*
- * Pre-compute a bunch of variables which are used by the
- * albers_project()
- *
- * southlat Southern latitude for Albers projection
- * northlat Northern latitute for Albers projection
- * originlon Longitude for origin of projected map
- * originlat Latitude for origin of projected map -
- * often (northlat + southlat) / 2
- */
- {
- double q1, q2, q0;
- double m1sq, m2sq;
-
- middlelon = originlon;
-
- cal_q_msq(southlat, &q1, &m1sq);
- cal_q_msq(northlat, &q2, &m2sq);
- cal_q_msq(originlat, &q0, NULL);
-
- cone_const = (m1sq - m2sq) / (q2 - q1);
- bigC = m1sq + cone_const * q1;
- r0 = CONST_Eradius * sqrt(bigC - cone_const *q0) / cone_const;
- }
-
- /***************************************************************/
-
- albers_project(lon, lat, xp, yp)
- double lon, lat;
- double *xp, *yp;
- /*
- * Project lon/lat (in radians) according to albers_setup and
- * return the results via xp, yp. Units of *xp and *yp are same
- * as the units used by CONST_Eradius.
- */
- {
- double q, r, theta;
- calc_q_msq(lat, &q, NULL);
- theta = cone_const * (lon -middlelon);
- r = CONST_Eradius * sqrt(bigC - cone_const * q) / cone_const;
- *xp = r * sin(theta);
- *yp = r0 - r * cos(theta);
- }
-
- #ifdef TESTPROGRAM
-
- /*
- * Test value from the USGS book. Because of roundoff, the
- * actual values are printed for visual inspection rather
- * than guessing what constitutes "close enough".
- */
- /* Convert a degress, minutes pair to radians */
- #define DEG_MIN2RAD(degrees, minutes) \
- ((double) ((degrees + minutes / 60.0) * M_PI / 180.0))
-
- #define Nlat DEG_MIN2RAD(29, 30) /* 29 degrees, 30' North Lat */
- #define Slat DEG_MIN2RAD(45, 30)
- #define Originlat DEG_MIN2RAD(23, 0)
- #define Originlon DEG_MIN2RAD(-96, 0) /* West longitude is negative */
-
- #define Testlat DEG_MIN2RAD(35, 0)
- #define Testlon DEG_MIN2RAD(-75, 0)
-
- #define TestX 1885.4727
- #define TestY 1535.9250
-
- main()
- {
- int i;
- double x, y;
-
- /* Setup is also from USGS book test set */
- albers_setup(Slat, Nlat, Originlon, Originlat);
-
- albers_project(Testlon, Testlat, &x, &y);
- printf("%.41f, %.41f =?= %.41f, %.41f/n",
- x * CONST_EradiusKM, y * CONST_EradiusKM,
- TestX, TestY);
- }
- #endif /* TESTPROGRAM */
-