diff --git a/include/boost/geometry/algorithms/detail/check_iterator_range.hpp b/include/boost/geometry/algorithms/detail/check_iterator_range.hpp index 71b06cc58..04355b7f5 100644 --- a/include/boost/geometry/algorithms/detail/check_iterator_range.hpp +++ b/include/boost/geometry/algorithms/detail/check_iterator_range.hpp @@ -10,6 +10,8 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP +#include + namespace boost { namespace geometry { @@ -22,7 +24,8 @@ namespace detail // predicate. // The predicate must be implemented as having a static apply unary // method that returns a bool. -template +// By default an empty range is accepted +template struct check_iterator_range { template @@ -35,7 +38,28 @@ struct check_iterator_range return false; } } - return AllowEmptyMultiRange || first != beyond; + return AllowEmptyRange || first != beyond; + }; + + + // version where we can pass a predicate object + template + static inline bool apply(InputIterator first, + InputIterator beyond, + Predicate const& predicate) + { + // in case predicate's apply method is static, MSVC will + // complain that predicate is not used + boost::ignore_unused(predicate); + + for (InputIterator it = first; it != beyond; ++it) + { + if ( !predicate.apply(*it) ) + { + return false; + } + } + return AllowEmptyRange || first != beyond; }; }; diff --git a/include/boost/geometry/algorithms/detail/is_simple/areal.hpp b/include/boost/geometry/algorithms/detail/is_simple/areal.hpp index 678253c07..97d52e45f 100644 --- a/include/boost/geometry/algorithms/detail/is_simple/areal.hpp +++ b/include/boost/geometry/algorithms/detail/is_simple/areal.hpp @@ -61,8 +61,7 @@ private: is_simple_ring < typename boost::range_value::type - >, - true // allow the iterator range to be empty + > >::apply(boost::begin(interior_rings), boost::end(interior_rings)); } @@ -126,7 +125,8 @@ struct is_simple detail::is_simple::is_simple_polygon < typename boost::range_value::type - > + >, + false // do not allow empty multi-polygon >::apply(boost::begin(multipolygon), boost::end(multipolygon)); } }; diff --git a/include/boost/geometry/algorithms/detail/is_simple/debug_linear.hpp b/include/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp similarity index 65% rename from include/boost/geometry/algorithms/detail/is_simple/debug_linear.hpp rename to include/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp index ad328219d..75c37c68f 100644 --- a/include/boost/geometry/algorithms/detail/is_simple/debug_linear.hpp +++ b/include/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp @@ -7,8 +7,8 @@ // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_LINEAR_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_LINEAR_HPP +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP #ifdef BOOST_GEOMETRY_TEST_DEBUG #include @@ -26,7 +26,6 @@ #include #include -#include #endif @@ -37,33 +36,6 @@ namespace detail { namespace is_simple { -#ifdef BOOST_GEOMETRY_TEST_DEBUG -template -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) - << " " - << geometry::dsv(tit->point) - << "] "; - } - std::cout << std::endl << std::endl; -} -#else -template -inline void debug_print_turns(TurnIterator, TurnIterator) -{ -} -#endif // BOOST_GEOMETRY_TEST_DEBUG - - #ifdef BOOST_GEOMETRY_TEST_DEBUG template inline void debug_print_boundary_points(MultiLinestring const& multilinestring) @@ -107,4 +79,4 @@ inline void debug_print_boundary_points(MultiLinestring const&) }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_LINEAR_HPP +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP diff --git a/include/boost/geometry/algorithms/detail/is_simple/linear.hpp b/include/boost/geometry/algorithms/detail/is_simple/linear.hpp index 69ea9d6d0..85b39f8bb 100644 --- a/include/boost/geometry/algorithms/detail/is_simple/linear.hpp +++ b/include/boost/geometry/algorithms/detail/is_simple/linear.hpp @@ -38,7 +38,8 @@ #include #include -#include +#include +#include #include @@ -75,34 +76,71 @@ template class is_simple_multilinestring { private: - template - static inline bool is_boundary_point_of(Point const& point, - Linestring const& linestring) + class is_acceptable_turn { - BOOST_ASSERT( boost::size(linestring) > 1 ); - return - !geometry::equals(range::front(linestring), - range::back(linestring)) - && - ( geometry::equals(point, range::front(linestring)) - || geometry::equals(point, range::back(linestring)) ); - } + private: + template + static inline bool is_boundary_point_of(Point const& point, + Linestring const& linestring) + { + BOOST_ASSERT( boost::size(linestring) > 1 ); + return + !geometry::equals(range::front(linestring), + range::back(linestring)) + && + ( geometry::equals(point, range::front(linestring)) + || geometry::equals(point, range::back(linestring)) ); + } - template - static inline bool have_same_boundary_points(Linestring1 const& ls1, - Linestring2 const& ls2) - { - return - geometry::equals(range::front(ls1), range::front(ls2)) - ? - geometry::equals(range::back(ls1), range::back(ls2)) - : - (geometry::equals(range::front(ls1), range::back(ls2)) - && - geometry::equals(range::back(ls1), range::front(ls2)) - ) - ; - } + template + static inline bool have_same_boundary_points(Linestring1 const& ls1, + Linestring2 const& ls2) + { + return + geometry::equals(range::front(ls1), range::front(ls2)) + ? + geometry::equals(range::back(ls1), range::back(ls2)) + : + (geometry::equals(range::front(ls1), range::back(ls2)) + && + geometry::equals(range::back(ls1), range::front(ls2)) + ) + ; + } + + public: + is_acceptable_turn(MultiLinestring const& multilinestring) + : m_multilinestring(multilinestring) + {} + + template + inline bool apply(Turn const& turn) const + { + typedef typename boost::range_value + < + MultiLinestring + >::type linestring; + + linestring const& ls1 = + range::at(m_multilinestring, + turn.operations[0].seg_id.multi_index); + + linestring const& ls2 = + range::at(m_multilinestring, + turn.operations[0].other_id.multi_index); + + return + is_boundary_point_of(turn.point, ls1) + && is_boundary_point_of(turn.point, ls2) + && + ( boost::size(ls1) != 2 + || boost::size(ls2) != 2 + || !have_same_boundary_points(ls1, ls2) ); + } + + private: + MultiLinestring const& m_multilinestring; + }; public: @@ -116,7 +154,8 @@ public: // check each of the linestrings for simplicity if ( !detail::check_iterator_range < - is_simple_linestring + is_simple_linestring, + false // do not allow empty multilinestring >::apply(boost::begin(multilinestring), boost::end(multilinestring)) ) @@ -142,8 +181,11 @@ public: detail::disjoint::assign_disjoint_policy > turn_policy; - detail::self_get_turn_points::no_interrupt_policy - interrupt_policy; + is_acceptable_turn predicate(multilinestring); + detail::overlay::predicate_based_interrupt_policy + < + is_acceptable_turn + > interrupt_policy(predicate); detail::self_get_turn_points::get_turns < @@ -153,37 +195,10 @@ public: turns, interrupt_policy); - debug_print_turns(turns.begin(), turns.end()); + detail::is_valid::debug_print_turns(turns.begin(), turns.end()); debug_print_boundary_points(multilinestring); - // check if the generated turns are all boundary points of the - // linestrings in the multi-linestring - for (typename std::deque::const_iterator tit = turns.begin(); - tit != turns.end(); ++tit) - { - linestring const& ls1 = - range::at(multilinestring, - tit->operations[0].seg_id.multi_index); - - linestring const& ls2 = - range::at(multilinestring, - tit->operations[0].other_id.multi_index); - - if ( !is_boundary_point_of(tit->point, ls1) - || !is_boundary_point_of(tit->point, ls2) ) - { - return false; - } - - if ( boost::size(ls1) == 2 - && boost::size(ls2) == 2 - && have_same_boundary_points(ls1, ls2) ) - { - return false; - } - } - - return true; + return !interrupt_policy.has_intersections; } }; diff --git a/include/boost/geometry/algorithms/detail/is_valid/box.hpp b/include/boost/geometry/algorithms/detail/is_valid/box.hpp index 488c8c6ca..ad1a5d15f 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/box.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/box.hpp @@ -46,7 +46,7 @@ struct has_valid_corners template struct has_valid_corners { - static inline bool apply(Box const& box) + static inline bool apply(Box const&) { return true; } diff --git a/include/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp b/include/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp index 7d67aa56d..330d75e66 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp @@ -12,7 +12,6 @@ #include -#include #include #include #include @@ -232,29 +231,9 @@ public: return false; } - void print(std::ostream& os = std::cout) const - { - os << "num rings: " << m_num_rings << std::endl; - os << "vertex ids: {"; - for (vertex_handle it = m_vertices.begin(); - it != m_vertices.end(); ++it) - { - os << " " << it->id(); - } - os << " }" << std::endl; - - for (vertex_handle it = m_vertices.begin(); - it != m_vertices.end(); ++it) - { - os << "neighbors of " << it->id() << ": {"; - for (typename Vertex::neighbor_iterator nit = it->neighbors_begin(); - nit != it->neighbors_end(); ++nit) - { - os << " " << (*nit)->id(); - } - os << "}" << std::endl; - } - } + template + friend inline + void debug_print_complement_graph(OStream&, complement_graph const&); private: std::size_t m_num_rings, m_num_turns; diff --git a/include/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp b/include/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp new file mode 100644 index 000000000..83997a675 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp @@ -0,0 +1,65 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_COMPLEMENT_GRAPH_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_COMPLEMENT_GRAPH_HPP + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +#include +#endif + +namespace boost { namespace geometry +{ + +namespace detail { namespace is_valid +{ + + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +template +inline void debug_print_complement_graph(OutputStream& os, + complement_graph const& graph) +{ + typedef typename complement_graph::vertex_handle vertex_handle; + + os << "num rings: " << graph.m_num_rings << std::endl; + os << "vertex ids: {"; + for (vertex_handle it = graph.m_vertices.begin(); + it != graph.m_vertices.end(); ++it) + { + os << " " << it->id(); + } + os << " }" << std::endl; + + for (vertex_handle it = graph.m_vertices.begin(); + it != graph.m_vertices.end(); ++it) + { + os << "neighbors of " << it->id() << ": {"; + for (typename Vertex::neighbor_iterator nit = it->neighbors_begin(); + nit != it->neighbors_end(); ++nit) + { + os << " " << (*nit)->id(); + } + os << "}" << std::endl; + } +} +#else +template +void debug_print_complement_graph(OutputStream&, + complement_graph const&) +{ +} +#endif + + +}} // namespace detail::is_valid + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP diff --git a/include/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp b/include/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp new file mode 100644 index 000000000..b14355639 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp @@ -0,0 +1,64 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +#include + +#include +#include +#endif + + +namespace boost { namespace geometry +{ + +namespace detail { namespace is_valid +{ + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +template +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[0].other_id.multi_index + << "} {" + << tit->operations[0].seg_id.ring_index + << ", " + << tit->operations[0].other_id.ring_index + << "} " + << geometry::dsv(tit->point) + << "]"; + } + std::cout << std::endl << std::endl; +} +#else +template +inline void debug_print_turns(TurnIterator, TurnIterator) +{} +#endif // BOOST_GEOMETRY_TEST_DEBUG + +}} // namespace detail::is_valid + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP diff --git a/include/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp b/include/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp new file mode 100644 index 000000000..6f1c26364 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp @@ -0,0 +1,68 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP + +#ifdef GEOMETRY_TEST_DEBUG +#include + +#include +#include +#endif + + +namespace boost { namespace geometry +{ + +namespace detail { namespace is_valid +{ + +template ::type> +struct debug_validity_phase +{ + static inline void apply(int) + { + } +}; + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +template +struct debug_validity_phase +{ + static inline void apply(int phase) + { + switch (phase) + { + case 1: + std::cout << "checking exterior ring..." << std::endl; + break; + case 2: + std::cout << "checking interior rings..." << std::endl; + break; + case 3: + std::cout << "computing and analyzing turns..." << std::endl; + break; + case 4: + std::cout << "checking if holes are inside the exterior ring..." + << std::endl; + break; + case 5: + std::cout << "checking connectivity of interior..." << std::endl; + break; + } + } +}; +#endif + +}} // namespace detail::is_valid + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP diff --git a/include/boost/geometry/algorithms/detail/is_valid/linear.hpp b/include/boost/geometry/algorithms/detail/is_valid/linear.hpp index 3d67b71cb..708c4f4b8 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/linear.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/linear.hpp @@ -107,7 +107,8 @@ struct is_valid < typename boost::range_value::type, AllowSpikes - > + >, + false // do not allow empty multilinestring >::apply(boost::begin(multilinestring), boost::end(multilinestring)); } diff --git a/include/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/include/boost/geometry/algorithms/detail/is_valid/polygon.hpp index 15a3b4c83..87f4590d6 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/polygon.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/polygon.hpp @@ -25,6 +25,7 @@ #include +#include #include #include @@ -39,14 +40,12 @@ #include #include +#include +#include +#include #include -#ifdef BOOST_GEOMETRY_TEST_DEBUG -#include -#include -#endif - namespace boost { namespace geometry { @@ -136,25 +135,27 @@ private: && turn.operations[1].operation == operation; } - template - static inline bool is_acceptable_turn(Turn const& turn) + struct is_acceptable_turn { - if ( turn.operations[0].seg_id.ring_index - == turn.operations[0].other_id.ring_index ) + template + static inline bool apply(Turn const& turn) { - return false; + if ( turn.operations[0].seg_id.ring_index + == turn.operations[0].other_id.ring_index ) + { + return false; + } + + detail::overlay::operation_type const op = acceptable_operation + < + geometry::point_order::value + >::value; + + return check_turn(turn, detail::overlay::method_touch_interior, op) + || check_turn(turn, detail::overlay::method_touch, op) + ; } - - detail::overlay::operation_type const op = acceptable_operation - < - geometry::point_order::value - >::value; - - return check_turn(turn, detail::overlay::method_touch_interior, op) - || check_turn(turn, detail::overlay::method_touch, op) - ; - } - + }; template @@ -169,8 +170,7 @@ private: AllowDuplicates, false, // do not check self-intersections true // indicate that the ring is interior - >, - true // allow the iterator range to be empty + > >::apply(boost::begin(interior_rings), boost::end(interior_rings)); } @@ -183,10 +183,11 @@ public: typedef typename point_type::type point_type; typedef typename ring_type::type ring_type; + typedef debug_validity_phase debug_phase; + // check validity of exterior ring -#ifdef BOOST_GEOMETRY_TEST_DEBUG - std::cout << "checking exterior ring..." << std::endl; -#endif + debug_phase::apply(1); + if ( !detail::is_valid::is_valid_ring < ring_type, @@ -197,11 +198,9 @@ public: return false; } - // check validity of interior rings -#ifdef BOOST_GEOMETRY_TEST_DEBUG - std::cout << "checking interior rings..." << std::endl; -#endif + debug_phase::apply(2); + if ( !are_valid_interior_rings(geometry::interior_rings(polygon)) ) { return false; @@ -209,9 +208,8 @@ public: // compute turns and check if all are acceptable -#ifdef BOOST_GEOMETRY_TEST_DEBUG - std::cout << "computing and analyzing turns..." << std::endl; -#endif + debug_phase::apply(3); + typedef typename geometry::rescale_policy_type < point_type @@ -235,51 +233,38 @@ public: rescale_policy_type robust_policy = geometry::get_rescale_policy(polygon); - std::deque turns; - detail::self_get_turn_points::no_interrupt_policy interrupt_policy; + detail::overlay::stateless_predicate_based_interrupt_policy + < + is_acceptable_turn + > interrupt_policy; + std::deque turns; geometry::self_turns(polygon, robust_policy, turns, interrupt_policy); -#ifdef BOOST_GEOMETRY_TEST_DEBUG - std::cout << "turns:"; - for (typename std::deque::const_iterator tit = turns.begin(); - tit != turns.end(); ++tit) + if ( interrupt_policy.has_intersections ) { - std::cout << " [" << geometry::method_char(tit->method); - std::cout << "," - << geometry::operation_char(tit->operations[0].operation); - std::cout << "/" - << geometry::operation_char(tit->operations[1].operation); - std::cout << " {" << tit->operations[0].seg_id.ring_index - << ", " << tit->operations[0].other_id.ring_index - << "}"; - std::cout << " " << geometry::dsv(tit->point); - std::cout << "] "; + return false; } - std::cout << std::endl << std::endl; -#endif + debug_print_turns(turns.begin(), turns.end()); + + // put the ring id's that are associated with turns in a + // container with fast lookup (std::set) std::set rings_with_turns; for (typename std::deque::const_iterator tit = turns.begin(); tit != turns.end(); ++tit) { - if ( !is_acceptable_turn(*tit) ) - { - return false; - } rings_with_turns.insert(tit->operations[0].seg_id.ring_index); rings_with_turns.insert(tit->operations[0].other_id.ring_index); } // check if all interior rings are inside the exterior ring -#ifdef BOOST_GEOMETRY_TEST_DEBUG - std::cout << "checking if holes are inside the exterior ring..." - << std::endl; -#endif + debug_phase::apply(4); + if ( !are_holes_inside(geometry::interior_rings(polygon), geometry::exterior_ring(polygon), rings_with_turns) ) @@ -289,9 +274,8 @@ public: // check whether the interior of the polygon is a connected set -#ifdef BOOST_GEOMETRY_TEST_DEBUG - std::cout << "checking connectivity of interior..." << std::endl; -#endif + debug_phase::apply(5); + typedef graph_vertex graph_vertex; typedef complement_graph graph; @@ -309,9 +293,8 @@ public: g.add_edge(v2, vip); } -#ifdef BOOST_GEOMETRY_TEST_DEBUG - g.print(); -#endif + debug_print_complement_graph(std::cout, g); + return !g.has_cycles(); } }; @@ -352,7 +335,8 @@ struct is_valid < typename boost::range_value::type, AllowDuplicates - > + >, + false // do not allow empty multi-polygons >::apply(boost::begin(multipolygon), boost::end(multipolygon)) ) { diff --git a/include/boost/geometry/policies/predicate_based_interrupt_policy.hpp b/include/boost/geometry/policies/predicate_based_interrupt_policy.hpp new file mode 100644 index 000000000..0021b12dc --- /dev/null +++ b/include/boost/geometry/policies/predicate_based_interrupt_policy.hpp @@ -0,0 +1,101 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP + +#include + +#include + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +template +< + typename IsAcceptableTurnPredicate, + bool AllowEmptyTurnRange = true // by default, allow an empty turn range +> +struct stateless_predicate_based_interrupt_policy +{ + static bool const enabled = true; + bool has_intersections; // set to true if there is at least one + // unacceptable turn + + inline stateless_predicate_based_interrupt_policy() + : has_intersections(false) + {} + + template + inline bool apply(Range const& range) + { + // if there is at least one unacceptable turn in the range, return false + has_intersections = !detail::check_iterator_range + < + IsAcceptableTurnPredicate, + AllowEmptyTurnRange + >::apply(boost::begin(range), boost::end(range)); + + return has_intersections; + } +}; + + + + +template +< + typename IsAcceptableTurnPredicate, + bool AllowEmptyTurnRange = true // by default, allow an empty turn range +> +struct predicate_based_interrupt_policy +{ + static bool const enabled = true; + bool has_intersections; // set to true if there is at least one + // unacceptable turn + IsAcceptableTurnPredicate const& m_predicate; + + inline + predicate_based_interrupt_policy(IsAcceptableTurnPredicate const& predicate) + : has_intersections(false) + , m_predicate(predicate) + {} + + template + inline bool apply(Range const& range) + { + // if there is at least one unacceptable turn in the range, return false + has_intersections = !detail::check_iterator_range + < + IsAcceptableTurnPredicate, + AllowEmptyTurnRange + >::apply(boost::begin(range), boost::end(range), m_predicate); + + return has_intersections; + } +}; + + + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP diff --git a/test/algorithms/is_valid.cpp b/test/algorithms/is_valid.cpp index cda748cc8..ab259b534 100644 --- a/test/algorithms/is_valid.cpp +++ b/test/algorithms/is_valid.cpp @@ -129,7 +129,8 @@ struct is_convertible_to_closed { return bg::detail::check_iterator_range < - is_convertible_to_closed + is_convertible_to_closed, + false // do not allow empty multi-polygon >::apply(boost::begin(multi_polygon), boost::end(multi_polygon)); }