I have a shapefile which has the following PRJ

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

As far as I understand, this means lat, long ordering. However, when I read the features using geotools, I get coordinates in long, lat ordering, at least that's what I see in my debugger after the features have been parsed. The problem is then that I do a reprojection to 4326 using the following code (I'm doing a generic shapefile import service):

        CoordinateReferenceSystem geo = CRS.decode("EPSG:4326", true);
        CoordinateReferenceSystem crs = feature.getFeatureType().getCoordinateReferenceSystem();
        MathTransform transform = null;
        if (!crs.equals(geo)) {
            try {
                transform = CRS.findMathTransform(crs, geo, true);
            } catch (FactoryException e) {
                throw new Exception("Unsupported projection type");

And this reverts all the lat long coordinates!

If it is correct to say that the axis order is important in the PRJ file, and assuming there is indeed an order mismatch between the PRJ and the SHP, how can I deal with this?

  • Fortunately in shapefiles axis order is always left-to-right - top-to-bottom. Officially the format is projection-unaware and having .prj is an extra feature, though useful. The only three compulsory parts are .shp, .shx, and .dbf. – user30184 Nov 13 '15 at 8:47
  • Thanks! That's the bit I was missing ;-) How can I force this in Geotools though? my math transform is inverting the coordinates as it understand it to be lat, long (as far as I understand) so I need to force it to use the long, lat order... – Thomas Nov 13 '15 at 8:56
  • I believe that when GeoTools reads data in through a driver it is converting geometries into some internal geometry objects and you should not need to force anything. I wonder is this tutorial would help you docs.geotools.org/stable/tutorials/geometry/geometrycrs.html. – user30184 Nov 13 '15 at 12:45
  • Yes, that what I would have assumed but it doesn't seemed to. The code I use mostly comes from that page. In the end I am having to check for axis inversion, and if it is inverted, reload the crs using the actual definition and forcing XY ordering, but I am not too sure I am doing it the correct way... – Thomas Nov 13 '15 at 14:04

What I would do is first check whether my assumption of the source axis ordering (lat, lon) is correct. Simply visualize in, say, google maps your coordinates and see whether your study area is indeed there.

Another thing to bare in mind is that different software products have a different back-end encoding of how they handle CRSs. It might be very well the case that geotools or your code is written in a way that is ingesting the data based on a predefined axis order definition.

In any occasion, once your reprojection is done and if the shapefile doesn't display where it is supposed to, you could manually change the axis orders in the .prj file. This has certainly worked for me in cases of schema transformations with HALE, where the software wasn't handling my projections accurately. Manual meddles with the .prj were a solution, but if you have a large data set, things might become impractical.


In general for cases like these refer to the GeoTools axis order FAQ - so you are correct that your axis order in the shapefile is lat/lon.

Next, there are some issues with your code:

    CoordinateReferenceSystem geo = CRS.decode("EPSG:4326", true);

creates a CRS with lon/lat if (and only if) the system hint FORCE_LONGITUDE_FIRST_AXIS_ORDER is set true, which may or may not be the case.

It's better to be sure and use something like:

// force the output CRS to be long, lat as required by spec
CRSAuthorityFactory cFactory = CRS.getAuthorityFactory(true);
try {
  outCRS = cFactory.createCoordinateReferenceSystem("EPSG:4326");
} catch (FactoryException e) {
  throw new RuntimeException("CRS factory not found ", e);



    if (!crs.equals(geo)) {

Will nearly always be false as the chances of 2 CRS objects being the same object are slim it's much better to use:

     if(!CRS.equalsIgnoreMetadata(crs, geo)){

as that will check if the actual parameters match.

You can also use CRS.getAxisOrder(crs) to get the axis order as an easily comparable Enumeration.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.