convert.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
  5. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  6. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  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_ALGORITHMS_CONVERT_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
  12. #include <cstddef>
  13. #include <boost/numeric/conversion/cast.hpp>
  14. #include <boost/range.hpp>
  15. #include <boost/type_traits/is_array.hpp>
  16. #include <boost/geometry/arithmetic/arithmetic.hpp>
  17. #include <boost/geometry/algorithms/not_implemented.hpp>
  18. #include <boost/geometry/algorithms/append.hpp>
  19. #include <boost/geometry/algorithms/clear.hpp>
  20. #include <boost/geometry/algorithms/for_each.hpp>
  21. #include <boost/geometry/algorithms/detail/assign_values.hpp>
  22. #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
  23. #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
  24. #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
  25. #include <boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp>
  26. #include <boost/geometry/views/closeable_view.hpp>
  27. #include <boost/geometry/views/reversible_view.hpp>
  28. #include <boost/geometry/core/cs.hpp>
  29. #include <boost/geometry/core/closure.hpp>
  30. #include <boost/geometry/core/point_order.hpp>
  31. #include <boost/geometry/geometries/concepts/check.hpp>
  32. #include <boost/variant/static_visitor.hpp>
  33. #include <boost/variant/apply_visitor.hpp>
  34. #include <boost/variant/variant_fwd.hpp>
  35. namespace boost { namespace geometry
  36. {
  37. // Silence warning C4127: conditional expression is constant
  38. // Silence warning C4512: assignment operator could not be generated
  39. #if defined(_MSC_VER)
  40. #pragma warning(push)
  41. #pragma warning(disable : 4127 4512)
  42. #endif
  43. #ifndef DOXYGEN_NO_DETAIL
  44. namespace detail { namespace conversion
  45. {
  46. template
  47. <
  48. typename Point,
  49. typename Box,
  50. std::size_t Index,
  51. std::size_t Dimension,
  52. std::size_t DimensionCount
  53. >
  54. struct point_to_box
  55. {
  56. static inline void apply(Point const& point, Box& box)
  57. {
  58. typedef typename coordinate_type<Box>::type coordinate_type;
  59. set<Index, Dimension>(box,
  60. boost::numeric_cast<coordinate_type>(get<Dimension>(point)));
  61. point_to_box
  62. <
  63. Point, Box,
  64. Index, Dimension + 1, DimensionCount
  65. >::apply(point, box);
  66. }
  67. };
  68. template
  69. <
  70. typename Point,
  71. typename Box,
  72. std::size_t Index,
  73. std::size_t DimensionCount
  74. >
  75. struct point_to_box<Point, Box, Index, DimensionCount, DimensionCount>
  76. {
  77. static inline void apply(Point const& , Box& )
  78. {}
  79. };
  80. template <typename Box, typename Range, bool Close, bool Reverse>
  81. struct box_to_range
  82. {
  83. static inline void apply(Box const& box, Range& range)
  84. {
  85. traits::resize<Range>::apply(range, Close ? 5 : 4);
  86. assign_box_corners_oriented<Reverse>(box, range);
  87. if (Close)
  88. {
  89. range[4] = range[0];
  90. }
  91. }
  92. };
  93. template <typename Segment, typename Range>
  94. struct segment_to_range
  95. {
  96. static inline void apply(Segment const& segment, Range& range)
  97. {
  98. traits::resize<Range>::apply(range, 2);
  99. typename boost::range_iterator<Range>::type it = boost::begin(range);
  100. assign_point_from_index<0>(segment, *it);
  101. ++it;
  102. assign_point_from_index<1>(segment, *it);
  103. }
  104. };
  105. template
  106. <
  107. typename Range1,
  108. typename Range2,
  109. bool Reverse = false
  110. >
  111. struct range_to_range
  112. {
  113. typedef typename reversible_view
  114. <
  115. Range1 const,
  116. Reverse ? iterate_reverse : iterate_forward
  117. >::type rview_type;
  118. typedef typename closeable_view
  119. <
  120. rview_type const,
  121. geometry::closure<Range1>::value
  122. >::type view_type;
  123. static inline void apply(Range1 const& source, Range2& destination)
  124. {
  125. geometry::clear(destination);
  126. rview_type rview(source);
  127. // We consider input always as closed, and skip last
  128. // point for open output.
  129. view_type view(rview);
  130. int n = boost::size(view);
  131. if (geometry::closure<Range2>::value == geometry::open)
  132. {
  133. n--;
  134. }
  135. int i = 0;
  136. for (typename boost::range_iterator<view_type const>::type it
  137. = boost::begin(view);
  138. it != boost::end(view) && i < n;
  139. ++it, ++i)
  140. {
  141. geometry::append(destination, *it);
  142. }
  143. }
  144. };
  145. template <typename Polygon1, typename Polygon2>
  146. struct polygon_to_polygon
  147. {
  148. typedef range_to_range
  149. <
  150. typename geometry::ring_type<Polygon1>::type,
  151. typename geometry::ring_type<Polygon2>::type,
  152. geometry::point_order<Polygon1>::value
  153. != geometry::point_order<Polygon2>::value
  154. > per_ring;
  155. static inline void apply(Polygon1 const& source, Polygon2& destination)
  156. {
  157. // Clearing managed per ring, and in the resizing of interior rings
  158. per_ring::apply(geometry::exterior_ring(source),
  159. geometry::exterior_ring(destination));
  160. // Container should be resizeable
  161. traits::resize
  162. <
  163. typename boost::remove_reference
  164. <
  165. typename traits::interior_mutable_type<Polygon2>::type
  166. >::type
  167. >::apply(interior_rings(destination), num_interior_rings(source));
  168. typename interior_return_type<Polygon1 const>::type rings_source
  169. = interior_rings(source);
  170. typename interior_return_type<Polygon2>::type rings_dest
  171. = interior_rings(destination);
  172. BOOST_AUTO_TPL(it_source, boost::begin(rings_source));
  173. BOOST_AUTO_TPL(it_dest, boost::begin(rings_dest));
  174. for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
  175. {
  176. per_ring::apply(*it_source, *it_dest);
  177. }
  178. }
  179. };
  180. }} // namespace detail::conversion
  181. #endif // DOXYGEN_NO_DETAIL
  182. #ifndef DOXYGEN_NO_DISPATCH
  183. namespace dispatch
  184. {
  185. template
  186. <
  187. typename Geometry1, typename Geometry2,
  188. typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
  189. typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
  190. std::size_t DimensionCount = dimension<Geometry1>::type::value,
  191. bool UseAssignment = boost::is_same<Geometry1, Geometry2>::value
  192. && !boost::is_array<Geometry1>::value
  193. >
  194. struct convert: not_implemented<Tag1, Tag2, mpl::int_<DimensionCount> >
  195. {};
  196. template
  197. <
  198. typename Geometry1, typename Geometry2,
  199. typename Tag,
  200. std::size_t DimensionCount
  201. >
  202. struct convert<Geometry1, Geometry2, Tag, Tag, DimensionCount, true>
  203. {
  204. // Same geometry type -> copy whole geometry
  205. static inline void apply(Geometry1 const& source, Geometry2& destination)
  206. {
  207. destination = source;
  208. }
  209. };
  210. template
  211. <
  212. typename Geometry1, typename Geometry2,
  213. std::size_t DimensionCount
  214. >
  215. struct convert<Geometry1, Geometry2, point_tag, point_tag, DimensionCount, false>
  216. : detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount>
  217. {};
  218. template
  219. <
  220. typename Box1, typename Box2,
  221. std::size_t DimensionCount
  222. >
  223. struct convert<Box1, Box2, box_tag, box_tag, DimensionCount, false>
  224. : detail::conversion::indexed_to_indexed<Box1, Box2, 0, DimensionCount>
  225. {};
  226. template
  227. <
  228. typename Segment1, typename Segment2,
  229. std::size_t DimensionCount
  230. >
  231. struct convert<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, false>
  232. : detail::conversion::indexed_to_indexed<Segment1, Segment2, 0, DimensionCount>
  233. {};
  234. template <typename Segment, typename LineString, std::size_t DimensionCount>
  235. struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount, false>
  236. : detail::conversion::segment_to_range<Segment, LineString>
  237. {};
  238. template <typename Ring1, typename Ring2, std::size_t DimensionCount>
  239. struct convert<Ring1, Ring2, ring_tag, ring_tag, DimensionCount, false>
  240. : detail::conversion::range_to_range
  241. <
  242. Ring1,
  243. Ring2,
  244. geometry::point_order<Ring1>::value
  245. != geometry::point_order<Ring2>::value
  246. >
  247. {};
  248. template <typename LineString1, typename LineString2, std::size_t DimensionCount>
  249. struct convert<LineString1, LineString2, linestring_tag, linestring_tag, DimensionCount, false>
  250. : detail::conversion::range_to_range<LineString1, LineString2>
  251. {};
  252. template <typename Polygon1, typename Polygon2, std::size_t DimensionCount>
  253. struct convert<Polygon1, Polygon2, polygon_tag, polygon_tag, DimensionCount, false>
  254. : detail::conversion::polygon_to_polygon<Polygon1, Polygon2>
  255. {};
  256. template <typename Box, typename Ring>
  257. struct convert<Box, Ring, box_tag, ring_tag, 2, false>
  258. : detail::conversion::box_to_range
  259. <
  260. Box,
  261. Ring,
  262. geometry::closure<Ring>::value == closed,
  263. geometry::point_order<Ring>::value == counterclockwise
  264. >
  265. {};
  266. template <typename Box, typename Polygon>
  267. struct convert<Box, Polygon, box_tag, polygon_tag, 2, false>
  268. {
  269. static inline void apply(Box const& box, Polygon& polygon)
  270. {
  271. typedef typename ring_type<Polygon>::type ring_type;
  272. convert
  273. <
  274. Box, ring_type,
  275. box_tag, ring_tag,
  276. 2, false
  277. >::apply(box, exterior_ring(polygon));
  278. }
  279. };
  280. template <typename Point, typename Box, std::size_t DimensionCount>
  281. struct convert<Point, Box, point_tag, box_tag, DimensionCount, false>
  282. {
  283. static inline void apply(Point const& point, Box& box)
  284. {
  285. detail::conversion::point_to_box
  286. <
  287. Point, Box, min_corner, 0, DimensionCount
  288. >::apply(point, box);
  289. detail::conversion::point_to_box
  290. <
  291. Point, Box, max_corner, 0, DimensionCount
  292. >::apply(point, box);
  293. }
  294. };
  295. template <typename Ring, typename Polygon, std::size_t DimensionCount>
  296. struct convert<Ring, Polygon, ring_tag, polygon_tag, DimensionCount, false>
  297. {
  298. static inline void apply(Ring const& ring, Polygon& polygon)
  299. {
  300. typedef typename ring_type<Polygon>::type ring_type;
  301. convert
  302. <
  303. Ring, ring_type,
  304. ring_tag, ring_tag,
  305. DimensionCount, false
  306. >::apply(ring, exterior_ring(polygon));
  307. }
  308. };
  309. template <typename Polygon, typename Ring, std::size_t DimensionCount>
  310. struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
  311. {
  312. static inline void apply(Polygon const& polygon, Ring& ring)
  313. {
  314. typedef typename ring_type<Polygon>::type ring_type;
  315. convert
  316. <
  317. ring_type, Ring,
  318. ring_tag, ring_tag,
  319. DimensionCount, false
  320. >::apply(exterior_ring(polygon), ring);
  321. }
  322. };
  323. template <typename Geometry1, typename Geometry2>
  324. struct devarianted_convert
  325. {
  326. static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2)
  327. {
  328. concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
  329. convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
  330. }
  331. };
  332. template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
  333. struct devarianted_convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
  334. {
  335. struct visitor: static_visitor<void>
  336. {
  337. Geometry2& m_geometry2;
  338. visitor(Geometry2& geometry2)
  339. : m_geometry2(geometry2)
  340. {}
  341. template <typename Geometry1>
  342. inline void operator()(Geometry1 const& geometry1) const
  343. {
  344. devarianted_convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
  345. }
  346. };
  347. static inline void apply(
  348. boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
  349. Geometry2& geometry2
  350. )
  351. {
  352. apply_visitor(visitor(geometry2), geometry1);
  353. }
  354. };
  355. } // namespace dispatch
  356. #endif // DOXYGEN_NO_DISPATCH
  357. /*!
  358. \brief Converts one geometry to another geometry
  359. \details The convert algorithm converts one geometry, e.g. a BOX, to another
  360. geometry, e.g. a RING. This only works if it is possible and applicable.
  361. If the point-order is different, or the closure is different between two
  362. geometry types, it will be converted correctly by explicitly reversing the
  363. points or closing or opening the polygon rings.
  364. \ingroup convert
  365. \tparam Geometry1 \tparam_geometry
  366. \tparam Geometry2 \tparam_geometry
  367. \param geometry1 \param_geometry (source)
  368. \param geometry2 \param_geometry (target)
  369. \qbk{[include reference/algorithms/convert.qbk]}
  370. */
  371. template <typename Geometry1, typename Geometry2>
  372. inline void convert(Geometry1 const& geometry1, Geometry2& geometry2)
  373. {
  374. dispatch::devarianted_convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
  375. }
  376. #if defined(_MSC_VER)
  377. #pragma warning(pop)
  378. #endif
  379. }} // namespace boost::geometry
  380. #endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP