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 // Purpose: Implementation of the krovak (Krovak) projection.
23 // Definition: http://www.ihsenergy.com/epsg/guid7.html#1.4.3
24 // Author: Thomas Flemming, tf@ttqv.com
25 // Copyright (c) 2001, Thomas Flemming, tf@ttqv.com
27 // Permission is hereby granted, free of charge, to any person obtaining a
28 // copy of this software and associated documentation files (the "Software"),
29 // to deal in the Software without restriction, including without limitation
30 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
31 // and/or sell copies of the Software, and to permit persons to whom the
32 // Software is furnished to do so, subject to the following conditions:
34 // The above copyright notice and this permission notice shall be included
35 // in all copies or substantial portions of the Software.
37 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
38 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
40 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
42 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
43 // DEALINGS IN THE SOFTWARE.
45 #ifndef BOOST_GEOMETRY_PROJECTIONS_KROVAK_HPP
46 #define BOOST_GEOMETRY_PROJECTIONS_KROVAK_HPP
48 #include <boost/geometry/srs/projections/impl/base_static.hpp>
49 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
50 #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
51 #include <boost/geometry/srs/projections/impl/pj_param.hpp>
52 #include <boost/geometry/srs/projections/impl/projects.hpp>
54 namespace boost { namespace geometry
59 #ifndef DOXYGEN_NO_DETAIL
60 namespace detail { namespace krovak
62 static double epsilon = 1e-15;
63 static double S45 = 0.785398163397448; /* 45 deg */
64 static double S90 = 1.570796326794896; /* 90 deg */
65 static double UQ = 1.04216856380474; /* DU(2, 59, 42, 42.69689) */
66 static double S0 = 1.37008346281555; /* Latitude of pseudo standard parallel 78deg 30'00" N */
67 /* Not sure at all of the appropriate number for max_iter... */
68 static int max_iter = 100;
82 NOTES: According to EPSG the full Krovak projection method should have
83 the following parameters. Within PROJ.4 the azimuth, and pseudo
84 standard parallel are hardcoded in the algorithm and can't be
85 altered from outside. The others all have defaults to match the
86 common usage with Krovak projection.
88 lat_0 = latitude of centre of the projection
90 lon_0 = longitude of centre of the projection
92 ** = azimuth (true) of the centre line passing through the centre of the projection
94 ** = latitude of pseudo standard parallel
96 k = scale factor on the pseudo standard parallel
98 x_0 = False Easting of the centre of the projection at the apex of the cone
100 y_0 = False Northing of the centre of the projection at the apex of the cone
104 template <typename T, typename Parameters>
105 struct base_krovak_ellipsoid
107 par_krovak<T> m_proj_parm;
109 // FORWARD(e_forward) ellipsoid
110 // Project coordinates from geographic (lon, lat) to cartesian (x, y)
111 inline void fwd(Parameters const& par, T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
113 T gfi, u, deltav, s, d, eps, rho;
115 gfi = math::pow( (T(1) + par.e * sin(lp_lat)) / (T(1) - par.e * sin(lp_lat)), this->m_proj_parm.alpha * par.e / T(2));
117 u = 2. * (atan(this->m_proj_parm.k * math::pow( tan(lp_lat / T(2) + S45), this->m_proj_parm.alpha) / gfi)-S45);
118 deltav = -lp_lon * this->m_proj_parm.alpha;
120 s = asin(cos(this->m_proj_parm.ad) * sin(u) + sin(this->m_proj_parm.ad) * cos(u) * cos(deltav));
121 d = asin(cos(u) * sin(deltav) / cos(s));
123 eps = this->m_proj_parm.n * d;
124 rho = this->m_proj_parm.rho0 * math::pow(tan(S0 / T(2) + S45) , this->m_proj_parm.n) / math::pow(tan(s / T(2) + S45) , this->m_proj_parm.n);
126 xy_y = rho * cos(eps);
127 xy_x = rho * sin(eps);
129 xy_y *= this->m_proj_parm.czech;
130 xy_x *= this->m_proj_parm.czech;
133 // INVERSE(e_inverse) ellipsoid
134 // Project coordinates from cartesian (x, y) to geographic (lon, lat)
135 inline void inv(Parameters const& par, T xy_x, T xy_y, T& lp_lon, T& lp_lat) const
137 T u, deltav, s, d, eps, rho, fi1, xy0;
140 // TODO: replace with std::swap()
145 xy_x *= this->m_proj_parm.czech;
146 xy_y *= this->m_proj_parm.czech;
148 rho = sqrt(xy_x * xy_x + xy_y * xy_y);
149 eps = atan2(xy_y, xy_x);
152 s = T(2) * (atan(math::pow(this->m_proj_parm.rho0 / rho, T(1) / this->m_proj_parm.n) * tan(S0 / T(2) + S45)) - S45);
154 u = asin(cos(this->m_proj_parm.ad) * sin(s) - sin(this->m_proj_parm.ad) * cos(s) * cos(d));
155 deltav = asin(cos(s) * sin(d) / cos(u));
157 lp_lon = par.lam0 - deltav / this->m_proj_parm.alpha;
159 /* ITERATION FOR lp_lat */
162 for (i = max_iter; i ; --i) {
163 lp_lat = T(2) * ( atan( math::pow( this->m_proj_parm.k, T(-1) / this->m_proj_parm.alpha) *
164 math::pow( tan(u / T(2) + S45) , T(1) / this->m_proj_parm.alpha) *
165 math::pow( (T(1) + par.e * sin(fi1)) / (T(1) - par.e * sin(fi1)) , par.e / T(2))
168 if (fabs(fi1 - lp_lat) < epsilon)
173 BOOST_THROW_EXCEPTION( projection_exception(error_non_convergent) );
178 static inline std::string get_name()
180 return "krovak_ellipsoid";
186 template <typename Params, typename Parameters, typename T>
187 inline void setup_krovak(Params const& params, Parameters& par, par_krovak<T>& proj_parm)
191 /* we want Bessel as fixed ellipsoid */
193 par.es = 0.006674372230614;
194 par.e = sqrt(par.es);
196 /* if latitude of projection center is not set, use 49d30'N */
197 if (!pj_param_exists<srs::spar::lat_0>(params, "lat_0", srs::dpar::lat_0))
198 par.phi0 = 0.863937979737193;
200 /* if center long is not set use 42d30'E of Ferro - 17d40' for Ferro */
201 /* that will correspond to using longitudes relative to greenwich */
202 /* as input and output, instead of lat/long relative to Ferro */
203 if (!pj_param_exists<srs::spar::lon_0>(params, "lon_0", srs::dpar::lon_0))
204 par.lam0 = 0.7417649320975901 - 0.308341501185665;
206 /* if scale not set default to 0.9999 */
207 if (!pj_param_exists<srs::spar::k>(params, "k", srs::dpar::k))
211 if( !pj_param_exists<srs::spar::czech>(params, "czech", srs::dpar::czech) )
212 proj_parm.czech = -1;
214 /* Set up shared parameters between forward and inverse */
215 proj_parm.alpha = sqrt(T(1) + (par.es * math::pow(cos(par.phi0), 4)) / (T(1) - par.es));
216 u0 = asin(sin(par.phi0) / proj_parm.alpha);
217 g = math::pow( (T(1) + par.e * sin(par.phi0)) / (T(1) - par.e * sin(par.phi0)) , proj_parm.alpha * par.e / T(2) );
218 proj_parm.k = tan( u0 / 2. + S45) / math::pow(tan(par.phi0 / T(2) + S45) , proj_parm.alpha) * g;
219 n0 = sqrt(T(1) - par.es) / (T(1) - par.es * math::pow(sin(par.phi0), 2));
220 proj_parm.n = sin(S0);
221 proj_parm.rho0 = par.k0 * n0 / tan(S0);
222 proj_parm.ad = S90 - UQ;
225 }} // namespace detail::krovak
229 \brief Krovak projection
231 \tparam Geographic latlong point type
232 \tparam Cartesian xy point type
233 \tparam Parameters parameter type
234 \par Projection characteristics
237 \par Projection parameters
238 - lat_ts: Latitude of true scale (degrees)
239 - lat_0: Latitude of origin
240 - lon_0: Central meridian
241 - k: Scale factor on the pseudo standard parallel
243 \image html ex_krovak.gif
245 template <typename T, typename Parameters>
246 struct krovak_ellipsoid : public detail::krovak::base_krovak_ellipsoid<T, Parameters>
248 template <typename Params>
249 inline krovak_ellipsoid(Params const& params, Parameters & par)
251 detail::krovak::setup_krovak(params, par, this->m_proj_parm);
255 #ifndef DOXYGEN_NO_DETAIL
260 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_krovak, krovak_ellipsoid)
263 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(krovak_entry, krovak_ellipsoid)
265 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(krovak_init)
267 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(krovak, krovak_entry)
270 } // namespace detail
273 } // namespace projections
275 }} // namespace boost::geometry
277 #endif // BOOST_GEOMETRY_PROJECTIONS_KROVAK_HPP