/** * Return the center of the rectangle in latitude-longitude space (in general * this is not the center of the region on the sphere). */ /** * Return the minimum distance (measured along the surface of the sphere) * from a given point to the rectangle (both its boundary and its interior). * The latLng must be valid. */ public S1Angle GetDistance(S2LatLng p) { // The algorithm here is the same as in getDistance(S2LagLngRect), only // with simplified calculations. var a = this; Preconditions.CheckState(!a.IsEmpty); Preconditions.CheckArgument(p.IsValid); if (a.Lng.Contains(p.Lng.Radians)) { return(S1Angle.FromRadians(Math.Max(0.0, Math.Max(p.Lat.Radians - a.Lat.Hi, a.Lat.Lo - p.Lat.Radians)))); } var interval = new S1Interval(a.Lng.Hi, a.Lng.Complement.Center); var aLng = a.Lng.Lo; if (interval.Contains(p.Lng.Radians)) { aLng = a.Lng.Hi; } var lo = S2LatLng.FromRadians(a.Lat.Lo, aLng).ToPoint(); var hi = S2LatLng.FromRadians(a.Lat.Hi, aLng).ToPoint(); var loCrossHi = S2LatLng.FromRadians(0, aLng - S2.PiOver2).Normalized.ToPoint(); return(S2EdgeUtil.GetDistance(p.ToPoint(), lo, hi, loCrossHi)); }
/** * Return true if the edge AB intersects the given edge of constant latitude. */ private static bool IntersectsLatEdge(S2Point a, S2Point b, double lat, S1Interval lng) { // Return true if the segment AB intersects the given edge of constant // latitude. Unfortunately, lines of constant latitude are curves on // the sphere. They can intersect a straight edge in 0, 1, or 2 points. // assert (S2.isUnitLength(a) && S2.isUnitLength(b)); // First, compute the normal to the plane AB that points vaguely north. var z = S2Point.Normalize(S2.RobustCrossProd(a, b)); if (z.Z < 0) { z = -z; } // Extend this to an orthonormal frame (x,y,z) where x is the direction // where the great circle through AB achieves its maximium latitude. var y = S2Point.Normalize(S2.RobustCrossProd(z, new S2Point(0, 0, 1))); var x = S2Point.CrossProd(y, z); // assert (S2.isUnitLength(x) && x.z >= 0); // Compute the angle "theta" from the x-axis (in the x-y plane defined // above) where the great circle intersects the given line of latitude. var sinLat = Math.Sin(lat); if (Math.Abs(sinLat) >= x.Z) { return(false); // The great circle does not reach the given latitude. } // assert (x.z > 0); var cosTheta = sinLat / x.Z; var sinTheta = Math.Sqrt(1 - cosTheta * cosTheta); var theta = Math.Atan2(sinTheta, cosTheta); // The candidate intersection points are located +/- theta in the x-y // plane. For an intersection to be valid, we need to check that the // intersection point is contained in the interior of the edge AB and // also that it is contained within the given longitude interval "lng". // Compute the range of theta values spanned by the edge AB. var abTheta = S1Interval.FromPointPair(Math.Atan2( a.DotProd(y), a.DotProd(x)), Math.Atan2(b.DotProd(y), b.DotProd(x))); if (abTheta.Contains(theta)) { // Check if the intersection point is also in the given "lng" interval. var isect = (x * cosTheta) + (y * sinTheta); if (lng.Contains(Math.Atan2(isect.Y, isect.X))) { return(true); } } if (abTheta.Contains(-theta)) { // Check if the intersection point is also in the given "lng" interval. var intersection = (x * cosTheta) - (y * sinTheta); if (lng.Contains(Math.Atan2(intersection.Y, intersection.X))) { return(true); } } return(false); }
/** * Return the width and height of this rectangle in latitude-longitude space. * Empty rectangles have a negative width and height. */ /** * More efficient version of Contains() that accepts a S2LatLng rather than an * S2Point. */ public bool Contains(S2LatLng ll) { // assert (ll.isValid()); return(_lat.Contains(ll.Lat.Radians) && _lng.Contains(ll.Lng.Radians)); }