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 // Author: Gerald Evenden (1995)
19 // Thomas Knudsen (2016) - revise/add regression tests
21 // Last updated version of proj: 5.0.0
23 // Original copyright notice:
25 // Purpose: Implementation of the aea (Albers Equal Area) projection.
26 // Author: Gerald Evenden
27 // Copyright (c) 1995, Gerald Evenden
29 // Permission is hereby granted, free of charge, to any person obtaining a
30 // copy of this software and associated documentation files (the "Software"),
31 // to deal in the Software without restriction, including without limitation
32 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
33 // and/or sell copies of the Software, and to permit persons to whom the
34 // Software is furnished to do so, subject to the following conditions:
36 // The above copyright notice and this permission notice shall be included
37 // in all copies or substantial portions of the Software.
39 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
40 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
42 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
44 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
45 // DEALINGS IN THE SOFTWARE.
47 #ifndef BOOST_GEOMETRY_PROJECTIONS_AEA_HPP
48 #define BOOST_GEOMETRY_PROJECTIONS_AEA_HPP
50 #include <boost/core/ignore_unused.hpp>
51 #include <boost/geometry/util/math.hpp>
52 #include <boost/math/special_functions/hypot.hpp>
54 #include <boost/geometry/srs/projections/impl/base_static.hpp>
55 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
56 #include <boost/geometry/srs/projections/impl/projects.hpp>
57 #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
58 #include <boost/geometry/srs/projections/impl/pj_mlfn.hpp>
59 #include <boost/geometry/srs/projections/impl/pj_msfn.hpp>
60 #include <boost/geometry/srs/projections/impl/pj_param.hpp>
61 #include <boost/geometry/srs/projections/impl/pj_qsfn.hpp>
64 namespace boost { namespace geometry
69 #ifndef DOXYGEN_NO_DETAIL
70 namespace detail { namespace aea
73 static const double epsilon10 = 1.e-10;
74 static const double tolerance7 = 1.e-7;
75 static const double epsilon = 1.0e-7;
76 static const double tolerance = 1.0e-10;
77 static const int n_iter = 15;
94 /* determine latitude angle phi-1 */
96 inline T phi1_(T const& qs, T const& Te, T const& Tone_es)
99 T Phi, sinpi, cospi, con, com, dphi;
101 Phi = asin (.5 * qs);
109 com = 1. - con * con;
110 dphi = .5 * com * com / cospi * (qs / Tone_es -
111 sinpi / com + .5 / Te * log ((1. - con) /
114 } while (fabs(dphi) > tolerance && --i);
115 return( i ? Phi : HUGE_VAL );
118 template <typename T, typename Parameters>
119 struct base_aea_ellipsoid
121 par_aea<T> m_proj_parm;
123 // FORWARD(e_forward) ellipsoid & spheroid
124 // Project coordinates from geographic (lon, lat) to cartesian (x, y)
125 inline void fwd(Parameters const& par, T lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
127 T rho = this->m_proj_parm.c - (this->m_proj_parm.ellips
128 ? this->m_proj_parm.n * pj_qsfn(sin(lp_lat), par.e, par.one_es)
129 : this->m_proj_parm.n2 * sin(lp_lat));
131 BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
132 rho = this->m_proj_parm.dd * sqrt(rho);
133 xy_x = rho * sin( lp_lon *= this->m_proj_parm.n );
134 xy_y = this->m_proj_parm.rho0 - rho * cos(lp_lon);
137 // INVERSE(e_inverse) ellipsoid & spheroid
138 // Project coordinates from cartesian (x, y) to geographic (lon, lat)
139 inline void inv(Parameters const& par, T xy_x, T xy_y, T& lp_lon, T& lp_lat) const
141 static const T half_pi = detail::half_pi<T>();
144 if( (rho = boost::math::hypot(xy_x, xy_y = this->m_proj_parm.rho0 - xy_y)) != 0.0 ) {
145 if (this->m_proj_parm.n < 0.) {
150 lp_lat = rho / this->m_proj_parm.dd;
151 if (this->m_proj_parm.ellips) {
152 lp_lat = (this->m_proj_parm.c - lp_lat * lp_lat) / this->m_proj_parm.n;
153 if (fabs(this->m_proj_parm.ec - fabs(lp_lat)) > tolerance7) {
154 if ((lp_lat = phi1_(lp_lat, par.e, par.one_es)) == HUGE_VAL)
155 BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
157 lp_lat = lp_lat < 0. ? -half_pi : half_pi;
158 } else if (fabs(lp_lat = (this->m_proj_parm.c - lp_lat * lp_lat) / this->m_proj_parm.n2) <= 1.)
159 lp_lat = asin(lp_lat);
161 lp_lat = lp_lat < 0. ? -half_pi : half_pi;
162 lp_lon = atan2(xy_x, xy_y) / this->m_proj_parm.n;
165 lp_lat = this->m_proj_parm.n > 0. ? half_pi : - half_pi;
169 static inline std::string get_name()
171 return "aea_ellipsoid";
176 template <typename Parameters, typename T>
177 inline void setup(Parameters const& par, par_aea<T>& proj_parm)
182 if (fabs(proj_parm.phi1 + proj_parm.phi2) < epsilon10)
183 BOOST_THROW_EXCEPTION( projection_exception(error_conic_lat_equal) );
184 proj_parm.n = sinphi = sin(proj_parm.phi1);
185 cosphi = cos(proj_parm.phi1);
186 secant = fabs(proj_parm.phi1 - proj_parm.phi2) >= epsilon10;
187 if( (proj_parm.ellips = (par.es > 0.))) {
190 proj_parm.en = pj_enfn<T>(par.es);
191 m1 = pj_msfn(sinphi, cosphi, par.es);
192 ml1 = pj_qsfn(sinphi, par.e, par.one_es);
193 if (secant) { /* secant cone */
196 sinphi = sin(proj_parm.phi2);
197 cosphi = cos(proj_parm.phi2);
198 m2 = pj_msfn(sinphi, cosphi, par.es);
199 ml2 = pj_qsfn(sinphi, par.e, par.one_es);
201 BOOST_THROW_EXCEPTION( projection_exception(0) );
203 proj_parm.n = (m1 * m1 - m2 * m2) / (ml2 - ml1);
205 proj_parm.ec = 1. - .5 * par.one_es * log((1. - par.e) /
206 (1. + par.e)) / par.e;
207 proj_parm.c = m1 * m1 + proj_parm.n * ml1;
208 proj_parm.dd = 1. / proj_parm.n;
209 proj_parm.rho0 = proj_parm.dd * sqrt(proj_parm.c - proj_parm.n * pj_qsfn(sin(par.phi0),
212 if (secant) proj_parm.n = .5 * (proj_parm.n + sin(proj_parm.phi2));
213 proj_parm.n2 = proj_parm.n + proj_parm.n;
214 proj_parm.c = cosphi * cosphi + proj_parm.n2 * sinphi;
215 proj_parm.dd = 1. / proj_parm.n;
216 proj_parm.rho0 = proj_parm.dd * sqrt(proj_parm.c - proj_parm.n2 * sin(par.phi0));
222 template <typename Params, typename Parameters, typename T>
223 inline void setup_aea(Params const& params, Parameters const& par, par_aea<T>& proj_parm)
225 proj_parm.phi1 = 0.0;
226 proj_parm.phi2 = 0.0;
227 bool is_phi1_set = pj_param_r<srs::spar::lat_1>(params, "lat_1", srs::dpar::lat_1, proj_parm.phi1);
228 bool is_phi2_set = pj_param_r<srs::spar::lat_2>(params, "lat_2", srs::dpar::lat_2, proj_parm.phi2);
230 // Boost.Geometry specific, set default parameters manually
231 if (! is_phi1_set || ! is_phi2_set) {
232 bool const use_defaults = ! pj_get_param_b<srs::spar::no_defs>(params, "no_defs", srs::dpar::no_defs);
235 proj_parm.phi1 = 29.5;
237 proj_parm.phi2 = 45.5;
241 setup(par, proj_parm);
244 // Lambert Equal Area Conic
245 template <typename Params, typename Parameters, typename T>
246 inline void setup_leac(Params const& params, Parameters const& par, par_aea<T>& proj_parm)
248 static const T half_pi = detail::half_pi<T>();
250 proj_parm.phi2 = pj_get_param_r<T, srs::spar::lat_1>(params, "lat_1", srs::dpar::lat_1);
251 proj_parm.phi1 = pj_get_param_b<srs::spar::south>(params, "south", srs::dpar::south) ? -half_pi : half_pi;
252 setup(par, proj_parm);
255 }} // namespace detail::aea
259 \brief Albers Equal Area projection
261 \tparam Geographic latlong point type
262 \tparam Cartesian xy point type
263 \tparam Parameters parameter type
264 \par Projection characteristics
268 \par Projection parameters
269 - lat_1: Latitude of first standard parallel (degrees)
270 - lat_2: Latitude of second standard parallel (degrees)
272 \image html ex_aea.gif
274 template <typename T, typename Parameters>
275 struct aea_ellipsoid : public detail::aea::base_aea_ellipsoid<T, Parameters>
277 template <typename Params>
278 inline aea_ellipsoid(Params const& params, Parameters const& par)
280 detail::aea::setup_aea(params, par, this->m_proj_parm);
285 \brief Lambert Equal Area Conic projection
287 \tparam Geographic latlong point type
288 \tparam Cartesian xy point type
289 \tparam Parameters parameter type
290 \par Projection characteristics
294 \par Projection parameters
295 - lat_1: Latitude of first standard parallel (degrees)
296 - south: Denotes southern hemisphere UTM zone (boolean)
298 \image html ex_leac.gif
300 template <typename T, typename Parameters>
301 struct leac_ellipsoid : public detail::aea::base_aea_ellipsoid<T, Parameters>
303 template <typename Params>
304 inline leac_ellipsoid(Params const& params, Parameters const& par)
306 detail::aea::setup_leac(params, par, this->m_proj_parm);
310 #ifndef DOXYGEN_NO_DETAIL
315 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_aea, aea_ellipsoid)
316 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_leac, leac_ellipsoid)
319 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(aea_entry, aea_ellipsoid)
320 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(leac_entry, leac_ellipsoid)
322 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(aea_init)
324 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(aea, aea_entry)
325 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(leac, leac_entry)
328 } // namespace detail
331 } // namespace projections
333 }} // namespace boost::geometry
335 #endif // BOOST_GEOMETRY_PROJECTIONS_AEA_HPP