File indexing completed on 2025-01-18 09:35:14
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
0015 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
0016
0017 #include <boost/core/ignore_unused.hpp>
0018 #include <boost/range/size.hpp>
0019
0020 #include <boost/geometry/core/assert.hpp>
0021 #include <boost/geometry/core/topological_dimension.hpp>
0022
0023 #include <boost/geometry/util/condition.hpp>
0024 #include <boost/geometry/util/range.hpp>
0025 #include <boost/geometry/util/type_traits.hpp>
0026
0027 #include <boost/geometry/algorithms/num_interior_rings.hpp>
0028 #include <boost/geometry/algorithms/detail/point_on_border.hpp>
0029 #include <boost/geometry/algorithms/detail/sub_range.hpp>
0030 #include <boost/geometry/algorithms/detail/single_geometry.hpp>
0031
0032 #include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
0033 #include <boost/geometry/algorithms/detail/relate/turns.hpp>
0034 #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
0035 #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
0036
0037 #include <boost/geometry/geometries/helper_geometry.hpp>
0038
0039 #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
0040
0041 namespace boost { namespace geometry
0042 {
0043
0044 #ifndef DOXYGEN_NO_DETAIL
0045 namespace detail { namespace relate {
0046
0047
0048
0049
0050
0051
0052 template
0053 <
0054 typename Geometry2,
0055 typename Result,
0056 typename Strategy,
0057 typename BoundaryChecker,
0058 bool TransposeResult
0059 >
0060 class no_turns_la_linestring_pred
0061 {
0062 public:
0063 no_turns_la_linestring_pred(Geometry2 const& geometry2,
0064 Result & res,
0065 Strategy const& strategy,
0066 BoundaryChecker const& boundary_checker)
0067 : m_geometry2(geometry2)
0068 , m_result(res)
0069 , m_strategy(strategy)
0070 , m_boundary_checker(boundary_checker)
0071 , m_interrupt_flags(0)
0072 {
0073 if ( ! may_update<interior, interior, '1', TransposeResult>(m_result) )
0074 {
0075 m_interrupt_flags |= 1;
0076 }
0077
0078 if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) )
0079 {
0080 m_interrupt_flags |= 2;
0081 }
0082
0083 if ( ! may_update<boundary, interior, '0', TransposeResult>(m_result) )
0084 {
0085 m_interrupt_flags |= 4;
0086 }
0087
0088 if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) )
0089 {
0090 m_interrupt_flags |= 8;
0091 }
0092 }
0093
0094 template <typename Linestring>
0095 bool operator()(Linestring const& linestring)
0096 {
0097 std::size_t const count = boost::size(linestring);
0098
0099
0100 if ( count < 2 )
0101 {
0102
0103
0104 return true;
0105 }
0106
0107
0108 if ( m_interrupt_flags == 0xF )
0109 {
0110 return false;
0111 }
0112
0113 int const pig = detail::within::point_in_geometry(range::front(linestring),
0114 m_geometry2,
0115 m_strategy);
0116
0117
0118 if ( pig > 0 )
0119 {
0120 update<interior, interior, '1', TransposeResult>(m_result);
0121 m_interrupt_flags |= 1;
0122 }
0123 else
0124 {
0125 update<interior, exterior, '1', TransposeResult>(m_result);
0126 m_interrupt_flags |= 2;
0127 }
0128
0129
0130 if ((m_interrupt_flags & 0xC) != 0xC
0131 && (m_boundary_checker.is_endpoint_boundary(range::front(linestring))
0132 || m_boundary_checker.is_endpoint_boundary(range::back(linestring))))
0133 {
0134 if ( pig > 0 )
0135 {
0136 update<boundary, interior, '0', TransposeResult>(m_result);
0137 m_interrupt_flags |= 4;
0138 }
0139 else
0140 {
0141 update<boundary, exterior, '0', TransposeResult>(m_result);
0142 m_interrupt_flags |= 8;
0143 }
0144 }
0145
0146 return m_interrupt_flags != 0xF
0147 && ! m_result.interrupt;
0148 }
0149
0150 private:
0151 Geometry2 const& m_geometry2;
0152 Result & m_result;
0153 Strategy const& m_strategy;
0154 BoundaryChecker const& m_boundary_checker;
0155 unsigned m_interrupt_flags;
0156 };
0157
0158
0159 template <typename Result, bool TransposeResult>
0160 class no_turns_la_areal_pred
0161 {
0162 public:
0163 no_turns_la_areal_pred(Result & res)
0164 : m_result(res)
0165 , interrupt(! may_update<interior, exterior, '2', TransposeResult>(m_result)
0166 && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) )
0167 {}
0168
0169 template <typename Areal>
0170 bool operator()(Areal const& areal)
0171 {
0172 if ( interrupt )
0173 {
0174 return false;
0175 }
0176
0177
0178
0179
0180 using point_type = typename geometry::point_type<Areal>::type;
0181 typename helper_geometry<point_type>::type pt;
0182 bool const ok = geometry::point_on_border(pt, areal);
0183
0184
0185 if ( !ok )
0186 {
0187 return true;
0188 }
0189
0190 update<interior, exterior, '2', TransposeResult>(m_result);
0191 update<boundary, exterior, '1', TransposeResult>(m_result);
0192
0193 return false;
0194 }
0195
0196 private:
0197 Result & m_result;
0198 bool const interrupt;
0199 };
0200
0201
0202 template <typename It, typename Strategy>
0203 inline It find_next_non_duplicated(It first, It current, It last, Strategy const& strategy)
0204 {
0205 BOOST_GEOMETRY_ASSERT(current != last);
0206
0207 It it = current;
0208 for (++it ; it != last ; ++it)
0209 {
0210 if (! equals::equals_point_point(*current, *it, strategy))
0211 {
0212 return it;
0213 }
0214 }
0215
0216
0217 for (it = first ; it != current ; ++it)
0218 {
0219 if (! equals::equals_point_point(*current, *it, strategy))
0220 {
0221 return it;
0222 }
0223 }
0224
0225 return current;
0226 }
0227
0228
0229
0230 template
0231 <
0232 typename Pi, typename Pj, typename Pk,
0233 typename Qi, typename Qj, typename Qk,
0234 typename Strategy
0235 >
0236 inline bool calculate_from_inside_sides(Pi const& pi, Pj const& pj, Pk const& pk,
0237 Qi const& , Qj const& qj, Qk const& qk,
0238 Strategy const& strategy)
0239 {
0240 auto const side_strategy = strategy.side();
0241
0242 int const side_pk_p = side_strategy.apply(pi, pj, pk);
0243 int const side_qk_p = side_strategy.apply(pi, pj, qk);
0244
0245 if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p))
0246 {
0247 int const side_pk_q2 = side_strategy.apply(qj, qk, pk);
0248 return side_pk_q2 == -1;
0249 }
0250 else
0251 {
0252 return side_pk_p == -1;
0253 }
0254 }
0255
0256
0257
0258 template
0259 <
0260 std::size_t OpId,
0261 typename Geometry1, typename Geometry2,
0262 typename Turn, typename Strategy
0263 >
0264 inline bool calculate_from_inside(Geometry1 const& geometry1,
0265 Geometry2 const& geometry2,
0266 Turn const& turn,
0267 Strategy const& strategy)
0268 {
0269 static const std::size_t op_id = OpId;
0270 static const std::size_t other_op_id = (OpId + 1) % 2;
0271
0272 if (turn.operations[op_id].position == overlay::position_front)
0273 {
0274 return false;
0275 }
0276
0277 auto const& range1 = sub_range(geometry1, turn.operations[op_id].seg_id);
0278
0279 using range2_view = detail::closed_clockwise_view<typename ring_type<Geometry2>::type const>;
0280 range2_view const range2(sub_range(geometry2, turn.operations[other_op_id].seg_id));
0281
0282 BOOST_GEOMETRY_ASSERT(boost::size(range1));
0283 std::size_t const s2 = boost::size(range2);
0284 BOOST_GEOMETRY_ASSERT(s2 > 2);
0285 std::size_t const seg_count2 = s2 - 1;
0286
0287 std::size_t const p_seg_ij = static_cast<std::size_t>(turn.operations[op_id].seg_id.segment_index);
0288 std::size_t const q_seg_ij = static_cast<std::size_t>(turn.operations[other_op_id].seg_id.segment_index);
0289
0290 BOOST_GEOMETRY_ASSERT(p_seg_ij + 1 < boost::size(range1));
0291 BOOST_GEOMETRY_ASSERT(q_seg_ij + 1 < s2);
0292
0293 auto const& pi = range::at(range1, p_seg_ij);
0294 auto const& qi = range::at(range2, q_seg_ij);
0295 auto const& qj = range::at(range2, q_seg_ij + 1);
0296
0297 bool const is_ip_qj = equals::equals_point_point(turn.point, qj, strategy);
0298
0299
0300
0301
0302 if (is_ip_qj)
0303 {
0304 std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2;
0305
0306
0307 auto qk_it = find_next_non_duplicated(boost::begin(range2),
0308 range::pos(range2, q_seg_jk),
0309 boost::end(range2),
0310 strategy);
0311
0312
0313
0314 return calculate_from_inside_sides(qi, turn.point, pi, qi, qj, *qk_it, strategy);
0315 }
0316 else
0317 {
0318
0319 return calculate_from_inside_sides(qi, turn.point, pi, qi, turn.point, qj, strategy);
0320 }
0321 }
0322
0323
0324
0325 template <typename Geometry1, typename Geometry2, bool TransposeResult = false>
0326 struct linear_areal
0327 {
0328
0329 BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 1
0330 && topological_dimension<Geometry2>::value == 2);
0331
0332 static const bool interruption_enabled = true;
0333
0334 template <typename Geom1, typename Geom2, typename Strategy>
0335 struct multi_turn_info
0336 : turns::get_turns<Geom1, Geom2>::template turn_info_type<Strategy>::type
0337 {
0338 multi_turn_info() : priority(0) {}
0339 int priority;
0340 };
0341
0342 template <typename Geom1, typename Geom2, typename Strategy>
0343 struct turn_info_type
0344 : std::conditional
0345 <
0346 util::is_multi<Geometry2>::value,
0347 multi_turn_info<Geom1, Geom2, Strategy>,
0348 typename turns::get_turns<Geom1, Geom2>::template turn_info_type<Strategy>::type
0349 >
0350 {};
0351
0352 template <typename Result, typename Strategy>
0353 static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
0354 Result & result,
0355 Strategy const& strategy)
0356 {
0357 boundary_checker<Geometry1, Strategy> boundary_checker1(geometry1, strategy);
0358 apply(geometry1, geometry2, boundary_checker1, result, strategy);
0359 }
0360
0361 template <typename BoundaryChecker1, typename Result, typename Strategy>
0362 static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
0363 BoundaryChecker1 const& boundary_checker1,
0364 Result & result,
0365 Strategy const& strategy)
0366 {
0367
0368
0369 update<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);
0370
0371 if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
0372 {
0373 return;
0374 }
0375
0376
0377 using turn_type = typename turn_info_type<Geometry1, Geometry2, Strategy>::type;
0378 std::vector<turn_type> turns;
0379
0380 interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result);
0381
0382 turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, strategy);
0383 if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
0384 {
0385 return;
0386 }
0387
0388 no_turns_la_linestring_pred
0389 <
0390 Geometry2,
0391 Result,
0392 Strategy,
0393 BoundaryChecker1,
0394 TransposeResult
0395 > pred1(geometry2,
0396 result,
0397 strategy,
0398 boundary_checker1);
0399 for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
0400 if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
0401 {
0402 return;
0403 }
0404
0405 no_turns_la_areal_pred<Result, !TransposeResult> pred2(result);
0406 for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
0407 if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
0408 {
0409 return;
0410 }
0411
0412 if ( turns.empty() )
0413 {
0414 return;
0415 }
0416
0417
0418
0419 update<exterior, interior, '2', TransposeResult>(result);
0420 if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
0421 {
0422 return;
0423 }
0424
0425 {
0426 sort_dispatch(turns.begin(), turns.end(), strategy, util::is_multi<Geometry2>());
0427
0428 turns_analyser<turn_type> analyser;
0429 analyse_each_turn(result, analyser,
0430 turns.begin(), turns.end(),
0431 geometry1, geometry2,
0432 boundary_checker1,
0433 strategy);
0434
0435 if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
0436 {
0437 return;
0438 }
0439 }
0440
0441
0442 if ( !interrupt_policy.is_boundary_found )
0443 {
0444 update<exterior, boundary, '1', TransposeResult>(result);
0445 }
0446
0447 else if ( may_update<exterior, boundary, '1', TransposeResult>(result) )
0448 {
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458 std::sort(turns.begin(), turns.end(), less_ring());
0459
0460 segment_identifier * prev_seg_id_ptr = NULL;
0461
0462 for (auto it = turns.begin() ; it != turns.end() ; )
0463 {
0464
0465 if ( prev_seg_id_ptr == NULL
0466 || prev_seg_id_ptr->multi_index != it->operations[1].seg_id.multi_index )
0467 {
0468
0469 if ( it->operations[1].seg_id.ring_index > -1 )
0470 {
0471
0472 update<exterior, boundary, '1', TransposeResult>(result);
0473 break;
0474 }
0475
0476 if ( prev_seg_id_ptr != NULL )
0477 {
0478 signed_size_type const next_ring_index = prev_seg_id_ptr->ring_index + 1;
0479 BOOST_GEOMETRY_ASSERT(next_ring_index >= 0);
0480
0481
0482 if ( static_cast<std::size_t>(next_ring_index)
0483 < geometry::num_interior_rings(
0484 single_geometry(geometry2, *prev_seg_id_ptr)) )
0485 {
0486
0487 update<exterior, boundary, '1', TransposeResult>(result);
0488 break;
0489 }
0490 }
0491 }
0492
0493 else
0494 {
0495
0496 if ( prev_seg_id_ptr != NULL
0497 && prev_seg_id_ptr->ring_index + 1 < it->operations[1].seg_id.ring_index )
0498 {
0499
0500 update<exterior, boundary, '1', TransposeResult>(result);
0501 break;
0502 }
0503 }
0504
0505 prev_seg_id_ptr = boost::addressof(it->operations[1].seg_id);
0506
0507
0508 has_boundary_intersection has_boundary_inters;
0509 auto next = find_next_ring(it, turns.end(), has_boundary_inters);
0510
0511
0512 if ( !has_boundary_inters.result )
0513 {
0514
0515 update<exterior, boundary, '1', TransposeResult>(result);
0516 break;
0517 }
0518
0519 else
0520 {
0521
0522 using less_t = turns::less<1, turns::less_op_areal_linear<1>, Strategy>;
0523 std::sort(it, next, less_t());
0524
0525
0526 areal_boundary_analyser<turn_type> analyser;
0527 for (auto rit = it ; rit != next ; ++rit)
0528 {
0529
0530 if ( !analyser.apply(it, rit, next, strategy) )
0531 break;
0532 }
0533
0534
0535 if ( analyser.is_union_detected )
0536 {
0537
0538 update<exterior, boundary, '1', TransposeResult>(result);
0539 break;
0540 }
0541 }
0542
0543 it = next;
0544 }
0545
0546
0547 if ( prev_seg_id_ptr != NULL )
0548 {
0549 signed_size_type const next_ring_index = prev_seg_id_ptr->ring_index + 1;
0550 BOOST_GEOMETRY_ASSERT(next_ring_index >= 0);
0551
0552
0553 if ( static_cast<std::size_t>(next_ring_index)
0554 < geometry::num_interior_rings(
0555 single_geometry(geometry2, *prev_seg_id_ptr)) )
0556 {
0557
0558 update<exterior, boundary, '1', TransposeResult>(result);
0559 }
0560 }
0561 }
0562 }
0563
0564 template <typename It, typename Pred, typename Comp>
0565 static void for_each_equal_range(It first, It last, Pred pred, Comp comp)
0566 {
0567 if ( first == last )
0568 {
0569 return;
0570 }
0571
0572 It first_equal = first;
0573 It prev = first;
0574 for ( ++first ; ; ++first, ++prev )
0575 {
0576 if ( first == last || !comp(*prev, *first) )
0577 {
0578 pred(first_equal, first);
0579 first_equal = first;
0580 }
0581
0582 if ( first == last )
0583 {
0584 break;
0585 }
0586 }
0587 }
0588
0589 struct same_ip
0590 {
0591 template <typename Turn>
0592 bool operator()(Turn const& left, Turn const& right) const
0593 {
0594 return left.operations[0].seg_id == right.operations[0].seg_id
0595 && left.operations[0].fraction == right.operations[0].fraction;
0596 }
0597 };
0598
0599 struct same_ip_and_multi_index
0600 {
0601 template <typename Turn>
0602 bool operator()(Turn const& left, Turn const& right) const
0603 {
0604 return same_ip()(left, right)
0605 && left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index;
0606 }
0607 };
0608
0609 template <typename OpToPriority>
0610 struct set_turns_group_priority
0611 {
0612 template <typename TurnIt>
0613 void operator()(TurnIt first, TurnIt last) const
0614 {
0615 BOOST_GEOMETRY_ASSERT(first != last);
0616 static OpToPriority op_to_priority;
0617
0618 int least_priority = op_to_priority(first->operations[0]);
0619 for ( TurnIt it = first + 1 ; it != last ; ++it )
0620 {
0621 int priority = op_to_priority(it->operations[0]);
0622 if ( priority < least_priority )
0623 least_priority = priority;
0624 }
0625
0626 for ( TurnIt it = first ; it != last ; ++it )
0627 {
0628 it->priority = least_priority;
0629 }
0630 }
0631 };
0632
0633 template <typename SingleLess>
0634 struct sort_turns_group
0635 {
0636 struct less
0637 {
0638 template <typename Turn>
0639 bool operator()(Turn const& left, Turn const& right) const
0640 {
0641 return left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index ?
0642 SingleLess()(left, right) :
0643 left.priority < right.priority;
0644 }
0645 };
0646
0647 template <typename TurnIt>
0648 void operator()(TurnIt first, TurnIt last) const
0649 {
0650 std::sort(first, last, less());
0651 }
0652 };
0653
0654 template <typename TurnIt, typename Strategy>
0655 static void sort_dispatch(TurnIt first, TurnIt last, Strategy const& ,
0656 std::true_type const& )
0657 {
0658
0659 using less_t = turns::less<0, turns::less_other_multi_index<0>, Strategy>;
0660 std::sort(first, last, less_t());
0661
0662
0663
0664
0665 typedef turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic;
0666 for_each_equal_range(first, last,
0667 set_turns_group_priority<op_to_int_xuic>(),
0668 same_ip_and_multi_index());
0669
0670
0671
0672
0673 using single_less_t = turns::less<0, turns::less_op_linear_areal_single<0>, Strategy>;
0674 for_each_equal_range(first, last,
0675 sort_turns_group<single_less_t>(),
0676 same_ip());
0677 }
0678
0679 template <typename TurnIt, typename Strategy>
0680 static void sort_dispatch(TurnIt first, TurnIt last, Strategy const& ,
0681 std::false_type const& )
0682 {
0683
0684
0685
0686 using less_t = turns::less<0, turns::less_op_linear_areal_single<0>, Strategy>;
0687 std::sort(first, last, less_t());
0688 }
0689
0690
0691
0692
0693 template <typename Areal, typename Result>
0694 class interrupt_policy_linear_areal
0695 {
0696 public:
0697 static bool const enabled = true;
0698
0699 interrupt_policy_linear_areal(Areal const& areal, Result & result)
0700 : m_result(result), m_areal(areal)
0701 , is_boundary_found(false)
0702 {}
0703
0704
0705
0706 template <typename Range>
0707 inline bool apply(Range const& turns)
0708 {
0709 for (auto it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
0710 {
0711 if ( it->operations[0].operation == overlay::operation_intersection )
0712 {
0713 bool const no_interior_rings
0714 = geometry::num_interior_rings(
0715 single_geometry(m_areal, it->operations[1].seg_id)) == 0;
0716
0717
0718
0719 if ( no_interior_rings )
0720 update<interior, interior, '1', TransposeResult>(m_result);
0721 }
0722 else if ( it->operations[0].operation == overlay::operation_continue )
0723 {
0724 update<interior, boundary, '1', TransposeResult>(m_result);
0725 is_boundary_found = true;
0726 }
0727 else if ( ( it->operations[0].operation == overlay::operation_union
0728 || it->operations[0].operation == overlay::operation_blocked )
0729 && it->operations[0].position == overlay::position_middle )
0730 {
0731
0732 update<interior, boundary, '0', TransposeResult>(m_result);
0733 }
0734 }
0735
0736 return m_result.interrupt;
0737 }
0738
0739 private:
0740 Result & m_result;
0741 Areal const& m_areal;
0742
0743 public:
0744 bool is_boundary_found;
0745 };
0746
0747
0748
0749 template <typename TurnInfo>
0750 class turns_analyser
0751 {
0752 typedef typename TurnInfo::point_type turn_point_type;
0753
0754 static const std::size_t op_id = 0;
0755 static const std::size_t other_op_id = 1;
0756
0757 public:
0758 turns_analyser()
0759 : m_previous_turn_ptr(NULL)
0760 , m_previous_operation(overlay::operation_none)
0761 , m_boundary_counter(0)
0762 , m_interior_detected(false)
0763 , m_first_interior_other_id_ptr(NULL)
0764 , m_first_from_unknown(false)
0765 , m_first_from_unknown_boundary_detected(false)
0766 {}
0767
0768 template <typename Result,
0769 typename TurnIt,
0770 typename Geometry,
0771 typename OtherGeometry,
0772 typename BoundaryChecker,
0773 typename Strategy>
0774 void apply(Result & res, TurnIt it,
0775 Geometry const& geometry,
0776 OtherGeometry const& other_geometry,
0777 BoundaryChecker const& boundary_checker,
0778 Strategy const& strategy)
0779 {
0780 overlay::operation_type op = it->operations[op_id].operation;
0781
0782 if ( op != overlay::operation_union
0783 && op != overlay::operation_intersection
0784 && op != overlay::operation_blocked
0785 && op != overlay::operation_continue )
0786 {
0787 return;
0788 }
0789
0790 segment_identifier const& seg_id = it->operations[op_id].seg_id;
0791 segment_identifier const& other_id = it->operations[other_op_id].seg_id;
0792
0793 const bool first_in_range = m_seg_watcher.update(seg_id);
0794
0795
0796
0797
0798
0799
0800
0801 bool fake_enter_detected = false;
0802 if ( m_exit_watcher.get_exit_operation() == overlay::operation_union )
0803 {
0804
0805
0806 if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it,
0807 strategy) )
0808 {
0809 m_exit_watcher.reset_detected_exit();
0810
0811 update<interior, exterior, '1', TransposeResult>(res);
0812
0813
0814 if ( first_in_range && m_previous_turn_ptr )
0815 {
0816
0817 segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
0818
0819 bool const prev_back_b = boundary_checker.is_endpoint_boundary(
0820 range::back(sub_range(geometry, prev_seg_id)));
0821
0822
0823 if ( prev_back_b )
0824 {
0825 update<boundary, exterior, '0', TransposeResult>(res);
0826 }
0827 }
0828 }
0829
0830 else if ( op == overlay::operation_intersection
0831 || op == overlay::operation_continue )
0832 {
0833 m_exit_watcher.reset_detected_exit();
0834 fake_enter_detected = true;
0835 }
0836 }
0837 else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked )
0838 {
0839
0840 if ( op == overlay::operation_blocked
0841 && seg_id.multi_index == m_previous_turn_ptr->operations[op_id].seg_id.multi_index )
0842 {
0843 return;
0844 }
0845
0846 if ( ( op == overlay::operation_intersection
0847 || op == overlay::operation_continue )
0848 && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it,
0849 strategy) )
0850 {
0851 fake_enter_detected = true;
0852 }
0853
0854 m_exit_watcher.reset_detected_exit();
0855 }
0856
0857 if ( BOOST_GEOMETRY_CONDITION( util::is_multi<OtherGeometry>::value )
0858 && m_first_from_unknown )
0859 {
0860
0861
0862
0863
0864
0865 if ( ( m_previous_operation == overlay::operation_blocked
0866 && ( op != overlay::operation_blocked
0867 || seg_id.multi_index != m_previous_turn_ptr->operations[op_id].seg_id.multi_index ) )
0868 || ( m_previous_operation == overlay::operation_union
0869 && ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it,
0870 strategy) )
0871 )
0872 {
0873 update<interior, exterior, '1', TransposeResult>(res);
0874 if ( m_first_from_unknown_boundary_detected )
0875 {
0876 update<boundary, exterior, '0', TransposeResult>(res);
0877 }
0878
0879 m_first_from_unknown = false;
0880 m_first_from_unknown_boundary_detected = false;
0881 }
0882 }
0883
0884
0885
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896
0897 if ( m_interior_detected )
0898 {
0899 BOOST_GEOMETRY_ASSERT_MSG(m_previous_turn_ptr, "non-NULL ptr expected");
0900
0901
0902 if ( ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it,
0903 strategy) )
0904 {
0905 update<interior, interior, '1', TransposeResult>(res);
0906 m_interior_detected = false;
0907
0908
0909 if ( first_in_range )
0910 {
0911 segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
0912
0913 bool const prev_back_b = boundary_checker.is_endpoint_boundary(
0914 range::back(sub_range(geometry, prev_seg_id)));
0915
0916
0917 if ( prev_back_b )
0918 {
0919 update<boundary, interior, '0', TransposeResult>(res);
0920 }
0921
0922
0923
0924 }
0925 }
0926
0927 else if ( op == overlay::operation_continue )
0928 {
0929 m_interior_detected = false;
0930 }
0931 else if ( op == overlay::operation_union )
0932 {
0933
0934
0935
0936
0937 if ( m_first_interior_other_id_ptr
0938 && m_first_interior_other_id_ptr->multi_index == other_id.multi_index )
0939 {
0940 m_interior_detected = false;
0941 }
0942 }
0943 }
0944
0945
0946 if ( first_in_range )
0947 {
0948 m_exit_watcher.reset();
0949 m_boundary_counter = 0;
0950 m_first_from_unknown = false;
0951 m_first_from_unknown_boundary_detected = false;
0952 }
0953
0954
0955 if ( op == overlay::operation_intersection
0956 || op == overlay::operation_continue )
0957 {
0958 bool const first_point = first_in_range || m_first_from_unknown;
0959 bool no_enters_detected = m_exit_watcher.is_outside();
0960 m_exit_watcher.enter(*it);
0961
0962 if ( op == overlay::operation_intersection )
0963 {
0964 if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear )
0965 --m_boundary_counter;
0966
0967 if ( m_boundary_counter == 0 )
0968 {
0969
0970
0971
0972
0973
0974 if ( !m_interior_detected )
0975 {
0976
0977
0978 m_interior_detected = true;
0979 m_first_interior_other_id_ptr = boost::addressof(other_id);
0980 }
0981 }
0982 }
0983 else
0984 {
0985
0986
0987 if ( first_point || !it->operations[op_id].is_collinear )
0988 ++m_boundary_counter;
0989
0990 update<interior, boundary, '1', TransposeResult>(res);
0991 }
0992
0993 bool const this_b = is_ip_on_boundary(it->point, it->operations[op_id],
0994 boundary_checker);
0995
0996 if ( this_b )
0997 {
0998 update<boundary, boundary, '0', TransposeResult>(res);
0999 }
1000
1001 else
1002 {
1003 update<interior, boundary, '0', TransposeResult>(res);
1004
1005
1006 if ( no_enters_detected
1007 && ! fake_enter_detected
1008 && it->operations[op_id].position != overlay::position_front )
1009 {
1010
1011 bool const from_inside =
1012 first_point && calculate_from_inside<op_id>(geometry,
1013 other_geometry,
1014 *it,
1015 strategy);
1016
1017 if ( from_inside )
1018 update<interior, interior, '1', TransposeResult>(res);
1019 else
1020 update<interior, exterior, '1', TransposeResult>(res);
1021
1022
1023 if ( first_point )
1024 {
1025 bool const front_b = boundary_checker.is_endpoint_boundary(
1026 range::front(sub_range(geometry, seg_id)));
1027
1028
1029 if ( front_b )
1030 {
1031 if ( from_inside )
1032 update<boundary, interior, '0', TransposeResult>(res);
1033 else
1034 update<boundary, exterior, '0', TransposeResult>(res);
1035 }
1036 }
1037 }
1038 }
1039
1040 if ( BOOST_GEOMETRY_CONDITION( util::is_multi<OtherGeometry>::value ) )
1041 {
1042 m_first_from_unknown = false;
1043 m_first_from_unknown_boundary_detected = false;
1044 }
1045 }
1046
1047 else if ( op == overlay::operation_union || op == overlay::operation_blocked )
1048 {
1049 bool const op_blocked = op == overlay::operation_blocked;
1050 bool const no_enters_detected = m_exit_watcher.is_outside()
1051
1052
1053 && m_exit_watcher.get_exit_operation() == overlay::operation_none;
1054
1055 if ( op == overlay::operation_union )
1056 {
1057 if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear )
1058 --m_boundary_counter;
1059 }
1060 else
1061 {
1062 m_boundary_counter = 0;
1063 }
1064
1065
1066 if ( ! no_enters_detected )
1067 {
1068 if ( op_blocked
1069 && it->operations[op_id].position == overlay::position_back )
1070 {
1071
1072
1073 if (boundary_checker.is_endpoint_boundary(it->point))
1074 {
1075 update<boundary, boundary, '0', TransposeResult>(res);
1076 }
1077 }
1078
1079
1080
1081
1082
1083
1084 }
1085
1086 else
1087 {
1088 bool const this_b = is_ip_on_boundary(it->point, it->operations[op_id],
1089 boundary_checker);
1090
1091 if ( this_b )
1092 {
1093 update<boundary, boundary, '0', TransposeResult>(res);
1094 }
1095
1096 else
1097 {
1098 update<interior, boundary, '0', TransposeResult>(res);
1099 }
1100
1101
1102 if ( it->operations[op_id].position != overlay::position_front )
1103 {
1104
1105
1106
1107
1108 bool const first_point = first_in_range || m_first_from_unknown;
1109 bool const first_from_inside =
1110 first_point && calculate_from_inside<op_id>(geometry,
1111 other_geometry,
1112 *it,
1113 strategy);
1114 if ( first_from_inside )
1115 {
1116 update<interior, interior, '1', TransposeResult>(res);
1117
1118
1119 m_exit_watcher.enter(*it);
1120
1121 m_first_from_unknown = false;
1122 m_first_from_unknown_boundary_detected = false;
1123 }
1124 else
1125 {
1126 if ( BOOST_GEOMETRY_CONDITION( util::is_multi<OtherGeometry>::value )
1127
1128 )
1129 {
1130 m_first_from_unknown = true;
1131 }
1132 else
1133 {
1134 update<interior, exterior, '1', TransposeResult>(res);
1135 }
1136 }
1137
1138
1139 if ( first_point && ( !this_b || op_blocked ) )
1140 {
1141 bool const front_b = boundary_checker.is_endpoint_boundary(
1142 range::front(sub_range(geometry, seg_id)));
1143
1144
1145 if ( front_b )
1146 {
1147 if ( first_from_inside )
1148 {
1149 update<boundary, interior, '0', TransposeResult>(res);
1150 }
1151 else
1152 {
1153 if ( BOOST_GEOMETRY_CONDITION( util::is_multi<OtherGeometry>::value )
1154
1155 )
1156 {
1157 BOOST_GEOMETRY_ASSERT(m_first_from_unknown);
1158 m_first_from_unknown_boundary_detected = true;
1159 }
1160 else
1161 {
1162 update<boundary, exterior, '0', TransposeResult>(res);
1163 }
1164 }
1165 }
1166 }
1167 }
1168 }
1169
1170
1171 if ( m_boundary_counter == 0
1172 || it->operations[op_id].is_collinear )
1173 {
1174
1175 m_exit_watcher.exit(*it);
1176 }
1177 }
1178
1179
1180 m_previous_turn_ptr = boost::addressof(*it);
1181
1182 m_previous_operation = op;
1183 }
1184
1185
1186 template <typename Result,
1187 typename TurnIt,
1188 typename Geometry,
1189 typename OtherGeometry,
1190 typename BoundaryChecker>
1191 void apply(Result & res,
1192 TurnIt first, TurnIt last,
1193 Geometry const& geometry,
1194 OtherGeometry const& ,
1195 BoundaryChecker const& boundary_checker)
1196 {
1197 boost::ignore_unused(first, last);
1198
1199
1200
1201
1202
1203 if ( BOOST_GEOMETRY_CONDITION( util::is_multi<OtherGeometry>::value )
1204 && m_first_from_unknown )
1205 {
1206 update<interior, exterior, '1', TransposeResult>(res);
1207 if ( m_first_from_unknown_boundary_detected )
1208 {
1209 update<boundary, exterior, '0', TransposeResult>(res);
1210 }
1211
1212
1213
1214
1215 }
1216
1217
1218
1219 if (
1220 m_previous_operation == overlay::operation_union
1221 && !m_interior_detected )
1222 {
1223
1224 update<interior, exterior, '1', TransposeResult>(res);
1225
1226 BOOST_GEOMETRY_ASSERT(first != last);
1227 BOOST_GEOMETRY_ASSERT(m_previous_turn_ptr);
1228
1229 segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
1230
1231 bool const prev_back_b = boundary_checker.is_endpoint_boundary(
1232 range::back(sub_range(geometry, prev_seg_id)));
1233
1234
1235 if ( prev_back_b )
1236 {
1237 update<boundary, exterior, '0', TransposeResult>(res);
1238 }
1239 }
1240
1241 else if ( m_previous_operation == overlay::operation_intersection
1242 || m_interior_detected )
1243 {
1244
1245 update<interior, interior, '1', TransposeResult>(res);
1246 m_interior_detected = false;
1247
1248 BOOST_GEOMETRY_ASSERT(first != last);
1249 BOOST_GEOMETRY_ASSERT(m_previous_turn_ptr);
1250
1251 segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
1252
1253 bool const prev_back_b = boundary_checker.is_endpoint_boundary(
1254 range::back(sub_range(geometry, prev_seg_id)));
1255
1256
1257 if ( prev_back_b )
1258 {
1259 update<boundary, interior, '0', TransposeResult>(res);
1260 }
1261 }
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272 if ( m_previous_operation == overlay::operation_continue )
1273 {
1274 update<interior, exterior, '1', TransposeResult>(res);
1275
1276 segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
1277
1278 bool const prev_back_b = boundary_checker.is_endpoint_boundary(
1279 range::back(sub_range(geometry, prev_seg_id)));
1280
1281
1282 if ( prev_back_b )
1283 {
1284 update<boundary, exterior, '0', TransposeResult>(res);
1285 }
1286 }
1287
1288
1289 m_exit_watcher.reset();
1290 m_boundary_counter = 0;
1291 m_first_from_unknown = false;
1292 m_first_from_unknown_boundary_detected = false;
1293 }
1294
1295 private:
1296 exit_watcher<TurnInfo, op_id> m_exit_watcher;
1297 segment_watcher<same_single> m_seg_watcher;
1298 TurnInfo * m_previous_turn_ptr;
1299 overlay::operation_type m_previous_operation;
1300 unsigned m_boundary_counter;
1301 bool m_interior_detected;
1302 const segment_identifier * m_first_interior_other_id_ptr;
1303 bool m_first_from_unknown;
1304 bool m_first_from_unknown_boundary_detected;
1305 };
1306
1307
1308
1309 template <typename Result,
1310 typename TurnIt,
1311 typename Analyser,
1312 typename Geometry,
1313 typename OtherGeometry,
1314 typename BoundaryChecker,
1315 typename Strategy>
1316 static inline void analyse_each_turn(Result & res,
1317 Analyser & analyser,
1318 TurnIt first, TurnIt last,
1319 Geometry const& geometry,
1320 OtherGeometry const& other_geometry,
1321 BoundaryChecker const& boundary_checker,
1322 Strategy const& strategy)
1323 {
1324 if ( first == last )
1325 {
1326 return;
1327 }
1328
1329 for ( TurnIt it = first ; it != last ; ++it )
1330 {
1331 analyser.apply(res, it,
1332 geometry, other_geometry,
1333 boundary_checker,
1334 strategy);
1335
1336 if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) )
1337 {
1338 return;
1339 }
1340 }
1341
1342 analyser.apply(res, first, last,
1343 geometry, other_geometry,
1344 boundary_checker);
1345 }
1346
1347
1348
1349 struct less_ring
1350 {
1351 template <typename Turn>
1352 inline bool operator()(Turn const& left, Turn const& right) const
1353 {
1354 return left.operations[1].seg_id.multi_index < right.operations[1].seg_id.multi_index
1355 || ( left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index
1356 && left.operations[1].seg_id.ring_index < right.operations[1].seg_id.ring_index );
1357 }
1358 };
1359
1360
1361 struct has_boundary_intersection
1362 {
1363 has_boundary_intersection()
1364 : result(false) {}
1365
1366 template <typename Turn>
1367 inline void operator()(Turn const& turn)
1368 {
1369 if ( turn.operations[1].operation == overlay::operation_continue )
1370 result = true;
1371 }
1372
1373 bool result;
1374 };
1375
1376
1377
1378 template <typename It, typename Fun>
1379 static inline It find_next_ring(It first, It last, Fun & fun)
1380 {
1381 if ( first == last )
1382 return last;
1383
1384 signed_size_type const multi_index = first->operations[1].seg_id.multi_index;
1385 signed_size_type const ring_index = first->operations[1].seg_id.ring_index;
1386
1387 fun(*first);
1388 ++first;
1389
1390 for ( ; first != last ; ++first )
1391 {
1392 if ( multi_index != first->operations[1].seg_id.multi_index
1393 || ring_index != first->operations[1].seg_id.ring_index )
1394 {
1395 return first;
1396 }
1397
1398 fun(*first);
1399 }
1400
1401 return last;
1402 }
1403
1404
1405
1406
1407 template <typename TurnInfo>
1408 class areal_boundary_analyser
1409 {
1410 public:
1411 areal_boundary_analyser()
1412 : is_union_detected(false)
1413 , m_previous_turn_ptr(NULL)
1414 {}
1415
1416 template <typename TurnIt, typename Strategy>
1417 bool apply(TurnIt , TurnIt it, TurnIt last,
1418 Strategy const& strategy)
1419 {
1420 overlay::operation_type op = it->operations[1].operation;
1421
1422 if ( it != last )
1423 {
1424 if ( op != overlay::operation_union
1425 && op != overlay::operation_continue )
1426 {
1427 return true;
1428 }
1429
1430 if ( is_union_detected )
1431 {
1432 BOOST_GEOMETRY_ASSERT(m_previous_turn_ptr != NULL);
1433 if ( !detail::equals::equals_point_point(it->point, m_previous_turn_ptr->point, strategy) )
1434 {
1435
1436 return false;
1437 }
1438 else if ( op == overlay::operation_continue )
1439 {
1440 is_union_detected = false;
1441 }
1442 }
1443
1444 if ( op == overlay::operation_union )
1445 {
1446 is_union_detected = true;
1447 m_previous_turn_ptr = boost::addressof(*it);
1448 }
1449
1450 return true;
1451 }
1452 else
1453 {
1454 return false;
1455 }
1456 }
1457
1458 bool is_union_detected;
1459
1460 private:
1461 const TurnInfo * m_previous_turn_ptr;
1462 };
1463 };
1464
1465 template <typename Geometry1, typename Geometry2>
1466 struct areal_linear
1467 {
1468 typedef linear_areal<Geometry2, Geometry1, true> linear_areal_type;
1469
1470 static const bool interruption_enabled = linear_areal_type::interruption_enabled;
1471
1472 template <typename Result, typename Strategy>
1473 static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
1474 Result & result,
1475 Strategy const& strategy)
1476 {
1477 linear_areal_type::apply(geometry2, geometry1, result, strategy);
1478 }
1479
1480 template <typename BoundaryChecker2, typename Result, typename Strategy>
1481 static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
1482 BoundaryChecker2 const& boundary_checker2,
1483 Result & result,
1484 Strategy const& strategy)
1485 {
1486 linear_areal_type::apply(geometry2, geometry1, boundary_checker2, result, strategy);
1487 }
1488 };
1489
1490 }}
1491 #endif
1492
1493 }}
1494
1495 #endif