GeographicLib 2.5
AlbersEqualArea.hpp
Go to the documentation of this file.
1/**
2 * \file AlbersEqualArea.hpp
3 * \brief Header for GeographicLib::AlbersEqualArea class
4 *
5 * Copyright (c) Charles Karney (2010-2023) <karney@alum.mit.edu> and licensed
6 * under the MIT/X11 License. For more information, see
7 * https://geographiclib.sourceforge.io/
8 **********************************************************************/
9
10#if !defined(GEOGRAPHICLIB_ALBERSEQUALAREA_HPP)
11#define GEOGRAPHICLIB_ALBERSEQUALAREA_HPP 1
12
14
15namespace GeographicLib {
16
17 /**
18 * \brief Albers equal area conic projection
19 *
20 * Implementation taken from the report,
21 * - J. P. Snyder,
22 * <a href="https://pubs.usgs.gov/publication/pp1395"> Map Projections: A
23 * Working Manual</a>, USGS Professional Paper 1395 (1987),
24 * pp. 101--102.
25 *
26 * This is a implementation of the equations in Snyder except that divided
27 * differences will be [have been] used to transform the expressions into
28 * ones which may be evaluated accurately. [In this implementation, the
29 * projection correctly becomes the cylindrical equal area or the azimuthal
30 * equal area projection when the standard latitude is the equator or a
31 * pole.]
32 *
33 * The ellipsoid parameters, the standard parallels, and the scale on the
34 * standard parallels are set in the constructor. Internally, the case with
35 * two standard parallels is converted into a single standard parallel, the
36 * latitude of minimum azimuthal scale, with an azimuthal scale specified on
37 * this parallel. This latitude is also used as the latitude of origin which
38 * is returned by AlbersEqualArea::OriginLatitude. The azimuthal scale on
39 * the latitude of origin is given by AlbersEqualArea::CentralScale. The
40 * case with two standard parallels at opposite poles is singular and is
41 * disallowed. The central meridian (which is a trivial shift of the
42 * longitude) is specified as the \e lon0 argument of the
43 * AlbersEqualArea::Forward and AlbersEqualArea::Reverse functions.
44 * AlbersEqualArea::Forward and AlbersEqualArea::Reverse also return the
45 * meridian convergence, &gamma;, and azimuthal scale, \e k. A small square
46 * aligned with the cardinal directions is projected to a rectangle with
47 * dimensions \e k (in the E-W direction) and 1/\e k (in the N-S direction).
48 * The E-W sides of the rectangle are oriented &gamma; degrees
49 * counter-clockwise from the \e x axis. There is no provision in this class
50 * for specifying a false easting or false northing or a different latitude
51 * of origin.
52 *
53 * Example of use:
54 * \include example-AlbersEqualArea.cpp
55 *
56 * <a href="ConicProj.1.html">ConicProj</a> is a command-line utility
57 * providing access to the functionality of LambertConformalConic and
58 * AlbersEqualArea.
59 **********************************************************************/
61 private:
62 typedef Math::real real;
63 real eps_, epsx_, epsx2_, tol_, tol0_;
64 real _a, _f, _fm, _e2, _e, _e2m, _qZ, _qx;
65 real _sign, _lat0, _k0;
66 real _n0, _m02, _nrho0, _k2, _txi0, _scxi0, _sxi0;
67 static const int numit_ = 5; // Newton iterations in Reverse
68 static const int numit0_ = 20; // Newton iterations in Init
69 static real hyp(real x) {
70 using std::hypot;
71 return hypot(real(1), x);
72 }
73 // atanh( e * x)/ e if f > 0
74 // atan (sqrt(-e2) * x)/sqrt(-e2) if f < 0
75 // x if f = 0
76 real atanhee(real x) const {
77 using std::atan; using std::atanh;
78 return _f > 0 ? atanh(_e * x)/_e : (_f < 0 ? (atan(_e * x)/_e) : x);
79 }
80 // return atanh(sqrt(x))/sqrt(x) - 1, accurate for small x
81 static real atanhxm1(real x);
82
83 // Divided differences
84 // Definition: Df(x,y) = (f(x)-f(y))/(x-y)
85 // See:
86 // W. M. Kahan and R. J. Fateman,
87 // Symbolic computation of divided differences,
88 // SIGSAM Bull. 33(2), 7-28 (1999)
89 // https://doi.org/10.1145/334714.334716
90 // http://www.cs.berkeley.edu/~fateman/papers/divdiff.pdf
91 //
92 // General rules
93 // h(x) = f(g(x)): Dh(x,y) = Df(g(x),g(y))*Dg(x,y)
94 // h(x) = f(x)*g(x):
95 // Dh(x,y) = Df(x,y)*g(x) + Dg(x,y)*f(y)
96 // = Df(x,y)*g(y) + Dg(x,y)*f(x)
97 // = Df(x,y)*(g(x)+g(y))/2 + Dg(x,y)*(f(x)+f(y))/2
98 //
99 // sn(x) = x/sqrt(1+x^2): Dsn(x,y) = (x+y)/((sn(x)+sn(y))*(1+x^2)*(1+y^2))
100 static real Dsn(real x, real y, real sx, real sy) {
101 // sx = x/hyp(x)
102 real t = x * y;
103 return t > 0 ? (x + y) * Math::sq( (sx * sy)/t ) / (sx + sy) :
104 (x - y != 0 ? (sx - sy) / (x - y) : 1);
105 }
106 // Datanhee(x,y) = (atanee(x)-atanee(y))/(x-y)
107 // = atanhee((x-y)/(1-e^2*x*y))/(x-y)
108 real Datanhee(real x, real y) const {
109 real t = x - y, d = 1 - _e2 * x * y;
110 return t == 0 ? 1 / d :
111 (x*y < 0 ? atanhee(x) - atanhee(y) : atanhee(t / d)) / t;
112 }
113 // DDatanhee(x,y) = (Datanhee(1,y) - Datanhee(1,x))/(y-x)
114 real DDatanhee(real x, real y) const;
115 real DDatanhee0(real x, real y) const;
116 real DDatanhee1(real x, real y) const;
117 real DDatanhee2(real x, real y) const;
118 void Init(real sphi1, real cphi1, real sphi2, real cphi2, real k1);
119 real txif(real tphi) const;
120 real tphif(real txi) const;
121 public:
122
123 /**
124 * Constructor with a single standard parallel.
125 *
126 * @param[in] a equatorial radius of ellipsoid (meters).
127 * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
128 * Negative \e f gives a prolate ellipsoid.
129 * @param[in] stdlat standard parallel (degrees), the circle of tangency.
130 * @param[in] k0 azimuthal scale on the standard parallel.
131 * @exception GeographicErr if \e a, (1 &minus; \e f) \e a, or \e k0 is
132 * not positive.
133 * @exception GeographicErr if \e stdlat is not in [&minus;90&deg;,
134 * 90&deg;].
135 **********************************************************************/
136 AlbersEqualArea(real a, real f, real stdlat, real k0);
137
138 /**
139 * Constructor with two standard parallels.
140 *
141 * @param[in] a equatorial radius of ellipsoid (meters).
142 * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
143 * Negative \e f gives a prolate ellipsoid.
144 * @param[in] stdlat1 first standard parallel (degrees).
145 * @param[in] stdlat2 second standard parallel (degrees).
146 * @param[in] k1 azimuthal scale on the standard parallels.
147 * @exception GeographicErr if \e a, (1 &minus; \e f) \e a, or \e k1 is
148 * not positive.
149 * @exception GeographicErr if \e stdlat1 or \e stdlat2 is not in
150 * [&minus;90&deg;, 90&deg;], or if \e stdlat1 and \e stdlat2 are
151 * opposite poles.
152 **********************************************************************/
153 AlbersEqualArea(real a, real f, real stdlat1, real stdlat2, real k1);
154
155 /**
156 * Constructor with two standard parallels specified by sines and cosines.
157 *
158 * @param[in] a equatorial radius of ellipsoid (meters).
159 * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
160 * Negative \e f gives a prolate ellipsoid.
161 * @param[in] sinlat1 sine of first standard parallel.
162 * @param[in] coslat1 cosine of first standard parallel.
163 * @param[in] sinlat2 sine of second standard parallel.
164 * @param[in] coslat2 cosine of second standard parallel.
165 * @param[in] k1 azimuthal scale on the standard parallels.
166 * @exception GeographicErr if \e a, (1 &minus; \e f) \e a, or \e k1 is
167 * not positive.
168 * @exception GeographicErr if \e stdlat1 or \e stdlat2 is not in
169 * [&minus;90&deg;, 90&deg;], or if \e stdlat1 and \e stdlat2 are
170 * opposite poles.
171 *
172 * This allows parallels close to the poles to be specified accurately.
173 * This routine computes the latitude of origin and the azimuthal scale at
174 * this latitude. If \e dlat = abs(\e lat2 &minus; \e lat1) &le; 160&deg;,
175 * then the error in the latitude of origin is less than 4.5 &times;
176 * 10<sup>&minus;14</sup>d;.
177 **********************************************************************/
178 AlbersEqualArea(real a, real f,
179 real sinlat1, real coslat1,
180 real sinlat2, real coslat2,
181 real k1);
182
183 /**
184 * Set the azimuthal scale for the projection.
185 *
186 * @param[in] lat (degrees).
187 * @param[in] k azimuthal scale at latitude \e lat (default 1).
188 * @exception GeographicErr \e k is not positive.
189 * @exception GeographicErr if \e lat is not in (&minus;90&deg;,
190 * 90&deg;).
191 *
192 * This allows a "latitude of conformality" to be specified.
193 **********************************************************************/
194 void SetScale(real lat, real k = real(1));
195
196 /**
197 * Forward projection, from geographic to Lambert conformal conic.
198 *
199 * @param[in] lon0 central meridian longitude (degrees).
200 * @param[in] lat latitude of point (degrees).
201 * @param[in] lon longitude of point (degrees).
202 * @param[out] x easting of point (meters).
203 * @param[out] y northing of point (meters).
204 * @param[out] gamma meridian convergence at point (degrees).
205 * @param[out] k azimuthal scale of projection at point; the radial
206 * scale is the 1/\e k.
207 *
208 * The latitude origin is given by AlbersEqualArea::LatitudeOrigin(). No
209 * false easting or northing is added and \e lat should be in the range
210 * [&minus;90&deg;, 90&deg;]. The values of \e x and \e y returned for
211 * points which project to infinity (i.e., one or both of the poles) will
212 * be large but finite.
213 **********************************************************************/
214 void Forward(real lon0, real lat, real lon,
215 real& x, real& y, real& gamma, real& k) const;
216
217 /**
218 * Reverse projection, from Lambert conformal conic to geographic.
219 *
220 * @param[in] lon0 central meridian longitude (degrees).
221 * @param[in] x easting of point (meters).
222 * @param[in] y northing of point (meters).
223 * @param[out] lat latitude of point (degrees).
224 * @param[out] lon longitude of point (degrees).
225 * @param[out] gamma meridian convergence at point (degrees).
226 * @param[out] k azimuthal scale of projection at point; the radial
227 * scale is the 1/\e k.
228 *
229 * The latitude origin is given by AlbersEqualArea::LatitudeOrigin(). No
230 * false easting or northing is added. The value of \e lon returned is in
231 * the range [&minus;180&deg;, 180&deg;]. The value of \e lat returned is
232 * in the range [&minus;90&deg;, 90&deg;]. If the input point is outside
233 * the legal projected space the nearest pole is returned.
234 **********************************************************************/
235 void Reverse(real lon0, real x, real y,
236 real& lat, real& lon, real& gamma, real& k) const;
237
238 /**
239 * AlbersEqualArea::Forward without returning the convergence and
240 * scale.
241 **********************************************************************/
242 void Forward(real lon0, real lat, real lon,
243 real& x, real& y) const {
244 real gamma, k;
245 Forward(lon0, lat, lon, x, y, gamma, k);
246 }
247
248 /**
249 * AlbersEqualArea::Reverse without returning the convergence and
250 * scale.
251 **********************************************************************/
252 void Reverse(real lon0, real x, real y,
253 real& lat, real& lon) const {
254 real gamma, k;
255 Reverse(lon0, x, y, lat, lon, gamma, k);
256 }
257
258 /** \name Inspector functions
259 **********************************************************************/
260 ///@{
261 /**
262 * @return \e a the equatorial radius of the ellipsoid (meters). This is
263 * the value used in the constructor.
264 **********************************************************************/
265 Math::real EquatorialRadius() const { return _a; }
266
267 /**
268 * @return \e f the flattening of the ellipsoid. This is the value used in
269 * the constructor.
270 **********************************************************************/
271 Math::real Flattening() const { return _f; }
272
273 /**
274 * @return latitude of the origin for the projection (degrees).
275 *
276 * This is the latitude of minimum azimuthal scale and equals the \e stdlat
277 * in the 1-parallel constructor and lies between \e stdlat1 and \e stdlat2
278 * in the 2-parallel constructors.
279 **********************************************************************/
280 Math::real OriginLatitude() const { return _lat0; }
281
282 /**
283 * @return central scale for the projection. This is the azimuthal scale
284 * on the latitude of origin.
285 **********************************************************************/
286 Math::real CentralScale() const { return _k0; }
287 ///@}
288
289 /**
290 * A global instantiation of AlbersEqualArea with the WGS84 ellipsoid, \e
291 * stdlat = 0, and \e k0 = 1. This degenerates to the cylindrical equal
292 * area projection.
293 **********************************************************************/
294 static const AlbersEqualArea& CylindricalEqualArea();
295
296 /**
297 * A global instantiation of AlbersEqualArea with the WGS84 ellipsoid, \e
298 * stdlat = 90&deg;, and \e k0 = 1. This degenerates to the
299 * Lambert azimuthal equal area projection.
300 **********************************************************************/
301 static const AlbersEqualArea& AzimuthalEqualAreaNorth();
302
303 /**
304 * A global instantiation of AlbersEqualArea with the WGS84 ellipsoid, \e
305 * stdlat = &minus;90&deg;, and \e k0 = 1. This degenerates to the
306 * Lambert azimuthal equal area projection.
307 **********************************************************************/
308 static const AlbersEqualArea& AzimuthalEqualAreaSouth();
309 };
310
311} // namespace GeographicLib
312
313#endif // GEOGRAPHICLIB_ALBERSEQUALAREA_HPP
Header for GeographicLib::Constants class.
#define GEOGRAPHICLIB_EXPORT
Definition Constants.hpp:67
GeographicLib::Math::real real
Definition GeodSolve.cpp:28
Albers equal area conic projection.
void Reverse(real lon0, real x, real y, real &lat, real &lon) const
void Forward(real lon0, real lat, real lon, real &x, real &y) const
Namespace for GeographicLib.