Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / geometry / test / strategies / segment_intersection_sph.hpp
1 // Boost.Geometry
2 // Unit Test
3
4 // Copyright (c) 2016-2018, Oracle and/or its affiliates.
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
29 #include <boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp>
30
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
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());
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];
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();
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));
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");
126     }
127     if (res_count > 1 && expected_count > 1)
128     {
129         P const& res_i1 = boost::get<0>(res).intersections[1];
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();
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));
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");
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