Geotools: ограничительная рамка для буфера в wgs84
Мне нужна функция Java, которая будет генерировать ограничивающий прямоугольник (прямоугольник) вокруг буфера. Буфер определяется центральной точкой (координата WGS84) и радиусом (в метрах).
Получение ограничительной рамки для буфера в JTS кажется довольно простым:
Point center = ....
Geometry boundingBox = center.buffer(...).getEnvelope();
Это, однако, чисто плоская геометрия. Есть ли способ сделать это, используя систему координат с расстоянием в метрах?
Оптимально с Geotools, но другие решения Java также будут работать...
3 ответа
Хотя вы подошли к этому по-другому, у меня есть другое решение для этого. Результаты будут намного более точными, чем с вашим предложенным решением.
GeometryFactory GEOMETRY_FACTORY = JTSFactoryFinder.getGeometryFactory();
// Remember, order is (longitude, latitude)
Coordinate center = Coordinate(2.29443, 48.85816);
Point point = GEOMETRY_FACTORY.createPoint(center);
// Buffer 50KM around the point, then get the envelope
Envelope envelopeInternal = buffer(point, 50000).getEnvelopeInternal();
// Then you can play with the envelope, e.g.,
double minX = envelopeInternal.getMinX();
double maxX = envelopeInternal.getMaxX();
// The buffer using distanceInMeters
private Geometry buffer(Geometry geometry, double distanceInMeters) throws FactoryException, TransformException {
String code = "AUTO:42001," + geometry.getCentroid().getCoordinate().x + "," + geometry.getCentroid().getCoordinate().y;
CoordinateReferenceSystem auto = CRS.decode(code);
MathTransform toTransform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto);
MathTransform fromTransform = CRS.findMathTransform(auto, DefaultGeographicCRS.WGS84);
Geometry pGeom = JTS.transform(geometry, toTransform);
Geometry pBufferedGeom = pGeom.buffer(distanceInMeters);
return JTS.transform(pBufferedGeom, fromTransform);
}
А вот карта с результатом, буфер в красном, конверт в черном.
Я в конечном итоге с помощью GeodeticCalculator
вручную найти углы коробки. Честно говоря, результаты не очень точные, но это лучшее решение, которое я нашел до сих пор:
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
CoordinateReferenceSystem wgs84 = DefaultGeographicCRS.WGS84;
GeodeticCalculator geodeticCalculator = new GeodeticCalculator(wgs84);
geodeticCalculator.setStartingGeographicPoint(center.getX(), center.getY());
Coordinate[] coordinates = new Coordinate[5];
for (int i = 0; i < 4; i++) {
geodeticCalculator.setDirection(-180 + i * 90 + 45, bufferRadiusMeters * Math.sqrt(2));
Point2D point2D = geodeticCalculator.getDestinationGeographicPoint();
coordinates[i] = new Coordinate(point2D.getX(), point2D.getY());
}
coordinates[4] = coordinates[0];
Polygon box = geometryFactory.createPolygon(coordinates);
Вот простое решение, которое я использовал для генерации координат ограничивающего прямоугольника, который я использую с GeoNames citieJSON API для получения больших городов поблизости от десятичной координаты GPS.
Это метод Java из моего репозитория GitHub: FusionTableModifyJava
У меня было десятичное местоположение GPS, и мне нужно было найти самый большой город / штат "рядом" с этим местоположением. Мне нужно было относительно точную ограничивающую рамку, чтобы перейти на веб-сервис cityJSON GeoNames, чтобы вернуть самый большой город в этой ограничительной рамке. Я передаю местоположение и интересующий меня "радиус" (в км), и он возвращает десятичные координаты севера, юга, востока и запада, необходимые для передачи в города JSON.
(Я нашел эти ресурсы полезными для моих исследований:
Рассчитать расстояние, направление и многое другое между точками широты и долготы.
Это не супер точно, но достаточно точно для того, что я использовал для:
// Compute bounding Box coordinates for use with Geonames API.
class BoundingBox
{
public double north, south, east, west;
public BoundingBox(String location, float km)
{
//System.out.println(location + " : "+ km);
String[] parts = location.replaceAll("\\s","").split(","); //remove spaces and split on ,
double lat = Double.parseDouble(parts[0]);
double lng = Double.parseDouble(parts[1]);
double adjust = .008983112; // 1km in degrees at equator.
//adjust = 0.008983152770714983; // 1km in degrees at equator.
//System.out.println("deg: "+(1.0/40075.017)*360.0);
north = lat + ( km * adjust);
south = lat - ( km * adjust);
double lngRatio = 1/Math.cos(Math.toRadians(lat)); //ratio for lng size
//System.out.println("lngRatio: "+lngRatio);
east = lng + (km * adjust) * lngRatio;
west = lng - (km * adjust) * lngRatio;
}
}