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 #include <boost/geometry/strategies/strategy_transform.hpp>
19 #include <boost/geometry/algorithms/transform.hpp>
20 #include <boost/geometry/geometries/point.hpp>
21 #include <boost/geometry/geometries/point_xy.hpp>
22 
23 template <typename T, typename P>
check_distance(P const & p)24 inline T check_distance(P const& p)
25 {
26     T x = bg::get<0>(p);
27     T y = bg::get<1>(p);
28     T z = bg::get<2>(p);
29     return sqrt(x * x + y * y + z * z);
30 }
31 
32 template <typename T>
test_transformations_spherical()33 void test_transformations_spherical()
34 {
35     T const input_long = 15.0;
36     T const input_lat = 5.0;
37 
38     T const expected_long = 0.26179938779914943653855361527329;
39     T const expected_lat = 0.08726646259971647884618453842443;
40 
41     // Can be checked using http://www.calc3d.com/ejavascriptcoordcalc.html
42     // (for phi use long, in radians, for theta use lat, in radians, they are listed there as "theta, phi")
43     T const expected_polar_x = 0.084186;
44     T const expected_polar_y = 0.0225576;
45     T const expected_polar_z = 0.996195;
46 
47     // Can be checked with same URL using 90-theta for lat.
48     // So for theta use 85 degrees, in radians: 0.08726646259971647884618453842443
49     T const expected_equatorial_x = 0.962250;
50     T const expected_equatorial_y = 0.257834;
51     T const expected_equatorial_z = 0.0871557;
52 
53     // 1: Spherical-polar (lat=5, so it is near the pole - on a unit sphere)
54     bg::model::point<T, 2, bg::cs::spherical<bg::degree> > sp(input_long, input_lat);
55 
56     // 1a: to radian
57     bg::model::point<T, 2, bg::cs::spherical<bg::radian> > spr;
58     bg::transform(sp, spr);
59     BOOST_CHECK_CLOSE(bg::get<0>(spr), expected_long, 0.001);
60     BOOST_CHECK_CLOSE(bg::get<1>(spr), expected_lat, 0.001);
61 
62     // 1b: to cartesian-3d
63     bg::model::point<T, 3, bg::cs::cartesian> pc3;
64     bg::transform(sp, pc3);
65     BOOST_CHECK_CLOSE(bg::get<0>(pc3), expected_polar_x, 0.001);
66     BOOST_CHECK_CLOSE(bg::get<1>(pc3), expected_polar_y, 0.001);
67     BOOST_CHECK_CLOSE(bg::get<2>(pc3), expected_polar_z, 0.001);
68     BOOST_CHECK_CLOSE(check_distance<T>(pc3), 1.0, 0.001);
69 
70     // 1c: back
71     bg::transform(pc3, spr);
72     BOOST_CHECK_CLOSE(bg::get<0>(spr), expected_long, 0.001);
73     BOOST_CHECK_CLOSE(bg::get<1>(spr), expected_lat, 0.001);
74 
75     // 2: Spherical-equatorial (lat=5, so it is near the equator)
76     bg::model::point<T, 2, bg::cs::spherical_equatorial<bg::degree> > se(input_long, input_lat);
77 
78     // 2a: to radian
79     bg::model::point<T, 2, bg::cs::spherical_equatorial<bg::radian> > ser;
80     bg::transform(se, ser);
81     BOOST_CHECK_CLOSE(bg::get<0>(ser), expected_long, 0.001);
82     BOOST_CHECK_CLOSE(bg::get<1>(ser), expected_lat, 0.001);
83 
84     bg::transform(se, pc3);
85     BOOST_CHECK_CLOSE(bg::get<0>(pc3), expected_equatorial_x, 0.001);
86     BOOST_CHECK_CLOSE(bg::get<1>(pc3), expected_equatorial_y, 0.001);
87     BOOST_CHECK_CLOSE(bg::get<2>(pc3), expected_equatorial_z, 0.001);
88     BOOST_CHECK_CLOSE(check_distance<T>(pc3), 1.0, 0.001);
89 
90     // 2c: back
91     bg::transform(pc3, ser);
92     BOOST_CHECK_CLOSE(bg::get<0>(spr), expected_long, 0.001);  // expected_long
93     BOOST_CHECK_CLOSE(bg::get<1>(spr), expected_lat, 0.001); // expected_lat
94 
95 
96     // 3: Spherical-polar including radius
97     bg::model::point<T, 3, bg::cs::spherical<bg::degree> > sp3(input_long, input_lat, 0.5);
98 
99     // 3a: to radian
100     bg::model::point<T, 3, bg::cs::spherical<bg::radian> > spr3;
101     bg::transform(sp3, spr3);
102     BOOST_CHECK_CLOSE(bg::get<0>(spr3), expected_long, 0.001);
103     BOOST_CHECK_CLOSE(bg::get<1>(spr3), expected_lat, 0.001);
104     BOOST_CHECK_CLOSE(bg::get<2>(spr3), 0.5, 0.001);
105 
106     // 3b: to cartesian-3d
107     bg::transform(sp3, pc3);
108     BOOST_CHECK_CLOSE(bg::get<0>(pc3), expected_polar_x / 2.0, 0.001);
109     BOOST_CHECK_CLOSE(bg::get<1>(pc3), expected_polar_y / 2.0, 0.001);
110     BOOST_CHECK_CLOSE(bg::get<2>(pc3), expected_polar_z / 2.0, 0.001);
111     BOOST_CHECK_CLOSE(check_distance<T>(pc3), 0.5, 0.001);
112 
113     // 3c: back
114     bg::transform(pc3, spr3);
115     BOOST_CHECK_CLOSE(bg::get<0>(spr3), expected_long, 0.001);
116     BOOST_CHECK_CLOSE(bg::get<1>(spr3), expected_lat, 0.001);
117     BOOST_CHECK_CLOSE(bg::get<2>(spr3), 0.5, 0.001);
118 
119 
120     // 4: Spherical-equatorial including radius
121     bg::model::point<T, 3, bg::cs::spherical_equatorial<bg::degree> > se3(input_long, input_lat, 0.5);
122 
123     // 4a: to radian
124     bg::model::point<T, 3, bg::cs::spherical_equatorial<bg::radian> > ser3;
125     bg::transform(se3, ser3);
126     BOOST_CHECK_CLOSE(bg::get<0>(ser3), expected_long, 0.001);
127     BOOST_CHECK_CLOSE(bg::get<1>(ser3), expected_lat, 0.001);
128     BOOST_CHECK_CLOSE(bg::get<2>(ser3), 0.5, 0.001);
129 
130     // 4b: to cartesian-3d
131     bg::transform(se3, pc3);
132     BOOST_CHECK_CLOSE(bg::get<0>(pc3), expected_equatorial_x / 2.0, 0.001);
133     BOOST_CHECK_CLOSE(bg::get<1>(pc3), expected_equatorial_y / 2.0, 0.001);
134     BOOST_CHECK_CLOSE(bg::get<2>(pc3), expected_equatorial_z / 2.0, 0.001);
135     BOOST_CHECK_CLOSE(check_distance<T>(pc3), 0.5, 0.001);
136 
137     // 4c: back
138     bg::transform(pc3, ser3);
139     BOOST_CHECK_CLOSE(bg::get<0>(ser3), expected_long, 0.001);
140     BOOST_CHECK_CLOSE(bg::get<1>(ser3), expected_lat, 0.001);
141     BOOST_CHECK_CLOSE(bg::get<2>(ser3), 0.5, 0.001);
142 }
143 
test_main(int,char * [])144 int test_main(int, char* [])
145 {
146     test_transformations_spherical<double>();
147 
148     return 0;
149 }
150