Class S2ShapeUtil
- java.lang.Object
-
- com.google.common.geometry.S2ShapeUtil
-
@GwtCompatible public class S2ShapeUtil extends Object
Utilities for working with S2Shape.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static classS2ShapeUtil.AreaCentroidMeasureA collector of both combined area and centroid values.static classS2ShapeUtil.AreaMeasureA collector of the steradian area.static classS2ShapeUtil.CentroidMeasureA collector of the center of mass.static interfaceS2ShapeUtil.IntPredicateA filter of indexes.static interfaceS2ShapeUtil.TriangleConsumerA consumer of triangles.
-
Method Summary
All Methods Static Methods Concrete Methods Modifier and Type Method Description static booleancontainsBruteForce(S2Shape shape, S2Point point)Returns true if the given shape contains the given point.static booleanequals(S2ShapeIndex.Cell a, S2ShapeIndex.Cell b)Returns true if the index cells 'a' and 'b' contain identical contents.static booleanequals(S2ShapeIndex.S2ClippedShape a, S2ShapeIndex.S2ClippedShape b)Returns true if the clipped shapes 'a' and 'b' have identical edge offsets.static booleanequals(S2ShapeIndex a, S2ShapeIndex b)Returns true if all methods of the two S2ShapeIndex values return identical results, including all the S2Shapes in both indexes.static booleanequals(S2Shape a, S2Shape b)Returns true if all methods of the two S2Shapes return identical results, except for id() and typeTag().static booleanequals(List<S2Shape> a, List<S2Shape> b)Returns true if the lists 'a' and 'b' have identical shapes according toequals(S2Shape, S2Shape).static S2Shape.ReferencePointgetReferencePoint(S2Shape shape)This is a helper function for implementing S2Shape.getReferencePoint().static intlowerBound(int low, int high, S2ShapeUtil.IntPredicate targetIsGreater)Returns the lowest index in the range[low, high)not smaller than a target.static intupperBound(int low, int high, S2ShapeUtil.IntPredicate targetIsSmaller)Returns the lowest index in the range[low, high)greater than a target.static voidvisitSurfaceIntegral(List<S2Point> vertices, S2ShapeUtil.TriangleConsumer consumer)Visits the surface integral of the vertices, that is, a collection of oriented triangles, possibly overlapping.
-
-
-
Method Detail
-
lowerBound
public static int lowerBound(int low, int high, S2ShapeUtil.IntPredicate targetIsGreater)Returns the lowest index in the range[low, high)not smaller than a target.
-
upperBound
public static int upperBound(int low, int high, S2ShapeUtil.IntPredicate targetIsSmaller)Returns the lowest index in the range[low, high)greater than a target.
-
equals
public static boolean equals(S2Shape a, S2Shape b)
Returns true if all methods of the two S2Shapes return identical results, except for id() and typeTag(). Also returns true if both instances are null.
-
equals
public static boolean equals(List<S2Shape> a, List<S2Shape> b)
Returns true if the lists 'a' and 'b' have identical shapes according toequals(S2Shape, S2Shape).
-
equals
public static boolean equals(S2ShapeIndex.S2ClippedShape a, S2ShapeIndex.S2ClippedShape b)
Returns true if the clipped shapes 'a' and 'b' have identical edge offsets.This method does not check that
a.shape()andb.shape()are equal.
-
equals
public static boolean equals(S2ShapeIndex.Cell a, S2ShapeIndex.Cell b)
Returns true if the index cells 'a' and 'b' contain identical contents.
-
equals
public static boolean equals(S2ShapeIndex a, S2ShapeIndex b)
Returns true if all methods of the two S2ShapeIndex values return identical results, including all the S2Shapes in both indexes.
-
containsBruteForce
public static boolean containsBruteForce(S2Shape shape, S2Point point)
Returns true if the given shape contains the given point. Most clients should not use this method, since its running time is linear in the number of shape edges. Instead clients should create an S2ShapeIndex and useS2ContainsPointQuery, since that strategy is much more efficient when many points need to be tested.Polygon boundaries are treated as being semi-open. See
S2ContainsPointQuery.S2VertexModelfor other options.
-
getReferencePoint
public static S2Shape.ReferencePoint getReferencePoint(S2Shape shape)
This is a helper function for implementing S2Shape.getReferencePoint().Given a shape consisting of closed polygonal loops, the interior of the shape is defined as the region to the left of all edges (which must be oriented consistently). This function then chooses an arbitrary point and returns true if that point is contained by the shape.
Unlike S2Loop and S2Polygon, this method allows duplicate vertices and edges, which requires some extra care with definitions. The rule that we apply is that an edge and its reverse edge "cancel" each other: the result is the same as if that edge pair were not present. Therefore shapes that consist only of degenerate loop(s) are either empty or full; by convention, the shape is considered full if and only if it contains an empty loop (see S2LaxPolygonShape for details).
Determining whether a loop on the sphere contains a point is harder than the corresponding problem in 2D plane geometry. It cannot be implemented just by counting edge crossings because there is no such thing as a "point at infinity" that is guaranteed to be outside the loop.
-
visitSurfaceIntegral
public static void visitSurfaceIntegral(List<S2Point> vertices, S2ShapeUtil.TriangleConsumer consumer)
Visits the surface integral of the vertices, that is, a collection of oriented triangles, possibly overlapping.Let the sign of a triangle be +1 if it is CCW and -1 otherwise, and let the sign of a point "x" be the sum of the signs of the triangles containing "x". Then the collection of triangles T is chosen such that either:
- Each point in the loop interior has sign +1, and sign 0 otherwise; or
- Each point in the loop exterior has sign -1, and sign 0 otherwise.
The triangles basically consist of a "fan" from vertex 0 to every loop edge that does not include vertex 0. These triangles will always satisfy either (1) or (2).
However, what makes this a bit tricky is that spherical edges become numerically unstable as their length approaches 180 degrees. Of course there is not much we can do if the loop itself contains such edges, but we would like to make sure that all the triangle edges under our control (i.e., the non-loop edges) are stable. For example, consider a loop around the equator consisting of four equally spaced points. This is a well-defined loop, but we cannot just split it into two triangles by connecting vertex 0 to vertex 2.
We handle this type of situation by moving the origin of the triangle fan whenever we are about to create an unstable edge. We choose a new location for the origin such that all relevant edges are stable. We also create extra triangles with the appropriate orientation so that the sum of the triangle signs is still correct at every point.
-
-