1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2014-2015, Oracle and/or its affiliates.
5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
7 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
10 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
11 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
15 #include <boost/core/ignore_unused.hpp>
16 #include <boost/range.hpp>
17 #include <boost/type_traits/is_same.hpp>
19 #include <boost/geometry/core/assert.hpp>
20 #include <boost/geometry/core/point_type.hpp>
21 #include <boost/geometry/core/tag.hpp>
22 #include <boost/geometry/core/tags.hpp>
24 #include <boost/geometry/policies/is_valid/default_policy.hpp>
26 #include <boost/geometry/util/range.hpp>
28 #include <boost/geometry/views/closeable_view.hpp>
30 #include <boost/geometry/algorithms/equals.hpp>
31 #include <boost/geometry/algorithms/validity_failure_type.hpp>
32 #include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
33 #include <boost/geometry/io/dsv/write.hpp>
36 namespace boost { namespace geometry
40 #ifndef DOXYGEN_NO_DETAIL
41 namespace detail { namespace is_valid
44 template <typename Point>
49 equal_to(Point const& point)
53 template <typename OtherPoint>
54 inline bool operator()(OtherPoint const& other) const
56 return geometry::equals(m_point, other);
60 template <typename Point>
65 not_equal_to(Point const& point)
69 template <typename OtherPoint>
70 inline bool operator()(OtherPoint const& other) const
72 return ! geometry::equals(other, m_point);
78 template <typename Range, closure_selector Closure>
81 template <typename Iterator>
82 static inline Iterator find_different_from_first(Iterator first,
85 typedef not_equal_to<typename point_type<Range>::type> not_equal;
87 BOOST_GEOMETRY_ASSERT(first != last);
89 Iterator second = first;
91 return std::find_if(second, last, not_equal(*first));
94 template <typename VisitPolicy>
95 static inline bool apply(Range const& range, VisitPolicy& visitor)
97 boost::ignore_unused(visitor);
99 typedef typename closeable_view<Range const, Closure>::type view_type;
100 typedef typename boost::range_iterator<view_type const>::type iterator;
103 = boost::is_same<typename tag<Range>::type, linestring_tag>::value;
105 view_type const view(range);
107 iterator prev = boost::begin(view);
109 iterator cur = find_different_from_first(prev, boost::end(view));
110 if (cur == boost::end(view))
112 // the range has only one distinct point, so it
113 // cannot have a spike
114 return ! visitor.template apply<no_failure>();
117 iterator next = find_different_from_first(cur, boost::end(view));
118 if (next == boost::end(view))
120 // the range has only two distinct points, so it
121 // cannot have a spike
122 return ! visitor.template apply<no_failure>();
125 while (next != boost::end(view))
127 if ( geometry::detail::point_is_spike_or_equal(*prev,
132 ! visitor.template apply<failure_spikes>(is_linear, *cur);
136 next = find_different_from_first(cur, boost::end(view));
139 if (geometry::equals(range::front(view), range::back(view)))
141 iterator cur = boost::begin(view);
142 typename boost::range_reverse_iterator
145 >::type prev = find_different_from_first(boost::rbegin(view),
148 iterator next = find_different_from_first(cur, boost::end(view));
149 if (detail::point_is_spike_or_equal(*prev, *next, *cur))
152 ! visitor.template apply<failure_spikes>(is_linear, *cur);
156 return ! visitor.template apply<no_failure>();
160 return ! visitor.template apply<no_failure>();
166 }} // namespace detail::is_valid
167 #endif // DOXYGEN_NO_DETAIL
170 }} // namespace boost::geometry
173 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP