summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/is_valid/polygon.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail/is_valid/polygon.hpp')
-rw-r--r--boost/geometry/algorithms/detail/is_valid/polygon.hpp155
1 files changed, 126 insertions, 29 deletions
diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
index f7e22fb8d2..5c6229b793 100644
--- a/boost/geometry/algorithms/detail/is_valid/polygon.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
@@ -1,5 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
+
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -43,6 +45,7 @@
#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/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
@@ -142,43 +145,103 @@ protected:
};
+ // Iterator value_type is a Ring or Polygon
+ template <typename Iterator, typename Box>
+ struct partition_item
+ {
+ explicit partition_item(Iterator it)
+ : m_it(it)
+ , m_is_initialized(false)
+ {}
+
+ Iterator get() const
+ {
+ return m_it;
+ }
+
+ template <typename EnvelopeStrategy>
+ Box const& get_envelope(EnvelopeStrategy const& strategy) const
+ {
+ if (! m_is_initialized)
+ {
+ m_box = geometry::return_envelope<Box>(*m_it, strategy);
+ m_is_initialized = true;
+ }
+ return m_box;
+ }
+
+ private:
+ Iterator m_it;
+ mutable Box m_box;
+ mutable bool m_is_initialized;
+ };
+
// structs for partition -- start
+ template <typename EnvelopeStrategy>
struct expand_box
{
+ explicit expand_box(EnvelopeStrategy const& strategy) : m_strategy(strategy) {}
+
template <typename Box, typename Iterator>
- static inline void apply(Box& total, Iterator const& it)
+ inline void apply(Box& total, partition_item<Iterator, Box> const& item) const
{
- geometry::expand(total, geometry::return_envelope<Box>(*it));
+ geometry::expand(total, item.get_envelope(m_strategy));
}
+ EnvelopeStrategy const& m_strategy;
};
+ template <typename EnvelopeStrategy>
struct overlaps_box
{
+ explicit overlaps_box(EnvelopeStrategy const& strategy) : m_strategy(strategy) {}
+
template <typename Box, typename Iterator>
- static inline bool apply(Box const& box, Iterator const& it)
+ inline bool apply(Box const& box, partition_item<Iterator, Box> const& item) const
{
- return ! geometry::disjoint(*it, box);
+ return ! geometry::disjoint(item.get_envelope(m_strategy), box);
}
+
+ EnvelopeStrategy const& m_strategy;
};
+ template <typename WithinStrategy>
struct item_visitor_type
{
bool items_overlap;
+ WithinStrategy const& m_strategy;
+
+ explicit item_visitor_type(WithinStrategy const& strategy)
+ : items_overlap(false)
+ , m_strategy(strategy)
+ {}
- item_visitor_type() : items_overlap(false) {}
+ template <typename Item>
+ inline bool is_within(Item const& first, Item const& second)
+ {
+ typename point_type<Polygon>::type point;
+ typedef detail::point_on_border::point_on_range<true> pob;
+
+ // TODO: this should check for a point on the interior, instead
+ // of on border. Or it should check using the overlap function.
+
+ return pob::apply(point, points_begin(first), points_end(first))
+ && geometry::within(point, second, m_strategy);
+ }
- template <typename Item1, typename Item2>
- inline void apply(Item1 const& item1, Item2 const& item2)
+ template <typename Iterator, typename Box>
+ inline bool apply(partition_item<Iterator, Box> const& item1,
+ partition_item<Iterator, Box> const& item2)
{
if (! items_overlap
- && (geometry::within(*points_begin(*item1), *item2)
- || geometry::within(*points_begin(*item2), *item1))
- )
+ && (is_within(*item1.get(), *item2.get())
+ || is_within(*item2.get(), *item1.get())))
{
items_overlap = true;
+ return false; // interrupt
}
+ return true;
}
};
// structs for partition -- end
@@ -189,14 +252,16 @@ protected:
typename RingIterator,
typename ExteriorRing,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool are_holes_inside(RingIterator rings_first,
RingIterator rings_beyond,
ExteriorRing const& exterior_ring,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
boost::ignore_unused(visitor);
@@ -217,6 +282,14 @@ protected:
}
}
+ // prepare strategy
+ typedef typename std::iterator_traits<RingIterator>::value_type inter_ring_type;
+ typename Strategy::template point_in_geometry_strategy
+ <
+ inter_ring_type, ExteriorRing
+ >::type const in_exterior_strategy
+ = strategy.template get_point_in_geometry_strategy<inter_ring_type, ExteriorRing>();
+
signed_size_type ring_index = 0;
for (RingIterator it = rings_first; it != rings_beyond;
++it, ++ring_index)
@@ -224,7 +297,7 @@ 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))
+ && ! geometry::covered_by(range::front(*it), exterior_ring, in_exterior_strategy))
{
return visitor.template apply<failure_interior_rings_outside>();
}
@@ -237,26 +310,42 @@ protected:
ring_indices.insert(tit->operations[1].seg_id.ring_index);
}
+ typedef geometry::model::box<typename point_type<Polygon>::type> box_type;
+ typedef partition_item<RingIterator, box_type> item_type;
+
// put iterators for interior rings without turns in a vector
- std::vector<RingIterator> ring_iterators;
+ std::vector<item_type> ring_iterators;
ring_index = 0;
for (RingIterator it = rings_first; it != rings_beyond;
++it, ++ring_index)
{
if (ring_indices.find(ring_index) == ring_indices.end())
{
- ring_iterators.push_back(it);
+ ring_iterators.push_back(item_type(it));
}
}
- // call partition to check is interior rings are disjoint from
+ // prepare strategies
+ typedef typename Strategy::template point_in_geometry_strategy
+ <
+ inter_ring_type, inter_ring_type
+ >::type in_interior_strategy_type;
+ in_interior_strategy_type const in_interior_strategy
+ = strategy.template get_point_in_geometry_strategy<inter_ring_type, inter_ring_type>();
+ typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
+ envelope_strategy_type const envelope_strategy
+ = strategy.get_envelope_strategy();
+
+ // call partition to check if interior rings are disjoint from
// each other
- item_visitor_type item_visitor;
+ item_visitor_type<in_interior_strategy_type> item_visitor(in_interior_strategy);
geometry::partition
<
- geometry::model::box<typename point_type<Polygon>::type>
- >::apply(ring_iterators, item_visitor, expand_box(), overlaps_box());
+ box_type
+ >::apply(ring_iterators, item_visitor,
+ expand_box<envelope_strategy_type>(envelope_strategy),
+ overlaps_box<envelope_strategy_type>(envelope_strategy));
if (item_visitor.items_overlap)
{
@@ -273,35 +362,40 @@ protected:
typename InteriorRings,
typename ExteriorRing,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool are_holes_inside(InteriorRings const& interior_rings,
ExteriorRing const& exterior_ring,
TurnIterator first,
TurnIterator beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
return are_holes_inside(boost::begin(interior_rings),
boost::end(interior_rings),
exterior_ring,
first,
beyond,
- visitor);
+ visitor,
+ strategy);
}
struct has_holes_inside
{
- template <typename TurnIterator, typename VisitPolicy>
+ template <typename TurnIterator, typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
TurnIterator beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
return are_holes_inside(geometry::interior_rings(polygon),
geometry::exterior_ring(polygon),
first,
beyond,
- visitor);
+ visitor,
+ strategy);
}
};
@@ -310,11 +404,12 @@ protected:
struct has_connected_interior
{
- template <typename TurnIterator, typename VisitPolicy>
+ template <typename TurnIterator, typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
TurnIterator beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& )
{
boost::ignore_unused(visitor);
@@ -388,7 +483,8 @@ public:
if (! has_holes_inside::apply(polygon,
turns.begin(), turns.end(),
- visitor))
+ visitor,
+ strategy))
{
return false;
}
@@ -399,7 +495,8 @@ public:
return has_connected_interior::apply(polygon,
turns.begin(),
turns.end(),
- visitor);
+ visitor,
+ strategy);
}
};