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); }
public void Test_S2PaddedCell_GetEntryExitVertices() { int kIters = 1000; for (int iter = 0; iter < kIters; ++iter) { S2CellId id = S2Testing.GetRandomCellId(); // Check that entry/exit vertices do not depend on padding. Assert.Equal(new S2PaddedCell(id, 0).GetEntryVertex(), new S2PaddedCell(id, 0.5).GetEntryVertex()); Assert.Equal(new S2PaddedCell(id, 0).GetExitVertex(), new S2PaddedCell(id, 0.5).GetExitVertex()); // Check that the exit vertex of one cell is the same as the entry vertex // of the immediately following cell. (This also tests wrapping from the // end to the start of the S2CellId curve with high probability.) Assert.Equal(new S2PaddedCell(id, 0).GetExitVertex(), new S2PaddedCell(id.NextWrap(), 0).GetEntryVertex()); // Check that the entry vertex of a cell is the same as the entry vertex // of its first child, and similarly for the exit vertex. if (!id.IsLeaf()) { Assert.Equal(new S2PaddedCell(id, 0).GetEntryVertex(), new S2PaddedCell(id.Child(0), 0).GetEntryVertex()); Assert.Equal(new S2PaddedCell(id, 0).GetExitVertex(), new S2PaddedCell(id.Child(3), 0).GetExitVertex()); } } }
public void Test_S2CellId_Inverses() { // Check the conversion of random leaf cells to S2LatLngs and back. for (int i = 0; i < 200000; ++i) { S2CellId id = S2Testing.GetRandomCellId(S2.kMaxCellLevel); Assert.True(id.IsLeaf()); Assert.Equal(S2.kMaxCellLevel, id.Level()); S2LatLng center = id.ToLatLng(); Assert.Equal(id.Id, new S2CellId(center).Id); } }
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_S2PaddedCell_S2CellMethods() { // Test the S2PaddedCell methods that have approximate S2Cell equivalents. int kIters = 1000; for (int iter = 0; iter < kIters; ++iter) { S2CellId id = S2Testing.GetRandomCellId(); double padding = Math.Pow(1e-15, S2Testing.Random.RandDouble()); S2Cell cell = new(id); S2PaddedCell pcell = new(id, padding); CompareS2CellToPadded(cell, pcell, padding); if (!id.IsLeaf()) { var children = new S2Cell[4]; Assert.True(cell.Subdivide(children)); for (int pos = 0; pos < 4; ++pos) { pcell.GetChildIJ(pos, out var i, out var j); CompareS2CellToPadded(children[pos], new S2PaddedCell(pcell, i, j), padding); } } } }
// Positions the iterator at the range containing "target". (Such a range // always exists as long as the target is a valid leaf cell.) // // REQUIRES: target.IsLeaf public void Seek(S2CellId target) { System.Diagnostics.Debug.Assert(target.IsLeaf()); Position = range_nodes_.GetUpperBound(new RangeNode(target, -1)) - 1; }
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); } }