예제 #1
0
        /**
         * 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));
        }
        /**
         *  Indexing structure to efficiently clipEdge() of a polygon. This is an
         * abstract class because we need to use if for both polygons (for
         * initToIntersection() and friends) and for sets of lists of points (for
         * initToSimplified()).
         *
         *  Usage -- in your subclass, create an array of vertex counts for each loop
         * in the loop sequence and pass it to this constructor. Overwrite
         * edgeFromTo(), calling decodeIndex() and use the resulting two indices to
         * access your accessing vertices.
         */

        private static void AddIntersection(S2Point a0,
                                            S2Point a1,
                                            S2Point b0,
                                            S2Point b1,
                                            bool addSharedEdges,
                                            int crossing, System.Collections.Generic.ICollection <ParametrizedS2Point> intersections)
        {
            if (crossing > 0)
            {
                // There is a proper edge crossing.
                var x = S2EdgeUtil.GetIntersection(a0, a1, b0, b1);
                var t = S2EdgeUtil.GetDistanceFraction(x, a0, a1);
                intersections.Add(new ParametrizedS2Point(t, x));
            }
            else if (S2EdgeUtil.VertexCrossing(a0, a1, b0, b1))
            {
                // There is a crossing at one of the vertices. The basic rule is simple:
                // if a0 equals one of the "b" vertices, the crossing occurs at t=0;
                // otherwise, it occurs at t=1.
                //
                // This has the effect that when two symmetric edges are encountered (an
                // edge an its reverse), neither one is included in the output. When two
                // duplicate edges are encountered, both are included in the output. The
                // "addSharedEdges" flag allows one of these two copies to be removed by
                // changing its intersection parameter from 0 to 1.
                double t = (a0 == b0 || a0 == b1) ? 0 : 1;
                if (!addSharedEdges && a1 == b1)
                {
                    t = 1;
                }
                intersections.Add(new ParametrizedS2Point(t, t == 0 ? a0 : a1));
            }
        }
        // S2Region interface (see {@code S2Region} for details):

        /** Return a bounding spherical cap. */

        /**
         * Given a point, returns the index of the start point of the (first) edge on
         * the polyline that is closest to the given point. The polyline must have at
         * least one vertex. Throws IllegalStateException if this is not the case.
         */

        public int GetNearestEdgeIndex(S2Point point)
        {
            Preconditions.CheckState(NumVertices > 0, "Empty polyline");

            if (NumVertices == 1)
            {
                // If there is only one vertex, the "edge" is trivial, and it's the only one
                return(0);
            }

            // Initial value larger than any possible distance on the unit sphere.
            var minDistance = S1Angle.FromRadians(10);
            var minIndex    = -1;

            // Find the line segment in the polyline that is closest to the point given.
            for (var i = 0; i < NumVertices - 1; ++i)
            {
                var distanceToSegment = S2EdgeUtil.GetDistance(point, Vertex(i), Vertex(i + 1));
                if (distanceToSegment < minDistance)
                {
                    minDistance = distanceToSegment;
                    minIndex    = i;
                }
            }
            return(minIndex);
        }
        /**
         * Given a point p and the index of the start point of an edge of this polyline,
         * returns the point on that edge that is closest to p.
         */

        public S2Point ProjectToEdge(S2Point point, int index)
        {
            Preconditions.CheckState(NumVertices > 0, "Empty polyline");
            Preconditions.CheckState(NumVertices == 1 || index < NumVertices - 1, "Invalid edge index");
            if (NumVertices == 1)
            {
                // If there is only one vertex, it is always closest to any given point.
                return(Vertex(0));
            }
            return(S2EdgeUtil.GetClosestPoint(point, Vertex(index), Vertex(index + 1)));
        }
예제 #5
0
        /**
         * Returns the shortest distance from a point P to this loop, given as the
         * angle formed between P, the origin and the nearest point on the loop to P.
         * This angle in radians is equivalent to the arclength along the unit sphere.
         */

        public S1Angle GetDistance(S2Point p)
        {
            var normalized = S2Point.Normalize(p);

            // The furthest point from p on the sphere is its antipode, which is an
            // angle of PI radians. This is an upper bound on the angle.
            var minDistance = S1Angle.FromRadians(Math.PI);

            for (var i = 0; i < NumVertices; i++)
            {
                minDistance =
                    S1Angle.Min(minDistance, S2EdgeUtil.GetDistance(normalized, Vertex(i), Vertex(i + 1)));
            }
            return(minDistance);
        }
예제 #6
0
        /**
         * This method is equivalent to the S2EdgeUtil.edgeOrVertexCrossing() method
         * defined below. It is similar to robustCrossing, but handles cases where
         * two vertices are identical in a way that makes it easy to implement
         * point-in-polygon containment tests.
         */

        public bool EdgeOrVertexCrossing(S2Point d)
        {
            // We need to copy c since it is clobbered by robustCrossing().
            var c2 = new S2Point(c[0], c[1], c[2]);

            var crossing = RobustCrossing(d);

            if (crossing < 0)
            {
                return(false);
            }
            if (crossing > 0)
            {
                return(true);
            }

            return(S2EdgeUtil.VertexCrossing(a, b, c2, d));
        }
예제 #7
0
        /**
         * Return the minimum distance (measured along the surface of the sphere) to
         * the given S2LatLngRect. Both S2LatLngRects must be non-empty.
         */

        public S1Angle GetDistance(S2LatLngRect other)
        {
            var a = this;
            var b = other;

            Preconditions.CheckState(!a.IsEmpty);
            Preconditions.CheckArgument(!b.IsEmpty);

            // First, handle the trivial cases where the longitude intervals overlap.
            if (a.Lng.Intersects(b.Lng))
            {
                if (a.Lat.Intersects(b.Lat))
                {
                    return(S1Angle.FromRadians(0)); // Intersection between a and b.
                }

                // We found an overlap in the longitude interval, but not in the latitude
                // interval. This means the shortest path travels along some line of
                // longitude connecting the high-latitude of the lower rect with the
                // low-latitude of the higher rect.
                S1Angle lo, hi;
                if (a.Lat.Lo > b.Lat.Hi)
                {
                    lo = b.LatHi;
                    hi = a.LatLo;
                }
                else
                {
                    lo = a.LatHi;
                    hi = b.LatLo;
                }
                return(S1Angle.FromRadians(hi.Radians - lo.Radians));
            }

            // The longitude intervals don't overlap. In this case, the closest points
            // occur somewhere on the pair of longitudinal edges which are nearest in
            // longitude-space.
            S1Angle aLng, bLng;
            var     loHi = S1Interval.FromPointPair(a.Lng.Lo, b.Lng.Hi);
            var     hiLo = S1Interval.FromPointPair(a.Lng.Hi, b.Lng.Lo);

            if (loHi.Length < hiLo.Length)
            {
                aLng = a.LngLo;
                bLng = b.LngHi;
            }
            else
            {
                aLng = a.LngHi;
                bLng = b.LngLo;
            }

            // The shortest distance between the two longitudinal segments will include
            // at least one segment endpoint. We could probably narrow this down further
            // to a single point-edge distance by comparing the relative latitudes of the
            // endpoints, but for the sake of clarity, we'll do all four point-edge
            // distance tests.
            var aLo        = new S2LatLng(a.LatLo, aLng).ToPoint();
            var aHi        = new S2LatLng(a.LatHi, aLng).ToPoint();
            var aLoCrossHi =
                S2LatLng.FromRadians(0, aLng.Radians - S2.PiOver2).Normalized.ToPoint();
            var bLo        = new S2LatLng(b.LatLo, bLng).ToPoint();
            var bHi        = new S2LatLng(b.LatHi, bLng).ToPoint();
            var bLoCrossHi =
                S2LatLng.FromRadians(0, bLng.Radians - S2.PiOver2).Normalized.ToPoint();

            return(S1Angle.Min(S2EdgeUtil.GetDistance(aLo, bLo, bHi, bLoCrossHi),
                               S1Angle.Min(S2EdgeUtil.GetDistance(aHi, bLo, bHi, bLoCrossHi),
                                           S1Angle.Min(S2EdgeUtil.GetDistance(bLo, aLo, aHi, aLoCrossHi),
                                                       S2EdgeUtil.GetDistance(bHi, aLo, aHi, aLoCrossHi)))));
        }