/// <summary> /// Appends all edges in the given S2ShapeIndexCell to the given vector. /// </summary> private static void AppendShapeEdges(S2ShapeIndex index, S2ShapeIndexCell cell, ShapeEdgeVector shape_edges) { for (int s = 0; s < cell.NumClipped(); ++s) { var clipped = cell.Clipped(s); var shape = index.Shape(clipped.ShapeId); var num_edges = clipped.NumEdges; for (int i = 0; i < num_edges; i++) { shape_edges.Add(new ShapeEdge(shape, clipped.Edge(i))); } } }
// Returns the total area of all polygons in the index. Returns zero if no // polygons are present. This method has good relative accuracy for both very // large and very small regions. Note that the result may exceed 4*Pi if the // index contains overlapping polygons. // // All edges are modeled as spherical geodesics. The result can be converted // to an area on the Earth's surface (with a worst-case error of 0.900% near // the poles) using the functions in s2earth.h. public static double GetArea(S2ShapeIndex index) { double area = 0; for (int i = 0; i < index.NumShapeIds(); ++i) { var shape = index.Shape(i); if (shape != null) { area += S2.GetArea(shape); } } return(area); }
// Returns the total perimeter of all polygons in the index (including both // "shells" and "holes"). Returns zero if no polygons are present. // // All edges are modeled as spherical geodesics. The result can be converted // to a distance on the Earth's surface (with a worst-case error of 0.562% // near the equator) using the functions in s2earth.h. public static S1Angle GetPerimeter(S2ShapeIndex index) { var perimeter = S1Angle.Zero; for (int i = 0; i < index.NumShapeIds(); ++i) { var shape = index.Shape(i); if (shape != null) { perimeter += S2.GetPerimeter(shape); } } return(perimeter); }
// Returns the total length of all polylines in the index. Returns zero if no // polylines are present. // // All edges are modeled as spherical geodesics. The result can be converted // to a distance on the Earth's surface (with a worst-case error of 0.562% // near the equator) using the functions in s2earth.h. public static S1Angle GetLength(S2ShapeIndex index) { var length = S1Angle.Zero; for (int i = 0; i < index.NumShapeIds(); ++i) { var shape = index.Shape(i); if (shape != null) { length += S2.GetLength(shape); } } return(length); }
// Returns the number of points (objects of dimension zero) in the index. // Note that polyline and polygon vertices are *not* included in this count. public static int GetNumPoints(S2ShapeIndex index) { int count = 0; for (int i = 0; i < index.NumShapeIds(); ++i) { var shape = index.Shape(i); if (shape != null && shape.Dimension() == 0) { count += shape.NumEdges(); } } return(count); }
// Returns the maximum dimension of any shape in the index. Returns -1 if the // index does not contain any shapes. // // Note that the dimension does *not* depend on whether the shapes in the // index contain any points; for example, the dimension of an empty point set // is 0, and the dimension of an empty polygon is 2. public static int GetDimension(S2ShapeIndex index) { int dim = -1; for (int i = 0; i < index.NumShapeIds(); ++i) { var shape = index.Shape(i); if (shape != null) { dim = Math.Max(dim, shape.Dimension()); } } return(dim); }
public bool MoveNext() { while (++edge_id_ >= num_edges_) { if (++shape_id_ >= index_.NumShapeIds()) { break; } var shape = index_.Shape(shape_id_); num_edges_ = (shape == null) ? 0 : shape.NumEdges(); edge_id_ = -1; } return(!Done()); }
public VisitIntersectingShapesTest(S2ShapeIndex index) { index_ = index; iter_ = new(index); region_ = new(index); // Create an S2ShapeIndex for each shape in the original index, so that we // can use MayIntersect() and Contains() to determine the status of // individual shapes. for (int s = 0; s < index_.NumShapeIds(); ++s) { var shape_index = new MutableS2ShapeIndex(); shape_index.Add(new S2WrappedShape(index_.Shape(s))); shape_indexes_.Add(shape_index); } }
// Returns the centroid of all shapes whose dimension is maximal within the // index, multiplied by the measure of those shapes. For example, if the // index contains points and polylines, then the result is defined as the // centroid of the polylines multiplied by the total length of those // polylines. The points would be ignored when computing the centroid. // // The measure of a given shape is defined as follows: // // - For dimension 0 shapes, the measure is shape.num_edges(). // - For dimension 1 shapes, the measure is GetLength(shape). // - For dimension 2 shapes, the measure is GetArea(shape). // // Note that the centroid is not unit length, so you may need to call // Normalize() before passing it to other S2 functions. Note that this // function returns (0, 0, 0) if the index contains no geometry. // // The centroid is scaled by the total measure of the shapes for two reasons: // (1) it is cheaper to compute this way, and (2) this makes it easier to // compute the centroid of a collection of shapes (since the individual // centroids can simply be summed). public static S2Point GetCentroid(S2ShapeIndex index) { int dim = GetDimension(index); var centroid = S2Point.Empty; for (int i = 0; i < index.NumShapeIds(); ++i) { var shape = index.Shape(i); if (shape != null && shape.Dimension() == dim) { centroid += S2.GetCentroid(shape); } } return(centroid); }
/// <summary> /// Verifies that two S2ShapeIndexes have identical contents (including all the /// S2Shapes in both indexes). /// </summary> public static void ExpectEqual(S2ShapeIndex a, S2ShapeIndex b) { // Check that both indexes have identical shapes. Assert.True(a.NumShapeIds() == b.NumShapeIds()); for (int shape_id = 0; shape_id < a.NumShapeIds(); ++shape_id) { var a_shape = a.Shape(shape_id); var b_shape = b.Shape(shape_id); if (a_shape == null || b_shape == null) { Assert.True(a_shape == b_shape); } else { Assert.True(a_shape.Id == b_shape.Id); Assert.True(a_shape == b_shape); } } // Check that both indexes have identical cell contents. var a_it = a.GetNewEnumerator(); var b_it = b.GetNewEnumerator(); var aHasNext = a_it.MoveNext(); var bHasNext = b_it.MoveNext(); while (aHasNext && bHasNext) { Assert.True(a_it.Current.Item1 == b_it.Current.Item1); var a_cell = a_it.Current.Item2; var b_cell = b_it.Current.Item2; Assert.True(a_cell.NumClipped() == b_cell.NumClipped()); for (var i = 0; i < a_cell.NumClipped(); ++i) { var a_clipped = a_cell.Clipped(i); var b_clipped = b_cell.Clipped(i); Assert.True(a_clipped.ShapeId == b_clipped.ShapeId); Assert.True(a_clipped.ContainsCenter == b_clipped.ContainsCenter); Assert.True(a_clipped.NumEdges == b_clipped.NumEdges); for (int j = 0; j < a_clipped.NumEdges; ++j) { Assert.True(a_clipped.Edge(j) == b_clipped.Edge(j)); } } aHasNext = a_it.MoveNext(); bHasNext = b_it.MoveNext(); } Assert.True(!bHasNext); // Spot-check the other iterator methods. (We know that both indexes have // the same contents, so any differences are due to implementation bugs.) a_it.Reset(); b_it.Reset(); a_it.MoveNext(); b_it.MoveNext(); Assert.True(a_it.Current.Item1 == b_it.Current.Item1); aHasNext = a_it.MoveNext(); bHasNext = b_it.MoveNext(); if (aHasNext) { Assert.True(a_it.Current.Item1 == b_it.Current.Item1); Assert.True(aHasNext == bHasNext); // Assert.True(a_it.MovePrevious()); // Assert.True(b_it.MovePrevious()); Assert.True(a_it.Current.Item1 == b_it.Current.Item1); } // Assert.False(a_it.MovePrevious()); // Assert.False(b_it.MovePrevious()); // a_it.Finish(); // b_it.Finish(); // Assert.True(a_it.id() == b_it.id()); // a_it.Seek(a_it.id().Next); // b_it.Seek(b_it.id().Next); // Assert.True(a_it.id() == b_it.id()); }