Package org.apache.sis.geometry

## Class AbstractEnvelope

- Object
- - FormattableObject
  - - AbstractEnvelope

- All Implemented Interfaces:
    `Emptiable`, `Envelope`
  Direct Known Subclasses:
    `GeneralEnvelope`, `ImmutableEnvelope`

      public abstract class AbstractEnvelope
      extends FormattableObject
      implements Envelope, Emptiable

  Default implementations of most `Envelope` methods, leaving the data storage to subclasses. This base class does not hold any state and does not implement the `Serializable` or `Cloneable` interfaces. The internal representation, and the choice to be cloneable or serializable, is left to subclasses.

  Implementers needs to define at least the following methods:

  - `Envelope​.getDimension()`
  - `Envelope​.getCoordinateReferenceSystem()`
  - `getLower(int)`
  - `getUpper(int)`

  All other methods, including `toString()`, `equals(Object)` and `hashCode()`, are implemented on top of the above four methods.

  Spanning the anti-meridian of a Geographic CRS
  The Web Coverage Service (WCS) specification authorizes (with special treatment) cases where upper < lower at least in the longitude case. They are envelopes crossing the anti-meridian, like the red box below (the green box is the usual case). The default implementation of methods listed in the right column can handle such cases.
  Supported methods:
  - `getMinimum(int)`
  - `getMaximum(int)`
  - `getMedian(int)`
  - `getSpan(int)`
  - `toSimpleEnvelopes()`
  - `contains(DirectPosition)`
  - `contains(Envelope)`
  - `intersects(Envelope)`
  Choosing the range of longitude values
  Geographic CRS typically have longitude values in the [-180 … +180]° range, but the [0 … 360]° range is also occasionally used. Users of this class need to ensure that this envelope CRS is associated to axes having the desired minimum and maximum value.
  Note on positive and negative zeros
  The IEEE 754 standard defines two different values for positive zero and negative zero. When used with SIS envelopes and keeping in mind the above discussion, those zeros have different meanings:
  - The [-0…0]° range is an empty envelope.
  - The [0…-0]° range makes a full turn around the globe, like the [-180…180]° range except that the former range spans across the anti-meridian.
  Since:
    0.3

  Defined in the `sis-referencing` module

- - ### Constructor Summary

    Constructors
    Modifier | Constructor | Description
    --- | --- | ---
    `protected` | `AbstractEnvelope()` | Constructs an envelope.

  - ### Method Summary

    All Methods Static Methods Instance Methods Abstract Methods Concrete Methods
    Modifier and Type | Method | Description
    --- | --- | ---
    `static AbstractEnvelope` | `castOrCopy​(Envelope envelope)` | Returns the given envelope as an `AbstractEnvelope` instance.
    `boolean` | `contains​(DirectPosition position)` | Tests if a specified coordinate is inside the boundary of this envelope.
    `boolean` | `contains​(Envelope envelope)` | Returns `true` if this envelope completely encloses the specified envelope.
    `boolean` | `contains​(Envelope envelope, boolean edgesInclusive)` | Returns `true` if this envelope completely encloses the specified envelope.
    `boolean` | `equals​(Object object)` | Returns `true` if the specified object is an envelope of the same class with equals coordinates and CRS.
    `boolean` | `equals​(Envelope other, double eps, boolean epsIsRelative)` | Compares to the specified envelope for equality up to the specified tolerance value.
    `protected String` | `formatTo​(Formatter formatter)` | Formats this envelope as a "`BOX`" element.
    `abstract double` | `getLower​(int dimension)` | Returns the limit in the direction of decreasing coordinate values in the specified dimension.
    `DirectPosition` | `getLowerCorner()` | A coordinate position consisting of all the lower coordinate values.
    `double` | `getMaximum​(int dimension)` | Returns the maximal coordinate value for the specified dimension.
    `DirectPosition` | `getMedian()` | A coordinate position consisting of all the median coordinate values.
    `double` | `getMedian​(int dimension)` | Returns the median coordinate along the specified dimension.
    `double` | `getMinimum​(int dimension)` | Returns the minimal coordinate value for the specified dimension.
    `double` | `getSpan​(int dimension)` | Returns the envelope span (typically width or height) along the specified dimension.
    `double` | `getSpan​(int dimension, Unit<?> unit)` | Returns the envelope span along the specified dimension, in terms of the given units.
    `abstract double` | `getUpper​(int dimension)` | Returns the limit in the direction of increasing coordinate values in the specified dimension.
    `DirectPosition` | `getUpperCorner()` | A coordinate position consisting of all the upper coordinate values.
    `int` | `hashCode()` | Returns a hash value for this envelope.
    `boolean` | `intersects​(Envelope envelope)` | Returns `true` if this envelope intersects the specified envelope.
    `boolean` | `intersects​(Envelope envelope, boolean touch)` | Returns `true` if this envelope intersects or (optionally) touches the specified envelope.
    `boolean` | `isAllNaN()` | Returns `false` if at least one coordinate value is not NaN.
    `boolean` | `isEmpty()` | Determines whether or not this envelope is empty.
    `Envelope[]` | `toSimpleEnvelopes()` | Returns this envelope as an array of simple (without wraparound) envelopes.
    `String` | `toString()` | Formats this envelope as a "`BOX`" element.

    - ### Methods inherited from class FormattableObject

      `print, toString, toWKT`

    - ### Methods inherited from class Object

      `clone, finalize, getClass, notify, notifyAll, wait, wait, wait`

    - ### Methods inherited from interface Envelope

      `getCoordinateReferenceSystem, getDimension`

- - ### Constructor Detail

    - #### AbstractEnvelope

          protected AbstractEnvelope()

      Constructs an envelope.

  - ### Method Detail

    - #### castOrCopy

          public static AbstractEnvelope castOrCopy​(Envelope envelope)

      Returns the given envelope as an `AbstractEnvelope` instance. If the given envelope is already an instance of `AbstractEnvelope`, then it is returned unchanged. Otherwise the coordinate values and the CRS of the given envelope are copied in a new envelope.
      Parameters:
        `envelope` - the envelope to cast, or `null`.
      Returns:
        the values of the given envelope as an `AbstractEnvelope` instance.
      See Also:
        `GeneralEnvelope​.castOrCopy(Envelope)`, `ImmutableEnvelope​.castOrCopy(Envelope)`

    - #### getLowerCorner

          public DirectPosition getLowerCorner()

      A coordinate position consisting of all the lower coordinate values. The default implementation returns a view over the `getLower(int)` method, so changes in this envelope will be immediately reflected in the returned direct position. If the particular case of the `GeneralEnvelope` subclass, the returned position supports also write operations, so changes in the position are reflected back in the envelope.
      Note: The Web Coverage Service (WCS) 1.1 specification uses an extended interpretation of the bounding box definition. In a WCS 1.1 data structure, the lower corner defines the edges region in the directions of decreasing coordinate values in the envelope CRS. This is usually the algebraic minimum coordinates, but not always. For example, an envelope crossing the anti-meridian could have a lower corner longitude greater than the upper corner longitude. Such extended interpretation applies mostly to axes having `WRAPAROUND` range meaning.
      Specified by:
        `getLowerCorner` in interface `Envelope`
      Returns:
        a view over the lower corner, typically (but not necessarily) containing minimal coordinate values.

    - #### getUpperCorner

          public DirectPosition getUpperCorner()

      A coordinate position consisting of all the upper coordinate values. The default implementation returns a view over the `getUpper(int)` method, so changes in this envelope will be immediately reflected in the returned direct position. If the particular case of the `GeneralEnvelope` subclass, the returned position supports also write operations, so changes in the position are reflected back in the envelope.
      Note: The Web Coverage Service (WCS) 1.1 specification uses an extended interpretation of the bounding box definition. In a WCS 1.1 data structure, the upper corner defines the edges region in the directions of increasing coordinate values in the envelope CRS. This is usually the algebraic maximum coordinates, but not always. For example, an envelope crossing the anti-meridian could have an upper corner longitude less than the lower corner longitude. Such extended interpretation applies mostly to axes having `WRAPAROUND` range meaning.
      Specified by:
        `getUpperCorner` in interface `Envelope`
      Returns:
        a view over the upper corner, typically (but not necessarily) containing maximal coordinate values.

    - #### getMedian

          public DirectPosition getMedian()

      A coordinate position consisting of all the median coordinate values. The default implementation returns a view over the `getMedian(int)` method, so changes in this envelope will be immediately reflected in the returned direct position.
      Returns:
        the median coordinates.

    - #### getLower

          public abstract double getLower​(int dimension)
                                   throws IndexOutOfBoundsException

      Returns the limit in the direction of decreasing coordinate values in the specified dimension. This is usually the algebraic minimum, except if this envelope spans the anti-meridian.
      Parameters:
        `dimension` - the dimension for which to obtain the coordinate value.
      Returns:
        the starting coordinate value at the given dimension.
      Throws:
        `IndexOutOfBoundsException` - if the given index is negative or is equals or greater than the envelope dimension.

    - #### getUpper

          public abstract double getUpper​(int dimension)
                                   throws IndexOutOfBoundsException

      Returns the limit in the direction of increasing coordinate values in the specified dimension. This is usually the algebraic maximum, except if this envelope spans the anti-meridian.
      Parameters:
        `dimension` - the dimension for which to obtain the coordinate value.
      Returns:
        the starting coordinate value at the given dimension.
      Throws:
        `IndexOutOfBoundsException` - if the given index is negative or is equals or greater than the envelope dimension.

    - #### getMinimum

          public double getMinimum​(int dimension)
                            throws IndexOutOfBoundsException

      Returns the minimal coordinate value for the specified dimension. In the typical case of non-empty envelopes not spanning the anti-meridian, this method returns the `getLower(int)` value verbatim. In the case of envelope spanning the anti-meridian, this method returns the axis minimum value. If the range in the given dimension is invalid, then this method returns `NaN`.
      Specified by:
        `getMinimum` in interface `Envelope`
      Parameters:
        `dimension` - the dimension for which to obtain the coordinate value.
      Returns:
        the minimal coordinate value at the given dimension.
      Throws:
        `IndexOutOfBoundsException` - if the given index is negative or is equals or greater than the envelope dimension.

    - #### getMaximum

          public double getMaximum​(int dimension)
                            throws IndexOutOfBoundsException

      Returns the maximal coordinate value for the specified dimension. In the typical case of non-empty envelopes not spanning the anti-meridian, this method returns the `getUpper(int)` value verbatim. In the case of envelope spanning the anti-meridian, this method returns the axis maximum value. If the range in the given dimension is invalid, then this method returns `NaN`.
      Specified by:
        `getMaximum` in interface `Envelope`
      Parameters:
        `dimension` - the dimension for which to obtain the coordinate value.
      Returns:
        the maximal coordinate value at the given dimension.
      Throws:
        `IndexOutOfBoundsException` - if the given index is negative or is equals or greater than the envelope dimension.

    - #### getMedian

          public double getMedian​(int dimension)
                           throws IndexOutOfBoundsException

      Returns the median coordinate along the specified dimension. In most cases, the result is equals (minus rounding error) to:

      >     median = (getUpper(dimension) + getLower(dimension)) / 2;

      Spanning the anti-meridian of a Geographic CRS
      If upper < lower and the range meaning for the requested dimension is wraparound, then the median calculated above is actually in the middle of the space outside the envelope. In such cases, this method shifts the median value by half of the periodicity (180° in the longitude case) in order to switch from outer space to inner space. If the axis range meaning is not `WRAPAROUND`, then this method returns `NaN`.
      Specified by:
        `getMedian` in interface `Envelope`
      Parameters:
        `dimension` - the dimension for which to obtain the coordinate value.
      Returns:
        the median coordinate at the given dimension, or `Double​.NaN`.
      Throws:
        `IndexOutOfBoundsException` - if the given index is negative or is equals or greater than the envelope dimension.

    - #### getSpan

          public double getSpan​(int dimension)

      Returns the envelope span (typically width or height) along the specified dimension. In most cases, the result is equals (minus rounding error) to:

      >     span = getUpper(dimension) - getLower(dimension);

      Spanning the anti-meridian of a Geographic CRS
      If upper < lower and the range meaning for the requested dimension is wraparound, then the span calculated above is negative. In such cases, this method adds the periodicity (typically 360° of longitude) to the span. If the result is a positive number, it is returned. Otherwise this method returns `NaN`.
      Specified by:
        `getSpan` in interface `Envelope`
      Parameters:
        `dimension` - the dimension for which to obtain the span.
      Returns:
        the span (typically width or height) at the given dimension, or `Double​.NaN`.
      Throws:
        `IndexOutOfBoundsException` - if the given index is negative or is equals or greater than the envelope dimension.

    - #### getSpan

          public double getSpan​(int dimension,
                                Unit<?> unit)
                         throws IndexOutOfBoundsException,
                                IncommensurableException

      Returns the envelope span along the specified dimension, in terms of the given units. The default implementation invokes `getSpan(int)` and converts the result.
      Parameters:
        `dimension` - the dimension to query.
        `unit` - the unit for the return value.
      Returns:
        the span in terms of the given unit.
      Throws:
        `IndexOutOfBoundsException` - if the given index is out of bounds.
        `IncommensurableException` - if the length can't be converted to the specified units.

    - #### toSimpleEnvelopes

          public Envelope[] toSimpleEnvelopes()

      Returns this envelope as an array of simple (without wraparound) envelopes. The length of the returned array depends on the number of dimensions where a wraparound range is found. Typically, wraparound occurs only in the range of longitude values, when the range crosses the anti-meridian (a.k.a. date line). However this implementation will take in account any axis having wraparound range meaning.

      Special cases:

      - If this envelope is empty, then this method returns an empty array.
      - If this envelope does not have any wraparound behavior, then this method returns `this` in an array of length 1. This envelope is not cloned.
      - If this envelope crosses the anti-meridian (a.k.a. date line) then this method represents this envelope as two separated simple envelopes.
      - While uncommon, the envelope could theoretically crosses the limit of other axis having wraparound range meaning. If wraparound occur along n axes, then this method represents this envelope as 2ⁿ separated simple envelopes.
      Returns:
        a representation of this envelope as an array of non-empty envelope.
      Since:
        0.4
      See Also:
        `Envelope2D​.toRectangles()`, `GeneralEnvelope​.simplify()`

    - #### isEmpty

          public boolean isEmpty()

      Determines whether or not this envelope is empty. An envelope is empty if it has zero dimension, or if the span of at least one axis is negative, 0 or `NaN`.
      Note: Strictly speaking, there is an ambiguity if a span is `NaN` or if the envelope contains both 0 and infinite spans (since 0⋅∞ = `NaN`). In such cases, this method arbitrarily ignores the infinite values and returns `true`.
      If `isEmpty()` returns `false`, then `isAllNaN()` is guaranteed to also return `false`. However the converse is not always true.
      Specified by:
        `isEmpty` in interface `Emptiable`
      Returns:
        `true` if this envelope is empty.
      See Also:
        `DefaultGeographicBoundingBox​.isEmpty()`, `RectangularShape​.isEmpty()`

    - #### isAllNaN

          public boolean isAllNaN()

      Returns `false` if at least one coordinate value is not NaN. This `isAllNaN()` check is different than the `isEmpty()` check since it returns `false` for a partially initialized envelope, while `isEmpty()` returns `false` only after all dimensions have been initialized. More specifically, the following rules apply:
      - If `isAllNaN() == true`, then `isEmpty() == true`
      - If `isEmpty() == false`, then `isAllNaN() == false`
      - The converse of the above-cited rules are not always true.
      Note that an all-NaN envelope can still have a non-null coordinate reference system.
      Returns:
        `true` if this envelope has NaN values.
      See Also:
        `GeneralEnvelope​.setToNaN()`, `DefaultGeographicBoundingBox​.isEmpty()`

    - #### contains

          public boolean contains​(DirectPosition position)
                           throws MismatchedDimensionException

      Tests if a specified coordinate is inside the boundary of this envelope. Both lower and upper values of this envelope are considered inclusive. If it least one coordinate value in the given point is `NaN`, then this method returns `false`.
      Pre-conditions
      This method assumes that the specified point uses the same CRS than this envelope. For performance reasons, it will no be verified unless Java assertions are enabled.
      Spanning the anti-meridian of a Geographic CRS
      For any dimension, if upper < lower then this method uses an algorithm which is the opposite of the usual one: rather than testing if the given point is inside the envelope interior, this method tests if the given point is outside the envelope exterior.
      Parameters:
        `position` - the point to text.
      Returns:
        `true` if the specified coordinate is inside the boundary of this envelope; `false` otherwise.
      Throws:
        `MismatchedDimensionException` - if the specified point does not have the expected number of dimensions.
        `AssertionError` - if assertions are enabled and the envelopes have mismatched CRS.

    - #### contains

          public boolean contains​(Envelope envelope)
                           throws MismatchedDimensionException

      Returns `true` if this envelope completely encloses the specified envelope. The default implementation delegates to:

      >     contains(envelope, true)

      Pre-conditions
      This method assumes that the specified envelope uses the same CRS than this envelope. For performance reasons, it will no be verified unless Java assertions are enabled.
      Spanning the anti-meridian of a Geographic CRS
      For every cases illustrated below, the yellow box is considered completely enclosed in the blue envelope:

      Parameters:
        `envelope` - the envelope to test for inclusion.
      Returns:
        `true` if this envelope completely encloses the specified one.
      Throws:
        `MismatchedDimensionException` - if the specified envelope doesn't have the expected dimension.
        `AssertionError` - if assertions are enabled and the envelopes have mismatched CRS.
      Since:
        0.4
      See Also:
        `intersects(Envelope)`, `equals(Envelope, double, boolean)`

    - #### contains

          public boolean contains​(Envelope envelope,
                                  boolean edgesInclusive)
                           throws MismatchedDimensionException

      Returns `true` if this envelope completely encloses the specified envelope. If one or more edges from the specified envelope coincide with an edge from this envelope, then this method returns `true` only if `edgesInclusive` is `true`.

      This method is subject to the same pre-conditions than `contains(Envelope)`, and handles envelopes spanning the anti-meridian in the same way.

      Parameters:
        `envelope` - the envelope to test for inclusion.
        `edgesInclusive` - `true` if this envelope edges are inclusive.
      Returns:
        `true` if this envelope completely encloses the specified one.
      Throws:
        `MismatchedDimensionException` - if the specified envelope doesn't have the expected dimension.
        `AssertionError` - if assertions are enabled and the envelopes have mismatched CRS.
      See Also:
        `intersects(Envelope, boolean)`

    - #### intersects

          public boolean intersects​(Envelope envelope)
                             throws MismatchedDimensionException

      Returns `true` if this envelope intersects the specified envelope. This method returns `true` if two envelope interiors have at least one point in common (in other words, their intersection is non-empty). The default implementation delegates to:

      >     intersects(envelope, false)

      Pre-conditions
      This method assumes that the specified envelope uses the same CRS than this envelope. For performance reasons, it will no be verified unless Java assertions are enabled.
      Spanning the anti-meridian of a Geographic CRS
      This method can handle envelopes spanning the anti-meridian.
      Parameters:
        `envelope` - the envelope to test for intersection.
      Returns:
        `true` if this envelope intersects the specified one.
      Throws:
        `MismatchedDimensionException` - if the specified envelope doesn't have the expected dimension.
        `AssertionError` - if assertions are enabled and the envelopes have mismatched CRS.
      Since:
        0.4
      See Also:
        `contains(Envelope, boolean)`, `equals(Envelope, double, boolean)`

    - #### intersects

          public boolean intersects​(Envelope envelope,
                                    boolean touch)
                             throws MismatchedDimensionException

      Returns `true` if this envelope intersects or (optionally) touches the specified envelope. The `touch` argument controls the value to return if only the envelope boundaries (not the interiors) have a point in common:
      - If `false`, this method returns `true` if the intersection between the two envelopes is non-empty (i.e. the envelope interiors have points in common). This is the usual definition of `intersects` operation.
      - If `true`, this method returns `true` if the two envelopes intersect each other or touch each other.
      This method is subject to the same pre-conditions than `intersects(Envelope)`, and handles envelopes spanning the anti-meridian in the same way.
      Parameters:
        `envelope` - the envelope to test for intersection.
        `touch` - the value to return if the two envelopes touch each other.
      Returns:
        `true` if this envelope intersects the specified envelope, or `touch` if this envelope touches the specified envelope, or `false` otherwise.
      Throws:
        `MismatchedDimensionException` - if the specified envelope does not have the expected dimension.
        `AssertionError` - if assertions are enabled and the envelopes have mismatched CRS.
      See Also:
        `contains(Envelope, boolean)`, `equals(Envelope, double, boolean)`

    - #### equals

          public boolean equals​(Envelope other,
                                double eps,
                                boolean epsIsRelative)

      Compares to the specified envelope for equality up to the specified tolerance value. The tolerance value `eps` can be either relative to the envelope span along each dimension or can be an absolute value (as for example some ground resolution of a grid coverage).
      - If `epsIsRelative` is set to `true`, the actual tolerance value for a given dimension i is `eps` × `span` where `span` is the maximum of this envelope span and the specified envelope span along dimension i.
      - If `epsIsRelative` is set to `false`, the actual tolerance value for a given dimension i is `eps`.
      Note: Relative tolerance values (as opposed to absolute tolerance values) help to workaround the fact that tolerance value are CRS dependent. For example the tolerance value need to be smaller for geographic CRS than for UTM projections, because the former typically has a [-180…180]° range while the later can have a range of thousands of meters.
      Coordinate Reference System
      To be considered equal, the two envelopes must have the same dimension and their CRS must be equals, ignoring metadata. If at least one envelope has a null CRS, then the CRS are ignored and the coordinate values are compared as if the CRS were equal.
      Parameters:
        `other` - the envelope to compare with.
        `eps` - the tolerance value to use for numerical comparisons.
        `epsIsRelative` - `true` if the tolerance value should be relative to axis length, or `false` if it is an absolute value.
      Returns:
        `true` if the given object is equal to this envelope up to the given tolerance value.
      See Also:
        `contains(Envelope)`, `intersects(Envelope)`

    - #### equals

          public boolean equals​(Object object)

      Returns `true` if the specified object is an envelope of the same class with equals coordinates and CRS.
      Implementation note: This implementation requires that the provided `object` argument is of the same class than this envelope. We do not relax this rule since not every implementations in the SIS code base follow the same contract.
      Overrides:
        `equals` in class `Object`
      Parameters:
        `object` - the object to compare with this envelope.
      Returns:
        `true` if the given object is equal to this envelope.

    - #### hashCode

          public int hashCode()

      Returns a hash value for this envelope.
      Overrides:
        `hashCode` in class `Object`

    - #### toString

          public String toString()

      Formats this envelope as a "`BOX`" element. The output is of the form "`BOX` n `D(`lower corner`,`upper corner`)`" where n is the number of dimensions. The number of dimension is written only if different than 2.
      Example:
      - `BOX(-90 -180, 90 180)`
      - `BOX3D(-90 -180 0, 90 180 1)`
      Note: The `BOX` element is not part of the standard Well Known Text (WKT) format. However it is understood by many software libraries, for example GDAL and PostGIS.
      This method formats the numbers as with `Double​.toString(double)` (i.e. without fixed number of fraction digits). The string returned by this method can be parsed by the `GeneralEnvelope` constructor.
      Overrides:
        `toString` in class `FormattableObject`
      Returns:
        this envelope as a `BOX` or `BOX3D` (most typical dimensions) element.

    - #### formatTo

          protected String formatTo​(Formatter formatter)

      Formats this envelope as a "`BOX`" element. The output is of the form "`BOX` n `D[`lower corner`,`upper corner`]`" where n is the number of dimensions. The number of dimension is written only if different than 2.
      Note: The `BOX` element is not part of the standard Well Known Text (WKT) format. However it is understood by many software libraries, for example GDAL and PostGIS.
      If the coordinate reference system is geodetic or projected, then coordinate values are formatted with a precision equivalent to one centimetre on Earth (the actual number of fraction digits is adjusted for the axis unit of measurement and the planet size if different than Earth).
      Specified by:
        `formatTo` in class `FormattableObject`
      Parameters:
        `formatter` - the formatter where to format the inner content of this envelope.
      Returns:
        the pseudo-WKT keyword, which is `"Box"` for this element.
      Since:
        1.0
      See Also:
        `FormattableObject​.toWKT()`, `FormattableObject​.toString()`