[GIS] Finding distance in meters between point and path in lat/lon using GeoTools

distancegeotools

I need to find distance in meters between some point with given latitude and longitude and line (on Earth) defined by several points with lat/lon coordinates.

I read these questions:

In the second it is said that this is impossible with JTS and author decided to use some other utility.

If so, could you recommend any other java library for such problems?

In first, code in the accepted answer doesn't work for me, may be because of that I don't understand which transformation I should choose (and point can be on a big distance from the line, so the transformation may produce not accurate results).

My code for testing code from the first question:

GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
    Point spb = geometryFactory.createPoint(new Coordinate(30.3, 59.95));
    Point msk = geometryFactory.createPoint(new Coordinate(37.6167, 55.75));
    Point khabarovsk = geometryFactory.createPoint(new Coordinate(135.0667, 48.4833));

    Point syktyvkar = geometryFactory.createPoint(new Coordinate(50.8167, 61.6667));

    Coordinate[] coords = new Coordinate[] {
            spb.getCoordinate(),
            msk.getCoordinate(),
            khabarovsk.getCoordinate()
    };

    LineString route = geometryFactory.createLineString(coords);
    System.out.println(route.distance(syktyvkar)); //result: 6.881897419667442

    try {
        CoordinateReferenceSystem auto = CRS.decode("AUTO:42001,13.45,52.3");
        MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84,
                auto);
        Geometry g3 = JTS.transform(route, transform);
        Geometry g4 = JTS.transform(syktyvkar, transform);
        System.out.println(g3.distance(g4)); //result: 619842.1091396079
    }
    catch(Exception e) {}
}

The result must be quite close to 170 000 meters.

Best Answer

The code from the previous question does in fact solve this problem once you have explored the issue a bit.

Basically your line doesn't have enough points so it "cuts" the corner across the more localised projection that is used to allow JTS to proceed as if the Earth is flat. This needs one additional line of code:

route = (LineString) Densifier.densify(route, .01);

enter image description here

The brown line is your original 3 point line and the blue line is a densified line (that has points added so it projects properly), shown in a local projection (EPSG:2470). As you can see the distance to the brown line to the point is much shorter than it should be.

So here is some suitably modified code:

public double getDistance(Point point, LineString line) {
double dist = -1.0;
try {
  String code = "AUTO:42001," + point.getX() + "," + point.getY();
  CoordinateReferenceSystem auto = CRS.decode(code);
  // auto = CRS.decode("epsg:2470");
  MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto);
  Geometry g3 = JTS.transform(line, transform);
  Geometry g4 = JTS.transform(point, transform);

  Coordinate[] c = DistanceOp.nearestPoints(g4, g3);

  Coordinate c1 = new Coordinate();
  //System.out.println(c[1].distance(g4.getCoordinate()));
  JTS.transform(c[1], c1, transform.inverse());
  //System.out.println(geometryFactory.createPoint(c1));
  dist = JTS.orthodromicDistance(point.getCoordinate(), c1, DefaultGeographicCRS.WGS84);
} catch (Exception e) {
  e.printStackTrace();
}
return dist;

}

And incase you are wondering about the difference between the "flat distance" (c[1].distance(g4.getCoordinate())) is 760.731km and the "curved distance" (JTS.orthodromicDistance(point.getCoordinate(), c1, DefaultGeographicCRS.WGS84);) is 760.980km. For reference the distance tool in QGIS gives 760.919 km.