[comp.graphics] USGS Albers Map Projection

paul@hpldola.HP.COM (Paul Bame) (03/22/89)

To satisfy both those who wanted the USGS map projections book reference and
the Albers projection code, here is that code.  The first comment contains
the reference to the USGS book which may be obtained (it's pretty cheap
even) from either of the two main USGS places (I got it from Denver).  This
code could stand to be re-arranged a bit but should suffice for most uses
as-is.  No warranty implied or expressed by me or Hewlett-Packard - but note
that it passed the test cases in the book - for me anyway.  Enjoy,

	-Paul Bame
	hplabs!hpldola!paul
	paul@hpldola.hp.com

#!/bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by paul at hpldola on Tue Mar 21 09:33:29 1989
#
# This archive contains:
#	albers.c	mapconstants.h	
#

echo x - albers.c
cat >albers.c <<'@EOF'
#include <stdio.h>
#include <math.h>
#define CLARKE1866
#include "mapconstants.h"

/*
 * Albers Conic Equal-Area Projection
 *
 *	Formulae taken from "Map Projections Used by the U.S. Geological Survey"
 *	Bulletin #1532
 *
 * Many variable names taken from the reference.
 *
 * To use, call albers_setup() once and then albers_project() for each
 * coordinate pair of interest.
 *
 * AUTHOR: Paul Bame hplabs!hpldola!paul paul@hpldola.hp.com 719-590-5557
 *
 */

static double eradius, middlelon, bigC, cone_const, r0;

static
calc_q_msq(lat, qp, msqp)
double lat;
double *qp;
double *msqp;
/*
 * Given latitude, calculate 'q' [eq. 3-12] and 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(x_eradius, southlat, northlat, middlelat, x_middlelon)
double x_eradius;
double southlat, northlat;
double middlelat;
double x_middlelon;
/*
 * x_eradius is the desired radius of the Earth in any units
 *
 * *lat are the standard parallels used for the Albers projection in radians
 *
 * x_middlelon is the longitude of the center of the projection
 */
{
	double q1, q2, q0;
	double m1sq, m2sq;

	middlelon = x_middlelon;
	eradius = x_eradius;

	calc_q_msq(southlat, &q1, &m1sq);
	calc_q_msq(northlat, &q2, &m2sq);
	calc_q_msq(middlelat, &q0, NULL);

	cone_const = (m1sq - m2sq) / (q2 - q1);

	bigC = m1sq + cone_const * q1;

	r0 = 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.
 */
{
	double q, r, theta;

	calc_q_msq(lat, &q, NULL);

	theta = cone_const * (lon - middlelon);
	r = eradius * sqrt(bigC - cone_const * q) / cone_const;

	*xp = r * sin(theta);
	*yp = r0 - r * cos(theta);
}
@EOF

chmod 644 albers.c

echo x - mapconstants.h
cat >mapconstants.h <<'@EOF'
/*
 * This somewhat obtuse header file gives constants required for the
 * Albers projection (Ec and Ecsq) and several Earth radii from which
 * to choose.
 *
 * CLARKE1866 means to use the Clarke 1866 Earth spheroid which is often
 * used by the USGS - there are other spheroids however - see the book.
 *
 * AUTHOR: Paul Bame hplabs!hpldola!paul paul@hpldola.hp.com 719-590-5557
 */

#ifdef XXX
#define CONST_Ecsq (0.006695662) /* */
#define CONST_Ec   (0.081827028) /* */
#endif

#ifdef CLARKE1866
#define CONST_EradiusKM (6378.2064) /* Kilometers */
#define CONST_Eradius (CONST_EradiusKM/1.609)
#define CONST_Ecsq (0.006768658) /* */
#define CONST_Ec   (0.082271854) /* */
#endif

#ifndef CONST_Ecsq
#define CONST_Ecsq (CONST_Ec * CONST_Ec)
#endif

#define CONST_Eradiussq (CONST_Eradius * CONST_Eradius)
@EOF

chmod 666 mapconstants.h

exit 0