]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/algorithms/detail/relate/areal_areal.hpp
18be9a255d67592a6d14a891deda5be08dc64acb
[ceph.git] / ceph / src / boost / boost / geometry / algorithms / detail / relate / areal_areal.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018, 2019.
6 // Modifications copyright (c) 2013-2019 Oracle and/or its affiliates.
7
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_RELATE_AREAL_AREAL_HPP
15 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
16
17 #include <boost/geometry/core/topological_dimension.hpp>
18
19 #include <boost/geometry/util/condition.hpp>
20 #include <boost/geometry/util/range.hpp>
21
22 #include <boost/geometry/algorithms/num_interior_rings.hpp>
23 #include <boost/geometry/algorithms/detail/point_on_border.hpp>
24 #include <boost/geometry/algorithms/detail/sub_range.hpp>
25 #include <boost/geometry/algorithms/detail/single_geometry.hpp>
26
27 #include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
28 #include <boost/geometry/algorithms/detail/relate/turns.hpp>
29 #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
30 #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
31
32 namespace boost { namespace geometry
33 {
34
35 #ifndef DOXYGEN_NO_DETAIL
36 namespace detail { namespace relate {
37
38 // WARNING!
39 // TODO: In the worst case calling this Pred in a loop for MultiPolygon/MultiPolygon may take O(NM)
40 // Use the rtree in this case!
41
42 // may be used to set EI and EB for an Areal geometry for which no turns were generated
43 template
44 <
45 typename OtherAreal,
46 typename Result,
47 typename PointInArealStrategy,
48 bool TransposeResult
49 >
50 class no_turns_aa_pred
51 {
52 public:
53 no_turns_aa_pred(OtherAreal const& other_areal,
54 Result & res,
55 PointInArealStrategy const& point_in_areal_strategy)
56 : m_result(res)
57 , m_point_in_areal_strategy(point_in_areal_strategy)
58 , m_other_areal(other_areal)
59 , m_flags(0)
60 {
61 // check which relations must be analysed
62
63 if ( ! may_update<interior, interior, '2', TransposeResult>(m_result)
64 && ! may_update<boundary, interior, '1', TransposeResult>(m_result)
65 && ! may_update<exterior, interior, '2', TransposeResult>(m_result) )
66 {
67 m_flags |= 1;
68 }
69
70 if ( ! may_update<interior, exterior, '2', TransposeResult>(m_result)
71 && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) )
72 {
73 m_flags |= 2;
74 }
75 }
76
77 template <typename Areal>
78 bool operator()(Areal const& areal)
79 {
80 using detail::within::point_in_geometry;
81
82 // if those flags are set nothing will change
83 if ( m_flags == 3 )
84 {
85 return false;
86 }
87
88 typedef typename geometry::point_type<Areal>::type point_type;
89 point_type pt;
90 bool const ok = boost::geometry::point_on_border(pt, areal);
91
92 // TODO: for now ignore, later throw an exception?
93 if ( !ok )
94 {
95 return true;
96 }
97
98 // check if the areal is inside the other_areal
99 // TODO: This is O(N)
100 // Run in a loop O(NM) - optimize!
101 int const pig = point_in_geometry(pt,
102 m_other_areal,
103 m_point_in_areal_strategy);
104 //BOOST_GEOMETRY_ASSERT( pig != 0 );
105
106 // inside
107 if ( pig > 0 )
108 {
109 update<interior, interior, '2', TransposeResult>(m_result);
110 update<boundary, interior, '1', TransposeResult>(m_result);
111 update<exterior, interior, '2', TransposeResult>(m_result);
112 m_flags |= 1;
113
114 // TODO: OPTIMIZE!
115 // Only the interior rings of other ONE single geometry must be checked
116 // NOT all geometries
117
118 // Check if any interior ring is outside
119 ring_identifier ring_id(0, -1, 0);
120 std::size_t const irings_count = geometry::num_interior_rings(areal);
121 for ( ; static_cast<std::size_t>(ring_id.ring_index) < irings_count ;
122 ++ring_id.ring_index )
123 {
124 typename detail::sub_range_return_type<Areal const>::type
125 range_ref = detail::sub_range(areal, ring_id);
126
127 if ( boost::empty(range_ref) )
128 {
129 // TODO: throw exception?
130 continue; // ignore
131 }
132
133 // TODO: O(N)
134 // Optimize!
135 int const hpig = point_in_geometry(range::front(range_ref),
136 m_other_areal,
137 m_point_in_areal_strategy);
138
139 // hole outside
140 if ( hpig < 0 )
141 {
142 update<interior, exterior, '2', TransposeResult>(m_result);
143 update<boundary, exterior, '1', TransposeResult>(m_result);
144 m_flags |= 2;
145 break;
146 }
147 }
148 }
149 // outside
150 else
151 {
152 update<interior, exterior, '2', TransposeResult>(m_result);
153 update<boundary, exterior, '1', TransposeResult>(m_result);
154 m_flags |= 2;
155
156 // Check if any interior ring is inside
157 ring_identifier ring_id(0, -1, 0);
158 std::size_t const irings_count = geometry::num_interior_rings(areal);
159 for ( ; static_cast<std::size_t>(ring_id.ring_index) < irings_count ;
160 ++ring_id.ring_index )
161 {
162 typename detail::sub_range_return_type<Areal const>::type
163 range_ref = detail::sub_range(areal, ring_id);
164
165 if ( boost::empty(range_ref) )
166 {
167 // TODO: throw exception?
168 continue; // ignore
169 }
170
171 // TODO: O(N)
172 // Optimize!
173 int const hpig = point_in_geometry(range::front(range_ref),
174 m_other_areal,
175 m_point_in_areal_strategy);
176
177 // hole inside
178 if ( hpig > 0 )
179 {
180 update<interior, interior, '2', TransposeResult>(m_result);
181 update<boundary, interior, '1', TransposeResult>(m_result);
182 update<exterior, interior, '2', TransposeResult>(m_result);
183 m_flags |= 1;
184 break;
185 }
186 }
187 }
188
189 return m_flags != 3 && !m_result.interrupt;
190 }
191
192 private:
193 Result & m_result;
194 PointInArealStrategy const& m_point_in_areal_strategy;
195 OtherAreal const& m_other_areal;
196 int m_flags;
197 };
198
199 // The implementation of an algorithm calculating relate() for A/A
200 template <typename Geometry1, typename Geometry2>
201 struct areal_areal
202 {
203 // check Linear / Areal
204 BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 2
205 && topological_dimension<Geometry2>::value == 2);
206
207 static const bool interruption_enabled = true;
208
209 typedef typename geometry::point_type<Geometry1>::type point1_type;
210 typedef typename geometry::point_type<Geometry2>::type point2_type;
211
212 template <typename Result, typename IntersectionStrategy>
213 static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
214 Result & result,
215 IntersectionStrategy const& intersection_strategy)
216 {
217 // TODO: If Areal geometry may have infinite size, change the following line:
218
219 // The result should be FFFFFFFFF
220 relate::set<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T
221
222 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
223 return;
224
225 // get and analyse turns
226 typedef typename turns::get_turns
227 <
228 Geometry1, Geometry2
229 >::template turn_info_type<IntersectionStrategy>::type turn_type;
230 std::vector<turn_type> turns;
231
232 interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result);
233
234 turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy);
235 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
236 return;
237
238 typedef typename IntersectionStrategy::cs_tag cs_tag;
239
240 typedef typename IntersectionStrategy::template point_in_geometry_strategy
241 <
242 Geometry1, Geometry2
243 >::type point_in_areal_strategy12_type;
244 point_in_areal_strategy12_type point_in_areal_strategy12
245 = intersection_strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>();
246 typedef typename IntersectionStrategy::template point_in_geometry_strategy
247 <
248 Geometry2, Geometry1
249 >::type point_in_areal_strategy21_type;
250 point_in_areal_strategy21_type point_in_areal_strategy21
251 = intersection_strategy.template get_point_in_geometry_strategy<Geometry2, Geometry1>();
252
253 no_turns_aa_pred<Geometry2, Result, point_in_areal_strategy12_type, false>
254 pred1(geometry2, result, point_in_areal_strategy12);
255 for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
256 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
257 return;
258
259 no_turns_aa_pred<Geometry1, Result, point_in_areal_strategy21_type, true>
260 pred2(geometry1, result, point_in_areal_strategy21);
261 for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
262 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
263 return;
264
265 if ( turns.empty() )
266 return;
267
268 if ( may_update<interior, interior, '2'>(result)
269 || may_update<interior, exterior, '2'>(result)
270 || may_update<boundary, interior, '1'>(result)
271 || may_update<boundary, exterior, '1'>(result)
272 || may_update<exterior, interior, '2'>(result) )
273 {
274 // sort turns
275 typedef turns::less<0, turns::less_op_areal_areal<0>, cs_tag> less;
276 std::sort(turns.begin(), turns.end(), less());
277
278 /*if ( may_update<interior, exterior, '2'>(result)
279 || may_update<boundary, exterior, '1'>(result)
280 || may_update<boundary, interior, '1'>(result)
281 || may_update<exterior, interior, '2'>(result) )*/
282 {
283 // analyse sorted turns
284 turns_analyser<turn_type, 0> analyser;
285 analyse_each_turn(result, analyser, turns.begin(), turns.end(),
286 point_in_areal_strategy12.get_equals_point_point_strategy());
287
288 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
289 return;
290 }
291
292 if ( may_update<interior, interior, '2'>(result)
293 || may_update<interior, exterior, '2'>(result)
294 || may_update<boundary, interior, '1'>(result)
295 || may_update<boundary, exterior, '1'>(result)
296 || may_update<exterior, interior, '2'>(result) )
297 {
298 // analyse rings for which turns were not generated
299 // or only i/i or u/u was generated
300 uncertain_rings_analyser<0, Result, Geometry1, Geometry2, point_in_areal_strategy12_type>
301 rings_analyser(result, geometry1, geometry2, point_in_areal_strategy12);
302 analyse_uncertain_rings<0>::apply(rings_analyser, turns.begin(), turns.end());
303
304 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
305 return;
306 }
307 }
308
309 if ( may_update<interior, interior, '2', true>(result)
310 || may_update<interior, exterior, '2', true>(result)
311 || may_update<boundary, interior, '1', true>(result)
312 || may_update<boundary, exterior, '1', true>(result)
313 || may_update<exterior, interior, '2', true>(result) )
314 {
315 // sort turns
316 typedef turns::less<1, turns::less_op_areal_areal<1>, cs_tag> less;
317 std::sort(turns.begin(), turns.end(), less());
318
319 /*if ( may_update<interior, exterior, '2', true>(result)
320 || may_update<boundary, exterior, '1', true>(result)
321 || may_update<boundary, interior, '1', true>(result)
322 || may_update<exterior, interior, '2', true>(result) )*/
323 {
324 // analyse sorted turns
325 turns_analyser<turn_type, 1> analyser;
326 analyse_each_turn(result, analyser, turns.begin(), turns.end(),
327 point_in_areal_strategy21.get_equals_point_point_strategy());
328
329 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
330 return;
331 }
332
333 if ( may_update<interior, interior, '2', true>(result)
334 || may_update<interior, exterior, '2', true>(result)
335 || may_update<boundary, interior, '1', true>(result)
336 || may_update<boundary, exterior, '1', true>(result)
337 || may_update<exterior, interior, '2', true>(result) )
338 {
339 // analyse rings for which turns were not generated
340 // or only i/i or u/u was generated
341 uncertain_rings_analyser<1, Result, Geometry2, Geometry1, point_in_areal_strategy21_type>
342 rings_analyser(result, geometry2, geometry1, point_in_areal_strategy21);
343 analyse_uncertain_rings<1>::apply(rings_analyser, turns.begin(), turns.end());
344
345 //if ( result.interrupt )
346 // return;
347 }
348 }
349 }
350
351 // interrupt policy which may be passed to get_turns to interrupt the analysis
352 // based on the info in the passed result/mask
353 template <typename Result>
354 class interrupt_policy_areal_areal
355 {
356 public:
357 static bool const enabled = true;
358
359 interrupt_policy_areal_areal(Geometry1 const& geometry1,
360 Geometry2 const& geometry2,
361 Result & result)
362 : m_result(result)
363 , m_geometry1(geometry1)
364 , m_geometry2(geometry2)
365 {}
366
367 template <typename Range>
368 inline bool apply(Range const& turns)
369 {
370 typedef typename boost::range_iterator<Range const>::type iterator;
371
372 for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
373 {
374 per_turn<0>(*it);
375 per_turn<1>(*it);
376 }
377
378 return m_result.interrupt;
379 }
380
381 private:
382 template <std::size_t OpId, typename Turn>
383 inline void per_turn(Turn const& turn)
384 {
385 //static const std::size_t other_op_id = (OpId + 1) % 2;
386 static const bool transpose_result = OpId != 0;
387
388 overlay::operation_type const op = turn.operations[OpId].operation;
389
390 if ( op == overlay::operation_union )
391 {
392 // ignore u/u
393 /*if ( turn.operations[other_op_id].operation != overlay::operation_union )
394 {
395 update<interior, exterior, '2', transpose_result>(m_result);
396 update<boundary, exterior, '1', transpose_result>(m_result);
397 }*/
398
399 update<boundary, boundary, '0', transpose_result>(m_result);
400 }
401 else if ( op == overlay::operation_intersection )
402 {
403 // ignore i/i
404 /*if ( turn.operations[other_op_id].operation != overlay::operation_intersection )
405 {
406 // not correct e.g. for G1 touching G2 in a point where a hole is touching the exterior ring
407 // in this case 2 turns i/... and u/u will be generated for this IP
408 //update<interior, interior, '2', transpose_result>(m_result);
409
410 //update<boundary, interior, '1', transpose_result>(m_result);
411 }*/
412
413 update<boundary, boundary, '0', transpose_result>(m_result);
414 }
415 else if ( op == overlay::operation_continue )
416 {
417 update<boundary, boundary, '1', transpose_result>(m_result);
418 update<interior, interior, '2', transpose_result>(m_result);
419 }
420 else if ( op == overlay::operation_blocked )
421 {
422 update<boundary, boundary, '1', transpose_result>(m_result);
423 update<interior, exterior, '2', transpose_result>(m_result);
424 }
425 }
426
427 Result & m_result;
428 Geometry1 const& m_geometry1;
429 Geometry2 const& m_geometry2;
430 };
431
432 // This analyser should be used like Input or SinglePass Iterator
433 // IMPORTANT! It should be called also for the end iterator - last
434 template <typename TurnInfo, std::size_t OpId>
435 class turns_analyser
436 {
437 typedef typename TurnInfo::point_type turn_point_type;
438
439 static const std::size_t op_id = OpId;
440 static const std::size_t other_op_id = (OpId + 1) % 2;
441 static const bool transpose_result = OpId != 0;
442
443 public:
444 turns_analyser()
445 : m_previous_turn_ptr(0)
446 , m_previous_operation(overlay::operation_none)
447 , m_enter_detected(false)
448 , m_exit_detected(false)
449 {}
450
451 template <typename Result, typename TurnIt, typename EqPPStrategy>
452 void apply(Result & result, TurnIt it, EqPPStrategy const& strategy)
453 {
454 //BOOST_GEOMETRY_ASSERT( it != last );
455
456 overlay::operation_type const op = it->operations[op_id].operation;
457
458 if ( op != overlay::operation_union
459 && op != overlay::operation_intersection
460 && op != overlay::operation_blocked
461 && op != overlay::operation_continue )
462 {
463 return;
464 }
465
466 segment_identifier const& seg_id = it->operations[op_id].seg_id;
467 //segment_identifier const& other_id = it->operations[other_op_id].seg_id;
468
469 const bool first_in_range = m_seg_watcher.update(seg_id);
470
471 if ( m_previous_turn_ptr )
472 {
473 if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ )
474 {
475 // real exit point - may be multiple
476 if ( first_in_range
477 || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) )
478 {
479 update_exit(result);
480 m_exit_detected = false;
481 }
482 // fake exit point, reset state
483 else if ( op != overlay::operation_union )
484 {
485 m_exit_detected = false;
486 }
487 }
488 /*else*/
489 if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ )
490 {
491 // real entry point
492 if ( first_in_range
493 || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) )
494 {
495 update_enter(result);
496 m_enter_detected = false;
497 }
498 // fake entry point, reset state
499 else if ( op != overlay::operation_intersection )
500 {
501 m_enter_detected = false;
502 }
503 }
504 }
505
506 if ( op == overlay::operation_union )
507 {
508 // already set in interrupt policy
509 //update<boundary, boundary, '0', transpose_result>(m_result);
510
511 // ignore u/u
512 //if ( it->operations[other_op_id].operation != overlay::operation_union )
513 {
514 m_exit_detected = true;
515 }
516 }
517 else if ( op == overlay::operation_intersection )
518 {
519 // ignore i/i
520 if ( it->operations[other_op_id].operation != overlay::operation_intersection )
521 {
522 // this was set in the interrupt policy but it was wrong
523 // also here it's wrong since it may be a fake entry point
524 //update<interior, interior, '2', transpose_result>(result);
525
526 // already set in interrupt policy
527 //update<boundary, boundary, '0', transpose_result>(result);
528 m_enter_detected = true;
529 }
530 }
531 else if ( op == overlay::operation_blocked )
532 {
533 // already set in interrupt policy
534 }
535 else // if ( op == overlay::operation_continue )
536 {
537 // already set in interrupt policy
538 }
539
540 // store ref to previously analysed (valid) turn
541 m_previous_turn_ptr = boost::addressof(*it);
542 // and previously analysed (valid) operation
543 m_previous_operation = op;
544 }
545
546 // it == last
547 template <typename Result>
548 void apply(Result & result)
549 {
550 //BOOST_GEOMETRY_ASSERT( first != last );
551
552 if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ )
553 {
554 update_exit(result);
555 m_exit_detected = false;
556 }
557
558 if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ )
559 {
560 update_enter(result);
561 m_enter_detected = false;
562 }
563 }
564
565 template <typename Result>
566 static inline void update_exit(Result & result)
567 {
568 update<interior, exterior, '2', transpose_result>(result);
569 update<boundary, exterior, '1', transpose_result>(result);
570 }
571
572 template <typename Result>
573 static inline void update_enter(Result & result)
574 {
575 update<interior, interior, '2', transpose_result>(result);
576 update<boundary, interior, '1', transpose_result>(result);
577 update<exterior, interior, '2', transpose_result>(result);
578 }
579
580 private:
581 segment_watcher<same_ring> m_seg_watcher;
582 TurnInfo * m_previous_turn_ptr;
583 overlay::operation_type m_previous_operation;
584 bool m_enter_detected;
585 bool m_exit_detected;
586 };
587
588 // call analyser.apply() for each turn in range
589 // IMPORTANT! The analyser is also called for the end iterator - last
590 template
591 <
592 typename Result,
593 typename Analyser,
594 typename TurnIt,
595 typename EqPPStrategy
596 >
597 static inline void analyse_each_turn(Result & res,
598 Analyser & analyser,
599 TurnIt first, TurnIt last,
600 EqPPStrategy const& strategy)
601 {
602 if ( first == last )
603 return;
604
605 for ( TurnIt it = first ; it != last ; ++it )
606 {
607 analyser.apply(res, it, strategy);
608
609 if ( BOOST_GEOMETRY_CONDITION(res.interrupt) )
610 return;
611 }
612
613 analyser.apply(res);
614 }
615
616 template
617 <
618 std::size_t OpId,
619 typename Result,
620 typename Geometry,
621 typename OtherGeometry,
622 typename PointInArealStrategy
623 >
624 class uncertain_rings_analyser
625 {
626 static const bool transpose_result = OpId != 0;
627 static const int other_id = (OpId + 1) % 2;
628
629 public:
630 inline uncertain_rings_analyser(Result & result,
631 Geometry const& geom,
632 OtherGeometry const& other_geom,
633 PointInArealStrategy const& point_in_areal_strategy)
634 : geometry(geom)
635 , other_geometry(other_geom)
636 , interrupt(result.interrupt) // just in case, could be false as well
637 , m_result(result)
638 , m_point_in_areal_strategy(point_in_areal_strategy)
639 , m_flags(0)
640 {
641 // check which relations must be analysed
642 // NOTE: 1 and 4 could probably be connected
643
644 if ( ! may_update<interior, interior, '2', transpose_result>(m_result) )
645 {
646 m_flags |= 1;
647 }
648
649 if ( ! may_update<interior, exterior, '2', transpose_result>(m_result)
650 && ! may_update<boundary, exterior, '1', transpose_result>(m_result) )
651 {
652 m_flags |= 2;
653 }
654
655 if ( ! may_update<boundary, interior, '1', transpose_result>(m_result)
656 && ! may_update<exterior, interior, '2', transpose_result>(m_result) )
657 {
658 m_flags |= 4;
659 }
660 }
661
662 inline void no_turns(segment_identifier const& seg_id)
663 {
664 // if those flags are set nothing will change
665 if ( m_flags == 7 )
666 {
667 return;
668 }
669
670 typename detail::sub_range_return_type<Geometry const>::type
671 range_ref = detail::sub_range(geometry, seg_id);
672
673 if ( boost::empty(range_ref) )
674 {
675 // TODO: throw an exception?
676 return; // ignore
677 }
678
679 // TODO: possible optimization
680 // if the range is an interior ring we may use other IPs generated for this single geometry
681 // to know which other single geometries should be checked
682
683 // TODO: optimize! e.g. use spatial index
684 // O(N) - running it in a loop gives O(NM)
685 using detail::within::point_in_geometry;
686 int const pig = point_in_geometry(range::front(range_ref),
687 other_geometry,
688 m_point_in_areal_strategy);
689
690 //BOOST_GEOMETRY_ASSERT(pig != 0);
691 if ( pig > 0 )
692 {
693 update<interior, interior, '2', transpose_result>(m_result);
694 m_flags |= 1;
695
696 update<boundary, interior, '1', transpose_result>(m_result);
697 update<exterior, interior, '2', transpose_result>(m_result);
698 m_flags |= 4;
699 }
700 else
701 {
702 update<boundary, exterior, '1', transpose_result>(m_result);
703 update<interior, exterior, '2', transpose_result>(m_result);
704 m_flags |= 2;
705 }
706
707 // TODO: break if all things are set
708 // also some of them could be checked outside, before the analysis
709 // In this case we shouldn't relay just on dummy flags
710 // Flags should be initialized with proper values
711 // or the result should be checked directly
712 // THIS IS ALSO TRUE FOR OTHER ANALYSERS! in L/L and L/A
713
714 interrupt = m_flags == 7 || m_result.interrupt;
715 }
716
717 template <typename TurnIt>
718 inline void turns(TurnIt first, TurnIt last)
719 {
720 // if those flags are set nothing will change
721 if ( (m_flags & 6) == 6 )
722 {
723 return;
724 }
725
726 bool found_ii = false;
727 bool found_uu = false;
728
729 for ( TurnIt it = first ; it != last ; ++it )
730 {
731 if ( it->operations[0].operation == overlay::operation_intersection
732 && it->operations[1].operation == overlay::operation_intersection )
733 {
734 found_ii = true;
735 }
736 else if ( it->operations[0].operation == overlay::operation_union
737 && it->operations[1].operation == overlay::operation_union )
738 {
739 found_uu = true;
740 }
741 else // ignore
742 {
743 return; // don't interrupt
744 }
745 }
746
747 // only i/i was generated for this ring
748 if ( found_ii )
749 {
750 update<interior, interior, '2', transpose_result>(m_result);
751 m_flags |= 1;
752
753 //update<boundary, boundary, '0', transpose_result>(m_result);
754
755 update<boundary, interior, '1', transpose_result>(m_result);
756 update<exterior, interior, '2', transpose_result>(m_result);
757 m_flags |= 4;
758 }
759
760 // only u/u was generated for this ring
761 if ( found_uu )
762 {
763 update<boundary, exterior, '1', transpose_result>(m_result);
764 update<interior, exterior, '2', transpose_result>(m_result);
765 m_flags |= 2;
766 }
767
768 interrupt = m_flags == 7 || m_result.interrupt; // interrupt if the result won't be changed in the future
769 }
770
771 Geometry const& geometry;
772 OtherGeometry const& other_geometry;
773 bool interrupt;
774
775 private:
776 Result & m_result;
777 PointInArealStrategy const& m_point_in_areal_strategy;
778 int m_flags;
779 };
780
781 template <std::size_t OpId>
782 class analyse_uncertain_rings
783 {
784 public:
785 template <typename Analyser, typename TurnIt>
786 static inline void apply(Analyser & analyser, TurnIt first, TurnIt last)
787 {
788 if ( first == last )
789 return;
790
791 for_preceding_rings(analyser, *first);
792 //analyser.per_turn(*first);
793
794 TurnIt prev = first;
795 for ( ++first ; first != last ; ++first, ++prev )
796 {
797 // same multi
798 if ( prev->operations[OpId].seg_id.multi_index
799 == first->operations[OpId].seg_id.multi_index )
800 {
801 // same ring
802 if ( prev->operations[OpId].seg_id.ring_index
803 == first->operations[OpId].seg_id.ring_index )
804 {
805 //analyser.per_turn(*first);
806 }
807 // same multi, next ring
808 else
809 {
810 //analyser.end_ring(*prev);
811 analyser.turns(prev, first);
812
813 //if ( prev->operations[OpId].seg_id.ring_index + 1
814 // < first->operations[OpId].seg_id.ring_index)
815 {
816 for_no_turns_rings(analyser,
817 *first,
818 prev->operations[OpId].seg_id.ring_index + 1,
819 first->operations[OpId].seg_id.ring_index);
820 }
821
822 //analyser.per_turn(*first);
823 }
824 }
825 // next multi
826 else
827 {
828 //analyser.end_ring(*prev);
829 analyser.turns(prev, first);
830 for_following_rings(analyser, *prev);
831 for_preceding_rings(analyser, *first);
832 //analyser.per_turn(*first);
833 }
834
835 if ( analyser.interrupt )
836 {
837 return;
838 }
839 }
840
841 //analyser.end_ring(*prev);
842 analyser.turns(prev, first); // first == last
843 for_following_rings(analyser, *prev);
844 }
845
846 private:
847 template <typename Analyser, typename Turn>
848 static inline void for_preceding_rings(Analyser & analyser, Turn const& turn)
849 {
850 segment_identifier const& seg_id = turn.operations[OpId].seg_id;
851
852 for_no_turns_rings(analyser, turn, -1, seg_id.ring_index);
853 }
854
855 template <typename Analyser, typename Turn>
856 static inline void for_following_rings(Analyser & analyser, Turn const& turn)
857 {
858 segment_identifier const& seg_id = turn.operations[OpId].seg_id;
859
860 signed_size_type
861 count = boost::numeric_cast<signed_size_type>(
862 geometry::num_interior_rings(
863 detail::single_geometry(analyser.geometry, seg_id)));
864
865 for_no_turns_rings(analyser, turn, seg_id.ring_index + 1, count);
866 }
867
868 template <typename Analyser, typename Turn>
869 static inline void for_no_turns_rings(Analyser & analyser,
870 Turn const& turn,
871 signed_size_type first,
872 signed_size_type last)
873 {
874 segment_identifier seg_id = turn.operations[OpId].seg_id;
875
876 for ( seg_id.ring_index = first ; seg_id.ring_index < last ; ++seg_id.ring_index )
877 {
878 analyser.no_turns(seg_id);
879 }
880 }
881 };
882 };
883
884 }} // namespace detail::relate
885 #endif // DOXYGEN_NO_DETAIL
886
887 }} // namespace boost::geometry
888
889 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP