projection.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2017-2020.
  4. // Modifications copyright (c) 2017-2020, 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. #ifndef BOOST_GEOMETRY_SRS_PROJECTION_HPP
  10. #define BOOST_GEOMETRY_SRS_PROJECTION_HPP
  11. #include <string>
  12. #include <type_traits>
  13. #include <boost/smart_ptr/shared_ptr.hpp>
  14. #include <boost/throw_exception.hpp>
  15. #include <boost/geometry/algorithms/convert.hpp>
  16. #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
  17. #include <boost/geometry/core/coordinate_dimension.hpp>
  18. #include <boost/geometry/core/static_assert.hpp>
  19. #include <boost/geometry/srs/projections/dpar.hpp>
  20. #include <boost/geometry/srs/projections/exception.hpp>
  21. #include <boost/geometry/srs/projections/factory.hpp>
  22. #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
  23. #include <boost/geometry/srs/projections/impl/base_static.hpp>
  24. #include <boost/geometry/srs/projections/impl/pj_init.hpp>
  25. #include <boost/geometry/srs/projections/invalid_point.hpp>
  26. #include <boost/geometry/srs/projections/proj4.hpp>
  27. #include <boost/geometry/srs/projections/spar.hpp>
  28. #include <boost/geometry/views/detail/indexed_point_view.hpp>
  29. namespace boost { namespace geometry
  30. {
  31. namespace projections
  32. {
  33. #ifndef DOXYGEN_NO_DETAIL
  34. namespace detail
  35. {
  36. template <typename G1, typename G2>
  37. struct same_tags
  38. : std::is_same
  39. <
  40. typename geometry::tag<G1>::type,
  41. typename geometry::tag<G2>::type
  42. >
  43. {};
  44. template <typename CT>
  45. struct promote_to_double
  46. {
  47. typedef std::conditional_t
  48. <
  49. std::is_integral<CT>::value || std::is_same<CT, float>::value,
  50. double, CT
  51. > type;
  52. };
  53. // Copy coordinates of dimensions >= MinDim
  54. template <std::size_t MinDim, typename Point1, typename Point2>
  55. inline void copy_higher_dimensions(Point1 const& point1, Point2 & point2)
  56. {
  57. static const std::size_t dim1 = geometry::dimension<Point1>::value;
  58. static const std::size_t dim2 = geometry::dimension<Point2>::value;
  59. static const std::size_t lesser_dim = dim1 < dim2 ? dim1 : dim2;
  60. BOOST_GEOMETRY_STATIC_ASSERT((lesser_dim >= MinDim),
  61. "The dimension of Point1 or Point2 is too small.",
  62. Point1, Point2);
  63. geometry::detail::conversion::point_to_point
  64. <
  65. Point1, Point2, MinDim, lesser_dim
  66. > ::apply(point1, point2);
  67. // TODO: fill point2 with zeros if dim1 < dim2 ?
  68. // currently no need because equal dimensions are checked
  69. }
  70. struct forward_point_projection_policy
  71. {
  72. template <typename LL, typename XY, typename Proj>
  73. static inline bool apply(LL const& ll, XY & xy, Proj const& proj)
  74. {
  75. return proj.forward(ll, xy);
  76. }
  77. };
  78. struct inverse_point_projection_policy
  79. {
  80. template <typename XY, typename LL, typename Proj>
  81. static inline bool apply(XY const& xy, LL & ll, Proj const& proj)
  82. {
  83. return proj.inverse(xy, ll);
  84. }
  85. };
  86. template <typename PointPolicy>
  87. struct project_point
  88. {
  89. template <typename P1, typename P2, typename Proj>
  90. static inline bool apply(P1 const& p1, P2 & p2, Proj const& proj)
  91. {
  92. // (Geographic -> Cartesian) will be projected, rest will be copied.
  93. // So first copy third or higher dimensions
  94. projections::detail::copy_higher_dimensions<2>(p1, p2);
  95. if (! PointPolicy::apply(p1, p2, proj))
  96. {
  97. // For consistency with transformation
  98. set_invalid_point(p2);
  99. return false;
  100. }
  101. return true;
  102. }
  103. };
  104. template <typename PointPolicy>
  105. struct project_range
  106. {
  107. template <typename Proj>
  108. struct convert_policy
  109. {
  110. explicit convert_policy(Proj const& proj)
  111. : m_proj(proj)
  112. , m_result(true)
  113. {}
  114. template <typename Point1, typename Point2>
  115. inline void apply(Point1 const& point1, Point2 & point2)
  116. {
  117. if (! project_point<PointPolicy>::apply(point1, point2, m_proj) )
  118. m_result = false;
  119. }
  120. bool result() const
  121. {
  122. return m_result;
  123. }
  124. private:
  125. Proj const& m_proj;
  126. bool m_result;
  127. };
  128. template <typename R1, typename R2, typename Proj>
  129. static inline bool apply(R1 const& r1, R2 & r2, Proj const& proj)
  130. {
  131. return geometry::detail::conversion::range_to_range
  132. <
  133. R1, R2,
  134. geometry::point_order<R1>::value != geometry::point_order<R2>::value
  135. >::apply(r1, r2, convert_policy<Proj>(proj)).result();
  136. }
  137. };
  138. template <typename Policy>
  139. struct project_multi
  140. {
  141. template <typename G1, typename G2, typename Proj>
  142. static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
  143. {
  144. range::resize(g2, boost::size(g1));
  145. return apply(boost::begin(g1), boost::end(g1),
  146. boost::begin(g2),
  147. proj);
  148. }
  149. private:
  150. template <typename It1, typename It2, typename Proj>
  151. static inline bool apply(It1 g1_first, It1 g1_last, It2 g2_first, Proj const& proj)
  152. {
  153. bool result = true;
  154. for ( ; g1_first != g1_last ; ++g1_first, ++g2_first )
  155. {
  156. if (! Policy::apply(*g1_first, *g2_first, proj))
  157. {
  158. result = false;
  159. }
  160. }
  161. return result;
  162. }
  163. };
  164. template
  165. <
  166. typename Geometry,
  167. typename PointPolicy,
  168. typename Tag = typename geometry::tag<Geometry>::type
  169. >
  170. struct project_geometry
  171. {};
  172. template <typename Geometry, typename PointPolicy>
  173. struct project_geometry<Geometry, PointPolicy, point_tag>
  174. : project_point<PointPolicy>
  175. {};
  176. template <typename Geometry, typename PointPolicy>
  177. struct project_geometry<Geometry, PointPolicy, multi_point_tag>
  178. : project_range<PointPolicy>
  179. {};
  180. template <typename Geometry, typename PointPolicy>
  181. struct project_geometry<Geometry, PointPolicy, segment_tag>
  182. {
  183. template <typename G1, typename G2, typename Proj>
  184. static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
  185. {
  186. bool r1 = apply<0>(g1, g2, proj);
  187. bool r2 = apply<1>(g1, g2, proj);
  188. return r1 && r2;
  189. }
  190. private:
  191. template <std::size_t Index, typename G1, typename G2, typename Proj>
  192. static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
  193. {
  194. geometry::detail::indexed_point_view<G1 const, Index> pt1(g1);
  195. geometry::detail::indexed_point_view<G2, Index> pt2(g2);
  196. return project_point<PointPolicy>::apply(pt1, pt2, proj);
  197. }
  198. };
  199. template <typename Geometry, typename PointPolicy>
  200. struct project_geometry<Geometry, PointPolicy, linestring_tag>
  201. : project_range<PointPolicy>
  202. {};
  203. template <typename Geometry, typename PointPolicy>
  204. struct project_geometry<Geometry, PointPolicy, multi_linestring_tag>
  205. : project_multi< project_range<PointPolicy> >
  206. {};
  207. template <typename Geometry, typename PointPolicy>
  208. struct project_geometry<Geometry, PointPolicy, ring_tag>
  209. : project_range<PointPolicy>
  210. {};
  211. template <typename Geometry, typename PointPolicy>
  212. struct project_geometry<Geometry, PointPolicy, polygon_tag>
  213. {
  214. template <typename G1, typename G2, typename Proj>
  215. static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
  216. {
  217. bool r1 = project_range
  218. <
  219. PointPolicy
  220. >::apply(geometry::exterior_ring(g1),
  221. geometry::exterior_ring(g2),
  222. proj);
  223. bool r2 = project_multi
  224. <
  225. project_range<PointPolicy>
  226. >::apply(geometry::interior_rings(g1),
  227. geometry::interior_rings(g2),
  228. proj);
  229. return r1 && r2;
  230. }
  231. };
  232. template <typename MultiPolygon, typename PointPolicy>
  233. struct project_geometry<MultiPolygon, PointPolicy, multi_polygon_tag>
  234. : project_multi
  235. <
  236. project_geometry
  237. <
  238. typename boost::range_value<MultiPolygon>::type,
  239. PointPolicy,
  240. polygon_tag
  241. >
  242. >
  243. {};
  244. } // namespace detail
  245. #endif // DOXYGEN_NO_DETAIL
  246. template <typename Params>
  247. struct dynamic_parameters
  248. {
  249. static const bool is_specialized = false;
  250. };
  251. template <>
  252. struct dynamic_parameters<srs::proj4>
  253. {
  254. static const bool is_specialized = true;
  255. static inline srs::detail::proj4_parameters apply(srs::proj4 const& params)
  256. {
  257. return srs::detail::proj4_parameters(params.str());
  258. }
  259. };
  260. template <typename T>
  261. struct dynamic_parameters<srs::dpar::parameters<T> >
  262. {
  263. static const bool is_specialized = true;
  264. static inline srs::dpar::parameters<T> const& apply(srs::dpar::parameters<T> const& params)
  265. {
  266. return params;
  267. }
  268. };
  269. // proj_wrapper class and its specializations wrapps the internal projection
  270. // representation and implements transparent creation of projection object
  271. template <typename Proj, typename CT>
  272. class proj_wrapper
  273. {
  274. BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
  275. "Unknown projection definition.",
  276. Proj);
  277. };
  278. template <typename CT>
  279. class proj_wrapper<srs::dynamic, CT>
  280. {
  281. // Some projections do not work with float -> wrong results
  282. // select <double> from int/float/double and else selects T
  283. typedef typename projections::detail::promote_to_double<CT>::type calc_t;
  284. typedef projections::parameters<calc_t> parameters_type;
  285. typedef projections::detail::dynamic_wrapper_b<calc_t, parameters_type> vprj_t;
  286. public:
  287. template
  288. <
  289. typename Params,
  290. std::enable_if_t
  291. <
  292. dynamic_parameters<Params>::is_specialized,
  293. int
  294. > = 0
  295. >
  296. proj_wrapper(Params const& params)
  297. : m_ptr(create(dynamic_parameters<Params>::apply(params)))
  298. {}
  299. vprj_t const& proj() const { return *m_ptr; }
  300. vprj_t & mutable_proj() { return *m_ptr; }
  301. private:
  302. template <typename Params>
  303. static vprj_t* create(Params const& params)
  304. {
  305. parameters_type parameters = projections::detail::pj_init<calc_t>(params);
  306. vprj_t* result = projections::detail::create_new(params, parameters);
  307. if (result == NULL)
  308. {
  309. if (parameters.id.is_unknown())
  310. {
  311. BOOST_THROW_EXCEPTION(projection_not_named_exception());
  312. }
  313. else
  314. {
  315. // TODO: handle non-string projection id
  316. BOOST_THROW_EXCEPTION(projection_unknown_id_exception());
  317. }
  318. }
  319. return result;
  320. }
  321. boost::shared_ptr<vprj_t> m_ptr;
  322. };
  323. template <typename StaticParameters, typename CT>
  324. class static_proj_wrapper_base
  325. {
  326. typedef typename projections::detail::promote_to_double<CT>::type calc_t;
  327. typedef projections::parameters<calc_t> parameters_type;
  328. typedef typename srs::spar::detail::pick_proj_tag
  329. <
  330. StaticParameters
  331. >::type proj_tag;
  332. typedef typename projections::detail::static_projection_type
  333. <
  334. proj_tag,
  335. typename projections::detail::static_srs_tag<StaticParameters>::type,
  336. StaticParameters,
  337. calc_t,
  338. parameters_type
  339. >::type projection_type;
  340. public:
  341. projection_type const& proj() const { return m_proj; }
  342. projection_type & mutable_proj() { return m_proj; }
  343. protected:
  344. explicit static_proj_wrapper_base(StaticParameters const& s_params)
  345. : m_proj(s_params,
  346. projections::detail::pj_init<calc_t>(s_params))
  347. {}
  348. private:
  349. projection_type m_proj;
  350. };
  351. template <typename ...Ps, typename CT>
  352. class proj_wrapper<srs::spar::parameters<Ps...>, CT>
  353. : public static_proj_wrapper_base<srs::spar::parameters<Ps...>, CT>
  354. {
  355. typedef srs::spar::parameters<Ps...>
  356. static_parameters_type;
  357. typedef static_proj_wrapper_base
  358. <
  359. static_parameters_type,
  360. CT
  361. > base_t;
  362. public:
  363. proj_wrapper()
  364. : base_t(static_parameters_type())
  365. {}
  366. proj_wrapper(static_parameters_type const& s_params)
  367. : base_t(s_params)
  368. {}
  369. };
  370. // projection class implements transparent forward/inverse projection interface
  371. template <typename Proj, typename CT>
  372. class projection
  373. : private proj_wrapper<Proj, CT>
  374. {
  375. typedef proj_wrapper<Proj, CT> base_t;
  376. public:
  377. projection()
  378. {}
  379. template <typename Params>
  380. explicit projection(Params const& params)
  381. : base_t(params)
  382. {}
  383. /// Forward projection, from Latitude-Longitude to Cartesian
  384. template <typename LL, typename XY>
  385. inline bool forward(LL const& ll, XY& xy) const
  386. {
  387. BOOST_GEOMETRY_STATIC_ASSERT(
  388. (projections::detail::same_tags<LL, XY>::value),
  389. "Not supported combination of Geometries.",
  390. LL, XY);
  391. concepts::check_concepts_and_equal_dimensions<LL const, XY>();
  392. return projections::detail::project_geometry
  393. <
  394. LL,
  395. projections::detail::forward_point_projection_policy
  396. >::apply(ll, xy, base_t::proj());
  397. }
  398. /// Inverse projection, from Cartesian to Latitude-Longitude
  399. template <typename XY, typename LL>
  400. inline bool inverse(XY const& xy, LL& ll) const
  401. {
  402. BOOST_GEOMETRY_STATIC_ASSERT(
  403. (projections::detail::same_tags<XY, LL>::value),
  404. "Not supported combination of Geometries.",
  405. XY, LL);
  406. concepts::check_concepts_and_equal_dimensions<XY const, LL>();
  407. return projections::detail::project_geometry
  408. <
  409. XY,
  410. projections::detail::inverse_point_projection_policy
  411. >::apply(xy, ll, base_t::proj());
  412. }
  413. };
  414. } // namespace projections
  415. namespace srs
  416. {
  417. /*!
  418. \brief Representation of projection
  419. \details Either dynamic or static projection representation
  420. \ingroup projection
  421. \tparam Parameters default dynamic tag or static projection parameters
  422. \tparam CT calculation type used internally
  423. */
  424. template
  425. <
  426. typename Parameters = srs::dynamic,
  427. typename CT = double
  428. >
  429. class projection
  430. : public projections::projection<Parameters, CT>
  431. {
  432. typedef projections::projection<Parameters, CT> base_t;
  433. public:
  434. projection()
  435. {}
  436. projection(Parameters const& parameters)
  437. : base_t(parameters)
  438. {}
  439. /*!
  440. \ingroup projection
  441. \brief Initializes a projection as a string, using the format with + and =
  442. \details The projection can be initialized with a string (with the same format as the PROJ4 package) for
  443. convenient initialization from, for example, the command line
  444. \par Example
  445. <tt>srs::proj4("+proj=labrd +ellps=intl +lon_0=46d26'13.95E +lat_0=18d54S +azi=18d54 +k_0=.9995 +x_0=400000 +y_0=800000")</tt>
  446. for the Madagascar projection.
  447. */
  448. template
  449. <
  450. typename DynamicParameters,
  451. std::enable_if_t
  452. <
  453. projections::dynamic_parameters<DynamicParameters>::is_specialized,
  454. int
  455. > = 0
  456. >
  457. projection(DynamicParameters const& dynamic_parameters)
  458. : base_t(dynamic_parameters)
  459. {}
  460. };
  461. } // namespace srs
  462. }} // namespace boost::geometry
  463. #endif // BOOST_GEOMETRY_SRS_PROJECTION_HPP