get_left_turns.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. //
  3. // Copyright (c) 2012-2014 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. #include <geometry_test_common.hpp>
  8. #include <boost/algorithm/string/trim.hpp>
  9. #include <boost/assign/list_of.hpp>
  10. #include <boost/geometry/geometries/point_xy.hpp>
  11. #include <boost/geometry/algorithms/detail/get_left_turns.hpp>
  12. #if defined(TEST_WITH_SVG)
  13. # include <boost/geometry/io/svg/svg_mapper.hpp>
  14. #endif
  15. NOTE: this unit test is out of date.
  16. get_left_turns is used by buffer and might be used in the future by solving self-tangencies in overlays.
  17. it is currently being changed by buffer.
  18. namespace bglt = boost::geometry::detail::left_turns;
  19. #if defined(TEST_WITH_SVG)
  20. template <typename Point>
  21. inline Point further_than(Point const& p, Point const& origin, int mul, int div)
  22. {
  23. typedef Point vector_type;
  24. vector_type v = p;
  25. bg::subtract_point(v, origin);
  26. bg::divide_value(v, div);
  27. bg::multiply_value(v, mul);
  28. Point result = origin;
  29. bg::add_point(result, v);
  30. return result;
  31. }
  32. inline std::string get_color(int index)
  33. {
  34. switch (index)
  35. {
  36. case 0 : return "rgb(0,192,0)";
  37. case 1 : return "rgb(0,0,255)";
  38. case 2 : return "rgb(255,0,0)";
  39. case 3 : return "rgb(255,255,0)";
  40. }
  41. return "rgb(128,128,128)";
  42. }
  43. #endif
  44. template <typename Point>
  45. void test_one(std::string const& caseid,
  46. Point const& p,
  47. std::vector<bglt::turn_angle_info<Point> > const& angles,
  48. std::string const& expected_sorted_indices,
  49. std::string const& expected_left_indices)
  50. {
  51. typedef Point vector_type;
  52. std::vector<bglt::angle_info<Point> > sorted;
  53. for (typename std::vector<bglt::turn_angle_info<Point> >::const_iterator it =
  54. angles.begin(); it != angles.end(); ++it)
  55. {
  56. for (int i = 0; i < 2; i++)
  57. {
  58. bglt::angle_info<Point> info(it->seg_id, i == 0, it->points[i]);
  59. sorted.push_back(info);
  60. }
  61. }
  62. // Sort on angle
  63. std::sort(sorted.begin(), sorted.end(), bglt::angle_less<Point>(p));
  64. // Block all turns on the right side of any turn
  65. bglt::block_turns_on_right_sides(angles, sorted);
  66. // Check the sorting
  67. {
  68. std::ostringstream out;
  69. out << std::boolalpha;
  70. for (typename std::vector<bglt::angle_info<Point> >::const_iterator it =
  71. sorted.begin(); it != sorted.end(); ++it)
  72. {
  73. out << " " << it->seg_id.segment_index
  74. << "-" << it->incoming;
  75. }
  76. std::string detected = boost::trim_copy(out.str());
  77. BOOST_CHECK_EQUAL(expected_sorted_indices, detected);
  78. }
  79. // Check outgoing lines
  80. std::vector<bglt::left_turn> seg_ids;
  81. bglt::get_left_turns(sorted, p, seg_ids);
  82. {
  83. std::ostringstream out;
  84. out << std::boolalpha;
  85. for (std::vector<bglt::left_turn>::const_iterator it =
  86. seg_ids.begin(); it != seg_ids.end(); ++it)
  87. {
  88. out
  89. << " " << it->from.segment_index
  90. << "->" << it->to.segment_index
  91. ;
  92. }
  93. std::string detected = boost::trim_copy(out.str());
  94. BOOST_CHECK_EQUAL(expected_left_indices, detected);
  95. }
  96. #if defined(TEST_WITH_SVG)
  97. {
  98. std::ostringstream filename;
  99. filename << "get_left_turns_" << caseid
  100. << "_" << string_from_type<typename bg::coordinate_type<Point>::type>::name()
  101. << ".svg";
  102. std::ofstream svg(filename.str().c_str());
  103. bg::svg_mapper<Point> mapper(svg, 500, 500);
  104. mapper.add(p);
  105. for (typename std::vector<bglt::turn_angle_info<Point> >::const_iterator it =
  106. angles.begin(); it != angles.end(); ++it)
  107. {
  108. // Add a point further then it->to_point, just for the mapping
  109. for (int i = 0; i < 2; i++)
  110. {
  111. mapper.add(further_than(it->points[i], p, 12, 10));
  112. }
  113. }
  114. int color_index = 0;
  115. typedef bg::model::referring_segment<Point const> segment_type;
  116. for (typename std::vector<bglt::turn_angle_info<Point> >::const_iterator it =
  117. angles.begin(); it != angles.end(); ++it, color_index++)
  118. {
  119. for (int i = 0; i < 2; i++)
  120. {
  121. std::string style = "opacity:0.5;stroke-width:1;stroke:rgb(0,0,0);fill:" + get_color(color_index);
  122. bool const incoming = i == 0;
  123. Point const& pf = incoming ? it->points[i] : p;
  124. Point const& pt = incoming ? p : it->points[i];
  125. vector_type v = pt;
  126. bg::subtract_point(v, pf);
  127. bg::divide_value(v, 10.0);
  128. // Generate perpendicular vector to right-side
  129. vector_type perpendicular;
  130. bg::set<0>(perpendicular, bg::get<1>(v));
  131. bg::set<1>(perpendicular, -bg::get<0>(v));
  132. bg::model::ring<Point> ring;
  133. ring.push_back(pf);
  134. ring.push_back(pt);
  135. // Extra point at 9/10
  136. {
  137. Point pe = pt;
  138. bg::add_point(pe, perpendicular);
  139. ring.push_back(pe);
  140. }
  141. {
  142. Point pe = pf;
  143. bg::add_point(pe, perpendicular);
  144. ring.push_back(pe);
  145. }
  146. ring.push_back(pf);
  147. mapper.map(ring, style);
  148. segment_type s(pf, pt);
  149. mapper.map(s, "opacity:0.9;stroke-width:4;stroke:rgb(0,0,0);");
  150. }
  151. }
  152. // Output angles for left-turns
  153. for (std::vector<bglt::left_turn>::const_iterator ltit =
  154. seg_ids.begin(); ltit != seg_ids.end(); ++ltit)
  155. {
  156. for (typename std::vector<bglt::angle_info<Point> >::const_iterator sit =
  157. sorted.begin(); sit != sorted.end(); ++sit, color_index++)
  158. {
  159. Point pf, pt;
  160. int factor = 0;
  161. if (sit->seg_id == ltit->from && sit->incoming)
  162. {
  163. pf = sit->point;
  164. pt = p;
  165. factor = -1; // left side
  166. }
  167. else if (sit->seg_id == ltit->to && ! sit->incoming)
  168. {
  169. pf = p;
  170. pt = sit->point;
  171. factor = -1; // left side
  172. }
  173. if (factor != 0)
  174. {
  175. vector_type v = pt;
  176. bg::subtract_point(v, pf);
  177. bg::divide_value(v, 10.0);
  178. // Generate perpendicular vector to right-side
  179. vector_type perpendicular;
  180. bg::set<0>(perpendicular, factor * bg::get<1>(v));
  181. bg::set<1>(perpendicular, -factor * bg::get<0>(v));
  182. bg::add_point(pf, v);
  183. bg::subtract_point(pt, v);
  184. bg::add_point(pf, perpendicular);
  185. bg::add_point(pt, perpendicular);
  186. segment_type s(pf, pt);
  187. mapper.map(s, "opacity:0.9;stroke-width:4;stroke:rgb(255,0,0);");
  188. }
  189. }
  190. }
  191. // Output texts with info about sorted/blocked
  192. int index = 0;
  193. for (typename std::vector<bglt::angle_info<Point> >::const_iterator it =
  194. sorted.begin(); it != sorted.end(); ++it, ++index)
  195. {
  196. std::ostringstream out;
  197. out << std::boolalpha;
  198. out << " seg:" << it->seg_id.segment_index
  199. << " " << (it->incoming ? "in" : "out")
  200. << " idx:" << index
  201. << (it->blocked ? " blocked" : "")
  202. ;
  203. mapper.text(further_than(it->point, p, 11, 10), out.str(), "fill:rgb(0,0,0);font-family='Verdana'");
  204. }
  205. mapper.map(p, "fill:rgb(255,0,0)");
  206. }
  207. #endif
  208. }
  209. template <typename P>
  210. void test_all()
  211. {
  212. using bglt::turn_angle_info;
  213. test_one<P>("cross",
  214. bg::make<P>(50, 50), // ip
  215. boost::assign::list_of
  216. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 1), bg::make<P>(100, 100), bg::make<P>(0, 0)))
  217. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 2), bg::make<P>(100, 0), bg::make<P>(0, 100)))
  218. , "1-true 2-true 1-false 2-false"
  219. , "2->1"
  220. );
  221. test_one<P>("occupied",
  222. bg::make<P>(50, 50), // ip
  223. boost::assign::list_of
  224. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 1), bg::make<P>(100, 100), bg::make<P>(0, 0)))
  225. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 2), bg::make<P>(100, 0), bg::make<P>(0, 100)))
  226. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 3), bg::make<P>(0, 30), bg::make<P>(100, 70)))
  227. , "1-true 3-false 2-true 1-false 3-true 2-false"
  228. , ""
  229. );
  230. test_one<P>("uu",
  231. bg::make<P>(50, 50), // ip
  232. boost::assign::list_of
  233. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 1), bg::make<P>(0, 0), bg::make<P>(100, 0)))
  234. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 2), bg::make<P>(100, 100), bg::make<P>(0, 100)))
  235. , "2-true 1-false 1-true 2-false"
  236. , "2->1 1->2"
  237. );
  238. test_one<P>("uu2",
  239. bg::make<P>(50, 50), // ip
  240. boost::assign::list_of
  241. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 1), bg::make<P>(0, 0), bg::make<P>(100, 0)))
  242. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 2), bg::make<P>(100, 100), bg::make<P>(0, 100)))
  243. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 3), bg::make<P>(0, 50), bg::make<P>(100, 50)))
  244. , "2-true 3-false 1-false 1-true 3-true 2-false"
  245. , "2->3 3->2"
  246. );
  247. test_one<P>("uu3",
  248. bg::make<P>(50, 50), // ip
  249. boost::assign::list_of
  250. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 1), bg::make<P>(0, 0), bg::make<P>(100, 0)))
  251. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 2), bg::make<P>(100, 100), bg::make<P>(0, 100)))
  252. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 3), bg::make<P>(50, 0), bg::make<P>(50, 100)))
  253. , "3-false 2-true 1-false 3-true 1-true 2-false"
  254. , "1->2"
  255. );
  256. test_one<P>("longer",
  257. bg::make<P>(50, 50), // ip
  258. boost::assign::list_of
  259. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 1), bg::make<P>(100, 100), bg::make<P>(0, 0)))
  260. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 2), bg::make<P>(100, 0), bg::make<P>(0, 100)))
  261. (turn_angle_info<P>(bg::segment_identifier(0, -1, -1, 3), bg::make<P>(90, 10), bg::make<P>(10, 10)))
  262. , "1-true 2-true 3-true 1-false 3-false 2-false"
  263. , "3->1"
  264. );
  265. }
  266. int test_main( int , char* [] )
  267. {
  268. test_all<bg::model::d2::point_xy<int> >();
  269. return 0;
  270. }