Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / geometry / srs / projections / proj / bipc.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 // Permission is hereby granted, free of charge, to any person obtaining a
23 // copy of this software and associated documentation files (the "Software"),
24 // to deal in the Software without restriction, including without limitation
25 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
26 // and/or sell copies of the Software, and to permit persons to whom the
27 // Software is furnished to do so, subject to the following conditions:
28
29 // The above copyright notice and this permission notice shall be included
30 // in all copies or substantial portions of the Software.
31
32 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
33 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
35 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
37 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
38 // DEALINGS IN THE SOFTWARE.
39
40 #ifndef BOOST_GEOMETRY_PROJECTIONS_BIPC_HPP
41 #define BOOST_GEOMETRY_PROJECTIONS_BIPC_HPP
42
43 #include <boost/geometry/srs/projections/impl/base_static.hpp>
44 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
45 #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
46 #include <boost/geometry/srs/projections/impl/pj_param.hpp>
47 #include <boost/geometry/srs/projections/impl/projects.hpp>
48
49 #include <boost/geometry/util/math.hpp>
50
51 #include <boost/math/special_functions/hypot.hpp>
52
53 namespace boost { namespace geometry
54 {
55
56 namespace projections
57 {
58     #ifndef DOXYGEN_NO_DETAIL
59     namespace detail { namespace bipc
60     {
61
62             static const double epsilon = 1e-10;
63             static const double epsilon10 = 1e-10;
64             static const double one_plus_eps = 1.000000001;
65             static const int n_iter = 10;
66             static const double lamB = -.34894976726250681539;
67             static const double n = .63055844881274687180;
68             static const double F = 1.89724742567461030582;
69             static const double Azab = .81650043674686363166;
70             static const double Azba = 1.82261843856185925133;
71             static const double const_T = 1.27246578267089012270;
72             static const double rhoc = 1.20709121521568721927;
73             static const double cAzc = .69691523038678375519;
74             static const double sAzc = .71715351331143607555;
75             static const double C45 = .70710678118654752469;
76             static const double S45 = .70710678118654752410;
77             static const double C20 = .93969262078590838411;
78             static const double S20 = -.34202014332566873287;
79             static const double R110 = 1.91986217719376253360;
80             static const double R104 = 1.81514242207410275904;
81
82             struct par_bipc
83             {
84                 bool   noskew;
85             };
86
87             template <typename T, typename Parameters>
88             struct base_bipc_spheroid
89             {
90                 par_bipc m_proj_parm;
91
92                 // FORWARD(s_forward)  spheroid
93                 // Project coordinates from geographic (lon, lat) to cartesian (x, y)
94                 inline void fwd(Parameters const& , T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
95                 {
96                     static const T half_pi = detail::half_pi<T>();
97                     static const T pi = detail::pi<T>();
98
99                     T cphi, sphi, tphi, t, al, Az, z, Av, cdlam, sdlam, r;
100                     int tag;
101
102                     cphi = cos(lp_lat);
103                     sphi = sin(lp_lat);
104                     cdlam = cos(sdlam = lamB - lp_lon);
105                     sdlam = sin(sdlam);
106                     if (fabs(fabs(lp_lat) - half_pi) < epsilon10) {
107                         Az = lp_lat < 0. ? pi : 0.;
108                         tphi = HUGE_VAL;
109                     } else {
110                         tphi = sphi / cphi;
111                         Az = atan2(sdlam , C45 * (tphi - cdlam));
112                     }
113                     if( (tag = (Az > Azba)) ) {
114                         cdlam = cos(sdlam = lp_lon + R110);
115                         sdlam = sin(sdlam);
116                         z = S20 * sphi + C20 * cphi * cdlam;
117                         if (fabs(z) > 1.) {
118                             if (fabs(z) > one_plus_eps)
119                                 BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
120                             else
121                                 z = z < 0. ? -1. : 1.;
122                         } else
123                             z = acos(z);
124                         if (tphi != HUGE_VAL)
125                             Az = atan2(sdlam, (C20 * tphi - S20 * cdlam));
126                         Av = Azab;
127                         xy_y = rhoc;
128                     } else {
129                         z = S45 * (sphi + cphi * cdlam);
130                         if (fabs(z) > 1.) {
131                             if (fabs(z) > one_plus_eps)
132                                 BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
133                             else
134                                 z = z < 0. ? -1. : 1.;
135                         } else
136                             z = acos(z);
137                         Av = Azba;
138                         xy_y = -rhoc;
139                     }
140                     if (z < 0.) {
141                         BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
142                     }
143                     r = F * (t = math::pow(tan(T(0.5) * z), n));
144                     if ((al = .5 * (R104 - z)) < 0.) {
145                         BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
146                     }
147                     al = (t + math::pow(al, n)) / const_T;
148                     if (fabs(al) > 1.) {
149                         if (fabs(al) > one_plus_eps)
150                             BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
151                         else
152                             al = al < 0. ? -1. : 1.;
153                     } else
154                         al = acos(al);
155                     if (fabs(t = n * (Av - Az)) < al)
156                         r /= cos(al + (tag ? t : -t));
157                     xy_x = r * sin(t);
158                     xy_y += (tag ? -r : r) * cos(t);
159                     if (this->m_proj_parm.noskew) {
160                         t = xy_x;
161                         xy_x = -xy_x * cAzc - xy_y * sAzc;
162                         xy_y = -xy_y * cAzc + t * sAzc;
163                     }
164                 }
165
166                 // INVERSE(s_inverse)  spheroid
167                 // Project coordinates from cartesian (x, y) to geographic (lon, lat)
168                 inline void inv(Parameters const& , T xy_x, T xy_y, T& lp_lon, T& lp_lat) const
169                 {
170                     T t, r, rp, rl, al, z, fAz, Az, s, c, Av;
171                     int neg, i;
172
173                     if (this->m_proj_parm.noskew) {
174                         t = xy_x;
175                         xy_x = -xy_x * cAzc + xy_y * sAzc;
176                         xy_y = -xy_y * cAzc - t * sAzc;
177                     }
178                     if( (neg = (xy_x < 0.)) ) {
179                         xy_y = rhoc - xy_y;
180                         s = S20;
181                         c = C20;
182                         Av = Azab;
183                     } else {
184                         xy_y += rhoc;
185                         s = S45;
186                         c = C45;
187                         Av = Azba;
188                     }
189                     rl = rp = r = boost::math::hypot(xy_x, xy_y);
190                     fAz = fabs(Az = atan2(xy_x, xy_y));
191                     for (i = n_iter; i ; --i) {
192                         z = 2. * atan(math::pow(r / F,T(1) / n));
193                         al = acos((math::pow(tan(T(0.5) * z), n) +
194                            math::pow(tan(T(0.5) * (R104 - z)), n)) / const_T);
195                         if (fAz < al)
196                             r = rp * cos(al + (neg ? Az : -Az));
197                         if (fabs(rl - r) < epsilon)
198                             break;
199                         rl = r;
200                     }
201                     if (! i)
202                         BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
203                     Az = Av - Az / n;
204                     lp_lat = asin(s * cos(z) + c * sin(z) * cos(Az));
205                     lp_lon = atan2(sin(Az), c / tan(z) - s * cos(Az));
206                     if (neg)
207                         lp_lon -= R110;
208                     else
209                         lp_lon = lamB - lp_lon;
210                 }
211
212                 static inline std::string get_name()
213                 {
214                     return "bipc_spheroid";
215                 }
216
217             };
218
219             // Bipolar conic of western hemisphere
220             template <typename Params, typename Parameters>
221             inline void setup_bipc(Params const& params, Parameters& par, par_bipc& proj_parm)
222             {
223                 proj_parm.noskew = pj_get_param_b<srs::spar::ns>(params, "ns", srs::dpar::ns);
224                 par.es = 0.;
225             }
226
227     }} // namespace detail::bipc
228     #endif // doxygen
229
230     /*!
231         \brief Bipolar conic of western hemisphere projection
232         \ingroup projections
233         \tparam Geographic latlong point type
234         \tparam Cartesian xy point type
235         \tparam Parameters parameter type
236         \par Projection characteristics
237          - Conic
238          - Spheroid
239         \par Projection parameters
240          - ns (boolean)
241         \par Example
242         \image html ex_bipc.gif
243     */
244     template <typename T, typename Parameters>
245     struct bipc_spheroid : public detail::bipc::base_bipc_spheroid<T, Parameters>
246     {
247         template <typename Params>
248         inline bipc_spheroid(Params const& params, Parameters & par)
249         {
250             detail::bipc::setup_bipc(params, par, this->m_proj_parm);
251         }
252     };
253
254     #ifndef DOXYGEN_NO_DETAIL
255     namespace detail
256     {
257
258         // Static projection
259         BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_bipc, bipc_spheroid)
260
261         // Factory entry(s)
262         BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(bipc_entry, bipc_spheroid)
263         
264         BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(bipc_init)
265         {
266             BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(bipc, bipc_entry)
267         }
268
269     } // namespace detail
270     #endif // doxygen
271
272 } // namespace projections
273
274 }} // namespace boost::geometry
275
276 #endif // BOOST_GEOMETRY_PROJECTIONS_BIPC_HPP
277