summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp')
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp193
1 files changed, 173 insertions, 20 deletions
diff --git a/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp b/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
index 39c55db759..9c4a3094e0 100644
--- a/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
+++ b/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
@@ -11,6 +11,7 @@
#include <boost/range.hpp>
+#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/within.hpp>
@@ -24,9 +25,9 @@ namespace detail { namespace overlay
struct discard_turns
{
- template <typename Turns, typename Geometry0, typename Geometry1>
+ template <typename Turns, typename Clusters, typename Geometry0, typename Geometry1>
static inline
- void apply(Turns& , Geometry0 const& , Geometry1 const& )
+ void apply(Turns& , Clusters const& , Geometry0 const& , Geometry1 const& )
{}
};
@@ -38,9 +39,9 @@ template <>
struct discard_closed_turns<overlay_union, operation_union>
{
- template <typename Turns, typename Geometry0, typename Geometry1>
+ template <typename Turns, typename Clusters, typename Geometry0, typename Geometry1>
static inline
- void apply(Turns& turns,
+ void apply(Turns& turns, Clusters const& clusters,
Geometry0 const& geometry0, Geometry1 const& geometry1)
{
typedef typename boost::range_value<Turns>::type turn_type;
@@ -52,9 +53,7 @@ struct discard_closed_turns<overlay_union, operation_union>
{
turn_type& turn = *it;
- if (turn.cluster_id >= 0
- || turn.discarded
- || ! is_self_turn<overlay_union>(turn))
+ if (turn.discarded || ! is_self_turn<overlay_union>(turn))
{
continue;
}
@@ -75,11 +74,106 @@ struct discard_closed_turns<overlay_union, operation_union>
struct discard_self_intersection_turns
{
- template <typename Turns, typename Geometry0, typename Geometry1>
+private :
+
+ template <typename Turns, typename Clusters>
+ static inline
+ bool any_blocked(signed_size_type cluster_id,
+ const Turns& turns, Clusters const& clusters)
+ {
+ typename Clusters::const_iterator cit = clusters.find(cluster_id);
+ if (cit == clusters.end())
+ {
+ return false;
+ }
+ cluster_info const& cinfo = cit->second;
+ for (std::set<signed_size_type>::const_iterator it
+ = cinfo.turn_indices.begin();
+ it != cinfo.turn_indices.end(); ++it)
+ {
+ typename boost::range_value<Turns>::type const& turn = turns[*it];
+ if (turn.any_blocked())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template <typename Turns, typename Clusters>
+ static inline
+ bool is_self_cluster(signed_size_type cluster_id,
+ const Turns& turns, Clusters const& clusters)
+ {
+ typename Clusters::const_iterator cit = clusters.find(cluster_id);
+ if (cit == clusters.end())
+ {
+ return false;
+ }
+
+ cluster_info const& cinfo = cit->second;
+ for (std::set<signed_size_type>::const_iterator it
+ = cinfo.turn_indices.begin();
+ it != cinfo.turn_indices.end(); ++it)
+ {
+ if (! is_self_turn<overlay_intersection>(turns[*it]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ template <typename Turn, typename Geometry0, typename Geometry1>
+ static inline
+ bool within(Turn const& turn, Geometry0 const& geometry0,
+ Geometry1 const& geometry1)
+ {
+ return turn.operations[0].seg_id.source_index == 0
+ ? geometry::within(turn.point, geometry1)
+ : geometry::within(turn.point, geometry0);
+ }
+
+ template <typename Turns, typename Clusters,
+ typename Geometry0, typename Geometry1>
+ static inline
+ void discard_clusters(Turns& turns, Clusters const& clusters,
+ Geometry0 const& geometry0, Geometry1 const& geometry1)
+ {
+ for (typename Clusters::const_iterator cit = clusters.begin();
+ cit != clusters.end(); ++cit)
+ {
+ signed_size_type cluster_id = cit->first;
+
+ // If there are only self-turns in the cluster, the cluster should
+ // be located within the other geometry, for intersection
+ if (is_self_cluster(cluster_id, turns, clusters))
+ {
+ cluster_info const& cinfo = cit->second;
+ if (! within(turns[*cinfo.turn_indices.begin()], geometry0, geometry1))
+ {
+ // Discard all turns in cluster
+ for (std::set<signed_size_type>::const_iterator sit = cinfo.turn_indices.begin();
+ sit != cinfo.turn_indices.end(); ++sit)
+ {
+ turns[*sit].discarded = true;
+ }
+ }
+ }
+ }
+ }
+
+public :
+
+ template <typename Turns, typename Clusters,
+ typename Geometry0, typename Geometry1>
static inline
- void apply(Turns& turns,
+ void apply(Turns& turns, Clusters const& clusters,
Geometry0 const& geometry0, Geometry1 const& geometry1)
{
+ discard_clusters(turns, clusters, geometry0, geometry1);
+
typedef typename boost::range_value<Turns>::type turn_type;
for (typename boost::range_iterator<Turns>::type
@@ -89,9 +183,7 @@ struct discard_self_intersection_turns
{
turn_type& turn = *it;
- if (turn.cluster_id >= 0
- || turn.discarded
- || ! is_self_turn<overlay_intersection>(turn))
+ if (turn.discarded || ! is_self_turn<overlay_intersection>(turn))
{
continue;
}
@@ -106,16 +198,22 @@ struct discard_self_intersection_turns
continue;
}
- // It is a non co-located ii self-turn
+ if (turn.is_clustered() && turn.has_colocated_both)
+ {
+ // Don't delete a self-ii-turn colocated with another ii-turn
+ // (for example #case_recursive_boxes_70)
+ // But for some cases (#case_58_iet) they should be deleted,
+ // there are many self-turns there and also blocked turns there
+ if (! any_blocked(turn.cluster_id, turns, clusters))
+ {
+ continue;
+ }
+ }
+
+ // It is a ii self-turn
// Check if it is within the other geometry
// If not, it can be ignored
-
- bool const within =
- turn.operations[0].seg_id.source_index == 0
- ? geometry::within(turn.point, geometry1)
- : geometry::within(turn.point, geometry0);
-
- if (! within)
+ if (! within(turn, geometry0, geometry1))
{
// It is not within another geometry, discard the turn
turn.discarded = true;
@@ -134,6 +232,61 @@ struct discard_open_turns<overlay_intersection, operation_intersection>
// For difference, it should be done in a different way (TODO)
+
+template <overlay_type OverlayType, typename Turns>
+inline void discard_self_turns_which_loop(Turns& turns)
+{
+ if (operation_from_overlay<OverlayType>::value == operation_union)
+ {
+ // For union, self-turn i/u traveling to itself are allowed to form
+ // holes. #case_recursive_boxes_37
+ // TODO: this can be finetuned by inspecting the cluster too,
+ // and if there are non-self-turns the polygons on their sides can
+ // be checked
+ return;
+ }
+
+ typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename turn_type::turn_operation_type op_type;
+
+ signed_size_type turn_index = 0;
+ for (typename boost::range_iterator<Turns>::type
+ it = boost::begin(turns);
+ it != boost::end(turns);
+ ++it, ++turn_index)
+ {
+ turn_type& turn = *it;
+
+ if (! is_self_turn<OverlayType>(turn))
+ {
+ continue;
+ }
+ if (! turn.combination(operation_intersection, operation_union))
+ {
+ // ii may travel to itself
+ continue;
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ op_type& op = turn.operations[i];
+
+ if (op.enriched.startable
+ && op.operation == operation_intersection
+ && op.enriched.get_next_turn_index() == turn_index)
+ {
+ // Self-turn i/u, i part traveling to itself. Discard it.
+ // (alternatively it might be made unstartable - but the
+ // intersection-operation may not be traveled anyway, and the
+ // union-operation is not traveled at all in intersections
+ // #case_recursive_boxes_77
+ turn.discarded = true;
+ }
+ }
+ }
+
+}
+
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL