buffer_inserter.hpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2022-2023 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2017-2022.
  5. // Modifications copyright (c) 2017-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_BUFFER_INSERTER_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
  12. #include <cstddef>
  13. #include <iterator>
  14. #include <boost/core/ignore_unused.hpp>
  15. #include <boost/range/begin.hpp>
  16. #include <boost/range/end.hpp>
  17. #include <boost/range/rbegin.hpp>
  18. #include <boost/range/rend.hpp>
  19. #include <boost/range/size.hpp>
  20. #include <boost/range/value_type.hpp>
  21. #include <boost/geometry/algorithms/detail/direction_code.hpp>
  22. #include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp>
  23. #include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
  24. #include <boost/geometry/algorithms/num_interior_rings.hpp>
  25. #include <boost/geometry/algorithms/simplify.hpp>
  26. #include <boost/geometry/core/assert.hpp>
  27. #include <boost/geometry/core/closure.hpp>
  28. #include <boost/geometry/core/exterior_ring.hpp>
  29. #include <boost/geometry/core/interior_rings.hpp>
  30. #include <boost/geometry/geometries/linestring.hpp>
  31. #include <boost/geometry/geometries/ring.hpp>
  32. #include <boost/geometry/strategies/buffer.hpp>
  33. #include <boost/geometry/strategies/side.hpp>
  34. #include <boost/geometry/util/constexpr.hpp>
  35. #include <boost/geometry/util/math.hpp>
  36. #include <boost/geometry/util/type_traits.hpp>
  37. #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
  38. namespace boost { namespace geometry
  39. {
  40. #ifndef DOXYGEN_NO_DETAIL
  41. namespace detail { namespace buffer
  42. {
  43. template <typename RangeIn, typename DistanceStrategy, typename RangeOut, typename Strategies>
  44. inline void simplify_input(RangeIn const& range,
  45. DistanceStrategy const& distance,
  46. RangeOut& simplified,
  47. Strategies const& strategies)
  48. {
  49. // We have to simplify the ring before to avoid very small-scaled
  50. // features in the original (convex/concave/convex) being enlarged
  51. // in a very large scale and causing issues (IP's within pieces).
  52. // This might be reconsidered later. Simplifying with a very small
  53. // distance (1%% of the buffer) will never be visible in the result,
  54. // if it is using round joins. For miter joins they are even more
  55. // sensitive to small scale input features, however the result will
  56. // look better.
  57. // It also gets rid of duplicate points
  58. geometry::detail::simplify::simplify_range<2>::apply(range,
  59. simplified, distance.simplify_distance(),
  60. detail::simplify::douglas_peucker(),
  61. strategies);
  62. }
  63. template <typename RingOutput>
  64. struct buffer_range
  65. {
  66. typedef typename point_type<RingOutput>::type output_point_type;
  67. typedef typename coordinate_type<RingOutput>::type coordinate_type;
  68. template
  69. <
  70. typename Collection,
  71. typename Point,
  72. typename DistanceStrategy,
  73. typename SegmentStrategy,
  74. typename JoinStrategy,
  75. typename EndStrategy,
  76. typename RobustPolicy,
  77. typename Strategies
  78. >
  79. static inline
  80. void add_join(Collection& collection,
  81. Point const& penultimate_input,
  82. Point const& previous_input,
  83. output_point_type const& prev_perp1,
  84. output_point_type const& prev_perp2,
  85. Point const& input,
  86. output_point_type const& perp1,
  87. output_point_type const& perp2,
  88. geometry::strategy::buffer::buffer_side_selector side,
  89. DistanceStrategy const& distance,
  90. SegmentStrategy const& segment_strategy,
  91. JoinStrategy const& join_strategy,
  92. EndStrategy const& end_strategy,
  93. RobustPolicy const& ,
  94. Strategies const& strategies)
  95. {
  96. geometry::strategy::buffer::join_selector const join
  97. = get_join_type(penultimate_input, previous_input, input,
  98. strategies);
  99. switch(join)
  100. {
  101. case geometry::strategy::buffer::join_continue :
  102. // No join, we get two consecutive sides
  103. break;
  104. case geometry::strategy::buffer::join_concave :
  105. {
  106. std::vector<output_point_type> range_out;
  107. range_out.push_back(prev_perp2);
  108. range_out.push_back(previous_input);
  109. collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
  110. range_out.clear();
  111. range_out.push_back(previous_input);
  112. range_out.push_back(perp1);
  113. collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
  114. }
  115. break;
  116. case geometry::strategy::buffer::join_spike :
  117. {
  118. // For linestrings, only add spike at one side to avoid
  119. // duplicates
  120. std::vector<output_point_type> range_out;
  121. end_strategy.apply(penultimate_input, prev_perp2, previous_input, perp1, side, distance, range_out);
  122. collection.add_endcap(end_strategy, range_out, previous_input);
  123. collection.set_current_ring_concave();
  124. }
  125. break;
  126. case geometry::strategy::buffer::join_convex :
  127. {
  128. // The corner is convex, we create a join
  129. // TODO (future) - avoid a separate vector, add the piece directly
  130. output_point_type intersection_point;
  131. if (line_line_intersection::apply(prev_perp1, prev_perp2,
  132. perp1, perp2, previous_input,
  133. segment_strategy.equidistant(),
  134. intersection_point))
  135. {
  136. std::vector<output_point_type> range_out;
  137. if (join_strategy.apply(intersection_point,
  138. previous_input, prev_perp2, perp1,
  139. distance.apply(previous_input, input, side),
  140. range_out))
  141. {
  142. collection.add_piece(geometry::strategy::buffer::buffered_join,
  143. previous_input, range_out);
  144. }
  145. }
  146. }
  147. break;
  148. }
  149. }
  150. // Returns true if collinear point p2 continues after p0 and p1.
  151. // If it turns back (spike), it returns false.
  152. static inline bool same_direction(output_point_type const& p0,
  153. output_point_type const& p1,
  154. output_point_type const& p2)
  155. {
  156. typedef typename cs_tag<output_point_type>::type cs_tag;
  157. return direction_code<cs_tag>(p0, p1, p2) == 1;
  158. }
  159. template <typename Strategies>
  160. static inline geometry::strategy::buffer::join_selector get_join_type(
  161. output_point_type const& p0,
  162. output_point_type const& p1,
  163. output_point_type const& p2,
  164. Strategies const& strategies)
  165. {
  166. int const side = strategies.side().apply(p0, p1, p2);
  167. return side == -1 ? geometry::strategy::buffer::join_convex
  168. : side == 1 ? geometry::strategy::buffer::join_concave
  169. : same_direction(p0, p1, p2) ? geometry::strategy::buffer::join_continue
  170. : geometry::strategy::buffer::join_spike;
  171. }
  172. template
  173. <
  174. typename Collection,
  175. typename Iterator,
  176. typename DistanceStrategy,
  177. typename SegmentStrategy,
  178. typename JoinStrategy,
  179. typename EndStrategy,
  180. typename RobustPolicy,
  181. typename Strategies
  182. >
  183. static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
  184. Iterator begin, Iterator end,
  185. geometry::strategy::buffer::buffer_side_selector side,
  186. DistanceStrategy const& distance_strategy,
  187. SegmentStrategy const& segment_strategy,
  188. JoinStrategy const& join_strategy,
  189. EndStrategy const& end_strategy,
  190. RobustPolicy const& robust_policy,
  191. Strategies const& strategies,
  192. bool linear,
  193. output_point_type& first_p1,
  194. output_point_type& first_p2,
  195. output_point_type& last_p1,
  196. output_point_type& last_p2)
  197. {
  198. boost::ignore_unused(segment_strategy);
  199. typedef typename std::iterator_traits
  200. <
  201. Iterator
  202. >::value_type point_type;
  203. point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end
  204. /*
  205. * last.p1 last.p2 these are the "previous (last) perpendicular points"
  206. * --------------
  207. * | |
  208. * *------------*____ <- *prev
  209. * pup | | p1 "current perpendicular point 1"
  210. * | |
  211. * | | this forms a "side", a side is a piece
  212. * | |
  213. * *____| p2
  214. *
  215. * ^
  216. * *it
  217. *
  218. * pup: penultimate_point
  219. */
  220. bool const mark_flat
  221. = linear
  222. && end_strategy.get_piece_type() == geometry::strategy::buffer::buffered_flat_end;
  223. geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output;
  224. bool first = true;
  225. Iterator it = begin;
  226. std::vector<output_point_type> generated_side;
  227. generated_side.reserve(2);
  228. for (Iterator prev = it++; it != end; ++it)
  229. {
  230. generated_side.clear();
  231. geometry::strategy::buffer::result_code error_code
  232. = segment_strategy.apply(*prev, *it, side,
  233. distance_strategy, generated_side);
  234. if (error_code == geometry::strategy::buffer::result_no_output)
  235. {
  236. // Because input is simplified, this is improbable,
  237. // but it can happen for degenerate geometries
  238. // Further handling of this side is skipped
  239. continue;
  240. }
  241. else if (error_code == geometry::strategy::buffer::result_error_numerical)
  242. {
  243. return error_code;
  244. }
  245. BOOST_GEOMETRY_ASSERT(! generated_side.empty());
  246. result = geometry::strategy::buffer::result_normal;
  247. if (! first)
  248. {
  249. add_join(collection,
  250. penultimate_point,
  251. *prev, last_p1, last_p2,
  252. *it, generated_side.front(), generated_side.back(),
  253. side,
  254. distance_strategy, segment_strategy, join_strategy, end_strategy,
  255. robust_policy, strategies);
  256. }
  257. collection.add_side_piece(*prev, *it, generated_side, first, distance_strategy.empty(side));
  258. if (first && mark_flat)
  259. {
  260. collection.mark_flat_start(*prev);
  261. }
  262. penultimate_point = *prev;
  263. ultimate_point = *it;
  264. last_p1 = generated_side.front();
  265. last_p2 = generated_side.back();
  266. prev = it;
  267. if (first)
  268. {
  269. first = false;
  270. second_point = *it;
  271. first_p1 = generated_side.front();
  272. first_p2 = generated_side.back();
  273. }
  274. }
  275. if (mark_flat)
  276. {
  277. collection.mark_flat_end(ultimate_point);
  278. }
  279. return result;
  280. }
  281. };
  282. template
  283. <
  284. typename Multi,
  285. typename PolygonOutput,
  286. typename Policy
  287. >
  288. struct buffer_multi
  289. {
  290. template
  291. <
  292. typename Collection,
  293. typename DistanceStrategy,
  294. typename SegmentStrategy,
  295. typename JoinStrategy,
  296. typename EndStrategy,
  297. typename PointStrategy,
  298. typename RobustPolicy,
  299. typename Strategies
  300. >
  301. static inline void apply(Multi const& multi,
  302. Collection& collection,
  303. DistanceStrategy const& distance_strategy,
  304. SegmentStrategy const& segment_strategy,
  305. JoinStrategy const& join_strategy,
  306. EndStrategy const& end_strategy,
  307. PointStrategy const& point_strategy,
  308. RobustPolicy const& robust_policy,
  309. Strategies const& strategies)
  310. {
  311. for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
  312. {
  313. Policy::apply(*it, collection,
  314. distance_strategy, segment_strategy,
  315. join_strategy, end_strategy, point_strategy,
  316. robust_policy, strategies);
  317. }
  318. }
  319. };
  320. struct visit_pieces_default_policy
  321. {
  322. template <typename Collection>
  323. static inline void apply(Collection const&, int)
  324. {}
  325. };
  326. template
  327. <
  328. typename OutputPointType,
  329. typename Point,
  330. typename Collection,
  331. typename DistanceStrategy,
  332. typename PointStrategy
  333. >
  334. inline void buffer_point(Point const& point, Collection& collection,
  335. DistanceStrategy const& distance_strategy,
  336. PointStrategy const& point_strategy)
  337. {
  338. collection.start_new_ring(false);
  339. std::vector<OutputPointType> range_out;
  340. point_strategy.apply(point, distance_strategy, range_out);
  341. collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false);
  342. collection.set_piece_center(point);
  343. collection.finish_ring(geometry::strategy::buffer::result_normal);
  344. }
  345. }} // namespace detail::buffer
  346. #endif // DOXYGEN_NO_DETAIL
  347. #ifndef DOXYGEN_NO_DISPATCH
  348. namespace dispatch
  349. {
  350. template
  351. <
  352. typename Tag,
  353. typename RingInput,
  354. typename RingOutput
  355. >
  356. struct buffer_inserter
  357. {};
  358. template
  359. <
  360. typename Point,
  361. typename RingOutput
  362. >
  363. struct buffer_inserter<point_tag, Point, RingOutput>
  364. {
  365. template
  366. <
  367. typename Collection,
  368. typename DistanceStrategy,
  369. typename SegmentStrategy,
  370. typename JoinStrategy,
  371. typename EndStrategy,
  372. typename PointStrategy,
  373. typename RobustPolicy,
  374. typename Strategies
  375. >
  376. static inline void apply(Point const& point, Collection& collection,
  377. DistanceStrategy const& distance_strategy,
  378. SegmentStrategy const& ,
  379. JoinStrategy const& ,
  380. EndStrategy const& ,
  381. PointStrategy const& point_strategy,
  382. RobustPolicy const& ,
  383. Strategies const& )
  384. {
  385. detail::buffer::buffer_point
  386. <
  387. typename point_type<RingOutput>::type
  388. >(point, collection, distance_strategy, point_strategy);
  389. }
  390. };
  391. // Not a specialization, but called from specializations of ring and of polygon.
  392. // Calling code starts/finishes ring before/after apply
  393. template
  394. <
  395. typename RingInput,
  396. typename RingOutput
  397. >
  398. struct buffer_inserter_ring
  399. {
  400. using output_point_type = typename point_type<RingOutput>::type;
  401. template
  402. <
  403. typename Collection,
  404. typename Iterator,
  405. typename DistanceStrategy,
  406. typename SegmentStrategy,
  407. typename JoinStrategy,
  408. typename EndStrategy,
  409. typename RobustPolicy,
  410. typename Strategies
  411. >
  412. static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
  413. Iterator begin, Iterator end,
  414. geometry::strategy::buffer::buffer_side_selector side,
  415. DistanceStrategy const& distance_strategy,
  416. SegmentStrategy const& segment_strategy,
  417. JoinStrategy const& join_strategy,
  418. EndStrategy const& end_strategy,
  419. RobustPolicy const& robust_policy,
  420. Strategies const& strategies)
  421. {
  422. output_point_type first_p1, first_p2, last_p1, last_p2;
  423. typedef detail::buffer::buffer_range<RingOutput> buffer_range;
  424. geometry::strategy::buffer::result_code result
  425. = buffer_range::iterate(collection, begin, end,
  426. side,
  427. distance_strategy, segment_strategy, join_strategy, end_strategy,
  428. robust_policy, strategies,
  429. false, first_p1, first_p2, last_p1, last_p2);
  430. // Generate closing join
  431. if (result == geometry::strategy::buffer::result_normal)
  432. {
  433. buffer_range::add_join(collection,
  434. *(end - 2),
  435. *(end - 1), last_p1, last_p2,
  436. *(begin + 1), first_p1, first_p2,
  437. side,
  438. distance_strategy, segment_strategy, join_strategy, end_strategy,
  439. robust_policy, strategies);
  440. }
  441. // Buffer is closed automatically by last closing corner
  442. return result;
  443. }
  444. template
  445. <
  446. typename Collection,
  447. typename DistanceStrategy,
  448. typename SegmentStrategy,
  449. typename JoinStrategy,
  450. typename EndStrategy,
  451. typename PointStrategy,
  452. typename RobustPolicy,
  453. typename Strategies
  454. >
  455. static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
  456. Collection& collection,
  457. DistanceStrategy const& distance,
  458. SegmentStrategy const& segment_strategy,
  459. JoinStrategy const& join_strategy,
  460. EndStrategy const& end_strategy,
  461. PointStrategy const& point_strategy,
  462. RobustPolicy const& robust_policy,
  463. Strategies const& strategies)
  464. {
  465. // Use helper geometry to support non-mutable input Rings
  466. using simplified_ring_t = model::ring
  467. <
  468. output_point_type,
  469. point_order<RingInput>::value != counterclockwise,
  470. closure<RingInput>::value != open
  471. >;
  472. simplified_ring_t simplified;
  473. detail::buffer::simplify_input(ring, distance, simplified, strategies);
  474. geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
  475. std::size_t n = boost::size(simplified);
  476. std::size_t const min_points = core_detail::closure::minimum_ring_size
  477. <
  478. geometry::closure<simplified_ring_t>::value
  479. >::value;
  480. if (n >= min_points)
  481. {
  482. detail::closed_clockwise_view<simplified_ring_t const> view(simplified);
  483. if (distance.negative())
  484. {
  485. // Walk backwards (rings will be reversed afterwards)
  486. code = iterate(collection, boost::rbegin(view), boost::rend(view),
  487. geometry::strategy::buffer::buffer_side_right,
  488. distance, segment_strategy, join_strategy, end_strategy,
  489. robust_policy, strategies);
  490. }
  491. else
  492. {
  493. code = iterate(collection, boost::begin(view), boost::end(view),
  494. geometry::strategy::buffer::buffer_side_left,
  495. distance, segment_strategy, join_strategy, end_strategy,
  496. robust_policy, strategies);
  497. }
  498. }
  499. if (code == geometry::strategy::buffer::result_no_output && n >= 1)
  500. {
  501. // Use point_strategy to buffer degenerated ring
  502. detail::buffer::buffer_point<output_point_type>
  503. (
  504. geometry::range::front(simplified),
  505. collection, distance, point_strategy
  506. );
  507. }
  508. return code;
  509. }
  510. };
  511. template
  512. <
  513. typename RingInput,
  514. typename RingOutput
  515. >
  516. struct buffer_inserter<ring_tag, RingInput, RingOutput>
  517. {
  518. template
  519. <
  520. typename Collection,
  521. typename DistanceStrategy,
  522. typename SegmentStrategy,
  523. typename JoinStrategy,
  524. typename EndStrategy,
  525. typename PointStrategy,
  526. typename RobustPolicy,
  527. typename Strategies
  528. >
  529. static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
  530. Collection& collection,
  531. DistanceStrategy const& distance,
  532. SegmentStrategy const& segment_strategy,
  533. JoinStrategy const& join_strategy,
  534. EndStrategy const& end_strategy,
  535. PointStrategy const& point_strategy,
  536. RobustPolicy const& robust_policy,
  537. Strategies const& strategies)
  538. {
  539. collection.start_new_ring(distance.negative());
  540. geometry::strategy::buffer::result_code const code
  541. = buffer_inserter_ring<RingInput, RingOutput>::apply(ring,
  542. collection, distance,
  543. segment_strategy, join_strategy, end_strategy, point_strategy,
  544. robust_policy, strategies);
  545. collection.finish_ring(code, ring, false, false);
  546. return code;
  547. }
  548. };
  549. template
  550. <
  551. typename Linestring,
  552. typename Polygon
  553. >
  554. struct buffer_inserter<linestring_tag, Linestring, Polygon>
  555. {
  556. using output_ring_type = typename ring_type<Polygon>::type;
  557. using output_point_type = typename point_type<output_ring_type>::type;
  558. template
  559. <
  560. typename Collection,
  561. typename Iterator,
  562. typename DistanceStrategy,
  563. typename SegmentStrategy,
  564. typename JoinStrategy,
  565. typename EndStrategy,
  566. typename RobustPolicy,
  567. typename Strategies
  568. >
  569. static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
  570. Iterator begin, Iterator end,
  571. geometry::strategy::buffer::buffer_side_selector side,
  572. DistanceStrategy const& distance_strategy,
  573. SegmentStrategy const& segment_strategy,
  574. JoinStrategy const& join_strategy,
  575. EndStrategy const& end_strategy,
  576. RobustPolicy const& robust_policy,
  577. Strategies const& strategies,
  578. output_point_type& first_p1)
  579. {
  580. output_point_type const& ultimate_point = *(end - 1);
  581. output_point_type const& penultimate_point = *(end - 2);
  582. // For the end-cap, we need to have the last perpendicular point on the
  583. // other side of the linestring. If it is the second pass (right),
  584. // we have it already from the first phase (left).
  585. // But for the first pass, we have to generate it
  586. output_point_type reverse_p1;
  587. if (side == geometry::strategy::buffer::buffer_side_right)
  588. {
  589. reverse_p1 = first_p1;
  590. }
  591. else
  592. {
  593. std::vector<output_point_type> generated_side;
  594. geometry::strategy::buffer::result_code code
  595. = segment_strategy.apply(ultimate_point, penultimate_point,
  596. geometry::strategy::buffer::buffer_side_right,
  597. distance_strategy, generated_side);
  598. if (code != geometry::strategy::buffer::result_normal)
  599. {
  600. // No output or numerical error
  601. return code;
  602. }
  603. reverse_p1 = generated_side.front();
  604. }
  605. output_point_type first_p2, last_p1, last_p2;
  606. geometry::strategy::buffer::result_code result
  607. = detail::buffer::buffer_range<output_ring_type>::iterate(collection,
  608. begin, end, side,
  609. distance_strategy, segment_strategy, join_strategy, end_strategy,
  610. robust_policy, strategies,
  611. true, first_p1, first_p2, last_p1, last_p2);
  612. if (result == geometry::strategy::buffer::result_normal)
  613. {
  614. std::vector<output_point_type> range_out;
  615. end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1,
  616. side, distance_strategy, range_out);
  617. collection.add_endcap(end_strategy, range_out, ultimate_point);
  618. }
  619. return result;
  620. }
  621. template
  622. <
  623. typename Collection,
  624. typename DistanceStrategy,
  625. typename SegmentStrategy,
  626. typename JoinStrategy,
  627. typename EndStrategy,
  628. typename PointStrategy,
  629. typename RobustPolicy,
  630. typename Strategies
  631. >
  632. static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring,
  633. Collection& collection,
  634. DistanceStrategy const& distance,
  635. SegmentStrategy const& segment_strategy,
  636. JoinStrategy const& join_strategy,
  637. EndStrategy const& end_strategy,
  638. PointStrategy const& point_strategy,
  639. RobustPolicy const& robust_policy,
  640. Strategies const& strategies)
  641. {
  642. // Use helper geometry to support non-mutable input Linestrings
  643. model::linestring<output_point_type> simplified;
  644. detail::buffer::simplify_input(linestring, distance, simplified, strategies);
  645. geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
  646. std::size_t n = boost::size(simplified);
  647. if (n > 1)
  648. {
  649. collection.start_new_ring(false);
  650. output_point_type first_p1;
  651. code = iterate(collection,
  652. boost::begin(simplified), boost::end(simplified),
  653. geometry::strategy::buffer::buffer_side_left,
  654. distance, segment_strategy, join_strategy, end_strategy,
  655. robust_policy, strategies,
  656. first_p1);
  657. if (code == geometry::strategy::buffer::result_normal)
  658. {
  659. code = iterate(collection,
  660. boost::rbegin(simplified), boost::rend(simplified),
  661. geometry::strategy::buffer::buffer_side_right,
  662. distance, segment_strategy, join_strategy, end_strategy,
  663. robust_policy, strategies,
  664. first_p1);
  665. }
  666. collection.finish_ring(code);
  667. }
  668. if (code == geometry::strategy::buffer::result_no_output && n >= 1)
  669. {
  670. // Use point_strategy to buffer degenerated linestring
  671. detail::buffer::buffer_point<output_point_type>
  672. (
  673. geometry::range::front(simplified),
  674. collection, distance, point_strategy
  675. );
  676. }
  677. return code;
  678. }
  679. };
  680. template
  681. <
  682. typename PolygonInput,
  683. typename PolygonOutput
  684. >
  685. struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput>
  686. {
  687. private:
  688. typedef typename ring_type<PolygonInput>::type input_ring_type;
  689. typedef typename ring_type<PolygonOutput>::type output_ring_type;
  690. typedef buffer_inserter_ring<input_ring_type, output_ring_type> policy;
  691. template
  692. <
  693. typename Iterator,
  694. typename Collection,
  695. typename DistanceStrategy,
  696. typename SegmentStrategy,
  697. typename JoinStrategy,
  698. typename EndStrategy,
  699. typename PointStrategy,
  700. typename RobustPolicy,
  701. typename Strategies
  702. >
  703. static inline
  704. void iterate(Iterator begin, Iterator end,
  705. Collection& collection,
  706. DistanceStrategy const& distance,
  707. SegmentStrategy const& segment_strategy,
  708. JoinStrategy const& join_strategy,
  709. EndStrategy const& end_strategy,
  710. PointStrategy const& point_strategy,
  711. RobustPolicy const& robust_policy,
  712. Strategies const& strategies,
  713. bool is_interior)
  714. {
  715. for (Iterator it = begin; it != end; ++it)
  716. {
  717. // For exterior rings, it deflates if distance is negative.
  718. // For interior rings, it is vice versa
  719. bool const deflate = is_interior
  720. ? ! distance.negative()
  721. : distance.negative();
  722. collection.start_new_ring(deflate);
  723. geometry::strategy::buffer::result_code const code
  724. = policy::apply(*it, collection, distance, segment_strategy,
  725. join_strategy, end_strategy, point_strategy,
  726. robust_policy, strategies);
  727. collection.finish_ring(code, *it, is_interior, false);
  728. }
  729. }
  730. template
  731. <
  732. typename InteriorRings,
  733. typename Collection,
  734. typename DistanceStrategy,
  735. typename SegmentStrategy,
  736. typename JoinStrategy,
  737. typename EndStrategy,
  738. typename PointStrategy,
  739. typename RobustPolicy,
  740. typename Strategies
  741. >
  742. static inline
  743. void apply_interior_rings(InteriorRings const& interior_rings,
  744. Collection& collection,
  745. DistanceStrategy const& distance,
  746. SegmentStrategy const& segment_strategy,
  747. JoinStrategy const& join_strategy,
  748. EndStrategy const& end_strategy,
  749. PointStrategy const& point_strategy,
  750. RobustPolicy const& robust_policy,
  751. Strategies const& strategies)
  752. {
  753. iterate(boost::begin(interior_rings), boost::end(interior_rings),
  754. collection, distance, segment_strategy,
  755. join_strategy, end_strategy, point_strategy,
  756. robust_policy, strategies, true);
  757. }
  758. public:
  759. template
  760. <
  761. typename Collection,
  762. typename DistanceStrategy,
  763. typename SegmentStrategy,
  764. typename JoinStrategy,
  765. typename EndStrategy,
  766. typename PointStrategy,
  767. typename RobustPolicy,
  768. typename Strategies
  769. >
  770. static inline void apply(PolygonInput const& polygon,
  771. Collection& collection,
  772. DistanceStrategy const& distance,
  773. SegmentStrategy const& segment_strategy,
  774. JoinStrategy const& join_strategy,
  775. EndStrategy const& end_strategy,
  776. PointStrategy const& point_strategy,
  777. RobustPolicy const& robust_policy,
  778. Strategies const& strategies)
  779. {
  780. {
  781. collection.start_new_ring(distance.negative());
  782. geometry::strategy::buffer::result_code const code
  783. = policy::apply(exterior_ring(polygon), collection,
  784. distance, segment_strategy,
  785. join_strategy, end_strategy, point_strategy,
  786. robust_policy, strategies);
  787. collection.finish_ring(code, exterior_ring(polygon), false,
  788. geometry::num_interior_rings(polygon) > 0u);
  789. }
  790. apply_interior_rings(interior_rings(polygon),
  791. collection, distance, segment_strategy,
  792. join_strategy, end_strategy, point_strategy,
  793. robust_policy, strategies);
  794. }
  795. };
  796. template
  797. <
  798. typename Multi,
  799. typename PolygonOutput
  800. >
  801. struct buffer_inserter<multi_tag, Multi, PolygonOutput>
  802. : public detail::buffer::buffer_multi
  803. <
  804. Multi,
  805. PolygonOutput,
  806. dispatch::buffer_inserter
  807. <
  808. typename single_tag_of
  809. <
  810. typename tag<Multi>::type
  811. >::type,
  812. typename boost::range_value<Multi const>::type,
  813. typename geometry::ring_type<PolygonOutput>::type
  814. >
  815. >
  816. {};
  817. } // namespace dispatch
  818. #endif // DOXYGEN_NO_DISPATCH
  819. #ifndef DOXYGEN_NO_DETAIL
  820. namespace detail { namespace buffer
  821. {
  822. template
  823. <
  824. typename GeometryOutput,
  825. typename GeometryInput,
  826. typename OutputIterator,
  827. typename DistanceStrategy,
  828. typename SegmentStrategy,
  829. typename JoinStrategy,
  830. typename EndStrategy,
  831. typename PointStrategy,
  832. typename Strategies,
  833. typename RobustPolicy,
  834. typename VisitPiecesPolicy
  835. >
  836. inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
  837. DistanceStrategy const& distance_strategy,
  838. SegmentStrategy const& segment_strategy,
  839. JoinStrategy const& join_strategy,
  840. EndStrategy const& end_strategy,
  841. PointStrategy const& point_strategy,
  842. Strategies const& strategies,
  843. RobustPolicy const& robust_policy,
  844. VisitPiecesPolicy& visit_pieces_policy
  845. )
  846. {
  847. boost::ignore_unused(visit_pieces_policy);
  848. using collection_type = detail::buffer::buffered_piece_collection
  849. <
  850. typename geometry::ring_type<GeometryOutput>::type,
  851. Strategies,
  852. DistanceStrategy,
  853. RobustPolicy
  854. >;
  855. collection_type collection(strategies, distance_strategy, robust_policy);
  856. collection_type const& const_collection = collection;
  857. static constexpr bool areal = util::is_areal<GeometryInput>::value;
  858. dispatch::buffer_inserter
  859. <
  860. typename tag_cast
  861. <
  862. typename tag<GeometryInput>::type,
  863. multi_tag
  864. >::type,
  865. GeometryInput,
  866. GeometryOutput
  867. >::apply(geometry_input, collection,
  868. distance_strategy, segment_strategy, join_strategy,
  869. end_strategy, point_strategy,
  870. robust_policy, strategies);
  871. collection.get_turns();
  872. if BOOST_GEOMETRY_CONSTEXPR (areal)
  873. {
  874. collection.check_turn_in_original();
  875. }
  876. collection.handle_colocations();
  877. collection.check_turn_in_pieces();
  878. collection.make_traversable_consistent_per_cluster();
  879. // Visit the piece collection. This does nothing (by default), but
  880. // optionally a debugging tool can be attached (e.g. console or svg),
  881. // or the piece collection can be unit-tested
  882. // phase 0: turns (before discarded)
  883. visit_pieces_policy.apply(const_collection, 0);
  884. collection.discard_rings();
  885. collection.block_turns();
  886. collection.enrich();
  887. // phase 1: turns (after enrichment/clustering)
  888. visit_pieces_policy.apply(const_collection, 1);
  889. if BOOST_GEOMETRY_CONSTEXPR (areal)
  890. {
  891. collection.deflate_check_turns();
  892. }
  893. collection.traverse();
  894. // Reverse all offsetted rings / traversed rings if:
  895. // - they were generated on the negative side (deflate) of polygons
  896. // - the output is counter clockwise
  897. // and avoid reversing twice
  898. bool reverse = distance_strategy.negative() && areal;
  899. if BOOST_GEOMETRY_CONSTEXPR (geometry::point_order<GeometryOutput>::value == counterclockwise)
  900. {
  901. reverse = ! reverse;
  902. }
  903. if (reverse)
  904. {
  905. collection.reverse();
  906. }
  907. if BOOST_GEOMETRY_CONSTEXPR (areal)
  908. {
  909. if (distance_strategy.negative())
  910. {
  911. collection.discard_nonintersecting_deflated_rings();
  912. }
  913. }
  914. collection.template assign<GeometryOutput>(out);
  915. // Visit collection again
  916. // phase 2: rings (after traversing)
  917. visit_pieces_policy.apply(const_collection, 2);
  918. }
  919. template
  920. <
  921. typename GeometryOutput,
  922. typename GeometryInput,
  923. typename OutputIterator,
  924. typename DistanceStrategy,
  925. typename SegmentStrategy,
  926. typename JoinStrategy,
  927. typename EndStrategy,
  928. typename PointStrategy,
  929. typename Strategies,
  930. typename RobustPolicy
  931. >
  932. inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
  933. DistanceStrategy const& distance_strategy,
  934. SegmentStrategy const& segment_strategy,
  935. JoinStrategy const& join_strategy,
  936. EndStrategy const& end_strategy,
  937. PointStrategy const& point_strategy,
  938. Strategies const& strategies,
  939. RobustPolicy const& robust_policy)
  940. {
  941. detail::buffer::visit_pieces_default_policy visitor;
  942. buffer_inserter<GeometryOutput>(geometry_input, out,
  943. distance_strategy, segment_strategy, join_strategy,
  944. end_strategy, point_strategy,
  945. strategies, robust_policy, visitor);
  946. }
  947. #endif // DOXYGEN_NO_DETAIL
  948. }} // namespace detail::buffer
  949. }} // namespace boost::geometry
  950. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP