// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2017 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { inline bool check_pairs(std::vector const& aggregation, signed_size_type incoming_region_id, std::size_t first, std::size_t last) { // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy for (std::size_t i = first; i <= last; i += 2) { sort_by_side::rank_with_rings const& curr = aggregation[i]; sort_by_side::rank_with_rings const& next = aggregation[i + 1]; signed_size_type const curr_id = curr.region_id(); signed_size_type const next_id = next.region_id(); bool const possible = curr.rings.size() == 2 && curr.is_isolated() && curr.has_unique_region_id() && next.rings.size() == 2 && next.is_isolated() && next.has_unique_region_id() && curr_id == next_id && curr_id != incoming_region_id; if (! possible) { return false; } } return true; } inline bool intersection_pattern_common_interior1(std::size_t& selected_rank, std::vector const& aggregation) { // Pattern: coming from exterior ring, encountering an isolated // parallel interior ring, which should be skipped, and the first // left (normally intersection takes first right) should be taken. // Solves cases #case_133_multi // and #case_recursive_boxes_49 std::size_t const n = aggregation.size(); if (n < 4) { return false; } sort_by_side::rank_with_rings const& incoming = aggregation.front(); sort_by_side::rank_with_rings const& outgoing = aggregation.back(); bool const incoming_ok = incoming.all_from() && incoming.rings.size() == 1 && incoming.has_only(operation_intersection); if (! incoming_ok) { return false; } bool const outgoing_ok = outgoing.all_to() && outgoing.rings.size() == 1 && outgoing.has_only(operation_intersection) && outgoing.region_id() == incoming.region_id(); if (! outgoing_ok) { return false; } if (check_pairs(aggregation, incoming.region_id(), 1, n - 2)) { selected_rank = n - 1; return true; } return false; } inline bool intersection_pattern_common_interior2(std::size_t& selected_rank, std::vector const& aggregation) { // Pattern: coming from two exterior rings, encountering two isolated // equal interior rings // See (for example, for ii) #case_recursive_boxes_53: // INCOMING: // Rank 0 {11[0] (s:0, m:0) i F rgn: 1 ISO} {13[1] (s:1, m:0) i F rgn: 1 ISO} // PAIR: // Rank 1 {13[0] (s:0, r:1, m:0) i T rgn: 3 ISO ->16} {11[1] (s:1, r:5, m:0) i T rgn: 3 ISO ->16} // Rank 2 {13[0] (s:0, r:1, m:0) i F rgn: 3 ISO} {11[1] (s:1, r:5, m:0) i F rgn: 3 ISO} // LEAVING (in the same direction, take last one) // Rank 3 {11[0] (s:0, m:0) i T rgn: 1 ISO ->10} {13[1] (s:1, m:0) i T rgn: 1 ISO ->10} std::size_t const n = aggregation.size(); if (n < 4) { return false; } sort_by_side::rank_with_rings const& incoming = aggregation.front(); sort_by_side::rank_with_rings const& outgoing = aggregation.back(); bool const incoming_ok = incoming.all_from() && incoming.rings.size() == 2 && incoming.has_unique_region_id(); if (! incoming_ok) { return false; } bool const outgoing_ok = outgoing.all_to() && outgoing.rings.size() == 2 && outgoing.has_unique_region_id() && outgoing.region_id() == incoming.region_id(); if (! outgoing_ok) { return false; } bool const operation_ok = (incoming.has_only(operation_continue) && outgoing.has_only(operation_continue)) || (incoming.has_only(operation_intersection) && outgoing.has_only(operation_intersection)); if (! operation_ok) { return false; } // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy if (check_pairs(aggregation, incoming.region_id(), 1, n - 2)) { selected_rank = n - 1; return true; } return false; } inline bool intersection_pattern_common_interior3(std::size_t& selected_rank, std::vector const& aggregation) { // Pattern: approaches colocated turn (exterior+interior) from two // different directions, and both leaves in the same direction // See #case_136_multi: // INCOMING: //Rank 0 {10[0] (s:0, m:0) c F rgn: 1 ISO} // PAIR: //Rank 1 {14[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->16} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->16} //Rank 2 {14[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO} // LEAVING (select this one): //Rank 3 {10[0] (s:0, m:0) c T rgn: 1 ISO ->12} {10[1] (s:1, m:0) c T rgn: 1 ISO ->12} // ADDITIONALLY: (other polygon coming in) //Rank 4 {10[1] (s:1, m:0) c F rgn: 1 ISO} std::size_t const n = aggregation.size(); if (n < 4) { return false; } sort_by_side::rank_with_rings const& incoming = aggregation.front(); sort_by_side::rank_with_rings const& outgoing = aggregation[n - 2]; sort_by_side::rank_with_rings const& last = aggregation.back(); bool const incoming_ok = incoming.all_from() && incoming.rings.size() == 1 && incoming.has_only(operation_continue); if (! incoming_ok) { return false; } bool const outgoing_ok = outgoing.all_to() && outgoing.rings.size() == 2 && outgoing.has_only(operation_continue) && outgoing.has_unique_region_id() && outgoing.region_id() == incoming.region_id() && last.all_from() && last.rings.size() == 1 && last.region_id() == incoming.region_id() && last.all_from(); if (! outgoing_ok) { return false; } // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy if (check_pairs(aggregation, incoming.region_id(), 1, n - 3)) { selected_rank = n - 2; return true; } return false; } inline bool intersection_pattern_common_interior4(std::size_t& selected_rank, std::vector const& aggregation) { // Pattern: approaches colocated turn (exterior+interior) from same // direction, but leaves in two different directions // See #case_137_multi: // INCOMING: //Rank 0 {11[0] (s:0, m:0) i F rgn: 1 ISO} {10[1] (s:1, m:0) i F rgn: 1 ISO} // PAIR: //Rank 1 {13[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->15} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->15} //Rank 2 {13[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO} // LEAVING (in two different directions, take penultimate one) //Rank 3 {10[1] (s:1, m:0) i T rgn: 1 ISO ->0} //Rank 4 {11[0] (s:0, m:0) i T rgn: 1 ISO ->12} std::size_t const n = aggregation.size(); if (n < 4) { return false; } sort_by_side::rank_with_rings const& incoming = aggregation.front(); sort_by_side::rank_with_rings const& extra = aggregation[n - 2]; sort_by_side::rank_with_rings const& outgoing = aggregation.back(); bool const incoming_ok = incoming.all_from() && incoming.rings.size() == 2 && incoming.has_unique_region_id() && incoming.has_only(operation_intersection); if (! incoming_ok) { return false; } bool const outgoing_ok = outgoing.all_to() && outgoing.rings.size() == 1 && outgoing.has_only(operation_intersection) && outgoing.region_id() == incoming.region_id() && extra.all_to() && extra.rings.size() == 1 && extra.has_only(operation_intersection) && extra.region_id() == incoming.region_id(); if (! outgoing_ok) { return false; } // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy if (check_pairs(aggregation, incoming.region_id(), 1, n - 3)) { selected_rank = n - 2; return true; } return false; } inline bool intersection_pattern_common_interior5(std::size_t& selected_rank, std::vector const& aggregation) { // Pattern: isolated regions // See #case_recursive_boxes_65 // INCOMING: // Rank 0 {19[0] (s:0, r:2, m:0) i F rgn: 4 ISO} // Rank 1 {19[1] (s:1, m:0) i T rgn: 1 ISO FIN ->18 (2.5)} // Rank 2 {21[1] (s:1, m:2) i F rgn: 1 ISO} // Rank 3 {21[1] (s:1, m:2) i T rgn: 1 ISO ->17 (2)} // Rank 4 {19[1] (s:1, m:0) i F rgn: 1 ISO FIN} // LEAVING (take this one): // Rank 5 {19[0] (s:0, r:2, m:0) i T rgn: 4 ISO ->22 (1)} std::size_t const n = aggregation.size(); if (n < 3) { return false; } sort_by_side::rank_with_rings const& incoming = aggregation.front(); sort_by_side::rank_with_rings const& outgoing = aggregation.back(); bool const incoming_ok = incoming.all_from() && incoming.has_unique_region_id() && incoming.is_isolated(); if (! incoming_ok) { return false; } signed_size_type const incoming_region_id = incoming.region_id(); bool const outgoing_ok = outgoing.all_to() && outgoing.has_unique_region_id() && outgoing.is_isolated() && outgoing.region_id() == incoming_region_id; if (! outgoing_ok) { return false; } selected_rank = n - 1; bool other_region = true; // Assumed is that other regions go (T) and come back (F) for (std::size_t i = 1; i < n - 1; i++) { sort_by_side::rank_with_rings const& rwr = aggregation[i]; if (! rwr.has_unique_region_id() || ! rwr.is_isolated()) { return false; } signed_size_type const region_id = rwr.region_id(); if (other_region && region_id != incoming_region_id) { // OK } else if (other_region && region_id == incoming_region_id) { // OK, next phase (same region as incoming region) selected_rank = i; other_region = false; } else if (! other_region && region_id != incoming_region_id) { // After that the region is the same is incoming, it should // stay like that return false; } } return true; } inline bool intersection_pattern_common_interior6(std::size_t& selected_rank, std::vector const& aggregation) { // Pattern: isolated regions in between // See #case_recursive_boxes_75 // Incoming: one region // In between: several rings having isolated region, all the same // Outging == incoming std::size_t const n = aggregation.size(); if (n < 3) { return false; } sort_by_side::rank_with_rings const& incoming = aggregation.front(); sort_by_side::rank_with_rings const& outgoing = aggregation.back(); sort_by_side::rank_with_rings const& first_isolated = aggregation[2]; bool const incoming_ok = incoming.all_from() && incoming.has_unique_region_id() && ! incoming.is_isolated(); if (! incoming_ok) { return false; } signed_size_type const incoming_region_id = incoming.region_id(); bool const outgoing_ok = outgoing.all_to() && outgoing.has_unique_region_id() && ! outgoing.is_isolated() && outgoing.region_id() == incoming_region_id; if (! outgoing_ok) { return false; } const signed_size_type isolated_region_id = first_isolated.region_id(); for (std::size_t i = 1; i < n - 1; i++) { sort_by_side::rank_with_rings const& rwr = aggregation[i]; if (! rwr.has_unique_region_id() || ! rwr.is_isolated() || rwr.region_id() != isolated_region_id) { return false; } } selected_rank = n - 1; return true; } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP