mod_ster.hpp 18 KB

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