示例#1
0
    public void Test_ExpandedByDistance_NegativeDistanceLatWithSouthPoleAndLngFull()
    {
        S2LatLngRect rect = RectFromDegrees(-90.0, -180.0, 0.0, 180.0)
                            .ExpandedByDistance(-S1Angle.FromDegrees(5.0));

        Assert.True(rect.ApproxEquals(RectFromDegrees(-90.0, -180.0, -5.0, 180.0)));
    }
        public List <S2CellId> GetS2CellIds(ushort level, int maxCells)
        {
            //var geofence = Geofence.FromMultiPolygon(this);
            var bbox          = GetBoundingBox();
            var regionCoverer = new S2RegionCoverer
            {
                MinLevel = level,
                MaxLevel = level,
                MaxCells = maxCells,
            };
            var region = new S2LatLngRect(
                S2LatLng.FromDegrees(bbox.MinimumLatitude, bbox.MinimumLongitude),
                S2LatLng.FromDegrees(bbox.MaximumLatitude, bbox.MaximumLongitude)
                );
            var coverage = new List <S2CellId>();

            regionCoverer.GetCovering(region, coverage);
            var result = new List <S2CellId>();

            foreach (var cellId in coverage)
            {
                var cell = new S2Cell(cellId);
                for (var i = 0; i <= 3; i++)
                {
                    var vertex = cell.GetVertex(i);
                    var coord  = new S2LatLng(new S2Point(vertex.X, vertex.Y, vertex.Z));
                    //if (geofence.Intersects(coord.LatDegrees, coord.LngDegrees))
                    if (GeofenceService.InPolygon(this, coord.LatDegrees, coord.LngDegrees))
                    {
                        result.Add(cellId);
                    }
                }
            }
            return(result);
        }
示例#3
0
        /// <summary>
        /// Find the cell of the given level that covers the given Geoposition.
        /// This method uses the library given S2RegionCoverer to find the leaf cell containing the given Geoposition
        /// and uses binary operation on the leaf cell's Id to find the higher level cell containing the leaf.
        /// This is somehow more accurate than using the S2RegionCoverer for the higher level cell, where some errors occured.
        /// </summary>
        /// <param name="pos">Position in the cell</param>
        /// <param name="level">Level of the cell</param>
        /// <returns>The cell covering the given position that matches the specifications</returns>
        private S2Cell FindExactCell(BasicGeoposition pos, int level)
        {
            var point = S2LatLngRect.FromPoint(S2LatLng.FromDegrees(pos.Latitude, pos.Longitude));

            var cells = new List <S2CellId>();

            // find leaf cell
            var coverer = new S2RegionCoverer()
            {
                MinLevel = 30,
                MaxLevel = 30,
                MaxCells = 1
            };

            coverer.GetCovering(point, cells);

            var leaf = new S2Cell(cells[0]);

            int   shift = 64 - (3 + level * 2 + 1);
            ulong id    = leaf.Id.Id & ulong.MaxValue << shift;

            id |= 0 | ((ulong)1 << shift);

            return(new S2Cell(new S2CellId(id)));
        }
        public void testIntervalOps(S2LatLngRect x, S2LatLngRect y, String expectedRelation,
                                    S2LatLngRect expectedUnion, S2LatLngRect expectedIntersection)
        {
            // Test all of the interval operations on the given pair of intervals.
            // "expected_relation" is a sequence of "T" and "F" characters corresponding
            // to the expected results of Contains(), InteriorContains(), Intersects(),
            // and InteriorIntersects() respectively.

            assertEquals(x.Contains(y), expectedRelation[0] == 'T');
            assertEquals(x.InteriorContains(y), expectedRelation[1] == 'T');
            assertEquals(x.Intersects(y), expectedRelation[2] == 'T');
            assertEquals(x.InteriorIntersects(y), expectedRelation[3] == 'T');

            assertEquals(x.Contains(y), x.Union(y).Equals(x));
            assertEquals(x.Intersects(y), !x.Intersection(y).IsEmpty);

            assertTrue(x.Union(y).Equals(expectedUnion));
            assertTrue(x.Intersection(y).Equals(expectedIntersection));

            if (y.Size == S2LatLng.FromRadians(0, 0))
            {
                var r = x.AddPoint(y.Lo);
                assertTrue(r == expectedUnion);
            }
        }
        private static List <Coordinate> GetS2Cells(BoundingBox bbox)
        {
            var regionCoverer = new S2RegionCoverer
            {
                MinLevel = 15,
                MaxLevel = 15,
                //MaxCells = 100,
            };
            var region = new S2LatLngRect(
                S2LatLng.FromDegrees(bbox.MinimumLatitude, bbox.MinimumLongitude),
                S2LatLng.FromDegrees(bbox.MaximumLatitude, bbox.MaximumLongitude)
                );
            var cellIds = regionCoverer.GetCovering(region);
            var list    = new List <Coordinate>();

            foreach (var cellId in cellIds)
            {
                var center = cellId.ToLatLng();
                list.Add(new Coordinate(center.LatDegrees, center.LngDegrees));
            }
            // TODO: Check if point is within geofence
            //var filtered = FilterCoordinates(coordinates);
            //return filtered;
            return(list);
        }
示例#6
0
    private static void TestIntervalOps(S2LatLngRect x, S2LatLngRect y, string expected_relation, S2LatLngRect expected_union, S2LatLngRect expected_intersection)
    {
        // Test all of the interval operations on the given pair of intervals.
        // "expected_relation" is a sequence of "T" and "F" characters corresponding
        // to the expected results of Contains(), InteriorContains(), Intersects(),
        // and InteriorIntersects() respectively.

        Assert.Equal(x.Contains(y), expected_relation[0] == 'T');
        Assert.Equal(x.InteriorContains(y), expected_relation[1] == 'T');
        Assert.Equal(x.Intersects(y), expected_relation[2] == 'T');
        Assert.Equal(x.InteriorIntersects(y), expected_relation[3] == 'T');

        Assert.Equal(x.Contains(y), x.Union(y) == x);
        Assert.Equal(x.Intersects(y), !x.Intersection(y).IsEmpty());

        Assert.Equal(x.Union(y), expected_union);
        Assert.Equal(x.Intersection(y), expected_intersection);

        if (y.Size() == S2LatLng.FromRadians(0, 0))
        {
            S2LatLngRect r = x;
            r.AddPoint(y.Lo());
            Assert.Equal(r, expected_union);
        }
    }
示例#7
0
    public void Test_ExpandedByDistance_NegativeDistanceLngFull()
    {
        S2LatLngRect rect = RectFromDegrees(0.0, -180.0, 30.0, 180.0)
                            .ExpandedByDistance(-S1Angle.FromDegrees(5.0));

        Assert.True(rect.ApproxEquals(RectFromDegrees(5.0, -180.0, 25.0, 180.0)));
    }
        /**
         * This method verifies a.getDistance(b) by comparing its result against a
         * brute-force implementation. The correctness of the brute-force version is
         * much easier to verify by inspection.
         */

        private static void verifyGetDistance(S2LatLngRect a, S2LatLngRect b)
        {
            var distance1 = bruteForceDistance(a, b);
            var distance2 = a.GetDistance(b);

            assertEquals(distance1.Radians, distance2.Radians, 1e-10);
        }
示例#9
0
    public void Test_BoundaryIntersects_RectCrossingAntiMeridian()
    {
        S2LatLngRect rect = RectFromDegrees(20, 170, 40, -170);

        Assert.True(rect.Contains(MakePointOrDie("30:180")));

        // Check that crossings of all four sides are detected.
        Assert.True(rect.BoundaryIntersects(
                        MakePointOrDie("25:160"), MakePointOrDie("25:180")));
        Assert.True(rect.BoundaryIntersects(
                        MakePointOrDie("25:-160"), MakePointOrDie("25:-180")));
        Assert.True(rect.BoundaryIntersects(
                        MakePointOrDie("15:175"), MakePointOrDie("30:175")));
        Assert.True(rect.BoundaryIntersects(
                        MakePointOrDie("45:175"), MakePointOrDie("30:175")));

        // Check that the edges on the opposite side of the sphere but at the same
        // latitude do not intersect the rectangle boundary.
        Assert.False(rect.BoundaryIntersects(
                         MakePointOrDie("25:-20"), MakePointOrDie("25:0")));
        Assert.False(rect.BoundaryIntersects(
                         MakePointOrDie("25:20"), MakePointOrDie("25:0")));
        Assert.False(rect.BoundaryIntersects(
                         MakePointOrDie("15:-5"), MakePointOrDie("30:-5")));
        Assert.False(rect.BoundaryIntersects(
                         MakePointOrDie("45:-5"), MakePointOrDie("30:-5")));
    }
        public void testIntervalOps(S2LatLngRect x, S2LatLngRect y, String expectedRelation,
                                    S2LatLngRect expectedUnion, S2LatLngRect expectedIntersection)
        {
            // Test all of the interval operations on the given pair of intervals.
            // "expected_relation" is a sequence of "T" and "F" characters corresponding
            // to the expected results of Contains(), InteriorContains(), Intersects(),
            // and InteriorIntersects() respectively.

            assertEquals(x.Contains(y), expectedRelation[0] == 'T');
            assertEquals(x.InteriorContains(y), expectedRelation[1] == 'T');
            assertEquals(x.Intersects(y), expectedRelation[2] == 'T');
            assertEquals(x.InteriorIntersects(y), expectedRelation[3] == 'T');

            assertEquals(x.Contains(y), x.Union(y).Equals(x));
            assertEquals(x.Intersects(y), !x.Intersection(y).IsEmpty);

            assertTrue(x.Union(y).Equals(expectedUnion));
            assertTrue(x.Intersection(y).Equals(expectedIntersection));

            if (y.Size == S2LatLng.FromRadians(0, 0))
            {
                var r = x.AddPoint(y.Lo);
                assertTrue(r == expectedUnion);
            }
        }
示例#11
0
    public void Test_ExpandedByDistance_NegativeDistanceLatResultEmpty()
    {
        S2LatLngRect rect = RectFromDegrees(0.0, 0.0, 9.9, 90.0)
                            .ExpandedByDistance(-S1Angle.FromDegrees(5.0));

        Assert.True(rect.IsEmpty());
    }
示例#12
0
    public void Test_S2LatLngRect_GetDirectedHausdorffDistanceRandomPairs()
    {
        // Test random pairs.
        int kIters = 1000;

        for (int i = 0; i < kIters; ++i)
        {
            S2LatLngRect a =
                S2LatLngRect.FromPointPair(new S2LatLng(S2Testing.RandomPoint()),
                                           new S2LatLng(S2Testing.RandomPoint()));
            S2LatLngRect b =
                S2LatLngRect.FromPointPair(new S2LatLng(S2Testing.RandomPoint()),
                                           new S2LatLng(S2Testing.RandomPoint()));
            // a and b are *minimum* bounding rectangles of two random points, in
            // particular, their Voronoi diagrams are always of the same topology. We
            // take the "complements" of a and b for more thorough testing.
            S2LatLngRect a2 = new(a.Lat, a.Lng.Complement());
            S2LatLngRect b2 = new(b.Lat, b.Lng.Complement());

            // Note that "a" and "b" come from the same distribution, so there is no
            // need to test pairs such as (b, a), (b, a2), etc.
            VerifyGetDirectedHausdorffDistance(a, b);
            VerifyGetDirectedHausdorffDistance(a, b2);
            VerifyGetDirectedHausdorffDistance(a2, b);
            VerifyGetDirectedHausdorffDistance(a2, b2);
        }
    }
        /**
         * This method verifies a.getDistance(b), where b is a S2LatLng, by comparing
         * its result against a.getDistance(c), c being the point rectangle created
         * from b.
         */

        private static void verifyGetRectPointDistance(S2LatLngRect a, S2LatLng p)
        {
            var distance1 = bruteForceRectPointDistance(a, p.Normalized);
            var distance2 = a.GetDistance(p.Normalized);

            assertEquals(distance1.Radians, distance2.Radians, 1e-10);
        }
示例#14
0
        public static S2CellUnion FindCellIds(S2LatLngRect latLngRect)
        {
            var queue = new ConcurrentQueue <S2CellId>();


            var cellIds = new List <S2CellId>();

            for (var c = S2CellId.Begin(0); !c.Equals(S2CellId.End(0)); c = c.Next)
            {
                if (ContainsGeodataToFind(c, latLngRect))
                {
                    queue.Enqueue(c);
                }
            }

            ProcessQueue(queue, cellIds, latLngRect);
            Debug.Assert(queue.Count == 0);

            queue = null;

            if (cellIds.Count > 0)
            {
                var cellUnion = new S2CellUnion();
                cellUnion.InitFromCellIds(cellIds); // This normalize the cells.
                // cellUnion.initRawCellIds(cellIds); // This does not normalize the cells.
                cellIds = null;

                return(cellUnion);
            }

            return(null);
        }
示例#15
0
    public void Test_S2LatLngRect_FromPoint()
    {
        S2LatLng p = S2LatLng.FromDegrees(23, 47);

        Assert.Equal(S2LatLngRect.FromPoint(p), new S2LatLngRect(p, p));
        Assert.True(S2LatLngRect.FromPoint(p).IsPoint());
    }
示例#16
0
    public void Test_ExpandedByDistance_NegativeDistanceLatWithNorthPole()
    {
        S2LatLngRect rect = RectFromDegrees(0.0, -90.0, 90.0, 180.0)
                            .ExpandedByDistance(-S1Angle.FromDegrees(5.0));

        Assert.True(rect.ApproxEquals(RectFromDegrees(5.0, 0.0, 85.0, 90.0)));
    }
示例#17
0
    // This function assumes that GetDirectedHausdorffDistance() always returns
    // a distance from some point in a to b. So the function mainly tests whether
    // the returned distance is large enough, and only does a weak test on whether
    // it is small enough.
    private static void VerifyGetDirectedHausdorffDistance(S2LatLngRect a, S2LatLngRect b)
    {
        S1Angle hausdorff_distance = a.GetDirectedHausdorffDistance(b);

        const double kResolution  = 0.1;
        S1Angle      max_distance = S1Angle.Zero;

        int sample_size_on_lat =
            (int)(a.Lat.GetLength() / kResolution) + 1;
        int sample_size_on_lng =
            (int)(a.Lng.GetLength() / kResolution) + 1;
        double delta_on_lat = a.Lat.GetLength() / sample_size_on_lat;
        double delta_on_lng = a.Lng.GetLength() / sample_size_on_lng;

        double lng = a.Lng.Lo;

        for (int i = 0; i <= sample_size_on_lng; ++i, lng += delta_on_lng)
        {
            double lat = a.Lat.Lo;
            for (int j = 0; j <= sample_size_on_lat; ++j, lat += delta_on_lat)
            {
                S2LatLng latlng        = S2LatLng.FromRadians(lat, lng).Normalized();
                S1Angle  distance_to_b = b.GetDistance(latlng);

                if (distance_to_b >= max_distance)
                {
                    max_distance = distance_to_b;
                }
            }
        }

        Assert.True(max_distance.Radians <= hausdorff_distance.Radians + 1e-10);
        Assert.True(max_distance.Radians >= hausdorff_distance.Radians - kResolution);
    }
示例#18
0
    // This method verifies a.GetDistance(b), where b is a S2LatLng, by comparing
    // its result against a.GetDistance(c), c being the point rectangle created
    // from b.
    private static void VerifyGetRectPointDistance(S2LatLngRect a, S2LatLng p)
    {
        S1Angle distance1 = BruteForceRectPointDistance(a, p.Normalized());
        S1Angle distance2 = a.GetDistance(p.Normalized());

        Assert2.Near(Math.Abs(distance1.Radians - distance2.Radians), 0, 1e-10);
    }
示例#19
0
    // This method verifies a.GetDistance(b) by comparing its result against a
    // brute-force implementation. The correctness of the brute-force version is
    // much easier to verify by inspection.
    private static void VerifyGetDistance(S2LatLngRect a, S2LatLngRect b)
    {
        S1Angle distance1 = BruteForceDistance(a, b);
        S1Angle distance2 = a.GetDistance(b);

        Assert2.Near(distance1.Radians - distance2.Radians, 0, 1e-10);
    }
示例#20
0
    public void Test_S2LatLngRect_GetDirectHausdorffDistancePointToRect()
    {
        // The Hausdorff distance from a point to a rect should be the same as its
        // distance to the rect.
        S2LatLngRect a1 = PointRectFromDegrees(5, 8);
        S2LatLngRect a2 = PointRectFromDegrees(90, 10);  // north pole

        S2LatLngRect b = RectFromDegrees(-85, -50, -80, 10);

        Assert2.DoubleEqual(a1.GetDirectedHausdorffDistance(b).Radians,
                            a1.GetDistance(b).Radians);
        Assert2.DoubleEqual(a2.GetDirectedHausdorffDistance(b).Radians,
                            a2.GetDistance(b).Radians);

        b = RectFromDegrees(4, -10, 80, 10);
        Assert2.DoubleEqual(a1.GetDirectedHausdorffDistance(b).Radians,
                            a1.GetDistance(b).Radians);
        Assert2.DoubleEqual(a2.GetDirectedHausdorffDistance(b).Radians,
                            a2.GetDistance(b).Radians);

        b = RectFromDegrees(70, 170, 80, -170);
        Assert2.DoubleEqual(a1.GetDirectedHausdorffDistance(b).Radians,
                            a1.GetDistance(b).Radians);
        Assert2.DoubleEqual(a2.GetDirectedHausdorffDistance(b).Radians,
                            a2.GetDistance(b).Radians);
    }
示例#21
0
    public void Test_ExpandedByDistance_NegativeDistanceNorthEast()
    {
        S2LatLngRect in_rect  = RectFromDegrees(0.0, 0.0, 30.0, 90.0);
        S1Angle      distance = S1Angle.FromDegrees(5.0);
        S2LatLngRect out_rect = in_rect.ExpandedByDistance(distance).ExpandedByDistance(-distance);

        Assert.True(out_rect.ApproxEquals(in_rect));
    }
示例#22
0
    public void Test_S2LatLngRect_CellOps()
    {
        // Contains(S2Cell), MayIntersect(S2Cell), Intersects(S2Cell)

        // Special cases.
        TestCellOps(S2LatLngRect.Empty, S2Cell.FromFacePosLevel(3, 0, 0), 0);
        TestCellOps(S2LatLngRect.Full, S2Cell.FromFacePosLevel(2, 0, 0), 4);
        TestCellOps(S2LatLngRect.Full, S2Cell.FromFacePosLevel(5, 0, 25), 4);

        // This rectangle includes the first quadrant of face 0.  It's expanded
        // slightly because cell bounding rectangles are slightly conservative.
        S2LatLngRect r4 = RectFromDegrees(-45.1, -45.1, 0.1, 0.1);

        TestCellOps(r4, S2Cell.FromFacePosLevel(0, 0, 0), 3);
        TestCellOps(r4, S2Cell.FromFacePosLevel(0, 0, 1), 4);
        TestCellOps(r4, S2Cell.FromFacePosLevel(1, 0, 1), 0);

        // This rectangle intersects the first quadrant of face 0.
        S2LatLngRect r5 = RectFromDegrees(-10, -45, 10, 0);

        TestCellOps(r5, S2Cell.FromFacePosLevel(0, 0, 0), 3);
        TestCellOps(r5, S2Cell.FromFacePosLevel(0, 0, 1), 3);
        TestCellOps(r5, S2Cell.FromFacePosLevel(1, 0, 1), 0);

        // Rectangle consisting of a single point.
        TestCellOps(RectFromDegrees(4, 4, 4, 4), S2Cell.FromFace(0), 3);

        // Rectangles that intersect the bounding rectangle of a face
        // but not the face itself.
        TestCellOps(RectFromDegrees(41, -87, 42, -79), S2Cell.FromFace(2), 1);
        TestCellOps(RectFromDegrees(-41, 160, -40, -160), S2Cell.FromFace(5), 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.
        S2Cell cell0tr = new(new S2Point(1 + 1e-12, 1, 1));

        _ = cell0tr.GetRectBound();
        S2LatLng v0 = new(cell0tr.VertexRaw(0));

        TestCellOps(RectFromDegrees(v0.Lat().GetDegrees() - 1e-8,
                                    v0.Lng().GetDegrees() - 1e-8,
                                    v0.Lat().GetDegrees() - 2e-10,
                                    v0.Lng().GetDegrees() + 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.FromFace(5), 2);

        // These two intersect like a diamond and a square.
        S2Cell       cell202  = S2Cell.FromFacePosLevel(2, 0, 2);
        S2LatLngRect bound202 = cell202.GetRectBound();

        TestCellOps(RectFromDegrees(bound202.Lo().Lat().GetDegrees() + 3,
                                    bound202.Lo().Lng().GetDegrees() + 3,
                                    bound202.Hi().Lat().GetDegrees() - 3,
                                    bound202.Hi().Lng().GetDegrees() - 3), cell202, 2);
    }
示例#23
0
    public void Test_BoundaryIntersects_FullRectangle()
    {
        S2LatLngRect rect = S2LatLngRect.Full;
        S2Point      lo   = rect.Lo().ToPoint();
        var          hi   = rect.Hi().ToPoint();

        Assert.False(rect.BoundaryIntersects(lo, lo));
        Assert.False(rect.BoundaryIntersects(lo, hi));
    }
示例#24
0
    public S2LatLngRect GetRectBound()
    {
        S2LatLngRect result = S2LatLngRect.Full;

        for (int i = 0; i < Regions.Length; ++i)
        {
            result = result.Intersection(Region(i).GetRectBound());
        }
        return(result);
    }
 private static S2LatLngRect getEdgeBound(double x1,
                                          double y1,
                                          double z1,
                                          double x2,
                                          double y2,
                                          double z2)
 {
     return(S2LatLngRect.FromEdge(
                S2Point.Normalize(new S2Point(x1, y1, z1)), S2Point.Normalize(new S2Point(x2, y2, z2))));
 }
示例#26
0
    private static S1Angle BruteForceDistance(S2LatLngRect a, S2LatLngRect b)
    {
        if (a.Intersects(b))
        {
            return(S1Angle.FromRadians(0));
        }

        // Compare every point in 'a' against every latitude edge and longitude edge
        // in 'b', and vice-versa, for a total of 16 point-vs-latitude-edge tests and
        // 16 point-vs-longitude-edge tests.
        var pnt_a = new S2LatLng[4];
        var pnt_b = new S2LatLng[4];

        pnt_a[0] = new S2LatLng(a.LatLo(), a.LngLo());
        pnt_a[1] = new S2LatLng(a.LatLo(), a.LngHi());
        pnt_a[2] = new S2LatLng(a.LatHi(), a.LngHi());
        pnt_a[3] = new S2LatLng(a.LatHi(), a.LngLo());
        pnt_b[0] = new S2LatLng(b.LatLo(), b.LngLo());
        pnt_b[1] = new S2LatLng(b.LatLo(), b.LngHi());
        pnt_b[2] = new S2LatLng(b.LatHi(), b.LngHi());
        pnt_b[3] = new S2LatLng(b.LatHi(), b.LngLo());

        // Make arrays containing the lo/hi latitudes and the lo/hi longitude edges.
        var lat_a = new S1Angle[2] {
            a.LatLo(), a.LatHi()
        };
        var lat_b = new S1Angle[2] {
            b.LatLo(), b.LatHi()
        };
        var lng_edge_a = new S2Point[][] { new S2Point[] { pnt_a[0].ToPoint(), pnt_a[3].ToPoint() },
                                           new S2Point[] { pnt_a[1].ToPoint(), pnt_a[2].ToPoint() } };
        var lng_edge_b = new S2Point[][] { new S2Point[] { pnt_b[0].ToPoint(), pnt_b[3].ToPoint() },
                                           new S2Point[] { pnt_b[1].ToPoint(), pnt_b[2].ToPoint() } };

        S1Angle min_distance = S1Angle.FromDegrees(180.0);

        for (int i = 0; i < 4; ++i)
        {
            // For each point in a and b.
            var current_a = pnt_a[i];
            var current_b = pnt_b[i];

            for (int j = 0; j < 2; ++j)
            {
                // Get distances to latitude and longitude edges.
                S1Angle a_to_lat = GetDistance(current_a, lat_b[j], b.Lng);
                S1Angle b_to_lat = GetDistance(current_b, lat_a[j], a.Lng);
                S1Angle a_to_lng = S2.GetDistance(current_a.ToPoint(), lng_edge_b[j][0], lng_edge_b[j][1]);
                S1Angle b_to_lng = S2.GetDistance(current_b.ToPoint(), lng_edge_a[j][0], lng_edge_a[j][1]);

                min_distance = new[] { min_distance, a_to_lat, b_to_lat, a_to_lng, b_to_lng }.Min();
            }
        }
        return(min_distance);
    }
示例#27
0
    public void Test_S2LatLngRect_GetDirectedHausdorffDistanceRectToPoint()
    {
        S2LatLngRect a = RectFromDegrees(1, -8, 10, 20);

        VerifyGetDirectedHausdorffDistance(a, PointRectFromDegrees(5, 8));
        VerifyGetDirectedHausdorffDistance(a, PointRectFromDegrees(-6, -100));
        // south pole
        VerifyGetDirectedHausdorffDistance(a, PointRectFromDegrees(-90, -20));
        // north pole
        VerifyGetDirectedHausdorffDistance(a, PointRectFromDegrees(90, 0));
    }
示例#28
0
    public void Test_ExpandedByDistance_NegativeDistanceLngResultEmpty()
    {
        S2LatLngRect rect = RectFromDegrees(0.0, 0.0, 30.0, 11.0)
                            .ExpandedByDistance(-S1Angle.FromDegrees(5.0));

        // The cap center is at latitude 30 - 5 = 25 degrees. The length of the
        // latitude 25 degree line is 0.906 times the length of the equator. Thus the
        // cap whose radius is 5 degrees covers the rectangle whose latitude interval
        // is 11 degrees.
        Assert.True(rect.IsEmpty());
    }
示例#29
0
    public void Test_S2LatLngRect_Accessors()
    {
        // Check various accessor methods.
        S2LatLngRect d1 = RectFromDegrees(-90, 0, -45, 180);

        Assert2.DoubleEqual(d1.LatLo().GetDegrees(), -90);
        Assert2.DoubleEqual(d1.LatHi().GetDegrees(), -45);
        Assert2.DoubleEqual(d1.LngLo().GetDegrees(), 0);
        Assert2.DoubleEqual(d1.LngHi().GetDegrees(), 180);
        Assert.Equal(d1.Lat, new(-S2.M_PI_2, -S2.M_PI_4));
        Assert.Equal(d1.Lng, new(0, Math.PI));
    }
示例#30
0
    public void Test_S2LatLngRect_GetDirectedHausdorffDistanceRectToRectNearPole()
    {
        // Tests near south pole.
        S2LatLngRect a = RectFromDegrees(-87, 0, -85, 3);

        VerifyGetDirectedHausdorffDistance(a, RectFromDegrees(-89, 1, -88, 2));
        VerifyGetDirectedHausdorffDistance(a, RectFromDegrees(-84, 1, -83, 2));
        VerifyGetDirectedHausdorffDistance(a, RectFromDegrees(-88, 90, -86, 91));
        VerifyGetDirectedHausdorffDistance(a, RectFromDegrees(-84, -91, -83, -90));
        VerifyGetDirectedHausdorffDistance(a, RectFromDegrees(-90, 181, -89, 182));
        VerifyGetDirectedHausdorffDistance(a, RectFromDegrees(-84, 181, -83, 182));
    }
示例#31
0
    public void Test_S2LatLngRect_EncodeDecode()
    {
        S2LatLngRect r       = RectFromDegrees(-20, -80, 10, 20);
        Encoder      encoder = new();

        r.Encode(encoder);
        var decoder = encoder.Decoder();

        var(success, decoded_rect) = S2LatLngRect.Decode(decoder);
        Assert.True(success);
        Assert.Equal(r, decoded_rect);
    }
        private static S1Angle bruteForceDistance(S2LatLngRect a, S2LatLngRect b)
        {
            if (a.Intersects(b))
            {
                return S1Angle.FromRadians(0);
            }

            // Compare every point in 'a' against every latitude edge and longitude edge
            // in 'b', and vice-versa, for a total of 16 point-vs-latitude-edge tests
            // and 16 point-vs-longitude-edge tests.
            S2LatLng[] pntA =
            {
                new S2LatLng(a.LatLo, a.LngLo), new S2LatLng(a.LatLo, a.LngHi),
                new S2LatLng(a.LatHi, a.LngHi), new S2LatLng(a.LatHi, a.LngLo)
            };
            S2LatLng[] pntB =
            {
                new S2LatLng(b.LatLo, b.LngLo), new S2LatLng(b.LatLo, b.LngHi),
                new S2LatLng(b.LatHi, b.LngHi), new S2LatLng(b.LatHi, b.LngLo)
            };

            // Make arrays containing the lo/hi latitudes and the lo/hi longitude edges.
            S1Angle[] latA = {a.LatLo, a.LatHi};
            S1Angle[] latB = {b.LatLo, b.LatHi};
            S2Point[][] lng_edge_a =
            {new[] {pntA[0].ToPoint(), pntA[3].ToPoint()}, new[] {pntA[1].ToPoint(), pntA[2].ToPoint()}};
            S2Point[][] lng_edge_b =
            {new[] {pntB[0].ToPoint(), pntB[3].ToPoint()}, new[] {pntB[1].ToPoint(), pntB[2].ToPoint()}};

            var minDistance = S1Angle.FromDegrees(180.0);
            for (var i = 0; i < 4; ++i)
            {
                // For each point in a and b.
                var currentA = pntA[i];
                var currentB = pntB[i];

                for (var j = 0; j < 2; ++j)
                {
                    // Get distances to latitude and longitude edges.
                    var aToLat = getDistance(currentA, latB[j], b.Lng);
                    var bToLat = getDistance(currentB, latA[j], a.Lng);
                    var aToLng =
                        S2EdgeUtil.GetDistance(currentA.ToPoint(), lng_edge_b[j][0], lng_edge_b[j][1]);
                    var bToLng =
                        S2EdgeUtil.GetDistance(currentB.ToPoint(), lng_edge_a[j][0], lng_edge_a[j][1]);

                    minDistance = S1Angle.Min(
                        minDistance, S1Angle.Min(aToLat, S1Angle.Min(bToLat, S1Angle.Min(aToLng, bToLng))));
                }
            }
            return minDistance;
        }
        public void testCellOps(S2LatLngRect r, S2Cell cell, int level)
        {
            // Test the relationship between the given rectangle and cell:
            // 0 == no intersection, 1 == MayIntersect, 2 == Intersects,
            // 3 == Vertex Containment, 4 == Contains

            var vertexContained = false;
            for (var i = 0; i < 4; ++i)
            {
                if (r.Contains(cell.GetVertexRaw(i))
                    || (!r.IsEmpty && cell.Contains(r.GetVertex(i).ToPoint())))
                {
                    vertexContained = true;
                }
            }
            assertEquals(r.MayIntersect(cell), level >= 1);
            assertEquals(r.Intersects(cell), level >= 2);
            assertEquals(vertexContained, level >= 3);
            assertEquals(r.Contains(cell), level >= 4);
        }
        public void AddPoint(S2Point b)
        {
            // assert (S2.isUnitLength(b));

            var bLatLng = new S2LatLng(b);

            if (bound.IsEmpty)
            {
                bound = bound.AddPoint(bLatLng);
            }
            else
            {
                // We can't just call bound.addPoint(bLatLng) here, since we need to
                // ensure that all the longitudes between "a" and "b" are included.
                bound = bound.Union(S2LatLngRect.FromPointPair(aLatLng, bLatLng));

                // Check whether the Min/Max latitude occurs in the edge interior.
                // We find the normal to the plane containing AB, and then a vector
                // "dir" in this plane that also passes through the equator. We use
                // RobustCrossProd to ensure that the edge normal is accurate even
                // when the two points are very close together.
                var aCrossB = S2.RobustCrossProd(a, b);
                var dir = S2Point.CrossProd(aCrossB, new S2Point(0, 0, 1));
                var da = dir.DotProd(a);
                var db = dir.DotProd(b);

                if (da*db < 0)
                {
                    // Minimum/maximum latitude occurs in the edge interior. This affects
                    // the latitude bounds but not the longitude bounds.
                    var absLat = Math.Acos(Math.Abs(aCrossB[2]/aCrossB.Norm));
                    var lat = bound.Lat;
                    if (da < 0)
                    {
                        // It's possible that absLat < lat.lo() due to numerical errors.
                        lat = new R1Interval(lat.Lo, Math.Max(absLat, bound.Lat.Hi));
                    }
                    else
                    {
                        lat = new R1Interval(Math.Min(-absLat, bound.Lat.Lo), lat.Hi);
                    }
                    bound = new S2LatLngRect(lat, bound.Lng);
                }
            }
            a = b;
            aLatLng = bLatLng;
        }
        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);
            }
        }
        /**
         * This method verifies a.getDistance(b) by comparing its result against a
         * brute-force implementation. The correctness of the brute-force version is
         * much easier to verify by inspection.
         */

        private static void verifyGetDistance(S2LatLngRect a, S2LatLngRect b)
        {
            var distance1 = bruteForceDistance(a, b);
            var distance2 = a.GetDistance(b);
            assertEquals(distance1.Radians, distance2.Radians, 1e-10);
        }
        /**
         * This method verifies a.getDistance(b), where b is a S2LatLng, by comparing
         * its result against a.getDistance(c), c being the point rectangle created
         * from b.
         */

        private static void verifyGetRectPointDistance(S2LatLngRect a, S2LatLng p)
        {
            var distance1 = bruteForceRectPointDistance(a, p.Normalized);
            var distance2 = a.GetDistance(p.Normalized);
            assertEquals(distance1.Radians, distance2.Radians, 1e-10);
        }
 public RectBounder()
 {
     bound = S2LatLngRect.Empty;
 }
        private static S1Angle bruteForceRectPointDistance(S2LatLngRect a, S2LatLng b)
        {
            if (a.Contains(b))
            {
                return S1Angle.FromRadians(0);
            }

            var bToLoLat = getDistance(b, a.LatLo, a.Lng);
            var bToHiLat = getDistance(b, a.LatHi, a.Lng);
            var bToLoLng =
                S2EdgeUtil.GetDistance(b.ToPoint(), new S2LatLng(a.LatLo, a.LngLo).ToPoint(),
                                       new S2LatLng(a.LatHi, a.LngLo).ToPoint());
            var bToHiLng =
                S2EdgeUtil.GetDistance(b.ToPoint(), new S2LatLng(a.LatLo, a.LngHi).ToPoint(),
                                       new S2LatLng(a.LatHi, a.LngHi).ToPoint());
            return S1Angle.Min(bToLoLat, S1Angle.Min(bToHiLat, S1Angle.Min(bToLoLng, bToHiLng)));
        }