Exemplo n.º 1
0
    public void Test_S2RegionTermIndexer_MaxLevelSetLoosely()
    {
        // Test that correct terms are generated even when (max_level - min_level)
        // is not a multiple of level_mod.
        var options = new S2RegionTermIndexer.Options();

        options.MinLevel = (1);
        options.LevelMod = (2);
        options.MaxLevel = (19);
        var indexer1 = new S2RegionTermIndexer(options);

        options.MaxLevel = (20);
        var indexer2 = new S2RegionTermIndexer(options);

        S2Point point = S2Testing.RandomPoint();

        Assert.Equal(indexer1.GetIndexTerms(point, ""),
                     indexer2.GetIndexTerms(point, ""));
        Assert.Equal(indexer1.GetQueryTerms(point, ""),
                     indexer2.GetQueryTerms(point, ""));

        S2Cap cap = S2Testing.GetRandomCap(0.0, 1.0);  // Area range.

        Assert.Equal(indexer1.GetIndexTerms(cap, ""),
                     indexer2.GetIndexTerms(cap, ""));
        Assert.Equal(indexer1.GetQueryTerms(cap, ""),
                     indexer2.GetQueryTerms(cap, ""));
    }
Exemplo n.º 2
0
    public void Test_S2PointVectorShape_ConstructionAndAccess()
    {
        const int kNumPoints = 100;

        S2Point[] points = new S2Point[kNumPoints];
        S2Testing.Random.Reset(S2Testing.Random.RandomSeed);
        for (int i = 0; i < kNumPoints; ++i)
        {
            points[i] = S2Testing.RandomPoint();
        }
        S2PointVectorShape shape = new(points);

        Assert.Equal(kNumPoints, shape.NumEdges());
        Assert.Equal(kNumPoints, shape.NumChains());
        Assert.Equal(0, shape.Dimension());
        Assert.False(shape.IsEmpty());
        Assert.False(shape.IsFull());
        for (int i = 0; i < kNumPoints; ++i)
        {
            Assert.Equal(i, shape.GetChain(i).Start);
            Assert.Equal(1, shape.GetChain(i).Length);
            var     edge = shape.GetEdge(i);
            S2Point pt   = points[i];
            Assert.Equal(pt, edge.V0);
            Assert.Equal(pt, edge.V1);
        }
    }
Exemplo n.º 3
0
        public void Test_S2EdgeVectorShape_EdgeAccess()
        {
            S2EdgeVectorShape shape = new();

            S2Testing.Random.Reset(S2Testing.Random.RandomSeed);
            int kNumEdges = 100;
            List <(S2Point, S2Point)> edges = new();

            for (int i = 0; i < kNumEdges; ++i)
            {
                S2Point a = S2Testing.RandomPoint();  // Control the evaluation order
                edges.Add((a, S2Testing.RandomPoint()));
                shape.Add(edges.Last().Item1, edges.Last().Item2);
            }
            Assert.Equal(kNumEdges, shape.NumEdges());
            Assert.Equal(kNumEdges, shape.NumChains());
            Assert.Equal(1, shape.Dimension());
            Assert.False(shape.IsEmpty());
            Assert.False(shape.IsFull());
            for (int i = 0; i < kNumEdges; ++i)
            {
                Assert.Equal(i, shape.GetChain(i).Start);
                Assert.Equal(1, shape.GetChain(i).Length);
                var edge = shape.GetEdge(i);
                Assert.Equal(edges[i].Item1, edge.V0);
                Assert.Equal(edges[i].Item2, edge.V1);
            }
        }
Exemplo n.º 4
0
 public void Test_S2_Rotate()
 {
     for (int iter = 0; iter < 1000; ++iter)
     {
         S2Point axis   = S2Testing.RandomPoint();
         S2Point target = S2Testing.RandomPoint();
         // Choose a distance whose logarithm is uniformly distributed.
         double distance = Math.PI * Math.Pow(1e-15, S2Testing.Random.RandDouble());
         // Sometimes choose points near the far side of the axis.
         if (S2Testing.Random.OneIn(5))
         {
             distance = Math.PI - distance;
         }
         S2Point p = S2.InterpolateAtDistance(S1Angle.FromRadians(distance),
                                              axis, target);
         // Choose the rotation angle.
         double angle = S2.M_2_PI * Math.Pow(1e-15, S2Testing.Random.RandDouble());
         if (S2Testing.Random.OneIn(3))
         {
             angle = -angle;
         }
         if (S2Testing.Random.OneIn(10))
         {
             angle = 0;
         }
         TestRotate(p, axis, S1Angle.FromRadians(angle));
     }
 }
Exemplo n.º 5
0
        public void Test_S2ClosestEdgeQuery_IsConservativeDistanceLessOrEqual()
        {
            // Test
            int num_tested = 0;
            int num_conservative_needed = 0;

            for (int iter = 0; iter < 1000; ++iter)
            {
                S2Testing.Random.Reset(iter + 1);  // Easier to reproduce a specific case.
                S2Point  x     = S2Testing.RandomPoint();
                S2Point  dir   = S2Testing.RandomPoint();
                S1Angle  r     = S1Angle.FromRadians(Math.PI * Math.Pow(1e-30, S2Testing.Random.RandDouble()));
                S2Point  y     = S2.InterpolateAtDistance(r, x, dir);
                Distance limit = new(r);
                if (S2Pred.CompareDistance(x, y, limit) <= 0)
                {
                    MutableS2ShapeIndex index = new();
                    index.Add(new S2PointVectorShape(new S2Point[] { x }));
                    S2ClosestEdgeQuery             query  = new(index);
                    S2ClosestEdgeQuery.PointTarget target = new(y);
                    Assert.True(query.IsConservativeDistanceLessOrEqual(target, limit));
                    ++num_tested;
                    if (!query.IsDistanceLess(target, limit))
                    {
                        ++num_conservative_needed;
                    }
                }
            }
            // Verify that in most test cases, the distance between the target points
            // was close to the desired value.  Also verify that at least in some test
            // cases, the conservative distance test was actually necessary.
            Assert.True(num_tested >= 300);
            Assert.True(num_tested <= 700);
            Assert.True(num_conservative_needed >= 25);
        }
Exemplo n.º 6
0
        private static void ChooseEdgeNearCell(S2Cell cell, out S2Point a, out S2Point b)
        {
            S2Cap cap = cell.GetCapBound();

            if (S2Testing.Random.OneIn(5))
            {
                // Choose a point anywhere on the sphere.
                a = S2Testing.RandomPoint();
            }
            else
            {
                // Choose a point inside or somewhere near the cell.
                a = S2Testing.SamplePoint(new S2Cap(cap.Center, 1.5 * cap.RadiusAngle()));
            }
            // Now choose a maximum edge length ranging from very short to very long
            // relative to the cell size, and choose the other endpoint.
            double max_length = Math.Min(100 * Math.Pow(1e-4, S2Testing.Random.RandDouble()) *
                                         cap.Radius.Radians(), S2.M_PI_2);

            b = S2Testing.SamplePoint(new S2Cap(a, S1Angle.FromRadians(max_length)));

            if (S2Testing.Random.OneIn(20))
            {
                // Occasionally replace edge with antipodal edge.
                a = -a;
                b = -b;
            }
        }
Exemplo n.º 7
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);
        }
    }
Exemplo n.º 8
0
    // This function is designed to choose line segment endpoints that are difficult
    // to handle correctly.  Given two adjacent cube vertices P and Q, it returns
    // either an edge midpoint, face midpoint, or corner vertex along the edge PQ
    // and then perturbs it slightly.  It also sometimes returns a random point from
    // anywhere on the sphere.
    private S2Point PerturbedCornerOrMidpoint(S2Point p, S2Point q)
    {
        S2Point a = (S2Testing.Random.Uniform(3) - 1) * p + (S2Testing.Random.Uniform(3) - 1) * q;

        if (S2Testing.Random.OneIn(10))
        {
            // This perturbation often has no effect except on coordinates that are
            // zero, in which case the perturbed value is so small that operations on
            // it often result in underflow.
            a += Math.Pow(1e-300, S2Testing.Random.RandDouble()) * S2Testing.RandomPoint();
        }
        else if (S2Testing.Random.OneIn(2))
        {
            // For coordinates near 1 (say > 0.5), this perturbation yields values
            // that are only a few representable values away from the initial value.
            a += 4 * S2.DoubleEpsilon * S2Testing.RandomPoint();
        }
        else
        {
            // A perturbation whose magnitude is in the range [1e-25, 1e-10].
            a += 1e-10 * Math.Pow(S2.DoubleError, S2Testing.Random.RandDouble()) * S2Testing.RandomPoint();
        }
        if (a.Norm2() < S2.DoubleMinNorm)
        {
            // If a.Norm2 is denormalized, Normalize() loses too much precision.
            return(PerturbedCornerOrMidpoint(p, q));
        }
        return(a);
    }
Exemplo n.º 9
0
 public void Test_S1ChordAngle_GetS2PointConstructorMaxError()
 {
     // Check that the error bound returned by GetS2PointConstructorMaxError() is
     // large enough.
     for (var iter = 0; iter < 100000; ++iter)
     {
         S2Testing.Random.Reset(iter);  // Easier to reproduce a specific case.
         var x = S2Testing.RandomPoint();
         var y = S2Testing.RandomPoint();
         if (S2Testing.Random.OneIn(10))
         {
             // Occasionally test a point pair that is nearly identical or antipodal.
             var r = S1Angle.FromRadians(S2.DoubleError * S2Testing.Random.RandDouble());
             y = S2.GetPointOnLine(x, y, r);
             if (S2Testing.Random.OneIn(2))
             {
                 y = -y;
             }
         }
         S1ChordAngle dist  = new(x, y);
         var          error = dist.GetS2PointConstructorMaxError();
         var          er1   = S2Pred.CompareDistance(x, y, dist.PlusError(error));
         if (er1 > 0)
         {
         }
         Assert.True(er1 <= 0);
         var er2 = S2Pred.CompareDistance(x, y, dist.PlusError(-error));
         if (er2 < 0)
         {
         }
         Assert.True(er2 >= 0);
     }
 }
Exemplo n.º 10
0
 public void Test_E6()
 {
     for (var i = 0; i < kIters; i++)
     {
         var ll    = S2LatLng.FromPoint(S2Testing.RandomPoint());
         var ll_e6 = S2LatLng.FromE6(ll.Lat().E6(), ll.Lng().E6());
         ExpectMaxDigits(ll_e6, 6);
     }
 }
Exemplo n.º 11
0
 public void Test_E7()
 {
     ExpectMaxDigits(S2LatLng.FromDegrees(0, 0), 7);
     for (var i = 0; i < kIters; i++)
     {
         var ll    = S2LatLng.FromPoint(S2Testing.RandomPoint());
         var ll_e7 = S2LatLng.FromE7(ll.Lat().E7(), ll.Lng().E7());
         ExpectMaxDigits(ll_e7, 7);
     }
 }
Exemplo n.º 12
0
    // Chooses a random S2Point that is often near the intersection of one of the
    // coodinates planes or coordinate axes with the unit sphere.  (It is possible
    // to represent very small perturbations near such points.)
    private static S2Point ChoosePoint()
    {
        var x = S2Testing.RandomPoint().ToArray();

        for (int i = 0; i < 3; ++i)
        {
            if (S2Testing.Random.OneIn(3))
            {
                x[i] *= Math.Pow(1e-50, S2Testing.Random.RandDouble());
            }
        }
        return(new S2Point(x).Normalize());
    }
Exemplo n.º 13
0
    public void Test_VisitIntersectingShapes_Points()
    {
        List <S2Point> vertices = new();

        for (int i = 0; i < 100; ++i)
        {
            vertices.Add(S2Testing.RandomPoint());
        }
        MutableS2ShapeIndex index = new();

        index.Add(new S2PointVectorShape(vertices.ToArray()));
        new VisitIntersectingShapesTest(index).Run();
    }
Exemplo n.º 14
0
 public void Test_S2_RepeatedInterpolation()
 {
     // Check that points do not drift away from unit length when repeated
     // interpolations are done.
     for (int i = 0; i < 100; ++i)
     {
         S2Point a = S2Testing.RandomPoint();
         S2Point b = S2Testing.RandomPoint();
         for (int j = 0; j < 1000; ++j)
         {
             a = S2.Interpolate(a, b, 0.01);
         }
         Assert.True(a.IsUnitLength());
     }
 }
Exemplo n.º 15
0
    public void Test_S2LatLng_TestConversion()
    {
        // Test special cases: poles, "date line"
        Assert2.DoubleEqual(90.0, new S2LatLng(S2LatLng.FromDegrees(90.0, 65.0).ToPoint()).Lat().GetDegrees());
        Assert.Equal(-S2.M_PI_2, new S2LatLng(S2LatLng.FromRadians(-S2.M_PI_2, 1).ToPoint()).LatRadians);
        Assert2.DoubleEqual(180.0, Math.Abs(new S2LatLng(S2LatLng.FromDegrees(12.2, 180.0).ToPoint()).Lng().GetDegrees()));
        Assert.Equal(Math.PI, Math.Abs(new S2LatLng(S2LatLng.FromRadians(0.1, -Math.PI).ToPoint()).LngRadians));

        // Test a bunch of random points.
        for (int i = 0; i < 100000; ++i)
        {
            S2Point p = S2Testing.RandomPoint();
            Assert.True(S2.ApproxEquals(p, new S2LatLng(p).ToPoint()));
        }
    }
Exemplo n.º 16
0
    public void Test_S2_CollinearEdgesThatDontTouch()
    {
        int kIters = 500;

        for (int iter = 0; iter < kIters; ++iter)
        {
            S2Point a = S2Testing.RandomPoint();
            S2Point d = S2Testing.RandomPoint();
            S2Point b = S2.Interpolate(0.05, a, d);
            S2Point c = S2.Interpolate(0.95, a, d);
            Assert.True(0 > S2.CrossingSign(a, b, c, d));
            Assert.True(0 > S2.CrossingSign(a, b, c, d));
            S2EdgeCrosser crosser = new(a, b, c);
            Assert.True(0 > crosser.CrossingSign(d));
            Assert.True(0 > crosser.CrossingSign(c));
        }
    }
Exemplo n.º 17
0
        public void Test_S2Cap_GetCentroid()
        {
            // Empty and full caps.
            Assert.Equal(new S2Point(), S2Cap.Empty.Centroid());
            Assert.True(S2Cap.Full.Centroid().Norm() <= S2.DoubleError);

            // Random caps.
            for (int i = 0; i < 100; ++i)
            {
                S2Point center   = S2Testing.RandomPoint();
                double  height   = S2Testing.Random.UniformDouble(0.0, 2.0);
                S2Cap   cap      = S2Cap.FromCenterHeight(center, height);
                S2Point centroid = cap.Centroid();
                S2Point expected = center * (1.0 - height / 2.0) * cap.Area();
                Assert.True((expected - centroid).Norm() <= S2.DoubleError);
            }
        }
Exemplo n.º 18
0
        public void Test_S2ClosestPointQuery_EmptyTargetOptimized()
        {
            // Ensure that the optimized algorithm handles empty targets when a distance
            // limit is specified.
            TestIndex index = new();

            for (int i = 0; i < 1000; ++i)
            {
                index.Add(S2Testing.RandomPoint(), i);
            }
            TestQuery query = new(index);

            query.Options_.MaxDistance = new S1ChordAngle(S1Angle.FromRadians(1e-5));
            MutableS2ShapeIndex target_index = new();

            TestQuery.ShapeIndexTarget target = new(target_index);
            Assert.Empty(query.FindClosestPoints(target));
        }
Exemplo n.º 19
0
        public void Test_S2CellId_Coverage()
        {
            // Make sure that random points on the sphere can be represented to the
            // expected level of accuracy, which in the worst case is Math.Sqrt(2/3) times
            // the maximum arc length between the points on the sphere associated with
            // adjacent values of "i" or "j".  (It is Math.Sqrt(2/3) rather than 1/2 because
            // the cells at the corners of each face are stretched -- they have 60 and
            // 120 degree angles.)

            double max_dist = 0.5 * S2.kMaxDiag.GetValue(S2.kMaxCellLevel);

            for (int i = 0; i < 1000000; ++i)
            {
                S2Point p = S2Testing.RandomPoint();
                S2Point q = new S2CellId(p).ToPointRaw();
                Assert.True(p.Angle(q) <= max_dist);
            }
        }
Exemplo n.º 20
0
    public void Test_S2LatLngRect_GetDistanceRandomPairs()
    {
        // Test random pairs.
        for (int i = 0; i < 10000; ++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()));
            VerifyGetDistance(a, b);


            S2LatLng c = new(S2Testing.RandomPoint());
            VerifyGetRectPointDistance(a, c);
            VerifyGetRectPointDistance(b, c);
        }
    }
Exemplo n.º 21
0
    public void Test_S2_GetUpdateMinInteriorDistanceMaxError()
    {
        // Check that the error bound returned by
        // GetUpdateMinInteriorDistanceMaxError() is large enough.
        for (int iter = 0; iter < 10000; ++iter)
        {
            S2Point a0         = S2Testing.RandomPoint();
            var     lenRadians = Math.PI * Math.Pow(1e-20, S2Testing.Random.RandDouble());
            S1Angle len        = S1Angle.FromRadians(lenRadians);
            if (S2Testing.Random.OneIn(4))
            {
                len = S1Angle.FromRadians(S2.M_PI) - len;
            }
            S2Point a1 = S2.GetPointOnLine(a0, S2Testing.RandomPoint(), len);

            // TODO(ericv): The error bound holds for antipodal points, but the S2
            // predicates used to test the error do not support antipodal points yet.
            if (a1 == -a0)
            {
                continue;
            }
            S2Point n        = S2.RobustCrossProd(a0, a1).Normalize();
            double  f        = Math.Pow(1e-20, S2Testing.Random.RandDouble());
            S2Point a        = ((1 - f) * a0 + f * a1).Normalize();
            var     rRadians = S2.M_PI_2 * Math.Pow(1e-20, S2Testing.Random.RandDouble());
            S1Angle r        = S1Angle.FromRadians(rRadians);
            if (S2Testing.Random.OneIn(2))
            {
                r = S1Angle.FromRadians(S2.M_PI_2) - r;
            }
            S2Point      x        = S2.GetPointOnLine(a, n, r);
            S1ChordAngle min_dist = S1ChordAngle.Infinity;
            if (!S2.UpdateMinInteriorDistance(x, a0, a1, ref min_dist))
            {
                --iter; continue;
            }
            double error = S2.GetUpdateMinDistanceMaxError(min_dist);
            Assert.True(S2Pred.CompareEdgeDistance(x, a0, a1, min_dist.PlusError(error)) <= 0);
            Assert.True(S2Pred.CompareEdgeDistance(x, a0, a1, min_dist.PlusError(-error)) >= 0);
        }
    }
Exemplo n.º 22
0
    public void Test_S2LaxPolygonShape_CompareToS2Loop()
    {
        for (int iter = 0; iter < 100; ++iter)
        {
            var fractal = new S2Testing.Fractal();
            fractal.MaxLevel         = (S2Testing.Random.Uniform(5));
            fractal.FractalDimension = (1 + S2Testing.Random.RandDouble());
            S2Point center = S2Testing.RandomPoint();
            var     loop   = fractal.MakeLoop(
                S2Testing.GetRandomFrameAt(center), S1Angle.FromDegrees(5));

            // Compare S2Loop to S2LaxLoopShape.
            CompareS2LoopToShape(loop, new S2LaxLoopShape(loop));

            // Compare S2Loop to S2LaxPolygonShape.
            var loops = new List <List <S2Point> > {
                loop.CloneVertices().ToList()
            };
            CompareS2LoopToShape(loop, new S2LaxPolygonShape(loops));
        }
    }
Exemplo n.º 23
0
        public void Test_S2_GoodFastHashSpreads()
        {
            int kTestPoints = 1 << 16;
            var set         = new List <int>();
            var points      = new SortedSet <S2Point>();
            var base_       = new S2Point(1, 1, 1);

            for (var i = 0; i < kTestPoints; ++i)
            {
                // All points in a tiny cap to test avalanche property of hash
                // function (the cap would be of radius 1mm on Earth (4*10^9/2^35).
                S2Point perturbed = base_ + S2Testing.RandomPoint() / (1UL << 35);
                perturbed = perturbed.Normalize();
                set.Add(perturbed.GetHashCode());
                points.Add(perturbed);
            }
            // A real collision is extremely unlikely.
            Assert.Equal(0, kTestPoints - points.Count);
            // Allow a few for the hash.
            Assert.True(10 >= kTestPoints - set.Count);
        }
        public void Test_IntLatLngSnapFunction_SnapPoint()
        {
            for (int iter = 0; iter < 1000; ++iter)
            {
                // Test that IntLatLngSnapFunction does not modify points that were
                // generated using the S2LatLng.From{E5,E6,E7} methods.  This ensures
                // that both functions are using bitwise-compatible conversion methods.
                S2Point  p  = S2Testing.RandomPoint();
                S2LatLng ll = new(p);
                S2Point  p5 = S2LatLng.FromE5(ll.Lat().E5(), ll.Lng().E5()).ToPoint();
                Assert.Equal(p5, new IntLatLngSnapFunction(5).SnapPoint(p5));
                S2Point p6 = S2LatLng.FromE6(ll.Lat().E6(), ll.Lng().E6()).ToPoint();
                Assert.Equal(p6, new IntLatLngSnapFunction(6).SnapPoint(p6));
                S2Point p7 = S2LatLng.FromE7(ll.Lat().E7(), ll.Lng().E7()).ToPoint();
                Assert.Equal(p7, new IntLatLngSnapFunction(7).SnapPoint(p7));

                // Make sure that we're not snapping using some lower exponent.
                S2Point p7not6 = S2LatLng.FromE7(10 * ll.Lat().E6() + 1,
                                                 10 * ll.Lng().E6() + 1).ToPoint();
                Assert.NotEqual(p7not6, new IntLatLngSnapFunction(6).SnapPoint(p7not6));
            }
        }
Exemplo n.º 25
0
    public void Test_S2ContainsPointQuery_GetContainingShapes()
    {
        // Also tests ShapeContains().
        int                 kNumVerticesPerLoop = 10;
        S1Angle             kMaxLoopRadius      = S2Testing.KmToAngle(10);
        S2Cap               center_cap          = new(S2Testing.RandomPoint(), kMaxLoopRadius);
        MutableS2ShapeIndex index = new();

        for (int i = 0; i < 100; ++i)
        {
            var loop = S2Loop.MakeRegularLoop(
                S2Testing.SamplePoint(center_cap),
                S2Testing.Random.RandDouble() * kMaxLoopRadius, kNumVerticesPerLoop);
            index.Add(new S2Loop.Shape(loop));
        }
        var query = index.MakeS2ContainsPointQuery();

        for (int i = 0; i < 100; ++i)
        {
            S2Point        p        = S2Testing.SamplePoint(center_cap);
            List <S2Shape> expected = new();
            foreach (var shape in index)
            {
                var loop = ((S2Loop.Shape)shape).Loop;
                if (loop.Contains(p))
                {
                    Assert.True(query.ShapeContains(shape, p));
                    expected.Add(shape);
                }
                else
                {
                    Assert.False(query.ShapeContains(shape, p));
                }
            }
            var actual = query.GetContainingShapes(p);
            Assert.Equal(expected, actual);
        }
    }
Exemplo n.º 26
0
 public void Test_S2Cell_GetDistanceToPoint()
 {
     S2Testing.Random.Reset(S2Testing.Random.RandomSeed);
     for (int iter = 0; iter < 1000; ++iter)
     {
         _logger.WriteLine($"Iteration {iter}");
         S2Cell  cell   = new(S2Testing.GetRandomCellId());
         S2Point target = S2Testing.RandomPoint();
         S1Angle expected_to_boundary =
             GetDistanceToPointBruteForce(cell, target).ToAngle();
         S1Angle expected_to_interior =
             cell.Contains(target) ? S1Angle.Zero : expected_to_boundary;
         S1Angle expected_max =
             GetMaxDistanceToPointBruteForce(cell, target).ToAngle();
         S1Angle actual_to_boundary = cell.BoundaryDistance(target).ToAngle();
         S1Angle actual_to_interior = cell.Distance(target).ToAngle();
         S1Angle actual_max         = cell.MaxDistance(target).ToAngle();
         // The error has a peak near Pi/2 for edge distance, and another peak near
         // Pi for vertex distance.
         Assert2.Near(expected_to_boundary.Radians,
                      actual_to_boundary.Radians, 1e-12);
         Assert2.Near(expected_to_interior.Radians,
                      actual_to_interior.Radians, 1e-12);
         Assert2.Near(expected_max.Radians,
                      actual_max.Radians, 1e-12);
         if (expected_to_boundary.Radians <= Math.PI / 3)
         {
             Assert2.Near(expected_to_boundary.Radians,
                          actual_to_boundary.Radians, S2.DoubleError);
             Assert2.Near(expected_to_interior.Radians,
                          actual_to_interior.Radians, S2.DoubleError);
         }
         if (expected_max.Radians <= Math.PI / 3)
         {
             Assert2.Near(expected_max.Radians, actual_max.Radians, S2.DoubleError);
         }
     }
 }
Exemplo n.º 27
0
    public void Test_RectBounder_MaxLatitudeRandom()
    {
        // Check that the maximum latitude of edges is computed accurately to within
        // 3 * S2Constants.DoubleEpsilon (the expected maximum error).  We concentrate on maximum
        // latitudes near the equator and north pole since these are the extremes.

        const int kIters = 100;

        for (int iter = 0; iter < kIters; ++iter)
        {
            // Construct a right-handed coordinate frame (U,V,W) such that U points
            // slightly above the equator, V points at the equator, and W is slightly
            // offset from the north pole.
            S2Point u = S2Testing.RandomPoint();
            u = new S2Point(u.X, u.Y, S2.DoubleEpsilon * 1e-6 * Math.Pow(1e12, S2Testing.Random.RandDouble()));  // log is uniform
            u = u.Normalize();
            S2Point v = S2.RobustCrossProd(new S2Point(0, 0, 1), u).Normalize();
            S2Point w = S2.RobustCrossProd(u, v).Normalize();

            // Construct a line segment AB that passes through U, and check that the
            // maximum latitude of this segment matches the latitude of U.
            S2Point      a        = (u - S2Testing.Random.RandDouble() * v).Normalize();
            S2Point      b        = (u + S2Testing.Random.RandDouble() * v).Normalize();
            S2LatLngRect ab_bound = GetEdgeBound(a, b);
            Assert2.Near(S2LatLng.Latitude(u).Radians,
                         ab_bound.Lat.Hi, kRectError.LatRadians);

            // Construct a line segment CD that passes through W, and check that the
            // maximum latitude of this segment matches the latitude of W.
            S2Point      c        = (w - S2Testing.Random.RandDouble() * v).Normalize();
            S2Point      d        = (w + S2Testing.Random.RandDouble() * v).Normalize();
            S2LatLngRect cd_bound = GetEdgeBound(c, d);
            Assert2.Near(S2LatLng.Latitude(w).Radians,
                         cd_bound.Lat.Hi, kRectError.LatRadians);
        }
    }
Exemplo n.º 28
0
        public void Test_S2PolylineSimplifier_Precision()
        {
            // This is a rough upper bound on both the error in constructing the disc
            // locations (i.e., S2.InterpolateAtDistance, etc), and also on the
            // padding that S2PolylineSimplifier uses to ensure that its results are
            // conservative (i.e., the error calculated by GetSemiwidth).
            S1Angle kMaxError = S1Angle.FromRadians(25 * S2.DoubleEpsilon);

            // We repeatedly generate a random edge.  We then target several discs that
            // barely overlap the edge, and avoid several discs that barely miss the
            // edge.  About half the time, we choose one disc and make it slightly too
            // large or too small so that targeting fails.
            int kIters = 1000;  // Passes with 1 million iterations.

            for (int iter = 0; iter < kIters; ++iter)
            {
                S2Testing.Random.Reset(iter + 1);  // Easier to reproduce a specific case.
                S2Point src        = S2Testing.RandomPoint();
                var     simplifier = new S2PolylineSimplifier(src);
                S2Point dst        = S2.InterpolateAtDistance(
                    S1Angle.FromRadians(S2Testing.Random.RandDouble()),
                    src, S2Testing.RandomPoint());
                S2Point n = S2.RobustCrossProd(src, dst).Normalize();

                // If bad_disc >= 0, then we make targeting fail for that disc.
                int kNumDiscs = 5;
                int bad_disc  = S2Testing.Random.Uniform(2 * kNumDiscs) - kNumDiscs;
                for (int i = 0; i < kNumDiscs; ++i)
                {
                    // The center of the disc projects to a point that is the given fraction
                    // "f" along the edge (src, dst).  If f < 0, the center is located
                    // behind "src" (in order to test this case).
                    double  f       = S2Testing.Random.UniformDouble(-0.5, 1.0);
                    S2Point a       = ((1 - f) * src + f * dst).Normalize();
                    S1Angle r       = S1Angle.FromRadians(S2Testing.Random.RandDouble());
                    bool    on_left = S2Testing.Random.OneIn(2);
                    S2Point x       = S2.InterpolateAtDistance(r, a, on_left ? n : -n);
                    // If the disc is behind "src", adjust its radius so that it just
                    // touches "src" rather than just touching the line through (src, dst).
                    if (f < 0)
                    {
                        r = new S1Angle(src, x);
                    }
                    // We grow the radius slightly if we want to target the disc and shrink
                    // it otherwise, *unless* we want targeting to fail for this disc, in
                    // which case these actions are reversed.
                    bool avoid       = S2Testing.Random.OneIn(2);
                    bool grow_radius = (avoid == (i == bad_disc));
                    var  radius      = new S1ChordAngle(grow_radius ? r + kMaxError : r - kMaxError);
                    if (avoid)
                    {
                        simplifier.AvoidDisc(x, radius, on_left);
                    }
                    else
                    {
                        simplifier.TargetDisc(x, radius);
                    }
                }
                // The result is true iff all the discraints were satisfiable.
                Assert.Equal(bad_disc < 0, simplifier.Extend(dst));
            }
        }
Exemplo n.º 29
0
    public void Test_S2_AreaMethods()
    {
        S2Point pz   = new(0, 0, 1);
        S2Point p000 = new(1, 0, 0);
        S2Point p045 = new S2Point(1, 1, 0).Normalize();
        S2Point p090 = new(0, 1, 0);
        S2Point p180 = new(-1, 0, 0);

        Assert2.Near(S2.Area(p000, p090, pz), S2.M_PI_2);
        Assert2.Near(S2.Area(p045, pz, p180), 3 * S2.M_PI_4);

        // Make sure that Area() has good *relative* accuracy even for
        // very small areas.
        const double eps       = 1e-10;
        S2Point      pepsx     = new S2Point(eps, 0, 1).Normalize();
        S2Point      pepsy     = new S2Point(0, eps, 1).Normalize();
        double       expected1 = 0.5 * eps * eps;

        Assert2.Near(S2.Area(pepsx, pepsy, pz), expected1, 1e-14 * expected1);

        // Make sure that it can handle degenerate triangles.
        S2Point pr = new S2Point(0.257, -0.5723, 0.112).Normalize();
        S2Point pq = new S2Point(-0.747, 0.401, 0.2235).Normalize();

        Assert.Equal(0, S2.Area(pr, pr, pr));
        // The following test is not exact due to rounding error.
        Assert2.Near(S2.Area(pr, pq, pr), 0, S2.DoubleError);
        Assert.Equal(0, S2.Area(p000, p045, p090));

        double max_girard = 0;

        for (int i = 0; i < 10000; ++i)
        {
            S2Point p0 = S2Testing.RandomPoint();
            S2Point d1 = S2Testing.RandomPoint();
            S2Point d2 = S2Testing.RandomPoint();
            S2Point p1 = (p0 + S2.DoubleError * d1).Normalize();
            S2Point p2 = (p0 + S2.DoubleError * d2).Normalize();
            // The actual displacement can be as much as 1.2e-15 due to roundoff.
            // This yields a maximum triangle area of about 0.7e-30.
            Assert.True(S2.Area(p0, p1, p2) <= 0.7e-30);
            max_girard = Math.Max(max_girard, S2.GirardArea(p0, p1, p2));
        }
        // This check only passes if GirardArea() uses RobustCrossProd().
        Assert.True(max_girard <= 1e-14);

        // Try a very long and skinny triangle.
        S2Point p045eps   = new S2Point(1, 1, eps).Normalize();
        double  expected2 = 5.8578643762690495119753e-11; // Mathematica.

        Assert2.Near(S2.Area(p000, p045eps, p090), expected2, 1e-9 * expected2);

        // Triangles with near-180 degree edges that sum to a quarter-sphere.
        const double eps2          = 1e-14;
        S2Point      p000eps2      = new S2Point(1, 0.1 * eps2, eps2).Normalize();
        double       quarter_area1 = S2.Area(p000eps2, p000, p045) +
                                     S2.Area(p000eps2, p045, p180) +
                                     S2.Area(p000eps2, p180, pz) +
                                     S2.Area(p000eps2, pz, p000);

        Assert2.Near(quarter_area1, Math.PI);

        // Four other triangles that sum to a quarter-sphere.
        S2Point p045eps2      = new S2Point(1, 1, eps2).Normalize();
        double  quarter_area2 = S2.Area(p045eps2, p000, p045) +
                                S2.Area(p045eps2, p045, p180) +
                                S2.Area(p045eps2, p180, pz) +
                                S2.Area(p045eps2, pz, p000);

        Assert2.Near(quarter_area2, Math.PI);

        // Compute the area of a hemisphere using four triangles with one near-180
        // degree edge and one near-degenerate edge.
        for (int i = 0; i < 100; ++i)
        {
            double  lng    = S2.M_2_PI * S2Testing.Random.RandDouble();
            S2Point p0     = S2LatLng.FromRadians(1e-20, lng).Normalized().ToPoint();
            S2Point p1     = S2LatLng.FromRadians(0, lng).Normalized().ToPoint();
            double  p2_lng = lng + S2Testing.Random.RandDouble();
            S2Point p2     = S2LatLng.FromRadians(0, p2_lng).Normalized().ToPoint();
            S2Point p3     = S2LatLng.FromRadians(0, lng + Math.PI).Normalized().ToPoint();
            S2Point p4     = S2LatLng.FromRadians(0, lng + 5.0).Normalized().ToPoint();
            double  area   = (S2.Area(p0, p1, p2) + S2.Area(p0, p2, p3) +
                              S2.Area(p0, p3, p4) + S2.Area(p0, p4, p1));
            Assert2.Near(area, S2.M_2_PI, 2e-15);
        }

        // This tests a case where the triangle has zero area, but S2.Area()
        // computes (dmin > 0) due to rounding errors.
        Assert.Equal(0.0, S2.Area(S2LatLng.FromDegrees(-45, -170).ToPoint(),
                                  S2LatLng.FromDegrees(45, -170).ToPoint(),
                                  S2LatLng.FromDegrees(0, -170).ToPoint()));
    }
Exemplo n.º 30
0
    private void TestRandomCaps(S2RegionTermIndexer.Options options, QueryType query_type)
    {
        // This function creates an index consisting either of points (if
        // options.index_contains_points_only() is true) or S2Caps of random size.
        // It then executes queries consisting of points (if query_type == POINT)
        // or S2Caps of random size (if query_type == CAP).
        var indexer = new S2RegionTermIndexer(options);
        var coverer = new S2RegionCoverer(options);
        var caps = new List <S2Cap>();
        var coverings = new List <S2CellUnion>();
        var index = new Dictionary <string, List <int> >();
        int index_terms = 0, query_terms = 0;

        for (int i = 0; i < iters; ++i)
        {
            // Choose the region to be indexed: either a single point or a cap
            // of random size (up to a full sphere).
            S2Cap         cap;
            List <string> terms;
            if (options.IndexContainsPointsOnly)
            {
                cap   = S2Cap.FromPoint(S2Testing.RandomPoint());
                terms = indexer.GetIndexTerms(cap.Center, "");
            }
            else
            {
                cap = S2Testing.GetRandomCap(
                    0.3 * S2Cell.AverageArea(options.MaxLevel),
                    4.0 * S2Cell.AverageArea(options.MinLevel));
                terms = indexer.GetIndexTerms(cap, "");
            }
            caps.Add(cap);
            coverings.Add(coverer.GetCovering(cap));
            foreach (var term in terms)
            {
                if (!index.ContainsKey(term))
                {
                    index.Add(term, new List <int>());
                }

                index[term].Add(i);
            }
            index_terms += terms.Count;
        }
        for (int i = 0; i < iters; ++i)
        {
            // Choose the region to be queried: either a random point or a cap of
            // random size.
            S2Cap         cap;
            List <string> terms;
            if (query_type == QueryType.CAP)
            {
                cap   = S2Cap.FromPoint(S2Testing.RandomPoint());
                terms = indexer.GetQueryTerms(cap.Center, "");
            }
            else
            {
                cap = S2Testing.GetRandomCap(
                    0.3 * S2Cell.AverageArea(options.MaxLevel),
                    4.0 * S2Cell.AverageArea(options.MinLevel));
                terms = indexer.GetQueryTerms(cap, "");
            }
            // Compute the expected results of the S2Cell query by brute force.
            S2CellUnion covering = coverer.GetCovering(cap);
            var         expected = new List <int>();
            var         actual   = new List <int>();
            for (int j = 0; j < caps.Count; ++j)
            {
                if (covering.Intersects(coverings[j]))
                {
                    expected.Add(j);
                }
            }
            foreach (var term in terms)
            {
                actual.AddRange(index[term]);
            }
            Assert.Equal(expected, actual);
            query_terms += terms.Count;
        }
        _logger.WriteLine($"Index terms/doc: {((double)index_terms) / iters:2f},  Query terms/doc: {((double)query_terms) / iters:2f}");
    }