# Class CRS

Object
CRS

public final class CRS extends Object
Static methods working on Coordinate Reference System (CRS) objects. The methods defined in this class can be grouped in three categories:

- Factory methods, the most notable one being `forCode(String)`.
- Methods providing information, like `isHorizontalCRS(CoordinateReferenceSystem)`.
- Finding coordinate operations between a source and a target CRS.

## Usage example

The most frequently used methods in this class are `forCode(…)`, `fromWKT(…)` and `findOperation(…)`. An usage example is like below (see the Apache SIS™ Coordinate Reference System (CRS) codes page for the complete list of EPSG codes):

    CoordinateReferenceSystem source = CRS.forCode("EPSG:4326");                   // WGS 84
    CoordinateReferenceSystem target = CRS.forCode("EPSG:3395");                   // WGS 84 / World Mercator
    CoordinateOperation operation = CRS.findOperation(source, target, null);
    if (CRS.getLinearAccuracy(operation) > 100) {
        // If the accuracy is coarser than 100 metres (or any other threshold at application choice)
        // maybe the operation is not suitable. Decide here what to do (throw an exception, etc).
    }
    MathTransform mt = operation.getMathTransform();
    DirectPosition position = new DirectPosition2D(20, 30);            // 20°N 30°E   (watch out axis order!)
    position = mt.transform(position, position);
    System.out.println(position);

## Note on kinds of CRS

The `getSingleComponents(CoordinateReferenceSystem)` method decomposes an arbitrary CRS into a flat list of single components. In such flat list, vertical and temporal components can easily be identified by `instanceof` checks. But identifying the horizontal component is not as easy. The list below suggests ways to classify the components:

- `if (crs instanceof TemporalCRS)` determines if the CRS is for the temporal component.
- `if (crs instanceof VerticalCRS)` determines if the CRS is for the vertical component.
- `if (CRS.isHorizontalCRS(crs))` determines if the CRS is for the horizontal component.

Since:
  0.3

- ## Nested Class Summary

  Nested Classes
  Modifier and Type
  Class
  Description
  `static enum`
  `CRS​.SeparationMode`
  Action to take when a CRS cannot be separated in components at the requested dimensions.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static CoordinateReferenceSystem`
  `compound(CoordinateReferenceSystem... components)`
  Creates a compound coordinate reference system from an ordered list of CRS components.
  `static boolean`
  `equivalent(CoordinateReferenceSystem object1, CoordinateReferenceSystem object2)`
  Returns whether the given Coordinate Reference Systems can be considered as equivalent.
  `static CoordinateOperation`
  `findOperation(DefaultCoordinateMetadata source, DefaultCoordinateMetadata target, CoordinateOperationContext context)`
  Finds a mathematical operation that transforms coordinates between the given CRSs and epochs.
  `static CoordinateOperation`
  `findOperation(DefaultCoordinateMetadata source, DefaultCoordinateMetadata target, GeographicBoundingBox areaOfInterest)`
  Deprecated, for removal: This API element is subject to removal in a future version.
  Replaced by `findOperation(DefaultCoordinateMetadata, DefaultCoordinateMetadata, CoordinateOperationContext)`.
  `static CoordinateOperation`
  `findOperation(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, GeographicBoundingBox areaOfInterest)`
  Finds a mathematical operation that transform coordinates from the given source to the given target CRS.
  `static List<CoordinateOperation>`
  `findOperations(DefaultCoordinateMetadata source, DefaultCoordinateMetadata target, CoordinateOperationContext context)`
  Finds mathematical operations that transforms coordinates between the given CRSs and epochs.
  `static List<CoordinateOperation>`
  `findOperations(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, GeographicBoundingBox areaOfInterest)`
  Finds mathematical operations that transform coordinates from the given source to the given target CRS in a given area of interest.
  `static CoordinateReferenceSystem`
  `forCode(String code)`
  Returns the Coordinate Reference System for the given authority code.
  `static CoordinateReferenceSystem`
  `fromAuthority(CoordinateReferenceSystem crs, CRSAuthorityFactory factory, Filter warningFilter)`
  Replaces the given coordinate reference system by an authoritative description, if one can be found.
  `static CoordinateReferenceSystem`
  `fromWKT(String wkt)`
  Creates a Coordinate Reference System object from a Well Known Text (WKT).
  `static CoordinateReferenceSystem`
  `fromXML(String xml)`
  Creates a coordinate reference system object from a XML string.
  `static CRSAuthorityFactory`
  `getAuthorityFactory(String authority)`
  Returns the system-wide authority factory used by `forCode(String)` and other SIS methods.
  `static CoordinateReferenceSystem`
  `getComponentAt(CoordinateReferenceSystem crs, int lower, int upper)`
  Returns the coordinate reference system in the given range of dimension indices.
  `static int`
  `getDimensionOrZero(CoordinateReferenceSystem crs)`
  Returns the number of dimensions of the given CRS, or 0 if `null`.
  `static Envelope`
  `getDomainOfValidity(CoordinateReferenceSystem crs)`
  Returns the domain of validity of the specified coordinate reference system, or `null` if unknown.
  `static Optional<Temporal>`
  `getFrameReferenceEpoch(CoordinateReferenceSystem crs)`
  Returns the epoch to which the coordinates of stations defining the dynamic CRS are referenced.
  `static Optional<GeodeticDatum>`
  `getGeodeticReferenceFrame(CoordinateReferenceSystem crs)`
  Returns the geodetic reference frame used by the given coordinate reference system.
  `static GeographicBoundingBox`
  `getGeographicBoundingBox(CoordinateReferenceSystem crs)`
  Returns the valid geographic area for the given coordinate reference system, or `null` if unknown.
  `static GeographicBoundingBox`
  `getGeographicBoundingBox(CoordinateOperation operation)`
  Returns the valid geographic area for the given coordinate operation, or `null` if unknown.
  `static double`
  `getGreenwichLongitude(GeodeticCRS crs)`
  Returns the Greenwich longitude of the prime meridian of the given CRS in degrees.
  `static SingleCRS`
  `getHorizontalComponent(CoordinateReferenceSystem crs)`
  Returns the first horizontal coordinate reference system found in the given CRS, or `null` if there is none.
  `static double`
  `getLinearAccuracy(CoordinateOperation operation)`
  Returns a positional accuracy estimation in metres for the given operation, or `NaN` if unknown.
  `static List<SingleCRS>`
  `getSingleComponents(CoordinateReferenceSystem crs)`
  Returns the ordered list of single coordinate reference systems for the specified CRS.
  `static TemporalCRS`
  `getTemporalComponent(CoordinateReferenceSystem crs)`
  Returns the first temporal coordinate reference system found in the given CRS, or `null` if there is none.
  `static VerticalCRS`
  `getVerticalComponent(CoordinateReferenceSystem crs, boolean allowCreateEllipsoidal)`
  Returns the first vertical coordinate reference system found in the given CRS, or `null` if there is none.
  `static boolean`
  `hasHorizontalComponent(CoordinateReferenceSystem crs)`
  Returns `true` if the given coordinate reference system has an horizontal component.
  `static boolean`
  `isHorizontalCRS(CoordinateReferenceSystem crs)`
  Returns `true` if the given CRS is horizontal.
  `static BitSet`
  `locateDimensions(CoordinateReferenceSystem crs, SingleCRS... subCRS)`
  Returns a mask of the dimensions where a `subCRS` element is found in the given CRS.
  `static List<CoordinateReferenceSystem>`
  `selectComponents(CoordinateReferenceSystem crs, int... dimensions)`
  Gets or creates CRS components for a subset of the dimensions of the given CRS.
  `static List<CoordinateReferenceSystem>`
  `selectComponents(CoordinateReferenceSystem crs, BitSet mask, CRS​.SeparationMode mode)`
  Gets or creates CRS components for a subset of the dimensions of the given CRS.
  `static CoordinateReferenceSystem`
  `selectDimensions(CoordinateReferenceSystem crs, int... dimensions)`
  Gets or creates a coordinate reference system with a subset of the dimensions of the given CRS.
  `static CoordinateReferenceSystem`
  `selectDimensions(CoordinateReferenceSystem crs, BitSet mask, CRS​.SeparationMode mode)`
  Gets or creates a coordinate reference system with a subset of the dimensions of the given CRS.
  `static CoordinateReferenceSystem`
  `suggestCommonTarget(GeographicBoundingBox regionOfInterest, CoordinateReferenceSystem... sourceCRS)`
  Suggests a coordinate reference system which could be a common target for coordinate operations having the given sources.

  ### Methods inherited from class Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Method Details

  - ### forCode

    public static CoordinateReferenceSystem forCode(String code) throws NoSuchAuthorityCodeException, FactoryException
    Returns the Coordinate Reference System for the given authority code. There is many thousands of reference systems defined by the EPSG authority or by other authorities. Whether those codes are recognized or not depends on whether the EPSG dataset is installed. The following table lists a small subset of codes which are guaranteed to be available on any installation of Apache SIS:

    > Minimal set of supported authority codes
    > Code | Enum | CRS Type | Description
    > --- | --- | --- | ---
    > CRS:27 | `NAD27` | Geographic | Like EPSG:4267 except for (longitude, latitude) axis order
    > CRS:83 | `NAD83` | Geographic | Like EPSG:4269 except for (longitude, latitude) axis order
    > CRS:84 | `WGS84` | Geographic | Like EPSG:4326 except for (longitude, latitude) axis order
    > CRS:88 | `NAVD88` | Vertical | North American Vertical Datum 1988 height
    > EPSG:3395 | `WGS84` | Projected | WGS 84 / World Mercator
    > EPSG:3857 | `WGS84` | Projected | WGS 84 / Pseudo-Mercator
    > EPSG:4230 | `ED50` | Geographic | European Datum 1950
    > EPSG:4258 | `ETRS89` | Geographic | European Terrestrial Reference System 1989
    > EPSG:4267 | `NAD27` | Geographic | North American Datum 1927
    > EPSG:4269 | `NAD83` | Geographic | North American Datum 1983
    > EPSG:4322 | `WGS72` | Geographic | World Geodetic System 1972
    > EPSG:4326 | `WGS84` | Geographic | World Geodetic System 1984
    > EPSG:4936 | `ETRS89` | Geocentric | European Terrestrial Reference System 1989
    > EPSG:4937 | `ETRS89` | Geographic 3D | European Terrestrial Reference System 1989
    > EPSG:4978 | `WGS84` | Geocentric | World Geodetic System 1984
    > EPSG:4979 | `WGS84` | Geographic 3D | World Geodetic System 1984
    > EPSG:4984 | `WGS72` | Geocentric | World Geodetic System 1972
    > EPSG:4985 | `WGS72` | Geographic 3D | World Geodetic System 1972
    > EPSG:5041 | `WGS84` | Projected | WGS 84 / UPS North (E,N)
    > EPSG:5042 | `WGS84` | Projected | WGS 84 / UPS South (E,N)
    > EPSG:322## | `WGS72` | Projected | WGS 72 / UTM zone ##N
    > EPSG:323## | `WGS72` | Projected | WGS 72 / UTM zone ##S
    > EPSG:326## | `WGS84` | Projected | WGS 84 / UTM zone ##N
    > EPSG:327## | `WGS84` | Projected | WGS 84 / UTM zone ##S
    > EPSG:5714 | `MEAN_SEA_LEVEL` | Vertical | Mean Sea Level height
    > EPSG:5715 | `DEPTH` | Vertical | Mean Sea Level depth
    > OGC:JulianDate | `JULIAN` | Temporal | Julian date (days)
    > OGC:TruncatedJulianDate | `TRUNCATED_JULIAN` | Temporal | Truncated Julian date (days)
    > OGC:UnixTime | `UNIX` | Unix | Unix time (seconds)

    For codes in above table, the EPSG geodetic database is used when available, otherwise Apache SIS fallbacks on definitions from public sources with no EPSG metadata except the identifiers. If the EPSG geodetic dataset has been used, the authority title will be something like EPSG geodetic dataset, otherwise it will be Subset of EPSG.

    #### Extended set of codes

    If this method is invoked during the parsing of a GML document, then the set of known codes temporarily includes the `<gml:identifier>` values of all `CoordinateReferenceSystem` definitions which have been parsed before this method call. Those codes are local to the document being parsed (many documents can be parsed concurrently without conflict), and are discarded after the parsing is completed (e.g., on `XML​.unmarshal(String)` return). This feature allows embedded or linked data to references a CRS definition in the same file or a file included by an `xlink:href` attribute.

    #### URI forms

    This method accepts also the URN and URL syntaxes. For example, the following codes are considered equivalent to `"EPSG:4326"`:
    - `"EPSG::4326"`
    - `"urn:ogc:def:crs:EPSG::4326"`
    - `"http://www​.opengis​.net/def/crs/epsg/0/4326"`
    - `"http://www​.opengis​.net/gml/srs/epsg​.xml#4326"`
    URIs can be combined for creating larger objects. For example, the following URIs combine a two-dimensional WGS84 reference system (EPSG:4326) with a Mean Sea Level height (EPSG:5714). The result is a three-dimensional compound coordinate reference system:
    - `"urn:ogc:def:crs,crs:EPSG::4326,crs:EPSG::5714"`
    - `"http://www​.opengis​.net/def/crs-compound?
      1=http://www​.opengis​.net/def/crs/epsg/0/4326&
      2=http://www​.opengis​.net/def/crs/epsg/0/5714"`

    URNs (but not URLs) can also combine a geodetic reference frame with an ellipsoidal coordinate system for creating a new geographic CRS, or a base geographic CRS with a conversion and a Cartesian coordinate system for creating a new projected coordinate reference system.

    #### Reverse operation

    The `IdentifiedObjects​.lookupURN(IdentifiedObject, Citation)` method can be seen as a converse of this method: from a CRS object, it tries to find a URN that describes it. More codes may also be supported depending on which extension modules are available.
    Parameters:
      `code` - the authority code.
    Returns:
      the Coordinate Reference System for the given authority code.
    Throws:
      `NoSuchAuthorityCodeException` - if there is no known CRS associated to the given code.
      `FactoryException` - if the CRS creation failed for another reason.
    See Also:
      - `getAuthorityFactory(String)`
      - `GeodeticAuthorityFactory`
      - EPSG Geodetic Registry

  - ### fromWKT

    public static CoordinateReferenceSystem fromWKT(String wkt) throws FactoryException
    Creates a Coordinate Reference System object from a Well Known Text (WKT). The default Apache SIS parser understands both version 1 (a.k.a. OGC 01-009) and version 2 (a.k.a. ISO 19162) of the WKT format.

    #### Example

    Below is a slightly simplified WKT 2 string for a Mercator projection. For making this example smaller, some optional `UNIT[…]` and `ORDER[…]` elements have been omitted.

        ProjectedCRS["SIRGAS 2000 / Brazil Mercator",
          BaseGeogCRS["SIRGAS 2000",
            Datum["Sistema de Referencia Geocentrico para las Americas 2000",
              Ellipsoid["GRS 1980", 6378137, 298.257222101]]],
          Conversion["Petrobras Mercator",
            Method["Mercator (variant B)", Id["EPSG",9805]],
            Parameter["Latitude of 1st standard parallel", -2],
            Parameter["Longitude of natural origin", -43],
            Parameter["False easting", 5000000],
            Parameter["False northing", 10000000]],
          CS[cartesian,2],
            Axis["easting (E)", east],
            Axis["northing (N)", north],
            LengthUnit["metre", 1],
          Id["EPSG",5641]]

    #### Logging

    If the parsing produced warnings, they will be reported in a logger named `"org​.apache​.sis​.io​.wkt"`. In particular, this method verifies if the description provided by the WKT matches the description provided by the authority (`"EPSG:5641"` in the above example) and reports discrepancies. Note that this comparison between parsed CRS and authoritative CRS is specific to this convenience method; other APIs documented in see also section do not perform this comparison automatically. Should the WKT description and the authoritative description be in conflict, the WKT description prevails as mandated by ISO 19162 standard (see `fromAuthority(…)` if a different behavior is needed).

    #### Usage and performance considerations

    This convenience method delegates to `GeodeticObjectFactory​.createFromWKT(String)` using a default factory instance. This is okay for occasional use, but has the following limitations:
    - Performance may be sub-optimal in a multi-thread environment.
    - No control on the WKT conventions in use.
    - No control on the handling of warnings.
    Applications which need to parse a large number of WKT strings should consider to use the `WKTFormat` class instead of this method.
    Parameters:
      `wkt` - coordinate system encoded in Well-Known Text format (version 1 or 2).
    Returns:
      the parsed Coordinate Reference System.
    Throws:
      `FactoryException` - if the given WKT cannot be parsed.
    Since:
      0.6
    See Also:
      - `WKTFormat`
      - `GeodeticObjectFactory​.createFromWKT(String)`
      - `Envelopes​.fromWKT(CharSequence)`
      - WKT 2 specification

  - ### fromXML

    public static CoordinateReferenceSystem fromXML(String xml) throws FactoryException
    Creates a coordinate reference system object from a XML string. Note that the given argument is the XML document itself, not a URL to a XML document. For reading XML documents from readers or input streams, see static methods in the `XML` class.

    If the unmarshalling produced warnings, they will be reported in a logger named `"org​.apache​.sis​.xml"`. In particular, this method verifies if the description provided by the XML matches the description provided by the authority code given in `<gml:identifier>` element, and reports discrepancies. Note that this comparison between unmarshalled CRS and authoritative CRS is specific to this convenience method; other APIs documented in see also section do not perform this comparison automatically. Should the XML description and the authoritative description be in conflict, the XML description prevails (see `fromAuthority(…)` if a different behavior is needed).

    Parameters:
      `xml` - coordinate reference system encoded in XML format.
    Returns:
      the unmarshalled Coordinate Reference System.
    Throws:
      `FactoryException` - if the object creation failed.
    Since:
      0.7
    See Also:
      - `GeodeticObjectFactory​.createFromXML(String)`
      - `XML​.unmarshal(String)`

  - ### fromAuthority

    public static CoordinateReferenceSystem fromAuthority(CoordinateReferenceSystem crs, CRSAuthorityFactory factory, Filter warningFilter) throws FactoryException
    Replaces the given coordinate reference system by an authoritative description, if one can be found. This method can be invoked after constructing a CRS in a context where the EPSG (or other authority) code is suspected more reliable than the rest of the description. A common case is a Well Known Text (WKT) string declaring wrong projection method or parameter values for the EPSG code that it pretends to describe. For example:

    > `PROJCS["WGS 84 / Pseudo-Mercator",`
    > `` (…base CRS omitted for brevity…)
    > `PROJECTION["Mercator (variant A)"],` — wrong: shall be "Popular Visualisation Pseudo Mercator"
    > `` (…parameters and axes omitted for brevity…)
    > `AUTHORITY["EPSG", "3857"]]`

    In such cases, Apache SIS behavior in `fromWKT(String)`, `fromXML(String)` and other methods is conform to the WKT 2 specification:

    > Should any attributes or values given in the cited identifier be in conflict with attributes or values given explicitly in the WKT description, the WKT values shall prevail.

    In situations where the opposite behavior is desired (i.e. to make the authority identifier prevails), this method can be invoked. This method performs the following actions:
    - If the given CRS has an identifier and if the authority factory can create a CRS for that identifier, then:
      - If the CRS defined by the authority is equivalent to the given CRS, then this method returns silently the authoritative CRS.
      - Otherwise if the CRS defined by the authority is equal, ignoring axis order and units, to the given CRS, then this method returns a new CRS derived from the authoritative one but with same axes convention than the given CRS. A warning is emitted.
      - Otherwise this method discards the given CRS and returns the authoritative CRS. A warning is emitted with a message indicating where a difference has been found.
    - Otherwise if the given CRS does not have identifier, then this method searches for an equivalent CRS defined by the authority factory. If such CRS is found, then:
      - If the CRS defined by the authority is equivalent to the given CRS, then this method returns silently the authoritative CRS.
      - Otherwise if the CRS defined by the authority is equal, ignoring axis order and units, to the given CRS, then this method returns silently a new CRS derived from the authoritative one but with same axes convention than the given CRS.
    - Otherwise this method silently returns the given CRS as-is.

    #### Avoiding warning redundancies

    The warnings logged by this method are redundant with warnings logged by other methods in this class, in particular `fromWKT(String)` and `fromXML(String)` methods. For avoiding this annoyance, a `null` value for the `warningFilter` argument means to shut off those redundant loggings. A non-null `warningFilter` argument is more useful for CRS parsed by methods outside this class, for example `WKTFormat` or `XML​.unmarshal(String)`.
    Parameters:
      `crs` - the CRS to replace by an authoritative CRS, or `null`.
      `factory` - the factory where to search for authoritative definitions, or `null` for the default.
      `warningFilter` - whether to log warnings, or `null` for the default behavior (which is to filter out the warnings that are redundant with warnings emitted by other methods in this class).
    Returns:
      the suggested CRS to use (may be the `crs` argument itself), or `null` if the given CRS was null.
    Throws:
      `FactoryException` - if an error occurred while querying the authority factory.
    Since:
      1.0

  - ### equivalent

    public static boolean equivalent(CoordinateReferenceSystem object1, CoordinateReferenceSystem object2)
    Returns whether the given Coordinate Reference Systems can be considered as equivalent. Two CRSs are considered equivalent if they may have some differences in metadata or data structure, but replacing one CRS by the other should not change the input and output coordinate values in operations.

    #### Implementation note

    This is a convenience method for the following method call:

        return deepEquals(object1, object2, ComparisonMode.IGNORE_METADATA);

    Parameters:
      `object1` - the first object to compare (may be null).
      `object2` - the second object to compare (may be null).
    Returns:
      `true` if both objects are equivalent.
    Since:
      1.5
    See Also:
      - `ComparisonMode​.COMPATIBILITY`
      - `Utilities​.equalsIgnoreMetadata(Object, Object)`

  - ### suggestCommonTarget

    @OptionalCandidate public static CoordinateReferenceSystem suggestCommonTarget(GeographicBoundingBox regionOfInterest, CoordinateReferenceSystem... sourceCRS)
    Suggests a coordinate reference system which could be a common target for coordinate operations having the given sources. This method compares the domain of validity of all given CRSs. If a CRS has a domain of validity that contains the domain of all other CRS, then that CRS is returned. Otherwise this method verifies if a base CRS (usually a geographic CRS instance) would be suitable. If no suitable CRS is found, then this method returns `null`.

    #### Use case

    Before to test if two arbitrary envelopes intersect each other, they need to be transformed in the same CRS. However if one CRS is a Transverse Mercator projection while the other CRS is a world-wide geographic CRS, then attempts to use the Transverse Mercator projection as the common CRS is likely to fail since the geographic envelope may span an area far outside the projection domain of validity. This `suggestCommonTarget(…)` method can used for choosing a common CRS which is less likely to fail.
    Parameters:
      `regionOfInterest` - the geographic area for which the coordinate operations will be applied, or `null` if unknown. Will be intersected with CRS domains of validity.
      `sourceCRS` - the coordinate reference systems for which a common target CRS is desired. May contain `null` elements, which are ignored.
    Returns:
      a CRS that may be used as a common target for all the given source CRS in the given region of interest, or `null` if this method did not find a common target CRS. The returned CRS may be different than all given CRS.
    Since:
      0.8

  - ### findOperation

    @Deprecated(since="1.6", forRemoval=true) public static CoordinateOperation findOperation(DefaultCoordinateMetadata source, DefaultCoordinateMetadata target, GeographicBoundingBox areaOfInterest) throws FactoryException
    Deprecated, for removal: This API element is subject to removal in a future version.
    Replaced by `findOperation(DefaultCoordinateMetadata, DefaultCoordinateMetadata, CoordinateOperationContext)`. This method will be removed for avoiding ambiguity when the last argument is null.
    Finds a mathematical operation that transforms or converts coordinates between the given CRSs and epochs. This method performs the same work as the variant working on CRS objects, except that the coordinate epochs may be taken in account.
    Parameters:
      `source` - the CRS and epoch of source coordinates.
      `target` - the CRS and epoch of target coordinates.
      `areaOfInterest` - the area of interest, or `null` if none.
    Returns:
      the mathematical operation from `source` to `target`.
    Throws:
      `OperationNotFoundException` - if no operation was found between the given pair of CRSs and epochs.
      `FactoryException` - if the operation cannot be created for another reason.
    Since:
      1.5

  - ### findOperation

    public static CoordinateOperation findOperation(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, GeographicBoundingBox areaOfInterest) throws FactoryException
    Finds a mathematical operation that transform coordinates from the given source to the given target CRS. If an estimation of the geographic area containing the points to transform is known, it can be specified for helping this method to find a better suited operation. If no area of interest is specified, then the current default is the widest domain of validity. A future Apache SIS version may also take the country of current locale in account.

    Note that the area of interest is only one aspect that may affect the coordinate operation. Other aspects are the data epochs (because some coordinate operations take in account the plate tectonics movement) or the desired accuracy. For more control on the coordinate operation to create, see the method below. Alternatively, the area of interest can also be specified as envelopes.

    After the caller received a `CoordinateOperation` instance, the following methods can be invoked for checking if the operation suits the caller's needs:

    - `getGeographicBoundingBox(CoordinateOperation)` for checking if the operation is valid in the caller's area of interest.
    - `getLinearAccuracy(CoordinateOperation)` for checking if the operation has sufficient accuracy for caller's purpose.

    If the source and target CRS are equivalent, then this method returns an operation backed by an identity transform. If there is no known operation between the given pair of CRSs, then this method throws an `OperationNotFoundException`.

    #### Inverse operation

    Note that `CRS​.findOperation(B, A, aoi)` is not necessarily the exact converse of `CRS​.findOperation(A, B, aoi)`. Some deviations may exist, for example because of different paths explored in the geodetic database. For the mathematical inverse of an existing `CoordinateOperation`, using `MathTransform​.inverse()` is preferable.

    #### Advanced usages

    It is not recommended to use the returned coordinate operation for transforming bounding boxes simply by transforming the four corners. Use the envelope transformation methods instead. These methods will take care of line curvature, envelope spanning the anti-meridian (longitude wraparound) and singularity points at the poles.

    Likewise, for finding an operation for transforming pixel coordinates between two rasters, use the grid geometry method instead. That latter method will take care of rasters spanning the anti-meridian, contrarily to the operations returned by this `CRS` class.

    Parameters:
      `sourceCRS` - the CRS of source coordinates.
      `targetCRS` - the CRS of target coordinates.
      `areaOfInterest` - the area of interest, or `null` if none.
    Returns:
      the mathematical operation from `sourceCRS` to `targetCRS`.
    Throws:
      `OperationNotFoundException` - if no operation was found between the given pair of CRSs.
      `FactoryException` - if the operation cannot be created for another reason.
    Since:
      0.7
    See Also:
      - `Envelopes​.findOperation(Envelope, Envelope)`

  - ### findOperation

    public static CoordinateOperation findOperation(DefaultCoordinateMetadata source, DefaultCoordinateMetadata target, CoordinateOperationContext context) throws FactoryException
    Finds a mathematical operation that transforms coordinates between the given CRSs and epochs. If many operations exist between the specified pair of CRSs, an operation is selected using the area of interest (AOI) and desired accuracy specified in the optional `context` argument: the operation having a domain of validity resulting in the widest intersection with the AOI is preferred. If many operations result in the same intersection, then the operation having an accuracy just sufficient for the desired accuracy is preferred.

    After the caller received a `CoordinateOperation` instance, the following methods can be invoked for checking if the operation suits the caller's needs:

    - `getGeographicBoundingBox(CoordinateOperation)` for checking if the operation is valid in the caller's area of interest.
    - `getLinearAccuracy(CoordinateOperation)` for checking if the operation has sufficient accuracy for caller's purpose.

    If the source and target CRS are equivalent, then this method returns an operation backed by an identity transform. If there is no known operation between the given pair of CRSs, then this method throws an `OperationNotFoundException`.

    #### Inverse operation

    Note that `CRS​.findOperation(B, A, context)` is not necessarily the exact converse of `CRS​.findOperation(A, B, context)`. Some deviations may exist, for example because of different paths explored in the geodetic database. For the mathematical inverse of an existing `CoordinateOperation`, using `MathTransform​.inverse()` is preferable.
    Parameters:
      `source` - the CRS and epoch of source coordinates.
      `target` - the CRS and epoch of target coordinates.
      `context` - area of interest, desired accuracy and other options, or `null` if none.
    Returns:
      the mathematical operation from `source` to `target`.
    Throws:
      `OperationNotFoundException` - if no operation was found between the given pair of CRSs and epochs.
      `FactoryException` - if the operation cannot be created for another reason.
    Since:
      1.6
    See Also:
      - `DefaultCoordinateOperationFactory​.createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem, CoordinateOperationContext)`

  - ### findOperations

    public static List<CoordinateOperation> findOperations(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, GeographicBoundingBox areaOfInterest) throws FactoryException
    Finds mathematical operations that transform coordinates from the given source to the given target CRS in a given area of interest. If many operations exist, they are returned in preference order: the operation having the widest intersection between its domain of validity and the given area of interest are returned first.

    This is a convenience method for static CRSs and a context defined only by the area of interest. For an alternative allowing to specify data epochs (for dynamic CRSs) and desired accuracy, see the method below.

    Parameters:
      `sourceCRS` - the CRS of source coordinates.
      `targetCRS` - the CRS of target coordinates.
      `areaOfInterest` - the area of interest, or `null` if none.
    Returns:
      mathematical operations from `sourceCRS` to `targetCRS`.
    Throws:
      `OperationNotFoundException` - if no operation was found between the given pair of CRSs.
      `FactoryException` - if the operation cannot be created for another reason.
    Since:
      1.0

  - ### findOperations

    public static List<CoordinateOperation> findOperations(DefaultCoordinateMetadata source, DefaultCoordinateMetadata target, CoordinateOperationContext context) throws FactoryException
    Finds mathematical operations that transforms coordinates between the given CRSs and epochs. If many operations exist, they are sorted in preference order according criteria specified by `context`: best matches with the area of interest (AOI) are first, then operations matching AOI equally well are sorted by best matches with the desired accuracy.
    Parameters:
      `source` - the CRS and epoch of source coordinates.
      `target` - the CRS and epoch of target coordinates.
      `context` - area of interest, desired accuracy and other options, or `null` if none.
    Returns:
      mathematical operations from `source` to `target` CRS and epoch.
    Throws:
      `OperationNotFoundException` - if no operation was found between the given pair of CRSs.
      `FactoryException` - if the operation cannot be created for another reason.
    Since:
      1.6
    See Also:
      - `DefaultCoordinateOperationFactory​.createOperations(CoordinateReferenceSystem, CoordinateReferenceSystem, CoordinateOperationContext)`

  - ### getLinearAccuracy

    @OptionalCandidate public static double getLinearAccuracy(CoordinateOperation operation)
    Returns a positional accuracy estimation in metres for the given operation, or `NaN` if unknown. This method applies the following heuristics:
    - If the given operation is an instance of `AbstractCoordinateOperation`, then delegate to the operation `getLinearAccuracy()` method.
    - Otherwise if at least one quantitative result is found with a linear unit, then return the largest value converted to metres.
    - Otherwise if the operation is a conversion, then returns 0 since a conversion is by definition accurate up to rounding errors.
    - Otherwise if the operation is a transformation, then the returned value depends on whether the datum shift were applied with the help of Bursa-Wolf parameters of not.
    See `AbstractCoordinateOperation​.getLinearAccuracy()` for more details on the above heuristic rules.
    Parameters:
      `operation` - the coordinate operation for which to get the accuracy estimation, or `null`.
    Returns:
      the accuracy estimation (always in meters), or NaN if unknown.
    Since:
      0.7
    See Also:
      - `findOperation(CoordinateReferenceSystem, CoordinateReferenceSystem, GeographicBoundingBox)`
      - `DatumOrEnsemble​.getAccuracy(IdentifiedObject)`

  - ### getGeographicBoundingBox

    @OptionalCandidate public static GeographicBoundingBox getGeographicBoundingBox(CoordinateOperation operation)
    Returns the valid geographic area for the given coordinate operation, or `null` if unknown. This method explores the domain of validity associated with the given operation. If more than one geographic bounding box is found, then this method computes their union.

    Fallback: if the given operation does not declare explicitly a domain of validity, then this method computes the intersection of the domain of validity declared by source and target CRS. If no CRS declare a domain of validity, then this method returns `null`.

    Parameters:
      `operation` - the coordinate operation for which to get the domain of validity, or `null`.
    Returns:
      the geographic area where the operation is valid, or `null` if unspecified.
    Since:
      0.7
    See Also:
      - `findOperation(CoordinateReferenceSystem, CoordinateReferenceSystem, GeographicBoundingBox)`
      - `Extents​.getGeographicBoundingBox(Extent)`

  - ### getGeographicBoundingBox

    @OptionalCandidate public static GeographicBoundingBox getGeographicBoundingBox(CoordinateReferenceSystem crs)
    Returns the valid geographic area for the given coordinate reference system, or `null` if unknown. This method explores the domain of validity associated with the given CRS. If more than one geographic bounding box is found, then this method computes their union. together.
    Parameters:
      `crs` - the coordinate reference system for which to get the domain of validity, or `null`.
    Returns:
      the geographic area where the coordinate reference system is valid, or `null` if unspecified.
    See Also:
      - `getDomainOfValidity(CoordinateReferenceSystem)`
      - `Extents​.getGeographicBoundingBox(Extent)`

  - ### getDomainOfValidity

    @OptionalCandidate public static Envelope getDomainOfValidity(CoordinateReferenceSystem crs)
    Returns the domain of validity of the specified coordinate reference system, or `null` if unknown. If non-null, then the returned envelope will use the same coordinate reference system than the given CRS argument.
    Parameters:
      `crs` - the coordinate reference system, or `null`.
    Returns:
      the envelope with coordinates in the given CRS, or `null` if none.
    Since:
      0.8
    See Also:
      - `getGeographicBoundingBox(CoordinateReferenceSystem)`

  - ### getFrameReferenceEpoch

    public static Optional<Temporal> getFrameReferenceEpoch(CoordinateReferenceSystem crs)
    Returns the epoch to which the coordinates of stations defining the dynamic CRS are referenced. If the CRS is associated to a dynamic datum, then the epoch of that datum is returned. Otherwise if the CRS is compound, then this method requires that all dynamic components have the same epoch.
    Parameters:
      `crs` - the coordinate reference frame from which to get the epoch, or `null`.
    Returns:
      epoch to which the coordinates of stations defining the dynamic CRS frame are referenced.
    Throws:
      `GeodeticException` - if some CRS components haave different epochs.
    Since:
      1.5

  - ### getGeodeticReferenceFrame

    public static Optional<GeodeticDatum> getGeodeticReferenceFrame(CoordinateReferenceSystem crs)
    Returns the geodetic reference frame used by the given coordinate reference system. If the given CRS is an instance of `GeodeticCRS`, then this method returns the CRS's datum. Otherwise, if the given CRS is an instance of `CompoundCRS`, then this method searches for the first geodetic component. Otherwise, this method returns an empty value.
    Parameters:
      `crs` - the coordinate reference system for which to get the geodetic reference frame, or `null`.
    Returns:
      the geodetic reference frame, or an empty value if none.
    Since:
      1.6
    See Also:
      - `DatumOrEnsemble​.getEllipsoid(CoordinateReferenceSystem)`
      - `DatumOrEnsemble​.getPrimeMeridian(CoordinateReferenceSystem)`
      - `getGreenwichLongitude(GeodeticCRS)`

  - ### getDimensionOrZero

    public static int getDimensionOrZero(CoordinateReferenceSystem crs)
    Returns the number of dimensions of the given CRS, or 0 if `null`. This method also returns 0 if the CRS is associated to a null coordinate system.

    This is convenience method for cases such as CRS separated in optional components. For example, a class may have an optional `VerticalCRS` component allowed to be `null`. When computing the total number of dimensions, it is sometime convenient to handle null components as a component of dimension zero.

    Parameters:
      `crs` - the CRS from which to get the number of dimensions, or `null`.
    Returns:
      the number of dimensions, or 0 if the given CRS or its coordinate system is null.
    Since:
      1.6

  - ### compound

    public static CoordinateReferenceSystem compound(CoordinateReferenceSystem... components) throws FactoryException
    Creates a compound coordinate reference system from an ordered list of CRS components. A CRS is inferred from the given components and the domain of validity is set to the intersection of the domain of validity of all components.

    #### Ellipsoidal height

    If a two-dimensional geographic or projected CRS is followed or preceded by a vertical CRS with ellipsoidal datum type, this method combines them in a single three-dimensional geographic or projected CRS. Note that standalone ellipsoidal heights are not allowed according ISO 19111. But if such situation is nevertheless found, then the action described here fixes the issue. This is the reverse of `getVerticalComponent(crs, true)`.

    #### Components order

    Apache SIS is permissive on the order of components that can be used in a compound CRS. However for better inter-operability, users are encouraged to follow the order mandated by ISO 19162:
    1. A mandatory horizontal CRS (only one of two-dimensional `GeographicCRS` or `ProjectedCRS` or `EngineeringCRS`).
    2. Optionally followed by a `VerticalCRS` or a `ParametricCRS` (but not both).
    3. Optionally followed by a `TemporalCRS`.
    Parameters:
      `components` - the sequence of coordinate reference systems making the compound CRS.
    Returns:
      the compound CRS, or `components[0]` if the given array contains only one component.
    Throws:
      `IllegalArgumentException` - if the given array is empty or if the array contains incompatible components.
      `FactoryException` - if the geodetic factory failed to create the compound CRS.
    Since:
      0.8
    See Also:
      - `DefaultCompoundCRS`
      - `GeodeticObjectFactory​.createCompoundCRS(Map, CoordinateReferenceSystem...)`
      - `Envelopes​.compound(Envelope...)`
      - `MathTransforms​.compound(MathTransform...)`

  - ### locateDimensions

    public static BitSet locateDimensions(CoordinateReferenceSystem crs, SingleCRS... subCRS)
    Returns a mask of the dimensions where a `subCRS` element is found in the given CRS. If the given `crs` is equivalent to an element of the `subCRS` array, then this method returns a `BitSet` in which all bits are set to `true` in the range from 0 to n−1, where n is the number of dimensions of `crs`. Otherwise, if `crs` is an instance of `CompoundCRS`, then the `crs` components are traversed recursively and compared in the same way as described above, except that the range of bits set to `true` does not start at index 0. Instead, the range starts at the index of the first dimension of the matched `crs` component. If no match is found, then the returned `BitSet` is empty.

    #### Example

    The following snippet gets the dimensions of the temporal and vertical components of a CRS:

        CoordinateReferenceSystem crs = ...;
        SingleCRS temporal = CRS.getTemporalComponent(crs);
        SingleCRS vertical = CRS.getVerticalComponent(crs, false);
        BitSet mask = CRS.locateDimensions(crs, vertical, temporal);
        int[] dimensions = mask.stream().toArray();

    Tip 1: if only the index of the first dimension is desired, `mask​.stream()​.toArray()` can be replaced by `mask.nextSetBit(0)`.

    Tip 2: for locating all dimensions except the vertical and temporal ones, use `mask.flip(0, CRS​.getDimensionOrZero(crs))`.

    #### Null values

    This method is null-safe: if `crs` or `subCRS` is `null`, this method returns an empty set. If `subCRS` contains `null` elements, these elements are ignored. The latter makes easy to use directly the return value of methods such as `getTemporalComponent(CoordinateReferenceSystem)`.
    Parameters:
      `crs` - the CRS for which the indexes of some dimensions are wanted.
      `subCRS` - the CRSs to compare with `crs` or `crs` components.
    Returns:
      indexes of the dimensions where a `subCRS` element is found in `crs`.
    Since:
      1.6
    See Also:
      - `selectDimensions(CoordinateReferenceSystem, BitSet, SeparationMode)`

  - ### selectDimensions

    public static CoordinateReferenceSystem selectDimensions(CoordinateReferenceSystem crs, BitSet mask, CRS.SeparationMode mode) throws FactoryException
    Gets or creates a coordinate reference system with a subset of the dimensions of the given CRS. The dimensions to retain are specified by a mask. The bit at index 0 specifies whether to retain dimension 0, the bit at index 1 specifies whether to retain dimension 1, etc. After this method call, the given mask is updated to the dimensions that the `crs` dimensions that were effectively retained. The return value is always a CRS with axes in the same order as the given `crs`.

    #### Ellipsoidal height

    This method can transform a three-dimensional geographic CRS into a two-dimensional geographic CRS, i.e. this method can do the converse of `compound(CoordinateReferenceSystem...)`. This method can also extract the ellipsoidal height from a three-dimensional geographic CRS, but this is generally not recommended because ellipsoidal heights make little sense without the (latitude, longitude) coordinates.

    #### Unseparable CRS

    It is illegal to extract only the latitude or longitude axis from a geodetic CRS. Similar constraints exist also for projected and engineering CRS. If `crs` or a component of `crs` cannot be separated as requested by the `dimensions` mask, then the behavior of this method depends on the `mode` enumeration value:
    - If `CRS​.SeparationMode​.EXACT`, then a `FactoryException` is thrown.
    - If `CRS​.SeparationMode​.OMIT_UNSEPARABLE`, then the result may contain less dimensions than requested.
    - If `CRS​.SeparationMode​.WHOLE_UNSEPARABLE`, then the result may contain more dimensions than requested.
    Parameters:
      `crs` - the CRS to reduce the dimensionality, or `null` if none.
      `mask` - on input, the dimensions to select. On output, the dimensions effectively selected.
      `mode` - action to take if the `crs` cannot be separated in components at the requested dimensions.
    Returns:
      a coordinate reference system for the given dimensions, or `null` if the given `crs` was null.
    Throws:
      `IllegalArgumentException` - if the given `mask` is invalid.
      `FactoryException` - if this method needs to create a new CRS and that operation failed.
    Since:
      1.6
    See Also:
      - `locateDimensions(CoordinateReferenceSystem, SingleCRS...)`
      - `compound(CoordinateReferenceSystem...)`

  - ### selectDimensions

    public static CoordinateReferenceSystem selectDimensions(CoordinateReferenceSystem crs, int... dimensions) throws FactoryException
    Gets or creates a coordinate reference system with a subset of the dimensions of the given CRS. This method can be used for dimensionality reduction, but not for changing axis order. The specified dimensions are used as if they were in strictly increasing order without duplicated values.

    #### Ellipsoidal height

    This method can transform a three-dimensional geographic CRS into a two-dimensional geographic CRS, i.e. this method can do the converse of `compound(CoordinateReferenceSystem...)`. This method can also extract the ellipsoidal height from a three-dimensional geographic CRS, but this is generally not recommended because ellipsoidal heights make little sense without the (latitude, longitude) coordinates.
    Parameters:
      `crs` - the CRS to reduce the dimensionality, or `null` if none.
      `dimensions` - the dimensions to retain. Will be taken in increasing order, ignoring duplicated values.
    Returns:
      a coordinate reference system for the given dimensions, or `null` if the given `crs` was null.
    Throws:
      `IllegalArgumentException` - if the content of the given `dimensions` array is invalid.
      `FactoryException` - if this method needs to create a new CRS and that operation failed.
    Since:
      1.3
    See Also:
      - `getComponentAt(CoordinateReferenceSystem, int, int)`
      - `compound(CoordinateReferenceSystem...)`

  - ### selectComponents

    public static List<CoordinateReferenceSystem> selectComponents(CoordinateReferenceSystem crs, BitSet mask, CRS.SeparationMode mode) throws FactoryException
    Gets or creates CRS components for a subset of the dimensions of the given CRS. This method does the same work as `selectDimensions(crs, mask, mode)`, but without the final step creating a `CompoundCRS` from the selected components.
    Parameters:
      `crs` - the CRS from which to get a subset of the components, or `null` if none.
      `mask` - on input, the dimensions to select. On output, the dimensions effectively selected.
      `mode` - action to take if the `crs` cannot be separated in components at the requested dimensions.
    Returns:
      components in the specified dimensions, or an empty list if the specified `crs` is `null`.
    Throws:
      `IllegalArgumentException` - if the content of the given `dimensions` array is invalid.
      `FactoryException` - if this method needs to create a new CRS and that operation failed.
    Since:
      1.6
    See Also:
      - `selectDimensions(CoordinateReferenceSystem, BitSet, SeparationMode)`

  - ### selectComponents

    public static List<CoordinateReferenceSystem> selectComponents(CoordinateReferenceSystem crs, int... dimensions) throws FactoryException
    Gets or creates CRS components for a subset of the dimensions of the given CRS. This method does the same work as `selectDimensions(crs, dimensions)`, but without the final step creating a `CompoundCRS` from the selected components.
    Parameters:
      `crs` - the CRS from which to get a subset of the components, or `null` if none.
      `dimensions` - the dimensions to retain. Will be taken in increasing order, ignoring duplicated values.
    Returns:
      components in the specified dimensions, or an empty list if the specified `crs` is `null`.
    Throws:
      `IllegalArgumentException` - if the content of the given `dimensions` array is invalid.
      `FactoryException` - if this method needs to create a new CRS and that operation failed.
    Since:
      1.4
    See Also:
      - `selectDimensions(CoordinateReferenceSystem, int...)`

  - ### isHorizontalCRS

    public static boolean isHorizontalCRS(CoordinateReferenceSystem crs)
    Returns `true` if the given CRS is horizontal. The current implementation considers a CRS as horizontal if it is two-dimensional and comply with one of the following conditions:
    - is an instance of `GeographicCRS` (or an equivalent `GeodeticCRS`), or
    - is an instance of `ProjectedCRS`, or
    - is an instance of `EngineeringCRS` (following WKT 2 definition of <horizontal crs>).
    In case of doubt, this method conservatively returns `false`.
    Parameters:
      `crs` - the coordinate reference system, or `null`.
    Returns:
      `true` if the given CRS is non-null and likely horizontal, or `false` otherwise.
    See Also:
      - `getHorizontalComponent(CoordinateReferenceSystem)`
    "TODO:"
      Future SIS implementation may extend the above conditions list. For example, a radar station could use a polar coordinate system in a `DerivedCRS` instance based on a projected CRS. Conversely, a future SIS versions may impose more conditions on `EngineeringCRS`. See SIS-161.

  - ### hasHorizontalComponent

    public static boolean hasHorizontalComponent(CoordinateReferenceSystem crs)
    Returns `true` if the given coordinate reference system has an horizontal component. The horizontal component may be part of a higher dimensional CRS, either in the form of a three-dimensional CRS (with an ellipsoidal height) or a compound CRS.
    Parameters:
      `crs` - the coordinate reference system, or `null`.
    Returns:
      whether the given CRS has an horizontal component.
    Since:
      1.5

  - ### getHorizontalComponent

    @OptionalCandidate public static SingleCRS getHorizontalComponent(CoordinateReferenceSystem crs)
    Returns the first horizontal coordinate reference system found in the given CRS, or `null` if there is none. If the given CRS is already horizontal according `isHorizontalCRS(CoordinateReferenceSystem)`, then this method returns it as-is. Otherwise if the given CRS is compound, then this method searches for the first horizontal component in the list of single components.

    In the special case where a three-dimensional geographic or projected CRS is found, this method will create a two-dimensional geographic or projected CRS without the vertical axis.

    Parameters:
      `crs` - the coordinate reference system, or `null`.
    Returns:
      the first horizontal CRS, or `null` if none.
    See Also:
      - `GeneralEnvelope​.horizontal()`

  - ### getVerticalComponent

    @OptionalCandidate public static VerticalCRS getVerticalComponent(CoordinateReferenceSystem crs, boolean allowCreateEllipsoidal)
    Returns the first vertical coordinate reference system found in the given CRS, or `null` if there is none. If the given CRS is already an instance of `VerticalCRS`, then this method returns it as-is. Otherwise if the given CRS is compound, then this method searches for the first vertical component in the list of single components.

    #### Height in a three-dimensional geographic CRS

    In ISO 19111 model, ellipsoidal heights are indissociable from geographic CRS because such heights without their (latitude, longitude) locations make little sense. Consequently a standard-conformant library should return `null` when asked for the `VerticalCRS` component of a geographic CRS. This is what `getVerticalComponent(…)` does when the `allowCreateEllipsoidal` argument is `false`.

    However, in some exceptional cases, handling ellipsoidal heights like any other kind of heights may simplify the task. For example, when computing difference between heights above the same datum, the impact of ignoring locations may be smaller (but not necessarily canceled). Orphan `VerticalCRS` may also be useful for information purpose like labeling a plot axis. If the caller feels confident that ellipsoidal heights are safe for his task, he can set the `allowCreateEllipsoidal` argument to `true`. In such case, this `getVerticalComponent(…)` method will create a temporary `VerticalCRS` from the first three-dimensional `GeographicCRS` in last resort, only if it cannot find an existing `VerticalCRS` instance. Note that this is not a valid CRS according ISO 19111 — use with care.

    Parameters:
      `crs` - the coordinate reference system, or `null`.
      `allowCreateEllipsoidal` - `true` for allowing the creation of orphan CRS for ellipsoidal heights. The recommended value is `false`.
    Returns:
      the first vertical CRS, or `null` if none.
    See Also:
      - `compound(CoordinateReferenceSystem...)`

  - ### getTemporalComponent

    @OptionalCandidate public static TemporalCRS getTemporalComponent(CoordinateReferenceSystem crs)
    Returns the first temporal coordinate reference system found in the given CRS, or `null` if there is none. If the given CRS is already an instance of `TemporalCRS`, then this method returns it as-is. Otherwise if the given CRS is compound, then this method searches for the first temporal component in the list of single components.
    Parameters:
      `crs` - the coordinate reference system, or `null`.
    Returns:
      the first temporal CRS, or `null` if none.

  - ### getSingleComponents

    public static List<SingleCRS> getSingleComponents(CoordinateReferenceSystem crs)
    Returns the ordered list of single coordinate reference systems for the specified CRS. This method performs the following choices:
    - If the given CRS is null, returns an empty list.
    - If the given CRS is an instance of `SingleCRS`, returns that instance in a singleton list.
    - If the given CRS is an instance of `CompoundCRS`, returns a flattened list of its components. Some components may themselves be other `CompoundCRS` instances, in which case those compound CRS are also flattened in their list of `SingleCRS` components.
    - Otherwise throws a `ClassCastException`.

    #### Example

    Apache SIS allows 4-dimensional (x,y,z,t) coordinate reference system to be built in two different ways as shown below:

    Hierarchical structure

    > `CompoundCRS` — (x, y, z, t)
    > `├─CompoundCRS` — (x, y, z)
    > `│ ├─ProjectedCRS` — (x, y)
    > `│ └─VerticalCRS` — (z)
    > `└─TemporalCRS` — (t)

    Flat list

    > `CompoundCRS` — (x, y, z, t)
    > `├─ProjectedCRS` — (x, y)
    > `├─VerticalCRS` — (z)
    > `└─TemporalCRS` — (t)

    This method guaranteed that the returned list is a flat one as shown on the right side. Note that such flat lists are the only one allowed by ISO/OGC standards for compound CRS. The hierarchical structure is an Apache SIS flexibility.
    Parameters:
      `crs` - the coordinate reference system, or `null`.
    Returns:
      the single coordinate reference systems, or an empty list if the given CRS is `null`.
    Throws:
      `ClassCastException` - if a CRS is neither a `SingleCRS` or a `CompoundCRS`.
    See Also:
      - `DefaultCompoundCRS​.getSingleComponents()`

  - ### getComponentAt

    @OptionalCandidate public static CoordinateReferenceSystem getComponentAt(CoordinateReferenceSystem crs, int lower, int upper)
    Returns the coordinate reference system in the given range of dimension indices. This method processes as below:
    - If the given `crs` is `null`, then this method returns `null`.
    - Otherwise if `lower` is 0 and `upper` is the number of CRS dimensions, then this method returns the given CRS unchanged.
    - Otherwise if the given CRS is an instance of `CompoundCRS`, then this method searches for a component where:
      - The number of dimensions is equal to `upper - lower`;
      - The sum of the number of dimensions of all previous CRS is equal to `lower`.
      If such component is found, then it is returned.
    - Otherwise (i.e. no component match), this method returns `null`.
    This method does not build new CRS from the components. For example, this method does not create a `CompoundCRS` or a three-dimensional CRS if the given range spans more than one component.
    Parameters:
      `crs` - the coordinate reference system to decompose, or `null`.
      `lower` - the first dimension to keep, inclusive.
      `upper` - the last dimension to keep, exclusive.
    Returns:
      the sub-coordinate system, or `null` if the given `crs` was `null` or cannot be decomposed for dimensions in the [`lower` … `upper`] range.
    Throws:
      `IndexOutOfBoundsException` - if the given index are out of bounds.
    Since:
      0.5
    See Also:
      - `selectDimensions(CoordinateReferenceSystem, int...)`
      - `GeneralEnvelope​.subEnvelope(int, int)`

  - ### getGreenwichLongitude

    public static double getGreenwichLongitude(GeodeticCRS crs)
    Returns the Greenwich longitude of the prime meridian of the given CRS in degrees. If the prime meridian uses another unit than degrees, then the value will be converted.
    Parameters:
      `crs` - the coordinate reference system from which to get the prime meridian.
    Returns:
      the Greenwich longitude (in degrees) of the prime meridian of the given CRS.
    Since:
      0.5
    See Also:
      - `DefaultPrimeMeridian​.getGreenwichLongitude(Unit)`
      - `DatumOrEnsemble​.getPrimeMeridian(CoordinateReferenceSystem)`

  - ### getAuthorityFactory

    public static CRSAuthorityFactory getAuthorityFactory(String authority) throws FactoryException
    Returns the system-wide authority factory used by `forCode(String)` and other SIS methods. If the given authority is non-null, then this method returns a factory specifically for that authority. Otherwise, this method returns the `MultiAuthoritiesFactory` instance that manages all other factories.

    The `authority` argument can be `"EPSG"`, `"OGC"` or any other authority found on the module path. In the `"EPSG"` case, whether the full set of EPSG codes is supported or not depends on whether a connection to the database can be established. If no connection can be established, then this method returns a small embedded EPSG factory containing at least the CRSs defined in the `forCode(String)` method javadoc.

    User-defined authorities can be added to the SIS environment by creating a `CRSAuthorityFactory` implementation with a public no-argument constructor or a public static `provider()` method, and declaring the name of that class in the `module-info​.java` file as a provider of the `org​.opengis​.referencing​.crs​.CRSAuthorityFactory` service.

    Parameters:
      `authority` - the authority of the desired factory (typically `"EPSG"` or `"OGC"`), or `null` for the `MultiAuthoritiesFactory` instance that manage all factories.
    Returns:
      the system-wide authority factory used by SIS for the given authority.
    Throws:
      `FactoryException` - if no factory can be returned for the given authority.
    Since:
      0.7
    See Also:
      - `MultiRegisterOperations`