line_interpolate.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. // Boost.Geometry
  2. // Unit Test
  3. // Copyright (c) 2018, Oracle and/or its affiliates.
  4. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  5. // Licensed under the Boost Software License version 1.0.
  6. // http://www.boost.org/users/license.html
  7. #include <geometry_test_common.hpp>
  8. #include <boost/geometry.hpp>
  9. #include <boost/geometry/geometries/geometries.hpp>
  10. #include <boost/geometry/algorithms/line_interpolate.hpp>
  11. #include <boost/geometry/algorithms/length.hpp>
  12. #include <boost/geometry/iterators/segment_iterator.hpp>
  13. #include <boost/geometry/strategies/strategies.hpp>
  14. #include <boost/geometry/io/wkt/wkt.hpp>
  15. template <typename P, typename Tag = typename bg::tag<P>::type>
  16. struct check_points: bg::not_implemented<Tag>
  17. {};
  18. template <typename P>
  19. struct check_points<P, bg::point_tag>
  20. {
  21. static void apply(P const& p0, P const& p1)
  22. {
  23. double p00 = bg::get<0>(p0);
  24. double p10 = bg::get<0>(p1);
  25. BOOST_CHECK_CLOSE(p00, p10, 0.001);
  26. double p01 = bg::get<1>(p0);
  27. double p11 = bg::get<1>(p1);
  28. BOOST_CHECK_CLOSE(p01, p11, 0.001);
  29. }
  30. };
  31. template <typename P>
  32. struct check_points<P, bg::multi_point_tag>
  33. {
  34. template <typename Range>
  35. static void apply(Range const& r0, Range const& r1)
  36. {
  37. typedef typename boost::range_iterator<Range const>::type iterator_t;
  38. typedef typename boost::range_value<Range const>::type point_t;
  39. std::size_t count0 = boost::size(r0);
  40. std::size_t count1 = boost::size(r1);
  41. BOOST_CHECK_MESSAGE(count0 == count1, bg::wkt(r0) << " != " << bg::wkt(r1));
  42. if (count0 == count1)
  43. {
  44. for (iterator_t it0 = boost::begin(r0), it1 = boost::begin(r1);
  45. it0 < boost::end(r0); it0++, it1++)
  46. {
  47. check_points<point_t>::apply(*it0, *it1);
  48. }
  49. }
  50. }
  51. };
  52. template <typename G, typename P, typename S>
  53. inline void test(std::string const& wkt1,
  54. double fraction,
  55. std::string const& wkt2,
  56. S str)
  57. {
  58. G g;
  59. bg::read_wkt(wkt1, g);
  60. P o;
  61. bg::read_wkt(wkt2, o);
  62. P p1;
  63. bg::line_interpolate(g, fraction * bg::length(g), p1, str);
  64. check_points<P>::apply(p1, o);
  65. }
  66. template <typename G, typename P>
  67. inline void test(std::string const& wkt1,
  68. double fraction,
  69. std::string const& wkt2)
  70. {
  71. G g;
  72. bg::read_wkt(wkt1, g);
  73. P o;
  74. bg::read_wkt(wkt2, o);
  75. P p1;
  76. bg::line_interpolate(g, fraction * bg::length(g), p1);
  77. check_points<P>::apply(p1, o);
  78. }
  79. template <typename G, typename P>
  80. inline void test_distance(std::string const& wkt1,
  81. double distance,
  82. std::string const& wkt2)
  83. {
  84. G g;
  85. bg::read_wkt(wkt1, g);
  86. P o;
  87. bg::read_wkt(wkt2, o);
  88. P p1;
  89. bg::line_interpolate(g, distance, p1);
  90. check_points<P>::apply(p1, o);
  91. }
  92. template <typename G, typename P, typename S>
  93. inline void test_distance(std::string const& wkt1,
  94. double distance,
  95. std::string const& wkt2,
  96. S str)
  97. {
  98. G g;
  99. bg::read_wkt(wkt1, g);
  100. P o;
  101. bg::read_wkt(wkt2, o);
  102. P p1;
  103. bg::line_interpolate(g, distance, p1, str);
  104. check_points<P>::apply(p1, o);
  105. }
  106. std::string const s = "SEGMENT(1 1, 2 2)";
  107. std::string const l1 = "LINESTRING(1 1, 2 1, 2 2, 1 2, 1 3)";
  108. std::string const l2 = "LINESTRING(0 2, 5 2, 5 1, 20 1)";
  109. std::string const l00 = "LINESTRING()";
  110. std::string const l01 = "LINESTRING(1 1)";
  111. std::string const l02 = "LINESTRING(1 1, 1 1)";
  112. void test_car_edge_cases()
  113. {
  114. typedef bg::model::point<double, 2, bg::cs::cartesian> P;
  115. typedef bg::model::multi_point<P> MP;
  116. typedef bg::model::linestring<P> LS;
  117. //negative input distance
  118. test_distance<LS,P>(l1, -1, "POINT(1 1)");
  119. test_distance<LS,MP>(l1, -1, "MULTIPOINT((1 1))");
  120. //input distance longer than total length
  121. test_distance<LS,P>(l1, 5, "POINT(1 3)");
  122. test_distance<LS,MP>(l1, 5, "MULTIPOINT((1 3))");
  123. //linestring with only one point
  124. test_distance<LS,P>(l01, 1, "POINT(1 1)");
  125. test_distance<LS,MP>(l01, 1, "MULTIPOINT((1 1))");
  126. //linestring with two same points
  127. test_distance<LS,P>(l02, 1, "POINT(1 1)");
  128. test_distance<LS,MP>(l02, 1, "MULTIPOINT((1 1))");
  129. //empty linestring
  130. try
  131. {
  132. test_distance<LS,P>(l00, 1, "POINT(1 1)");
  133. }
  134. catch(bg::empty_input_exception const& )
  135. {
  136. return;
  137. }
  138. BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" );
  139. }
  140. void test_car()
  141. {
  142. typedef bg::model::point<double, 2, bg::cs::cartesian> P;
  143. typedef bg::model::multi_point<P> MP;
  144. typedef bg::model::segment<P> S;
  145. typedef bg::model::linestring<P> LS;
  146. test<S,P>(s, 0, "POINT(1 1)");
  147. test<S,P>(s, 0.5, "POINT(1.5 1.5)");
  148. test<S,P>(s, 1, "POINT(2 2)");
  149. test<LS,P>(l1, 0, "POINT(1 1)");
  150. test<LS,P>(l1, 0.1, "POINT(1.4 1)");
  151. test<LS,P>(l1, 0.2, "POINT(1.8 1)");
  152. test<LS,P>(l1, 0.3, "POINT(2 1.2)");
  153. test<LS,P>(l1, 0.4, "POINT(2 1.6)");
  154. test<LS,P>(l1, 0.5, "POINT(2 2)");
  155. test<LS,P>(l1, 0.6, "POINT(1.6 2)");
  156. test<LS,P>(l1, 0.7, "POINT(1.2 2)");
  157. test<LS,P>(l1, 0.8, "POINT(1 2.2)");
  158. test<LS,P>(l1, 0.9, "POINT(1 2.6)");
  159. test<LS,P>(l1, 1, "POINT(1 3)");
  160. test<LS,MP>(l1, 0, "MULTIPOINT((1 1))");
  161. //(1 3) missing due to floating point round off errors
  162. test<LS,MP>(l1, 0.1, "MULTIPOINT((1.4 1)(1.8 1)(2 1.2)(2 1.6)(2 2)(1.6 2)\
  163. (1.2 2)(1 2.2)(1 2.6))");
  164. //(1 3) is not missing if you directly pass the distance
  165. test_distance<LS,MP>(l1, 0.4, "MULTIPOINT((1.4 1)(1.8 1)(2 1.2)(2 1.6)(2 2)(1.6 2)\
  166. (1.2 2)(1 2.2)(1 2.6)(1 3))");
  167. test<LS,MP>(l1, 0.2, "MULTIPOINT((1.8 1)(2 1.6)(1.6 2)(1 2.2))");//(1 3) missing
  168. test<LS,MP>(l1, 0.4, "MULTIPOINT((2 1.6)(1 2.2))");
  169. test<LS,MP>(l1, 0.5, "MULTIPOINT((2 2)(1 3))");
  170. test<LS,MP>(l1, 0.6, "MULTIPOINT((1.6 2))");
  171. test<LS,MP>(l1, 1, "MULTIPOINT((1 3))");
  172. }
  173. void test_sph()
  174. {
  175. typedef bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree> > P;
  176. typedef bg::model::multi_point<P> MP;
  177. typedef bg::model::segment<P> S;
  178. typedef bg::model::linestring<P> LS;
  179. test<S,P>(s, 0, "POINT(1 1)");
  180. test<S,P>(s, 0.5, "POINT(1.4998857365615981 1.5000570914791198)");
  181. test<S,P>(s, 1, "POINT(2 2)");
  182. test<LS,P>(l1, 0, "POINT(1 1)");
  183. test<LS,P>(l1, 0.1, "POINT(1.39998476912905323 1.0000365473536286)");
  184. test<LS,P>(l1, 0.2, "POINT(1.79996953825810646 1.0000243679448551)");
  185. test<LS,P>(l1, 0.3, "POINT(2 1.1999238595669637)");
  186. test<LS,P>(l1, 0.4, "POINT(2 1.5998477098527744)");
  187. test<LS,P>(l1, 0.5, "POINT(2 1.9997715601390484)");
  188. test<LS,P>(l1, 0.6, "POINT(1.6000609543036084 2.0000730473928678)");
  189. test<LS,P>(l1, 0.7, "POINT(1.1998933176222553 2.0000486811516014)");
  190. test<LS,P>(l1, 0.8, "POINT(1 2.2001522994279883)");
  191. test<LS,P>(l1, 0.9, "POINT(1 2.6000761497139444)");
  192. test<LS,P>(l1, 1, "POINT(1 3)");
  193. test<LS,MP>(l1, 0, "MULTIPOINT((1 1))");
  194. test<LS,MP>(l1, 0.1, "MULTIPOINT((1.39998476912905323 1.0000365473536286)\
  195. (1.79996953825810646 1.0000243679448551)\
  196. (2 1.1999238595669637)\
  197. (2 1.5998477098527744)\
  198. (2 1.9997715601385837)\
  199. (1.6000609543036084 2.0000730473928678)\
  200. (1.1998933176222553 2.0000486811516014)\
  201. (1 2.2001522994279883)\
  202. (1 2.6000761497139444)\
  203. )");//(1,3)
  204. test<LS,MP>(l1, 0.2, "MULTIPOINT((1.79996953825810646 1.0000243679448551)\
  205. (2 1.5998477098527744)\
  206. (1.6000609543036084 2.0000730473928678)\
  207. (1 2.2001522994279883)\
  208. )");//(1,3)
  209. test<LS,MP>(l1, 0.4, "MULTIPOINT((2 1.5998477098527744)(1 2.2001522994279883))");
  210. test<LS,MP>(l1, 0.5, "MULTIPOINT((2 1.9997715601385837)(1 3))");
  211. test<LS,MP>(l1, 0.6, "MULTIPOINT((1.6000609543036084 2.0000730473928678))");
  212. test<LS,MP>(l1, 1, "MULTIPOINT((1 3))");
  213. test<LS,MP>(l2, 0.3, "MULTIPOINT((5.3014893312120446 1.0006787676128222)\
  214. (11.600850053156366 1.0085030143490989)\
  215. (17.9002174825842 1.0041514208039872))");
  216. }
  217. template <typename Strategy>
  218. void test_sph(Strategy str)
  219. {
  220. typedef bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree> > P;
  221. typedef bg::model::segment<P> S;
  222. test_distance<S,P>(s, 0, "POINT(1 1)", str);
  223. test_distance<S,P>(s, 0.01, "POINT(1.4051065077123643 1.405268220524982)");
  224. test_distance<S,P>(s, 0.01, "POINT(1.0040505023484179 1.0040529633262307)", str);
  225. test_distance<S,P>(s, 1, "POINT(1.4051065077123015 1.405268220524919)", str);
  226. test_distance<S,P>(s, 1, "POINT(2 2)");
  227. test_distance<S,P>(s, 10, "POINT(2 2)");
  228. }
  229. template <typename Strategy>
  230. void test_geo(Strategy str)
  231. {
  232. typedef bg::model::point<double, 2, bg::cs::geographic<bg::degree> > P;
  233. typedef bg::model::multi_point<P> MP;
  234. typedef bg::model::segment<P> S;
  235. typedef bg::model::linestring<P> LS;
  236. test<S,P>(s, 0, "POINT(1 1)", str);
  237. test<S,P>(s, 0.5, "POINT(1.4998780900539985 1.5000558288006378)", str);
  238. test<S,P>(s, 1, "POINT(2 2)", str);
  239. test<LS,P>(l1, 0, "POINT(1 1)", str);
  240. test<LS,P>(l1, 0.1, "POINT(1.3986445638301882 1.0000367522730751)", str);
  241. test<LS,P>(l1, 0.2, "POINT(1.79728912766037641 1.0000247772611039)", str);
  242. test<LS,P>(l1, 0.3, "POINT(2 1.1972285554368427)", str);
  243. test<LS,P>(l1, 0.4, "POINT(2 1.598498298996567)", str);
  244. test<LS,P>(l1, 0.5, "POINT(2 1.9997664696834965)", str);
  245. test<LS,P>(l1, 0.6, "POINT(1.6013936980010324 2.0000734568388099)", str);
  246. test<LS,P>(l1, 0.7, "POINT(1.2025664628960846 2.0000494983098767)", str);
  247. test<LS,P>(l1, 0.8, "POINT(1 2.1974612279909937)", str);
  248. test<LS,P>(l1, 0.9, "POINT(1 2.5987263175375022)", str);
  249. test<LS,P>(l1, 1, "POINT(1 3)", str);
  250. test<LS,MP>(l1, 0, "MULTIPOINT((1 1))", str);
  251. //adnoyer is missing the last point in the following cases
  252. // of linestrings due to inaccuracy
  253. if (!boost::is_same<Strategy, bg::strategy::line_interpolate::geographic
  254. <bg::strategy::andoyer> >::value)
  255. {
  256. test<LS,MP>(l1, 0.1, "MULTIPOINT((1.3986445638301882 1.0000367522730751)\
  257. (1.79728912766037641 1.0000247772582571)\
  258. (2 1.1972285554368427)\
  259. (2 1.598498298996567)\
  260. (2 1.9997664696834965)\
  261. (1.6013936980010324 2.0000734568388099)\
  262. (1.2025664628960846 2.0000495003440779)\
  263. (1 2.1974612279909937)\
  264. (1 2.5987263175375022)\
  265. (1 3))", str);
  266. test<LS,MP>(l1, 0.2, "MULTIPOINT((1.79728912766037641 1.0000247772613331)\
  267. (2 1.598498298996567)\
  268. (1.6013936980010324 2.0000734568388099)\
  269. (1 2.1974612279909937)\
  270. (1 3))", str);
  271. }
  272. test<LS,MP>(l1, 0.4, "MULTIPOINT((2 1.598498298996567)(1 2.1974612279909937))", str);
  273. test<LS,MP>(l1, 0.5, "MULTIPOINT((2 1.9997664696834965)(1 3))", str);
  274. test<LS,MP>(l1, 0.6, "MULTIPOINT((1.6013936980010324 2.0000734568388099))", str);
  275. test<LS,MP>(l1, 1, "MULTIPOINT((1 3))", str);
  276. test<LS,MP>(l2, 0.3, "MULTIPOINT((5.306157814 1.0006937303)\
  277. (11.60351281 1.0085614548123072)\
  278. (17.90073492 1.004178475142552))", str);
  279. }
  280. template <typename Strategy>
  281. void test_geo_non_standard_spheroid(Strategy str)
  282. {
  283. typedef bg::model::point<double, 2, bg::cs::geographic<bg::degree> > P;
  284. typedef bg::model::segment<P> S;
  285. test<S,P>(s, 0, "POINT(1 1)", str);
  286. test<S,P>(s, 0.5, "POINT(1.5127731436886724 1.5129021873759412)", str);
  287. test<S,P>(s, 1, "POINT(2 2)", str);
  288. }
  289. int test_main(int, char* [])
  290. {
  291. test_car();
  292. test_car_edge_cases();
  293. test_sph();
  294. test_sph(bg::strategy::line_interpolate::spherical<>(100));
  295. typedef bg::srs::spheroid<double> stype;
  296. test_geo(bg::strategy::line_interpolate::geographic<bg::strategy::andoyer>());
  297. test_geo(bg::strategy::line_interpolate::geographic<bg::strategy::thomas>());
  298. test_geo(bg::strategy::line_interpolate::geographic<bg::strategy::vincenty>());
  299. test_geo_non_standard_spheroid(bg::strategy::line_interpolate::geographic
  300. <bg::strategy::vincenty>(stype(5000000,6000000)));
  301. return 0;
  302. }