如何使用 GeoTools 创建具有纬度、经度和半径的圆?

How do I create a circle with latitude, longitude and radius with GeoTools?

现在我有:

Polygon circle = geometryBuilder.circle(
myLong,
myLat, 
radiusInMeters, 10);

它创建了(lat=28.456306,long=-16.292034 和 radius=500)一个具有巨大纬度和经度的废话多边形,例如:

POLYGON ((483.678055 28.482505000000003, 388.1865521874737 -265.4101211462366, 138.1865521874737 -447.04575314757676, -170.8304421874737 -447.0457531475768, -420.8304421874737 -265.41012114623663, -516.321945 28.482504999999943, -420.83044218747375 322.3751311462365, -170.8304421874738 504.01076314757677, 138.18655218747358 504.0107631475768, 388.18655218747364 322.3751311462367, 483.678055 28.482505000000003))

我希望在我提供的中心点附近有十对经纬度坐标。

任何帮助都会更有帮助。提前致谢!

编辑

除了@iant 的回答之外,我还必须创建一个 Point 作为 Feature

//build the type
SimpleFeatureType TYPE = null;
try {
    TYPE = DataUtilities.createType("", "Location", "locations:Point:srid=4326," + "id:Integer" // a
            // number
            // attribute
            );
} catch (Exception e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}

SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
com.vividsolutions.jts.geom.Point point = geometryFactory.createPoint(
        new Coordinate(
                currentDevicePosition.getLongitude(), 
                currentDevicePosition.getLatitude()
                )
        );
featureBuilder.add(point);
SimpleFeature feature = featureBuilder.buildFeature( "fid.1" ); // build the 1st feature

如 iant 的 Gist 中所述:https://gitlab.com/snippets/17558 and here: http://docs.geotools.org/, oh, and also I was missing a dependency as explained here SchemaException in java

有两种解决方法:

  1. 将以米为单位的半径转换为度数,并将问题视为平面问题

  2. 将 lat/lon 点转换为米,计算局部平面投影中的圆并重新投影回 lat/lon。

对于 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提供了一个"pseudo"投影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();
      }

    }

所以现在 pGeom 是以米为单位的点。缓冲现在很容易

  Geometry out = bufferFeature(pGeom, distance.doubleValue(SI.METER)); 

然后我们使用我们之前查找的反向变换投影回 WGS84 (lat/lon):

  retGeom = JTS.transform(out, fromTransform); 

然后有一些混乱来更改要素类型以反映我们返回的是多边形而不是点的事实。完整代码在这个 gist 中。

当我 运行 它时,我得到以下输出:

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))
    double latitude = 40.689234d;
    double longitude = -74.044598d;
    double diameterInMeters = 2000d; //2km

    GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
    shapeFactory.setNumPoints(64); // adjustable
    shapeFactory.setCentre(new Coordinate(latitude, longitude));
    // Length in meters of 1° of latitude = always 111.32 km
    shapeFactory.setWidth(diameterInMeters/111320d);
    // Length in meters of 1° of longitude = 40075 km * cos( latitude ) / 360
    shapeFactory.setHeight(diameterInMeters / (40075000 * Math.cos(Math.toRadians(latitude)) / 360));

    Polygon circle = shapeFactory.createEllipse();

GeometricShapeFactory shapeFactory = new GeometricShapeFactory(); shapeFactory.setNumPoints(64); adjustableshapeFactory.setCentre(新坐标(经纬度)); // 1°的长度(以米为单位)