Interface S2LaxPolygonShape

  • All Superinterfaces:
    S2Shape, S2ShapeAspect.ChainAspect, S2ShapeAspect.EdgeAspect, S2ShapeAspect.EdgeAspect.Closed, S2ShapeAspect.Mixed, S2ShapeAspect.TopoAspect, S2ShapeAspect.VertexAspect
    All Known Implementing Classes:
    S2LaxPolygonShape.MultiArray, S2LaxPolygonShape.MultiList, S2LaxPolygonShape.MultiPacked, S2LaxPolygonShape.MultiSnapped, S2LaxPolygonShape.SimpleArray, S2LaxPolygonShape.SimpleList, S2LaxPolygonShape.SimplePacked, S2LaxPolygonShape.SimpleSnapped

    @GwtIncompatible("S2ShapeAspect incompatible")
    public interface S2LaxPolygonShape
    extends S2ShapeAspect.EdgeAspect.Closed
    A region defined by a collection of zero or more closed loops. The interior is the region to the left of all loops. Loops are not closed, that is, the last edge is an implicit path from the last vertex back to the first vertex.

    This is similar to S2Polygon.shape(), except that this class supports polygons with two types of degeneracy:

    1. Degenerate edges (from a vertex to itself)
    2. Sibling edge pairs (consisting of two oppositely oriented edges)

    Degeneracies can represent either "shells" or "holes" depending on the loop they are contained by. For example, a degenerate edge or sibling pair contained by a "shell" would be interpreted as a degenerate hole. Such edges form part of the boundary of the polygon.

    Loops with fewer than three vertices are interpreted as follows:

    • A loop with two vertices defines two edges (in opposite directions).
    • A loop with one vertex defines a single degenerate edge.
    • A loop with no vertices is interpreted as the "full loop" containing all points on the sphere. If this loop is present, then all other loops must form degeneracies (i.e., degenerate edges or sibling pairs). For example, two loops {} and {X} would be interpreted as the full polygon with a degenerate single-point hole at X.

    No error checking is performed during construction. It is perfectly fine to create objects that do not meet the requirements below (e.g., in order to analyze or fix those problems). However, some additional conditions must be satisfied in order to perform certain operations:

    • In order to be valid for point containment tests, the polygon must satisfy the "interior is on the left" rule. This means that there must not be any crossing edges, and if there are duplicate edges then all but at most one of them must belong to a sibling pair (i.e., the number of edges in opposite directions must differ by at most one).
    • To be valid for boolean operations, degenerate edges and sibling pairs cannot coincide with any other edges. For example, the following situations are not allowed:
      • {AA, AA} // degenerate edge coincides with another edge
      • {AA, AB} // degenerate edge coincides with another edge
      • {AB, BA, AB} // sibling pair coincides with another edge

    Note that this class is faster to initialize and is more compact than S2Polygon, but it does not have any built-in operations, as those are by design provided by other classes. All the design considerations here are focused on the meaning and storage of the model itself. All implementations store a single list of vertices, and if there are multiple loops, an int[] that provides the offset into the list where each loop's vertices begin. This scales at a rate of one int per loop. This compares favorably to S2Polygon, which requires 4 objects and an int per loop. Heap size of the vertex data scales at different rates, depending on the storage:

    1. Standard polygons copy points into one immutable list, which requires 48 bytes per vertex on a standard 64-bit JVM.
    2. Packed polygons copy coordinates into a double[], and convert these coordinates back to point instances on demand. This consumes 24 bytes/vertex, but construction and other operations are slower and drive the garbage collector harder.
    3. Snapped polygons copy cells into a long[], and convert the cell centers to point instances on demand. This consumes just 8 bytes/vertex, but construction and especially operations are even slower and drive the garbage collector even harder.
      • Method Detail

        • create

          static S2LaxPolygonShape create​(java.lang.Iterable<? extends java.lang.Iterable<S2Point>> loops)
          Creates a polygon from the given loops, defensively copying any loop's Iterable except an ImmutableList, to ensure the polygon is deeply immutable.

          If given no loops, the empty polygon is the result. If given only empty loops, the full polygon is the result. Otherwise the resulting polygon's interior is on the left of the loops when walking the vertices in the given order.

          Each loop should not be closed, that is, the last vertex in each inner iterable should differ from the first vertex, since an implicit edge from the last vertex back to the first is assumed.

        • createPacked

          static S2LaxPolygonShape createPacked​(java.lang.Iterable<? extends java.lang.Iterable<S2Point>> loops)
          As create(com.google.common.geometry.S2Polygon), but packs coordinates into a double[] array. Operations are slower since S2Points are constructed on each access, but this representation has vastly fewer objects, and so can be a better choice if polygons may be held in RAM for a long time.
        • createSnapped

          static S2LaxPolygonShape createSnapped​(java.lang.Iterable<? extends java.lang.Iterable<S2CellId>> loops)
          As create(com.google.common.geometry.S2Polygon), but packs vertices into a long[] array. Operations may be much slower since S2Points are constructed on each access, but this representation is the smallest, and so may be far better if polygons may be held in RAM for a long time.
        • readResolve

          default java.lang.Object readResolve()
          Canonicalizes the empty/full instances on deserialization.
        • dimension

          default int dimension()
          Description copied from interface: S2Shape
          Returns the dimension of the geometry represented by this shape.
          • 0 - Point geometry. Each point is represented as a degenerate edge.
          • 1 - Polyline geometry. Polyline edges may be degenerate. A shape may represent any number of polylines. Polylines edges may intersect.
          • 2 - Polygon geometry. Edges should be oriented such that the polygon interior is always on the left. In theory the edges may be returned in any order, but typically the edges are organized as a collection of edge chains where each chain represents one polygon loop. Polygons may have degeneracies, e.g., degenerate edges or sibling pairs consisting of an edge and its corresponding reversed edge. A polygon loop may also be full (containing all points on the sphere); by convention this is represented as a chain with no edges.

          Note that this method allows degenerate geometry of different dimensions to be distinguished, e.g., it allows a point to be distinguished from a polyline or polygon that has been simplified to a single point.

          Specified by:
          dimension in interface S2Shape
          Specified by:
          dimension in interface S2ShapeAspect.TopoAspect
        • isEmpty

          default boolean isEmpty()
          Returns true if this polygon contains no area, i.e. has no loops.
        • isFull

          default boolean isFull()
          Returns true if this polygon contains all points, i.e. there are loops, but all are empty.
        • hasInterior

          default boolean hasInterior()
          Description copied from interface: S2Shape
          Returns true if this shape has an interior, i.e. the shape consists of one or more closed non-intersecting loops.
          Specified by:
          hasInterior in interface S2Shape
          Specified by:
          hasInterior in interface S2ShapeAspect.TopoAspect