Internal

Please note that this page is optional and only for the curious. It covers some of the implementation classes.

A CoordinateReferenceSystem is a gt-api interface describing how a set of ordinates is to be interpreted as a three dimensional point. This definition is standardized, mathematical and generally not of interest unless something goes wrong.

CoordinateReferenceSystem

For most cases you are only interested in using a CoordinateReferenceSystem as a parameter to a mathematical calculation (distance along the surface of the earth and “re-projection” being the most common).

Creating a CoordinateReferenceSystem:

        CoordinateReferenceSystem crs = CRS.decode("EPSG:26910", false);

You will need to ensure GeoTools is configured with an appropriate plugin for this example to work. This plugin will provide an CRSAuthorityFactory registered for “EPSG” codes.

CRSAuthorityFactory

Internally the CRS class makes use of a CRSAuthorityFactory to provide the definition for the indicated code. If you wish you can make use of the same facilities directly:

        String code = "26910";
        CRSAuthorityFactory crsAuthorityFactory =
                ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", null);
        CoordinateReferenceSystem crs = crsAuthorityFactory.createCoordinateReferenceSystem(code);

To create the actual CoordinateReferenceSystem object a CRSFactory is used, for example when parsing a “well known text” (WKT) definition:

        CRSFactory crsFactory = ReferencingFactoryFinder.getCRSFactory(null);
        String wkt =
                "PROJCS[\"UTM_Zone_10N\", "
                        + "GEOGCS[\"WGS84\", "
                        + "DATUM[\"WGS84\", "
                        + "SPHEROID[\"WGS84\", 6378137.0, 298.257223563]], "
                        + "PRIMEM[\"Greenwich\", 0.0], "
                        + "UNIT[\"degree\",0.017453292519943295], "
                        + "AXIS[\"Longitude\",EAST], "
                        + "AXIS[\"Latitude\",NORTH]], "
                        + "PROJECTION[\"Transverse_Mercator\"], "
                        + "PARAMETER[\"semi_major\", 6378137.0], "
                        + "PARAMETER[\"semi_minor\", 6356752.314245179], "
                        + "PARAMETER[\"central_meridian\", -123.0], "
                        + "PARAMETER[\"latitude_of_origin\", 0.0], "
                        + "PARAMETER[\"scale_factor\", 0.9996], "
                        + "PARAMETER[\"false_easting\", 500000.0], "
                        + "PARAMETER[\"false_northing\", 0.0], "
                        + "UNIT[\"metre\",1.0], "
                        + "AXIS[\"x\",EAST], "
                        + "AXIS[\"y\",NORTH]]";

        CoordinateReferenceSystem crs = crsFactory.createFromWKT(wkt);

Where the code above corresponds to this definition:

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["DMSH",0.0174532925199433,AUTHORITY["EPSG","9108"]],
  AXIS["Lat",NORTH],
  AXIS["Long",EAST],
  AUTHORITY["EPSG","4326"]]

Creating a CoordinateReferenceSystem

You can use factories defined by the referencing system to create things by hand using java code.

This example shows the creation of a WGS84 / UTM 10N CoordinateReferenceSystem:

        MathTransformFactory mtFactory = ReferencingFactoryFinder.getMathTransformFactory(null);
        CRSFactory crsFactory = ReferencingFactoryFinder.getCRSFactory(null);

        GeographicCRS geoCRS = org.geotools.referencing.crs.DefaultGeographicCRS.WGS84;
        CartesianCS cartCS = org.geotools.referencing.cs.DefaultCartesianCS.GENERIC_2D;

        ParameterValueGroup parameters = mtFactory.getDefaultParameters("Transverse_Mercator");
        parameters.parameter("central_meridian").setValue(-111.0);
        parameters.parameter("latitude_of_origin").setValue(0.0);
        parameters.parameter("scale_factor").setValue(0.9996);
        parameters.parameter("false_easting").setValue(500000.0);
        parameters.parameter("false_northing").setValue(0.0);
        Conversion conversion = new DefiningConversion("Transverse_Mercator", parameters);

        Map<String, ?> properties = Collections.singletonMap("name", "WGS 84 / UTM Zone 12N");
        ProjectedCRS projCRS =
                crsFactory.createProjectedCRS(properties, geoCRS, conversion, cartCS);

The next example shows NAD 27 geographic CRS being defined, with a couple of interesting things to note:

  • The datum factory automatically adds alias names to the datum. (The DatumAliasesTable.txt file inside gt-referencing has an entry for “North American Datum 1927”).

  • The toWGS84 information being supplied for use in a datum transform is added to the Datum

Here is the example:

        CRSFactory crsFactory = ReferencingFactoryFinder.getCRSFactory(null);
        DatumFactory datumFactory = ReferencingFactoryFinder.getDatumFactory(null);
        CSFactory csFactory = ReferencingFactoryFinder.getCSFactory(null);

        Map<String, Object> map = new HashMap<>();
        map.put("name", "Clarke 1866");

        Ellipsoid clark1866ellipse =
                datumFactory.createFlattenedSphere(map, 6378206.4, 294.978698213901, SI.METRE);

        PrimeMeridian greenwichMeridian =
                org.geotools.referencing.datum.DefaultPrimeMeridian.GREENWICH;

        final BursaWolfParameters toWGS84 = new BursaWolfParameters(DefaultGeodeticDatum.WGS84);
        toWGS84.dx = -3.0;
        toWGS84.dy = 142;
        toWGS84.dz = 183;

        map.clear();
        map.put("name", "North American Datum 1927");
        map.put(DefaultGeodeticDatum.BURSA_WOLF_KEY, toWGS84);

        GeodeticDatum clark1866datum =
                datumFactory.createGeodeticDatum(map, clark1866ellipse, greenwichMeridian);
        System.out.println(clark1866datum.toWKT());
        // notice all of the lovely datum aliases (used to determine if two
        // datums are the same)
        System.out.println("Identified Datum object:");
        printIdentifierStuff(clark1866datum);

        map.clear();
        map.put("name", "<lat>, <long>");
        CoordinateSystemAxis latAxis =
                org.geotools.referencing.cs.DefaultCoordinateSystemAxis.GEODETIC_LATITUDE;
        CoordinateSystemAxis longAxis =
                org.geotools.referencing.cs.DefaultCoordinateSystemAxis.GEODETIC_LONGITUDE;
        EllipsoidalCS ellipsCS = csFactory.createEllipsoidalCS(map, latAxis, longAxis);

        map.clear();
        map.put("name", "NAD 27");
        map.put("authority", "9999");
        // TODO add an authority code here (should be an identifier)
        GeographicCRS nad27CRS = crsFactory.createGeographicCRS(map, clark1866datum, ellipsCS);

Finally, here is no-holds-barred creation of a CoordinateReferenceSystem with all the usual helper classes stripped away. It does not use any of the static objects available in GeoTools. The following example creates a CoordinateReferenceSystem to represent WGS84.

        CRSFactory crsFactory = ReferencingFactoryFinder.getCRSFactory(null);
        DatumFactory datumFactory = ReferencingFactoryFinder.getDatumFactory(null);
        CSFactory csFactory = ReferencingFactoryFinder.getCSFactory(null);
        Map<String, Object> map = new HashMap<>();

        //
        // Create a datum used for each CRS
        //
        map.clear();
        map.put("name", "Greenwich Meridian");
        PrimeMeridian greenwichMeridian =
                datumFactory.createPrimeMeridian(map, 0, NonSI.DEGREE_ANGLE);

        map.clear();
        map.put("name", "WGS 84 Ellipsoid Datum");
        Ellipsoid wgs84Ellipsoid =
                datumFactory.createFlattenedSphere(map, 6378137, 298.257223563, SI.METRE);

        map.clear();
        map.put("name", "WGS84 Height Datum");
        GeodeticDatum wgs84Datum =
                datumFactory.createGeodeticDatum(map, wgs84Ellipsoid, greenwichMeridian);

        //
        // Create a geocentric CRS
        //
        // Create a collection of axes for the coordinate system.
        map.clear();
        map.put("name", "Cartesian X axis");
        CoordinateSystemAxis xAxis =
                csFactory.createCoordinateSystemAxis(
                        map, "X", AxisDirection.GEOCENTRIC_X, SI.METRE);

        map.clear();
        map.put("name", "Cartesian Y axis");
        CoordinateSystemAxis yAxis =
                csFactory.createCoordinateSystemAxis(
                        map, "Y", AxisDirection.GEOCENTRIC_Y, SI.METRE);

        map.clear();
        map.put("name", "Cartesian Z axis");
        CoordinateSystemAxis zAxis =
                csFactory.createCoordinateSystemAxis(
                        map, "Z", AxisDirection.GEOCENTRIC_Z, SI.METRE);

        map.clear();
        map.put("name", "Rendered Cartesian CS");
        CartesianCS worldCS = csFactory.createCartesianCS(map, xAxis, yAxis, zAxis);

        // Now, the geocentric coordinate reference system that we'd use for output - eg to a 3D
        // renderer
        map.clear();
        map.put("name", "Output Cartesian CS");
        CoordinateReferenceSystem geocentricCRS =
                crsFactory.createGeocentricCRS(map, wgs84Datum, worldCS);
        System.out.println("Geocentric CRS: " + geocentricCRS.toWKT());

        //
        // Create a geograyhic CRS for the Airy 1830 ellipsoid
        // map.clear();
        // map.put("name", "Airy 1830");
        // Ellipsoid airyEllipse =
        // datumFactory.createFlattenedSphere(map, 6377563.396, 299.3249646, SI.METRE);

        map.clear();
        map.put("name", "Geodetic North axis");
        CoordinateSystemAxis northAxis =
                csFactory.createCoordinateSystemAxis(
                        map, "N", AxisDirection.NORTH, NonSI.DEGREE_ANGLE);

        map.clear();
        map.put("name", "Geodetic East axis");
        CoordinateSystemAxis eastAxis =
                csFactory.createCoordinateSystemAxis(
                        map, "E", AxisDirection.EAST, NonSI.DEGREE_ANGLE);

        map.clear();
        map.put("name", "Geodetic Height axis");
        CoordinateSystemAxis heightAxis =
                csFactory.createCoordinateSystemAxis(map, "Up", AxisDirection.UP, SI.METRE);

        map.clear();
        map.put("name", "<long>,<lat> Airy 1830 geodetic");
        EllipsoidalCS airyCS = csFactory.createEllipsoidalCS(map, eastAxis, northAxis, heightAxis);

        // finally create the source geographic CRS
        CoordinateReferenceSystem airyCRS = crsFactory.createGeographicCRS(map, wgs84Datum, airyCS);

Referencing Factories

These are the “real” factories - interfaces that actually create stuff. All are gt-api interfaces, so you will need to use ReferencingFactoryFinder to get started:

  • DatumFactory: Makes datums!

  • CSFactory Makes CoordinateSystem instances, and many more

  • CRSFactory Makes CoordinateReferenceSystem instances, and many more

  • MathTransformFactory Makes MathTransform instances, and many more

You can quickly grab all four factories at once using ReferencingFactoryContainer:

        Hints hints = null; // configure hints for the group of factories
        ReferencingFactoryContainer group = new ReferencingFactoryContainer(hints);
        CRSFactory crsFactory = group.getCRSFactory();
        CSFactory csFactory = group.getCSFactory();
        DatumFactory datumFactory = group.getDatumFactory();
  • ReferencingFactoryFinder

    As is custom we have included a FactoryFinder so you can look up a good implementation on the CLASSPATH:

    DatumFactory datumFactory = ReferencingFactoryFinder.getDatumFactory(null);
    

    The ReferencingFactoryFinder returns a couple of GeoTools implementations right now, in the future we hope to replace these defaults with an implementation from JScience.

  • ReferencingFactoryContainer

    You may have noticed that to actually do anything you need several factories. We have gathered these together into a “container” for you. The container also adds a few more methods which use a couple of factories to gang up on a problem

    You can set up ReferencingFactoryContainer to use your own custom factory using hints as shown below:

            Map<Key, Object> map = new HashMap<>();
    
            map.put(Hints.DATUM_FACTORY, datumFactory);
            map.put(Hints.CS_FACTORY, csFactory);
            map.put(Hints.CRS_FACTORY, crsFactory);
            map.put(Hints.MATH_TRANSFORM_FACTORY, mtFactory);
    
            Hints hints = new Hints(map);
    
            ReferencingFactoryContainer container = new ReferencingFactoryContainer(hints);
    

    Please note that ReferencingFactoryContainer is not strictly needed, it just makes things easier. ReferencingFactoryFinder will be smart and recycle instances where possible:

            Hints hints = GeoTools.getDefaultHints();
            DatumFactory datumFactory = ReferencingFactoryFinder.getDatumFactory(hints);
    
            ReferencingFactoryContainer container = new ReferencingFactoryContainer(hints);
    
            if (datumFactory == container.getDatumFactory()) {
                System.out.println("Will be the same DatumFactory");
            }
    

Referencing Authority Factories

Deep behind that CRS utility class is an amazing constellation of “factories” used to define what a CoordinateReferenceSystem is, actually create the parts, and finally stitch them all together in a unified whole.

These things are factories in name only; their real job is to supply the definitions (in pattern speak they would be called builders).

  • DatumAuthorityFactory: Defines a Datum using a code provided by a authority such as EPSG

  • CSAuthorityFactory: Defines a CoordinateSystem using a code provided by an authority such as EPSG

  • CRSAuthorityFactory: Defines a CoordinateReferenceSystem for a given authority (such as EPSG)

  • CoordinateOperationAuthorityFactory: Defines coordinate operations from codes, backed by math transforms

To actually perform their function these authorities acquire a definition internally and then call a “real” factory class from ReferencingFactoryContainer.

  • Getting the EPSG AuthorityFactory

    You can make direct use of the CRSAuthorityFactory configured to handle “EPSG” codes:

    CRSAuthorityFactory factory = ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", null);
    CoordinateReferenceSystem crs = factory.createCoordinateReferenceSystem("4326");
    

You will need to make sure that one of the epsg plugins is on your CLASSPATH (such as epsg-hsql).

  • Finding the available EPSG Codes:

    CRSAuthorityFactory factory = ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", null);
    Set<String> authorityCodes = factory.getAuthorityCodes(CoordinateReferenceSystem.class);
    
  • Getting Other AuthorityFactory Instances

    Here are several more examples that are understood by GeoTools:

    Hints hints = null; // Put optional hints here.
    CRSAuthorityFactory crsAuthority  = ReferencingFactoryFinder.getCRSAuthorityFactory("CRS",   hints);
    CRSAuthorityFactory wms2Authority = ReferencingFactoryFinder.getCRSAuthorityFactory("AUTO",  hints);
    CRSAuthorityFactory wms3Authority = ReferencingFactoryFinder.getCRSAuthorityFactory("AUTO2", hints);
    
  • IdentifiedObject Finder for Controlled Searching

    One bit of functionality that is not available via the CRSAuthority interfaces directly is the ability to carefully search through all the available definitions.:

    CRSAuthorityFactory factory = ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", null);
    AbstractAuthorityFactory custom = (AbstractAuthorityFactory) factory;
    
    IdentifiedObjectFinder finder = custom.getIdentifiedObjectFinder(CoordinateReferenceSystem.class);
    
    finder.setFullScanAllowed(true); // will search everything ever defined (may be slow)
    IdentifiedObject find = finder.find(crs);
    
    finder.setFullScanAllowed(false); // will limit search to what has been cached in memory
    IdentifiedObject find = finder.find(crs);
    

    As shown above this is additional functionality made available through AbstractAuthorityFactory - it is not part of the normal gt-api interfaces.

You can construct finders to search through other categories of referencing Objects (like Datum and ReferencingSystem).