buffered_piece_collection.hpp 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2016-2019.
  5. // Modifications copyright (c) 2016-2019 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.hpp>
  17. #include <boost/geometry/core/assert.hpp>
  18. #include <boost/geometry/core/coordinate_type.hpp>
  19. #include <boost/geometry/core/point_type.hpp>
  20. #include <boost/geometry/algorithms/comparable_distance.hpp>
  21. #include <boost/geometry/algorithms/covered_by.hpp>
  22. #include <boost/geometry/algorithms/envelope.hpp>
  23. #include <boost/geometry/algorithms/is_convex.hpp>
  24. #include <boost/geometry/strategies/buffer.hpp>
  25. #include <boost/geometry/geometries/ring.hpp>
  26. #include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp>
  27. #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
  28. #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
  29. #include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp>
  30. #include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp>
  31. #include <boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp>
  32. #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
  33. #include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
  34. #include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
  35. #include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
  36. #include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
  37. #include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
  38. #include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
  39. #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
  40. #include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
  41. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  42. #include <boost/geometry/algorithms/detail/occupation_info.hpp>
  43. #include <boost/geometry/algorithms/detail/partition.hpp>
  44. #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
  45. #include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
  46. #include <boost/geometry/util/range.hpp>
  47. namespace boost { namespace geometry
  48. {
  49. #ifndef DOXYGEN_NO_DETAIL
  50. namespace detail { namespace buffer
  51. {
  52. enum segment_relation_code
  53. {
  54. segment_relation_on_left,
  55. segment_relation_on_right,
  56. segment_relation_within,
  57. segment_relation_disjoint
  58. };
  59. /*
  60. * Terminology
  61. *
  62. * Suppose we make a buffer (using blocked corners) of this rectangle:
  63. *
  64. * +-------+
  65. * | |
  66. * | rect |
  67. * | |
  68. * +-------+
  69. *
  70. * For the sides we get these four buffered side-pieces (marked with s)
  71. * and four buffered corner pieces (marked with c)
  72. *
  73. * c---+---s---+---c
  74. * | | piece | | <- see below for details of the middle top-side-piece
  75. * +---+-------+---+
  76. * | | | |
  77. * s | rect | s <- two side pieces left/right of rect
  78. * | | | |
  79. * +---+-------+---+
  80. * | | piece | | <- one side-piece below, and two corner pieces
  81. * c---+---s---+---c
  82. *
  83. * The outer part of the picture above, using all pieces,
  84. * form together the offsetted ring (marked with o below)
  85. * The 8 pieces are part of the piece collection and use for inside-checks
  86. * The inner parts form (using 1 or 2 points per piece, often co-located)
  87. * form together the robust_polygons (marked with r below)
  88. * The remaining piece-segments are helper-segments (marked with h)
  89. *
  90. * ooooooooooooooooo
  91. * o h h o
  92. * ohhhrrrrrrrrrhhho
  93. * o r r o
  94. * o r r o
  95. * o r r o
  96. * ohhhrrrrrrrrrhhho
  97. * o h h o
  98. * ooooooooooooooooo
  99. *
  100. */
  101. template <typename Ring, typename IntersectionStrategy, typename RobustPolicy>
  102. struct buffered_piece_collection
  103. {
  104. typedef buffered_piece_collection
  105. <
  106. Ring, IntersectionStrategy, RobustPolicy
  107. > this_type;
  108. typedef typename geometry::point_type<Ring>::type point_type;
  109. typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
  110. typedef typename geometry::robust_point_type
  111. <
  112. point_type,
  113. RobustPolicy
  114. >::type robust_point_type;
  115. // Robust ring/polygon type, always clockwise
  116. typedef geometry::model::ring<robust_point_type> robust_ring_type;
  117. typedef geometry::model::box<robust_point_type> robust_box_type;
  118. typedef typename default_comparable_distance_result
  119. <
  120. robust_point_type
  121. >::type robust_comparable_radius_type;
  122. typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
  123. typedef typename IntersectionStrategy::envelope_strategy_type envelope_strategy_type;
  124. typedef typename IntersectionStrategy::expand_strategy_type expand_strategy_type;
  125. typedef typename IntersectionStrategy::template area_strategy
  126. <
  127. point_type
  128. >::type area_strategy_type;
  129. typedef typename IntersectionStrategy::template area_strategy
  130. <
  131. robust_point_type
  132. >::type robust_area_strategy_type;
  133. typedef typename area_strategy_type::template result_type
  134. <
  135. point_type
  136. >::type area_result_type;
  137. typedef typename robust_area_strategy_type::template result_type
  138. <
  139. robust_point_type
  140. >::type robust_area_result_type;
  141. typedef typename IntersectionStrategy::template point_in_geometry_strategy
  142. <
  143. robust_point_type,
  144. robust_ring_type
  145. >::type point_in_geometry_strategy_type;
  146. typedef typename geometry::rescale_policy_type
  147. <
  148. typename geometry::point_type<Ring>::type,
  149. typename IntersectionStrategy::cs_tag
  150. >::type rescale_policy_type;
  151. typedef geometry::segment_ratio
  152. <
  153. typename geometry::coordinate_type<robust_point_type>::type
  154. > ratio_type;
  155. typedef buffer_turn_info
  156. <
  157. point_type,
  158. robust_point_type,
  159. ratio_type
  160. > buffer_turn_info_type;
  161. typedef buffer_turn_operation
  162. <
  163. point_type,
  164. ratio_type
  165. > buffer_turn_operation_type;
  166. typedef std::vector<buffer_turn_info_type> turn_vector_type;
  167. struct robust_turn
  168. {
  169. std::size_t turn_index;
  170. int operation_index;
  171. robust_point_type point;
  172. segment_identifier seg_id;
  173. ratio_type fraction;
  174. };
  175. struct piece
  176. {
  177. typedef robust_ring_type piece_robust_ring_type;
  178. typedef geometry::section<robust_box_type, 1> section_type;
  179. strategy::buffer::piece_type type;
  180. signed_size_type index;
  181. signed_size_type left_index; // points to previous piece of same ring
  182. signed_size_type right_index; // points to next piece of same ring
  183. // The next two members (1, 2) form together a complete clockwise ring
  184. // for each piece (with one dupped point)
  185. // The complete clockwise ring is also included as a robust ring (3)
  186. // 1: half, part of offsetted_rings
  187. segment_identifier first_seg_id;
  188. signed_size_type last_segment_index; // no segment-identifier - it is the same as first_seg_id
  189. signed_size_type offsetted_count; // part in robust_ring which is part of offsetted ring
  190. #if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS)
  191. // 2: half, not part of offsetted rings - part of robust ring
  192. std::vector<point_type> helper_points; // 4 points for side, 3 points for join - 0 points for flat-end
  193. #endif
  194. bool is_flat_start;
  195. bool is_flat_end;
  196. bool is_deflated;
  197. bool is_convex;
  198. bool is_monotonic_increasing[2]; // 0=x, 1=y
  199. bool is_monotonic_decreasing[2]; // 0=x, 1=y
  200. // Monotonic sections of pieces around points
  201. std::vector<section_type> sections;
  202. // Robust representations
  203. // 3: complete ring
  204. robust_ring_type robust_ring;
  205. robust_box_type robust_envelope;
  206. robust_box_type robust_offsetted_envelope;
  207. std::vector<robust_turn> robust_turns; // Used only in insert_rescaled_piece_turns - we might use a map instead
  208. robust_point_type robust_center;
  209. robust_comparable_radius_type robust_min_comparable_radius;
  210. robust_comparable_radius_type robust_max_comparable_radius;
  211. piece()
  212. : type(strategy::buffer::piece_type_unknown)
  213. , index(-1)
  214. , left_index(-1)
  215. , right_index(-1)
  216. , last_segment_index(-1)
  217. , offsetted_count(-1)
  218. , is_flat_start(false)
  219. , is_flat_end(false)
  220. , is_deflated(false)
  221. , is_convex(false)
  222. , robust_min_comparable_radius(0)
  223. , robust_max_comparable_radius(0)
  224. {
  225. is_monotonic_increasing[0] = false;
  226. is_monotonic_increasing[1] = false;
  227. is_monotonic_decreasing[0] = false;
  228. is_monotonic_decreasing[1] = false;
  229. }
  230. };
  231. struct robust_original
  232. {
  233. typedef robust_ring_type original_robust_ring_type;
  234. typedef geometry::sections<robust_box_type, 1> sections_type;
  235. inline robust_original()
  236. : m_is_interior(false)
  237. , m_has_interiors(true)
  238. {}
  239. inline robust_original(robust_ring_type const& ring,
  240. bool is_interior, bool has_interiors,
  241. envelope_strategy_type const& envelope_strategy,
  242. expand_strategy_type const& expand_strategy)
  243. : m_ring(ring)
  244. , m_is_interior(is_interior)
  245. , m_has_interiors(has_interiors)
  246. {
  247. geometry::envelope(m_ring, m_box, envelope_strategy);
  248. // create monotonic sections in x-dimension
  249. // The dimension is critical because the direction is later used
  250. // in the optimization for within checks using winding strategy
  251. // and this strategy is scanning in x direction.
  252. typedef boost::mpl::vector_c<std::size_t, 0> dimensions;
  253. geometry::sectionalize<false, dimensions>(m_ring,
  254. detail::no_rescale_policy(), m_sections,
  255. envelope_strategy, expand_strategy);
  256. }
  257. robust_ring_type m_ring;
  258. robust_box_type m_box;
  259. sections_type m_sections;
  260. bool m_is_interior;
  261. bool m_has_interiors;
  262. };
  263. typedef std::vector<piece> piece_vector_type;
  264. piece_vector_type m_pieces;
  265. turn_vector_type m_turns;
  266. signed_size_type m_first_piece_index;
  267. bool m_deflate;
  268. bool m_has_deflated;
  269. buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; // indexed by multi_index
  270. std::vector<robust_original> robust_originals; // robust representation of the original(s)
  271. robust_ring_type current_robust_ring;
  272. buffered_ring_collection<Ring> traversed_rings;
  273. segment_identifier current_segment_id;
  274. // Specificly for offsetted rings around points
  275. // but also for large joins with many points
  276. typedef geometry::sections<robust_box_type, 2> sections_type;
  277. sections_type monotonic_sections;
  278. // Define the clusters, mapping cluster_id -> turns
  279. typedef std::map
  280. <
  281. signed_size_type,
  282. detail::overlay::cluster_info
  283. > cluster_type;
  284. cluster_type m_clusters;
  285. IntersectionStrategy m_intersection_strategy;
  286. side_strategy_type m_side_strategy;
  287. area_strategy_type m_area_strategy;
  288. envelope_strategy_type m_envelope_strategy;
  289. expand_strategy_type m_expand_strategy;
  290. point_in_geometry_strategy_type m_point_in_geometry_strategy;
  291. robust_area_strategy_type m_robust_area_strategy;
  292. RobustPolicy const& m_robust_policy;
  293. struct redundant_turn
  294. {
  295. inline bool operator()(buffer_turn_info_type const& turn) const
  296. {
  297. return turn.remove_on_multi;
  298. }
  299. };
  300. buffered_piece_collection(IntersectionStrategy const& intersection_strategy,
  301. RobustPolicy const& robust_policy)
  302. : m_first_piece_index(-1)
  303. , m_deflate(false)
  304. , m_has_deflated(false)
  305. , m_intersection_strategy(intersection_strategy)
  306. , m_side_strategy(intersection_strategy.get_side_strategy())
  307. , m_area_strategy(intersection_strategy
  308. .template get_area_strategy<point_type>())
  309. , m_envelope_strategy(intersection_strategy.get_envelope_strategy())
  310. , m_expand_strategy(intersection_strategy.get_expand_strategy())
  311. , m_point_in_geometry_strategy(intersection_strategy
  312. .template get_point_in_geometry_strategy<robust_point_type,
  313. robust_ring_type>())
  314. , m_robust_area_strategy(intersection_strategy
  315. .template get_area_strategy<robust_point_type>())
  316. , m_robust_policy(robust_policy)
  317. {}
  318. #if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
  319. // Will (most probably) be removed later
  320. template <typename OccupationMap>
  321. inline void adapt_mapped_robust_point(OccupationMap const& map,
  322. buffer_turn_info_type& turn, int distance) const
  323. {
  324. for (int x = -distance; x <= distance; x++)
  325. {
  326. for (int y = -distance; y <= distance; y++)
  327. {
  328. robust_point_type rp = turn.robust_point;
  329. geometry::set<0>(rp, geometry::get<0>(rp) + x);
  330. geometry::set<1>(rp, geometry::get<1>(rp) + y);
  331. if (map.find(rp) != map.end())
  332. {
  333. turn.mapped_robust_point = rp;
  334. return;
  335. }
  336. }
  337. }
  338. }
  339. #endif
  340. inline void get_occupation(
  341. #if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
  342. int distance = 0
  343. #endif
  344. )
  345. {
  346. typedef occupation_info<angle_info<robust_point_type, coordinate_type> >
  347. buffer_occupation_info;
  348. typedef std::map
  349. <
  350. robust_point_type,
  351. buffer_occupation_info,
  352. geometry::less<robust_point_type>
  353. > occupation_map_type;
  354. occupation_map_type occupation_map;
  355. // 1: Add all intersection points to occupation map
  356. typedef typename boost::range_iterator<turn_vector_type>::type
  357. iterator_type;
  358. for (iterator_type it = boost::begin(m_turns);
  359. it != boost::end(m_turns);
  360. ++it)
  361. {
  362. if (it->location == location_ok)
  363. {
  364. #if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
  365. if (distance > 0 && ! occupation_map.empty())
  366. {
  367. adapt_mapped_robust_point(occupation_map, *it, distance);
  368. }
  369. #endif
  370. occupation_map[it->get_robust_point()].count++;
  371. }
  372. }
  373. // Remove all points with one or more u/u points from the map
  374. // (Alternatively, we could NOT do this here and change all u/u
  375. // behaviour in overlay. Currently nothing is done: each polygon is
  376. // just followed there. We could also always switch polygons there. For
  377. // buffer behaviour, where 3 pieces might meet of which 2 (or more) form
  378. // a u/u turn, this last option would have been better, probably).
  379. for (iterator_type it = boost::begin(m_turns);
  380. it != boost::end(m_turns);
  381. ++it)
  382. {
  383. if (it->both(detail::overlay::operation_union))
  384. {
  385. typename occupation_map_type::iterator mit =
  386. occupation_map.find(it->get_robust_point());
  387. if (mit != occupation_map.end())
  388. {
  389. occupation_map.erase(mit);
  390. }
  391. }
  392. }
  393. // 2: Remove all points from map which has only one
  394. typename occupation_map_type::iterator it = occupation_map.begin();
  395. while (it != occupation_map.end())
  396. {
  397. if (it->second.count <= 1)
  398. {
  399. typename occupation_map_type::iterator to_erase = it;
  400. ++it;
  401. occupation_map.erase(to_erase);
  402. }
  403. else
  404. {
  405. ++it;
  406. }
  407. }
  408. if (occupation_map.empty())
  409. {
  410. return;
  411. }
  412. // 3: Add vectors (incoming->intersection-point,
  413. // intersection-point -> outgoing)
  414. // for all (co-located) points still present in the map
  415. for (iterator_type tit = boost::begin(m_turns);
  416. tit != boost::end(m_turns);
  417. ++tit)
  418. {
  419. typename occupation_map_type::iterator mit =
  420. occupation_map.find(tit->get_robust_point());
  421. if (mit != occupation_map.end())
  422. {
  423. buffer_occupation_info& info = mit->second;
  424. for (int i = 0; i < 2; i++)
  425. {
  426. add_incoming_and_outgoing_angles(tit->get_robust_point(), *tit,
  427. m_pieces,
  428. i, tit->operations[i].seg_id,
  429. info);
  430. }
  431. tit->count_on_multi++;
  432. }
  433. }
  434. #if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
  435. // X: Check rounding issues
  436. if (distance == 0)
  437. {
  438. for (typename occupation_map_type::const_iterator it = occupation_map.begin();
  439. it != occupation_map.end(); ++it)
  440. {
  441. if (it->second.has_rounding_issues(it->first))
  442. {
  443. if(distance == 0)
  444. {
  445. get_occupation(distance + 1);
  446. return;
  447. }
  448. }
  449. }
  450. }
  451. #endif
  452. // Get left turns from all clusters
  453. for (typename occupation_map_type::iterator mit = occupation_map.begin();
  454. mit != occupation_map.end(); ++mit)
  455. {
  456. mit->second.get_left_turns(mit->first, m_turns, m_side_strategy);
  457. }
  458. }
  459. inline void classify_turns()
  460. {
  461. for (typename boost::range_iterator<turn_vector_type>::type it =
  462. boost::begin(m_turns); it != boost::end(m_turns); ++it)
  463. {
  464. if (it->count_within > 0)
  465. {
  466. it->location = inside_buffer;
  467. }
  468. if (it->count_within_near_offsetted > 0)
  469. {
  470. // Within can have in rare cases a rounding issue. We don't discard this
  471. // point, so it can be used to continue started rings in traversal. But
  472. // will never start a new ring from this type of points.
  473. it->operations[0].enriched.startable = false;
  474. it->operations[1].enriched.startable = false;
  475. }
  476. }
  477. }
  478. struct deflate_properties
  479. {
  480. bool has_inflated;
  481. std::size_t count;
  482. inline deflate_properties()
  483. : has_inflated(false)
  484. , count(0u)
  485. {}
  486. };
  487. inline void discard_turns_for_deflate()
  488. {
  489. // Deflate cases should have at least 3 points PER deflated original
  490. // to form a correct triangle
  491. // But if there are intersections between a deflated ring and another
  492. // ring, it is all accepted
  493. // In deflate most turns are i/u by nature, but u/u is also possible
  494. std::map<signed_size_type, deflate_properties> properties;
  495. for (typename boost::range_iterator<turn_vector_type const>::type it =
  496. boost::begin(m_turns); it != boost::end(m_turns); ++it)
  497. {
  498. const buffer_turn_info_type& turn = *it;
  499. if (turn.location == location_ok)
  500. {
  501. const buffer_turn_operation_type& op0 = turn.operations[0];
  502. const buffer_turn_operation_type& op1 = turn.operations[1];
  503. if (! m_pieces[op0.seg_id.piece_index].is_deflated
  504. || ! m_pieces[op1.seg_id.piece_index].is_deflated)
  505. {
  506. properties[op0.seg_id.multi_index].has_inflated = true;
  507. properties[op1.seg_id.multi_index].has_inflated = true;
  508. continue;
  509. }
  510. // It is deflated, update counts
  511. for (int i = 0; i < 2; i++)
  512. {
  513. const buffer_turn_operation_type& op = turn.operations[i];
  514. if (op.operation == detail::overlay::operation_union
  515. || op.operation == detail::overlay::operation_continue)
  516. {
  517. properties[op.seg_id.multi_index].count++;
  518. }
  519. }
  520. }
  521. }
  522. for (typename boost::range_iterator<turn_vector_type>::type it =
  523. boost::begin(m_turns); it != boost::end(m_turns); ++it)
  524. {
  525. buffer_turn_info_type& turn = *it;
  526. if (turn.location == location_ok)
  527. {
  528. const buffer_turn_operation_type& op0 = turn.operations[0];
  529. const buffer_turn_operation_type& op1 = turn.operations[1];
  530. signed_size_type const multi0 = op0.seg_id.multi_index;
  531. signed_size_type const multi1 = op1.seg_id.multi_index;
  532. if (multi0 == multi1)
  533. {
  534. const deflate_properties& prop = properties[multi0];
  535. // NOTE: Keep brackets around prop.count
  536. // avoid gcc-bug "parse error in template argument list"
  537. // GCC versions 5.4 and 5.5 (and probably more)
  538. if (! prop.has_inflated && (prop.count) < 3)
  539. {
  540. // Property is not inflated
  541. // Not enough points, this might be caused by <float> where
  542. // detection turn-in-original failed because of numeric errors
  543. turn.location = location_discard;
  544. }
  545. }
  546. else
  547. {
  548. // Two different (possibly deflated) rings
  549. }
  550. }
  551. }
  552. }
  553. template <typename DistanceStrategy>
  554. inline void check_remaining_points(DistanceStrategy const& distance_strategy)
  555. {
  556. // Check if a turn is inside any of the originals
  557. typedef turn_in_original_ovelaps_box
  558. <
  559. typename IntersectionStrategy::disjoint_point_box_strategy_type
  560. > turn_in_original_ovelaps_box_type;
  561. typedef original_ovelaps_box
  562. <
  563. typename IntersectionStrategy::disjoint_box_box_strategy_type
  564. > original_ovelaps_box_type;
  565. turn_in_original_visitor
  566. <
  567. turn_vector_type,
  568. point_in_geometry_strategy_type
  569. > visitor(m_turns, m_point_in_geometry_strategy);
  570. geometry::partition
  571. <
  572. robust_box_type,
  573. include_turn_policy,
  574. detail::partition::include_all_policy
  575. >::apply(m_turns, robust_originals, visitor,
  576. turn_get_box(), turn_in_original_ovelaps_box_type(),
  577. original_get_box(), original_ovelaps_box_type());
  578. bool const deflate = distance_strategy.negative();
  579. for (typename boost::range_iterator<turn_vector_type>::type it =
  580. boost::begin(m_turns); it != boost::end(m_turns); ++it)
  581. {
  582. buffer_turn_info_type& turn = *it;
  583. if (turn.location == location_ok)
  584. {
  585. if (deflate && turn.count_in_original <= 0)
  586. {
  587. // For deflate/negative buffers: it is not in original, discard
  588. turn.location = location_discard;
  589. }
  590. else if (! deflate && turn.count_in_original > 0)
  591. {
  592. // For inflate: it is in original, discard
  593. turn.location = location_discard;
  594. }
  595. }
  596. }
  597. if (m_has_deflated)
  598. {
  599. // Either strategy was negative, or there were interior rings
  600. discard_turns_for_deflate();
  601. }
  602. }
  603. inline bool assert_indices_in_robust_rings() const
  604. {
  605. geometry::equal_to<robust_point_type> comparator;
  606. for (typename boost::range_iterator<turn_vector_type const>::type it =
  607. boost::begin(m_turns); it != boost::end(m_turns); ++it)
  608. {
  609. for (int i = 0; i < 2; i++)
  610. {
  611. robust_point_type const &p1
  612. = m_pieces[it->operations[i].piece_index].robust_ring
  613. [it->operations[i].index_in_robust_ring];
  614. robust_point_type const &p2 = it->robust_point;
  615. if (! comparator(p1, p2))
  616. {
  617. return false;
  618. }
  619. }
  620. }
  621. return true;
  622. }
  623. inline void insert_rescaled_piece_turns()
  624. {
  625. // Add rescaled turn points to corresponding pieces
  626. // (after this, each turn occurs twice)
  627. std::size_t index = 0;
  628. for (typename boost::range_iterator<turn_vector_type>::type it =
  629. boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index)
  630. {
  631. geometry::recalculate(it->robust_point, it->point, m_robust_policy);
  632. #if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
  633. it->mapped_robust_point = it->robust_point;
  634. #endif
  635. robust_turn turn;
  636. it->turn_index = index;
  637. turn.turn_index = index;
  638. turn.point = it->robust_point;
  639. for (int i = 0; i < 2; i++)
  640. {
  641. turn.operation_index = i;
  642. turn.seg_id = it->operations[i].seg_id;
  643. turn.fraction = it->operations[i].fraction;
  644. piece& pc = m_pieces[it->operations[i].piece_index];
  645. pc.robust_turns.push_back(turn);
  646. // Take into account for the box (intersection points should fall inside,
  647. // but in theory they can be one off because of rounding
  648. geometry::expand(pc.robust_envelope, it->robust_point);
  649. geometry::expand(pc.robust_offsetted_envelope, it->robust_point);
  650. }
  651. }
  652. if (! use_side_of_intersection<typename geometry::cs_tag<point_type>::type>::value)
  653. {
  654. // Insert all rescaled turn-points into these rings, to form a
  655. // reliable integer-based ring. All turns can be compared (inside) to this
  656. // rings to see if they are inside.
  657. for (typename boost::range_iterator<piece_vector_type>::type
  658. it = boost::begin(m_pieces); it != boost::end(m_pieces); ++it)
  659. {
  660. piece& pc = *it;
  661. signed_size_type piece_segment_index = pc.first_seg_id.segment_index;
  662. if (! pc.robust_turns.empty())
  663. {
  664. if (pc.robust_turns.size() > 1u)
  665. {
  666. std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less());
  667. }
  668. // Walk through them, in reverse to insert at right index
  669. signed_size_type index_offset = static_cast<signed_size_type>(pc.robust_turns.size()) - 1;
  670. for (typename boost::range_reverse_iterator<const std::vector<robust_turn> >::type
  671. rit = boost::const_rbegin(pc.robust_turns);
  672. rit != boost::const_rend(pc.robust_turns);
  673. ++rit, --index_offset)
  674. {
  675. signed_size_type const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index;
  676. BOOST_GEOMETRY_ASSERT
  677. (
  678. index_in_vector > 0
  679. && index_in_vector < pc.offsetted_count
  680. );
  681. pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point);
  682. pc.offsetted_count++;
  683. m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset;
  684. }
  685. }
  686. }
  687. BOOST_GEOMETRY_ASSERT(assert_indices_in_robust_rings());
  688. }
  689. }
  690. template <std::size_t Dimension>
  691. static inline void determine_monotonicity(piece& pc,
  692. robust_point_type const& current,
  693. robust_point_type const& next)
  694. {
  695. if (geometry::get<Dimension>(current) >= geometry::get<Dimension>(next))
  696. {
  697. pc.is_monotonic_increasing[Dimension] = false;
  698. }
  699. if (geometry::get<Dimension>(current) <= geometry::get<Dimension>(next))
  700. {
  701. pc.is_monotonic_decreasing[Dimension] = false;
  702. }
  703. }
  704. inline void determine_properties(piece& pc) const
  705. {
  706. pc.is_monotonic_increasing[0] = true;
  707. pc.is_monotonic_increasing[1] = true;
  708. pc.is_monotonic_decreasing[0] = true;
  709. pc.is_monotonic_decreasing[1] = true;
  710. pc.is_convex = geometry::is_convex(pc.robust_ring, m_side_strategy);
  711. if (pc.offsetted_count < 2)
  712. {
  713. return;
  714. }
  715. typename robust_ring_type::const_iterator current = pc.robust_ring.begin();
  716. typename robust_ring_type::const_iterator next = current + 1;
  717. for (signed_size_type i = 1; i < pc.offsetted_count; i++)
  718. {
  719. determine_monotonicity<0>(pc, *current, *next);
  720. determine_monotonicity<1>(pc, *current, *next);
  721. current = next;
  722. ++next;
  723. }
  724. }
  725. void determine_properties()
  726. {
  727. for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
  728. it != boost::end(m_pieces);
  729. ++it)
  730. {
  731. determine_properties(*it);
  732. }
  733. }
  734. inline void reverse_negative_robust_rings()
  735. {
  736. for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
  737. it != boost::end(m_pieces);
  738. ++it)
  739. {
  740. piece& pc = *it;
  741. if (geometry::area(pc.robust_ring, m_robust_area_strategy) < 0)
  742. {
  743. // Rings can be ccw:
  744. // - in a concave piece
  745. // - in a line-buffer with a negative buffer-distance
  746. std::reverse(pc.robust_ring.begin(), pc.robust_ring.end());
  747. }
  748. }
  749. }
  750. inline void prepare_buffered_point_piece(piece& pc)
  751. {
  752. // create monotonic sections in y-dimension
  753. typedef boost::mpl::vector_c<std::size_t, 1> dimensions;
  754. geometry::sectionalize<false, dimensions>(pc.robust_ring,
  755. detail::no_rescale_policy(), pc.sections,
  756. m_envelope_strategy, m_expand_strategy);
  757. // Determine min/max radius
  758. typedef geometry::model::referring_segment<robust_point_type const>
  759. robust_segment_type;
  760. typename robust_ring_type::const_iterator current = pc.robust_ring.begin();
  761. typename robust_ring_type::const_iterator next = current + 1;
  762. for (signed_size_type i = 1; i < pc.offsetted_count; i++)
  763. {
  764. robust_segment_type s(*current, *next);
  765. robust_comparable_radius_type const d
  766. = geometry::comparable_distance(pc.robust_center, s);
  767. if (i == 1 || d < pc.robust_min_comparable_radius)
  768. {
  769. pc.robust_min_comparable_radius = d;
  770. }
  771. if (i == 1 || d > pc.robust_max_comparable_radius)
  772. {
  773. pc.robust_max_comparable_radius = d;
  774. }
  775. current = next;
  776. ++next;
  777. }
  778. }
  779. inline void prepare_buffered_point_pieces()
  780. {
  781. for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
  782. it != boost::end(m_pieces);
  783. ++it)
  784. {
  785. if (it->type == geometry::strategy::buffer::buffered_point)
  786. {
  787. prepare_buffered_point_piece(*it);
  788. }
  789. }
  790. }
  791. template <typename DistanceStrategy>
  792. inline void get_turns(DistanceStrategy const& distance_strategy)
  793. {
  794. for(typename boost::range_iterator<sections_type>::type it
  795. = boost::begin(monotonic_sections);
  796. it != boost::end(monotonic_sections);
  797. ++it)
  798. {
  799. enlarge_box(it->bounding_box, 1);
  800. }
  801. {
  802. // Calculate the turns
  803. piece_turn_visitor
  804. <
  805. piece_vector_type,
  806. buffered_ring_collection<buffered_ring<Ring> >,
  807. turn_vector_type,
  808. IntersectionStrategy,
  809. RobustPolicy
  810. > visitor(m_pieces, offsetted_rings, m_turns,
  811. m_intersection_strategy, m_robust_policy);
  812. typedef detail::section::get_section_box
  813. <
  814. typename IntersectionStrategy::expand_box_strategy_type
  815. > get_section_box_type;
  816. typedef detail::section::overlaps_section_box
  817. <
  818. typename IntersectionStrategy::disjoint_box_box_strategy_type
  819. > overlaps_section_box_type;
  820. geometry::partition
  821. <
  822. robust_box_type
  823. >::apply(monotonic_sections, visitor,
  824. get_section_box_type(),
  825. overlaps_section_box_type());
  826. }
  827. insert_rescaled_piece_turns();
  828. reverse_negative_robust_rings();
  829. determine_properties();
  830. prepare_buffered_point_pieces();
  831. {
  832. // Check if it is inside any of the pieces
  833. turn_in_piece_visitor
  834. <
  835. typename geometry::cs_tag<point_type>::type,
  836. turn_vector_type, piece_vector_type,
  837. DistanceStrategy,
  838. point_in_geometry_strategy_type,
  839. side_strategy_type
  840. > visitor(m_turns, m_pieces,
  841. distance_strategy,
  842. m_point_in_geometry_strategy,
  843. m_side_strategy);
  844. typedef turn_ovelaps_box
  845. <
  846. typename IntersectionStrategy::disjoint_point_box_strategy_type
  847. > turn_ovelaps_box_type;
  848. typedef piece_ovelaps_box
  849. <
  850. typename IntersectionStrategy::disjoint_box_box_strategy_type
  851. > piece_ovelaps_box_type;
  852. geometry::partition
  853. <
  854. robust_box_type
  855. >::apply(m_turns, m_pieces, visitor,
  856. turn_get_box(), turn_ovelaps_box_type(),
  857. piece_get_box(), piece_ovelaps_box_type());
  858. }
  859. }
  860. inline void start_new_ring(bool deflate)
  861. {
  862. signed_size_type const n = static_cast<signed_size_type>(offsetted_rings.size());
  863. current_segment_id.source_index = 0;
  864. current_segment_id.multi_index = n;
  865. current_segment_id.ring_index = -1;
  866. current_segment_id.segment_index = 0;
  867. offsetted_rings.resize(n + 1);
  868. current_robust_ring.clear();
  869. m_first_piece_index = static_cast<signed_size_type>(boost::size(m_pieces));
  870. m_deflate = deflate;
  871. if (deflate)
  872. {
  873. // Pieces contain either deflated exterior rings, or inflated
  874. // interior rings which are effectively deflated too
  875. m_has_deflated = true;
  876. }
  877. }
  878. inline void abort_ring()
  879. {
  880. // Remove all created pieces for this ring, sections, last offsetted
  881. while (! m_pieces.empty()
  882. && m_pieces.back().first_seg_id.multi_index
  883. == current_segment_id.multi_index)
  884. {
  885. m_pieces.erase(m_pieces.end() - 1);
  886. }
  887. while (! monotonic_sections.empty()
  888. && monotonic_sections.back().ring_id.multi_index
  889. == current_segment_id.multi_index)
  890. {
  891. monotonic_sections.erase(monotonic_sections.end() - 1);
  892. }
  893. offsetted_rings.erase(offsetted_rings.end() - 1);
  894. current_robust_ring.clear();
  895. m_first_piece_index = -1;
  896. }
  897. inline void update_closing_point()
  898. {
  899. BOOST_GEOMETRY_ASSERT(! offsetted_rings.empty());
  900. buffered_ring<Ring>& added = offsetted_rings.back();
  901. if (! boost::empty(added))
  902. {
  903. range::back(added) = range::front(added);
  904. }
  905. }
  906. inline void update_last_point(point_type const& p,
  907. buffered_ring<Ring>& ring)
  908. {
  909. // For the first point of a new piece, and there were already
  910. // points in the offsetted ring, for some piece types the first point
  911. // is a duplicate of the last point of the previous piece.
  912. // TODO: disable that, that point should not be added
  913. // For now, it is made equal because due to numerical instability,
  914. // it can be a tiny bit off, possibly causing a self-intersection
  915. BOOST_GEOMETRY_ASSERT(boost::size(m_pieces) > 0);
  916. if (! ring.empty()
  917. && current_segment_id.segment_index
  918. == m_pieces.back().first_seg_id.segment_index)
  919. {
  920. ring.back() = p;
  921. }
  922. }
  923. inline void set_piece_center(point_type const& center)
  924. {
  925. BOOST_GEOMETRY_ASSERT(! m_pieces.empty());
  926. geometry::recalculate(m_pieces.back().robust_center, center,
  927. m_robust_policy);
  928. }
  929. inline void finish_ring(strategy::buffer::result_code code,
  930. bool is_interior = false, bool has_interiors = false)
  931. {
  932. if (code == strategy::buffer::result_error_numerical)
  933. {
  934. abort_ring();
  935. return;
  936. }
  937. if (m_first_piece_index == -1)
  938. {
  939. return;
  940. }
  941. if (m_first_piece_index < static_cast<signed_size_type>(boost::size(m_pieces)))
  942. {
  943. // If piece was added
  944. // Reassign left-of-first and right-of-last
  945. geometry::range::at(m_pieces, m_first_piece_index).left_index
  946. = static_cast<signed_size_type>(boost::size(m_pieces)) - 1;
  947. geometry::range::back(m_pieces).right_index = m_first_piece_index;
  948. }
  949. m_first_piece_index = -1;
  950. update_closing_point();
  951. if (! current_robust_ring.empty())
  952. {
  953. BOOST_GEOMETRY_ASSERT
  954. (
  955. geometry::equals(current_robust_ring.front(),
  956. current_robust_ring.back())
  957. );
  958. robust_originals.push_back(
  959. robust_original(current_robust_ring,
  960. is_interior, has_interiors, m_envelope_strategy, m_expand_strategy));
  961. }
  962. }
  963. inline void set_current_ring_concave()
  964. {
  965. BOOST_GEOMETRY_ASSERT(boost::size(offsetted_rings) > 0);
  966. offsetted_rings.back().has_concave = true;
  967. }
  968. inline signed_size_type add_point(point_type const& p)
  969. {
  970. BOOST_GEOMETRY_ASSERT(boost::size(offsetted_rings) > 0);
  971. buffered_ring<Ring>& current_ring = offsetted_rings.back();
  972. update_last_point(p, current_ring);
  973. current_segment_id.segment_index++;
  974. current_ring.push_back(p);
  975. return static_cast<signed_size_type>(current_ring.size());
  976. }
  977. //-------------------------------------------------------------------------
  978. inline piece& create_piece(strategy::buffer::piece_type type,
  979. bool decrease_segment_index_by_one)
  980. {
  981. if (type == strategy::buffer::buffered_concave)
  982. {
  983. offsetted_rings.back().has_concave = true;
  984. }
  985. piece pc;
  986. pc.type = type;
  987. pc.index = static_cast<signed_size_type>(boost::size(m_pieces));
  988. pc.is_deflated = m_deflate;
  989. current_segment_id.piece_index = pc.index;
  990. pc.first_seg_id = current_segment_id;
  991. // Assign left/right (for first/last piece per ring they will be re-assigned later)
  992. pc.left_index = pc.index - 1;
  993. pc.right_index = pc.index + 1;
  994. std::size_t const n = boost::size(offsetted_rings.back());
  995. pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n;
  996. pc.last_segment_index = pc.first_seg_id.segment_index;
  997. m_pieces.push_back(pc);
  998. return m_pieces.back();
  999. }
  1000. inline void init_rescale_piece(piece& pc, std::size_t helper_points_size)
  1001. {
  1002. if (pc.first_seg_id.segment_index < 0)
  1003. {
  1004. // This indicates an error situation: an earlier piece was empty
  1005. // It currently does not happen
  1006. // std::cout << "EMPTY " << pc.type << " " << pc.index << " " << pc.first_seg_id.multi_index << std::endl;
  1007. pc.offsetted_count = 0;
  1008. return;
  1009. }
  1010. BOOST_GEOMETRY_ASSERT(pc.first_seg_id.multi_index >= 0);
  1011. BOOST_GEOMETRY_ASSERT(pc.last_segment_index >= 0);
  1012. pc.offsetted_count = pc.last_segment_index - pc.first_seg_id.segment_index;
  1013. BOOST_GEOMETRY_ASSERT(pc.offsetted_count >= 0);
  1014. pc.robust_ring.reserve(pc.offsetted_count + helper_points_size);
  1015. // Add rescaled offsetted segments
  1016. {
  1017. buffered_ring<Ring> const& ring = offsetted_rings[pc.first_seg_id.multi_index];
  1018. typedef typename boost::range_iterator<const buffered_ring<Ring> >::type it_type;
  1019. for (it_type it = boost::begin(ring) + pc.first_seg_id.segment_index;
  1020. it != boost::begin(ring) + pc.last_segment_index;
  1021. ++it)
  1022. {
  1023. robust_point_type point;
  1024. geometry::recalculate(point, *it, m_robust_policy);
  1025. pc.robust_ring.push_back(point);
  1026. }
  1027. }
  1028. }
  1029. inline robust_point_type add_helper_point(piece& pc, const point_type& point)
  1030. {
  1031. #if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS)
  1032. pc.helper_points.push_back(point);
  1033. #endif
  1034. robust_point_type rob_point;
  1035. geometry::recalculate(rob_point, point, m_robust_policy);
  1036. pc.robust_ring.push_back(rob_point);
  1037. return rob_point;
  1038. }
  1039. // TODO: this is shared with sectionalize, move to somewhere else (assign?)
  1040. template <typename Box, typename Value>
  1041. inline void enlarge_box(Box& box, Value value)
  1042. {
  1043. geometry::set<0, 0>(box, geometry::get<0, 0>(box) - value);
  1044. geometry::set<0, 1>(box, geometry::get<0, 1>(box) - value);
  1045. geometry::set<1, 0>(box, geometry::get<1, 0>(box) + value);
  1046. geometry::set<1, 1>(box, geometry::get<1, 1>(box) + value);
  1047. }
  1048. inline void calculate_robust_envelope(piece& pc)
  1049. {
  1050. if (pc.offsetted_count == 0)
  1051. {
  1052. return;
  1053. }
  1054. geometry::envelope(pc.robust_ring, pc.robust_envelope, m_envelope_strategy);
  1055. geometry::assign_inverse(pc.robust_offsetted_envelope);
  1056. for (signed_size_type i = 0; i < pc.offsetted_count; i++)
  1057. {
  1058. geometry::expand(pc.robust_offsetted_envelope, pc.robust_ring[i]);
  1059. }
  1060. // Take roundings into account, enlarge boxes with 1 integer
  1061. enlarge_box(pc.robust_envelope, 1);
  1062. enlarge_box(pc.robust_offsetted_envelope, 1);
  1063. }
  1064. inline void sectionalize(piece& pc)
  1065. {
  1066. buffered_ring<Ring> const& ring = offsetted_rings.back();
  1067. typedef geometry::detail::sectionalize::sectionalize_part
  1068. <
  1069. point_type,
  1070. boost::mpl::vector_c<std::size_t, 0, 1> // x,y dimension
  1071. > sectionalizer;
  1072. // Create a ring-identifier. The source-index is the piece index
  1073. // The multi_index is as in this collection (the ring), but not used here
  1074. // The ring_index is not used
  1075. ring_identifier ring_id(pc.index, pc.first_seg_id.multi_index, -1);
  1076. sectionalizer::apply(monotonic_sections,
  1077. boost::begin(ring) + pc.first_seg_id.segment_index,
  1078. boost::begin(ring) + pc.last_segment_index,
  1079. m_robust_policy,
  1080. ring_id, 10);
  1081. }
  1082. inline void finish_piece(piece& pc)
  1083. {
  1084. init_rescale_piece(pc, 0u);
  1085. calculate_robust_envelope(pc);
  1086. sectionalize(pc);
  1087. }
  1088. inline void finish_piece(piece& pc,
  1089. const point_type& point1,
  1090. const point_type& point2,
  1091. const point_type& point3)
  1092. {
  1093. init_rescale_piece(pc, 3u);
  1094. if (pc.offsetted_count == 0)
  1095. {
  1096. return;
  1097. }
  1098. add_helper_point(pc, point1);
  1099. robust_point_type mid_point = add_helper_point(pc, point2);
  1100. add_helper_point(pc, point3);
  1101. calculate_robust_envelope(pc);
  1102. sectionalize(pc);
  1103. current_robust_ring.push_back(mid_point);
  1104. }
  1105. inline void finish_piece(piece& pc,
  1106. const point_type& point1,
  1107. const point_type& point2,
  1108. const point_type& point3,
  1109. const point_type& point4)
  1110. {
  1111. init_rescale_piece(pc, 4u);
  1112. add_helper_point(pc, point1);
  1113. robust_point_type mid_point2 = add_helper_point(pc, point2);
  1114. robust_point_type mid_point1 = add_helper_point(pc, point3);
  1115. add_helper_point(pc, point4);
  1116. sectionalize(pc);
  1117. calculate_robust_envelope(pc);
  1118. // Add mid-points in other order to current helper_ring
  1119. current_robust_ring.push_back(mid_point1);
  1120. current_robust_ring.push_back(mid_point2);
  1121. }
  1122. inline void add_piece(strategy::buffer::piece_type type, point_type const& p,
  1123. point_type const& b1, point_type const& b2)
  1124. {
  1125. piece& pc = create_piece(type, false);
  1126. add_point(b1);
  1127. pc.last_segment_index = add_point(b2);
  1128. finish_piece(pc, b2, p, b1);
  1129. }
  1130. template <typename Range>
  1131. inline void add_range_to_piece(piece& pc, Range const& range, bool add_front)
  1132. {
  1133. BOOST_GEOMETRY_ASSERT(boost::size(range) != 0u);
  1134. typename Range::const_iterator it = boost::begin(range);
  1135. // If it follows a non-join (so basically the same piece-type) point b1 should be added.
  1136. // There should be two intersections later and it should be discarded.
  1137. // But for now we need it to calculate intersections
  1138. if (add_front)
  1139. {
  1140. add_point(*it);
  1141. }
  1142. for (++it; it != boost::end(range); ++it)
  1143. {
  1144. pc.last_segment_index = add_point(*it);
  1145. }
  1146. }
  1147. template <typename Range>
  1148. inline void add_piece(strategy::buffer::piece_type type, Range const& range,
  1149. bool decrease_segment_index_by_one)
  1150. {
  1151. piece& pc = create_piece(type, decrease_segment_index_by_one);
  1152. if (boost::size(range) > 0u)
  1153. {
  1154. add_range_to_piece(pc, range, offsetted_rings.back().empty());
  1155. }
  1156. finish_piece(pc);
  1157. }
  1158. template <typename Range>
  1159. inline void add_side_piece(point_type const& p1, point_type const& p2,
  1160. Range const& range, bool first)
  1161. {
  1162. BOOST_GEOMETRY_ASSERT(boost::size(range) >= 2u);
  1163. piece& pc = create_piece(strategy::buffer::buffered_segment, ! first);
  1164. add_range_to_piece(pc, range, first);
  1165. finish_piece(pc, range.back(), p2, p1, range.front());
  1166. }
  1167. template <typename Range>
  1168. inline void add_piece(strategy::buffer::piece_type type,
  1169. point_type const& p, Range const& range)
  1170. {
  1171. piece& pc = create_piece(type, true);
  1172. if (boost::size(range) > 0u)
  1173. {
  1174. add_range_to_piece(pc, range, offsetted_rings.back().empty());
  1175. finish_piece(pc, range.back(), p, range.front());
  1176. }
  1177. else
  1178. {
  1179. finish_piece(pc);
  1180. }
  1181. }
  1182. template <typename EndcapStrategy, typename Range>
  1183. inline void add_endcap(EndcapStrategy const& strategy, Range const& range,
  1184. point_type const& end_point)
  1185. {
  1186. boost::ignore_unused(strategy);
  1187. if (range.empty())
  1188. {
  1189. return;
  1190. }
  1191. strategy::buffer::piece_type pt = strategy.get_piece_type();
  1192. if (pt == strategy::buffer::buffered_flat_end)
  1193. {
  1194. // It is flat, should just be added, without helper segments
  1195. add_piece(pt, range, true);
  1196. }
  1197. else
  1198. {
  1199. // Normal case, it has an "inside", helper segments should be added
  1200. add_piece(pt, end_point, range);
  1201. }
  1202. }
  1203. inline void mark_flat_start()
  1204. {
  1205. if (! m_pieces.empty())
  1206. {
  1207. piece& back = m_pieces.back();
  1208. back.is_flat_start = true;
  1209. }
  1210. }
  1211. inline void mark_flat_end()
  1212. {
  1213. if (! m_pieces.empty())
  1214. {
  1215. piece& back = m_pieces.back();
  1216. back.is_flat_end = true;
  1217. }
  1218. }
  1219. //-------------------------------------------------------------------------
  1220. inline void enrich()
  1221. {
  1222. enrich_intersection_points<false, false, overlay_buffer>(m_turns,
  1223. m_clusters, offsetted_rings, offsetted_rings,
  1224. m_robust_policy,
  1225. m_intersection_strategy);
  1226. }
  1227. // Discards all rings which do have not-OK intersection points only.
  1228. // Those can never be traversed and should not be part of the output.
  1229. inline void discard_rings()
  1230. {
  1231. for (typename boost::range_iterator<turn_vector_type const>::type it =
  1232. boost::begin(m_turns); it != boost::end(m_turns); ++it)
  1233. {
  1234. if (it->location != location_ok)
  1235. {
  1236. offsetted_rings[it->operations[0].seg_id.multi_index].has_discarded_intersections = true;
  1237. offsetted_rings[it->operations[1].seg_id.multi_index].has_discarded_intersections = true;
  1238. }
  1239. else
  1240. {
  1241. offsetted_rings[it->operations[0].seg_id.multi_index].has_accepted_intersections = true;
  1242. offsetted_rings[it->operations[1].seg_id.multi_index].has_accepted_intersections = true;
  1243. }
  1244. }
  1245. }
  1246. inline bool point_coveredby_original(point_type const& point)
  1247. {
  1248. typedef typename IntersectionStrategy::disjoint_point_box_strategy_type d_pb_strategy_type;
  1249. robust_point_type any_point;
  1250. geometry::recalculate(any_point, point, m_robust_policy);
  1251. signed_size_type count_in_original = 0;
  1252. // Check of the robust point of this outputted ring is in
  1253. // any of the robust original rings
  1254. // This can go quadratic if the input has many rings, and there
  1255. // are many untouched deflated rings around
  1256. for (typename std::vector<robust_original>::const_iterator it
  1257. = robust_originals.begin();
  1258. it != robust_originals.end();
  1259. ++it)
  1260. {
  1261. robust_original const& original = *it;
  1262. if (detail::disjoint::disjoint_point_box(any_point,
  1263. original.m_box,
  1264. d_pb_strategy_type()))
  1265. {
  1266. continue;
  1267. }
  1268. int const geometry_code
  1269. = detail::within::point_in_geometry(any_point,
  1270. original.m_ring, m_point_in_geometry_strategy);
  1271. if (geometry_code == -1)
  1272. {
  1273. // Outside, continue
  1274. continue;
  1275. }
  1276. // Apply for possibly nested interior rings
  1277. if (original.m_is_interior)
  1278. {
  1279. count_in_original--;
  1280. }
  1281. else if (original.m_has_interiors)
  1282. {
  1283. count_in_original++;
  1284. }
  1285. else
  1286. {
  1287. // Exterior ring without interior rings
  1288. return true;
  1289. }
  1290. }
  1291. return count_in_original > 0;
  1292. }
  1293. // For a deflate, all rings around inner rings which are untouched
  1294. // (no intersections/turns) and which are OUTSIDE the original should
  1295. // be discarded
  1296. inline void discard_nonintersecting_deflated_rings()
  1297. {
  1298. for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it
  1299. = boost::begin(offsetted_rings);
  1300. it != boost::end(offsetted_rings);
  1301. ++it)
  1302. {
  1303. buffered_ring<Ring>& ring = *it;
  1304. if (! ring.has_intersections()
  1305. && boost::size(ring) > 0u
  1306. && geometry::area(ring, m_area_strategy) < 0)
  1307. {
  1308. if (! point_coveredby_original(geometry::range::front(ring)))
  1309. {
  1310. ring.is_untouched_outside_original = true;
  1311. }
  1312. }
  1313. }
  1314. }
  1315. inline void block_turns()
  1316. {
  1317. // To fix left-turn issues like #rt_u13
  1318. // But currently it causes more other issues than it fixes
  1319. // m_turns.erase
  1320. // (
  1321. // std::remove_if(boost::begin(m_turns), boost::end(m_turns),
  1322. // redundant_turn()),
  1323. // boost::end(m_turns)
  1324. // );
  1325. for (typename boost::range_iterator<turn_vector_type>::type it =
  1326. boost::begin(m_turns); it != boost::end(m_turns); ++it)
  1327. {
  1328. buffer_turn_info_type& turn = *it;
  1329. if (turn.location != location_ok)
  1330. {
  1331. // Discard this turn (don't set it to blocked to avoid colocated
  1332. // clusters being discarded afterwards
  1333. turn.discarded = true;
  1334. }
  1335. }
  1336. }
  1337. inline void traverse()
  1338. {
  1339. typedef detail::overlay::traverse
  1340. <
  1341. false, false,
  1342. buffered_ring_collection<buffered_ring<Ring> >,
  1343. buffered_ring_collection<buffered_ring<Ring > >,
  1344. overlay_buffer,
  1345. backtrack_for_buffer
  1346. > traverser;
  1347. std::map<ring_identifier, overlay::ring_turn_info> turn_info_per_ring;
  1348. traversed_rings.clear();
  1349. buffer_overlay_visitor visitor;
  1350. traverser::apply(offsetted_rings, offsetted_rings,
  1351. m_intersection_strategy, m_robust_policy,
  1352. m_turns, traversed_rings,
  1353. turn_info_per_ring,
  1354. m_clusters, visitor);
  1355. }
  1356. inline void reverse()
  1357. {
  1358. for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it = boost::begin(offsetted_rings);
  1359. it != boost::end(offsetted_rings);
  1360. ++it)
  1361. {
  1362. if (! it->has_intersections())
  1363. {
  1364. std::reverse(it->begin(), it->end());
  1365. }
  1366. }
  1367. for (typename boost::range_iterator<buffered_ring_collection<Ring> >::type
  1368. it = boost::begin(traversed_rings);
  1369. it != boost::end(traversed_rings);
  1370. ++it)
  1371. {
  1372. std::reverse(it->begin(), it->end());
  1373. }
  1374. }
  1375. template <typename GeometryOutput, typename OutputIterator>
  1376. inline OutputIterator assign(OutputIterator out) const
  1377. {
  1378. typedef detail::overlay::ring_properties<point_type, area_result_type> properties;
  1379. std::map<ring_identifier, properties> selected;
  1380. // Select all rings which do not have any self-intersection
  1381. // Inner rings, for deflate, which do not have intersections, and
  1382. // which are outside originals, are skipped
  1383. // (other ones should be traversed)
  1384. signed_size_type index = 0;
  1385. for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings);
  1386. it != boost::end(offsetted_rings);
  1387. ++it, ++index)
  1388. {
  1389. if (! it->has_intersections()
  1390. && ! it->is_untouched_outside_original)
  1391. {
  1392. properties p = properties(*it, m_area_strategy);
  1393. if (p.valid)
  1394. {
  1395. ring_identifier id(0, index, -1);
  1396. selected[id] = p;
  1397. }
  1398. }
  1399. }
  1400. // Select all created rings
  1401. index = 0;
  1402. for (typename boost::range_iterator<buffered_ring_collection<Ring> const>::type
  1403. it = boost::begin(traversed_rings);
  1404. it != boost::end(traversed_rings);
  1405. ++it, ++index)
  1406. {
  1407. properties p = properties(*it, m_area_strategy);
  1408. if (p.valid)
  1409. {
  1410. ring_identifier id(2, index, -1);
  1411. selected[id] = p;
  1412. }
  1413. }
  1414. detail::overlay::assign_parents<overlay_buffer>(offsetted_rings, traversed_rings,
  1415. selected, m_intersection_strategy);
  1416. return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out,
  1417. m_area_strategy);
  1418. }
  1419. };
  1420. }} // namespace detail::buffer
  1421. #endif // DOXYGEN_NO_DETAIL
  1422. }} // namespace boost::geometry
  1423. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP