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