krovak.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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.
  4. // Modifications copyright (c) 2017-2018, 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 class, using CRTP to implement forward/inverse
  80. template <typename T, typename Parameters>
  81. struct base_krovak_ellipsoid
  82. : public base_t_fi<base_krovak_ellipsoid<T, Parameters>, T, Parameters>
  83. {
  84. par_krovak<T> m_proj_parm;
  85. inline base_krovak_ellipsoid(const Parameters& par)
  86. : base_t_fi<base_krovak_ellipsoid<T, Parameters>, T, Parameters>(*this, par)
  87. {}
  88. // FORWARD(e_forward) ellipsoid
  89. // Project coordinates from geographic (lon, lat) to cartesian (x, y)
  90. inline void fwd(T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
  91. {
  92. T gfi, u, deltav, s, d, eps, rho;
  93. gfi = math::pow( (T(1) + this->m_par.e * sin(lp_lat)) / (T(1) - this->m_par.e * sin(lp_lat)), this->m_proj_parm.alpha * this->m_par.e / T(2));
  94. u = 2. * (atan(this->m_proj_parm.k * math::pow( tan(lp_lat / T(2) + S45), this->m_proj_parm.alpha) / gfi)-S45);
  95. deltav = -lp_lon * this->m_proj_parm.alpha;
  96. s = asin(cos(this->m_proj_parm.ad) * sin(u) + sin(this->m_proj_parm.ad) * cos(u) * cos(deltav));
  97. d = asin(cos(u) * sin(deltav) / cos(s));
  98. eps = this->m_proj_parm.n * d;
  99. 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);
  100. xy_y = rho * cos(eps);
  101. xy_x = rho * sin(eps);
  102. xy_y *= this->m_proj_parm.czech;
  103. xy_x *= this->m_proj_parm.czech;
  104. }
  105. // INVERSE(e_inverse) ellipsoid
  106. // Project coordinates from cartesian (x, y) to geographic (lon, lat)
  107. inline void inv(T xy_x, T xy_y, T& lp_lon, T& lp_lat) const
  108. {
  109. T u, deltav, s, d, eps, rho, fi1, xy0;
  110. int i;
  111. // TODO: replace with std::swap()
  112. xy0 = xy_x;
  113. xy_x = xy_y;
  114. xy_y = xy0;
  115. xy_x *= this->m_proj_parm.czech;
  116. xy_y *= this->m_proj_parm.czech;
  117. rho = sqrt(xy_x * xy_x + xy_y * xy_y);
  118. eps = atan2(xy_y, xy_x);
  119. d = eps / sin(S0);
  120. 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);
  121. u = asin(cos(this->m_proj_parm.ad) * sin(s) - sin(this->m_proj_parm.ad) * cos(s) * cos(d));
  122. deltav = asin(cos(s) * sin(d) / cos(u));
  123. lp_lon = this->m_par.lam0 - deltav / this->m_proj_parm.alpha;
  124. /* ITERATION FOR lp_lat */
  125. fi1 = u;
  126. for (i = max_iter; i ; --i) {
  127. lp_lat = T(2) * ( atan( math::pow( this->m_proj_parm.k, T(-1) / this->m_proj_parm.alpha) *
  128. math::pow( tan(u / T(2) + S45) , T(1) / this->m_proj_parm.alpha) *
  129. math::pow( (T(1) + this->m_par.e * sin(fi1)) / (T(1) - this->m_par.e * sin(fi1)) , this->m_par.e / T(2))
  130. ) - S45);
  131. if (fabs(fi1 - lp_lat) < epsilon)
  132. break;
  133. fi1 = lp_lat;
  134. }
  135. if( i == 0 )
  136. BOOST_THROW_EXCEPTION( projection_exception(error_non_convergent) );
  137. lp_lon -= this->m_par.lam0;
  138. }
  139. static inline std::string get_name()
  140. {
  141. return "krovak_ellipsoid";
  142. }
  143. };
  144. // Krovak
  145. template <typename Params, typename Parameters, typename T>
  146. inline void setup_krovak(Params const& params, Parameters& par, par_krovak<T>& proj_parm)
  147. {
  148. T u0, n0, g;
  149. /* we want Bessel as fixed ellipsoid */
  150. par.a = 6377397.155;
  151. par.es = 0.006674372230614;
  152. par.e = sqrt(par.es);
  153. /* if latitude of projection center is not set, use 49d30'N */
  154. if (!pj_param_exists<srs::spar::lat_0>(params, "lat_0", srs::dpar::lat_0))
  155. par.phi0 = 0.863937979737193;
  156. /* if center long is not set use 42d30'E of Ferro - 17d40' for Ferro */
  157. /* that will correspond to using longitudes relative to greenwich */
  158. /* as input and output, instead of lat/long relative to Ferro */
  159. if (!pj_param_exists<srs::spar::lon_0>(params, "lon_0", srs::dpar::lon_0))
  160. par.lam0 = 0.7417649320975901 - 0.308341501185665;
  161. /* if scale not set default to 0.9999 */
  162. if (!pj_param_exists<srs::spar::k>(params, "k", srs::dpar::k))
  163. par.k0 = 0.9999;
  164. proj_parm.czech = 1;
  165. if( !pj_param_exists<srs::spar::czech>(params, "czech", srs::dpar::czech) )
  166. proj_parm.czech = -1;
  167. /* Set up shared parameters between forward and inverse */
  168. proj_parm.alpha = sqrt(T(1) + (par.es * math::pow(cos(par.phi0), 4)) / (T(1) - par.es));
  169. u0 = asin(sin(par.phi0) / proj_parm.alpha);
  170. g = math::pow( (T(1) + par.e * sin(par.phi0)) / (T(1) - par.e * sin(par.phi0)) , proj_parm.alpha * par.e / T(2) );
  171. proj_parm.k = tan( u0 / 2. + S45) / math::pow(tan(par.phi0 / T(2) + S45) , proj_parm.alpha) * g;
  172. n0 = sqrt(T(1) - par.es) / (T(1) - par.es * math::pow(sin(par.phi0), 2));
  173. proj_parm.n = sin(S0);
  174. proj_parm.rho0 = par.k0 * n0 / tan(S0);
  175. proj_parm.ad = S90 - UQ;
  176. }
  177. }} // namespace detail::krovak
  178. #endif // doxygen
  179. /*!
  180. \brief Krovak projection
  181. \ingroup projections
  182. \tparam Geographic latlong point type
  183. \tparam Cartesian xy point type
  184. \tparam Parameters parameter type
  185. \par Projection characteristics
  186. - Pseudocylindrical
  187. - Ellipsoid
  188. \par Projection parameters
  189. - lat_ts: Latitude of true scale (degrees)
  190. - lat_0: Latitude of origin
  191. - lon_0: Central meridian
  192. - k: Scale factor on the pseudo standard parallel
  193. \par Example
  194. \image html ex_krovak.gif
  195. */
  196. template <typename T, typename Parameters>
  197. struct krovak_ellipsoid : public detail::krovak::base_krovak_ellipsoid<T, Parameters>
  198. {
  199. template <typename Params>
  200. inline krovak_ellipsoid(Params const& params, Parameters const& par)
  201. : detail::krovak::base_krovak_ellipsoid<T, Parameters>(par)
  202. {
  203. detail::krovak::setup_krovak(params, this->m_par, this->m_proj_parm);
  204. }
  205. };
  206. #ifndef DOXYGEN_NO_DETAIL
  207. namespace detail
  208. {
  209. // Static projection
  210. BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::spar::proj_krovak, krovak_ellipsoid, krovak_ellipsoid)
  211. // Factory entry(s)
  212. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(krovak_entry, krovak_ellipsoid)
  213. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(krovak_init)
  214. {
  215. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(krovak, krovak_entry)
  216. }
  217. } // namespace detail
  218. #endif // doxygen
  219. } // namespace projections
  220. }} // namespace boost::geometry
  221. #endif // BOOST_GEOMETRY_PROJECTIONS_KROVAK_HPP