projection.hpp 15 KB

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