From 4211a2b1e9f79993c8d6df2f0209e7f11245def8 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 26 Feb 2014 12:05:48 +0100 Subject: [PATCH] [geometry] Use robust_policy in append_no_dups_or_spikes Only if robust_policy would make any difference, so we added an "enabled" boolean into the policy --- .../overlay/append_no_dups_or_spikes.hpp | 105 ++++++++++++++++-- .../algorithms/detail/overlay/traverse.hpp | 4 +- .../detail/point_is_spike_or_equal.hpp | 55 ++++++++- .../policies/robustness/no_rescale_policy.hpp | 2 + .../policies/robustness/zoom_to_robust.hpp | 2 + 5 files changed, 152 insertions(+), 16 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp b/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp index 55af203cd..b911b6b6d 100644 --- a/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp @@ -24,37 +24,118 @@ namespace boost { namespace geometry namespace detail { namespace overlay { -template +// TODO: move this / rename this +template +inline bool points_equal_or_close(Point1 const& point1, + Point2 const& point2, + RobustPolicy const& robust_policy) +{ + if (detail::equals::equals_point_point(point1, point2)) + { + return true; + } + + if (! RobustPolicy::enabled) + { + return false; + } + + // Try using specified robust policy + typedef typename geometry::robust_point_type + < + Point1, + RobustPolicy + >::type robust_point_type; + + robust_point_type point1_rob, point2_rob; + geometry::recalculate(point1_rob, point1, robust_policy); + geometry::recalculate(point2_rob, point2, robust_policy); + + return detail::equals::equals_point_point(point1_rob, point2_rob); +} + + +template inline void append_no_dups_or_spikes(Range& range, Point const& point, - RobustPolicys const& robust_policy) + RobustPolicy const& robust_policy) { #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION std::cout << " add: (" << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")" << std::endl; #endif - boost::ignore_unused_variable_warning(robust_policy); + // The code below thies condition checks all spikes/dups + // for geometries >= 3 points. + // So we have to check the first potential duplicate differently + if (boost::size(range) == 1 + && points_equal_or_close(*(boost::begin(range)), point, robust_policy)) + { + return; + } traits::push_back::apply(range, point); - // If a point is equal, or forming a spike, remove the pen-ultimate point because this one caused the spike. - // If so, the now-new-pen-ultimate point can again cause a spike (possibly at a corner). So keep doing this. - // Besides spikes it will also avoid duplicates. + // If a point is equal, or forming a spike, remove the pen-ultimate point + // because this one caused the spike. + // If so, the now-new-pen-ultimate point can again cause a spike + // (possibly at a corner). So keep doing this. + // Besides spikes it will also avoid adding duplicates. while(boost::size(range) >= 3 - && point_is_spike_or_equal(point, *(boost::end(range) - 3), *(boost::end(range) - 2))) + && point_is_spike_or_equal(point, + *(boost::end(range) - 3), + *(boost::end(range) - 2), + robust_policy)) { // Use the Concept/traits, so resize and append again traits::resize::apply(range, boost::size(range) - 2); traits::push_back::apply(range, point); } +} - // There might still be one duplicate not catched by the condition above - if (boost::size(range) == 2 - && geometry::detail::equals::equals_point_point(*boost::begin(range), point)) +template +inline void clean_closing_dups_and_spikes(Range& range, + RobustPolicy const& robust_policy) +{ + int const minsize + = core_detail::closure::minimum_ring_size + < + geometry::closure::value + >::value; + + if (boost::size(range) <= minsize) { - traits::clear::apply(range); - traits::push_back::apply(range, point); + return; } + + typedef typename boost::range_iterator::type iterator_type; + const bool closed = geometry::closure::value == geometry::closed; + bool found = false; + do + { + found = false; + iterator_type first = boost::begin(range); + iterator_type second = first + 1; + iterator_type ultimate = boost::end(range) - 1; + if (closed) + { + ultimate--; + } + + // Check if closing point is a spike (this is so if the second point is + // considered as a spike w.r.t. the last segment) + if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy)) + { + range.erase(first); + if (closed) + { + // Remove closing last point + traits::resize::apply(range, boost::size(range) - 1); + // Add new closing point + traits::push_back::apply(range, *boost::begin(range)); + } + found = true; + } + } while(found && boost::size(range) > minsize); } diff --git a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp index a01337b66..880203639 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -399,9 +399,7 @@ public : detail::overlay::debug_traverse(*current, *iit, "->Finished"); if (geometry::num_points(current_output) >= min_num_points) { - // TODO this call should go, it should already be clean from dups/spikes - clean_dups_and_spikes(current_output, rescale_policy); - // END TODO + clean_closing_dups_and_spikes(current_output, rescale_policy); rings.push_back(current_output); } } diff --git a/include/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp b/include/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp index 23078bf64..647488329 100644 --- a/include/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp +++ b/include/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp @@ -25,8 +25,18 @@ namespace boost { namespace geometry namespace detail { +// Checks if a point ("last_point") causes a spike w.r.t. +// the specified two other points (segment_a, segment_b) +// +// x-------x------x +// a lp b +// +// Above, lp generates a spike w.r.t. segment(a,b) +// So specify last point first, then (a,b) (this is unordered, so unintuitive) template -static inline bool point_is_spike_or_equal(Point1 const& last_point, Point2 const& segment_a, Point3 const& segment_b) +static inline bool point_is_spike_or_equal(Point1 const& last_point, + Point2 const& segment_a, + Point3 const& segment_b) { typedef typename strategy::side::services::default_strategy < @@ -62,6 +72,49 @@ static inline bool point_is_spike_or_equal(Point1 const& last_point, Point2 cons return false; } +template +< + typename Point1, + typename Point2, + typename Point3, + typename RobustPolicy +> +static inline bool point_is_spike_or_equal(Point1 const& last_point, + Point2 const& segment_a, + Point3 const& segment_b, + RobustPolicy const& robust_policy) +{ + if (point_is_spike_or_equal(last_point, segment_a, segment_b)) + { + return true; + } + + if (! RobustPolicy::enabled) + { + return false; + } + + // Try using specified robust policy + typedef typename geometry::robust_point_type + < + Point1, + RobustPolicy + >::type robust_point_type; + + robust_point_type last_point_rob, segment_a_rob, segment_b_rob; + geometry::recalculate(last_point_rob, last_point, robust_policy); + geometry::recalculate(segment_a_rob, segment_a, robust_policy); + geometry::recalculate(segment_b_rob, segment_b, robust_policy); + + return point_is_spike_or_equal + ( + last_point_rob, + segment_a_rob, + segment_b_rob + ); +} + + } // namespace detail #endif diff --git a/include/boost/geometry/policies/robustness/no_rescale_policy.hpp b/include/boost/geometry/policies/robustness/no_rescale_policy.hpp index 585f059c2..a7899842c 100644 --- a/include/boost/geometry/policies/robustness/no_rescale_policy.hpp +++ b/include/boost/geometry/policies/robustness/no_rescale_policy.hpp @@ -29,6 +29,8 @@ namespace detail // Probably this will be moved out of namespace detail struct no_rescale_policy { + static bool const enabled = false; + // We don't rescale but return the reference of the input template inline Value const& apply(Value const& value) const diff --git a/include/boost/geometry/policies/robustness/zoom_to_robust.hpp b/include/boost/geometry/policies/robustness/zoom_to_robust.hpp index 60292028a..e64138f86 100644 --- a/include/boost/geometry/policies/robustness/zoom_to_robust.hpp +++ b/include/boost/geometry/policies/robustness/zoom_to_robust.hpp @@ -59,6 +59,8 @@ struct get_max_size template struct rescale_strategy { + static bool const enabled = true; + typedef typename geometry::coordinate_type::type output_ct; rescale_strategy(FpPoint const& fp_min, IntPoint const& int_min, CalculationType const& the_factor)