# RFC 20: OGRSpatialReference Axis Support

Author: Frank Warmerdam

Contact: warmerdam@pobox.com

Status: Adopted

## Summary

The OGRSpatialReference and OGRCoordinateTransformation classes assume that all coordinate systems use (easting, northing) coordinate order (or in geographic terms (longitude, latitude)). In practice some coordinate systems use alternate axis orientations (such as the Krovak projection), and some standards (GML, WMS 1.3, WCS 1.1) require honouring the EPSG declaration that all it's geographic coordinates have (latitude, longitude) coordinate ordering.

This RFC attempts to extend the OGRSpatialReference, and OGRCoordinateTransformation classes to support alternate axis orientations, and to update selected drivers (GML, WMS, WCS, GMLJP2) to properly support axis ordering.

## WKT Axis Representation

The OGC WKT SRS format (per OGC 01-???) already indicates a way of defining coordinate system axes as shown in this example:

    GEOGCS["WGS 84",
        DATUM["WGS_1984",
            SPHEROID["WGS 84",6378137,298.257223563,
                AUTHORITY["EPSG","7030"]],
            TOWGS84[0,0,0,0,0,0,0],
            AUTHORITY["EPSG","6326"]],
        PRIMEM["Greenwich",0,
            AUTHORITY["EPSG","8901"]],
        UNIT["degree",0.0174532925199433,
            AUTHORITY["EPSG","9108"]],
        AXIS["Lat",NORTH],
        AXIS["Long",EAST],
        AUTHORITY["EPSG","4326"]]

There is one AXIS definition per axis with order relating to position within a tuple. The first argument is the user name for the axis and exact values are not specified. The second argument is a direction and may be one of NORTH, SOUTH, EAST or WEST.

## Dilemma

The core challenge of this RFC is adding support for axes orders, including honouring EPSG desired axis order for geographic coordinate systems where appropriate without breaking existing files and code that make extensive use of EPSG coordinate systems but override axis orientations and assume they should be treated as long, lat regardless of what EPSG says.

In particular, we come up with appropriate policies and mechanisms to decide when a file in a geographic coordinate system like EPSG:4326 is to be treated as lat/long and when it should be long/lat. Because of the extensive existing practice it behooves us to err on the side of past practice, and require "opting in" to honouring EPSG axis ordering.

## The Hack

The main mechanism by I propose to work around the dilemma is to differentiate between geographic coordinate systems with the AXIS values set and those without. In particular, a WKT coordinate system with the EPSG authority code (ie. 4326) set, but no axis declarations will be assumed to be long, lat even though that is contrary to the definition from EPSG of 4326. Only in cases where we really know we want to honour EPSG's axis order will we actually populate the axis declarations indicating lat, long.

The hope is that this will let us continue to (mis)use EPSG:4326 definitions without necessary honouring the EPSG axis ordering except in specific circumstances.

## OGRSpatialReference

### New Enumeration

    typedef enum {
      OAO_Unknown = 0,
      OAO_North = 1,
      OAO_South = 2,
      OAO_East = 3,
      OAO_West = 4
    } OGRAxisOrientation;

### New methods

    const char *GetAxis( const char *pszTargetKey, int iAxis,
                         OGRAxisOrientation *peOrientation );

Fetch information about one axis (iAxis is zero based).

    OGRErr      SetAxes( const char *pszTargetKey,
                         const char *pszXAxisName, OGRAxisOrientation eXAxisOrientation,
                         const char *pszYAxisName, OGRAxisOrientation eYAxisOrientation,
                         const char *pszZAxisName=NULL, OGRAxisOrientation eZAxisOrientation = OAO_Unknown );

Defines the X and Y axes for a given target key (PROJCS or GEOGCS).

    int         EPSGTreatsAsLatLong();

Returns true based on the EPSG code if EPSG would like this coordinate system to be treated as lat/long. This is useful in contexts like WMS 1.3 where EPSG:4326 needs to be interpreted as lat/long due to the standard.

    OGRErr      importFromEPSGA( int );

This works like importFromEPSG() but will assign the EPSG defined AXIS definition.

Note that OGRSpatialReference::StripNodes( "AXIS" ); can be used to strip axis definitions where they are not desired.

### importFromURN

Modify importFromURN() to set AXIS values properly for EPSG and OGC geographic coordinate systems. So urn:...:EPSG: will be assumed to really honour EPSG conventions.

### SetWellKnownGeogCS()

This method appears to be the only code

- Modify SetWellKnownGeogCS() to not set AXIS values, and strip AXIS values out of any other hardcoded WKT definitions.

### importFromEPSG()

- importFromEPSG() will continue to not set AXIS values for GEOGCS coordinate systems.

- importFromEPSG() will now set axis values for projected coordinate systems (at least in cases like Krovak where it is a non-default axis orientation).

- importFromEPSG() will be implemented by calling importFromEPSGA() and stripping off axis definitions from the geographic portion of the returned definition.

### SetFromUserInput()

- This method will have one new option which is a value prefixed by EPSGA: will be passed to importFromEPSGA() (similarly to EPSG:n being passed to importFromEPSG()).

## OGRCoordinateTransformation

If AXIS values are set on source and/or destination coordinate system, the OGRCoordinateTransformation code will take care of converting into normal easting/northing before calling PROJ.

The CPL config option "GDAL_IGNORE_AXIS_ORIENTATION" may also be set to "TRUE" to disable OGRCoordinateTransformation's checking, and application of axis orientation changes. Effectively this is a backdoor to disable the core effects of the RFC.

## Drivers Affected

- GMLJP2 (classes in gcore/gdalgmlcoverage.cpp and gcore/gdaljp2metadata.cpp).

- WCS (based on interpretation of urns).

- WMS (maybe? actually, I suspect we don't actually get the coordinate system from the capabalities)

- OGR GML (maybe? only GML3 affected?)

- BSB, SAR_CEOS, ENVISAT, HDF4, JDEM, L1B, LAN, SRTMHGT: Like SetWellKnownGeogCS() these all include lat/long AXIS specifications in their hardcoded WGS84 coordinate systems. These need to be removed so they will default to being interpreted as long/lat.

## Versions

Work will be in trunk for GDAL/OGR 1.6.0 with the following exceptions which will be address in 1.5.x:

- Existing use of AXIS specifier will for geographic coordinate systems will be stripped from SetWellKnownGeogCS() and the various drivers with hard coded WKT strings.

- Some sort of hack will need to be introduced into the GMLJP2 (and possibly WCS) code to flip EPSG authority lat/long values (details to be worked out).

## Implementation

Implementation would be done by Frank Warmerdam. Some aspects (such as properly capturing axis ordering for projected coordinate systems) might not be implemented immediately.

## Compatibility Issues

The greatest concern is that any existing WKT coordinate systems with LAT/LONG axis ordering (in VRT files, or .aux.xml files for instance) will be interpreted differently by GDAL/OGR 1.6.0 than they were by 1.5.0. This could easily occur if files in formats like BSB, or HDF4 were copied to a format using WKT coordinate systems (such as JPEG with a .aux.xml file). To partially mitigate this I am proposing that AXIS definitions be removed from GDAL 1.5.1.

## Supporting Information

- OSGeo Wiki Summary: http://wiki.osgeo.org/index.php/Axis_Order_Confusion