[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
This commit is contained in:
Barend Gehrels
2014-02-26 12:05:48 +01:00
parent 1236aad099
commit 4211a2b1e9
5 changed files with 152 additions and 16 deletions

View File

@@ -24,37 +24,118 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
template <typename Range, typename Point, typename RobustPolicys>
// TODO: move this / rename this
template <typename Point1, typename Point2, typename RobustPolicy>
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 <typename Range, typename Point, typename RobustPolicy>
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<Range>::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<Range>::apply(range, boost::size(range) - 2);
traits::push_back<Range>::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 <typename Range, typename RobustPolicy>
inline void clean_closing_dups_and_spikes(Range& range,
RobustPolicy const& robust_policy)
{
int const minsize
= core_detail::closure::minimum_ring_size
<
geometry::closure<Range>::value
>::value;
if (boost::size(range) <= minsize)
{
traits::clear<Range>::apply(range);
traits::push_back<Range>::apply(range, point);
return;
}
typedef typename boost::range_iterator<Range>::type iterator_type;
const bool closed = geometry::closure<Range>::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<Range>::apply(range, boost::size(range) - 1);
// Add new closing point
traits::push_back<Range>::apply(range, *boost::begin(range));
}
found = true;
}
} while(found && boost::size(range) > minsize);
}

View File

@@ -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);
}
}

View File

@@ -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 <typename Point1, typename Point2, typename Point3>
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

View File

@@ -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 <std::size_t Dimension, typename Value>
inline Value const& apply(Value const& value) const

View File

@@ -59,6 +59,8 @@ struct get_max_size<Box, 0>
template <typename FpPoint, typename IntPoint, typename CalculationType>
struct rescale_strategy
{
static bool const enabled = true;
typedef typename geometry::coordinate_type<IntPoint>::type output_ct;
rescale_strategy(FpPoint const& fp_min, IntPoint const& int_min, CalculationType const& the_factor)