projection.hpp 15 KB

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