对此有两种解决方案:
将半径(米)转换为度并将问题视为平面问题
将纬度/经度点转换为米,计算局部平面投影中的圆,然后重新投影回纬度/经度。
对于 1 ,你可以做类似的事情,这对于赤道附近的小半径来说是很好的:
GeodeticCalculator calc = new GeodeticCalculator(DefaultGeographicCRS.WGS84);
calc.setStartingGeographicPoint(point.getX(), point.getY());
calc.setDirection(0.0, 10000);
Point2D p2 = calc.getDestinationGeographicPoint();
calc.setDirection(90.0, 10000);
Point2D p3 = calc.getDestinationGeographicPoint();
double dy = p2.getY() - point.getY();
double dx = p3.getX() - point.getX();
double distance = (dy + dx) / 2.0;
Polygon p1 = (Polygon) point.buffer(distance);
我将展示第二个的一些代码,因为它更通用(即它工作得更好并且半径范围更大)。
首先需要找到本地投影,GeoTools提供了“伪”投影AUTO42001,x,y
这是以 X,Y 为中心的 UTM 投影:
public SimpleFeature bufferFeature(SimpleFeature feature, Measure<Double, Length> distance) {
// extract the geometry
GeometryAttribute gProp = feature.getDefaultGeometryProperty();
CoordinateReferenceSystem origCRS = gProp.getDescriptor().getCoordinateReferenceSystem();
Geometry geom = (Geometry) feature.getDefaultGeometry();
Geometry pGeom = geom;
MathTransform toTransform, fromTransform = null;
// reproject the geometry to a local projection
if (!(origCRS instanceof ProjectedCRS)) {
double x = geom.getCoordinate().x;
double y = geom.getCoordinate().y;
String code = "AUTO:42001," + x + "," + y;
// System.out.println(code);
CoordinateReferenceSystem auto;
try {
auto = CRS.decode(code);
toTransform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto);
fromTransform = CRS.findMathTransform(auto, DefaultGeographicCRS.WGS84);
pGeom = JTS.transform(geom, toTransform);
} catch (MismatchedDimensionException | TransformException | FactoryException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
So now pGeom
是以米为单位的点。缓冲现在很容易
Geometry out = bufferFeature(pGeom, distance.doubleValue(SI.METER));
然后我们使用之前查找的反向变换投影回 WGS84(纬度/经度):
retGeom = JTS.transform(out, fromTransform);
然后,需要稍微修改一下要素类型,以反映我们返回的是多边形而不是点的事实。完整代码在此gist https://gitlab.com/snippets/17558.
当我运行它时,我得到以下输出:
POINT (10.840378413128576 3.4152050343701745)
POLYGON ((10.84937634426605 3.4151876838951822, 10.849200076653755 3.413423962919184, 10.84868480171117 3.4117286878605766, 10.847850322146979 3.4101670058279794, 10.846728706726902 3.4087989300555464, 10.845363057862208 3.407677033830687, 10.843805855306746 3.406844430298736, 10.84211693959797 3.406333115754347, 10.840361212705258 3.4061627400701946, 10.838606144204721 3.4063398515107184, 10.836919178768184 3.4068576449605277, 10.835365144548726 3.4076962232621035, 10.834003762019957 3.408823361646906, 10.832887348980522 3.410195745914279, 10.832058809914859 3.411760636805914, 10.831549986992338 3.4134578966399034, 10.831380436105858 3.4152223003379722, 10.831556675029052 3.416986042039048, 10.832071932633442 3.4186813409639054, 10.832906408849936 3.4202430463705085, 10.834028035422469 3.4216111414662183, 10.835393708241908 3.422733050021835, 10.836950943907517 3.4235656570147763, 10.838639896841123 3.424076965623486, 10.840395659406198 3.4242473268789406, 10.842150756595839 3.4240701947133396, 10.843837739370569 3.4235523773972796, 10.845391776937724 3.4227137757216988, 10.846753148314034 3.4215866180136185, 10.847869537398722 3.4202142214154887, 10.848698043354238 3.4186493270628633, 10.849206829051935 3.4169520731645546, 10.84937634426605 3.4151876838951822))