blob: 090c026e8b7fc4156a46b3f73c61dc1e24119d74 [file] [log] [blame]
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
#include <algorithm>
#include <boost/range.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/policies/is_valid/default_policy.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
#include <boost/geometry/io/dsv/write.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename Point>
struct equal_to
{
Point const& m_point;
equal_to(Point const& point)
: m_point(point)
{}
template <typename OtherPoint>
inline bool operator()(OtherPoint const& other) const
{
return geometry::equals(m_point, other);
}
};
template <typename Point>
struct not_equal_to
{
Point const& m_point;
not_equal_to(Point const& point)
: m_point(point)
{}
template <typename OtherPoint>
inline bool operator()(OtherPoint const& other) const
{
return ! geometry::equals(other, m_point);
}
};
template <typename Range, closure_selector Closure>
struct has_spikes
{
template <typename VisitPolicy>
static inline bool apply(Range const& range, VisitPolicy& visitor)
{
typedef not_equal_to<typename point_type<Range>::type> not_equal;
typedef typename closeable_view<Range const, Closure>::type view_type;
typedef typename boost::range_iterator<view_type const>::type iterator;
bool const is_linear
= boost::is_same<typename tag<Range>::type, linestring_tag>::value;
view_type const view(range);
iterator prev = boost::begin(view);
iterator cur = std::find_if(prev, boost::end(view), not_equal(*prev));
if ( cur == boost::end(view) )
{
// the range has only one distinct point, so it
// cannot have a spike
return ! visitor.template apply<no_failure>();
}
iterator next = std::find_if(cur, boost::end(view), not_equal(*cur));
if ( next == boost::end(view) )
{
// the range has only two distinct points, so it
// cannot have a spike
return ! visitor.template apply<no_failure>();
}
while ( next != boost::end(view) )
{
if ( geometry::detail::point_is_spike_or_equal(*prev,
*next,
*cur) )
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);
}
prev = cur;
cur = next;
next = std::find_if(cur, boost::end(view), not_equal(*cur));
}
if ( geometry::equals(range::front(view), range::back(view)) )
{
iterator cur = boost::begin(view);
typename boost::range_reverse_iterator
<
view_type const
>::type prev = std::find_if(boost::rbegin(view),
boost::rend(view),
not_equal(range::back(view)));
iterator next =
std::find_if(cur, boost::end(view), not_equal(*cur));
if (detail::point_is_spike_or_equal(*prev, *next, *cur))
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);
}
else
{
return ! visitor.template apply<no_failure>();
}
}
return ! visitor.template apply<no_failure>();
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP