123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Copyright (c) 2014-2023, Oracle and/or its affiliates.
- // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
- // 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, typename Strategy>
- 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, -1, Strategy
- >()(*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, typename Strategy>
- class complement_graph
- {
- private:
- typedef complement_graph_vertex<TurnPoint, Strategy> 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 OutputStream>
- friend inline
- void debug_print_complement_graph(OutputStream&,
- complement_graph<TurnPoint, Strategy> 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
|