static S2RegionCoverer() { for (var face = 0; face < 6; ++face) { FaceCells[face] = S2Cell.FromFacePosLevel(face, (byte)0, 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); } } } } }
/** * 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)); }
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)); }
/** * 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(); }
/** * 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); }
/** * 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); }
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); }
/** * 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); }
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)); }
/** * 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)); }
// ////////////////////////////////////////////////////////////////////// // 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); }
/** * 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"); }
public bool Contains(S2Cell cell) { return(Contains(cell.Id)); }
/** This is a fast operation (logarithmic in the size of the cell union). */ public bool MayIntersect(S2Cell cell) { return(Intersects(cell.Id)); }