From 83f3920ab9933ca7e890c2e4803d371cf5fc3cca Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 3 Jan 2018 17:36:13 +0100 Subject: [PATCH] [dissolve] using preferred operations, they are now also used to determine the order in which turns are traversed (first preferred). This introduces a specific traverse umbrella class for dissolve --- .../detail/overlay/traversal_ring_creator.hpp | 54 ++++++++++++ .../detail/overlay/dissolve_traverse.hpp | 82 +++++++++++++++++++ .../extensions/algorithms/dissolve.hpp | 13 +-- 3 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 include/boost/geometry/extensions/algorithms/detail/overlay/dissolve_traverse.hpp diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp index 4df3f6e7a..74a03acaf 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp @@ -344,6 +344,60 @@ struct traversal_ring_creator } } + template + void iterate_with_preference(std::size_t phase, + Rings& rings, std::size_t& finalized_ring_size, + typename Backtrack::state_type& state) + { + for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) + { + turn_type const& turn = m_turns[turn_index]; + + if (turn.discarded || turn.blocked()) + { + // Skip discarded and blocked turns + continue; + } + + turn_operation_type const& op0 = turn.operations[0]; + turn_operation_type const& op1 = turn.operations[1]; + + if (phase == 0) + { + if (! op0.enriched.prefer_start && ! op1.enriched.prefer_start) + { + // Not preferred, take next one + continue; + } + } + + if (turn.both(operation_continue)) + { + // Traverse only one turn, the one with the SMALLEST remaining distance + // to avoid skipping a turn in between, which can happen in rare cases + // (e.g. #130) + int const op_index + = op0.remaining_distance <= op1.remaining_distance ? 0 : 1; + + traverse_with_operation(turn, turn_index, op_index, + rings, finalized_ring_size, state); + } + else + { + bool const forward = op0.enriched.prefer_start; + + int op_index = forward ? 0 : 1; + int const increment = forward ? 1 : -1; + + for (int i = 0; i < 2; i++, op_index += increment) + { + traverse_with_operation(turn, turn_index, op_index, + rings, finalized_ring_size, state); + } + } + } + } + private: traversal_type m_trav; diff --git a/include/boost/geometry/extensions/algorithms/detail/overlay/dissolve_traverse.hpp b/include/boost/geometry/extensions/algorithms/detail/overlay/dissolve_traverse.hpp new file mode 100644 index 000000000..598cd16bc --- /dev/null +++ b/include/boost/geometry/extensions/algorithms/detail/overlay/dissolve_traverse.hpp @@ -0,0 +1,82 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2018 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_EXTENSIONS_ALGORITHMS_DISSOLVE_TRAVERSE_HPP +#define BOOST_GEOMETRY_EXTENSIONS_ALGORITHMS_DISSOLVE_TRAVERSE_HPP + +#include + +#include +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace dissolve +{ + + +/*! + \brief Traverses through intersection points / geometries. This version + for dissolves calls traversal_ring_creator in two phases + \ingroup dissolve + */ +template +class traverse +{ + +public : + template + < + typename Geometry, + typename IntersectionStrategy, + typename RobustPolicy, + typename Turns, + typename Rings, + typename TurnInfoMap, + typename Clusters, + typename Visitor + > + static inline void apply(Geometry const& geometry, + IntersectionStrategy const& intersection_strategy, + RobustPolicy const& robust_policy, + Turns& turns, Rings& rings, + TurnInfoMap& turn_info_map, + Clusters& clusters, + Visitor& visitor) + { + detail::overlay::traversal_ring_creator + < + false, false, overlay_dissolve, + Geometry, Geometry, + Turns, TurnInfoMap, Clusters, + IntersectionStrategy, + RobustPolicy, Visitor, + Backtrack + > trav(geometry, geometry, turns, turn_info_map, clusters, + intersection_strategy, robust_policy, visitor); + + std::size_t finalized_ring_size = boost::size(rings); + + typename Backtrack::state_type state; + + for (std::size_t phase = 0; phase < 2; phase++) + { + trav.iterate_with_preference(phase, rings, finalized_ring_size, state); + } + } +}; + +}} // namespace detail::dissolve +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_ALGORITHMS_DISSOLVE_TRAVERSE_HPP diff --git a/include/boost/geometry/extensions/algorithms/dissolve.hpp b/include/boost/geometry/extensions/algorithms/dissolve.hpp index 73938a4fa..ee5d72bbd 100644 --- a/include/boost/geometry/extensions/algorithms/dissolve.hpp +++ b/include/boost/geometry/extensions/algorithms/dissolve.hpp @@ -44,6 +44,7 @@ #include +#include namespace boost { namespace geometry { @@ -219,7 +220,7 @@ struct dissolve_ring_or_polygon cluster_type clusters; - // Enrich/traverse the polygons twice: first for union... + // Enrich/traverse the polygons typename Strategy::side_strategy_type const side_strategy = strategy.get_side_strategy(); @@ -233,14 +234,8 @@ struct dissolve_ring_or_polygon std::map turn_info_per_ring; - detail::overlay::traverse - < - false, false, - Geometry, Geometry, - overlay_dissolve, - backtrack_for_dissolve - >::apply(geometry, geometry, - strategy, rescale_policy, + detail::dissolve::traverse > + ::apply(geometry, strategy, rescale_policy, turns, rings, turn_info_per_ring, clusters, visitor); visitor.visit_turns(3, turns);