summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail/overlay/handle_colocations.hpp')
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_colocations.hpp170
1 files changed, 154 insertions, 16 deletions
diff --git a/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp b/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
index ad75127fab..110e1be2f1 100644
--- a/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
+++ b/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
@@ -15,6 +15,9 @@
#include <vector>
#include <boost/range.hpp>
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
@@ -201,7 +204,6 @@ inline signed_size_type add_turn_to_cluster(Turn const& turn,
template
<
- bool Reverse1, bool Reverse2,
typename Turns,
typename ClusterPerSegment,
typename Operations,
@@ -212,7 +214,7 @@ inline void handle_colocation_cluster(Turns& turns,
signed_size_type& cluster_id,
ClusterPerSegment& cluster_per_segment,
Operations const& operations,
- Geometry1 const& geometry1, Geometry2 const& geometry2)
+ Geometry1 const& /*geometry1*/, Geometry2 const& /*geometry2*/)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
@@ -318,7 +320,7 @@ inline void assign_cluster_to_turns(Turns& turns,
std::cout << " CONFLICT " << std::endl;
}
turn.cluster_id = it->second;
- clusters[turn.cluster_id].insert(turn_index);
+ clusters[turn.cluster_id].turn_indices.insert(turn_index);
}
}
}
@@ -339,7 +341,8 @@ inline void remove_clusters(Turns& turns, Clusters& clusters)
typename Clusters::iterator current_it = it;
++it;
- std::set<signed_size_type> const& turn_indices = current_it->second;
+ std::set<signed_size_type> const& turn_indices
+ = current_it->second.turn_indices;
if (turn_indices.size() == 1)
{
signed_size_type turn_index = *turn_indices.begin();
@@ -349,6 +352,134 @@ inline void remove_clusters(Turns& turns, Clusters& clusters)
}
}
+template <typename Turn, typename IdSet>
+inline void discard_ie_turn(Turn& turn, IdSet& ids, signed_size_type id)
+{
+ turn.discarded = true;
+ turn.cluster_id = -1;
+ // To remove it later from clusters
+ ids.insert(id);
+}
+
+template <bool Reverse>
+inline bool is_interior(segment_identifier const& seg_id)
+{
+ return Reverse ? seg_id.ring_index == -1 : seg_id.ring_index >= 0;
+}
+
+template <bool Reverse0, bool Reverse1>
+inline bool is_ie_turn(segment_identifier const& ext_seg_0,
+ segment_identifier const& ext_seg_1,
+ segment_identifier const& int_seg_0,
+ segment_identifier const& other_seg_1)
+{
+ // Compares two segment identifiers from two turns (external / one internal)
+
+ // From first turn [0], both are from same polygon (multi_index),
+ // one is exterior (-1), the other is interior (>= 0),
+ // and the second turn [1] handles the same ring
+
+ // For difference, where the rings are processed in reversal, all interior
+ // rings become exterior and vice versa. But also the multi property changes:
+ // rings originally from the same multi should now be considered as from
+ // different multi polygons.
+ // But this is not always the case, and at this point hard to figure out
+ // (not yet implemented, TODO)
+
+ bool const same_multi0 = ! Reverse0
+ && ext_seg_0.multi_index == int_seg_0.multi_index;
+
+ bool const same_multi1 = ! Reverse1
+ && ext_seg_1.multi_index == other_seg_1.multi_index;
+
+ return same_multi0
+ && same_multi1
+ && ! is_interior<Reverse0>(ext_seg_0)
+ && is_interior<Reverse0>(int_seg_0)
+ && ext_seg_1.ring_index == other_seg_1.ring_index;
+
+ // The other way round is tested in another call
+}
+
+template
+<
+ bool Reverse0, bool Reverse1, // Reverse interpretation interior/exterior
+ typename Turns,
+ typename Clusters
+>
+inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
+{
+ typedef std::set<signed_size_type>::const_iterator set_iterator;
+ typedef typename boost::range_value<Turns>::type turn_type;
+
+ std::set<signed_size_type> ids_to_remove;
+
+ for (typename Clusters::iterator cit = clusters.begin();
+ cit != clusters.end(); ++cit)
+ {
+ cluster_info& cinfo = cit->second;
+ std::set<signed_size_type>& ids = cinfo.turn_indices;
+
+ ids_to_remove.clear();
+
+ for (set_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ turn_type& turn = turns[*it];
+ segment_identifier const& seg_0 = turn.operations[0].seg_id;
+ segment_identifier const& seg_1 = turn.operations[1].seg_id;
+
+ if (turn.both(operation_intersection)
+ && Reverse0 == Reverse1)
+ {
+ if ( is_interior<Reverse0>(seg_0)
+ && is_interior<Reverse1>(seg_1))
+ {
+ // ii touch with, two interior rings
+ discard_ie_turn(turn, ids_to_remove, *it);
+ }
+
+ continue;
+ }
+
+ if (! (turn.both(operation_union)
+ || turn.combination(operation_union, operation_blocked)))
+ {
+ // Not a uu/ux, so cannot be colocated with a iu turn
+ continue;
+ }
+
+ for (set_iterator int_it = ids.begin(); int_it != ids.end(); ++int_it)
+ {
+ if (*it == *int_it)
+ {
+ continue;
+ }
+
+ // Turn with, possibly, an interior ring involved
+ turn_type& int_turn = turns[*int_it];
+ segment_identifier const& int_seg_0 = int_turn.operations[0].seg_id;
+ segment_identifier const& int_seg_1 = int_turn.operations[1].seg_id;
+
+ if (is_ie_turn<Reverse0, Reverse1>(seg_0, seg_1, int_seg_0, int_seg_1))
+ {
+ discard_ie_turn(int_turn, ids_to_remove, *int_it);
+ }
+ if (is_ie_turn<Reverse1, Reverse0>(seg_1, seg_0, int_seg_1, int_seg_0))
+ {
+ discard_ie_turn(int_turn, ids_to_remove, *int_it);
+ }
+ }
+ }
+
+ // Erase from the ids (which cannot be done above)
+ for (set_iterator sit = ids_to_remove.begin();
+ sit != ids_to_remove.end(); ++sit)
+ {
+ ids.erase(*sit);
+ }
+ }
+}
+
// Checks colocated turns and flags combinations of uu/other, possibly a
// combination of a ring touching another geometry's interior ring which is
@@ -434,13 +565,17 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters,
{
if (it->second.size() > 1u)
{
- handle_colocation_cluster<Reverse1, Reverse2>(turns, cluster_id,
- cluster_per_segment, it->second,
- geometry1, geometry2);
+ handle_colocation_cluster(turns, cluster_id, cluster_per_segment,
+ it->second, geometry1, geometry2);
}
}
assign_cluster_to_turns(turns, clusters, cluster_per_segment);
+ discard_interior_exterior_turns
+ <
+ do_reverse<geometry::point_order<Geometry1>::value>::value != Reverse1,
+ do_reverse<geometry::point_order<Geometry2>::value>::value != Reverse2
+ >(turns, clusters);
remove_clusters(turns, clusters);
#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
@@ -497,7 +632,7 @@ template
typename Geometry1,
typename Geometry2
>
-inline void assign_startable_in_clusters(Clusters& clusters, Turns& turns,
+inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2)
{
@@ -515,7 +650,8 @@ inline void assign_startable_in_clusters(Clusters& clusters, Turns& turns,
for (typename Clusters::iterator mit = clusters.begin();
mit != clusters.end(); ++mit)
{
- std::set<signed_size_type> const& ids = mit->second;
+ cluster_info& cinfo = mit->second;
+ std::set<signed_size_type> const& ids = cinfo.turn_indices;
if (ids.empty())
{
continue;
@@ -545,30 +681,32 @@ inline void assign_startable_in_clusters(Clusters& clusters, Turns& turns,
sbs.find_open();
- // Unset the startable flag for all 'closed' spaces
+ // Unset the startable flag for all 'closed' zones
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
const typename sbs_type::rp& ranked = sbs.m_ranked_points[i];
turn_type& turn = turns[ranked.turn_index];
- turn_operation_type& op = turn.operations[ranked.op_index];
+ turn_operation_type& op = turn.operations[ranked.operation_index];
- if (ranked.index != sort_by_side::index_to)
+ if (ranked.direction != sort_by_side::dir_to)
{
continue;
}
- op.enriched.count_left = ranked.left_count;
- op.enriched.count_right = ranked.right_count;
+ op.enriched.count_left = ranked.count_left;
+ op.enriched.count_right = ranked.count_right;
+ op.enriched.zone = ranked.zone;
if ((for_operation == operation_union
- && ranked.left_count != 0)
+ && ranked.count_left != 0)
|| (for_operation == operation_intersection
- && ranked.right_count != 2))
+ && ranked.count_right != 2))
{
op.enriched.startable = false;
}
}
+ cinfo.open_count = sbs.open_count(turns);
}
}