/Src/Dependencies/Boost/boost/graph/is_straight_line_drawing.hpp

http://hadesmem.googlecode.com/ · C++ Header · 252 lines · 189 code · 44 blank · 19 comment · 27 complexity · eb3ab295857fe2de632b426dbeb53b24 MD5 · raw file

  1. //=======================================================================
  2. // Copyright 2007 Aaron Windsor
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //=======================================================================
  8. #ifndef __IS_STRAIGHT_LINE_DRAWING_HPP__
  9. #define __IS_STRAIGHT_LINE_DRAWING_HPP__
  10. #include <boost/config.hpp>
  11. #include <boost/utility.hpp> //for next and prior
  12. #include <boost/tuple/tuple.hpp>
  13. #include <boost/tuple/tuple_comparison.hpp>
  14. #include <boost/property_map/property_map.hpp>
  15. #include <boost/graph/properties.hpp>
  16. #include <boost/graph/planar_detail/bucket_sort.hpp>
  17. #include <algorithm>
  18. #include <vector>
  19. #include <set>
  20. namespace boost
  21. {
  22. // Return true exactly when the line segments s1 = ((x1,y1), (x2,y2)) and
  23. // s2 = ((a1,b1), (a2,b2)) intersect in a point other than the endpoints of
  24. // the line segments. The one exception to this rule is when s1 = s2, in
  25. // which case false is returned - this is to accomodate multiple edges
  26. // between the same pair of vertices, which shouldn't invalidate the straight
  27. // line embedding. A tolerance variable epsilon can also be used, which
  28. // defines how far away from the endpoints of s1 and s2 we want to consider
  29. // an intersection.
  30. bool intersects(double x1, double y1,
  31. double x2, double y2,
  32. double a1, double b1,
  33. double a2, double b2,
  34. double epsilon = 0.000001
  35. )
  36. {
  37. if (x1 - x2 == 0)
  38. {
  39. std::swap(x1,a1);
  40. std::swap(y1,b1);
  41. std::swap(x2,a2);
  42. std::swap(y2,b2);
  43. }
  44. if (x1 - x2 == 0)
  45. {
  46. BOOST_USING_STD_MAX();
  47. BOOST_USING_STD_MIN();
  48. //two vertical line segments
  49. double min_y = min BOOST_PREVENT_MACRO_SUBSTITUTION(y1,y2);
  50. double max_y = max BOOST_PREVENT_MACRO_SUBSTITUTION(y1,y2);
  51. double min_b = min BOOST_PREVENT_MACRO_SUBSTITUTION(b1,b2);
  52. double max_b = max BOOST_PREVENT_MACRO_SUBSTITUTION(b1,b2);
  53. if ((max_y > max_b && max_b > min_y) ||
  54. (max_b > max_y && max_y > min_b)
  55. )
  56. return true;
  57. else
  58. return false;
  59. }
  60. double x_diff = x1 - x2;
  61. double y_diff = y1 - y2;
  62. double a_diff = a2 - a1;
  63. double b_diff = b2 - b1;
  64. double beta_denominator = b_diff - (y_diff/((double)x_diff)) * a_diff;
  65. if (beta_denominator == 0)
  66. {
  67. //parallel lines
  68. return false;
  69. }
  70. double beta = (b2 - y2 - (y_diff/((double)x_diff)) * (a2 - x2)) /
  71. beta_denominator;
  72. double alpha = (a2 - x2 - beta*(a_diff))/x_diff;
  73. double upper_bound = 1 - epsilon;
  74. double lower_bound = 0 + epsilon;
  75. return (beta < upper_bound && beta > lower_bound &&
  76. alpha < upper_bound && alpha > lower_bound);
  77. }
  78. template <typename Graph,
  79. typename GridPositionMap,
  80. typename VertexIndexMap
  81. >
  82. bool is_straight_line_drawing(const Graph& g,
  83. GridPositionMap drawing,
  84. VertexIndexMap
  85. )
  86. {
  87. typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
  88. typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
  89. typedef typename graph_traits<Graph>::edge_descriptor edge_t;
  90. typedef typename graph_traits<Graph>::edge_iterator edge_iterator_t;
  91. typedef typename graph_traits<Graph>::edges_size_type e_size_t;
  92. typedef typename graph_traits<Graph>::vertices_size_type v_size_t;
  93. typedef std::size_t x_coord_t;
  94. typedef std::size_t y_coord_t;
  95. typedef boost::tuple<edge_t, x_coord_t, y_coord_t> edge_event_t;
  96. typedef typename std::vector< edge_event_t > edge_event_queue_t;
  97. typedef tuple<y_coord_t, y_coord_t, x_coord_t, x_coord_t> active_map_key_t;
  98. typedef edge_t active_map_value_t;
  99. typedef std::map< active_map_key_t, active_map_value_t > active_map_t;
  100. typedef typename active_map_t::iterator active_map_iterator_t;
  101. edge_event_queue_t edge_event_queue;
  102. active_map_t active_edges;
  103. edge_iterator_t ei, ei_end;
  104. for(tie(ei,ei_end) = edges(g); ei != ei_end; ++ei)
  105. {
  106. edge_t e(*ei);
  107. vertex_t s(source(e,g));
  108. vertex_t t(target(e,g));
  109. edge_event_queue.push_back
  110. (make_tuple(e,
  111. static_cast<std::size_t>(drawing[s].x),
  112. static_cast<std::size_t>(drawing[s].y)
  113. )
  114. );
  115. edge_event_queue.push_back
  116. (make_tuple(e,
  117. static_cast<std::size_t>(drawing[t].x),
  118. static_cast<std::size_t>(drawing[t].y)
  119. )
  120. );
  121. }
  122. // Order by edge_event_queue by first, then second coordinate
  123. // (bucket_sort is a stable sort.)
  124. bucket_sort(edge_event_queue.begin(), edge_event_queue.end(),
  125. property_map_tuple_adaptor<edge_event_t, 2>()
  126. );
  127. bucket_sort(edge_event_queue.begin(), edge_event_queue.end(),
  128. property_map_tuple_adaptor<edge_event_t, 1>()
  129. );
  130. typedef typename edge_event_queue_t::iterator event_queue_iterator_t;
  131. event_queue_iterator_t itr_end = edge_event_queue.end();
  132. for(event_queue_iterator_t itr = edge_event_queue.begin();
  133. itr != itr_end; ++itr
  134. )
  135. {
  136. edge_t e(get<0>(*itr));
  137. vertex_t source_v(source(e,g));
  138. vertex_t target_v(target(e,g));
  139. if (drawing[source_v].y > drawing[target_v].y)
  140. std::swap(source_v, target_v);
  141. active_map_key_t key(get(drawing, source_v).y,
  142. get(drawing, target_v).y,
  143. get(drawing, source_v).x,
  144. get(drawing, target_v).x
  145. );
  146. active_map_iterator_t a_itr = active_edges.find(key);
  147. if (a_itr == active_edges.end())
  148. {
  149. active_edges[key] = e;
  150. }
  151. else
  152. {
  153. active_map_iterator_t before, after;
  154. if (a_itr == active_edges.begin())
  155. before = active_edges.end();
  156. else
  157. before = prior(a_itr);
  158. after = boost::next(a_itr);
  159. if (before != active_edges.end())
  160. {
  161. edge_t f = before->second;
  162. vertex_t e_source(source(e,g));
  163. vertex_t e_target(target(e,g));
  164. vertex_t f_source(source(f,g));
  165. vertex_t f_target(target(f,g));
  166. if (intersects(drawing[e_source].x,
  167. drawing[e_source].y,
  168. drawing[e_target].x,
  169. drawing[e_target].y,
  170. drawing[f_source].x,
  171. drawing[f_source].y,
  172. drawing[f_target].x,
  173. drawing[f_target].y
  174. )
  175. )
  176. return false;
  177. }
  178. if (after != active_edges.end())
  179. {
  180. edge_t f = after->second;
  181. vertex_t e_source(source(e,g));
  182. vertex_t e_target(target(e,g));
  183. vertex_t f_source(source(f,g));
  184. vertex_t f_target(target(f,g));
  185. if (intersects(drawing[e_source].x,
  186. drawing[e_source].y,
  187. drawing[e_target].x,
  188. drawing[e_target].y,
  189. drawing[f_source].x,
  190. drawing[f_source].y,
  191. drawing[f_target].x,
  192. drawing[f_target].y
  193. )
  194. )
  195. return false;
  196. }
  197. active_edges.erase(a_itr);
  198. }
  199. }
  200. return true;
  201. }
  202. template <typename Graph, typename GridPositionMap>
  203. bool is_straight_line_drawing(const Graph& g, GridPositionMap drawing)
  204. {
  205. return is_straight_line_drawing(g, drawing, get(vertex_index,g));
  206. }
  207. }
  208. #endif // __IS_STRAIGHT_LINE_DRAWING_HPP__