sectionalize.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Unit Test
  3. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  4. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
  5. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
  6. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  7. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  8. // Use, modification and distribution is subject to the Boost Software License,
  9. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #include <iostream>
  12. #include <string>
  13. #include <geometry_test_common.hpp>
  14. #include <boost/geometry/algorithms/make.hpp>
  15. #include <boost/geometry/algorithms/num_points.hpp>
  16. #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
  17. #include <boost/geometry/geometries/geometries.hpp>
  18. #include <boost/geometry/geometries/point_xy.hpp>
  19. #include <boost/geometry/io/wkt/read.hpp>
  20. #include <boost/geometry/io/wkt/write.hpp>
  21. #include <test_common/test_point.hpp>
  22. #if defined(TEST_WITH_SVG)
  23. # include <boost/geometry/io/svg/svg_mapper.hpp>
  24. # include <boost/geometry/algorithms/buffer.hpp>
  25. # include <boost/geometry/algorithms/centroid.hpp>
  26. #endif
  27. template <int DimensionCount, typename Geometry>
  28. void test_sectionalize_part()
  29. {
  30. typedef typename bg::point_type<Geometry>::type point_type;
  31. typedef bg::model::box<point_type> box_type;
  32. typedef bg::sections<box_type, DimensionCount> sections_type;
  33. typedef typename boost::range_value<sections_type>::type section_type;
  34. typedef boost::mpl::vector_c<std::size_t, 0> dimension_list;
  35. typedef bg::detail::sectionalize::sectionalize_part
  36. <
  37. point_type, dimension_list
  38. > sectionalize_part;
  39. sections_type sections;
  40. section_type section;
  41. Geometry geometry;
  42. geometry.push_back(bg::make<point_type>(1, 1));
  43. bg::detail::no_rescale_policy rescale_policy;
  44. bg::ring_identifier ring_id;
  45. sectionalize_part::apply(sections, geometry.begin(), geometry.end(), rescale_policy, ring_id, 10);
  46. // There should not yet be anything generated, because it is only ONE point
  47. geometry.push_back(bg::make<point_type>(2, 2));
  48. sectionalize_part::apply(sections, geometry.begin(), geometry.end(), rescale_policy, ring_id, 10);
  49. }
  50. template <typename DimensionVector, bool Reverse, typename G>
  51. void test_sectionalize(std::string const& caseid, G const& g, std::size_t section_count,
  52. std::string const& index_check, std::string const& dir_check,
  53. std::size_t max_count = 10)
  54. {
  55. boost::ignore_unused(caseid);
  56. static const std::size_t dimension_count = boost::mpl::size<DimensionVector>::value;
  57. typedef typename bg::point_type<G>::type point;
  58. typedef bg::model::box<point> box;
  59. typedef bg::sections<box, dimension_count> sections;
  60. sections s;
  61. bg::sectionalize<Reverse, DimensionVector>(g,
  62. bg::detail::no_rescale_policy(), s, 0, max_count);
  63. BOOST_CHECK_EQUAL(s.size(), section_count);
  64. // Check if sections are consecutive and consistent
  65. int previous_index = -1;
  66. BOOST_FOREACH(typename sections::value_type const& sec, s)
  67. {
  68. if (sec.begin_index > 0)
  69. {
  70. BOOST_CHECK_EQUAL(previous_index, sec.begin_index);
  71. }
  72. BOOST_CHECK_EQUAL(int(sec.count), int(sec.end_index - sec.begin_index));
  73. previous_index = sec.end_index;
  74. }
  75. // Output streams for sections, boxes, other
  76. std::ostringstream out_sections;
  77. std::ostringstream out_boxes;
  78. std::ostringstream out_dirs;
  79. for (typename sections::size_type i = 0; i < s.size(); i++)
  80. {
  81. box const& b = s[i].bounding_box;
  82. if (i > 0)
  83. {
  84. out_sections << "|";
  85. out_dirs << "|";
  86. out_boxes << "|";
  87. }
  88. out_sections << s[i].begin_index << ".." << s[i].end_index;
  89. out_boxes << bg::get<0,0>(b) << " " << bg::get<0,1>(b)
  90. << ".." << bg::get<1,0>(b) << " " << bg::get<1,1>(b);
  91. for (std::size_t d = 0; d < dimension_count; d++)
  92. {
  93. out_dirs << (d == 0 ? "" : " ");
  94. switch(s[i].directions[d])
  95. {
  96. case -99: out_dirs << "DUP"; break;
  97. case -1 : out_dirs << "-"; break;
  98. case 0 : out_dirs << "."; break;
  99. case +1 : out_dirs << "+"; break;
  100. }
  101. }
  102. }
  103. if (! index_check.empty())
  104. {
  105. BOOST_CHECK_EQUAL(out_sections.str(), index_check);
  106. }
  107. if (! dir_check.empty())
  108. {
  109. BOOST_CHECK_EQUAL(out_dirs.str(), dir_check);
  110. }
  111. #if defined(TEST_WITH_SVG)
  112. {
  113. std::ostringstream filename;
  114. filename << "sectionalize_"
  115. << caseid << ".svg";
  116. std::ofstream svg(filename.str().c_str());
  117. typedef typename bg::point_type<G>::type point_type;
  118. bg::svg_mapper<point_type> mapper(svg, 500, 500);
  119. mapper.add(g);
  120. static const bool is_line = bg::geometry_id<G>::type::value == 2;
  121. mapper.map(g, is_line
  122. ? "opacity:0.6;stroke:rgb(0,0,255);stroke-width:5"
  123. : "opacity:0.6;fill:rgb(0,0,255);stroke:rgb(0,0,0);stroke-width:0.5");
  124. for (typename sections::size_type i = 0; i < s.size(); i++)
  125. {
  126. box b = s[i].bounding_box;
  127. bg::buffer(b, b, 0.01);
  128. mapper.map(b, s[i].duplicate
  129. ? "fill-opacity:0.4;stroke-opacity:0.6;fill:rgb(0,128,0);stroke:rgb(0,255,0);stroke-width:2.0"
  130. : "fill-opacity:0.2;stroke-opacity:0.4;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:0.5");
  131. std::ostringstream out;
  132. for (int d = 0; d < dimension_count; d++)
  133. {
  134. out << (d == 0 ? "[" : " ");
  135. switch(s[i].directions[d])
  136. {
  137. case -99: out << "DUP"; break;
  138. case -1 : out << "-"; break;
  139. case 0 : out << "."; break;
  140. case +1 : out << "+"; break;
  141. }
  142. }
  143. out << "] " << s[i].begin_index << ".." << s[i].end_index;
  144. point_type p;
  145. bg::centroid(b, p);
  146. mapper.text(p, out.str(), "");
  147. }
  148. }
  149. #endif
  150. }
  151. template <typename G, bool Reverse>
  152. void test_sectionalize(std::string const& caseid, std::string const& wkt,
  153. std::size_t count2, std::string const& s2, std::string const d2,
  154. std::size_t count1, std::string const& s1, std::string const d1,
  155. std::size_t max_count = 10)
  156. {
  157. G g;
  158. bg::read_wkt(wkt, g);
  159. typedef boost::mpl::vector_c<std::size_t, 0, 1> dim2;
  160. typedef boost::mpl::vector_c<std::size_t, 0> dim1;
  161. test_sectionalize<dim2, Reverse>(caseid + "_d2", g, count2, s2, d2, max_count);
  162. test_sectionalize<dim1, Reverse>(caseid + "_d1", g, count1, s1, d1, max_count);
  163. }
  164. template <typename P>
  165. void test_all()
  166. {
  167. test_sectionalize_part<1, bg::model::linestring<P> >();
  168. test_sectionalize<bg::model::linestring<P>, false>("ls",
  169. "LINESTRING(1 1,2 2,3 0,5 0,5 8)",
  170. 4, "0..1|1..2|2..3|3..4", "+ +|+ -|+ .|. +",
  171. 2, "0..3|3..4", "+|.");
  172. // These strings mean:
  173. // 0..1|1..2 -> first section: [0, 1] | second section [1, 2], etc
  174. // + +|+ - -> X increases, Y increases | X increases, Y decreases
  175. // +|. -> (only X considered) X increases | X constant
  176. test_sectionalize<bg::model::polygon<P>, false>("simplex",
  177. "POLYGON((0 0,0 7,4 2,2 0,0 0))",
  178. 4, "0..1|1..2|2..3|3..4", ". +|+ -|- -|- .",
  179. // . + - - -> 3 sections
  180. 3, "0..1|1..2|2..4", ".|+|-");
  181. // CCW polygon - orientation is not (always) relevant for sections,
  182. // they are just generated in the order they come.
  183. test_sectionalize<bg::model::polygon<P, false>, false>("simplex_ccw",
  184. "POLYGON((0 0,2 0,4 2,0 7,0 0))",
  185. 4, "0..1|1..2|2..3|3..4", "+ .|+ +|- +|. -",
  186. // . + - - -> 3 sections
  187. 3, "0..2|2..3|3..4", "+|-|.");
  188. // Open polygon - closeness IS relevant for sections, the
  189. // last section which is not explicit here should be included.
  190. // So results are the same as the pre-previous one.
  191. test_sectionalize<bg::model::polygon<P, true, false>, false>("simplex_open",
  192. "POLYGON((0 0,0 7,4 2,2 0))",
  193. 4, "0..1|1..2|2..3|3..4", ". +|+ -|- -|- .",
  194. // . + - - -> 3 sections
  195. 3, "0..1|1..2|2..4", ".|+|-");
  196. test_sectionalize<bg::model::polygon<P>, false>("first",
  197. "polygon((2.0 1.3, 2.4 1.7, 2.8 1.8, 3.4 1.2, 3.7 1.6,3.4 2.0, 4.1 3.0, 5.3 2.6, 5.4 1.2, 4.9 0.8, 2.9 0.7,2.0 1.3))",
  198. 8, "0..2|2..3|3..4|4..5|5..6|6..8|8..10|10..11", "+ +|+ -|+ +|- +|+ +|+ -|- -|- +",
  199. 4, "0..4|4..5|5..8|8..11", "+|-|+|-");
  200. test_sectionalize<bg::model::polygon<P, false>, true>("first_reverse",
  201. "polygon((2.0 1.3, 2.4 1.7, 2.8 1.8, 3.4 1.2, 3.7 1.6,3.4 2.0, 4.1 3.0, 5.3 2.6, 5.4 1.2, 4.9 0.8, 2.9 0.7,2.0 1.3))",
  202. 8, "0..1|1..3|3..5|5..6|6..7|7..8|8..9|9..11", "+ -|+ +|- +|- -|+ -|- -|- +|- -",
  203. 4, "0..3|3..6|6..7|7..11", "+|-|+|-");
  204. test_sectionalize<bg::model::polygon<P>, false>("second",
  205. "POLYGON((3 1,2 2,1 3,2 4,3 5,4 4,5 3,4 2,3 1))",
  206. 4, "0..2|2..4|4..6|6..8", "- +|+ +|+ -|- -",
  207. // - - - + + + + - - -> 3 sections
  208. 3, "0..2|2..6|6..8", "-|+|-");
  209. // With holes
  210. test_sectionalize<bg::model::polygon<P>, false>("with_holes",
  211. "POLYGON((3 1,2 2,1 3,2 4,3 5,4 4,5 3,4 2,3 1), (3 2,2 2,3 4,3 2))",
  212. 7, "0..2|2..4|4..6|6..8|0..1|1..2|2..3", "- +|+ +|+ -|- -|- .|+ +|. -",
  213. // - - - + + + + - - - + . -> 6 sections
  214. 6, "0..2|2..6|6..8|0..1|1..2|2..3", "-|+|-|-|+|.");
  215. // With duplicates
  216. test_sectionalize<bg::model::linestring<P>, false>("with_dups",
  217. "LINESTRING(1 1,2 2,3 0,3 0,5 0,5 8)",
  218. 5, "0..1|1..2|2..3|3..4|4..5", "+ +|+ -|DUP DUP|+ .|. +",
  219. 4, "0..2|2..3|3..4|4..5", "+|DUP|+|.");
  220. // With two subsequent duplicate segments
  221. test_sectionalize<bg::model::linestring<P>, false>("with_subseq_dups",
  222. "LINESTRING(1 1,2 2,3 0,3 0,3 0,5 0,5 0,5 0,5 0,5 8)",
  223. 6, "0..1|1..2|2..4|4..5|5..8|8..9", "+ +|+ -|DUP DUP|+ .|DUP DUP|. +",
  224. 5, "0..2|2..4|4..5|5..8|8..9", "+|DUP|+|DUP|.");
  225. typedef bg::model::box<P> B;
  226. test_sectionalize<B, false>("box2", "BOX(0 0,4 4)",
  227. 4, "0..1|1..2|2..3|3..4", ". +|+ .|. -|- .",
  228. 4, "0..1|1..2|2..3|3..4", ".|+|.|-");
  229. std::string horizontal("POLYGON((0 10,1 8,2 10,3 8,4 10,5 8,6 10,7 8,8 10,9 8,10 10,11 8,12 10,12 5,9 5,9 4,8 4,8 5,7 5,7 4,6 4,6 5,5 5,5 4,4 4,4 5,3 5,3 4,2 4,2 5,1 5,1 4,0 4,0 10))");
  230. test_sectionalize<bg::model::polygon<P>, false>("horizontal", horizontal,
  231. 33, "", "",
  232. 22, "", "", 100);
  233. test_sectionalize<bg::model::polygon<P>, false>("horizontal4", horizontal,
  234. 33, "", "",
  235. 24, "", "", 4);
  236. std::string vertical("POLYGON((4 0,6 1,4 2,6 3,4 4,6 5,4 6,6 7,4 8,6 9,4 10,10 10,10 9,9 9,9 8,10 8,10 7,9 7,9 6,10 6,10 5,9 5,9 4,10 4,10 3,9 3,9 2,10 2,10 1,9 1,9 0,5 0))");
  237. test_sectionalize<bg::model::polygon<P>, false>("vertical", vertical,
  238. 31, "", "",
  239. 31, "", "", 100);
  240. {
  241. typedef boost::mpl::vector_c<std::size_t, 1> only_y_dim;
  242. bg::model::polygon<P> pol;
  243. bg::read_wkt(vertical, pol);
  244. test_sectionalize<only_y_dim, false>("vertical_y", pol, 22, "", "", 100);
  245. }
  246. return;
  247. // Buffer-case
  248. test_sectionalize<bg::model::polygon<P>, false>("buffer",
  249. "POLYGON((-1.1713 0.937043,2.8287 5.93704,2.90334 6.02339,2.98433 6.10382,2.98433 6.10382,3.07121 6.17786,3.16346 6.24507,3.16346 6.24507,3.16346 6.24507,3.26056 6.30508,3.36193 6.35752,3.36193 6.35752,3.46701 6.40211,3.57517 6.43858,3.57517 6.43858,3.57517 6.43858,3.57517 6.43858,3.68579 6.46672,3.79822 6.48637,3.79822 6.48637,3.91183 6.49741,4.02595 6.49978,4.02595 6.49978,4.02595 6.49978,4.13991 6.49346,4.25307 6.4785,4.25307 6.4785,4.36476 6.45497,4.47434 6.42302,4.47434 6.42302,4.47434 6.42302,4.47434 6.42302,7.47434 5.42302,6.84189 3.52566,4.39043 4.68765,0.390434 -0.312348,-1.1713 0.937043))",
  250. 8, "0..2|2..3|3..4|4..5|5..6|6..8|8..10|10..11", "+ +|+ -|+ +|- +|+ +|+ -|- -|- +",
  251. 4, "0..4|4..5|5..8|8..11", "+|-|+|-");
  252. }
  253. void test_large_integers()
  254. {
  255. typedef bg::model::point<int, 2, bg::cs::cartesian> int_point_type;
  256. typedef bg::model::point<double, 2, bg::cs::cartesian> double_point_type;
  257. std::string const polygon_li = "POLYGON((1872000 528000,1872000 192000,1536119 192000,1536000 528000,1200000 528000,1200000 863880,1536000 863880,1872000 863880,1872000 528000))";
  258. bg::model::polygon<int_point_type> int_poly;
  259. bg::model::polygon<double_point_type> double_poly;
  260. bg::read_wkt(polygon_li, int_poly);
  261. bg::read_wkt(polygon_li, double_poly);
  262. typedef boost::mpl::vector_c<std::size_t, 0> dimensions;
  263. bg::sections<bg::model::box<int_point_type>, 1> int_sections;
  264. bg::sections<bg::model::box<double_point_type>, 1> double_sections;
  265. bg::sectionalize<false, dimensions>(int_poly, bg::detail::no_rescale_policy(), int_sections);
  266. bg::sectionalize<false, dimensions>(double_poly, bg::detail::no_rescale_policy(), double_sections);
  267. bool equally_sized = int_sections.size() == double_sections.size();
  268. BOOST_CHECK(equally_sized);
  269. if (! equally_sized)
  270. {
  271. return;
  272. }
  273. for (unsigned int i = 0; i < int_sections.size(); i++)
  274. {
  275. BOOST_CHECK(int_sections[i].begin_index == double_sections[i].begin_index);
  276. BOOST_CHECK(int_sections[i].count == double_sections[i].count);
  277. }
  278. }
  279. int test_main(int, char* [])
  280. {
  281. test_large_integers();
  282. //test_all<bg::model::d2::point_xy<float> >();
  283. test_all<bg::model::d2::point_xy<double> >();
  284. return 0;
  285. }