1 // Copyright 2005 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS-IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 
16 // Author: ericv@google.com (Eric Veach)
17 
18 #include "s2/s1angle.h"
19 
20 #include <gtest/gtest.h>
21 
22 #include "s2/base/integral_types.h"
23 #include "s2/base/logging.h"
24 #include "s2/s2latlng.h"
25 #include "s2/s2testing.h"
26 
TEST(S1Angle,DefaultConstructor)27 TEST(S1Angle, DefaultConstructor) {
28   // Check that the default constructor returns an angle of 0.
29   S1Angle a;
30   EXPECT_EQ(0, a.radians());
31 }
32 
TEST(S1Angle,Infinity)33 TEST(S1Angle, Infinity) {
34   EXPECT_LT(S1Angle::Radians(1e30), S1Angle::Infinity());
35   EXPECT_LT(-S1Angle::Infinity(), S1Angle::Zero());
36   EXPECT_EQ(S1Angle::Infinity(), S1Angle::Infinity());
37 }
38 
TEST(S1Angle,Zero)39 TEST(S1Angle, Zero) {
40   EXPECT_EQ(S1Angle::Radians(0), S1Angle::Zero());
41 }
42 
TEST(S1Angle,PiRadiansExactly180Degrees)43 TEST(S1Angle, PiRadiansExactly180Degrees) {
44   // Check that the conversion between Pi radians and 180 degrees is exact.
45   EXPECT_EQ(M_PI, S1Angle::Radians(M_PI).radians());
46   EXPECT_EQ(180.0, S1Angle::Radians(M_PI).degrees());
47   EXPECT_EQ(M_PI, S1Angle::Degrees(180).radians());
48   EXPECT_EQ(180.0, S1Angle::Degrees(180).degrees());
49 
50   EXPECT_EQ(90.0, S1Angle::Radians(M_PI_2).degrees());
51 
52   // Check negative angles.
53   EXPECT_EQ(-90.0, S1Angle::Radians(-M_PI_2).degrees());
54   EXPECT_EQ(-M_PI_4, S1Angle::Degrees(-45).radians());
55 }
56 
TEST(S1Angle,E5E6E7Representations)57 TEST(S1Angle, E5E6E7Representations) {
58   // Check that E5/E6/E7 representations work as expected.
59   EXPECT_DOUBLE_EQ(S1Angle::Degrees(-45).radians(),
60                    S1Angle::E5(-4500000).radians());
61   EXPECT_DOUBLE_EQ(S1Angle::Degrees(-60).radians(),
62                    S1Angle::E6(-60000000).radians());
63   EXPECT_DOUBLE_EQ(S1Angle::Degrees(75).radians(),
64                    S1Angle::E7(750000000).radians());
65   EXPECT_EQ(-17256123, S1Angle::Degrees(-172.56123).e5());
66   EXPECT_EQ(12345678, S1Angle::Degrees(12.345678).e6());
67   EXPECT_EQ(-123456789, S1Angle::Degrees(-12.3456789).e7());
68 }
69 
TEST(S1Angle,E6E7RepresentationsUnsigned)70 TEST(S1Angle, E6E7RepresentationsUnsigned) {
71   // Check that unsigned E6/E7 representations work as expected.
72   EXPECT_DOUBLE_EQ(
73       S1Angle::Degrees(60).radians(),
74       S1Angle::UnsignedE6(static_cast<uint32>(60000000)).radians());
75   EXPECT_DOUBLE_EQ(
76       S1Angle::Degrees(-60).radians(),
77       S1Angle::UnsignedE6(static_cast<uint32>(-60000000)).radians());
78   EXPECT_DOUBLE_EQ(
79       S1Angle::Degrees(75).radians(),
80       S1Angle::UnsignedE7(static_cast<uint32>(750000000)).radians());
81   EXPECT_DOUBLE_EQ(
82       S1Angle::Degrees(-75).radians(),
83       S1Angle::UnsignedE7(static_cast<uint32>(-750000000)).radians());
84 }
85 
TEST(S1Angle,NormalizeCorrectlyCanonicalizesAngles)86 TEST(S1Angle, NormalizeCorrectlyCanonicalizesAngles) {
87   EXPECT_DOUBLE_EQ(0.0, S1Angle::Degrees(360.0).Normalized().degrees());
88   EXPECT_DOUBLE_EQ(-90.0, S1Angle::Degrees(-90.0).Normalized().degrees());
89   EXPECT_DOUBLE_EQ(180.0, S1Angle::Degrees(-180.0).Normalized().degrees());
90   EXPECT_DOUBLE_EQ(180.0, S1Angle::Degrees(180.0).Normalized().degrees());
91   EXPECT_DOUBLE_EQ(180.0, S1Angle::Degrees(540.0).Normalized().degrees());
92   EXPECT_DOUBLE_EQ(90.0, S1Angle::Degrees(-270.0).Normalized().degrees());
93 }
94 
TEST(S1Angle,ArithmeticOperationsOnAngles)95 TEST(S1Angle, ArithmeticOperationsOnAngles) {
96   EXPECT_DOUBLE_EQ(0.3, S1Angle::Radians(-0.3).abs().radians());
97   EXPECT_DOUBLE_EQ(-0.1, (-S1Angle::Radians(0.1)).radians());
98   EXPECT_DOUBLE_EQ(0.4,
99                    (S1Angle::Radians(0.1) + S1Angle::Radians(0.3)).radians());
100   EXPECT_DOUBLE_EQ(-0.2,
101                    (S1Angle::Radians(0.1) - S1Angle::Radians(0.3)).radians());
102   EXPECT_DOUBLE_EQ(0.6, (2 * S1Angle::Radians(0.3)).radians());
103   EXPECT_DOUBLE_EQ(0.6, (S1Angle::Radians(0.3) * 2).radians());
104   EXPECT_DOUBLE_EQ(0.15, (S1Angle::Radians(0.3) / 2).radians());
105   EXPECT_DOUBLE_EQ(0.5, (S1Angle::Radians(0.3) / S1Angle::Radians(0.6)));
106 
107   S1Angle tmp = S1Angle::Radians(1.0);
108   tmp += S1Angle::Radians(0.5);
109   EXPECT_DOUBLE_EQ(1.5, tmp.radians());
110   tmp -= S1Angle::Radians(1.0);
111   EXPECT_DOUBLE_EQ(0.5, tmp.radians());
112   tmp *= 5;
113   EXPECT_DOUBLE_EQ(2.5, tmp.radians());
114   tmp /= 2;
115   EXPECT_DOUBLE_EQ(1.25, tmp.radians());
116 }
117 
TEST(S1Angle,Trigonometry)118 TEST(S1Angle, Trigonometry) {
119   // Spot check a few angles to ensure that the correct function is called.
120   EXPECT_DOUBLE_EQ(1, cos(S1Angle::Degrees(0)));
121   EXPECT_DOUBLE_EQ(1, sin(S1Angle::Degrees(90)));
122   EXPECT_DOUBLE_EQ(1, tan(S1Angle::Degrees(45)));
123 }
124 
TEST(S1Angle,ConstructorsThatMeasureAngles)125 TEST(S1Angle, ConstructorsThatMeasureAngles) {
126   EXPECT_DOUBLE_EQ(M_PI_2,
127                    S1Angle(S2Point(1, 0, 0), S2Point(0, 0, 2)).radians());
128   EXPECT_DOUBLE_EQ(0.0, S1Angle(S2Point(1, 0, 0), S2Point(1, 0, 0)).radians());
129   EXPECT_NEAR(50.0,
130               S1Angle(S2LatLng::FromDegrees(20, 20),
131                       S2LatLng::FromDegrees(70, 20)).degrees(),
132               1e-13);
133 }
134 
TEST(S1Angle,TestFormatting)135 TEST(S1Angle, TestFormatting) {
136   std::ostringstream ss;
137   ss << S1Angle::Degrees(180.0);
138   EXPECT_EQ("180.0000000", ss.str());
139 }
140 
141 // The current implementation guarantees exact conversions between
142 // Degrees() and E6() when the Degrees() argument is an integer.
TEST(S1Angle,DegreesVsE6)143 TEST(S1Angle, DegreesVsE6) {
144   for (int i = 0; i <= 180; ++i) {
145     EXPECT_EQ(S1Angle::Degrees(i), S1Angle::E6(1000000 * i));
146   }
147 }
148 
149 // The current implementation guarantees exact conversions between
150 // Degrees() and E7() when the Degrees() argument is an integer.
TEST(S1Angle,DegreesVsE7)151 TEST(S1Angle, DegreesVsE7) {
152   for (int i = 0; i <= 180; ++i) {
153     EXPECT_EQ(S1Angle::Degrees(i), S1Angle::E7(10000000 * i));
154   }
155 }
156 
157 // The current implementation guarantees exact conversions between
158 // E6() and E7() when the E6() argument is an integer.
TEST(S1Angle,E6VsE7)159 TEST(S1Angle, E6VsE7) {
160   S2Testing::rnd.Reset(FLAGS_s2_random_seed);
161   for (int iter = 0; iter < 1000; ++iter) {
162     int i = S2Testing::rnd.Uniform(180000000);
163     EXPECT_EQ(S1Angle::E6(i), S1Angle::E7(10 * i));
164   }
165 }
166 
167 // The current implementation guarantees certain exact conversions between
168 // degrees and radians (see the header file for details).
TEST(S1Angle,DegreesVsRadians)169 TEST(S1Angle, DegreesVsRadians) {
170   for (int k = -8; k <= 8; ++k) {
171     EXPECT_EQ(S1Angle::Degrees(45 * k), S1Angle::Radians(k * M_PI / 4));
172     EXPECT_EQ(45 * k, S1Angle::Degrees(45 * k).degrees());
173   }
174   for (int k = 0; k <= 30; ++k) {
175     int n = 1 << k;
176     EXPECT_EQ(S1Angle::Degrees(180. / n), S1Angle::Radians(M_PI / n));
177     EXPECT_EQ(S1Angle::Degrees(60. / n), S1Angle::Radians(M_PI / (3. * n)));
178     EXPECT_EQ(S1Angle::Degrees(36. / n), S1Angle::Radians(M_PI / (5. * n)));
179     EXPECT_EQ(S1Angle::Degrees(20. / n), S1Angle::Radians(M_PI / (9. * n)));
180     EXPECT_EQ(S1Angle::Degrees(4. / n), S1Angle::Radians(M_PI / (45. * n)));
181   }
182   // We also spot check a couple of non-identities.
183   EXPECT_NE(S1Angle::Degrees(3), S1Angle::Radians(M_PI / 60));
184   EXPECT_NE(60, S1Angle::Degrees(60).degrees());
185 }
186