mod_ster.hpp 20 KB

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