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 // The earth modeled as a sphere.  There are lots of convenience
19 // functions so that it doesn't take 2 lines of code just to do
20 // a single conversion.
21 
22 #ifndef S2_S2EARTH_H_
23 #define S2_S2EARTH_H_
24 
25 #include "s2/s1angle.h"
26 #include "s2/s1chord_angle.h"
27 #include "s2/s2latlng.h"
28 #include "s2/s2point.h"
29 #include "s2/util/units/length-units.h"
30 
31 class S2Earth {
32  public:
33   // These functions convert between distances on the unit sphere
34   // (expressed as angles subtended from the sphere's center) and
35   // distances on the Earth's surface.  This is possible only because
36   // the Earth is modeled as a sphere; otherwise a given angle would
37   // correspond to a range of distances depending on where the
38   // corresponding line segment was located.
39   //
40   // Note that you will lose precision if you use the ToDistance() method,
41   // since Meters is a single-precision type.  If you need more precision,
42   // use one of the direct conversion methods below.
43   inline static S1Angle ToAngle(const util::units::Meters& distance);
44   inline static S1ChordAngle ToChordAngle(const util::units::Meters& distance);
45   inline static util::units::Meters ToDistance(const S1Angle& angle);
46   inline static util::units::Meters ToDistance(const S1ChordAngle& cangle);
47 
48   // Convenience functions.  These methods also return a double-precision
49   // result, unlike the generic ToDistance() method.
50   inline static double ToRadians(const util::units::Meters& distance);
51   inline static double ToMeters(const S1Angle& angle);
52   inline static double ToMeters(const S1ChordAngle& cangle);
53   inline static double ToKm(const S1Angle& angle);
54   inline static double ToKm(const S1ChordAngle& cangle);
55   inline static double KmToRadians(double km);
56   inline static double RadiansToKm(double radians);
57   inline static double MetersToRadians(double meters);
58   inline static double RadiansToMeters(double radians);
59 
60   // These functions convert between areas on the unit sphere
61   // (as returned by the S2 library) and areas on the Earth's surface.
62   // Note that the area of a region on the unit sphere is equal to the
63   // solid angle it subtends from the sphere's center (measured in steradians).
64   inline static double SquareKmToSteradians(double km2);
65   inline static double SquareMetersToSteradians(double m2);
66   inline static double SteradiansToSquareKm(double steradians);
67   inline static double SteradiansToSquareMeters(double steradians);
68 
69   // Convenience function for the frequent case where you need to call
70   // ToRadians in order to convert an east-west distance on the globe to
71   // radians. The output is a function of how close to the poles you are
72   // (i.e. at the bulge at the equator, one unit of longitude represents a
73   // much farther distance). The function will never return more than 2*PI
74   // radians, even if you're trying to go 100 million miles west at the north
75   // pole.
76   static double ToLongitudeRadians(const util::units::Meters& distance,
77                                    double latitude_radians);
78 
79   // Computes the initial bearing from a to b. This is the bearing an observer
80   // at point a has when facing point b. A bearing of 0 degrees is north, and it
81   // increases clockwise (90 degrees is east, etc).
82   // If a == b, a == -b, or a is one of the Earths' poles, the return value is
83   // undefined.
84   static S1Angle GetInitialBearing(const S2LatLng& a, const S2LatLng& b);
85 
86   // Returns the distance between two points.  Example:
87   // double miles = Miles(geostore::S2Earth::GetDistance(a, b)).value();
88   //
89   // Note that these methods only have single-precision accuracy, since
90   // Meters is a single-precision type.  If you ned more precision, use one
91   // of the methods below.
92   inline static util::units::Meters GetDistance(const S2Point& a,
93                                                 const S2Point& b);
94   inline static util::units::Meters GetDistance(const S2LatLng& a,
95                                                 const S2LatLng& b);
96 
97   // Convenience functions.  These methods also return a double-precision
98   // result, unlike the generic GetDistance() method.
99   inline static double GetDistanceKm(const S2Point& a, const S2Point& b);
100   inline static double GetDistanceKm(const S2LatLng& a, const S2LatLng& b);
101   inline static double GetDistanceMeters(const S2Point& a, const S2Point& b);
102   inline static double GetDistanceMeters(const S2LatLng& a, const S2LatLng& b);
103 
104   // Returns the Earth's mean radius, which is the radius of the equivalent
105   // sphere with the same surface area.  According to NASA, this value is
106   // 6371.01 +/- 0.02 km.  The equatorial radius is 6378.136 km, and the polar
107   // radius is 6356.752 km.  They differ by one part in 298.257.
108   //
109   // Reference: http://ssd.jpl.nasa.gov/phys_props_earth.html, which quotes
110   // Yoder, C.F. 1995. "Astrometric and Geodetic Properties of Earth and the
111   // Solar System" in Global Earth Physics, A Handbook of Physical Constants,
112   // AGU Reference Shelf 1, American Geophysical Union, Table 2.
113   inline static util::units::Meters Radius();
114 
115   // Convenience functions.
116   inline static double RadiusKm();
117   inline static double RadiusMeters();
118 
119   // Returns the altitude of the lowest known point on Earth. The lowest known
120   // point on Earth is the Challenger Deep with an altitude of -10898 meters
121   // above the surface of the spherical earth.
122   inline static util::units::Meters LowestAltitude();
123 
124   // Convenience functions.
125   inline static double LowestAltitudeKm();
126   inline static double LowestAltitudeMeters();
127 
128   // Returns the altitude of the highest known point on Earth. The highest
129   // known point on Earth is Mount Everest with an altitude of 8846 meters
130   // above the surface of the spherical earth.
131   inline static util::units::Meters HighestAltitude();
132 
133   // Convenience functions.
134   inline static double HighestAltitudeKm();
135   inline static double HighestAltitudeMeters();
136 };
137 
ToAngle(const util::units::Meters & distance)138 inline S1Angle S2Earth::ToAngle(const util::units::Meters& distance) {
139   return S1Angle::Radians(ToRadians(distance));
140 }
141 
ToChordAngle(const util::units::Meters & distance)142 inline S1ChordAngle S2Earth::ToChordAngle(const util::units::Meters& distance) {
143   return S1ChordAngle(ToAngle(distance));
144 }
145 
ToDistance(const S1Angle & angle)146 inline util::units::Meters S2Earth::ToDistance(const S1Angle& angle) {
147   return util::units::Meters(ToMeters(angle));
148 }
149 
ToDistance(const S1ChordAngle & cangle)150 inline util::units::Meters S2Earth::ToDistance(const S1ChordAngle& cangle) {
151   return util::units::Meters(ToMeters(cangle));
152 }
153 
ToRadians(const util::units::Meters & distance)154 inline double S2Earth::ToRadians(const util::units::Meters& distance) {
155   return distance.value() / RadiusMeters();
156 }
157 
ToMeters(const S1Angle & angle)158 inline double S2Earth::ToMeters(const S1Angle& angle) {
159   return angle.radians() * RadiusMeters();
160 }
161 
ToKm(const S1Angle & angle)162 inline double S2Earth::ToKm(const S1Angle& angle) {
163   return angle.radians() * RadiusKm();
164 }
165 
ToMeters(const S1ChordAngle & cangle)166 inline double S2Earth::ToMeters(const S1ChordAngle& cangle) {
167   return ToMeters(cangle.ToAngle());
168 }
169 
ToKm(const S1ChordAngle & cangle)170 inline double S2Earth::ToKm(const S1ChordAngle& cangle) {
171   return ToKm(cangle.ToAngle());
172 }
173 
KmToRadians(double km)174 inline double S2Earth::KmToRadians(double km) {
175   return km / RadiusKm();
176 }
177 
RadiansToKm(double radians)178 inline double S2Earth::RadiansToKm(double radians) {
179   return radians * RadiusKm();
180 }
181 
MetersToRadians(double meters)182 inline double S2Earth::MetersToRadians(double meters) {
183   return meters / RadiusMeters();
184 }
185 
RadiansToMeters(double radians)186 inline double S2Earth::RadiansToMeters(double radians) {
187   return radians * RadiusMeters();
188 }
189 
SquareKmToSteradians(double km2)190 inline double S2Earth::SquareKmToSteradians(double km2) {
191   return km2 / (RadiusKm() * RadiusKm());
192 }
193 
SquareMetersToSteradians(double m2)194 inline double S2Earth::SquareMetersToSteradians(double m2) {
195   return m2 / (RadiusMeters() * RadiusMeters());
196 }
197 
SteradiansToSquareKm(double steradians)198 inline double S2Earth::SteradiansToSquareKm(double steradians) {
199   return steradians * RadiusKm() * RadiusKm();
200 }
201 
SteradiansToSquareMeters(double steradians)202 inline double S2Earth::SteradiansToSquareMeters(double steradians) {
203   return steradians * RadiusMeters() * RadiusMeters();
204 }
205 
GetDistance(const S2Point & a,const S2Point & b)206 inline util::units::Meters S2Earth::GetDistance(const S2Point& a,
207                                                 const S2Point& b) {
208   return ToDistance(S1Angle(a, b));
209 }
210 
GetDistance(const S2LatLng & a,const S2LatLng & b)211 inline util::units::Meters S2Earth::GetDistance(const S2LatLng& a,
212                                                 const S2LatLng& b) {
213   return ToDistance(a.GetDistance(b));
214 }
215 
GetDistanceKm(const S2Point & a,const S2Point & b)216 inline double S2Earth::GetDistanceKm(const S2Point& a, const S2Point& b) {
217   return RadiansToKm(a.Angle(b));
218 }
219 
GetDistanceKm(const S2LatLng & a,const S2LatLng & b)220 inline double S2Earth::GetDistanceKm(const S2LatLng& a, const S2LatLng& b) {
221   return ToKm(a.GetDistance(b));
222 }
223 
GetDistanceMeters(const S2Point & a,const S2Point & b)224 inline double S2Earth::GetDistanceMeters(const S2Point& a, const S2Point& b) {
225   return RadiansToMeters(a.Angle(b));
226 }
227 
GetDistanceMeters(const S2LatLng & a,const S2LatLng & b)228 inline double S2Earth::GetDistanceMeters(const S2LatLng& a, const S2LatLng& b) {
229   return ToMeters(a.GetDistance(b));
230 }
231 
Radius()232 inline util::units::Meters S2Earth::Radius() {
233   return util::units::Meters(RadiusMeters());
234 }
235 
RadiusKm()236 inline double S2Earth::RadiusKm() {
237   return 0.001 * RadiusMeters();
238 }
239 
RadiusMeters()240 inline double S2Earth::RadiusMeters() {
241   return 6371010.0;
242 }
243 
LowestAltitude()244 inline util::units::Meters S2Earth::LowestAltitude() {
245   return util::units::Meters(LowestAltitudeMeters());
246 }
247 
LowestAltitudeKm()248 inline double S2Earth::LowestAltitudeKm() {
249   return 0.001 * LowestAltitudeMeters();
250 }
251 
LowestAltitudeMeters()252 inline double S2Earth::LowestAltitudeMeters() {
253   return -10898;
254 }
255 
HighestAltitude()256 inline util::units::Meters S2Earth::HighestAltitude() {
257   return util::units::Meters(HighestAltitudeMeters());
258 }
259 
HighestAltitudeKm()260 inline double S2Earth::HighestAltitudeKm() {
261   return 0.001 * HighestAltitudeMeters();
262 }
263 
HighestAltitudeMeters()264 inline double S2Earth::HighestAltitudeMeters() {
265   return 8846;
266 }
267 
268 #endif  // S2_S2EARTH_H_
269