Exemple #1
0
        public void Test_S2CellId_ParentChildRelationships()
        {
            S2CellId id = S2CellId.FromFacePosLevel(3, 0x12345678, S2.kMaxCellLevel - 4);

            Assert.True(id.IsValid());
            Assert.Equal(3UL, id.Face());
            Assert.Equal(0x12345700UL, id.Pos());
            Assert.Equal(S2.kMaxCellLevel - 4, id.Level());
            Assert.False(id.IsLeaf());

            Assert.Equal(0x12345610UL, id.ChildBegin(id.Level() + 2).Pos());
            Assert.Equal(0x12345640UL, id.ChildBegin().Pos());
            Assert.Equal(0x12345400UL, id.Parent().Pos());
            Assert.Equal(0x12345000UL, id.Parent(id.Level() - 2).Pos());

            // Check ordering of children relative to parents.
            Assert.True(id.ChildBegin() < id);
            Assert.True(id.ChildEnd() > id);
            Assert.Equal(id.ChildEnd(), id.ChildBegin().Next().Next().Next().Next());
            Assert.Equal(id.RangeMin(), id.ChildBegin(S2.kMaxCellLevel));
            Assert.Equal(id.RangeMax().Next(), id.ChildEnd(S2.kMaxCellLevel));

            // Check that cells are represented by the position of their center
            // along the Hilbert curve.
            Assert.Equal(2 * id.Id, id.RangeMin().Id + id.RangeMax().Id);
        }
Exemple #2
0
        public void Test_S2CellId_CenterSiTi()
        {
            S2CellId id = S2CellId.FromFacePosLevel(3, 0x12345678,
                                                    S2.kMaxCellLevel);

            // Check that the (si, ti) coordinates of the center end in a
            // 1 followed by (30 - level) 0s.

            // Leaf level, 30.
            id.CenterSiTi(out var si, out var ti);
            Assert.Equal(1 << 0, si & 1);
            Assert.Equal(1 << 0, ti & 1);

            // Level 29.
            id.Parent(S2.kMaxCellLevel - 1).CenterSiTi(out si, out ti);
            Assert.Equal(1 << 1, si & 3);
            Assert.Equal(1 << 1, ti & 3);

            // Level 28.
            id.Parent(S2.kMaxCellLevel - 2).CenterSiTi(out si, out ti);
            Assert.Equal(1 << 2, si & 7);
            Assert.Equal(1 << 2, ti & 7);

            // Level 20.
            id.Parent(S2.kMaxCellLevel - 10).CenterSiTi(out si, out ti);
            Assert.Equal(1 << 10, si & ((1 << 11) - 1));
            Assert.Equal(1 << 10, ti & ((1 << 11) - 1));

            // Level 10.
            id.Parent(S2.kMaxCellLevel - 20).CenterSiTi(out si, out ti);
            Assert.Equal(1 << 20, si & ((1 << 21) - 1));
            Assert.Equal(1 << 20, ti & ((1 << 21) - 1));

            // Level 0.
            id.Parent(0).CenterSiTi(out si, out ti);
            Assert.Equal(1 << 30, si & ((1U << 31) - 1));
            Assert.Equal(1 << 30, ti & ((1U << 31) - 1));
        }
Exemple #3
0
 // Computes the smallest S2Cell that covers the S2Cell range (first, last) and
 // adds this cell to "cell_ids".
 //
 // REQUIRES: "first" and "last" have a common ancestor.
 private static void CoverRange(S2CellId first, S2CellId last, List <S2CellId> cell_ids)
 {
     if (first == last)
     {
         // The range consists of a single index cell.
         cell_ids.Add(first);
     }
     else
     {
         // Add the lowest common ancestor of the given range.
         int level = first.CommonAncestorLevel(last);
         System.Diagnostics.Debug.Assert(level >= 0);
         cell_ids.Add(first.Parent(level));
     }
 }
Exemple #4
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));
            }
        }
        public void Test_CellTarget_VisitContainingShapes()
        {
            var index = MakeIndexOrDie(
                "1:1 # 1:1, 2:2 # 0:0, 0:3, 3:0 | 6:6, 6:9, 9:6 | -1:-1, -1:5, 5:-1");
            // Only shapes 2 and 4 should contain a very small cell near 1:1.
            var cellid1 = new S2CellId(MakePointOrDie("1:1"));
            var target1 = new S2MinDistanceCellTarget(new S2Cell(cellid1));

            Assert.True(IsSubsetOfSize(GetContainingShapes(target1, index, 1),
                                       new int[] { 2, 4 }, 1));
            Assert.Equal(new int[] { 2, 4 }, GetContainingShapes(target1, index, 5));

            // For a larger cell that properly contains one or more index cells, all
            // shapes that intersect the first such cell in S2CellId order are returned.
            // In the test below, this happens to again be the 1st and 3rd polygons
            // (whose shape_ids are 2 and 4).
            var cellid2 = cellid1.Parent(5);
            var target2 = new S2MinDistanceCellTarget(new S2Cell(cellid2));

            Assert.Equal(new int[] { 2, 4 }, GetContainingShapes(target2, index, 5));
        }
Exemple #6
0
    public void CanonicalizeCovering(List <S2CellId> covering)
    {
        // We check this on each call because of Options().
        System.Diagnostics.Debug.Assert(Options_.MinLevel <= Options_.MaxLevel);

        // Note that when the covering parameters have their default values, almost
        // all of the code in this function is skipped.

        // If any cells are too small, or don't satisfy level_mod(), then replace
        // them with ancestors.
        if (Options_.MaxLevel < S2.kMaxCellLevel || Options_.LevelMod > 1)
        {
            for (var i = 0; i < covering.Count; i++)
            {
                var id        = covering[i];
                int level     = id.Level();
                int new_level = AdjustLevel(Math.Min(level, Options_.MaxLevel));
                if (new_level != level)
                {
                    covering[i] = id.Parent(new_level);
                }
            }
        }

        // Sort the cells and simplify them.
        S2CellUnion.Normalize(covering);

        // Make sure that the covering satisfies min_level() and level_mod(),
        // possibly at the expense of satisfying max_cells().
        if (Options_.MinLevel > 0 || Options_.LevelMod > 1)
        {
            var tmp = new List <S2CellId>();
            S2CellUnion.Denormalize(covering, Options_.MinLevel, Options_.LevelMod, tmp);
            covering.Clear();
            covering.AddRange(tmp);
        }

        // If there are too many cells and the covering is very large, use the
        // S2RegionCoverer to compute a new covering.  (This avoids possible O(n^2)
        // behavior of the simpler algorithm below.)
        var excess = covering.Count - Options_.MaxCells;

        if (excess <= 0 || IsCanonical(covering))
        {
            return;
        }
        if (excess * covering.Count > 10000)
        {
            GetCovering(new S2CellUnion(covering), out covering);
        }
        else
        {
            // Repeatedly replace two adjacent cells in S2CellId order by their lowest
            // common ancestor until the number of cells is acceptable.
            while (covering.Count > Options_.MaxCells)
            {
                int best_index = -1, best_level = -1;
                for (int i = 0; i + 1 < covering.Count; ++i)
                {
                    int level = covering[i].CommonAncestorLevel(covering[i + 1]);
                    level = AdjustLevel(level);
                    if (level > best_level)
                    {
                        best_level = level;
                        best_index = i;
                    }
                }
                if (best_level < Options_.MinLevel)
                {
                    break;
                }

                // Replace all cells contained by the new ancestor cell.
                S2CellId id = covering[best_index].Parent(best_level);
                ReplaceCellsWithAncestor(covering, id);

                // Now repeatedly check whether all children of the parent cell are
                // present, in which case we can replace those cells with their parent.
                while (best_level > Options_.MinLevel)
                {
                    best_level -= Options_.LevelMod;
                    id          = id.Parent(best_level);
                    if (!ContainsAllChildren(covering, id))
                    {
                        break;
                    }
                    ReplaceCellsWithAncestor(covering, id);
                }
            }
        }
        System.Diagnostics.Debug.Assert(IsCanonical(covering));
    }
Exemple #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);
            }
        }
Exemple #8
0
        public void Test_S2Cap_S2CellMethods()
        {
            // For each cube face, we construct some cells on
            // that face and some caps whose positions are relative to that face,
            // and then check for the expected intersection/containment results.

            for (var face = 0; face < 6; ++face)
            {
                // The cell consisting of the entire face.
                S2Cell root_cell = S2Cell.FromFace(face);

                // A leaf cell at the midpoint of the v=1 edge.
                S2Cell edge_cell = new(S2.FaceUVtoXYZ(face, 0, 1 - kEps));

                // A leaf cell at the u=1, v=1 corner.
                S2Cell corner_cell = new(S2.FaceUVtoXYZ(face, 1 - kEps, 1 - kEps));

                // Quick check for full and empty caps.
                Assert.True(S2Cap.Full.Contains(root_cell));
                Assert.False(S2Cap.Empty.MayIntersect(root_cell));

                // Check intersections with the bounding caps of the leaf cells that are
                // adjacent to 'corner_cell' along the Hilbert curve.  Because this corner
                // is at (u=1,v=1), the curve stays locally within the same cube face.
                S2CellId first = corner_cell.Id.Advance(-3);
                S2CellId last  = corner_cell.Id.Advance(4);
                for (S2CellId id = first; id < last; id = id.Next())
                {
                    S2Cell cell = new(id);
                    Assert.Equal(id == corner_cell.Id,
                                 cell.GetCapBound().Contains(corner_cell));
                    Assert.Equal(id.Parent().Contains(corner_cell.Id),
                                 cell.GetCapBound().MayIntersect(corner_cell));
                }

                var anti_face = (face + 3) % 6;  // Opposite face.
                for (var cap_face = 0; cap_face < 6; ++cap_face)
                {
                    // A cap that barely contains all of 'cap_face'.
                    S2Point center   = S2.GetNorm(cap_face);
                    S2Cap   covering = new(center, S1Angle.FromRadians(kFaceRadius + kEps));
                    Assert.Equal(cap_face == face, covering.Contains(root_cell));
                    Assert.Equal(cap_face != anti_face, covering.MayIntersect(root_cell));
                    Assert.Equal(center.DotProd(edge_cell.Center()) > 0.1,
                                 covering.Contains(edge_cell));
                    Assert.Equal(covering.MayIntersect(edge_cell), covering.Contains(edge_cell));
                    Assert.Equal(cap_face == face, covering.Contains(corner_cell));
                    Assert.Equal(center.DotProd(corner_cell.Center()) > 0,
                                 covering.MayIntersect(corner_cell));

                    // A cap that barely intersects the edges of 'cap_face'.
                    S2Cap bulging = new(center, S1Angle.FromRadians(S2.M_PI_4 + kEps));
                    Assert.False(bulging.Contains(root_cell));
                    Assert.Equal(cap_face != anti_face, bulging.MayIntersect(root_cell));
                    Assert.Equal(cap_face == face, bulging.Contains(edge_cell));
                    Assert.Equal(center.DotProd(edge_cell.Center()) > 0.1,
                                 bulging.MayIntersect(edge_cell));
                    Assert.False(bulging.Contains(corner_cell));
                    Assert.False(bulging.MayIntersect(corner_cell));

                    // A singleton cap.
                    S2Cap singleton = new(center, S1Angle.Zero);
                    Assert.Equal(cap_face == face, singleton.MayIntersect(root_cell));
                    Assert.False(singleton.MayIntersect(edge_cell));
                    Assert.False(singleton.MayIntersect(corner_cell));
                }
            }
        }