Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:30:39

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