GeographicLib 2.3

TransverseMercator.cpp
Go to the documentation of this file.
1/**
2 * \file TransverseMercator.cpp
3 * \brief Implementation for GeographicLib::TransverseMercator class
4 *
5 * Copyright (c) Charles Karney (2008-2023) <karney@alum.mit.edu> and licensed
6 * under the MIT/X11 License. For more information, see
7 * https://geographiclib.sourceforge.io/
8 *
9 * This implementation follows closely JHS 154, ETRS89 -
10 * j&auml;rjestelm&auml;&auml;n liittyv&auml;t karttaprojektiot,
11 * tasokoordinaatistot ja karttalehtijako</a> (Map projections, plane
12 * coordinates, and map sheet index for ETRS89), published by JUHTA, Finnish
13 * Geodetic Institute, and the National Land Survey of Finland (2006).
14 *
15 * The relevant section is available as the 2008 PDF file
16 * http://docs.jhs-suositukset.fi/jhs-suositukset/JHS154/JHS154_liite1.pdf
17 *
18 * This is a straight transcription of the formulas in this paper with the
19 * following exceptions:
20 * - use of 6th order series instead of 4th order series. This reduces the
21 * error to about 5nm for the UTM range of coordinates (instead of 200nm),
22 * with a speed penalty of only 1%;
23 * - use Newton's method instead of plain iteration to solve for latitude in
24 * terms of isometric latitude in the Reverse method;
25 * - use of Horner's representation for evaluating polynomials and Clenshaw's
26 * method for summing trigonometric series;
27 * - several modifications of the formulas to improve the numerical accuracy;
28 * - evaluating the convergence and scale using the expression for the
29 * projection or its inverse.
30 *
31 * If the preprocessor variable GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER is set
32 * to an integer between 4 and 8, then this specifies the order of the series
33 * used for the forward and reverse transformations. The default value is 6.
34 * (The series accurate to 12th order is given in \ref tmseries.)
35 **********************************************************************/
36
37#include <complex>
38#include <GeographicLib/TransverseMercator.hpp>
39
40#if defined(_MSC_VER)
41// Squelch warnings about enum-float expressions
42# pragma warning (disable: 5055)
43#endif
44
45 namespace GeographicLib {
46
47 using namespace std;
48
49 TransverseMercator::TransverseMercator(real a, real f, real k0,
50 bool exact, bool extendp)
51 : _a(a)
52 , _f(f)
53 , _k0(k0)
54 , _exact(exact)
55 , _e2(_f * (2 - _f))
56 , _es((_f < 0 ? -1 : 1) * sqrt(fabs(_e2)))
57 , _e2m(1 - _e2)
58 // _c = sqrt( pow(1 + _e, 1 + _e) * pow(1 - _e, 1 - _e) ) )
59 // See, for example, Lee (1976), p 100.
60 , _c( sqrt(_e2m) * exp(Math::eatanhe(real(1), _es)) )
61 , _n(_f / (2 - _f))
62 , _tmexact(_exact ? TransverseMercatorExact(a, f, k0, extendp) :
63 TransverseMercatorExact())
64 {
65 if (_exact) return;
66 if (!(isfinite(_a) && _a > 0))
67 throw GeographicErr("Equatorial radius is not positive");
68 if (!(isfinite(_f) && _f < 1))
69 throw GeographicErr("Polar semi-axis is not positive");
70 if (!(isfinite(_k0) && _k0 > 0))
71 throw GeographicErr("Scale is not positive");
72 if (extendp)
73 throw GeographicErr("TransverseMercator extendp not allowed if !exact");
74
75 // Generated by Maxima on 2015-05-14 22:55:13-04:00
76#if GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER/2 == 2
77 static const real b1coeff[] = {
78 // b1*(n+1), polynomial in n2 of order 2
79 1, 16, 64, 64,
80 }; // count = 4
81#elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER/2 == 3
82 static const real b1coeff[] = {
83 // b1*(n+1), polynomial in n2 of order 3
84 1, 4, 64, 256, 256,
85 }; // count = 5
86#elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER/2 == 4
87 static const real b1coeff[] = {
88 // b1*(n+1), polynomial in n2 of order 4
89 25, 64, 256, 4096, 16384, 16384,
90 }; // count = 6
91#else
92#error "Bad value for GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER"
93#endif
94
95#if GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 4
96 static const real alpcoeff[] = {
97 // alp[1]/n^1, polynomial in n of order 3
98 164, 225, -480, 360, 720,
99 // alp[2]/n^2, polynomial in n of order 2
100 557, -864, 390, 1440,
101 // alp[3]/n^3, polynomial in n of order 1
102 -1236, 427, 1680,
103 // alp[4]/n^4, polynomial in n of order 0
104 49561, 161280,
105 }; // count = 14
106#elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 5
107 static const real alpcoeff[] = {
108 // alp[1]/n^1, polynomial in n of order 4
109 -635, 328, 450, -960, 720, 1440,
110 // alp[2]/n^2, polynomial in n of order 3
111 4496, 3899, -6048, 2730, 10080,
112 // alp[3]/n^3, polynomial in n of order 2
113 15061, -19776, 6832, 26880,
114 // alp[4]/n^4, polynomial in n of order 1
115 -171840, 49561, 161280,
116 // alp[5]/n^5, polynomial in n of order 0
117 34729, 80640,
118 }; // count = 20
119#elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 6
120 static const real alpcoeff[] = {
121 // alp[1]/n^1, polynomial in n of order 5
122 31564, -66675, 34440, 47250, -100800, 75600, 151200,
123 // alp[2]/n^2, polynomial in n of order 4
124 -1983433, 863232, 748608, -1161216, 524160, 1935360,
125 // alp[3]/n^3, polynomial in n of order 3
126 670412, 406647, -533952, 184464, 725760,
127 // alp[4]/n^4, polynomial in n of order 2
128 6601661, -7732800, 2230245, 7257600,
129 // alp[5]/n^5, polynomial in n of order 1
130 -13675556, 3438171, 7983360,
131 // alp[6]/n^6, polynomial in n of order 0
132 212378941, 319334400,
133 }; // count = 27
134#elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 7
135 static const real alpcoeff[] = {
136 // alp[1]/n^1, polynomial in n of order 6
137 1804025, 2020096, -4267200, 2204160, 3024000, -6451200, 4838400, 9676800,
138 // alp[2]/n^2, polynomial in n of order 5
139 4626384, -9917165, 4316160, 3743040, -5806080, 2620800, 9676800,
140 // alp[3]/n^3, polynomial in n of order 4
141 -67102379, 26816480, 16265880, -21358080, 7378560, 29030400,
142 // alp[4]/n^4, polynomial in n of order 3
143 155912000, 72618271, -85060800, 24532695, 79833600,
144 // alp[5]/n^5, polynomial in n of order 2
145 102508609, -109404448, 27505368, 63866880,
146 // alp[6]/n^6, polynomial in n of order 1
147 -12282192400LL, 2760926233LL, 4151347200LL,
148 // alp[7]/n^7, polynomial in n of order 0
149 1522256789, 1383782400,
150 }; // count = 35
151#elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 8
152 static const real alpcoeff[] = {
153 // alp[1]/n^1, polynomial in n of order 7
154 -75900428, 37884525, 42422016, -89611200, 46287360, 63504000, -135475200,
155 101606400, 203212800,
156 // alp[2]/n^2, polynomial in n of order 6
157 148003883, 83274912, -178508970, 77690880, 67374720, -104509440,
158 47174400, 174182400,
159 // alp[3]/n^3, polynomial in n of order 5
160 318729724, -738126169, 294981280, 178924680, -234938880, 81164160,
161 319334400,
162 // alp[4]/n^4, polynomial in n of order 4
163 -40176129013LL, 14967552000LL, 6971354016LL, -8165836800LL, 2355138720LL,
164 7664025600LL,
165 // alp[5]/n^5, polynomial in n of order 3
166 10421654396LL, 3997835751LL, -4266773472LL, 1072709352, 2490808320LL,
167 // alp[6]/n^6, polynomial in n of order 2
168 175214326799LL, -171950693600LL, 38652967262LL, 58118860800LL,
169 // alp[7]/n^7, polynomial in n of order 1
170 -67039739596LL, 13700311101LL, 12454041600LL,
171 // alp[8]/n^8, polynomial in n of order 0
172 1424729850961LL, 743921418240LL,
173 }; // count = 44
174#else
175#error "Bad value for GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER"
176#endif
177
178#if GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 4
179 static const real betcoeff[] = {
180 // bet[1]/n^1, polynomial in n of order 3
181 -4, 555, -960, 720, 1440,
182 // bet[2]/n^2, polynomial in n of order 2
183 -437, 96, 30, 1440,
184 // bet[3]/n^3, polynomial in n of order 1
185 -148, 119, 3360,
186 // bet[4]/n^4, polynomial in n of order 0
187 4397, 161280,
188 }; // count = 14
189#elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 5
190 static const real betcoeff[] = {
191 // bet[1]/n^1, polynomial in n of order 4
192 -3645, -64, 8880, -15360, 11520, 23040,
193 // bet[2]/n^2, polynomial in n of order 3
194 4416, -3059, 672, 210, 10080,
195 // bet[3]/n^3, polynomial in n of order 2
196 -627, -592, 476, 13440,
197 // bet[4]/n^4, polynomial in n of order 1
198 -3520, 4397, 161280,
199 // bet[5]/n^5, polynomial in n of order 0
200 4583, 161280,
201 }; // count = 20
202#elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 6
203 static const real betcoeff[] = {
204 // bet[1]/n^1, polynomial in n of order 5
205 384796, -382725, -6720, 932400, -1612800, 1209600, 2419200,
206 // bet[2]/n^2, polynomial in n of order 4
207 -1118711, 1695744, -1174656, 258048, 80640, 3870720,
208 // bet[3]/n^3, polynomial in n of order 3
209 22276, -16929, -15984, 12852, 362880,
210 // bet[4]/n^4, polynomial in n of order 2
211 -830251, -158400, 197865, 7257600,
212 // bet[5]/n^5, polynomial in n of order 1
213 -435388, 453717, 15966720,
214 // bet[6]/n^6, polynomial in n of order 0
215 20648693, 638668800,
216 }; // count = 27
217#elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 7
218 static const real betcoeff[] = {
219 // bet[1]/n^1, polynomial in n of order 6
220 -5406467, 6156736, -6123600, -107520, 14918400, -25804800, 19353600,
221 38707200,
222 // bet[2]/n^2, polynomial in n of order 5
223 829456, -5593555, 8478720, -5873280, 1290240, 403200, 19353600,
224 // bet[3]/n^3, polynomial in n of order 4
225 9261899, 3564160, -2708640, -2557440, 2056320, 58060800,
226 // bet[4]/n^4, polynomial in n of order 3
227 14928352, -9132761, -1742400, 2176515, 79833600,
228 // bet[5]/n^5, polynomial in n of order 2
229 -8005831, -1741552, 1814868, 63866880,
230 // bet[6]/n^6, polynomial in n of order 1
231 -261810608, 268433009, 8302694400LL,
232 // bet[7]/n^7, polynomial in n of order 0
233 219941297, 5535129600LL,
234 }; // count = 35
235#elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 8
236 static const real betcoeff[] = {
237 // bet[1]/n^1, polynomial in n of order 7
238 31777436, -37845269, 43097152, -42865200, -752640, 104428800, -180633600,
239 135475200, 270950400,
240 // bet[2]/n^2, polynomial in n of order 6
241 24749483, 14930208, -100683990, 152616960, -105719040, 23224320, 7257600,
242 348364800,
243 // bet[3]/n^3, polynomial in n of order 5
244 -232468668, 101880889, 39205760, -29795040, -28131840, 22619520,
245 638668800,
246 // bet[4]/n^4, polynomial in n of order 4
247 324154477, 1433121792, -876745056, -167270400, 208945440, 7664025600LL,
248 // bet[5]/n^5, polynomial in n of order 3
249 457888660, -312227409, -67920528, 70779852, 2490808320LL,
250 // bet[6]/n^6, polynomial in n of order 2
251 -19841813847LL, -3665348512LL, 3758062126LL, 116237721600LL,
252 // bet[7]/n^7, polynomial in n of order 1
253 -1989295244, 1979471673, 49816166400LL,
254 // bet[8]/n^8, polynomial in n of order 0
255 191773887257LL, 3719607091200LL,
256 }; // count = 44
257#else
258#error "Bad value for GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER"
259#endif
260
261 static_assert(sizeof(b1coeff) / sizeof(real) == maxpow_/2 + 2,
262 "Coefficient array size mismatch for b1");
263 static_assert(sizeof(alpcoeff) / sizeof(real) ==
264 (maxpow_ * (maxpow_ + 3))/2,
265 "Coefficient array size mismatch for alp");
266 static_assert(sizeof(betcoeff) / sizeof(real) ==
267 (maxpow_ * (maxpow_ + 3))/2,
268 "Coefficient array size mismatch for bet");
269 int m = maxpow_/2;
270 _b1 = Math::polyval(m, b1coeff, Math::sq(_n)) / (b1coeff[m + 1] * (1+_n));
271 // _a1 is the equivalent radius for computing the circumference of
272 // ellipse.
273 _a1 = _b1 * _a;
274 int o = 0;
275 real d = _n;
276 for (int l = 1; l <= maxpow_; ++l) {
277 m = maxpow_ - l;
278 _alp[l] = d * Math::polyval(m, alpcoeff + o, _n) / alpcoeff[o + m + 1];
279 _bet[l] = d * Math::polyval(m, betcoeff + o, _n) / betcoeff[o + m + 1];
280 o += m + 2;
281 d *= _n;
282 }
283 // Post condition: o == sizeof(alpcoeff) / sizeof(real) &&
284 // o == sizeof(betcoeff) / sizeof(real)
285 }
286
287 const TransverseMercator& TransverseMercator::UTM() {
288 static const TransverseMercator utm(Constants::WGS84_a(),
289 Constants::WGS84_f(),
290 Constants::UTM_k0());
291 return utm;
292 }
293
294 // Engsager and Poder (2007) use trigonometric series to convert between phi
295 // and phip. Here are the series...
296 //
297 // Conversion from phi to phip:
298 //
299 // phip = phi + sum(c[j] * sin(2*j*phi), j, 1, 6)
300 //
301 // c[1] = - 2 * n
302 // + 2/3 * n^2
303 // + 4/3 * n^3
304 // - 82/45 * n^4
305 // + 32/45 * n^5
306 // + 4642/4725 * n^6;
307 // c[2] = 5/3 * n^2
308 // - 16/15 * n^3
309 // - 13/9 * n^4
310 // + 904/315 * n^5
311 // - 1522/945 * n^6;
312 // c[3] = - 26/15 * n^3
313 // + 34/21 * n^4
314 // + 8/5 * n^5
315 // - 12686/2835 * n^6;
316 // c[4] = 1237/630 * n^4
317 // - 12/5 * n^5
318 // - 24832/14175 * n^6;
319 // c[5] = - 734/315 * n^5
320 // + 109598/31185 * n^6;
321 // c[6] = 444337/155925 * n^6;
322 //
323 // Conversion from phip to phi:
324 //
325 // phi = phip + sum(d[j] * sin(2*j*phip), j, 1, 6)
326 //
327 // d[1] = 2 * n
328 // - 2/3 * n^2
329 // - 2 * n^3
330 // + 116/45 * n^4
331 // + 26/45 * n^5
332 // - 2854/675 * n^6;
333 // d[2] = 7/3 * n^2
334 // - 8/5 * n^3
335 // - 227/45 * n^4
336 // + 2704/315 * n^5
337 // + 2323/945 * n^6;
338 // d[3] = 56/15 * n^3
339 // - 136/35 * n^4
340 // - 1262/105 * n^5
341 // + 73814/2835 * n^6;
342 // d[4] = 4279/630 * n^4
343 // - 332/35 * n^5
344 // - 399572/14175 * n^6;
345 // d[5] = 4174/315 * n^5
346 // - 144838/6237 * n^6;
347 // d[6] = 601676/22275 * n^6;
348 //
349 // In order to maintain sufficient relative accuracy close to the pole use
350 //
351 // S = sum(c[i]*sin(2*i*phi),i,1,6)
352 // taup = (tau + tan(S)) / (1 - tau * tan(S))
353
354 // In Math::taupf and Math::tauf we evaluate the forward transform explicitly
355 // and solve the reverse one by Newton's method.
356 //
357 // There are adapted from TransverseMercatorExact (taup and taupinv). tau =
358 // tan(phi), taup = sinh(psi)
359
360 void TransverseMercator::Forward(real lon0, real lat, real lon,
361 real& x, real& y,
362 real& gamma, real& k) const {
363 if (_exact)
364 return _tmexact.Forward(lon0, lat, lon, x, y, gamma, k);
365 lat = Math::LatFix(lat);
366 lon = Math::AngDiff(lon0, lon);
367 // Explicitly enforce the parity
368 int
369 latsign = signbit(lat) ? -1 : 1,
370 lonsign = signbit(lon) ? -1 : 1;
371 lon *= lonsign;
372 lat *= latsign;
373 bool backside = lon > Math::qd;
374 if (backside) {
375 if (lat == 0)
376 latsign = -1;
377 lon = Math::hd - lon;
378 }
379 real sphi, cphi, slam, clam;
380 Math::sincosd(lat, sphi, cphi);
381 Math::sincosd(lon, slam, clam);
382 // phi = latitude
383 // phi' = conformal latitude
384 // psi = isometric latitude
385 // tau = tan(phi)
386 // tau' = tan(phi')
387 // [xi', eta'] = Gauss-Schreiber TM coordinates
388 // [xi, eta] = Gauss-Krueger TM coordinates
389 //
390 // We use
391 // tan(phi') = sinh(psi)
392 // sin(phi') = tanh(psi)
393 // cos(phi') = sech(psi)
394 // denom^2 = 1-cos(phi')^2*sin(lam)^2 = 1-sech(psi)^2*sin(lam)^2
395 // sin(xip) = sin(phi')/denom = tanh(psi)/denom
396 // cos(xip) = cos(phi')*cos(lam)/denom = sech(psi)*cos(lam)/denom
397 // cosh(etap) = 1/denom = 1/denom
398 // sinh(etap) = cos(phi')*sin(lam)/denom = sech(psi)*sin(lam)/denom
399 real etap, xip;
400 if (lat != Math::qd) {
401 real
402 tau = sphi / cphi,
403 taup = Math::taupf(tau, _es);
404 xip = atan2(taup, clam);
405 // Used to be
406 // etap = Math::atanh(sin(lam) / cosh(psi));
407 etap = asinh(slam / hypot(taup, clam));
408 // convergence and scale for Gauss-Schreiber TM (xip, etap) -- gamma0 =
409 // atan(tan(xip) * tanh(etap)) = atan(tan(lam) * sin(phi'));
410 // sin(phi') = tau'/sqrt(1 + tau'^2)
411 // Krueger p 22 (44)
412 gamma = Math::atan2d(slam * taup, clam * hypot(real(1), taup));
413 // k0 = sqrt(1 - _e2 * sin(phi)^2) * (cos(phi') / cos(phi)) * cosh(etap)
414 // Note 1/cos(phi) = cosh(psip);
415 // and cos(phi') * cosh(etap) = 1/hypot(sinh(psi), cos(lam))
416 //
417 // This form has cancelling errors. This property is lost if cosh(psip)
418 // is replaced by 1/cos(phi), even though it's using "primary" data (phi
419 // instead of psip).
420 k = sqrt(_e2m + _e2 * Math::sq(cphi)) * hypot(real(1), tau)
421 / hypot(taup, clam);
422 } else {
423 xip = Math::pi()/2;
424 etap = 0;
425 gamma = lon;
426 k = _c;
427 }
428 // {xi',eta'} is {northing,easting} for Gauss-Schreiber transverse Mercator
429 // (for eta' = 0, xi' = bet). {xi,eta} is {northing,easting} for transverse
430 // Mercator with constant scale on the central meridian (for eta = 0, xip =
431 // rectifying latitude). Define
432 //
433 // zeta = xi + i*eta
434 // zeta' = xi' + i*eta'
435 //
436 // The conversion from conformal to rectifying latitude can be expressed as
437 // a series in _n:
438 //
439 // zeta = zeta' + sum(h[j-1]' * sin(2 * j * zeta'), j = 1..maxpow_)
440 //
441 // where h[j]' = O(_n^j). The reversion of this series gives
442 //
443 // zeta' = zeta - sum(h[j-1] * sin(2 * j * zeta), j = 1..maxpow_)
444 //
445 // which is used in Reverse.
446 //
447 // Evaluate sums via Clenshaw method. See
448 // https://en.wikipedia.org/wiki/Clenshaw_algorithm
449 //
450 // Let
451 //
452 // S = sum(a[k] * phi[k](x), k = 0..n)
453 // phi[k+1](x) = alpha[k](x) * phi[k](x) + beta[k](x) * phi[k-1](x)
454 //
455 // Evaluate S with
456 //
457 // b[n+2] = b[n+1] = 0
458 // b[k] = alpha[k](x) * b[k+1] + beta[k+1](x) * b[k+2] + a[k]
459 // S = (a[0] + beta[1](x) * b[2]) * phi[0](x) + b[1] * phi[1](x)
460 //
461 // Here we have
462 //
463 // x = 2 * zeta'
464 // phi[k](x) = sin(k * x)
465 // alpha[k](x) = 2 * cos(x)
466 // beta[k](x) = -1
467 // [ sin(A+B) - 2*cos(B)*sin(A) + sin(A-B) = 0, A = k*x, B = x ]
468 // n = maxpow_
469 // a[k] = _alp[k]
470 // S = b[1] * sin(x)
471 //
472 // For the derivative we have
473 //
474 // x = 2 * zeta'
475 // phi[k](x) = cos(k * x)
476 // alpha[k](x) = 2 * cos(x)
477 // beta[k](x) = -1
478 // [ cos(A+B) - 2*cos(B)*cos(A) + cos(A-B) = 0, A = k*x, B = x ]
479 // a[0] = 1; a[k] = 2*k*_alp[k]
480 // S = (a[0] - b[2]) + b[1] * cos(x)
481 //
482 // Matrix formulation (not used here):
483 // phi[k](x) = [sin(k * x); k * cos(k * x)]
484 // alpha[k](x) = 2 * [cos(x), 0; -sin(x), cos(x)]
485 // beta[k](x) = -1 * [1, 0; 0, 1]
486 // a[k] = _alp[k] * [1, 0; 0, 1]
487 // b[n+2] = b[n+1] = [0, 0; 0, 0]
488 // b[k] = alpha[k](x) * b[k+1] + beta[k+1](x) * b[k+2] + a[k]
489 // N.B., for all k: b[k](1,2) = 0; b[k](1,1) = b[k](2,2)
490 // S = (a[0] + beta[1](x) * b[2]) * phi[0](x) + b[1] * phi[1](x)
491 // phi[0](x) = [0; 0]
492 // phi[1](x) = [sin(x); cos(x)]
493 real
494 c0 = cos(2 * xip), ch0 = cosh(2 * etap),
495 s0 = sin(2 * xip), sh0 = sinh(2 * etap);
496 complex<real> a(2 * c0 * ch0, -2 * s0 * sh0); // 2 * cos(2*zeta')
497 int n = maxpow_;
498 complex<real>
499 y0(n & 1 ? _alp[n] : 0), y1, // default initializer is 0+i0
500 z0(n & 1 ? 2*n * _alp[n] : 0), z1;
501 if (n & 1) --n;
502 while (n) {
503 y1 = a * y0 - y1 + _alp[n];
504 z1 = a * z0 - z1 + 2*n * _alp[n];
505 --n;
506 y0 = a * y1 - y0 + _alp[n];
507 z0 = a * z1 - z0 + 2*n * _alp[n];
508 --n;
509 }
510 a /= real(2); // cos(2*zeta')
511 z1 = real(1) - z1 + a * z0;
512 a = complex<real>(s0 * ch0, c0 * sh0); // sin(2*zeta')
513 y1 = complex<real>(xip, etap) + a * y0;
514 // Fold in change in convergence and scale for Gauss-Schreiber TM to
515 // Gauss-Krueger TM.
516 gamma -= Math::atan2d(z1.imag(), z1.real());
517 k *= _b1 * abs(z1);
518 real xi = y1.real(), eta = y1.imag();
519 y = _a1 * _k0 * (backside ? Math::pi() - xi : xi) * latsign;
520 x = _a1 * _k0 * eta * lonsign;
521 if (backside)
522 gamma = Math::hd - gamma;
523 gamma *= latsign * lonsign;
524 gamma = Math::AngNormalize(gamma);
525 k *= _k0;
526 }
527
528 void TransverseMercator::Reverse(real lon0, real x, real y,
529 real& lat, real& lon,
530 real& gamma, real& k) const {
531 if (_exact)
532 return _tmexact.Reverse(lon0, x, y, lat, lon, gamma, k);
533 // This undoes the steps in Forward. The wrinkles are: (1) Use of the
534 // reverted series to express zeta' in terms of zeta. (2) Newton's method
535 // to solve for phi in terms of tan(phi).
536 real
537 xi = y / (_a1 * _k0),
538 eta = x / (_a1 * _k0);
539 // Explicitly enforce the parity
540 int
541 xisign = signbit(xi) ? -1 : 1,
542 etasign = signbit(eta) ? -1 : 1;
543 xi *= xisign;
544 eta *= etasign;
545 bool backside = xi > Math::pi()/2;
546 if (backside)
547 xi = Math::pi() - xi;
548 real
549 c0 = cos(2 * xi), ch0 = cosh(2 * eta),
550 s0 = sin(2 * xi), sh0 = sinh(2 * eta);
551 complex<real> a(2 * c0 * ch0, -2 * s0 * sh0); // 2 * cos(2*zeta)
552 int n = maxpow_;
553 complex<real>
554 y0(n & 1 ? -_bet[n] : 0), y1, // default initializer is 0+i0
555 z0(n & 1 ? -2*n * _bet[n] : 0), z1;
556 if (n & 1) --n;
557 while (n) {
558 y1 = a * y0 - y1 - _bet[n];
559 z1 = a * z0 - z1 - 2*n * _bet[n];
560 --n;
561 y0 = a * y1 - y0 - _bet[n];
562 z0 = a * z1 - z0 - 2*n * _bet[n];
563 --n;
564 }
565 a /= real(2); // cos(2*zeta)
566 z1 = real(1) - z1 + a * z0;
567 a = complex<real>(s0 * ch0, c0 * sh0); // sin(2*zeta)
568 y1 = complex<real>(xi, eta) + a * y0;
569 // Convergence and scale for Gauss-Schreiber TM to Gauss-Krueger TM.
570 gamma = Math::atan2d(z1.imag(), z1.real());
571 k = _b1 / abs(z1);
572 // JHS 154 has
573 //
574 // phi' = asin(sin(xi') / cosh(eta')) (Krueger p 17 (25))
575 // lam = asin(tanh(eta') / cos(phi')
576 // psi = asinh(tan(phi'))
577 real
578 xip = y1.real(), etap = y1.imag(),
579 s = sinh(etap),
580 c = fmax(real(0), cos(xip)), // cos(pi/2) might be negative
581 r = hypot(s, c);
582 if (r != 0) {
583 lon = Math::atan2d(s, c); // Krueger p 17 (25)
584 // Use Newton's method to solve for tau
585 real
586 sxip = sin(xip),
587 tau = Math::tauf(sxip/r, _es);
588 gamma += Math::atan2d(sxip * tanh(etap), c); // Krueger p 19 (31)
589 lat = Math::atand(tau);
590 // Note cos(phi') * cosh(eta') = r
591 k *= sqrt(_e2m + _e2 / (1 + Math::sq(tau))) *
592 hypot(real(1), tau) * r;
593 } else {
594 lat = Math::qd;
595 lon = 0;
596 k *= _c;
597 }
598 lat *= xisign;
599 if (backside)
600 lon = Math::hd - lon;
601 lon *= etasign;
602 lon = Math::AngNormalize(lon + lon0);
603 if (backside)
604 gamma = Math::hd - gamma;
605 gamma *= xisign * etasign;
606 gamma = Math::AngNormalize(gamma);
607 k *= _k0;
608 }
609
610} // namespace GeographicLib
TransverseMercator.hpp
Header for GeographicLib::TransverseMercator class.
GeographicLib::Constants::UTM_k0
static T UTM_k0()
Definition: Constants.hpp:199
GeographicLib::Constants::WGS84_f
static T WGS84_f()
Definition: Constants.hpp:141
GeographicLib::Constants::WGS84_a
static T WGS84_a()
Definition: Constants.hpp:135
GeographicLib::GeographicErr
Exception handling for GeographicLib.
Definition: Constants.hpp:316
GeographicLib::Math
Mathematical functions needed by GeographicLib.
Definition: Math.hpp:77
GeographicLib::Math::LatFix
static T LatFix(T x)
Definition: Math.hpp:293
GeographicLib::Math::sincosd
static void sincosd(T x, T &sinx, T &cosx)
Definition: Math.cpp:106
GeographicLib::Math::atan2d
static T atan2d(T y, T x)
Definition: Math.cpp:183
GeographicLib::Math::sq
static T sq(T x)
Definition: Math.hpp:205
GeographicLib::Math::tauf
static T tauf(T taup, T es)
Definition: Math.cpp:219
GeographicLib::Math::AngNormalize
static T AngNormalize(T x)
Definition: Math.cpp:71
GeographicLib::Math::atand
static T atand(T x)
Definition: Math.cpp:202
GeographicLib::Math::taupf
static T taupf(T tau, T es)
Definition: Math.cpp:209
GeographicLib::Math::pi
static T pi()
Definition: Math.hpp:183
GeographicLib::Math::polyval
static T polyval(int N, const T p[], T x)
Definition: Math.hpp:264
GeographicLib::Math::AngDiff
static T AngDiff(T x, T y, T &e)
Definition: Math.cpp:82
GeographicLib::Math::hd
@ hd
degrees per half turn
Definition: Math.hpp:141
GeographicLib::Math::qd
@ qd
degrees per quarter turn
Definition: Math.hpp:138
GeographicLib::TransverseMercatorExact
An exact implementation of the transverse Mercator projection.
Definition: TransverseMercatorExact.hpp:85
GeographicLib::TransverseMercatorExact::Forward
void Forward(real lon0, real lat, real lon, real &x, real &y, real &gamma, real &k) const
Definition: TransverseMercatorExact.cpp:350
GeographicLib::TransverseMercatorExact::Reverse
void Reverse(real lon0, real x, real y, real &lat, real &lon, real &gamma, real &k) const
Definition: TransverseMercatorExact.cpp:410
GeographicLib::TransverseMercator
Transverse Mercator projection.
Definition: TransverseMercator.hpp:94
GeographicLib::TransverseMercator::TransverseMercator
TransverseMercator(real a, real f, real k0, bool exact=false, bool extendp=false)
Definition: TransverseMercator.cpp:49
GeographicLib::TransverseMercator::Reverse
void Reverse(real lon0, real x, real y, real &lat, real &lon, real &gamma, real &k) const
Definition: TransverseMercator.cpp:528
GeographicLib::TransverseMercator::UTM
static const TransverseMercator & UTM()
Definition: TransverseMercator.cpp:287
GeographicLib::TransverseMercator::Forward
void Forward(real lon0, real lat, real lon, real &x, real &y, real &gamma, real &k) const
Definition: TransverseMercator.cpp:360
GeographicLib
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
std
Definition: NearestNeighbor.hpp:812