mod_ster.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  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. // Permission is hereby granted, free of charge, to any person obtaining a
  16. // copy of this software and associated documentation files (the "Software"),
  17. // to deal in the Software without restriction, including without limitation
  18. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  19. // and/or sell copies of the Software, and to permit persons to whom the
  20. // Software is furnished to do so, subject to the following conditions:
  21. // The above copyright notice and this permission notice shall be included
  22. // in all copies or substantial portions of the Software.
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  24. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  25. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  26. // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  27. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  28. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  29. // DEALINGS IN THE SOFTWARE.
  30. #ifndef BOOST_GEOMETRY_PROJECTIONS_MOD_STER_HPP
  31. #define BOOST_GEOMETRY_PROJECTIONS_MOD_STER_HPP
  32. #include <boost/geometry/util/math.hpp>
  33. #include <boost/math/special_functions/hypot.hpp>
  34. #include <boost/geometry/srs/projections/impl/base_static.hpp>
  35. #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
  36. #include <boost/geometry/srs/projections/impl/projects.hpp>
  37. #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
  38. #include <boost/geometry/srs/projections/impl/aasincos.hpp>
  39. #include <boost/geometry/srs/projections/impl/pj_zpoly1.hpp>
  40. namespace boost { namespace geometry
  41. {
  42. namespace projections
  43. {
  44. #ifndef DOXYGEN_NO_DETAIL
  45. namespace detail { namespace mod_ster
  46. {
  47. static const double epsilon = 1e-12;
  48. template <typename T>
  49. struct par_mod_ster
  50. {
  51. pj_complex<T> *zcoeff;
  52. T cchio, schio;
  53. int n;
  54. };
  55. /* based upon Snyder and Linck, USGS-NMD */
  56. // template class, using CRTP to implement forward/inverse
  57. template <typename T, typename Parameters>
  58. struct base_mod_ster_ellipsoid
  59. : public base_t_fi<base_mod_ster_ellipsoid<T, Parameters>, T, Parameters>
  60. {
  61. par_mod_ster<T> m_proj_parm;
  62. inline base_mod_ster_ellipsoid(const Parameters& par)
  63. : base_t_fi<base_mod_ster_ellipsoid<T, Parameters>, T, Parameters>(*this, par)
  64. {}
  65. // FORWARD(e_forward) ellipsoid
  66. // Project coordinates from geographic (lon, lat) to cartesian (x, y)
  67. inline void fwd(T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
  68. {
  69. static const T half_pi = detail::half_pi<T>();
  70. T sinlon, coslon, esphi, chi, schi, cchi, s;
  71. pj_complex<T> p;
  72. sinlon = sin(lp_lon);
  73. coslon = cos(lp_lon);
  74. esphi = this->m_par.e * sin(lp_lat);
  75. chi = 2. * atan(tan((half_pi + lp_lat) * .5) *
  76. math::pow((T(1) - esphi) / (T(1) + esphi), this->m_par.e * T(0.5))) - half_pi;
  77. schi = sin(chi);
  78. cchi = cos(chi);
  79. s = 2. / (1. + this->m_proj_parm.schio * schi + this->m_proj_parm.cchio * cchi * coslon);
  80. p.r = s * cchi * sinlon;
  81. p.i = s * (this->m_proj_parm.cchio * schi - this->m_proj_parm.schio * cchi * coslon);
  82. p = pj_zpoly1(p, this->m_proj_parm.zcoeff, this->m_proj_parm.n);
  83. xy_x = p.r;
  84. xy_y = p.i;
  85. }
  86. // INVERSE(e_inverse) ellipsoid
  87. // Project coordinates from cartesian (x, y) to geographic (lon, lat)
  88. inline void inv(T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
  89. {
  90. static const T half_pi = detail::half_pi<T>();
  91. int nn;
  92. pj_complex<T> p, fxy, fpxy, dp;
  93. T den, rh = 0, z, sinz = 0, cosz = 0, chi, phi = 0, dphi, esphi;
  94. p.r = xy_x;
  95. p.i = xy_y;
  96. for (nn = 20; nn ;--nn) {
  97. fxy = pj_zpolyd1(p, this->m_proj_parm.zcoeff, this->m_proj_parm.n, &fpxy);
  98. fxy.r -= xy_x;
  99. fxy.i -= xy_y;
  100. den = fpxy.r * fpxy.r + fpxy.i * fpxy.i;
  101. dp.r = -(fxy.r * fpxy.r + fxy.i * fpxy.i) / den;
  102. dp.i = -(fxy.i * fpxy.r - fxy.r * fpxy.i) / den;
  103. p.r += dp.r;
  104. p.i += dp.i;
  105. if ((fabs(dp.r) + fabs(dp.i)) <= epsilon)
  106. break;
  107. }
  108. if (nn) {
  109. rh = boost::math::hypot(p.r, p.i);
  110. z = 2. * atan(.5 * rh);
  111. sinz = sin(z);
  112. cosz = cos(z);
  113. lp_lon = this->m_par.lam0;
  114. if (fabs(rh) <= epsilon) {
  115. /* if we end up here input coordinates were (0,0).
  116. * pj_inv() adds P->lam0 to lp.lam, this way we are
  117. * sure to get the correct offset */
  118. lp_lon = 0.0;
  119. lp_lat = this->m_par.phi0;
  120. return;
  121. }
  122. chi = aasin(cosz * this->m_proj_parm.schio + p.i * sinz * this->m_proj_parm.cchio / rh);
  123. phi = chi;
  124. for (nn = 20; nn ;--nn) {
  125. esphi = this->m_par.e * sin(phi);
  126. dphi = 2. * atan(tan((half_pi + chi) * .5) *
  127. math::pow((T(1) + esphi) / (T(1) - esphi), this->m_par.e * T(0.5))) - half_pi - phi;
  128. phi += dphi;
  129. if (fabs(dphi) <= epsilon)
  130. break;
  131. }
  132. }
  133. if (nn) {
  134. lp_lat = phi;
  135. lp_lon = atan2(p.r * sinz, rh * this->m_proj_parm.cchio * cosz - p.i *
  136. this->m_proj_parm.schio * sinz);
  137. } else
  138. lp_lon = lp_lat = HUGE_VAL;
  139. }
  140. static inline std::string get_name()
  141. {
  142. return "mod_ster_ellipsoid";
  143. }
  144. };
  145. template <typename Parameters, typename T>
  146. inline void setup(Parameters& par, par_mod_ster<T>& proj_parm) /* general initialization */
  147. {
  148. static T const half_pi = detail::half_pi<T>();
  149. T esphi, chio;
  150. if (par.es != 0.0) {
  151. esphi = par.e * sin(par.phi0);
  152. chio = 2. * atan(tan((half_pi + par.phi0) * .5) *
  153. math::pow((T(1) - esphi) / (T(1) + esphi), par.e * T(0.5))) - half_pi;
  154. } else
  155. chio = par.phi0;
  156. proj_parm.schio = sin(chio);
  157. proj_parm.cchio = cos(chio);
  158. }
  159. /* Miller Oblated Stereographic */
  160. template <typename Parameters, typename T>
  161. inline void setup_mil_os(Parameters& par, par_mod_ster<T>& proj_parm)
  162. {
  163. static const T d2r = geometry::math::d2r<T>();
  164. static pj_complex<T> AB[] = {
  165. {0.924500, 0.},
  166. {0., 0.},
  167. {0.019430, 0.}
  168. };
  169. proj_parm.n = 2;
  170. par.lam0 = d2r * 20.;
  171. par.phi0 = d2r * 18.;
  172. proj_parm.zcoeff = AB;
  173. par.es = 0.;
  174. setup(par, proj_parm);
  175. }
  176. /* Lee Oblated Stereographic */
  177. template <typename Parameters, typename T>
  178. inline void setup_lee_os(Parameters& par, par_mod_ster<T>& proj_parm)
  179. {
  180. static const T d2r = geometry::math::d2r<T>();
  181. static pj_complex<T> AB[] = {
  182. { 0.721316, 0.},
  183. { 0., 0.},
  184. {-0.0088162, -0.00617325}
  185. };
  186. proj_parm.n = 2;
  187. par.lam0 = d2r * -165.;
  188. par.phi0 = d2r * -10.;
  189. proj_parm.zcoeff = AB;
  190. par.es = 0.;
  191. setup(par, proj_parm);
  192. }
  193. // Mod. Stererographics of 48 U.S.
  194. template <typename Parameters, typename T>
  195. inline void setup_gs48(Parameters& par, par_mod_ster<T>& proj_parm)
  196. {
  197. static const T d2r = geometry::math::d2r<T>();
  198. static pj_complex<T> AB[] = { /* 48 United States */
  199. { 0.98879, 0.},
  200. { 0., 0.},
  201. {-0.050909, 0.},
  202. { 0., 0.},
  203. { 0.075528, 0.}
  204. };
  205. proj_parm.n = 4;
  206. par.lam0 = d2r * -96.;
  207. par.phi0 = d2r * -39.;
  208. proj_parm.zcoeff = AB;
  209. par.es = 0.;
  210. par.a = 6370997.;
  211. setup(par, proj_parm);
  212. }
  213. // Mod. Stererographics of Alaska
  214. template <typename Parameters, typename T>
  215. inline void setup_alsk(Parameters& par, par_mod_ster<T>& proj_parm)
  216. {
  217. static const T d2r = geometry::math::d2r<T>();
  218. static pj_complex<T> ABe[] = { /* Alaska ellipsoid */
  219. { .9945303, 0.},
  220. { .0052083, -.0027404},
  221. { .0072721, .0048181},
  222. {-.0151089, -.1932526},
  223. { .0642675, -.1381226},
  224. { .3582802, -.2884586}
  225. };
  226. static pj_complex<T> ABs[] = { /* Alaska sphere */
  227. { .9972523, 0.},
  228. { .0052513, -.0041175},
  229. { .0074606, .0048125},
  230. {-.0153783, -.1968253},
  231. { .0636871, -.1408027},
  232. { .3660976, -.2937382}
  233. };
  234. proj_parm.n = 5;
  235. par.lam0 = d2r * -152.;
  236. par.phi0 = d2r * 64.;
  237. if (par.es != 0.0) { /* fixed ellipsoid/sphere */
  238. proj_parm.zcoeff = ABe;
  239. par.a = 6378206.4;
  240. par.e = sqrt(par.es = 0.00676866);
  241. } else {
  242. proj_parm.zcoeff = ABs;
  243. par.a = 6370997.;
  244. }
  245. setup(par, proj_parm);
  246. }
  247. // Mod. Stererographics of 50 U.S.
  248. template <typename Parameters, typename T>
  249. inline void setup_gs50(Parameters& par, par_mod_ster<T>& proj_parm)
  250. {
  251. static const T d2r = geometry::math::d2r<T>();
  252. static pj_complex<T> ABe[] = { /* GS50 ellipsoid */
  253. { .9827497, 0.},
  254. { .0210669, .0053804},
  255. {-.1031415, -.0571664},
  256. {-.0323337, -.0322847},
  257. { .0502303, .1211983},
  258. { .0251805, .0895678},
  259. {-.0012315, -.1416121},
  260. { .0072202, -.1317091},
  261. {-.0194029, .0759677},
  262. {-.0210072, .0834037}
  263. };
  264. static pj_complex<T> ABs[] = { /* GS50 sphere */
  265. { .9842990, 0.},
  266. { .0211642, .0037608},
  267. {-.1036018, -.0575102},
  268. {-.0329095, -.0320119},
  269. { .0499471, .1223335},
  270. { .0260460, .0899805},
  271. { .0007388, -.1435792},
  272. { .0075848, -.1334108},
  273. {-.0216473, .0776645},
  274. {-.0225161, .0853673}
  275. };
  276. proj_parm.n = 9;
  277. par.lam0 = d2r * -120.;
  278. par.phi0 = d2r * 45.;
  279. if (par.es != 0.0) { /* fixed ellipsoid/sphere */
  280. proj_parm.zcoeff = ABe;
  281. par.a = 6378206.4;
  282. par.e = sqrt(par.es = 0.00676866);
  283. } else {
  284. proj_parm.zcoeff = ABs;
  285. par.a = 6370997.;
  286. }
  287. setup(par, proj_parm);
  288. }
  289. }} // namespace detail::mod_ster
  290. #endif // doxygen
  291. /*!
  292. \brief Miller Oblated Stereographic projection
  293. \ingroup projections
  294. \tparam Geographic latlong point type
  295. \tparam Cartesian xy point type
  296. \tparam Parameters parameter type
  297. \par Projection characteristics
  298. - Azimuthal (mod)
  299. \par Example
  300. \image html ex_mil_os.gif
  301. */
  302. template <typename T, typename Parameters>
  303. struct mil_os_ellipsoid : public detail::mod_ster::base_mod_ster_ellipsoid<T, Parameters>
  304. {
  305. template <typename Params>
  306. inline mil_os_ellipsoid(Params const& , Parameters const& par)
  307. : detail::mod_ster::base_mod_ster_ellipsoid<T, Parameters>(par)
  308. {
  309. detail::mod_ster::setup_mil_os(this->m_par, this->m_proj_parm);
  310. }
  311. };
  312. /*!
  313. \brief Lee Oblated Stereographic projection
  314. \ingroup projections
  315. \tparam Geographic latlong point type
  316. \tparam Cartesian xy point type
  317. \tparam Parameters parameter type
  318. \par Projection characteristics
  319. - Azimuthal (mod)
  320. \par Example
  321. \image html ex_lee_os.gif
  322. */
  323. template <typename T, typename Parameters>
  324. struct lee_os_ellipsoid : public detail::mod_ster::base_mod_ster_ellipsoid<T, Parameters>
  325. {
  326. template <typename Params>
  327. inline lee_os_ellipsoid(Params const& , Parameters const& par)
  328. : detail::mod_ster::base_mod_ster_ellipsoid<T, Parameters>(par)
  329. {
  330. detail::mod_ster::setup_lee_os(this->m_par, this->m_proj_parm);
  331. }
  332. };
  333. /*!
  334. \brief Mod. Stererographics of 48 U.S. projection
  335. \ingroup projections
  336. \tparam Geographic latlong point type
  337. \tparam Cartesian xy point type
  338. \tparam Parameters parameter type
  339. \par Projection characteristics
  340. - Azimuthal (mod)
  341. \par Example
  342. \image html ex_gs48.gif
  343. */
  344. template <typename T, typename Parameters>
  345. struct gs48_ellipsoid : public detail::mod_ster::base_mod_ster_ellipsoid<T, Parameters>
  346. {
  347. template <typename Params>
  348. inline gs48_ellipsoid(Params const& , Parameters const& par)
  349. : detail::mod_ster::base_mod_ster_ellipsoid<T, Parameters>(par)
  350. {
  351. detail::mod_ster::setup_gs48(this->m_par, this->m_proj_parm);
  352. }
  353. };
  354. /*!
  355. \brief Mod. Stererographics of Alaska projection
  356. \ingroup projections
  357. \tparam Geographic latlong point type
  358. \tparam Cartesian xy point type
  359. \tparam Parameters parameter type
  360. \par Projection characteristics
  361. - Azimuthal (mod)
  362. \par Example
  363. \image html ex_alsk.gif
  364. */
  365. template <typename T, typename Parameters>
  366. struct alsk_ellipsoid : public detail::mod_ster::base_mod_ster_ellipsoid<T, Parameters>
  367. {
  368. template <typename Params>
  369. inline alsk_ellipsoid(Params const& , Parameters const& par)
  370. : detail::mod_ster::base_mod_ster_ellipsoid<T, Parameters>(par)
  371. {
  372. detail::mod_ster::setup_alsk(this->m_par, this->m_proj_parm);
  373. }
  374. };
  375. /*!
  376. \brief Mod. Stererographics of 50 U.S. projection
  377. \ingroup projections
  378. \tparam Geographic latlong point type
  379. \tparam Cartesian xy point type
  380. \tparam Parameters parameter type
  381. \par Projection characteristics
  382. - Azimuthal (mod)
  383. \par Example
  384. \image html ex_gs50.gif
  385. */
  386. template <typename T, typename Parameters>
  387. struct gs50_ellipsoid : public detail::mod_ster::base_mod_ster_ellipsoid<T, Parameters>
  388. {
  389. template <typename Params>
  390. inline gs50_ellipsoid(Params const& , Parameters const& par)
  391. : detail::mod_ster::base_mod_ster_ellipsoid<T, Parameters>(par)
  392. {
  393. detail::mod_ster::setup_gs50(this->m_par, this->m_proj_parm);
  394. }
  395. };
  396. #ifndef DOXYGEN_NO_DETAIL
  397. namespace detail
  398. {
  399. // Static projection
  400. BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::spar::proj_mil_os, mil_os_ellipsoid, mil_os_ellipsoid)
  401. BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::spar::proj_lee_os, lee_os_ellipsoid, lee_os_ellipsoid)
  402. BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::spar::proj_gs48, gs48_ellipsoid, gs48_ellipsoid)
  403. BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::spar::proj_alsk, alsk_ellipsoid, alsk_ellipsoid)
  404. BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::spar::proj_gs50, gs50_ellipsoid, gs50_ellipsoid)
  405. // Factory entry(s)
  406. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(mil_os_entry, mil_os_ellipsoid)
  407. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(lee_os_entry, lee_os_ellipsoid)
  408. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(gs48_entry, gs48_ellipsoid)
  409. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(alsk_entry, alsk_ellipsoid)
  410. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(gs50_entry, gs50_ellipsoid)
  411. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(mod_ster_init)
  412. {
  413. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(mil_os, mil_os_entry)
  414. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(lee_os, lee_os_entry)
  415. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(gs48, gs48_entry)
  416. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(alsk, alsk_entry)
  417. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(gs50, gs50_entry)
  418. }
  419. } // namespace detail
  420. #endif // doxygen
  421. } // namespace projections
  422. }} // namespace boost::geometry
  423. #endif // BOOST_GEOMETRY_PROJECTIONS_MOD_STER_HPP