Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:35:13

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2015-2016 Barend Gehrels, Amsterdam, the Netherlands.
0004 
0005 // This file was modified by Oracle on 2018-2020.
0006 // Modifications copyright (c) 2018-2020 Oracle and/or its affiliates.
0007 
0008 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0009 
0010 // Use, modification and distribution is subject to the Boost Software License,
0011 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0012 // http://www.boost.org/LICENSE_1_0.txt)
0013 
0014 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP
0015 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP
0016 
0017 #include <boost/range/value_type.hpp>
0018 
0019 #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
0020 #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
0021 #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
0022 #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
0023 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
0024 
0025 #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
0026 #include <boost/geometry/core/access.hpp>
0027 #endif
0028 
0029 #include <boost/geometry/util/condition.hpp>
0030 
0031 #include <cstddef>
0032 #include <map>
0033 
0034 namespace boost { namespace geometry
0035 {
0036 
0037 #ifndef DOXYGEN_NO_DETAIL
0038 namespace detail { namespace overlay
0039 {
0040 
0041 // The switch detector, the first phase in traversal, inspects UU and II turns.
0042 // Suppose you have these two polygons in a union. There is one UU turn.
0043 // +-------+
0044 // |       |
0045 // |   A   |
0046 // |       |
0047 // +-------U---------+       U = UU turn
0048 //         |         |
0049 //         |    B    |
0050 //         |         |
0051 //         +---------+
0052 // It first assigns region ids, A gets id 1 and B gets id 2.
0053 // Because of that, it should NOT switch sources in traversal at U.
0054 // So coming from upper left, it follows A, and also at U it keeps following A.
0055 // The result is two rings. (See for example testcase "case_31" or others.)
0056 //
0057 // But suppose you have two larger input polygons, partially overlapping:
0058 // +-----------------+
0059 // |                 |
0060 // |   A   +-----T---C       I = interior in output
0061 // |       |  I  | O |       O = overlap A & B (included in output)
0062 // +-------U-----T---C       U = UU turn
0063 //         |         |       T = normal turn (u/i)
0064 //         |    B    |       C = collinear turn (c/c)
0065 //         |         |
0066 //         +---------+
0067 // Rings A and B will be connected (by inspecting turn information)
0068 // and there will be one region 1.
0069 // Because of that, it will switch sources in traversal at U.
0070 // So coming from lower right, it follows B but at U it will switch to A.
0071 // Also for the generated interior ring, coming from the top via A it will at U
0072 // switch to B and go to the right, generating I. (See for example "case_91")
0073 // Switching using region_id is only relevant for UU or II turns.
0074 // In all T turns it will follow "u" for union or "i" for intersection,
0075 // and in C turns it will follow either direction (they are the same).
0076 // There is also "isolated", making it more complex, and documented below.
0077 template
0078 <
0079     bool Reverse1,
0080     bool Reverse2,
0081     overlay_type OverlayType,
0082     typename Geometry1,
0083     typename Geometry2,
0084     typename Turns,
0085     typename Clusters,
0086     typename RobustPolicy,
0087     typename Visitor
0088 >
0089 struct traversal_switch_detector
0090 {
0091     static const operation_type target_operation
0092             = operation_from_overlay<OverlayType>::value;
0093 
0094     enum isolation_type
0095     {
0096         isolation_no = 0,
0097         isolation_yes = 1,
0098         isolation_multiple = 2
0099     };
0100 
0101     using turn_type = typename boost::range_value<Turns>::type;
0102     using set_type= std::set<signed_size_type>;
0103 
0104     // Per ring, first turns are collected (in turn_indices), and later
0105     // a region_id is assigned
0106     struct merged_ring_properties
0107     {
0108         signed_size_type region_id = -1;
0109         set_type turn_indices;
0110     };
0111 
0112     struct connection_properties
0113     {
0114         std::size_t count = 0;
0115         // Set with turn-index OR (if clustered) the negative cluster_id
0116         set_type unique_turn_ids;
0117     };
0118 
0119     // Maps region_id -> properties
0120     using connection_map = std::map<signed_size_type, connection_properties>;
0121 
0122     // Per region, a set of properties is maintained, including its connections
0123     // to other regions
0124     struct region_properties
0125     {
0126         signed_size_type region_id = -1;
0127         isolation_type isolated = isolation_no;
0128         set_type unique_turn_ids;
0129         connection_map connected_region_counts;
0130     };
0131 
0132     // Maps ring -> properties
0133     using merge_map = std::map<ring_identifier, merged_ring_properties>;
0134 
0135     // Maps region_id -> properties
0136     using region_connection_map = std::map<signed_size_type, region_properties>;
0137 
0138     inline traversal_switch_detector(Geometry1 const& geometry1,
0139             Geometry2 const& geometry2,
0140             Turns& turns, Clusters const& clusters,
0141             RobustPolicy const& robust_policy, Visitor& visitor)
0142         : m_geometry1(geometry1)
0143         , m_geometry2(geometry2)
0144         , m_turns(turns)
0145         , m_clusters(clusters)
0146         , m_robust_policy(robust_policy)
0147         , m_visitor(visitor)
0148     {
0149     }
0150 
0151     bool one_connection_to_another_region(region_properties const& region) const
0152     {
0153         // For example:
0154         // +----------------------+
0155         // |                   __ |
0156         // |                  /  \|
0157         // |                 |    x
0158         // |                  \__/|
0159         // |                      |
0160         // +----------------------+
0161 
0162         if (region.connected_region_counts.size() == 1)
0163         {
0164             auto const& cprop = region.connected_region_counts.begin()->second;
0165             return cprop.count <= 1;
0166         }
0167         return region.connected_region_counts.empty();
0168     }
0169 
0170     // TODO: might be combined with previous
0171     bool multiple_connections_to_one_region(region_properties const& region) const
0172     {
0173         // For example:
0174         // +----------------------+
0175         // |                   __ |
0176         // |                  /  \|
0177         // |                 |    x
0178         // |                  \  /|
0179         // |                  /  \|
0180         // |                 |    x
0181         // |                  \__/|
0182         // |                      |
0183         // +----------------------+
0184 
0185         if (region.connected_region_counts.size() == 1)
0186         {
0187             auto const& cprop = region.connected_region_counts.begin()->second;
0188             return cprop.count > 1;
0189         }
0190         return false;
0191     }
0192 
0193     bool one_connection_to_multiple_regions(region_properties const& region) const
0194     {
0195         // For example:
0196         // +----------------------+
0197         // |                   __ | __
0198         // |                  /  \|/  |
0199         // |                 |    x   |
0200         // |                  \__/|\__|
0201         // |                      |
0202         // +----------------------+
0203 
0204         bool first = true;
0205         signed_size_type first_turn_id = 0;
0206         for (auto const& key_val : region.connected_region_counts)
0207         {
0208             auto const& cprop = key_val.second;
0209 
0210             if (cprop.count != 1)
0211             {
0212                 return false;
0213             }
0214             auto const unique_turn_id = *cprop.unique_turn_ids.begin();
0215             if (first)
0216             {
0217                 first_turn_id = unique_turn_id;
0218                 first = false;
0219             }
0220             else if (first_turn_id != unique_turn_id)
0221             {
0222                 return false;
0223             }
0224         }
0225         return true;
0226     }
0227 
0228     bool ii_turn_connects_two_regions(region_properties const& region,
0229             region_properties const& connected_region,
0230             signed_size_type turn_index) const
0231     {
0232         turn_type const& turn = m_turns[turn_index];
0233         if (! turn.both(operation_intersection))
0234         {
0235             return false;
0236         }
0237 
0238         signed_size_type const id0 = turn.operations[0].enriched.region_id;
0239         signed_size_type const id1 = turn.operations[1].enriched.region_id;
0240 
0241         return (id0 == region.region_id && id1 == connected_region.region_id)
0242             || (id1 == region.region_id && id0 == connected_region.region_id);
0243     }
0244 
0245 
0246     bool isolated_multiple_connection(region_properties const& region,
0247             region_properties const& connected_region) const
0248     {
0249         if (connected_region.isolated != isolation_multiple)
0250         {
0251             return false;
0252         }
0253 
0254         // First step: compare turns of regions with turns of connected region
0255         set_type turn_ids = region.unique_turn_ids;
0256         for (auto turn_id : connected_region.unique_turn_ids)
0257         {
0258             turn_ids.erase(turn_id);
0259         }
0260 
0261         // There should be one connection (turn or cluster) left
0262         if (turn_ids.size() != 1)
0263         {
0264             return false;
0265         }
0266 
0267         for (auto id_or_index : connected_region.unique_turn_ids)
0268         {
0269             if (id_or_index >= 0)
0270             {
0271                 if (! ii_turn_connects_two_regions(region, connected_region, id_or_index))
0272                 {
0273                     return false;
0274                 }
0275             }
0276             else
0277             {
0278                 signed_size_type const cluster_id = -id_or_index;
0279                 auto it = m_clusters.find(cluster_id);
0280                 if (it != m_clusters.end())
0281                 {
0282                     cluster_info const& cinfo = it->second;
0283                     for (auto turn_index : cinfo.turn_indices)
0284                     {
0285                         if (! ii_turn_connects_two_regions(region, connected_region, turn_index))
0286                         {
0287                             return false;
0288                         }
0289                     }
0290                 }
0291             }
0292         }
0293 
0294         return true;
0295     }
0296 
0297     bool has_only_isolated_children(region_properties const& region) const
0298     {
0299         bool first_with_turn = true;
0300         signed_size_type first_turn_id = 0;
0301 
0302         for (auto const& key_val : region.connected_region_counts)
0303         {
0304             signed_size_type const region_id = key_val.first;
0305             connection_properties const& cprop = key_val.second;
0306 
0307             auto mit = m_connected_regions.find(region_id);
0308             if (mit == m_connected_regions.end())
0309             {
0310                 // Should not occur
0311                 return false;
0312             }
0313 
0314             region_properties const& connected_region = mit->second;
0315 
0316             if (cprop.count != 1)
0317             {
0318                 // If there are more connections, check their isolation
0319                 if (! isolated_multiple_connection(region, connected_region))
0320                 {
0321                     return false;
0322                 }
0323             }
0324 
0325             if (connected_region.isolated != isolation_yes
0326                 && connected_region.isolated != isolation_multiple)
0327             {
0328                 signed_size_type const unique_turn_id = *cprop.unique_turn_ids.begin();
0329                 if (first_with_turn)
0330                 {
0331                     first_turn_id = unique_turn_id;
0332                     first_with_turn = false;
0333                 }
0334                 else if (first_turn_id != unique_turn_id)
0335                 {
0336                     return false;
0337                 }
0338             }
0339         }
0340 
0341         // If there is only one connection (with a 'parent'), and all other
0342         // connections are itself isolated, it is isolated
0343         return true;
0344     }
0345 
0346     void get_isolated_regions()
0347     {
0348         // First time: check regions isolated (one connection only),
0349         // semi-isolated (multiple connections between same region),
0350         // and complex isolated (connection with multiple rings but all
0351         // at same point)
0352         for (auto& key_val : m_connected_regions)
0353         {
0354             region_properties& properties = key_val.second;
0355             if (one_connection_to_another_region(properties))
0356             {
0357                 properties.isolated = isolation_yes;
0358             }
0359             else if (multiple_connections_to_one_region(properties))
0360             {
0361                 properties.isolated = isolation_multiple;
0362             }
0363             else if (one_connection_to_multiple_regions(properties))
0364             {
0365                 properties.isolated = isolation_yes;
0366             }
0367         }
0368 
0369         // Propagate isolation to next level
0370         // TODO: should be optimized
0371         std::size_t defensive_check = 0;
0372         bool changed = true;
0373         while (changed && defensive_check++ < m_connected_regions.size())
0374         {
0375             changed = false;
0376             for (auto& key_val : m_connected_regions)
0377             {
0378                 region_properties& properties = key_val.second;
0379 
0380                 if (properties.isolated == isolation_no
0381                         && has_only_isolated_children(properties))
0382                 {
0383                     properties.isolated = isolation_yes;
0384                     changed = true;
0385                 }
0386             }
0387         }
0388     }
0389 
0390     void assign_isolation_to_enriched()
0391     {
0392         for (turn_type& turn : m_turns)
0393         {
0394             // For difference, for the input walked through in reverse,
0395             // the meaning is reversed: what is isolated is actually not,
0396             // and vice versa.
0397             bool const reverseMeaningInTurn
0398                     = (Reverse1 || Reverse2)
0399                       && ! turn.is_self()
0400                       && ! turn.is_clustered()
0401                       && uu_or_ii(turn)
0402                       && turn.operations[0].enriched.region_id
0403                          != turn.operations[1].enriched.region_id;
0404 
0405             for (auto& op : turn.operations)
0406             {
0407                 auto mit = m_connected_regions.find(op.enriched.region_id);
0408                 if (mit != m_connected_regions.end())
0409                 {
0410                     bool const reverseMeaningInOp
0411                         = reverseMeaningInTurn
0412                           && ((op.seg_id.source_index == 0 && Reverse1)
0413                                || (op.seg_id.source_index == 1 && Reverse2));
0414 
0415                     // It is assigned to isolated if it's property is "Yes",
0416                     // (one connected interior, or chained).
0417                     // "Multiple" doesn't count for isolation,
0418                     // neither for intersection, neither for difference.
0419                     region_properties const& prop = mit->second;
0420                     op.enriched.isolated
0421                             = reverseMeaningInOp
0422                             ? false
0423                             : prop.isolated == isolation_yes;
0424                 }
0425             }
0426         }
0427     }
0428 
0429     void assign_region_ids_to_enriched()
0430     {
0431         for (auto const& key_val : m_turns_per_ring)
0432         {
0433             ring_identifier const& ring_id = key_val.first;
0434             merged_ring_properties const& properties = key_val.second;
0435 
0436             for (auto turn_index : properties.turn_indices)
0437             {
0438                 turn_type& turn = m_turns[turn_index];
0439 
0440                 if (! acceptable(turn))
0441                 {
0442                     // No assignment necessary
0443                     continue;
0444                 }
0445 
0446                 for (auto& op : turn.operations)
0447                 {
0448                     if (ring_id_by_seg_id(op.seg_id) == ring_id)
0449                     {
0450                         op.enriched.region_id = properties.region_id;
0451                     }
0452                 }
0453             }
0454         }
0455     }
0456 
0457     void assign_connected_regions()
0458     {
0459         for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
0460         {
0461             turn_type const& turn = m_turns[turn_index];
0462 
0463             signed_size_type const unique_turn_id
0464                     = turn.is_clustered() ? -turn.cluster_id : turn_index;
0465 
0466             signed_size_type const& id0 = turn.operations[0].enriched.region_id;
0467             signed_size_type const& id1 = turn.operations[1].enriched.region_id;
0468 
0469             // Add region (by assigning) and add involved turns
0470             if (id0 != -1)
0471             {
0472                 m_connected_regions[id0].region_id = id0;
0473                 m_connected_regions[id0].unique_turn_ids.insert(unique_turn_id);
0474             }
0475             if (id1 != -1 && id0 != id1)
0476             {
0477                 m_connected_regions[id1].region_id = id1;
0478                 m_connected_regions[id1].unique_turn_ids.insert(unique_turn_id);
0479             }
0480 
0481             if (id0 != id1 && id0 != -1 && id1 != -1)
0482             {
0483                 // Assign connections
0484                 connection_properties& prop0 = m_connected_regions[id0].connected_region_counts[id1];
0485                 connection_properties& prop1 = m_connected_regions[id1].connected_region_counts[id0];
0486 
0487                 // Reference this turn or cluster to later check uniqueness on ring
0488                 if (prop0.unique_turn_ids.count(unique_turn_id) == 0)
0489                 {
0490                     prop0.count++;
0491                     prop0.unique_turn_ids.insert(unique_turn_id);
0492                 }
0493                 if (prop1.unique_turn_ids.count(unique_turn_id) == 0)
0494                 {
0495                     prop1.count++;
0496                     prop1.unique_turn_ids.insert(unique_turn_id);
0497                 }
0498             }
0499         }
0500     }
0501 
0502     inline bool acceptable(turn_type const& turn) const
0503     {
0504         // Discarded turns don't connect rings to the same region
0505         // Also xx are not relevant
0506         // (otherwise discarded colocated uu turn could make a connection)
0507         return ! turn.discarded && ! turn.both(operation_blocked);
0508     }
0509 
0510     inline bool uu_or_ii(turn_type const& turn) const
0511     {
0512         return turn.both(operation_union) || turn.both(operation_intersection);
0513     }
0514 
0515     inline bool connects_same_region(turn_type const& turn) const
0516     {
0517         if (! acceptable(turn))
0518         {
0519             return false;
0520         }
0521 
0522         if (! turn.is_clustered())
0523         {
0524             // If it is a uu/ii-turn (non clustered), it is never same region
0525             return ! uu_or_ii(turn);
0526         }
0527 
0528         if (BOOST_GEOMETRY_CONDITION(target_operation == operation_union))
0529         {
0530             // It is a cluster, check zones
0531             // (assigned by sort_by_side/handle colocations) of both operations
0532             return turn.operations[0].enriched.zone
0533                     == turn.operations[1].enriched.zone;
0534         }
0535 
0536         // For an intersection, two regions connect if they are not ii
0537         // (ii-regions are isolated) or, in some cases, not iu (for example
0538         // when a multi-polygon is inside an interior ring and connecting it)
0539         return ! (turn.both(operation_intersection)
0540                   || turn.combination(operation_intersection, operation_union));
0541     }
0542 
0543     void create_region(signed_size_type& new_region_id, ring_identifier const& ring_id,
0544                 merged_ring_properties& properties, signed_size_type region_id = -1)
0545     {
0546         if (properties.region_id > 0)
0547         {
0548             // Already handled
0549             return;
0550         }
0551 
0552         // Assign new id if this is a new region
0553         if (region_id == -1)
0554         {
0555             region_id = new_region_id++;
0556         }
0557 
0558         // Assign this ring to specified region
0559         properties.region_id = region_id;
0560 
0561 #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
0562         std::cout << " ADD " << ring_id << " TO REGION " << region_id << std::endl;
0563 #endif
0564 
0565         // Find connecting rings, recursively
0566         for (auto turn_index : properties.turn_indices)
0567         {
0568             turn_type const& turn = m_turns[turn_index];
0569             if (! connects_same_region(turn))
0570             {
0571                 // This is a non clustered uu/ii-turn, or a cluster connecting different 'zones'
0572                 continue;
0573             }
0574 
0575             // Union: This turn connects two rings (interior connected), create the region
0576             // Intersection: This turn connects two rings, set same regions for these two rings
0577             for (auto const& op : turn.operations)
0578             {
0579                 ring_identifier connected_ring_id = ring_id_by_seg_id(op.seg_id);
0580                 if (connected_ring_id != ring_id)
0581                 {
0582                     propagate_region(new_region_id, connected_ring_id, region_id);
0583                 }
0584             }
0585         }
0586     }
0587 
0588     void propagate_region(signed_size_type& new_region_id,
0589             ring_identifier const& ring_id, signed_size_type region_id)
0590     {
0591         auto it = m_turns_per_ring.find(ring_id);
0592         if (it != m_turns_per_ring.end())
0593         {
0594             create_region(new_region_id, ring_id, it->second, region_id);
0595         }
0596     }
0597 
0598 #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
0599     void debug_show_results()
0600     {
0601         auto isolation_to_string = [](isolation_type const& iso) -> std::string
0602         {
0603             switch(iso)
0604             {
0605                 case isolation_no : return "no";
0606                 case isolation_yes : return "yes";
0607                 case isolation_multiple : return "multiple";
0608             }
0609             return "error";
0610         };
0611         auto set_to_string = [](auto const& s) -> std::string
0612         {
0613             std::ostringstream result;
0614             for (auto item : s) { result << " " << item; }
0615             return result.str();
0616         };
0617 
0618         for (auto const& kv : m_connected_regions)
0619         {
0620             auto const& prop = kv.second;
0621 
0622             std::ostringstream sub;
0623             sub << "[turns" << set_to_string(prop.unique_turn_ids)
0624                 << "] regions";
0625             for (auto const& kvs : prop.connected_region_counts)
0626             {
0627                 sub << " { " << kvs.first
0628                     << " : via [" << set_to_string(kvs.second.unique_turn_ids)
0629                     << " ] }";
0630             }
0631 
0632             std::cout << "REGION " << prop.region_id
0633                       << " " << isolation_to_string(prop.isolated)
0634                       << " " << sub.str()
0635                       << std::endl;
0636         }
0637 
0638         for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
0639         {
0640             turn_type const& turn = m_turns[turn_index];
0641 
0642             if (uu_or_ii(turn) && ! turn.is_clustered())
0643             {
0644                 std::cout << (turn.both(operation_union) ? "UU" : "II")
0645                           << " " << turn_index
0646                           << " (" << geometry::get<0>(turn.point)
0647                           << ", " << geometry::get<1>(turn.point) << ")"
0648                           << " -> " << std::boolalpha
0649                           << " [" << turn.operations[0].seg_id.source_index
0650                           << "/" << turn.operations[1].seg_id.source_index << "] "
0651                           << "(" << turn.operations[0].enriched.region_id
0652                           << " " << turn.operations[0].enriched.isolated
0653                           << ") / (" << turn.operations[1].enriched.region_id
0654                           << " " << turn.operations[1].enriched.isolated << ")"
0655                           << std::endl;
0656             }
0657         }
0658 
0659         for (auto const& key_val : m_clusters)
0660         {
0661             cluster_info const& cinfo = key_val.second;
0662             std::cout << "CL RESULT " << key_val.first
0663                          << " -> " << cinfo.open_count << std::endl;
0664         }
0665     }
0666 #endif
0667 
0668     void iterate()
0669     {
0670 #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
0671         std::cout << "BEGIN SWITCH DETECTOR (region_ids and isolation)"
0672                   << (Reverse1 ? " REVERSE_1" : "")
0673                   << (Reverse2 ? " REVERSE_2" : "")
0674                   << std::endl;
0675 #endif
0676 
0677         // Collect turns per ring
0678         m_turns_per_ring.clear();
0679         m_connected_regions.clear();
0680 
0681         for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
0682         {
0683             turn_type const& turn = m_turns[turn_index];
0684 
0685             if (turn.discarded
0686                 && BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection))
0687             {
0688                 // Discarded turn (union currently still needs it to determine regions)
0689                 continue;
0690             }
0691 
0692             for (auto const& op : turn.operations)
0693             {
0694                 m_turns_per_ring[ring_id_by_seg_id(op.seg_id)].turn_indices.insert(turn_index);
0695             }
0696         }
0697 
0698         // All rings having turns are in turns/ring map. Process them.
0699         {
0700             signed_size_type new_region_id = 1;
0701             for (auto& key_val : m_turns_per_ring)
0702             {
0703                 create_region(new_region_id, key_val.first, key_val.second);
0704             }
0705 
0706             assign_region_ids_to_enriched();
0707             assign_connected_regions();
0708             get_isolated_regions();
0709             assign_isolation_to_enriched();
0710         }
0711 
0712 #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
0713         std::cout << "END SWITCH DETECTOR" << std::endl;
0714         debug_show_results();
0715 #endif
0716 
0717     }
0718 
0719 private:
0720 
0721     Geometry1 const& m_geometry1;
0722     Geometry2 const& m_geometry2;
0723     Turns& m_turns;
0724     Clusters const& m_clusters;
0725     merge_map m_turns_per_ring;
0726     region_connection_map m_connected_regions;
0727     RobustPolicy const& m_robust_policy;
0728     Visitor& m_visitor;
0729 };
0730 
0731 }} // namespace detail::overlay
0732 #endif // DOXYGEN_NO_DETAIL
0733 
0734 }} // namespace boost::geometry
0735 
0736 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP