예제 #1
0
 static S2RegionCoverer()
 {
     for (var face = 0; face < 6; ++face)
     {
         FaceCells[face] = S2Cell.FromFacePosLevel(face, (byte)0, 0);
     }
 }
예제 #2
0
        /**
         * Populate the children of "candidate" by expanding the given number of
         * levels from the given cell. Returns the number of children that were marked
         * "terminal".
         */

        private int ExpandChildren(Candidate candidate, S2Cell cell, int numLevels)
        {
            numLevels--;
            var childCells = new S2Cell[4];

            for (var i = 0; i < 4; ++i)
            {
                childCells[i] = new S2Cell();
            }
            cell.Subdivide(childCells);
            var numTerminals = 0;

            for (var i = 0; i < 4; ++i)
            {
                if (numLevels > 0)
                {
                    if (_region.MayIntersect(childCells[i]))
                    {
                        numTerminals += ExpandChildren(candidate, childCells[i], numLevels);
                    }
                    continue;
                }
                var child = NewCandidate(childCells[i]);
                if (child != null)
                {
                    candidate.Children[candidate.NumChildren++] = child;
                    if (child.IsTerminal)
                    {
                        ++numTerminals;
                    }
                }
            }
            return(numTerminals);
        }
        /**
         * Appends to candidateCrossings the edges that are fully contained in an S2
         * covering of edge. The covering of edge used is initially cover, but is
         * refined to eliminate quickly subcells that contain many edges but do not
         * intersect with edge.
         */

        private void GetEdgesInChildrenCells(S2Point a, S2Point b, IList <S2CellId> cover,
                                             ISet <int> candidateCrossings)
        {
            // Put all edge references of (covering cells + descendant cells) into
            // result.
            // This relies on the natural ordering of S2CellIds.
            S2Cell[] children = null;
            while (cover.Any())
            {
                var cell = cover[cover.Count - 1];
                cover.RemoveAt(cover.Count - 1);
                var bounds = GetEdges(cell.RangeMin.Id, cell.RangeMax.Id);
                if (bounds[1] - bounds[0] <= 16)
                {
                    for (var i = bounds[0]; i < bounds[1]; i++)
                    {
                        candidateCrossings.Add(_edges[i]);
                    }
                }
                else
                {
                    // Add cells at this level
                    bounds = GetEdges(cell.Id, cell.Id);
                    for (var i = bounds[0]; i < bounds[1]; i++)
                    {
                        candidateCrossings.Add(_edges[i]);
                    }
                    // Recurse on the children -- hopefully some will be empty.
                    if (children == null)
                    {
                        children = new S2Cell[4];
                        for (var i = 0; i < 4; ++i)
                        {
                            children[i] = new S2Cell();
                        }
                    }
                    new S2Cell(cell).Subdivide(children);
                    foreach (var child in children)
                    {
                        // TODO(user): Do the check for the four cells at once,
                        // as it is enough to check the four edges between the cells. At
                        // this time, we are checking 16 edges, 4 times too many.
                        //
                        // Note that given the guarantee of AppendCovering, it is enough
                        // to check that the edge intersect with the cell boundary as it
                        // cannot be fully contained in a cell.
                        if (EdgeIntersectsCellBoundary(a, b, child))
                        {
                            cover.Add(child.Id);
                        }
                    }
                }
            }
        }
예제 #4
0
        /**
         * If this method returns false, the region does not intersect the given cell.
         * Otherwise, either region intersects the cell, or the intersection
         * relationship could not be determined.
         */

        public bool MayIntersect(S2Cell cell)
        {
            // It is faster to construct a bounding rectangle for an S2Cell than for
            // a general polygon. A future optimization could also take advantage of
            // the fact than an S2Cell is convex.

            var cellBound = cell.RectBound;

            if (!_bound.Intersects(cellBound))
            {
                return(false);
            }
            return(new S2Loop(cell, cellBound).Intersects(this));
        }
예제 #5
0
        public bool MayIntersect(S2Cell cell)
        {
            // If the cap contains any cell vertex, return true.
            var vertices = new S2Point[4];

            for (var k = 0; k < 4; ++k)
            {
                vertices[k] = cell.GetVertex(k);
                if (Contains(vertices[k]))
                {
                    return(true);
                }
            }
            return(Intersects(cell, vertices));
        }
예제 #6
0
        /**
         * Like the constructor above, but assumes that the cell's bounding rectangle
         * has been precomputed.
         *
         * @param cell
         * @param bound
         */

        public S2Loop(S2Cell cell, S2LatLngRect bound)
        {
            _bound         = bound;
            _numVertices   = 4;
            _vertices      = new S2Point[_numVertices];
            _vertexToIndex = null;
            _index         = null;
            _depth         = 0;
            for (var i = 0; i < 4; ++i)
            {
                _vertices[i] = cell.GetVertex(i);
            }
            InitOrigin();
            InitFirstLogicalVertex();
        }
예제 #7
0
        /**
         * If this method returns true, the region completely contains the given cell.
         * Otherwise, either the region does not contain the cell or the containment
         * relationship could not be determined.
         */

        public bool Contains(S2Cell cell)
        {
            // It is faster to construct a bounding rectangle for an S2Cell than for
            // a general polygon. A future optimization could also take advantage of
            // the fact than an S2Cell is convex.

            var cellBound = cell.RectBound;

            if (!_bound.Contains(cellBound))
            {
                return(false);
            }
            var cellLoop = new S2Loop(cell, cellBound);

            return(Contains(cellLoop));
        }
        /**
         * If this method returns false, the region does not intersect the given cell.
         * Otherwise, either region intersects the cell, or the intersection
         * relationship could not be determined.
         */

        public bool MayIntersect(S2Cell cell)
        {
            if (NumLoops == 1)
            {
                return(Loop(0).MayIntersect(cell));
            }
            var cellBound = cell.RectBound;

            if (!_bound.Intersects(cellBound))
            {
                return(false);
            }

            var cellLoop = new S2Loop(cell, cellBound);
            var cellPoly = new S2Polygon(cellLoop);

            return(Intersects(cellPoly));
        }
        /**
         * If this method returns true, the region completely contains the given cell.
         * Otherwise, either the region does not contain the cell or the containment
         * relationship could not be determined.
         */

        public bool Contains(S2Cell cell)
        {
            if (NumLoops == 1)
            {
                return(Loop(0).Contains(cell));
            }
            var cellBound = cell.RectBound;

            if (!_bound.Contains(cellBound))
            {
                return(false);
            }

            var cellLoop = new S2Loop(cell, cellBound);
            var cellPoly = new S2Polygon(cellLoop);

            return(Contains(cellPoly));
        }
        /**
         * Returns true if the edge and the cell (including boundary) intersect.
         */

        private static bool EdgeIntersectsCellBoundary(S2Point a, S2Point b, S2Cell cell)
        {
            var vertices = new S2Point[4];

            for (var i = 0; i < 4; ++i)
            {
                vertices[i] = cell.GetVertex(i);
            }
            for (var i = 0; i < 4; ++i)
            {
                var fromPoint = vertices[i];
                var toPoint   = vertices[(i + 1) % 4];
                if (LenientCrossing(a, b, fromPoint, toPoint))
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #11
0
        /**
         * If the cell intersects the given region, return a new candidate with no
         * children, otherwise return null. Also marks the candidate as "terminal" if
         * it should not be expanded further.
         */

        private Candidate NewCandidate(S2Cell cell)
        {
            if (!_region.MayIntersect(cell))
            {
                return(null);
            }

            var isTerminal = false;

            if (cell.Level >= _minLevel)
            {
                if (_interiorCovering)
                {
                    if (_region.Contains(cell))
                    {
                        isTerminal = true;
                    }
                    else if (cell.Level + _levelMod > _maxLevel)
                    {
                        return(null);
                    }
                }
                else
                {
                    if (cell.Level + _levelMod > _maxLevel || _region.Contains(cell))
                    {
                        isTerminal = true;
                    }
                }
            }
            var candidate = new Candidate();

            candidate.Cell       = cell;
            candidate.IsTerminal = isTerminal;
            if (!isTerminal)
            {
                candidate.Children = new Candidate[1 << MaxChildrenShift];
            }
            _candidatesCreatedCounter++;
            return(candidate);
        }
예제 #12
0
        public bool Contains(S2Cell cell)
        {
            // If the cap does not contain all cell vertices, return false.
            // We check the vertices before taking the Complement() because we can't
            // accurately represent the complement of a very small cap (a height
            // of 2-epsilon is rounded off to 2).
            var vertices = new S2Point[4];

            for (var k = 0; k < 4; ++k)
            {
                vertices[k] = cell.GetVertex(k);
                if (!Contains(vertices[k]))
                {
                    return(false);
                }
            }
            // Otherwise, return true if the complement of the cap does not intersect
            // the cell. (This test is slightly conservative, because technically we
            // want Complement().InteriorIntersects() here.)
            return(!Complement.Intersects(cell, vertices));
        }
        /**
         * If this method returns false, the region does not intersect the given cell.
         * Otherwise, either region intersects the cell, or the intersection
         * relationship could not be determined.
         */

        public bool MayIntersect(S2Cell cell)
        {
            if (NumVertices == 0)
            {
                return(false);
            }

            // We only need to check whether the cell contains vertex 0 for correctness,
            // but these tests are cheap compared to edge crossings so we might as well
            // check all the vertices.
            for (var i = 0; i < NumVertices; ++i)
            {
                if (cell.Contains(Vertex(i)))
                {
                    return(true);
                }
            }
            var cellVertices = new S2Point[4];

            for (var i = 0; i < 4; ++i)
            {
                cellVertices[i] = cell.GetVertex(i);
            }
            for (var j = 0; j < 4; ++j)
            {
                var crosser =
                    new EdgeCrosser(cellVertices[j], cellVertices[(j + 1) & 3], Vertex(0));
                for (var i = 1; i < NumVertices; ++i)
                {
                    if (crosser.RobustCrossing(Vertex(i)) >= 0)
                    {
                        // There is a proper crossing, or two vertices were the same.
                        return(true);
                    }
                }
            }
            return(false);
        }
예제 #14
0
        /**
         * Returns true if this rectangle intersects the given cell. (This is an exact
         * test and may be fairly expensive, see also MayIntersect below.)
         */

        public bool Intersects(S2Cell cell)
        {
            // First we eliminate the cases where one region completely contains the
            // other. Once these are disposed of, then the regions will intersect
            // if and only if their boundaries intersect.

            if (IsEmpty)
            {
                return(false);
            }
            if (Contains(cell.Center))
            {
                return(true);
            }
            if (cell.Contains(Center.ToPoint()))
            {
                return(true);
            }

            // Quick rejection test (not required for correctness).
            if (!Intersects(cell.RectBound))
            {
                return(false);
            }

            // Now check whether the boundaries intersect. Unfortunately, a
            // latitude-longitude rectangle does not have straight edges -- two edges
            // are curved, and at least one of them is concave.

            // Precompute the cell vertices as points and latitude-longitudes.
            var cellV  = new S2Point[4];
            var cellLl = new S2LatLng[4];

            for (var i = 0; i < 4; ++i)
            {
                cellV[i]  = cell.GetVertex(i); // Must be normalized.
                cellLl[i] = new S2LatLng(cellV[i]);
                if (Contains(cellLl[i]))
                {
                    return(true); // Quick acceptance test.
                }
            }

            for (var i = 0; i < 4; ++i)
            {
                var edgeLng = S1Interval.FromPointPair(
                    cellLl[i].Lng.Radians, cellLl[(i + 1) & 3].Lng.Radians);
                if (!_lng.Intersects(edgeLng))
                {
                    continue;
                }

                var a = cellV[i];
                var b = cellV[(i + 1) & 3];
                if (edgeLng.Contains(_lng.Lo))
                {
                    if (IntersectsLngEdge(a, b, _lat, _lng.Lo))
                    {
                        return(true);
                    }
                }
                if (edgeLng.Contains(_lng.Hi))
                {
                    if (IntersectsLngEdge(a, b, _lat, _lng.Hi))
                    {
                        return(true);
                    }
                }
                if (IntersectsLatEdge(a, b, _lat.Lo, _lng))
                {
                    return(true);
                }
                if (IntersectsLatEdge(a, b, _lat.Hi, _lng))
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #15
0
 public bool Contains(S2Cell cell)
 {
     // A latitude-longitude rectangle contains a cell if and only if it contains
     // the cell's bounding rectangle. (This is an exact test.)
     return(Contains(cell.RectBound));
 }
예제 #16
0
        /**
         * This test is cheap but is NOT exact. Use Intersects() if you want a more
         * accurate and more expensive test. Note that when this method is used by an
         * S2RegionCoverer, the accuracy isn't all that important since if a cell may
         * intersect the region then it is subdivided, and the accuracy of this method
         * goes up as the cells get smaller.
         */

        public bool MayIntersect(S2Cell cell)
        {
            // This test is cheap but is NOT exact (see s2latlngrect.h).
            return(Intersects(cell.RectBound));
        }
예제 #17
0
        // //////////////////////////////////////////////////////////////////////
        // S2Region interface (see {@code S2Region} for details):

        /**
         * Return true if the cap intersects 'cell', given that the cap vertices have
         * alrady been checked.
         */

        public bool Intersects(S2Cell cell, IReadOnlyList <S2Point> vertices)
        {
            // Return true if this cap intersects any point of 'cell' excluding its
            // vertices (which are assumed to already have been checked).

            // If the cap is a hemisphere or larger, the cell and the complement of the
            // cap are both convex. Therefore since no vertex of the cell is contained,
            // no other interior point of the cell is contained either.
            if (_height >= 1)
            {
                return(false);
            }

            // We need to check for empty caps due to the axis check just below.
            if (IsEmpty)
            {
                return(false);
            }

            // Optimization: return true if the cell contains the cap axis. (This
            // allows half of the edge checks below to be skipped.)
            if (cell.Contains(_axis))
            {
                return(true);
            }

            // At this point we know that the cell does not contain the cap axis,
            // and the cap does not contain any cell vertex. The only way that they
            // can intersect is if the cap intersects the interior of some edge.

            var sin2Angle = _height * (2 - _height); // sin^2(capAngle)

            for (var k = 0; k < 4; ++k)
            {
                var edge = cell.GetEdgeRaw(k);
                var dot  = _axis.DotProd(edge);
                if (dot > 0)
                {
                    // The axis is in the interior half-space defined by the edge. We don't
                    // need to consider these edges, since if the cap intersects this edge
                    // then it also intersects the edge on the opposite side of the cell
                    // (because we know the axis is not contained with the cell).
                    continue;
                }
                // The Norm2() factor is necessary because "edge" is not normalized.
                if (dot * dot > sin2Angle * edge.Norm2)
                {
                    return(false); // Entire cap is on the exterior side of this edge.
                }
                // Otherwise, the great circle containing this edge intersects
                // the interior of the cap. We just need to check whether the point
                // of closest approach occurs between the two edge endpoints.
                var dir = S2Point.CrossProd(edge, _axis);
                if (dir.DotProd(vertices[k]) < 0 &&
                    dir.DotProd(vertices[(k + 1) & 3]) > 0)
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #18
0
        /**
         * Initialize a loop corresponding to the given cell.
         */

        public S2Loop(S2Cell cell) : this(cell, cell.RectBound)
        {
        }
        /**
         * If this method returns true, the region completely contains the given cell.
         * Otherwise, either the region does not contain the cell or the containment
         * relationship could not be determined.
         */

        public bool Contains(S2Cell cell)
        {
            throw new NotSupportedException(
                      "'containment' is not numerically well-defined " + "except at the polyline vertices");
        }
예제 #20
0
 public bool Contains(S2Cell cell)
 {
     return(Contains(cell.Id));
 }
예제 #21
0
        /** This is a fast operation (logarithmic in the size of the cell union). */

        public bool MayIntersect(S2Cell cell)
        {
            return(Intersects(cell.Id));
        }