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>
7using 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.
23class 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};
117DECLARE_POD(S2LatLng);
118
119inline S2LatLng::S2LatLng(S1Angle const& lat, S1Angle const& lng)
120 : coords_(lat.radians(), lng.radians()) {}
121
122inline S2LatLng::S2LatLng() : coords_(0, 0) {}
123
124inline S2LatLng S2LatLng::FromRadians(double lat_radians, double lng_radians) {
125 return S2LatLng(lat_radians, lng_radians);
126}
127
128inline S2LatLng S2LatLng::FromDegrees(double lat_degrees, double lng_degrees) {
129 return S2LatLng(S1Angle::Degrees(lat_degrees), S1Angle::Degrees(lng_degrees));
130}
131
132inline S2LatLng S2LatLng::FromE5(int32 lat_e5, int32 lng_e5) {
133 return S2LatLng(S1Angle::E5(lat_e5), S1Angle::E5(lng_e5));
134}
135
136inline S2LatLng S2LatLng::FromE6(int32 lat_e6, int32 lng_e6) {
137 return S2LatLng(S1Angle::E6(lat_e6), S1Angle::E6(lng_e6));
138}
139
140inline S2LatLng S2LatLng::FromE7(int32 lat_e7, int32 lng_e7) {
141 return S2LatLng(S1Angle::E7(lat_e7), S1Angle::E7(lng_e7));
142}
143
144inline S2LatLng S2LatLng::FromUnsignedE6(uint32 lat_e6, uint32 lng_e6) {
145 return S2LatLng(S1Angle::UnsignedE6(lat_e6), S1Angle::UnsignedE6(lng_e6));
146}
147
148inline S2LatLng S2LatLng::FromUnsignedE7(uint32 lat_e7, uint32 lng_e7) {
149 return S2LatLng(S1Angle::UnsignedE7(lat_e7), S1Angle::UnsignedE7(lng_e7));
150}
151
152inline S2LatLng S2LatLng::Invalid() {
153 // These coordinates are outside the bounds allowed by is_valid().
154 return S2LatLng(M_PI, 2 * M_PI);
155}
156
157inline 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
163inline 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
168inline bool S2LatLng::is_valid() const {
169 return fabs(lat().radians()) <= M_PI_2 && fabs(lng().radians()) <= M_PI;
170}
171
172inline S2LatLng operator+(S2LatLng const& a, S2LatLng const& b) {
173 return S2LatLng(a.coords_ + b.coords_);
174}
175
176inline S2LatLng operator-(S2LatLng const& a, S2LatLng const& b) {
177 return S2LatLng(a.coords_ - b.coords_);
178}
179
180inline S2LatLng operator*(double m, S2LatLng const& a) {
181 return S2LatLng(m * a.coords_);
182}
183
184inline S2LatLng operator*(S2LatLng const& a, double m) {
185 return S2LatLng(m * a.coords_);
186}
187
188ostream& operator<<(ostream& os, S2LatLng const& ll);
189
190#endif // UTIL_GEOMETRY_S2LATLNG_H__
191