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