densify.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Boost.Geometry
  2. // Unit Test
  3. // Copyright (c) 2017-2018, Oracle and/or its affiliates.
  4. // Contributed and/or modified by Adam Wulkiewicz, 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/geometries/geometries.hpp>
  9. #include <boost/geometry/algorithms/densify.hpp>
  10. #include <boost/geometry/algorithms/length.hpp>
  11. #include <boost/geometry/algorithms/num_points.hpp>
  12. #include <boost/geometry/algorithms/perimeter.hpp>
  13. #include <boost/geometry/iterators/segment_iterator.hpp>
  14. #include <boost/geometry/strategies/cartesian/densify.hpp>
  15. #include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
  16. #include <boost/geometry/strategies/geographic/densify.hpp>
  17. #include <boost/geometry/strategies/geographic/distance.hpp>
  18. #include <boost/geometry/strategies/spherical/densify.hpp>
  19. #include <boost/geometry/strategies/spherical/distance_haversine.hpp>
  20. #include <boost/geometry/io/wkt/wkt.hpp>
  21. struct check_lengths
  22. {
  23. template <typename G, typename S>
  24. void operator()(G const& g, G const& o, S const& s) const
  25. {
  26. double d1 = bg::length(g, s);
  27. double d2 = bg::length(o, s);
  28. BOOST_CHECK_CLOSE(d1, d2, 0.0001);
  29. }
  30. };
  31. struct check_perimeters
  32. {
  33. template <typename G, typename S>
  34. void operator()(G const& g, G const& o, S const& s) const
  35. {
  36. double d1 = bg::perimeter(g, s);
  37. double d2 = bg::perimeter(o, s);
  38. BOOST_CHECK_CLOSE(d1, d2, 0.0001);
  39. }
  40. };
  41. template <typename G, typename DistS>
  42. double inline shortest_length(G const& g, DistS const& dist_s)
  43. {
  44. double min_len = (std::numeric_limits<double>::max)();
  45. for (bg::segment_iterator<G const> it = bg::segments_begin(g);
  46. it != bg::segments_end(g); ++it)
  47. {
  48. double len = bg::length(*it, dist_s);
  49. min_len = (std::min)(min_len, len);
  50. }
  51. return min_len;
  52. }
  53. template <typename G, typename DistS>
  54. double inline greatest_length(G const& o, DistS const& dist_s)
  55. {
  56. double max_len = 0.0;
  57. for (bg::segment_iterator<G const> it = bg::segments_begin(o);
  58. it != bg::segments_end(o); ++it)
  59. {
  60. double len = bg::length(*it, dist_s);
  61. max_len = (std::max)(max_len, len);
  62. }
  63. return max_len;
  64. }
  65. template <typename G, typename CSTag = typename bg::cs_tag<G>::type>
  66. struct cs_data
  67. {};
  68. template <typename G>
  69. struct cs_data<G, bg::cartesian_tag>
  70. {
  71. bg::strategy::densify::cartesian<> compl_s;
  72. bg::strategy::distance::pythagoras<> dist_s;
  73. };
  74. template <typename G>
  75. struct cs_data<G, bg::spherical_equatorial_tag>
  76. {
  77. cs_data()
  78. : model(6378137.0)
  79. , compl_s(model)
  80. , dist_s(6378137.0)
  81. {}
  82. bg::srs::sphere<double> model;
  83. bg::strategy::densify::spherical<> compl_s;
  84. bg::strategy::distance::haversine<double> dist_s;
  85. };
  86. template <typename G>
  87. struct cs_data<G, bg::geographic_tag>
  88. {
  89. cs_data()
  90. : model(6378137.0, 6356752.3142451793)
  91. , compl_s(model)
  92. , dist_s(model)
  93. {}
  94. bg::srs::spheroid<double> model;
  95. bg::strategy::densify::geographic<> compl_s;
  96. bg::strategy::distance::geographic<> dist_s;
  97. };
  98. template <typename G, typename DistS, typename Check>
  99. inline void check_result(G const& g, G const& o, double max_distance,
  100. DistS const& dist_s, Check const& check)
  101. {
  102. // geometry was indeed densified
  103. std::size_t g_count = bg::num_points(g);
  104. std::size_t o_count = bg::num_points(o);
  105. BOOST_CHECK(g_count < o_count);
  106. // all segments have lengths smaller or equal to max_distance
  107. double gr_len = greatest_length(o, dist_s);
  108. // NOTE: Currently geographic strategies can generate segments that have
  109. // lengths slightly greater than max_distance. In order to change
  110. // this the generation of new points should e.g. be recursive with
  111. // stop condition comparing the current distance calculated by
  112. // inverse strategy.
  113. // NOTE: Closeness value tweaked for Andoyer
  114. bool is_close = (gr_len - max_distance) / (std::max)(gr_len, max_distance) < 0.0001;
  115. BOOST_CHECK(gr_len <= max_distance || is_close);
  116. // the overall length or perimeter didn't change
  117. check(g, o, dist_s);
  118. }
  119. template <typename G, typename Check>
  120. inline void test_geometry(std::string const& wkt, Check const& check)
  121. {
  122. cs_data<G> d;
  123. G g;
  124. bg::read_wkt(wkt, g);
  125. {
  126. bg::default_strategy def_s;
  127. double max_distance = shortest_length(g, def_s) / 3.0;
  128. G o;
  129. bg::densify(g, o, max_distance);
  130. check_result(g, o, max_distance, def_s, check);
  131. }
  132. {
  133. double max_distance = shortest_length(g, d.dist_s) / 3.0;
  134. G o;
  135. bg::densify(g, o, max_distance, d.compl_s);
  136. check_result(g, o, max_distance, d.dist_s, check);
  137. }
  138. }
  139. template <typename G>
  140. inline void test_linear(std::string const& wkt)
  141. {
  142. test_geometry<G>(wkt, check_lengths());
  143. }
  144. template <typename G>
  145. inline void test_areal(std::string const& wkt)
  146. {
  147. test_geometry<G>(wkt, check_perimeters());
  148. }
  149. template <typename P>
  150. void test_all()
  151. {
  152. typedef bg::model::linestring<P> ls_t;
  153. typedef bg::model::multi_linestring<ls_t> mls_t;
  154. typedef bg::model::ring<P> ring_t;
  155. typedef bg::model::polygon<P> poly_t;
  156. typedef bg::model::multi_polygon<poly_t> mpoly_t;
  157. typedef bg::model::ring<P, true, false> oring_t;
  158. typedef bg::model::polygon<P, true, false> opoly_t;
  159. typedef bg::model::multi_polygon<opoly_t> ompoly_t;
  160. test_linear<ls_t>("LINESTRING(4 -4, 4 -1)");
  161. test_linear<ls_t>("LINESTRING(4 4, 4 1)");
  162. test_linear<ls_t>("LINESTRING(0 0, 180 0)");
  163. test_linear<ls_t>("LINESTRING(1 1, -179 -1)");
  164. test_linear<ls_t>("LINESTRING(1 1, 2 2, 4 2)");
  165. test_linear<mls_t>("MULTILINESTRING((1 1, 2 2),(2 2, 4 2))");
  166. test_areal<ring_t>("POLYGON((1 1, 1 2, 2 2, 1 1))");
  167. test_areal<poly_t>("POLYGON((1 1, 1 4, 4 4, 4 1, 1 1),(1 1, 2 2, 2 3, 1 1))");
  168. test_areal<mpoly_t>("MULTIPOLYGON(((1 1, 1 4, 4 4, 4 1, 1 1),(1 1, 2 2, 2 3, 1 1)),((4 4, 5 5, 5 4, 4 4)))");
  169. test_areal<oring_t>("POLYGON((1 1, 1 2, 2 2))");
  170. test_areal<opoly_t>("POLYGON((1 1, 1 4, 4 4, 4 1),(1 1, 2 2, 2 3))");
  171. test_areal<ompoly_t>("MULTIPOLYGON(((1 1, 1 4, 4 4, 4 1),(1 1, 2 2, 2 3)),((4 4, 5 5, 5 4)))");
  172. test_areal<ring_t>("POLYGON((0 0,0 40,40 40,40 0,0 0))");
  173. test_areal<oring_t>("POLYGON((0 0,0 40,40 40,40 0))");
  174. }
  175. int test_main(int, char* [])
  176. {
  177. test_all< bg::model::point<double, 2, bg::cs::cartesian> >();
  178. test_all< bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree> > >();
  179. test_all< bg::model::point<double, 2, bg::cs::geographic<bg::degree> > >();
  180. return 0;
  181. }