recursive_polygons_buffer.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Robustness Test
  3. // Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
  4. // This file was modified by Oracle on 2015.
  5. // Modifications copyright (c) 2015 Oracle and/or its affiliates.
  6. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #if defined(_MSC_VER)
  11. # pragma warning( disable : 4244 )
  12. # pragma warning( disable : 4267 )
  13. #endif
  14. #include <fstream>
  15. #include <sstream>
  16. #include <boost/foreach.hpp>
  17. #include <boost/program_options.hpp>
  18. #include <boost/random/linear_congruential.hpp>
  19. #include <boost/random/uniform_int.hpp>
  20. #include <boost/random/uniform_real.hpp>
  21. #include <boost/random/variate_generator.hpp>
  22. #include <boost/timer.hpp>
  23. #include <boost/geometry.hpp>
  24. #include <boost/geometry/geometries/geometries.hpp>
  25. #include <boost/geometry/geometries/point_xy.hpp>
  26. #include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp>
  27. #include <boost/geometry/strategies/buffer.hpp>
  28. #include <common/common_settings.hpp>
  29. #include <common/make_square_polygon.hpp>
  30. struct buffer_settings : public common_settings
  31. {
  32. int join_code;
  33. double distance;
  34. };
  35. namespace bg = boost::geometry;
  36. template <typename Geometry1, typename Geometry2>
  37. void create_svg(std::string const& filename
  38. , Geometry1 const& mp
  39. , Geometry2 const& buffer
  40. )
  41. {
  42. typedef typename boost::geometry::point_type<Geometry1>::type point_type;
  43. std::ofstream svg(filename.c_str());
  44. boost::geometry::svg_mapper<point_type> mapper(svg, 800, 800);
  45. boost::geometry::model::box<point_type> box;
  46. bg::envelope(mp, box);
  47. bg::buffer(box, box, 1.0);
  48. mapper.add(box);
  49. if (! bg::is_empty(buffer))
  50. {
  51. bg::envelope(buffer, box);
  52. bg::buffer(box, box, 1.0);
  53. mapper.add(box);
  54. }
  55. mapper.map(mp, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:3");
  56. mapper.map(buffer, "stroke-opacity:0.9;stroke:rgb(0,0,0);fill:none;stroke-width:1");
  57. //mapper.map(intersection,"opacity:0.6;stroke:rgb(0,128,0);stroke-width:5");
  58. }
  59. template <typename MultiPolygon, typename Settings>
  60. bool verify(std::string const& caseid, MultiPolygon const& mp, MultiPolygon const& buffer, Settings const& settings)
  61. {
  62. bool result = true;
  63. // Area of buffer must be larger than of original polygon
  64. double area_mp = bg::area(mp);
  65. double area_buf = bg::area(buffer);
  66. if (area_buf < area_mp)
  67. {
  68. result = false;
  69. }
  70. if (result)
  71. {
  72. typedef typename boost::range_value<MultiPolygon const>::type polygon_type;
  73. BOOST_FOREACH(polygon_type const& polygon, mp)
  74. {
  75. typename bg::point_type<polygon_type>::type point;
  76. bg::point_on_border(point, polygon);
  77. if (! bg::within(point, buffer))
  78. {
  79. result = false;
  80. }
  81. }
  82. }
  83. if (result)
  84. {
  85. std::string message;
  86. if (! bg::is_valid(buffer, message))
  87. {
  88. std::cout << "Buffer is not valid: " << message << std::endl;
  89. result = false;
  90. }
  91. }
  92. bool svg = settings.svg;
  93. bool wkt = settings.wkt;
  94. if (! result)
  95. {
  96. std::cout << "ERROR " << caseid << std::endl;
  97. //std::cout << bg::wkt(mp) << std::endl;
  98. //std::cout << bg::wkt(buffer) << std::endl;
  99. svg = true;
  100. wkt = true;
  101. }
  102. if (svg || wkt)
  103. {
  104. //std::cout << caseid << std::endl;
  105. }
  106. if (svg)
  107. {
  108. std::ostringstream filename;
  109. filename << caseid << "_"
  110. << typeid(typename bg::coordinate_type<MultiPolygon>::type).name()
  111. << ".svg";
  112. create_svg(filename.str(), mp, buffer);
  113. }
  114. if (wkt)
  115. {
  116. std::ostringstream filename;
  117. filename << caseid << "_"
  118. << typeid(typename bg::coordinate_type<MultiPolygon>::type).name()
  119. << ".wkt";
  120. std::ofstream stream(filename.str().c_str());
  121. stream << bg::wkt(mp) << std::endl;
  122. stream << bg::wkt(buffer) << std::endl;
  123. }
  124. return result;
  125. }
  126. template <typename MultiPolygon, typename Generator, typename Settings>
  127. bool test_buffer(MultiPolygon& result, int& index,
  128. Generator& generator,
  129. int level, Settings const& settings)
  130. {
  131. MultiPolygon p, q;
  132. // Generate two boxes
  133. if (level == 0)
  134. {
  135. p.resize(1);
  136. q.resize(1);
  137. make_square_polygon(p.front(), generator, settings);
  138. make_square_polygon(q.front(), generator, settings);
  139. bg::correct(p);
  140. bg::correct(q);
  141. }
  142. else
  143. {
  144. bg::correct(p);
  145. bg::correct(q);
  146. if (! test_buffer(p, index, generator, level - 1, settings)
  147. || ! test_buffer(q, index, generator, level - 1, settings))
  148. {
  149. return false;
  150. }
  151. }
  152. typedef typename boost::range_value<MultiPolygon>::type polygon;
  153. MultiPolygon mp;
  154. bg::detail::union_::union_insert
  155. <
  156. polygon
  157. >(p, q, std::back_inserter(mp));
  158. bg::unique(mp);
  159. bg::unique(mp);
  160. bg::correct(mp);
  161. result = mp;
  162. typedef typename bg::coordinate_type<MultiPolygon>::type coordinate_type;
  163. typedef bg::strategy::buffer::distance_asymmetric<coordinate_type> distance_strategy_type;
  164. distance_strategy_type distance_strategy(settings.distance, settings.distance);
  165. MultiPolygon buffered;
  166. std::ostringstream out;
  167. out << "recursive_polygons_buffer_" << index++ << "_" << level;
  168. bg::strategy::buffer::end_round end_strategy;
  169. bg::strategy::buffer::point_circle point_strategy;
  170. bg::strategy::buffer::side_straight side_strategy;
  171. bg::strategy::buffer::join_round join_round_strategy(32); // Compatible with MySQL
  172. bg::strategy::buffer::join_miter join_miter_strategy;
  173. try
  174. {
  175. switch(settings.join_code)
  176. {
  177. case 1 :
  178. bg::buffer(mp, buffered,
  179. distance_strategy, side_strategy,
  180. join_round_strategy,
  181. end_strategy, point_strategy);
  182. break;
  183. case 2 :
  184. bg::buffer(mp, buffered,
  185. distance_strategy, side_strategy,
  186. join_miter_strategy,
  187. end_strategy, point_strategy);
  188. break;
  189. default :
  190. return false;
  191. }
  192. }
  193. catch(std::exception const& e)
  194. {
  195. MultiPolygon empty;
  196. std::cout << out.str() << std::endl;
  197. std::cout << "Exception " << e.what() << std::endl;
  198. verify(out.str(), mp, empty, settings);
  199. return false;
  200. }
  201. return verify(out.str(), mp, buffered, settings);
  202. }
  203. template <typename T, bool Clockwise, bool Closed, typename Settings>
  204. void test_all(int seed, int count, int level, Settings const& settings)
  205. {
  206. boost::timer t;
  207. typedef boost::minstd_rand base_generator_type;
  208. base_generator_type generator(seed);
  209. boost::uniform_int<> random_coordinate(0, settings.field_size - 1);
  210. boost::variate_generator<base_generator_type&, boost::uniform_int<> >
  211. coordinate_generator(generator, random_coordinate);
  212. typedef bg::model::polygon
  213. <
  214. bg::model::d2::point_xy<T>, Clockwise, Closed
  215. > polygon;
  216. typedef bg::model::multi_polygon<polygon> mp;
  217. int index = 0;
  218. for(int i = 0; i < count; i++)
  219. {
  220. mp p;
  221. test_buffer<mp>(p, index, coordinate_generator, level, settings);
  222. }
  223. std::cout
  224. << "geometries: " << index
  225. << " type: " << typeid(T).name()
  226. << " time: " << t.elapsed() << std::endl;
  227. }
  228. int main(int argc, char** argv)
  229. {
  230. try
  231. {
  232. namespace po = boost::program_options;
  233. po::options_description description("=== recursive_polygons_linear_areal ===\nAllowed options");
  234. int count = 1;
  235. int seed = static_cast<unsigned int>(std::time(0));
  236. int level = 3;
  237. bool ccw = false;
  238. bool open = false;
  239. buffer_settings settings;
  240. std::string form = "box";
  241. std::string join = "round";
  242. description.add_options()
  243. ("help", "Help message")
  244. ("seed", po::value<int>(&seed), "Initialization seed for random generator")
  245. ("count", po::value<int>(&count)->default_value(1), "Number of tests")
  246. ("level", po::value<int>(&level)->default_value(3), "Level to reach (higher->slower)")
  247. ("distance", po::value<double>(&settings.distance)->default_value(1.0), "Distance (1.0)")
  248. ("form", po::value<std::string>(&form)->default_value("box"), "Form of the polygons (box, triangle)")
  249. ("join", po::value<std::string>(&join)->default_value("round"), "Form of the joins (round, miter)")
  250. ("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
  251. ("open", po::value<bool>(&open)->default_value(false), "Open polygons")
  252. ("size", po::value<int>(&settings.field_size)->default_value(10), "Size of the field")
  253. ("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
  254. ("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
  255. ;
  256. po::variables_map varmap;
  257. po::store(po::parse_command_line(argc, argv, description), varmap);
  258. po::notify(varmap);
  259. if (varmap.count("help")
  260. || (form != "box" && form != "triangle")
  261. || (join != "round" && join != "miter")
  262. )
  263. {
  264. std::cout << description << std::endl;
  265. return 1;
  266. }
  267. settings.triangular = form != "box";
  268. settings.join_code = join == "round" ? 1 : 2;
  269. if (ccw && open)
  270. {
  271. test_all<double, false, false>(seed, count, level, settings);
  272. }
  273. else if (ccw)
  274. {
  275. test_all<double, false, true>(seed, count, level, settings);
  276. }
  277. else if (open)
  278. {
  279. test_all<double, true, false>(seed, count, level, settings);
  280. }
  281. else
  282. {
  283. test_all<double, true, true>(seed, count, level, settings);
  284. }
  285. #if defined(HAVE_TTMATH)
  286. // test_all<ttmath_big, true, true>(seed, count, max, svg, level);
  287. #endif
  288. }
  289. catch(std::exception const& e)
  290. {
  291. std::cout << "Exception " << e.what() << std::endl;
  292. }
  293. catch(...)
  294. {
  295. std::cout << "Other exception" << std::endl;
  296. }
  297. return 0;
  298. }