/** * Checks that "covering" completely covers the given region. If "check_tight" * is true, also checks that it does not contain any cells that do not * intersect the given region. ("id" is only used internally.) */ protected void checkCovering(IS2Region region, S2CellUnion covering, bool checkTight, S2CellId id) { if (!id.IsValid) { for (var face = 0; face < 6; ++face) { checkCovering(region, covering, checkTight, S2CellId.FromFacePosLevel(face, 0, 0)); } return; } if (!region.MayIntersect(new S2Cell(id))) { // If region does not intersect id, then neither should the covering. if (checkTight) { Assert.True(!covering.Intersects(id)); } } else if (!covering.Contains(id)) { // The region may intersect id, but we can't assert that the covering // intersects id because we may discover that the region does not actually // intersect upon further subdivision. (MayIntersect is not exact.) Assert.True(!region.Contains(new S2Cell(id))); var result = !id.IsLeaf; Assert.True(result); var end = id.ChildEnd; for (var child = id.ChildBegin; !child.Equals(end); child = child.Next) { checkCovering(region, covering, checkTight, child); } } }
public void Test_S2CellUnion_Normalize() { // Try a bunch of random test cases, and keep track of average // statistics for normalization (to see if they agree with the // analysis above). double in_sum = 0, out_sum = 0; const int kIters = 2000; for (int i = 0; i < kIters; ++i) { var input = new List <S2CellId>(); var expected = new List <S2CellId>(); AddCells(S2CellId.None, false, input, expected); in_sum += input.Count; out_sum += expected.Count; var cellunion = new S2CellUnion(input); Assert.Equal(expected.Count, cellunion.Size()); for (var j = 0; j < expected.Count; ++j) { Assert.Equal(expected[j], cellunion.CellId(j)); } // Test GetCapBound(). var cap = cellunion.GetCapBound(); foreach (var id in cellunion) { Assert.True(cap.Contains(new S2Cell(id))); } // Test Contains(S2CellId) and Intersects(S2CellId). foreach (var input_id in input) { Assert.True(cellunion.Contains(input_id)); Assert.True(cellunion.Contains(input_id.ToPoint())); Assert.True(cellunion.Intersects(input_id)); if (!input_id.IsFace()) { Assert.True(cellunion.Intersects(input_id.Parent())); if (input_id.Level() > 1) { Assert.True(cellunion.Intersects(input_id.Parent().Parent())); Assert.True(cellunion.Intersects(input_id.Parent(0))); } } if (!input_id.IsLeaf()) { Assert.True(cellunion.Contains(input_id.ChildBegin())); Assert.True(cellunion.Intersects(input_id.ChildBegin())); Assert.True(cellunion.Contains(input_id.ChildEnd().Prev())); Assert.True(cellunion.Intersects(input_id.ChildEnd().Prev())); Assert.True(cellunion.Contains(input_id.ChildBegin(S2.kMaxCellLevel))); Assert.True(cellunion.Intersects(input_id.ChildBegin(S2.kMaxCellLevel))); } } foreach (var expected_id in expected) { if (!expected_id.IsFace()) { Assert.True(!cellunion.Contains(expected_id.Parent())); Assert.True(!cellunion.Contains(expected_id.Parent(0))); } } // Test Contains(S2CellUnion), Intersects(S2CellUnion), Union(), // Intersection(), and Difference(). var x = new List <S2CellId>(); var y = new List <S2CellId>(); var x_or_y = new List <S2CellId>(); var x_and_y = new List <S2CellId>(); foreach (var input_id in input) { var in_x = rnd.OneIn(2); var in_y = rnd.OneIn(2); if (in_x) { x.Add(input_id); } if (in_y) { y.Add(input_id); } if (in_x || in_y) { x_or_y.Add(input_id); } } var xcells = new S2CellUnion(x); var ycells = new S2CellUnion(y); var x_or_y_expected = new S2CellUnion(x_or_y); var x_or_y_cells = xcells.Union(ycells); Assert.True(x_or_y_cells == x_or_y_expected); // Compute the intersection of "x" with each cell of "y", // check that this intersection is correct, and append the // results to x_and_y_expected. foreach (var yid in ycells) { var ucells = xcells.Intersection(yid); foreach (var xid in xcells) { if (xid.Contains(yid)) { Assert.True(ucells.Size() == 1 && ucells.CellId(0) == yid); } else if (yid.Contains(xid)) { Assert.True(ucells.Contains(xid)); } } foreach (var uid in ucells) { Assert.True(xcells.Contains(uid)); Assert.True(yid.Contains(uid)); } x_and_y.AddRange(ucells); } var x_and_y_expected = new S2CellUnion(x_and_y); var x_and_y_cells = xcells.Intersection(ycells); Assert.True(x_and_y_cells == x_and_y_expected); var x_minus_y_cells = xcells.Difference(ycells); var y_minus_x_cells = ycells.Difference(xcells); Assert.True(xcells.Contains(x_minus_y_cells)); Assert.True(!x_minus_y_cells.Intersects(ycells)); Assert.True(ycells.Contains(y_minus_x_cells)); Assert.True(!y_minus_x_cells.Intersects(xcells)); Assert.True(!x_minus_y_cells.Intersects(y_minus_x_cells)); var diff_intersection_union = x_minus_y_cells.Union(y_minus_x_cells).Union(x_and_y_cells); Assert.True(diff_intersection_union == x_or_y_cells); var test = new List <S2CellId>(); var dummy = new List <S2CellId>(); AddCells(S2CellId.None, false, test, dummy); foreach (var test_id in test) { var contains = false; var intersects = false; foreach (var expected_id in expected) { if (expected_id.Contains(test_id)) { contains = true; } if (expected_id.Intersects(test_id)) { intersects = true; } } Assert.Equal(contains, cellunion.Contains(test_id)); Assert.Equal(intersects, cellunion.Intersects(test_id)); } } _logger.WriteLine($"avg in {in_sum / kIters:2f}, avg out {out_sum / kIters:2f}"); }
private void TestRandomCaps(S2RegionTermIndexer.Options options, QueryType query_type) { // This function creates an index consisting either of points (if // options.index_contains_points_only() is true) or S2Caps of random size. // It then executes queries consisting of points (if query_type == POINT) // or S2Caps of random size (if query_type == CAP). var indexer = new S2RegionTermIndexer(options); var coverer = new S2RegionCoverer(options); var caps = new List <S2Cap>(); var coverings = new List <S2CellUnion>(); var index = new Dictionary <string, List <int> >(); int index_terms = 0, query_terms = 0; for (int i = 0; i < iters; ++i) { // Choose the region to be indexed: either a single point or a cap // of random size (up to a full sphere). S2Cap cap; List <string> terms; if (options.IndexContainsPointsOnly) { cap = S2Cap.FromPoint(S2Testing.RandomPoint()); terms = indexer.GetIndexTerms(cap.Center, ""); } else { cap = S2Testing.GetRandomCap( 0.3 * S2Cell.AverageArea(options.MaxLevel), 4.0 * S2Cell.AverageArea(options.MinLevel)); terms = indexer.GetIndexTerms(cap, ""); } caps.Add(cap); coverings.Add(coverer.GetCovering(cap)); foreach (var term in terms) { if (!index.ContainsKey(term)) { index.Add(term, new List <int>()); } index[term].Add(i); } index_terms += terms.Count; } for (int i = 0; i < iters; ++i) { // Choose the region to be queried: either a random point or a cap of // random size. S2Cap cap; List <string> terms; if (query_type == QueryType.CAP) { cap = S2Cap.FromPoint(S2Testing.RandomPoint()); terms = indexer.GetQueryTerms(cap.Center, ""); } else { cap = S2Testing.GetRandomCap( 0.3 * S2Cell.AverageArea(options.MaxLevel), 4.0 * S2Cell.AverageArea(options.MinLevel)); terms = indexer.GetQueryTerms(cap, ""); } // Compute the expected results of the S2Cell query by brute force. S2CellUnion covering = coverer.GetCovering(cap); var expected = new List <int>(); var actual = new List <int>(); for (int j = 0; j < caps.Count; ++j) { if (covering.Intersects(coverings[j])) { expected.Add(j); } } foreach (var term in terms) { actual.AddRange(index[term]); } Assert.Equal(expected, actual); query_terms += terms.Count; } _logger.WriteLine($"Index terms/doc: {((double)index_terms) / iters:2f}, Query terms/doc: {((double)query_terms) / iters:2f}"); }