pj_datum_set.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // This file is manually converted from PROJ4
  3. // Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.
  4. // Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
  5. // This file was modified by Oracle on 2017-2020.
  6. // Modifications copyright (c) 2017-2020, Oracle and/or its affiliates.
  7. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  8. // Use, modification and distribution is subject to the Boost Software License,
  9. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. // This file is converted from PROJ4, http://trac.osgeo.org/proj
  12. // PROJ4 is originally written by Gerald Evenden (then of the USGS)
  13. // PROJ4 is maintained by Frank Warmerdam
  14. // PROJ4 is converted to Geometry Library by Barend Gehrels (Geodan, Amsterdam)
  15. // Original copyright notice:
  16. // Permission is hereby granted, free of charge, to any person obtaining a
  17. // copy of this software and associated documentation files (the "Software"),
  18. // to deal in the Software without restriction, including without limitation
  19. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  20. // and/or sell copies of the Software, and to permit persons to whom the
  21. // Software is furnished to do so, subject to the following conditions:
  22. // The above copyright notice and this permission notice shall be included
  23. // in all copies or substantial portions of the Software.
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  25. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  27. // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  28. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  29. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  30. // DEALINGS IN THE SOFTWARE.
  31. #ifndef BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_DATUM_SET_HPP
  32. #define BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_DATUM_SET_HPP
  33. #include <string>
  34. #include <vector>
  35. #include <boost/algorithm/string/classification.hpp>
  36. #include <boost/algorithm/string/split.hpp>
  37. #include <boost/geometry/srs/projections/dpar.hpp>
  38. #include <boost/geometry/srs/projections/exception.hpp>
  39. #include <boost/geometry/srs/projections/impl/projects.hpp>
  40. #include <boost/geometry/srs/projections/impl/pj_datums.hpp>
  41. #include <boost/geometry/srs/projections/impl/pj_param.hpp>
  42. #include <boost/geometry/srs/projections/proj4.hpp>
  43. #include <boost/geometry/srs/projections/spar.hpp>
  44. namespace boost { namespace geometry { namespace projections {
  45. namespace detail {
  46. /* SEC_TO_RAD = Pi/180/3600 */
  47. template <typename T>
  48. inline T sec_to_rad() { return 4.84813681109535993589914102357e-6; }
  49. /************************************************************************/
  50. /* pj_datum_find_datum() */
  51. /************************************************************************/
  52. template <typename T>
  53. inline const pj_datums_type<T>* pj_datum_find_datum(srs::detail::proj4_parameters const& params)
  54. {
  55. std::string name = pj_get_param_s(params, "datum");
  56. if(! name.empty())
  57. {
  58. /* find the datum definition */
  59. const pj_datums_type<T>* pj_datums = pj_get_datums<T>().first;
  60. const int n = pj_get_datums<T>().second;
  61. int index = -1;
  62. for (int i = 0; i < n && index == -1; i++)
  63. {
  64. if(pj_datums[i].id == name)
  65. {
  66. index = i;
  67. }
  68. }
  69. if (index != -1)
  70. {
  71. return pj_datums + index;
  72. }
  73. else
  74. {
  75. BOOST_THROW_EXCEPTION( projection_exception(error_unknown_ellp_param) );
  76. }
  77. }
  78. return NULL;
  79. }
  80. template <typename T>
  81. inline const pj_datums_type<T>* pj_datum_find_datum(srs::dpar::parameters<T> const& params)
  82. {
  83. typename srs::dpar::parameters<T>::const_iterator
  84. it = pj_param_find(params, srs::dpar::datum);
  85. if (it != params.end())
  86. {
  87. const pj_datums_type<T>* pj_datums = pj_get_datums<T>().first;
  88. const int n = pj_get_datums<T>().second;
  89. int i = it->template get_value<int>();
  90. if (i >= 0 && i < n)
  91. {
  92. return pj_datums + i;
  93. }
  94. else
  95. {
  96. BOOST_THROW_EXCEPTION( projection_exception(error_unknown_ellp_param) );
  97. }
  98. }
  99. return NULL;
  100. }
  101. template
  102. <
  103. typename Params,
  104. typename Param = typename geometry::tuples::find_if
  105. <
  106. Params,
  107. srs::spar::detail::is_param_tr<srs::spar::detail::datum_traits>::pred
  108. >::type,
  109. bool IsFound = geometry::tuples::is_found<Param>::value
  110. >
  111. struct pj_datum_find_datum_static
  112. {
  113. template <typename T>
  114. static const pj_datums_type<T>* apply(Params const& )
  115. {
  116. const pj_datums_type<T>* pj_datums = pj_get_datums<T>().first;
  117. const int n = pj_get_datums<T>().second;
  118. const int i = srs::spar::detail::datum_traits<Param>::id;
  119. if (i >= 0 && i < n)
  120. {
  121. return pj_datums + i;
  122. }
  123. else
  124. {
  125. // TODO: Implemnt as BOOST_GEOMETRY_STATIC_ASSERT instead
  126. BOOST_THROW_EXCEPTION( projection_exception(error_unknown_ellp_param) );
  127. }
  128. }
  129. };
  130. template <typename Params, typename Param>
  131. struct pj_datum_find_datum_static<Params, Param, false>
  132. {
  133. template <typename T>
  134. static const pj_datums_type<T>* apply(Params const& )
  135. {
  136. return NULL;
  137. }
  138. };
  139. template <typename T, typename ...Ps>
  140. inline const pj_datums_type<T>* pj_datum_find_datum(srs::spar::parameters<Ps...> const& params)
  141. {
  142. return pj_datum_find_datum_static
  143. <
  144. srs::spar::parameters<Ps...>
  145. >::template apply<T>(params);
  146. }
  147. /************************************************************************/
  148. /* pj_datum_find_nadgrids() */
  149. /************************************************************************/
  150. inline bool pj_datum_find_nadgrids(srs::detail::proj4_parameters const& params,
  151. srs::detail::nadgrids & out)
  152. {
  153. std::string snadgrids = pj_get_param_s(params, "nadgrids");
  154. if (! snadgrids.empty())
  155. {
  156. for (std::string::size_type i = 0 ; i < snadgrids.size() ; )
  157. {
  158. std::string::size_type end = snadgrids.find(',', i);
  159. std::string name = snadgrids.substr(i, end - i);
  160. i = end;
  161. if (end != std::string::npos)
  162. ++i;
  163. if (! name.empty())
  164. out.push_back(name);
  165. }
  166. }
  167. return ! out.empty();
  168. }
  169. template <typename T>
  170. inline bool pj_datum_find_nadgrids(srs::dpar::parameters<T> const& params,
  171. srs::detail::nadgrids & out)
  172. {
  173. typename srs::dpar::parameters<T>::const_iterator
  174. it = pj_param_find(params, srs::dpar::nadgrids);
  175. if (it != params.end())
  176. {
  177. out = it->template get_value<srs::detail::nadgrids>();
  178. }
  179. return ! out.empty();
  180. }
  181. template
  182. <
  183. typename Params,
  184. int I = geometry::tuples::find_index_if
  185. <
  186. Params,
  187. srs::spar::detail::is_param<srs::spar::nadgrids>::pred
  188. >::value,
  189. int N = geometry::tuples::size<Params>::value
  190. >
  191. struct pj_datum_find_nadgrids_static
  192. {
  193. static void apply(Params const& params, srs::detail::nadgrids & out)
  194. {
  195. out = geometry::tuples::get<I>(params);
  196. }
  197. };
  198. template <typename Params, int N>
  199. struct pj_datum_find_nadgrids_static<Params, N, N>
  200. {
  201. static void apply(Params const& , srs::detail::nadgrids & )
  202. {}
  203. };
  204. template <typename ...Ps>
  205. inline bool pj_datum_find_nadgrids(srs::spar::parameters<Ps...> const& params,
  206. srs::detail::nadgrids & out)
  207. {
  208. pj_datum_find_nadgrids_static
  209. <
  210. srs::spar::parameters<Ps...>
  211. >::apply(params, out);
  212. return ! out.empty();
  213. }
  214. /************************************************************************/
  215. /* pj_datum_find_towgs84() */
  216. /************************************************************************/
  217. template <typename T>
  218. inline bool pj_datum_find_towgs84(srs::detail::proj4_parameters const& params,
  219. srs::detail::towgs84<T> & out)
  220. {
  221. std::string towgs84 = pj_get_param_s(params, "towgs84");
  222. if(! towgs84.empty())
  223. {
  224. std::vector<std::string> parm;
  225. boost::split(parm, towgs84, boost::is_any_of(" ,"));
  226. std::size_t n = (std::min<std::size_t>)(parm.size(), 7);
  227. std::size_t z = n <= 3 ? 3 : 7;
  228. /* parse out the pvalues */
  229. for (std::size_t i = 0 ; i < n; ++i)
  230. {
  231. out.push_back(geometry::str_cast<T>(parm[i]));
  232. }
  233. for (std::size_t i = out.size() ; i < z; ++i)
  234. {
  235. out.push_back(T(0));
  236. }
  237. }
  238. return ! out.empty();
  239. }
  240. template <typename T>
  241. inline bool pj_datum_find_towgs84(srs::dpar::parameters<T> const& params,
  242. srs::detail::towgs84<T> & out)
  243. {
  244. typename srs::dpar::parameters<T>::const_iterator
  245. it = pj_param_find(params, srs::dpar::towgs84);
  246. if (it != params.end())
  247. {
  248. srs::detail::towgs84<T> const&
  249. towgs84 = it->template get_value<srs::detail::towgs84<T> >();
  250. std::size_t n = (std::min<std::size_t>)(towgs84.size(), 7u);
  251. std::size_t z = n <= 3 ? 3 : 7;
  252. for (std::size_t i = 0 ; i < n; ++i)
  253. {
  254. out.push_back(towgs84[i]);
  255. }
  256. for (std::size_t i = out.size() ; i < z; ++i)
  257. {
  258. out.push_back(T(0));
  259. }
  260. }
  261. return ! out.empty();
  262. }
  263. template
  264. <
  265. typename Params,
  266. int I = geometry::tuples::find_index_if
  267. <
  268. Params,
  269. srs::spar::detail::is_param_t<srs::spar::towgs84>::pred
  270. >::value,
  271. int N = geometry::tuples::size<Params>::value
  272. >
  273. struct pj_datum_find_towgs84_static
  274. {
  275. template <typename T>
  276. static void apply(Params const& params, srs::detail::towgs84<T> & out)
  277. {
  278. typename geometry::tuples::element<I, Params>::type const&
  279. towgs84 = geometry::tuples::get<I>(params);
  280. std::size_t n = (std::min<std::size_t>)(towgs84.size(), 7u);
  281. std::size_t z = n <= 3 ? 3 : 7;
  282. for (std::size_t i = 0 ; i < n; ++i)
  283. {
  284. out.push_back(towgs84[i]);
  285. }
  286. for (std::size_t i = out.size() ; i < z; ++i)
  287. {
  288. out.push_back(T(0));
  289. }
  290. }
  291. };
  292. template <typename Params, int N>
  293. struct pj_datum_find_towgs84_static<Params, N, N>
  294. {
  295. template <typename T>
  296. static void apply(Params const& , srs::detail::towgs84<T> & )
  297. {}
  298. };
  299. template <typename T, typename ...Ps>
  300. inline bool pj_datum_find_towgs84(srs::spar::parameters<Ps...> const& params,
  301. srs::detail::towgs84<T> & out)
  302. {
  303. pj_datum_find_towgs84_static
  304. <
  305. srs::spar::parameters<Ps...>
  306. >::apply(params, out);
  307. return ! out.empty();
  308. }
  309. /************************************************************************/
  310. /* pj_datum_prepare_towgs84() */
  311. /************************************************************************/
  312. template <typename T>
  313. inline bool pj_datum_prepare_towgs84(srs::detail::towgs84<T> & towgs84)
  314. {
  315. if( towgs84.size() == 7
  316. && (towgs84[3] != 0.0
  317. || towgs84[4] != 0.0
  318. || towgs84[5] != 0.0
  319. || towgs84[6] != 0.0) )
  320. {
  321. static const T sec_to_rad = detail::sec_to_rad<T>();
  322. /* transform from arc seconds to radians */
  323. towgs84[3] *= sec_to_rad;
  324. towgs84[4] *= sec_to_rad;
  325. towgs84[5] *= sec_to_rad;
  326. /* transform from parts per million to scaling factor */
  327. towgs84[6] = (towgs84[6]/1000000.0) + 1;
  328. return true;
  329. }
  330. else
  331. {
  332. return false;
  333. }
  334. }
  335. /************************************************************************/
  336. /* pj_datum_init() */
  337. /************************************************************************/
  338. // This function works differently than the original pj_datum_set().
  339. // It doesn't push parameters defined in datum into params list.
  340. // Instead it tries to use nadgrids and towgs84 and only then
  341. // falls back to nadgrid or towgs84 defiend in datum parameter.
  342. template <typename Params, typename T>
  343. inline void pj_datum_init(Params const& params, parameters<T> & projdef)
  344. {
  345. projdef.datum_type = datum_unknown;
  346. // Check for nadgrids parameter.
  347. if(pj_datum_find_nadgrids(params, projdef.nadgrids))
  348. {
  349. // NOTE: It's different than in the original proj4.
  350. // Nadgrids names are stored in projection definition.
  351. projdef.datum_type = datum_gridshift;
  352. }
  353. // Check for towgs84 parameter.
  354. else if(pj_datum_find_towgs84(params, projdef.datum_params))
  355. {
  356. if (pj_datum_prepare_towgs84(projdef.datum_params))
  357. {
  358. projdef.datum_type = datum_7param;
  359. }
  360. else
  361. {
  362. projdef.datum_type = datum_3param;
  363. }
  364. /* Note that pj_init() will later switch datum_type to
  365. PJD_WGS84 if shifts are all zero, and ellipsoid is WGS84 or GRS80 */
  366. }
  367. // Check for datum parameter.
  368. else
  369. {
  370. const pj_datums_type<T>* datum = pj_datum_find_datum<T>(params);
  371. if (datum != NULL)
  372. {
  373. if (! datum->nadgrids.empty())
  374. {
  375. projdef.nadgrids = datum->nadgrids;
  376. projdef.datum_type = datum_gridshift;
  377. }
  378. else if ( ! datum->towgs84.empty() )
  379. {
  380. projdef.datum_params = datum->towgs84;
  381. if (pj_datum_prepare_towgs84(projdef.datum_params))
  382. {
  383. projdef.datum_type = datum_7param;
  384. }
  385. else
  386. {
  387. projdef.datum_type = datum_3param;
  388. }
  389. }
  390. }
  391. }
  392. }
  393. } // namespace detail
  394. }}} // namespace boost::geometry::projections
  395. #endif // BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_DATUM_SET_HPP