buffered_piece_collection.hpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2017-2023 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2016-2022.
  5. // Modifications copyright (c) 2016-2022 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_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
  12. #include <algorithm>
  13. #include <cstddef>
  14. #include <set>
  15. #include <boost/core/ignore_unused.hpp>
  16. #include <boost/range/begin.hpp>
  17. #include <boost/range/empty.hpp>
  18. #include <boost/range/end.hpp>
  19. #include <boost/range/size.hpp>
  20. #include <boost/range/value_type.hpp>
  21. #include <boost/geometry/core/assert.hpp>
  22. #include <boost/geometry/core/coordinate_type.hpp>
  23. #include <boost/geometry/core/point_type.hpp>
  24. #include <boost/geometry/algorithms/covered_by.hpp>
  25. #include <boost/geometry/algorithms/envelope.hpp>
  26. #include <boost/geometry/strategies/buffer.hpp>
  27. #include <boost/geometry/geometries/ring.hpp>
  28. #include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp>
  29. #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
  30. #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
  31. #include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp>
  32. #include <boost/geometry/algorithms/detail/buffer/piece_border.hpp>
  33. #include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp>
  34. #include <boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp>
  35. #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
  36. #include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
  37. #include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
  38. #include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
  39. #include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
  40. #include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
  41. #include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
  42. #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
  43. #include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
  44. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  45. #include <boost/geometry/algorithms/detail/partition.hpp>
  46. #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
  47. #include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
  48. #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
  49. #include <boost/geometry/util/for_each_with_index.hpp>
  50. #include <boost/geometry/util/range.hpp>
  51. namespace boost { namespace geometry
  52. {
  53. #ifndef DOXYGEN_NO_DETAIL
  54. namespace detail { namespace buffer
  55. {
  56. /*
  57. * Terminology
  58. *
  59. * Suppose we make a buffer (using blocked corners) of this rectangle:
  60. *
  61. * +-------+
  62. * | |
  63. * | rect |
  64. * | |
  65. * +-------+
  66. *
  67. * For the sides we get these four buffered side-pieces (marked with s)
  68. * and four buffered corner pieces (marked with c)
  69. *
  70. * c---+---s---+---c
  71. * | | piece | | <- see below for details of the middle top-side-piece
  72. * +---+-------+---+
  73. * | | | |
  74. * s | rect | s <- two side pieces left/right of rect
  75. * | | | |
  76. * +---+-------+---+
  77. * | | piece | | <- one side-piece below, and two corner pieces
  78. * c---+---s---+---c
  79. *
  80. * The outer part of the picture above, using all pieces,
  81. * form together the offsetted ring (marked with o below)
  82. * The 8 pieces are part of the piece collection and use for inside-checks
  83. * The inner parts form (using 1 or 2 points per piece, often co-located)
  84. * form together the robust_polygons (marked with r below)
  85. * The remaining piece-segments are helper-segments (marked with h)
  86. *
  87. * ooooooooooooooooo
  88. * o h h o
  89. * ohhhrrrrrrrrrhhho
  90. * o r r o
  91. * o r r o
  92. * o r r o
  93. * ohhhrrrrrrrrrhhho
  94. * o h h o
  95. * ooooooooooooooooo
  96. *
  97. */
  98. template
  99. <
  100. typename Ring,
  101. typename Strategy,
  102. typename DistanceStrategy,
  103. typename RobustPolicy
  104. >
  105. struct buffered_piece_collection
  106. {
  107. typedef typename geometry::point_type<Ring>::type point_type;
  108. typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
  109. // Ring/polygon type, always clockwise
  110. typedef geometry::model::ring<point_type> clockwise_ring_type;
  111. typedef geometry::model::box<point_type> box_type;
  112. typedef buffer_turn_info
  113. <
  114. point_type,
  115. typename segment_ratio_type<point_type, RobustPolicy>::type
  116. > buffer_turn_info_type;
  117. typedef buffer_turn_operation
  118. <
  119. point_type,
  120. typename segment_ratio_type<point_type, RobustPolicy>::type
  121. > buffer_turn_operation_type;
  122. typedef std::vector<buffer_turn_info_type> turn_vector_type;
  123. typedef piece_border<Ring, point_type> piece_border_type;
  124. struct piece
  125. {
  126. strategy::buffer::piece_type type;
  127. signed_size_type index;
  128. signed_size_type left_index; // points to previous piece of same ring
  129. signed_size_type right_index; // points to next piece of same ring
  130. // The next two members (1, 2) form together a complete clockwise ring
  131. // for each piece (with one dupped point)
  132. // The complete clockwise ring is also included as a robust ring (3)
  133. // 1: half, part of offsetted_rings
  134. // Segment identifier of this piece, including its start index
  135. segment_identifier first_seg_id;
  136. // One-beyond index of this piece, to iterate over a ring
  137. // from: ring.begin() + pc.first_seg_id.segment_index;
  138. // to (not including): ring.begin() + pc.beyond_last_segment_index;
  139. // Its ring_id etc are shared with first_seg_id
  140. signed_size_type beyond_last_segment_index;
  141. // part in offsetted ring which is part of offsetted ring
  142. signed_size_type offsetted_count;
  143. bool is_flat_start;
  144. bool is_flat_end;
  145. bool is_deflated;
  146. // Ring (parts) of this piece, always clockwise
  147. piece_border_type m_piece_border;
  148. point_type m_label_point;
  149. // For a point buffer
  150. point_type m_center;
  151. piece()
  152. : type(strategy::buffer::piece_type_unknown)
  153. , index(-1)
  154. , left_index(-1)
  155. , right_index(-1)
  156. , beyond_last_segment_index(-1)
  157. , offsetted_count(-1)
  158. , is_flat_start(false)
  159. , is_flat_end(false)
  160. , is_deflated(false)
  161. {
  162. }
  163. };
  164. struct original_ring
  165. {
  166. typedef geometry::sections<box_type, 1> sections_type;
  167. // Creates an empty instance
  168. inline original_ring()
  169. : m_is_interior(false)
  170. , m_has_interiors(false)
  171. {}
  172. inline original_ring(clockwise_ring_type const& ring,
  173. bool is_interior, bool has_interiors,
  174. Strategy const& strategy)
  175. : m_ring(ring)
  176. , m_is_interior(is_interior)
  177. , m_has_interiors(has_interiors)
  178. {
  179. geometry::envelope(m_ring, m_box, strategy);
  180. // create monotonic sections in x-dimension
  181. // The dimension is critical because the direction is later used
  182. // in the optimization for within checks using winding strategy
  183. // and this strategy is scanning in x direction.
  184. typedef std::integer_sequence<std::size_t, 0> dimensions;
  185. geometry::sectionalize
  186. <
  187. false, dimensions
  188. >(m_ring, detail::no_rescale_policy(), m_sections, strategy);
  189. }
  190. clockwise_ring_type m_ring;
  191. box_type m_box;
  192. sections_type m_sections;
  193. bool m_is_interior;
  194. bool m_has_interiors;
  195. };
  196. typedef std::vector<piece> piece_vector_type;
  197. piece_vector_type m_pieces;
  198. turn_vector_type m_turns;
  199. signed_size_type m_first_piece_index;
  200. bool m_deflate;
  201. bool m_has_deflated;
  202. // Offsetted rings, and representations of original ring(s)
  203. // both indexed by multi_index
  204. using ring_collection_t = buffered_ring_collection<buffered_ring<Ring>>;
  205. ring_collection_t offsetted_rings;
  206. std::vector<original_ring> original_rings;
  207. std::vector<point_type> m_linear_end_points;
  208. buffered_ring_collection<Ring> traversed_rings;
  209. segment_identifier current_segment_id;
  210. // Monotonic sections (used for offsetted rings around points)
  211. // are still using a robust type, to be comparable with turn calculations,
  212. // which is using rescaling.
  213. typedef geometry::model::box
  214. <
  215. typename geometry::robust_point_type<point_type, RobustPolicy>::type
  216. > robust_box_type;
  217. typedef geometry::sections <robust_box_type, 2> robust_sections_type;
  218. robust_sections_type monotonic_sections;
  219. // Define the clusters, mapping cluster_id -> turns
  220. typedef std::map
  221. <
  222. signed_size_type,
  223. detail::overlay::cluster_info
  224. > cluster_type;
  225. cluster_type m_clusters;
  226. Strategy m_strategy;
  227. DistanceStrategy m_distance_strategy;
  228. RobustPolicy const& m_robust_policy;
  229. buffered_piece_collection(Strategy const& strategy,
  230. DistanceStrategy const& distance_strategy,
  231. RobustPolicy const& robust_policy)
  232. : m_first_piece_index(-1)
  233. , m_deflate(false)
  234. , m_has_deflated(false)
  235. , m_strategy(strategy)
  236. , m_distance_strategy(distance_strategy)
  237. , m_robust_policy(robust_policy)
  238. {}
  239. inline void check_linear_endpoints(buffer_turn_info_type& turn) const
  240. {
  241. // TODO this is quadratic. But the #endpoints, expected, is low,
  242. // and only applicable for linear features
  243. // (in a multi linestring with many short lines, the #endpoints can be
  244. // much higher)
  245. for (auto const& p : m_linear_end_points)
  246. {
  247. if (detail::equals::equals_point_point(turn.point, p, m_strategy))
  248. {
  249. turn.is_linear_end_point = true;
  250. }
  251. }
  252. }
  253. inline void deflate_check_turns()
  254. {
  255. if (! m_has_deflated)
  256. {
  257. return;
  258. }
  259. // Deflated rings may not travel to themselves, there should at least
  260. // be three turns (which cannot be checked here - TODO: add to traverse)
  261. for (auto& turn : m_turns)
  262. {
  263. if (! turn.is_turn_traversable)
  264. {
  265. continue;
  266. }
  267. for (auto& op : turn.operations)
  268. {
  269. if (op.enriched.get_next_turn_index() == static_cast<signed_size_type>(turn.turn_index)
  270. && m_pieces[op.seg_id.piece_index].is_deflated)
  271. {
  272. // Keep traversable, but don't start here
  273. op.enriched.startable = false;
  274. }
  275. }
  276. }
  277. }
  278. // Check if a turn is inside any of the originals
  279. inline void check_turn_in_original()
  280. {
  281. turn_in_original_visitor
  282. <
  283. turn_vector_type,
  284. Strategy
  285. > visitor(m_turns, m_strategy);
  286. geometry::partition
  287. <
  288. box_type,
  289. include_turn_policy,
  290. detail::partition::include_all_policy
  291. >::apply(m_turns, original_rings, visitor,
  292. turn_get_box<Strategy>(m_strategy),
  293. turn_in_original_overlaps_box<Strategy>(m_strategy),
  294. original_get_box<Strategy>(m_strategy),
  295. original_overlaps_box<Strategy>(m_strategy));
  296. bool const deflate = m_distance_strategy.negative();
  297. for (auto& turn : m_turns)
  298. {
  299. if (turn.is_turn_traversable)
  300. {
  301. if (deflate && turn.count_in_original <= 0)
  302. {
  303. // For deflate/negative buffers:
  304. // it is not in the original, so don't use it
  305. turn.is_turn_traversable = false;
  306. }
  307. else if (! deflate && turn.count_in_original > 0)
  308. {
  309. // For inflate: it is in original, so don't use it
  310. turn.is_turn_traversable = false;
  311. }
  312. }
  313. }
  314. }
  315. inline void update_turn_administration()
  316. {
  317. for_each_with_index(m_turns, [this](std::size_t index, auto& turn)
  318. {
  319. turn.turn_index = index;
  320. // Verify if a turn is a linear endpoint
  321. if (! turn.is_linear_end_point)
  322. {
  323. this->check_linear_endpoints(turn);
  324. }
  325. });
  326. }
  327. // Calculate properties of piece borders which are not influenced
  328. // by turns themselves:
  329. // - envelopes (essential for partitioning during calc turns)
  330. // - convexity
  331. // - monotonicity
  332. // - min/max radius of point buffers
  333. // - (if pieces are reversed)
  334. inline void update_piece_administration()
  335. {
  336. for (auto& pc : m_pieces)
  337. {
  338. piece_border_type& border = pc.m_piece_border;
  339. buffered_ring<Ring> const& ring = offsetted_rings[pc.first_seg_id.multi_index];
  340. if (pc.offsetted_count > 0)
  341. {
  342. if (pc.type != strategy::buffer::buffered_concave)
  343. {
  344. border.set_offsetted(ring, pc.first_seg_id.segment_index,
  345. pc.beyond_last_segment_index);
  346. }
  347. // Calculate envelopes for piece borders
  348. border.get_properties_of_border(pc.type == geometry::strategy::buffer::buffered_point,
  349. pc.m_center, m_strategy);
  350. if (! pc.is_flat_end && ! pc.is_flat_start)
  351. {
  352. border.get_properties_of_offsetted_ring_part(m_strategy);
  353. }
  354. }
  355. }
  356. }
  357. inline void get_turns()
  358. {
  359. update_piece_administration();
  360. {
  361. // Calculate the turns
  362. piece_turn_visitor
  363. <
  364. piece_vector_type,
  365. buffered_ring_collection<buffered_ring<Ring> >,
  366. turn_vector_type,
  367. Strategy,
  368. RobustPolicy
  369. > visitor(m_pieces, offsetted_rings, m_turns,
  370. m_strategy, m_robust_policy);
  371. detail::sectionalize::enlarge_sections(monotonic_sections, m_strategy);
  372. geometry::partition
  373. <
  374. robust_box_type
  375. >::apply(monotonic_sections, visitor,
  376. detail::section::get_section_box<Strategy>(m_strategy),
  377. detail::section::overlaps_section_box<Strategy>(m_strategy));
  378. }
  379. update_turn_administration();
  380. }
  381. inline void check_turn_in_pieces()
  382. {
  383. // Check if turns are inside pieces
  384. turn_in_piece_visitor
  385. <
  386. typename geometry::cs_tag<point_type>::type,
  387. turn_vector_type, piece_vector_type, DistanceStrategy, Strategy
  388. > visitor(m_turns, m_pieces, m_distance_strategy, m_strategy);
  389. geometry::partition
  390. <
  391. box_type
  392. >::apply(m_turns, m_pieces, visitor,
  393. turn_get_box<Strategy>(m_strategy),
  394. turn_overlaps_box<Strategy>(m_strategy),
  395. piece_get_box<Strategy>(m_strategy),
  396. piece_overlaps_box<Strategy>(m_strategy));
  397. }
  398. inline void start_new_ring(bool deflate)
  399. {
  400. std::size_t const n = offsetted_rings.size();
  401. current_segment_id.source_index = 0;
  402. current_segment_id.multi_index = static_cast<signed_size_type>(n);
  403. current_segment_id.ring_index = -1;
  404. current_segment_id.segment_index = 0;
  405. offsetted_rings.resize(n + 1);
  406. original_rings.resize(n + 1);
  407. m_first_piece_index = static_cast<signed_size_type>(boost::size(m_pieces));
  408. m_deflate = deflate;
  409. if (deflate)
  410. {
  411. // Pieces contain either deflated exterior rings, or inflated
  412. // interior rings which are effectively deflated too
  413. m_has_deflated = true;
  414. }
  415. }
  416. inline void abort_ring()
  417. {
  418. // Remove all created pieces for this ring, sections, last offsetted
  419. while (! m_pieces.empty()
  420. && m_pieces.back().first_seg_id.multi_index
  421. == current_segment_id.multi_index)
  422. {
  423. m_pieces.pop_back();
  424. }
  425. offsetted_rings.pop_back();
  426. original_rings.pop_back();
  427. m_first_piece_index = -1;
  428. }
  429. inline void update_last_point(point_type const& p,
  430. buffered_ring<Ring>& ring)
  431. {
  432. // For the first point of a new piece, and there were already
  433. // points in the offsetted ring, for some piece types the first point
  434. // is a duplicate of the last point of the previous piece.
  435. // TODO: disable that, that point should not be added
  436. // For now, it is made equal because due to numerical instability,
  437. // it can be a tiny bit off, possibly causing a self-intersection
  438. BOOST_GEOMETRY_ASSERT(boost::size(m_pieces) > 0);
  439. if (! ring.empty()
  440. && current_segment_id.segment_index
  441. == m_pieces.back().first_seg_id.segment_index)
  442. {
  443. ring.back() = p;
  444. }
  445. }
  446. inline void set_piece_center(point_type const& center)
  447. {
  448. BOOST_GEOMETRY_ASSERT(! m_pieces.empty());
  449. m_pieces.back().m_center = center;
  450. }
  451. inline bool finish_ring(strategy::buffer::result_code code)
  452. {
  453. if (code == strategy::buffer::result_error_numerical)
  454. {
  455. abort_ring();
  456. return false;
  457. }
  458. if (m_first_piece_index == -1)
  459. {
  460. return false;
  461. }
  462. // Casted version
  463. std::size_t const first_piece_index
  464. = static_cast<std::size_t>(m_first_piece_index);
  465. signed_size_type const last_piece_index
  466. = static_cast<signed_size_type>(boost::size(m_pieces)) - 1;
  467. if (first_piece_index < boost::size(m_pieces))
  468. {
  469. // If pieces were added,
  470. // reassign left-of-first and right-of-last
  471. geometry::range::at(m_pieces, first_piece_index).left_index
  472. = last_piece_index;
  473. geometry::range::back(m_pieces).right_index = m_first_piece_index;
  474. }
  475. buffered_ring<Ring>& added = offsetted_rings.back();
  476. if (! boost::empty(added))
  477. {
  478. // Make sure the closing point is identical (they are calculated
  479. // separately by different pieces)
  480. range::back(added) = range::front(added);
  481. }
  482. for (std::size_t i = first_piece_index; i < boost::size(m_pieces); i++)
  483. {
  484. sectionalize(m_pieces[i], added);
  485. }
  486. m_first_piece_index = -1;
  487. return true;
  488. }
  489. template <typename InputRing>
  490. inline void finish_ring(strategy::buffer::result_code code,
  491. InputRing const& input_ring,
  492. bool is_interior, bool has_interiors)
  493. {
  494. if (! finish_ring(code))
  495. {
  496. return;
  497. }
  498. if (! boost::empty(input_ring))
  499. {
  500. // Assign the ring to the original_ring collection
  501. // For rescaling, it is recalculated. Without rescaling, it
  502. // is just assigning (note that this Ring type is the
  503. // GeometryOut type, which might differ from the input ring type)
  504. clockwise_ring_type clockwise_ring;
  505. using view_type = detail::closed_clockwise_view<InputRing const>;
  506. view_type const view(input_ring);
  507. for (auto it = boost::begin(view); it != boost::end(view); ++it)
  508. {
  509. clockwise_ring.push_back(*it);
  510. }
  511. original_rings.back()
  512. = original_ring(clockwise_ring,
  513. is_interior, has_interiors,
  514. m_strategy);
  515. }
  516. }
  517. inline void set_current_ring_concave()
  518. {
  519. BOOST_GEOMETRY_ASSERT(boost::size(offsetted_rings) > 0);
  520. offsetted_rings.back().has_concave = true;
  521. }
  522. inline signed_size_type add_point(point_type const& p)
  523. {
  524. BOOST_GEOMETRY_ASSERT(boost::size(offsetted_rings) > 0);
  525. buffered_ring<Ring>& current_ring = offsetted_rings.back();
  526. update_last_point(p, current_ring);
  527. current_segment_id.segment_index++;
  528. current_ring.push_back(p);
  529. return static_cast<signed_size_type>(current_ring.size());
  530. }
  531. //-------------------------------------------------------------------------
  532. inline piece& create_piece(strategy::buffer::piece_type type,
  533. bool decrease_segment_index_by_one)
  534. {
  535. if (type == strategy::buffer::buffered_concave)
  536. {
  537. offsetted_rings.back().has_concave = true;
  538. }
  539. piece pc;
  540. pc.type = type;
  541. pc.index = static_cast<signed_size_type>(boost::size(m_pieces));
  542. pc.is_deflated = m_deflate;
  543. current_segment_id.piece_index = pc.index;
  544. pc.first_seg_id = current_segment_id;
  545. // Assign left/right (for first/last piece per ring they will be re-assigned later)
  546. pc.left_index = pc.index - 1;
  547. pc.right_index = pc.index + 1;
  548. std::size_t const n = boost::size(offsetted_rings.back());
  549. pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n;
  550. pc.beyond_last_segment_index = pc.first_seg_id.segment_index;
  551. m_pieces.push_back(pc);
  552. return m_pieces.back();
  553. }
  554. inline void init_rescale_piece(piece& pc)
  555. {
  556. if (pc.first_seg_id.segment_index < 0)
  557. {
  558. // This indicates an error situation: an earlier piece was empty
  559. // It currently does not happen
  560. pc.offsetted_count = 0;
  561. return;
  562. }
  563. BOOST_GEOMETRY_ASSERT(pc.first_seg_id.multi_index >= 0);
  564. BOOST_GEOMETRY_ASSERT(pc.beyond_last_segment_index >= 0);
  565. pc.offsetted_count = pc.beyond_last_segment_index - pc.first_seg_id.segment_index;
  566. BOOST_GEOMETRY_ASSERT(pc.offsetted_count >= 0);
  567. }
  568. inline void add_piece_point(piece& pc, point_type const& point, bool add_to_original)
  569. {
  570. if (add_to_original && pc.type != strategy::buffer::buffered_concave)
  571. {
  572. pc.m_piece_border.add_original_point(point);
  573. }
  574. else
  575. {
  576. pc.m_label_point = point;
  577. }
  578. }
  579. inline void sectionalize(piece const& pc, buffered_ring<Ring> const& ring)
  580. {
  581. using sectionalizer = geometry::detail::sectionalize::sectionalize_part
  582. <
  583. std::integer_sequence<std::size_t, 0, 1> // x,y dimension
  584. >;
  585. // Create a ring-identifier. The source-index is the piece index
  586. // The multi_index is as in this collection (the ring), but not used here
  587. // The ring_index is not used
  588. ring_identifier const ring_id(pc.index, pc.first_seg_id.multi_index, -1);
  589. sectionalizer::apply(monotonic_sections,
  590. boost::begin(ring) + pc.first_seg_id.segment_index,
  591. boost::begin(ring) + pc.beyond_last_segment_index,
  592. m_robust_policy,
  593. m_strategy,
  594. ring_id, 10);
  595. }
  596. inline void finish_piece(piece& pc)
  597. {
  598. init_rescale_piece(pc);
  599. }
  600. inline void finish_piece(piece& pc,
  601. point_type const& point1,
  602. point_type const& point2,
  603. point_type const& point3)
  604. {
  605. init_rescale_piece(pc);
  606. if (pc.offsetted_count == 0)
  607. {
  608. return;
  609. }
  610. add_piece_point(pc, point1, false);
  611. add_piece_point(pc, point2, true);
  612. add_piece_point(pc, point3, false);
  613. }
  614. inline void finish_piece(piece& pc,
  615. point_type const& point1,
  616. point_type const& point2,
  617. point_type const& point3,
  618. point_type const& point4)
  619. {
  620. init_rescale_piece(pc);
  621. // Add the four points. Note that points 2 and 3 are the originals,
  622. // and that they are already passed in reverse order
  623. // (because the offsetted ring is in clockwise order)
  624. add_piece_point(pc, point1, false);
  625. add_piece_point(pc, point2, true);
  626. add_piece_point(pc, point3, true);
  627. add_piece_point(pc, point4, false);
  628. }
  629. template <typename Range>
  630. inline void add_range_to_piece(piece& pc, Range const& range, bool add_front)
  631. {
  632. BOOST_GEOMETRY_ASSERT(boost::size(range) != 0u);
  633. auto it = boost::begin(range);
  634. // If it follows a non-join (so basically the same piece-type) point b1 should be added.
  635. // There should be two intersections later and it should be discarded.
  636. // But for now we need it to calculate intersections
  637. if (add_front)
  638. {
  639. add_point(*it);
  640. }
  641. for (++it; it != boost::end(range); ++it)
  642. {
  643. pc.beyond_last_segment_index = add_point(*it);
  644. }
  645. }
  646. inline void add_piece(strategy::buffer::piece_type type, point_type const& p,
  647. point_type const& b1, point_type const& b2)
  648. {
  649. piece& pc = create_piece(type, false);
  650. add_point(b1);
  651. pc.beyond_last_segment_index = add_point(b2);
  652. finish_piece(pc, b2, p, b1);
  653. }
  654. template <typename Range>
  655. inline void add_piece(strategy::buffer::piece_type type, Range const& range,
  656. bool decrease_segment_index_by_one)
  657. {
  658. piece& pc = create_piece(type, decrease_segment_index_by_one);
  659. if (boost::size(range) > 0u)
  660. {
  661. add_range_to_piece(pc, range, offsetted_rings.back().empty());
  662. }
  663. finish_piece(pc);
  664. }
  665. template <typename Range>
  666. inline void add_piece(strategy::buffer::piece_type type,
  667. point_type const& p, Range const& range)
  668. {
  669. piece& pc = create_piece(type, true);
  670. if (boost::size(range) > 0u)
  671. {
  672. add_range_to_piece(pc, range, offsetted_rings.back().empty());
  673. finish_piece(pc, range.back(), p, range.front());
  674. }
  675. else
  676. {
  677. finish_piece(pc);
  678. }
  679. }
  680. template <typename Range>
  681. inline void add_side_piece(point_type const& original_point1,
  682. point_type const& original_point2,
  683. Range const& range, bool is_first, bool is_empty)
  684. {
  685. BOOST_GEOMETRY_ASSERT(boost::size(range) >= 2u);
  686. auto const piece_type = is_empty
  687. ? strategy::buffer::buffered_empty_side
  688. : strategy::buffer::buffered_segment;
  689. piece& pc = create_piece(piece_type, ! is_first);
  690. add_range_to_piece(pc, range, is_first);
  691. // Add the four points of the side, starting with the last point of the
  692. // range, and reversing the order of the originals to keep it clockwise
  693. finish_piece(pc, range.back(), original_point2, original_point1, range.front());
  694. }
  695. template <typename EndcapStrategy, typename Range>
  696. inline void add_endcap(EndcapStrategy const& strategy, Range const& range,
  697. point_type const& end_point)
  698. {
  699. boost::ignore_unused(strategy);
  700. if (range.empty())
  701. {
  702. return;
  703. }
  704. strategy::buffer::piece_type pt = strategy.get_piece_type();
  705. if (pt == strategy::buffer::buffered_flat_end)
  706. {
  707. // It is flat, should just be added, without helper segments
  708. add_piece(pt, range, true);
  709. }
  710. else
  711. {
  712. // Normal case, it has an "inside", helper segments should be added
  713. add_piece(pt, end_point, range);
  714. }
  715. }
  716. inline void mark_flat_start(point_type const& point)
  717. {
  718. if (! m_pieces.empty())
  719. {
  720. piece& back = m_pieces.back();
  721. back.is_flat_start = true;
  722. // This happens to linear buffers, and it will be the very
  723. // first or last point. If that coincides with a turn,
  724. // and the turn was marked as ON_BORDER
  725. // the turn should NOT be within (even though it can be marked
  726. // as such)
  727. m_linear_end_points.push_back(point);
  728. }
  729. }
  730. inline void mark_flat_end(point_type const& point)
  731. {
  732. if (! m_pieces.empty())
  733. {
  734. piece& back = m_pieces.back();
  735. back.is_flat_end = true;
  736. m_linear_end_points.push_back(point);
  737. }
  738. }
  739. //-------------------------------------------------------------------------
  740. inline void handle_colocations()
  741. {
  742. if (! detail::overlay::handle_colocations
  743. <
  744. false, false, overlay_buffer,
  745. ring_collection_t, ring_collection_t
  746. >(m_turns, m_clusters, m_robust_policy))
  747. {
  748. return;
  749. }
  750. detail::overlay::gather_cluster_properties
  751. <
  752. false, false, overlay_buffer
  753. >(m_clusters, m_turns, detail::overlay::operation_union,
  754. offsetted_rings, offsetted_rings, m_strategy);
  755. for (auto const& cluster : m_clusters)
  756. {
  757. if (cluster.second.open_count == 0 && cluster.second.spike_count == 0)
  758. {
  759. // If the cluster is completely closed, mark it as not traversable.
  760. for (auto const& index : cluster.second.turn_indices)
  761. {
  762. m_turns[index].is_turn_traversable = false;
  763. }
  764. }
  765. }
  766. }
  767. inline void make_traversable_consistent_per_cluster()
  768. {
  769. for (auto const& cluster : m_clusters)
  770. {
  771. bool is_traversable = false;
  772. for (auto const& index : cluster.second.turn_indices)
  773. {
  774. if (m_turns[index].is_turn_traversable)
  775. {
  776. // If there is one turn traversable in the cluster,
  777. // then all turns should be traversable.
  778. is_traversable = true;
  779. break;
  780. }
  781. }
  782. if (is_traversable)
  783. {
  784. for (auto const& index : cluster.second.turn_indices)
  785. {
  786. m_turns[index].is_turn_traversable = true;
  787. }
  788. }
  789. }
  790. }
  791. inline void enrich()
  792. {
  793. enrich_intersection_points<false, false, overlay_buffer>(m_turns,
  794. m_clusters, offsetted_rings, offsetted_rings,
  795. m_robust_policy,
  796. m_strategy);
  797. }
  798. // Discards all rings which do have not-OK intersection points only.
  799. // Those can never be traversed and should not be part of the output.
  800. inline void discard_rings()
  801. {
  802. for (auto const& turn : m_turns)
  803. {
  804. if (turn.is_turn_traversable)
  805. {
  806. offsetted_rings[turn.operations[0].seg_id.multi_index].has_accepted_intersections = true;
  807. offsetted_rings[turn.operations[1].seg_id.multi_index].has_accepted_intersections = true;
  808. }
  809. else
  810. {
  811. offsetted_rings[turn.operations[0].seg_id.multi_index].has_discarded_intersections = true;
  812. offsetted_rings[turn.operations[1].seg_id.multi_index].has_discarded_intersections = true;
  813. }
  814. }
  815. }
  816. inline bool point_coveredby_original(point_type const& point)
  817. {
  818. signed_size_type count_in_original = 0;
  819. // Check of the robust point of this outputted ring is in
  820. // any of the robust original rings
  821. // This can go quadratic if the input has many rings, and there
  822. // are many untouched deflated rings around
  823. for (auto const& original : original_rings)
  824. {
  825. if (original.m_ring.empty())
  826. {
  827. continue;
  828. }
  829. if (detail::disjoint::disjoint_point_box(point, original.m_box,m_strategy))
  830. {
  831. continue;
  832. }
  833. int const geometry_code
  834. = detail::within::point_in_geometry(point, original.m_ring, m_strategy);
  835. if (geometry_code == -1)
  836. {
  837. // Outside, continue
  838. continue;
  839. }
  840. // Apply for possibly nested interior rings
  841. if (original.m_is_interior)
  842. {
  843. count_in_original--;
  844. }
  845. else if (original.m_has_interiors)
  846. {
  847. count_in_original++;
  848. }
  849. else
  850. {
  851. // Exterior ring without interior rings
  852. return true;
  853. }
  854. }
  855. return count_in_original > 0;
  856. }
  857. // For a deflate, all rings around inner rings which are untouched
  858. // (no intersections/turns) and which are OUTSIDE the original should
  859. // be discarded
  860. inline void discard_nonintersecting_deflated_rings()
  861. {
  862. for (auto& ring : offsetted_rings)
  863. {
  864. if (! ring.has_intersections()
  865. && boost::size(ring) > 0u
  866. && geometry::area(ring, m_strategy) < 0)
  867. {
  868. if (! point_coveredby_original(geometry::range::front(ring)))
  869. {
  870. ring.is_untouched_outside_original = true;
  871. }
  872. }
  873. }
  874. }
  875. inline void block_turns()
  876. {
  877. for (auto& turn : m_turns)
  878. {
  879. if (! turn.is_turn_traversable)
  880. {
  881. // Discard this turn (don't set it to blocked to avoid colocated
  882. // clusters being discarded afterwards
  883. turn.discarded = true;
  884. }
  885. }
  886. }
  887. inline void traverse()
  888. {
  889. typedef detail::overlay::traverse
  890. <
  891. false, false,
  892. buffered_ring_collection<buffered_ring<Ring> >,
  893. buffered_ring_collection<buffered_ring<Ring > >,
  894. overlay_buffer,
  895. backtrack_for_buffer
  896. > traverser;
  897. std::map<ring_identifier, overlay::ring_turn_info> turn_info_per_ring;
  898. traversed_rings.clear();
  899. buffer_overlay_visitor visitor;
  900. traverser::apply(offsetted_rings, offsetted_rings,
  901. m_strategy, m_robust_policy,
  902. m_turns, traversed_rings,
  903. turn_info_per_ring,
  904. m_clusters, visitor);
  905. }
  906. inline void reverse()
  907. {
  908. for (auto& ring : offsetted_rings)
  909. {
  910. if (! ring.has_intersections())
  911. {
  912. std::reverse(ring.begin(), ring.end());
  913. }
  914. }
  915. for (auto& ring : traversed_rings)
  916. {
  917. std::reverse(ring.begin(), ring.end());
  918. }
  919. }
  920. template <typename GeometryOutput, typename OutputIterator>
  921. inline OutputIterator assign(OutputIterator out) const
  922. {
  923. typedef typename geometry::area_result
  924. <
  925. buffered_ring<Ring>, Strategy
  926. >::type area_result_type;
  927. typedef detail::overlay::ring_properties
  928. <
  929. point_type, area_result_type
  930. > properties;
  931. std::map<ring_identifier, properties> selected;
  932. // Select all rings which do not have any self-intersection
  933. // Inner rings, for deflate, which do not have intersections, and
  934. // which are outside originals, are skipped
  935. // (other ones should be traversed)
  936. for_each_with_index(offsetted_rings, [&](std::size_t index, auto const& ring)
  937. {
  938. if (! ring.has_intersections()
  939. && ! ring.is_untouched_outside_original)
  940. {
  941. properties p = properties(ring, m_strategy);
  942. if (p.valid)
  943. {
  944. ring_identifier id(0, index, -1);
  945. selected[id] = p;
  946. }
  947. }
  948. });
  949. // Select all created rings
  950. for_each_with_index(traversed_rings, [&](std::size_t index, auto const& ring)
  951. {
  952. properties p = properties(ring, m_strategy);
  953. if (p.valid)
  954. {
  955. ring_identifier id(2, index, -1);
  956. selected[id] = p;
  957. }
  958. });
  959. detail::overlay::assign_parents<overlay_buffer>(offsetted_rings, traversed_rings,
  960. selected, m_strategy);
  961. return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out,
  962. m_strategy);
  963. }
  964. };
  965. }} // namespace detail::buffer
  966. #endif // DOXYGEN_NO_DETAIL
  967. }} // namespace boost::geometry
  968. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP