Exemple #1
0
    private static void TestIntervalOps(S1Interval x, S1Interval y, string expected_relation, S1Interval expected_union, S1Interval 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');

        // bounds() returns a reference to a member variable, so we need to
        // make a copy when invoking it on a temporary object.
        Assert.Equal(R2Point.FromCoords(x.Union(y).Bounds()).Bounds(), expected_union.Bounds());
        Assert.Equal(R2Point.FromCoords(x.Intersection(y).Bounds()).Bounds(),
                     expected_intersection.Bounds());

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

        if (y.Lo == y.Hi)
        {
            var r = S1Interval.AddPoint(x, y.Lo);
            Assert.Equal(r.Bounds(), expected_union.Bounds());
        }
    }
Exemple #2
0
 public void Test_S1IntervalTestBase_Contains()
 {
     // Contains(double), InteriorContains(double)
     Assert.True(!empty.Contains(0) && !empty.Contains(Math.PI) &&
                 !empty.Contains(-Math.PI));
     Assert.True(!empty.InteriorContains(Math.PI) && !empty.InteriorContains(-Math.PI));
     Assert.True(full.Contains(0) && full.Contains(Math.PI) && full.Contains(-Math.PI));
     Assert.True(full.InteriorContains(Math.PI) && full.InteriorContains(-Math.PI));
     Assert.True(quad12.Contains(0) && quad12.Contains(Math.PI) &&
                 quad12.Contains(-Math.PI));
     Assert.True(quad12.InteriorContains(S2.M_PI_2) && !quad12.InteriorContains(0));
     Assert.True(!quad12.InteriorContains(Math.PI) &&
                 !quad12.InteriorContains(-Math.PI));
     Assert.True(quad23.Contains(S2.M_PI_2) && quad23.Contains(-S2.M_PI_2));
     Assert.True(quad23.Contains(Math.PI) && quad23.Contains(-Math.PI));
     Assert.True(!quad23.Contains(0));
     Assert.True(!quad23.InteriorContains(S2.M_PI_2) &&
                 !quad23.InteriorContains(-S2.M_PI_2));
     Assert.True(quad23.InteriorContains(Math.PI) && quad23.InteriorContains(-Math.PI));
     Assert.True(!quad23.InteriorContains(0));
     Assert.True(pi.Contains(Math.PI) && pi.Contains(-Math.PI) && !pi.Contains(0));
     Assert.True(!pi.InteriorContains(Math.PI) && !pi.InteriorContains(-Math.PI));
     Assert.True(mipi.Contains(Math.PI) && mipi.Contains(-Math.PI) && !mipi.Contains(0));
     Assert.True(!mipi.InteriorContains(Math.PI) && !mipi.InteriorContains(-Math.PI));
     Assert.True(zero.Contains(0) && !zero.InteriorContains(0));
 }
Exemple #3
0
    // Returns the minimum distance from X to the latitude line segment defined by
    // the given latitude and longitude interval.
    private static S1Angle GetDistance(S2LatLng x, S1Angle lat, S1Interval interval)
    {
        Assert.True(x.IsValid());
        Assert.True(interval.IsValid());

        // Is X inside the longitude interval?
        if (interval.Contains(x.LngRadians))
        {
            return(S1Angle.FromRadians((x.Lat() - lat).Abs()));
        }

        // Return the distance to the closer endpoint.
        return(new[] { x.GetDistance(new S2LatLng(lat, S1Angle.FromRadians(interval.Lo))),
                       x.GetDistance(new S2LatLng(lat, S1Angle.FromRadians(interval.Hi))) }.Min());
    }
        /**
         * Returns the minimum distance from X to the latitude line segment defined by
         * the given latitude and longitude interval.
         */

        private static S1Angle getDistance(S2LatLng x, S1Angle lat, S1Interval interval)
        {
            assertTrue(x.IsValid);
            assertTrue(interval.IsValid);

            // Is X inside the longitude interval?
            if (interval.Contains(x.Lng.Radians))
            {
                return(S1Angle.FromRadians(Math.Abs(x.Lat.Radians - lat.Radians)));
            }

            // Return the distance to the closer endpoint.
            return(S1Angle.Min(x.GetDistance(new S2LatLng(lat, S1Angle.FromRadians(interval.Lo))),
                               x.GetDistance(new S2LatLng(lat, S1Angle.FromRadians(interval.Hi)))));
        }
        /**
         * Returns the minimum distance from X to the latitude line segment defined by
         * the given latitude and longitude interval.
         */

        private static S1Angle getDistance(S2LatLng x, S1Angle lat, S1Interval interval)
        {
            assertTrue(x.IsValid);
            assertTrue(interval.IsValid);

            // Is X inside the longitude interval?
            if (interval.Contains(x.Lng.Radians))
                return S1Angle.FromRadians(Math.Abs(x.Lat.Radians - lat.Radians));

            // Return the distance to the closer endpoint.
            return S1Angle.Min(x.GetDistance(new S2LatLng(lat, S1Angle.FromRadians(interval.Lo))),
                               x.GetDistance(new S2LatLng(lat, S1Angle.FromRadians(interval.Hi))));
        }
    private void TestFaceClipping(S2Point a_raw, S2Point b_raw)
    {
        S2Point a = a_raw.Normalize();
        S2Point b = b_raw.Normalize();

        // First we test GetFaceSegments.
        FaceSegmentVector segments = new();

        GetFaceSegments(a, b, segments);
        int n = segments.Count;

        Assert.True(n >= 1);

        var msg = new StringBuilder($"\nA={a_raw}\nB={b_raw}\nN={S2.RobustCrossProd(a, b)}\nSegments:\n");
        int i1  = 0;

        foreach (var s in segments)
        {
            msg.AppendLine($"{i1++}: face={s.face}, a={s.a}, b={s.b}");
        }
        _logger.WriteLine(msg.ToString());

        R2Rect biunit        = new(new R1Interval(-1, 1), new R1Interval(-1, 1));
        var    kErrorRadians = kFaceClipErrorRadians;

        // The first and last vertices should approximately equal A and B.
        Assert.True(a.Angle(S2.FaceUVtoXYZ(segments[0].face, segments[0].a)) <=
                    kErrorRadians);
        Assert.True(b.Angle(S2.FaceUVtoXYZ(segments[n - 1].face, segments[n - 1].b)) <=
                    kErrorRadians);

        S2Point norm      = S2.RobustCrossProd(a, b).Normalize();
        S2Point a_tangent = norm.CrossProd(a);
        S2Point b_tangent = b.CrossProd(norm);

        for (int i = 0; i < n; ++i)
        {
            // Vertices may not protrude outside the biunit square.
            Assert.True(biunit.Contains(segments[i].a));
            Assert.True(biunit.Contains(segments[i].b));
            if (i == 0)
            {
                continue;
            }

            // The two representations of each interior vertex (on adjacent faces)
            // must correspond to exactly the same S2Point.
            Assert.NotEqual(segments[i - 1].face, segments[i].face);
            Assert.Equal(S2.FaceUVtoXYZ(segments[i - 1].face, segments[i - 1].b),
                         S2.FaceUVtoXYZ(segments[i].face, segments[i].a));

            // Interior vertices should be in the plane containing A and B, and should
            // be contained in the wedge of angles between A and B (i.e., the dot
            // products with a_tangent and b_tangent should be non-negative).
            S2Point p = S2.FaceUVtoXYZ(segments[i].face, segments[i].a).Normalize();
            Assert.True(Math.Abs(p.DotProd(norm)) <= kErrorRadians);
            Assert.True(p.DotProd(a_tangent) >= -kErrorRadians);
            Assert.True(p.DotProd(b_tangent) >= -kErrorRadians);
        }

        // Now we test ClipToPaddedFace (sometimes with a padding of zero).  We do
        // this by defining an (x,y) coordinate system for the plane containing AB,
        // and converting points along the great circle AB to angles in the range
        // [-Pi, Pi].  We then accumulate the angle intervals spanned by each
        // clipped edge; the union over all 6 faces should approximately equal the
        // interval covered by the original edge.
        double     padding = S2Testing.Random.OneIn(10) ? 0.0 : 1e-10 * Math.Pow(1e-5, S2Testing.Random.RandDouble());
        S2Point    x_axis = a, y_axis = a_tangent;
        S1Interval expected_angles = new(0, a.Angle(b));
        S1Interval max_angles      = expected_angles.Expanded(kErrorRadians);
        S1Interval actual_angles   = new();

        for (int face = 0; face < 6; ++face)
        {
            if (ClipToPaddedFace(a, b, face, padding, out var a_uv, out var b_uv))
            {
                S2Point a_clip = S2.FaceUVtoXYZ(face, a_uv).Normalize();
                S2Point b_clip = S2.FaceUVtoXYZ(face, b_uv).Normalize();
                Assert.True(Math.Abs(a_clip.DotProd(norm)) <= kErrorRadians);
                Assert.True(Math.Abs(b_clip.DotProd(norm)) <= kErrorRadians);
                if (a_clip.Angle(a) > kErrorRadians)
                {
                    Assert2.DoubleEqual(1 + padding, Math.Max(Math.Abs(a_uv[0]), Math.Abs(a_uv[1])));
                }
                if (b_clip.Angle(b) > kErrorRadians)
                {
                    Assert2.DoubleEqual(1 + padding, Math.Max(Math.Abs(b_uv[0]), Math.Abs(b_uv[1])));
                }
                double a_angle = Math.Atan2(a_clip.DotProd(y_axis), a_clip.DotProd(x_axis));
                double b_angle = Math.Atan2(b_clip.DotProd(y_axis), b_clip.DotProd(x_axis));
                // Rounding errors may cause b_angle to be slightly less than a_angle.
                // We handle this by constructing the interval with FromPointPair(),
                // which is okay since the interval length is much less than Math.PI.
                S1Interval face_angles = S1Interval.FromPointPair(a_angle, b_angle);
                Assert.True(max_angles.Contains(face_angles));
                actual_angles = actual_angles.Union(face_angles);
            }
        }
        Assert.True(actual_angles.Expanded(kErrorRadians).Contains(expected_angles));
    }