get_turns.hpp 41 KB

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