segment_intersection_sph.hpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Boost.Geometry
  2. // Unit Test
  3. // Copyright (c) 2016-2018, Oracle and/or its affiliates.
  4. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  5. // Use, modification and distribution is subject to the Boost Software License,
  6. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. #ifndef BOOST_GEOMETRY_TEST_STRATEGIES_SEGMENT_INTERSECTION_SPH_HPP
  9. #define BOOST_GEOMETRY_TEST_STRATEGIES_SEGMENT_INTERSECTION_SPH_HPP
  10. #include <geometry_test_common.hpp>
  11. #include <boost/geometry/algorithms/equals.hpp>
  12. #include <boost/geometry/geometries/point.hpp>
  13. #include <boost/geometry/geometries/segment.hpp>
  14. #include <boost/geometry/io/wkt/read.hpp>
  15. #include <boost/geometry/io/wkt/write.hpp>
  16. #include <boost/geometry/policies/relate/direction.hpp>
  17. #include <boost/geometry/policies/relate/intersection_points.hpp>
  18. #include <boost/geometry/policies/relate/tupled.hpp>
  19. #include <boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp>
  20. template <typename T>
  21. bool equals_relaxed_val(T const& v1, T const& v2, T const& eps_scale)
  22. {
  23. T const c1 = 1;
  24. T relaxed_eps = std::numeric_limits<T>::epsilon()
  25. * bg::math::detail::greatest(c1, bg::math::abs(v1), bg::math::abs(v2))
  26. * eps_scale;
  27. return bg::math::abs(v1 - v2) <= relaxed_eps;
  28. }
  29. template <typename P1, typename P2, typename T>
  30. bool equals_relaxed(P1 const& p1, P2 const& p2, T const& eps_scale)
  31. {
  32. typedef typename bg::select_coordinate_type<P1, P2>::type calc_t;
  33. calc_t c1 = 1;
  34. calc_t p10 = bg::get<0>(p1);
  35. calc_t p11 = bg::get<1>(p1);
  36. calc_t p20 = bg::get<0>(p2);
  37. calc_t p21 = bg::get<1>(p2);
  38. calc_t relaxed_eps = std::numeric_limits<calc_t>::epsilon()
  39. * bg::math::detail::greatest(c1, bg::math::abs(p10), bg::math::abs(p11), bg::math::abs(p20), bg::math::abs(p21))
  40. * eps_scale;
  41. calc_t diff0 = p10 - p20;
  42. // needed e.g. for -179.999999 - 180.0
  43. if (diff0 < -180)
  44. diff0 += 360;
  45. return bg::math::abs(diff0) <= relaxed_eps
  46. && bg::math::abs(p11 - p21) <= relaxed_eps;
  47. }
  48. template <typename S1, typename S2, typename Strategy, typename P>
  49. void test_strategy_one(S1 const& s1, S2 const& s2,
  50. Strategy const& strategy,
  51. char m, std::size_t expected_count,
  52. P const& ip0 = P(), P const& ip1 = P(),
  53. int opposite_id = -1)
  54. {
  55. typedef typename bg::coordinate_type<P>::type coord_t;
  56. typedef bg::policies::relate::segments_tupled
  57. <
  58. bg::policies::relate::segments_intersection_points
  59. <
  60. bg::segment_intersection_points<P, bg::segment_ratio<coord_t> >
  61. >,
  62. bg::policies::relate::segments_direction
  63. > policy_t;
  64. typedef typename policy_t::return_type return_type;
  65. bg::detail::segment_as_subrange<S1> sr1(s1);
  66. bg::detail::segment_as_subrange<S2> sr2(s2);
  67. return_type res = strategy.apply(sr1, sr2, policy_t());
  68. size_t const res_count = boost::get<0>(res).count;
  69. char const res_method = boost::get<1>(res).how;
  70. BOOST_CHECK_MESSAGE(res_method == m,
  71. "IP method: " << res_method << " different than expected: " << m
  72. << " for " << bg::wkt(s1) << " and " << bg::wkt(s2));
  73. BOOST_CHECK_MESSAGE(res_count == expected_count,
  74. "IP count: " << res_count << " different than expected: " << expected_count
  75. << " for " << bg::wkt(s1) << " and " << bg::wkt(s2));
  76. // The EPS is scaled because during the conversion various angles may be not converted
  77. // to cartesian 3d the same way which results in a different intersection point
  78. // For more information read the info in spherical intersection strategy file.
  79. // Plus in geographic CS the result strongly depends on the compiler,
  80. // probably due to differences in FP trigonometric function implementations
  81. int eps_scale = 1;
  82. bool is_geographic = boost::is_same<typename bg::cs_tag<S1>::type, bg::geographic_tag>::value;
  83. if (is_geographic)
  84. {
  85. eps_scale = 100000;
  86. }
  87. else
  88. {
  89. eps_scale = res_method != 'i' ? 1 : 1000;
  90. }
  91. if (res_count > 0 && expected_count > 0)
  92. {
  93. P const& res_i0 = boost::get<0>(res).intersections[0];
  94. coord_t denom_a0 = boost::get<0>(res).fractions[0].robust_ra.denominator();
  95. coord_t denom_b0 = boost::get<0>(res).fractions[0].robust_rb.denominator();
  96. BOOST_CHECK_MESSAGE(equals_relaxed(res_i0, ip0, eps_scale),
  97. "IP0: " << std::setprecision(16) << bg::wkt(res_i0) << " different than expected: " << bg::wkt(ip0)
  98. << " for " << bg::wkt(s1) << " and " << bg::wkt(s2));
  99. BOOST_CHECK_MESSAGE(denom_a0 > coord_t(0),
  100. "IP0 fraction A denominator: " << std::setprecision(16) << denom_a0 << " is incorrect");
  101. BOOST_CHECK_MESSAGE(denom_b0 > coord_t(0),
  102. "IP0 fraction B denominator: " << std::setprecision(16) << denom_b0 << " is incorrect");
  103. }
  104. if (res_count > 1 && expected_count > 1)
  105. {
  106. P const& res_i1 = boost::get<0>(res).intersections[1];
  107. coord_t denom_a1 = boost::get<0>(res).fractions[1].robust_ra.denominator();
  108. coord_t denom_b1 = boost::get<0>(res).fractions[1].robust_rb.denominator();
  109. BOOST_CHECK_MESSAGE(equals_relaxed(res_i1, ip1, eps_scale),
  110. "IP1: " << std::setprecision(16) << bg::wkt(res_i1) << " different than expected: " << bg::wkt(ip1)
  111. << " for " << bg::wkt(s1) << " and " << bg::wkt(s2));
  112. BOOST_CHECK_MESSAGE(denom_a1 > coord_t(0),
  113. "IP1 fraction A denominator: " << std::setprecision(16) << denom_a1 << " is incorrect");
  114. BOOST_CHECK_MESSAGE(denom_b1 > coord_t(0),
  115. "IP1 fraction B denominator: " << std::setprecision(16) << denom_b1 << " is incorrect");
  116. }
  117. if (opposite_id >= 0)
  118. {
  119. bool opposite = opposite_id != 0;
  120. BOOST_CHECK_MESSAGE(opposite == boost::get<1>(res).opposite,
  121. bg::wkt(s1) << " and " << bg::wkt(s2) << (opposite_id == 0 ? " are not " : " are ") << "opposite" );
  122. }
  123. }
  124. template <typename T>
  125. T translated(T v, double t)
  126. {
  127. v += T(t);
  128. if (v > 180)
  129. v -= 360;
  130. return v;
  131. }
  132. template <typename S1, typename S2, typename Strategy, typename P>
  133. void test_strategy(S1 const& s1, S2 const& s2,
  134. Strategy const& strategy,
  135. char m, std::size_t expected_count,
  136. P const& ip0 = P(), P const& ip1 = P(),
  137. int opposite_id = -1)
  138. {
  139. S1 s1t = s1;
  140. S2 s2t = s2;
  141. P ip0t = ip0;
  142. P ip1t = ip1;
  143. #ifndef BOOST_GEOMETRY_TEST_GEO_INTERSECTION_TEST_SIMILAR
  144. test_strategy_one(s1t, s2t, strategy, m, expected_count, ip0t, ip1t, opposite_id);
  145. #else
  146. double t = 0;
  147. for (int i = 0; i < 4; ++i, t += 90)
  148. {
  149. bg::set<0, 0>(s1t, translated(bg::get<0, 0>(s1), t));
  150. bg::set<1, 0>(s1t, translated(bg::get<1, 0>(s1), t));
  151. bg::set<0, 0>(s2t, translated(bg::get<0, 0>(s2), t));
  152. bg::set<1, 0>(s2t, translated(bg::get<1, 0>(s2), t));
  153. if (expected_count > 0)
  154. bg::set<0>(ip0t, translated(bg::get<0>(ip0), t));
  155. if (expected_count > 1)
  156. bg::set<0>(ip1t, translated(bg::get<0>(ip1), t));
  157. test_strategy_one(s1t, s2t, strategy, m, expected_count, ip0t, ip1t, opposite_id);
  158. }
  159. #endif
  160. }
  161. template <typename S1, typename S2, typename P, typename Strategy>
  162. void test_strategy(std::string const& s1_wkt, std::string const& s2_wkt,
  163. Strategy const& strategy,
  164. char m, std::size_t expected_count,
  165. std::string const& ip0_wkt = "", std::string const& ip1_wkt = "",
  166. int opposite_id = -1)
  167. {
  168. S1 s1;
  169. S2 s2;
  170. P ip0, ip1;
  171. bg::read_wkt(s1_wkt, s1);
  172. bg::read_wkt(s2_wkt, s2);
  173. if (! ip0_wkt.empty())
  174. bg::read_wkt(ip0_wkt, ip0);
  175. if (!ip1_wkt.empty())
  176. bg::read_wkt(ip1_wkt, ip1);
  177. test_strategy(s1, s2, strategy, m, expected_count, ip0, ip1, opposite_id);
  178. }
  179. template <typename S, typename P, typename Strategy>
  180. void test_strategy(std::string const& s1_wkt, std::string const& s2_wkt,
  181. Strategy const& strategy,
  182. char m, std::size_t expected_count,
  183. std::string const& ip0_wkt = "", std::string const& ip1_wkt = "",
  184. int opposite_id = -1)
  185. {
  186. test_strategy<S, S, P>(s1_wkt, s2_wkt, strategy, m, expected_count, ip0_wkt, ip1_wkt, opposite_id);
  187. }
  188. #endif // BOOST_GEOMETRY_TEST_STRATEGIES_SEGMENT_INTERSECTION_SPH_HPP