summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/is_valid
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail/is_valid')
-rw-r--r--boost/geometry/algorithms/detail/is_valid/box.hpp27
-rw-r--r--boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp50
-rw-r--r--boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp4
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp13
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_spikes.hpp36
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp32
-rw-r--r--boost/geometry/algorithms/detail/is_valid/interface.hpp99
-rw-r--r--boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp12
-rw-r--r--boost/geometry/algorithms/detail/is_valid/linear.hpp81
-rw-r--r--boost/geometry/algorithms/detail/is_valid/multipolygon.hpp131
-rw-r--r--boost/geometry/algorithms/detail/is_valid/pointlike.hpp28
-rw-r--r--boost/geometry/algorithms/detail/is_valid/polygon.hpp163
-rw-r--r--boost/geometry/algorithms/detail/is_valid/ring.hpp98
-rw-r--r--boost/geometry/algorithms/detail/is_valid/segment.hpp16
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>();
+ }
}
};