diff options
Diffstat (limited to 'boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp')
-rw-r--r-- | boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp | 166 |
1 files changed, 159 insertions, 7 deletions
diff --git a/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp b/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp index df62a1f2f6..106ecaad07 100644 --- a/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp +++ b/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp @@ -24,8 +24,12 @@ struct ring_with_direction { ring_identifier ring_id; direction_type direction; - bool only_turn_on_ring; + std::size_t turn_index; + int operation_index; + operation_type operation; + signed_size_type region_id; + bool isolated; inline bool operator<(ring_with_direction const& other) const { @@ -36,7 +40,11 @@ struct ring_with_direction ring_with_direction() : direction(dir_unknown) - , only_turn_on_ring(false) + , turn_index(-1) + , operation_index(0) + , operation(operation_none) + , region_id(-1) + , isolated(false) {} }; @@ -50,28 +58,168 @@ struct rank_with_rings { } + inline bool all_equal(direction_type dir_type) const + { + for (std::set<ring_with_direction>::const_iterator it = rings.begin(); + it != rings.end(); ++it) + { + if (it->direction != dir_type) + { + return false; + } + } + return true; + } + inline bool all_to() const { + return all_equal(sort_by_side::dir_to); + } + + inline bool all_from() const + { + return all_equal(sort_by_side::dir_from); + } + + inline bool has_only(operation_type op) const + { + for (std::set<ring_with_direction>::const_iterator it = rings.begin(); + it != rings.end(); ++it) + { + const ring_with_direction& rwd = *it; + if (rwd.operation != op) + { + return false; + } + } + return true; + } + + //! Check if set has both op1 and op2, but no others + inline bool has_only_both(operation_type op1, operation_type op2) const + { + bool has1 = false; + bool has2 = false; for (std::set<ring_with_direction>::const_iterator it = rings.begin(); it != rings.end(); ++it) { - if (it->direction == sort_by_side::dir_from) + const ring_with_direction& rwd = *it; + + if (rwd.operation == op1) { has1 = true; } + else if (rwd.operation == op2) { has2 = true; } + else { return false; } + } + return has1 && has2; + } + + inline bool is_isolated() const + { + for (std::set<ring_with_direction>::const_iterator it = rings.begin(); + it != rings.end(); ++it) + { + const ring_with_direction& rwd = *it; + if (! rwd.isolated) { return false; } } return true; } + + inline bool has_unique_region_id() const + { + int region_id = -1; + for (std::set<ring_with_direction>::const_iterator it = rings.begin(); + it != rings.end(); ++it) + { + const ring_with_direction& rwd = *it; + if (region_id == -1) + { + region_id = rwd.region_id; + } + else if (rwd.region_id != region_id) + { + return false; + } + } + return true; + } + + inline int region_id() const + { + int region_id = -1; + for (std::set<ring_with_direction>::const_iterator it = rings.begin(); + it != rings.end(); ++it) + { + const ring_with_direction& rwd = *it; + if (region_id == -1) + { + region_id = rwd.region_id; + } + else if (rwd.region_id != region_id) + { + return -1; + } + } + return region_id; + } + + template <typename Turns> + inline bool traversable(Turns const& turns) const + { + typedef typename boost::range_value<Turns>::type turn_type; + typedef typename turn_type::turn_operation_type turn_operation_type; + + for (std::set<ring_with_direction>::const_iterator it = rings.begin(); + it != rings.end(); ++it) + { + const ring_with_direction& rwd = *it; + turn_type const& turn = turns[rwd.turn_index]; + turn_operation_type const& op = turn.operations[rwd.operation_index]; + + // TODO: this is still necessary, but makes it order-dependent + // which should not be done. + + // This would obsolete the whole function and should be solved + // in a different way + if (op.visited.finalized() || op.visited.visited()) + { + return false; + } + } + return true; + } + }; -template <typename Sbs> -inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& aggregation) +template <typename Sbs, typename Turns> +inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& aggregation, + Turns const& turns, + operation_type target_operation) { + typedef typename boost::range_value<Turns>::type turn_type; + typedef typename turn_type::turn_operation_type turn_operation_type; + aggregation.clear(); for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) { typename Sbs::rp const& ranked_point = sbs.m_ranked_points[i]; + turn_type const& turn = turns[ranked_point.turn_index]; + + turn_operation_type const& op = turn.operations[ranked_point.operation_index]; + + if (! ((target_operation == operation_union && ranked_point.rank == 0) + || op.operation == target_operation + || op.operation == operation_continue + || (op.operation == operation_blocked && ranked_point.direction == dir_from))) + { + // Always take rank 0 (because self-turns are blocked) + // Don't consider union/blocked (aggregate is only used for intersections) + // Blocked is allowed for from + continue; + } + if (aggregation.empty() || aggregation.back().rank != ranked_point.rank) { rank_with_rings current; @@ -81,10 +229,14 @@ inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& a ring_with_direction rwd; segment_identifier const& sid = ranked_point.seg_id; + rwd.ring_id = ring_identifier(sid.source_index, sid.multi_index, sid.ring_index); rwd.direction = ranked_point.direction; - rwd.only_turn_on_ring = ranked_point.only_turn_on_ring; - + rwd.turn_index = ranked_point.turn_index; + rwd.operation_index = ranked_point.operation_index; + rwd.operation = op.operation; + rwd.region_id = op.enriched.region_id; + rwd.isolated = op.enriched.isolated; aggregation.back().rings.insert(rwd); } |