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