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