traverse_ccw.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Unit Test
  3. // Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands.
  4. // Use, modification and distribution is subject to the Boost Software License,
  5. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. #define BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO
  8. #include <fstream>
  9. #include <iostream>
  10. #include <iomanip>
  11. #include <boost/foreach.hpp>
  12. #include <geometry_test_common.hpp>
  13. #include <boost/geometry/geometry.hpp>
  14. #include <boost/geometry/geometries/point_xy.hpp>
  15. #include <boost/geometry/geometries/polygon.hpp>
  16. #include <boost/geometry/io/wkt/wkt.hpp>
  17. #if defined(TEST_WITH_SVG)
  18. # include <boost/geometry/io/svg/svg_mapper.hpp>
  19. #endif
  20. #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
  21. #include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
  22. #include <algorithms/overlay/overlay_cases.hpp>
  23. template <typename Geometry>
  24. struct rev : boost::mpl::if_c<bg::point_order<Geometry>::value == bg::counterclockwise, boost::true_type, boost::false_type>::type
  25. {};
  26. template <typename Geometry1, typename Geometry2>
  27. inline typename bg::coordinate_type<Geometry1>::type
  28. intersect(Geometry1 const& g1, Geometry2 const& g2, std::string const& name,
  29. bg::detail::overlay::operation_type op)
  30. {
  31. boost::ignore_unused(name);
  32. typedef typename bg::strategy::side::services::default_strategy
  33. <
  34. typename bg::cs_tag<Geometry1>::type
  35. >::type side_strategy_type;
  36. typedef typename bg::point_type<Geometry1>::type point_type;
  37. typedef typename bg::rescale_policy_type<point_type>::type
  38. rescale_policy_type;
  39. rescale_policy_type rescale_policy
  40. = bg::get_rescale_policy<rescale_policy_type>(g1, g2);
  41. typedef bg::detail::overlay::traversal_turn_info
  42. <
  43. point_type,
  44. typename bg::detail::segment_ratio_type<point_type, rescale_policy_type>::type
  45. > turn_info;
  46. std::vector<turn_info> turns;
  47. bg::detail::get_turns::no_interrupt_policy policy;
  48. bg::get_turns
  49. <
  50. rev<Geometry1>::value,
  51. rev<Geometry2>::value,
  52. bg::detail::overlay::assign_null_policy
  53. >(g1, g2, rescale_policy, turns, policy);
  54. bg::enrich_intersection_points
  55. <
  56. rev<Geometry1>::value, rev<Geometry2>::value,
  57. bg::overlay_intersection
  58. >(turns, bg::detail::overlay::operation_intersection,
  59. g1, g2, rescale_policy, side_strategy_type());
  60. typedef bg::model::ring<typename bg::point_type<Geometry1>::type> ring_type;
  61. typedef std::deque<ring_type> out_vector;
  62. out_vector v;
  63. bg::detail::overlay::traverse
  64. <
  65. rev<Geometry1>::value, rev<Geometry2>::value,
  66. Geometry1, Geometry2
  67. >::apply(g1, g2, op, rescale_policy, turns, v);
  68. typename bg::coordinate_type<Geometry1>::type result = 0.0;
  69. BOOST_FOREACH(ring_type& ring, v)
  70. {
  71. result += bg::area(ring);
  72. }
  73. #if defined(TEST_WITH_SVG)
  74. {
  75. std::ostringstream filename;
  76. filename
  77. << name << "_"
  78. << (op == bg::detail::overlay::operation_intersection ? "i" : "u")
  79. << "_" << (rev<Geometry1>::value ? "ccw" : "cw")
  80. << "_" << (rev<Geometry2>::value ? "ccw" : "cw")
  81. << ".svg";
  82. std::ofstream svg(filename.str().c_str());
  83. bg::svg_mapper<typename bg::point_type<Geometry1>::type> mapper(svg, 500, 500);
  84. mapper.add(g1);
  85. mapper.add(g2);
  86. // Input shapes in green/blue
  87. mapper.map(g1, "fill-opacity:0.5;fill:rgb(153,204,0);"
  88. "stroke:rgb(153,204,0);stroke-width:3");
  89. mapper.map(g2, "fill-opacity:0.3;fill:rgb(51,51,153);"
  90. "stroke:rgb(51,51,153);stroke-width:3");
  91. // Traversal rings in magenta/light yellow fill
  92. BOOST_FOREACH(ring_type const& ring, v)
  93. {
  94. mapper.map(ring, "fill-opacity:0.3;stroke-opacity:0.4;fill:rgb(255,255,0);"
  95. "stroke:rgb(255,0,255);stroke-width:8");
  96. }
  97. // turn points in orange, + enrichment/traversal info
  98. // Simple map to avoid two texts at same place (note that can still overlap!)
  99. std::map<std::pair<int, int>, int> offsets;
  100. int index = 0;
  101. int const lineheight = 10;
  102. int const margin = 5;
  103. BOOST_FOREACH(turn_info const& turn, turns)
  104. {
  105. mapper.map(turn.point, "fill:rgb(255,128,0);"
  106. "stroke:rgb(0,0,0);stroke-width:1", 3);
  107. {
  108. // Map characteristics
  109. // Create a rounded off point
  110. std::pair<int, int> p
  111. = std::make_pair(
  112. boost::numeric_cast<int>(0.5 + 10 * bg::get<0>(turn.point)),
  113. boost::numeric_cast<int>(0.5 + 10 * bg::get<1>(turn.point))
  114. );
  115. std::string style = "fill:rgb(0,0,0);font-family:Arial;font-size:10px";
  116. std::ostringstream out;
  117. out << index
  118. << ": " << bg::method_char(turn.method)
  119. << std::endl
  120. << "op: " << bg::operation_char(turn.operations[0].operation)
  121. << " / " << bg::operation_char(turn.operations[1].operation)
  122. << (turn.is_discarded() ? " (discarded) " : turn.blocked() ? " (blocked)" : "")
  123. << std::endl;
  124. if (turn.operations[0].enriched.next_ip_index != -1)
  125. {
  126. out << "ip: " << turn.operations[0].enriched.next_ip_index;
  127. }
  128. else
  129. {
  130. out << "vx: " << turn.operations[0].enriched.travels_to_vertex_index;
  131. }
  132. out << " ";
  133. if (turn.operations[1].enriched.next_ip_index != -1)
  134. {
  135. out << "ip: " << turn.operations[1].enriched.next_ip_index;
  136. }
  137. else
  138. {
  139. out << "vx: " << turn.operations[1].enriched.travels_to_vertex_index;
  140. }
  141. out << std::endl;
  142. out
  143. << std::setprecision(3)
  144. << "dist: " << turn.operations[0].fraction
  145. << " / " << turn.operations[1].fraction
  146. << std::endl;
  147. offsets[p] += lineheight;
  148. int offset = offsets[p];
  149. offsets[p] += lineheight * 5;
  150. mapper.text(turn.point, out.str(), style, margin, offset, lineheight);
  151. }
  152. index++;
  153. }
  154. }
  155. #endif
  156. return result;
  157. }
  158. template <typename Geometry1, typename Geometry2>
  159. inline typename bg::coordinate_type<Geometry1>::type intersect(std::string const& wkt1, std::string const& wkt2, std::string const& name,
  160. bg::detail::overlay::operation_type op)
  161. {
  162. Geometry1 geometry1;
  163. Geometry2 geometry2;
  164. bg::read_wkt(wkt1, geometry1);
  165. bg::read_wkt(wkt2, geometry2);
  166. // Reverse if necessary: adapt to cw/ccw
  167. bg::correct(geometry1);
  168. bg::correct(geometry2);
  169. return intersect(geometry1, geometry2, name, op);
  170. }
  171. template <typename T>
  172. inline void test_polygon(std::string const& wkt1, std::string const& wkt2, std::string const& name)
  173. {
  174. typedef bg::model::d2::point_xy<T> point;
  175. typedef bg::model::polygon<point> clock;
  176. typedef bg::model::polygon<point, false> counter;
  177. namespace ov = bg::detail::overlay;
  178. T area1 = intersect<clock, clock>(wkt1, wkt2, name, ov::operation_intersection);
  179. T area2 = intersect<counter, counter>(wkt1, wkt2, name, ov::operation_intersection);
  180. T area3 = intersect<clock, counter>(wkt1, wkt2, name, ov::operation_intersection);
  181. T area4 = intersect<counter, clock>(wkt1, wkt2, name, ov::operation_intersection);
  182. BOOST_CHECK_CLOSE(area1, area2, 0.001);
  183. BOOST_CHECK_CLOSE(area3, area4, 0.001);
  184. BOOST_CHECK_CLOSE(area1, area3, 0.001);
  185. BOOST_CHECK_CLOSE(area2, area4, 0.001);
  186. area1 = intersect<clock, clock>(wkt1, wkt2, name, ov::operation_union);
  187. area2 = intersect<counter, counter>(wkt1, wkt2, name, ov::operation_union);
  188. area3 = intersect<clock, counter>(wkt1, wkt2, name, ov::operation_union);
  189. area4 = intersect<counter, clock>(wkt1, wkt2, name, ov::operation_union);
  190. BOOST_CHECK_CLOSE(area1, area2, 0.001);
  191. BOOST_CHECK_CLOSE(area3, area4, 0.001);
  192. BOOST_CHECK_CLOSE(area1, area3, 0.001);
  193. BOOST_CHECK_CLOSE(area2, area4, 0.001);
  194. }
  195. template <typename T>
  196. inline void test_box_polygon(std::string const& wkt1, std::string const& wkt2, std::string const& name)
  197. {
  198. typedef bg::model::d2::point_xy<T> point;
  199. typedef bg::model::box<point> box;
  200. typedef bg::model::polygon<point> clock;
  201. typedef bg::model::polygon<point, false> counter;
  202. namespace ov = bg::detail::overlay;
  203. T area1 = intersect<box, clock>(wkt1, wkt2, name + "_bp", ov::operation_intersection);
  204. T area2 = intersect<box, counter>(wkt1, wkt2, name + "_bp", ov::operation_intersection);
  205. T area3 = intersect<clock, box>(wkt2, wkt1, name + "_pb", ov::operation_intersection);
  206. T area4 = intersect<counter, box>(wkt2, wkt1, name + "_pb", ov::operation_intersection);
  207. BOOST_CHECK_CLOSE(area1, area2, 0.001);
  208. BOOST_CHECK_CLOSE(area3, area4, 0.001);
  209. BOOST_CHECK_CLOSE(area1, area3, 0.001);
  210. BOOST_CHECK_CLOSE(area2, area4, 0.001);
  211. area1 = intersect<box, clock>(wkt1, wkt2, name + "_bp", ov::operation_union);
  212. area2 = intersect<box, counter>(wkt1, wkt2, name + "_bp", ov::operation_union);
  213. area3 = intersect<clock, box>(wkt2, wkt1, name + "_pb", ov::operation_union);
  214. area4 = intersect<counter, box>(wkt2, wkt1, name + "_pb", ov::operation_union);
  215. BOOST_CHECK_CLOSE(area1, area2, 0.001);
  216. BOOST_CHECK_CLOSE(area3, area4, 0.001);
  217. BOOST_CHECK_CLOSE(area1, area3, 0.001);
  218. BOOST_CHECK_CLOSE(area2, area4, 0.001);
  219. }
  220. int test_main(int, char* [])
  221. {
  222. //bool const ig = true;
  223. test_polygon<double>(case_1[0], case_1[1], "c1");
  224. test_polygon<double>(case_2[0], case_2[1], "c2");
  225. test_polygon<double>(case_3[0], case_3[1], "c3");
  226. test_polygon<double>(case_4[0], case_4[1], "c4");
  227. test_polygon<double>(case_5[0], case_5[1], "c5");
  228. test_polygon<double>(case_6[0], case_6[1], "c6");
  229. test_polygon<double>(case_7[0], case_7[1], "c7");
  230. test_polygon<double>(case_8[0], case_8[1], "c8");
  231. test_polygon<double>(case_9[0], case_9[1], "c9" /*, ig */);
  232. test_polygon<double>(case_10[0], case_10[1], "c10");
  233. test_polygon<double>(case_11[0], case_11[1], "c11");
  234. test_polygon<double>(case_12[0], case_12[1], "c12");
  235. test_polygon<double>(case_13[0], case_13[1], "c13");
  236. test_polygon<double>(case_14[0], case_14[1], "c14");
  237. test_polygon<double>(case_15[0], case_15[1], "c15");
  238. test_polygon<double>(case_16[0], case_16[1], "c16");
  239. test_polygon<double>(case_17[0], case_17[1], "c17");
  240. test_polygon<double>(case_18[0], case_18[1], "c18");
  241. test_polygon<double>(case_19[0], case_19[1], "c19");
  242. test_polygon<double>(case_20[0], case_20[1], "c20");
  243. test_polygon<double>(case_21[0], case_21[1], "c21");
  244. test_polygon<double>(case_22[0], case_22[1], "c22" /*, ig */);
  245. test_polygon<double>(case_23[0], case_23[1], "c23");
  246. test_polygon<double>(case_24[0], case_24[1], "c24");
  247. test_polygon<double>(case_25[0], case_25[1], "c25" /*, ig */);
  248. test_polygon<double>(case_26[0], case_26[1], "c26" /*, ig */);
  249. test_polygon<double>(case_27[0], case_27[1], "c27");
  250. test_polygon<double>(case_28[0], case_28[1], "c28");
  251. test_polygon<double>(case_29[0], case_29[1], "c29");
  252. test_polygon<double>(case_30[0], case_30[1], "c30");
  253. test_polygon<double>(case_31[0], case_31[1], "c31" /*, ig */);
  254. test_polygon<double>(case_32[0], case_32[1], "c32" /*, ig */);
  255. test_polygon<double>(case_33[0], case_33[1], "c33" /*, ig */);
  256. test_polygon<double>(case_34[0], case_34[1], "c34");
  257. test_polygon<double>(case_35[0], case_35[1], "c35");
  258. test_polygon<double>(case_36[0], case_36[1], "c36" /*, ig */);
  259. test_polygon<double>(case_37[0], case_37[1], "c37" /*, ig */);
  260. test_polygon<double>(case_38[0], case_38[1], "c38" /*, ig */);
  261. test_polygon<double>(case_39[0], case_39[1], "c39");
  262. test_polygon<double>(case_40[0], case_40[1], "c40" /*, ig */);
  263. test_polygon<double>(case_41[0], case_41[1], "c41");
  264. test_polygon<double>(case_42[0], case_42[1], "c42");
  265. //test_polygon<double>(case_43[0], case_43[1], "c43", inv);
  266. test_polygon<double>(case_44[0], case_44[1], "c44");
  267. test_polygon<double>(case_45[0], case_45[1], "c45");
  268. //test_polygon<double>(case_46[0], case_46[1], "c46", inv);
  269. //test_polygon<double>(case_47[0], case_47[1], "c47" /*, ig */);
  270. //test_polygon<double>(case_48[0], case_48[1], "c48");
  271. test_polygon<double>(case_49[0], case_49[1], "c49");
  272. test_polygon<double>(case_50[0], case_50[1], "c50");
  273. test_polygon<double>(case_51[0], case_51[1], "c51");
  274. test_polygon<double>(case_52[0], case_52[1], "c52" /*, ig */);
  275. test_polygon<double>(case_53[0], case_53[1], "c53");
  276. // Invalid ones / overlaying intersection points / self tangencies
  277. //test_polygon<double>(case_54[0], case_54[1], "c54");
  278. //test_polygon<double>(case_55[0], case_55[1], "c55");
  279. //test_polygon<double>(case_56[0], case_56[1], "c56");
  280. //test_polygon<double>(case_57[0], case_57[1], "c57" /*, ig */);
  281. //test_polygon<double>(case_58[0], case_58[1], "c58");
  282. //test_polygon<double>(case_59[0], case_59[1], "c59");
  283. test_polygon<double>(pie_16_4_12[0], pie_16_4_12[1], "pie_16_4_12");
  284. test_polygon<double>(pie_23_21_12_500[0], pie_23_21_12_500[1], "pie_23_21_12_500");
  285. test_polygon<double>(pie_23_23_3_2000[0], pie_23_23_3_2000[1], "pie_23_23_3_2000");
  286. test_polygon<double>(pie_23_16_16[0], pie_23_16_16[1], "pie_23_16_16");
  287. test_polygon<double>(pie_16_2_15_0[0], pie_16_2_15_0[1], "pie_16_2_15_0");
  288. test_polygon<double>(pie_4_13_15[0], pie_4_13_15[1], "pie_4_13_15");
  289. test_polygon<double>(pie_20_20_7_100[0], pie_20_20_7_100[1], "pie_20_20_7_100");
  290. test_polygon<double>(hv_1[0], hv_1[1], "hv1");
  291. test_polygon<double>(hv_2[0], hv_2[1], "hv2");
  292. test_polygon<double>(hv_3[0], hv_3[1], "hv3");
  293. test_polygon<double>(hv_4[0], hv_4[1], "hv4");
  294. test_polygon<double>(hv_5[0], hv_5[1], "hv5");
  295. test_polygon<double>(hv_6[0], hv_6[1], "hv6");
  296. test_polygon<double>(hv_7[0], hv_7[1], "hv7");
  297. test_polygon<double>(dz_1[0], dz_1[1], "dz_1");
  298. test_polygon<double>(dz_2[0], dz_2[1], "dz_2");
  299. test_polygon<double>(dz_3[0], dz_3[1], "dz_3");
  300. test_box_polygon<double>("POLYGON((1 1,4 4))", case_1[0], "bp1");
  301. {
  302. static std::string example_box = "POLYGON((1.5 1.5, 4.5 2.5))";
  303. static std::string example_ring =
  304. "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 3,5.3 2.6,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3))";
  305. test_box_polygon<double>(example_box, example_ring, "bp2");
  306. }
  307. return 0;
  308. }