Пример #1
0
    // Construct the child of "parent" with the given (i,j) index.  The four
    // child cells have indices of (0,0), (0,1), (1,0), (1,1), where the i and j
    // indices correspond to increasing u- and v-values respectively.
    public S2PaddedCell(S2PaddedCell parent, int i, int j)
    {
        ij_lo_  = new int[2];
        Padding = parent.Padding;
        Level   = parent.Level + 1;
        // Compute the position and orientation of the child incrementally from the
        // orientation of the parent.
        int pos = S2.kIJtoPos[parent.orientation_][2 * i + j];

        Id = parent.Id.Child(pos);
        int ij_size = S2CellId.SizeIJ(Level);

        ij_lo_[0]    = parent.ij_lo_[0] + i * ij_size;
        ij_lo_[1]    = parent.ij_lo_[1] + j * ij_size;
        orientation_ = parent.orientation_ ^ S2.kPosToOrientation[pos];
        // For each child, one corner of the bound is taken directly from the parent
        // while the diagonally opposite corner is taken from middle().
        var middle = parent.Middle;
        var x      = new double[] { parent.Bound[0][0], parent.Bound[0][1] };
        var y      = new double[] { parent.Bound[1][0], parent.Bound[1][1] };

        x[1 - i] = middle[0][1 - i];
        y[1 - j] = middle[1][1 - j];
        Bound    = new R2Rect(new R1Interval(x), new R1Interval(y));
    }
Пример #2
0
        public void Test_R2Rect_ConstructorsAndAccessors()
        {
            // Check various constructors and accessor methods.
            R2Rect r = new(new R2Point(0.1, 0), new R2Point(0.25, 1));

            Assert.Equal(0.1, r.X.Lo);
            Assert.Equal(0.25, r.X.Hi);
            Assert.Equal(0.0, r.Y.Lo);
            Assert.Equal(1.0, r.Y.Hi);

            Assert.Equal(0.1, r[0][0]);
            Assert.Equal(0.25, r[0][1]);
            Assert.Equal(0.0, r[1][0]);
            Assert.Equal(1.0, r[1][1]);

            Assert.Equal(new R1Interval(0.1, 0.25), r.X);
            Assert.Equal(new R1Interval(0, 1), r.Y);

            Assert.Equal(new R1Interval(0.1, 0.25), r[0]);
            Assert.Equal(new R1Interval(0, 1), r[1]);

            r = new R2Rect(new R1Interval(3, 4), new R1Interval(5, 6));
            Assert.Equal(new R1Interval(3, 4), r[0]);
            Assert.Equal(new R1Interval(5, 6), r[1]);

            Assert.Equal(r, r);
            Assert.NotEqual(r, R2Rect.Empty);

            R2Rect r2 = new();

            Assert.True(r2.IsEmpty());
            Assert.Equal(r2, R2Rect.Empty);
        }
Пример #3
0
    private readonly int orientation_;  // Hilbert curve orientation of this cell (see s2coords.h)

    #region Constructors

    // Construct an S2PaddedCell for the given cell id and padding.
    public S2PaddedCell(S2CellId id, double padding)
    {
        ij_lo_  = new int[2];
        Id      = id;
        Padding = padding;
        if (Id.IsFace())
        {
            // Fast path for constructing a top-level face (the most common case).
            double limit = 1 + padding;
            Bound = new R2Rect(new R1Interval(-limit, limit),
                               new R1Interval(-limit, limit));
            middle_ = new R2Rect(new R1Interval(-padding, padding),
                                 new R1Interval(-padding, padding));
            ij_lo_[0]    = ij_lo_[1] = 0;
            orientation_ = (int)(Id.Face() & 1);
            Level        = 0;
        }
        else
        {
            var ij = new int[2];
            id.ToFaceIJOrientation(out ij[0], out ij[1], out orientation_, true);
            Level = id.Level();
            Bound = S2CellId.IJLevelToBoundUV(ij, Level).Expanded(padding);
            int ij_size = S2CellId.SizeIJ(Level);
            ij_lo_[0] = ij[0] & -ij_size;
            ij_lo_[1] = ij[1] & -ij_size;
        }
    }
Пример #4
0
        private static void TestIntervalOps(R2Rect x, R2Rect y, string expected_rexion,
                                            R2Rect expected_union, R2Rect expected_intersection)
        {
            // Test all of the interval operations on the given pair of intervals.
            // "expected_rexion" is a sequence of "T" and "F" characters corresponding
            // to the expected results of Contains(), InteriorContains(), Intersects(),
            // and InteriorIntersects() respectively.

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

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

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

            R2Rect r = x;

            r = r.AddRect(y);
            Assert.Equal(expected_union, r);
            if (y.GetSize() == new R2Point(0, 0))
            {
                r = x;
                r = r.AddPoint(y.Lo());
                Assert.Equal(expected_union, r);
            }
        }
Пример #5
0
 public void Test_R2Rect_FromCenterSize()
 {
     // FromCenterSize()
     Assert.True(R2Rect.FromCenterSize(new R2Point(0.3, 0.5), new R2Point(0.2, 0.4)).
                 ApproxEquals(new R2Rect(new R2Point(0.2, 0.3), new R2Point(0.4, 0.7))));
     Assert.True(R2Rect.FromCenterSize(new R2Point(1, 0.1), new R2Point(0, 2)).
                 ApproxEquals(new R2Rect(new R2Point(1, -0.9), new R2Point(1, 1.1))));
 }
Пример #6
0
 // Given a point P representing a possibly clipped endpoint A of an edge AB,
 // verify that "clip" contains P, and that if clipping occurred (i.e., P != A)
 // then P is on the boundary of "clip".
 private static void CheckPointOnBoundary(R2Point p, R2Point a, R2Rect clip)
 {
     Assert.True(clip.Contains(p));
     if (p != a)
     {
         Assert.False(clip.Contains(new R2Point(MathUtils.NextAfter(p[0], a[0]),
                                                MathUtils.NextAfter(p[1], a[1]))));
     }
 }
Пример #7
0
        public void Test_R2Rect_EmptyRectangles()
        {
            // Test basic properties of empty rectangles.
            R2Rect empty = R2Rect.Empty;

            Assert.True(empty.IsValid());
            Assert.True(empty.IsEmpty());
            Assert.Equal(empty, empty);
        }
Пример #8
0
    // Return the smallest cell that contains all descendants of this cell whose
    // bounds intersect "rect".  For algorithms that use recursive subdivision
    // to find the cells that intersect a particular object, this method can be
    // used to skip all the initial subdivision steps where only one child needs
    // to be expanded.
    //
    // Note that this method is not the same as returning the smallest cell that
    // contains the intersection of this cell with "rect".  Because of the
    // padding, even if one child completely contains "rect" it is still
    // possible that a neighboring child also intersects "rect".
    //
    // REQUIRES: bound().Intersects(rect)
    public S2CellId ShrinkToFit(R2Rect rect)
    {
        System.Diagnostics.Debug.Assert(Bound.Intersects(rect));

        // Quick rejection test: if "rect" contains the center of this cell along
        // either axis, then no further shrinking is possible.
        int ij_size = S2CellId.SizeIJ(Level);

        if (Level == 0)
        {
            // Fast path (most calls to this function start with a face cell).
            if (rect[0].Contains(0) || rect[1].Contains(0))
            {
                return(Id);
            }
        }
        else
        {
            if (rect[0].Contains(S2.STtoUV(S2.SiTitoST((uint)(2 * ij_lo_[0] + ij_size)))) ||
                rect[1].Contains(S2.STtoUV(S2.SiTitoST((uint)(2 * ij_lo_[1] + ij_size)))))
            {
                return(Id);
            }
        }
        // Otherwise we expand "rect" by the given padding() on all sides and find
        // the range of coordinates that it spans along the i- and j-axes.  We then
        // compute the highest bit position at which the min and max coordinates
        // differ.  This corresponds to the first cell level at which at least two
        // children intersect "rect".

        // Increase the padding to compensate for the error in S2Coords.UVtoST().
        // (The constant below is a provable upper bound on the additional error.)
        R2Rect padded = rect.Expanded(Padding + 1.5 * S2.DoubleEpsilon);
        var    ij_min = new int[2]; // Min i- or j- coordinate spanned by "padded"
        var    ij_xor = new int[2]; // XOR of the min and max i- or j-coordinates

        for (int d = 0; d < 2; ++d)
        {
            ij_min[d] = Math.Max(ij_lo_[d], S2.STtoIJ(S2.UVtoST(padded[d][0])));
            int ij_max = Math.Min(ij_lo_[d] + ij_size - 1,
                                  S2.STtoIJ(S2.UVtoST(padded[d][1])));
            ij_xor[d] = ij_min[d] ^ ij_max;
        }
        // Compute the highest bit position where the two i- or j-endpoints differ,
        // and then choose the cell level that includes both of these endpoints.  So
        // if both pairs of endpoints are equal we choose kMaxLevel; if they differ
        // only at bit 0, we choose (kMaxLevel - 1), and so on.
        var level_msb = ((ij_xor[0] | ij_xor[1]) << 1) + 1;
        var level     = S2.kMaxCellLevel - BitsUtils.FindMSBSetNonZero((uint)level_msb);

        if (level <= Level)
        {
            return(Id);
        }
        return(S2CellId.FromFaceIJ((int)Id.Face(), ij_min[0], ij_min[1]).Parent(level));
    }
Пример #9
0
    // Given an edge AB and a rectangle "clip", verify that IntersectsRect(),
    // ClipEdge(), and ClipEdgeBound() produce consistent results.
    private static void TestClipEdge(R2Point a, R2Point b, R2Rect clip)
    {
        // A bound for the error in edge clipping plus the error in the
        // IntersectsRect calculation below.
        double kError = kEdgeClipErrorUVDist + kIntersectsRectErrorUVDist;

        if (!ClipEdge(a, b, clip, out var a_clipped, out var b_clipped))
        {
            Assert.False(IntersectsRect(a, b, clip.Expanded(-kError)));
        }
Пример #10
0
        public void Test_R2Rect_FromPoint()
        {
            // FromPoint(), FromPointPair()
            R2Rect d1 = new(new R2Point(0.1, 0), new R2Point(0.25, 1));

            Assert.Equal(new R2Rect(d1.Lo(), d1.Lo()), R2Rect.FromPoint(d1.Lo()));
            Assert.Equal(new R2Rect(new R2Point(0.15, 0.3), new R2Point(0.35, 0.9)),
                         R2Rect.FromPointPair(new R2Point(0.15, 0.9), new R2Point(0.35, 0.3)));
            Assert.Equal(new R2Rect(new R2Point(0.12, 0), new R2Point(0.83, 0.5)),
                         R2Rect.FromPointPair(new R2Point(0.83, 0), new R2Point(0.12, 0.5)));
        }
Пример #11
0
        private static void CompareS2CellToPadded(S2Cell cell, S2PaddedCell pcell, double padding)
        {
            Assert.Equal(cell.Id, pcell.Id);
            Assert.Equal(cell.Level, pcell.Level);
            Assert.Equal(padding, pcell.Padding);
            Assert.Equal(cell.BoundUV.Expanded(padding), pcell.Bound);
            var center_uv = cell.Id.CenterUV();

            Assert.Equal(R2Rect.FromPoint(center_uv).Expanded(padding), pcell.Middle);
            Assert.Equal(cell.Center(), pcell.GetCenter());
        }
Пример #12
0
        public void Test_R2Rect_AddPoint()
        {
            // AddPoint()
            R2Point sw1 = new(0, 0.25);
            R2Point ne1 = new(0.5, 0.75);
            R2Rect  r1  = new(sw1, ne1);

            R2Rect r2 = R2Rect.Empty;

            r2 = r2.AddPoint(new R2Point(0, 0.25));
            r2 = r2.AddPoint(new R2Point(0.5, 0.25));
            r2 = r2.AddPoint(new R2Point(0, 0.75));
            r2 = r2.AddPoint(new R2Point(0.1, 0.4));
            Assert.Equal(r1, r2);
        }
Пример #13
0
        public void Test_R2Rect_IntervalOperations()
        {
            // Contains(R2Rect), InteriorContains(R2Rect),
            // Intersects(), InteriorIntersects(), Union(), Intersection().
            //
            // Much more testing of these methods is done in s1interval_test
            // and r1interval_test.

            R2Rect  empty  = R2Rect.Empty;
            R2Point sw1    = new(0, 0.25);
            R2Point ne1    = new(0.5, 0.75);
            R2Rect  r1     = new(sw1, ne1);
            R2Rect  r1_mid = new(new R2Point(0.25, 0.5), new R2Point(0.25, 0.5));
            R2Rect  r_sw1  = new(sw1, sw1);
            R2Rect  r_ne1  = new(ne1, ne1);

            TestIntervalOps(r1, r1_mid, "TTTT", r1, r1_mid);
            TestIntervalOps(r1, r_sw1, "TFTF", r1, r_sw1);
            TestIntervalOps(r1, r_ne1, "TFTF", r1, r_ne1);

            Assert.Equal(new R2Rect(new R2Point(0, 0.25), new R2Point(0.5, 0.75)), r1);
            TestIntervalOps(r1, new R2Rect(new R2Point(0.45, 0.1), new R2Point(0.75, 0.3)), "FFTT",
                            new R2Rect(new R2Point(0, 0.1), new R2Point(0.75, 0.75)),
                            new R2Rect(new R2Point(0.45, 0.25), new R2Point(0.5, 0.3)));
            TestIntervalOps(r1, new R2Rect(new R2Point(0.5, 0.1), new R2Point(0.7, 0.3)), "FFTF",
                            new R2Rect(new R2Point(0, 0.1), new R2Point(0.7, 0.75)),
                            new R2Rect(new R2Point(0.5, 0.25), new R2Point(0.5, 0.3)));
            TestIntervalOps(r1, new R2Rect(new R2Point(0.45, 0.1), new R2Point(0.7, 0.25)), "FFTF",
                            new R2Rect(new R2Point(0, 0.1), new R2Point(0.7, 0.75)),
                            new R2Rect(new R2Point(0.45, 0.25), new R2Point(0.5, 0.25)));

            TestIntervalOps(new R2Rect(new R2Point(0.1, 0.2), new R2Point(0.1, 0.3)),
                            new R2Rect(new R2Point(0.15, 0.7), new R2Point(0.2, 0.8)), "FFFF",
                            new R2Rect(new R2Point(0.1, 0.2), new R2Point(0.2, 0.8)),
                            empty);

            // Check that the intersection of two rectangles that overlap in x but not y
            // is valid, and vice versa.
            TestIntervalOps(new R2Rect(new R2Point(0.1, 0.2), new R2Point(0.4, 0.5)),
                            new R2Rect(new R2Point(0, 0), new R2Point(0.2, 0.1)), "FFFF",
                            new R2Rect(new R2Point(0, 0), new R2Point(0.4, 0.5)), empty);
            TestIntervalOps(new R2Rect(new R2Point(0, 0), new R2Point(0.1, 0.3)),
                            new R2Rect(new R2Point(0.2, 0.1), new R2Point(0.3, 0.4)), "FFFF",
                            new R2Rect(new R2Point(0, 0), new R2Point(0.3, 0.4)), empty);
        }
Пример #14
0
        public void Test_S2PaddedCell_ShrinkToFit()
        {
            const int kIters = 1000;

            for (int iter = 0; iter < kIters; ++iter)
            {
                // Start with the desired result and work backwards.
                S2CellId result    = S2Testing.GetRandomCellId();
                R2Rect   result_uv = result.BoundUV();
                R2Point  size_uv   = result_uv.GetSize();

                // Find the biggest rectangle that fits in "result" after padding.
                // (These calculations ignore numerical errors.)
                double max_padding = 0.5 * Math.Min(size_uv[0], size_uv[1]);
                double padding     = max_padding * S2Testing.Random.RandDouble();
                R2Rect max_rect    = result_uv.Expanded(-padding);

                // Start with a random subset of the maximum rectangle.
                R2Point a = new(SampleInterval(max_rect[0]), SampleInterval(max_rect[1]));
                R2Point b = new(SampleInterval(max_rect[0]), SampleInterval(max_rect[1]));
                if (!result.IsLeaf())
                {
                    // If the result is not a leaf cell, we must ensure that no child of
                    // "result" also satisfies the conditions of ShrinkToFit().  We do this
                    // by ensuring that "rect" intersects at least two children of "result"
                    // (after padding).
                    int    axis   = S2Testing.Random.Uniform(2);
                    double center = result.CenterUV()[axis];

                    // Find the range of coordinates that are shared between child cells
                    // along that axis.
                    R1Interval shared = new(center - padding, center + padding);
                    double     mid    = SampleInterval(shared.Intersection(max_rect[axis]));
                    a = a.SetAxis(axis, SampleInterval(new R1Interval(max_rect[axis].Lo, mid)));
                    b = b.SetAxis(axis, SampleInterval(new R1Interval(mid, max_rect[axis].Hi)));
                }
                R2Rect rect = R2Rect.FromPointPair(a, b);

                // Choose an arbitrary ancestor as the S2PaddedCell.
                S2CellId initial_id = result.Parent(S2Testing.Random.Uniform(result.Level() + 1));
                Assert.Equal(result, new S2PaddedCell(initial_id, padding).ShrinkToFit(rect));
            }
        }