2

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)));)

  • 1
    Please Edit the question to be less opinion-based and more problem-oriented. You need to include crucial information -- the projection of the basemap -- because the answer to "Why is my geodetic circle elongated on a Web Mercator map" is "Because it's Web Mercator". – Vince Jan 20 '18 at 14:14
  • 1
    Your code generates the circle in longitude/latidude units. You expect wrong that 10*0.009 degrees is about 10 km in both N-S and E-W directions when you location is at latitude of 40 degrees N. Just check what the E-W distance would be as kilometers at 80 degrees N. Nothing weird at all. – user30184 Jan 20 '18 at 16:52
  • You still haven't stated what basemap your graphic uses. – Vince Jan 20 '18 at 16:54
  • @Vince I used darrinward.com/lat-long – user3529850 Jan 20 '18 at 17:04
  • 1
    Please edit the question to clarify it. It's not fair to those who would answer to need to mine the comments for critical information. – Vince Jan 20 '18 at 17:57
4

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);
}
2

This essentially comes down to a choice as to how accurate you need your circle to be versus how much effort you want to expend calculating the circles.

The reason you need to make this choice is that the Earth is spherical and you want to draw your map on a flat screen (or paper). Thus this, and all other maps are a compromise. It is impossible to accurately portray a curved shape on a flat map and preserve its shape and area.

You have chosen a "quick" and "dirty" method to calculate your circle by assuming that lengths are the same in the N-S direction as the W-E direction. This is not the case in your chosen projection (Web Mercator, EPSG:3857) so you end up with an ellipse. This is the smaller ellipse in the picture below.

If you had used the GeoTools code I gave in the other question you refer to then it would have transformed the point into a projection where lengths were the same in both directions, calculated the circle and transformed it back to lat/lon (EPSG:4326). This is the solid circle shown in the picture.

The other dotted ellipse is what you get if you take the average of 10km N-S and E-W and use that distance for a simple buffer.

enter image description here

But if we switch the map to EPSG:4326 (Lat/Lon degrees) we get:

enter image description here

Now the "simple" circles look closer to round and the "real" circle looks elliptical, but they are all enclosing exactly the same points on the map.

  • I think that the problem was in believing that the distances in N-S and W-E directions are the same if EPSG:4326 degrees are converted into meters. EPSG:3857 is almost conformal and circles remain almost round but the size of the circle would be nonsense cartonerd.blogspot.fi/2014/08/web-mercator-and-comparisons.html. – user30184 Jan 22 '18 at 13:40
  • 1
    Your assertions about impossibility misinterpret the facts. It not only is possible to map a spherical circle with perfect accuracy of shape and area, it's easy to do so. No compromise is necessary. What is not possible is to map all shapes on an intrinsically curved surface with perfect metric accuracy. The distinction is important, because it helps us understand what we may reasonably hope to accomplish with a map. – whuber Jan 22 '18 at 18:30
0
double latitude = 40.748754d;
double longitude = -73.985460d;
double diameterInMeters = 20000d; //20km

GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
shapeFactory.setNumPoints(128); // adjustable
shapeFactory.setCentre(new Coordinate(latitude, longitude));

// Length in meters of 1° of latitude = always 111.32 km
shapeFactory.setHeight(diameterInMeters/111320d);

// Length in meters of 1° of longitude = 40075 km * cos( latitude ) / 360
shapeFactory.setWidth(diameterInMeters / (40075000 * Math.cos(Math.toRadians(latitude)) / 360));

Polygon circle = shapeFactory.createEllipse();

result

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.