krovak.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. // Boost.Geometry - gis-projections (based on PROJ4)
  2. // Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2017, 2018, 2019.
  4. // Modifications copyright (c) 2017-2019, Oracle and/or its affiliates.
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle.
  6. // Use, modification and distribution is subject to the Boost Software License,
  7. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. // This file is converted from PROJ4, http://trac.osgeo.org/proj
  10. // PROJ4 is originally written by Gerald Evenden (then of the USGS)
  11. // PROJ4 is maintained by Frank Warmerdam
  12. // PROJ4 is converted to Boost.Geometry by Barend Gehrels
  13. // Last updated version of proj: 5.0.0
  14. // Original copyright notice:
  15. // Purpose: Implementation of the krovak (Krovak) projection.
  16. // Definition: http://www.ihsenergy.com/epsg/guid7.html#1.4.3
  17. // Author: Thomas Flemming, tf@ttqv.com
  18. // Copyright (c) 2001, Thomas Flemming, tf@ttqv.com
  19. // Permission is hereby granted, free of charge, to any person obtaining a
  20. // copy of this software and associated documentation files (the "Software"),
  21. // to deal in the Software without restriction, including without limitation
  22. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  23. // and/or sell copies of the Software, and to permit persons to whom the
  24. // Software is furnished to do so, subject to the following conditions:
  25. // The above copyright notice and this permission notice shall be included
  26. // in all copies or substantial portions of the Software.
  27. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  28. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  29. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  30. // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  31. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  32. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  33. // DEALINGS IN THE SOFTWARE.
  34. #ifndef BOOST_GEOMETRY_PROJECTIONS_KROVAK_HPP
  35. #define BOOST_GEOMETRY_PROJECTIONS_KROVAK_HPP
  36. #include <boost/geometry/srs/projections/impl/base_static.hpp>
  37. #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
  38. #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
  39. #include <boost/geometry/srs/projections/impl/pj_param.hpp>
  40. #include <boost/geometry/srs/projections/impl/projects.hpp>
  41. namespace boost { namespace geometry
  42. {
  43. namespace projections
  44. {
  45. #ifndef DOXYGEN_NO_DETAIL
  46. namespace detail { namespace krovak
  47. {
  48. static double epsilon = 1e-15;
  49. static double S45 = 0.785398163397448; /* 45 deg */
  50. static double S90 = 1.570796326794896; /* 90 deg */
  51. static double UQ = 1.04216856380474; /* DU(2, 59, 42, 42.69689) */
  52. static double S0 = 1.37008346281555; /* Latitude of pseudo standard parallel 78deg 30'00" N */
  53. /* Not sure at all of the appropriate number for max_iter... */
  54. static int max_iter = 100;
  55. template <typename T>
  56. struct par_krovak
  57. {
  58. T alpha;
  59. T k;
  60. T n;
  61. T rho0;
  62. T ad;
  63. int czech;
  64. };
  65. /**
  66. NOTES: According to EPSG the full Krovak projection method should have
  67. the following parameters. Within PROJ.4 the azimuth, and pseudo
  68. standard parallel are hardcoded in the algorithm and can't be
  69. altered from outside. The others all have defaults to match the
  70. common usage with Krovak projection.
  71. lat_0 = latitude of centre of the projection
  72. lon_0 = longitude of centre of the projection
  73. ** = azimuth (true) of the centre line passing through the centre of the projection
  74. ** = latitude of pseudo standard parallel
  75. k = scale factor on the pseudo standard parallel
  76. x_0 = False Easting of the centre of the projection at the apex of the cone
  77. y_0 = False Northing of the centre of the projection at the apex of the cone
  78. **/
  79. template <typename T, typename Parameters>
  80. struct base_krovak_ellipsoid
  81. {
  82. par_krovak<T> m_proj_parm;
  83. // FORWARD(e_forward) ellipsoid
  84. // Project coordinates from geographic (lon, lat) to cartesian (x, y)
  85. inline void fwd(Parameters const& par, T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
  86. {
  87. T gfi, u, deltav, s, d, eps, rho;
  88. 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));
  89. u = 2. * (atan(this->m_proj_parm.k * math::pow( tan(lp_lat / T(2) + S45), this->m_proj_parm.alpha) / gfi)-S45);
  90. deltav = -lp_lon * this->m_proj_parm.alpha;
  91. s = asin(cos(this->m_proj_parm.ad) * sin(u) + sin(this->m_proj_parm.ad) * cos(u) * cos(deltav));
  92. d = asin(cos(u) * sin(deltav) / cos(s));
  93. eps = this->m_proj_parm.n * d;
  94. 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);
  95. xy_y = rho * cos(eps);
  96. xy_x = rho * sin(eps);
  97. xy_y *= this->m_proj_parm.czech;
  98. xy_x *= this->m_proj_parm.czech;
  99. }
  100. // INVERSE(e_inverse) ellipsoid
  101. // Project coordinates from cartesian (x, y) to geographic (lon, lat)
  102. inline void inv(Parameters const& par, T xy_x, T xy_y, T& lp_lon, T& lp_lat) const
  103. {
  104. T u, deltav, s, d, eps, rho, fi1, xy0;
  105. int i;
  106. // TODO: replace with std::swap()
  107. xy0 = xy_x;
  108. xy_x = xy_y;
  109. xy_y = xy0;
  110. xy_x *= this->m_proj_parm.czech;
  111. xy_y *= this->m_proj_parm.czech;
  112. rho = sqrt(xy_x * xy_x + xy_y * xy_y);
  113. eps = atan2(xy_y, xy_x);
  114. d = eps / sin(S0);
  115. 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);
  116. u = asin(cos(this->m_proj_parm.ad) * sin(s) - sin(this->m_proj_parm.ad) * cos(s) * cos(d));
  117. deltav = asin(cos(s) * sin(d) / cos(u));
  118. lp_lon = par.lam0 - deltav / this->m_proj_parm.alpha;
  119. /* ITERATION FOR lp_lat */
  120. fi1 = u;
  121. for (i = max_iter; i ; --i) {
  122. lp_lat = T(2) * ( atan( math::pow( this->m_proj_parm.k, T(-1) / this->m_proj_parm.alpha) *
  123. math::pow( tan(u / T(2) + S45) , T(1) / this->m_proj_parm.alpha) *
  124. math::pow( (T(1) + par.e * sin(fi1)) / (T(1) - par.e * sin(fi1)) , par.e / T(2))
  125. ) - S45);
  126. if (fabs(fi1 - lp_lat) < epsilon)
  127. break;
  128. fi1 = lp_lat;
  129. }
  130. if( i == 0 )
  131. BOOST_THROW_EXCEPTION( projection_exception(error_non_convergent) );
  132. lp_lon -= par.lam0;
  133. }
  134. static inline std::string get_name()
  135. {
  136. return "krovak_ellipsoid";
  137. }
  138. };
  139. // Krovak
  140. template <typename Params, typename Parameters, typename T>
  141. inline void setup_krovak(Params const& params, Parameters& par, par_krovak<T>& proj_parm)
  142. {
  143. T u0, n0, g;
  144. /* we want Bessel as fixed ellipsoid */
  145. par.a = 6377397.155;
  146. par.es = 0.006674372230614;
  147. par.e = sqrt(par.es);
  148. /* if latitude of projection center is not set, use 49d30'N */
  149. if (!pj_param_exists<srs::spar::lat_0>(params, "lat_0", srs::dpar::lat_0))
  150. par.phi0 = 0.863937979737193;
  151. /* if center long is not set use 42d30'E of Ferro - 17d40' for Ferro */
  152. /* that will correspond to using longitudes relative to greenwich */
  153. /* as input and output, instead of lat/long relative to Ferro */
  154. if (!pj_param_exists<srs::spar::lon_0>(params, "lon_0", srs::dpar::lon_0))
  155. par.lam0 = 0.7417649320975901 - 0.308341501185665;
  156. /* if scale not set default to 0.9999 */
  157. if (!pj_param_exists<srs::spar::k>(params, "k", srs::dpar::k))
  158. par.k0 = 0.9999;
  159. proj_parm.czech = 1;
  160. if( !pj_param_exists<srs::spar::czech>(params, "czech", srs::dpar::czech) )
  161. proj_parm.czech = -1;
  162. /* Set up shared parameters between forward and inverse */
  163. proj_parm.alpha = sqrt(T(1) + (par.es * math::pow(cos(par.phi0), 4)) / (T(1) - par.es));
  164. u0 = asin(sin(par.phi0) / proj_parm.alpha);
  165. g = math::pow( (T(1) + par.e * sin(par.phi0)) / (T(1) - par.e * sin(par.phi0)) , proj_parm.alpha * par.e / T(2) );
  166. proj_parm.k = tan( u0 / 2. + S45) / math::pow(tan(par.phi0 / T(2) + S45) , proj_parm.alpha) * g;
  167. n0 = sqrt(T(1) - par.es) / (T(1) - par.es * math::pow(sin(par.phi0), 2));
  168. proj_parm.n = sin(S0);
  169. proj_parm.rho0 = par.k0 * n0 / tan(S0);
  170. proj_parm.ad = S90 - UQ;
  171. }
  172. }} // namespace detail::krovak
  173. #endif // doxygen
  174. /*!
  175. \brief Krovak projection
  176. \ingroup projections
  177. \tparam Geographic latlong point type
  178. \tparam Cartesian xy point type
  179. \tparam Parameters parameter type
  180. \par Projection characteristics
  181. - Pseudocylindrical
  182. - Ellipsoid
  183. \par Projection parameters
  184. - lat_ts: Latitude of true scale (degrees)
  185. - lat_0: Latitude of origin
  186. - lon_0: Central meridian
  187. - k: Scale factor on the pseudo standard parallel
  188. \par Example
  189. \image html ex_krovak.gif
  190. */
  191. template <typename T, typename Parameters>
  192. struct krovak_ellipsoid : public detail::krovak::base_krovak_ellipsoid<T, Parameters>
  193. {
  194. template <typename Params>
  195. inline krovak_ellipsoid(Params const& params, Parameters & par)
  196. {
  197. detail::krovak::setup_krovak(params, par, this->m_proj_parm);
  198. }
  199. };
  200. #ifndef DOXYGEN_NO_DETAIL
  201. namespace detail
  202. {
  203. // Static projection
  204. BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_krovak, krovak_ellipsoid)
  205. // Factory entry(s)
  206. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(krovak_entry, krovak_ellipsoid)
  207. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(krovak_init)
  208. {
  209. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(krovak, krovak_entry)
  210. }
  211. } // namespace detail
  212. #endif // doxygen
  213. } // namespace projections
  214. }} // namespace boost::geometry
  215. #endif // BOOST_GEOMETRY_PROJECTIONS_KROVAK_HPP