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