add boost on mac

This commit is contained in:
Bassem Girgis
2019-08-10 16:38:17 -05:00
parent 861b918727
commit be945cb63b
14105 changed files with 2714968 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP
#include <cstddef>
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/core/access.hpp>
#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/detail/is_valid/has_invalid_coordinate.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename Box, std::size_t I>
struct has_valid_corners
{
template <typename VisitPolicy>
static inline bool apply(Box const& box, VisitPolicy& visitor)
{
if (math::equals(geometry::get<geometry::min_corner, I-1>(box),
geometry::get<geometry::max_corner, I-1>(box)))
{
return
visitor.template apply<failure_wrong_topological_dimension>();
}
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);
}
};
template <typename Box>
struct has_valid_corners<Box, 0>
{
template <typename VisitPolicy>
static inline bool apply(Box const&, VisitPolicy& visitor)
{
boost::ignore_unused(visitor);
return visitor.template apply<no_failure>();
}
};
template <typename Box>
struct is_valid_box
{
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Box const& box, VisitPolicy& visitor, Strategy const&)
{
return
! has_invalid_coordinate<Box>::apply(box, visitor)
&&
has_valid_corners<Box, dimension<Box>::value>::apply(box, visitor);
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A box is always simple
// A box is a Polygon, and it satisfies the conditions for Polygon validity.
//
// The only thing we have to check is whether the max corner lies in
// the upper-right quadrant as defined by the min corner
//
// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
template <typename Box>
struct is_valid<Box, box_tag>
: detail::is_valid::is_valid_box<Box>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP

View File

@@ -0,0 +1,243 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, 2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_COMPLEMENT_GRAPH_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
#include <cstddef>
#include <set>
#include <stack>
#include <utility>
#include <vector>
#include <boost/core/addressof.hpp>
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/policies/compare.hpp>
namespace boost { namespace geometry
{
namespace detail { namespace is_valid
{
template <typename TurnPoint>
class complement_graph_vertex
{
public:
complement_graph_vertex(std::size_t id)
: m_id(id)
, m_turn_point(NULL)
{}
complement_graph_vertex(TurnPoint const* turn_point,
std::size_t expected_id)
: m_id(expected_id)
, m_turn_point(turn_point)
{}
inline std::size_t id() const { return m_id; }
inline bool operator<(complement_graph_vertex const& other) const
{
if ( m_turn_point != NULL && other.m_turn_point != NULL )
{
return geometry::less
<
TurnPoint
>()(*m_turn_point, *other.m_turn_point);
}
if ( m_turn_point == NULL && other.m_turn_point == NULL )
{
return m_id < other.m_id;
}
return m_turn_point == NULL;
}
private:
// the value of m_turn_point determines the type of the vertex
// non-NULL: vertex corresponds to an IP
// NULL : vertex corresponds to a hole or outer space, and the id
// is the ring id of the corresponding ring of the polygon
std::size_t m_id;
TurnPoint const* m_turn_point;
};
template <typename TurnPoint>
class complement_graph
{
private:
typedef complement_graph_vertex<TurnPoint> vertex;
typedef std::set<vertex> vertex_container;
public:
typedef typename vertex_container::const_iterator vertex_handle;
private:
struct vertex_handle_less
{
inline bool operator()(vertex_handle v1, vertex_handle v2) const
{
return v1->id() < v2->id();
}
};
typedef std::set<vertex_handle, vertex_handle_less> neighbor_container;
class has_cycles_dfs_data
{
public:
has_cycles_dfs_data(std::size_t num_nodes)
: m_visited(num_nodes, false)
, m_parent_id(num_nodes, -1)
{}
inline signed_size_type parent_id(vertex_handle v) const
{
return m_parent_id[v->id()];
}
inline void set_parent_id(vertex_handle v, signed_size_type id)
{
m_parent_id[v->id()] = id;
}
inline bool visited(vertex_handle v) const
{
return m_visited[v->id()];
}
inline void set_visited(vertex_handle v, bool value)
{
m_visited[v->id()] = value;
}
private:
std::vector<bool> m_visited;
std::vector<signed_size_type> m_parent_id;
};
inline bool has_cycles(vertex_handle start_vertex,
has_cycles_dfs_data& data) const
{
std::stack<vertex_handle> stack;
stack.push(start_vertex);
while ( !stack.empty() )
{
vertex_handle v = stack.top();
stack.pop();
data.set_visited(v, true);
for (typename neighbor_container::const_iterator nit
= m_neighbors[v->id()].begin();
nit != m_neighbors[v->id()].end(); ++nit)
{
if ( static_cast<signed_size_type>((*nit)->id()) != data.parent_id(v) )
{
if ( data.visited(*nit) )
{
return true;
}
else
{
data.set_parent_id(*nit, static_cast<signed_size_type>(v->id()));
stack.push(*nit);
}
}
}
}
return false;
}
public:
// num_rings: total number of rings, including the exterior ring
complement_graph(std::size_t num_rings)
: m_num_rings(num_rings)
, m_num_turns(0)
, m_vertices()
, m_neighbors(num_rings)
{}
// inserts a ring vertex in the graph and returns its handle
// ring id's are zero-based (so the first interior ring has id 1)
inline vertex_handle add_vertex(signed_size_type id)
{
return m_vertices.insert(vertex(static_cast<std::size_t>(id))).first;
}
// inserts an IP in the graph and returns its id
inline vertex_handle add_vertex(TurnPoint const& turn_point)
{
std::pair<vertex_handle, bool> res
= m_vertices.insert(vertex(boost::addressof(turn_point),
m_num_rings + m_num_turns)
);
if ( res.second )
{
// a new element is inserted
m_neighbors.push_back(neighbor_container());
++m_num_turns;
}
return res.first;
}
inline void add_edge(vertex_handle v1, vertex_handle v2)
{
BOOST_GEOMETRY_ASSERT( v1 != m_vertices.end() );
BOOST_GEOMETRY_ASSERT( v2 != m_vertices.end() );
m_neighbors[v1->id()].insert(v2);
m_neighbors[v2->id()].insert(v1);
}
inline bool has_cycles() const
{
// initialize all vertices as non-visited and with no parent set
// this is done by the constructor of has_cycles_dfs_data
has_cycles_dfs_data data(m_num_rings + m_num_turns);
// for each non-visited vertex, start a DFS from that vertex
for (vertex_handle it = m_vertices.begin();
it != m_vertices.end(); ++it)
{
if ( !data.visited(it) && has_cycles(it, data) )
{
return true;
}
}
return false;
}
#ifdef BOOST_GEOMETRY_TEST_DEBUG
template <typename OStream, typename TP>
friend inline
void debug_print_complement_graph(OStream&, complement_graph<TP> const&);
#endif // BOOST_GEOMETRY_TEST_DEBUG
private:
std::size_t m_num_rings, m_num_turns;
vertex_container m_vertices;
std::vector<neighbor_container> m_neighbors;
};
}} // namespace detail::is_valid
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP

View File

@@ -0,0 +1,73 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, 2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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 <iostream>
#endif
#include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp>
namespace boost { namespace geometry
{
namespace detail { namespace is_valid
{
#ifdef BOOST_GEOMETRY_TEST_DEBUG
template <typename OutputStream, typename TurnPoint>
inline void
debug_print_complement_graph(OutputStream& os,
complement_graph<TurnPoint> const& graph)
{
typedef typename complement_graph<TurnPoint>::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 complement_graph
<
TurnPoint
>::neighbor_container::const_iterator
nit = graph.m_neighbors[it->id()].begin();
nit != graph.m_neighbors[it->id()].end(); ++nit)
{
os << " " << (*nit)->id();
}
os << "}" << std::endl;
}
}
#else
template <typename OutputStream, typename TurnPoint>
inline void debug_print_complement_graph(OutputStream&,
complement_graph<TurnPoint> const&)
{
}
#endif
}} // namespace detail::is_valid
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP

View File

@@ -0,0 +1,78 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, 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 <iostream>
#include <boost/geometry/io/dsv/write.hpp>
#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
#endif
namespace boost { namespace geometry
{
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)
{
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)
{}
#endif // BOOST_GEOMETRY_TEST_DEBUG
}} // namespace detail::is_valid
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP

View File

@@ -0,0 +1,68 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, 2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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 <iostream>
#endif
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry
{
namespace detail { namespace is_valid
{
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct debug_validity_phase
{
static inline void apply(int)
{
}
};
#ifdef BOOST_GEOMETRY_TEST_DEBUG
template <typename Polygon>
struct debug_validity_phase<Polygon, polygon_tag>
{
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 interior rings 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

View File

@@ -0,0 +1,80 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, 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_HAS_DUPLICATES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#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
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename Range, closure_selector Closure>
struct has_duplicates
{
template <typename VisitPolicy>
static inline bool apply(Range const& range, VisitPolicy& visitor)
{
boost::ignore_unused(visitor);
typedef typename closeable_view<Range const, Closure>::type view_type;
typedef typename boost::range_const_iterator
<
view_type const
>::type const_iterator;
view_type view(range);
if ( boost::size(view) < 2 )
{
return ! visitor.template apply<no_failure>();
}
geometry::equal_to<typename boost::range_value<Range>::type> equal;
const_iterator it = boost::const_begin(view);
const_iterator next = it;
++next;
for (; next != boost::const_end(view); ++it, ++next)
{
if ( equal(*it, *next) )
{
return ! visitor.template apply<failure_duplicate_points>(*it);
}
}
return ! visitor.template apply<no_failure>();
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP

View File

@@ -0,0 +1,153 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_HAS_INVALID_COORDINATE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_INVALID_COORDINATE_HPP
#include <cstddef>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/iterators/point_iterator.hpp>
#include <boost/geometry/views/detail/indexed_point_view.hpp>
#include <boost/geometry/util/has_non_finite_coordinate.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
struct always_valid
{
template <typename Geometry, typename VisitPolicy>
static inline bool apply(Geometry const&, VisitPolicy& visitor)
{
return ! visitor.template apply<no_failure>();
}
};
struct point_has_invalid_coordinate
{
template <typename Point, typename VisitPolicy>
static inline bool apply(Point const& point, VisitPolicy& visitor)
{
boost::ignore_unused(visitor);
return
geometry::has_non_finite_coordinate(point)
?
(! visitor.template apply<failure_invalid_coordinate>())
:
(! visitor.template apply<no_failure>());
}
template <typename Point>
static inline bool apply(Point const& point)
{
return geometry::has_non_finite_coordinate(point);
}
};
struct indexed_has_invalid_coordinate
{
template <typename Geometry, typename VisitPolicy>
static inline bool apply(Geometry const& geometry, VisitPolicy& visitor)
{
geometry::detail::indexed_point_view<Geometry const, 0> p0(geometry);
geometry::detail::indexed_point_view<Geometry const, 1> p1(geometry);
return point_has_invalid_coordinate::apply(p0, visitor)
|| point_has_invalid_coordinate::apply(p1, visitor);
}
};
struct range_has_invalid_coordinate
{
struct point_has_valid_coordinates
{
template <typename Point>
static inline bool apply(Point const& point)
{
return ! point_has_invalid_coordinate::apply(point);
}
};
template <typename Geometry, typename VisitPolicy>
static inline bool apply(Geometry const& geometry, VisitPolicy& visitor)
{
boost::ignore_unused(visitor);
bool const has_valid_coordinates = detail::check_iterator_range
<
point_has_valid_coordinates,
true // do not consider an empty range as problematic
>::apply(geometry::points_begin(geometry),
geometry::points_end(geometry));
return has_valid_coordinates
?
(! visitor.template apply<no_failure>())
:
(! visitor.template apply<failure_invalid_coordinate>());
}
};
template
<
typename Geometry,
typename Tag = typename tag<Geometry>::type,
bool HasFloatingPointCoordinates = boost::is_floating_point
<
typename coordinate_type<Geometry>::type
>::value
>
struct has_invalid_coordinate
: range_has_invalid_coordinate
{};
template <typename Geometry, typename Tag>
struct has_invalid_coordinate<Geometry, Tag, false>
: always_valid
{};
template <typename Point>
struct has_invalid_coordinate<Point, point_tag, true>
: point_has_invalid_coordinate
{};
template <typename Segment>
struct has_invalid_coordinate<Segment, segment_tag, true>
: indexed_has_invalid_coordinate
{};
template <typename Box>
struct has_invalid_coordinate<Box, box_tag, true>
: indexed_has_invalid_coordinate
{};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_INVALID_COORDINATE_HPP

View File

@@ -0,0 +1,177 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_HAS_SPIKES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
#include <algorithm>
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/core/assert.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
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename Point>
struct equal_to
{
Point const& m_point;
equal_to(Point const& point)
: m_point(point)
{}
template <typename OtherPoint>
inline bool operator()(OtherPoint const& other) const
{
return geometry::equals(m_point, other);
}
};
template <typename Point>
struct not_equal_to
{
Point const& m_point;
not_equal_to(Point const& point)
: m_point(point)
{}
template <typename OtherPoint>
inline bool operator()(OtherPoint const& other) const
{
return ! geometry::equals(other, m_point);
}
};
template <typename Range, closure_selector Closure>
struct has_spikes
{
template <typename Iterator>
static inline Iterator find_different_from_first(Iterator first,
Iterator last)
{
typedef not_equal_to<typename point_type<Range>::type> not_equal;
BOOST_GEOMETRY_ASSERT(first != last);
Iterator second = first;
++second;
return std::find_if(second, last, not_equal(*first));
}
template <typename VisitPolicy, typename SideStrategy>
static inline bool apply(Range const& range, VisitPolicy& visitor,
SideStrategy const& strategy)
{
boost::ignore_unused(visitor);
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);
iterator cur = find_different_from_first(prev, boost::end(view));
if (cur == boost::end(view))
{
// the range has only one distinct point, so it
// cannot have a spike
return ! visitor.template apply<no_failure>();
}
iterator next = find_different_from_first(cur, boost::end(view));
if (next == boost::end(view))
{
// the range has only two distinct points, so it
// cannot have a spike
return ! visitor.template apply<no_failure>();
}
while (next != boost::end(view))
{
// Verify spike. TODO: this is a reverse order from expected
// in is_spike_or_equal, but this order calls the side
// strategy in the way to correctly detect the spikes,
// also in geographic cases going over the pole
if (detail::is_spike_or_equal(*next, *cur, *prev, strategy))
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);
}
prev = cur;
cur = next;
next = find_different_from_first(cur, boost::end(view));
}
if (geometry::equals(range::front(view), range::back(view)))
{
iterator cur = boost::begin(view);
typename boost::range_reverse_iterator
<
view_type const
>::type prev = find_different_from_first(boost::rbegin(view),
boost::rend(view));
iterator next = find_different_from_first(cur, boost::end(view));
if (detail::is_spike_or_equal(*next, *cur, *prev, strategy))
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);
}
else
{
return ! visitor.template apply<no_failure>();
}
}
return ! visitor.template apply<no_failure>();
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP

View File

@@ -0,0 +1,121 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_HAS_VALID_SELF_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP
#include <vector>
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/policies/predicate_based_interrupt_policy.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template
<
typename Geometry,
typename IsAcceptableTurn = is_acceptable_turn<Geometry>
>
class has_valid_self_turns
{
private:
typedef typename point_type<Geometry>::type point_type;
typedef typename geometry::rescale_policy_type
<
point_type
>::type rescale_policy_type;
typedef detail::overlay::get_turn_info
<
detail::overlay::assign_null_policy
> turn_policy;
public:
typedef detail::overlay::turn_info
<
point_type,
typename geometry::segment_ratio_type
<
point_type,
rescale_policy_type
>::type
> turn_type;
// returns true if all turns are valid
template <typename Turns, typename VisitPolicy, typename Strategy>
static inline bool apply(Geometry const& geometry,
Turns& turns,
VisitPolicy& visitor,
Strategy const& strategy)
{
boost::ignore_unused(visitor);
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry);
detail::overlay::stateless_predicate_based_interrupt_policy
<
IsAcceptableTurn
> interrupt_policy;
detail::self_get_turn_points::self_turns<false, turn_policy>(geometry,
strategy,
robust_policy,
turns,
interrupt_policy);
if (interrupt_policy.has_intersections)
{
BOOST_GEOMETRY_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, typename Strategy>
static inline bool apply(Geometry const& geometry, VisitPolicy& visitor, Strategy const& strategy)
{
std::vector<turn_type> turns;
return apply(geometry, turns, visitor, strategy);
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP

View File

@@ -0,0 +1,21 @@
// 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_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP
#include <boost/geometry/algorithms/detail/is_valid/pointlike.hpp>
#include <boost/geometry/algorithms/detail/is_valid/linear.hpp>
#include <boost/geometry/algorithms/detail/is_valid/polygon.hpp>
#include <boost/geometry/algorithms/detail/is_valid/multipolygon.hpp>
#include <boost/geometry/algorithms/detail/is_valid/ring.hpp>
#include <boost/geometry/algorithms/detail/is_valid/segment.hpp>
#include <boost/geometry/algorithms/detail/is_valid/box.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP

View File

@@ -0,0 +1,272 @@
// Boost.Geometry
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_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/algorithms/dispatch/is_valid.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/geometries/concepts/check.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>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/intersection.hpp>
namespace boost { namespace geometry
{
namespace resolve_strategy
{
struct is_valid
{
template <typename Geometry, typename VisitPolicy, typename Strategy>
static inline bool apply(Geometry const& geometry,
VisitPolicy& visitor,
Strategy const& strategy)
{
return dispatch::is_valid<Geometry>::apply(geometry, visitor, strategy);
}
template <typename Geometry, typename VisitPolicy>
static inline bool apply(Geometry const& geometry,
VisitPolicy& visitor,
default_strategy)
{
// NOTE: Currently the strategy is only used for Areal geometries
typedef typename strategy::intersection::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type strategy_type;
return dispatch::is_valid<Geometry>::apply(geometry, visitor, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant
{
template <typename Geometry>
struct is_valid
{
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Geometry const& geometry,
VisitPolicy& visitor,
Strategy const& strategy)
{
concepts::check<Geometry const>();
return resolve_strategy::is_valid::apply(geometry, visitor, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename VisitPolicy, typename Strategy>
struct visitor : boost::static_visitor<bool>
{
visitor(VisitPolicy& policy, Strategy const& strategy)
: m_policy(policy)
, m_strategy(strategy)
{}
template <typename Geometry>
bool operator()(Geometry const& geometry) const
{
return is_valid<Geometry>::apply(geometry, m_policy, m_strategy);
}
VisitPolicy& m_policy;
Strategy const& m_strategy;
};
template <typename VisitPolicy, typename Strategy>
static inline bool
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
VisitPolicy& policy_visitor,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<VisitPolicy, Strategy>(policy_visitor, strategy),
geometry);
}
};
} // namespace resolve_variant
// Undocumented for now
template <typename Geometry, typename VisitPolicy, typename Strategy>
inline bool is_valid(Geometry const& geometry,
VisitPolicy& visitor,
Strategy const& strategy)
{
return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
}
/*!
\brief \brief_check{is valid (in the OGC sense)}
\ingroup is_valid
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Is_valid}
\param geometry \param_geometry
\param strategy \param_strategy{is_valid}
\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 strategy}
\qbk{[include reference/algorithms/is_valid.qbk]}
*/
template <typename Geometry, typename Strategy>
inline bool is_valid(Geometry const& geometry, Strategy const& strategy)
{
is_valid_default_policy<> visitor;
return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
}
/*!
\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);
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 is_valid(geometry, default_strategy());
}
/*!
\brief \brief_check{is valid (in the OGC sense)}
\ingroup is_valid
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Is_valid}
\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
\param strategy \param_strategy{is_valid}
\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 and strategy}
\qbk{[include reference/algorithms/is_valid_with_failure.qbk]}
*/
template <typename Geometry, typename Strategy>
inline bool is_valid(Geometry const& geometry, validity_failure_type& failure, Strategy const& strategy)
{
failure_type_policy<> visitor;
bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
failure = 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 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)
{
return is_valid(geometry, failure, default_strategy());
}
/*!
\brief \brief_check{is valid (in the OGC sense)}
\ingroup is_valid
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Is_valid}
\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
\param strategy \param_strategy{is_valid}
\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 and strategy}
\qbk{[include reference/algorithms/is_valid_with_message.qbk]}
*/
template <typename Geometry, typename Strategy>
inline bool is_valid(Geometry const& geometry, std::string& message, Strategy const& strategy)
{
std::ostringstream stream;
failing_reason_policy<> visitor(stream);
bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
message = stream.str();
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)
{
return is_valid(geometry, message, default_strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP

View File

@@ -0,0 +1,161 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, 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_IS_ACCEPTABLE_TURN_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP
#include <boost/range.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template
<
typename Geometry,
order_selector Order = geometry::point_order<Geometry>::value,
typename Tag = typename tag<Geometry>::type
>
struct acceptable_operation
{};
template <typename Polygon>
struct acceptable_operation<Polygon, counterclockwise, polygon_tag>
{
static const detail::overlay::operation_type value =
detail::overlay::operation_union;
};
template <typename Polygon>
struct acceptable_operation<Polygon, clockwise, polygon_tag>
{
static const detail::overlay::operation_type value =
detail::overlay::operation_intersection;
};
template <typename MultiPolygon>
struct acceptable_operation<MultiPolygon, counterclockwise, multi_polygon_tag>
{
static const detail::overlay::operation_type value =
detail::overlay::operation_intersection;
};
template <typename MultiPolygon>
struct acceptable_operation<MultiPolygon, clockwise, multi_polygon_tag>
{
static const detail::overlay::operation_type value =
detail::overlay::operation_union;
};
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>
{
protected:
template <typename Turn, typename Method, typename Operation>
static inline bool check_turn(Turn const& turn,
Method method,
Operation operation)
{
return turn.method == method
&& turn.operations[0].operation == operation
&& turn.operations[1].operation == operation;
}
public:
template <typename Turn>
static inline bool apply(Turn const& turn)
{
using namespace detail::overlay;
if ( turn.operations[0].seg_id.ring_index
== turn.operations[1].seg_id.ring_index )
{
return false;
}
operation_type const op = acceptable_operation<Polygon>::value;
return check_turn(turn, method_touch_interior, op)
|| check_turn(turn, method_touch, op)
;
}
};
template <typename MultiPolygon>
class is_acceptable_turn<MultiPolygon, multi_polygon_tag>
: is_acceptable_turn<typename boost::range_value<MultiPolygon>::type>
{
private:
typedef typename boost::range_value<MultiPolygon>::type polygon;
typedef is_acceptable_turn<polygon> base;
public:
template <typename Turn>
static inline bool apply(Turn const& turn)
{
using namespace detail::overlay;
if ( turn.operations[0].seg_id.multi_index
== turn.operations[1].seg_id.multi_index )
{
return base::apply(turn);
}
operation_type const op = acceptable_operation<MultiPolygon>::value;
if ( base::check_turn(turn, method_touch_interior, op)
|| base::check_turn(turn, method_touch, op))
{
return true;
}
// Turn is acceptable only in case of a touch(interior) and both lines
// (polygons) do not cross
return (turn.method == method_touch
|| turn.method == method_touch_interior)
&& turn.touch_only;
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP

View File

@@ -0,0 +1,186 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/condition.hpp>
#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_invalid_coordinate.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
#include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename Linestring>
struct is_valid_linestring
{
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Linestring const& linestring,
VisitPolicy& visitor,
Strategy const& strategy)
{
if (has_invalid_coordinate<Linestring>::apply(linestring, visitor))
{
return false;
}
if (boost::size(linestring) < 2)
{
return visitor.template apply<failure_few_points>();
}
std::size_t num_distinct = detail::num_distinct_consecutive_points
<
Linestring,
3u,
true,
not_equal_to<typename point_type<Linestring>::type>
>::apply(linestring);
if (num_distinct < 2u)
{
return
visitor.template apply<failure_wrong_topological_dimension>();
}
if (num_distinct == 2u)
{
return visitor.template apply<no_failure>();
}
return ! has_spikes
<
Linestring, closed
>::apply(linestring, visitor,
strategy.get_side_strategy());
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A linestring is a curve.
// A curve is 1-dimensional so it has to have at least two distinct
// points.
// A curve is simple if it does not pass through the same point twice,
// with the possible exception of its two endpoints
//
// There is an option here as to whether spikes are allowed for linestrings;
// here we pass this as an additional template parameter: allow_spikes
// If allow_spikes is set to true, spikes are allowed, false otherwise.
// By default, spikes are disallowed
//
// Reference: OGC 06-103r4 (6.1.6.1)
template <typename Linestring, bool AllowEmptyMultiGeometries>
struct is_valid
<
Linestring, linestring_tag, AllowEmptyMultiGeometries
> : detail::is_valid::is_valid_linestring<Linestring>
{};
// A MultiLinestring is a MultiCurve
// A MultiCurve is simple if all of its elements are simple and the
// only intersections between any two elements occur at Points that
// are on the boundaries of both elements.
//
// Reference: OGC 06-103r4 (6.1.8.1; Fig. 9)
template <typename MultiLinestring, bool AllowEmptyMultiGeometries>
class is_valid
<
MultiLinestring, multi_linestring_tag, AllowEmptyMultiGeometries
>
{
private:
template <typename VisitPolicy, typename Strategy>
struct per_linestring
{
per_linestring(VisitPolicy& policy, Strategy const& strategy)
: m_policy(policy)
, m_strategy(strategy)
{}
template <typename Linestring>
inline bool apply(Linestring const& linestring) const
{
return detail::is_valid::is_valid_linestring
<
Linestring
>::apply(linestring, m_policy, m_strategy);
}
VisitPolicy& m_policy;
Strategy const& m_strategy;
};
public:
template <typename VisitPolicy, typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
VisitPolicy& visitor,
Strategy const& strategy)
{
if (BOOST_GEOMETRY_CONDITION(
AllowEmptyMultiGeometries && boost::empty(multilinestring)))
{
return visitor.template apply<no_failure>();
}
typedef per_linestring<VisitPolicy, Strategy> per_ls;
return detail::check_iterator_range
<
per_ls,
false // do not check for empty multilinestring (done above)
>::apply(boost::begin(multilinestring),
boost::end(multilinestring),
per_ls(visitor, strategy));
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP

View File

@@ -0,0 +1,395 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_MULTIPOLYGON_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP
#include <deque>
#include <vector>
#include <boost/core/ignore_unused.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#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>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
#include <boost/geometry/algorithms/detail/is_valid/polygon.hpp>
#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
#include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
#include <boost/geometry/strategies/intersection.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename MultiPolygon, bool AllowEmptyMultiGeometries>
class is_valid_multipolygon
: is_valid_polygon
<
typename boost::range_value<MultiPolygon>::type,
true // check only the validity of rings
>
{
private:
typedef is_valid_polygon
<
typename boost::range_value<MultiPolygon>::type,
true
> base;
template
<
typename PolygonIterator,
typename TurnIterator,
typename VisitPolicy,
typename Strategy
>
static inline
bool are_polygon_interiors_disjoint(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
VisitPolicy& visitor,
Strategy const& strategy)
{
boost::ignore_unused(visitor);
// collect all polygons that have crossing turns
std::set<signed_size_type> multi_indices;
for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
{
if (! tit->touch_only)
{
multi_indices.insert(tit->operations[0].seg_id.multi_index);
multi_indices.insert(tit->operations[1].seg_id.multi_index);
}
}
typedef geometry::model::box<typename point_type<MultiPolygon>::type> box_type;
typedef typename base::template partition_item<PolygonIterator, box_type> item_type;
// put polygon iterators without turns in a vector
std::vector<item_type> polygon_iterators;
signed_size_type multi_index = 0;
for (PolygonIterator it = polygons_first; it != polygons_beyond;
++it, ++multi_index)
{
if (multi_indices.find(multi_index) == multi_indices.end())
{
polygon_iterators.push_back(item_type(it));
}
}
// prepare strategies
typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
envelope_strategy_type const envelope_strategy
= strategy.get_envelope_strategy();
// call partition to check if polygons are disjoint from each other
typename base::template item_visitor_type<Strategy> item_visitor(strategy);
geometry::partition
<
geometry::model::box<typename point_type<MultiPolygon>::type>
>::apply(polygon_iterators, item_visitor,
typename base::template expand_box<envelope_strategy_type>(envelope_strategy),
typename base::template overlaps_box<envelope_strategy_type>(envelope_strategy));
if (item_visitor.items_overlap)
{
return visitor.template apply<failure_intersecting_interiors>();
}
else
{
return visitor.template apply<no_failure>();
}
}
class has_multi_index
{
public:
has_multi_index(signed_size_type multi_index)
: m_multi_index(multi_index)
{}
template <typename Turn>
inline bool operator()(Turn const& turn) const
{
return turn.operations[0].seg_id.multi_index == m_multi_index
&& turn.operations[1].seg_id.multi_index == m_multi_index;
}
private:
signed_size_type const m_multi_index;
};
template <typename Predicate>
struct has_property_per_polygon
{
template
<
typename PolygonIterator,
typename TurnIterator,
typename VisitPolicy,
typename Strategy
>
static inline bool apply(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
VisitPolicy& visitor,
Strategy const& strategy)
{
signed_size_type multi_index = 0;
for (PolygonIterator it = polygons_first; it != polygons_beyond;
++it, ++multi_index)
{
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,
visitor,
strategy))
{
return false;
}
}
return true;
}
};
template
<
typename PolygonIterator,
typename TurnIterator,
typename VisitPolicy,
typename Strategy
>
static inline bool have_holes_inside(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
VisitPolicy& visitor,
Strategy const& strategy)
{
return has_property_per_polygon
<
typename base::has_holes_inside
>::apply(polygons_first, polygons_beyond,
turns_first, turns_beyond, visitor, strategy);
}
template
<
typename PolygonIterator,
typename TurnIterator,
typename VisitPolicy,
typename Strategy
>
static inline bool have_connected_interior(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
VisitPolicy& visitor,
Strategy const& strategy)
{
return has_property_per_polygon
<
typename base::has_connected_interior
>::apply(polygons_first, polygons_beyond,
turns_first, turns_beyond, visitor, strategy);
}
template <typename VisitPolicy, typename Strategy>
struct per_polygon
{
per_polygon(VisitPolicy& policy, Strategy const& strategy)
: m_policy(policy)
, m_strategy(strategy)
{}
template <typename Polygon>
inline bool apply(Polygon const& polygon) const
{
return base::apply(polygon, m_policy, m_strategy);
}
VisitPolicy& m_policy;
Strategy const& m_strategy;
};
public:
template <typename VisitPolicy, typename Strategy>
static inline bool apply(MultiPolygon const& multipolygon,
VisitPolicy& visitor,
Strategy const& strategy)
{
typedef debug_validity_phase<MultiPolygon> debug_phase;
if (BOOST_GEOMETRY_CONDITION(
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
<
per_polygon<VisitPolicy, Strategy>,
false // do not check for empty multipolygon (done above)
>::apply(boost::begin(multipolygon),
boost::end(multipolygon),
per_polygon<VisitPolicy, Strategy>(visitor, strategy)))
{
return false;
}
// compute turns and check if all are acceptable
debug_phase::apply(2);
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, visitor, strategy);
debug_print_turns(turns.begin(), turns.end());
if (has_invalid_turns)
{
return false;
}
// check if each polygon's interior rings are inside the
// exterior and not one inside the other
debug_phase::apply(3);
if (! have_holes_inside(boost::begin(multipolygon),
boost::end(multipolygon),
turns.begin(),
turns.end(),
visitor,
strategy))
{
return false;
}
// check that each polygon's interior is connected
debug_phase::apply(4);
if (! have_connected_interior(boost::begin(multipolygon),
boost::end(multipolygon),
turns.begin(),
turns.end(),
visitor,
strategy))
{
return false;
}
// check if polygon interiors are disjoint
debug_phase::apply(5);
return are_polygon_interiors_disjoint(boost::begin(multipolygon),
boost::end(multipolygon),
turns.begin(),
turns.end(),
visitor,
strategy);
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// Not clear what the definition is.
// Right now we check that each element is simple (in fact valid), and
// that the MultiPolygon is also valid.
//
// Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14)
template <typename MultiPolygon, bool AllowEmptyMultiGeometries>
struct is_valid
<
MultiPolygon, multi_polygon_tag, AllowEmptyMultiGeometries
> : detail::is_valid::is_valid_multipolygon
<
MultiPolygon, AllowEmptyMultiGeometries
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP

View File

@@ -0,0 +1,92 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_POINTLIKE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
#include <boost/geometry/util/condition.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A point is always simple
template <typename Point>
struct is_valid<Point, point_tag>
{
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Point const& point, VisitPolicy& visitor, Strategy const&)
{
boost::ignore_unused(visitor);
return ! detail::is_valid::has_invalid_coordinate
<
Point
>::apply(point, visitor);
}
};
// A MultiPoint is simple if no two Points in the MultiPoint are equal
// (have identical coordinate values in X and Y)
//
// Reference: OGC 06-103r4 (6.1.5)
template <typename MultiPoint, bool AllowEmptyMultiGeometries>
struct is_valid<MultiPoint, multi_point_tag, AllowEmptyMultiGeometries>
{
template <typename VisitPolicy, typename Strategy>
static inline bool apply(MultiPoint const& multipoint,
VisitPolicy& visitor,
Strategy const&)
{
boost::ignore_unused(multipoint, visitor);
if (BOOST_GEOMETRY_CONDITION(
AllowEmptyMultiGeometries || !boost::empty(multipoint)))
{
// we allow empty multi-geometries, so an empty multipoint
// is considered valid
return ! detail::is_valid::has_invalid_coordinate
<
MultiPoint
>::apply(multipoint, visitor);
}
else
{
// we do not allow an empty multipoint
return visitor.template apply<failure_few_points>();
}
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP

View File

@@ -0,0 +1,518 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_POLYGON_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
#include <cstddef>
#ifdef BOOST_GEOMETRY_TEST_DEBUG
#include <iostream>
#endif // BOOST_GEOMETRY_TEST_DEBUG
#include <algorithm>
#include <deque>
#include <iterator>
#include <set>
#include <vector>
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#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>
#include <boost/geometry/iterators/point_iterator.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#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/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
#include <boost/geometry/algorithms/detail/is_valid/ring.hpp>
#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
#include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp>
#include <boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename Polygon, bool CheckRingValidityOnly = false>
class is_valid_polygon
{
protected:
typedef debug_validity_phase<Polygon> debug_phase;
template <typename VisitPolicy, typename Strategy>
struct per_ring
{
per_ring(VisitPolicy& policy, Strategy const& strategy)
: m_policy(policy)
, m_strategy(strategy)
{}
template <typename Ring>
inline bool apply(Ring const& ring) const
{
return detail::is_valid::is_valid_ring
<
Ring, false, true
>::apply(ring, m_policy, m_strategy);
}
VisitPolicy& m_policy;
Strategy const& m_strategy;
};
template <typename InteriorRings, typename VisitPolicy, typename Strategy>
static bool has_valid_interior_rings(InteriorRings const& interior_rings,
VisitPolicy& visitor,
Strategy const& strategy)
{
return
detail::check_iterator_range
<
per_ring<VisitPolicy, Strategy>,
true // allow for empty interior ring range
>::apply(boost::begin(interior_rings),
boost::end(interior_rings),
per_ring<VisitPolicy, Strategy>(visitor, strategy));
}
struct has_valid_rings
{
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
VisitPolicy& visitor,
Strategy const& strategy)
{
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,
false // do not check self intersections
>::apply(exterior_ring(polygon), visitor, strategy))
{
return false;
}
// check validity of interior rings
debug_phase::apply(2);
return has_valid_interior_rings(geometry::interior_rings(polygon),
visitor,
strategy);
}
};
// 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>
inline void apply(Box& total, partition_item<Iterator, Box> const& item) const
{
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>
inline bool apply(Box const& box, partition_item<Iterator, Box> const& item) const
{
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)
{}
template <typename Iterator, typename Box>
inline bool apply(partition_item<Iterator, Box> const& item1,
partition_item<Iterator, Box> const& item2)
{
typedef boost::mpl::vector
<
geometry::de9im::static_mask<'T'>,
geometry::de9im::static_mask<'*', 'T'>,
geometry::de9im::static_mask<'*', '*', '*', 'T'>
> relate_mask_t;
if ( ! items_overlap
&& geometry::relate(*item1.get(), *item2.get(), relate_mask_t(), m_strategy) )
{
items_overlap = true;
return false; // interrupt
}
return true;
}
};
// structs for partition -- end
template
<
typename RingIterator,
typename ExteriorRing,
typename TurnIterator,
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,
Strategy const& strategy)
{
boost::ignore_unused(visitor);
// collect the interior ring indices that have turns with the
// exterior ring
std::set<signed_size_type> ring_indices;
for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
{
if (tit->operations[0].seg_id.ring_index == -1)
{
BOOST_GEOMETRY_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)
{
BOOST_GEOMETRY_ASSERT(tit->operations[0].seg_id.ring_index != -1);
ring_indices.insert(tit->operations[0].seg_id.ring_index);
}
}
// 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)
{
// 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, in_exterior_strategy))
{
return visitor.template apply<failure_interior_rings_outside>();
}
}
// 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[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<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(item_type(it));
}
}
// prepare strategies
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<Strategy> item_visitor(strategy);
geometry::partition
<
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)
{
return visitor.template apply<failure_nested_interior_rings>();
}
else
{
return visitor.template apply<no_failure>();
}
}
template
<
typename InteriorRings,
typename ExteriorRing,
typename TurnIterator,
typename VisitPolicy,
typename Strategy
>
static inline bool are_holes_inside(InteriorRings const& interior_rings,
ExteriorRing const& exterior_ring,
TurnIterator first,
TurnIterator beyond,
VisitPolicy& visitor,
Strategy const& strategy)
{
return are_holes_inside(boost::begin(interior_rings),
boost::end(interior_rings),
exterior_ring,
first,
beyond,
visitor,
strategy);
}
struct has_holes_inside
{
template <typename TurnIterator, typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
TurnIterator beyond,
VisitPolicy& visitor,
Strategy const& strategy)
{
return are_holes_inside(geometry::interior_rings(polygon),
geometry::exterior_ring(polygon),
first,
beyond,
visitor,
strategy);
}
};
struct has_connected_interior
{
template <typename TurnIterator, typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
TurnIterator beyond,
VisitPolicy& visitor,
Strategy const& )
{
boost::ignore_unused(visitor);
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[1].seg_id.ring_index + 1 );
typename graph::vertex_handle vip = g.add_vertex(tit->point);
g.add_edge(v1, vip);
g.add_edge(v2, vip);
}
#ifdef BOOST_GEOMETRY_TEST_DEBUG
debug_print_complement_graph(std::cout, g);
#endif // BOOST_GEOMETRY_TEST_DEBUG
if (g.has_cycles())
{
return visitor.template apply<failure_disconnected_interior>();
}
else
{
return visitor.template apply<no_failure>();
}
}
};
public:
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
VisitPolicy& visitor,
Strategy const& strategy)
{
if (! has_valid_rings::apply(polygon, visitor, strategy))
{
return false;
}
if (BOOST_GEOMETRY_CONDITION(CheckRingValidityOnly))
{
return true;
}
// compute turns and check if all are acceptable
debug_phase::apply(3);
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, visitor, strategy);
debug_print_turns(turns.begin(), turns.end());
if (has_invalid_turns)
{
return false;
}
// check if all interior rings are inside the exterior ring
debug_phase::apply(4);
if (! has_holes_inside::apply(polygon,
turns.begin(), turns.end(),
visitor,
strategy))
{
return false;
}
// check whether the interior of the polygon is a connected set
debug_phase::apply(5);
return has_connected_interior::apply(polygon,
turns.begin(),
turns.end(),
visitor,
strategy);
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
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 AllowEmptyMultiGeometries>
struct is_valid
<
Polygon, polygon_tag, AllowEmptyMultiGeometries
> : detail::is_valid::is_valid_polygon<Polygon>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP

View File

@@ -0,0 +1,239 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_RING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
#include <deque>
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/order_as_direction.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/equals.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_duplicates.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
#include <boost/geometry/strategies/area.hpp>
#ifdef BOOST_GEOMETRY_TEST_DEBUG
#include <boost/geometry/io/dsv/write.hpp>
#endif
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
// struct to check whether a ring is topologically closed
template <typename Ring, closure_selector Closure /* open */>
struct is_topologically_closed
{
template <typename VisitPolicy>
static inline bool apply(Ring const&, VisitPolicy& visitor)
{
boost::ignore_unused(visitor);
return visitor.template apply<no_failure>();
}
};
template <typename Ring>
struct is_topologically_closed<Ring, closed>
{
template <typename VisitPolicy>
static inline bool apply(Ring const& ring, VisitPolicy& visitor)
{
boost::ignore_unused(visitor);
if (geometry::equals(range::front(ring), range::back(ring)))
{
return visitor.template apply<no_failure>();
}
else
{
return visitor.template apply<failure_not_closed>();
}
}
};
template <typename ResultType, bool IsInteriorRing /* false */>
struct ring_area_predicate
{
typedef std::greater<ResultType> type;
};
template <typename ResultType>
struct ring_area_predicate<ResultType, true>
{
typedef std::less<ResultType> type;
};
template <typename Ring, bool IsInteriorRing>
struct is_properly_oriented
{
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Ring const& ring, VisitPolicy& visitor,
Strategy const& strategy)
{
boost::ignore_unused(visitor);
typedef detail::area::ring_area
<
order_as_direction<geometry::point_order<Ring>::value>::value,
geometry::closure<Ring>::value
> ring_area_type;
typedef typename Strategy::template area_strategy
<
Ring
>::type::template result_type<Ring>::type area_result_type;
typename ring_area_predicate
<
area_result_type, IsInteriorRing
>::type predicate;
// Check area
area_result_type const zero = 0;
area_result_type const area
= ring_area_type::apply(ring,
strategy.template get_area_strategy<Ring>());
if (predicate(area, zero))
{
return visitor.template apply<no_failure>();
}
else
{
return visitor.template apply<failure_wrong_orientation>();
}
}
};
template
<
typename Ring,
bool CheckSelfIntersections = true,
bool IsInteriorRing = false
>
struct is_valid_ring
{
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Ring const& ring, VisitPolicy& visitor,
Strategy const& strategy)
{
// return invalid if any of the following condition holds:
// (a) the ring's point coordinates are not invalid (e.g., NaN)
// (b) the ring's size is below the minimal one
// (c) the ring consists of at most two distinct points
// (d) the ring is not topologically closed
// (e) the ring has spikes
// (f) the ring has duplicate points (if AllowDuplicates is false)
// (g) the boundary of the ring has self-intersections
// (h) 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 (d).
if (has_invalid_coordinate<Ring>::apply(ring, visitor))
{
return false;
}
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
is_topologically_closed<Ring, closure>::apply(ring, visitor)
&& ! has_duplicates<Ring, closure>::apply(ring, visitor)
&& ! has_spikes<Ring, closure>::apply(ring, visitor, strategy.get_side_strategy())
&& (! CheckSelfIntersections
|| has_valid_self_turns<Ring>::apply(ring, visitor, strategy))
&& is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor, strategy);
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A Ring is a Polygon with exterior boundary only.
// The Ring's boundary must be a LinearRing (see OGC 06-103-r4,
// 6.1.7.1, for the definition of LinearRing)
//
// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
template <typename Ring, bool AllowEmptyMultiGeometries>
struct is_valid
<
Ring, ring_tag, AllowEmptyMultiGeometries
> : detail::is_valid::is_valid_ring<Ring>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP

View File

@@ -0,0 +1,83 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, 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_SEGMENT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A segment is a curve.
// A curve is simple if it does not pass through the same point twice,
// with the possible exception of its two endpoints
// A curve is 1-dimensional, hence we have to check is the two
// endpoints of the segment coincide, since in this case it is
// 0-dimensional.
//
// Reference: OGC 06-103r4 (6.1.6.1)
template <typename Segment>
struct is_valid<Segment, segment_tag>
{
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Segment const& segment, VisitPolicy& visitor, Strategy const&)
{
boost::ignore_unused(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]);
if (detail::is_valid::has_invalid_coordinate
<
Segment
>::apply(segment, visitor))
{
return false;
}
else if (! geometry::equals(p[0], p[1]))
{
return visitor.template apply<no_failure>();
}
else
{
return
visitor.template apply<failure_wrong_topological_dimension>();
}
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP