예제 #1
0
        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);
        }
예제 #2
0
        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));
        }
예제 #5
0
        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);
        }
예제 #6
0
        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));
            }
        }
예제 #7
0
        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));
                }
            }
        }
예제 #8
0
        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);
            }
        }
예제 #10
0
        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);
            }
        }