diff options
Diffstat (limited to 'boost/geometry/algorithms/detail/is_valid')
14 files changed, 579 insertions, 211 deletions
diff --git a/boost/geometry/algorithms/detail/is_valid/box.hpp b/boost/geometry/algorithms/detail/is_valid/box.hpp index f82b3f9bf1..139502af78 100644 --- a/boost/geometry/algorithms/detail/is_valid/box.hpp +++ b/boost/geometry/algorithms/detail/is_valid/box.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -16,6 +16,7 @@ #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> @@ -30,15 +31,22 @@ namespace detail { namespace is_valid template <typename Box, std::size_t I> struct has_valid_corners { - static inline bool apply(Box const& box) + template <typename VisitPolicy> + static inline bool apply(Box const& box, VisitPolicy& visitor) { - if ( geometry::get<geometry::max_corner, I-1>(box) - <= - geometry::get<geometry::min_corner, I-1>(box) ) + if (math::equals(geometry::get<geometry::min_corner, I-1>(box), + geometry::get<geometry::max_corner, I-1>(box))) { - return false; + return + visitor.template apply<failure_wrong_topological_dimension>(); } - return has_valid_corners<Box, I-1>::apply(box); + else if (geometry::get<geometry::min_corner, I-1>(box) + > + geometry::get<geometry::max_corner, I-1>(box)) + { + return visitor.template apply<failure_wrong_corner_order>(); + } + return has_valid_corners<Box, I-1>::apply(box, visitor); } }; @@ -46,9 +54,10 @@ struct has_valid_corners template <typename Box> struct has_valid_corners<Box, 0> { - static inline bool apply(Box const&) + template <typename VisitPolicy> + static inline bool apply(Box const&, VisitPolicy& visitor) { - return true; + return visitor.template apply<no_failure>(); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp index 6824921b63..ab99a9921b 100644 --- a/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp +++ b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -25,33 +25,47 @@ namespace detail { namespace is_valid { #ifdef BOOST_GEOMETRY_TEST_DEBUG +template <typename Turn> +inline void debug_print_turn(Turn const& turn) +{ + std::cout << " [" + << geometry::method_char(turn.method) + << "," + << geometry::operation_char(turn.operations[0].operation) + << "/" + << geometry::operation_char(turn.operations[1].operation) + << " {" + << turn.operations[0].seg_id.multi_index + << ", " + << turn.operations[1].seg_id.multi_index + << "} {" + << turn.operations[0].seg_id.ring_index + << ", " + << turn.operations[1].seg_id.ring_index + << "} {" + << turn.operations[0].seg_id.segment_index + << ", " + << turn.operations[1].seg_id.segment_index + << "} " + << geometry::dsv(turn.point) + << "]"; +} + template <typename TurnIterator> inline void debug_print_turns(TurnIterator first, TurnIterator beyond) { std::cout << "turns:"; for (TurnIterator tit = first; tit != beyond; ++tit) { - std::cout << " [" - << geometry::method_char(tit->method) - << "," - << geometry::operation_char(tit->operations[0].operation) - << "/" - << geometry::operation_char(tit->operations[1].operation) - << " {" - << tit->operations[0].seg_id.multi_index - << ", " - << tit->operations[1].seg_id.multi_index - << "} {" - << tit->operations[0].seg_id.ring_index - << ", " - << tit->operations[1].seg_id.ring_index - << "} " - << geometry::dsv(tit->point) - << "]"; + debug_print_turn(*tit); } std::cout << std::endl << std::endl; } #else +template <typename Turn> +inline void debug_print_turn(Turn const&) +{} + template <typename TurnIterator> inline void debug_print_turns(TurnIterator, TurnIterator) {} diff --git a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp index 6f1c263646..a10e0fe596 100644 --- a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp +++ b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp @@ -50,8 +50,8 @@ struct debug_validity_phase<Polygon, polygon_tag> std::cout << "computing and analyzing turns..." << std::endl; break; case 4: - std::cout << "checking if holes are inside the exterior ring..." - << std::endl; + std::cout << "checking if interior rings are inside " + << "the exterior ring..." << std::endl; break; case 5: std::cout << "checking connectivity of interior..." << std::endl; diff --git a/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp index dd0922bb2b..5878841e70 100644 --- a/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp +++ b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -15,8 +15,10 @@ #include <boost/geometry/core/closure.hpp> #include <boost/geometry/policies/compare.hpp> +#include <boost/geometry/policies/is_valid/default_policy.hpp> #include <boost/geometry/views/closeable_view.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> namespace boost { namespace geometry @@ -30,7 +32,8 @@ namespace detail { namespace is_valid template <typename Range, closure_selector Closure> struct has_duplicates { - static inline bool apply(Range const& range) + template <typename VisitPolicy> + static inline bool apply(Range const& range, VisitPolicy& visitor) { typedef typename closeable_view<Range const, Closure>::type view_type; typedef typename boost::range_iterator<view_type const>::type iterator; @@ -39,7 +42,7 @@ struct has_duplicates if ( boost::size(view) < 2 ) { - return false; + return ! visitor.template apply<no_failure>(); } geometry::equal_to<typename boost::range_value<Range>::type> equal; @@ -50,10 +53,10 @@ struct has_duplicates { if ( equal(*it, *next) ) { - return true; + return ! visitor.template apply<failure_duplicate_points>(*it); } } - return false; + return ! visitor.template apply<no_failure>(); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp index 9b95017482..090c026e8b 100644 --- a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp +++ b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -13,15 +13,22 @@ #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 @@ -60,7 +67,7 @@ struct not_equal_to template <typename OtherPoint> inline bool operator()(OtherPoint const& other) const { - return !geometry::equals(other, m_point); + return ! geometry::equals(other, m_point); } }; @@ -69,13 +76,17 @@ struct not_equal_to template <typename Range, closure_selector Closure> struct has_spikes { - static inline bool apply(Range const& range) + 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); @@ -85,7 +96,7 @@ struct has_spikes { // the range has only one distinct point, so it // cannot have a spike - return false; + return ! visitor.template apply<no_failure>(); } iterator next = std::find_if(cur, boost::end(view), not_equal(*cur)); @@ -93,7 +104,7 @@ struct has_spikes { // the range has only two distinct points, so it // cannot have a spike - return false; + return ! visitor.template apply<no_failure>(); } while ( next != boost::end(view) ) @@ -102,7 +113,8 @@ struct has_spikes *next, *cur) ) { - return true; + return + ! visitor.template apply<failure_spikes>(is_linear, *cur); } prev = cur; cur = next; @@ -120,10 +132,18 @@ struct has_spikes not_equal(range::back(view))); iterator next = std::find_if(cur, boost::end(view), not_equal(*cur)); - return detail::point_is_spike_or_equal(*prev, *next, *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 false; + return ! visitor.template apply<no_failure>(); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp index 220a67bcd1..ecbc4782b2 100644 --- a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp +++ b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -10,6 +10,11 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP +#include <vector> + +#include <boost/assert.hpp> +#include <boost/range.hpp> + #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/policies/predicate_based_interrupt_policy.hpp> @@ -22,7 +27,6 @@ #include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp> - namespace boost { namespace geometry { @@ -64,8 +68,10 @@ public: > turn_type; // returns true if all turns are valid - template <typename Turns> - static inline bool apply(Geometry const& geometry, Turns& turns) + template <typename Turns, typename VisitPolicy> + static inline bool apply(Geometry const& geometry, + Turns& turns, + VisitPolicy& visitor) { rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>(geometry); @@ -80,7 +86,23 @@ public: turns, interrupt_policy); - return !interrupt_policy.has_intersections; + if (interrupt_policy.has_intersections) + { + BOOST_ASSERT(! boost::empty(turns)); + return visitor.template apply<failure_self_intersections>(turns); + } + else + { + return visitor.template apply<no_failure>(); + } + } + + // returns true if all turns are valid + template <typename VisitPolicy> + static inline bool apply(Geometry const& geometry, VisitPolicy& visitor) + { + std::vector<turn_type> turns; + return apply(geometry, turns, visitor); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/interface.hpp b/boost/geometry/algorithms/detail/is_valid/interface.hpp index 4b232fd436..f83b09c437 100644 --- a/boost/geometry/algorithms/detail/is_valid/interface.hpp +++ b/boost/geometry/algorithms/detail/is_valid/interface.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -10,13 +10,19 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP -#include <boost/variant/static_visitor.hpp> +#include <sstream> +#include <string> + #include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> +#include <boost/geometry/policies/is_valid/default_policy.hpp> +#include <boost/geometry/policies/is_valid/failing_reason_policy.hpp> +#include <boost/geometry/policies/is_valid/failure_type_policy.hpp> namespace boost { namespace geometry @@ -28,48 +34,123 @@ namespace resolve_variant { template <typename Geometry> struct is_valid { - static inline bool apply(Geometry const& geometry) + template <typename VisitPolicy> + static inline bool apply(Geometry const& geometry, VisitPolicy& visitor) { concept::check<Geometry const>(); - return dispatch::is_valid<Geometry>::apply(geometry); + return dispatch::is_valid<Geometry>::apply(geometry, visitor); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { + template <typename VisitPolicy> struct visitor : boost::static_visitor<bool> { + visitor(VisitPolicy& policy) : m_policy(policy) {} + template <typename Geometry> bool operator()(Geometry const& geometry) const { - return is_valid<Geometry>::apply(geometry); + return is_valid<Geometry>::apply(geometry, m_policy); } + + VisitPolicy& m_policy; }; + template <typename VisitPolicy> static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + VisitPolicy& policy_visitor) { - return boost::apply_visitor(visitor(), geometry); + return boost::apply_visitor(visitor<VisitPolicy>(policy_visitor), + geometry); } }; } // namespace resolve_variant +// Undocumented for now +template <typename Geometry, typename VisitPolicy> +inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor) +{ + return resolve_variant::is_valid<Geometry>::apply(geometry, visitor); +} + + /*! \brief \brief_check{is valid (in the OGC sense)} \ingroup is_valid \tparam Geometry \tparam_geometry \param geometry \param_geometry -\return \return_check{is valid (in the OGC sense)} +\return \return_check{is valid (in the OGC sense); + furthermore, the following geometries are considered valid: + multi-geometries with no elements, + linear geometries containing spikes, + areal geometries with duplicate (consecutive) points} \qbk{[include reference/algorithms/is_valid.qbk]} */ template <typename Geometry> inline bool is_valid(Geometry const& geometry) { - return resolve_variant::is_valid<Geometry>::apply(geometry); + is_valid_default_policy<> policy_visitor; + return is_valid(geometry, policy_visitor); +} + + +/*! +\brief \brief_check{is valid (in the OGC sense)} +\ingroup is_valid +\tparam Geometry \tparam_geometry +\param geometry \param_geometry +\param failure An enumeration value indicating that the geometry is + valid or not, and if not valid indicating the reason why +\return \return_check{is valid (in the OGC sense); + furthermore, the following geometries are considered valid: + multi-geometries with no elements, + linear geometries containing spikes, + areal geometries with duplicate (consecutive) points} + +\qbk{distinguish,with failure value} +\qbk{[include reference/algorithms/is_valid_with_failure.qbk]} +*/ +template <typename Geometry> +inline bool is_valid(Geometry const& geometry, validity_failure_type& failure) +{ + failure_type_policy<> policy_visitor; + bool result = is_valid(geometry, policy_visitor); + failure = policy_visitor.failure(); + return result; +} + + +/*! +\brief \brief_check{is valid (in the OGC sense)} +\ingroup is_valid +\tparam Geometry \tparam_geometry +\param geometry \param_geometry +\param message A string containing a message stating if the geometry + is valid or not, and if not valid a reason why +\return \return_check{is valid (in the OGC sense); + furthermore, the following geometries are considered valid: + multi-geometries with no elements, + linear geometries containing spikes, + areal geometries with duplicate (consecutive) points} + +\qbk{distinguish,with message} +\qbk{[include reference/algorithms/is_valid_with_message.qbk]} +*/ +template <typename Geometry> +inline bool is_valid(Geometry const& geometry, std::string& message) +{ + std::ostringstream stream; + failing_reason_policy<> policy_visitor(stream); + bool result = is_valid(geometry, policy_visitor); + message = stream.str(); + return result; } diff --git a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp index f9d926770e..0d80d6f6c0 100644 --- a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp +++ b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -72,6 +72,16 @@ template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct is_acceptable_turn {}; +template <typename Ring> +struct is_acceptable_turn<Ring, ring_tag> +{ + template <typename Turn> + static inline bool apply(Turn const&) + { + return false; + } +}; + template <typename Polygon> class is_acceptable_turn<Polygon, polygon_tag> { diff --git a/boost/geometry/algorithms/detail/is_valid/linear.hpp b/boost/geometry/algorithms/detail/is_valid/linear.hpp index 244df9b035..69243563ec 100644 --- a/boost/geometry/algorithms/detail/is_valid/linear.hpp +++ b/boost/geometry/algorithms/detail/is_valid/linear.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -21,6 +21,7 @@ #include <boost/geometry/util/range.hpp> #include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp> #include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp> @@ -36,11 +37,18 @@ namespace detail { namespace is_valid { -template <typename Linestring, bool AllowSpikes> +template <typename Linestring> struct is_valid_linestring { - static inline bool apply(Linestring const& linestring) + template <typename VisitPolicy> + static inline bool apply(Linestring const& linestring, + VisitPolicy& visitor) { + if (boost::size(linestring) < 2) + { + return visitor.template apply<failure_few_points>(); + } + std::size_t num_distinct = detail::num_distinct_consecutive_points < Linestring, @@ -49,14 +57,17 @@ struct is_valid_linestring not_equal_to<typename point_type<Linestring>::type> >::apply(linestring); - if ( num_distinct < 2u ) + if (num_distinct < 2u) { - return false; + return + visitor.template apply<failure_wrong_topological_dimension>(); } - return num_distinct == 2u - || AllowSpikes - || !has_spikes<Linestring, closed>::apply(linestring); + if (num_distinct == 2u) + { + return visitor.template apply<no_failure>(); + } + return ! has_spikes<Linestring, closed>::apply(linestring, visitor); } }; @@ -84,9 +95,11 @@ namespace dispatch // By default, spikes are disallowed // // Reference: OGC 06-103r4 (6.1.6.1) -template <typename Linestring, bool AllowSpikes> -struct is_valid<Linestring, linestring_tag, AllowSpikes> - : detail::is_valid::is_valid_linestring<Linestring, AllowSpikes> +template <typename Linestring, bool AllowEmptyMultiGeometries> +struct is_valid + < + Linestring, linestring_tag, AllowEmptyMultiGeometries + > : detail::is_valid::is_valid_linestring<Linestring> {}; @@ -96,21 +109,47 @@ struct is_valid<Linestring, linestring_tag, AllowSpikes> // are on the boundaries of both elements. // // Reference: OGC 06-103r4 (6.1.8.1; Fig. 9) -template <typename MultiLinestring, bool AllowSpikes> -struct is_valid<MultiLinestring, multi_linestring_tag, AllowSpikes> +template <typename MultiLinestring, bool AllowEmptyMultiGeometries> +class is_valid + < + MultiLinestring, multi_linestring_tag, AllowEmptyMultiGeometries + > { - static inline bool apply(MultiLinestring const& multilinestring) +private: + template <typename VisitPolicy> + struct per_linestring + { + per_linestring(VisitPolicy& policy) : m_policy(policy) {} + + template <typename Linestring> + inline bool apply(Linestring const& linestring) const + { + return detail::is_valid::is_valid_linestring + < + Linestring + >::apply(linestring, m_policy); + } + + VisitPolicy& m_policy; + }; + +public: + template <typename VisitPolicy> + static inline bool apply(MultiLinestring const& multilinestring, + VisitPolicy& visitor) { + if (AllowEmptyMultiGeometries && boost::empty(multilinestring)) + { + return visitor.template apply<no_failure>(); + } + return detail::check_iterator_range < - detail::is_valid::is_valid_linestring - < - typename boost::range_value<MultiLinestring>::type, - AllowSpikes - >, - false // do not allow empty multilinestring + per_linestring<VisitPolicy>, + false // do not check for empty multilinestring (done above) >::apply(boost::begin(multilinestring), - boost::end(multilinestring)); + boost::end(multilinestring), + per_linestring<VisitPolicy>(visitor)); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp index 3d0ebb5f82..9362bfca0e 100644 --- a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp +++ b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -25,6 +25,7 @@ #include <boost/geometry/geometries/box.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/within.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> @@ -49,12 +50,11 @@ namespace detail { namespace is_valid { -template <typename MultiPolygon, bool AllowDuplicates> +template <typename MultiPolygon, bool AllowEmptyMultiGeometries> class is_valid_multipolygon : is_valid_polygon < typename boost::range_value<MultiPolygon>::type, - AllowDuplicates, true // check only the validity of rings > { @@ -62,18 +62,23 @@ private: typedef is_valid_polygon < typename boost::range_value<MultiPolygon>::type, - AllowDuplicates, true > base; - template <typename PolygonIterator, typename TurnIterator> + template + < + typename PolygonIterator, + typename TurnIterator, + typename VisitPolicy + > static inline bool are_polygon_interiors_disjoint(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, - TurnIterator turns_beyond) + TurnIterator turns_beyond, + VisitPolicy& visitor) { // collect all polygons that have turns std::set<signed_index_type> multi_indices; @@ -89,22 +94,29 @@ private: for (PolygonIterator it = polygons_first; it != polygons_beyond; ++it, ++multi_index) { - if ( multi_indices.find(multi_index) == multi_indices.end() ) + if (multi_indices.find(multi_index) == multi_indices.end()) { polygon_iterators.push_back(it); } } - typename base::item_visitor visitor; + typename base::item_visitor_type item_visitor; geometry::partition < geometry::model::box<typename point_type<MultiPolygon>::type>, typename base::expand_box, typename base::overlaps_box - >::apply(polygon_iterators, visitor); + >::apply(polygon_iterators, item_visitor); - return !visitor.items_overlap; + if (item_visitor.items_overlap) + { + return visitor.template apply<failure_intersecting_interiors>(); + } + else + { + return visitor.template apply<no_failure>(); + } } @@ -132,11 +144,17 @@ private: template <typename Predicate> struct has_property_per_polygon { - template <typename PolygonIterator, typename TurnIterator> + template + < + typename PolygonIterator, + typename TurnIterator, + typename VisitPolicy + > static inline bool apply(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, - TurnIterator turns_beyond) + TurnIterator turns_beyond, + VisitPolicy& visitor) { signed_index_type multi_index = 0; for (PolygonIterator it = polygons_first; it != polygons_beyond; @@ -157,9 +175,10 @@ private: turns_beyond, turns_beyond); - if ( !Predicate::apply(*it, + if (! Predicate::apply(*it, filtered_turns_first, - filtered_turns_beyond) ) + filtered_turns_beyond, + visitor)) { return false; } @@ -170,49 +189,82 @@ private: - template <typename PolygonIterator, typename TurnIterator> + template + < + typename PolygonIterator, + typename TurnIterator, + typename VisitPolicy + > static inline bool have_holes_inside(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, - TurnIterator turns_beyond) + TurnIterator turns_beyond, + VisitPolicy& visitor) { return has_property_per_polygon < typename base::has_holes_inside >::apply(polygons_first, polygons_beyond, - turns_first, turns_beyond); + turns_first, turns_beyond, visitor); } - template <typename PolygonIterator, typename TurnIterator> + template + < + typename PolygonIterator, + typename TurnIterator, + typename VisitPolicy + > static inline bool have_connected_interior(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, - TurnIterator turns_beyond) + TurnIterator turns_beyond, + VisitPolicy& visitor) { return has_property_per_polygon < typename base::has_connected_interior >::apply(polygons_first, polygons_beyond, - turns_first, turns_beyond); + turns_first, turns_beyond, visitor); } + template <typename VisitPolicy> + struct per_polygon + { + per_polygon(VisitPolicy& policy) : m_policy(policy) {} + + template <typename Polygon> + inline bool apply(Polygon const& polygon) const + { + return base::apply(polygon, m_policy); + } + + VisitPolicy& m_policy; + }; public: - static inline bool apply(MultiPolygon const& multipolygon) + template <typename VisitPolicy> + static inline bool apply(MultiPolygon const& multipolygon, + VisitPolicy& visitor) { typedef debug_validity_phase<MultiPolygon> debug_phase; + if (AllowEmptyMultiGeometries && boost::empty(multipolygon)) + { + return visitor.template apply<no_failure>(); + } + // check validity of all polygons ring debug_phase::apply(1); - if ( !detail::check_iterator_range + if (! detail::check_iterator_range < - base, - false // do not allow empty multi-polygons + per_polygon<VisitPolicy>, + false // do not check for empty multipolygon (done above) >::apply(boost::begin(multipolygon), - boost::end(multipolygon)) ) + boost::end(multipolygon), + per_polygon<VisitPolicy>(visitor))) { return false; } @@ -224,10 +276,11 @@ public: typedef has_valid_self_turns<MultiPolygon> has_valid_turns; std::deque<typename has_valid_turns::turn_type> turns; - bool has_invalid_turns = !has_valid_turns::apply(multipolygon, turns); + bool has_invalid_turns = + ! has_valid_turns::apply(multipolygon, turns, visitor); debug_print_turns(turns.begin(), turns.end()); - if ( has_invalid_turns ) + if (has_invalid_turns) { return false; } @@ -237,10 +290,11 @@ public: // exterior and not one inside the other debug_phase::apply(3); - if ( !have_holes_inside(boost::begin(multipolygon), + if (! have_holes_inside(boost::begin(multipolygon), boost::end(multipolygon), turns.begin(), - turns.end()) ) + turns.end(), + visitor)) { return false; } @@ -249,10 +303,11 @@ public: // check that each polygon's interior is connected debug_phase::apply(4); - if ( !have_connected_interior(boost::begin(multipolygon), + if (! have_connected_interior(boost::begin(multipolygon), boost::end(multipolygon), turns.begin(), - turns.end()) ) + turns.end(), + visitor)) { return false; } @@ -263,7 +318,8 @@ public: return are_polygon_interiors_disjoint(boost::begin(multipolygon), boost::end(multipolygon), turns.begin(), - turns.end()); + turns.end(), + visitor); } }; @@ -282,9 +338,14 @@ namespace dispatch // that the MultiPolygon is also valid. // // Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14) -template <typename MultiPolygon, bool AllowSpikes, bool AllowDuplicates> -struct is_valid<MultiPolygon, multi_polygon_tag, AllowSpikes, AllowDuplicates> - : detail::is_valid::is_valid_multipolygon<MultiPolygon, AllowDuplicates> +template <typename MultiPolygon, bool AllowEmptyMultiGeometries> +struct is_valid + < + MultiPolygon, multi_polygon_tag, AllowEmptyMultiGeometries + > : detail::is_valid::is_valid_multipolygon + < + MultiPolygon, AllowEmptyMultiGeometries + > {}; diff --git a/boost/geometry/algorithms/detail/is_valid/pointlike.hpp b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp index 8a4818ef15..8e5ebaadcc 100644 --- a/boost/geometry/algorithms/detail/is_valid/pointlike.hpp +++ b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -14,6 +14,7 @@ #include <boost/geometry/core/tags.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> @@ -30,9 +31,10 @@ namespace dispatch template <typename Point> struct is_valid<Point, point_tag> { - static inline bool apply(Point const&) + template <typename VisitPolicy> + static inline bool apply(Point const&, VisitPolicy& visitor) { - return true; + return visitor.template apply<no_failure>(); } }; @@ -42,12 +44,24 @@ struct is_valid<Point, point_tag> // (have identical coordinate values in X and Y) // // Reference: OGC 06-103r4 (6.1.5) -template <typename MultiPoint> -struct is_valid<MultiPoint, multi_point_tag> +template <typename MultiPoint, bool AllowEmptyMultiGeometries> +struct is_valid<MultiPoint, multi_point_tag, AllowEmptyMultiGeometries> { - static inline bool apply(MultiPoint const& multipoint) + template <typename VisitPolicy> + static inline bool apply(MultiPoint const& multipoint, + VisitPolicy& visitor) { - return boost::size(multipoint) > 0; + if (AllowEmptyMultiGeometries || boost::size(multipoint) > 0) + { + // we allow empty multi-geometries, so an empty multipoint + // is considered valid + return visitor.template apply<no_failure>(); + } + else + { + // we do not allow an empty multipoint + return visitor.template apply<failure_few_points>(); + } } }; diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp index 3a91999208..17eefd226f 100644 --- a/boost/geometry/algorithms/detail/is_valid/polygon.hpp +++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -26,6 +26,7 @@ #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> +#include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/geometries/box.hpp> @@ -36,6 +37,7 @@ #include <boost/geometry/algorithms/disjoint.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/within.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> @@ -62,51 +64,58 @@ namespace detail { namespace is_valid { -template -< - typename Polygon, - bool AllowDuplicates, - bool CheckRingValidityOnly = false -> +template <typename Polygon, bool CheckRingValidityOnly = false> class is_valid_polygon { protected: typedef debug_validity_phase<Polygon> debug_phase; + template <typename VisitPolicy> + struct per_ring + { + per_ring(VisitPolicy& policy) : m_policy(policy) {} + + template <typename Ring> + inline bool apply(Ring const& ring) const + { + return detail::is_valid::is_valid_ring + < + Ring, false, true + >::apply(ring, m_policy); + } + VisitPolicy& m_policy; + }; - template <typename InteriorRings> - static bool has_valid_interior_rings(InteriorRings const& interior_rings) + template <typename InteriorRings, typename VisitPolicy> + static bool has_valid_interior_rings(InteriorRings const& interior_rings, + VisitPolicy& visitor) { return detail::check_iterator_range < - detail::is_valid::is_valid_ring - < - typename boost::range_value<InteriorRings>::type, - AllowDuplicates, - false, // do not check self-intersections - true // indicate that the ring is interior - > + per_ring<VisitPolicy>, + true // allow for empty interior ring range >::apply(boost::begin(interior_rings), - boost::end(interior_rings)); + boost::end(interior_rings), + per_ring<VisitPolicy>(visitor)); } struct has_valid_rings { - static inline bool apply(Polygon const& polygon) + template <typename VisitPolicy> + static inline bool apply(Polygon const& polygon, VisitPolicy& visitor) { typedef typename ring_type<Polygon>::type ring_type; // check validity of exterior ring debug_phase::apply(1); - if ( !detail::is_valid::is_valid_ring + if (! detail::is_valid::is_valid_ring < ring_type, - AllowDuplicates, false // do not check self intersections - >::apply(exterior_ring(polygon)) ) + >::apply(exterior_ring(polygon), visitor)) { return false; } @@ -114,12 +123,13 @@ protected: // check validity of interior rings debug_phase::apply(2); - return has_valid_interior_rings(geometry::interior_rings(polygon)); + return has_valid_interior_rings(geometry::interior_rings(polygon), + visitor); } }; - // structs from partition -- start + // structs for partition -- start struct expand_box { template <typename Box, typename Iterator> @@ -135,24 +145,24 @@ protected: template <typename Box, typename Iterator> static inline bool apply(Box const& box, Iterator const& it) { - return !geometry::disjoint(*it, box); + return ! geometry::disjoint(*it, box); } }; - struct item_visitor + struct item_visitor_type { bool items_overlap; - item_visitor() : items_overlap(false) {} + item_visitor_type() : items_overlap(false) {} template <typename Item1, typename Item2> inline void apply(Item1 const& item1, Item2 const& item2) { - if ( !items_overlap - && (geometry::within(*points_begin(*item1), *item2) - || geometry::within(*points_begin(*item2), *item1)) - ) + if (! items_overlap + && (geometry::within(*points_begin(*item1), *item2) + || geometry::within(*points_begin(*item2), *item1)) + ) { items_overlap = true; } @@ -165,27 +175,29 @@ protected: < typename RingIterator, typename ExteriorRing, - typename TurnIterator + typename TurnIterator, + typename VisitPolicy > static inline bool are_holes_inside(RingIterator rings_first, RingIterator rings_beyond, ExteriorRing const& exterior_ring, TurnIterator turns_first, - TurnIterator turns_beyond) + TurnIterator turns_beyond, + VisitPolicy& visitor) { // collect the interior ring indices that have turns with the // exterior ring std::set<signed_index_type> ring_indices; for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit) { - if ( tit->operations[0].seg_id.ring_index == -1 ) + if (tit->operations[0].seg_id.ring_index == -1) { - BOOST_ASSERT( tit->operations[1].seg_id.ring_index != -1 ); + BOOST_ASSERT(tit->operations[1].seg_id.ring_index != -1); ring_indices.insert(tit->operations[1].seg_id.ring_index); } - else if ( tit->operations[1].seg_id.ring_index == -1 ) + else if (tit->operations[1].seg_id.ring_index == -1) { - BOOST_ASSERT( tit->operations[0].seg_id.ring_index != -1 ); + BOOST_ASSERT(tit->operations[0].seg_id.ring_index != -1); ring_indices.insert(tit->operations[0].seg_id.ring_index); } } @@ -196,10 +208,10 @@ protected: { // do not examine interior rings that have turns with the // exterior ring - if ( ring_indices.find(ring_index) == ring_indices.end() - && !geometry::covered_by(range::front(*it), exterior_ring) ) + if (ring_indices.find(ring_index) == ring_indices.end() + && ! geometry::covered_by(range::front(*it), exterior_ring)) { - return false; + return visitor.template apply<failure_interior_rings_outside>(); } } @@ -216,7 +228,7 @@ protected: for (RingIterator it = rings_first; it != rings_beyond; ++it, ++ring_index) { - if ( ring_indices.find(ring_index) == ring_indices.end() ) + if (ring_indices.find(ring_index) == ring_indices.end()) { ring_iterators.push_back(it); } @@ -224,47 +236,59 @@ protected: // call partition to check is interior rings are disjoint from // each other - item_visitor visitor; + item_visitor_type item_visitor; geometry::partition < geometry::model::box<typename point_type<Polygon>::type>, expand_box, overlaps_box - >::apply(ring_iterators, visitor); + >::apply(ring_iterators, item_visitor); - return !visitor.items_overlap; + if (item_visitor.items_overlap) + { + return visitor.template apply<failure_nested_interior_rings>(); + } + else + { + return visitor.template apply<no_failure>(); + } } template < typename InteriorRings, typename ExteriorRing, - typename TurnIterator + typename TurnIterator, + typename VisitPolicy > static inline bool are_holes_inside(InteriorRings const& interior_rings, ExteriorRing const& exterior_ring, TurnIterator first, - TurnIterator beyond) + TurnIterator beyond, + VisitPolicy& visitor) { return are_holes_inside(boost::begin(interior_rings), boost::end(interior_rings), exterior_ring, first, - beyond); + beyond, + visitor); } struct has_holes_inside { - template <typename TurnIterator> + template <typename TurnIterator, typename VisitPolicy> static inline bool apply(Polygon const& polygon, TurnIterator first, - TurnIterator beyond) + TurnIterator beyond, + VisitPolicy& visitor) { return are_holes_inside(geometry::interior_rings(polygon), geometry::exterior_ring(polygon), first, - beyond); + beyond, + visitor); } }; @@ -273,10 +297,11 @@ protected: struct has_connected_interior { - template <typename TurnIterator> + template <typename TurnIterator, typename VisitPolicy> static inline bool apply(Polygon const& polygon, TurnIterator first, - TurnIterator beyond) + TurnIterator beyond, + VisitPolicy& visitor) { typedef typename std::iterator_traits < @@ -299,19 +324,27 @@ protected: debug_print_complement_graph(std::cout, g); - return !g.has_cycles(); + if (g.has_cycles()) + { + return visitor.template apply<failure_disconnected_interior>(); + } + else + { + return visitor.template apply<no_failure>(); + } } }; public: - static inline bool apply(Polygon const& polygon) + template <typename VisitPolicy> + static inline bool apply(Polygon const& polygon, VisitPolicy& visitor) { - if ( !has_valid_rings::apply(polygon) ) + if (! has_valid_rings::apply(polygon, visitor)) { return false; } - if ( CheckRingValidityOnly ) + if (BOOST_GEOMETRY_CONDITION(CheckRingValidityOnly)) { return true; } @@ -322,10 +355,11 @@ public: typedef has_valid_self_turns<Polygon> has_valid_turns; std::deque<typename has_valid_turns::turn_type> turns; - bool has_invalid_turns = !has_valid_turns::apply(polygon, turns); + bool has_invalid_turns + = ! has_valid_turns::apply(polygon, turns, visitor); debug_print_turns(turns.begin(), turns.end()); - if ( has_invalid_turns ) + if (has_invalid_turns) { return false; } @@ -333,7 +367,9 @@ public: // check if all interior rings are inside the exterior ring debug_phase::apply(4); - if ( !has_holes_inside::apply(polygon, turns.begin(), turns.end()) ) + if (! has_holes_inside::apply(polygon, + turns.begin(), turns.end(), + visitor)) { return false; } @@ -343,7 +379,8 @@ public: return has_connected_interior::apply(polygon, turns.begin(), - turns.end()); + turns.end(), + visitor); } }; @@ -361,9 +398,11 @@ namespace dispatch // A Polygon is always a simple geometric object provided that it is valid. // // Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1) -template <typename Polygon, bool AllowSpikes, bool AllowDuplicates> -struct is_valid<Polygon, polygon_tag, AllowSpikes, AllowDuplicates> - : detail::is_valid::is_valid_polygon<Polygon, AllowDuplicates> +template <typename Polygon, bool AllowEmptyMultiGeometries> +struct is_valid + < + Polygon, polygon_tag, AllowEmptyMultiGeometries + > : detail::is_valid::is_valid_polygon<Polygon> {}; diff --git a/boost/geometry/algorithms/detail/is_valid/ring.hpp b/boost/geometry/algorithms/detail/is_valid/ring.hpp index c88df79b05..c663a96d28 100644 --- a/boost/geometry/algorithms/detail/is_valid/ring.hpp +++ b/boost/geometry/algorithms/detail/is_valid/ring.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -10,6 +10,8 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP +#include <deque> + #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/point_order.hpp> @@ -19,16 +21,22 @@ #include <boost/geometry/algorithms/equals.hpp> -#include <boost/geometry/views/reversible_view.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/intersects.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> +#include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> +#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp> #include <boost/geometry/strategies/area.hpp> +#ifdef BOOST_GEOMETRY_TEST_DEBUG +#include <boost/geometry/io/dsv/write.hpp> +#endif + namespace boost { namespace geometry { @@ -42,18 +50,27 @@ namespace detail { namespace is_valid template <typename Ring, closure_selector Closure /* open */> struct is_topologically_closed { - static inline bool apply(Ring const&) + template <typename VisitPolicy> + static inline bool apply(Ring const&, VisitPolicy& visitor) { - return true; + return visitor.template apply<no_failure>(); } }; template <typename Ring> struct is_topologically_closed<Ring, closed> { - static inline bool apply(Ring const& ring) + template <typename VisitPolicy> + static inline bool apply(Ring const& ring, VisitPolicy& visitor) { - return geometry::equals(range::front(ring), range::back(ring)); + if (geometry::equals(range::front(ring), range::back(ring))) + { + return visitor.template apply<no_failure>(); + } + else + { + return visitor.template apply<failure_not_closed>(); + } } }; @@ -92,7 +109,8 @@ struct is_properly_oriented typedef typename default_area_result<Ring>::type area_result_type; - static inline bool apply(Ring const& ring) + template <typename VisitPolicy> + static inline bool apply(Ring const& ring, VisitPolicy& visitor) { typename ring_area_predicate < @@ -101,7 +119,14 @@ struct is_properly_oriented // Check area area_result_type const zero = area_result_type(); - return predicate(ring_area_type::apply(ring, strategy_type()), zero); + if (predicate(ring_area_type::apply(ring, strategy_type()), zero)) + { + return visitor.template apply<no_failure>(); + } + else + { + return visitor.template apply<failure_wrong_orientation>(); + } } }; @@ -110,41 +135,60 @@ struct is_properly_oriented template < typename Ring, - bool AllowDuplicates, bool CheckSelfIntersections = true, bool IsInteriorRing = false > struct is_valid_ring { - static inline bool apply(Ring const& ring) + template <typename VisitPolicy> + static inline bool apply(Ring const& ring, VisitPolicy& visitor) { // return invalid if any of the following condition holds: // (a) the ring's size is below the minimal one - // (b) the ring is not topologically closed - // (c) the ring has spikes - // (d) the ring has duplicate points (if AllowDuplicates is false) - // (e) the boundary of the ring has self-intersections - // (f) the order of the points is inconsistent with the defined order + // (b) the ring consists of at most two distinct points + // (c) the ring is not topologically closed + // (d) the ring has spikes + // (e) the ring has duplicate points (if AllowDuplicates is false) + // (f) the boundary of the ring has self-intersections + // (g) 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 (c). closure_selector const closure = geometry::closure<Ring>::value; + typedef typename closeable_view<Ring const, closure>::type view_type; + + if (boost::size(ring) + < core_detail::closure::minimum_ring_size<closure>::value) + { + return visitor.template apply<failure_few_points>(); + } + + view_type const view(ring); + if (detail::num_distinct_consecutive_points + < + view_type, 4u, true, + not_equal_to<typename point_type<Ring>::type> + >::apply(view) + < 4u) + { + return + visitor.template apply<failure_wrong_topological_dimension>(); + } return - ( boost::size(ring) - >= core_detail::closure::minimum_ring_size<closure>::value ) - && is_topologically_closed<Ring, closure>::apply(ring) - && (AllowDuplicates || !has_duplicates<Ring, closure>::apply(ring)) - && !has_spikes<Ring, closure>::apply(ring) - && !(CheckSelfIntersections && geometry::intersects(ring)) - && is_properly_oriented<Ring, IsInteriorRing>::apply(ring); + is_topologically_closed<Ring, closure>::apply(ring, visitor) + && ! has_duplicates<Ring, closure>::apply(ring, visitor) + && ! has_spikes<Ring, closure>::apply(ring, visitor) + && (! CheckSelfIntersections + || has_valid_self_turns<Ring>::apply(ring, visitor)) + && is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor); } }; -}} // namespace dispatch +}} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL @@ -158,9 +202,11 @@ namespace dispatch // 6.1.7.1, for the definition of LinearRing) // // Reference (for polygon validity): OGC 06-103r4 (6.1.11.1) -template <typename Ring, bool AllowSpikes, bool AllowDuplicates> -struct is_valid<Ring, ring_tag, AllowSpikes, AllowDuplicates> - : detail::is_valid::is_valid_ring<Ring, AllowDuplicates> +template <typename Ring, bool AllowEmptyMultiGeometries> +struct is_valid + < + Ring, ring_tag, AllowEmptyMultiGeometries + > : detail::is_valid::is_valid_ring<Ring> {}; diff --git a/boost/geometry/algorithms/detail/is_valid/segment.hpp b/boost/geometry/algorithms/detail/is_valid/segment.hpp index 486289dabe..0b60890dc0 100644 --- a/boost/geometry/algorithms/detail/is_valid/segment.hpp +++ b/boost/geometry/algorithms/detail/is_valid/segment.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -15,6 +15,7 @@ #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> @@ -40,13 +41,22 @@ namespace dispatch template <typename Segment> struct is_valid<Segment, segment_tag> { - static inline bool apply(Segment const& segment) + template <typename VisitPolicy> + static inline bool apply(Segment const& segment, VisitPolicy& visitor) { typename point_type<Segment>::type p[2]; detail::assign_point_from_index<0>(segment, p[0]); detail::assign_point_from_index<1>(segment, p[1]); - return !geometry::equals(p[0], p[1]); + if(! geometry::equals(p[0], p[1])) + { + return visitor.template apply<no_failure>(); + } + else + { + return + visitor.template apply<failure_wrong_topological_dimension>(); + } } }; |