Class ShapeCollection<S extends Shape>

  • All Implemented Interfaces:
    Iterable<S>, Collection<S>, List<S>, Shape

    public class ShapeCollection<S extends Shape>
    extends AbstractList<S>
    implements Shape
    A collection of Shape objects, analogous to an OGC GeometryCollection. The implementation demands a List (with random access) so that the order can be retained if an application requires it, although logically it's treated as an unordered Set, mostly.

    Ideally, relate(Shape) should return the same result no matter what the shape order is, although the default implementation can be order dependent when the shapes overlap; see relateContainsShortCircuits(). To improve performance slightly, the caller could order the shapes by largest first so that relate() will have a greater chance of short-circuit'ing sooner. As the Shape contract states; it may return intersects when the best answer is actually contains or within. If any shape intersects the provided shape then that is the answer.

    This implementation is not optimized for a large number of shapes; relate is O(N). A more sophisticated implementation might do an R-Tree based on bbox'es, for example.

    • Constructor Detail

      • ShapeCollection

        public ShapeCollection​(List<S> shapes,
                               SpatialContext ctx)
        WARNING: shapes is copied by reference.
        Parameters:
        shapes - Copied by reference! (make a defensive copy if caller modifies)
        ctx -
    • Method Detail

      • getShapes

        public List<S> getShapes()
      • getBoundingBox

        public Rectangle getBoundingBox()
        Description copied from interface: Shape
        Get the bounding box for this Shape. This means the shape is within the bounding box and that it touches each side of the rectangle.

        Postcondition: this.getBoundingBox().relate(this) == CONTAINS

        Specified by:
        getBoundingBox in interface Shape
      • getCenter

        public Point getCenter()
        Description copied from interface: Shape
        Returns the center point of this shape. This is usually the same as getBoundingBox().getCenter() but it doesn't have to be.

        Postcondition: this.relate(this.getCenter()) == CONTAINS

        Specified by:
        getCenter in interface Shape
      • hasArea

        public boolean hasArea()
        Description copied from interface: Shape
        Does the shape have area? This will be false for points and lines. It will also be false for shapes that normally have area but are constructed in a degenerate case as to not have area (e.g. a circle with 0 radius or rectangle with no height or no width).
        Specified by:
        hasArea in interface Shape
      • getBuffered

        public ShapeCollection getBuffered​(double distance,
                                           SpatialContext ctx)
        Description copied from interface: Shape
        Returns a buffered version of this shape. The buffer is usually a rounded-corner buffer, although some shapes might buffer differently. This is an optional operation.
        Specified by:
        getBuffered in interface Shape
        Returns:
        Not null, and the returned shape should contain the current shape.
      • relate

        public SpatialRelation relate​(Shape other)
        Description copied from interface: Shape
        Describe the relationship between the two objects. For example
        • this is WITHIN other
        • this CONTAINS other
        • this is DISJOINT other
        • this INTERSECTS other
        Note that a Shape implementation may choose to return INTERSECTS when the true answer is WITHIN or CONTAINS for performance reasons. If a shape does this then it must document when it does. Ideally the shape will not do this approximation in all circumstances, just sometimes.

        If the shapes are equal then the result is CONTAINS (preferred) or WITHIN.

        Specified by:
        relate in interface Shape
      • relateContainsShortCircuits

        protected boolean relateContainsShortCircuits()
        Called by relate() to determine whether to return early if it finds CONTAINS, instead of checking the remaining shapes. It will do so without calling this method if the "other" shape is a Point. If a remaining shape finds INTERSECTS, then INTERSECTS will be returned. The only problem with this returning true is that if some of the shapes overlap, it's possible that the result of relate() could be dependent on the order of the shapes, which could be unexpected / wrong depending on the application. The default implementation returns true because it probably doesn't matter. If it does, a subclass could add a boolean flag that this method could return. That flag could be initialized to true only if the shapes are mutually disjoint.
        See Also:
        .
      • computeMutualDisjoint

        protected static boolean computeMutualDisjoint​(List<? extends Shape> shapes)
        Computes whether the shapes are mutually disjoint. This is a utility method offered for use by a subclass implementing relateContainsShortCircuits(). Beware: this is an O(N^2) algorithm.. Consequently, consider safely assuming non-disjoint if shapes.size() > 10 or something. And if all shapes are a Point then the result of this method doesn't ultimately matter.
      • getArea

        public double getArea​(SpatialContext ctx)
        Description copied from interface: Shape
        Calculates the area of the shape, in square-degrees. If ctx is null then simple Euclidean calculations will be used. This figure can be an estimate.
        Specified by:
        getArea in interface Shape
      • getContext

        public SpatialContext getContext()
        Description copied from interface: Shape
        Get the SpatialContext that created the Shape
        Specified by:
        getContext in interface Shape