1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
5
6 // This file was modified by Oracle on 2016.
7 // Modifications copyright (c) 2016 Oracle and/or its affiliates.
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
9
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
13
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
15 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
16
17
18 #include <boost/core/ignore_unused.hpp>
19
20 #include <boost/range.hpp>
21
22 #include <boost/geometry/core/assert.hpp>
23
24 #include <boost/geometry/arithmetic/dot_product.hpp>
25 #include <boost/geometry/algorithms/assign.hpp>
26 #include <boost/geometry/algorithms/comparable_distance.hpp>
27 #include <boost/geometry/algorithms/equals.hpp>
28 #include <boost/geometry/algorithms/expand.hpp>
29 #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
30 #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
31 #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
32 #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
33 #include <boost/geometry/policies/compare.hpp>
34 #include <boost/geometry/strategies/buffer.hpp>
35 #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
36
37 #if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
38 #include <boost/geometry/strategies/cartesian/side_of_intersection.hpp>
39 #endif
40
41
42 namespace boost { namespace geometry
43 {
44
45
46 #ifndef DOXYGEN_NO_DETAIL
47 namespace detail { namespace buffer
48 {
49
50 struct piece_get_box
51 {
52 template <typename Box, typename Piece>
applyboost::geometry::detail::buffer::piece_get_box53 static inline void apply(Box& total, Piece const& piece)
54 {
55 geometry::expand(total, piece.robust_envelope);
56 }
57 };
58
59 struct piece_ovelaps_box
60 {
61 template <typename Box, typename Piece>
applyboost::geometry::detail::buffer::piece_ovelaps_box62 static inline bool apply(Box const& box, Piece const& piece)
63 {
64 if (piece.type == strategy::buffer::buffered_flat_end
65 || piece.type == strategy::buffer::buffered_concave)
66 {
67 // Turns cannot be inside a flat end (though they can be on border)
68 // Neither we need to check if they are inside concave helper pieces
69
70 // Skip all pieces not used as soon as possible
71 return false;
72 }
73
74 return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope);
75 }
76 };
77
78 struct turn_get_box
79 {
80 template <typename Box, typename Turn>
applyboost::geometry::detail::buffer::turn_get_box81 static inline void apply(Box& total, Turn const& turn)
82 {
83 geometry::expand(total, turn.robust_point);
84 }
85 };
86
87 struct turn_ovelaps_box
88 {
89 template <typename Box, typename Turn>
applyboost::geometry::detail::buffer::turn_ovelaps_box90 static inline bool apply(Box const& box, Turn const& turn)
91 {
92 return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box);
93 }
94 };
95
96
97 enum analyse_result
98 {
99 analyse_unknown,
100 analyse_continue,
101 analyse_disjoint,
102 analyse_within,
103 analyse_on_original_boundary,
104 analyse_on_offsetted
105 #if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
106 , analyse_near_offsetted
107 #endif
108 };
109
110 template <typename Point>
in_box(Point const & previous,Point const & current,Point const & point)111 inline bool in_box(Point const& previous,
112 Point const& current, Point const& point)
113 {
114 // Get its box (TODO: this can be prepared-on-demand later)
115 typedef geometry::model::box<Point> box_type;
116 box_type box;
117 geometry::assign_inverse(box);
118 geometry::expand(box, previous);
119 geometry::expand(box, current);
120
121 return geometry::covered_by(point, box);
122 }
123
124 template <typename Point, typename Turn>
check_segment(Point const & previous,Point const & current,Turn const & turn,bool from_monotonic)125 inline analyse_result check_segment(Point const& previous,
126 Point const& current, Turn const& turn,
127 bool from_monotonic)
128 {
129
130 #if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
131 typedef geometry::model::referring_segment<Point const> segment_type;
132 segment_type const p(turn.rob_pi, turn.rob_pj);
133 segment_type const q(turn.rob_qi, turn.rob_qj);
134 segment_type const r(previous, current);
135 int const side = strategy::side::side_of_intersection::apply(p, q, r,
136 turn.robust_point);
137
138 if (side == 0)
139 {
140 return analyse_on_offsetted;
141 }
142 if (side == -1 && from_monotonic)
143 {
144 return analyse_within;
145 }
146 if (side == 1 && from_monotonic)
147 {
148 return analyse_disjoint;
149 }
150 return analyse_continue;
151
152 #else
153
154 typedef typename strategy::side::services::default_strategy
155 <
156 typename cs_tag<Point>::type
157 >::type side_strategy;
158 typedef typename geometry::coordinate_type<Point>::type coordinate_type;
159
160 coordinate_type const twice_area
161 = side_strategy::template side_value
162 <
163 coordinate_type,
164 coordinate_type
165 >(previous, current, turn.robust_point);
166
167 if (twice_area == 0)
168 {
169 // Collinear, only on segment if it is covered by its bbox
170 if (in_box(previous, current, turn.robust_point))
171 {
172 return analyse_on_offsetted;
173 }
174 }
175 else if (twice_area < 0)
176 {
177 // It is in the triangle right-of the segment where the
178 // segment is the hypothenusa. Check if it is close
179 // (within rounding-area)
180 if (twice_area * twice_area < geometry::comparable_distance(previous, current)
181 && in_box(previous, current, turn.robust_point))
182 {
183 return analyse_near_offsetted;
184 }
185 else if (from_monotonic)
186 {
187 return analyse_within;
188 }
189 }
190 else if (twice_area > 0 && from_monotonic)
191 {
192 // Left of segment
193 return analyse_disjoint;
194 }
195
196 // Not monotonic, on left or right side: continue analysing
197 return analyse_continue;
198 #endif
199 }
200
201
202 class analyse_turn_wrt_point_piece
203 {
204 public :
205 template <typename Turn, typename Piece>
apply(Turn const & turn,Piece const & piece)206 static inline analyse_result apply(Turn const& turn, Piece const& piece)
207 {
208 typedef typename Piece::section_type section_type;
209 typedef typename Turn::robust_point_type point_type;
210 typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
211
212 #if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
213 typedef geometry::model::referring_segment<point_type const> segment_type;
214 segment_type const p(turn.rob_pi, turn.rob_pj);
215 segment_type const q(turn.rob_qi, turn.rob_qj);
216 #else
217 typedef strategy::within::winding<point_type> strategy_type;
218
219 typename strategy_type::state_type state;
220 strategy_type strategy;
221 boost::ignore_unused(strategy);
222 #endif
223
224 BOOST_GEOMETRY_ASSERT(! piece.sections.empty());
225
226 coordinate_type const point_x = geometry::get<0>(turn.robust_point);
227
228 for (std::size_t s = 0; s < piece.sections.size(); s++)
229 {
230 section_type const& section = piece.sections[s];
231 // If point within horizontal range of monotonic section:
232 if (! section.duplicate
233 && section.begin_index < section.end_index
234 && point_x >= geometry::get<min_corner, 0>(section.bounding_box) - 1
235 && point_x <= geometry::get<max_corner, 0>(section.bounding_box) + 1)
236 {
237 for (signed_size_type i = section.begin_index + 1; i <= section.end_index; i++)
238 {
239 point_type const& previous = piece.robust_ring[i - 1];
240 point_type const& current = piece.robust_ring[i];
241
242 #if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
243
244 // First check if it is in range - if it is not, the
245 // expensive side_of_intersection does not need to be
246 // applied
247 coordinate_type x1 = geometry::get<0>(previous);
248 coordinate_type x2 = geometry::get<0>(current);
249
250 if (x1 > x2)
251 {
252 std::swap(x1, x2);
253 }
254
255 if (point_x >= x1 - 1 && point_x <= x2 + 1)
256 {
257 segment_type const r(previous, current);
258 int const side = strategy::side::side_of_intersection::apply(p, q, r,
259 turn.robust_point);
260
261 // Sections are monotonic in x-dimension
262 if (side == 1)
263 {
264 // Left on segment
265 return analyse_disjoint;
266 }
267 else if (side == 0)
268 {
269 // Collinear - TODO: check if really on segment
270 return analyse_on_offsetted;
271 }
272 }
273 #else
274 analyse_result code = check_segment(previous, current, turn, false);
275 if (code != analyse_continue)
276 {
277 return code;
278 }
279
280 // Get the state (to determine it is within), we don't have
281 // to cover the on-segment case (covered above)
282 strategy.apply(turn.robust_point, previous, current, state);
283 #endif
284 }
285 }
286 }
287
288 #if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
289 // It is nowhere outside, and not on segment, so it is within
290 return analyse_within;
291 #else
292 int const code = strategy.result(state);
293 if (code == 1)
294 {
295 return analyse_within;
296 }
297 else if (code == -1)
298 {
299 return analyse_disjoint;
300 }
301
302 // Should normally not occur - on-segment is covered
303 return analyse_unknown;
304 #endif
305 }
306
307 };
308
309 class analyse_turn_wrt_piece
310 {
311 template <typename Point, typename Turn>
check_helper_segment(Point const & s1,Point const & s2,Turn const & turn,bool is_original,Point const & offsetted)312 static inline analyse_result check_helper_segment(Point const& s1,
313 Point const& s2, Turn const& turn,
314 bool is_original,
315 Point const& offsetted)
316 {
317 boost::ignore_unused(offsetted);
318 #if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
319 typedef geometry::model::referring_segment<Point const> segment_type;
320 segment_type const p(turn.rob_pi, turn.rob_pj);
321 segment_type const q(turn.rob_qi, turn.rob_qj);
322 segment_type const r(s1, s2);
323 int const side = strategy::side::side_of_intersection::apply(p, q, r,
324 turn.robust_point);
325
326 if (side == 1)
327 {
328 // left of segment
329 return analyse_disjoint;
330 }
331 else if (side == 0)
332 {
333 // If is collinear, either on segment or before/after
334 typedef geometry::model::box<Point> box_type;
335
336 box_type box;
337 geometry::assign_inverse(box);
338 geometry::expand(box, s1);
339 geometry::expand(box, s2);
340
341 if (geometry::covered_by(turn.robust_point, box))
342 {
343 // Points on helper-segments are considered as within
344 // Points on original boundary are processed differently
345 return is_original
346 ? analyse_on_original_boundary
347 : analyse_within;
348 }
349
350 // It is collinear but not on the segment. Because these
351 // segments are convex, it is outside
352 // Unless the offsetted ring is collinear or concave w.r.t.
353 // helper-segment but that scenario is not yet supported
354 return analyse_disjoint;
355 }
356
357 // right of segment
358 return analyse_continue;
359 #else
360 typedef typename strategy::side::services::default_strategy
361 <
362 typename cs_tag<Point>::type
363 >::type side_strategy;
364
365 switch(side_strategy::apply(s1, s2, turn.robust_point))
366 {
367 case 1 :
368 return analyse_disjoint; // left of segment
369 case 0 :
370 {
371 // If is collinear, either on segment or before/after
372 typedef geometry::model::box<Point> box_type;
373
374 box_type box;
375 geometry::assign_inverse(box);
376 geometry::expand(box, s1);
377 geometry::expand(box, s2);
378
379 if (geometry::covered_by(turn.robust_point, box))
380 {
381 // It is on the segment
382 if (! is_original
383 && geometry::comparable_distance(turn.robust_point, offsetted) <= 1)
384 {
385 // It is close to the offsetted-boundary, take
386 // any rounding-issues into account
387 return analyse_near_offsetted;
388 }
389
390 // Points on helper-segments are considered as within
391 // Points on original boundary are processed differently
392 return is_original
393 ? analyse_on_original_boundary
394 : analyse_within;
395 }
396
397 // It is collinear but not on the segment. Because these
398 // segments are convex, it is outside
399 // Unless the offsetted ring is collinear or concave w.r.t.
400 // helper-segment but that scenario is not yet supported
401 return analyse_disjoint;
402 }
403 break;
404 }
405
406 // right of segment
407 return analyse_continue;
408 #endif
409 }
410
411 template <typename Turn, typename Piece>
check_helper_segments(Turn const & turn,Piece const & piece)412 static inline analyse_result check_helper_segments(Turn const& turn, Piece const& piece)
413 {
414 typedef typename Turn::robust_point_type point_type;
415 geometry::equal_to<point_type> comparator;
416
417 point_type points[4];
418
419 signed_size_type helper_count = static_cast<signed_size_type>(piece.robust_ring.size())
420 - piece.offsetted_count;
421 if (helper_count == 4)
422 {
423 for (int i = 0; i < 4; i++)
424 {
425 points[i] = piece.robust_ring[piece.offsetted_count + i];
426 }
427 }
428 else if (helper_count == 3)
429 {
430 // Triangular piece, assign points but assign second twice
431 for (int i = 0; i < 4; i++)
432 {
433 int index = i < 2 ? i : i - 1;
434 points[i] = piece.robust_ring[piece.offsetted_count + index];
435 }
436 }
437 else
438 {
439 // Some pieces (e.g. around points) do not have helper segments.
440 // Others should have 3 (join) or 4 (side)
441 return analyse_continue;
442 }
443
444 // First check point-equality
445 point_type const& point = turn.robust_point;
446 if (comparator(point, points[0]) || comparator(point, points[3]))
447 {
448 return analyse_on_offsetted;
449 }
450 if (comparator(point, points[1]) || comparator(point, points[2]))
451 {
452 return analyse_on_original_boundary;
453 }
454
455 // Right side of the piece
456 analyse_result result
457 = check_helper_segment(points[0], points[1], turn,
458 false, points[0]);
459 if (result != analyse_continue)
460 {
461 return result;
462 }
463
464 // Left side of the piece
465 result = check_helper_segment(points[2], points[3], turn,
466 false, points[3]);
467 if (result != analyse_continue)
468 {
469 return result;
470 }
471
472 if (! comparator(points[1], points[2]))
473 {
474 // Side of the piece at side of original geometry
475 result = check_helper_segment(points[1], points[2], turn,
476 true, point);
477 if (result != analyse_continue)
478 {
479 return result;
480 }
481 }
482
483 // We are within the \/ or |_| shaped piece, where the top is the
484 // offsetted ring.
485 if (! geometry::covered_by(point, piece.robust_offsetted_envelope))
486 {
487 // Not in offsetted-area. This makes a cheap check possible
488 typedef typename strategy::side::services::default_strategy
489 <
490 typename cs_tag<point_type>::type
491 >::type side_strategy;
492
493 switch(side_strategy::apply(points[3], points[0], point))
494 {
495 case 1 : return analyse_disjoint;
496 case -1 : return analyse_within;
497 case 0 : return analyse_disjoint;
498 }
499 }
500
501 return analyse_continue;
502 }
503
504 template <typename Turn, typename Piece, typename Compare>
check_monotonic(Turn const & turn,Piece const & piece,Compare const & compare)505 static inline analyse_result check_monotonic(Turn const& turn, Piece const& piece, Compare const& compare)
506 {
507 typedef typename Piece::piece_robust_ring_type ring_type;
508 typedef typename ring_type::const_iterator it_type;
509 it_type end = piece.robust_ring.begin() + piece.offsetted_count;
510 it_type it = std::lower_bound(piece.robust_ring.begin(),
511 end,
512 turn.robust_point,
513 compare);
514
515 if (it != end
516 && it != piece.robust_ring.begin())
517 {
518 // iterator points to point larger than point
519 // w.r.t. specified direction, and prev points to a point smaller
520 // We now know if it is inside/outside
521 it_type prev = it - 1;
522 return check_segment(*prev, *it, turn, true);
523 }
524 return analyse_continue;
525 }
526
527 public :
528 template <typename Turn, typename Piece>
apply(Turn const & turn,Piece const & piece)529 static inline analyse_result apply(Turn const& turn, Piece const& piece)
530 {
531 typedef typename Turn::robust_point_type point_type;
532 analyse_result code = check_helper_segments(turn, piece);
533 if (code != analyse_continue)
534 {
535 return code;
536 }
537
538 geometry::equal_to<point_type> comparator;
539
540 if (piece.offsetted_count > 8)
541 {
542 // If the offset contains some points and is monotonic, we try
543 // to avoid walking all points linearly.
544 // We try it only once.
545 if (piece.is_monotonic_increasing[0])
546 {
547 code = check_monotonic(turn, piece, geometry::less<point_type, 0>());
548 if (code != analyse_continue) return code;
549 }
550 else if (piece.is_monotonic_increasing[1])
551 {
552 code = check_monotonic(turn, piece, geometry::less<point_type, 1>());
553 if (code != analyse_continue) return code;
554 }
555 else if (piece.is_monotonic_decreasing[0])
556 {
557 code = check_monotonic(turn, piece, geometry::greater<point_type, 0>());
558 if (code != analyse_continue) return code;
559 }
560 else if (piece.is_monotonic_decreasing[1])
561 {
562 code = check_monotonic(turn, piece, geometry::greater<point_type, 1>());
563 if (code != analyse_continue) return code;
564 }
565 }
566
567 // It is small or not monotonic, walk linearly through offset
568 // TODO: this will be combined with winding strategy
569
570 for (signed_size_type i = 1; i < piece.offsetted_count; i++)
571 {
572 point_type const& previous = piece.robust_ring[i - 1];
573 point_type const& current = piece.robust_ring[i];
574
575 // The robust ring can contain duplicates
576 // (on which any side or side-value would return 0)
577 if (! comparator(previous, current))
578 {
579 code = check_segment(previous, current, turn, false);
580 if (code != analyse_continue)
581 {
582 return code;
583 }
584 }
585 }
586
587 return analyse_unknown;
588 }
589
590 };
591
592
593 template <typename Turns, typename Pieces>
594 class turn_in_piece_visitor
595 {
596 Turns& m_turns; // because partition is currently operating on const input only
597 Pieces const& m_pieces; // to check for piece-type
598
599 template <typename Operation, typename Piece>
skip(Operation const & op,Piece const & piece) const600 inline bool skip(Operation const& op, Piece const& piece) const
601 {
602 if (op.piece_index == piece.index)
603 {
604 return true;
605 }
606 Piece const& pc = m_pieces[op.piece_index];
607 if (pc.left_index == piece.index || pc.right_index == piece.index)
608 {
609 if (pc.type == strategy::buffer::buffered_flat_end)
610 {
611 // If it is a flat end, don't compare against its neighbor:
612 // it will always be located on one of the helper segments
613 return true;
614 }
615 if (pc.type == strategy::buffer::buffered_concave)
616 {
617 // If it is concave, the same applies: the IP will be
618 // located on one of the helper segments
619 return true;
620 }
621 }
622
623 return false;
624 }
625
626 #if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
627 // NOTE: this function returns a side value in {-1, 0, 1}
628 template <typename Turn, typename Piece>
turn_in_convex_piece(Turn const & turn,Piece const & piece)629 static inline int turn_in_convex_piece(Turn const& turn,
630 Piece const& piece)
631 {
632 typedef typename Turn::robust_point_type point_type;
633 typedef typename Piece::piece_robust_ring_type ring_type;
634 typedef geometry::model::referring_segment<point_type const> segment;
635
636 segment const p(turn.rob_pi, turn.rob_pj);
637 segment const q(turn.rob_qi, turn.rob_qj);
638
639 typedef typename boost::range_iterator<ring_type const>::type iterator_type;
640 iterator_type it = boost::begin(piece.robust_ring);
641 iterator_type end = boost::end(piece.robust_ring);
642
643 // A robust ring is always closed, and always clockwise
644 for (iterator_type previous = it++; it != end; ++previous, ++it)
645 {
646 geometry::equal_to<point_type> comparator;
647 if (comparator(*previous, *it))
648 {
649 // Points are the same
650 continue;
651 }
652
653 segment r(*previous, *it);
654
655 int const side = strategy::side::side_of_intersection::apply(p, q, r,
656 turn.robust_point);
657
658 if (side == 1)
659 {
660 // IP is left of segment, so it is outside
661 return -1; // outside
662 }
663 else if (side == 0)
664 {
665 // IP is collinear with segment. TODO: we should analyze this further
666 // For now we use the fallback point
667 if (in_box(*previous, *it, turn.robust_point))
668 {
669 return 0;
670 }
671 else
672 {
673 return -1; // outside
674 }
675 }
676 }
677 return 1; // inside
678 }
679 #endif
680
681
682 public:
683
turn_in_piece_visitor(Turns & turns,Pieces const & pieces)684 inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces)
685 : m_turns(turns)
686 , m_pieces(pieces)
687 {}
688
689 template <typename Turn, typename Piece>
apply(Turn const & turn,Piece const & piece,bool first=true)690 inline bool apply(Turn const& turn, Piece const& piece, bool first = true)
691 {
692 boost::ignore_unused_variable_warning(first);
693
694 if (turn.count_within > 0)
695 {
696 // Already inside - no need to check again
697 return true;
698 }
699
700 if (piece.type == strategy::buffer::buffered_flat_end
701 || piece.type == strategy::buffer::buffered_concave)
702 {
703 // Turns cannot be located within flat-end or concave pieces
704 return true;
705 }
706
707 if (! geometry::covered_by(turn.robust_point, piece.robust_envelope))
708 {
709 // Easy check: if the turn is not in the envelope, we can safely return
710 return true;
711 }
712
713 if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece))
714 {
715 return true;
716 }
717
718 // TODO: mutable_piece to make some on-demand preparations in analyse
719 Turn& mutable_turn = m_turns[turn.turn_index];
720
721 if (piece.type == geometry::strategy::buffer::buffered_point)
722 {
723 // Optimization for buffer around points: if distance from center
724 // is not between min/max radius, the result is clear
725 typedef typename default_comparable_distance_result
726 <
727 typename Turn::robust_point_type
728 >::type distance_type;
729
730 distance_type const cd
731 = geometry::comparable_distance(piece.robust_center,
732 turn.robust_point);
733
734 if (cd < piece.robust_min_comparable_radius)
735 {
736 mutable_turn.count_within++;
737 return true;
738 }
739 if (cd > piece.robust_max_comparable_radius)
740 {
741 return true;
742 }
743 }
744
745 analyse_result analyse_code =
746 piece.type == geometry::strategy::buffer::buffered_point
747 ? analyse_turn_wrt_point_piece::apply(turn, piece)
748 : analyse_turn_wrt_piece::apply(turn, piece);
749
750 switch(analyse_code)
751 {
752 case analyse_disjoint :
753 return true;
754 case analyse_on_offsetted :
755 mutable_turn.count_on_offsetted++; // value is not used anymore
756 return true;
757 case analyse_on_original_boundary :
758 mutable_turn.count_on_original_boundary++;
759 return true;
760 case analyse_within :
761 mutable_turn.count_within++;
762 return true;
763 #if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
764 case analyse_near_offsetted :
765 mutable_turn.count_within_near_offsetted++;
766 return true;
767 #endif
768 default :
769 break;
770 }
771
772 #if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
773 // We don't know (yet)
774 int geometry_code = 0;
775 if (piece.is_convex)
776 {
777 geometry_code = turn_in_convex_piece(turn, piece);
778 }
779 else
780 {
781
782 // TODO: this point_in_geometry is a performance-bottleneck here and
783 // will be replaced completely by extending analyse_piece functionality
784 geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
785 }
786 #else
787 int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
788 #endif
789
790 if (geometry_code == 1)
791 {
792 mutable_turn.count_within++;
793 }
794
795 return true;
796 }
797 };
798
799
800 }} // namespace detail::buffer
801 #endif // DOXYGEN_NO_DETAIL
802
803
804 }} // namespace boost::geometry
805
806 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
807