コード例 #1
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);
        }
コード例 #2
0
    private static S2Point PerturbATowardsB(S2Point a, S2Point b)
    {
        var choice = S2Testing.Random.RandDouble();

        if (choice < 0.1)
        {
            return(a);
        }
        if (choice < 0.3)
        {
            // Return a point that is exactly proportional to A and that still
            // satisfies S2.IsUnitLength().
            for (; ;)
            {
                var b2 = (2 - a.Norm() + 5 * (S2Testing.Random.RandDouble() - 0.5) * S2.DoubleEpsilon) * a;
                if (b2 != a && b2.IsUnitLength())
                {
                    return(b2);
                }
            }
        }
        if (choice < 0.5)
        {
            // Return a point such that the distance squared to A will underflow.
            return(S2.InterpolateAtDistance(S1Angle.FromRadians(1e-300), a, b));
        }
        // Otherwise return a point whose distance from A is near S2Constants.DoubleEpsilon such
        // that the log of the pdf is uniformly distributed.
        double distance = S2.DoubleEpsilon * 1e-5 * Math.Pow(1e6, S2Testing.Random.RandDouble());

        return(S2.InterpolateAtDistance(S1Angle.FromRadians(distance), a, b));
    }
コード例 #3
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));
     }
 }
コード例 #4
0
    private static S2Point PerturbAtDistance(S1Angle distance, S2Point a0, S2Point b0)
    {
        S2Point x = S2.InterpolateAtDistance(distance, a0, b0);

        if (S2Testing.Random.OneIn(2))
        {
            for (int i = 0; i < 3; ++i)
            {
                x = x.SetAxis(i, MathUtils.NextAfter(x[i], S2Testing.Random.OneIn(2) ? 1 : -1));
            }
            x = x.Normalize();
        }
        return(x);
    }
コード例 #5
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));
            }
        }