public void Test_S2CellId_Advance() { S2CellId id = S2CellId.FromFacePosLevel(3, 0x12345678, S2.kMaxCellLevel - 4); // Check basic properties of advance(). Assert.Equal(S2CellId.End(0), S2CellId.Begin(0).Advance(7)); Assert.Equal(S2CellId.End(0), S2CellId.Begin(0).Advance(12)); Assert.Equal(S2CellId.Begin(0), S2CellId.End(0).Advance(-7)); Assert.Equal(S2CellId.Begin(0), S2CellId.End(0).Advance(-12000000)); int num_level_5_cells = 6 << (2 * 5); Assert.Equal(S2CellId.End(5).Advance(500 - num_level_5_cells), S2CellId.Begin(5).Advance(500)); Assert.Equal(id.Next().ChildBegin(S2.kMaxCellLevel), id.ChildBegin(S2.kMaxCellLevel).Advance(256)); Assert.Equal(S2CellId.FromFacePosLevel(5, 0, S2.kMaxCellLevel), S2CellId.FromFacePosLevel(1, 0, S2.kMaxCellLevel) .Advance((long)(4UL << (2 * S2.kMaxCellLevel)))); // Check basic properties of advance_wrap(). Assert.Equal(S2CellId.FromFace(1), S2CellId.Begin(0).AdvanceWrap(7)); Assert.Equal(S2CellId.Begin(0), S2CellId.Begin(0).AdvanceWrap(12)); Assert.Equal(S2CellId.FromFace(4), S2CellId.FromFace(5).AdvanceWrap(-7)); Assert.Equal(S2CellId.Begin(0), S2CellId.Begin(0).AdvanceWrap(-12000000)); Assert.Equal(S2CellId.Begin(5).AdvanceWrap(6644), S2CellId.Begin(5).AdvanceWrap(-11788)); Assert.Equal(id.Next().ChildBegin(S2.kMaxCellLevel), id.ChildBegin(S2.kMaxCellLevel).AdvanceWrap(256)); Assert.Equal(S2CellId.FromFacePosLevel(1, 0, S2.kMaxCellLevel), S2CellId.FromFacePosLevel(5, 0, S2.kMaxCellLevel) .AdvanceWrap((long)(2UL << (2 * S2.kMaxCellLevel)))); }
public void Run() { for (S2CellId id = S2CellId.Begin(0); id != S2CellId.End(0); id = id.Next()) { TestCell(new S2Cell(id)); } }
public void Test_S2CellId_MaximumTile() { // This method is tested more thoroughly in s2cell_union_test.cc. for (int iter = 0; iter < 1000; ++iter) { S2CellId id = S2Testing.GetRandomCellId(10); // Check that "limit" is returned for tiles at or beyond "limit". Assert.Equal(id, id.MaximumTile(id)); Assert.Equal(id, id.Child(0).MaximumTile(id)); Assert.Equal(id, id.Child(1).MaximumTile(id)); Assert.Equal(id, id.Next().MaximumTile(id)); Assert.Equal(id.Child(0), id.MaximumTile(id.Child(0))); // Check that the tile size is increased when possible. Assert.Equal(id, id.Child(0).MaximumTile(id.Next())); Assert.Equal(id, id.Child(0).MaximumTile(id.Next().Child(0))); Assert.Equal(id, id.Child(0).MaximumTile(id.Next().Child(1).Child(0))); Assert.Equal(id, id.Child(0).Child(0).MaximumTile(id.Next())); Assert.Equal(id, id.Child(0).Child(0).Child(0).MaximumTile(id.Next())); // Check that the tile size is decreased when necessary. Assert.Equal(id.Child(0), id.MaximumTile(id.Child(0).Next())); Assert.Equal(id.Child(0), id.MaximumTile(id.Child(0).Next().Child(0))); Assert.Equal(id.Child(0), id.MaximumTile(id.Child(0).Next().Child(1))); Assert.Equal(id.Child(0).Child(0), id.MaximumTile(id.Child(0).Child(0).Next())); Assert.Equal(id.Child(0).Child(0).Child(0), id.MaximumTile(id.Child(0).Child(0).Child(0).Next())); // Check that the tile size is otherwise unchanged. Assert.Equal(id, id.MaximumTile(id.Next())); Assert.Equal(id, id.MaximumTile(id.Next().Child(0))); Assert.Equal(id, id.MaximumTile(id.Next().Child(1).Child(0))); } }
public void Test_S2CellUnion_RefuseToDecode() { List <S2CellId> cellids = new(); S2CellId id = S2CellId.Begin(S2.kMaxCellLevel); for (int i = 0; i <= S2CellUnion.Union_decode_max_num_cells; ++i) { cellids.Add(id); id = id.Next(); } S2CellUnion cell_union = S2CellUnion.FromVerbatim(cellids); Encoder encoder = new(); cell_union.Encode(encoder); var decoder = encoder.Decoder(); var(success, _) = S2CellUnion.Decode(decoder); Assert.False(success); }
public void Test_S2CellId_Continuity() { // Make sure that sequentially increasing cell ids form a continuous // path over the surface of the sphere, i.e. there are no // discontinuous jumps from one region to another. double max_dist = S2.kMaxEdge.GetValue(kMaxWalkLevel); S2CellId end = S2CellId.End(kMaxWalkLevel); S2CellId id = S2CellId.Begin(kMaxWalkLevel); for (; id != end; id = id.Next()) { Assert.True(id.ToPointRaw().Angle(id.NextWrap().ToPointRaw()) <= max_dist); Assert.Equal(id.NextWrap(), id.AdvanceWrap(1)); Assert.Equal(id, id.NextWrap().AdvanceWrap(-1)); // Check that the ToPointRaw() returns the center of each cell // in (s,t) coordinates. S2.XYZtoFaceUV(id.ToPointRaw(), out var u, out var v); Assert2.Near(Math.IEEERemainder(S2.UVtoST(u), 0.5 * kCellSize), 0.0, S2.DoubleError); Assert2.Near(Math.IEEERemainder(S2.UVtoST(v), 0.5 * kCellSize), 0.0, S2.DoubleError); } }
static void TestSubdivide(S2Cell cell) { GatherStats(cell); if (cell.IsLeaf()) { return; } var children = new S2Cell[4]; Assert.True(cell.Subdivide(children)); S2CellId child_id = cell.Id.ChildBegin(); double exact_area = 0; double approx_area = 0; double average_area = 0; for (int i = 0; i < 4; ++i, child_id = child_id.Next()) { exact_area += children[i].ExactArea(); approx_area += children[i].ApproxArea(); average_area += children[i].AverageArea(); // Check that the child geometry is consistent with its cell ID. Assert.Equal(child_id, children[i].Id); Assert.True(S2.ApproxEquals(children[i].Center(), child_id.ToPoint())); S2Cell direct = new(child_id); Assert.Equal(direct.Face, children[i].Face); Assert.Equal(direct.Level, children[i].Level); Assert.Equal(direct.Orientation, children[i].Orientation); Assert.Equal(direct.CenterRaw(), children[i].CenterRaw()); for (int k = 0; k < 4; ++k) { Assert.Equal(direct.VertexRaw(k), children[i].VertexRaw(k)); Assert.Equal(direct.EdgeRaw(k), children[i].EdgeRaw(k)); } // Test Contains() and MayIntersect(). Assert.True(cell.Contains(children[i])); Assert.True(cell.MayIntersect(children[i])); Assert.False(children[i].Contains(cell)); Assert.True(cell.Contains(children[i].CenterRaw())); for (int j = 0; j < 4; ++j) { Assert.True(cell.Contains(children[i].VertexRaw(j))); if (j != i) { Assert.False(children[i].Contains(children[j].CenterRaw())); Assert.False(children[i].MayIntersect(children[j])); } } // Test GetCapBound and GetRectBound. S2Cap parent_cap = cell.GetCapBound(); S2LatLngRect parent_rect = cell.GetRectBound(); if (cell.Contains(new S2Point(0, 0, 1)) || cell.Contains(new S2Point(0, 0, -1))) { Assert.True(parent_rect.Lng.IsFull()); } S2Cap child_cap = children[i].GetCapBound(); S2LatLngRect child_rect = children[i].GetRectBound(); Assert.True(child_cap.Contains(children[i].Center())); Assert.True(child_rect.Contains(children[i].CenterRaw())); Assert.True(parent_cap.Contains(children[i].Center())); Assert.True(parent_rect.Contains(children[i].CenterRaw())); for (int j = 0; j < 4; ++j) { Assert.True(child_cap.Contains(children[i].Vertex(j))); Assert.True(child_rect.Contains(children[i].Vertex(j))); Assert.True(child_rect.Contains(children[i].VertexRaw(j))); Assert.True(parent_cap.Contains(children[i].Vertex(j))); Assert.True(parent_rect.Contains(children[i].Vertex(j))); Assert.True(parent_rect.Contains(children[i].VertexRaw(j))); if (j != i) { // The bounding caps and rectangles should be tight enough so that // they exclude at least two vertices of each adjacent cell. int cap_count = 0; int rect_count = 0; for (int k = 0; k < 4; ++k) { if (child_cap.Contains(children[j].Vertex(k))) { ++cap_count; } if (child_rect.Contains(children[j].VertexRaw(k))) { ++rect_count; } } Assert.True(cap_count <= 2); if (child_rect.LatLo().Radians > -S2.M_PI_2 && child_rect.LatHi().Radians < S2.M_PI_2) { // Bounding rectangles may be too large at the poles because the // pole itself has an arbitrary fixed longitude. Assert.True(rect_count <= 2); } } } // Check all children for the first few levels, and then sample randomly. // We also always subdivide the cells containing a few chosen points so // that we have a better chance of sampling the minimum and maximum metric // values. kMaxSizeUV is the absolute value of the u- and v-coordinate // where the cell size at a given level is maximal. double kMaxSizeUV = 0.3964182625366691; R2Point[] special_uv = { new R2Point(S2.DoubleEpsilon, S2.DoubleEpsilon), // Face center new R2Point(S2.DoubleEpsilon, 1), // Edge midpoint new R2Point(1, 1), // Face corner new R2Point(kMaxSizeUV, kMaxSizeUV), // Largest cell area new R2Point(S2.DoubleEpsilon, kMaxSizeUV), // Longest edge/diagonal }; bool force_subdivide = false; foreach (R2Point uv in special_uv) { if (children[i].BoundUV.Contains(uv)) { force_subdivide = true; } } var debugFlag = #if s2debug true; #else false; #endif if (force_subdivide || cell.Level < (debugFlag ? 5 : 6) || S2Testing.Random.OneIn(debugFlag ? 5 : 4)) { TestSubdivide(children[i]); } } // Check sum of child areas equals parent area. // // For ExactArea(), the best relative error we can expect is about 1e-6 // because the precision of the unit vector coordinates is only about 1e-15 // and the edge length of a leaf cell is about 1e-9. // // For ApproxArea(), the areas are accurate to within a few percent. // // For AverageArea(), the areas themselves are not very accurate, but // the average area of a parent is exactly 4 times the area of a child. Assert.True(Math.Abs(Math.Log(exact_area / cell.ExactArea())) <= Math.Abs(Math.Log((1 + 1e-6)))); Assert.True(Math.Abs(Math.Log((approx_area / cell.ApproxArea()))) <= Math.Abs(Math.Log((1.03)))); Assert.True(Math.Abs(Math.Log((average_area / cell.AverageArea()))) <= Math.Abs(Math.Log((1 + 1e-15)))); }
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)); } } }