voronoi_benchmark_segments.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // Boost.Polygon library voronoi_benchmark.cpp file
  2. // Copyright Andrii Sydorchuk 2010-2012.
  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. #include <algorithm>
  8. #include <iomanip>
  9. #include <iostream>
  10. #include <fstream>
  11. #include <numeric>
  12. #include <vector>
  13. #include <utility>
  14. #include <boost/random/mersenne_twister.hpp>
  15. #include <boost/timer/timer.hpp>
  16. typedef boost::int32_t int32;
  17. using boost::timer::cpu_times;
  18. using boost::timer::nanosecond_type;
  19. // Include for the Boost.Polygon Voronoi library.
  20. #include <boost/polygon/voronoi.hpp>
  21. typedef boost::polygon::voronoi_diagram<double> VD_BOOST;
  22. // Includes for the CGAL library.
  23. #include <CGAL/Simple_cartesian.h>
  24. #include <CGAL/Segment_Delaunay_graph_filtered_traits_2.h>
  25. #include <CGAL/Segment_Delaunay_graph_2.h>
  26. typedef CGAL::Simple_cartesian<double> K;
  27. typedef CGAL::Segment_Delaunay_graph_filtered_traits_without_intersections_2<K> GT;
  28. typedef CGAL::Segment_Delaunay_graph_2<GT> SDT_CGAL;
  29. typedef SDT_CGAL::Point_2 Point_CGAL;
  30. typedef SDT_CGAL::Site_2 Site_CGAL;
  31. // Include for the Boost.Polygon library.
  32. #include <boost/polygon/polygon.hpp>
  33. typedef boost::polygon::point_data<int32> POINT_POLYGON;
  34. typedef boost::polygon::segment_data<int32> SEGMENT_POLYGON;
  35. typedef std::vector<SEGMENT_POLYGON> SSD_POLYGON;
  36. const int RANDOM_SEED = 27;
  37. const int NUM_TESTS = 6;
  38. const int NUM_SEGMENTS[] = {10, 100, 1000, 10000, 100000, 1000000};
  39. const int NUM_RUNS[] = {100000, 10000, 1000, 100, 10, 1};
  40. std::ofstream bf("benchmark_segments.txt",
  41. std::ios_base::out | std::ios_base::app);
  42. boost::timer::cpu_timer timer;
  43. void format_line(int num_points, int num_tests, double time_per_test) {
  44. bf << "| " << std::setw(16) << num_points << " ";
  45. bf << "| " << std::setw(15) << num_tests << " ";
  46. bf << "| " << std::setw(17) << time_per_test << " ";
  47. bf << "|" << std::endl;
  48. }
  49. double get_elapsed_secs() {
  50. cpu_times elapsed_times(timer.elapsed());
  51. return 1E-9 * static_cast<double>(
  52. elapsed_times.system + elapsed_times.user);
  53. }
  54. void clean_segment_set(std::vector<SEGMENT_POLYGON>* data) {
  55. typedef int32 Unit;
  56. typedef boost::polygon::scanline_base<Unit>::Point Point;
  57. typedef boost::polygon::scanline_base<Unit>::half_edge half_edge;
  58. typedef int segment_id;
  59. std::vector<std::pair<half_edge, segment_id> > half_edges;
  60. std::vector<std::pair<half_edge, segment_id> > half_edges_out;
  61. segment_id id = 0;
  62. half_edges.reserve(data->size());
  63. for (std::vector<SEGMENT_POLYGON>::iterator it = data->begin();
  64. it != data->end(); ++it) {
  65. POINT_POLYGON l = it->low();
  66. POINT_POLYGON h = it->high();
  67. half_edges.push_back(std::make_pair(half_edge(l, h), id++));
  68. }
  69. half_edges_out.reserve(half_edges.size());
  70. // Apparently no need to pre-sort data when calling validate_scan.
  71. boost::polygon::line_intersection<Unit>::validate_scan(
  72. half_edges_out, half_edges.begin(), half_edges.end());
  73. std::vector<SEGMENT_POLYGON> result;
  74. result.reserve(half_edges_out.size());
  75. for (std::size_t i = 0; i < half_edges_out.size(); ++i) {
  76. id = half_edges_out[i].second;
  77. POINT_POLYGON l = half_edges_out[i].first.first;
  78. POINT_POLYGON h = half_edges_out[i].first.second;
  79. SEGMENT_POLYGON orig_seg = data->at(id);
  80. if (orig_seg.high() < orig_seg.low())
  81. std::swap(l, h);
  82. result.push_back(SEGMENT_POLYGON(l, h));
  83. }
  84. std::swap(result, *data);
  85. }
  86. std::vector<double> get_intersection_runtime() {
  87. std::vector<double> running_times;
  88. boost::mt19937 gen(RANDOM_SEED);
  89. for (int i = 0; i < NUM_TESTS; ++i) {
  90. timer.start();
  91. for (int j = 0; j < NUM_RUNS[i]; ++j) {
  92. SSD_POLYGON ssd;
  93. for (int k = 0; k < NUM_SEGMENTS[i]; ++k) {
  94. int32 x1 = gen();
  95. int32 y1 = gen();
  96. int32 dx = (gen() & 1023) + 1;
  97. int32 dy = (gen() & 1023) + 1;
  98. ssd.push_back(SEGMENT_POLYGON(
  99. POINT_POLYGON(x1, y1), POINT_POLYGON(x1 + dx, y1 + dy)));
  100. }
  101. clean_segment_set(&ssd);
  102. }
  103. running_times.push_back(get_elapsed_secs());
  104. }
  105. return running_times;
  106. }
  107. void run_boost_voronoi_test(const std::vector<double> &running_times) {
  108. boost::mt19937 gen(RANDOM_SEED);
  109. bf << "Boost.Polygon Voronoi of Segments:\n";
  110. for (int i = 0; i < NUM_TESTS; ++i) {
  111. timer.start();
  112. for (int j = 0; j < NUM_RUNS[i]; ++j) {
  113. SSD_POLYGON ssd;
  114. VD_BOOST vd;
  115. for (int k = 0; k < NUM_SEGMENTS[i]; ++k) {
  116. int32 x1 = gen();
  117. int32 y1 = gen();
  118. int32 dx = (gen() & 1023) + 1;
  119. int32 dy = (gen() & 1023) + 1;
  120. ssd.push_back(SEGMENT_POLYGON(
  121. POINT_POLYGON(x1, y1),
  122. POINT_POLYGON(x1 + dx, y1 + dy)));
  123. }
  124. clean_segment_set(&ssd);
  125. boost::polygon::construct_voronoi(ssd.begin(), ssd.end(), &vd);
  126. }
  127. double time_per_test =
  128. (get_elapsed_secs() - running_times[i]) / NUM_RUNS[i];
  129. format_line(NUM_SEGMENTS[i], NUM_RUNS[i], time_per_test);
  130. }
  131. bf << "\n";
  132. }
  133. void run_cgal_delaunay_test(const std::vector<double> &running_times) {
  134. boost::mt19937 gen(RANDOM_SEED);
  135. bf << "CGAL Triangulation of Segments:\n";
  136. for (int i = 0; i < NUM_TESTS; ++i) {
  137. timer.start();
  138. for (int j = 0; j < NUM_RUNS[i]; ++j) {
  139. SSD_POLYGON ssd;
  140. for (int k = 0; k < NUM_SEGMENTS[i]; ++k) {
  141. int32 x1 = gen();
  142. int32 y1 = gen();
  143. int32 dx = (gen() & 1023) + 1;
  144. int32 dy = (gen() & 1023) + 1;
  145. ssd.push_back(SEGMENT_POLYGON(
  146. POINT_POLYGON(x1, y1),
  147. POINT_POLYGON(x1 + dx, y1 + dy)));
  148. }
  149. clean_segment_set(&ssd);
  150. typedef std::vector<Point_CGAL> Points_container;
  151. typedef std::vector<Points_container>::size_type Index_type;
  152. typedef std::vector< std::pair<Index_type, Index_type> > Constraints_container;
  153. Points_container points;
  154. Constraints_container constraints;
  155. points.reserve(ssd.size() * 2);
  156. constraints.reserve(ssd.size());
  157. for (SSD_POLYGON::iterator it = ssd.begin(); it != ssd.end(); ++it) {
  158. points.push_back(Point_CGAL(
  159. boost::polygon::x(it->low()),
  160. boost::polygon::y(it->low())));
  161. points.push_back(Point_CGAL(
  162. boost::polygon::x(it->high()),
  163. boost::polygon::y(it->high())));
  164. constraints.push_back(
  165. std::make_pair(points.size() - 2, points.size() - 1));
  166. }
  167. SDT_CGAL sdg;
  168. sdg.insert_segments(
  169. points.begin(), points.end(),
  170. constraints.begin(), constraints.end());
  171. }
  172. double time_per_test =
  173. (get_elapsed_secs() - running_times[i]) / NUM_RUNS[i];
  174. format_line(NUM_SEGMENTS[i], NUM_RUNS[i], time_per_test);
  175. }
  176. bf << "\n";
  177. }
  178. int main() {
  179. bf << std::setiosflags(std::ios::right | std::ios::fixed)
  180. << std::setprecision(6);
  181. std::vector<double> running_times = get_intersection_runtime();
  182. run_boost_voronoi_test(running_times);
  183. run_cgal_delaunay_test(running_times);
  184. bf.close();
  185. return 0;
  186. }