igh.hpp 18 KB

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