douglas_peucker.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Unit Test
  3. // Copyright (c) 2015, Oracle and/or its affiliates.
  4. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  5. // Licensed under the Boost Software License version 1.0.
  6. // http://www.boost.org/users/license.html
  7. #ifndef BOOST_TEST_MODULE
  8. #define BOOST_TEST_MODULE test_douglas_peucker
  9. #endif
  10. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  11. #ifndef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
  12. #define BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
  13. #endif
  14. #endif
  15. #include <iostream>
  16. #include <iterator>
  17. #include <sstream>
  18. #include <string>
  19. #include <boost/test/included/unit_test.hpp>
  20. #include <boost/geometry/core/point_type.hpp>
  21. #include <boost/geometry/core/tags.hpp>
  22. #include <boost/geometry/strategies/distance.hpp>
  23. #include <boost/geometry/strategies/strategies.hpp>
  24. #include <boost/geometry/geometries/geometries.hpp>
  25. #include <boost/geometry/geometries/adapted/boost_tuple.hpp>
  26. #include <boost/geometry/geometries/register/multi_point.hpp>
  27. #include <boost/geometry/algorithms/comparable_distance.hpp>
  28. #include <boost/geometry/algorithms/equals.hpp>
  29. #include <boost/geometry/io/wkt/wkt.hpp>
  30. #include <boost/geometry/io/dsv/write.hpp>
  31. #include <boost/assign/list_of.hpp>
  32. #include <boost/core/ignore_unused.hpp>
  33. #include <boost/type_traits/is_same.hpp>
  34. #include <boost/tuple/tuple.hpp>
  35. namespace bg = ::boost::geometry;
  36. namespace ba = ::boost::assign;
  37. namespace services = bg::strategy::distance::services;
  38. typedef boost::tuple<double, double> tuple_point_type;
  39. typedef std::vector<tuple_point_type> tuple_multi_point_type;
  40. BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)
  41. BOOST_GEOMETRY_REGISTER_MULTI_POINT(tuple_multi_point_type)
  42. BOOST_GEOMETRY_REGISTER_MULTI_POINT_TEMPLATED(std::vector)
  43. typedef bg::strategy::distance::projected_point<> distance_strategy_type;
  44. typedef bg::strategy::distance::projected_point
  45. <
  46. void, bg::strategy::distance::comparable::pythagoras<>
  47. > comparable_distance_strategy_type;
  48. template <typename CoordinateType>
  49. struct default_simplify_strategy
  50. {
  51. typedef bg::model::point<CoordinateType, 2, bg::cs::cartesian> point_type;
  52. typedef typename bg::strategy::distance::services::default_strategy
  53. <
  54. bg::point_tag, bg::segment_tag, point_type
  55. >::type default_distance_strategy_type;
  56. typedef bg::strategy::simplify::douglas_peucker
  57. <
  58. point_type, default_distance_strategy_type
  59. > type;
  60. };
  61. template <typename CoordinateType>
  62. struct simplify_regular_distance_strategy
  63. {
  64. typedef bg::model::point<CoordinateType, 2, bg::cs::cartesian> point_type;
  65. typedef bg::strategy::simplify::douglas_peucker
  66. <
  67. point_type, distance_strategy_type
  68. > type;
  69. };
  70. template <typename CoordinateType>
  71. struct simplify_comparable_distance_strategy
  72. {
  73. typedef bg::model::point<CoordinateType, 2, bg::cs::cartesian> point_type;
  74. typedef bg::strategy::simplify::douglas_peucker
  75. <
  76. point_type, comparable_distance_strategy_type
  77. > type;
  78. };
  79. template <typename Geometry>
  80. inline Geometry from_wkt(std::string const& wkt)
  81. {
  82. Geometry geometry;
  83. boost::geometry::read_wkt(wkt, geometry);
  84. return geometry;
  85. }
  86. template <typename Iterator>
  87. inline std::ostream& print_point_range(std::ostream& os,
  88. Iterator first,
  89. Iterator beyond,
  90. std::string const& header)
  91. {
  92. os << header << "(";
  93. for (Iterator it = first; it != beyond; ++it)
  94. {
  95. os << " " << bg::dsv(*it);
  96. }
  97. os << " )";
  98. return os;
  99. }
  100. struct equals
  101. {
  102. template <typename Iterator1, typename Iterator2>
  103. static inline bool apply(Iterator1 begin1, Iterator1 end1,
  104. Iterator2 begin2, Iterator2 end2)
  105. {
  106. std::size_t num_points1 = std::distance(begin1, end1);
  107. std::size_t num_points2 = std::distance(begin2, end2);
  108. if ( num_points1 != num_points2 )
  109. {
  110. return false;
  111. }
  112. Iterator1 it1 = begin1;
  113. Iterator2 it2 = begin2;
  114. for (; it1 != end1; ++it1, ++it2)
  115. {
  116. if ( !bg::equals(*it1, *it2) )
  117. {
  118. return false;
  119. }
  120. }
  121. return true;
  122. }
  123. template <typename Range1, typename Range2>
  124. static inline bool apply(Range1 const& range1, Range2 const& range2)
  125. {
  126. return apply(boost::begin(range1), boost::end(range1),
  127. boost::begin(range2), boost::end(range2));
  128. }
  129. };
  130. template <typename Geometry>
  131. struct test_one_case
  132. {
  133. template <typename Strategy, typename Range>
  134. static inline void apply(std::string const& case_id,
  135. std::string const& wkt,
  136. double max_distance,
  137. Strategy const& strategy,
  138. Range const& expected_result)
  139. {
  140. typedef typename bg::point_type<Geometry>::type point_type;
  141. std::vector<point_type> result;
  142. Geometry geometry = from_wkt<Geometry>(wkt);
  143. std::string typeid_name
  144. = typeid(typename bg::coordinate_type<point_type>::type).name();
  145. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  146. std::cout << case_id << " - " << typeid_name
  147. << std::endl;
  148. std::cout << wkt << std::endl;
  149. #endif
  150. strategy.apply(geometry, std::back_inserter(result), max_distance);
  151. boost::ignore_unused(strategy);
  152. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  153. print_point_range(std::cout, boost::begin(result), boost::end(result),
  154. "output: ");
  155. std::cout << std::endl << std::endl;
  156. #endif
  157. std::stringstream stream_expected;
  158. print_point_range(stream_expected, boost::begin(expected_result),
  159. boost::end(expected_result),
  160. "");
  161. std::stringstream stream_detected;
  162. print_point_range(stream_detected, boost::begin(result),
  163. boost::end(result),
  164. "");
  165. BOOST_CHECK_MESSAGE(equals::apply(result, expected_result),
  166. "case id: " << case_id << " - " << typeid_name
  167. << ", geometry: " << wkt
  168. << ", Expected: " << stream_expected.str()
  169. << " - Detected: " << stream_detected.str());
  170. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  171. std::cout << "---------------" << std::endl;
  172. std::cout << "---------------" << std::endl;
  173. std::cout << std::endl << std::endl;
  174. #endif
  175. }
  176. };
  177. template <typename CoordinateType, typename Strategy>
  178. inline void test_with_strategy(std::string label)
  179. {
  180. std::cout.precision(20);
  181. Strategy strategy;
  182. typedef bg::model::point<CoordinateType, 2, bg::cs::cartesian> point_type;
  183. typedef bg::model::linestring<point_type> linestring_type;
  184. typedef bg::model::segment<point_type> segment_type;
  185. typedef test_one_case<linestring_type> tester;
  186. label = " (" + label + ")";
  187. {
  188. point_type const p1(-6,-13), p2(0,-15);
  189. segment_type const s(point_type(12,-3), point_type(-12,5));
  190. if (bg::comparable_distance(p1, s) >= bg::comparable_distance(p2, s))
  191. {
  192. tester::apply("l01c1" + label,
  193. "LINESTRING(12 -3, 4 8,-6 -13,-9 4,0 -15,-12 5)",
  194. 10,
  195. strategy,
  196. ba::tuple_list_of(12,-3)(4,8)(-6,-13)(-12,5)
  197. );
  198. }
  199. else
  200. {
  201. tester::apply("l01c2" + label,
  202. "LINESTRING(12 -3, 4 8,-6 -13,-9 4,0 -15,-12 5)",
  203. 10,
  204. strategy,
  205. ba::tuple_list_of(12,-3)(4,8)(-6,-13)(-9,4)(0,-15)(-12,5)
  206. );
  207. }
  208. }
  209. tester::apply("l02" + label,
  210. "LINESTRING(-6 -13,-9 4,0 -15,-12 5)",
  211. 10,
  212. strategy,
  213. ba::tuple_list_of(-6,-13)(-12,5)
  214. );
  215. tester::apply("l03" + label,
  216. "LINESTRING(12 -3, 4 8,-6 -13,-9 4,0 -14,-12 5)",
  217. 10,
  218. strategy,
  219. ba::tuple_list_of(12,-3)(4,8)(-6,-13)(-12,5)
  220. );
  221. tester::apply("l04" + label,
  222. "LINESTRING(12 -3, 4 8,-6 -13,-9 4,0 -14,-12 5)",
  223. 14,
  224. strategy,
  225. ba::tuple_list_of(12,-3)(-6,-13)(-12,5)
  226. );
  227. {
  228. segment_type const s(point_type(0,-1), point_type(5,-4));
  229. point_type const p1(5,-1), p2(0,-4);
  230. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  231. bool d_larger_first = (bg::distance(p1, s) > bg::distance(p2, s));
  232. bool d_larger_second = (bg::distance(p1, s) < bg::distance(p2, s));
  233. bool cd_larger_first
  234. = (bg::comparable_distance(p1, s) > bg::comparable_distance(p2, s));
  235. bool cd_larger_second
  236. = (bg::comparable_distance(p1, s) < bg::comparable_distance(p2, s));
  237. std::cout << "segment: " << bg::dsv(s) << std::endl;
  238. std::cout << "distance from " << bg::dsv(p1) << ": "
  239. << bg::distance(p1, s) << std::endl;
  240. std::cout << "comp. distance from " << bg::dsv(p1) << ": "
  241. << bg::comparable_distance(p1, s) << std::endl;
  242. std::cout << "distance from " << bg::dsv(p2) << ": "
  243. << bg::distance(p2, s) << std::endl;
  244. std::cout << "comp. distance from " << bg::dsv(p2) << ": "
  245. << bg::comparable_distance(p2, s) << std::endl;
  246. std::cout << "larger distance from "
  247. << (d_larger_first ? "first" : (d_larger_second ? "second" : "equal"))
  248. << std::endl;
  249. std::cout << "larger comp. distance from "
  250. << (cd_larger_first ? "first" : (cd_larger_second ? "second" : "equal"))
  251. << std::endl;
  252. std::cout << "difference of distances: "
  253. << (bg::distance(p1, s) - bg::distance(p2, s))
  254. << std::endl;
  255. std::cout << "difference of comp. distances: "
  256. << (bg::comparable_distance(p1, s) - bg::comparable_distance(p2, s))
  257. << std::endl;
  258. #endif
  259. std::string wkt =
  260. "LINESTRING(0 0,5 0,0 -1,5 -1,0 -2,5 -2,0 -3,5 -3,0 -4,5 -4,0 0)";
  261. if (bg::comparable_distance(p1, s) >= bg::comparable_distance(p2, s))
  262. {
  263. tester::apply("l05c1" + label,
  264. wkt,
  265. 1,
  266. strategy,
  267. ba::tuple_list_of(0,0)(5,0)(0,-1)(5,-1)(0,-2)(5,-2)(0,-3)(5,-4)(0,0)
  268. );
  269. tester::apply("l05c1a" + label,
  270. wkt,
  271. 2,
  272. strategy,
  273. ba::tuple_list_of(0,0)(5,0)(0,-1)(5,-1)(0,-2)(5,-4)(0,0)
  274. );
  275. }
  276. else
  277. {
  278. tester::apply("l05c2" + label,
  279. wkt,
  280. 1,
  281. strategy,
  282. ba::tuple_list_of(0,0)(5,0)(0,-1)(5,-1)(0,-2)(5,-2)(0,-4)(5,-4)(0,0)
  283. );
  284. tester::apply("l05c2a" + label,
  285. wkt,
  286. 2,
  287. strategy,
  288. ba::tuple_list_of(0,0)(5,0)(0,-1)(5,-1)(0,-4)(5,-4)(0,0)
  289. );
  290. }
  291. }
  292. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  293. std::cout << std::endl;
  294. std::cout << std::endl;
  295. std::cout << "*************************************************";
  296. std::cout << std::endl;
  297. std::cout << std::endl;
  298. #endif
  299. }
  300. BOOST_AUTO_TEST_CASE( test_default_strategy )
  301. {
  302. test_with_strategy<int, default_simplify_strategy<int>::type>("i");
  303. test_with_strategy<float, default_simplify_strategy<float>::type>("f");
  304. test_with_strategy<double, default_simplify_strategy<double>::type>("d");
  305. test_with_strategy
  306. <
  307. long double,
  308. default_simplify_strategy<long double>::type
  309. >("ld");
  310. }
  311. BOOST_AUTO_TEST_CASE( test_with_regular_distance_strategy )
  312. {
  313. test_with_strategy
  314. <
  315. int,
  316. simplify_regular_distance_strategy<int>::type
  317. >("i");
  318. test_with_strategy
  319. <
  320. float,
  321. simplify_regular_distance_strategy<float>::type
  322. >("f");
  323. test_with_strategy
  324. <
  325. double,
  326. simplify_regular_distance_strategy<double>::type
  327. >("d");
  328. test_with_strategy
  329. <
  330. long double,
  331. simplify_regular_distance_strategy<long double>::type
  332. >("ld");
  333. }
  334. BOOST_AUTO_TEST_CASE( test_with_comparable_distance_strategy )
  335. {
  336. test_with_strategy
  337. <
  338. int,
  339. simplify_comparable_distance_strategy<int>::type
  340. >("i");
  341. test_with_strategy
  342. <
  343. float,
  344. simplify_comparable_distance_strategy<float>::type
  345. >("f");
  346. test_with_strategy
  347. <
  348. double,
  349. simplify_comparable_distance_strategy<double>::type
  350. >("d");
  351. test_with_strategy
  352. <
  353. long double,
  354. simplify_comparable_distance_strategy<long double>::type
  355. >("ld");
  356. }