public void Test_S2RegionTermIndexer_MaxLevelSetLoosely() { // Test that correct terms are generated even when (max_level - min_level) // is not a multiple of level_mod. var options = new S2RegionTermIndexer.Options(); options.MinLevel = (1); options.LevelMod = (2); options.MaxLevel = (19); var indexer1 = new S2RegionTermIndexer(options); options.MaxLevel = (20); var indexer2 = new S2RegionTermIndexer(options); S2Point point = S2Testing.RandomPoint(); Assert.Equal(indexer1.GetIndexTerms(point, ""), indexer2.GetIndexTerms(point, "")); Assert.Equal(indexer1.GetQueryTerms(point, ""), indexer2.GetQueryTerms(point, "")); S2Cap cap = S2Testing.GetRandomCap(0.0, 1.0); // Area range. Assert.Equal(indexer1.GetIndexTerms(cap, ""), indexer2.GetIndexTerms(cap, "")); Assert.Equal(indexer1.GetQueryTerms(cap, ""), indexer2.GetQueryTerms(cap, "")); }
private static void ChooseEdgeNearCell(S2Cell cell, out S2Point a, out S2Point b) { S2Cap cap = cell.GetCapBound(); if (S2Testing.Random.OneIn(5)) { // Choose a point anywhere on the sphere. a = S2Testing.RandomPoint(); } else { // Choose a point inside or somewhere near the cell. a = S2Testing.SamplePoint(new S2Cap(cap.Center, 1.5 * cap.RadiusAngle())); } // Now choose a maximum edge length ranging from very short to very long // relative to the cell size, and choose the other endpoint. double max_length = Math.Min(100 * Math.Pow(1e-4, S2Testing.Random.RandDouble()) * cap.Radius.Radians(), S2.M_PI_2); b = S2Testing.SamplePoint(new S2Cap(a, S1Angle.FromRadians(max_length))); if (S2Testing.Random.OneIn(20)) { // Occasionally replace edge with antipodal edge. a = -a; b = -b; } }
public List <Guid> Search(double lon, double lat, int radius) { var latlng = S2LatLng.FromDegrees(lat, lon); var centerPoint = pointFromLatLng(lat, lon); var centerAngle = ((double)radius) / EarthRadiusM; var cap = S2Cap.FromAxisAngle(centerPoint, S1Angle.FromRadians(centerAngle)); var regionCoverer = new S2RegionCoverer(); regionCoverer.MaxLevel = 13; // regionCoverer.MinLevel = 13; //regionCoverer.MaxCells = 1000; // regionCoverer.LevelMod = 0; var covering = regionCoverer.GetCovering(cap); var res = new List <Guid>(); foreach (var u in covering) { var sell = new S2CellId(u.Id); if (sell.Level < _level) { var begin = sell.ChildBeginForLevel(_level); var end = sell.ChildEndForLevel(_level); do { var cur = tree.Search(new S2CellId(begin.Id)); if (cur != null) { res.AddRange(cur.Pointer); } begin = begin.Next; } while (begin.Id != end.Id); } else { var item = tree.Search(sell); if (item != null) { res.AddRange(item.Pointer); } } } return(res); }
public void Test_S2Cap_AddNonEmptyCapToEmptyCap() { S2Cap empty = S2Cap.Empty; S2Cap non_empty_cap = new(new S2Point(1, 0, 0), S1Angle.FromDegrees(10)); empty = empty.AddCap(non_empty_cap); Assert.Equal(non_empty_cap.Area(), empty.Area()); }
public List <Guid> Search(double lon, double lat, int radius) { var latlng = S2LatLng.FromDegrees(lat, lon); var centerPoint = Index.pointFromLatLng(lat, lon); var centerAngle = ((double)radius) / Index.EarthRadiusM; var cap = S2Cap.FromAxisAngle(centerPoint, S1Angle.FromRadians(centerAngle)); var regionCoverer = new S2RegionCoverer(); regionCoverer.MaxLevel = 13; // regionCoverer.MinLevel = 13; //regionCoverer.MaxCells = 1000; // regionCoverer.LevelMod = 0; var covering = regionCoverer.GetCovering(cap); var res = new List <Guid>(); foreach (var u in covering) { var sell = new S2CellId(u.Id); if (sell.Level < _level) { var begin = sell.ChildBeginForLevel(_level); var end = sell.ChildEndForLevel(_level); var qres = rtree.Query(new Range <S2CellId>(begin, end)); foreach (var r in qres) { res.AddRange(r.Content); } } else { var qres = rtree.Query(new Range <S2CellId>(sell)); if (qres.Count > 0) { foreach (var r in qres) { res.AddRange(r.Content); } } } } return(res); }
public void AddEdges(S2Cap index_cap, int num_edges, MutableS2ShapeIndex index) { var fractal = new S2Testing.Fractal(); fractal.SetLevelForApproxMaxEdges(num_edges); index.Add(new S2Loop.Shape( fractal.MakeLoop(S2Testing.GetRandomFrameAt(index_cap.Center), index_cap.RadiusAngle()))); }
public void Test_S2ConvexHullQuery_PointsInsideHull() { // Repeatedly build the convex hull of a set of points, then add more points // inside that loop and build the convex hull again. The result should // always be the same. int kIters = 1000; for (int iter = 0; iter < kIters; ++iter) { S2Testing.Random.Reset(iter + 1); // Easier to reproduce a specific case. // Choose points from within a cap of random size, up to but not including // an entire hemisphere. S2Cap cap = S2Testing.GetRandomCap(S2.DoubleError, 1.999 * Math.PI); S2ConvexHullQuery query = new(); int num_points1 = S2Testing.Random.Uniform(100) + 3; for (int i = 0; i < num_points1; ++i) { query.AddPoint(S2Testing.SamplePoint(cap)); } var hull = query.GetConvexHull(); // When the convex hull is nearly a hemisphere, the algorithm sometimes // returns a full cap instead. This is because it first computes a // bounding rectangle for all the input points/edges and then converts it // to a bounding cap, which sometimes yields a non-convex cap (radius // larger than 90 degrees). This should not be a problem in practice // (since most convex hulls are not hemispheres), but in order make this // test pass reliably it means that we need to reject convex hulls whose // bounding cap (when computed from a bounding rectangle) is not convex. // // TODO(b/203702905): This test can still fail (about 1 iteration in // 500,000) because the S2LatLngRect::GetCapBound implementation does not // guarantee that A.Contains(B) implies // A.GetCapBound().Contains(B.GetCapBound()). if (hull.GetCapBound().Height() >= 1) { continue; } // Otherwise, add more points inside the convex hull. int num_points2 = 1000; for (int i = 0; i < num_points2; ++i) { S2Point p = S2Testing.SamplePoint(cap); if (hull.Contains(p)) { query.AddPoint(p); } } // Finally, build a new convex hull and check that it hasn't changed. var hull2 = (query.GetConvexHull()); _logger.WriteLine("Iteration: " + iter); Assert.True(hull2.BoundaryEquals(hull)); } }
public void AddEdges(S2Cap index_cap, int num_edges, MutableS2ShapeIndex index) { var points = new List <S2Point>(); for (int i = 0; i < num_edges; ++i) { points.Add(S2Testing.SamplePoint(index_cap)); } index.Add(new S2PointVectorShape(points.ToArray())); }
protected S2Cap getRandomCap(double minArea, double maxArea) { var capArea = maxArea * Math.Pow(minArea / maxArea, rand.NextDouble()); Assert.True(capArea >= minArea && capArea <= maxArea); // The surface area of a cap is 2*Pi times its height. return(S2Cap.FromAxisArea(randomPoint(), capArea)); }
public void AddPoints(S2Cap index_cap, int num_points, TestIndex index) { var points = S2Testing.MakeRegularPoints( index_cap.Center, index_cap.RadiusAngle(), num_points); for (int i = 0; i < points.Length; ++i) { index.Add(points[i], i); } }
public void Test_S2Cap_Union() { // Two caps which have the same center but one has a larger radius. S2Cap a = new(GetLatLngPoint(50.0, 10.0), S1Angle.FromDegrees(0.2)); S2Cap b = new(GetLatLngPoint(50.0, 10.0), S1Angle.FromDegrees(0.3)); Assert.True(b.Contains(a)); Assert.Equal(b, a.Union(b)); // Two caps where one is the full cap. Assert.True(a.Union(S2Cap.Full).IsFull()); // Two caps where one is the empty cap. Assert.Equal(a, a.Union(S2Cap.Empty)); // Two caps which have different centers, one entirely encompasses the other. S2Cap c = new(GetLatLngPoint(51.0, 11.0), S1Angle.FromDegrees(1.5)); Assert.True(c.Contains(a)); Assert.Equal(a.Union(c).Center, c.Center); Assert.Equal(a.Union(c).Radius, c.Radius); // Two entirely disjoint caps. S2Cap d = new(GetLatLngPoint(51.0, 11.0), S1Angle.FromDegrees(0.1)); Assert.False(d.Contains(a)); Assert.False(d.Intersects(a)); Assert.True(a.Union(d).ApproxEquals(d.Union(a))); Assert2.Near(50.4588, new S2LatLng(a.Union(d).Center).Lat().GetDegrees(), 0.001); Assert2.Near(10.4525, new S2LatLng(a.Union(d).Center).Lng().GetDegrees(), 0.001); Assert2.Near(0.7425, a.Union(d).Radius.Degrees(), 0.001); // Two partially overlapping caps. S2Cap e = new(GetLatLngPoint(50.3, 10.3), S1Angle.FromDegrees(0.2)); Assert.False(e.Contains(a)); Assert.True(e.Intersects(a)); Assert.True(a.Union(e).ApproxEquals(e.Union(a))); Assert2.Near(50.1500, new S2LatLng(a.Union(e).Center).Lat().GetDegrees(), 0.001); Assert2.Near(10.1495, new S2LatLng(a.Union(e).Center).Lng().GetDegrees(), 0.001); Assert2.Near(0.3781, a.Union(e).Radius.Degrees(), 0.001); // Two very large caps, whose radius sums to in excess of 180 degrees, and // whose centers are not antipodal. S2Cap f = new(new S2Point(0, 0, 1).Normalize(), S1Angle.FromDegrees(150)); S2Cap g = new(new S2Point(0, 1, 0).Normalize(), S1Angle.FromDegrees(150)); Assert.True(f.Union(g).IsFull()); // Two non-overlapping hemisphere caps with antipodal centers. S2Cap hemi = S2Cap.FromCenterHeight(new S2Point(0, 0, 1).Normalize(), 1); Assert.True(hemi.Union(hemi.Complement()).IsFull()); }
/** * Generates a random edge whose center is in the given cap. */ private S2Edge randomEdgeCrossingCap(double maxLengthMeters, S2Cap cap) { // Pick the edge center at random. var edgeCenter = samplePoint(cap); // Pick two random points in a suitably sized cap about the edge center. var edgeCap = S2Cap.FromAxisAngle( edgeCenter, S1Angle.FromRadians(maxLengthMeters/S2LatLng.EarthRadiusMeters/2)); var p1 = samplePoint(edgeCap); var p2 = samplePoint(edgeCap); return new S2Edge(p1, p2); }
/* * Generates "numEdges" random edges, of length at most "edgeLengthMetersMax" * and each of whose center is in a randomly located cap with radius * "capSpanMeters", and puts results into "edges". */ private void generateRandomEarthEdges( double edgeLengthMetersMax, double capSpanMeters, int numEdges, List <S2Edge> edges) { var cap = S2Cap.FromAxisAngle( randomPoint(), S1Angle.FromRadians(capSpanMeters / S2LatLng.EarthRadiusMeters)); for (var i = 0; i < numEdges; ++i) { edges.Add(randomEdgeCrossingCap(edgeLengthMetersMax, cap)); } }
public void Test_S2Cap_EncodeDecode() { S2Cap cap = S2Cap.FromCenterHeight(new S2Point(3, 2, 1).Normalize(), 1); Encoder encoder = new(); cap.Encode(encoder); var decoder = encoder.Decoder(); var(success, decoded_cap) = S2Cap.Decode(decoder); Assert.True(success); Assert.Equal(cap, decoded_cap); }
public void Test_S2Cap_GetRectBound() { // Empty and full caps. Assert.True(S2Cap.Empty.GetRectBound().IsEmpty()); Assert.True(S2Cap.Full.GetRectBound().IsFull()); // Maximum allowable error for latitudes and longitudes measured in // degrees. (Assert2.Near isn't sufficient.) // Cap that includes the south pole. S2LatLngRect rect = new S2Cap(GetLatLngPoint(-45, 57), S1Angle.FromDegrees(50)).GetRectBound(); Assert2.Near(rect.LatLo().GetDegrees(), -90, kDegreeEps); Assert2.Near(rect.LatHi().GetDegrees(), 5, kDegreeEps); Assert.True(rect.Lng.IsFull()); // Cap that is tangent to the north pole. rect = new S2Cap(new S2Point(1, 0, 1).Normalize(), S1Angle.FromRadians(S2.M_PI_4 + 1e-16)).GetRectBound(); Assert2.Near(rect.Lat.Lo, 0, kEps); Assert2.Near(rect.Lat.Hi, S2.M_PI_2, kEps); Assert.True(rect.Lng.IsFull()); var p = new S2Point(1, 0, 1).Normalize(); var rb1 = S1Angle.FromDegrees(45 + 5e-15); rect = new S2Cap(p, rb1).GetRectBound(); Assert2.Near(rect.LatLo().GetDegrees(), 0, kDegreeEps); Assert2.Near(rect.LatHi().GetDegrees(), 90, kDegreeEps); Assert.True(rect.Lng.IsFull()); // The eastern hemisphere. var rb2 = S1Angle.FromRadians(S2.M_PI_2 + 2e-16); rect = new S2Cap(new S2Point(0, 1, 0), rb2).GetRectBound(); Assert2.Near(rect.LatLo().GetDegrees(), -90, kDegreeEps); Assert2.Near(rect.LatHi().GetDegrees(), 90, kDegreeEps); Assert.True(rect.Lng.IsFull()); // A cap centered on the equator. rect = new S2Cap(GetLatLngPoint(0, 50), S1Angle.FromDegrees(20)).GetRectBound(); Assert2.Near(rect.LatLo().GetDegrees(), -20, kDegreeEps); Assert2.Near(rect.LatHi().GetDegrees(), 20, kDegreeEps); Assert2.Near(rect.LngLo().GetDegrees(), 30, kDegreeEps); Assert2.Near(rect.LngHi().GetDegrees(), 70, kDegreeEps); // A cap centered on the north pole. rect = new S2Cap(GetLatLngPoint(90, 123), S1Angle.FromDegrees(10)).GetRectBound(); Assert2.Near(rect.LatLo().GetDegrees(), 80, kDegreeEps); Assert2.Near(rect.LatHi().GetDegrees(), 90, kDegreeEps); Assert.True(rect.Lng.IsFull()); }
public void Test_S2CellUnion_Expand() { // This test generates coverings for caps of random sizes, expands // the coverings by a random radius, and then make sure that the new // covering covers the expanded cap. It also makes sure that the // new covering is not too much larger than expected. var coverer = new S2RegionCoverer(); for (var i = 0; i < 1000; ++i) { _logger.WriteLine($"Iteration {i}"); var cap = S2Testing.GetRandomCap( S2Cell.AverageArea(S2.kMaxCellLevel), S2.M_4_PI); // Expand the cap area by a random factor whose log is uniformly // distributed between 0 and log(1e2). var expanded_cap = S2Cap.FromCenterHeight( cap.Center, Math.Min(2.0, Math.Pow(1e2, rnd.RandDouble()) * cap.Height())); var radius = (expanded_cap.Radius - cap.Radius).Radians(); var max_level_diff = rnd.Uniform(8); // Generate a covering for the original cap, and measure the maximum // distance from the cap center to any point in the covering. coverer.Options_.MaxCells = 1 + rnd.Skewed(10); var covering = coverer.GetCovering(cap); S2Testing.CheckCovering(cap, covering, true); var covering_radius = GetRadius(covering, cap.Center); // This code duplicates the logic in Expand(min_radius, max_level_diff) // that figures out an appropriate cell level to use for the expansion. int min_level = S2.kMaxCellLevel; foreach (var id in covering) { min_level = Math.Min(min_level, id.Level()); } var expand_level = Math.Min(min_level + max_level_diff, S2.kMinWidth.GetLevelForMinValue(radius)); // Generate a covering for the expanded cap, and measure the new maximum // distance from the cap center to any point in the covering. covering.Expand(S1Angle.FromRadians(radius), max_level_diff); S2Testing.CheckCovering(expanded_cap, covering, false); double expanded_covering_radius = GetRadius(covering, cap.Center); // If the covering includes a tiny cell along the boundary, in theory the // maximum angle of the covering from the cap center can increase by up to // twice the maximum length of a cell diagonal. Assert.True(expanded_covering_radius - covering_radius <= 2 * S2.kMaxDiag.GetValue(expand_level)); } }
/** * Generates a random edge whose center is in the given cap. */ private S2Edge randomEdgeCrossingCap(double maxLengthMeters, S2Cap cap) { // Pick the edge center at random. var edgeCenter = samplePoint(cap); // Pick two random points in a suitably sized cap about the edge center. var edgeCap = S2Cap.FromAxisAngle( edgeCenter, S1Angle.FromRadians(maxLengthMeters / S2LatLng.EarthRadiusMeters / 2)); var p1 = samplePoint(edgeCap); var p2 = samplePoint(edgeCap); return(new S2Edge(p1, p2)); }
public void AddPoints(S2Cap index_cap, int num_points, TestIndex index) { S2Testing.Fractal fractal = new(); fractal.SetLevelForApproxMaxEdges(num_points); fractal.FractalDimension = (1.5); var loop = ( fractal.MakeLoop(S2Testing.GetRandomFrameAt(index_cap.Center), index_cap.RadiusAngle())); for (int i = 0; i < loop.NumVertices; ++i) { index.Add(loop.Vertex(i), i); } }
public void testRectBound() { // Empty and full caps. Assert.True(S2Cap.Empty.RectBound.IsEmpty); Assert.True(S2Cap.Full.RectBound.IsFull); var kDegreeEps = 1e-13; // Maximum allowable error for latitudes and longitudes measured in // degrees. (assertDoubleNear uses a fixed tolerance that is too small.) // Cap that includes the south pole. var rect = S2Cap.FromAxisAngle(getLatLngPoint(-45, 57), S1Angle.FromDegrees(50)).RectBound; assertDoubleNear(rect.LatLo.Degrees, -90, kDegreeEps); assertDoubleNear(rect.LatHi.Degrees, 5, kDegreeEps); Assert.True(rect.Lng.IsFull); // Cap that is tangent to the north pole. rect = S2Cap.FromAxisAngle(S2Point.Normalize(new S2Point(1, 0, 1)), S1Angle.FromRadians(S2.PiOver4)).RectBound; assertDoubleNear(rect.Lat.Lo, 0); assertDoubleNear(rect.Lat.Hi, S2.PiOver2); Assert.True(rect.Lng.IsFull); rect = S2Cap .FromAxisAngle(S2Point.Normalize(new S2Point(1, 0, 1)), S1Angle.FromDegrees(45)).RectBound; assertDoubleNear(rect.LatLo.Degrees, 0, kDegreeEps); assertDoubleNear(rect.LatHi.Degrees, 90, kDegreeEps); Assert.True(rect.Lng.IsFull); // The eastern hemisphere. rect = S2Cap .FromAxisAngle(new S2Point(0, 1, 0), S1Angle.FromRadians(S2.PiOver2 + 5e-16)).RectBound; assertDoubleNear(rect.LatLo.Degrees, -90, kDegreeEps); assertDoubleNear(rect.LatHi.Degrees, 90, kDegreeEps); Assert.True(rect.Lng.IsFull); // A cap centered on the equator. rect = S2Cap.FromAxisAngle(getLatLngPoint(0, 50), S1Angle.FromDegrees(20)).RectBound; assertDoubleNear(rect.LatLo.Degrees, -20, kDegreeEps); assertDoubleNear(rect.LatHi.Degrees, 20, kDegreeEps); assertDoubleNear(rect.LngLo.Degrees, 30, kDegreeEps); assertDoubleNear(rect.LngHi.Degrees, 70, kDegreeEps); // A cap centered on the north pole. rect = S2Cap.FromAxisAngle(getLatLngPoint(90, 123), S1Angle.FromDegrees(10)).RectBound; assertDoubleNear(rect.LatLo.Degrees, 80, kDegreeEps); assertDoubleNear(rect.LatHi.Degrees, 90, kDegreeEps); Assert.True(rect.Lng.IsFull); }
// Encode/Decode not yet implemented for these types. // S2R2Rect // S2RegionIntersection // S2RegionUnion // TestEncodeDecode tests that the input encodes to match the expected // golden data, and then returns the decode of the data into dst. private static Region TestEncodeDecode <Region>(string golden, Region src) where Region : IEncoder, IS2Region <Region> { Encoder encoder = new(); src.Encode(encoder); var str = encoder.HexString(); Assert.Equal(golden, str); var decoder = encoder.Decoder(); Dictionary <Type, Func <Decoder, (bool, IEncoder?)> > funcDict = new() { { typeof(S2Cap), (d) => S2Cap.Decode(d) }, { typeof(S2Cell), (d) => S2Cell.Decode(d) },
public void Test_S2RegionEncodeDecodeTest_S2Cap() { S2Cap cap_from_point = S2Cap.FromPoint(new S2Point(3, 2, 1).Normalize()); var cap_from_center_height = S2Cap.FromCenterHeight(new S2Point(0, 0, 1).Normalize(), 5); var cap = TestEncodeDecode(kEncodedCapEmpty, S2Cap.Empty); Assert.True(S2Cap.Empty.ApproxEquals(cap)); cap = TestEncodeDecode(kEncodedCapFull, S2Cap.Full); Assert.True(S2Cap.Full.ApproxEquals(cap)); cap = TestEncodeDecode(kEncodedCapFromPoint, cap_from_point); Assert.True(cap_from_point.ApproxEquals(cap)); cap = TestEncodeDecode(kEncodedCapFromCenterHeight, cap_from_center_height); Assert.True(cap_from_center_height.ApproxEquals(cap)); }
private static void CompareS2LoopToShape(S2Loop loop, S2Shape shape) { MutableS2ShapeIndex index = new(); index.Add(shape); S2Cap cap = loop.GetCapBound(); var query = index.MakeS2ContainsPointQuery(); for (int iter = 0; iter < 100; ++iter) { S2Point point = S2Testing.SamplePoint(cap); Assert.Equal(loop.Contains(point), query.ShapeContains(index.Shape(0), point)); } }
public void Test_S2Cap_GetCentroid() { // Empty and full caps. Assert.Equal(new S2Point(), S2Cap.Empty.Centroid()); Assert.True(S2Cap.Full.Centroid().Norm() <= S2.DoubleError); // Random caps. for (int i = 0; i < 100; ++i) { S2Point center = S2Testing.RandomPoint(); double height = S2Testing.Random.UniformDouble(0.0, 2.0); S2Cap cap = S2Cap.FromCenterHeight(center, height); S2Point centroid = cap.Centroid(); S2Point expected = center * (1.0 - height / 2.0) * cap.Area(); Assert.True((expected - centroid).Norm() <= S2.DoubleError); } }
public void Test_S2ShapeIndexRegion_GetCapBound() { var id = S2CellId.FromDebugString("3/0123012301230123012301230123"); // Add a polygon that is slightly smaller than the cell being tested. MutableS2ShapeIndex index = new(); index.Add(NewPaddedCell(id, -kPadding)); S2Cap cell_bound = new S2Cell(id).GetCapBound(); S2Cap index_bound = index.MakeS2ShapeIndexRegion().GetCapBound(); Assert.True(index_bound.Contains(cell_bound)); // Note that S2CellUnion.GetCapBound returns a slightly larger bound than // S2Cell.GetBound even when the cell union consists of a single S2CellId. Assert.True(index_bound.RadiusAngle() <= 1.00001 * cell_bound.RadiusAngle()); }
public void AddPoints(S2Cap index_cap, int num_points, TestIndex index) { int sqrt_num_points = (int)Math.Ceiling(Math.Sqrt(num_points)); S2PointVector3 frame = S2Testing.GetRandomFrameAt(index_cap.Center); double radius = index_cap.RadiusAngle().Radians; double spacing = 2 * radius / sqrt_num_points; for (int i = 0; i < sqrt_num_points; ++i) { for (int j = 0; j < sqrt_num_points; ++j) { S2Point point = new(Math.Tan((i + 0.5) * spacing - radius), Math.Tan((j + 0.5) * spacing - radius), 1.0); index.Add(S2.FromFrame(frame, point.Normalize()), i * sqrt_num_points + j); } } }
public void Test_S2LatLngRect_GetCapBound() { // Bounding cap at center is smaller: Assert.True(RectFromDegrees(-45, -45, 45, 45).GetCapBound(). ApproxEquals(S2Cap.FromCenterHeight(new S2Point(1, 0, 0), 0.5))); // Bounding cap at north pole is smaller: Assert.True(RectFromDegrees(88, -80, 89, 80).GetCapBound(). ApproxEquals(new S2Cap(new S2Point(0, 0, 1), S1Angle.FromDegrees(2)))); // Longitude span > 180 degrees: Assert.True(RectFromDegrees(-30, -150, -10, 50).GetCapBound(). ApproxEquals(new S2Cap(new S2Point(0, 0, -1), S1Angle.FromDegrees(80)))); // Ensure hemispheres are bounded conservatively. Assert.True(RectFromDegrees(-10, -100, 0, 100).GetCapBound().Radius >= S1ChordAngle.Right); }
private void getVertices(String str, S2Point x, S2Point y, S2Point z, double maxPerturbation, List <S2Point> vertices) { // Parse the vertices, perturb them if desired, and transform them into the // given frame. var line = makePolyline(str); for (var i = 0; i < line.NumVertices; ++i) { var p = line.Vertex(i); // (p[0]*x + p[1]*y + p[2]*z).Normalize() var axis = S2Point.Normalize(((x * p.X) + (y * p.Y)) + (z * p.Z)); var cap = S2Cap.FromAxisAngle(axis, S1Angle.FromRadians(maxPerturbation)); vertices.Add(samplePoint(cap)); } }
protected S2Point samplePoint(S2Cap cap) { // We consider the cap axis to be the "z" axis. We choose two other axes to // complete the coordinate frame. var z = cap.Axis; var x = z.Ortho; var y = S2Point.CrossProd(z, x); // The surface area of a spherical cap is directly proportional to its // height. First we choose a random height, and then we choose a random // point along the circle at that height. var h = rand.NextDouble() * cap.Height; var theta = 2 * S2.Pi * rand.NextDouble(); var r = Math.Sqrt(h * (2 - h)); // Radius of circle. // (cos(theta)*r*x + sin(theta)*r*y + (1-h)*z).Normalize() return(S2Point.Normalize(((x * Math.Cos(theta) * r) + (y * Math.Sin(theta) * r)) + (z * (1 - h)))); }
public void Test_S2RegionCoverer_SimpleCoverings() { Assert.True(false); //TODO const int kMaxLevel = S2.kMaxCellLevel; var options = new S2RegionCoverer.Options { MaxCells = Int32.MaxValue }; for (int i = 0; i < 1000; ++i) { int level = S2Testing.Random.Uniform(kMaxLevel + 1); options.MinLevel = (level); options.MaxLevel = (level); double max_area = Math.Min(S2.M_4_PI, 1000 * S2Cell.AverageArea(level)); S2Cap cap = S2Testing.GetRandomCap(0.1 * S2Cell.AverageArea(kMaxLevel), max_area); var covering = new List <S2CellId>(); S2RegionCoverer.GetSimpleCovering(cap, cap.Center, level, covering); CheckCovering(options, cap, covering, false); } }
public void Test_S2RegionCoverer_RandomCaps() { const int kMaxLevel = S2.kMaxCellLevel; S2RegionCoverer.Options options = new(); for (int i = 0; i < 1000; ++i) { do { options.MinLevel = (S2Testing.Random.Uniform(kMaxLevel + 1)); options.MaxLevel = (S2Testing.Random.Uniform(kMaxLevel + 1)); } while (options.MinLevel > options.MaxLevel); options.MaxCells = S2Testing.Random.Skewed(10); options.LevelMod = (1 + S2Testing.Random.Uniform(3)); double max_area = Math.Min(S2.M_4_PI, (3 * options.MaxCells + 1) * S2Cell.AverageArea(options.MinLevel)); S2Cap cap = S2Testing.GetRandomCap(0.1 * S2Cell.AverageArea(kMaxLevel), max_area); S2RegionCoverer coverer = new(options); coverer.GetCovering(cap, out var covering); CheckCovering(options, cap, covering, false); coverer.GetInteriorCovering(cap, out var interior); CheckCovering(options, cap, interior, true); // Check that GetCovering is deterministic. coverer.GetCovering(cap, out var covering2); Assert.Equal(covering, covering2); // Also check S2CellUnion.Denormalize(). The denormalized covering // may still be different and smaller than "covering" because // S2RegionCoverer does not guarantee that it will not output all four // children of the same parent. S2CellUnion cells = new(covering); var denormalized = new List <S2CellId>(); cells.Denormalize(options.MinLevel, options.LevelMod, denormalized); CheckCovering(options, cap, denormalized, false); } }
// The implementation is approximate but conservative; it always returns // "false" if the cell is not contained by the buffered region, but it may // also return false in some cases where "cell" is in fact contained. public bool Contains(S2Cell cell) { // Return true if the buffered region is guaranteed to cover whole globe. if (radius_successor_ > S1ChordAngle.Straight) { return(true); } // To implement this method perfectly would require computing the directed // Hausdorff distance, which is expensive (and not currently implemented). // However the following heuristic is almost as good in practice and much // cheaper to compute. // Return true if the unbuffered region contains this cell. if (Index().MakeS2ShapeIndexRegion().Contains(cell)) { return(true); } // Otherwise approximate the cell by its bounding cap. // // NOTE(ericv): It would be slightly more accurate to first find the closest // point in the indexed geometry to the cell, and then measure the actual // maximum distance from that point to the cell (a poor man's Hausdorff // distance). But based on actual tests this is not worthwhile. S2Cap cap = cell.GetCapBound(); if (Radius < cap.Radius) { return(false); } // Return true if the distance to the cell center plus the radius of the // cell's bounding cap is less than or equal to "radius_". var target = new S2ClosestEdgeQuery.PointTarget(cell.Center()); return(query_.IsDistanceLess(target, radius_successor_ - cap.Radius)); }
protected S2Point samplePoint(S2Cap cap) { // We consider the cap axis to be the "z" axis. We choose two other axes to // complete the coordinate frame. var z = cap.Axis; var x = z.Ortho; var y = S2Point.CrossProd(z, x); // The surface area of a spherical cap is directly proportional to its // height. First we choose a random height, and then we choose a random // point along the circle at that height. var h = rand.NextDouble()*cap.Height; var theta = 2*S2.Pi*rand.NextDouble(); var r = Math.Sqrt(h*(2 - h)); // Radius of circle. // (cos(theta)*r*x + sin(theta)*r*y + (1-h)*z).Normalize() return S2Point.Normalize(((x * Math.Cos(theta)*r) + (y * Math.Sin(theta)*r)) + (z * (1 - h))); }