public void Test_S2CellUnion_FromBeginEnd() { // Since FromMinMax() is implemented in terms of FromBeginEnd(), we // focus on test cases that generate an empty range. S2CellId initial_id = S2CellId.FromFace(3); // Test an empty range before the minimum S2CellId. S2CellUnion cell_union = new(new List <S2CellId> { initial_id }); S2CellId id_begin = S2CellId.Begin(S2.kMaxCellLevel); cell_union.InitFromBeginEnd(id_begin, id_begin); Assert.True(cell_union.IsEmpty()); // Test an empty range after the maximum S2CellId. cell_union = new S2CellUnion(new List <S2CellId> { initial_id }); S2CellId id_end = S2CellId.End(S2.kMaxCellLevel); cell_union.InitFromBeginEnd(id_end, id_end); Assert.True(cell_union.IsEmpty()); // Test the full sphere. cell_union = S2CellUnion.FromBeginEnd(id_begin, id_end); Assert.Equal(6, cell_union.Size()); foreach (S2CellId id in cell_union) { Assert.True(id.IsFace()); } }
public static S2CellUnion FindCellIds(S2LatLngRect latLngRect) { var queue = new ConcurrentQueue <S2CellId>(); var cellIds = new List <S2CellId>(); for (var c = S2CellId.Begin(0); !c.Equals(S2CellId.End(0)); c = c.Next) { if (ContainsGeodataToFind(c, latLngRect)) { queue.Enqueue(c); } } ProcessQueue(queue, cellIds, latLngRect); Debug.Assert(queue.Count == 0); queue = null; if (cellIds.Count > 0) { var cellUnion = new S2CellUnion(); cellUnion.InitFromCellIds(cellIds); // This normalize the cells. // cellUnion.initRawCellIds(cellIds); // This does not normalize the cells. cellIds = null; return(cellUnion); } return(null); }
public void testContinuity() { Trace.WriteLine("TestContinuity"); // 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. var maxDist = S2Projections.MaxEdge.GetValue(MAX_WALK_LEVEL); var end = S2CellId.End(MAX_WALK_LEVEL); var id = S2CellId.Begin(MAX_WALK_LEVEL); for (; !id.Equals(end); id = id.Next) { Assert.True(id.ToPointRaw().Angle(id.NextWithWrap.ToPointRaw()) <= maxDist); // Check that the ToPointRaw() returns the center of each cell // in (s,t) coordinates. var p = id.ToPointRaw(); var face = S2Projections.XyzToFace(p); var uv = S2Projections.ValidFaceXyzToUv(face, p); assertDoubleNear(Math.IEEERemainder( S2Projections.UvToSt(uv.X), 1.0 / (1 << MAX_WALK_LEVEL)), 0); assertDoubleNear(Math.IEEERemainder( S2Projections.UvToSt(uv.Y), 1.0 / (1 << MAX_WALK_LEVEL)), 0); } }
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 S2CellIdTestBasic() { Trace.WriteLine("TestBasic"); // Check default constructor. var id = new S2CellId(); //JavaAssert.Equal(id.id(), 0); //Assert.True(!id.isValid()); // Check basic accessor methods. id = S2CellId.FromFacePosLevel(3, 0x12345678, S2CellId.MaxLevel - 4); //Assert.True(id.isValid()); //JavaAssert.Equal(id.face(), 3); // JavaAssert.Equal(id.pos(), 0x12345700); //JavaAssert.Equal(id.level(), S2CellId.MAX_LEVEL - 4); //Assert.True(!id.isLeaf()); //// Check face definitions //JavaAssert.Equal(getCellId(0, 0).face(), 0); //JavaAssert.Equal(getCellId(0, 90).face(), 1); //JavaAssert.Equal(getCellId(90, 0).face(), 2); //JavaAssert.Equal(getCellId(0, 180).face(), 3); //JavaAssert.Equal(getCellId(0, -90).face(), 4); //JavaAssert.Equal(getCellId(-90, 0).face(), 5); //// Check parent/child relationships. //JavaAssert.Equal(id.childBegin(id.level() + 2).pos(), 0x12345610); //JavaAssert.Equal(id.childBegin().pos(), 0x12345640); //JavaAssert.Equal(id.parent().pos(), 0x12345400); //JavaAssert.Equal(id.parent(id.level() - 2).pos(), 0x12345000); //// Check ordering of children relative to parents. //Assert.True(id.childBegin().lessThan(id)); //var childEnd = id.childEnd(); //var childId = childEnd.id(); //var id1 = id.id(); //Assert.True(id.childEnd().greaterThan(id)); //JavaAssert.Equal(id.childBegin().next().next().next().next(), id.childEnd()); //JavaAssert.Equal(id.childBegin(S2CellId.MAX_LEVEL), id.rangeMin()); //JavaAssert.Equal(id.childEnd(S2CellId.MAX_LEVEL), id.rangeMax().next()); // Check wrapping from beginning of Hilbert curve to end and vice versa. // JavaAssert.Equal(S2CellId.begin(0).prevWrap(), S2CellId.end(0).prev()); JavaAssert.Equal(S2CellId.Begin(S2CellId.MaxLevel).PreviousWithWrap, S2CellId.FromFacePosLevel(5, ~0UL >> S2CellId.FaceBits, S2CellId.MaxLevel)); JavaAssert.Equal(S2CellId.End(4).Previous.NextWithWrap, S2CellId.Begin(4)); JavaAssert.Equal(S2CellId.End(S2CellId.MaxLevel).Previous.NextWithWrap, S2CellId.FromFacePosLevel(0, 0, S2CellId.MaxLevel)); // Check that cells are represented by the position of their center // along the Hilbert curve. JavaAssert.Equal(id.RangeMin.Id + id.RangeMax.Id, 2 * id.Id); }
public void Test_EncodedS2PointVectorTest_FirstAtAllLevels() { // Test encoding the first S2CellId at each level (which also happens to have // the maximum face, si, and ti values). All such S2CellIds can be encoded in // 6 bytes because most of the bits are zero. for (int level = 0; level <= S2.kMaxCellLevel; ++level) { _logger.WriteLine("Level = " + level); TestEncodedS2PointVector(new S2Point[] { S2CellId.Begin(level).ToPoint() }, CodingHint.COMPACT, 6); } }
// Constructs the index. This method may only be called once. No iterators // may be used until the index is built. public void Build() { // To build the cell tree and leaf cell ranges, we maintain a stack of // (cell_id, label) pairs that contain the current leaf cell. This class // represents an instruction to push or pop a (cell_id, label) pair. // // If label >= 0, the (cell_id, label) pair is pushed on the stack. // If cell_id == S2CellId.Sentinel(), a pair is popped from the stack. // Otherwise the stack is unchanged but a RangeNode is still emitted. var deltas = new List <DeltaBuild>(2 * cell_tree_.Count + 2); // Create two deltas for each (cell_id, label) pair: one to add the pair to // the stack (at the start of its leaf cell range), and one to remove it from // the stack (at the end of its leaf cell range). foreach (var node in cell_tree_) { deltas.Add(new DeltaBuild(node.CellId.RangeMin(), node.CellId, node.Label)); deltas.Add(new DeltaBuild(node.CellId.RangeMax().Next(), S2CellId.Sentinel, -1)); } // We also create two special deltas to ensure that a RangeNode is emitted at // the beginning and end of the S2CellId range. deltas.Add(new DeltaBuild(S2CellId.Begin(S2.kMaxCellLevel), S2CellId.None, -1)); deltas.Add(new DeltaBuild(S2CellId.End(S2.kMaxCellLevel), S2CellId.None, -1)); deltas.Sort(); // Now walk through the deltas to build the leaf cell ranges and cell tree // (which is essentially a permanent form of the "stack" described above). cell_tree_.Clear(); range_nodes_.Capacity = deltas.Count; int contents = -1; for (int i = 0; i < deltas.Count;) { var start_id = deltas[i].StartId; // Process all the deltas associated with the current start_id. for (; i < deltas.Count && deltas[i].StartId == start_id; ++i) { if (deltas[i].Label >= 0) { cell_tree_.Add(new CellNode(deltas[i].CellId, deltas[i].Label, contents)); contents = cell_tree_.Count - 1; } else if (deltas[i].CellId == S2CellId.Sentinel) { contents = cell_tree_[contents].Parent; } } range_nodes_.Add(new RangeNode(start_id, contents)); } }
public void testContains() { assertTrue(candyCane.Contains(S2LatLng.FromDegrees(5, 71).ToPoint())); for (var i = 0; i < 4; ++i) { assertTrue(northHemi.Contains(new S2Point(0, 0, 1))); assertTrue(!northHemi.Contains(new S2Point(0, 0, -1))); assertTrue(!southHemi.Contains(new S2Point(0, 0, 1))); assertTrue(southHemi.Contains(new S2Point(0, 0, -1))); assertTrue(!westHemi.Contains(new S2Point(0, 1, 0))); assertTrue(westHemi.Contains(new S2Point(0, -1, 0))); assertTrue(eastHemi.Contains(new S2Point(0, 1, 0))); assertTrue(!eastHemi.Contains(new S2Point(0, -1, 0))); northHemi = rotate(northHemi); southHemi = rotate(southHemi); eastHemi = rotate(eastHemi); westHemi = rotate(westHemi); } // This code checks each cell vertex is contained by exactly one of // the adjacent cells. for (var level = 0; level < 3; ++level) { var loops = new List <S2Loop>(); var loopVertices = new List <S2Point>(); ISet <S2Point> points = new HashSet <S2Point>(); for (var id = S2CellId.Begin(level); !id.Equals(S2CellId.End(level)); id = id.Next) { var cell = new S2Cell(id); points.Add(cell.Center); for (var k = 0; k < 4; ++k) { loopVertices.Add(cell.GetVertex(k)); points.Add(cell.GetVertex(k)); } loops.Add(new S2Loop(loopVertices)); loopVertices.Clear(); } foreach (var point in points) { var count = 0; for (var j = 0; j < loops.Count; ++j) { if (loops[j].Contains(point)) { ++count; } } assertEquals(count, 1); } } }
public void Test_S2CellId_DistanceFromBegin() { Assert.Equal(6, S2CellId.End(0).DistanceFromBegin()); Assert.Equal(6 * (1L << (2 * S2.kMaxCellLevel)), S2CellId.End(S2.kMaxCellLevel).DistanceFromBegin()); Assert.Equal(0, S2CellId.Begin(0).DistanceFromBegin()); Assert.Equal(0, S2CellId.Begin(S2.kMaxCellLevel).DistanceFromBegin()); S2CellId id = S2CellId.FromFacePosLevel(3, 0x12345678, S2.kMaxCellLevel - 4); Assert.Equal(id, S2CellId.Begin(id.Level()).Advance(id.DistanceFromBegin())); }
public void Test_EncodedS2CellIdVector_LowerBoundLimits() { // Test seeking before the beginning and past the end of the vector. var first = S2CellId.Begin(S2.kMaxCellLevel); var last = S2CellId.End(S2.kMaxCellLevel).Prev(); Encoder encoder = new(); var cell_ids = MakeEncodedS2CellIdVector( new() { first, last }, encoder); Assert.Equal(0, cell_ids.LowerBound(S2CellId.None)); Assert.Equal(0, cell_ids.LowerBound(first)); Assert.Equal(1, cell_ids.LowerBound(first.Next())); Assert.Equal(1, cell_ids.LowerBound(last.Prev())); Assert.Equal(1, cell_ids.LowerBound(last)); Assert.Equal(2, cell_ids.LowerBound(last.Next())); Assert.Equal(2, cell_ids.LowerBound(S2CellId.Sentinel)); }
public void Test_EncodedS2PointVectorTest_SixtyFourBitOffset() { // Tests a case where a 64-bit block offset is needed. // // Encoding: header (2 bytes), block count (1 byte), block offsets (2 bytes) // Block 0: header (1 byte), 8 deltas (8 bytes) // Block 1: header (1 byte), offset (8 bytes), 2 deltas (1 byte) const int level = S2.kMaxCellLevel; var points = new S2Point[kBlockSize] .Fill(S2CellId.Begin(level).ToPoint()); points = new List <S2Point>(points) { S2CellId.End(level).Prev().ToPoint(), S2CellId.End(level).Prev().Prev().ToPoint(), }.ToArray(); TestEncodedS2PointVector(points, CodingHint.COMPACT, 16 + kBlockSize / 2); }
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_Wrapping() { // Check wrapping from beginning of Hilbert curve to end and vice versa. Assert.Equal(S2CellId.End(0).Prev(), S2CellId.Begin(0).PrevWrap()); Assert.Equal(S2CellId.FromFacePosLevel( 5, ~0UL >> S2CellId.kFaceBits, S2.kMaxCellLevel), S2CellId.Begin(S2.kMaxCellLevel).PrevWrap()); Assert.Equal(S2CellId.FromFacePosLevel( 5, ~0UL >> S2CellId.kFaceBits, S2.kMaxCellLevel), S2CellId.Begin(S2.kMaxCellLevel).AdvanceWrap(-1)); Assert.Equal(S2CellId.Begin(4), S2CellId.End(4).Prev().NextWrap()); Assert.Equal(S2CellId.Begin(4), S2CellId.End(4).Advance(-1).AdvanceWrap(1)); Assert.Equal(S2CellId.FromFacePosLevel(0, 0, S2.kMaxCellLevel), S2CellId.End(S2.kMaxCellLevel).Prev().NextWrap()); Assert.Equal(S2CellId.FromFacePosLevel(0, 0, S2.kMaxCellLevel), S2CellId.End(S2.kMaxCellLevel).Advance(-1).AdvanceWrap(1)); }
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); } }