public List <Guid> Search(double lon, double lat, int radius) { var latlng = S2LatLng.FromDegrees(lat, lon); var centerPoint = pointFromLatLng(lat, lon); var centerAngle = ((double)radius) / EarthRadiusM; var cap = S2Cap.FromAxisAngle(centerPoint, S1Angle.FromRadians(centerAngle)); var regionCoverer = new S2RegionCoverer(); regionCoverer.MaxLevel = 13; // regionCoverer.MinLevel = 13; //regionCoverer.MaxCells = 1000; // regionCoverer.LevelMod = 0; var covering = regionCoverer.GetCovering(cap); var res = new List <Guid>(); foreach (var u in covering) { var sell = new S2CellId(u.Id); if (sell.Level < _level) { var begin = sell.ChildBeginForLevel(_level); var end = sell.ChildEndForLevel(_level); do { var cur = tree.Search(new S2CellId(begin.Id)); if (cur != null) { res.AddRange(cur.Pointer); } begin = begin.Next; } while (begin.Id != end.Id); } else { var item = tree.Search(sell); if (item != null) { res.AddRange(item.Pointer); } } } return(res); }
public List <Guid> Search(double lon, double lat, int radius) { var latlng = S2LatLng.FromDegrees(lat, lon); var centerPoint = Index.pointFromLatLng(lat, lon); var centerAngle = ((double)radius) / Index.EarthRadiusM; var cap = S2Cap.FromAxisAngle(centerPoint, S1Angle.FromRadians(centerAngle)); var regionCoverer = new S2RegionCoverer(); regionCoverer.MaxLevel = 13; // regionCoverer.MinLevel = 13; //regionCoverer.MaxCells = 1000; // regionCoverer.LevelMod = 0; var covering = regionCoverer.GetCovering(cap); var res = new List <Guid>(); foreach (var u in covering) { var sell = new S2CellId(u.Id); if (sell.Level < _level) { var begin = sell.ChildBeginForLevel(_level); var end = sell.ChildEndForLevel(_level); var qres = rtree.Query(new Range <S2CellId>(begin, end)); foreach (var r in qres) { res.AddRange(r.Content); } } else { var qres = rtree.Query(new Range <S2CellId>(sell)); if (qres.Count > 0) { foreach (var r in qres) { res.AddRange(r.Content); } } } } return(res); }
/* * Generates "numEdges" random edges, of length at most "edgeLengthMetersMax" * and each of whose center is in a randomly located cap with radius * "capSpanMeters", and puts results into "edges". */ private void generateRandomEarthEdges( double edgeLengthMetersMax, double capSpanMeters, int numEdges, List <S2Edge> edges) { var cap = S2Cap.FromAxisAngle( randomPoint(), S1Angle.FromRadians(capSpanMeters / S2LatLng.EarthRadiusMeters)); for (var i = 0; i < numEdges; ++i) { edges.Add(randomEdgeCrossingCap(edgeLengthMetersMax, cap)); } }
/** * Generates a random edge whose center is in the given cap. */ private S2Edge randomEdgeCrossingCap(double maxLengthMeters, S2Cap cap) { // Pick the edge center at random. var edgeCenter = samplePoint(cap); // Pick two random points in a suitably sized cap about the edge center. var edgeCap = S2Cap.FromAxisAngle( edgeCenter, S1Angle.FromRadians(maxLengthMeters / S2LatLng.EarthRadiusMeters / 2)); var p1 = samplePoint(edgeCap); var p2 = samplePoint(edgeCap); return(new S2Edge(p1, p2)); }
public void testRectBound() { // Empty and full caps. Assert.True(S2Cap.Empty.RectBound.IsEmpty); Assert.True(S2Cap.Full.RectBound.IsFull); var kDegreeEps = 1e-13; // Maximum allowable error for latitudes and longitudes measured in // degrees. (assertDoubleNear uses a fixed tolerance that is too small.) // Cap that includes the south pole. var rect = S2Cap.FromAxisAngle(getLatLngPoint(-45, 57), S1Angle.FromDegrees(50)).RectBound; assertDoubleNear(rect.LatLo.Degrees, -90, kDegreeEps); assertDoubleNear(rect.LatHi.Degrees, 5, kDegreeEps); Assert.True(rect.Lng.IsFull); // Cap that is tangent to the north pole. rect = S2Cap.FromAxisAngle(S2Point.Normalize(new S2Point(1, 0, 1)), S1Angle.FromRadians(S2.PiOver4)).RectBound; assertDoubleNear(rect.Lat.Lo, 0); assertDoubleNear(rect.Lat.Hi, S2.PiOver2); Assert.True(rect.Lng.IsFull); rect = S2Cap .FromAxisAngle(S2Point.Normalize(new S2Point(1, 0, 1)), S1Angle.FromDegrees(45)).RectBound; assertDoubleNear(rect.LatLo.Degrees, 0, kDegreeEps); assertDoubleNear(rect.LatHi.Degrees, 90, kDegreeEps); Assert.True(rect.Lng.IsFull); // The eastern hemisphere. rect = S2Cap .FromAxisAngle(new S2Point(0, 1, 0), S1Angle.FromRadians(S2.PiOver2 + 5e-16)).RectBound; assertDoubleNear(rect.LatLo.Degrees, -90, kDegreeEps); assertDoubleNear(rect.LatHi.Degrees, 90, kDegreeEps); Assert.True(rect.Lng.IsFull); // A cap centered on the equator. rect = S2Cap.FromAxisAngle(getLatLngPoint(0, 50), S1Angle.FromDegrees(20)).RectBound; assertDoubleNear(rect.LatLo.Degrees, -20, kDegreeEps); assertDoubleNear(rect.LatHi.Degrees, 20, kDegreeEps); assertDoubleNear(rect.LngLo.Degrees, 30, kDegreeEps); assertDoubleNear(rect.LngHi.Degrees, 70, kDegreeEps); // A cap centered on the north pole. rect = S2Cap.FromAxisAngle(getLatLngPoint(90, 123), S1Angle.FromDegrees(10)).RectBound; assertDoubleNear(rect.LatLo.Degrees, 80, kDegreeEps); assertDoubleNear(rect.LatHi.Degrees, 90, kDegreeEps); Assert.True(rect.Lng.IsFull); }
private void getVertices(String str, S2Point x, S2Point y, S2Point z, double maxPerturbation, List <S2Point> vertices) { // Parse the vertices, perturb them if desired, and transform them into the // given frame. var line = makePolyline(str); for (var i = 0; i < line.NumVertices; ++i) { var p = line.Vertex(i); // (p[0]*x + p[1]*y + p[2]*z).Normalize() var axis = S2Point.Normalize(((x * p.X) + (y * p.Y)) + (z * p.Z)); var cap = S2Cap.FromAxisAngle(axis, S1Angle.FromRadians(maxPerturbation)); vertices.Add(samplePoint(cap)); } }
public void testCells() { // For each cube face, we construct some cells on // that face and some caps whose positions are relative to that face, // and then check for the expected intersection/containment results. // The distance from the center of a face to one of its vertices. var kFaceRadius = Math.Atan(S2.Sqrt2); for (var face = 0; face < 6; ++face) { // The cell consisting of the entire face. var rootCell = S2Cell.FromFacePosLevel(face, (byte)0, 0); // A leaf cell at the midpoint of the v=1 edge. var edgeCell = new S2Cell(S2Projections.FaceUvToXyz(face, 0, 1 - EPS)); // A leaf cell at the u=1, v=1 corner. var cornerCell = new S2Cell(S2Projections.FaceUvToXyz(face, 1 - EPS, 1 - EPS)); // Quick check for full and empty caps. Assert.True(S2Cap.Full.Contains(rootCell)); Assert.True(!S2Cap.Empty.MayIntersect(rootCell)); // Check intersections with the bounding caps of the leaf cells that are // adjacent to 'corner_cell' along the Hilbert curve. Because this corner // is at (u=1,v=1), the curve stays locally within the same cube face. var first = cornerCell.Id.Previous.Previous.Previous; var last = cornerCell.Id.Next.Next.Next.Next; for (var id = first; id < last; id = id.Next) { var cell = new S2Cell(id); JavaAssert.Equal(cell.CapBound.Contains(cornerCell), id.Equals(cornerCell.Id)); JavaAssert.Equal( cell.CapBound.MayIntersect(cornerCell), id.Parent.Contains(cornerCell.Id)); } var antiFace = (face + 3) % 6; // Opposite face. for (var capFace = 0; capFace < 6; ++capFace) { // A cap that barely contains all of 'cap_face'. var center = S2Projections.GetNorm(capFace); var covering = S2Cap.FromAxisAngle(center, S1Angle.FromRadians(kFaceRadius + EPS)); JavaAssert.Equal(covering.Contains(rootCell), capFace == face); JavaAssert.Equal(covering.MayIntersect(rootCell), capFace != antiFace); JavaAssert.Equal(covering.Contains(edgeCell), center.DotProd(edgeCell.Center) > 0.1); JavaAssert.Equal(covering.Contains(edgeCell), covering.MayIntersect(edgeCell)); JavaAssert.Equal(covering.Contains(cornerCell), capFace == face); JavaAssert.Equal( covering.MayIntersect(cornerCell), center.DotProd(cornerCell.Center) > 0); // A cap that barely intersects the edges of 'cap_face'. var bulging = S2Cap.FromAxisAngle(center, S1Angle.FromRadians(S2.PiOver4 + EPS)); Assert.True(!bulging.Contains(rootCell)); JavaAssert.Equal(bulging.MayIntersect(rootCell), capFace != antiFace); JavaAssert.Equal(bulging.Contains(edgeCell), capFace == face); JavaAssert.Equal(bulging.MayIntersect(edgeCell), center.DotProd(edgeCell.Center) > 0.1); Assert.True(!bulging.Contains(cornerCell)); Assert.True(!bulging.MayIntersect(cornerCell)); // A singleton cap. var singleton = S2Cap.FromAxisAngle(center, S1Angle.FromRadians(0)); JavaAssert.Equal(singleton.MayIntersect(rootCell), capFace == face); Assert.True(!singleton.MayIntersect(edgeCell)); Assert.True(!singleton.MayIntersect(cornerCell)); } } }
public void S2CapBasicTest() { // Test basic properties of empty and full caps. var empty = S2Cap.Empty; var full = S2Cap.Full; Assert.True(empty.IsValid); Assert.True(empty.IsEmpty); Assert.True(empty.Complement.IsFull); Assert.True(full.IsValid); Assert.True(full.IsFull); Assert.True(full.Complement.IsEmpty); JavaAssert.Equal(full.Height, 2.0); assertDoubleNear(full.Angle.Degrees, 180); // Containment and intersection of empty and full caps. Assert.True(empty.Contains(empty)); Assert.True(full.Contains(empty)); Assert.True(full.Contains(full)); Assert.True(!empty.InteriorIntersects(empty)); Assert.True(full.InteriorIntersects(full)); Assert.True(!full.InteriorIntersects(empty)); // Singleton cap containing the x-axis. var xaxis = S2Cap.FromAxisHeight(new S2Point(1, 0, 0), 0); Assert.True(xaxis.Contains(new S2Point(1, 0, 0))); Assert.True(!xaxis.Contains(new S2Point(1, 1e-20, 0))); JavaAssert.Equal(xaxis.Angle.Radians, 0.0); // Singleton cap containing the y-axis. var yaxis = S2Cap.FromAxisAngle(new S2Point(0, 1, 0), S1Angle.FromRadians(0)); Assert.True(!yaxis.Contains(xaxis.Axis)); JavaAssert.Equal(xaxis.Height, 0.0); // Check that the complement of a singleton cap is the full cap. var xcomp = xaxis.Complement; Assert.True(xcomp.IsValid); Assert.True(xcomp.IsFull); Assert.True(xcomp.Contains(xaxis.Axis)); // Check that the complement of the complement is *not* the original. Assert.True(xcomp.Complement.IsValid); Assert.True(xcomp.Complement.IsEmpty); Assert.True(!xcomp.Complement.Contains(xaxis.Axis)); // Check that very small caps can be represented accurately. // Here "kTinyRad" is small enough that unit vectors perturbed by this // amount along a tangent do not need to be renormalized. var kTinyRad = 1e-10; var tiny = S2Cap.FromAxisAngle(S2Point.Normalize(new S2Point(1, 2, 3)), S1Angle.FromRadians(kTinyRad)); var tangent = S2Point.Normalize(S2Point.CrossProd(tiny.Axis, new S2Point(3, 2, 1))); Assert.True(tiny.Contains(tiny.Axis + (tangent * 0.99 * kTinyRad))); Assert.True(!tiny.Contains(tiny.Axis + (tangent * 1.01 * kTinyRad))); // Basic tests on a hemispherical cap. var hemi = S2Cap.FromAxisHeight(S2Point.Normalize(new S2Point(1, 0, 1)), 1); JavaAssert.Equal(hemi.Complement.Axis, -hemi.Axis); JavaAssert.Equal(hemi.Complement.Height, 1.0); Assert.True(hemi.Contains(new S2Point(1, 0, 0))); Assert.True(!hemi.Complement.Contains(new S2Point(1, 0, 0))); Assert.True(hemi.Contains(S2Point.Normalize(new S2Point(1, 0, -(1 - EPS))))); Assert.True(!hemi.InteriorContains(S2Point.Normalize(new S2Point(1, 0, -(1 + EPS))))); // A concave cap. var concave = S2Cap.FromAxisAngle(getLatLngPoint(80, 10), S1Angle.FromDegrees(150)); Assert.True(concave.Contains(getLatLngPoint(-70 * (1 - EPS), 10))); Assert.True(!concave.Contains(getLatLngPoint(-70 * (1 + EPS), 10))); Assert.True(concave.Contains(getLatLngPoint(-50 * (1 - EPS), -170))); Assert.True(!concave.Contains(getLatLngPoint(-50 * (1 + EPS), -170))); // Cap containment tests. Assert.True(!empty.Contains(xaxis)); Assert.True(!empty.InteriorIntersects(xaxis)); Assert.True(full.Contains(xaxis)); Assert.True(full.InteriorIntersects(xaxis)); Assert.True(!xaxis.Contains(full)); Assert.True(!xaxis.InteriorIntersects(full)); Assert.True(xaxis.Contains(xaxis)); Assert.True(!xaxis.InteriorIntersects(xaxis)); Assert.True(xaxis.Contains(empty)); Assert.True(!xaxis.InteriorIntersects(empty)); Assert.True(hemi.Contains(tiny)); Assert.True(hemi.Contains( S2Cap.FromAxisAngle(new S2Point(1, 0, 0), S1Angle.FromRadians(S2.PiOver4 - EPS)))); Assert.True(!hemi.Contains( S2Cap.FromAxisAngle(new S2Point(1, 0, 0), S1Angle.FromRadians(S2.PiOver4 + EPS)))); Assert.True(concave.Contains(hemi)); Assert.True(concave.InteriorIntersects(hemi.Complement)); Assert.True(!concave.Contains(S2Cap.FromAxisHeight(-concave.Axis, 0.1))); }
public void testBasic() { // Most of the S2LatLngRect methods have trivial implementations that // use the R1Interval and S1Interval classes, so most of the testing // is done in those unit tests. // Test basic properties of empty and full caps. var empty = S2LatLngRect.Empty; var full = S2LatLngRect.Full; assertTrue(empty.IsValid); assertTrue(empty.IsEmpty); assertTrue(full.IsValid); assertTrue(full.IsFull); // assertTrue various constructors and accessor methods. var d1 = rectFromDegrees(-90, 0, -45, 180); assertDoubleNear(d1.LatLo.Degrees, -90); assertDoubleNear(d1.LatHi.Degrees, -45); assertDoubleNear(d1.LngLo.Degrees, 0); assertDoubleNear(d1.LngHi.Degrees, 180); assertTrue(d1.Lat.Equals(new R1Interval(-S2.PiOver2, -S2.PiOver4))); assertTrue(d1.Lng.Equals(new S1Interval(0, S2.Pi))); // FromCenterSize() assertTrue( S2LatLngRect.FromCenterSize(S2LatLng.FromDegrees(80, 170), S2LatLng.FromDegrees(40, 60)) .ApproxEquals(rectFromDegrees(60, 140, 90, -160))); assertTrue(S2LatLngRect .FromCenterSize(S2LatLng.FromDegrees(10, 40), S2LatLng.FromDegrees(210, 400)).IsFull); assertTrue( S2LatLngRect.FromCenterSize(S2LatLng.FromDegrees(-90, 180), S2LatLng.FromDegrees(20, 50)) .ApproxEquals(rectFromDegrees(-90, 155, -80, -155))); // FromPoint(), FromPointPair() assertEquals(S2LatLngRect.FromPoint(d1.Lo), new S2LatLngRect(d1.Lo, d1.Lo)); assertEquals( S2LatLngRect.FromPointPair(S2LatLng.FromDegrees(-35, -140), S2LatLng.FromDegrees(15, 155)), rectFromDegrees(-35, 155, 15, -140)); assertEquals( S2LatLngRect.FromPointPair(S2LatLng.FromDegrees(25, -70), S2LatLng.FromDegrees(-90, 80)), rectFromDegrees(-90, -70, 25, 80)); // GetCenter(), GetVertex(), Contains(S2LatLng), InteriorContains(S2LatLng). var eqM180 = S2LatLng.FromRadians(0, -S2.Pi); var northPole = S2LatLng.FromRadians(S2.PiOver2, 0); var r1 = new S2LatLngRect(eqM180, northPole); assertEquals(r1.Center, S2LatLng.FromRadians(S2.PiOver4, -S2.PiOver2)); assertEquals(r1.GetVertex(0), S2LatLng.FromRadians(0, S2.Pi)); assertEquals(r1.GetVertex(1), S2LatLng.FromRadians(0, 0)); assertEquals(r1.GetVertex(2), S2LatLng.FromRadians(S2.PiOver2, 0)); assertEquals(r1.GetVertex(3), S2LatLng.FromRadians(S2.PiOver2, S2.Pi)); assertTrue(r1.Contains(S2LatLng.FromDegrees(30, -45))); assertTrue(!r1.Contains(S2LatLng.FromDegrees(30, 45))); assertTrue(!r1.InteriorContains(eqM180) && !r1.InteriorContains(northPole)); assertTrue(r1.Contains(new S2Point(0.5, -0.3, 0.1))); assertTrue(!r1.Contains(new S2Point(0.5, 0.2, 0.1))); // Make sure that GetVertex() returns vertices in CCW order. for (var i = 0; i < 4; ++i) { var lat = S2.PiOver4 * (i - 2); var lng = S2.PiOver2 * (i - 2) + 0.2; var r = new S2LatLngRect(new R1Interval(lat, lat + S2.PiOver4), new S1Interval( Math.IEEERemainder(lng, 2 * S2.Pi), Math.IEEERemainder(lng + S2.PiOver2, 2 * S2.Pi))); for (var k = 0; k < 4; ++k) { assertTrue( S2.SimpleCcw(r.GetVertex((k - 1) & 3).ToPoint(), r.GetVertex(k).ToPoint(), r.GetVertex((k + 1) & 3).ToPoint())); } } // Contains(S2LatLngRect), InteriorContains(S2LatLngRect), // Intersects(), InteriorIntersects(), Union(), Intersection(). // // Much more testing of these methods is done in s1interval_unittest // and r1interval_unittest. var r1Mid = rectFromDegrees(45, -90, 45, -90); var reqM180 = new S2LatLngRect(eqM180, eqM180); var rNorthPole = new S2LatLngRect(northPole, northPole); testIntervalOps(r1, r1Mid, "TTTT", r1, r1Mid); testIntervalOps(r1, reqM180, "TFTF", r1, reqM180); testIntervalOps(r1, rNorthPole, "TFTF", r1, rNorthPole); assertTrue(r1.Equals(rectFromDegrees(0, -180, 90, 0))); testIntervalOps(r1, rectFromDegrees(-10, -1, 1, 20), "FFTT", rectFromDegrees(-10, -180, 90, 20), rectFromDegrees(0, -1, 1, 0)); testIntervalOps(r1, rectFromDegrees(-10, -1, 0, 20), "FFTF", rectFromDegrees(-10, -180, 90, 20), rectFromDegrees(0, -1, 0, 0)); testIntervalOps(r1, rectFromDegrees(-10, 0, 1, 20), "FFTF", rectFromDegrees(-10, -180, 90, 20), rectFromDegrees(0, 0, 1, 0)); testIntervalOps(rectFromDegrees(-15, -160, -15, -150), rectFromDegrees(20, 145, 25, 155), "FFFF", rectFromDegrees(-15, 145, 25, -150), empty); testIntervalOps(rectFromDegrees(70, -10, 90, -140), rectFromDegrees(60, 175, 80, 5), "FFTT", rectFromDegrees(60, -180, 90, 180), rectFromDegrees(70, 175, 80, 5)); // assertTrue that the intersection of two rectangles that overlap in // latitude // but not longitude is valid, and vice versa. testIntervalOps(rectFromDegrees(12, 30, 60, 60), rectFromDegrees(0, 0, 30, 18), "FFFF", rectFromDegrees(0, 0, 60, 60), empty); testIntervalOps(rectFromDegrees(0, 0, 18, 42), rectFromDegrees(30, 12, 42, 60), "FFFF", rectFromDegrees(0, 0, 42, 60), empty); // AddPoint() var p = S2LatLngRect.Empty; p = p.AddPoint(S2LatLng.FromDegrees(0, 0)); p = p.AddPoint(S2LatLng.FromRadians(0, -S2.PiOver2)); p = p.AddPoint(S2LatLng.FromRadians(S2.PiOver4, -S2.Pi)); p = p.AddPoint(new S2Point(0, 0, 1)); assertTrue(p.Equals(r1)); // Expanded() assertTrue( rectFromDegrees(70, 150, 80, 170).Expanded(S2LatLng.FromDegrees(20, 30)).ApproxEquals( rectFromDegrees(50, 120, 90, -160))); assertTrue(S2LatLngRect.Empty.Expanded(S2LatLng.FromDegrees(20, 30)).IsEmpty); assertTrue(S2LatLngRect.Full.Expanded(S2LatLng.FromDegrees(20, 30)).IsFull); assertTrue( rectFromDegrees(-90, 170, 10, 20).Expanded(S2LatLng.FromDegrees(30, 80)).ApproxEquals( rectFromDegrees(-90, -180, 40, 180))); // ConvolveWithCap() var llr1 = new S2LatLngRect(S2LatLng.FromDegrees(0, 170), S2LatLng.FromDegrees(0, -170)) .ConvolveWithCap(S1Angle.FromDegrees(15)); var llr2 = new S2LatLngRect(S2LatLng.FromDegrees(-15, 155), S2LatLng.FromDegrees(15, -155)); assertTrue(llr1.ApproxEquals(llr2)); llr1 = new S2LatLngRect(S2LatLng.FromDegrees(60, 150), S2LatLng.FromDegrees(80, 10)) .ConvolveWithCap(S1Angle.FromDegrees(15)); llr2 = new S2LatLngRect(S2LatLng.FromDegrees(45, -180), S2LatLng.FromDegrees(90, 180)); assertTrue(llr1.ApproxEquals(llr2)); // GetCapBound(), bounding cap at center is smaller: assertTrue(new S2LatLngRect(S2LatLng.FromDegrees(-45, -45), S2LatLng.FromDegrees(45, 45)).CapBound.ApproxEquals(S2Cap.FromAxisHeight(new S2Point(1, 0, 0), 0.5))); // GetCapBound(), bounding cap at north pole is smaller: assertTrue(new S2LatLngRect(S2LatLng.FromDegrees(88, -80), S2LatLng.FromDegrees(89, 80)).CapBound.ApproxEquals(S2Cap.FromAxisAngle(new S2Point(0, 0, 1), S1Angle.FromDegrees(2)))); // GetCapBound(), longitude span > 180 degrees: assertTrue( new S2LatLngRect(S2LatLng.FromDegrees(-30, -150), S2LatLng.FromDegrees(-10, 50)).CapBound .ApproxEquals(S2Cap.FromAxisAngle(new S2Point(0, 0, -1), S1Angle.FromDegrees(80)))); // Contains(S2Cell), MayIntersect(S2Cell), Intersects(S2Cell) // Special cases. testCellOps(empty, S2Cell.FromFacePosLevel(3, (byte)0, 0), 0); testCellOps(full, S2Cell.FromFacePosLevel(2, (byte)0, 0), 4); testCellOps(full, S2Cell.FromFacePosLevel(5, (byte)0, 25), 4); // This rectangle includes the first quadrant of face 0. It's expanded // slightly because cell bounding rectangles are slightly conservative. var r4 = rectFromDegrees(-45.1, -45.1, 0.1, 0.1); testCellOps(r4, S2Cell.FromFacePosLevel(0, (byte)0, 0), 3); testCellOps(r4, S2Cell.FromFacePosLevel(0, (byte)0, 1), 4); testCellOps(r4, S2Cell.FromFacePosLevel(1, (byte)0, 1), 0); // This rectangle intersects the first quadrant of face 0. var r5 = rectFromDegrees(-10, -45, 10, 0); testCellOps(r5, S2Cell.FromFacePosLevel(0, (byte)0, 0), 3); testCellOps(r5, S2Cell.FromFacePosLevel(0, (byte)0, 1), 3); testCellOps(r5, S2Cell.FromFacePosLevel(1, (byte)0, 1), 0); // Rectangle consisting of a single point. testCellOps(rectFromDegrees(4, 4, 4, 4), S2Cell.FromFacePosLevel(0, (byte)0, 0), 3); // Rectangles that intersect the bounding rectangle of a face // but not the face itself. testCellOps(rectFromDegrees(41, -87, 42, -79), S2Cell.FromFacePosLevel(2, (byte)0, 0), 1); testCellOps(rectFromDegrees(-41, 160, -40, -160), S2Cell.FromFacePosLevel(5, (byte)0, 0), 1); { // This is the leaf cell at the top right hand corner of face 0. // It has two angles of 60 degrees and two of 120 degrees. var cell0tr = new S2Cell(new S2Point(1 + 1e-12, 1, 1)); var bound0tr = cell0tr.RectBound; var v0 = new S2LatLng(cell0tr.GetVertexRaw(0)); testCellOps( rectFromDegrees(v0.Lat.Degrees - 1e-8, v0.Lng.Degrees - 1e-8, v0.Lat.Degrees - 2e-10, v0.Lng.Degrees + 1e-10), cell0tr, 1); } // Rectangles that intersect a face but where no vertex of one region // is contained by the other region. The first one passes through // a corner of one of the face cells. testCellOps(rectFromDegrees(-37, -70, -36, -20), S2Cell.FromFacePosLevel(5, (byte)0, 0), 2); { // These two intersect like a diamond and a square. var cell202 = S2Cell.FromFacePosLevel(2, (byte)0, 2); var bound202 = cell202.RectBound; testCellOps( rectFromDegrees(bound202.Lo.Lat.Degrees + 3, bound202.Lo.Lng.Degrees + 3, bound202.Hi.Lat.Degrees - 3, bound202.Hi.Lng.Degrees - 3), cell202, 2); } }
public List <Guid> Search(double lon, double lat, int radius) { lock (locker) { var latlng = S2LatLng.FromDegrees(lat, lon); var centerPoint = pointFromLatLng(lat, lon); var centerAngle = ((double)radius) / EarthRadiusM; var cap = S2Cap.FromAxisAngle(centerPoint, S1Angle.FromRadians(centerAngle)); var regionCoverer = new S2RegionCoverer(); regionCoverer.MaxLevel = 13; // regionCoverer.MinLevel = 13; //regionCoverer.MaxCells = 1000; // regionCoverer.LevelMod = 0; var covering = regionCoverer.GetCovering(cap); var res = new List <Guid>(); foreach (var u in covering) { var sell = new S2CellId(u.Id); if (sell.Level < _level) { var begin = sell.ChildBeginForLevel(_level); var end = sell.ChildEndForLevel(_level); var qres = rtree.Search(new Interval <UserList>(new UserList() { s2CellId = begin }, new UserList() { s2CellId = end })); foreach (var item in qres) { res.AddRange(item.Start.list); } } else { var qres = rtree.Search(new UserList() { s2CellId = sell }); if (qres.Count > 0) { foreach (var r in qres) { res.AddRange(r.Start.list); } } } } return(res); } }