sort_by_side_basic.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Unit Test
  3. // Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands.
  4. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  5. // This file was modified by Oracle on 2017.
  6. // Modifications copyright (c) 2017, Oracle and/or its affiliates.
  7. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  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 <geometry_test_common.hpp>
  12. #include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
  13. #include <boost/geometry/strategies/strategies.hpp> // for equals/within
  14. #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
  15. #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
  16. #include <boost/geometry/algorithms/correct.hpp>
  17. #include <boost/geometry/algorithms/equals.hpp>
  18. #include <boost/geometry/io/wkt/wkt.hpp>
  19. #include <boost/geometry/geometries/geometries.hpp>
  20. #include <boost/assign/list_of.hpp>
  21. #include <boost/foreach.hpp>
  22. #if defined(TEST_WITH_SVG)
  23. #include "debug_sort_by_side_svg.hpp"
  24. #endif
  25. namespace
  26. {
  27. template <typename T>
  28. std::string as_string(std::vector<T> const& v)
  29. {
  30. std::stringstream out;
  31. bool first = true;
  32. BOOST_FOREACH(T const& value, v)
  33. {
  34. out << (first ? "[" : " , ") << value;
  35. first = false;
  36. }
  37. out << (first ? "" : "]");
  38. return out.str();
  39. }
  40. }
  41. template
  42. <
  43. typename Geometry, typename Point,
  44. typename RobustPolicy, typename Strategy
  45. >
  46. std::vector<std::size_t> apply_get_turns(std::string const& case_id,
  47. Geometry const& geometry1, Geometry const& geometry2,
  48. Point const& turn_point, Point const& origin_point,
  49. RobustPolicy const& robust_policy,
  50. Strategy const& strategy,
  51. std::size_t expected_open_count,
  52. std::size_t expected_max_rank,
  53. std::vector<bg::signed_size_type> const& expected_right_count)
  54. {
  55. using namespace boost::geometry;
  56. std::vector<std::size_t> result;
  57. //todo: maybe should be enriched to count left/right - but can also be counted from ranks
  58. typedef typename bg::point_type<Geometry>::type point_type;
  59. typedef bg::detail::overlay::turn_info
  60. <
  61. point_type,
  62. typename bg::detail::segment_ratio_type<point_type, RobustPolicy>::type
  63. > turn_info;
  64. typedef std::deque<turn_info> turn_container_type;
  65. turn_container_type turns;
  66. detail::get_turns::no_interrupt_policy policy;
  67. bg::get_turns
  68. <
  69. false, false,
  70. detail::overlay::assign_null_policy
  71. >(geometry1, geometry2, strategy, robust_policy, turns, policy);
  72. // Define sorter, sorting counter-clockwise such that polygons are on the
  73. // right side
  74. typedef typename Strategy::side_strategy_type side_strategy;
  75. typedef bg::detail::overlay::sort_by_side::side_sorter
  76. <
  77. false, false, overlay_union,
  78. point_type, side_strategy, std::less<int>
  79. > sbs_type;
  80. sbs_type sbs(strategy.get_side_strategy());
  81. std::cout << "Case: " << case_id << std::endl;
  82. bool has_origin = false;
  83. for (std::size_t turn_index = 0; turn_index < turns.size(); turn_index++)
  84. {
  85. turn_info const& turn = turns[turn_index];
  86. if (bg::equals(turn.point, turn_point))
  87. {
  88. // std::cout << "Found turn: " << turn_index << std::endl;
  89. for (int i = 0; i < 2; i++)
  90. {
  91. Point point1, point2, point3;
  92. bg::copy_segment_points<false, false>(geometry1, geometry2,
  93. turn.operations[i].seg_id, point1, point2, point3);
  94. bool const is_origin = ! has_origin && bg::equals(point1, origin_point);
  95. if (is_origin)
  96. {
  97. has_origin = true;
  98. }
  99. sbs.add(turn.operations[i], turn_index, i,
  100. geometry1, geometry2, is_origin);
  101. }
  102. }
  103. }
  104. BOOST_CHECK_MESSAGE(has_origin,
  105. " caseid=" << case_id
  106. << " origin not found");
  107. if (!has_origin)
  108. {
  109. for (std::size_t turn_index = 0; turn_index < turns.size(); turn_index++)
  110. {
  111. turn_info const& turn = turns[turn_index];
  112. if (bg::equals(turn.point, turn_point))
  113. {
  114. for (int i = 0; i < 2; i++)
  115. {
  116. Point point1, point2, point3;
  117. bg::copy_segment_points<false, false>(geometry1, geometry2,
  118. turn.operations[i].seg_id, point1, point2, point3);
  119. // std::cout << "Turn " << turn_index << " op " << i << " point1=" << bg::wkt(point1) << std::endl;
  120. }
  121. }
  122. }
  123. return result;
  124. }
  125. sbs.apply(turn_point);
  126. sbs.find_open();
  127. sbs.assign_zones(detail::overlay::operation_union);
  128. std::size_t const open_count = sbs.open_count(detail::overlay::operation_union);
  129. std::size_t const max_rank = sbs.m_ranked_points.back().rank;
  130. std::vector<bg::signed_size_type> right_count(max_rank + 1, -1);
  131. int previous_rank = -1;
  132. int previous_to_rank = -1;
  133. for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
  134. {
  135. typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i];
  136. int const rank = static_cast<int>(ranked_point.rank);
  137. bool const set_right = rank != previous_to_rank;
  138. if (rank != previous_rank)
  139. {
  140. BOOST_CHECK_MESSAGE(rank == previous_rank + 1,
  141. " caseid=" << case_id
  142. << " ranks: conflict in ranks=" << ranked_point.rank
  143. << " vs " << previous_rank + 1);
  144. previous_rank = rank;
  145. }
  146. if (ranked_point.direction != bg::detail::overlay::sort_by_side::dir_to)
  147. {
  148. continue;
  149. }
  150. previous_to_rank = rank;
  151. if (set_right)
  152. {
  153. right_count[rank] = ranked_point.count_right;
  154. }
  155. else
  156. {
  157. BOOST_CHECK_MESSAGE(right_count[rank] == int(ranked_point.count_right),
  158. " caseid=" << case_id
  159. << " ranks: conflict in right_count=" << ranked_point.count_right
  160. << " vs " << right_count[rank]);
  161. }
  162. }
  163. BOOST_CHECK_MESSAGE(open_count == expected_open_count,
  164. " caseid=" << case_id
  165. << " open_count: expected=" << expected_open_count
  166. << " detected=" << open_count);
  167. BOOST_CHECK_MESSAGE(max_rank == expected_max_rank,
  168. " caseid=" << case_id
  169. << " max_rank: expected=" << expected_max_rank
  170. << " detected=" << max_rank);
  171. BOOST_CHECK_MESSAGE(right_count == expected_right_count,
  172. " caseid=" << case_id
  173. << " right count: expected=" << as_string(expected_right_count)
  174. << " detected=" << as_string(right_count));
  175. #if defined(TEST_WITH_SVG)
  176. debug::sorted_side_map(case_id, sbs, turn_point, geometry1, geometry2);
  177. #endif
  178. return result;
  179. }
  180. template <typename T>
  181. void test_basic(std::string const& case_id,
  182. std::string const& wkt1,
  183. std::string const& wkt2,
  184. std::string const& wkt_turn_point,
  185. std::string const& wkt_origin_point,
  186. std::size_t expected_open_count,
  187. std::size_t expected_max_rank,
  188. std::vector<bg::signed_size_type> const& expected_right_count)
  189. {
  190. typedef bg::model::point<T, 2, bg::cs::cartesian> point_type;
  191. typedef bg::model::polygon<point_type> polygon;
  192. typedef bg::model::multi_polygon<polygon> multi_polygon;
  193. multi_polygon g1;
  194. bg::read_wkt(wkt1, g1);
  195. multi_polygon g2;
  196. bg::read_wkt(wkt2, g2);
  197. point_type turn_point, origin_point;
  198. bg::read_wkt(wkt_turn_point, turn_point);
  199. bg::read_wkt(wkt_origin_point, origin_point);
  200. // Reverse if necessary
  201. bg::correct(g1);
  202. bg::correct(g2);
  203. typedef typename bg::rescale_overlay_policy_type
  204. <
  205. multi_polygon,
  206. multi_polygon
  207. >::type rescale_policy_type;
  208. rescale_policy_type robust_policy
  209. = bg::get_rescale_policy<rescale_policy_type>(g1, g2);
  210. typedef typename bg::strategy::intersection::services::default_strategy
  211. <
  212. typename bg::cs_tag<point_type>::type
  213. >::type strategy_type;
  214. strategy_type strategy;
  215. apply_get_turns(case_id, g1, g2, turn_point, origin_point,
  216. robust_policy, strategy,
  217. expected_open_count, expected_max_rank, expected_right_count);
  218. }
  219. using boost::assign::list_of;
  220. template <typename T>
  221. void test_all()
  222. {
  223. test_basic<T>("simplex",
  224. "MULTIPOLYGON(((0 2,1 2,1 1,0 1,0 2)))",
  225. "MULTIPOLYGON(((1 0,1 1,2 1,2 0,1, 0)))",
  226. "POINT(1 1)", "POINT(1 0)",
  227. 2, 3, list_of(-1)(1)(-1)(1));
  228. test_basic<T>("dup1",
  229. "MULTIPOLYGON(((0 2,1 2,1 1,0 1,0 2)))",
  230. "MULTIPOLYGON(((1 0,1 1,2 1,2 0,1, 0)),((0 2,1 2,1 1,0 1,0 2)))",
  231. "POINT(1 1)", "POINT(1 0)",
  232. 2, 3, list_of(-1)(1)(-1)(2));
  233. test_basic<T>("dup2",
  234. "MULTIPOLYGON(((0 2,1 2,1 1,0 1,0 2)),((1 0,1 1,2 1,2 0,1, 0)))",
  235. "MULTIPOLYGON(((1 0,1 1,2 1,2 0,1, 0)))",
  236. "POINT(1 1)", "POINT(1 0)",
  237. 2, 3, list_of(-1)(2)(-1)(1));
  238. test_basic<T>("dup3",
  239. "MULTIPOLYGON(((0 2,1 2,1 1,0 1,0 2)),((1 0,1 1,2 1,2 0,1, 0)))",
  240. "MULTIPOLYGON(((1 0,1 1,2 1,2 0,1, 0)),((0 2,1 2,1 1,0 1,0 2)))",
  241. "POINT(1 1)", "POINT(1 0)",
  242. 2, 3, list_of(-1)(2)(-1)(2));
  243. test_basic<T>("threequart1",
  244. "MULTIPOLYGON(((0 2,1 2,1 1,0 1,0 2)),((1 0,1 1,2 1,2 0,1, 0)))",
  245. "MULTIPOLYGON(((1 2,2 2,2 1,1 1,1 2)))",
  246. "POINT(1 1)", "POINT(1 0)",
  247. 1, 3, list_of(-1)(1)(1)(1));
  248. test_basic<T>("threequart2",
  249. "MULTIPOLYGON(((0 2,1 2,1 1,0 1,0 2)),((1 0,1 1,2 1,2 0,1, 0)))",
  250. "MULTIPOLYGON(((1 2,2 2,2 1,1 1,1 2)),((2 0,1 0,1 1,2 0)))",
  251. "POINT(1 1)", "POINT(1 0)",
  252. 1, 4, list_of(-1)(2)(1)(1)(1));
  253. test_basic<T>("threequart3",
  254. "MULTIPOLYGON(((0 2,1 2,1 1,0 1,0 2)),((1 0,1 1,2 1,2 0,1, 0)))",
  255. "MULTIPOLYGON(((1 2,2 2,2 1,1 1,1 2)),((2 0,1 0,1 1,2 0)),((0 1,0 2,1 1,0 1)))",
  256. "POINT(1 1)", "POINT(1 0)",
  257. 1, 5, list_of(-1)(2)(1)(1)(-1)(2));
  258. test_basic<T>("full1",
  259. "MULTIPOLYGON(((0 2,1 2,1 1,0 1,0 2)),((1 0,1 1,2 1,2 0,1, 0)))",
  260. "MULTIPOLYGON(((1 2,2 2,2 1,1 1,1 2)),((0 0,0 1,1 1,1 0,0 0)))",
  261. "POINT(1 1)", "POINT(1 0)",
  262. 0, 3, list_of(1)(1)(1)(1));
  263. test_basic<T>("hole1",
  264. "MULTIPOLYGON(((0 0,0 3,2 3,2 2,3 2,3 0,0 0),(1 1,2 1,2 2,1 2,1 1)),((4 2,3 2,3 3,4 3,4 2)))",
  265. "MULTIPOLYGON(((1 0,1 1,2 1,2 2,1 2,1 4,4 4,4 0,1, 0),(3 2,3 3,2 3,2 2,3 2)))",
  266. "POINT(1 2)", "POINT(2 2)",
  267. 1, 2, list_of(-1)(2)(1));
  268. test_basic<T>("hole2",
  269. "MULTIPOLYGON(((0 0,0 3,2 3,2 2,3 2,3 0,0 0),(1 1,2 1,2 2,1 2,1 1)),((4 2,3 2,3 3,4 3,4 2)))",
  270. "MULTIPOLYGON(((1 0,1 1,2 1,2 2,1 2,1 4,4 4,4 0,1, 0),(3 2,3 3,2 3,2 2,3 2)))",
  271. "POINT(2 2)", "POINT(2 1)",
  272. 2, 3, list_of(-1)(2)(-1)(2));
  273. test_basic<T>("hole3",
  274. "MULTIPOLYGON(((0 0,0 3,2 3,2 2,3 2,3 0,0 0),(1 1,2 1,2 2,1 2,1 1)),((4 2,3 2,3 3,4 3,4 2)))",
  275. "MULTIPOLYGON(((1 0,1 1,2 1,2 2,1 2,1 4,4 4,4 0,1, 0),(3 2,3 3,2 3,2 2,3 2)))",
  276. "POINT(3 2)", "POINT(2 2)",
  277. 1, 3, list_of(-1)(2)(-1)(2));
  278. }
  279. int test_main(int, char* [])
  280. {
  281. test_all<double>();
  282. return 0;
  283. }