projection.hpp 16 KB

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