summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail/is_valid/complement_graph.hpp')
-rw-r--r--boost/geometry/algorithms/detail/is_valid/complement_graph.hpp239
1 files changed, 239 insertions, 0 deletions
diff --git a/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp
new file mode 100644
index 0000000000..c59139a92e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp
@@ -0,0 +1,239 @@
+// 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_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/assert.hpp>
+#include <boost/core/addressof.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_index_type parent_id(vertex_handle v) const
+ {
+ return m_parent_id[v->id()];
+ }
+
+ inline void set_parent_id(vertex_handle v, signed_index_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_index_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_index_type>((*nit)->id()) != data.parent_id(v) )
+ {
+ if ( data.visited(*nit) )
+ {
+ return true;
+ }
+ else
+ {
+ data.set_parent_id(*nit, static_cast<signed_index_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_index_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_ASSERT( v1 != m_vertices.end() );
+ BOOST_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;
+ }
+
+ template <typename OStream, typename TP>
+ friend inline
+ void debug_print_complement_graph(OStream&, complement_graph<TP> const&);
+
+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