copy_segment_point.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2020-2021.
  5. // Modifications copyright (c) 2020-2021, 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_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
  12. #include <array>
  13. #include <boost/range/begin.hpp>
  14. #include <boost/range/end.hpp>
  15. #include <boost/range/size.hpp>
  16. #include <boost/range/value_type.hpp>
  17. #include <boost/geometry/algorithms/convert.hpp>
  18. #include <boost/geometry/algorithms/detail/signed_size_type.hpp>
  19. #include <boost/geometry/core/assert.hpp>
  20. #include <boost/geometry/core/exterior_ring.hpp>
  21. #include <boost/geometry/core/interior_rings.hpp>
  22. #include <boost/geometry/core/ring_type.hpp>
  23. #include <boost/geometry/core/static_assert.hpp>
  24. #include <boost/geometry/core/tags.hpp>
  25. #include <boost/geometry/geometries/concepts/check.hpp>
  26. #include <boost/geometry/util/range.hpp>
  27. #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
  28. namespace boost { namespace geometry
  29. {
  30. #ifndef DOXYGEN_NO_DETAIL
  31. namespace detail { namespace copy_segments
  32. {
  33. inline signed_size_type circular_offset(signed_size_type segment_count, signed_size_type index,
  34. signed_size_type offset)
  35. {
  36. signed_size_type result = (index + offset) % segment_count;
  37. if (result < 0)
  38. {
  39. result += segment_count;
  40. }
  41. return result;
  42. }
  43. template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut>
  44. struct copy_segment_point_range
  45. {
  46. static inline bool apply(Range const& range,
  47. SegmentIdentifier const& seg_id, signed_size_type offset,
  48. PointOut& point)
  49. {
  50. using view_type = detail::closed_clockwise_view
  51. <
  52. Range const,
  53. closure<Range>::value,
  54. Reverse ? counterclockwise : clockwise
  55. >;
  56. view_type view(range);
  57. std::size_t const segment_count = boost::size(view) - 1;
  58. signed_size_type const target = circular_offset(segment_count, seg_id.segment_index, offset);
  59. BOOST_GEOMETRY_ASSERT(target >= 0
  60. && std::size_t(target) < boost::size(view));
  61. geometry::convert(range::at(view, target), point);
  62. return true;
  63. }
  64. };
  65. template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
  66. struct copy_segment_point_polygon
  67. {
  68. static inline bool apply(Polygon const& polygon,
  69. SegmentIdentifier const& seg_id, signed_size_type offset,
  70. PointOut& point)
  71. {
  72. // Call ring-version with the right ring
  73. return copy_segment_point_range
  74. <
  75. typename geometry::ring_type<Polygon>::type,
  76. Reverse,
  77. SegmentIdentifier,
  78. PointOut
  79. >::apply
  80. (
  81. seg_id.ring_index < 0
  82. ? geometry::exterior_ring(polygon)
  83. : range::at(geometry::interior_rings(polygon), seg_id.ring_index),
  84. seg_id, offset,
  85. point
  86. );
  87. }
  88. };
  89. template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
  90. struct copy_segment_point_box
  91. {
  92. static inline bool apply(Box const& box,
  93. SegmentIdentifier const& seg_id, signed_size_type offset,
  94. PointOut& point)
  95. {
  96. std::array<typename point_type<Box>::type, 4> bp;
  97. assign_box_corners_oriented<Reverse>(box, bp);
  98. signed_size_type const target = circular_offset(4, seg_id.segment_index, offset);
  99. BOOST_GEOMETRY_ASSERT(target >= 0
  100. && std::size_t(target) < bp.size());
  101. point = bp[target];
  102. return true;
  103. }
  104. };
  105. template
  106. <
  107. typename MultiGeometry,
  108. typename SegmentIdentifier,
  109. typename PointOut,
  110. typename Policy
  111. >
  112. struct copy_segment_point_multi
  113. {
  114. static inline bool apply(MultiGeometry const& multi,
  115. SegmentIdentifier const& seg_id, signed_size_type offset,
  116. PointOut& point)
  117. {
  118. BOOST_GEOMETRY_ASSERT(seg_id.multi_index >= 0
  119. && std::size_t(seg_id.multi_index) < boost::size(multi));
  120. // Call the single-version
  121. return Policy::apply(range::at(multi, seg_id.multi_index), seg_id, offset, point);
  122. }
  123. };
  124. }} // namespace detail::copy_segments
  125. #endif // DOXYGEN_NO_DETAIL
  126. #ifndef DOXYGEN_NO_DISPATCH
  127. namespace dispatch
  128. {
  129. template
  130. <
  131. typename Tag,
  132. typename GeometryIn,
  133. bool Reverse,
  134. typename SegmentIdentifier,
  135. typename PointOut
  136. >
  137. struct copy_segment_point
  138. {
  139. BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
  140. "Not or not yet implemented for this Geometry type.",
  141. Tag, GeometryIn);
  142. };
  143. template <typename LineString, bool Reverse, typename SegmentIdentifier, typename PointOut>
  144. struct copy_segment_point<linestring_tag, LineString, Reverse, SegmentIdentifier, PointOut>
  145. : detail::copy_segments::copy_segment_point_range
  146. <
  147. LineString, Reverse, SegmentIdentifier, PointOut
  148. >
  149. {};
  150. template <typename Ring, bool Reverse, typename SegmentIdentifier, typename PointOut>
  151. struct copy_segment_point<ring_tag, Ring, Reverse, SegmentIdentifier, PointOut>
  152. : detail::copy_segments::copy_segment_point_range
  153. <
  154. Ring, Reverse, SegmentIdentifier, PointOut
  155. >
  156. {};
  157. template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
  158. struct copy_segment_point<polygon_tag, Polygon, Reverse, SegmentIdentifier, PointOut>
  159. : detail::copy_segments::copy_segment_point_polygon
  160. <
  161. Polygon, Reverse, SegmentIdentifier, PointOut
  162. >
  163. {};
  164. template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
  165. struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut>
  166. : detail::copy_segments::copy_segment_point_box
  167. <
  168. Box, Reverse, SegmentIdentifier, PointOut
  169. >
  170. {};
  171. template
  172. <
  173. typename MultiGeometry,
  174. bool Reverse,
  175. typename SegmentIdentifier,
  176. typename PointOut
  177. >
  178. struct copy_segment_point
  179. <
  180. multi_polygon_tag,
  181. MultiGeometry,
  182. Reverse,
  183. SegmentIdentifier,
  184. PointOut
  185. >
  186. : detail::copy_segments::copy_segment_point_multi
  187. <
  188. MultiGeometry,
  189. SegmentIdentifier,
  190. PointOut,
  191. detail::copy_segments::copy_segment_point_polygon
  192. <
  193. typename boost::range_value<MultiGeometry>::type,
  194. Reverse,
  195. SegmentIdentifier,
  196. PointOut
  197. >
  198. >
  199. {};
  200. template
  201. <
  202. typename MultiGeometry,
  203. bool Reverse,
  204. typename SegmentIdentifier,
  205. typename PointOut
  206. >
  207. struct copy_segment_point
  208. <
  209. multi_linestring_tag,
  210. MultiGeometry,
  211. Reverse,
  212. SegmentIdentifier,
  213. PointOut
  214. >
  215. : detail::copy_segments::copy_segment_point_multi
  216. <
  217. MultiGeometry,
  218. SegmentIdentifier,
  219. PointOut,
  220. detail::copy_segments::copy_segment_point_range
  221. <
  222. typename boost::range_value<MultiGeometry>::type,
  223. Reverse,
  224. SegmentIdentifier,
  225. PointOut
  226. >
  227. >
  228. {};
  229. } // namespace dispatch
  230. #endif // DOXYGEN_NO_DISPATCH
  231. /*!
  232. \brief Helper function, copies a point from a segment
  233. \ingroup overlay
  234. */
  235. template<bool Reverse, typename Geometry, typename SegmentIdentifier, typename PointOut>
  236. inline bool copy_segment_point(Geometry const& geometry,
  237. SegmentIdentifier const& seg_id, signed_size_type offset,
  238. PointOut& point_out)
  239. {
  240. concepts::check<Geometry const>();
  241. return dispatch::copy_segment_point
  242. <
  243. typename tag<Geometry>::type,
  244. Geometry,
  245. Reverse,
  246. SegmentIdentifier,
  247. PointOut
  248. >::apply(geometry, seg_id, offset, point_out);
  249. }
  250. /*!
  251. \brief Helper function, to avoid the same construct several times,
  252. copies a point, based on a source-index and two geometries
  253. \ingroup overlay
  254. */
  255. template
  256. <
  257. bool Reverse1, bool Reverse2,
  258. typename Geometry1, typename Geometry2,
  259. typename SegmentIdentifier,
  260. typename PointOut
  261. >
  262. inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geometry2,
  263. SegmentIdentifier const& seg_id, signed_size_type offset,
  264. PointOut& point_out)
  265. {
  266. concepts::check<Geometry1 const>();
  267. concepts::check<Geometry2 const>();
  268. BOOST_GEOMETRY_ASSERT(seg_id.source_index == 0 || seg_id.source_index == 1);
  269. if (seg_id.source_index == 0)
  270. {
  271. return dispatch::copy_segment_point
  272. <
  273. typename tag<Geometry1>::type,
  274. Geometry1,
  275. Reverse1,
  276. SegmentIdentifier,
  277. PointOut
  278. >::apply(geometry1, seg_id, offset, point_out);
  279. }
  280. else if (seg_id.source_index == 1)
  281. {
  282. return dispatch::copy_segment_point
  283. <
  284. typename tag<Geometry2>::type,
  285. Geometry2,
  286. Reverse2,
  287. SegmentIdentifier,
  288. PointOut
  289. >::apply(geometry2, seg_id, offset, point_out);
  290. }
  291. // Exception?
  292. return false;
  293. }
  294. /*!
  295. \brief Helper function, to avoid the same construct several times,
  296. copies a point, based on a source-index and two geometries
  297. \ingroup overlay
  298. */
  299. template
  300. <
  301. bool Reverse1, bool Reverse2,
  302. typename Geometry1, typename Geometry2,
  303. typename SegmentIdentifier,
  304. typename PointOut
  305. >
  306. inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geometry2,
  307. SegmentIdentifier const& seg_id,
  308. PointOut& point1, PointOut& point2)
  309. {
  310. concepts::check<Geometry1 const>();
  311. concepts::check<Geometry2 const>();
  312. return copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 0, point1)
  313. && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 1, point2);
  314. }
  315. /*!
  316. \brief Helper function, copies three points: two from the specified segment
  317. (from, to) and the next one
  318. \ingroup overlay
  319. */
  320. template
  321. <
  322. bool Reverse1, bool Reverse2,
  323. typename Geometry1, typename Geometry2,
  324. typename SegmentIdentifier,
  325. typename PointOut
  326. >
  327. inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geometry2,
  328. SegmentIdentifier const& seg_id,
  329. PointOut& point1, PointOut& point2, PointOut& point3)
  330. {
  331. concepts::check<Geometry1 const>();
  332. concepts::check<Geometry2 const>();
  333. return copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 0, point1)
  334. && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 1, point2)
  335. && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 2, point3);
  336. }
  337. }} // namespace boost::geometry
  338. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP