From 97c14576d5f95da4e16dbe34574f3d82a1201e58 Mon Sep 17 00:00:00 2001 From: Menelaos Karavelas Date: Fri, 13 Jun 2014 15:08:39 +0300 Subject: [PATCH] [algorithms][is_valid] finish implementation for rings: add missing includes; check more conditions; poslish code; --- .../algorithms/detail/is_valid/ring.hpp | 142 +++++++++--------- 1 file changed, 70 insertions(+), 72 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/is_valid/ring.hpp b/include/boost/geometry/algorithms/detail/is_valid/ring.hpp index fe69afb48..e1ac4fc74 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/ring.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/ring.hpp @@ -11,17 +11,22 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP #include +#include #include +#include +#include + #include -#include #include #include +#include #include -#include +#include +#include namespace boost { namespace geometry { @@ -33,12 +38,7 @@ namespace detail { namespace is_valid // struct to check whether a ring is topologically closed -template -struct is_topologically_closed -{}; - -template -struct is_topologically_closed +template { static inline bool apply(Ring const&) { @@ -51,90 +51,92 @@ struct is_topologically_closed { static inline bool apply(Ring const& ring) { - return geometry::equals(*boost::begin(ring), *boost::rbegin(ring)); + return geometry::equals(range::front(ring), range::back(ring)); } }; -// struct to check if the size is above the minimal one -// (3 for open, 4 for closed) -template -struct is_below_minimal_size -{}; -template -struct is_below_minimal_size +template +struct ring_area_predicate { + typedef std::greater type; +}; + +template +struct ring_area_predicate +{ + typedef std::less type; +}; + + + +template +struct is_properly_oriented +{ + typedef typename point_type::type point_type; + + typedef typename strategy::area::services::default_strategy + < + typename cs_tag::type, + point_type + >::type strategy_type; + + typedef detail::area::ring_area + < + order_as_direction::value>::value, + geometry::closure::value + > ring_area_type; + + typedef typename default_area_result::type area_result_type; + static inline bool apply(Ring const& ring) { - return boost::size(ring) < 4; + typename ring_area_predicate + < + area_result_type, IsInteriorRing + >::type predicate; + + // Check area + area_result_type const zero = area_result_type(); + return predicate(ring_area_type::apply(ring, strategy_type()), zero); } }; -template -struct is_below_minimal_size -{ - static inline bool apply(Ring const& ring) - { - return boost::size(ring) < 3; - } -}; - - - - template < typename Ring, - order_selector PointOrder, - closure_selector Closure + bool CheckSelfIntersections = true, + bool IsInteriorRing = false > struct is_valid_ring - : not_implemented -{}; - - -template -struct is_valid_ring -{ - static inline bool apply(Ring const& ring) - { - typedef typename reversible_view - < - Ring, iterate_reverse - >::type reversible_view_type; - - reversible_view_type reversed_ring(const_cast(ring)); - return is_valid_ring::apply(reversed_ring); - } -}; - -template -struct is_valid_ring { static inline bool apply(Ring const& ring) { // return invalid if any of the following condition holds: // (a) the ring's size is below the minimal one - // (b) the ring has less than three distinct points - // (c) the ring is not topologically closed - // (d) the ring has spikes + // (b) the ring is not topologically closed + // (c) the ring has spikes + // (d) the ring has duplicate points + // (e) the boundary of the ring has self-intersections + // (f) the order of the points is inconsistent with the defined order // // Note: no need to check if the area is zero. If this is the // case, then the ring must have at least two spikes, which is // checked by condition (d). - if ( is_below_minimal_size::apply(ring) - || !has_three_distinct_points::apply(ring) - || !is_topologically_closed::apply(ring) - || has_spikes::apply(ring) ) - { - return false; - } - // now call self turns to compute self intersections, if any, - // and analyze them + closure_selector const closure = geometry::closure::value; + + return + ( boost::size(ring) + >= core_detail::closure::minimum_ring_size::value ) + && is_topologically_closed::apply(ring) + && !is_simple::has_duplicates::apply(ring) + && !has_spikes::apply(ring) + && !(CheckSelfIntersections && geometry::intersects(ring)) + && is_properly_oriented::apply(ring); } }; @@ -148,18 +150,14 @@ struct is_valid_ring namespace dispatch { -// A Ring is a Polygon. -// A Polygon is always a simple geometric object provided that it is valid. +// A Ring is a Polygon with exterior boundary only. +// The Ring's boundary must be a LinearRing (see OGC 06-103-r4, +// §6.1.7.1, for the definition of LinearRing) // // Reference (for polygon validity): OGC 06-103r4 (§6.1.11.1) template struct is_valid - : detail::is_valid::is_valid_ring - < - Ring, - point_order::value, - closure::value - > + : detail::is_valid::is_valid_ring {};