igh.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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_IGH_HPP
  31. #define BOOST_GEOMETRY_PROJECTIONS_IGH_HPP
  32. #include <boost/geometry/srs/projections/impl/base_static.hpp>
  33. #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
  34. #include <boost/geometry/srs/projections/impl/projects.hpp>
  35. #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
  36. #include <boost/geometry/srs/projections/proj/gn_sinu.hpp>
  37. #include <boost/geometry/srs/projections/proj/moll.hpp>
  38. #include <boost/geometry/util/math.hpp>
  39. #include <boost/shared_ptr.hpp>
  40. namespace boost { namespace geometry
  41. {
  42. namespace projections
  43. {
  44. #ifndef DOXYGEN_NO_DETAIL
  45. namespace detail { namespace igh
  46. {
  47. template <typename T>
  48. struct par_igh_zone
  49. {
  50. T x0;
  51. T y0;
  52. T lam0;
  53. };
  54. // NOTE: x0, y0, lam0 are not used in moll nor sinu projections
  55. // so it is a waste of memory to keep 12 copies of projections
  56. // with parameters as in the original Proj4.
  57. // TODO: It would be possible to further decrease the size of par_igh
  58. // because spherical sinu and moll has constant parameters.
  59. // TODO: Furthermore there is no need to store par_igh_zone parameters
  60. // since they are constant for zones. In both fwd() and inv() there are
  61. // parts of code dependent on specific zones (if statements) anyway
  62. // so these parameters could be hardcoded there instead of stored.
  63. template <typename T, typename Parameters>
  64. struct par_igh
  65. {
  66. moll_spheroid<T, Parameters> moll;
  67. sinu_spheroid<T, Parameters> sinu;
  68. par_igh_zone<T> zones[12];
  69. T dy0;
  70. // NOTE: The constructors of moll and sinu projections sets
  71. // par.es = 0
  72. template <typename Params>
  73. inline par_igh(Params const& params, Parameters & par)
  74. : moll(params, par)
  75. , sinu(params, par)
  76. {}
  77. inline void fwd(int zone, Parameters const& par, T const& lp_lon, T const& lp_lat, T & xy_x, T & xy_y) const
  78. {
  79. if (zone <= 2 || zone >= 9) // 1, 2, 9, 10, 11, 12
  80. moll.fwd(par, lp_lon, lp_lat, xy_x, xy_y);
  81. else // 3, 4, 5, 6, 7, 8
  82. sinu.fwd(par, lp_lon, lp_lat, xy_x, xy_y);
  83. }
  84. inline void inv(int zone, Parameters const& par, T const& xy_x, T const& xy_y, T & lp_lon, T & lp_lat) const
  85. {
  86. if (zone <= 2 || zone >= 9) // 1, 2, 9, 10, 11, 12
  87. moll.inv(par, xy_x, xy_y, lp_lon, lp_lat);
  88. else // 3, 4, 5, 6, 7, 8
  89. sinu.inv(par, xy_x, xy_y, lp_lon, lp_lat);
  90. }
  91. inline void set_zone(int zone, T const& x_0, T const& y_0, T const& lon_0)
  92. {
  93. zones[zone - 1].x0 = x_0;
  94. zones[zone - 1].y0 = y_0;
  95. zones[zone - 1].lam0 = lon_0;
  96. }
  97. inline par_igh_zone<T> const& get_zone(int zone) const
  98. {
  99. return zones[zone - 1];
  100. }
  101. };
  102. /* 40d 44' 11.8" [degrees] */
  103. template <typename T>
  104. inline T d4044118() { return (T(40) + T(44)/T(60.) + T(11.8)/T(3600.)) * geometry::math::d2r<T>(); }
  105. template <typename T>
  106. inline T d10() { return T(10) * geometry::math::d2r<T>(); }
  107. template <typename T>
  108. inline T d20() { return T(20) * geometry::math::d2r<T>(); }
  109. template <typename T>
  110. inline T d30() { return T(30) * geometry::math::d2r<T>(); }
  111. template <typename T>
  112. inline T d40() { return T(40) * geometry::math::d2r<T>(); }
  113. template <typename T>
  114. inline T d50() { return T(50) * geometry::math::d2r<T>(); }
  115. template <typename T>
  116. inline T d60() { return T(60) * geometry::math::d2r<T>(); }
  117. template <typename T>
  118. inline T d80() { return T(80) * geometry::math::d2r<T>(); }
  119. template <typename T>
  120. inline T d90() { return T(90) * geometry::math::d2r<T>(); }
  121. template <typename T>
  122. inline T d100() { return T(100) * geometry::math::d2r<T>(); }
  123. template <typename T>
  124. inline T d140() { return T(140) * geometry::math::d2r<T>(); }
  125. template <typename T>
  126. inline T d160() { return T(160) * geometry::math::d2r<T>(); }
  127. template <typename T>
  128. inline T d180() { return T(180) * geometry::math::d2r<T>(); }
  129. static const double epsilon = 1.e-10; // allow a little 'slack' on zone edge positions
  130. template <typename T, typename Parameters>
  131. struct base_igh_spheroid
  132. {
  133. par_igh<T, Parameters> m_proj_parm;
  134. template <typename Params>
  135. inline base_igh_spheroid(Params const& params, Parameters & par)
  136. : m_proj_parm(params, par)
  137. {}
  138. // FORWARD(s_forward) spheroid
  139. // Project coordinates from geographic (lon, lat) to cartesian (x, y)
  140. inline void fwd(Parameters const& par, T lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
  141. {
  142. static const T d4044118 = igh::d4044118<T>();
  143. static const T d20 = igh::d20<T>();
  144. static const T d40 = igh::d40<T>();
  145. static const T d80 = igh::d80<T>();
  146. static const T d100 = igh::d100<T>();
  147. int z;
  148. if (lp_lat >= d4044118) { // 1|2
  149. z = (lp_lon <= -d40 ? 1: 2);
  150. }
  151. else if (lp_lat >= 0) { // 3|4
  152. z = (lp_lon <= -d40 ? 3: 4);
  153. }
  154. else if (lp_lat >= -d4044118) { // 5|6|7|8
  155. if (lp_lon <= -d100) z = 5; // 5
  156. else if (lp_lon <= -d20) z = 6; // 6
  157. else if (lp_lon <= d80) z = 7; // 7
  158. else z = 8; // 8
  159. }
  160. else { // 9|10|11|12
  161. if (lp_lon <= -d100) z = 9; // 9
  162. else if (lp_lon <= -d20) z = 10; // 10
  163. else if (lp_lon <= d80) z = 11; // 11
  164. else z = 12; // 12
  165. }
  166. lp_lon -= this->m_proj_parm.get_zone(z).lam0;
  167. this->m_proj_parm.fwd(z, par, lp_lon, lp_lat, xy_x, xy_y);
  168. xy_x += this->m_proj_parm.get_zone(z).x0;
  169. xy_y += this->m_proj_parm.get_zone(z).y0;
  170. }
  171. // INVERSE(s_inverse) spheroid
  172. // Project coordinates from cartesian (x, y) to geographic (lon, lat)
  173. inline void inv(Parameters const& par, T xy_x, T xy_y, T& lp_lon, T& lp_lat) const
  174. {
  175. static const T d4044118 = igh::d4044118<T>();
  176. static const T d10 = igh::d10<T>();
  177. static const T d20 = igh::d20<T>();
  178. static const T d40 = igh::d40<T>();
  179. static const T d50 = igh::d50<T>();
  180. static const T d60 = igh::d60<T>();
  181. static const T d80 = igh::d80<T>();
  182. static const T d90 = igh::d90<T>();
  183. static const T d100 = igh::d100<T>();
  184. static const T d160 = igh::d160<T>();
  185. static const T d180 = igh::d180<T>();
  186. static const T c2 = 2.0;
  187. const T y90 = this->m_proj_parm.dy0 + sqrt(c2); // lt=90 corresponds to y=y0+sqrt(2.0)
  188. int z = 0;
  189. if (xy_y > y90+epsilon || xy_y < -y90+epsilon) // 0
  190. z = 0;
  191. else if (xy_y >= d4044118) // 1|2
  192. z = (xy_x <= -d40? 1: 2);
  193. else if (xy_y >= 0) // 3|4
  194. z = (xy_x <= -d40? 3: 4);
  195. else if (xy_y >= -d4044118) { // 5|6|7|8
  196. if (xy_x <= -d100) z = 5; // 5
  197. else if (xy_x <= -d20) z = 6; // 6
  198. else if (xy_x <= d80) z = 7; // 7
  199. else z = 8; // 8
  200. }
  201. else { // 9|10|11|12
  202. if (xy_x <= -d100) z = 9; // 9
  203. else if (xy_x <= -d20) z = 10; // 10
  204. else if (xy_x <= d80) z = 11; // 11
  205. else z = 12; // 12
  206. }
  207. if (z)
  208. {
  209. int ok = 0;
  210. xy_x -= this->m_proj_parm.get_zone(z).x0;
  211. xy_y -= this->m_proj_parm.get_zone(z).y0;
  212. this->m_proj_parm.inv(z, par, xy_x, xy_y, lp_lon, lp_lat);
  213. lp_lon += this->m_proj_parm.get_zone(z).lam0;
  214. switch (z) {
  215. case 1: ok = (lp_lon >= -d180-epsilon && lp_lon <= -d40+epsilon) ||
  216. ((lp_lon >= -d40-epsilon && lp_lon <= -d10+epsilon) &&
  217. (lp_lat >= d60-epsilon && lp_lat <= d90+epsilon)); break;
  218. case 2: ok = (lp_lon >= -d40-epsilon && lp_lon <= d180+epsilon) ||
  219. ((lp_lon >= -d180-epsilon && lp_lon <= -d160+epsilon) &&
  220. (lp_lat >= d50-epsilon && lp_lat <= d90+epsilon)) ||
  221. ((lp_lon >= -d50-epsilon && lp_lon <= -d40+epsilon) &&
  222. (lp_lat >= d60-epsilon && lp_lat <= d90+epsilon)); break;
  223. case 3: ok = (lp_lon >= -d180-epsilon && lp_lon <= -d40+epsilon); break;
  224. case 4: ok = (lp_lon >= -d40-epsilon && lp_lon <= d180+epsilon); break;
  225. case 5: ok = (lp_lon >= -d180-epsilon && lp_lon <= -d100+epsilon); break;
  226. case 6: ok = (lp_lon >= -d100-epsilon && lp_lon <= -d20+epsilon); break;
  227. case 7: ok = (lp_lon >= -d20-epsilon && lp_lon <= d80+epsilon); break;
  228. case 8: ok = (lp_lon >= d80-epsilon && lp_lon <= d180+epsilon); break;
  229. case 9: ok = (lp_lon >= -d180-epsilon && lp_lon <= -d100+epsilon); break;
  230. case 10: ok = (lp_lon >= -d100-epsilon && lp_lon <= -d20+epsilon); break;
  231. case 11: ok = (lp_lon >= -d20-epsilon && lp_lon <= d80+epsilon); break;
  232. case 12: ok = (lp_lon >= d80-epsilon && lp_lon <= d180+epsilon); break;
  233. }
  234. z = (!ok? 0: z); // projectable?
  235. }
  236. // if (!z) pj_errno = -15; // invalid x or y
  237. if (!z) lp_lon = HUGE_VAL;
  238. if (!z) lp_lat = HUGE_VAL;
  239. }
  240. static inline std::string get_name()
  241. {
  242. return "igh_spheroid";
  243. }
  244. };
  245. // Interrupted Goode Homolosine
  246. template <typename Params, typename Parameters, typename T>
  247. inline void setup_igh(Params const& params, Parameters& par, par_igh<T, Parameters>& proj_parm)
  248. {
  249. static const T d0 = 0;
  250. static const T d4044118 = igh::d4044118<T>();
  251. static const T d20 = igh::d20<T>();
  252. static const T d30 = igh::d30<T>();
  253. static const T d60 = igh::d60<T>();
  254. static const T d100 = igh::d100<T>();
  255. static const T d140 = igh::d140<T>();
  256. static const T d160 = igh::d160<T>();
  257. /*
  258. Zones:
  259. -180 -40 180
  260. +--------------+-------------------------+ Zones 1,2,9,10,11 & 12:
  261. |1 |2 | Mollweide projection
  262. | | |
  263. +--------------+-------------------------+ Zones 3,4,5,6,7 & 8:
  264. |3 |4 | Sinusoidal projection
  265. | | |
  266. 0 +-------+------+-+-----------+-----------+
  267. |5 |6 |7 |8 |
  268. | | | | |
  269. +-------+--------+-----------+-----------+
  270. |9 |10 |11 |12 |
  271. | | | | |
  272. +-------+--------+-----------+-----------+
  273. -180 -100 -20 80 180
  274. */
  275. T lp_lam = 0, lp_phi = d4044118;
  276. T xy1_x, xy1_y;
  277. T xy3_x, xy3_y;
  278. // sinusoidal zones
  279. proj_parm.set_zone(3, -d100, d0, -d100);
  280. proj_parm.set_zone(4, d30, d0, d30);
  281. proj_parm.set_zone(5, -d160, d0, -d160);
  282. proj_parm.set_zone(6, -d60, d0, -d60);
  283. proj_parm.set_zone(7, d20, d0, d20);
  284. proj_parm.set_zone(8, d140, d0, d140);
  285. // mollweide zones
  286. proj_parm.set_zone(1, -d100, d0, -d100);
  287. // NOTE: x0, y0, lam0 are not used in moll nor sinu fwd
  288. // so the order of initialization doesn't matter that much.
  289. // But keep the original one from Proj4.
  290. // y0 ?
  291. proj_parm.fwd(1, par, lp_lam, lp_phi, xy1_x, xy1_y); // zone 1
  292. proj_parm.fwd(3, par, lp_lam, lp_phi, xy3_x, xy3_y); // zone 3
  293. // y0 + xy1_y = xy3_y for lt = 40d44'11.8"
  294. proj_parm.dy0 = xy3_y - xy1_y;
  295. proj_parm.zones[0].y0 = proj_parm.dy0; // zone 1
  296. // mollweide zones (cont'd)
  297. proj_parm.set_zone(2, d30, proj_parm.dy0, d30);
  298. proj_parm.set_zone(9, -d160, -proj_parm.dy0, -d160);
  299. proj_parm.set_zone(10, -d60, -proj_parm.dy0, -d60);
  300. proj_parm.set_zone(11, d20, -proj_parm.dy0, d20);
  301. proj_parm.set_zone(12, d140, -proj_parm.dy0, d140);
  302. // NOTE: Already done before in sinu and moll constructor
  303. //par.es = 0.;
  304. }
  305. }} // namespace detail::igh
  306. #endif // doxygen
  307. /*!
  308. \brief Interrupted Goode Homolosine projection
  309. \ingroup projections
  310. \tparam Geographic latlong point type
  311. \tparam Cartesian xy point type
  312. \tparam Parameters parameter type
  313. \par Projection characteristics
  314. - Pseudocylindrical
  315. - Spheroid
  316. \par Example
  317. \image html ex_igh.gif
  318. */
  319. template <typename T, typename Parameters>
  320. struct igh_spheroid : public detail::igh::base_igh_spheroid<T, Parameters>
  321. {
  322. template <typename Params>
  323. inline igh_spheroid(Params const& params, Parameters & par)
  324. : detail::igh::base_igh_spheroid<T, Parameters>(params, par)
  325. {
  326. detail::igh::setup_igh(params, par, this->m_proj_parm);
  327. }
  328. };
  329. #ifndef DOXYGEN_NO_DETAIL
  330. namespace detail
  331. {
  332. // Static projection
  333. BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_igh, igh_spheroid)
  334. // Factory entry(s)
  335. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(igh_entry, igh_spheroid)
  336. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(igh_init)
  337. {
  338. BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(igh, igh_entry)
  339. }
  340. } // namespace detail
  341. #endif // doxygen
  342. } // namespace projections
  343. }} // namespace boost::geometry
  344. #endif // BOOST_GEOMETRY_PROJECTIONS_IGH_HPP