pj_init.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  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. // This file was modified by Oracle on 2017, 2018.
  5. // Modifications copyright (c) 2017-2018, Oracle and/or its affiliates.
  6. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. // This file is converted from PROJ4, http://trac.osgeo.org/proj
  11. // PROJ4 is originally written by Gerald Evenden (then of the USGS)
  12. // PROJ4 is maintained by Frank Warmerdam
  13. // PROJ4 is converted to Geometry Library by Barend Gehrels (Geodan, Amsterdam)
  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_IMPL_PJ_INIT_HPP
  31. #define BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_INIT_HPP
  32. #include <cstdlib>
  33. #include <string>
  34. #include <vector>
  35. #include <boost/algorithm/string.hpp>
  36. #include <boost/mpl/find.hpp>
  37. #include <boost/mpl/if.hpp>
  38. #include <boost/range.hpp>
  39. #include <boost/type_traits/is_same.hpp>
  40. #include <boost/geometry/util/math.hpp>
  41. #include <boost/geometry/util/condition.hpp>
  42. #include <boost/geometry/srs/projections/dpar.hpp>
  43. #include <boost/geometry/srs/projections/impl/dms_parser.hpp>
  44. #include <boost/geometry/srs/projections/impl/pj_datum_set.hpp>
  45. #include <boost/geometry/srs/projections/impl/pj_datums.hpp>
  46. #include <boost/geometry/srs/projections/impl/pj_ell_set.hpp>
  47. #include <boost/geometry/srs/projections/impl/pj_param.hpp>
  48. #include <boost/geometry/srs/projections/impl/pj_units.hpp>
  49. #include <boost/geometry/srs/projections/impl/projects.hpp>
  50. #include <boost/geometry/srs/projections/proj4.hpp>
  51. #include <boost/geometry/srs/projections/spar.hpp>
  52. namespace boost { namespace geometry { namespace projections
  53. {
  54. namespace detail
  55. {
  56. /************************************************************************/
  57. /* pj_init_proj() */
  58. /************************************************************************/
  59. template <typename T>
  60. inline void pj_init_proj(srs::detail::proj4_parameters const& params,
  61. parameters<T> & par)
  62. {
  63. par.id = pj_get_param_s(params, "proj");
  64. }
  65. template <typename T>
  66. inline void pj_init_proj(srs::dpar::parameters<T> const& params,
  67. parameters<T> & par)
  68. {
  69. typename srs::dpar::parameters<T>::const_iterator it = pj_param_find(params, srs::dpar::proj);
  70. if (it != params.end())
  71. {
  72. par.id = static_cast<srs::dpar::value_proj>(it->template get_value<int>());
  73. }
  74. }
  75. template <typename T, BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX>
  76. inline void pj_init_proj(srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& ,
  77. parameters<T> & par)
  78. {
  79. typedef srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> params_type;
  80. typedef typename srs::spar::detail::tuples_find_if
  81. <
  82. params_type,
  83. srs::spar::detail::is_param_tr<srs::spar::detail::proj_traits>::pred
  84. >::type proj_type;
  85. static const bool is_found = srs::spar::detail::tuples_is_found<proj_type>::value;
  86. BOOST_MPL_ASSERT_MSG((is_found), PROJECTION_NOT_NAMED, (params_type));
  87. par.id = srs::spar::detail::proj_traits<proj_type>::id;
  88. }
  89. /************************************************************************/
  90. /* pj_init_units() */
  91. /************************************************************************/
  92. template <typename T, bool Vertical>
  93. inline void pj_init_units(srs::detail::proj4_parameters const& params,
  94. T & to_meter,
  95. T & fr_meter,
  96. T const& default_to_meter,
  97. T const& default_fr_meter)
  98. {
  99. std::string s;
  100. std::string units = pj_get_param_s(params, Vertical ? "vunits" : "units");
  101. if (! units.empty())
  102. {
  103. static const int n = sizeof(pj_units) / sizeof(pj_units[0]);
  104. int index = -1;
  105. for (int i = 0; i < n && index == -1; i++)
  106. {
  107. if(pj_units[i].id == units)
  108. {
  109. index = i;
  110. }
  111. }
  112. if (index == -1) {
  113. BOOST_THROW_EXCEPTION( projection_exception(error_unknow_unit_id) );
  114. }
  115. s = pj_units[index].to_meter;
  116. }
  117. if (s.empty())
  118. {
  119. s = pj_get_param_s(params, Vertical ? "vto_meter" : "to_meter");
  120. }
  121. // TODO: numerator and denominator could be taken from pj_units
  122. if (! s.empty())
  123. {
  124. std::size_t const pos = s.find('/');
  125. if (pos == std::string::npos)
  126. {
  127. to_meter = geometry::str_cast<T>(s);
  128. }
  129. else
  130. {
  131. T const numerator = geometry::str_cast<T>(s.substr(0, pos));
  132. T const denominator = geometry::str_cast<T>(s.substr(pos + 1));
  133. if (numerator == 0.0 || denominator == 0.0)
  134. {
  135. BOOST_THROW_EXCEPTION( projection_exception(error_unit_factor_less_than_0) );
  136. }
  137. to_meter = numerator / denominator;
  138. }
  139. if (to_meter == 0.0)
  140. {
  141. BOOST_THROW_EXCEPTION( projection_exception(error_unit_factor_less_than_0) );
  142. }
  143. fr_meter = 1. / to_meter;
  144. }
  145. else
  146. {
  147. to_meter = default_to_meter;
  148. fr_meter = default_fr_meter;
  149. }
  150. }
  151. template <typename T, bool Vertical>
  152. inline void pj_init_units(srs::dpar::parameters<T> const& params,
  153. T & to_meter,
  154. T & fr_meter,
  155. T const& default_to_meter,
  156. T const& default_fr_meter)
  157. {
  158. typename srs::dpar::parameters<T>::const_iterator
  159. it = pj_param_find(params, Vertical ? srs::dpar::vunits : srs::dpar::units);
  160. if (it != params.end())
  161. {
  162. static const int n = sizeof(pj_units) / sizeof(pj_units[0]);
  163. const int i = it->template get_value<int>();
  164. if (i >= 0 && i < n)
  165. {
  166. T const numerator = pj_units[i].numerator;
  167. T const denominator = pj_units[i].denominator;
  168. if (numerator == 0.0 || denominator == 0.0)
  169. {
  170. BOOST_THROW_EXCEPTION( projection_exception(error_unit_factor_less_than_0) );
  171. }
  172. to_meter = numerator / denominator;
  173. fr_meter = 1. / to_meter;
  174. }
  175. else
  176. {
  177. BOOST_THROW_EXCEPTION( projection_exception(error_unknow_unit_id) );
  178. }
  179. }
  180. else
  181. {
  182. it = pj_param_find(params, Vertical ? srs::dpar::vto_meter : srs::dpar::to_meter);
  183. if (it != params.end())
  184. {
  185. to_meter = it->template get_value<T>();
  186. fr_meter = 1. / to_meter;
  187. }
  188. else
  189. {
  190. to_meter = default_to_meter;
  191. fr_meter = default_fr_meter;
  192. }
  193. }
  194. }
  195. template
  196. <
  197. typename Params,
  198. bool Vertical,
  199. int UnitsI = srs::spar::detail::tuples_find_index_if
  200. <
  201. Params,
  202. boost::mpl::if_c
  203. <
  204. Vertical,
  205. srs::spar::detail::is_param_t<srs::spar::vunits>,
  206. srs::spar::detail::is_param_tr<srs::spar::detail::units_traits>
  207. >::type::template pred
  208. >::value,
  209. int ToMeterI = srs::spar::detail::tuples_find_index_if
  210. <
  211. Params,
  212. boost::mpl::if_c
  213. <
  214. Vertical,
  215. srs::spar::detail::is_param_t<srs::spar::vto_meter>,
  216. srs::spar::detail::is_param_t<srs::spar::to_meter>
  217. >::type::template pred
  218. >::value,
  219. int N = boost::tuples::length<Params>::value
  220. >
  221. struct pj_init_units_static
  222. : pj_init_units_static<Params, Vertical, UnitsI, N, N>
  223. {};
  224. template <typename Params, bool Vertical, int UnitsI, int N>
  225. struct pj_init_units_static<Params, Vertical, UnitsI, N, N>
  226. {
  227. static const int n = sizeof(pj_units) / sizeof(pj_units[0]);
  228. static const int i = srs::spar::detail::units_traits
  229. <
  230. typename boost::tuples::element<UnitsI, Params>::type
  231. >::id;
  232. static const bool is_valid = i >= 0 && i < n;
  233. BOOST_MPL_ASSERT_MSG((is_valid), UNKNOWN_UNIT_ID, (Params));
  234. template <typename T>
  235. static void apply(Params const& ,
  236. T & to_meter, T & fr_meter,
  237. T const& , T const& )
  238. {
  239. T const numerator = pj_units[i].numerator;
  240. T const denominator = pj_units[i].denominator;
  241. if (numerator == 0.0 || denominator == 0.0)
  242. {
  243. BOOST_THROW_EXCEPTION( projection_exception(error_unit_factor_less_than_0) );
  244. }
  245. to_meter = numerator / denominator;
  246. fr_meter = 1. / to_meter;
  247. }
  248. };
  249. template <typename Params, bool Vertical, int ToMeterI, int N>
  250. struct pj_init_units_static<Params, Vertical, N, ToMeterI, N>
  251. {
  252. template <typename T>
  253. static void apply(Params const& params,
  254. T & to_meter, T & fr_meter,
  255. T const& , T const& )
  256. {
  257. to_meter = boost::tuples::get<ToMeterI>(params).value;
  258. fr_meter = 1. / to_meter;
  259. }
  260. };
  261. template <typename Params, bool Vertical, int N>
  262. struct pj_init_units_static<Params, Vertical, N, N, N>
  263. {
  264. template <typename T>
  265. static void apply(Params const& ,
  266. T & to_meter, T & fr_meter,
  267. T const& default_to_meter, T const& default_fr_meter)
  268. {
  269. to_meter = default_to_meter;
  270. fr_meter = default_fr_meter;
  271. }
  272. };
  273. template <typename T, bool Vertical, BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX>
  274. inline void pj_init_units(srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& params,
  275. T & to_meter,
  276. T & fr_meter,
  277. T const& default_to_meter,
  278. T const& default_fr_meter)
  279. {
  280. pj_init_units_static
  281. <
  282. srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>,
  283. Vertical
  284. >::apply(params, to_meter, fr_meter, default_to_meter, default_fr_meter);
  285. }
  286. /************************************************************************/
  287. /* pj_init_pm() */
  288. /************************************************************************/
  289. template <typename T>
  290. inline void pj_init_pm(srs::detail::proj4_parameters const& params, T& val)
  291. {
  292. std::string pm = pj_get_param_s(params, "pm");
  293. if (! pm.empty())
  294. {
  295. int n = sizeof(pj_prime_meridians) / sizeof(pj_prime_meridians[0]);
  296. for (int i = 0; i < n ; i++)
  297. {
  298. if(pj_prime_meridians[i].id == pm)
  299. {
  300. val = pj_prime_meridians[i].deg * math::d2r<T>();
  301. return;
  302. }
  303. }
  304. // TODO: Is this try-catch needed?
  305. // In other cases the bad_str_cast exception is simply thrown
  306. BOOST_TRY
  307. {
  308. val = dms_parser<T, true>::apply(pm).angle();
  309. return;
  310. }
  311. BOOST_CATCH(geometry::bad_str_cast const&)
  312. {
  313. BOOST_THROW_EXCEPTION( projection_exception(error_unknown_prime_meridian) );
  314. }
  315. BOOST_CATCH_END
  316. }
  317. val = 0.0;
  318. }
  319. template <typename T>
  320. inline void pj_init_pm(srs::dpar::parameters<T> const& params, T& val)
  321. {
  322. typename srs::dpar::parameters<T>::const_iterator it = pj_param_find(params, srs::dpar::pm);
  323. if (it != params.end())
  324. {
  325. if (it->template is_value_set<int>())
  326. {
  327. int n = sizeof(pj_prime_meridians) / sizeof(pj_prime_meridians[0]);
  328. int i = it->template get_value<int>();
  329. if (i >= 0 && i < n)
  330. {
  331. val = pj_prime_meridians[i].deg * math::d2r<T>();
  332. return;
  333. }
  334. else
  335. {
  336. BOOST_THROW_EXCEPTION( projection_exception(error_unknown_prime_meridian) );
  337. }
  338. }
  339. else if (it->template is_value_set<T>())
  340. {
  341. val = it->template get_value<T>() * math::d2r<T>();
  342. return;
  343. }
  344. }
  345. val = 0.0;
  346. }
  347. template
  348. <
  349. typename Params,
  350. int I = srs::spar::detail::tuples_find_index_if
  351. <
  352. Params,
  353. srs::spar::detail::is_param_tr<srs::spar::detail::pm_traits>::pred
  354. >::value,
  355. int N = boost::tuples::length<Params>::value
  356. >
  357. struct pj_init_pm_static
  358. {
  359. template <typename T>
  360. static void apply(Params const& params, T & val)
  361. {
  362. typedef typename boost::tuples::element<I, Params>::type param_type;
  363. val = srs::spar::detail::pm_traits<param_type>::value(boost::tuples::get<I>(params));
  364. }
  365. };
  366. template <typename Params, int N>
  367. struct pj_init_pm_static<Params, N, N>
  368. {
  369. template <typename T>
  370. static void apply(Params const& , T & val)
  371. {
  372. val = 0;
  373. }
  374. };
  375. template <typename T, BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX>
  376. inline void pj_init_pm(srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& params, T& val)
  377. {
  378. pj_init_pm_static
  379. <
  380. srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>
  381. >::apply(params, val);
  382. }
  383. /************************************************************************/
  384. /* pj_init() */
  385. /* */
  386. /* Main entry point for initialing a PJ projections */
  387. /* definition. */
  388. /************************************************************************/
  389. template <typename T, typename Params>
  390. inline parameters<T> pj_init(Params const& params)
  391. {
  392. parameters<T> pin;
  393. // find projection -> implemented in projection factory
  394. pj_init_proj(params, pin);
  395. // exception thrown in projection<>
  396. // TODO: consider throwing here both projection_unknown_id_exception and
  397. // projection_not_named_exception in order to throw before other exceptions
  398. //if (pin.name.empty())
  399. //{ BOOST_THROW_EXCEPTION( projection_not_named_exception() ); }
  400. // NOTE: proj4 gets defaults from "proj_def.dat".
  401. // In Boost.Geometry this is emulated by manually setting them in
  402. // pj_ell_init and projections aea, lcc and lagrng
  403. /* set datum parameters */
  404. pj_datum_init(params, pin);
  405. /* set ellipsoid/sphere parameters */
  406. pj_ell_init(params, pin.a, pin.es);
  407. pin.a_orig = pin.a;
  408. pin.es_orig = pin.es;
  409. pin.e = sqrt(pin.es);
  410. pin.ra = 1. / pin.a;
  411. pin.one_es = 1. - pin.es;
  412. if (pin.one_es == 0.) {
  413. BOOST_THROW_EXCEPTION( projection_exception(error_eccentricity_is_one) );
  414. }
  415. pin.rone_es = 1./pin.one_es;
  416. /* Now that we have ellipse information check for WGS84 datum */
  417. if( pin.datum_type == datum_3param
  418. && pin.datum_params[0] == 0.0
  419. && pin.datum_params[1] == 0.0
  420. && pin.datum_params[2] == 0.0
  421. && pin.a == 6378137.0
  422. && geometry::math::abs(pin.es - 0.006694379990) < 0.000000000050 )/*WGS84/GRS80*/
  423. {
  424. pin.datum_type = datum_wgs84;
  425. }
  426. /* set pin.geoc coordinate system */
  427. pin.geoc = (pin.es && pj_get_param_b<srs::spar::geoc>(params, "geoc", srs::dpar::geoc));
  428. /* over-ranging flag */
  429. pin.over = pj_get_param_b<srs::spar::over>(params, "over", srs::dpar::over);
  430. /* longitude center for wrapping */
  431. pin.is_long_wrap_set = pj_param_r<srs::spar::lon_wrap>(params, "lon_wrap", srs::dpar::lon_wrap, pin.long_wrap_center);
  432. /* central meridian */
  433. pin.lam0 = pj_get_param_r<T, srs::spar::lon_0>(params, "lon_0", srs::dpar::lon_0);
  434. /* central latitude */
  435. pin.phi0 = pj_get_param_r<T, srs::spar::lat_0>(params, "lat_0", srs::dpar::lat_0);
  436. /* false easting and northing */
  437. pin.x0 = pj_get_param_f<T, srs::spar::x_0>(params, "x_0", srs::dpar::x_0);
  438. pin.y0 = pj_get_param_f<T, srs::spar::y_0>(params, "y_0", srs::dpar::y_0);
  439. /* general scaling factor */
  440. if (pj_param_f<srs::spar::k_0>(params, "k_0", srs::dpar::k_0, pin.k0)) {
  441. /* empty */
  442. } else if (pj_param_f<srs::spar::k>(params, "k", srs::dpar::k, pin.k0)) {
  443. /* empty */
  444. } else
  445. pin.k0 = 1.;
  446. if (pin.k0 <= 0.) {
  447. BOOST_THROW_EXCEPTION( projection_exception(error_k_less_than_zero) );
  448. }
  449. /* set units */
  450. pj_init_units<T, false>(params, pin.to_meter, pin.fr_meter, 1., 1.);
  451. pj_init_units<T, true>(params, pin.vto_meter, pin.vfr_meter, pin.to_meter, pin.fr_meter);
  452. /* prime meridian */
  453. pj_init_pm(params, pin.from_greenwich);
  454. return pin;
  455. }
  456. } // namespace detail
  457. }}} // namespace boost::geometry::projections
  458. #endif // BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_INIT_HPP