voronoi_test_helper.hpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Boost.Polygon library voronoi_test_helper.hpp file
  2. // Copyright Andrii Sydorchuk 2010-2011.
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // See http://www.boost.org for updates, documentation, and revision history.
  7. #ifndef VORONOI_TEST_HELPER
  8. #define VORONOI_TEST_HELPER
  9. #include <boost/polygon/polygon.hpp>
  10. #include <algorithm>
  11. #include <iostream>
  12. #include <iterator>
  13. #include <fstream>
  14. #include <map>
  15. #include <vector>
  16. #include <utility>
  17. using namespace boost::polygon;
  18. namespace voronoi_test_helper {
  19. enum kOrientation {
  20. RIGHT = -1,
  21. COLLINEAR = 0,
  22. LEFT = 1
  23. };
  24. template <typename VERTEX>
  25. kOrientation get_orientation(
  26. const VERTEX& v1, const VERTEX& v2, const VERTEX& v3) {
  27. typename VERTEX::coordinate_type lhs = (v2.x() - v1.x()) * (v3.y() - v2.y());
  28. typename VERTEX::coordinate_type rhs = (v2.y() - v1.y()) * (v3.x() - v2.x());
  29. if (lhs == rhs) {
  30. return COLLINEAR;
  31. }
  32. return (lhs < rhs) ? RIGHT : LEFT;
  33. }
  34. template <typename OUTPUT>
  35. bool verify_cell_convexity(const OUTPUT& output) {
  36. typename OUTPUT::const_cell_iterator cell_it;
  37. for (cell_it = output.cells().begin();
  38. cell_it != output.cells().end(); cell_it++) {
  39. const typename OUTPUT::edge_type* edge = cell_it->incident_edge();
  40. if (edge)
  41. do {
  42. if (edge->next()->prev() != edge) {
  43. return false;
  44. }
  45. if (edge->cell() != &(*cell_it)) {
  46. return false;
  47. }
  48. if (edge->vertex1() != edge->next()->vertex0()) {
  49. return false;
  50. }
  51. if (edge->vertex0() != NULL &&
  52. edge->vertex1() != NULL &&
  53. edge->next()->vertex1() != NULL) {
  54. if (get_orientation(*edge->vertex0(),
  55. *edge->vertex1(),
  56. *edge->next()->vertex1()) != LEFT) {
  57. return false;
  58. }
  59. }
  60. edge = edge->next();
  61. } while (edge != cell_it->incident_edge());
  62. }
  63. return true;
  64. }
  65. template <typename OUTPUT>
  66. bool verify_incident_edges_ccw_order(const OUTPUT& output) {
  67. typedef typename OUTPUT::edge_type voronoi_edge_type;
  68. typename OUTPUT::const_vertex_iterator vertex_it;
  69. for (vertex_it = output.vertices().begin();
  70. vertex_it != output.vertices().end(); vertex_it++) {
  71. if (vertex_it->is_degenerate())
  72. continue;
  73. const voronoi_edge_type* edge = vertex_it->incident_edge();
  74. do {
  75. const voronoi_edge_type* next_edge = edge->rot_next();
  76. if (edge->vertex0() != next_edge->vertex0()) {
  77. return false;
  78. }
  79. if (edge->vertex1() != NULL && next_edge->vertex1() != NULL &&
  80. get_orientation(*edge->vertex1(),
  81. *edge->vertex0(),
  82. *next_edge->vertex1()) == LEFT) {
  83. return false;
  84. }
  85. edge = edge->rot_next();
  86. } while (edge != vertex_it->incident_edge());
  87. }
  88. return true;
  89. }
  90. template <typename VERTEX>
  91. struct cmp {
  92. bool operator()(const VERTEX& v1, const VERTEX& v2) const {
  93. if (v1.x() != v2.x())
  94. return v1.x() < v2.x();
  95. return v1.y() < v2.y();
  96. }
  97. };
  98. template <typename Output>
  99. bool verfiy_no_line_edge_intersections(const Output &output) {
  100. // Create map from edges with first point less than the second one.
  101. // Key is the first point of the edge, value is a vector of second points
  102. // with the same first point.
  103. typedef typename Output::vertex_type vertex_type;
  104. cmp<vertex_type> comparator;
  105. std::map< vertex_type, std::vector<vertex_type>, cmp<vertex_type> > edge_map;
  106. typename Output::const_edge_iterator edge_it;
  107. for (edge_it = output.edges().begin();
  108. edge_it != output.edges().end(); edge_it++) {
  109. if (edge_it->is_finite()) {
  110. if (comparator(*edge_it->vertex0(), *edge_it->vertex1())) {
  111. edge_map[*edge_it->vertex0()].push_back(*edge_it->vertex1());
  112. }
  113. }
  114. }
  115. return !intersection_check(edge_map);
  116. }
  117. template <typename Point2D>
  118. bool intersection_check(
  119. const std::map< Point2D, std::vector<Point2D>, cmp<Point2D> > &edge_map) {
  120. // Iterate over map of edges and check if there are any intersections.
  121. // All the edges are stored by the low x value. That's why we iterate
  122. // left to right checking for intersections between all pairs of edges
  123. // that overlap in the x dimension.
  124. // Complexity. Approximately N*sqrt(N). Worst case N^2.
  125. typedef Point2D point_type;
  126. typedef typename point_type::coordinate_type coordinate_type;
  127. typedef typename std::map<point_type, std::vector<point_type>, cmp<Point2D> >::const_iterator
  128. edge_map_iterator;
  129. typedef typename std::vector<point_type>::size_type size_type;
  130. edge_map_iterator edge_map_it1, edge_map_it2, edge_map_it_bound;
  131. for (edge_map_it1 = edge_map.begin();
  132. edge_map_it1 != edge_map.end(); edge_map_it1++) {
  133. const point_type &point1 = edge_map_it1->first;
  134. for (size_type i = 0; i < edge_map_it1->second.size(); i++) {
  135. const point_type &point2 = edge_map_it1->second[i];
  136. coordinate_type min_y1 = (std::min)(point1.y(), point2.y());
  137. coordinate_type max_y1 = (std::max)(point1.y(), point2.y());
  138. // Find the first edge with greater or equal first point.
  139. edge_map_it_bound = edge_map.lower_bound(point2);
  140. edge_map_it2 = edge_map_it1;
  141. edge_map_it2++;
  142. for (; edge_map_it2 != edge_map_it_bound; edge_map_it2++) {
  143. const point_type &point3 = edge_map_it2->first;
  144. for (size_type j = 0; j < edge_map_it2->second.size(); j++) {
  145. const point_type &point4 = edge_map_it2->second[j];
  146. coordinate_type min_y2 = (std::min)(point3.y(), point4.y());
  147. coordinate_type max_y2 = (std::max)(point3.y(), point4.y());
  148. // In most cases it is enought to make
  149. // simple intersection check in the y dimension.
  150. if (!(max_y1 > min_y2 && max_y2 > min_y1))
  151. continue;
  152. // Intersection check.
  153. if (get_orientation(point1, point2, point3) *
  154. get_orientation(point1, point2, point4) == RIGHT &&
  155. get_orientation(point3, point4, point1) *
  156. get_orientation(point3, point4, point2) == RIGHT)
  157. return true;
  158. }
  159. }
  160. }
  161. }
  162. return false;
  163. }
  164. enum kVerification {
  165. CELL_CONVEXITY = 1,
  166. INCIDENT_EDGES_CCW_ORDER = 2,
  167. NO_HALF_EDGE_INTERSECTIONS = 4,
  168. FAST_VERIFICATION = 3,
  169. COMPLETE_VERIFICATION = 7
  170. };
  171. template <typename Output>
  172. bool verify_output(const Output &output, kVerification mask) {
  173. bool result = true;
  174. if (mask & CELL_CONVEXITY)
  175. result &= verify_cell_convexity(output);
  176. if (mask & INCIDENT_EDGES_CCW_ORDER)
  177. result &= verify_incident_edges_ccw_order(output);
  178. if (mask & NO_HALF_EDGE_INTERSECTIONS)
  179. result &= verfiy_no_line_edge_intersections(output);
  180. return result;
  181. }
  182. template <typename PointIterator>
  183. void save_points(
  184. PointIterator first, PointIterator last, const char* file_name) {
  185. std::ofstream ofs(file_name);
  186. ofs << std::distance(first, last) << std::endl;
  187. for (PointIterator it = first; it != last; ++it) {
  188. ofs << it->x() << " " << it->y() << std::endl;
  189. }
  190. ofs.close();
  191. }
  192. template <typename SegmentIterator>
  193. void save_segments(
  194. SegmentIterator first, SegmentIterator last, const char* file_name) {
  195. std::ofstream ofs(file_name);
  196. ofs << std::distance(first, last) << std::endl;
  197. for (SegmentIterator it = first; it != last; ++it) {
  198. ofs << it->low().x() << " " << it->low().y() << " ";
  199. ofs << it->high().x() << " " << it->high().y() << std::endl;
  200. }
  201. ofs.close();
  202. }
  203. template <typename T>
  204. void clean_segment_set(std::vector< segment_data<T> >& data) {
  205. typedef T Unit;
  206. typedef typename scanline_base<Unit>::Point Point;
  207. typedef typename scanline_base<Unit>::half_edge half_edge;
  208. typedef int segment_id;
  209. std::vector<std::pair<half_edge, segment_id> > half_edges;
  210. std::vector<std::pair<half_edge, segment_id> > half_edges_out;
  211. segment_id id = 0;
  212. half_edges.reserve(data.size());
  213. for (typename std::vector< segment_data<T> >::iterator it = data.begin();
  214. it != data.end(); ++it) {
  215. Point l = it->low();
  216. Point h = it->high();
  217. half_edges.push_back(std::make_pair(half_edge(l, h), id++));
  218. }
  219. half_edges_out.reserve(half_edges.size());
  220. // Apparently no need to pre-sort data when calling validate_scan.
  221. line_intersection<Unit>::validate_scan(
  222. half_edges_out, half_edges.begin(), half_edges.end());
  223. std::vector< segment_data<T> > result;
  224. result.reserve(half_edges_out.size());
  225. for (std::size_t i = 0; i < half_edges_out.size(); ++i) {
  226. id = half_edges_out[i].second;
  227. Point l = half_edges_out[i].first.first;
  228. Point h = half_edges_out[i].first.second;
  229. segment_data<T> orig_seg = data[id];
  230. if (orig_seg.high() < orig_seg.low())
  231. std::swap(l, h);
  232. result.push_back(segment_data<T>(l, h));
  233. }
  234. std::swap(result, data);
  235. }
  236. } // voronoi_test_helper
  237. #endif