1// Copyright 2005 Google Inc. All Rights Reserved.
2
3#ifndef UTIL_GEOMETRY_S1ANGLE_H_
4#define UTIL_GEOMETRY_S1ANGLE_H_
5
6#include <iosfwd>
7using std::ostream;
8 // to forward declare ostream
9#include <math.h>
10#include "base/basictypes.h"
11#include "util/math/mathutil.h"
12#include "s2.h"
13
14class S2LatLng;
15
16// This class represents a one-dimensional angle (as opposed to a
17// two-dimensional solid angle). It has methods for converting angles to
18// or from radians, degrees, and the E5/E6/E7 representations (i.e. degrees
19// multiplied by 1e5/1e6/1e7 and rounded to the nearest integer).
20//
21// This class has built-in support for the E5, E6, and E7
22// representations. An E5 is the measure of an angle in degrees,
23// multiplied by 10**5.
24//
25// This class is intended to be copied by value as desired. It uses
26// the default copy constructor and assignment operator.
27class S1Angle {
28 public:
29 // These methods construct S1Angle objects from their measure in radians
30 // or degrees.
31 inline static S1Angle Radians(double radians);
32 inline static S1Angle Degrees(double degrees);
33 inline static S1Angle E5(int32 e5);
34 inline static S1Angle E6(int32 e6);
35 inline static S1Angle E7(int32 e7);
36
37 // Convenience functions -- to use when args have been fixed32s in protos.
38 //
39 // The arguments are static_cast into int32, so very large unsigned values
40 // are treated as negative numbers.
41 inline static S1Angle UnsignedE6(uint32 e6);
42 inline static S1Angle UnsignedE7(uint32 e7);
43
44 // The default constructor yields a zero angle. This is useful for STL
45 // containers and class methods with output arguments.
46 inline S1Angle() : radians_(0) {}
47
48 // Return the angle between two points, which is also equal to the distance
49 // between these points on the unit sphere. The points do not need to be
50 // normalized.
51 S1Angle(S2Point const& x, S2Point const& y);
52
53 // Like the constructor above, but return the angle (i.e., distance)
54 // between two S2LatLng points.
55 S1Angle(S2LatLng const& x, S2LatLng const& y);
56
57 double radians() const { return radians_; }
58 double degrees() const { return radians_ * (180 / M_PI); }
59
60 int32 e5() const { return MathUtil::FastIntRound(degrees() * 1e5); }
61 int32 e6() const { return MathUtil::FastIntRound(degrees() * 1e6); }
62 int32 e7() const { return MathUtil::FastIntRound(degrees() * 1e7); }
63
64 // Return the absolute value of an angle.
65 S1Angle abs() const { return S1Angle(fabs(radians_)); }
66
67 // Comparison operators.
68 friend inline bool operator==(S1Angle const& x, S1Angle const& y);
69 friend inline bool operator!=(S1Angle const& x, S1Angle const& y);
70 friend inline bool operator<(S1Angle const& x, S1Angle const& y);
71 friend inline bool operator>(S1Angle const& x, S1Angle const& y);
72 friend inline bool operator<=(S1Angle const& x, S1Angle const& y);
73 friend inline bool operator>=(S1Angle const& x, S1Angle const& y);
74
75 // Simple arithmetic operators for manipulating S1Angles.
76 friend inline S1Angle operator-(S1Angle const& a);
77 friend inline S1Angle operator+(S1Angle const& a, S1Angle const& b);
78 friend inline S1Angle operator-(S1Angle const& a, S1Angle const& b);
79 friend inline S1Angle operator*(double m, S1Angle const& a);
80 friend inline S1Angle operator*(S1Angle const& a, double m);
81 friend inline S1Angle operator/(S1Angle const& a, double m);
82 friend inline double operator/(S1Angle const& a, S1Angle const& b);
83 inline S1Angle& operator+=(S1Angle const& a);
84 inline S1Angle& operator-=(S1Angle const& a);
85 inline S1Angle& operator*=(double m);
86 inline S1Angle& operator/=(double m);
87
88 // Return the angle normalized to the range (-180, 180] degrees.
89 S1Angle Normalized() const;
90
91 // Normalize this angle to the range (-180, 180] degrees.
92 void Normalize();
93
94 private:
95 explicit S1Angle(double radians) : radians_(radians) {}
96 double radians_;
97};
98DECLARE_POD(S1Angle);
99
100inline bool operator==(S1Angle const& x, S1Angle const& y) {
101 return x.radians() == y.radians();
102}
103
104inline bool operator!=(S1Angle const& x, S1Angle const& y) {
105 return x.radians() != y.radians();
106}
107
108inline bool operator<(S1Angle const& x, S1Angle const& y) {
109 return x.radians() < y.radians();
110}
111
112inline bool operator>(S1Angle const& x, S1Angle const& y) {
113 return x.radians() > y.radians();
114}
115
116inline bool operator<=(S1Angle const& x, S1Angle const& y) {
117 return x.radians() <= y.radians();
118}
119
120inline bool operator>=(S1Angle const& x, S1Angle const& y) {
121 return x.radians() >= y.radians();
122}
123
124inline S1Angle operator-(S1Angle const& a) {
125 return S1Angle::Radians(-a.radians());
126}
127
128inline S1Angle operator+(S1Angle const& a, S1Angle const& b) {
129 return S1Angle::Radians(a.radians() + b.radians());
130}
131
132inline S1Angle operator-(S1Angle const& a, S1Angle const& b) {
133 return S1Angle::Radians(a.radians() - b.radians());
134}
135
136inline S1Angle operator*(double m, S1Angle const& a) {
137 return S1Angle::Radians(m * a.radians());
138}
139
140inline S1Angle operator*(S1Angle const& a, double m) {
141 return S1Angle::Radians(m * a.radians());
142}
143
144inline S1Angle operator/(S1Angle const& a, double m) {
145 return S1Angle::Radians(a.radians() / m);
146}
147
148inline double operator/(S1Angle const& a, S1Angle const& b) {
149 return a.radians() / b.radians();
150}
151
152inline S1Angle& S1Angle::operator+=(S1Angle const& a) {
153 radians_ += a.radians();
154 return *this;
155}
156
157inline S1Angle& S1Angle::operator-=(S1Angle const& a) {
158 radians_ -= a.radians();
159 return *this;
160}
161
162inline S1Angle& S1Angle::operator*=(double m) {
163 radians_ *= m;
164 return *this;
165}
166
167inline S1Angle& S1Angle::operator/=(double m) {
168 radians_ /= m;
169 return *this;
170}
171
172inline S1Angle S1Angle::Radians(double radians) {
173 return S1Angle(radians);
174}
175
176inline S1Angle S1Angle::Degrees(double degrees) {
177 return S1Angle(degrees * (M_PI / 180));
178}
179
180inline S1Angle S1Angle::E5(int32 e5) {
181 // Multiplying by 1e-5 isn't quite as accurate as dividing by 1e5,
182 // but it's about 10 times faster and more than accurate enough.
183 return Degrees(e5 * 1e-5);
184}
185
186inline S1Angle S1Angle::E6(int32 e6) {
187 return Degrees(e6 * 1e-6);
188}
189
190inline S1Angle S1Angle::E7(int32 e7) {
191 return Degrees(e7 * 1e-7);
192}
193
194inline S1Angle S1Angle::UnsignedE6(uint32 e6) {
195 return Degrees(static_cast<int32>(e6) * 1e-6);
196}
197
198inline S1Angle S1Angle::UnsignedE7(uint32 e7) {
199 return Degrees(static_cast<int32>(e7) * 1e-7);
200}
201
202// Writes the angle in degrees with 7 digits of precision after the
203// decimal point, e.g. "17.3745904".
204ostream& operator<<(ostream& os, S1Angle const& a);
205
206#endif // UTIL_GEOMETRY_S1ANGLE_H_
207