complement_graph.hpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2014-2023, Oracle and/or its affiliates.
  3. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  4. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Licensed under the Boost Software License version 1.0.
  7. // http://www.boost.org/users/license.html
  8. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
  9. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
  10. #include <cstddef>
  11. #include <set>
  12. #include <stack>
  13. #include <utility>
  14. #include <vector>
  15. #include <boost/core/addressof.hpp>
  16. #include <boost/geometry/algorithms/detail/signed_size_type.hpp>
  17. #include <boost/geometry/core/assert.hpp>
  18. #include <boost/geometry/policies/compare.hpp>
  19. namespace boost { namespace geometry
  20. {
  21. namespace detail { namespace is_valid
  22. {
  23. template <typename TurnPoint, typename Strategy>
  24. class complement_graph_vertex
  25. {
  26. public:
  27. complement_graph_vertex(std::size_t id)
  28. : m_id(id)
  29. , m_turn_point(NULL)
  30. {}
  31. complement_graph_vertex(TurnPoint const* turn_point,
  32. std::size_t expected_id)
  33. : m_id(expected_id)
  34. , m_turn_point(turn_point)
  35. {}
  36. inline std::size_t id() const { return m_id; }
  37. inline bool operator<(complement_graph_vertex const& other) const
  38. {
  39. if ( m_turn_point != NULL && other.m_turn_point != NULL )
  40. {
  41. return geometry::less
  42. <
  43. TurnPoint, -1, Strategy
  44. >()(*m_turn_point, *other.m_turn_point);
  45. }
  46. if ( m_turn_point == NULL && other.m_turn_point == NULL )
  47. {
  48. return m_id < other.m_id;
  49. }
  50. return m_turn_point == NULL;
  51. }
  52. private:
  53. // the value of m_turn_point determines the type of the vertex
  54. // non-NULL: vertex corresponds to an IP
  55. // NULL : vertex corresponds to a hole or outer space, and the id
  56. // is the ring id of the corresponding ring of the polygon
  57. std::size_t m_id;
  58. TurnPoint const* m_turn_point;
  59. };
  60. template <typename TurnPoint, typename Strategy>
  61. class complement_graph
  62. {
  63. private:
  64. typedef complement_graph_vertex<TurnPoint, Strategy> vertex;
  65. typedef std::set<vertex> vertex_container;
  66. public:
  67. typedef typename vertex_container::const_iterator vertex_handle;
  68. private:
  69. struct vertex_handle_less
  70. {
  71. inline bool operator()(vertex_handle v1, vertex_handle v2) const
  72. {
  73. return v1->id() < v2->id();
  74. }
  75. };
  76. typedef std::set<vertex_handle, vertex_handle_less> neighbor_container;
  77. class has_cycles_dfs_data
  78. {
  79. public:
  80. has_cycles_dfs_data(std::size_t num_nodes)
  81. : m_visited(num_nodes, false)
  82. , m_parent_id(num_nodes, -1)
  83. {}
  84. inline signed_size_type parent_id(vertex_handle v) const
  85. {
  86. return m_parent_id[v->id()];
  87. }
  88. inline void set_parent_id(vertex_handle v, signed_size_type id)
  89. {
  90. m_parent_id[v->id()] = id;
  91. }
  92. inline bool visited(vertex_handle v) const
  93. {
  94. return m_visited[v->id()];
  95. }
  96. inline void set_visited(vertex_handle v, bool value)
  97. {
  98. m_visited[v->id()] = value;
  99. }
  100. private:
  101. std::vector<bool> m_visited;
  102. std::vector<signed_size_type> m_parent_id;
  103. };
  104. inline bool has_cycles(vertex_handle start_vertex,
  105. has_cycles_dfs_data& data) const
  106. {
  107. std::stack<vertex_handle> stack;
  108. stack.push(start_vertex);
  109. while ( !stack.empty() )
  110. {
  111. vertex_handle v = stack.top();
  112. stack.pop();
  113. data.set_visited(v, true);
  114. for (typename neighbor_container::const_iterator nit
  115. = m_neighbors[v->id()].begin();
  116. nit != m_neighbors[v->id()].end(); ++nit)
  117. {
  118. if ( static_cast<signed_size_type>((*nit)->id()) != data.parent_id(v) )
  119. {
  120. if ( data.visited(*nit) )
  121. {
  122. return true;
  123. }
  124. else
  125. {
  126. data.set_parent_id(*nit, static_cast<signed_size_type>(v->id()));
  127. stack.push(*nit);
  128. }
  129. }
  130. }
  131. }
  132. return false;
  133. }
  134. public:
  135. // num_rings: total number of rings, including the exterior ring
  136. complement_graph(std::size_t num_rings)
  137. : m_num_rings(num_rings)
  138. , m_num_turns(0)
  139. , m_vertices()
  140. , m_neighbors(num_rings)
  141. {}
  142. // inserts a ring vertex in the graph and returns its handle
  143. // ring id's are zero-based (so the first interior ring has id 1)
  144. inline vertex_handle add_vertex(signed_size_type id)
  145. {
  146. return m_vertices.insert(vertex(static_cast<std::size_t>(id))).first;
  147. }
  148. // inserts an IP in the graph and returns its id
  149. inline vertex_handle add_vertex(TurnPoint const& turn_point)
  150. {
  151. std::pair<vertex_handle, bool> res
  152. = m_vertices.insert(vertex(boost::addressof(turn_point),
  153. m_num_rings + m_num_turns)
  154. );
  155. if ( res.second )
  156. {
  157. // a new element is inserted
  158. m_neighbors.push_back(neighbor_container());
  159. ++m_num_turns;
  160. }
  161. return res.first;
  162. }
  163. inline void add_edge(vertex_handle v1, vertex_handle v2)
  164. {
  165. BOOST_GEOMETRY_ASSERT( v1 != m_vertices.end() );
  166. BOOST_GEOMETRY_ASSERT( v2 != m_vertices.end() );
  167. m_neighbors[v1->id()].insert(v2);
  168. m_neighbors[v2->id()].insert(v1);
  169. }
  170. inline bool has_cycles() const
  171. {
  172. // initialize all vertices as non-visited and with no parent set
  173. // this is done by the constructor of has_cycles_dfs_data
  174. has_cycles_dfs_data data(m_num_rings + m_num_turns);
  175. // for each non-visited vertex, start a DFS from that vertex
  176. for (vertex_handle it = m_vertices.begin();
  177. it != m_vertices.end(); ++it)
  178. {
  179. if ( !data.visited(it) && has_cycles(it, data) )
  180. {
  181. return true;
  182. }
  183. }
  184. return false;
  185. }
  186. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  187. template <typename OutputStream>
  188. friend inline
  189. void debug_print_complement_graph(OutputStream&,
  190. complement_graph<TurnPoint, Strategy> const&);
  191. #endif // BOOST_GEOMETRY_TEST_DEBUG
  192. private:
  193. std::size_t m_num_rings, m_num_turns;
  194. vertex_container m_vertices;
  195. std::vector<neighbor_container> m_neighbors;
  196. };
  197. }} // namespace detail::is_valid
  198. }} // namespace boost::geometry
  199. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP