Getting started

How do I transform a coordinate?

See the referencing section in the demos page.


Which EPSG codes are supported?

See the Authority codes for Coordinate Reference Systems page.


What is the axis order issue and how is it addressed?

The axis order is specified by the authority (typically a national agency) defining the Coordinate Reference System (CRS). The order depends on the CRS type and the country defining the CRS. In the case of geographic CRS, the (latitude, longitude) axis order is widely used by geographers and pilotes for centuries. However software developers tend to consistently use the (x,y) order for every kind of CRS. Those different practices resulted in contradictory definitions of axis order for almost every CRS of kind GeographicCRS, for some ProjectedCRS in the South hemisphere (South Africa, Australia, etc.) and for some polar projections among others.

Recent OGC standards mandate the use of axis order as defined by the authority. Oldest OGC standards used the (x,y) axis order instead, ignoring any authority specification. Many softwares still use the old (x,y) axis order, because it is easier to implement. Geotk supports both conventions.

By default, Geotk creates CRS with axis order as defined by the authority. Those CRS are created by calls to the CRS.decode(String) method. The actual axis order can be verified after the CRS creation with System.out.println(crs). See here for more information about the elements to look at.

If (x,y) axis order is wanted for compatibility with older OGC specifications or other softwares, CRS forced to longitude first axis order can be created by call to the CRS.decode(String, true) method. Note that while the documentation said "longitude first" for simplicity, the implementation actually try to build a right-handed coordinate system.

Note that the Well Known Text (WKT) specification is part of an older OGC standard. According that widely-used standard, CRS created by calls to the CRS.parseWKT(String) method will have (longitude, latitude) or (x,y) axis order by default if no AXIS[…] elements were explicitly specified in the WKT.

For any CRS identified by an EPSG code, the official axis order can be checked on the http://www.epsg-registry.org web site: Click on the "Retrieve by code" link and enter the numerical code. Then click on the "View" link on the right side, and click on the "+" symbol of the left side of "Axes".

Coordinate Reference Systems

How do I instantiate a Universal Transverse Mercator (UTM) projection?

The easiest way is to use the "EPSG" or "AUTO" authority factory. The EPSG code of some UTM projections can be determined as below, where zone is a number from 1 to 60 inclusive (unless otherwise specified):

  • WGS 84 (northern hemisphere): 32600 + zone
  • WGS 84 (southern hemisphere): 32700 + zone
  • WGS 72 (northern hemisphere): 32200 + zone
  • WGS 72 (southern hemisphere): 32300 + zone
  • NAD 83 (northern hemisphere): 26900 + zone (zone 1 to 23 only)
  • NAD 27 (northern hemisphere): 26700 + zone (zone 1 to 22 only)

Note that the above list is incomplete. See the EPSG database for additional UTM definitions (WGS 72BE, SIRGAS 2000, SIRGAS 1995, SAD 69, ETRS 89, etc., most of them defined only for a few zones).

Once the EPSG code of the UTM projection has been determined, the CRS can be obtained as in the example below:

int code = 32600 + zone;
CoordinateReferenceSystem crs = CRS.decode("EPSG:" + code);

The above approach requires the EPSG database to be installed. If installing the EPSG database is considered too heavy, a lighther approach is to use the "AUTO" authority factory as below (see the AutoCRSFactory javadoc for more details):

int centralMeridian = zone * 6 - 183;
int latitudeOfOrigin = 0;
CoordinateReferenceSystem crs = CRS.decode("AUTO:42001," + centralMeridian + "," + latitudeOfOrigin);

Finally the most powerful (but also the most difficult) way is to instantiate directly a MathTransform using the parameters documented in the TransverseMercator class, and build a DefaultProjectedCRS instance using it.


How do I instantiate a Google projection?

The Google projection is a Mercator projection that pretends to be defined on the WGS84 datum, but actually ignores the ellipsoid nature of that datum and uses the simpler spherical formulas instead. In Geotk this behavior can be obtained for any projections (not only the Mercator one used by Google) with explicit declarations of "semi_major" and "semi_minor" parameter values, like in the example below. Those parameters are usually inferred from the datum, but explicit declarations override the inferred values.

PROJCS["Google Mercator",
  GEOGCS["WGS 84",
    DATUM["World Geodetic System 1984",
      SPHEROID["WGS 84", 6378137, 298.257223563]],
    PRIMEM["Greenwich", 0],
    UNIT["degree", 0.017453292519943295]],
  PROJECTION["Mercator (1SP)"],
  PARAMETER["semi_major", 6378137],
  PARAMETER["semi_minor", 6378137],
  UNIT["m", 1]]

Since version 6.15 of the EPSG database, it is also possible to simply invoke CRS.decode("EPSG:3857"). The result of that method call is slightly different in that the "semi_minor" parameter is not modified. Instead EPSG handles that projection with a new Operation Method called "Popular Visualisation Pseudo Mercator".


How can I identify the projection kind of a CRS?

The "kind of projection" (Mercator, Lambert Conformal, etc.) is called Operation Method in ISO 19111 terminology. A good implementation independent approach is to check the value of OperationMethod.getName(). The operation method names are somewhat standardized in various ways. Some reliable names are the "OGC WKT Name" listed in the remotesensing.org web site.

For each projection supported by Geotk, the various operation method names are available (indirectly) in the PARAMETERS constant defined in each class of the providers package. The example below uses the constant defined in the AlbersEqualArea class in order to verify if the name of the given operation method is any name or alias known to be associated to the Albers Equal Area projection:

ProjectedCRS crs = ...;
OperationMethod method = crs.getConversionFromBase().getMethod();
if (AbstractIdentifiedObject.nameMatches(method, AlbersEqualArea.PARAMETERS)) {
    // Do some stuff here...
}

How do I get the EPSG code of an existing CRS?

The identifier of a Coordinate Reference System (CRS) object can be obtained by the getIdentifiers() method, which usually return a collection of zero or one element. If the CRS has been created from a Well Known Text (WKT) parsing and the WKT ends with an AUTHORITY["EPSG", "xxxx"] element, then the identifier (an EPSG code in this example) is the value in that AUTHORITY element. If the CRS has been created from the EPSG Authority Factory, then the factory should have already put the code in the collection of identifiers. If the CRS has been created in a different way, then the collection returned by the getIdentifiers() method may or may not be empty depending if the program that created the CRS has taken the responsibility of providing an identifier.

If the collection of identifiers is empty, the most effective fix is to make sure that the WKT contains an AUTHORITY declaration. If this is not possible, then the org.geotoolkit.referencing.CRS class contains some lookupIdentifier(…) convenience methods which may help. Example:

CoordinateReferenceSystem myCRS = ...;
String identifier = CRS.lookupIdentifier(Citations.EPSG, myCRS, true);
if (identifier != null) {
    System.out.println("The EPSG code has been found: " + identifier);
}

The above call will first inspects the collection returned by myCRS.getIdentifiers(). If no suitable value is found, then it will scan the EPSG database for a CRS equals (ignoring metadata) to the given one. Note that this scan is sensitive to axis order. Most geographic CRS in the EPSG database are declared with (latitude, longitude) axis order. Consequently If the given CRS has (longitude, latitude) axis order, then the scan is likely to find no match unless it has been instructed to force the longitude axis to appear first.


How do I get the "urn:ogc:def:crs:…" URN of an existing CRS?

OGC defines URN for CRS identifiers, for example "urn:ogc:def:crs:epsg:7.1:4326" where "7.1" is the version of the EPSG database used. URN may or may not be present in the set of identifiers returned by crs.getIdentifiers(). In many cases (especially if the CRS was parsed from a Well Known Text), only simple identifiers like "EPSG:4326" are provided. An easy way to build the full URN is to use the code below:

String urn = CRS.lookupIdentifier(Citations.URN_OGC, myCRS, false);

The boolean argument can be set to true for allowing a database scan (see the FAQ item above), and the authority can also be HTTP_OGC for a URL of the form "http://www.opengis.net/gml/srs/epsg.xml#4326".


Can I rely on CRS.lookupEpsgCode(…) to work correctly as the inverse of CRS.decode(…)?

For CRS created from the EPSG database, usually yes. Note however that CRS.getDeclaredIdentifier(…) is cheaper and insensitive to the details of CRS definition, since it never query the database. But it works only if the CRS declares explicitly its code, which is the case for CRS created from the EPSG database or parsed from a Well Known Text (WKT) having an AUTHORITY element. The lookupEpsgCode(…) method on the other hand is robust to erroneous code declaration, since it always compares the CRS with the database content. But it fails if there is slight mistmatch (for example rounding errors in projection parameters) between the supplied CRS and the CRS found in the database.


How can I determine if two CRS are "functionally" equal?

The three following Coordinate Reference Systems:

  • DefaultGeographicCRS.WGS84
  • CRS.decode("CRS:84")
  • CRS.decode("EPSG:4326", true)

are not considered equals(Object) to each other, even though they all represent the same logical CRS. This is because they are associated to different metadata (name, identifiers, scope, domain of validity, remarks). In order to test if two CRS are functionally equivalent, use equalsIgnoreMetadata(Object, Object).


Are CRS objects safe for use as keys in HashMap?

Yes, every classes defined in the org.geotoolkit.referencing.crs, cs and datum packages define properly their equals(Object) and hashCode() methods. The Geotk library itself uses CRS objects in HashMap-like containers for caching purpose.

As a side note, instances created by the Geotk ReferencingObjectFactory are unique, so even the identity check (==) works in a majority of cases. However the recommended approach still the use of equals(Object).

Coordinate transformations

Why do I get a "Bursa-Wolf parameters required" ProjectionException?

Coordinate Reference Systems (CRS) approximate the Earth's shape by an ellipsoid. Different ellipsoids (actually different datum) are used in different countries of the world and at different time in history. When transforming coordinates between two CRS using the same datum, no Bursa-Wolf parameters are needed. But when the transformation involves a change of datum, the referencing module needs some information about how to perform that datum shift.

There is many way to specify how to perform a datum shift, and most of them are only approximation. The Bursa-Wolf method is one of them, not the only one. However it is the most frequently used method in Geotk. In Well Known Text (WKT) format, the Bursa-Wolf parameters are specified inside a TOWGS84 element. If the CRS are parsed from a WKT string, make sure that the string contains the TOWGS84 element.

If there is no known Bursa-Wolf parameters that could be provided, it is possible to instruct Geotk to attempt the coordinate transformation despite that. However the results may be one kilometre away from the expected locations.

  • If the transform is created using the convenience static methods defined in the CRS class, then use CRS.findMathTransform(sourceCRS, targetCRS, true). Note the optional boolean argument which shall be explicitly set to true, meaning "lenient datum shift".

  • If the transform is created from the CoordinateOperationFactory interface, then use the following code snippet:

    Hints hints = new Hints(Hints.LENIENT_DATUM_SHIFT, Boolean.TRUE);
    factory = FactoryFinder.getCoordinateOperationFactory(hints);

My transformed coordinates are totally wrong!

This is most frequently caused by ordinate values given in the wrong order. Developpers tend to assume a (x, y) or (longitude, latitude) axis order. But geographers and pilotes are using (latitude, longitude) axis order for centuries, and the EPSG database defines geographic Coordinate Reference Systems that way. If a coordinate transformation seems to produce totally wrong values, the first thing to do should be to print the source and target Coordinate Reference Systems:

System.out.println(sourceCRS);
System.out.println(targetCRS);

Attention should be paid to the order of AXIS elements. In the example below, the Coordinate Reference System clearly uses (latitude, longitude) axis order:

GEOGCS["WGS 84",
  DATUM["World Geodetic System 1984",
    SPHEROID["WGS 84", 6378137.0, 298.257223563]],
  PRIMEM["Greenwich", 0.0],
  UNIT["degree", 0.017453292519943295],
  AXIS["Geodetic latitude", NORTH],
  AXIS["Geodetic longitude", EAST],
  AUTHORITY["EPSG","4326"]]

If (longitude, latitude) axis order is really wanted, Geotk can be forced to that order in two ways:

  • If CRS are created from authority codes using the convenience static methods defined in the CRS class, then use CRS.decode(myCode, true). Note the optional boolean argument which shall be explicitly set to true, meaning "force longitude first axis order".

  • If CRS are created from the AuthorityFactory interface, then use the following code snippet (assuming that the EPSG authority is wanted):

    Hints hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
    factory = AuthorityFactoryFinder.getCRSAuthorityFactory("EPSG", hints);

I have correct axis order but my transformed coordinates are still wrong.

Make sure that the right projection is used. Some projection names are confusing. For example "Oblique Mercator" and "Hotine Oblique Mercator" (in EPSG naming) are two different projections. But "Oblique Mercator" (not Hotine) in EPSG naming is also called "Hotine Oblique Mercator Azimuth Center" by ESRI, while "Hotine Oblique Mercator" (EPSG naming) is called "Hotine Oblique Mercator Azimuth Natural Origin" by ESRI.

The "Oblique Stereographic" projection (EPSG name) is called "Double Stereographic" by ESRI. ESRI also defines a "Stereographic" projection, which is actually an oblique projection like the former but using different formulas.

The "Krovak" projection in ESRI takes implicitly (southing, westing) axis orientation, while all projections in Geotk (including Krovak) default to (easting, northing) axis orientation, as required by the OGC 01-009 specification. In order to get the ESRI behavior with such projections, axis orientation must be explicitly specified in Geotk, for example with AXIS elements in Well Known Text (WKT) format.


I get slightly different results depending on the environment I’m running in.

The results of coordinates converted when running in a web application container (JBoss, etc.) may be a few meters off compared to coordinates converted in an IDE (NetBeans, Eclipse, etc.). The results depend on whatever an EPSG factory is available on the classpath, no matter how the CRS were created, because the EPSG factory specifies explicitly the coordinate operation to apply for some pair of CRS. In such case, the coordinate operation specified by EPSG has precedence over the Burwa-Wolf parameters (the TOWGS84 element in Well Known Text).

A connection to the EPSG database may have been established for one environment (typically the JEE one) and not the other (typically the IDE one) because only the former has JDBC driver. The recommended way to uniformize the results is to add in the second environment (IDE) the same JDBC driver than the first environment (JEE). It should be one of the following: JavaDB (a.k.a. Derby), HSQL or PostgreSQL (the later requires manual installation of EPSG database).


Can I always expect a transform from an arbitrary CRS to WGS84 to succeed?

For 2D horizontal CRS created from the EPSG database, calls to CRS.findMathTransform(…, true) - where the true argument is for lenient datum shift - should generally succeed. For 3D CRS having any kind of height different than ellipsoid height, or for a 2D CRS of type EngineeringCRS, it may fail.

Note however that even if the call to CRS.findMathTransform(…) succeed, the call to MathTransform.transform(…) may fail or produce NaN or infinity values if the coordinate to transform is far from the projection area of validity.

Configuration

How to fix the "No suitable driver found for jdbc:derby" exception?

If you are developing a desktop application with Maven, make sure that your project declares a dependency to the derby artifact from the org.apache.derby group. This is not done automatically by Geotk (except the geotk-epsg-javadb convenience module) because the choice of the database engine (Access, PostgreSQL, etc.) is left to the users.

If you are developing a desktop application without Maven, make sure that the derby.jar file is presents on the classpath.

If you are developing a server application to be deployed in a container like Glassfish or Tomcat, make sure that the Derby dependency does not appear in the WAR file. This is the opposite of what one may intuitively think. See the geotk-epsg-javadb module for more explanation.


Can I embed a small EPSG factory in my application without the need for JavaDB?

Yes. The GeoTools project was used to provide a gt-epsg-wkt module, which contain a plain text file listing various CRS in their Well Known Text (WKT) format. This text file is not provided in Geotk because it contained only a subset of the EPSG database, and the CRS defined in that file are not fully compliant with EPSG (especially regarding axis order). However Geotk provides the factory class that exploit this file, but it is up to the user to provide the file itself with the CRS of his choice. The only required action is to make that file available in the classpath (typically inside a JAR file) under the following directory and name:

org/geotoolkit/referencing/factory/epsg/epsg.properties

No coding is required to make it works, unless you wish to search for the epsg.properties file in an other directory (see PropertyEpsgFactory for more information). In order to create a epsg.properties file, the resources provided in the GeoTools gt-epsg-wkt module can be used as a starting point

Note that if a connection to an EPSG database is found, then that database will have precedence over the CRS defined in the properties file. If the properties file seems to be ignored when it should not, the code snippet provided in the FactoryDependencies javadoc may provide useful informations for debugging purpose.


How do I specify connection parameters to my own database?

The easiest way is to specify the connection parameters using the Swing widget provided by the geotk-setup module. Alternatively, the connection parameters can also be specified programmatically in database-specific implementation of javax.sql.DataSource (for example org.postgresql.ds.PGSimpleDataSource for PostgreSQL database). Then, put the following code at some application initialization point, before any Geotk referencing code is invoked:

DataSource ds = new MyDataSource(…);
Hints.putSystemDefault(Hints.EPSG_DATA_SOURCE, ds);

Queries against my EPSG database are slow.

For better performance, Geotk requires some database indexes in addition to the ones created by the EPSG SQL scripts. If the EPSG database has been created by direct execution of those SQL scripts rather than by the Geotk EpsgInstaller, then the Geotk Indexes.sql script needs to be executed after the database installation. Note that this is done automatically if the EPSG database has been created by the above-cited EpsgInstaller