get_turns.hpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2014-2023 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2014-2021.
  5. // Modifications copyright (c) 2014-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_GET_TURNS_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
  12. #include <array>
  13. #include <cstddef>
  14. #include <map>
  15. #include <boost/concept_check.hpp>
  16. #include <boost/core/ignore_unused.hpp>
  17. #include <boost/range/begin.hpp>
  18. #include <boost/range/end.hpp>
  19. #include <boost/range/size.hpp>
  20. #include <boost/range/value_type.hpp>
  21. #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
  22. #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
  23. #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
  24. #include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
  25. #include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp>
  26. #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
  27. #include <boost/geometry/algorithms/detail/partition.hpp>
  28. #include <boost/geometry/algorithms/detail/recalculate.hpp>
  29. #include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
  30. #include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
  31. #include <boost/geometry/algorithms/detail/sections/section_functions.hpp>
  32. #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
  33. #include <boost/geometry/core/assert.hpp>
  34. #include <boost/geometry/core/coordinate_dimension.hpp>
  35. #include <boost/geometry/core/exterior_ring.hpp>
  36. #include <boost/geometry/core/interior_rings.hpp>
  37. #include <boost/geometry/core/reverse_dispatch.hpp>
  38. #include <boost/geometry/core/ring_type.hpp>
  39. #include <boost/geometry/core/tags.hpp>
  40. #include <boost/geometry/geometries/box.hpp>
  41. #include <boost/geometry/geometries/concepts/check.hpp>
  42. #include <boost/geometry/geometries/segment.hpp>
  43. #include <boost/geometry/iterators/ever_circling_iterator.hpp>
  44. #include <boost/geometry/strategies/intersection_strategies.hpp>
  45. #include <boost/geometry/strategies/intersection_result.hpp>
  46. #include <boost/geometry/util/math.hpp>
  47. #include <boost/geometry/util/type_traits.hpp>
  48. #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
  49. #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
  50. # include <sstream>
  51. # include <boost/geometry/io/dsv/write.hpp>
  52. #endif
  53. namespace boost { namespace geometry
  54. {
  55. // Silence warning C4127: conditional expression is constant
  56. #if defined(_MSC_VER)
  57. #pragma warning(push)
  58. #pragma warning(disable : 4127)
  59. #endif
  60. #ifndef DOXYGEN_NO_DETAIL
  61. namespace detail { namespace get_turns
  62. {
  63. struct no_interrupt_policy
  64. {
  65. static bool const enabled = false;
  66. // variable required by self_get_turn_points::get_turns
  67. static bool const has_intersections = false;
  68. template <typename Range>
  69. static inline bool apply(Range const&)
  70. {
  71. return false;
  72. }
  73. };
  74. template
  75. <
  76. bool IsAreal,
  77. typename Section,
  78. typename Point,
  79. typename CircularIterator,
  80. typename Strategy,
  81. typename RobustPolicy
  82. >
  83. struct unique_sub_range_from_section
  84. {
  85. using point_type = Point;
  86. unique_sub_range_from_section(Section const& section, signed_size_type index,
  87. CircularIterator circular_iterator,
  88. Point const& previous, Point const& current,
  89. Strategy const& strategy,
  90. RobustPolicy const& robust_policy)
  91. : m_section(section)
  92. , m_index(index)
  93. , m_previous_point(previous)
  94. , m_current_point(current)
  95. , m_circular_iterator(circular_iterator)
  96. , m_next_point_retrieved(false)
  97. , m_strategy(strategy)
  98. , m_robust_policy(robust_policy)
  99. {}
  100. inline bool is_first_segment() const
  101. {
  102. return !IsAreal && m_section.is_non_duplicate_first && m_index == m_section.begin_index;
  103. }
  104. inline bool is_last_segment() const
  105. {
  106. return size() == 2u;
  107. }
  108. inline std::size_t size() const
  109. {
  110. return IsAreal ? 3
  111. : m_section.is_non_duplicate_last && m_index + 1 >= m_section.end_index ? 2 : 3;
  112. }
  113. inline Point const& at(std::size_t index) const
  114. {
  115. BOOST_GEOMETRY_ASSERT(index < size());
  116. switch (index)
  117. {
  118. case 0 : return m_previous_point;
  119. case 1 : return m_current_point;
  120. case 2 : return get_next_point();
  121. default : return m_previous_point;
  122. }
  123. }
  124. private :
  125. inline Point const& get_next_point() const
  126. {
  127. if (! m_next_point_retrieved)
  128. {
  129. advance_to_non_duplicate_next(m_current_point, m_circular_iterator);
  130. m_next_point_retrieved = true;
  131. }
  132. return *m_circular_iterator;
  133. }
  134. inline void advance_to_non_duplicate_next(Point const& current, CircularIterator& circular_iterator) const
  135. {
  136. using box_point_type = typename geometry::point_type<typename Section::box_type>::type;
  137. using robust_point_type = typename robust_point_type<box_point_type, RobustPolicy>::type;
  138. robust_point_type current_robust_point;
  139. robust_point_type next_robust_point;
  140. geometry::recalculate(current_robust_point, current, m_robust_policy);
  141. geometry::recalculate(next_robust_point, *circular_iterator, m_robust_policy);
  142. // To see where the next segments bend to, in case of touch/intersections
  143. // on end points, we need (in case of degenerate/duplicate points) an extra
  144. // iterator which moves to the REAL next point, so non duplicate.
  145. // This needs an extra comparison (disjoint).
  146. // (Note that within sections, non duplicate points are already asserted,
  147. // by the sectionalize process).
  148. // So advance to the "non duplicate next"
  149. // (the check is defensive, to avoid endless loops)
  150. std::size_t check = 0;
  151. while (! detail::disjoint::disjoint_point_point(
  152. current_robust_point, next_robust_point, m_strategy)
  153. && check++ < m_section.range_count)
  154. {
  155. circular_iterator++;
  156. geometry::recalculate(next_robust_point, *circular_iterator, m_robust_policy);
  157. }
  158. }
  159. Section const& m_section;
  160. signed_size_type m_index;
  161. Point const& m_previous_point;
  162. Point const& m_current_point;
  163. mutable CircularIterator m_circular_iterator;
  164. mutable bool m_next_point_retrieved;
  165. Strategy m_strategy;
  166. RobustPolicy m_robust_policy;
  167. };
  168. template
  169. <
  170. typename Geometry1, typename Geometry2,
  171. bool Reverse1, bool Reverse2,
  172. typename Section1, typename Section2,
  173. typename TurnPolicy
  174. >
  175. class get_turns_in_sections
  176. {
  177. using range1_view = detail::closed_clockwise_view
  178. <
  179. typename ring_type<Geometry1>::type const,
  180. geometry::closure<Geometry1>::value,
  181. Reverse1 ? counterclockwise : clockwise
  182. >;
  183. using range2_view = detail::closed_clockwise_view
  184. <
  185. typename ring_type<Geometry2>::type const,
  186. geometry::closure<Geometry2>::value,
  187. Reverse2 ? counterclockwise : clockwise
  188. >;
  189. using range1_iterator = typename boost::range_iterator<range1_view const>::type;
  190. using range2_iterator = typename boost::range_iterator<range2_view const>::type;
  191. using circular1_iterator = ever_circling_iterator<range1_iterator>;
  192. using circular2_iterator = ever_circling_iterator<range2_iterator>;
  193. template <typename Geometry, typename Section>
  194. static inline bool adjacent(Section const& section,
  195. signed_size_type index1, signed_size_type index2)
  196. {
  197. // About n-2:
  198. // (square: range_count=5, indices 0,1,2,3
  199. // -> 0-3 are adjacent, don't check on intersections)
  200. // Also tested for open polygons, and/or duplicates
  201. // About first condition: will be optimized by compiler (static)
  202. // It checks if it is areal (box, ring, (multi)polygon)
  203. signed_size_type const n = static_cast<signed_size_type>(section.range_count);
  204. boost::ignore_unused(n, index1, index2);
  205. return util::is_areal<Geometry>::value
  206. && index1 == 0
  207. && index2 >= n - 2
  208. ;
  209. }
  210. public :
  211. // Returns true if terminated, false if interrupted
  212. template <typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
  213. static inline bool apply(
  214. int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
  215. int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
  216. bool skip_larger, bool skip_adjacent,
  217. Strategy const& strategy,
  218. RobustPolicy const& robust_policy,
  219. Turns& turns,
  220. InterruptPolicy& interrupt_policy)
  221. {
  222. boost::ignore_unused(interrupt_policy);
  223. static bool const areal1 = util::is_areal<Geometry1>::value;
  224. static bool const areal2 = util::is_areal<Geometry2>::value;
  225. if ((sec1.duplicate && (sec1.count + 1) < sec1.range_count)
  226. || (sec2.duplicate && (sec2.count + 1) < sec2.range_count))
  227. {
  228. // Skip sections containig only duplicates.
  229. // They are still important (can indicate non-disjointness)
  230. // but they will be found processing adjacent sections.
  231. // Do NOT skip if they are the ONLY section
  232. return true;
  233. }
  234. range1_view const view1(range_by_section(geometry1, sec1));
  235. range2_view const view2(range_by_section(geometry2, sec2));
  236. range1_iterator begin_range_1 = boost::begin(view1);
  237. range1_iterator end_range_1 = boost::end(view1);
  238. range2_iterator begin_range_2 = boost::begin(view2);
  239. range2_iterator end_range_2 = boost::end(view2);
  240. int const dir1 = sec1.directions[0];
  241. int const dir2 = sec2.directions[0];
  242. signed_size_type index1 = sec1.begin_index;
  243. signed_size_type ndi1 = sec1.non_duplicate_index;
  244. range1_iterator prev1, it1, end1;
  245. get_start_point_iterator(sec1, view1, prev1, it1, end1,
  246. index1, ndi1, dir1, sec2.bounding_box, robust_policy);
  247. // We need a circular iterator because it might run through the closing point.
  248. // One circle is actually enough but this one is just convenient.
  249. circular1_iterator next1(begin_range_1, end_range_1, it1, true);
  250. next1++;
  251. // Walk through section and stop if we exceed the other box
  252. // section 2: [--------------]
  253. // section 1: |----|---|---|---|---|
  254. for (prev1 = it1++, next1++;
  255. it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec1.bounding_box, sec2.bounding_box, robust_policy);
  256. ++prev1, ++it1, ++index1, ++next1, ++ndi1)
  257. {
  258. unique_sub_range_from_section
  259. <
  260. areal1, Section1, point1_type, circular1_iterator,
  261. Strategy, RobustPolicy
  262. > unique_sub_range1(sec1, index1,
  263. circular1_iterator(begin_range_1, end_range_1, next1, true),
  264. *prev1, *it1,
  265. strategy, robust_policy);
  266. signed_size_type index2 = sec2.begin_index;
  267. signed_size_type ndi2 = sec2.non_duplicate_index;
  268. range2_iterator prev2, it2, end2;
  269. get_start_point_iterator(sec2, view2, prev2, it2, end2,
  270. index2, ndi2, dir2, sec1.bounding_box, robust_policy);
  271. circular2_iterator next2(begin_range_2, end_range_2, it2, true);
  272. next2++;
  273. for (prev2 = it2++, next2++;
  274. it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec2.bounding_box, sec1.bounding_box, robust_policy);
  275. ++prev2, ++it2, ++index2, ++next2, ++ndi2)
  276. {
  277. bool skip = false;
  278. if (source_id1 == source_id2
  279. && sec1.ring_id.multi_index == sec2.ring_id.multi_index
  280. && sec1.ring_id.ring_index == sec2.ring_id.ring_index)
  281. {
  282. // Sources and rings are the same
  283. if (skip_larger && index1 >= index2)
  284. {
  285. // Skip to avoid getting all intersections twice
  286. skip = true;
  287. }
  288. else if (skip_adjacent)
  289. {
  290. // In some cases (dissolve, has_self_intersections)
  291. // neighbouring segments should be checked
  292. // (for example to detect spikes properly)
  293. // skip if it is a neighbouring segment.
  294. // (including, for areas, first-last segment
  295. // and two segments with one or more degenerate/duplicate
  296. // (zero-length) segments in between)
  297. skip = ndi2 == ndi1 + 1
  298. || adjacent<Geometry1>(sec1, index1, index2);
  299. }
  300. }
  301. if (! skip)
  302. {
  303. unique_sub_range_from_section
  304. <
  305. areal2, Section2, point2_type, circular2_iterator,
  306. Strategy, RobustPolicy
  307. > unique_sub_range2(sec2, index2,
  308. circular2_iterator(begin_range_2, end_range_2, next2),
  309. *prev2, *it2,
  310. strategy, robust_policy);
  311. typedef typename boost::range_value<Turns>::type turn_info;
  312. turn_info ti;
  313. ti.operations[0].seg_id
  314. = segment_identifier(source_id1, sec1.ring_id.multi_index,
  315. sec1.ring_id.ring_index, index1);
  316. ti.operations[1].seg_id
  317. = segment_identifier(source_id2, sec2.ring_id.multi_index,
  318. sec2.ring_id.ring_index, index2);
  319. std::size_t const size_before = boost::size(turns);
  320. TurnPolicy::apply(unique_sub_range1, unique_sub_range2,
  321. ti, strategy, robust_policy,
  322. std::back_inserter(turns));
  323. if (InterruptPolicy::enabled)
  324. {
  325. if (interrupt_policy.apply(
  326. std::make_pair(range::pos(turns, size_before),
  327. boost::end(turns))))
  328. {
  329. return false;
  330. }
  331. }
  332. }
  333. }
  334. }
  335. return true;
  336. }
  337. private :
  338. typedef typename geometry::point_type<Geometry1>::type point1_type;
  339. typedef typename geometry::point_type<Geometry2>::type point2_type;
  340. // It is NOT possible to have section-iterators here
  341. // because of the logistics of "index" (the section-iterator automatically
  342. // skips to the begin-point, we loose the index or have to recalculate it)
  343. // So we mimic it here
  344. template <typename Range, typename Section, typename Box, typename RobustPolicy>
  345. static inline void get_start_point_iterator(Section const& section,
  346. Range const& range,
  347. typename boost::range_iterator<Range const>::type& it,
  348. typename boost::range_iterator<Range const>::type& prev,
  349. typename boost::range_iterator<Range const>::type& end,
  350. signed_size_type& index, signed_size_type& ndi,
  351. int dir, Box const& other_bounding_box, RobustPolicy const& robust_policy)
  352. {
  353. it = boost::begin(range) + section.begin_index;
  354. end = boost::begin(range) + section.end_index + 1;
  355. // Mimic section-iterator:
  356. // Skip to point such that section interects other box
  357. prev = it++;
  358. for(; it != end && detail::section::preceding<0>(dir, *it, section.bounding_box, other_bounding_box, robust_policy);
  359. prev = it++, index++, ndi++)
  360. {}
  361. // Go back one step because we want to start completely preceding
  362. it = prev;
  363. }
  364. };
  365. template
  366. <
  367. typename Geometry1, typename Geometry2,
  368. bool Reverse1, bool Reverse2,
  369. typename TurnPolicy,
  370. typename Strategy,
  371. typename RobustPolicy,
  372. typename Turns,
  373. typename InterruptPolicy
  374. >
  375. struct section_visitor
  376. {
  377. int m_source_id1;
  378. Geometry1 const& m_geometry1;
  379. int m_source_id2;
  380. Geometry2 const& m_geometry2;
  381. Strategy const& m_strategy;
  382. RobustPolicy const& m_rescale_policy;
  383. Turns& m_turns;
  384. InterruptPolicy& m_interrupt_policy;
  385. section_visitor(int id1, Geometry1 const& g1,
  386. int id2, Geometry2 const& g2,
  387. Strategy const& strategy,
  388. RobustPolicy const& robust_policy,
  389. Turns& turns,
  390. InterruptPolicy& ip)
  391. : m_source_id1(id1), m_geometry1(g1)
  392. , m_source_id2(id2), m_geometry2(g2)
  393. , m_strategy(strategy)
  394. , m_rescale_policy(robust_policy)
  395. , m_turns(turns)
  396. , m_interrupt_policy(ip)
  397. {}
  398. template <typename Section>
  399. inline bool apply(Section const& sec1, Section const& sec2)
  400. {
  401. if (! detail::disjoint::disjoint_box_box(sec1.bounding_box,
  402. sec2.bounding_box,
  403. m_strategy) )
  404. {
  405. // false if interrupted
  406. return get_turns_in_sections
  407. <
  408. Geometry1,
  409. Geometry2,
  410. Reverse1, Reverse2,
  411. Section, Section,
  412. TurnPolicy
  413. >::apply(m_source_id1, m_geometry1, sec1,
  414. m_source_id2, m_geometry2, sec2,
  415. false, false,
  416. m_strategy,
  417. m_rescale_policy,
  418. m_turns, m_interrupt_policy);
  419. }
  420. return true;
  421. }
  422. };
  423. template
  424. <
  425. typename Geometry1, typename Geometry2,
  426. bool Reverse1, bool Reverse2,
  427. typename TurnPolicy
  428. >
  429. class get_turns_generic
  430. {
  431. public:
  432. template <typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
  433. static inline void apply(
  434. int source_id1, Geometry1 const& geometry1,
  435. int source_id2, Geometry2 const& geometry2,
  436. Strategy const& strategy,
  437. RobustPolicy const& robust_policy,
  438. Turns& turns,
  439. InterruptPolicy& interrupt_policy)
  440. {
  441. // First create monotonic sections...
  442. typedef typename boost::range_value<Turns>::type ip_type;
  443. typedef typename ip_type::point_type point_type;
  444. typedef model::box
  445. <
  446. typename geometry::robust_point_type
  447. <
  448. point_type, RobustPolicy
  449. >::type
  450. > box_type;
  451. typedef geometry::sections<box_type, 2> sections_type;
  452. sections_type sec1, sec2;
  453. typedef std::integer_sequence<std::size_t, 0, 1> dimensions;
  454. geometry::sectionalize<Reverse1, dimensions>(geometry1, robust_policy,
  455. sec1, strategy, 0);
  456. geometry::sectionalize<Reverse2, dimensions>(geometry2, robust_policy,
  457. sec2, strategy, 1);
  458. // ... and then partition them, intersecting overlapping sections in visitor method
  459. section_visitor
  460. <
  461. Geometry1, Geometry2,
  462. Reverse1, Reverse2,
  463. TurnPolicy,
  464. Strategy, RobustPolicy,
  465. Turns, InterruptPolicy
  466. > visitor(source_id1, geometry1, source_id2, geometry2,
  467. strategy, robust_policy, turns, interrupt_policy);
  468. geometry::partition
  469. <
  470. box_type
  471. >::apply(sec1, sec2, visitor,
  472. detail::section::get_section_box<Strategy>(strategy),
  473. detail::section::overlaps_section_box<Strategy>(strategy));
  474. }
  475. };
  476. // Get turns for a range with a box, following Cohen-Sutherland (cs) approach
  477. template
  478. <
  479. typename Range, typename Box,
  480. bool ReverseRange, bool ReverseBox,
  481. typename TurnPolicy
  482. >
  483. struct get_turns_cs
  484. {
  485. typedef typename geometry::point_type<Range>::type range_point_type;
  486. typedef typename geometry::point_type<Box>::type box_point_type;
  487. typedef std::array<box_point_type, 4> box_array;
  488. using view_type = detail::closed_clockwise_view
  489. <
  490. Range const,
  491. geometry::closure<Range>::value,
  492. ReverseRange ? counterclockwise : clockwise
  493. >;
  494. using iterator_type = typename boost::range_iterator<view_type const>::type;
  495. struct unique_sub_range_from_box_policy
  496. {
  497. typedef box_point_type point_type;
  498. unique_sub_range_from_box_policy(box_array const& box)
  499. : m_box(box)
  500. , m_index(0)
  501. {}
  502. static inline bool is_first_segment() { return false; }
  503. static inline bool is_last_segment() { return false; }
  504. static inline std::size_t size() { return 4; }
  505. inline box_point_type const& at(std::size_t index) const
  506. {
  507. BOOST_GEOMETRY_ASSERT(index < size());
  508. return m_box[(m_index + index) % 4];
  509. }
  510. inline void next()
  511. {
  512. m_index++;
  513. }
  514. private :
  515. box_array const& m_box;
  516. std::size_t m_index;
  517. };
  518. struct unique_sub_range_from_view_policy
  519. {
  520. typedef range_point_type point_type;
  521. unique_sub_range_from_view_policy(view_type const& view, point_type const& pi, point_type const& pj, iterator_type it)
  522. : m_view(view)
  523. , m_pi(pi)
  524. , m_pj(pj)
  525. , m_circular_iterator(boost::begin(view), boost::end(view), it, true)
  526. {
  527. ++m_circular_iterator;
  528. }
  529. static inline bool is_first_segment() { return false; }
  530. static inline bool is_last_segment() { return false; }
  531. static inline std::size_t size() { return 3; }
  532. inline point_type const& at(std::size_t index) const
  533. {
  534. BOOST_GEOMETRY_ASSERT(index < size());
  535. switch (index)
  536. {
  537. case 0 : return m_pi;
  538. case 1 : return m_pj;
  539. case 2 : return *m_circular_iterator;
  540. default : return m_pi;
  541. }
  542. }
  543. private :
  544. view_type const& m_view;
  545. point_type const& m_pi;
  546. point_type const& m_pj;
  547. ever_circling_iterator<iterator_type> m_circular_iterator;
  548. };
  549. template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
  550. static inline void apply(
  551. int source_id1, Range const& range,
  552. int source_id2, Box const& box,
  553. IntersectionStrategy const& intersection_strategy,
  554. RobustPolicy const& robust_policy,
  555. Turns& turns,
  556. InterruptPolicy& interrupt_policy,
  557. signed_size_type multi_index = -1,
  558. signed_size_type ring_index = -1)
  559. {
  560. if ( boost::size(range) <= 1)
  561. {
  562. return;
  563. }
  564. box_array box_points;
  565. assign_box_corners_oriented<ReverseBox>(box, box_points);
  566. view_type const view(range);
  567. // TODO: in this code, possible duplicate points are not yet taken
  568. // into account (not in the iterator, nor in the retrieve policy)
  569. iterator_type it = boost::begin(view);
  570. signed_size_type index = 0;
  571. for (iterator_type prev = it++;
  572. it != boost::end(view);
  573. prev = it++, index++)
  574. {
  575. segment_identifier seg_id(source_id1,
  576. multi_index, ring_index, index);
  577. unique_sub_range_from_view_policy view_unique_sub_range(view, *prev, *it, it);
  578. get_turns_with_box(seg_id, source_id2,
  579. view_unique_sub_range,
  580. box_points,
  581. intersection_strategy,
  582. robust_policy,
  583. turns,
  584. interrupt_policy);
  585. // Future performance enhancement:
  586. // return if told by the interrupt policy
  587. }
  588. }
  589. private:
  590. template
  591. <
  592. typename IntersectionStrategy,
  593. typename Turns,
  594. typename InterruptPolicy,
  595. typename RobustPolicy
  596. >
  597. static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2,
  598. unique_sub_range_from_view_policy const& range_unique_sub_range,
  599. box_array const& box,
  600. IntersectionStrategy const& intersection_strategy,
  601. RobustPolicy const& robust_policy,
  602. // Output
  603. Turns& turns,
  604. InterruptPolicy& interrupt_policy)
  605. {
  606. boost::ignore_unused(interrupt_policy);
  607. // Depending on code some relations can be left out
  608. typedef typename boost::range_value<Turns>::type turn_info;
  609. turn_info ti;
  610. ti.operations[0].seg_id = seg_id;
  611. unique_sub_range_from_box_policy box_unique_sub_range(box);
  612. ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0);
  613. TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range,
  614. ti, intersection_strategy, robust_policy,
  615. std::back_inserter(turns));
  616. ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1);
  617. box_unique_sub_range.next();
  618. TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range,
  619. ti, intersection_strategy, robust_policy,
  620. std::back_inserter(turns));
  621. ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2);
  622. box_unique_sub_range.next();
  623. TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range,
  624. ti, intersection_strategy, robust_policy,
  625. std::back_inserter(turns));
  626. ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3);
  627. box_unique_sub_range.next();
  628. TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range,
  629. ti, intersection_strategy, robust_policy,
  630. std::back_inserter(turns));
  631. if (InterruptPolicy::enabled)
  632. {
  633. interrupt_policy.apply(turns);
  634. }
  635. }
  636. };
  637. template
  638. <
  639. typename Polygon, typename Box,
  640. bool Reverse, bool ReverseBox,
  641. typename TurnPolicy
  642. >
  643. struct get_turns_polygon_cs
  644. {
  645. template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
  646. static inline void apply(
  647. int source_id1, Polygon const& polygon,
  648. int source_id2, Box const& box,
  649. IntersectionStrategy const& intersection_strategy,
  650. RobustPolicy const& robust_policy,
  651. Turns& turns,
  652. InterruptPolicy& interrupt_policy,
  653. signed_size_type multi_index = -1)
  654. {
  655. typedef typename geometry::ring_type<Polygon>::type ring_type;
  656. typedef detail::get_turns::get_turns_cs
  657. <
  658. ring_type, Box,
  659. Reverse, ReverseBox,
  660. TurnPolicy
  661. > intersector_type;
  662. intersector_type::apply(
  663. source_id1, geometry::exterior_ring(polygon),
  664. source_id2, box,
  665. intersection_strategy,
  666. robust_policy,
  667. turns,
  668. interrupt_policy,
  669. multi_index, -1);
  670. signed_size_type i = 0;
  671. auto const& rings = interior_rings(polygon);
  672. for (auto it = boost::begin(rings); it != boost::end(rings); ++it, ++i)
  673. {
  674. intersector_type::apply(
  675. source_id1, *it,
  676. source_id2, box,
  677. intersection_strategy,
  678. robust_policy,
  679. turns, interrupt_policy,
  680. multi_index, i);
  681. }
  682. }
  683. };
  684. template
  685. <
  686. typename Multi, typename Box,
  687. bool Reverse, bool ReverseBox,
  688. typename TurnPolicy
  689. >
  690. struct get_turns_multi_polygon_cs
  691. {
  692. template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
  693. static inline void apply(
  694. int source_id1, Multi const& multi,
  695. int source_id2, Box const& box,
  696. IntersectionStrategy const& intersection_strategy,
  697. RobustPolicy const& robust_policy,
  698. Turns& turns,
  699. InterruptPolicy& interrupt_policy)
  700. {
  701. signed_size_type i = 0;
  702. for (auto it = boost::begin(multi); it != boost::end(multi); ++it, ++i)
  703. {
  704. // Call its single version
  705. get_turns_polygon_cs
  706. <
  707. typename boost::range_value<Multi>::type, Box,
  708. Reverse, ReverseBox,
  709. TurnPolicy
  710. >::apply(source_id1, *it, source_id2, box,
  711. intersection_strategy, robust_policy,
  712. turns, interrupt_policy, i);
  713. }
  714. }
  715. };
  716. // GET_TURN_INFO_TYPE
  717. template <typename Geometry>
  718. struct topological_tag_base
  719. {
  720. typedef typename tag_cast<typename tag<Geometry>::type, pointlike_tag, linear_tag, areal_tag>::type type;
  721. };
  722. template <typename Geometry1, typename Geometry2, typename AssignPolicy,
  723. typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
  724. typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
  725. struct get_turn_info_type
  726. : overlay::get_turn_info<AssignPolicy>
  727. {};
  728. template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
  729. struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, linear_tag>
  730. : overlay::get_turn_info_linear_linear<AssignPolicy>
  731. {};
  732. template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
  733. struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, areal_tag>
  734. : overlay::get_turn_info_linear_areal<AssignPolicy>
  735. {};
  736. template <typename Geometry1, typename Geometry2, typename Point, typename SegmentRatio,
  737. typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
  738. typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
  739. struct turn_operation_type
  740. {
  741. using type = overlay::turn_operation<Point, SegmentRatio>;
  742. };
  743. template <typename Geometry1, typename Geometry2, typename Point, typename SegmentRatio, typename Tag1, typename Tag2>
  744. struct turn_operation_type<Geometry1, Geometry2, Point, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag>
  745. {
  746. using type = overlay::turn_operation_linear<Point, SegmentRatio>;
  747. };
  748. template <typename Geometry1, typename Geometry2, typename Point, typename SegmentRatio, typename Tag1, typename Tag2>
  749. struct turn_operation_type<Geometry1, Geometry2, Point, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag>
  750. {
  751. using type = overlay::turn_operation_linear<Point, SegmentRatio>;
  752. };
  753. }} // namespace detail::get_turns
  754. #endif // DOXYGEN_NO_DETAIL
  755. #ifndef DOXYGEN_NO_DISPATCH
  756. namespace dispatch
  757. {
  758. // Because this is "detail" method, and most implementations will use "generic",
  759. // we take the freedom to derive it from "generic".
  760. template
  761. <
  762. typename GeometryTag1, typename GeometryTag2,
  763. typename Geometry1, typename Geometry2,
  764. bool Reverse1, bool Reverse2,
  765. typename TurnPolicy
  766. >
  767. struct get_turns
  768. : detail::get_turns::get_turns_generic
  769. <
  770. Geometry1, Geometry2,
  771. Reverse1, Reverse2,
  772. TurnPolicy
  773. >
  774. {};
  775. template
  776. <
  777. typename Polygon, typename Box,
  778. bool ReversePolygon, bool ReverseBox,
  779. typename TurnPolicy
  780. >
  781. struct get_turns
  782. <
  783. polygon_tag, box_tag,
  784. Polygon, Box,
  785. ReversePolygon, ReverseBox,
  786. TurnPolicy
  787. > : detail::get_turns::get_turns_polygon_cs
  788. <
  789. Polygon, Box,
  790. ReversePolygon, ReverseBox,
  791. TurnPolicy
  792. >
  793. {};
  794. template
  795. <
  796. typename Ring, typename Box,
  797. bool ReverseRing, bool ReverseBox,
  798. typename TurnPolicy
  799. >
  800. struct get_turns
  801. <
  802. ring_tag, box_tag,
  803. Ring, Box,
  804. ReverseRing, ReverseBox,
  805. TurnPolicy
  806. > : detail::get_turns::get_turns_cs
  807. <
  808. Ring, Box, ReverseRing, ReverseBox,
  809. TurnPolicy
  810. >
  811. {};
  812. template
  813. <
  814. typename MultiPolygon,
  815. typename Box,
  816. bool ReverseMultiPolygon, bool ReverseBox,
  817. typename TurnPolicy
  818. >
  819. struct get_turns
  820. <
  821. multi_polygon_tag, box_tag,
  822. MultiPolygon, Box,
  823. ReverseMultiPolygon, ReverseBox,
  824. TurnPolicy
  825. >
  826. : detail::get_turns::get_turns_multi_polygon_cs
  827. <
  828. MultiPolygon, Box,
  829. ReverseMultiPolygon, ReverseBox,
  830. TurnPolicy
  831. >
  832. {};
  833. template
  834. <
  835. typename GeometryTag1, typename GeometryTag2,
  836. typename Geometry1, typename Geometry2,
  837. bool Reverse1, bool Reverse2,
  838. typename TurnPolicy
  839. >
  840. struct get_turns_reversed
  841. {
  842. template <typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
  843. static inline void apply(int source_id1, Geometry1 const& g1,
  844. int source_id2, Geometry2 const& g2,
  845. Strategy const& strategy,
  846. RobustPolicy const& robust_policy,
  847. Turns& turns,
  848. InterruptPolicy& interrupt_policy)
  849. {
  850. get_turns
  851. <
  852. GeometryTag2, GeometryTag1,
  853. Geometry2, Geometry1,
  854. Reverse2, Reverse1,
  855. TurnPolicy
  856. >::apply(source_id2, g2, source_id1, g1,
  857. strategy, robust_policy,
  858. turns, interrupt_policy);
  859. }
  860. };
  861. } // namespace dispatch
  862. #endif // DOXYGEN_NO_DISPATCH
  863. /*!
  864. \brief \brief_calc2{turn points}
  865. \ingroup overlay
  866. \tparam Geometry1 \tparam_geometry
  867. \tparam Geometry2 \tparam_geometry
  868. \tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s)
  869. \param geometry1 \param_geometry
  870. \param geometry2 \param_geometry
  871. \param intersection_strategy segments intersection strategy
  872. \param robust_policy policy to handle robustness issues
  873. \param turns container which will contain turn points
  874. \param interrupt_policy policy determining if process is stopped
  875. when intersection is found
  876. */
  877. template
  878. <
  879. bool Reverse1, bool Reverse2,
  880. typename AssignPolicy,
  881. typename Geometry1,
  882. typename Geometry2,
  883. typename Strategy,
  884. typename RobustPolicy,
  885. typename Turns,
  886. typename InterruptPolicy
  887. >
  888. inline void get_turns(Geometry1 const& geometry1,
  889. Geometry2 const& geometry2,
  890. Strategy const& strategy,
  891. RobustPolicy const& robust_policy,
  892. Turns& turns,
  893. InterruptPolicy& interrupt_policy)
  894. {
  895. concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
  896. typedef detail::overlay::get_turn_info<AssignPolicy> TurnPolicy;
  897. //typedef detail::get_turns::get_turn_info_type<Geometry1, Geometry2, AssignPolicy> TurnPolicy;
  898. std::conditional_t
  899. <
  900. reverse_dispatch<Geometry1, Geometry2>::type::value,
  901. dispatch::get_turns_reversed
  902. <
  903. typename tag<Geometry1>::type,
  904. typename tag<Geometry2>::type,
  905. Geometry1, Geometry2,
  906. Reverse1, Reverse2,
  907. TurnPolicy
  908. >,
  909. dispatch::get_turns
  910. <
  911. typename tag<Geometry1>::type,
  912. typename tag<Geometry2>::type,
  913. Geometry1, Geometry2,
  914. Reverse1, Reverse2,
  915. TurnPolicy
  916. >
  917. >::apply(0, geometry1,
  918. 1, geometry2,
  919. strategy,
  920. robust_policy,
  921. turns, interrupt_policy);
  922. }
  923. #if defined(_MSC_VER)
  924. #pragma warning(pop)
  925. #endif
  926. }} // namespace boost::geometry
  927. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP