transformation.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2017-2018, Oracle and/or its affiliates.
  3. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  4. // Use, modification and distribution is subject to the Boost Software License,
  5. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_GEOMETRY_SRS_TRANSFORMATION_HPP
  8. #define BOOST_GEOMETRY_SRS_TRANSFORMATION_HPP
  9. #include <string>
  10. #include <boost/geometry/algorithms/convert.hpp>
  11. #include <boost/geometry/core/coordinate_dimension.hpp>
  12. #include <boost/geometry/geometries/point.hpp>
  13. #include <boost/geometry/geometries/multi_point.hpp>
  14. #include <boost/geometry/geometries/linestring.hpp>
  15. #include <boost/geometry/geometries/ring.hpp>
  16. #include <boost/geometry/geometries/segment.hpp>
  17. #include <boost/geometry/srs/projection.hpp>
  18. #include <boost/geometry/srs/projections/grids.hpp>
  19. #include <boost/geometry/srs/projections/impl/pj_transform.hpp>
  20. #include <boost/geometry/views/detail/indexed_point_view.hpp>
  21. #include <boost/mpl/assert.hpp>
  22. #include <boost/mpl/if.hpp>
  23. #include <boost/smart_ptr/shared_ptr.hpp>
  24. #include <boost/throw_exception.hpp>
  25. #include <boost/type_traits/is_integral.hpp>
  26. #include <boost/type_traits/is_same.hpp>
  27. namespace boost { namespace geometry
  28. {
  29. namespace projections { namespace detail
  30. {
  31. template <typename T1, typename T2>
  32. inline bool same_object(T1 const& , T2 const& )
  33. {
  34. return false;
  35. }
  36. template <typename T>
  37. inline bool same_object(T const& o1, T const& o2)
  38. {
  39. return boost::addressof(o1) == boost::addressof(o2);
  40. }
  41. template
  42. <
  43. typename PtIn,
  44. typename PtOut,
  45. bool SameUnits = geometry::is_radian
  46. <
  47. typename geometry::coordinate_system<PtIn>::type
  48. >::type::value
  49. ==
  50. geometry::is_radian
  51. <
  52. typename geometry::coordinate_system<PtOut>::type
  53. >::type::value
  54. >
  55. struct transform_geometry_point_coordinates
  56. {
  57. static inline void apply(PtIn const& in, PtOut & out, bool /*enable_angles*/)
  58. {
  59. geometry::set<0>(out, geometry::get<0>(in));
  60. geometry::set<1>(out, geometry::get<1>(in));
  61. }
  62. };
  63. template <typename PtIn, typename PtOut>
  64. struct transform_geometry_point_coordinates<PtIn, PtOut, false>
  65. {
  66. static inline void apply(PtIn const& in, PtOut & out, bool enable_angles)
  67. {
  68. if (enable_angles)
  69. {
  70. geometry::set_from_radian<0>(out, geometry::get_as_radian<0>(in));
  71. geometry::set_from_radian<1>(out, geometry::get_as_radian<1>(in));
  72. }
  73. else
  74. {
  75. geometry::set<0>(out, geometry::get<0>(in));
  76. geometry::set<1>(out, geometry::get<1>(in));
  77. }
  78. }
  79. };
  80. template <typename Geometry, typename CT>
  81. struct transform_geometry_point
  82. {
  83. typedef typename geometry::point_type<Geometry>::type point_type;
  84. typedef geometry::model::point
  85. <
  86. typename select_most_precise
  87. <
  88. typename geometry::coordinate_type<point_type>::type,
  89. CT
  90. >::type,
  91. geometry::dimension<point_type>::type::value,
  92. typename geometry::coordinate_system<point_type>::type
  93. > type;
  94. template <typename PtIn, typename PtOut>
  95. static inline void apply(PtIn const& in, PtOut & out, bool enable_angles)
  96. {
  97. transform_geometry_point_coordinates<PtIn, PtOut>::apply(in, out, enable_angles);
  98. projections::detail::copy_higher_dimensions<2>(in, out);
  99. }
  100. };
  101. template <typename Geometry, typename CT>
  102. struct transform_geometry_range_base
  103. {
  104. struct convert_strategy
  105. {
  106. convert_strategy(bool enable_angles)
  107. : m_enable_angles(enable_angles)
  108. {}
  109. template <typename PtIn, typename PtOut>
  110. void apply(PtIn const& in, PtOut & out)
  111. {
  112. transform_geometry_point<Geometry, CT>::apply(in, out, m_enable_angles);
  113. }
  114. bool m_enable_angles;
  115. };
  116. template <typename In, typename Out>
  117. static inline void apply(In const& in, Out & out, bool enable_angles)
  118. {
  119. // Change the order and/or closure if needed
  120. // In - arbitrary geometry
  121. // Out - either Geometry or std::vector
  122. // So the order and closure of In and Geometry shoudl be compared
  123. // std::vector's order is assumed to be the same as of Geometry
  124. geometry::detail::conversion::range_to_range
  125. <
  126. In,
  127. Out,
  128. geometry::point_order<In>::value != geometry::point_order<Out>::value
  129. >::apply(in, out, convert_strategy(enable_angles));
  130. }
  131. };
  132. template
  133. <
  134. typename Geometry,
  135. typename CT,
  136. typename Tag = typename geometry::tag<Geometry>::type
  137. >
  138. struct transform_geometry
  139. {};
  140. template <typename Point, typename CT>
  141. struct transform_geometry<Point, CT, point_tag>
  142. : transform_geometry_point<Point, CT>
  143. {};
  144. template <typename Segment, typename CT>
  145. struct transform_geometry<Segment, CT, segment_tag>
  146. {
  147. typedef geometry::model::segment
  148. <
  149. typename transform_geometry_point<Segment, CT>::type
  150. > type;
  151. template <typename In, typename Out>
  152. static inline void apply(In const& in, Out & out, bool enable_angles)
  153. {
  154. apply<0>(in, out, enable_angles);
  155. apply<1>(in, out, enable_angles);
  156. }
  157. private:
  158. template <std::size_t Index, typename In, typename Out>
  159. static inline void apply(In const& in, Out & out, bool enable_angles)
  160. {
  161. geometry::detail::indexed_point_view<In const, Index> in_pt(in);
  162. geometry::detail::indexed_point_view<Out, Index> out_pt(out);
  163. transform_geometry_point<Segment, CT>::apply(in_pt, out_pt, enable_angles);
  164. }
  165. };
  166. template <typename MultiPoint, typename CT>
  167. struct transform_geometry<MultiPoint, CT, multi_point_tag>
  168. : transform_geometry_range_base<MultiPoint, CT>
  169. {
  170. typedef model::multi_point
  171. <
  172. typename transform_geometry_point<MultiPoint, CT>::type
  173. > type;
  174. };
  175. template <typename LineString, typename CT>
  176. struct transform_geometry<LineString, CT, linestring_tag>
  177. : transform_geometry_range_base<LineString, CT>
  178. {
  179. typedef model::linestring
  180. <
  181. typename transform_geometry_point<LineString, CT>::type
  182. > type;
  183. };
  184. template <typename Ring, typename CT>
  185. struct transform_geometry<Ring, CT, ring_tag>
  186. : transform_geometry_range_base<Ring, CT>
  187. {
  188. typedef model::ring
  189. <
  190. typename transform_geometry_point<Ring, CT>::type,
  191. geometry::point_order<Ring>::value == clockwise,
  192. geometry::closure<Ring>::value == closed
  193. > type;
  194. };
  195. template
  196. <
  197. typename OutGeometry,
  198. typename CT,
  199. bool EnableTemporary = ! boost::is_same
  200. <
  201. typename select_most_precise
  202. <
  203. typename geometry::coordinate_type<OutGeometry>::type,
  204. CT
  205. >::type,
  206. typename geometry::coordinate_type<OutGeometry>::type
  207. >::type::value
  208. >
  209. struct transform_geometry_wrapper
  210. {
  211. typedef transform_geometry<OutGeometry, CT> transform;
  212. typedef typename transform::type type;
  213. template <typename InGeometry>
  214. transform_geometry_wrapper(InGeometry const& in, OutGeometry & out, bool input_angles)
  215. : m_out(out)
  216. {
  217. transform::apply(in, m_temp, input_angles);
  218. }
  219. type & get() { return m_temp; }
  220. void finish() { geometry::convert(m_temp, m_out); } // this is always copy 1:1 without changing the order or closure
  221. private:
  222. type m_temp;
  223. OutGeometry & m_out;
  224. };
  225. template
  226. <
  227. typename OutGeometry,
  228. typename CT
  229. >
  230. struct transform_geometry_wrapper<OutGeometry, CT, false>
  231. {
  232. typedef transform_geometry<OutGeometry, CT> transform;
  233. typedef OutGeometry type;
  234. transform_geometry_wrapper(OutGeometry const& in, OutGeometry & out, bool input_angles)
  235. : m_out(out)
  236. {
  237. if (! same_object(in, out))
  238. transform::apply(in, out, input_angles);
  239. }
  240. template <typename InGeometry>
  241. transform_geometry_wrapper(InGeometry const& in, OutGeometry & out, bool input_angles)
  242. : m_out(out)
  243. {
  244. transform::apply(in, out, input_angles);
  245. }
  246. OutGeometry & get() { return m_out; }
  247. void finish() {}
  248. private:
  249. OutGeometry & m_out;
  250. };
  251. template <typename CT>
  252. struct transform_range
  253. {
  254. template
  255. <
  256. typename Proj1, typename Par1,
  257. typename Proj2, typename Par2,
  258. typename RangeIn, typename RangeOut,
  259. typename Grids
  260. >
  261. static inline bool apply(Proj1 const& proj1, Par1 const& par1,
  262. Proj2 const& proj2, Par2 const& par2,
  263. RangeIn const& in, RangeOut & out,
  264. Grids const& grids1, Grids const& grids2)
  265. {
  266. // NOTE: this has to be consistent with pj_transform()
  267. bool const input_angles = !par1.is_geocent && par1.is_latlong;
  268. transform_geometry_wrapper<RangeOut, CT> wrapper(in, out, input_angles);
  269. bool res = true;
  270. try
  271. {
  272. res = pj_transform(proj1, par1, proj2, par2, wrapper.get(), grids1, grids2);
  273. }
  274. catch (projection_exception const&)
  275. {
  276. res = false;
  277. }
  278. catch(...)
  279. {
  280. BOOST_RETHROW
  281. }
  282. wrapper.finish();
  283. return res;
  284. }
  285. };
  286. template <typename Policy>
  287. struct transform_multi
  288. {
  289. template
  290. <
  291. typename Proj1, typename Par1,
  292. typename Proj2, typename Par2,
  293. typename MultiIn, typename MultiOut,
  294. typename Grids
  295. >
  296. static inline bool apply(Proj1 const& proj1, Par1 const& par1,
  297. Proj2 const& proj2, Par2 const& par2,
  298. MultiIn const& in, MultiOut & out,
  299. Grids const& grids1, Grids const& grids2)
  300. {
  301. if (! same_object(in, out))
  302. range::resize(out, boost::size(in));
  303. return apply(proj1, par1, proj2, par2,
  304. boost::begin(in), boost::end(in),
  305. boost::begin(out),
  306. grids1, grids2);
  307. }
  308. private:
  309. template
  310. <
  311. typename Proj1, typename Par1,
  312. typename Proj2, typename Par2,
  313. typename InIt, typename OutIt,
  314. typename Grids
  315. >
  316. static inline bool apply(Proj1 const& proj1, Par1 const& par1,
  317. Proj2 const& proj2, Par2 const& par2,
  318. InIt in_first, InIt in_last, OutIt out_first,
  319. Grids const& grids1, Grids const& grids2)
  320. {
  321. bool res = true;
  322. for ( ; in_first != in_last ; ++in_first, ++out_first )
  323. {
  324. if ( ! Policy::apply(proj1, par1, proj2, par2, *in_first, *out_first, grids1, grids2) )
  325. {
  326. res = false;
  327. }
  328. }
  329. return res;
  330. }
  331. };
  332. template
  333. <
  334. typename Geometry,
  335. typename CT,
  336. typename Tag = typename geometry::tag<Geometry>::type
  337. >
  338. struct transform
  339. : not_implemented<Tag>
  340. {};
  341. template <typename Point, typename CT>
  342. struct transform<Point, CT, point_tag>
  343. {
  344. template
  345. <
  346. typename Proj1, typename Par1,
  347. typename Proj2, typename Par2,
  348. typename PointIn, typename PointOut,
  349. typename Grids
  350. >
  351. static inline bool apply(Proj1 const& proj1, Par1 const& par1,
  352. Proj2 const& proj2, Par2 const& par2,
  353. PointIn const& in, PointOut & out,
  354. Grids const& grids1, Grids const& grids2)
  355. {
  356. // NOTE: this has to be consistent with pj_transform()
  357. bool const input_angles = !par1.is_geocent && par1.is_latlong;
  358. transform_geometry_wrapper<PointOut, CT> wrapper(in, out, input_angles);
  359. typedef typename transform_geometry_wrapper<PointOut, CT>::type point_type;
  360. point_type * ptr = boost::addressof(wrapper.get());
  361. std::pair<point_type *, point_type *> range = std::make_pair(ptr, ptr + 1);
  362. bool res = true;
  363. try
  364. {
  365. res = pj_transform(proj1, par1, proj2, par2, range, grids1, grids2);
  366. }
  367. catch (projection_exception const&)
  368. {
  369. res = false;
  370. }
  371. catch(...)
  372. {
  373. BOOST_RETHROW
  374. }
  375. wrapper.finish();
  376. return res;
  377. }
  378. };
  379. template <typename MultiPoint, typename CT>
  380. struct transform<MultiPoint, CT, multi_point_tag>
  381. : transform_range<CT>
  382. {};
  383. template <typename Segment, typename CT>
  384. struct transform<Segment, CT, segment_tag>
  385. {
  386. template
  387. <
  388. typename Proj1, typename Par1,
  389. typename Proj2, typename Par2,
  390. typename SegmentIn, typename SegmentOut,
  391. typename Grids
  392. >
  393. static inline bool apply(Proj1 const& proj1, Par1 const& par1,
  394. Proj2 const& proj2, Par2 const& par2,
  395. SegmentIn const& in, SegmentOut & out,
  396. Grids const& grids1, Grids const& grids2)
  397. {
  398. // NOTE: this has to be consistent with pj_transform()
  399. bool const input_angles = !par1.is_geocent && par1.is_latlong;
  400. transform_geometry_wrapper<SegmentOut, CT> wrapper(in, out, input_angles);
  401. typedef typename geometry::point_type
  402. <
  403. typename transform_geometry_wrapper<SegmentOut, CT>::type
  404. >::type point_type;
  405. point_type points[2];
  406. geometry::detail::assign_point_from_index<0>(wrapper.get(), points[0]);
  407. geometry::detail::assign_point_from_index<1>(wrapper.get(), points[1]);
  408. std::pair<point_type*, point_type*> range = std::make_pair(points, points + 2);
  409. bool res = true;
  410. try
  411. {
  412. res = pj_transform(proj1, par1, proj2, par2, range, grids1, grids2);
  413. }
  414. catch (projection_exception const&)
  415. {
  416. res = false;
  417. }
  418. catch(...)
  419. {
  420. BOOST_RETHROW
  421. }
  422. geometry::detail::assign_point_to_index<0>(points[0], wrapper.get());
  423. geometry::detail::assign_point_to_index<1>(points[1], wrapper.get());
  424. wrapper.finish();
  425. return res;
  426. }
  427. };
  428. template <typename Linestring, typename CT>
  429. struct transform<Linestring, CT, linestring_tag>
  430. : transform_range<CT>
  431. {};
  432. template <typename MultiLinestring, typename CT>
  433. struct transform<MultiLinestring, CT, multi_linestring_tag>
  434. : transform_multi<transform_range<CT> >
  435. {};
  436. template <typename Ring, typename CT>
  437. struct transform<Ring, CT, ring_tag>
  438. : transform_range<CT>
  439. {};
  440. template <typename Polygon, typename CT>
  441. struct transform<Polygon, CT, polygon_tag>
  442. {
  443. template
  444. <
  445. typename Proj1, typename Par1,
  446. typename Proj2, typename Par2,
  447. typename PolygonIn, typename PolygonOut,
  448. typename Grids
  449. >
  450. static inline bool apply(Proj1 const& proj1, Par1 const& par1,
  451. Proj2 const& proj2, Par2 const& par2,
  452. PolygonIn const& in, PolygonOut & out,
  453. Grids const& grids1, Grids const& grids2)
  454. {
  455. bool r1 = transform_range
  456. <
  457. CT
  458. >::apply(proj1, par1, proj2, par2,
  459. geometry::exterior_ring(in),
  460. geometry::exterior_ring(out),
  461. grids1, grids2);
  462. bool r2 = transform_multi
  463. <
  464. transform_range<CT>
  465. >::apply(proj1, par1, proj2, par2,
  466. geometry::interior_rings(in),
  467. geometry::interior_rings(out),
  468. grids1, grids2);
  469. return r1 && r2;
  470. }
  471. };
  472. template <typename MultiPolygon, typename CT>
  473. struct transform<MultiPolygon, CT, multi_polygon_tag>
  474. : transform_multi
  475. <
  476. transform
  477. <
  478. typename boost::range_value<MultiPolygon>::type,
  479. CT,
  480. polygon_tag
  481. >
  482. >
  483. {};
  484. }} // namespace projections::detail
  485. namespace srs
  486. {
  487. /*!
  488. \brief Representation of projection
  489. \details Either dynamic or static projection representation
  490. \ingroup projection
  491. \tparam Proj1 default_dynamic or static projection parameters
  492. \tparam Proj2 default_dynamic or static projection parameters
  493. \tparam CT calculation type used internally
  494. */
  495. template
  496. <
  497. typename Proj1 = srs::dynamic,
  498. typename Proj2 = srs::dynamic,
  499. typename CT = double
  500. >
  501. class transformation
  502. {
  503. typedef typename projections::detail::promote_to_double<CT>::type calc_t;
  504. public:
  505. transformation()
  506. {}
  507. template <typename Parameters1>
  508. explicit transformation(Parameters1 const& parameters1)
  509. : m_proj1(parameters1)
  510. {}
  511. template <typename Parameters1, typename Parameters2>
  512. transformation(Parameters1 const& parameters1, Parameters2 const& parameters2)
  513. : m_proj1(parameters1)
  514. , m_proj2(parameters2)
  515. {}
  516. template <typename GeometryIn, typename GeometryOut>
  517. bool forward(GeometryIn const& in, GeometryOut & out) const
  518. {
  519. return forward(in, out, transformation_grids<detail::empty_grids_storage>());
  520. }
  521. template <typename GeometryIn, typename GeometryOut>
  522. bool inverse(GeometryIn const& in, GeometryOut & out) const
  523. {
  524. return inverse(in, out, transformation_grids<detail::empty_grids_storage>());
  525. }
  526. template <typename GeometryIn, typename GeometryOut, typename GridsStorage>
  527. bool forward(GeometryIn const& in, GeometryOut & out,
  528. transformation_grids<GridsStorage> const& grids) const
  529. {
  530. BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<GeometryIn, GeometryOut>::value),
  531. NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
  532. (GeometryIn, GeometryOut));
  533. return projections::detail::transform
  534. <
  535. GeometryOut,
  536. calc_t
  537. >::apply(m_proj1.proj(), m_proj1.proj().params(),
  538. m_proj2.proj(), m_proj2.proj().params(),
  539. in, out,
  540. grids.src_grids,
  541. grids.dst_grids);
  542. }
  543. template <typename GeometryIn, typename GeometryOut, typename GridsStorage>
  544. bool inverse(GeometryIn const& in, GeometryOut & out,
  545. transformation_grids<GridsStorage> const& grids) const
  546. {
  547. BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<GeometryIn, GeometryOut>::value),
  548. NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
  549. (GeometryIn, GeometryOut));
  550. return projections::detail::transform
  551. <
  552. GeometryOut,
  553. calc_t
  554. >::apply(m_proj2.proj(), m_proj2.proj().params(),
  555. m_proj1.proj(), m_proj1.proj().params(),
  556. in, out,
  557. grids.dst_grids,
  558. grids.src_grids);
  559. }
  560. template <typename GridsStorage>
  561. inline transformation_grids<GridsStorage> initialize_grids(GridsStorage & grids_storage) const
  562. {
  563. transformation_grids<GridsStorage> result(grids_storage);
  564. using namespace projections::detail;
  565. pj_gridlist_from_nadgrids(m_proj1.proj().params(),
  566. result.src_grids);
  567. pj_gridlist_from_nadgrids(m_proj2.proj().params(),
  568. result.dst_grids);
  569. return result;
  570. }
  571. private:
  572. projections::proj_wrapper<Proj1, CT> m_proj1;
  573. projections::proj_wrapper<Proj2, CT> m_proj2;
  574. };
  575. } // namespace srs
  576. }} // namespace boost::geometry
  577. #endif // BOOST_GEOMETRY_SRS_TRANSFORMATION_HPP