// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2017, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { template struct equal_to { Point const& m_point; equal_to(Point const& point) : m_point(point) {} template inline bool operator()(OtherPoint const& other) const { return geometry::equals(m_point, other); } }; template struct not_equal_to { Point const& m_point; not_equal_to(Point const& point) : m_point(point) {} template inline bool operator()(OtherPoint const& other) const { return ! geometry::equals(other, m_point); } }; template struct has_spikes { template static inline Iterator find_different_from_first(Iterator first, Iterator last) { typedef not_equal_to::type> not_equal; BOOST_GEOMETRY_ASSERT(first != last); Iterator second = first; ++second; return std::find_if(second, last, not_equal(*first)); } template static inline bool apply(Range const& range, VisitPolicy& visitor, SideStrategy const& strategy) { boost::ignore_unused(visitor); typedef typename closeable_view::type view_type; typedef typename boost::range_iterator::type iterator; bool const is_linear = boost::is_same::type, linestring_tag>::value; view_type const view(range); iterator prev = boost::begin(view); iterator cur = find_different_from_first(prev, boost::end(view)); if (cur == boost::end(view)) { // the range has only one distinct point, so it // cannot have a spike return ! visitor.template apply(); } iterator next = find_different_from_first(cur, boost::end(view)); if (next == boost::end(view)) { // the range has only two distinct points, so it // cannot have a spike return ! visitor.template apply(); } while (next != boost::end(view)) { if ( geometry::detail::point_is_spike_or_equal(*prev, *next, *cur, strategy) ) { return ! visitor.template apply(is_linear, *cur); } prev = cur; cur = next; next = find_different_from_first(cur, boost::end(view)); } if (geometry::equals(range::front(view), range::back(view))) { iterator cur = boost::begin(view); typename boost::range_reverse_iterator < view_type const >::type prev = find_different_from_first(boost::rbegin(view), boost::rend(view)); iterator next = find_different_from_first(cur, boost::end(view)); if (detail::point_is_spike_or_equal(*prev, *next, *cur, strategy)) { return ! visitor.template apply(is_linear, *cur); } else { return ! visitor.template apply(); } } return ! visitor.template apply(); } }; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP