Exemplo n.º 1
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));
    }
Exemplo n.º 2
0
        public void Test_XYZToFaceSiTi()
        {
            // Check the conversion of random cells to center points and back.
            for (int level = 0; level <= S2.kMaxCellLevel; ++level)
            {
                for (int i = 0; i < 1000; ++i)
                {
                    S2CellId id           = S2Testing.GetRandomCellId(level);
                    int      actual_level = S2.XYZtoFaceSiTi(id.ToPoint(), out var face, out var si, out var ti);
                    Assert.Equal(level, actual_level);
                    S2CellId actual_id =
                        S2CellId.FromFaceIJ(face, (int)(si / 2), (int)(ti / 2)).Parent(level);
                    Assert.Equal(id, actual_id);

                    // Now test a point near the cell center but not equal to it.
                    S2Point p_moved = id.ToPoint() + new S2Point(1e-13, 1e-13, 1e-13);
                    actual_level = S2.XYZtoFaceSiTi(p_moved, out var face_moved, out var si_moved, out var ti_moved);
                    Assert.Equal(-1, actual_level);
                    Assert.Equal(face, face_moved);
                    Assert.Equal(si, si_moved);
                    Assert.Equal(ti, ti_moved);

                    // Finally, test some random (si,ti) values that may be at different
                    // levels, or not at a valid level at all (for example, si == 0).
                    int  face_random = S2Testing.Random.Uniform(S2CellId.kNumFaces);
                    uint si_random, ti_random;
                    uint mask = ~0U << (S2.kMaxCellLevel - level);
                    do
                    {
                        si_random = S2Testing.Random.Rand32() & mask;
                        ti_random = S2Testing.Random.Rand32() & mask;
                    } while (si_random > S2.kMaxSiTi || ti_random > S2.kMaxSiTi);
                    S2Point p_random = S2.FaceSiTitoXYZ(face_random, si_random, ti_random);
                    actual_level = S2.XYZtoFaceSiTi(p_random, out face, out si, out ti);
                    if (face != face_random)
                    {
                        // The chosen point is on the edge of a top-level face cell.
                        Assert.Equal(-1, actual_level);
                        Assert.True(si == 0 || si == S2.kMaxSiTi ||
                                    ti == 0 || ti == S2.kMaxSiTi);
                    }
                    else
                    {
                        Assert.Equal(si_random, si);
                        Assert.Equal(ti_random, ti);
                        if (actual_level >= 0)
                        {
                            Assert.Equal(p_random, S2CellId.FromFaceIJ(face, (int)(si / 2), (int)(ti / 2)).Parent(actual_level).ToPoint());
                        }
                    }
                }
            }
        }
Exemplo n.º 3
0
    public void Test_EncodedS2PointVectorTest_MaxFaceSiTiAtAllLevels()
    {
        // Similar to the test above, but tests encoding the S2CellId at each level
        // whose face, si, and ti values are all maximal.  This turns out to be the
        // S2CellId whose human-readable form is 5/222...22 (0xb555555555555555),
        // however for clarity we construct it using S2CellId.FromFaceIJ.
        for (int level = 0; level <= S2.kMaxCellLevel; ++level)
        {
            _logger.WriteLine("Level = " + level);
            S2CellId id = S2CellId.FromFaceIJ(5, S2.kLimitIJ - 1, S2.kLimitIJ - 1)
                          .Parent(level);

            // This encoding is one byte bigger than the previous test at levels 7, 11,
            // 15, 19, 23, and 27.  This is because in the previous test, the
            // odd-numbered value bits are all zero (except for the face number), which
            // reduces the number of base bits needed by exactly 1.  The encoding size
            // at level==3 is unaffected because for singleton blocks, the lowest 8
            // value bits are encoded in the delta.
            int expected_size = (level < 4) ? 6 : 6 + (level + 1) / 4;
            TestEncodedS2PointVector(new S2Point[] { id.ToPoint() },
                                     CodingHint.COMPACT, expected_size);
        }
    }
Exemplo n.º 4
0
        public void Test_S2CellId_Neighbors()
        {
            // Check the edge neighbors of face 1.
            var out_faces = new[] { 5, 3, 2, 0 };
            var face_nbrs = new S2CellId[4];

            S2CellId.FromFace(1).EdgeNeighbors(face_nbrs);
            for (int i = 0; i < 4; ++i)
            {
                Assert.True(face_nbrs[i].IsFace());
                Assert.Equal(out_faces[i], (int)face_nbrs[i].Face());
            }

            // Check the edge neighbors of the corner cells at all levels.  This case is
            // trickier because it requires projecting onto adjacent faces.
            const int kMaxIJ = S2CellId.kMaxSize - 1;

            for (int level = 1; level <= S2.kMaxCellLevel; ++level)
            {
                S2CellId id2   = S2CellId.FromFaceIJ(1, 0, 0).Parent(level);
                var      nbrs2 = new S2CellId[4];
                id2.EdgeNeighbors(nbrs2);
                // These neighbors were determined manually using the face and axis
                // relationships defined in s2coords.cc.
                int size_ij = S2CellId.SizeIJ(level);
                Assert.Equal(S2CellId.FromFaceIJ(5, kMaxIJ, kMaxIJ).Parent(level), nbrs2[0]);
                Assert.Equal(S2CellId.FromFaceIJ(1, size_ij, 0).Parent(level), nbrs2[1]);
                Assert.Equal(S2CellId.FromFaceIJ(1, 0, size_ij).Parent(level), nbrs2[2]);
                Assert.Equal(S2CellId.FromFaceIJ(0, kMaxIJ, 0).Parent(level), nbrs2[3]);
            }

            // Check the vertex neighbors of the center of face 2 at level 5.
            var nbrs = new List <S2CellId>();

            new S2CellId(new S2Point(0, 0, 1)).AppendVertexNeighbors(5, nbrs);
            nbrs.Sort();
            for (int i = 0; i < 4; ++i)
            {
                Assert.Equal(S2CellId.FromFaceIJ(
                                 2, (1 << 29) - ((i < 2) ? 1 : 0), (1 << 29) - ((i == 0 || i == 3) ? 1 : 0))
                             .Parent(5), nbrs[i]);
            }
            nbrs.Clear();

            // Check the vertex neighbors of the corner of faces 0, 4, and 5.
            S2CellId id1 = S2CellId.FromFacePosLevel(0, 0, S2.kMaxCellLevel);

            id1.AppendVertexNeighbors(0, nbrs);
            nbrs.Sort();
            Assert.Equal(3, nbrs.Count);
            Assert.Equal(S2CellId.FromFace(0), nbrs[0]);
            Assert.Equal(S2CellId.FromFace(4), nbrs[1]);
            Assert.Equal(S2CellId.FromFace(5), nbrs[2]);

            // Check that AppendAllNeighbors produces results that are consistent
            // with AppendVertexNeighbors for a bunch of random cells.
            for (var i = 0; i < 1000; ++i)
            {
                S2CellId id2 = S2Testing.GetRandomCellId();
                if (id2.IsLeaf())
                {
                    id2 = id2.Parent();
                }

                // TestAllNeighbors computes approximately 2**(2*(diff+1)) cell ids,
                // so it's not reasonable to use large values of "diff".
                int max_diff = Math.Min(5, S2.kMaxCellLevel - id2.Level() - 1);
                int level    = id2.Level() + S2Testing.Random.Uniform(max_diff + 1);
                TestAllNeighbors(id2, level);
            }
        }