2

I am a software developer who knows a bit about Gis/Geodesy, but I am not an expert so I might misuse terminology somewhat.

I have been tasked to extend an app in Java and have a need to transform data from one Coord System to another. We started using GeoTools which lets us transform using EPSG codes.

    private MathTransform getMathTransformForEpsgCode(String epsgCode) throws FactoryException {
    MathTransform sourceToTargetConversion = null;
    try {
        // Get the result SourceCRS
        CoordinateReferenceSystem sourceCRS = CRS_FACTORY.createCoordinateReferenceSystem(epsgCode);
        // Create and apply Transform
        sourceToTargetConversion = CRS.findMathTransform(sourceCRS, TARGET_CRS);
    } catch (NoSuchAuthorityCodeException e) {
        log.info("No CRS found for code, assuming it is a transform", e);
        throw e;
    }

    return sourceToTargetConversion;
}

Which was then used something like the following

JTS.transform(coordinate, coordinate, returnedMathtransform);

HOWEVER, what we want to do is actually specify the math transformation method used (Note: I think this is akin I think to this question "How to specify transformation method when using ogr2ogr to reproject geometry?".

Is this possible with GeoTools?

  • Ideally specifying the math transform using an ESPG code (i.e. http://epsg.io/27700-5339)
  • Alternativly specifying 3 or 7 parameters

So I am a wee bit out of my depth here (but learning fast). I believe the above can be accomplished using a (licensed) ESRI java api. Can it be achieved easily in GeoTools or any other open source libraries, again ideally usable as a java api and not the command line.

2

First you need to download the NTv2 file you need (e.g. from your national mapping agency), you then need to save the .gsb file in src/main/resources/org/geotools/referencing/factory/gridshift and proceed as normal. If you need a custom transform there are some examples in the GeoServer documentation.

For example this program:

import org.geotools.referencing.CRS;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.operation.MathTransform;

public class OSTN02 {

  public static void main(String[] args) throws NoSuchAuthorityCodeException, FactoryException  {
    MathTransform transform = CRS.findMathTransform(CRS.decode("epsg:4326"), CRS.decode("epsg:27700"));
    System.out.println(transform);
  }

}

Initially outputs:

CONCAT_MT[PARAM_MT["Affine", 
    PARAMETER["num_row", 3], 
    PARAMETER["num_col", 3], 
    PARAMETER["elt_0_0", 0.0], 
    PARAMETER["elt_0_1", 1.0], 
    PARAMETER["elt_1_0", 1.0], 
    PARAMETER["elt_1_1", 0.0]], 
  PARAM_MT["Ellipsoid_To_Geocentric", 
    PARAMETER["dim", 2], 
    PARAMETER["semi_major", 6378137.0], 
    PARAMETER["semi_minor", 6356752.314245179]], 
  PARAM_MT["Position Vector transformation (geog2D domain)", 
    PARAMETER["dx", -446.45598741153583], 
    PARAMETER["dy", 125.1609926805404], 
    PARAMETER["dz", -542.071732141031], 
    PARAMETER["ex", -0.1499999999990687], 
    PARAMETER["ey", -0.24699999999846645], 
    PARAMETER["ez", -0.841999999994772], 
    PARAMETER["ppm", 20.48940738963445]], 
  PARAM_MT["Geocentric_To_Ellipsoid", 
    PARAMETER["dim", 2], 
    PARAMETER["semi_major", 6377563.396], 
    PARAMETER["semi_minor", 6356256.909237285]], 
  PARAM_MT["Transverse_Mercator", 
    PARAMETER["semi_major", 6377563.396], 
    PARAMETER["semi_minor", 6356256.909237285], 
    PARAMETER["central_meridian", -2.0], 
    PARAMETER["latitude_of_origin", 48.99999999999999], 
    PARAMETER["scale_factor", 0.9996012717], 
    PARAMETER["false_easting", 400000.0], 
    PARAMETER["false_northing", -100000.0]]]

but with the grid file provided gives:

CONCAT_MT[PARAM_MT["Affine", 
    PARAMETER["num_row", 3], 
    PARAMETER["num_col", 3], 
    PARAMETER["elt_0_0", 0.0], 
    PARAMETER["elt_0_1", 1.0], 
    PARAMETER["elt_1_0", 1.0], 
    PARAMETER["elt_1_1", 0.0]], 
  INVERSE_MT[PARAM_MT["NTv2", 
      PARAMETER["Latitude and longitude difference file", "OSTN02_NTv2.gsb"]]], 
  PARAM_MT["Transverse_Mercator", 
    PARAMETER["semi_major", 6377563.396], 
    PARAMETER["semi_minor", 6356256.909237285], 
    PARAMETER["central_meridian", -2.0], 
    PARAMETER["latitude_of_origin", 48.99999999999999], 
    PARAMETER["scale_factor", 0.9996012717], 
    PARAMETER["false_easting", 400000.0], 
    PARAMETER["false_northing", -100000.0]]]
  • Hi Ian, Thanks for the speedy reply. So am I right in saying that these gridshift files are a more accurate transformation between two different coordinate systems from the default? What we need is to provide the client with the choice of which transformation to use, they have operations globally and 'my clients clients' all specify different transformations. – KieronFlynn Feb 26 at 16:54
  • The closest I have got is to create a transform via WKT. So something like this: DefaultMathTransformFactory defaultTrans = new DefaultMathTransformFactory() String myCustomTransformWkt = “CONCAT_MT etc…..”; MathTransForm myCustomTransform = defaultTrans.createFromWkt(myCustomTransformWkt ); – KieronFlynn Feb 26 at 16:54
  • For any specific EPSG code (e.g. EPSG:27700) you can specify a grid file and that will become the new default transform for that projection. So provided you don't have some clients in the UK who want low accuracy and some who want high you should be ok. – Ian Turton Feb 26 at 17:16
  • Ian, OP says that there will be worldwide customers. It's possible that some will not have NTv2 file for their areas of interest. – mkennedy Feb 26 at 18:47
  • There are a lot of NTv2 files (see the GeoServer docs for the list). GeoTools also supports NADCOM Or allows you to specify a custom transform though I've never needed to try either of the 2nd two. – Ian Turton Feb 26 at 19:59

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.