1 // Copyright 2008, Google Inc. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 //  1. Redistributions of source code must retain the above copyright notice,
7 //     this list of conditions and the following disclaimer.
8 //  2. Redistributions in binary form must reproduce the above copyright notice,
9 //     this list of conditions and the following disclaimer in the documentation
10 //     and/or other materials provided with the distribution.
11 //  3. Neither the name of Google Inc. nor the names of its contributors may be
12 //     used to endorse or promote products derived from this software without
13 //     specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 // This file contains the unit tests for the mathematical functions.
27 
28 #include "kml/base/math_util.h"
29 #include "boost/scoped_ptr.hpp"
30 #include "gtest/gtest.h"
31 
32 namespace kmlbase {
33 
TEST(BaseMathTest,TestAzimuthBetweenPoints)34 TEST(BaseMathTest, TestAzimuthBetweenPoints) {
35   // Sanity checks.
36   ASSERT_DOUBLE_EQ(0.0, AzimuthBetweenPoints(0,0,1,0));
37   ASSERT_DOUBLE_EQ(90.0, AzimuthBetweenPoints(0,0,0,1));
38   ASSERT_DOUBLE_EQ(180.0, AzimuthBetweenPoints(0,0,-1,0));
39   ASSERT_DOUBLE_EQ(-90.0, AzimuthBetweenPoints(0,0,0,-1));
40   ASSERT_NEAR(-180.0, AzimuthBetweenPoints(0,0,-1,-0.0000001), 0.0001);
41   // The example from the Aviation Formulary.
42   const double kLAX_lat = 33.944066;
43   const double kLAX_lng = -118.408294;
44   const double kJFK_lat = 40.642480;
45   const double kJFK_lng = -73.788071;
46   // The known azimuth from LAX to JFK.
47   const double kAzimuth = 65.8687;
48   double az1 = AzimuthBetweenPoints(kLAX_lat, kLAX_lng, kJFK_lat, kJFK_lng);
49   ASSERT_NEAR(kAzimuth, az1, 0.0001);
50   // The return flight.
51   const double kAzimuthReturn = -86.1617;
52   double az2 = AzimuthBetweenPoints(kJFK_lat, kJFK_lng, kLAX_lat, kLAX_lng);
53   ASSERT_NEAR(kAzimuthReturn, az2, 0.0001);
54 }
55 
TEST(BaseMathTest,TestDistanceBetweenPoints)56 TEST(BaseMathTest, TestDistanceBetweenPoints) {
57   const double kLAX_lat = 33.944066;
58   const double kLAX_lng = -118.408294;
59   const double kJFK_lat = 40.642480;
60   const double kJFK_lng = -73.788071;
61   // The known great circle distance in meters between LAX and JFK.
62   const double kDistance = 3970683.0;
63   double d = DistanceBetweenPoints(kLAX_lat, kLAX_lng, kJFK_lat, kJFK_lng);
64   ASSERT_NEAR(kDistance, d, 0.1);
65 }
66 
TEST(BaseMathTest,TestDistanceBetweenPoints3d)67 TEST(BaseMathTest, TestDistanceBetweenPoints3d) {
68   ASSERT_DOUBLE_EQ(0.0, DistanceBetweenPoints3d(0,0,0,0,0,0));
69   ASSERT_DOUBLE_EQ(1.0, DistanceBetweenPoints3d(0,0,0,0,0,1));
70   ASSERT_DOUBLE_EQ(1000.0, DistanceBetweenPoints3d(0,0,0,0,0,1000));
71   // Assert the 2d example works here.
72   double expected = 3970683.0;
73   ASSERT_NEAR(expected,
74               DistanceBetweenPoints3d(33.944066, -118.408294, 0,
75                                       40.642480, -73.788071, 0), 0.1);
76   // Put JFK 10,000 km in the sky:
77   expected = 4094670.171;
78   ASSERT_NEAR(expected,
79               DistanceBetweenPoints3d(33.944066, -118.408294, 0,
80                                       40.642480, -73.788071, 1000000.0), 0.1);
81 }
82 
TEST(BaseMathTest,TestElevationBetweenPoints)83 TEST(BaseMathTest, TestElevationBetweenPoints) {
84   double lat_from = 0;
85   double lng_from = 0;
86   double alt_from = 0;
87   double lat_to = 0.0000000000001;
88   double lng_to = 0.0000000000001;
89   // This is basically a flat line.
90   double alt_to = 0.0;
91   ASSERT_NEAR(
92     0.0, ElevationBetweenPoints(lat_from, lng_from, alt_from,
93                                 lat_to, lng_to, alt_to),
94     0.001);
95   // Near-vertical.
96   alt_to = 10000;
97   ASSERT_NEAR(
98     90.0, ElevationBetweenPoints(lat_from, lng_from, alt_from,
99                                  lat_to, lng_to, alt_to),
100     0.001);
101   lat_to = 0.145;
102   alt_to = 609.6;
103   ASSERT_NEAR(
104     2.1667, ElevationBetweenPoints(lat_from, lng_from, alt_from,
105                                    lat_to, lng_to, alt_to),
106     0.001);
107   lat_from = 37.0;
108   lng_from = -121.98;
109   alt_from = 600;
110   lat_to = 37.0;
111   lng_to = -122.0;
112   alt_to = 200;
113   ASSERT_NEAR(
114     -12.7004, ElevationBetweenPoints(lat_from, lng_from, alt_from,
115                                      lat_to, lng_to, alt_to),
116     0.001);
117 }
118 
TEST(BaseMathTest,TestLatLngOnRadialFromPoint)119 TEST(BaseMathTest, TestLatLngOnRadialFromPoint) {
120   // See http://williams.best.vwh.net/avform.htm#Example
121   // Coordinates of LAX.
122   const double kLAX_lat = 33.944066;
123   const double kLAX_lng = -118.408294;
124   // A distance and radial.
125   const double kDistance = 185200.0;
126   const double kRadial = 66.0;
127   // The known-accurate coordinates of the point along that radial from LAX.
128   const double kRadial_lat = 34.608154;
129   const double kRadial_lng = -116.558327;
130 
131   Vec3 v = LatLngOnRadialFromPoint(kLAX_lat, kLAX_lng, kDistance, kRadial);
132   ASSERT_NEAR(kRadial_lat, v.get_latitude(), 0.000001);
133   ASSERT_NEAR(kRadial_lng, v.get_longitude(), 0.000001);
134 }
135 
136 
137 // Tests the GroundDistanceFromRangeAndElevation() function.
TEST(BaseMathTest,TestGroundDistanceFromRangeAndElevation)138 TEST(BaseMathTest, TestGroundDistanceFromRangeAndElevation) {
139   ASSERT_NEAR(100.0, GroundDistanceFromRangeAndElevation(100.0, 0.0),
140               0.000001);
141   ASSERT_NEAR(99.939083, GroundDistanceFromRangeAndElevation(100.0, 2.0),
142               0.000001);
143   ASSERT_NEAR(17.364818, GroundDistanceFromRangeAndElevation(100.0, 80.0),
144               0.000001);
145   ASSERT_NEAR(0.0, GroundDistanceFromRangeAndElevation(100.0, 90.0),
146               0.000001);
147   ASSERT_NEAR(17.364818, GroundDistanceFromRangeAndElevation(100.0, 100.0),
148               0.000001);
149 }
150 
151 // Tests the HeightFromRangeAndElevation() function.
TEST(BaseMathTest,TestHeightFromRangeAndElevation)152 TEST(BaseMathTest, TestHeightFromRangeAndElevation) {
153   ASSERT_NEAR(0.0, HeightFromRangeAndElevation(100.0, 0.0),
154               0.000001);
155   ASSERT_NEAR(3.489950, HeightFromRangeAndElevation(100.0, 2.0),
156               0.000001);
157   ASSERT_NEAR(98.480775, HeightFromRangeAndElevation(100.0, 80.0),
158               0.000001);
159   ASSERT_NEAR(100.0, HeightFromRangeAndElevation(100.0, 90.0),
160               0.000001);
161   ASSERT_NEAR(98.480775, HeightFromRangeAndElevation(100.0, 100.0),
162               0.000001);
163 }
164 
165 // Tese test the conversion functions.
TEST(BaseMathTest,TestDegToRad)166 TEST(BaseMathTest, TestDegToRad) {
167   ASSERT_DOUBLE_EQ(0.0, DegToRad(0.0));
168   ASSERT_DOUBLE_EQ(M_PI, DegToRad(180.0));
169   ASSERT_DOUBLE_EQ(M_PI / 2, DegToRad(90.0));
170   ASSERT_DOUBLE_EQ(M_PI / -2, DegToRad(-90.0));
171 }
172 
TEST(BaseMathTest,TestRadToDeg)173 TEST(BaseMathTest, TestRadToDeg) {
174   ASSERT_DOUBLE_EQ(0.0, RadToDeg(0));
175   ASSERT_DOUBLE_EQ(360.0, RadToDeg(2 * M_PI));
176   ASSERT_DOUBLE_EQ(90.0, RadToDeg(M_PI / 2));
177   ASSERT_DOUBLE_EQ(-90.0, RadToDeg(M_PI / -2));
178 }
179 
TEST(BaseMathTest,TestMetersToRadians)180 TEST(BaseMathTest, TestMetersToRadians) {
181   ASSERT_DOUBLE_EQ(0, MetersToRadians(0));
182   ASSERT_DOUBLE_EQ(1, MetersToRadians(6366710));
183 }
184 
TEST(BaseMathTest,TestRadiansToMeters)185 TEST(BaseMathTest, TestRadiansToMeters) {
186   ASSERT_DOUBLE_EQ(0, RadiansToMeters(0));
187   ASSERT_DOUBLE_EQ(6366710, RadiansToMeters(1));
188 }
189 
190 }  // end namespace kmlbase
191