]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | // Unit Test | |
3 | ||
4 | // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. | |
5 | // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. | |
6 | // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. | |
7 | ||
8 | // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library | |
9 | // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. | |
10 | ||
11 | // Use, modification and distribution is subject to the Boost Software License, | |
12 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
13 | // http://www.boost.org/LICENSE_1_0.txt) | |
14 | ||
15 | ||
16 | #include <geometry_test_common.hpp> | |
17 | ||
18 | #if defined(_MSC_VER) | |
19 | # pragma warning( disable : 4101 ) | |
20 | #endif | |
21 | ||
22 | #include <boost/timer.hpp> | |
23 | ||
24 | #include <boost/concept/requires.hpp> | |
25 | #include <boost/concept_check.hpp> | |
26 | #include <boost/core/ignore_unused.hpp> | |
27 | ||
28 | #include <boost/geometry/algorithms/assign.hpp> | |
29 | #include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp> | |
30 | #include <boost/geometry/strategies/concepts/distance_concept.hpp> | |
31 | ||
32 | ||
33 | #include <boost/geometry/geometries/point.hpp> | |
34 | #include <boost/geometry/geometries/adapted/c_array.hpp> | |
35 | #include <boost/geometry/geometries/adapted/boost_tuple.hpp> | |
36 | ||
37 | #include <test_common/test_point.hpp> | |
38 | ||
39 | #ifdef HAVE_TTMATH | |
40 | # include <boost/geometry/extensions/contrib/ttmath_stub.hpp> | |
41 | #endif | |
42 | ||
43 | BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(cs::cartesian) | |
44 | BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian) | |
45 | ||
46 | ||
47 | template <typename P1, typename P2> | |
48 | void test_null_distance_3d() | |
49 | { | |
50 | P1 p1; | |
51 | bg::assign_values(p1, 1, 2, 3); | |
52 | P2 p2; | |
53 | bg::assign_values(p2, 1, 2, 3); | |
54 | ||
55 | typedef bg::strategy::distance::pythagoras<> pythagoras_type; | |
56 | typedef typename bg::strategy::distance::services::return_type<pythagoras_type, P1, P2>::type return_type; | |
57 | ||
58 | pythagoras_type pythagoras; | |
59 | return_type result = pythagoras.apply(p1, p2); | |
60 | ||
61 | BOOST_CHECK_EQUAL(result, return_type(0)); | |
62 | } | |
63 | ||
64 | template <typename P1, typename P2> | |
65 | void test_axis_3d() | |
66 | { | |
67 | P1 p1; | |
68 | bg::assign_values(p1, 0, 0, 0); | |
69 | P2 p2; | |
70 | bg::assign_values(p2, 1, 0, 0); | |
71 | ||
72 | typedef bg::strategy::distance::pythagoras<> pythagoras_type; | |
73 | typedef typename bg::strategy::distance::services::return_type<pythagoras_type, P1, P2>::type return_type; | |
74 | ||
75 | pythagoras_type pythagoras; | |
76 | ||
77 | return_type result = pythagoras.apply(p1, p2); | |
78 | BOOST_CHECK_EQUAL(result, return_type(1)); | |
79 | ||
80 | bg::assign_values(p2, 0, 1, 0); | |
81 | result = pythagoras.apply(p1, p2); | |
82 | BOOST_CHECK_EQUAL(result, return_type(1)); | |
83 | ||
84 | bg::assign_values(p2, 0, 0, 1); | |
85 | result = pythagoras.apply(p1, p2); | |
86 | BOOST_CHECK_CLOSE(result, return_type(1), 0.001); | |
87 | } | |
88 | ||
89 | template <typename P1, typename P2> | |
90 | void test_arbitrary_3d() | |
91 | { | |
92 | P1 p1; | |
93 | bg::assign_values(p1, 1, 2, 3); | |
94 | P2 p2; | |
95 | bg::assign_values(p2, 9, 8, 7); | |
96 | ||
97 | { | |
98 | typedef bg::strategy::distance::pythagoras<> strategy_type; | |
99 | typedef typename bg::strategy::distance::services::return_type<strategy_type, P1, P2>::type return_type; | |
100 | ||
101 | strategy_type strategy; | |
102 | return_type result = strategy.apply(p1, p2); | |
103 | BOOST_CHECK_CLOSE(result, return_type(10.77032961427), 0.001); | |
104 | } | |
105 | ||
106 | { | |
107 | // Check comparable distance | |
108 | typedef bg::strategy::distance::comparable::pythagoras<> strategy_type; | |
109 | typedef typename bg::strategy::distance::services::return_type<strategy_type, P1, P2>::type return_type; | |
110 | ||
111 | strategy_type strategy; | |
112 | return_type result = strategy.apply(p1, p2); | |
113 | BOOST_CHECK_EQUAL(result, return_type(116)); | |
114 | } | |
115 | } | |
116 | ||
117 | template <typename P1, typename P2, typename CalculationType> | |
118 | void test_services() | |
119 | { | |
120 | namespace bgsd = bg::strategy::distance; | |
121 | namespace services = bg::strategy::distance::services; | |
122 | ||
123 | { | |
124 | ||
125 | // Compile-check if there is a strategy for this type | |
126 | typedef typename services::default_strategy | |
127 | < | |
128 | bg::point_tag, bg::point_tag, P1, P2 | |
129 | >::type pythagoras_strategy_type; | |
130 | ||
131 | boost::ignore_unused<pythagoras_strategy_type>(); | |
132 | } | |
133 | ||
134 | ||
135 | P1 p1; | |
136 | bg::assign_values(p1, 1, 2, 3); | |
137 | ||
138 | P2 p2; | |
139 | bg::assign_values(p2, 4, 5, 6); | |
140 | ||
141 | double const sqr_expected = 3*3 + 3*3 + 3*3; // 27 | |
142 | double const expected = sqrt(sqr_expected); // sqrt(27)=5.1961524227 | |
143 | ||
144 | // 1: normal, calculate distance: | |
145 | ||
146 | typedef bgsd::pythagoras<CalculationType> strategy_type; | |
147 | ||
148 | BOOST_CONCEPT_ASSERT( (bg::concepts::PointDistanceStrategy<strategy_type, P1, P2>) ); | |
149 | ||
150 | typedef typename bgsd::services::return_type<strategy_type, P1, P2>::type return_type; | |
151 | ||
152 | strategy_type strategy; | |
153 | return_type result = strategy.apply(p1, p2); | |
154 | BOOST_CHECK_CLOSE(result, return_type(expected), 0.001); | |
155 | ||
156 | // 2: the strategy should return the same result if we reverse parameters | |
157 | result = strategy.apply(p2, p1); | |
158 | BOOST_CHECK_CLOSE(result, return_type(expected), 0.001); | |
159 | ||
160 | ||
161 | // 3: "comparable" to construct a "comparable strategy" for P1/P2 | |
162 | // a "comparable strategy" is a strategy which does not calculate the exact distance, but | |
163 | // which returns results which can be mutually compared (e.g. avoid sqrt) | |
164 | ||
165 | // 3a: "comparable_type" | |
166 | typedef typename services::comparable_type<strategy_type>::type comparable_type; | |
167 | ||
168 | // 3b: "get_comparable" | |
169 | comparable_type comparable = bgsd::services::get_comparable<strategy_type>::apply(strategy); | |
170 | ||
171 | return_type c_result = comparable.apply(p1, p2); | |
172 | BOOST_CHECK_CLOSE(c_result, return_type(sqr_expected), 0.001); | |
173 | ||
174 | // 4: the comparable_type should have a distance_strategy_constructor as well, | |
175 | // knowing how to compare something with a fixed distance | |
176 | return_type c_dist5 = services::result_from_distance<comparable_type, P1, P2>::apply(comparable, 5.0); | |
177 | return_type c_dist6 = services::result_from_distance<comparable_type, P1, P2>::apply(comparable, 6.0); | |
178 | ||
179 | // If this is the case: | |
180 | BOOST_CHECK(c_dist5 < c_result && c_result < c_dist6); | |
181 | ||
182 | // This should also be the case | |
183 | return_type dist5 = services::result_from_distance<strategy_type, P1, P2>::apply(strategy, 5.0); | |
184 | return_type dist6 = services::result_from_distance<strategy_type, P1, P2>::apply(strategy, 6.0); | |
185 | BOOST_CHECK(dist5 < result && result < dist6); | |
186 | } | |
187 | ||
188 | ||
189 | template <typename CoordinateType, typename CalculationType, typename AssignType> | |
190 | void test_big_2d_with(AssignType const& x1, AssignType const& y1, | |
191 | AssignType const& x2, AssignType const& y2) | |
192 | { | |
193 | typedef bg::model::point<CoordinateType, 2, bg::cs::cartesian> point_type; | |
194 | typedef bg::strategy::distance::pythagoras<CalculationType> pythagoras_type; | |
195 | ||
196 | pythagoras_type pythagoras; | |
197 | typedef typename bg::strategy::distance::services::return_type<pythagoras_type, point_type, point_type>::type return_type; | |
198 | ||
199 | ||
200 | point_type p1, p2; | |
201 | bg::assign_values(p1, x1, y1); | |
202 | bg::assign_values(p2, x2, y2); | |
203 | return_type d = pythagoras.apply(p1, p2); | |
204 | ||
205 | /*** | |
206 | std::cout << typeid(CalculationType).name() | |
207 | << " " << std::fixed << std::setprecision(20) << d | |
208 | << std::endl << std::endl; | |
209 | ***/ | |
210 | ||
211 | ||
212 | BOOST_CHECK_CLOSE(d, return_type(1076554.5485833955678294387789057), 0.001); | |
213 | } | |
214 | ||
215 | template <typename CoordinateType, typename CalculationType> | |
216 | void test_big_2d() | |
217 | { | |
218 | test_big_2d_with<CoordinateType, CalculationType> | |
219 | (123456.78900001, 234567.89100001, | |
220 | 987654.32100001, 876543.21900001); | |
221 | } | |
222 | ||
223 | template <typename CoordinateType, typename CalculationType> | |
224 | void test_big_2d_string() | |
225 | { | |
226 | test_big_2d_with<CoordinateType, CalculationType> | |
227 | ("123456.78900001", "234567.89100001", | |
228 | "987654.32100001", "876543.21900001"); | |
229 | } | |
230 | ||
231 | template <typename CoordinateType> | |
232 | void test_integer(bool check_types) | |
233 | { | |
234 | typedef bg::model::point<CoordinateType, 2, bg::cs::cartesian> point_type; | |
235 | ||
236 | point_type p1, p2; | |
237 | bg::assign_values(p1, 12345678, 23456789); | |
238 | bg::assign_values(p2, 98765432, 87654321); | |
239 | ||
240 | typedef bg::strategy::distance::pythagoras<> pythagoras_type; | |
241 | typedef typename bg::strategy::distance::services::comparable_type | |
242 | < | |
243 | pythagoras_type | |
244 | >::type comparable_type; | |
245 | ||
246 | typedef typename bg::strategy::distance::services::return_type | |
247 | < | |
248 | pythagoras_type, point_type, point_type | |
249 | >::type distance_type; | |
250 | typedef typename bg::strategy::distance::services::return_type | |
251 | < | |
252 | comparable_type, point_type, point_type | |
253 | >::type cdistance_type; | |
254 | ||
255 | pythagoras_type pythagoras; | |
256 | distance_type distance = pythagoras.apply(p1, p2); | |
257 | BOOST_CHECK_CLOSE(distance, 107655455.02347542, 0.001); | |
258 | ||
259 | comparable_type comparable; | |
260 | cdistance_type cdistance = comparable.apply(p1, p2); | |
b32b8144 | 261 | BOOST_CHECK_EQUAL(cdistance, 11589696996311540.0); |
7c673cae FG |
262 | |
263 | distance_type distance2 = sqrt(distance_type(cdistance)); | |
264 | BOOST_CHECK_CLOSE(distance, distance2, 0.001); | |
265 | ||
266 | if (check_types) | |
267 | { | |
268 | BOOST_CHECK((boost::is_same<distance_type, double>::type::value)); | |
269 | // comparable_distance results in now double too, obviously because | |
270 | // comp.distance point-segment can be fraction, even for integer input | |
271 | BOOST_CHECK((boost::is_same<cdistance_type, double>::type::value)); | |
272 | } | |
273 | } | |
274 | ||
275 | ||
276 | template <typename P1, typename P2> | |
277 | void test_all_3d() | |
278 | { | |
279 | test_null_distance_3d<P1, P2>(); | |
280 | test_axis_3d<P1, P2>(); | |
281 | test_arbitrary_3d<P1, P2>(); | |
282 | } | |
283 | ||
284 | template <typename P> | |
285 | void test_all_3d() | |
286 | { | |
287 | test_all_3d<P, int[3]>(); | |
288 | test_all_3d<P, float[3]>(); | |
289 | test_all_3d<P, double[3]>(); | |
290 | test_all_3d<P, test::test_point>(); | |
291 | test_all_3d<P, bg::model::point<int, 3, bg::cs::cartesian> >(); | |
292 | test_all_3d<P, bg::model::point<float, 3, bg::cs::cartesian> >(); | |
293 | test_all_3d<P, bg::model::point<double, 3, bg::cs::cartesian> >(); | |
294 | } | |
295 | ||
296 | template <typename P, typename Strategy> | |
297 | void time_compare_s(int const n) | |
298 | { | |
299 | boost::timer t; | |
300 | P p1, p2; | |
301 | bg::assign_values(p1, 1, 1); | |
302 | bg::assign_values(p2, 2, 2); | |
303 | Strategy strategy; | |
304 | typename bg::strategy::distance::services::return_type<Strategy, P, P>::type s = 0; | |
305 | for (int i = 0; i < n; i++) | |
306 | { | |
307 | for (int j = 0; j < n; j++) | |
308 | { | |
309 | bg::set<0>(p2, bg::get<0>(p2) + 0.001); | |
310 | s += strategy.apply(p1, p2); | |
311 | } | |
312 | } | |
313 | std::cout << "s: " << s << " t: " << t.elapsed() << std::endl; | |
314 | } | |
315 | ||
316 | template <typename P> | |
317 | void time_compare(int const n) | |
318 | { | |
319 | time_compare_s<P, bg::strategy::distance::pythagoras<> >(n); | |
320 | time_compare_s<P, bg::strategy::distance::comparable::pythagoras<> >(n); | |
321 | } | |
322 | ||
323 | int test_main(int, char* []) | |
324 | { | |
325 | test_integer<int>(true); | |
326 | test_integer<boost::long_long_type>(true); | |
327 | test_integer<double>(false); | |
328 | ||
329 | test_all_3d<int[3]>(); | |
330 | test_all_3d<float[3]>(); | |
331 | test_all_3d<double[3]>(); | |
332 | ||
333 | test_all_3d<test::test_point>(); | |
334 | ||
335 | test_all_3d<bg::model::point<int, 3, bg::cs::cartesian> >(); | |
336 | test_all_3d<bg::model::point<float, 3, bg::cs::cartesian> >(); | |
337 | test_all_3d<bg::model::point<double, 3, bg::cs::cartesian> >(); | |
338 | ||
339 | test_big_2d<float, float>(); | |
340 | test_big_2d<double, double>(); | |
341 | test_big_2d<long double, long double>(); | |
342 | test_big_2d<float, long double>(); | |
343 | ||
344 | test_services<bg::model::point<float, 3, bg::cs::cartesian>, double[3], long double>(); | |
345 | test_services<double[3], test::test_point, float>(); | |
346 | ||
347 | ||
348 | // TODO move this to another non-unit test | |
349 | // time_compare<bg::model::point<double, 2, bg::cs::cartesian> >(10000); | |
350 | ||
351 | #if defined(HAVE_TTMATH) | |
352 | ||
353 | typedef ttmath::Big<1,4> tt; | |
354 | typedef bg::model::point<tt, 3, bg::cs::cartesian> tt_point; | |
355 | ||
356 | //test_all_3d<tt[3]>(); | |
357 | test_all_3d<tt_point>(); | |
358 | test_all_3d<tt_point, tt_point>(); | |
359 | test_big_2d<tt, tt>(); | |
360 | test_big_2d_string<tt, tt>(); | |
361 | #endif | |
362 | return 0; | |
363 | } |