igh.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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_IGH_HPP
  31. #define BOOST_GEOMETRY_PROJECTIONS_IGH_HPP
  32. #include <boost/geometry/util/math.hpp>
  33. #include <boost/shared_ptr.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/proj/gn_sinu.hpp>
  39. #include <boost/geometry/srs/projections/proj/moll.hpp>
  40. namespace boost { namespace geometry
  41. {
  42. namespace srs { namespace par4
  43. {
  44. struct igh {}; // Interrupted Goode Homolosine
  45. }} //namespace srs::par4
  46. namespace projections
  47. {
  48. #ifndef DOXYGEN_NO_DETAIL
  49. namespace detail { namespace igh
  50. {
  51. // TODO: consider replacing dynamically created projections
  52. // with member objects
  53. template <typename T, typename Parameters>
  54. struct par_igh
  55. {
  56. boost::shared_ptr<base_v<T, Parameters> > pj[12];
  57. T dy0;
  58. };
  59. /* 40d 44' 11.8" [degrees] */
  60. template <typename T>
  61. inline T d4044118() { return (T(40) + T(44)/T(60.) + T(11.8)/T(3600.)) * geometry::math::d2r<T>(); }
  62. template <typename T>
  63. inline T d10() { return T(10) * geometry::math::d2r<T>(); }
  64. template <typename T>
  65. inline T d20() { return T(20) * geometry::math::d2r<T>(); }
  66. template <typename T>
  67. inline T d30() { return T(30) * geometry::math::d2r<T>(); }
  68. template <typename T>
  69. inline T d40() { return T(40) * geometry::math::d2r<T>(); }
  70. template <typename T>
  71. inline T d50() { return T(50) * geometry::math::d2r<T>(); }
  72. template <typename T>
  73. inline T d60() { return T(60) * geometry::math::d2r<T>(); }
  74. template <typename T>
  75. inline T d80() { return T(80) * geometry::math::d2r<T>(); }
  76. template <typename T>
  77. inline T d90() { return T(90) * geometry::math::d2r<T>(); }
  78. template <typename T>
  79. inline T d100() { return T(100) * geometry::math::d2r<T>(); }
  80. template <typename T>
  81. inline T d140() { return T(140) * geometry::math::d2r<T>(); }
  82. template <typename T>
  83. inline T d160() { return T(160) * geometry::math::d2r<T>(); }
  84. template <typename T>
  85. inline T d180() { return T(180) * geometry::math::d2r<T>(); }
  86. static const double epsilon = 1.e-10; // allow a little 'slack' on zone edge positions
  87. // Converted from #define SETUP(n, proj, x_0, y_0, lon_0)
  88. template <template <typename, typename> class Entry, typename Parameters, typename T>
  89. inline void do_setup(int n, Parameters const& par, par_igh<T, Parameters>& proj_parm,
  90. T const& x_0, T const& y_0,
  91. T const& lon_0)
  92. {
  93. // NOTE: in the original proj4 these projections are initialized
  94. // with zeroed parameters which could be done here as well instead
  95. // of initializing with parent projection's parameters.
  96. Entry<T, Parameters> entry;
  97. proj_parm.pj[n-1].reset(entry.create_new(par));
  98. proj_parm.pj[n-1]->mutable_params().x0 = x_0;
  99. proj_parm.pj[n-1]->mutable_params().y0 = y_0;
  100. proj_parm.pj[n-1]->mutable_params().lam0 = lon_0;
  101. }
  102. // template class, using CRTP to implement forward/inverse
  103. template <typename T, typename Parameters>
  104. struct base_igh_spheroid
  105. : public base_t_fi<base_igh_spheroid<T, Parameters>, T, Parameters>
  106. {
  107. par_igh<T, Parameters> m_proj_parm;
  108. inline base_igh_spheroid(const Parameters& par)
  109. : base_t_fi<base_igh_spheroid<T, Parameters>, T, Parameters>(*this, par)
  110. {}
  111. // FORWARD(s_forward) spheroid
  112. // Project coordinates from geographic (lon, lat) to cartesian (x, y)
  113. inline void fwd(T& lp_lon, T& lp_lat, T& xy_x, T& xy_y) const
  114. {
  115. static const T d4044118 = igh::d4044118<T>();
  116. static const T d20 = igh::d20<T>();
  117. static const T d40 = igh::d40<T>();
  118. static const T d80 = igh::d80<T>();
  119. static const T d100 = igh::d100<T>();
  120. int z;
  121. if (lp_lat >= d4044118) { // 1|2
  122. z = (lp_lon <= -d40 ? 1: 2);
  123. }
  124. else if (lp_lat >= 0) { // 3|4
  125. z = (lp_lon <= -d40 ? 3: 4);
  126. }
  127. else if (lp_lat >= -d4044118) { // 5|6|7|8
  128. if (lp_lon <= -d100) z = 5; // 5
  129. else if (lp_lon <= -d20) z = 6; // 6
  130. else if (lp_lon <= d80) z = 7; // 7
  131. else z = 8; // 8
  132. }
  133. else { // 9|10|11|12
  134. if (lp_lon <= -d100) z = 9; // 9
  135. else if (lp_lon <= -d20) z = 10; // 10
  136. else if (lp_lon <= d80) z = 11; // 11
  137. else z = 12; // 12
  138. }
  139. lp_lon -= this->m_proj_parm.pj[z-1]->params().lam0;
  140. this->m_proj_parm.pj[z-1]->fwd(lp_lon, lp_lat, xy_x, xy_y);
  141. xy_x += this->m_proj_parm.pj[z-1]->params().x0;
  142. xy_y += this->m_proj_parm.pj[z-1]->params().y0;
  143. }
  144. // INVERSE(s_inverse) spheroid
  145. // Project coordinates from cartesian (x, y) to geographic (lon, lat)
  146. inline void inv(T& xy_x, T& xy_y, T& lp_lon, T& lp_lat) const
  147. {
  148. static const T d4044118 = igh::d4044118<T>();
  149. static const T d10 = igh::d10<T>();
  150. static const T d20 = igh::d20<T>();
  151. static const T d40 = igh::d40<T>();
  152. static const T d50 = igh::d50<T>();
  153. static const T d60 = igh::d60<T>();
  154. static const T d80 = igh::d80<T>();
  155. static const T d90 = igh::d90<T>();
  156. static const T d100 = igh::d100<T>();
  157. static const T d160 = igh::d160<T>();
  158. static const T d180 = igh::d180<T>();
  159. static const T c2 = 2.0;
  160. const T y90 = this->m_proj_parm.dy0 + sqrt(c2); // lt=90 corresponds to y=y0+sqrt(2.0)
  161. int z = 0;
  162. if (xy_y > y90+epsilon || xy_y < -y90+epsilon) // 0
  163. z = 0;
  164. else if (xy_y >= d4044118) // 1|2
  165. z = (xy_x <= -d40? 1: 2);
  166. else if (xy_y >= 0) // 3|4
  167. z = (xy_x <= -d40? 3: 4);
  168. else if (xy_y >= -d4044118) { // 5|6|7|8
  169. if (xy_x <= -d100) z = 5; // 5
  170. else if (xy_x <= -d20) z = 6; // 6
  171. else if (xy_x <= d80) z = 7; // 7
  172. else z = 8; // 8
  173. }
  174. else { // 9|10|11|12
  175. if (xy_x <= -d100) z = 9; // 9
  176. else if (xy_x <= -d20) z = 10; // 10
  177. else if (xy_x <= d80) z = 11; // 11
  178. else z = 12; // 12
  179. }
  180. if (z)
  181. {
  182. int ok = 0;
  183. xy_x -= this->m_proj_parm.pj[z-1]->params().x0;
  184. xy_y -= this->m_proj_parm.pj[z-1]->params().y0;
  185. this->m_proj_parm.pj[z-1]->inv(xy_x, xy_y, lp_lon, lp_lat);
  186. lp_lon += this->m_proj_parm.pj[z-1]->params().lam0;
  187. switch (z) {
  188. case 1: ok = (lp_lon >= -d180-epsilon && lp_lon <= -d40+epsilon) ||
  189. ((lp_lon >= -d40-epsilon && lp_lon <= -d10+epsilon) &&
  190. (lp_lat >= d60-epsilon && lp_lat <= d90+epsilon)); break;
  191. case 2: ok = (lp_lon >= -d40-epsilon && lp_lon <= d180+epsilon) ||
  192. ((lp_lon >= -d180-epsilon && lp_lon <= -d160+epsilon) &&
  193. (lp_lat >= d50-epsilon && lp_lat <= d90+epsilon)) ||
  194. ((lp_lon >= -d50-epsilon && lp_lon <= -d40+epsilon) &&
  195. (lp_lat >= d60-epsilon && lp_lat <= d90+epsilon)); break;
  196. case 3: ok = (lp_lon >= -d180-epsilon && lp_lon <= -d40+epsilon); break;
  197. case 4: ok = (lp_lon >= -d40-epsilon && lp_lon <= d180+epsilon); break;
  198. case 5: ok = (lp_lon >= -d180-epsilon && lp_lon <= -d100+epsilon); break;
  199. case 6: ok = (lp_lon >= -d100-epsilon && lp_lon <= -d20+epsilon); break;
  200. case 7: ok = (lp_lon >= -d20-epsilon && lp_lon <= d80+epsilon); break;
  201. case 8: ok = (lp_lon >= d80-epsilon && lp_lon <= d180+epsilon); break;
  202. case 9: ok = (lp_lon >= -d180-epsilon && lp_lon <= -d100+epsilon); break;
  203. case 10: ok = (lp_lon >= -d100-epsilon && lp_lon <= -d20+epsilon); break;
  204. case 11: ok = (lp_lon >= -d20-epsilon && lp_lon <= d80+epsilon); break;
  205. case 12: ok = (lp_lon >= d80-epsilon && lp_lon <= d180+epsilon); break;
  206. }
  207. z = (!ok? 0: z); // projectable?
  208. }
  209. // if (!z) pj_errno = -15; // invalid x or y
  210. if (!z) lp_lon = HUGE_VAL;
  211. if (!z) lp_lat = HUGE_VAL;
  212. }
  213. static inline std::string get_name()
  214. {
  215. return "igh_spheroid";
  216. }
  217. };
  218. // Interrupted Goode Homolosine
  219. template <typename T, typename Parameters>
  220. inline void setup_igh(Parameters& par, par_igh<T, Parameters>& proj_parm)
  221. {
  222. static const T d0 = 0;
  223. static const T d4044118 = igh::d4044118<T>();
  224. static const T d20 = igh::d20<T>();
  225. static const T d30 = igh::d30<T>();
  226. static const T d60 = igh::d60<T>();
  227. static const T d100 = igh::d100<T>();
  228. static const T d140 = igh::d140<T>();
  229. static const T d160 = igh::d160<T>();
  230. /*
  231. Zones:
  232. -180 -40 180
  233. +--------------+-------------------------+ Zones 1,2,9,10,11 & 12:
  234. |1 |2 | Mollweide projection
  235. | | |
  236. +--------------+-------------------------+ Zones 3,4,5,6,7 & 8:
  237. |3 |4 | Sinusoidal projection
  238. | | |
  239. 0 +-------+------+-+-----------+-----------+
  240. |5 |6 |7 |8 |
  241. | | | | |
  242. +-------+--------+-----------+-----------+
  243. |9 |10 |11 |12 |
  244. | | | | |
  245. +-------+--------+-----------+-----------+
  246. -180 -100 -20 80 180
  247. */
  248. T lp_lam = 0, lp_phi = d4044118;
  249. T xy1_x, xy1_y;
  250. T xy3_x, xy3_y;
  251. // IMPORTANT: Force spherical sinu projection
  252. // This is required because unlike in the original proj4 here
  253. // parameters are used to initialize underlying projections.
  254. // In the original code zeroed parameters are passed which
  255. // could be done here as well though.
  256. par.es = 0.;
  257. // sinusoidal zones
  258. do_setup<sinu_entry>(3, par, proj_parm, -d100, d0, -d100);
  259. do_setup<sinu_entry>(4, par, proj_parm, d30, d0, d30);
  260. do_setup<sinu_entry>(5, par, proj_parm, -d160, d0, -d160);
  261. do_setup<sinu_entry>(6, par, proj_parm, -d60, d0, -d60);
  262. do_setup<sinu_entry>(7, par, proj_parm, d20, d0, d20);
  263. do_setup<sinu_entry>(8, par, proj_parm, d140, d0, d140);
  264. // mollweide zones
  265. do_setup<moll_entry>(1, par, proj_parm, -d100, d0, -d100);
  266. // y0 ?
  267. proj_parm.pj[0]->fwd(lp_lam, lp_phi, xy1_x, xy1_y); // zone 1
  268. proj_parm.pj[2]->fwd(lp_lam, lp_phi, xy3_x, xy3_y); // zone 3
  269. // y0 + xy1_y = xy3_y for lt = 40d44'11.8"
  270. proj_parm.dy0 = xy3_y - xy1_y;
  271. proj_parm.pj[0]->mutable_params().y0 = proj_parm.dy0;
  272. // mollweide zones (cont'd)
  273. do_setup<moll_entry>( 2, par, proj_parm, d30, proj_parm.dy0, d30);
  274. do_setup<moll_entry>( 9, par, proj_parm, -d160, -proj_parm.dy0, -d160);
  275. do_setup<moll_entry>(10, par, proj_parm, -d60, -proj_parm.dy0, -d60);
  276. do_setup<moll_entry>(11, par, proj_parm, d20, -proj_parm.dy0, d20);
  277. do_setup<moll_entry>(12, par, proj_parm, d140, -proj_parm.dy0, d140);
  278. // Already done before
  279. //par.es = 0.;
  280. }
  281. }} // namespace detail::igh
  282. #endif // doxygen
  283. /*!
  284. \brief Interrupted Goode Homolosine projection
  285. \ingroup projections
  286. \tparam Geographic latlong point type
  287. \tparam Cartesian xy point type
  288. \tparam Parameters parameter type
  289. \par Projection characteristics
  290. - Pseudocylindrical
  291. - Spheroid
  292. \par Example
  293. \image html ex_igh.gif
  294. */
  295. template <typename T, typename Parameters>
  296. struct igh_spheroid : public detail::igh::base_igh_spheroid<T, Parameters>
  297. {
  298. inline igh_spheroid(const Parameters& par) : detail::igh::base_igh_spheroid<T, Parameters>(par)
  299. {
  300. detail::igh::setup_igh(this->m_par, this->m_proj_parm);
  301. }
  302. };
  303. #ifndef DOXYGEN_NO_DETAIL
  304. namespace detail
  305. {
  306. // Static projection
  307. BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::par4::igh, igh_spheroid, igh_spheroid)
  308. // Factory entry(s)
  309. template <typename T, typename Parameters>
  310. class igh_entry : public detail::factory_entry<T, Parameters>
  311. {
  312. public :
  313. virtual base_v<T, Parameters>* create_new(const Parameters& par) const
  314. {
  315. return new base_v_fi<igh_spheroid<T, Parameters>, T, Parameters>(par);
  316. }
  317. };
  318. template <typename T, typename Parameters>
  319. inline void igh_init(detail::base_factory<T, Parameters>& factory)
  320. {
  321. factory.add_to_factory("igh", new igh_entry<T, Parameters>);
  322. }
  323. } // namespace detail
  324. #endif // doxygen
  325. } // namespace projections
  326. }} // namespace boost::geometry
  327. #endif // BOOST_GEOMETRY_PROJECTIONS_IGH_HPP