如何在 geoTools 中使用 GeometricShapeFactory 在地图上创建一个圆
How to use GeometricShapeFactory in geoTools to create a Circle on map
我目前正在使用以下代码创建 GeoJson 多边形。这给了我一个无效的坏圈...
在本例中 RADIUS = 1609.34
,即 1 英里(米)。
public GeoJsonPolygon createRadiusPolygon( Point point,double RADIUS) {
GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
shapeFactory.setNumPoints(32);
shapeFactory.setCentre(new com.vividsolutions.jts.geom.Coordinate(point.getX(), point.getY()));
shapeFactory.setSize(RADIUS * 2);
com.vividsolutions.jts.geom.Geometry circle = shapeFactory.createCircle();
List<Point> points = new ArrayList<Point>();
for (com.vividsolutions.jts.geom.Coordinate coordinate : circle.getCoordinates()) {
Point lngLatAtl = new Point(coordinate.x, coordinate.y);
points.add(lngLatAtl);
}
Collections.reverse(points);
return new GeoJsonPolygon(points);
}
参考:
http://docs.geotools.org/stable/userguide/library/jts/geometry.html
目前,如果我使用 Point(-73.87,40.84) RADIUS = 1609.34,我会得到以下 link。
https://gist.githubusercontent.com/VanitySoft/56c4ce0f5c1c7e7fe0461ed46fd5ed11/raw/94544750a140d81780ebe9206395a21ab88bb1f7/circle
===SOLVED== 来自@Ian 的回答:
在他的回答中使用方法。 RADIUS 以英里为单位,以获取用于创建 GeoJson 的 Circle。
...
com.vividsolutions.jts.geom.Point jtsPoint = new GeometryFactory().createPoint(new com.vividsolutions.jts.geom.Coordinate(point.getY(), point.getX()));
javax.measure.Measure measure = Measure.valueOf(RADIUS, NonSI.MILE);
com.vividsolutions.jts.geom.Geometry circle = createCircleRadis(measure,CRS.decode("epsg:4326"),jtsPoint );
...
...
您的输出圆是有效的,它恰好超过了地球表面的直径,因此您的 GIS 可能无法绘制它!问题是你不加区别地混合了度数和米,而 GeoTools 不知道你想要它做什么。
您需要在程序中添加有关点的坐标参考系统的一些信息,如果该投影是地理投影(即以度为单位),则将问题转换为以米为单位的投影。
public Geometry bufferPoint(Measure<Double, Length> distance, CoordinateReferenceSystem origCRS, Geometry geom) {
Geometry pGeom = geom;
MathTransform toTransform, fromTransform = null;
// reproject the geometry to a local projection
Unit<Length> unit = distance.getUnit();
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);
unit = SI.METER;
} catch (MismatchedDimensionException | TransformException | FactoryException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
unit = (Unit<Length>) origCRS.getCoordinateSystem().getAxis(0).getUnit();
}
// buffer
Geometry out = pGeom.buffer(distance.doubleValue(unit));
Geometry retGeom = out;
// reproject the geometry to the original projection
if (!(origCRS instanceof ProjectedCRS)) {
try {
retGeom = JTS.transform(out, fromTransform);
} catch (MismatchedDimensionException | TransformException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return retGeom;
}
AUTO:42001,x,y
是一个以米为单位的点 x,y
为中心的特殊投影,它允许我们使用 JTS buffer
方法,它比您正在使用的圆操作更容易。
对于你的输入,这让我在纽约上空看到了一个椭圆,请注意这是预期的,并且是由于在弯曲的地球上使用未投影的 Lat/Lon 坐标造成的扭曲效果。
您可以使用以下方式调用它:
//Measure<Double, Length> dist = Measure.valueOf(50.0, SI.KILOMETER);
Measure<Double, Length> dist = Measure.valueOf(1.0, NonSI.MILE);
GeometryFactory gf = new GeometryFactory();
Point p = gf.createPoint(new Coordinate(-73.87,40.84));
buf.bufferPoint(dist, DefaultGeographicCRS.WGS84, p);
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();
我目前正在使用以下代码创建 GeoJson 多边形。这给了我一个无效的坏圈...
在本例中 RADIUS = 1609.34
,即 1 英里(米)。
public GeoJsonPolygon createRadiusPolygon( Point point,double RADIUS) {
GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
shapeFactory.setNumPoints(32);
shapeFactory.setCentre(new com.vividsolutions.jts.geom.Coordinate(point.getX(), point.getY()));
shapeFactory.setSize(RADIUS * 2);
com.vividsolutions.jts.geom.Geometry circle = shapeFactory.createCircle();
List<Point> points = new ArrayList<Point>();
for (com.vividsolutions.jts.geom.Coordinate coordinate : circle.getCoordinates()) {
Point lngLatAtl = new Point(coordinate.x, coordinate.y);
points.add(lngLatAtl);
}
Collections.reverse(points);
return new GeoJsonPolygon(points);
}
参考: http://docs.geotools.org/stable/userguide/library/jts/geometry.html
目前,如果我使用 Point(-73.87,40.84) RADIUS = 1609.34,我会得到以下 link。 https://gist.githubusercontent.com/VanitySoft/56c4ce0f5c1c7e7fe0461ed46fd5ed11/raw/94544750a140d81780ebe9206395a21ab88bb1f7/circle
===SOLVED== 来自@Ian 的回答: 在他的回答中使用方法。 RADIUS 以英里为单位,以获取用于创建 GeoJson 的 Circle。
...
com.vividsolutions.jts.geom.Point jtsPoint = new GeometryFactory().createPoint(new com.vividsolutions.jts.geom.Coordinate(point.getY(), point.getX()));
javax.measure.Measure measure = Measure.valueOf(RADIUS, NonSI.MILE);
com.vividsolutions.jts.geom.Geometry circle = createCircleRadis(measure,CRS.decode("epsg:4326"),jtsPoint );
...
...
您的输出圆是有效的,它恰好超过了地球表面的直径,因此您的 GIS 可能无法绘制它!问题是你不加区别地混合了度数和米,而 GeoTools 不知道你想要它做什么。
您需要在程序中添加有关点的坐标参考系统的一些信息,如果该投影是地理投影(即以度为单位),则将问题转换为以米为单位的投影。
public Geometry bufferPoint(Measure<Double, Length> distance, CoordinateReferenceSystem origCRS, Geometry geom) {
Geometry pGeom = geom;
MathTransform toTransform, fromTransform = null;
// reproject the geometry to a local projection
Unit<Length> unit = distance.getUnit();
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);
unit = SI.METER;
} catch (MismatchedDimensionException | TransformException | FactoryException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
unit = (Unit<Length>) origCRS.getCoordinateSystem().getAxis(0).getUnit();
}
// buffer
Geometry out = pGeom.buffer(distance.doubleValue(unit));
Geometry retGeom = out;
// reproject the geometry to the original projection
if (!(origCRS instanceof ProjectedCRS)) {
try {
retGeom = JTS.transform(out, fromTransform);
} catch (MismatchedDimensionException | TransformException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return retGeom;
}
AUTO:42001,x,y
是一个以米为单位的点 x,y
为中心的特殊投影,它允许我们使用 JTS buffer
方法,它比您正在使用的圆操作更容易。
对于你的输入,这让我在纽约上空看到了一个椭圆,请注意这是预期的,并且是由于在弯曲的地球上使用未投影的 Lat/Lon 坐标造成的扭曲效果。
您可以使用以下方式调用它:
//Measure<Double, Length> dist = Measure.valueOf(50.0, SI.KILOMETER);
Measure<Double, Length> dist = Measure.valueOf(1.0, NonSI.MILE);
GeometryFactory gf = new GeometryFactory();
Point p = gf.createPoint(new Coordinate(-73.87,40.84));
buf.bufferPoint(dist, DefaultGeographicCRS.WGS84, p);
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();