[GIS] JTS GeometricShapeFactory generate an ellipse properly

coordinate systemdistancegeotoolsjavajts-topology-suite

This is what use to get a circle:

GeometricShapeFactory shape = new GeometricShapeFactory(gf);
        shape.setCentre(new Coordinate(40.748754,-73.985460));//Empire Sate Building
        shape.setSize(2* (10*0.009));//expect 10km radius
        shape.setNumPoints(64);
        final Polygon circle = shape.createEllipse();//createCircle deprecated

What I get is a weird ellipse. I know that closer to the equator we get 'more perfect' circle but still, is it valid circle for radius of 10km with ESB as a center point ?

ellipse generated by jts over nyc

Reading Dr. Ian Turton posts, github repo, and other great materials he shares, I know that I can use geotools and do that differently but I would like to stick with that approach.

EDITED:

I am writting an application. In MySQL I store malls with their location (spatial type Point). What I want to do is to get malls from db that are in a certain circle (via ORM). In order to do that I have to create a Polygon(circle, linearring) in which orm will look. And Instead of using complicated calculations (and additional library). I thought I can use GeometricShapeFactory from jts lib I am already using. But because I am less than beginner what it comes to these things, all I wanted to ask, is whether or not the vertical ellipse generated by jts is valid for my purposes or not ?

I am using google maps (as basemap).

My question:
Based on the fact that my ellipse is just wrong (considering given radius it should be a perfect circle – @whuber comment), how can I generate a proper Polygon(circle, linearring) based on radius and center point ? (I am going to use it in hibernate-spatial: (...).add(SpatialRestrictions.within(Mall.LOCATION, getCircle(centerPoint, 10)));)

Best Answer

My first approach was giving me wrong results (wrong circle - a vertically elongated ellipse). It is not the right one because (to quote @whuber):

"Because Mercator projections are conformal, a small circle (and 10 km radius is very small compared to the globe) should appear on the map as a circle, period".

After @user30184 help/comment/suggestion, I think I got something, that can be called an answer. Snippet about conversion from geogrpahic to projected coordiante system is taken from here. This code gives me a perfect circle over NYC:

final GeometricShapeFactory shape = new GeometricShapeFactory(new GeometryFactory());//INFO :jts lib
final PointWrapper circleCenterPoint = getCircleCenterPoint();

final Coordinate centreInUTM = new Coordinate(projectedToGeographic(circleCenterPoint.getLatitude(),
                                                                    circleCenterPoint.getLongitude()));
shape.setCentre(centreInUTM);
shape.setSize(2 * getRadiusInMeters());
shape.setNumPoints(64);

//WGS 1984 is a geographic coordinate system, and UTM is a projected coordinate system
Polygon polygon = new GeometryFactory().createPolygon(Arrays.stream(shape.createEllipse().getCoordinates())
                                                              .map(c -> geographicToProjected(c.getOrdinate(X),
                                                                                              c.getOrdinate(Y)))
                                                              .toArray(Coordinate[]::new));

criteria.add(SpatialRestrictions.within(Mall.LOCATION, polygon));//INFO :hibernate spatial

private Coordinate projectedToGeographic(double latitude, double longitude) {

    LatLong latlong = LatLong.valueOf(latitude, longitude, NonSI.DEGREE_ANGLE);

    UTM utm = UTM.latLongToUtm(latlong, ReferenceEllipsoid.WGS84); //INFO :jscience lib

    double cX = utm.getCoordinates()[0];
    double cY = utm.getCoordinates()[1];

    return new Coordinate(cX, cY);
}

private Coordinate geographicToProjected(double easting, double northing) {

    UTM utm = UTM.valueOf(18, 'T', easting, northing, METRE);//INFO :18T UTM for NYC
    CoordinatesConverter<UTM, LatLong> utmToLatLong = UTM.CRS.getConverterTo(LatLong.CRS);
    LatLong latLong = utmToLatLong.convert(utm);

    double cX = latLong.getCoordinates()[0];
    double cY = latLong.getCoordinates()[1];

    return new Coordinate(cX, cY);
}
Related Question