1 // Boost.Geometry - gis-projections (based on PROJ4)
3 // Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.
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.
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)
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
18 // Last updated version of proj: 5.0.0
20 // Original copyright notice:
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:
29 // The above copyright notice and this permission notice shall be included
30 // in all copies or substantial portions of the Software.
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.
40 #ifndef BOOST_GEOMETRY_PROJECTIONS_IMW_P_HPP
41 #define BOOST_GEOMETRY_PROJECTIONS_IMW_P_HPP
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_mlfn.hpp>
47 #include <boost/geometry/srs/projections/impl/pj_param.hpp>
48 #include <boost/geometry/srs/projections/impl/projects.hpp>
50 #include <boost/geometry/util/math.hpp>
52 namespace boost { namespace geometry
57 #ifndef DOXYGEN_NO_DETAIL
58 namespace detail { namespace imw_p
61 static const double tolerance = 1e-10;
62 static const double epsilon = 1e-10;
65 struct point_xy { T x, y; }; // specific for IMW_P
68 none_is_zero = 0, /* phi_1 and phi_2 != 0 */
69 phi_1_is_zero = 1, /* phi_1 = 0 */
70 phi_2_is_zero = -1 /* phi_2 = 0 */
76 T P, Pp, Q, Qp, R_1, R_2, sphi_1, sphi_2, C2;
77 T phi_1, phi_2, lam_1;
82 template <typename Params, typename T>
83 inline int phi12(Params const& params,
84 par_imw_p<T> & proj_parm, T *del, T *sig)
88 if (!pj_param_r<srs::spar::lat_1>(params, "lat_1", srs::dpar::lat_1, proj_parm.phi_1) ||
89 !pj_param_r<srs::spar::lat_2>(params, "lat_2", srs::dpar::lat_2, proj_parm.phi_2)) {
92 //proj_parm.phi_1 = pj_get_param_r(par.params, "lat_1"); // set above
93 //proj_parm.phi_2 = pj_get_param_r(par.params, "lat_2"); // set above
94 *del = 0.5 * (proj_parm.phi_2 - proj_parm.phi_1);
95 *sig = 0.5 * (proj_parm.phi_2 + proj_parm.phi_1);
96 err = (fabs(*del) < epsilon || fabs(*sig) < epsilon) ? -42 : 0;
100 template <typename Parameters, typename T>
101 inline point_xy<T> loc_for(T const& lp_lam, T const& lp_phi,
102 Parameters const& par,
103 par_imw_p<T> const& proj_parm,
112 T xa, ya, xb, yb, xc, D, B, m, sp, t, R, C;
115 m = pj_mlfn(lp_phi, sp, cos(lp_phi), proj_parm.en);
116 xa = proj_parm.Pp + proj_parm.Qp * m;
117 ya = proj_parm.P + proj_parm.Q * m;
118 R = 1. / (tan(lp_phi) * sqrt(1. - par.es * sp * sp));
119 C = sqrt(R * R - xa * xa);
120 if (lp_phi < 0.) C = - C;
122 if (proj_parm.mode == phi_2_is_zero) {
126 t = lp_lam * proj_parm.sphi_2;
127 xb = proj_parm.R_2 * sin(t);
128 yb = proj_parm.C2 + proj_parm.R_2 * (1. - cos(t));
130 if (proj_parm.mode == phi_1_is_zero) {
134 t = lp_lam * proj_parm.sphi_1;
135 xc = proj_parm.R_1 * sin(t);
136 *yc = proj_parm.R_1 * (1. - cos(t));
138 D = (xb - xc)/(yb - *yc);
139 B = xc + D * (C + R - *yc);
140 xy.x = D * sqrt(R * R * (1 + D * D) - B * B);
143 xy.x = (B + xy.x) / (1. + D * D);
144 xy.y = sqrt(R * R - xy.x * xy.x);
151 template <typename Parameters, typename T>
152 inline void xy(Parameters const& par, par_imw_p<T> const& proj_parm,
154 T *x, T *y, T *sp, T *R)
159 *R = 1./(tan(phi) * sqrt(1. - par.es * *sp * *sp ));
160 F = proj_parm.lam_1 * *sp;
161 *y = *R * (1 - cos(F));
165 template <typename T, typename Parameters>
166 struct base_imw_p_ellipsoid
168 par_imw_p<T> m_proj_parm;
170 // FORWARD(e_forward) ellipsoid
171 // Project coordinates from geographic (lon, lat) to cartesian (x, y)
172 inline void fwd(Parameters const& par, T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
175 point_xy<T> xy = loc_for(lp_lon, lp_lat, par, m_proj_parm, &yc);
176 xy_x = xy.x; xy_y = xy.y;
179 // INVERSE(e_inverse) ellipsoid
180 // Project coordinates from cartesian (x, y) to geographic (lon, lat)
181 inline void inv(Parameters const& par, T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
186 const int n_max_iter = 1000; /* Arbitrarily choosen number... */
188 lp_lat = this->m_proj_parm.phi_2;
189 lp_lon = xy_x / cos(lp_lat);
191 t = loc_for(lp_lon, lp_lat, par, m_proj_parm, &yc);
192 lp_lat = ((lp_lat - this->m_proj_parm.phi_1) * (xy_y - yc) / (t.y - yc)) + this->m_proj_parm.phi_1;
193 lp_lon = lp_lon * xy_x / t.x;
195 } while (i < n_max_iter &&
196 (fabs(t.x - xy_x) > tolerance || fabs(t.y - xy_y) > tolerance));
198 if( i == n_max_iter )
200 lp_lon = lp_lat = HUGE_VAL;
204 static inline std::string get_name()
206 return "imw_p_ellipsoid";
211 // International Map of the World Polyconic
212 template <typename Params, typename Parameters, typename T>
213 inline void setup_imw_p(Params const& params, Parameters const& par, par_imw_p<T>& proj_parm)
215 T del, sig, s, t, x1, x2, T2, y1, m1, m2, y2;
218 proj_parm.en = pj_enfn<T>(par.es);
219 if( (err = phi12(params, proj_parm, &del, &sig)) != 0)
220 BOOST_THROW_EXCEPTION( projection_exception(err) );
221 if (proj_parm.phi_2 < proj_parm.phi_1) { /* make sure proj_parm.phi_1 most southerly */
222 del = proj_parm.phi_1;
223 proj_parm.phi_1 = proj_parm.phi_2;
224 proj_parm.phi_2 = del;
226 if (pj_param_r<srs::spar::lon_1>(params, "lon_1", srs::dpar::lon_1, proj_parm.lam_1)) {
228 } else { /* use predefined based upon latitude */
229 sig = fabs(sig * geometry::math::r2d<T>());
230 if (sig <= 60) sig = 2.;
231 else if (sig <= 76) sig = 4.;
233 proj_parm.lam_1 = sig * geometry::math::d2r<T>();
235 proj_parm.mode = none_is_zero;
236 if (proj_parm.phi_1 != 0.0)
237 xy(par, proj_parm, proj_parm.phi_1, &x1, &y1, &proj_parm.sphi_1, &proj_parm.R_1);
239 proj_parm.mode = phi_1_is_zero;
241 x1 = proj_parm.lam_1;
243 if (proj_parm.phi_2 != 0.0)
244 xy(par, proj_parm, proj_parm.phi_2, &x2, &T2, &proj_parm.sphi_2, &proj_parm.R_2);
246 proj_parm.mode = phi_2_is_zero;
248 x2 = proj_parm.lam_1;
250 m1 = pj_mlfn(proj_parm.phi_1, proj_parm.sphi_1, cos(proj_parm.phi_1), proj_parm.en);
251 m2 = pj_mlfn(proj_parm.phi_2, proj_parm.sphi_2, cos(proj_parm.phi_2), proj_parm.en);
254 y2 = sqrt(t * t - s * s) + y1;
255 proj_parm.C2 = y2 - T2;
257 proj_parm.P = (m2 * y1 - m1 * y2) * t;
258 proj_parm.Q = (y2 - y1) * t;
259 proj_parm.Pp = (m2 * x1 - m1 * x2) * t;
260 proj_parm.Qp = (x2 - x1) * t;
263 }} // namespace detail::imw_p
267 \brief International Map of the World Polyconic projection
269 \tparam Geographic latlong point type
270 \tparam Cartesian xy point type
271 \tparam Parameters parameter type
272 \par Projection characteristics
275 \par Projection parameters
276 - lat_1: Latitude of first standard parallel
277 - lat_2: Latitude of second standard parallel
280 \image html ex_imw_p.gif
282 template <typename T, typename Parameters>
283 struct imw_p_ellipsoid : public detail::imw_p::base_imw_p_ellipsoid<T, Parameters>
285 template <typename Params>
286 inline imw_p_ellipsoid(Params const& params, Parameters const& par)
288 detail::imw_p::setup_imw_p(params, par, this->m_proj_parm);
292 #ifndef DOXYGEN_NO_DETAIL
297 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_imw_p, imw_p_ellipsoid)
300 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(imw_p_entry, imw_p_ellipsoid)
302 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(imw_p_init)
304 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(imw_p, imw_p_entry)
307 } // namespace detail
310 } // namespace projections
312 }} // namespace boost::geometry
314 #endif // BOOST_GEOMETRY_PROJECTIONS_IMW_P_HPP