예제 #1
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()));
    }
예제 #2
0
        public void testAngleArea()
        {
            var pz   = new S2Point(0, 0, 1);
            var p000 = new S2Point(1, 0, 0);
            var p045 = new S2Point(1, 1, 0);
            var p090 = new S2Point(0, 1, 0);
            var p180 = new S2Point(-1, 0, 0);

            assertDoubleNear(S2.Angle(p000, pz, p045), S2.PiOver4);
            assertDoubleNear(S2.Angle(p045, pz, p180), 3 * S2.PiOver4);
            assertDoubleNear(S2.Angle(p000, pz, p180), S2.Pi);
            assertDoubleNear(S2.Angle(pz, p000, pz), 0);
            assertDoubleNear(S2.Angle(pz, p000, p045), S2.PiOver2);

            assertDoubleNear(S2.Area(p000, p090, pz), S2.PiOver2);
            assertDoubleNear(S2.Area(p045, pz, p180), 3 * S2.PiOver4);

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

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

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

            assertEquals(S2.Area(pr, pr, pr), 0.0);
            // TODO: The following test is not exact in optimized mode because the
            // compiler chooses to mix 64-bit and 80-bit intermediate results.
            assertDoubleNear(S2.Area(pr, pq, pr), 0);
            assertEquals(S2.Area(p000, p045, p090), 0.0);

            double maxGirard = 0;

            for (var i = 0; i < 10000; ++i)
            {
                var p0 = randomPoint();
                var d1 = randomPoint();
                var d2 = randomPoint();
                var p1 = p0 + (d1 * 1e-15);
                var p2 = p0 + (d2 * 1e-15);
                // 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.
                assertTrue(S2.Area(p0, p1, p2) < 0.7e-30);
                maxGirard = Math.Max(maxGirard, S2.GirardArea(p0, p1, p2));
            }
            Console.WriteLine("Worst case Girard for triangle area 1e-30: " + maxGirard);

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

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

            // Triangles with near-180 degree edges that sum to a quarter-sphere.
            var eps2         = 1e-10;
            var p000eps2     = new S2Point(1, 0.1 * eps2, eps2);
            var quarterArea1 =
                S2.Area(p000eps2, p000, p090) + S2.Area(p000eps2, p090, p180) + S2.Area(p000eps2, p180, pz)
                + S2.Area(p000eps2, pz, p000);

            assertDoubleNear(quarterArea1, S2.Pi);

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

            assertDoubleNear(quarterArea2, S2.Pi);
        }