]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/srs/projections/proj/etmerc.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / geometry / srs / projections / proj / etmerc.hpp
1 // Boost.Geometry - gis-projections (based on PROJ4)
2
3 // Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // This file was modified by Oracle on 2017, 2018, 2019.
6 // Modifications copyright (c) 2017-2019, Oracle and/or its affiliates.
7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle.
8
9 // Use, modification and distribution is subject to the Boost Software License,
10 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12
13 // This file is converted from PROJ4, http://trac.osgeo.org/proj
14 // PROJ4 is originally written by Gerald Evenden (then of the USGS)
15 // PROJ4 is maintained by Frank Warmerdam
16 // PROJ4 is converted to Boost.Geometry by Barend Gehrels
17
18 // Last updated version of proj: 5.0.0
19
20 // Original copyright notice:
21
22 // Copyright (c) 2008 Gerald I. Evenden
23
24 // Permission is hereby granted, free of charge, to any person obtaining a
25 // copy of this software and associated documentation files (the "Software"),
26 // to deal in the Software without restriction, including without limitation
27 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
28 // and/or sell copies of the Software, and to permit persons to whom the
29 // Software is furnished to do so, subject to the following conditions:
30
31 // The above copyright notice and this permission notice shall be included
32 // in all copies or substantial portions of the Software.
33
34 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
35 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
37 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
39 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
40 // DEALINGS IN THE SOFTWARE.
41
42 /* The code in this file is largly based upon procedures:
43 *
44 * Written by: Knud Poder and Karsten Engsager
45 *
46 * Based on math from: R.Koenig and K.H. Weise, "Mathematische
47 * Grundlagen der hoeheren Geodaesie und Kartographie,
48 * Springer-Verlag, Berlin/Goettingen" Heidelberg, 1951.
49 *
50 * Modified and used here by permission of Reference Networks
51 * Division, Kort og Matrikelstyrelsen (KMS), Copenhagen, Denmark
52 */
53
54 #ifndef BOOST_GEOMETRY_PROJECTIONS_ETMERC_HPP
55 #define BOOST_GEOMETRY_PROJECTIONS_ETMERC_HPP
56
57 #include <boost/geometry/srs/projections/impl/base_static.hpp>
58 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
59 #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
60 #include <boost/geometry/srs/projections/impl/function_overloads.hpp>
61 #include <boost/geometry/srs/projections/impl/pj_param.hpp>
62 #include <boost/geometry/srs/projections/impl/projects.hpp>
63
64 #include <boost/math/special_functions/hypot.hpp>
65
66 namespace boost { namespace geometry
67 {
68
69 namespace projections
70 {
71 #ifndef DOXYGEN_NO_DETAIL
72 namespace detail { namespace etmerc
73 {
74
75 static const int PROJ_ETMERC_ORDER = 6;
76
77 template <typename T>
78 struct par_etmerc
79 {
80 T Qn; /* Merid. quad., scaled to the projection */
81 T Zb; /* Radius vector in polar coord. systems */
82 T cgb[6]; /* Constants for Gauss -> Geo lat */
83 T cbg[6]; /* Constants for Geo lat -> Gauss */
84 T utg[6]; /* Constants for transv. merc. -> geo */
85 T gtu[6]; /* Constants for geo -> transv. merc. */
86 };
87
88 template <typename T>
89 inline T log1py(T const& x) { /* Compute log(1+x) accurately */
90 volatile T
91 y = 1 + x,
92 z = y - 1;
93 /* Here's the explanation for this magic: y = 1 + z, exactly, and z
94 * approx x, thus log(y)/z (which is nearly constant near z = 0) returns
95 * a good approximation to the true log(1 + x)/x. The multiplication x *
96 * (log(y)/z) introduces little additional error. */
97 return z == 0 ? x : x * log(y) / z;
98 }
99
100 template <typename T>
101 inline T asinhy(T const& x) { /* Compute asinh(x) accurately */
102 T y = fabs(x); /* Enforce odd parity */
103 y = log1py(y * (1 + y/(boost::math::hypot(1.0, y) + 1)));
104 return x < 0 ? -y : y;
105 }
106
107 template <typename T>
108 inline T gatg(const T *p1, int len_p1, T const& B) {
109 const T *p;
110 T h = 0, h1, h2 = 0, cos_2B;
111
112 cos_2B = 2*cos(2*B);
113 for (p = p1 + len_p1, h1 = *--p; p - p1; h2 = h1, h1 = h)
114 h = -h2 + cos_2B*h1 + *--p;
115 return (B + h*sin(2*B));
116 }
117
118 /* Complex Clenshaw summation */
119 template <typename T>
120 inline T clenS(const T *a, int size, T const& arg_r, T const& arg_i, T *R, T *I) {
121 T r, i, hr, hr1, hr2, hi, hi1, hi2;
122 T sin_arg_r, cos_arg_r, sinh_arg_i, cosh_arg_i;
123
124 /* arguments */
125 const T* p = a + size;
126 sin_arg_r = sin(arg_r);
127 cos_arg_r = cos(arg_r);
128 sinh_arg_i = sinh(arg_i);
129 cosh_arg_i = cosh(arg_i);
130 r = 2*cos_arg_r*cosh_arg_i;
131 i = -2*sin_arg_r*sinh_arg_i;
132 /* summation loop */
133 for (hi1 = hr1 = hi = 0, hr = *--p; a - p;) {
134 hr2 = hr1;
135 hi2 = hi1;
136 hr1 = hr;
137 hi1 = hi;
138 hr = -hr2 + r*hr1 - i*hi1 + *--p;
139 hi = -hi2 + i*hr1 + r*hi1;
140 }
141 r = sin_arg_r*cosh_arg_i;
142 i = cos_arg_r*sinh_arg_i;
143 *R = r*hr - i*hi;
144 *I = r*hi + i*hr;
145 return(*R);
146 }
147
148 /* Real Clenshaw summation */
149 template <typename T>
150 inline T clens(const T *a, int size, T const& arg_r) {
151 T r, hr, hr1, hr2, cos_arg_r;
152
153 const T* p = a + size;
154 cos_arg_r = cos(arg_r);
155 r = 2*cos_arg_r;
156
157 /* summation loop */
158 for (hr1 = 0, hr = *--p; a - p;) {
159 hr2 = hr1;
160 hr1 = hr;
161 hr = -hr2 + r*hr1 + *--p;
162 }
163 return(sin(arg_r)*hr);
164 }
165
166 template <typename T, typename Parameters>
167 struct base_etmerc_ellipsoid
168 {
169 par_etmerc<T> m_proj_parm;
170
171 // FORWARD(e_forward) ellipsoid
172 // Project coordinates from geographic (lon, lat) to cartesian (x, y)
173 inline void fwd(Parameters const& , T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
174 {
175 T sin_Cn, cos_Cn, cos_Ce, sin_Ce, dCn, dCe;
176 T Cn = lp_lat, Ce = lp_lon;
177
178 /* ell. LAT, LNG -> Gaussian LAT, LNG */
179 Cn = gatg(this->m_proj_parm.cbg, PROJ_ETMERC_ORDER, Cn);
180 /* Gaussian LAT, LNG -> compl. sph. LAT */
181 sin_Cn = sin(Cn);
182 cos_Cn = cos(Cn);
183 sin_Ce = sin(Ce);
184 cos_Ce = cos(Ce);
185
186 Cn = atan2(sin_Cn, cos_Ce*cos_Cn);
187 Ce = atan2(sin_Ce*cos_Cn, boost::math::hypot(sin_Cn, cos_Cn*cos_Ce));
188
189 /* compl. sph. N, E -> ell. norm. N, E */
190 Ce = asinhy(tan(Ce)); /* Replaces: Ce = log(tan(fourth_pi + Ce*0.5)); */
191 Cn += clenS(this->m_proj_parm.gtu, PROJ_ETMERC_ORDER, 2*Cn, 2*Ce, &dCn, &dCe);
192 Ce += dCe;
193 if (fabs(Ce) <= 2.623395162778) {
194 xy_y = this->m_proj_parm.Qn * Cn + this->m_proj_parm.Zb; /* Northing */
195 xy_x = this->m_proj_parm.Qn * Ce; /* Easting */
196 } else
197 xy_x = xy_y = HUGE_VAL;
198 }
199
200 // INVERSE(e_inverse) ellipsoid
201 // Project coordinates from cartesian (x, y) to geographic (lon, lat)
202 inline void inv(Parameters const& , T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
203 {
204 T sin_Cn, cos_Cn, cos_Ce, sin_Ce, dCn, dCe;
205 T Cn = xy_y, Ce = xy_x;
206
207 /* normalize N, E */
208 Cn = (Cn - this->m_proj_parm.Zb)/this->m_proj_parm.Qn;
209 Ce = Ce/this->m_proj_parm.Qn;
210
211 if (fabs(Ce) <= 2.623395162778) { /* 150 degrees */
212 /* norm. N, E -> compl. sph. LAT, LNG */
213 Cn += clenS(this->m_proj_parm.utg, PROJ_ETMERC_ORDER, 2*Cn, 2*Ce, &dCn, &dCe);
214 Ce += dCe;
215 Ce = atan(sinh(Ce)); /* Replaces: Ce = 2*(atan(exp(Ce)) - fourth_pi); */
216 /* compl. sph. LAT -> Gaussian LAT, LNG */
217 sin_Cn = sin(Cn);
218 cos_Cn = cos(Cn);
219 sin_Ce = sin(Ce);
220 cos_Ce = cos(Ce);
221 Ce = atan2(sin_Ce, cos_Ce*cos_Cn);
222 Cn = atan2(sin_Cn*cos_Ce, boost::math::hypot(sin_Ce, cos_Ce*cos_Cn));
223 /* Gaussian LAT, LNG -> ell. LAT, LNG */
224 lp_lat = gatg(this->m_proj_parm.cgb, PROJ_ETMERC_ORDER, Cn);
225 lp_lon = Ce;
226 }
227 else
228 lp_lat = lp_lon = HUGE_VAL;
229 }
230
231 static inline std::string get_name()
232 {
233 return "etmerc_ellipsoid";
234 }
235
236 };
237
238 template <typename Parameters, typename T>
239 inline void setup(Parameters& par, par_etmerc<T>& proj_parm)
240 {
241 T f, n, np, Z;
242
243 if (par.es <= 0) {
244 BOOST_THROW_EXCEPTION( projection_exception(error_ellipsoid_use_required) );
245 }
246
247 f = par.es / (1 + sqrt(1 - par.es)); /* Replaces: f = 1 - sqrt(1-par.es); */
248
249 /* third flattening */
250 np = n = f/(2 - f);
251
252 /* COEF. OF TRIG SERIES GEO <-> GAUSS */
253 /* cgb := Gaussian -> Geodetic, KW p190 - 191 (61) - (62) */
254 /* cbg := Geodetic -> Gaussian, KW p186 - 187 (51) - (52) */
255 /* PROJ_ETMERC_ORDER = 6th degree : Engsager and Poder: ICC2007 */
256
257 proj_parm.cgb[0] = n*( 2 + n*(-2/3.0 + n*(-2 + n*(116/45.0 + n*(26/45.0 +
258 n*(-2854/675.0 ))))));
259 proj_parm.cbg[0] = n*(-2 + n*( 2/3.0 + n*( 4/3.0 + n*(-82/45.0 + n*(32/45.0 +
260 n*( 4642/4725.0))))));
261 np *= n;
262 proj_parm.cgb[1] = np*(7/3.0 + n*( -8/5.0 + n*(-227/45.0 + n*(2704/315.0 +
263 n*( 2323/945.0)))));
264 proj_parm.cbg[1] = np*(5/3.0 + n*(-16/15.0 + n*( -13/9.0 + n*( 904/315.0 +
265 n*(-1522/945.0)))));
266 np *= n;
267 /* n^5 coeff corrected from 1262/105 -> -1262/105 */
268 proj_parm.cgb[2] = np*( 56/15.0 + n*(-136/35.0 + n*(-1262/105.0 +
269 n*( 73814/2835.0))));
270 proj_parm.cbg[2] = np*(-26/15.0 + n*( 34/21.0 + n*( 8/5.0 +
271 n*(-12686/2835.0))));
272 np *= n;
273 /* n^5 coeff corrected from 322/35 -> 332/35 */
274 proj_parm.cgb[3] = np*(4279/630.0 + n*(-332/35.0 + n*(-399572/14175.0)));
275 proj_parm.cbg[3] = np*(1237/630.0 + n*( -12/5.0 + n*( -24832/14175.0)));
276 np *= n;
277 proj_parm.cgb[4] = np*(4174/315.0 + n*(-144838/6237.0 ));
278 proj_parm.cbg[4] = np*(-734/315.0 + n*( 109598/31185.0));
279 np *= n;
280 proj_parm.cgb[5] = np*(601676/22275.0 );
281 proj_parm.cbg[5] = np*(444337/155925.0);
282
283 /* Constants of the projections */
284 /* Transverse Mercator (UTM, ITM, etc) */
285 np = n*n;
286 /* Norm. mer. quad, K&W p.50 (96), p.19 (38b), p.5 (2) */
287 proj_parm.Qn = par.k0/(1 + n) * (1 + np*(1/4.0 + np*(1/64.0 + np/256.0)));
288 /* coef of trig series */
289 /* utg := ell. N, E -> sph. N, E, KW p194 (65) */
290 /* gtu := sph. N, E -> ell. N, E, KW p196 (69) */
291 proj_parm.utg[0] = n*(-0.5 + n*( 2/3.0 + n*(-37/96.0 + n*( 1/360.0 +
292 n*( 81/512.0 + n*(-96199/604800.0))))));
293 proj_parm.gtu[0] = n*( 0.5 + n*(-2/3.0 + n*( 5/16.0 + n*(41/180.0 +
294 n*(-127/288.0 + n*( 7891/37800.0 ))))));
295 proj_parm.utg[1] = np*(-1/48.0 + n*(-1/15.0 + n*(437/1440.0 + n*(-46/105.0 +
296 n*( 1118711/3870720.0)))));
297 proj_parm.gtu[1] = np*(13/48.0 + n*(-3/5.0 + n*(557/1440.0 + n*(281/630.0 +
298 n*(-1983433/1935360.0)))));
299 np *= n;
300 proj_parm.utg[2] = np*(-17/480.0 + n*( 37/840.0 + n*( 209/4480.0 +
301 n*( -5569/90720.0 ))));
302 proj_parm.gtu[2] = np*( 61/240.0 + n*(-103/140.0 + n*(15061/26880.0 +
303 n*(167603/181440.0))));
304 np *= n;
305 proj_parm.utg[3] = np*(-4397/161280.0 + n*( 11/504.0 + n*( 830251/7257600.0)));
306 proj_parm.gtu[3] = np*(49561/161280.0 + n*(-179/168.0 + n*(6601661/7257600.0)));
307 np *= n;
308 proj_parm.utg[4] = np*(-4583/161280.0 + n*( 108847/3991680.0));
309 proj_parm.gtu[4] = np*(34729/80640.0 + n*(-3418889/1995840.0));
310 np *= n;
311 proj_parm.utg[5] = np*(-20648693/638668800.0);
312 proj_parm.gtu[5] = np*(212378941/319334400.0);
313
314 /* Gaussian latitude value of the origin latitude */
315 Z = gatg(proj_parm.cbg, PROJ_ETMERC_ORDER, par.phi0);
316
317 /* Origin northing minus true northing at the origin latitude */
318 /* i.e. true northing = N - proj_parm.Zb */
319 proj_parm.Zb = - proj_parm.Qn*(Z + clens(proj_parm.gtu, PROJ_ETMERC_ORDER, 2*Z));
320 }
321
322 // Extended Transverse Mercator
323 template <typename Parameters, typename T>
324 inline void setup_etmerc(Parameters& par, par_etmerc<T>& proj_parm)
325 {
326 setup(par, proj_parm);
327 }
328
329 // Universal Transverse Mercator (UTM)
330 template <typename Params, typename Parameters, typename T>
331 inline void setup_utm(Params const& params, Parameters& par, par_etmerc<T>& proj_parm)
332 {
333 static const T pi = detail::pi<T>();
334
335 int zone;
336
337 if (par.es == 0.0) {
338 BOOST_THROW_EXCEPTION( projection_exception(error_ellipsoid_use_required) );
339 }
340
341 par.y0 = pj_get_param_b<srs::spar::south>(params, "south", srs::dpar::south) ? 10000000. : 0.;
342 par.x0 = 500000.;
343 if (pj_param_i<srs::spar::zone>(params, "zone", srs::dpar::zone, zone)) /* zone input ? */
344 {
345 if (zone > 0 && zone <= 60)
346 --zone;
347 else {
348 BOOST_THROW_EXCEPTION( projection_exception(error_invalid_utm_zone) );
349 }
350 }
351 else /* nearest central meridian input */
352 {
353 zone = int_floor((adjlon(par.lam0) + pi) * 30. / pi);
354 if (zone < 0)
355 zone = 0;
356 else if (zone >= 60)
357 zone = 59;
358 }
359 par.lam0 = (zone + .5) * pi / 30. - pi;
360 par.k0 = 0.9996;
361 par.phi0 = 0.;
362
363 setup(par, proj_parm);
364 }
365
366 }} // namespace detail::etmerc
367 #endif // doxygen
368
369 /*!
370 \brief Extended Transverse Mercator projection
371 \ingroup projections
372 \tparam Geographic latlong point type
373 \tparam Cartesian xy point type
374 \tparam Parameters parameter type
375 \par Projection characteristics
376 - Cylindrical
377 - Spheroid
378 \par Projection parameters
379 - lat_ts: Latitude of true scale
380 - lat_0: Latitude of origin
381 \par Example
382 \image html ex_etmerc.gif
383 */
384 template <typename T, typename Parameters>
385 struct etmerc_ellipsoid : public detail::etmerc::base_etmerc_ellipsoid<T, Parameters>
386 {
387 template <typename Params>
388 inline etmerc_ellipsoid(Params const& , Parameters & par)
389 {
390 detail::etmerc::setup_etmerc(par, this->m_proj_parm);
391 }
392 };
393
394 /*!
395 \brief Universal Transverse Mercator (UTM) projection
396 \ingroup projections
397 \tparam Geographic latlong point type
398 \tparam Cartesian xy point type
399 \tparam Parameters parameter type
400 \par Projection characteristics
401 - Cylindrical
402 - Spheroid
403 \par Projection parameters
404 - zone: UTM Zone (integer)
405 - south: Denotes southern hemisphere UTM zone (boolean)
406 \par Example
407 \image html ex_utm.gif
408 */
409 template <typename T, typename Parameters>
410 struct utm_ellipsoid : public detail::etmerc::base_etmerc_ellipsoid<T, Parameters>
411 {
412 template <typename Params>
413 inline utm_ellipsoid(Params const& params, Parameters & par)
414 {
415 detail::etmerc::setup_utm(params, par, this->m_proj_parm);
416 }
417 };
418
419 #ifndef DOXYGEN_NO_DETAIL
420 namespace detail
421 {
422
423 // Static projection
424 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_etmerc, etmerc_ellipsoid)
425 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_utm, utm_ellipsoid)
426
427 // Factory entry(s)
428 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(etmerc_entry, etmerc_ellipsoid)
429 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(utm_entry, utm_ellipsoid)
430
431 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(etmerc_init)
432 {
433 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(etmerc, etmerc_entry);
434 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(utm, utm_entry);
435 }
436
437 } // namespace detail
438 #endif // doxygen
439
440 } // namespace projections
441
442 }} // namespace boost::geometry
443
444 #endif // BOOST_GEOMETRY_PROJECTIONS_ETMERC_HPP
445