File indexing completed on 2025-01-18 09:35:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
0015 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
0016
0017 #include <boost/geometry/core/topological_dimension.hpp>
0018
0019 #include <boost/geometry/util/condition.hpp>
0020 #include <boost/geometry/util/range.hpp>
0021
0022 #include <boost/geometry/algorithms/num_interior_rings.hpp>
0023 #include <boost/geometry/algorithms/detail/point_on_border.hpp>
0024 #include <boost/geometry/algorithms/detail/sub_range.hpp>
0025 #include <boost/geometry/algorithms/detail/single_geometry.hpp>
0026
0027 #include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
0028 #include <boost/geometry/algorithms/detail/relate/turns.hpp>
0029 #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
0030 #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
0031
0032 #include <boost/geometry/geometries/helper_geometry.hpp>
0033
0034 namespace boost { namespace geometry
0035 {
0036
0037 #ifndef DOXYGEN_NO_DETAIL
0038 namespace detail { namespace relate {
0039
0040
0041
0042
0043
0044
0045 template
0046 <
0047 typename OtherAreal,
0048 typename Result,
0049 typename PointInArealStrategy,
0050 bool TransposeResult
0051 >
0052 class no_turns_aa_pred
0053 {
0054 public:
0055 no_turns_aa_pred(OtherAreal const& other_areal,
0056 Result & res,
0057 PointInArealStrategy const& point_in_areal_strategy)
0058 : m_result(res)
0059 , m_point_in_areal_strategy(point_in_areal_strategy)
0060 , m_other_areal(other_areal)
0061 , m_flags(0)
0062 {
0063
0064
0065 if ( ! may_update<interior, interior, '2', TransposeResult>(m_result)
0066 && ! may_update<boundary, interior, '1', TransposeResult>(m_result)
0067 && ! may_update<exterior, interior, '2', TransposeResult>(m_result) )
0068 {
0069 m_flags |= 1;
0070 }
0071
0072 if ( ! may_update<interior, exterior, '2', TransposeResult>(m_result)
0073 && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) )
0074 {
0075 m_flags |= 2;
0076 }
0077 }
0078
0079 template <typename Areal>
0080 bool operator()(Areal const& areal)
0081 {
0082 using detail::within::point_in_geometry;
0083
0084
0085 if ( m_flags == 3 )
0086 {
0087 return false;
0088 }
0089
0090 using point_type = typename geometry::point_type<Areal>::type;
0091 typename helper_geometry<point_type>::type pt;
0092 bool const ok = geometry::point_on_border(pt, areal);
0093
0094
0095 if ( !ok )
0096 {
0097 return true;
0098 }
0099
0100
0101
0102
0103 int const pig = point_in_geometry(pt,
0104 m_other_areal,
0105 m_point_in_areal_strategy);
0106
0107
0108
0109 if ( pig > 0 )
0110 {
0111 update<interior, interior, '2', TransposeResult>(m_result);
0112 update<boundary, interior, '1', TransposeResult>(m_result);
0113 update<exterior, interior, '2', TransposeResult>(m_result);
0114 m_flags |= 1;
0115
0116
0117
0118
0119
0120
0121 ring_identifier ring_id(0, -1, 0);
0122 std::size_t const irings_count = geometry::num_interior_rings(areal);
0123 for ( ; static_cast<std::size_t>(ring_id.ring_index) < irings_count ;
0124 ++ring_id.ring_index )
0125 {
0126 typename detail::sub_range_return_type<Areal const>::type
0127 range_ref = detail::sub_range(areal, ring_id);
0128
0129 if ( boost::empty(range_ref) )
0130 {
0131
0132 continue;
0133 }
0134
0135
0136
0137 int const hpig = point_in_geometry(range::front(range_ref),
0138 m_other_areal,
0139 m_point_in_areal_strategy);
0140
0141
0142 if ( hpig < 0 )
0143 {
0144 update<interior, exterior, '2', TransposeResult>(m_result);
0145 update<boundary, exterior, '1', TransposeResult>(m_result);
0146 m_flags |= 2;
0147 break;
0148 }
0149 }
0150 }
0151
0152 else
0153 {
0154 update<interior, exterior, '2', TransposeResult>(m_result);
0155 update<boundary, exterior, '1', TransposeResult>(m_result);
0156 m_flags |= 2;
0157
0158
0159 ring_identifier ring_id(0, -1, 0);
0160 std::size_t const irings_count = geometry::num_interior_rings(areal);
0161 for ( ; static_cast<std::size_t>(ring_id.ring_index) < irings_count ;
0162 ++ring_id.ring_index )
0163 {
0164 typename detail::sub_range_return_type<Areal const>::type
0165 range_ref = detail::sub_range(areal, ring_id);
0166
0167 if ( boost::empty(range_ref) )
0168 {
0169
0170 continue;
0171 }
0172
0173
0174
0175 int const hpig = point_in_geometry(range::front(range_ref),
0176 m_other_areal,
0177 m_point_in_areal_strategy);
0178
0179
0180 if ( hpig > 0 )
0181 {
0182 update<interior, interior, '2', TransposeResult>(m_result);
0183 update<boundary, interior, '1', TransposeResult>(m_result);
0184 update<exterior, interior, '2', TransposeResult>(m_result);
0185 m_flags |= 1;
0186 break;
0187 }
0188 }
0189 }
0190
0191 return m_flags != 3 && !m_result.interrupt;
0192 }
0193
0194 private:
0195 Result & m_result;
0196 PointInArealStrategy const& m_point_in_areal_strategy;
0197 OtherAreal const& m_other_areal;
0198 int m_flags;
0199 };
0200
0201
0202 template <typename Geometry1, typename Geometry2>
0203 struct areal_areal
0204 {
0205
0206 BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 2
0207 && topological_dimension<Geometry2>::value == 2);
0208
0209 static const bool interruption_enabled = true;
0210
0211 template <typename Result, typename Strategy>
0212 static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
0213 Result & result,
0214 Strategy const& strategy)
0215 {
0216
0217
0218 update<exterior, exterior, result_dimension<Geometry2>::value>(result);
0219
0220 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
0221 return;
0222
0223
0224 using turn_type = typename turns::get_turns
0225 <
0226 Geometry1, Geometry2
0227 >::template turn_info_type<Strategy>::type;
0228 std::vector<turn_type> turns;
0229
0230 interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result);
0231
0232 turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, strategy);
0233 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
0234 return;
0235
0236 no_turns_aa_pred<Geometry2, Result, Strategy, false>
0237 pred1(geometry2, result, strategy);
0238 for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
0239 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
0240 return;
0241
0242 no_turns_aa_pred<Geometry1, Result, Strategy, true>
0243 pred2(geometry1, result, strategy);
0244 for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
0245 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
0246 return;
0247
0248 if ( turns.empty() )
0249 return;
0250
0251 if ( may_update<interior, interior, '2'>(result)
0252 || may_update<interior, exterior, '2'>(result)
0253 || may_update<boundary, interior, '1'>(result)
0254 || may_update<boundary, exterior, '1'>(result)
0255 || may_update<exterior, interior, '2'>(result) )
0256 {
0257
0258 using less_t = turns::less<0, turns::less_op_areal_areal<0>, Strategy>;
0259 std::sort(turns.begin(), turns.end(), less_t());
0260
0261
0262
0263
0264
0265 {
0266
0267 turns_analyser<turn_type, 0> analyser;
0268 analyse_each_turn(result, analyser, turns.begin(), turns.end(), strategy);
0269
0270 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
0271 return;
0272 }
0273
0274 if ( may_update<interior, interior, '2'>(result)
0275 || may_update<interior, exterior, '2'>(result)
0276 || may_update<boundary, interior, '1'>(result)
0277 || may_update<boundary, exterior, '1'>(result)
0278 || may_update<exterior, interior, '2'>(result) )
0279 {
0280
0281
0282 uncertain_rings_analyser<0, Result, Geometry1, Geometry2, Strategy>
0283 rings_analyser(result, geometry1, geometry2, strategy);
0284 analyse_uncertain_rings<0>::apply(rings_analyser, turns.begin(), turns.end());
0285
0286 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
0287 return;
0288 }
0289 }
0290
0291 if ( may_update<interior, interior, '2', true>(result)
0292 || may_update<interior, exterior, '2', true>(result)
0293 || may_update<boundary, interior, '1', true>(result)
0294 || may_update<boundary, exterior, '1', true>(result)
0295 || may_update<exterior, interior, '2', true>(result) )
0296 {
0297
0298 using less_t = turns::less<1, turns::less_op_areal_areal<1>, Strategy>;
0299 std::sort(turns.begin(), turns.end(), less_t());
0300
0301
0302
0303
0304
0305 {
0306
0307 turns_analyser<turn_type, 1> analyser;
0308 analyse_each_turn(result, analyser, turns.begin(), turns.end(), strategy);
0309
0310 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
0311 return;
0312 }
0313
0314 if ( may_update<interior, interior, '2', true>(result)
0315 || may_update<interior, exterior, '2', true>(result)
0316 || may_update<boundary, interior, '1', true>(result)
0317 || may_update<boundary, exterior, '1', true>(result)
0318 || may_update<exterior, interior, '2', true>(result) )
0319 {
0320
0321
0322 uncertain_rings_analyser<1, Result, Geometry2, Geometry1, Strategy>
0323 rings_analyser(result, geometry2, geometry1, strategy);
0324 analyse_uncertain_rings<1>::apply(rings_analyser, turns.begin(), turns.end());
0325
0326
0327
0328 }
0329 }
0330 }
0331
0332
0333
0334 template <typename Result>
0335 class interrupt_policy_areal_areal
0336 {
0337 public:
0338 static bool const enabled = true;
0339
0340 interrupt_policy_areal_areal(Geometry1 const& geometry1,
0341 Geometry2 const& geometry2,
0342 Result & result)
0343 : m_result(result)
0344 , m_geometry1(geometry1)
0345 , m_geometry2(geometry2)
0346 {}
0347
0348 template <typename Range>
0349 inline bool apply(Range const& turns)
0350 {
0351 for (auto it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
0352 {
0353 per_turn<0>(*it);
0354 per_turn<1>(*it);
0355 }
0356
0357 return m_result.interrupt;
0358 }
0359
0360 private:
0361 template <std::size_t OpId, typename Turn>
0362 inline void per_turn(Turn const& turn)
0363 {
0364
0365 static const bool transpose_result = OpId != 0;
0366
0367 overlay::operation_type const op = turn.operations[OpId].operation;
0368
0369 if ( op == overlay::operation_union )
0370 {
0371
0372
0373
0374
0375
0376
0377
0378 update<boundary, boundary, '0', transpose_result>(m_result);
0379 }
0380 else if ( op == overlay::operation_intersection )
0381 {
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392 update<boundary, boundary, '0', transpose_result>(m_result);
0393 }
0394 else if ( op == overlay::operation_continue )
0395 {
0396 update<boundary, boundary, '1', transpose_result>(m_result);
0397 update<interior, interior, '2', transpose_result>(m_result);
0398 }
0399 else if ( op == overlay::operation_blocked )
0400 {
0401 update<boundary, boundary, '1', transpose_result>(m_result);
0402 update<interior, exterior, '2', transpose_result>(m_result);
0403 }
0404 }
0405
0406 Result & m_result;
0407 Geometry1 const& m_geometry1;
0408 Geometry2 const& m_geometry2;
0409 };
0410
0411
0412
0413 template <typename TurnInfo, std::size_t OpId>
0414 class turns_analyser
0415 {
0416 typedef typename TurnInfo::point_type turn_point_type;
0417
0418 static const std::size_t op_id = OpId;
0419 static const std::size_t other_op_id = (OpId + 1) % 2;
0420 static const bool transpose_result = OpId != 0;
0421
0422 public:
0423 turns_analyser()
0424 : m_previous_turn_ptr(0)
0425 , m_previous_operation(overlay::operation_none)
0426 , m_enter_detected(false)
0427 , m_exit_detected(false)
0428 {}
0429
0430 template <typename Result, typename TurnIt, typename EqPPStrategy>
0431 void apply(Result & result, TurnIt it, EqPPStrategy const& strategy)
0432 {
0433
0434
0435 overlay::operation_type const op = it->operations[op_id].operation;
0436
0437 if ( op != overlay::operation_union
0438 && op != overlay::operation_intersection
0439 && op != overlay::operation_blocked
0440 && op != overlay::operation_continue )
0441 {
0442 return;
0443 }
0444
0445 segment_identifier const& seg_id = it->operations[op_id].seg_id;
0446
0447
0448 const bool first_in_range = m_seg_watcher.update(seg_id);
0449
0450 if ( m_previous_turn_ptr )
0451 {
0452 if ( m_exit_detected )
0453 {
0454
0455 if ( first_in_range
0456 || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) )
0457 {
0458 update_exit(result);
0459 m_exit_detected = false;
0460 }
0461
0462 else if ( op != overlay::operation_union )
0463 {
0464 m_exit_detected = false;
0465 }
0466 }
0467
0468 if ( m_enter_detected )
0469 {
0470
0471 if ( first_in_range
0472 || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) )
0473 {
0474 update_enter(result);
0475 m_enter_detected = false;
0476 }
0477
0478 else if ( op != overlay::operation_intersection )
0479 {
0480 m_enter_detected = false;
0481 }
0482 }
0483 }
0484
0485 if ( op == overlay::operation_union )
0486 {
0487
0488
0489
0490
0491
0492 {
0493 m_exit_detected = true;
0494 }
0495 }
0496 else if ( op == overlay::operation_intersection )
0497 {
0498
0499 if ( it->operations[other_op_id].operation != overlay::operation_intersection )
0500 {
0501
0502
0503
0504
0505
0506
0507 m_enter_detected = true;
0508 }
0509 }
0510 else if ( op == overlay::operation_blocked )
0511 {
0512
0513 }
0514 else
0515 {
0516
0517 }
0518
0519
0520 m_previous_turn_ptr = boost::addressof(*it);
0521
0522 m_previous_operation = op;
0523 }
0524
0525
0526 template <typename Result>
0527 void apply(Result & result)
0528 {
0529
0530
0531 if ( m_exit_detected )
0532 {
0533 update_exit(result);
0534 m_exit_detected = false;
0535 }
0536
0537 if ( m_enter_detected )
0538 {
0539 update_enter(result);
0540 m_enter_detected = false;
0541 }
0542 }
0543
0544 template <typename Result>
0545 static inline void update_exit(Result & result)
0546 {
0547 update<interior, exterior, '2', transpose_result>(result);
0548 update<boundary, exterior, '1', transpose_result>(result);
0549 }
0550
0551 template <typename Result>
0552 static inline void update_enter(Result & result)
0553 {
0554 update<interior, interior, '2', transpose_result>(result);
0555 update<boundary, interior, '1', transpose_result>(result);
0556 update<exterior, interior, '2', transpose_result>(result);
0557 }
0558
0559 private:
0560 segment_watcher<same_ring> m_seg_watcher;
0561 TurnInfo * m_previous_turn_ptr;
0562 overlay::operation_type m_previous_operation;
0563 bool m_enter_detected;
0564 bool m_exit_detected;
0565 };
0566
0567
0568
0569 template
0570 <
0571 typename Result,
0572 typename Analyser,
0573 typename TurnIt,
0574 typename EqPPStrategy
0575 >
0576 static inline void analyse_each_turn(Result & res,
0577 Analyser & analyser,
0578 TurnIt first, TurnIt last,
0579 EqPPStrategy const& strategy)
0580 {
0581 if ( first == last )
0582 return;
0583
0584 for ( TurnIt it = first ; it != last ; ++it )
0585 {
0586 analyser.apply(res, it, strategy);
0587
0588 if ( BOOST_GEOMETRY_CONDITION(res.interrupt) )
0589 return;
0590 }
0591
0592 analyser.apply(res);
0593 }
0594
0595 template
0596 <
0597 std::size_t OpId,
0598 typename Result,
0599 typename Geometry,
0600 typename OtherGeometry,
0601 typename PointInArealStrategy
0602 >
0603 class uncertain_rings_analyser
0604 {
0605 static const bool transpose_result = OpId != 0;
0606 static const int other_id = (OpId + 1) % 2;
0607
0608 public:
0609 inline uncertain_rings_analyser(Result & result,
0610 Geometry const& geom,
0611 OtherGeometry const& other_geom,
0612 PointInArealStrategy const& point_in_areal_strategy)
0613 : geometry(geom)
0614 , other_geometry(other_geom)
0615 , interrupt(result.interrupt)
0616 , m_result(result)
0617 , m_point_in_areal_strategy(point_in_areal_strategy)
0618 , m_flags(0)
0619 {
0620
0621
0622
0623 if ( ! may_update<interior, interior, '2', transpose_result>(m_result) )
0624 {
0625 m_flags |= 1;
0626 }
0627
0628 if ( ! may_update<interior, exterior, '2', transpose_result>(m_result)
0629 && ! may_update<boundary, exterior, '1', transpose_result>(m_result) )
0630 {
0631 m_flags |= 2;
0632 }
0633
0634 if ( ! may_update<boundary, interior, '1', transpose_result>(m_result)
0635 && ! may_update<exterior, interior, '2', transpose_result>(m_result) )
0636 {
0637 m_flags |= 4;
0638 }
0639 }
0640
0641 inline void no_turns(segment_identifier const& seg_id)
0642 {
0643
0644 if ( m_flags == 7 )
0645 {
0646 return;
0647 }
0648
0649 auto const& sub_range = detail::sub_range(geometry, seg_id);
0650
0651 if ( boost::empty(sub_range) )
0652 {
0653
0654 return;
0655 }
0656
0657
0658
0659
0660
0661
0662
0663 using detail::within::point_in_geometry;
0664 int const pig = point_in_geometry(range::front(sub_range),
0665 other_geometry,
0666 m_point_in_areal_strategy);
0667
0668
0669 if ( pig > 0 )
0670 {
0671 update<interior, interior, '2', transpose_result>(m_result);
0672 m_flags |= 1;
0673
0674 update<boundary, interior, '1', transpose_result>(m_result);
0675 update<exterior, interior, '2', transpose_result>(m_result);
0676 m_flags |= 4;
0677 }
0678 else
0679 {
0680 update<boundary, exterior, '1', transpose_result>(m_result);
0681 update<interior, exterior, '2', transpose_result>(m_result);
0682 m_flags |= 2;
0683 }
0684
0685
0686
0687
0688
0689
0690
0691
0692 interrupt = m_flags == 7 || m_result.interrupt;
0693 }
0694
0695 template <typename TurnIt>
0696 inline void turns(TurnIt first, TurnIt last)
0697 {
0698
0699 if ( (m_flags & 6) == 6 )
0700 {
0701 return;
0702 }
0703
0704 bool found_ii = false;
0705 bool found_uu = false;
0706
0707 for ( TurnIt it = first ; it != last ; ++it )
0708 {
0709 if ( it->operations[0].operation == overlay::operation_intersection
0710 && it->operations[1].operation == overlay::operation_intersection )
0711 {
0712 found_ii = true;
0713 }
0714 else if ( it->operations[0].operation == overlay::operation_union
0715 && it->operations[1].operation == overlay::operation_union )
0716 {
0717 found_uu = true;
0718 }
0719 else
0720 {
0721 return;
0722 }
0723 }
0724
0725
0726 if ( found_ii )
0727 {
0728 update<interior, interior, '2', transpose_result>(m_result);
0729 m_flags |= 1;
0730
0731
0732
0733 update<boundary, interior, '1', transpose_result>(m_result);
0734 update<exterior, interior, '2', transpose_result>(m_result);
0735 m_flags |= 4;
0736 }
0737
0738
0739 if ( found_uu )
0740 {
0741 update<boundary, exterior, '1', transpose_result>(m_result);
0742 update<interior, exterior, '2', transpose_result>(m_result);
0743 m_flags |= 2;
0744 }
0745
0746 interrupt = m_flags == 7 || m_result.interrupt;
0747 }
0748
0749 Geometry const& geometry;
0750 OtherGeometry const& other_geometry;
0751 bool interrupt;
0752
0753 private:
0754 Result & m_result;
0755 PointInArealStrategy const& m_point_in_areal_strategy;
0756 int m_flags;
0757 };
0758
0759 template <std::size_t OpId>
0760 class analyse_uncertain_rings
0761 {
0762 public:
0763 template <typename Analyser, typename TurnIt>
0764 static inline void apply(Analyser & analyser, TurnIt first, TurnIt last)
0765 {
0766 if ( first == last )
0767 return;
0768
0769 for_preceding_rings(analyser, *first);
0770
0771
0772 TurnIt prev = first;
0773 for ( ++first ; first != last ; ++first, ++prev )
0774 {
0775
0776 if ( prev->operations[OpId].seg_id.multi_index
0777 == first->operations[OpId].seg_id.multi_index )
0778 {
0779
0780 if ( prev->operations[OpId].seg_id.ring_index
0781 == first->operations[OpId].seg_id.ring_index )
0782 {
0783
0784 }
0785
0786 else
0787 {
0788
0789 analyser.turns(prev, first);
0790
0791
0792
0793 {
0794 for_no_turns_rings(analyser,
0795 *first,
0796 prev->operations[OpId].seg_id.ring_index + 1,
0797 first->operations[OpId].seg_id.ring_index);
0798 }
0799
0800
0801 }
0802 }
0803
0804 else
0805 {
0806
0807 analyser.turns(prev, first);
0808 for_following_rings(analyser, *prev);
0809 for_preceding_rings(analyser, *first);
0810
0811 }
0812
0813 if ( analyser.interrupt )
0814 {
0815 return;
0816 }
0817 }
0818
0819
0820 analyser.turns(prev, first);
0821 for_following_rings(analyser, *prev);
0822 }
0823
0824 private:
0825 template <typename Analyser, typename Turn>
0826 static inline void for_preceding_rings(Analyser & analyser, Turn const& turn)
0827 {
0828 segment_identifier const& seg_id = turn.operations[OpId].seg_id;
0829
0830 for_no_turns_rings(analyser, turn, -1, seg_id.ring_index);
0831 }
0832
0833 template <typename Analyser, typename Turn>
0834 static inline void for_following_rings(Analyser & analyser, Turn const& turn)
0835 {
0836 segment_identifier const& seg_id = turn.operations[OpId].seg_id;
0837
0838 signed_size_type
0839 count = boost::numeric_cast<signed_size_type>(
0840 geometry::num_interior_rings(
0841 detail::single_geometry(analyser.geometry, seg_id)));
0842
0843 for_no_turns_rings(analyser, turn, seg_id.ring_index + 1, count);
0844 }
0845
0846 template <typename Analyser, typename Turn>
0847 static inline void for_no_turns_rings(Analyser & analyser,
0848 Turn const& turn,
0849 signed_size_type first,
0850 signed_size_type last)
0851 {
0852 segment_identifier seg_id = turn.operations[OpId].seg_id;
0853
0854 for ( seg_id.ring_index = first ; seg_id.ring_index < last ; ++seg_id.ring_index )
0855 {
0856 analyser.no_turns(seg_id);
0857 }
0858 }
0859 };
0860 };
0861
0862 }}
0863 #endif
0864
0865 }}
0866
0867 #endif