is_straight_line_drawing.hpp 8.0 KB

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