Search code examples
javageotools

Getting coordinates in GeoTools


Thanks to Reading ESRI shapefiles from the InputStream in Java I can read my shapefiles and access every GeometryAttribute, but I also need to convert it coordinates in long/lat format, it might be 40°44′55″N, 73 59 11W or best 40.7486, -73.9864.

example of my WKT is

GeometryAttribute sourceGeometry = feature.getDefaultGeometryProperty();
CoordinateReferenceSystem example = sourceGeometry.getDescriptor().getCoordinateReferenceSystem();
String wkt = example.toWKT();

PROJCS["ETRS_1989_Poland_CS92", 
  GEOGCS["GCS_ETRS_1989", 
    DATUM["D_ETRS_1989", 
      SPHEROID["GRS_1980", 6378137.0, 298.257222101]], 
    PRIMEM["Greenwich", 0.0], 
    UNIT["degree", 0.017453292519943295], 
    AXIS["Longitude", EAST], 
    AXIS["Latitude", NORTH]], 
  PROJECTION["Transverse_Mercator"], 
  PARAMETER["central_meridian", 19.0], 
  PARAMETER["latitude_of_origin", 0.0], 
  PARAMETER["scale_factor", 0.9993], 
  PARAMETER["false_easting", 500000.0], 
  PARAMETER["false_northing", -5300000.0], 
  UNIT["m", 1.0], 
  AXIS["x", EAST], 
  AXIS["y", NORTH]]

Solution

  • GeoTools has a number of ways to reproject your geometries depending on what you want to do after your reproject them.

    The simplest is to use a ReprojectingFeatureCollection to provide you with a new collection in your required projection (in this case EPSG:4326) or you can create a JTS.transform and use that on individual geometries.

    ReprojectingFeatureCollection rfc = new ReprojectingFeatureCollection(features, CRS.decode("epsg:4326"));
    

    or

    CoordinateReferenceSystem source = sourceGeometry.getDescriptor().getCoordinateReferenceSystem();
    CoordinateReferenceSystem target = CRS.decode("epsg:4326");
    MathTransform transform = CRS.findMathTransform(source, target, lenient);
    Geometry geometry2 = JTS.transform(geometry, transform);
    

    Printing the coordinates of those new geometries will give you decimal degrees (3.234545) if you need DMS (1°3'3") then a class like this will help:

    public class DMSToDegrees {
      static public double convert(int degrees, int minutes, double seconds) {
        //to allow for negative (i.e. W or S) values note the sign of the degrees
        float sign = Math.signum(degrees);
        if(sign==0.0) {
          //we'll consider 0 to be positive
          sign = 1.0f;
        }
        //seconds are 1/60th of a minute so express as a fractional minute
        double dmins = minutes+seconds/60.0;
        //minutes are 1/60th of a degree so express as a fractional degree
        double deg = Math.abs(degrees) + dmins/60.0;
        // put the sign back on the result
        return sign*deg;
      }
      static public double[] reverse(double degrees){
      //to allow for negative (i.e. W or S) values note the sign of the degrees
        double sign = Math.signum(degrees);
        if(sign==0.0) {
          //we'll consider 0 to be positive
          sign = 1.0f;
        }
        double[] ret = new double[3];
        degrees = Math.abs(degrees);
        ret[0] = Math.floor(degrees);
        double mins = degrees - ret[0];
        ret[1] = Math.floor(mins*60);
        ret[2] = ((mins*60 - ret[1]))*60;
        ret[0]*=sign;
        return ret;
      }
    }