buffer_inserter.hpp 35 KB

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