complement_graph.hpp 6.7 KB

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