1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // Use, modification and distribution is subject to the Boost Software License,
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8
9 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TANGENCIES_HPP
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TANGENCIES_HPP
11
12 #include <algorithm>
13
14 #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
15 #include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
16 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
17 #include <boost/geometry/algorithms/detail/recalculate.hpp>
18
19 #include <boost/geometry/policies/robustness/robust_point_type.hpp>
20 #include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
21 #include <boost/geometry/policies/robustness/robust_type.hpp>
22
23 #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
24 #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
25 #endif
26
27 #include <boost/geometry/geometries/point.hpp>
28 #include <boost/geometry/geometries/segment.hpp>
29
30
31 // TODO: the approach below should be completely replaced by the new
32 // get_left_turns, to keep the outgoing vector which has open space one of its
33 // sides.
34
35
36 namespace boost { namespace geometry
37 {
38
39 #ifndef DOXYGEN_NO_DETAIL
40 namespace detail { namespace overlay
41 {
42
43
44 template
45 <
46 typename TurnPoints,
47 typename Indexed,
48 typename Geometry1, typename Geometry2,
49 typename RobustPolicy,
50 bool Reverse1, bool Reverse2,
51 typename Strategy
52 >
53 struct sort_in_cluster
54 {
sort_in_clusterboost::geometry::detail::overlay::sort_in_cluster55 inline sort_in_cluster(TurnPoints const& turn_points
56 , Geometry1 const& geometry1
57 , Geometry2 const& geometry2
58 , RobustPolicy const& robust_policy
59 , Strategy const& strategy)
60 : m_turn_points(turn_points)
61 , m_geometry1(geometry1)
62 , m_geometry2(geometry2)
63 , m_rescale_policy(robust_policy)
64 , m_strategy(strategy)
65 {}
66
67 private :
68
69 TurnPoints const& m_turn_points;
70 Geometry1 const& m_geometry1;
71 Geometry2 const& m_geometry2;
72 RobustPolicy const& m_rescale_policy;
73 Strategy const& m_strategy;
74
75 typedef typename Indexed::type turn_operation_type;
76 typedef typename geometry::point_type<Geometry1>::type point_type;
77
78 typedef typename geometry::robust_point_type
79 <
80 point_type,
81 RobustPolicy
82 >::type robust_point_type;
83
default_orderboost::geometry::detail::overlay::sort_in_cluster84 inline bool default_order(Indexed const& left, Indexed const& right) const
85 {
86 // We've nothing to sort on. Take the indexes
87 return left.turn_index < right.turn_index;
88 }
89
90 // Still necessary in some situations,
91 // for example #case_102_multi, #case_107_multi, #case_recursive_boxes_3
get_situation_mapboost::geometry::detail::overlay::sort_in_cluster92 inline void get_situation_map(Indexed const& left, Indexed const& right,
93 robust_point_type& pi_rob, robust_point_type& pj_rob,
94 robust_point_type& ri_rob, robust_point_type& rj_rob,
95 robust_point_type& si_rob, robust_point_type& sj_rob) const
96 {
97 point_type pi, pj, ri, rj, si, sj;
98
99 geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
100 left.subject->seg_id,
101 pi, pj);
102 geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
103 *left.other_seg_id,
104 ri, rj);
105 geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
106 *right.other_seg_id,
107 si, sj);
108
109 geometry::recalculate(pi_rob, pi, m_rescale_policy);
110 geometry::recalculate(pj_rob, pj, m_rescale_policy);
111 geometry::recalculate(ri_rob, ri, m_rescale_policy);
112 geometry::recalculate(rj_rob, rj, m_rescale_policy);
113 geometry::recalculate(si_rob, si, m_rescale_policy);
114 geometry::recalculate(sj_rob, sj, m_rescale_policy);
115 }
116
117 #if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
118 // This method was still called but did no effect whatsoever on the results,
119 // with or without robustness-rescaling.
120 // Probable cause: we rescale in this file ourselves, ignoring passed policy
121 // TODO: check this more.
122 // Besides this, it currently does not compile for yet unknown reasons
123 // (does not find specialization for segment_ratio_type)
124 // It is currently only called from the Unit Test "multi_intersection.cpp"
125
126 // Determine how p/r and p/s are located.
overlap_infoboost::geometry::detail::overlay::sort_in_cluster127 inline void overlap_info(
128 robust_point_type const& pi, robust_point_type const& pj,
129 robust_point_type const& ri, robust_point_type const& rj,
130 robust_point_type const& si, robust_point_type const& sj,
131 bool& pr_overlap, bool& ps_overlap, bool& rs_overlap) const
132 {
133 // Determine how p/r and p/s are located.
134 // One of them is coming from opposite direction.
135
136 typedef segment_intersection_points
137 <
138 point_type,
139 typename segment_ratio_type
140 <
141 point_type, RobustPolicy
142 >::type
143 > intersection_return_type;
144
145 typedef strategy::intersection::relate_cartesian_segments
146 <
147 policies::relate::segments_intersection_points
148 <
149 intersection_return_type
150 >
151 > policy;
152
153 typedef model::referring_segment<robust_point_type const> segment_type;
154 segment_type p(pi, pj);
155 segment_type r(ri, rj);
156 segment_type s(si, sj);
157
158 // Get the intersection point (or two points)
159 intersection_return_type pr = policy::apply(p, r, m_rescale_policy, pi, pj, ri, rj);
160 intersection_return_type ps = policy::apply(p, s, m_rescale_policy, pi, pj, si, sj);
161 intersection_return_type rs = policy::apply(r, s, m_rescale_policy, ri, rj, si, sj);
162
163 // Check on overlap
164 pr_overlap = pr.count == 2;
165 ps_overlap = ps.count == 2;
166 rs_overlap = rs.count == 2;
167 }
168 #endif
169
170
171 #ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES
debug_considerboost::geometry::detail::overlay::sort_in_cluster172 inline void debug_consider(int order, Indexed const& left,
173 Indexed const& right, std::string const& header,
174 bool skip = true,
175 std::string const& extra = "", bool ret = false
176 ) const
177 {
178 if (skip) return;
179
180 std::cout << "Case: " << header << " for " << left.turn_index << " / " << right.turn_index << std::endl;
181
182 robust_point_type pi, pj, ri, rj, si, sj;
183 get_situation_map(left, right, pi, pj, ri, rj, si, sj);
184
185 #if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
186 bool prc = false, psc = false, rsc = false;
187 overlap_info(pi, pj, ri, rj, si, sj, prc, psc, rsc);
188 #endif
189
190 int const side_ri_p = m_strategy.apply(pi, pj, ri);
191 int const side_rj_p = m_strategy.apply(pi, pj, rj);
192 int const side_si_p = m_strategy.apply(pi, pj, si);
193 int const side_sj_p = m_strategy.apply(pi, pj, sj);
194 int const side_si_r = m_strategy.apply(ri, rj, si);
195 int const side_sj_r = m_strategy.apply(ri, rj, sj);
196
197 #ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES_MORE
198 std::cout << " Segment p:" << geometry::wkt(pi) << " .. " << geometry::wkt(pj) << std::endl;
199 std::cout << " Segment r:" << geometry::wkt(ri) << " .. " << geometry::wkt(rj) << std::endl;
200 std::cout << " Segment s:" << geometry::wkt(si) << " .. " << geometry::wkt(sj) << std::endl;
201
202 std::cout << " r//p: " << side_ri_p << " / " << side_rj_p << std::endl;
203 std::cout << " s//p: " << side_si_p << " / " << side_sj_p << std::endl;
204 std::cout << " s//r: " << side_si_r << " / " << side_sj_r << std::endl;
205 #endif
206
207 std::cout << header
208 //<< " order: " << order
209 << " ops: " << operation_char(left.subject->operation)
210 << "/" << operation_char(right.subject->operation)
211 << " ri//p: " << side_ri_p
212 << " si//p: " << side_si_p
213 << " si//r: " << side_si_r
214 #if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
215 << " cnts: " << int(prc) << "," << int(psc) << "," << int(rsc)
216 #endif
217 //<< " idx: " << left.turn_index << "/" << right.turn_index
218 ;
219
220 if (! extra.empty())
221 {
222 std::cout << " " << extra << " " << (ret ? "true" : "false");
223 }
224 std::cout << std::endl;
225 }
226 #else
debug_considerboost::geometry::detail::overlay::sort_in_cluster227 inline void debug_consider(int, Indexed const& ,
228 Indexed const& , std::string const& ,
229 bool = true,
230 std::string const& = "", bool = false
231 ) const
232 {}
233 #endif
234
235
236 // ux/ux
consider_ux_uxboost::geometry::detail::overlay::sort_in_cluster237 inline bool consider_ux_ux(Indexed const& left,
238 Indexed const& right
239 , std::string const& // header
240 ) const
241 {
242 bool ret = left.turn_index < right.turn_index;
243
244 // In combination of u/x, x/u: take first union, then blocked.
245 // Solves #88, #61, #56, #80
246 if (left.subject->operation == operation_union
247 && right.subject->operation == operation_blocked)
248 {
249 ret = true;
250 }
251 else if (left.subject->operation == operation_blocked
252 && right.subject->operation == operation_union)
253 {
254 ret = false;
255 }
256 else
257 {
258 #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
259 std::cout << "ux/ux unhandled" << std::endl;
260 #endif
261 }
262
263 //debug_consider(0, left, right, header, false, "-> return ", ret);
264
265 return ret;
266 }
267
consider_iu_uxboost::geometry::detail::overlay::sort_in_cluster268 inline bool consider_iu_ux(Indexed const& left,
269 Indexed const& right,
270 int order // 1: iu first, -1: ux first
271 , std::string const& // header
272 ) const
273 {
274 bool ret = false;
275
276 if (left.subject->operation == operation_union
277 && right.subject->operation == operation_union)
278 {
279 ret = order == 1;
280 }
281 else if (left.subject->operation == operation_union
282 && right.subject->operation == operation_blocked)
283 {
284 ret = true;
285 }
286 else if (right.subject->operation == operation_union
287 && left.subject->operation == operation_blocked)
288 {
289 ret = false;
290 }
291 else if (left.subject->operation == operation_union)
292 {
293 ret = true;
294 }
295 else if (right.subject->operation == operation_union)
296 {
297 ret = false;
298 }
299 else
300 {
301 #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
302 // this still happens in the traverse.cpp test
303 std::cout << " iu/ux unhandled" << std::endl;
304 #endif
305 ret = order == 1;
306 }
307
308 //debug_consider(0, left, right, header, false, "-> return", ret);
309 return ret;
310 }
311
consider_iu_ixboost::geometry::detail::overlay::sort_in_cluster312 inline bool consider_iu_ix(Indexed const& left,
313 Indexed const& right,
314 int order // 1: iu first, -1: ix first
315 , std::string const& // header
316 ) const
317 {
318 //debug_consider(order, left, right, header, false, "iu/ix");
319
320 return left.subject->operation == operation_intersection
321 && right.subject->operation == operation_intersection ? order == 1
322 : left.subject->operation == operation_intersection ? false
323 : right.subject->operation == operation_intersection ? true
324 : order == 1;
325 }
326
consider_ix_ixboost::geometry::detail::overlay::sort_in_cluster327 inline bool consider_ix_ix(Indexed const& left, Indexed const& right
328 , std::string const& // header
329 ) const
330 {
331 // Take first intersection, then blocked.
332 if (left.subject->operation == operation_intersection
333 && right.subject->operation == operation_blocked)
334 {
335 return true;
336 }
337 else if (left.subject->operation == operation_blocked
338 && right.subject->operation == operation_intersection)
339 {
340 return false;
341 }
342
343 // Default case, should not occur
344
345 #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
346 std::cout << "ix/ix unhandled" << std::endl;
347 #endif
348 //debug_consider(0, left, right, header, false, "-> return", ret);
349
350 return default_order(left, right);
351 }
352
353
consider_iu_iuboost::geometry::detail::overlay::sort_in_cluster354 inline bool consider_iu_iu(Indexed const& left, Indexed const& right,
355 std::string const& header, bool redo = false) const
356 {
357 //debug_consider(0, left, right, header);
358
359 // In general, order it like "union, intersection".
360 if (left.subject->operation == operation_intersection
361 && right.subject->operation == operation_union)
362 {
363 //debug_consider(0, left, right, header, false, "i,u", false);
364 return false;
365 }
366 else if (left.subject->operation == operation_union
367 && right.subject->operation == operation_intersection)
368 {
369 //debug_consider(0, left, right, header, false, "u,i", true);
370 return true;
371 }
372
373 robust_point_type pi, pj, ri, rj, si, sj;
374 get_situation_map(left, right, pi, pj, ri, rj, si, sj);
375
376 int const side_ri_p = m_strategy.apply(pi, pj, ri);
377 int const side_si_p = m_strategy.apply(pi, pj, si);
378 int const side_si_r = m_strategy.apply(ri, rj, si);
379
380 // Both located at same side (#58, pie_21_7_21_0_3)
381 if (side_ri_p * side_si_p == 1 && side_si_r != 0)
382 {
383 if (left.subject->operation == operation_union
384 && right.subject->operation == operation_union)
385 {
386 int const side_ri_s = m_strategy.apply(si, sj, ri);
387 if (side_si_r == side_ri_s)
388 {
389 return default_order(left, right);
390 }
391
392 // Take the most left one
393 bool const ret = side_si_r == 1;
394 //debug_consider(0, left, right, header, false, "same side", ret);
395 return ret;
396 }
397 }
398
399
400 // Coming from opposite sides (#59, #99)
401 if (side_ri_p * side_si_p == -1)
402 {
403 bool ret = false;
404
405 {
406 ret = side_ri_p == 1; // #100
407 debug_consider(0, left, right, header, false, "opp.", ret);
408 return ret;
409 }
410 #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
411 std::cout << " iu/iu coming from opposite unhandled" << std::endl;
412 #endif
413 }
414
415 #if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
416 // We need EXTRA information here: are p/r/s overlapping?
417 bool pr_ov = false, ps_ov = false, rs_ov = false;
418 overlap_info(pi, pj, ri, rj, si, sj, pr_ov, ps_ov, rs_ov);
419 #else
420 // std::cout << "Boost.Geometry: skipping overlap_info" << std::endl;
421 #endif
422
423 // One coming from right (#83,#90)
424 // One coming from left (#90, #94, #95)
425 if (side_si_r != 0 && (side_ri_p != 0 || side_si_p != 0))
426 {
427 int const side_ri_s = m_strategy.apply(si, sj, ri);
428 if (side_si_r == side_ri_s)
429 {
430 return default_order(left, right);
431 }
432
433 bool ret = false;
434
435 #if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
436 if (pr_ov || ps_ov)
437 {
438 int r = side_ri_p != 0 ? side_ri_p : side_si_p;
439 ret = r * side_si_r == 1;
440 }
441 else
442 #endif
443 {
444 ret = side_si_r == 1;
445 }
446
447 debug_consider(0, left, right, header, false, "left or right", ret);
448 return ret;
449 }
450
451 // All aligned (#92, #96)
452 if (side_ri_p == 0 && side_si_p == 0 && side_si_r == 0)
453 {
454 // One of them is coming from opposite direction.
455
456 // Take the one NOT overlapping
457 bool ret = false;
458 bool found = false;
459 #if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
460 if (pr_ov && ! ps_ov)
461 {
462 ret = true;
463 found = true;
464 }
465 else if (!pr_ov && ps_ov)
466 {
467 ret = false;
468 found = true;
469 }
470 #endif
471
472 debug_consider(0, left, right, header, false, "aligned", ret);
473 if (found)
474 {
475 return ret;
476 }
477 }
478
479 #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
480 std::cout << " iu/iu unhandled" << std::endl;
481 debug_consider(0, left, right, header, false, "unhandled", left.turn_index < right.turn_index);
482 #endif
483 if (! redo)
484 {
485 // In some cases behaviour is not symmetrical. TODO: fix this properly
486 // OR: alternatively we might consider calling all these functions one-way anyway
487 return ! consider_iu_iu(right, left, header, true);
488 }
489
490 return default_order(left, right);
491 }
492
consider_iiboost::geometry::detail::overlay::sort_in_cluster493 inline bool consider_ii(Indexed const& left, Indexed const& right,
494 std::string const& header) const
495 {
496 debug_consider(0, left, right, header);
497
498 robust_point_type pi, pj, ri, rj, si, sj;
499 get_situation_map(left, right, pi, pj, ri, rj, si, sj);
500
501 int const side_ri_p = m_strategy.apply(pi, pj, ri);
502 int const side_si_p = m_strategy.apply(pi, pj, si);
503
504 // Two other points are (mostly) lying both right of the considered segment
505 // Take the most left one
506 int const side_si_r = m_strategy.apply(ri, rj, si);
507 if (side_ri_p == -1
508 && side_si_p == -1
509 && side_si_r != 0)
510 {
511 bool const ret = side_si_r != 1;
512 return ret;
513 }
514 return default_order(left, right);
515 }
516
517
518 public :
operator ()boost::geometry::detail::overlay::sort_in_cluster519 inline bool operator()(Indexed const& left, Indexed const& right) const
520 {
521 if ((m_turn_points[left.turn_index].discarded || left.discarded)
522 && (m_turn_points[right.turn_index].discarded || right.discarded))
523 {
524 return default_order(left, right);
525 }
526 else if (m_turn_points[left.turn_index].discarded || left.discarded)
527 {
528 // Be careful to sort discarded first, then all others
529 return true;
530 }
531 else if (m_turn_points[right.turn_index].discarded || right.discarded)
532 {
533 // See above so return false here such that right (discarded)
534 // is sorted before left (not discarded)
535 return false;
536 }
537 else if (m_turn_points[left.turn_index].combination(operation_blocked, operation_union)
538 && m_turn_points[right.turn_index].combination(operation_blocked, operation_union))
539 {
540 // ux/ux
541 return consider_ux_ux(left, right, "ux/ux");
542 }
543 else if (m_turn_points[left.turn_index].both(operation_union)
544 && m_turn_points[right.turn_index].both(operation_union))
545 {
546 // uu/uu, Order is arbitrary
547 // Note: uu/uu is discarded now before so this point will
548 // not be reached.
549 return default_order(left, right);
550 }
551 else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
552 && m_turn_points[right.turn_index].combination(operation_intersection, operation_union))
553 {
554 return consider_iu_iu(left, right, "iu/iu");
555 }
556 else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_blocked)
557 && m_turn_points[right.turn_index].combination(operation_intersection, operation_blocked))
558 {
559 return consider_ix_ix(left, right, "ix/ix");
560 }
561 else if (m_turn_points[left.turn_index].both(operation_intersection)
562 && m_turn_points[right.turn_index].both(operation_intersection))
563 {
564 return consider_ii(left, right, "ii/ii");
565 }
566 else if (m_turn_points[left.turn_index].combination(operation_union, operation_blocked)
567 && m_turn_points[right.turn_index].combination(operation_intersection, operation_union))
568 {
569 return consider_iu_ux(left, right, -1, "ux/iu");
570 }
571 else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
572 && m_turn_points[right.turn_index].combination(operation_union, operation_blocked))
573 {
574 return consider_iu_ux(left, right, 1, "iu/ux");
575 }
576 else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_blocked)
577 && m_turn_points[right.turn_index].combination(operation_intersection, operation_union))
578 {
579 return consider_iu_ix(left, right, 1, "ix/iu");
580 }
581 else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
582 && m_turn_points[right.turn_index].combination(operation_intersection, operation_blocked))
583 {
584 return consider_iu_ix(left, right, -1, "iu/ix");
585 }
586 else if (m_turn_points[left.turn_index].method != method_equal
587 && m_turn_points[right.turn_index].method == method_equal
588 )
589 {
590 // If one of them was EQUAL or CONTINUES, it should always come first
591 return false;
592 }
593 else if (m_turn_points[left.turn_index].method == method_equal
594 && m_turn_points[right.turn_index].method != method_equal
595 )
596 {
597 return true;
598 }
599
600 // Now we have no clue how to sort.
601
602 #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
603 std::cout << " Consider: " << operation_char(m_turn_points[left.turn_index].operations[0].operation)
604 << operation_char(m_turn_points[left.turn_index].operations[1].operation)
605 << "/" << operation_char(m_turn_points[right.turn_index].operations[0].operation)
606 << operation_char(m_turn_points[right.turn_index].operations[1].operation)
607 << " " << " Take " << left.turn_index << " < " << right.turn_index
608 << std::endl;
609 #endif
610
611 return default_order(left, right);
612 }
613 };
614
615
616
617 template
618 <
619 typename IndexType,
620 typename Iterator,
621 typename TurnPoints,
622 typename Geometry1,
623 typename Geometry2,
624 typename Strategy
625 >
inspect_cluster(Iterator begin_cluster,Iterator end_cluster,TurnPoints & turn_points,operation_type,Geometry1 const &,Geometry2 const &,Strategy const &)626 inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
627 TurnPoints& turn_points,
628 operation_type ,
629 Geometry1 const& , Geometry2 const& ,
630 Strategy const& )
631 {
632 int count = 0;
633
634 // Make an analysis about all occuring cases here.
635 std::map<std::pair<operation_type, operation_type>, int> inspection;
636 for (Iterator it = begin_cluster; it != end_cluster; ++it)
637 {
638 operation_type first = turn_points[it->turn_index].operations[0].operation;
639 operation_type second = turn_points[it->turn_index].operations[1].operation;
640 if (first > second)
641 {
642 std::swap(first, second);
643 }
644 inspection[std::make_pair(first, second)]++;
645 count++;
646 }
647
648
649 bool keep_cc = false;
650
651 // Decide about which is going to be discarded here.
652 if (inspection[std::make_pair(operation_union, operation_union)] == 1
653 && inspection[std::make_pair(operation_continue, operation_continue)] == 1)
654 {
655 // In case of uu/cc, discard the uu, that indicates a tangency and
656 // inclusion would disturb the (e.g.) cc-cc-cc ordering
657 // NOTE: uu is now discarded anyhow.
658 keep_cc = true;
659 }
660 else if (count == 2
661 && inspection[std::make_pair(operation_intersection, operation_intersection)] == 1
662 && inspection[std::make_pair(operation_union, operation_intersection)] == 1)
663 {
664 // In case of ii/iu, discard the iu. The ii should always be visited,
665 // Because (in case of not discarding iu) correctly ordering of ii/iu appears impossible
666 for (Iterator it = begin_cluster; it != end_cluster; ++it)
667 {
668 if (turn_points[it->turn_index].combination(operation_intersection, operation_union))
669 {
670 it->discarded = true;
671 }
672 }
673 }
674
675 // Discard any continue turn, unless it is the only thing left
676 // (necessary to avoid cc-only rings, all being discarded
677 // e.g. traversal case #75)
678 int nd_count= 0, cc_count = 0;
679 for (Iterator it = begin_cluster; it != end_cluster; ++it)
680 {
681 if (! it->discarded)
682 {
683 nd_count++;
684 if (turn_points[it->turn_index].both(operation_continue))
685 {
686 cc_count++;
687 }
688 }
689 }
690
691 if (nd_count == cc_count)
692 {
693 keep_cc = true;
694 }
695
696 if (! keep_cc)
697 {
698 for (Iterator it = begin_cluster; it != end_cluster; ++it)
699 {
700 if (turn_points[it->turn_index].both(operation_continue))
701 {
702 it->discarded = true;
703 }
704 }
705 }
706 }
707
708
709 template
710 <
711 typename IndexType,
712 bool Reverse1, bool Reverse2,
713 typename Iterator,
714 typename TurnPoints,
715 typename Geometry1,
716 typename Geometry2,
717 typename RobustPolicy,
718 typename Strategy
719 >
handle_cluster(Iterator begin_cluster,Iterator end_cluster,TurnPoints & turn_points,operation_type for_operation,Geometry1 const & geometry1,Geometry2 const & geometry2,RobustPolicy & robust_policy,Strategy const & strategy)720 inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
721 TurnPoints& turn_points,
722 operation_type for_operation,
723 Geometry1 const& geometry1, Geometry2 const& geometry2,
724 RobustPolicy& robust_policy,
725 Strategy const& strategy)
726 {
727 // First inspect and (possibly) discard rows
728 inspect_cluster<IndexType>(begin_cluster, end_cluster, turn_points,
729 for_operation, geometry1, geometry2, strategy);
730
731
732 // Then sort this range (discarded rows will be ordered first and will be removed in enrich_assign)
733 std::sort(begin_cluster, end_cluster,
734 sort_in_cluster
735 <
736 TurnPoints,
737 IndexType,
738 Geometry1, Geometry2,
739 RobustPolicy,
740 Reverse1, Reverse2,
741 Strategy
742 >(turn_points, geometry1, geometry2, robust_policy, strategy));
743
744 #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
745 typedef typename IndexType::type operations_type;
746 operations_type const& op = turn_points[begin_cluster->turn_index].operations[begin_cluster->operation_index];
747 std::cout << std::endl << "Clustered points on equal distance " << op.fraction << std::endl;
748
749 std::cout << "->Indexes ";
750 for (Iterator it = begin_cluster; it != end_cluster; ++it)
751 {
752 std::cout << " " << it->turn_index;
753 }
754 std::cout << std::endl << "->Methods: ";
755 for (Iterator it = begin_cluster; it != end_cluster; ++it)
756 {
757 std::cout << " " << method_char(turn_points[it->turn_index].method);
758 }
759 std::cout << std::endl << "->Operations: ";
760 for (Iterator it = begin_cluster; it != end_cluster; ++it)
761 {
762 std::cout << " " << operation_char(turn_points[it->turn_index].operations[0].operation)
763 << operation_char(turn_points[it->turn_index].operations[1].operation);
764 }
765 std::cout << std::endl << "->Discarded: ";
766 for (Iterator it = begin_cluster; it != end_cluster; ++it)
767 {
768 std::cout << " " << (it->discarded ? "true" : "false");
769 }
770 std::cout << std::endl;
771 //<< "\tOn segments: " << prev_op.seg_id << " / " << prev_op.other_id
772 //<< " and " << op.seg_id << " / " << op.other_id
773 //<< geometry::distance(turn_points[prev->turn_index].point, turn_points[it->turn_index].point)
774 #endif
775
776 }
777
778
779 }} // namespace detail::overlay
780 #endif //DOXYGEN_NO_DETAIL
781
782
783 }} // namespace boost::geometry
784
785
786 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TANGENCIES_HPP
787