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 #include "s2/s2latlng_rect_bounder.h"
19
20 #include <cfloat>
21 #include <cmath>
22
23 #include "s2/base/logging.h"
24 #include "s2/r1interval.h"
25 #include "s2/s1chord_angle.h"
26 #include "s2/s1interval.h"
27 #include "s2/s2pointutil.h"
28
29 using std::fabs;
30 using std::max;
31 using std::min;
32
AddPoint(const S2Point & b)33 void S2LatLngRectBounder::AddPoint(const S2Point& b) {
34 S2_DCHECK(S2::IsUnitLength(b));
35 AddInternal(b, S2LatLng(b));
36 }
37
AddLatLng(const S2LatLng & b_latlng)38 void S2LatLngRectBounder::AddLatLng(const S2LatLng& b_latlng) {
39 AddInternal(b_latlng.ToPoint(), b_latlng);
40 }
41
AddInternal(const S2Point & b,const S2LatLng & b_latlng)42 void S2LatLngRectBounder::AddInternal(const S2Point& b,
43 const S2LatLng& b_latlng) {
44 // Simple consistency check to verify that b and b_latlng are alternate
45 // representations of the same vertex.
46 S2_DCHECK(S2::ApproxEquals(b, b_latlng.ToPoint()));
47
48 if (bound_.is_empty()) {
49 bound_.AddPoint(b_latlng);
50 } else {
51 // First compute the cross product N = A x B robustly. This is the normal
52 // to the great circle through A and B. We don't use S2::RobustCrossProd()
53 // since that method returns an arbitrary vector orthogonal to A if the two
54 // vectors are proportional, and we want the zero vector in that case.
55 Vector3_d n = (a_ - b).CrossProd(a_ + b); // N = 2 * (A x B)
56
57 // The relative error in N gets large as its norm gets very small (i.e.,
58 // when the two points are nearly identical or antipodal). We handle this
59 // by choosing a maximum allowable error, and if the error is greater than
60 // this we fall back to a different technique. Since it turns out that
61 // the other sources of error in converting the normal to a maximum
62 // latitude add up to at most 1.16 * DBL_EPSILON (see below), and it is
63 // desirable to have the total error be a multiple of DBL_EPSILON, we have
64 // chosen to limit the maximum error in the normal to 3.84 * DBL_EPSILON.
65 // It is possible to show that the error is less than this when
66 //
67 // n.Norm() >= 8 * sqrt(3) / (3.84 - 0.5 - sqrt(3)) * DBL_EPSILON
68 // = 1.91346e-15 (about 8.618 * DBL_EPSILON)
69 double n_norm = n.Norm();
70 if (n_norm < 1.91346e-15) {
71 // A and B are either nearly identical or nearly antipodal (to within
72 // 4.309 * DBL_EPSILON, or about 6 nanometers on the earth's surface).
73 if (a_.DotProd(b) < 0) {
74 // The two points are nearly antipodal. The easiest solution is to
75 // assume that the edge between A and B could go in any direction
76 // around the sphere.
77 bound_ = S2LatLngRect::Full();
78 } else {
79 // The two points are nearly identical (to within 4.309 * DBL_EPSILON).
80 // In this case we can just use the bounding rectangle of the points,
81 // since after the expansion done by GetBound() this rectangle is
82 // guaranteed to include the (lat,lng) values of all points along AB.
83 bound_ = bound_.Union(S2LatLngRect::FromPointPair(a_latlng_, b_latlng));
84 }
85 } else {
86 // Compute the longitude range spanned by AB.
87 S1Interval lng_ab = S1Interval::FromPointPair(a_latlng_.lng().radians(),
88 b_latlng.lng().radians());
89 if (lng_ab.GetLength() >= M_PI - 2 * DBL_EPSILON) {
90 // The points lie on nearly opposite lines of longitude to within the
91 // maximum error of the calculation. (Note that this test relies on
92 // the fact that M_PI is slightly less than the true value of Pi, and
93 // that representable values near M_PI are 2 * DBL_EPSILON apart.)
94 // The easiest solution is to assume that AB could go on either side
95 // of the pole.
96 lng_ab = S1Interval::Full();
97 }
98
99 // Next we compute the latitude range spanned by the edge AB. We start
100 // with the range spanning the two endpoints of the edge:
101 R1Interval lat_ab = R1Interval::FromPointPair(a_latlng_.lat().radians(),
102 b_latlng.lat().radians());
103
104 // This is the desired range unless the edge AB crosses the plane
105 // through N and the Z-axis (which is where the great circle through A
106 // and B attains its minimum and maximum latitudes). To test whether AB
107 // crosses this plane, we compute a vector M perpendicular to this
108 // plane and then project A and B onto it.
109 Vector3_d m = n.CrossProd(S2Point(0, 0, 1));
110 double m_a = m.DotProd(a_);
111 double m_b = m.DotProd(b);
112
113 // We want to test the signs of "m_a" and "m_b", so we need to bound
114 // the error in these calculations. It is possible to show that the
115 // total error is bounded by
116 //
117 // (1 + sqrt(3)) * DBL_EPSILON * n_norm + 8 * sqrt(3) * (DBL_EPSILON**2)
118 // = 6.06638e-16 * n_norm + 6.83174e-31
119
120 double m_error = 6.06638e-16 * n_norm + 6.83174e-31;
121 if (m_a * m_b < 0 || fabs(m_a) <= m_error || fabs(m_b) <= m_error) {
122 // Minimum/maximum latitude *may* occur in the edge interior.
123 //
124 // The maximum latitude is 90 degrees minus the latitude of N. We
125 // compute this directly using atan2 in order to get maximum accuracy
126 // near the poles.
127 //
128 // Our goal is compute a bound that contains the computed latitudes of
129 // all S2Points P that pass the point-in-polygon containment test.
130 // There are three sources of error we need to consider:
131 // - the directional error in N (at most 3.84 * DBL_EPSILON)
132 // - converting N to a maximum latitude
133 // - computing the latitude of the test point P
134 // The latter two sources of error are at most 0.955 * DBL_EPSILON
135 // individually, but it is possible to show by a more complex analysis
136 // that together they can add up to at most 1.16 * DBL_EPSILON, for a
137 // total error of 5 * DBL_EPSILON.
138 //
139 // We add 3 * DBL_EPSILON to the bound here, and GetBound() will pad
140 // the bound by another 2 * DBL_EPSILON.
141 double max_lat = min(
142 atan2(sqrt(n[0]*n[0] + n[1]*n[1]), fabs(n[2])) + 3 * DBL_EPSILON,
143 M_PI_2);
144
145 // In order to get tight bounds when the two points are close together,
146 // we also bound the min/max latitude relative to the latitudes of the
147 // endpoints A and B. First we compute the distance between A and B,
148 // and then we compute the maximum change in latitude between any two
149 // points along the great circle that are separated by this distance.
150 // This gives us a latitude change "budget". Some of this budget must
151 // be spent getting from A to B; the remainder bounds the round-trip
152 // distance (in latitude) from A or B to the min or max latitude
153 // attained along the edge AB.
154 double lat_budget = 2 * asin(0.5 * (a_ - b).Norm() * sin(max_lat));
155 double max_delta = 0.5*(lat_budget - lat_ab.GetLength()) + DBL_EPSILON;
156
157 // Test whether AB passes through the point of maximum latitude or
158 // minimum latitude. If the dot product(s) are small enough then the
159 // result may be ambiguous.
160 if (m_a <= m_error && m_b >= -m_error) {
161 lat_ab.set_hi(min(max_lat, lat_ab.hi() + max_delta));
162 }
163 if (m_b <= m_error && m_a >= -m_error) {
164 lat_ab.set_lo(max(-max_lat, lat_ab.lo() - max_delta));
165 }
166 }
167 bound_ = bound_.Union(S2LatLngRect(lat_ab, lng_ab));
168 }
169 }
170 a_ = b;
171 a_latlng_ = b_latlng;
172 }
173
GetBound() const174 S2LatLngRect S2LatLngRectBounder::GetBound() const {
175 // To save time, we ignore numerical errors in the computed S2LatLngs while
176 // accumulating the bounds and then account for them here.
177 //
178 // S2LatLng(S2Point) has a maximum error of 0.955 * DBL_EPSILON in latitude.
179 // In the worst case, we might have rounded "inwards" when computing the
180 // bound and "outwards" when computing the latitude of a contained point P,
181 // therefore we expand the latitude bounds by 2 * DBL_EPSILON in each
182 // direction. (A more complex analysis shows that 1.5 * DBL_EPSILON is
183 // enough, but the expansion amount should be a multiple of DBL_EPSILON in
184 // order to avoid rounding errors during the expansion itself.)
185 //
186 // S2LatLng(S2Point) has a maximum error of DBL_EPSILON in longitude, which
187 // is simply the maximum rounding error for results in the range [-Pi, Pi].
188 // This is true because the Gnu implementation of atan2() comes from the IBM
189 // Accurate Mathematical Library, which implements correct rounding for this
190 // instrinsic (i.e., it returns the infinite precision result rounded to the
191 // nearest representable value, with ties rounded to even values). This
192 // implies that we don't need to expand the longitude bounds at all, since
193 // we only guarantee that the bound contains the *rounded* latitudes of
194 // contained points. The *true* latitudes of contained points may lie up to
195 // DBL_EPSILON outside of the returned bound.
196
197 const S2LatLng kExpansion = S2LatLng::FromRadians(2 * DBL_EPSILON, 0);
198 return bound_.Expanded(kExpansion).PolarClosure();
199 }
200
ExpandForSubregions(const S2LatLngRect & bound)201 S2LatLngRect S2LatLngRectBounder::ExpandForSubregions(
202 const S2LatLngRect& bound) {
203 // Empty bounds don't need expansion.
204 if (bound.is_empty()) return bound;
205
206 // First we need to check whether the bound B contains any nearly-antipodal
207 // points (to within 4.309 * DBL_EPSILON). If so then we need to return
208 // S2LatLngRect::Full(), since the subregion might have an edge between two
209 // such points, and AddPoint() returns Full() for such edges. Note that
210 // this can happen even if B is not Full(); for example, consider a loop
211 // that defines a 10km strip straddling the equator extending from
212 // longitudes -100 to +100 degrees.
213 //
214 // It is easy to check whether B contains any antipodal points, but checking
215 // for nearly-antipodal points is trickier. Essentially we consider the
216 // original bound B and its reflection through the origin B', and then test
217 // whether the minimum distance between B and B' is less than 4.309 *
218 // DBL_EPSILON.
219
220 // "lng_gap" is a lower bound on the longitudinal distance between B and its
221 // reflection B'. (2.5 * DBL_EPSILON is the maximum combined error of the
222 // endpoint longitude calculations and the GetLength() call.)
223 double lng_gap = max(0.0, M_PI - bound.lng().GetLength() - 2.5 * DBL_EPSILON);
224
225 // "min_abs_lat" is the minimum distance from B to the equator (if zero or
226 // negative, then B straddles the equator).
227 double min_abs_lat = max(bound.lat().lo(), -bound.lat().hi());
228
229 // "lat_gap1" and "lat_gap2" measure the minimum distance from B to the
230 // south and north poles respectively.
231 double lat_gap1 = M_PI_2 + bound.lat().lo();
232 double lat_gap2 = M_PI_2 - bound.lat().hi();
233
234 if (min_abs_lat >= 0) {
235 // The bound B does not straddle the equator. In this case the minimum
236 // distance is between one endpoint of the latitude edge in B closest to
237 // the equator and the other endpoint of that edge in B'. The latitude
238 // distance between these two points is 2*min_abs_lat, and the longitude
239 // distance is lng_gap. We could compute the distance exactly using the
240 // Haversine formula, but then we would need to bound the errors in that
241 // calculation. Since we only need accuracy when the distance is very
242 // small (close to 4.309 * DBL_EPSILON), we substitute the Euclidean
243 // distance instead. This gives us a right triangle XYZ with two edges of
244 // length x = 2*min_abs_lat and y ~= lng_gap. The desired distance is the
245 // length of the third edge "z", and we have
246 //
247 // z ~= sqrt(x^2 + y^2) >= (x + y) / sqrt(2)
248 //
249 // Therefore the region may contain nearly antipodal points only if
250 //
251 // 2*min_abs_lat + lng_gap < sqrt(2) * 4.309 * DBL_EPSILON
252 // ~= 1.354e-15
253 //
254 // Note that because the given bound B is conservative, "min_abs_lat" and
255 // "lng_gap" are both lower bounds on their true values so we do not need
256 // to make any adjustments for their errors.
257 if (2 * min_abs_lat + lng_gap < 1.354e-15) {
258 return S2LatLngRect::Full();
259 }
260 } else if (lng_gap >= M_PI_2) {
261 // B spans at most Pi/2 in longitude. The minimum distance is always
262 // between one corner of B and the diagonally opposite corner of B'. We
263 // use the same distance approximation that we used above; in this case
264 // we have an obtuse triangle XYZ with two edges of length x = lat_gap1
265 // and y = lat_gap2, and angle Z >= Pi/2 between them. We then have
266 //
267 // z >= sqrt(x^2 + y^2) >= (x + y) / sqrt(2)
268 //
269 // Unlike the case above, "lat_gap1" and "lat_gap2" are not lower bounds
270 // (because of the extra addition operation, and because M_PI_2 is not
271 // exactly equal to Pi/2); they can exceed their true values by up to
272 // 0.75 * DBL_EPSILON. Putting this all together, the region may
273 // contain nearly antipodal points only if
274 //
275 // lat_gap1 + lat_gap2 < (sqrt(2) * 4.309 + 1.5) * DBL_EPSILON
276 // ~= 1.687e-15
277 if (lat_gap1 + lat_gap2 < 1.687e-15) {
278 return S2LatLngRect::Full();
279 }
280 } else {
281 // Otherwise we know that (1) the bound straddles the equator and (2) its
282 // width in longitude is at least Pi/2. In this case the minimum
283 // distance can occur either between a corner of B and the diagonally
284 // opposite corner of B' (as in the case above), or between a corner of B
285 // and the opposite longitudinal edge reflected in B'. It is sufficient
286 // to only consider the corner-edge case, since this distance is also a
287 // lower bound on the corner-corner distance when that case applies.
288
289 // Consider the spherical triangle XYZ where X is a corner of B with
290 // minimum absolute latitude, Y is the closest pole to X, and Z is the
291 // point closest to X on the opposite longitudinal edge of B'. This is a
292 // right triangle (Z = Pi/2), and from the spherical law of sines we have
293 //
294 // sin(z) / sin(Z) = sin(y) / sin(Y)
295 // sin(max_lat_gap) / 1 = sin(d_min) / sin(lng_gap)
296 // sin(d_min) = sin(max_lat_gap) * sin(lng_gap)
297 //
298 // where "max_lat_gap" = max(lat_gap1, lat_gap2) and "d_min" is the
299 // desired minimum distance. Now using the facts that sin(t) >= (2/Pi)*t
300 // for 0 <= t <= Pi/2, that we only need an accurate approximation when
301 // at least one of "max_lat_gap" or "lng_gap" is extremely small (in
302 // which case sin(t) ~= t), and recalling that "max_lat_gap" has an error
303 // of up to 0.75 * DBL_EPSILON, we want to test whether
304 //
305 // max_lat_gap * lng_gap < (4.309 + 0.75) * (Pi/2) * DBL_EPSILON
306 // ~= 1.765e-15
307 if (max(lat_gap1, lat_gap2) * lng_gap < 1.765e-15) {
308 return S2LatLngRect::Full();
309 }
310 }
311 // Next we need to check whether the subregion might contain any edges that
312 // span (M_PI - 2 * DBL_EPSILON) radians or more in longitude, since AddPoint
313 // sets the longitude bound to Full() in that case. This corresponds to
314 // testing whether (lng_gap <= 0) in "lng_expansion" below.
315
316 // Otherwise, the maximum latitude error in AddPoint is 4.8 * DBL_EPSILON.
317 // In the worst case, the errors when computing the latitude bound for a
318 // subregion could go in the opposite direction as the errors when computing
319 // the bound for the original region, so we need to double this value.
320 // (More analysis shows that it's okay to round down to a multiple of
321 // DBL_EPSILON.)
322 //
323 // For longitude, we rely on the fact that atan2 is correctly rounded and
324 // therefore no additional bounds expansion is necessary.
325
326 double lat_expansion = 9 * DBL_EPSILON;
327 double lng_expansion = (lng_gap <= 0) ? M_PI : 0;
328 return bound.Expanded(S2LatLng::FromRadians(lat_expansion,
329 lng_expansion)).PolarClosure();
330 }
331
MaxErrorForTests()332 S2LatLng S2LatLngRectBounder::MaxErrorForTests() {
333 // The maximum error in the latitude calculation is
334 // 3.84 * DBL_EPSILON for the RobustCrossProd calculation
335 // 0.96 * DBL_EPSILON for the Latitude() calculation
336 // 5 * DBL_EPSILON added by AddPoint/GetBound to compensate for error
337 // ------------------
338 // 9.80 * DBL_EPSILON maximum error in result
339 //
340 // The maximum error in the longitude calculation is DBL_EPSILON. GetBound
341 // does not do any expansion because this isn't necessary in order to
342 // bound the *rounded* longitudes of contained points.
343 return S2LatLng::FromRadians(10 * DBL_EPSILON, 1 * DBL_EPSILON);
344 }
345