]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/strategies/strategy_transform.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / geometry / strategies / strategy_transform.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
6
7 // This file was modified by Oracle on 2015.
8 // Modifications copyright (c) 2015 Oracle and/or its affiliates.
9
10 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
11
12 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
13 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
14
15 // Use, modification and distribution is subject to the Boost Software License,
16 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
17 // http://www.boost.org/LICENSE_1_0.txt)
18
19 #ifndef BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
20 #define BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
21
22 #include <cstddef>
23 #include <cmath>
24 #include <functional>
25
26 #include <boost/numeric/conversion/cast.hpp>
27
28 #include <boost/geometry/algorithms/convert.hpp>
29 #include <boost/geometry/arithmetic/arithmetic.hpp>
30 #include <boost/geometry/core/access.hpp>
31 #include <boost/geometry/core/radian_access.hpp>
32 #include <boost/geometry/core/coordinate_dimension.hpp>
33 #include <boost/geometry/core/coordinate_promotion.hpp>
34 #include <boost/geometry/strategies/transform.hpp>
35
36 #include <boost/geometry/util/math.hpp>
37 #include <boost/geometry/util/select_coordinate_type.hpp>
38
39 namespace boost { namespace geometry
40 {
41
42 namespace strategy { namespace transform
43 {
44
45 #ifndef DOXYGEN_NO_DETAIL
46 namespace detail
47 {
48
49 template
50 <
51 typename Src, typename Dst,
52 std::size_t D, std::size_t N,
53 template <typename> class F
54 >
55 struct transform_coordinates
56 {
57 template <typename T>
58 static inline void transform(Src const& source, Dst& dest, T value)
59 {
60 typedef typename select_coordinate_type<Src, Dst>::type coordinate_type;
61
62 F<coordinate_type> function;
63 set<D>(dest, boost::numeric_cast<coordinate_type>(function(get<D>(source), value)));
64 transform_coordinates<Src, Dst, D + 1, N, F>::transform(source, dest, value);
65 }
66 };
67
68 template
69 <
70 typename Src, typename Dst,
71 std::size_t N,
72 template <typename> class F
73 >
74 struct transform_coordinates<Src, Dst, N, N, F>
75 {
76 template <typename T>
77 static inline void transform(Src const& , Dst& , T )
78 {
79 }
80 };
81
82 } // namespace detail
83 #endif // DOXYGEN_NO_DETAIL
84
85
86 /*!
87 \brief Transformation strategy to copy one point to another using assignment operator
88 \ingroup transform
89 \tparam P point type
90 */
91 template <typename P>
92 struct copy_direct
93 {
94 inline bool apply(P const& p1, P& p2) const
95 {
96 p2 = p1;
97 return true;
98 }
99 };
100
101 /*!
102 \brief Transformation strategy to do copy a point, copying per coordinate.
103 \ingroup transform
104 \tparam P1 first point type
105 \tparam P2 second point type
106 */
107 template <typename P1, typename P2>
108 struct copy_per_coordinate
109 {
110 inline bool apply(P1 const& p1, P2& p2) const
111 {
112 // Defensive check, dimensions are equal, selected by specialization
113 assert_dimension_equal<P1, P2>();
114
115 geometry::convert(p1, p2);
116 return true;
117 }
118 };
119
120
121 /*!
122 \brief Transformation strategy to go from degree to radian and back
123 \ingroup transform
124 \tparam P1 first point type
125 \tparam P2 second point type
126 \tparam F additional functor to divide or multiply with d2r
127 */
128 template <typename P1, typename P2, template <typename> class F>
129 struct degree_radian_vv
130 {
131 inline bool apply(P1 const& p1, P2& p2) const
132 {
133 // Spherical coordinates always have 2 coordinates measured in angles
134 // The optional third one is distance/height, provided in another strategy
135 // Polar coordinates having one angle, will be also in another strategy
136 assert_dimension<P1, 2>();
137 assert_dimension<P2, 2>();
138
139 typedef typename promote_floating_point
140 <
141 typename select_coordinate_type<P1, P2>::type
142 >::type calculation_type;
143
144 detail::transform_coordinates
145 <
146 P1, P2, 0, 2, F
147 >::transform(p1, p2, math::d2r<calculation_type>());
148 return true;
149 }
150 };
151
152 template <typename P1, typename P2, template <typename> class F>
153 struct degree_radian_vv_3
154 {
155 inline bool apply(P1 const& p1, P2& p2) const
156 {
157 assert_dimension<P1, 3>();
158 assert_dimension<P2, 3>();
159
160 typedef typename promote_floating_point
161 <
162 typename select_coordinate_type<P1, P2>::type
163 >::type calculation_type;
164
165 detail::transform_coordinates
166 <
167 P1, P2, 0, 2, F
168 >::transform(p1, p2, math::d2r<calculation_type>());
169
170 // Copy height or other third dimension
171 set<2>(p2, get<2>(p1));
172 return true;
173 }
174 };
175
176
177 #ifndef DOXYGEN_NO_DETAIL
178 namespace detail
179 {
180
181 /// Helper function for conversion, phi/theta are in radians
182 template <typename P, typename T, typename R>
183 inline void spherical_polar_to_cartesian(T phi, T theta, R r, P& p)
184 {
185 assert_dimension<P, 3>();
186
187 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_spherical_coordinates
188 // http://www.vias.org/comp_geometry/math_coord_convert_3d.htm
189 // https://moodle.polymtl.ca/file.php/1183/Autres_Documents/Derivation_for_Spherical_Co-ordinates.pdf
190 // http://en.citizendium.org/wiki/Spherical_polar_coordinates
191
192 // Phi = first, theta is second, r is third, see documentation on cs::spherical
193
194 // (calculations are splitted to implement user defined types)
195
196 T r_sin_theta = r;
197 T r_cos_theta = r;
198 r_sin_theta *= sin(theta);
199 r_cos_theta *= cos(theta);
200
201 set<0>(p, r_sin_theta * cos(phi));
202 set<1>(p, r_sin_theta * sin(phi));
203 set<2>(p, r_cos_theta);
204 }
205
206 /// Helper function for conversion, lambda/delta (lon lat) are in radians
207 template <typename P, typename T, typename R>
208 inline void spherical_equatorial_to_cartesian(T lambda, T delta, R r, P& p)
209 {
210 assert_dimension<P, 3>();
211
212 // http://mathworld.wolfram.com/GreatCircle.html
213 // http://www.spenvis.oma.be/help/background/coortran/coortran.html WRONG
214
215 T r_cos_delta = r;
216 T r_sin_delta = r;
217 r_cos_delta *= cos(delta);
218 r_sin_delta *= sin(delta);
219
220 set<0>(p, r_cos_delta * cos(lambda));
221 set<1>(p, r_cos_delta * sin(lambda));
222 set<2>(p, r_sin_delta);
223 }
224
225
226 /// Helper function for conversion
227 template <typename P, typename T>
228 inline bool cartesian_to_spherical2(T x, T y, T z, P& p)
229 {
230 assert_dimension<P, 2>();
231
232 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
233
234 #if defined(BOOST_GEOMETRY_TRANSFORM_CHECK_UNIT_SPHERE)
235 // TODO: MAYBE ONLY IF TO BE CHECKED?
236 T const r = /*sqrt not necessary, sqrt(1)=1*/ (x * x + y * y + z * z);
237
238 // Unit sphere, so r should be 1
239 if (geometry::math::abs(r - 1.0) > T(1e-6))
240 {
241 return false;
242 }
243 // end todo
244 #endif
245
246 set_from_radian<0>(p, atan2(y, x));
247 set_from_radian<1>(p, acos(z));
248 return true;
249 }
250
251 template <typename P, typename T>
252 inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p)
253 {
254 assert_dimension<P, 2>();
255
256 set_from_radian<0>(p, atan2(y, x));
257 set_from_radian<1>(p, asin(z));
258 return true;
259 }
260
261
262 template <typename P, typename T>
263 inline bool cartesian_to_spherical3(T x, T y, T z, P& p)
264 {
265 assert_dimension<P, 3>();
266
267 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
268 T const r = math::sqrt(x * x + y * y + z * z);
269 set<2>(p, r);
270 set_from_radian<0>(p, atan2(y, x));
271 if (r > 0.0)
272 {
273 set_from_radian<1>(p, acos(z / r));
274 return true;
275 }
276 return false;
277 }
278
279 template <typename P, typename T>
280 inline bool cartesian_to_spherical_equatorial3(T x, T y, T z, P& p)
281 {
282 assert_dimension<P, 3>();
283
284 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
285 T const r = math::sqrt(x * x + y * y + z * z);
286 set<2>(p, r);
287 set_from_radian<0>(p, atan2(y, x));
288 if (r > 0.0)
289 {
290 set_from_radian<1>(p, asin(z / r));
291 return true;
292 }
293 return false;
294 }
295
296 } // namespace detail
297 #endif // DOXYGEN_NO_DETAIL
298
299
300 /*!
301 \brief Transformation strategy for 2D spherical (phi,theta) to 3D cartesian (x,y,z)
302 \details on Unit sphere
303 \ingroup transform
304 \tparam P1 first point type
305 \tparam P2 second point type
306 */
307 template <typename P1, typename P2>
308 struct from_spherical_polar_2_to_cartesian_3
309 {
310 inline bool apply(P1 const& p1, P2& p2) const
311 {
312 assert_dimension<P1, 2>();
313 detail::spherical_polar_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
314 return true;
315 }
316 };
317
318 template <typename P1, typename P2>
319 struct from_spherical_equatorial_2_to_cartesian_3
320 {
321 inline bool apply(P1 const& p1, P2& p2) const
322 {
323 assert_dimension<P1, 2>();
324 detail::spherical_equatorial_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
325 return true;
326 }
327 };
328
329
330 /*!
331 \brief Transformation strategy for 3D spherical (phi,theta,r) to 3D cartesian (x,y,z)
332 \ingroup transform
333 \tparam P1 first point type
334 \tparam P2 second point type
335 */
336 template <typename P1, typename P2>
337 struct from_spherical_polar_3_to_cartesian_3
338 {
339 inline bool apply(P1 const& p1, P2& p2) const
340 {
341 assert_dimension<P1, 3>();
342 detail::spherical_polar_to_cartesian(
343 get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
344 return true;
345 }
346 };
347
348 template <typename P1, typename P2>
349 struct from_spherical_equatorial_3_to_cartesian_3
350 {
351 inline bool apply(P1 const& p1, P2& p2) const
352 {
353 assert_dimension<P1, 3>();
354 detail::spherical_equatorial_to_cartesian(
355 get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
356 return true;
357 }
358 };
359
360
361 /*!
362 \brief Transformation strategy for 3D cartesian (x,y,z) to 2D spherical (phi,theta)
363 \details on Unit sphere
364 \ingroup transform
365 \tparam P1 first point type
366 \tparam P2 second point type
367 \note If x,y,z point is not lying on unit sphere, transformation will return false
368 */
369 template <typename P1, typename P2>
370 struct from_cartesian_3_to_spherical_polar_2
371 {
372 inline bool apply(P1 const& p1, P2& p2) const
373 {
374 assert_dimension<P1, 3>();
375 return detail::cartesian_to_spherical2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
376 }
377 };
378
379 template <typename P1, typename P2>
380 struct from_cartesian_3_to_spherical_equatorial_2
381 {
382 inline bool apply(P1 const& p1, P2& p2) const
383 {
384 assert_dimension<P1, 3>();
385 return detail::cartesian_to_spherical_equatorial2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
386 }
387 };
388
389
390 /*!
391 \brief Transformation strategy for 3D cartesian (x,y,z) to 3D spherical (phi,theta,r)
392 \ingroup transform
393 \tparam P1 first point type
394 \tparam P2 second point type
395 */
396 template <typename P1, typename P2>
397 struct from_cartesian_3_to_spherical_polar_3
398 {
399 inline bool apply(P1 const& p1, P2& p2) const
400 {
401 assert_dimension<P1, 3>();
402 return detail::cartesian_to_spherical3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
403 }
404 };
405
406 template <typename P1, typename P2>
407 struct from_cartesian_3_to_spherical_equatorial_3
408 {
409 inline bool apply(P1 const& p1, P2& p2) const
410 {
411 assert_dimension<P1, 3>();
412 return detail::cartesian_to_spherical_equatorial3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
413 }
414 };
415
416 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
417
418 namespace services
419 {
420
421 /// Specialization for same coordinate system family, same system, same dimension, same point type, can be copied
422 template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P>
423 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P, P>
424 {
425 typedef copy_direct<P> type;
426 };
427
428 /// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate
429 template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P1, typename P2>
430 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P1, P2>
431 {
432 typedef copy_per_coordinate<P1, P2> type;
433 };
434
435 /// Specialization to transform from degree to radian for any coordinate system / point type combination
436 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
437 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 2, 2, P1, P2>
438 {
439 typedef degree_radian_vv<P1, P2, std::multiplies> type;
440 };
441
442 /// Specialization to transform from radian to degree for any coordinate system / point type combination
443 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
444 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 2, 2, P1, P2>
445 {
446 typedef degree_radian_vv<P1, P2, std::divides> type;
447 };
448
449
450 /// Specialization degree->radian in 3D
451 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
452 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 3, 3, P1, P2>
453 {
454 typedef degree_radian_vv_3<P1, P2, std::multiplies> type;
455 };
456
457 /// Specialization radian->degree in 3D
458 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
459 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 3, 3, P1, P2>
460 {
461 typedef degree_radian_vv_3<P1, P2, std::divides> type;
462 };
463
464 /// Specialization to transform from unit sphere(phi,theta) to XYZ
465 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
466 struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
467 {
468 typedef from_spherical_polar_2_to_cartesian_3<P1, P2> type;
469 };
470
471 /// Specialization to transform from sphere(phi,theta,r) to XYZ
472 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
473 struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
474 {
475 typedef from_spherical_polar_3_to_cartesian_3<P1, P2> type;
476 };
477
478 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
479 struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
480 {
481 typedef from_spherical_equatorial_2_to_cartesian_3<P1, P2> type;
482 };
483
484 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
485 struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
486 {
487 typedef from_spherical_equatorial_3_to_cartesian_3<P1, P2> type;
488 };
489
490 /// Specialization to transform from XYZ to unit sphere(phi,theta)
491 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
492 struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
493 {
494 typedef from_cartesian_3_to_spherical_polar_2<P1, P2> type;
495 };
496
497 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
498 struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
499 {
500 typedef from_cartesian_3_to_spherical_equatorial_2<P1, P2> type;
501 };
502
503 /// Specialization to transform from XYZ to sphere(phi,theta,r)
504 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
505 struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
506 {
507 typedef from_cartesian_3_to_spherical_polar_3<P1, P2> type;
508 };
509 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
510 struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
511 {
512 typedef from_cartesian_3_to_spherical_equatorial_3<P1, P2> type;
513 };
514
515
516 } // namespace services
517
518
519 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
520
521
522 }} // namespace strategy::transform
523
524
525 }} // namespace boost::geometry
526
527 #endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP