is_straight_line_drawing.hpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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, double x2, double y2, double a1,
  32. double b1, double a2, double b2, double epsilon = 0.000001)
  33. {
  34. if (x1 - x2 == 0)
  35. {
  36. std::swap(x1, a1);
  37. std::swap(y1, b1);
  38. std::swap(x2, a2);
  39. std::swap(y2, b2);
  40. }
  41. if (x1 - x2 == 0)
  42. {
  43. BOOST_USING_STD_MAX();
  44. BOOST_USING_STD_MIN();
  45. // two vertical line segments
  46. double min_y = min BOOST_PREVENT_MACRO_SUBSTITUTION(y1, y2);
  47. double max_y = max BOOST_PREVENT_MACRO_SUBSTITUTION(y1, y2);
  48. double min_b = min BOOST_PREVENT_MACRO_SUBSTITUTION(b1, b2);
  49. double max_b = max BOOST_PREVENT_MACRO_SUBSTITUTION(b1, b2);
  50. if ((max_y > max_b && max_b > min_y)
  51. || (max_b > max_y && max_y > min_b))
  52. return true;
  53. else
  54. return false;
  55. }
  56. double x_diff = x1 - x2;
  57. double y_diff = y1 - y2;
  58. double a_diff = a2 - a1;
  59. double b_diff = b2 - b1;
  60. double beta_denominator = b_diff - (y_diff / ((double)x_diff)) * a_diff;
  61. if (beta_denominator == 0)
  62. {
  63. // parallel lines
  64. return false;
  65. }
  66. double beta = (b2 - y2 - (y_diff / ((double)x_diff)) * (a2 - x2))
  67. / beta_denominator;
  68. double alpha = (a2 - x2 - beta * (a_diff)) / x_diff;
  69. double upper_bound = 1 - epsilon;
  70. double lower_bound = 0 + epsilon;
  71. return (beta < upper_bound && beta > lower_bound && alpha < upper_bound
  72. && alpha > lower_bound);
  73. }
  74. template < typename Graph, typename GridPositionMap, typename VertexIndexMap >
  75. bool is_straight_line_drawing(
  76. const Graph& g, GridPositionMap drawing, VertexIndexMap)
  77. {
  78. typedef typename graph_traits< Graph >::vertex_descriptor vertex_t;
  79. typedef typename graph_traits< Graph >::edge_descriptor edge_t;
  80. typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t;
  81. typedef std::size_t x_coord_t;
  82. typedef std::size_t y_coord_t;
  83. typedef boost::tuple< edge_t, x_coord_t, y_coord_t > edge_event_t;
  84. typedef typename std::vector< edge_event_t > edge_event_queue_t;
  85. typedef tuple< y_coord_t, y_coord_t, x_coord_t, x_coord_t >
  86. active_map_key_t;
  87. typedef edge_t active_map_value_t;
  88. typedef std::map< active_map_key_t, active_map_value_t > active_map_t;
  89. typedef typename active_map_t::iterator active_map_iterator_t;
  90. edge_event_queue_t edge_event_queue;
  91. active_map_t active_edges;
  92. edge_iterator_t ei, ei_end;
  93. for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
  94. {
  95. edge_t e(*ei);
  96. vertex_t s(source(e, g));
  97. vertex_t t(target(e, g));
  98. edge_event_queue.push_back(
  99. make_tuple(e, static_cast< std::size_t >(drawing[s].x),
  100. static_cast< std::size_t >(drawing[s].y)));
  101. edge_event_queue.push_back(
  102. make_tuple(e, static_cast< std::size_t >(drawing[t].x),
  103. static_cast< std::size_t >(drawing[t].y)));
  104. }
  105. // Order by edge_event_queue by first, then second coordinate
  106. // (bucket_sort is a stable sort.)
  107. bucket_sort(edge_event_queue.begin(), edge_event_queue.end(),
  108. property_map_tuple_adaptor< edge_event_t, 2 >());
  109. bucket_sort(edge_event_queue.begin(), edge_event_queue.end(),
  110. property_map_tuple_adaptor< edge_event_t, 1 >());
  111. typedef typename edge_event_queue_t::iterator event_queue_iterator_t;
  112. event_queue_iterator_t itr_end = edge_event_queue.end();
  113. for (event_queue_iterator_t itr = edge_event_queue.begin(); itr != itr_end;
  114. ++itr)
  115. {
  116. edge_t e(get< 0 >(*itr));
  117. vertex_t source_v(source(e, g));
  118. vertex_t target_v(target(e, g));
  119. if (drawing[source_v].y > drawing[target_v].y)
  120. std::swap(source_v, target_v);
  121. active_map_key_t key(get(drawing, source_v).y, get(drawing, target_v).y,
  122. get(drawing, source_v).x, get(drawing, target_v).x);
  123. active_map_iterator_t a_itr = active_edges.find(key);
  124. if (a_itr == active_edges.end())
  125. {
  126. active_edges[key] = e;
  127. }
  128. else
  129. {
  130. active_map_iterator_t before, after;
  131. if (a_itr == active_edges.begin())
  132. before = active_edges.end();
  133. else
  134. before = prior(a_itr);
  135. after = boost::next(a_itr);
  136. if (before != active_edges.end())
  137. {
  138. edge_t f = before->second;
  139. vertex_t e_source(source(e, g));
  140. vertex_t e_target(target(e, g));
  141. vertex_t f_source(source(f, g));
  142. vertex_t f_target(target(f, g));
  143. if (intersects(drawing[e_source].x, drawing[e_source].y,
  144. drawing[e_target].x, drawing[e_target].y,
  145. drawing[f_source].x, drawing[f_source].y,
  146. drawing[f_target].x, drawing[f_target].y))
  147. return false;
  148. }
  149. if (after != active_edges.end())
  150. {
  151. edge_t f = after->second;
  152. vertex_t e_source(source(e, g));
  153. vertex_t e_target(target(e, g));
  154. vertex_t f_source(source(f, g));
  155. vertex_t f_target(target(f, g));
  156. if (intersects(drawing[e_source].x, drawing[e_source].y,
  157. drawing[e_target].x, drawing[e_target].y,
  158. drawing[f_source].x, drawing[f_source].y,
  159. drawing[f_target].x, drawing[f_target].y))
  160. return false;
  161. }
  162. active_edges.erase(a_itr);
  163. }
  164. }
  165. return true;
  166. }
  167. template < typename Graph, typename GridPositionMap >
  168. bool is_straight_line_drawing(const Graph& g, GridPositionMap drawing)
  169. {
  170. return is_straight_line_drawing(g, drawing, get(vertex_index, g));
  171. }
  172. }
  173. #endif // __IS_STRAIGHT_LINE_DRAWING_HPP__