1 | // Copyright 2005 Google Inc. All Rights Reserved. |
2 | |
3 | #ifndef UTIL_GEOMETRY_S2LATLNG_H__ |
4 | #define UTIL_GEOMETRY_S2LATLNG_H__ |
5 | |
6 | #include <string> |
7 | using std::string; |
8 | |
9 | #include <ostream> |
10 | #include "base/basictypes.h" |
11 | #include "s1angle.h" |
12 | #include "s2.h" |
13 | #include "util/math/vector2-inl.h" |
14 | |
15 | // This class represents a point on the unit sphere as a pair |
16 | // of latitude-longitude coordinates. Like the rest of the "geometry" |
17 | // package, the intent is to represent spherical geometry as a mathematical |
18 | // abstraction, so functions that are specifically related to the Earth's |
19 | // geometry (e.g. easting/northing conversions) should be put elsewhere. |
20 | // |
21 | // This class is intended to be copied by value as desired. It uses |
22 | // the default copy constructor and assignment operator. |
23 | class S2LatLng { |
24 | public: |
25 | // Constructor. The latitude and longitude are allowed to be outside |
26 | // the is_valid() range. However, note that most methods that accept |
27 | // S2LatLngs expect them to be normalized (see Normalized() below). |
28 | inline S2LatLng(S1Angle const& lat, S1Angle const& lng); |
29 | |
30 | // The default constructor sets the latitude and longitude to zero. This is |
31 | // mainly useful when declaring arrays, STL containers, etc. |
32 | inline S2LatLng(); |
33 | |
34 | // Convert a direction vector (not necessarily unit length) to an S2LatLng. |
35 | explicit S2LatLng(S2Point const& p); |
36 | |
37 | // Returns an S2LatLng for which is_valid() will return false. |
38 | inline static S2LatLng Invalid(); |
39 | |
40 | // Convenience functions -- shorter than calling S1Angle::Radians(), etc. |
41 | inline static S2LatLng FromRadians(double lat_radians, double lng_radians); |
42 | inline static S2LatLng FromDegrees(double lat_degrees, double lng_degrees); |
43 | inline static S2LatLng FromE5(int32 lat_e5, int32 lng_e5); |
44 | inline static S2LatLng FromE6(int32 lat_e6, int32 lng_e6); |
45 | inline static S2LatLng FromE7(int32 lat_e7, int32 lng_e7); |
46 | |
47 | // Convenience functions -- to use when args have been fixed32s in protos. |
48 | // |
49 | // The arguments are static_cast into int32, so very large unsigned values |
50 | // are treated as negative numbers. |
51 | inline static S2LatLng FromUnsignedE6(uint32 lat_e6, uint32 lng_e6); |
52 | inline static S2LatLng FromUnsignedE7(uint32 lat_e7, uint32 lng_e7); |
53 | |
54 | // Methods to compute the latitude and longitude of a point separately. |
55 | inline static S1Angle Latitude(S2Point const& p); |
56 | inline static S1Angle Longitude(S2Point const& p); |
57 | |
58 | // Accessor methods. |
59 | S1Angle lat() const { return S1Angle::Radians(coords_[0]); } |
60 | S1Angle lng() const { return S1Angle::Radians(coords_[1]); } |
61 | Vector2_d const& coords() const { return coords_; } |
62 | |
63 | // Return true if the latitude is between -90 and 90 degrees inclusive |
64 | // and the longitude is between -180 and 180 degrees inclusive. |
65 | inline bool is_valid() const; |
66 | |
67 | // Clamps the latitude to the range [-90, 90] degrees, and adds or subtracts |
68 | // a multiple of 360 degrees to the longitude if necessary to reduce it to |
69 | // the range [-180, 180]. |
70 | S2LatLng Normalized() const; |
71 | |
72 | // Convert a normalized S2LatLng to the equivalent unit-length vector. |
73 | S2Point ToPoint() const; |
74 | |
75 | // Return the distance (measured along the surface of the sphere) to the |
76 | // given S2LatLng. This is mathematically equivalent to: |
77 | // |
78 | // S1Angle::Radians(ToPoint().Angle(o.ToPoint())) |
79 | // |
80 | // but this implementation is slightly more efficient. Both S2LatLngs |
81 | // must be normalized. |
82 | S1Angle GetDistance(S2LatLng const& o) const; |
83 | |
84 | // Simple arithmetic operations for manipulating latitude-longitude pairs. |
85 | // The results are not normalized (see Normalized()). |
86 | friend inline S2LatLng operator+(S2LatLng const& a, S2LatLng const& b); |
87 | friend inline S2LatLng operator-(S2LatLng const& a, S2LatLng const& b); |
88 | friend inline S2LatLng operator*(double m, S2LatLng const& a); |
89 | friend inline S2LatLng operator*(S2LatLng const& a, double m); |
90 | |
91 | bool operator==(S2LatLng const& o) const { return coords_ == o.coords_; } |
92 | bool operator!=(S2LatLng const& o) const { return coords_ != o.coords_; } |
93 | bool operator<(S2LatLng const& o) const { return coords_ < o.coords_; } |
94 | bool operator>(S2LatLng const& o) const { return coords_ > o.coords_; } |
95 | bool operator<=(S2LatLng const& o) const { return coords_ <= o.coords_; } |
96 | bool operator>=(S2LatLng const& o) const { return coords_ >= o.coords_; } |
97 | |
98 | bool ApproxEquals(S2LatLng const& o, double max_error = 1e-15) const { |
99 | return coords_.aequal(o.coords_, max_error); |
100 | } |
101 | |
102 | // Export the latitude and longitude in degrees, separated by a comma. |
103 | // e.g. "94.518000,150.300000" |
104 | string ToStringInDegrees() const; |
105 | void ToStringInDegrees(string* s) const; |
106 | |
107 | private: |
108 | // Internal constructor. |
109 | inline S2LatLng(Vector2_d const& coords) : coords_(coords) {} |
110 | |
111 | // This is internal to avoid ambiguity about which units are expected. |
112 | inline S2LatLng(double lat_radians, double lng_radians) |
113 | : coords_(lat_radians, lng_radians) {} |
114 | |
115 | Vector2_d coords_; |
116 | }; |
117 | DECLARE_POD(S2LatLng); |
118 | |
119 | inline S2LatLng::S2LatLng(S1Angle const& lat, S1Angle const& lng) |
120 | : coords_(lat.radians(), lng.radians()) {} |
121 | |
122 | inline S2LatLng::S2LatLng() : coords_(0, 0) {} |
123 | |
124 | inline S2LatLng S2LatLng::FromRadians(double lat_radians, double lng_radians) { |
125 | return S2LatLng(lat_radians, lng_radians); |
126 | } |
127 | |
128 | inline S2LatLng S2LatLng::FromDegrees(double lat_degrees, double lng_degrees) { |
129 | return S2LatLng(S1Angle::Degrees(lat_degrees), S1Angle::Degrees(lng_degrees)); |
130 | } |
131 | |
132 | inline S2LatLng S2LatLng::FromE5(int32 lat_e5, int32 lng_e5) { |
133 | return S2LatLng(S1Angle::E5(lat_e5), S1Angle::E5(lng_e5)); |
134 | } |
135 | |
136 | inline S2LatLng S2LatLng::FromE6(int32 lat_e6, int32 lng_e6) { |
137 | return S2LatLng(S1Angle::E6(lat_e6), S1Angle::E6(lng_e6)); |
138 | } |
139 | |
140 | inline S2LatLng S2LatLng::FromE7(int32 lat_e7, int32 lng_e7) { |
141 | return S2LatLng(S1Angle::E7(lat_e7), S1Angle::E7(lng_e7)); |
142 | } |
143 | |
144 | inline S2LatLng S2LatLng::FromUnsignedE6(uint32 lat_e6, uint32 lng_e6) { |
145 | return S2LatLng(S1Angle::UnsignedE6(lat_e6), S1Angle::UnsignedE6(lng_e6)); |
146 | } |
147 | |
148 | inline S2LatLng S2LatLng::FromUnsignedE7(uint32 lat_e7, uint32 lng_e7) { |
149 | return S2LatLng(S1Angle::UnsignedE7(lat_e7), S1Angle::UnsignedE7(lng_e7)); |
150 | } |
151 | |
152 | inline S2LatLng S2LatLng::Invalid() { |
153 | // These coordinates are outside the bounds allowed by is_valid(). |
154 | return S2LatLng(M_PI, 2 * M_PI); |
155 | } |
156 | |
157 | inline S1Angle S2LatLng::Latitude(S2Point const& p) { |
158 | // We use atan2 rather than asin because the input vector is not necessarily |
159 | // unit length, and atan2 is much more accurate than asin near the poles. |
160 | return S1Angle::Radians(atan2(p[2], sqrt(p[0]*p[0] + p[1]*p[1]))); |
161 | } |
162 | |
163 | inline S1Angle S2LatLng::Longitude(S2Point const& p) { |
164 | // Note that atan2(0, 0) is defined to be zero. |
165 | return S1Angle::Radians(atan2(p[1], p[0])); |
166 | } |
167 | |
168 | inline bool S2LatLng::is_valid() const { |
169 | return fabs(lat().radians()) <= M_PI_2 && fabs(lng().radians()) <= M_PI; |
170 | } |
171 | |
172 | inline S2LatLng operator+(S2LatLng const& a, S2LatLng const& b) { |
173 | return S2LatLng(a.coords_ + b.coords_); |
174 | } |
175 | |
176 | inline S2LatLng operator-(S2LatLng const& a, S2LatLng const& b) { |
177 | return S2LatLng(a.coords_ - b.coords_); |
178 | } |
179 | |
180 | inline S2LatLng operator*(double m, S2LatLng const& a) { |
181 | return S2LatLng(m * a.coords_); |
182 | } |
183 | |
184 | inline S2LatLng operator*(S2LatLng const& a, double m) { |
185 | return S2LatLng(m * a.coords_); |
186 | } |
187 | |
188 | ostream& operator<<(ostream& os, S2LatLng const& ll); |
189 | |
190 | #endif // UTIL_GEOMETRY_S2LATLNG_H__ |
191 | |