mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-08 23:02:09 +00:00
[algorithms][is_valid] re-structure and polish code a bit;
check relative containment of rings only for rings that are not associated with turns
This commit is contained in:
@@ -64,13 +64,31 @@ private:
|
||||
|
||||
|
||||
|
||||
template <typename PolygonIterator>
|
||||
static inline bool are_polygon_interiors_disjoint(PolygonIterator first,
|
||||
PolygonIterator beyond)
|
||||
template <typename PolygonIterator, typename TurnIterator>
|
||||
static inline
|
||||
bool are_polygon_interiors_disjoint(PolygonIterator polygons_first,
|
||||
PolygonIterator polygons_beyond,
|
||||
TurnIterator turns_first,
|
||||
TurnIterator turns_beyond)
|
||||
{
|
||||
for (PolygonIterator it1 = first; it1 != beyond; ++it1)
|
||||
std::set<int> multi_indices;
|
||||
for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
|
||||
{
|
||||
for (PolygonIterator it2 = first; it2 != beyond; ++it2)
|
||||
multi_indices.insert(tit->operations[0].seg_id.multi_index);
|
||||
multi_indices.insert(tit->operations[0].other_id.multi_index);
|
||||
}
|
||||
|
||||
int multi_index = 0;
|
||||
for (PolygonIterator it1 = polygons_first; it1 != polygons_beyond;
|
||||
++it1, ++multi_index)
|
||||
{
|
||||
if ( multi_indices.find(multi_index) != multi_indices.end() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (PolygonIterator it2 = polygons_first;
|
||||
it2 != polygons_beyond; ++it2)
|
||||
{
|
||||
if ( it1 != it2
|
||||
&&
|
||||
@@ -104,35 +122,78 @@ private:
|
||||
int const m_multi_index;
|
||||
};
|
||||
|
||||
template <typename PolygonIterator, typename Turns>
|
||||
static inline bool have_connected_interior(PolygonIterator first,
|
||||
PolygonIterator beyond,
|
||||
Turns const& turns)
|
||||
|
||||
|
||||
template <typename Predicate>
|
||||
struct has_property_per_polygon
|
||||
{
|
||||
int multi_index = 0;
|
||||
for (PolygonIterator it = first; it != beyond; ++it, ++multi_index)
|
||||
template <typename PolygonIterator, typename TurnIterator>
|
||||
static inline bool apply(PolygonIterator polygons_first,
|
||||
PolygonIterator polygons_beyond,
|
||||
TurnIterator turns_first,
|
||||
TurnIterator turns_beyond)
|
||||
{
|
||||
has_multi_index predicate(multi_index);
|
||||
|
||||
typedef boost::filter_iterator
|
||||
<
|
||||
has_multi_index,
|
||||
typename boost::range_iterator<Turns const>::type
|
||||
> turn_iterator;
|
||||
|
||||
turn_iterator turns_first(predicate, turns.begin(), turns.end());
|
||||
turn_iterator turns_beyond(predicate, turns.end(), turns.end());
|
||||
|
||||
if ( !base::has_connected_interior(*it, turns_first, turns_beyond) )
|
||||
int multi_index = 0;
|
||||
for (PolygonIterator it = polygons_first; it != polygons_beyond;
|
||||
++it, ++multi_index)
|
||||
{
|
||||
return false;
|
||||
has_multi_index index_predicate(multi_index);
|
||||
|
||||
typedef boost::filter_iterator
|
||||
<
|
||||
has_multi_index, TurnIterator
|
||||
> filtered_turn_iterator;
|
||||
|
||||
filtered_turn_iterator filtered_turns_first(index_predicate,
|
||||
turns_first,
|
||||
turns_beyond);
|
||||
|
||||
filtered_turn_iterator filtered_turns_beyond(index_predicate,
|
||||
turns_beyond,
|
||||
turns_beyond);
|
||||
|
||||
if ( !Predicate::apply(*it,
|
||||
filtered_turns_first,
|
||||
filtered_turns_beyond) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename PolygonIterator, typename TurnIterator>
|
||||
static inline bool have_holes_inside(PolygonIterator polygons_first,
|
||||
PolygonIterator polygons_beyond,
|
||||
TurnIterator turns_first,
|
||||
TurnIterator turns_beyond)
|
||||
{
|
||||
return has_property_per_polygon
|
||||
<
|
||||
typename base::has_holes_inside
|
||||
>::apply(polygons_first, polygons_beyond,
|
||||
turns_first, turns_beyond);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename PolygonIterator, typename TurnIterator>
|
||||
static inline bool have_connected_interior(PolygonIterator polygons_first,
|
||||
PolygonIterator polygons_beyond,
|
||||
TurnIterator turns_first,
|
||||
TurnIterator turns_beyond)
|
||||
{
|
||||
return has_property_per_polygon
|
||||
<
|
||||
typename base::has_connected_interior
|
||||
>::apply(polygons_first, polygons_beyond,
|
||||
turns_first, turns_beyond);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
static inline bool apply(MultiPolygon const& multipolygon)
|
||||
{
|
||||
@@ -156,9 +217,8 @@ public:
|
||||
debug_phase::apply(2);
|
||||
|
||||
typedef has_valid_self_turns<MultiPolygon> has_valid_turns;
|
||||
typedef typename has_valid_turns::turn_type turn_type;
|
||||
|
||||
std::deque<turn_type> turns;
|
||||
std::deque<typename has_valid_turns::turn_type> turns;
|
||||
bool has_invalid_turns = !has_valid_turns::apply(multipolygon, turns);
|
||||
debug_print_turns(turns.begin(), turns.end());
|
||||
|
||||
@@ -172,11 +232,10 @@ public:
|
||||
// exterior and not one inside the other
|
||||
debug_phase::apply(3);
|
||||
|
||||
if ( !check_iterator_range
|
||||
<
|
||||
typename base::has_holes_inside
|
||||
>::apply(boost::begin(multipolygon),
|
||||
boost::end(multipolygon)) )
|
||||
if ( !have_holes_inside(boost::begin(multipolygon),
|
||||
boost::end(multipolygon),
|
||||
turns.begin(),
|
||||
turns.end()) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -187,7 +246,8 @@ public:
|
||||
|
||||
if ( !have_connected_interior(boost::begin(multipolygon),
|
||||
boost::end(multipolygon),
|
||||
turns) )
|
||||
turns.begin(),
|
||||
turns.end()) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -196,7 +256,9 @@ public:
|
||||
// check if polygon interiors are disjoint
|
||||
debug_phase::apply(5);
|
||||
return are_polygon_interiors_disjoint(boost::begin(multipolygon),
|
||||
boost::end(multipolygon));
|
||||
boost::end(multipolygon),
|
||||
turns.begin(),
|
||||
turns.end());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/core/exterior_ring.hpp>
|
||||
@@ -66,52 +67,6 @@ protected:
|
||||
typedef debug_validity_phase<Polygon> debug_phase;
|
||||
|
||||
|
||||
template <typename RingIterator, typename ExteriorRing>
|
||||
static inline bool are_holes_inside(RingIterator first,
|
||||
RingIterator beyond,
|
||||
ExteriorRing const& exterior_ring)
|
||||
{
|
||||
for (RingIterator it = first; it != beyond; ++it)
|
||||
{
|
||||
if ( !geometry::covered_by(range::front(*it), exterior_ring) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (RingIterator it1 = first; it1 != beyond; ++it1)
|
||||
{
|
||||
for (RingIterator it2 = first; it2 != beyond; ++it2)
|
||||
{
|
||||
if ( it1 != it2
|
||||
&& geometry::within(range::front(*it1), *it2) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename InteriorRings, typename ExteriorRing>
|
||||
static inline bool are_holes_inside(InteriorRings const& interior_rings,
|
||||
ExteriorRing const& exterior_ring)
|
||||
{
|
||||
return are_holes_inside(boost::begin(interior_rings),
|
||||
boost::end(interior_rings),
|
||||
exterior_ring);
|
||||
}
|
||||
|
||||
struct has_holes_inside
|
||||
{
|
||||
static inline bool apply(Polygon const& polygon)
|
||||
{
|
||||
return are_holes_inside(geometry::interior_rings(polygon),
|
||||
geometry::exterior_ring(polygon));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename InteriorRings>
|
||||
static bool has_valid_interior_rings(InteriorRings const& interior_rings)
|
||||
@@ -130,64 +85,175 @@ protected:
|
||||
boost::end(interior_rings));
|
||||
}
|
||||
|
||||
static inline bool has_valid_rings(Polygon const& polygon)
|
||||
struct has_valid_rings
|
||||
{
|
||||
typedef typename ring_type<Polygon>::type ring_type;
|
||||
|
||||
// check validity of exterior ring
|
||||
debug_phase::apply(1);
|
||||
|
||||
if ( !detail::is_valid::is_valid_ring
|
||||
<
|
||||
ring_type,
|
||||
AllowDuplicates,
|
||||
false // do not check self intersections
|
||||
>::apply(exterior_ring(polygon)) )
|
||||
static inline bool apply(Polygon const& polygon)
|
||||
{
|
||||
return false;
|
||||
typedef typename ring_type<Polygon>::type ring_type;
|
||||
|
||||
// check validity of exterior ring
|
||||
debug_phase::apply(1);
|
||||
|
||||
if ( !detail::is_valid::is_valid_ring
|
||||
<
|
||||
ring_type,
|
||||
AllowDuplicates,
|
||||
false // do not check self intersections
|
||||
>::apply(exterior_ring(polygon)) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// check validity of interior rings
|
||||
debug_phase::apply(2);
|
||||
|
||||
return has_valid_interior_rings(geometry::interior_rings(polygon));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename RingIterator,
|
||||
typename ExteriorRing,
|
||||
typename TurnIterator
|
||||
>
|
||||
static inline bool are_holes_inside(RingIterator rings_first,
|
||||
RingIterator rings_beyond,
|
||||
ExteriorRing const& exterior_ring,
|
||||
TurnIterator turns_first,
|
||||
TurnIterator turns_beyond)
|
||||
{
|
||||
// collect the interior ring indices that have turns with the
|
||||
// exterior ring
|
||||
std::set<int> ring_indices;
|
||||
for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
|
||||
{
|
||||
if ( tit->operations[0].seg_id.ring_index == -1 )
|
||||
{
|
||||
BOOST_ASSERT( tit->operations[0].other_id.ring_index != -1 );
|
||||
ring_indices.insert(tit->operations[0].other_id.ring_index);
|
||||
}
|
||||
else if ( tit->operations[0].other_id.ring_index == -1 )
|
||||
{
|
||||
BOOST_ASSERT( tit->operations[0].seg_id.ring_index != -1 );
|
||||
ring_indices.insert(tit->operations[0].seg_id.ring_index);
|
||||
}
|
||||
}
|
||||
|
||||
// check validity of interior rings
|
||||
debug_phase::apply(2);
|
||||
|
||||
return has_valid_interior_rings(geometry::interior_rings(polygon));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename TurnIterator>
|
||||
static inline bool has_connected_interior(Polygon const& polygon,
|
||||
TurnIterator first,
|
||||
TurnIterator beyond)
|
||||
{
|
||||
typedef typename std::iterator_traits
|
||||
<
|
||||
TurnIterator
|
||||
>::value_type turn_type;
|
||||
typedef complement_graph<typename turn_type::point_type> graph;
|
||||
|
||||
graph g(geometry::num_interior_rings(polygon) + 1);
|
||||
for (TurnIterator tit = first; tit != beyond; ++tit)
|
||||
int ring_index = 0;
|
||||
for (RingIterator it = rings_first; it != rings_beyond;
|
||||
++it, ++ring_index)
|
||||
{
|
||||
typename graph::vertex_handle v1 = g.add_vertex
|
||||
( tit->operations[0].seg_id.ring_index + 1 );
|
||||
typename graph::vertex_handle v2 = g.add_vertex
|
||||
( tit->operations[0].other_id.ring_index + 1 );
|
||||
typename graph::vertex_handle vip = g.add_vertex(tit->point);
|
||||
|
||||
g.add_edge(v1, vip);
|
||||
g.add_edge(v2, vip);
|
||||
// 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) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
debug_print_complement_graph(std::cout, g);
|
||||
// collect all rings (exterior and/or interior) that have turns
|
||||
for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
|
||||
{
|
||||
ring_indices.insert(tit->operations[0].seg_id.ring_index);
|
||||
ring_indices.insert(tit->operations[0].other_id.ring_index);
|
||||
}
|
||||
|
||||
return !g.has_cycles();
|
||||
ring_index = 0;
|
||||
for (RingIterator it1 = rings_first; it1 != rings_beyond;
|
||||
++it1, ++ring_index)
|
||||
{
|
||||
// do not examine rings that are associated with turns
|
||||
if ( ring_indices.find(ring_index) == ring_indices.end() )
|
||||
{
|
||||
for (RingIterator it2 = rings_first; it2 != rings_beyond; ++it2)
|
||||
{
|
||||
if ( it1 != it2
|
||||
&& geometry::within(range::front(*it1), *it2) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename InteriorRings,
|
||||
typename ExteriorRing,
|
||||
typename TurnIterator
|
||||
>
|
||||
static inline bool are_holes_inside(InteriorRings const& interior_rings,
|
||||
ExteriorRing const& exterior_ring,
|
||||
TurnIterator first,
|
||||
TurnIterator beyond)
|
||||
{
|
||||
return are_holes_inside(boost::begin(interior_rings),
|
||||
boost::end(interior_rings),
|
||||
exterior_ring,
|
||||
first,
|
||||
beyond);
|
||||
}
|
||||
|
||||
struct has_holes_inside
|
||||
{
|
||||
template <typename TurnIterator>
|
||||
static inline bool apply(Polygon const& polygon,
|
||||
TurnIterator first,
|
||||
TurnIterator beyond)
|
||||
{
|
||||
return are_holes_inside(geometry::interior_rings(polygon),
|
||||
geometry::exterior_ring(polygon),
|
||||
first,
|
||||
beyond);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct has_connected_interior
|
||||
{
|
||||
template <typename TurnIterator>
|
||||
static inline bool apply(Polygon const& polygon,
|
||||
TurnIterator first,
|
||||
TurnIterator beyond)
|
||||
{
|
||||
typedef typename std::iterator_traits
|
||||
<
|
||||
TurnIterator
|
||||
>::value_type turn_type;
|
||||
typedef complement_graph<typename turn_type::point_type> graph;
|
||||
|
||||
graph g(geometry::num_interior_rings(polygon) + 1);
|
||||
for (TurnIterator tit = first; tit != beyond; ++tit)
|
||||
{
|
||||
typename graph::vertex_handle v1 = g.add_vertex
|
||||
( tit->operations[0].seg_id.ring_index + 1 );
|
||||
typename graph::vertex_handle v2 = g.add_vertex
|
||||
( tit->operations[0].other_id.ring_index + 1 );
|
||||
typename graph::vertex_handle vip = g.add_vertex(tit->point);
|
||||
|
||||
g.add_edge(v1, vip);
|
||||
g.add_edge(v2, vip);
|
||||
}
|
||||
|
||||
debug_print_complement_graph(std::cout, g);
|
||||
|
||||
return !g.has_cycles();
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static inline bool apply(Polygon const& polygon)
|
||||
{
|
||||
if ( !has_valid_rings(polygon) )
|
||||
if ( !has_valid_rings::apply(polygon) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -201,9 +267,8 @@ public:
|
||||
debug_phase::apply(3);
|
||||
|
||||
typedef has_valid_self_turns<Polygon> has_valid_turns;
|
||||
typedef typename has_valid_turns::turn_type turn_type;
|
||||
|
||||
std::deque<turn_type> turns;
|
||||
std::deque<typename has_valid_turns::turn_type> turns;
|
||||
bool has_invalid_turns = !has_valid_turns::apply(polygon, turns);
|
||||
debug_print_turns(turns.begin(), turns.end());
|
||||
|
||||
@@ -215,7 +280,7 @@ public:
|
||||
// check if all interior rings are inside the exterior ring
|
||||
debug_phase::apply(4);
|
||||
|
||||
if ( !has_holes_inside::apply(polygon) )
|
||||
if ( !has_holes_inside::apply(polygon, turns.begin(), turns.end()) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -223,7 +288,9 @@ public:
|
||||
// check whether the interior of the polygon is a connected set
|
||||
debug_phase::apply(5);
|
||||
|
||||
return has_connected_interior(polygon, turns.begin(), turns.end());
|
||||
return has_connected_interior::apply(polygon,
|
||||
turns.begin(),
|
||||
turns.end());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user