コード例 #1
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;
        }
    }
コード例 #2
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));
    }
コード例 #3
0
    // Return the center of this cell.
    public S2Point GetCenter()
    {
        var ij_size = S2CellId.SizeIJ(Level);
        var si      = (uint)(2 * ij_lo_[0] + ij_size);
        var ti      = (uint)(2 * ij_lo_[1] + ij_size);

        return(S2.FaceSiTitoXYZ((int)Id.Face(), si, ti).Normalize());
    }
コード例 #4
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));
    }
コード例 #5
0
    // Return the vertex where the S2 space-filling curve enters this cell.
    public S2Point GetEntryVertex()
    {
        // The curve enters at the (0,0) vertex unless the axis directions are
        // reversed, in which case it enters at the (1,1) vertex.
        uint i = (uint)ij_lo_[0];
        uint j = (uint)ij_lo_[1];

        if ((orientation_ & S2.kInvertMask) != 0)
        {
            int ij_size = S2CellId.SizeIJ(Level);
            i = (uint)(i + ij_size);
            j = (uint)(j + ij_size);
        }
        return(S2.FaceSiTitoXYZ((int)Id.Face(), 2 * i, 2 * j).Normalize());
    }
コード例 #6
0
    // Return the vertex where the S2 space-filling curve exits this cell.
    public S2Point GetExitVertex()
    {
        // The curve exits at the (1,0) vertex unless the axes are swapped or
        // inverted but not both, in which case it exits at the (0,1) vertex.
        uint i       = (uint)ij_lo_[0];
        uint j       = (uint)ij_lo_[1];
        int  ij_size = S2CellId.SizeIJ(Level);

        if (orientation_ == 0 || orientation_ == S2.kSwapMask + S2.kInvertMask)
        {
            i = (uint)(i + ij_size);
        }
        else
        {
            j = (uint)(j + ij_size);
        }
        return(S2.FaceSiTitoXYZ((int)Id.Face(), 2 * i, 2 * j).Normalize());
    }
コード例 #7
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);
            }
        }