Java GeoTools:如何在形状文件中查找点到最近多边形的距离
Java GeoTools: how to find distance from a point to closest polygon in shape file
所以我有一个包含一堆多边形的 shp 文件。在这种情况下,多边形是一片内陆水域(如湖泊和类似的东西)。
我的系统正在跟踪一个移动的物体,所以为了确定这个物体是什么,我想看看这个物体是在水中还是在陆地上,以及它离最近的海岸有多远(是的,如果它在水里或水外)。我会时不时从物体上取一个样本点来测试一下。
系统是Java写的,我导入了GeoTools snapshot 17。不过如果其他的utils比较好用,就没有要求用这个了。
要测试该点是否在水中(即在多边形内),此方法有效:
private void findPolygonsForPoint(Coordinate point) {
Filter filter = null;
SimpleFeatureIterator iterator = null;
try {
filter = CQL.toFilter("CONTAINS(the_geom, POINT(" + point.x + " " + point.y + "))");
SimpleFeatureCollection collection = source.getFeatures(filter);
if(collection.size() < 1) {
System.out.println(coordinate2String(point) + " is NOT in a polygon");
} else {
System.out.println(coordinate2String(point) + " IS in a polygon");
insidePolygon++;
iterator = collection.features();
while(iterator.hasNext()) {
SimpleFeature feature = iterator.next();
//find nearest edge of the polygon
}
}
} catch(CQLException e) {
aLog.error("", e);
} catch(IOException e) {
aLog.error("", e);
} finally {
if(iterator != null) {
iterator.close();
}
}
}
现在问题:
1) 如果该点不在多边形中,我如何找到源中最近的多边形(作为 SimpleFeatureSource)?
2) 如何找到到最近的多边形边缘的距离?
非常感谢任何帮助!特别是代码示例 - 我对数学和几何有点生疏。
谢谢。
最简单的答案是使用 SpatialIndexFeatureCollection
为您完成繁重的工作,它会找到最近的多边形,然后您可以检查您是在内部还是外部。
如此简单的 class 比如:
public class NearestPolygon {
private static FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
private static GeometryFactory gf = new GeometryFactory();
private SpatialIndexFeatureCollection index;
private SimpleFeature lastMatched;
public NearestPolygon(SimpleFeatureCollection features) {
index = new SpatialIndexFeatureCollection(features.getSchema());
index.addAll(features);
}
public Point findNearestPolygon(Point p) {
final double MAX_SEARCH_DISTANCE = index.getBounds().getSpan(0);
Coordinate coordinate = p.getCoordinate();
ReferencedEnvelope search = new ReferencedEnvelope(new Envelope(coordinate),
index.getSchema().getCoordinateReferenceSystem());
search.expandBy(MAX_SEARCH_DISTANCE);
BBOX bbox = ff.bbox(ff.property(index.getSchema().getGeometryDescriptor().getName()), (BoundingBox) search);
SimpleFeatureCollection candidates = index.subCollection(bbox);
double minDist = MAX_SEARCH_DISTANCE + 1.0e-6;
Coordinate minDistPoint = null;
try (SimpleFeatureIterator itr = candidates.features()) {
while (itr.hasNext()) {
SimpleFeature feature = itr.next();
LocationIndexedLine line = new LocationIndexedLine(((MultiPolygon) feature.getDefaultGeometry()).getBoundary());
LinearLocation here = line.project(coordinate);
Coordinate point = line.extractPoint(here);
double dist = point.distance(coordinate);
if (dist < minDist) {
minDist = dist;
minDistPoint = point;
lastMatched = feature;
}
}
}
Point ret = null;
if (minDistPoint == null) {
ret = gf.createPoint((Coordinate) null);
} else {
ret = gf.createPoint(minDistPoint);
}
return ret;
}
public SimpleFeature getLastMatched() {
return lastMatched;
}
}
可以使用如下代码调用:
public static void main(String[] args) throws IOException {
String lakes = "/data/natural_earth/10m_physical/ne_10m_lakes.shp";
HashMap<String, Object> params = new HashMap<>();
params.put("url", DataUtilities.fileToURL(new File(lakes)));
DataStore ds = DataStoreFinder.getDataStore(params);
String name = ds.getTypeNames()[0];
SimpleFeatureSource source = ds.getFeatureSource(name);
SimpleFeatureCollection features = source.getFeatures();
NearestPolygon polyFinder = new NearestPolygon(features);
for (int i = 0; i < 100; i++) {
Point p = GenerateRandomData.createRandomPoint();
Point pointOnLine = polyFinder.findNearestPolygon(p);
if (!pointOnLine.isEmpty()) {
System.out.println(i+" At " + pointOnLine + " is closest to " + p);
SimpleFeature lastMatched2 = polyFinder.getLastMatched();
String attribute = (String) lastMatched2.getAttribute("name");
if(attribute.isEmpty()) {
attribute = (String) lastMatched2.getAttribute("note");
}
if (((Geometry) (lastMatched2.getDefaultGeometry())).contains(p)) {
System.out.println("is in lake " + attribute);
} else {
System.out.println("nearest lake is " + attribute);
}
}
}
}
所以我有一个包含一堆多边形的 shp 文件。在这种情况下,多边形是一片内陆水域(如湖泊和类似的东西)。
我的系统正在跟踪一个移动的物体,所以为了确定这个物体是什么,我想看看这个物体是在水中还是在陆地上,以及它离最近的海岸有多远(是的,如果它在水里或水外)。我会时不时从物体上取一个样本点来测试一下。
系统是Java写的,我导入了GeoTools snapshot 17。不过如果其他的utils比较好用,就没有要求用这个了。
要测试该点是否在水中(即在多边形内),此方法有效:
private void findPolygonsForPoint(Coordinate point) {
Filter filter = null;
SimpleFeatureIterator iterator = null;
try {
filter = CQL.toFilter("CONTAINS(the_geom, POINT(" + point.x + " " + point.y + "))");
SimpleFeatureCollection collection = source.getFeatures(filter);
if(collection.size() < 1) {
System.out.println(coordinate2String(point) + " is NOT in a polygon");
} else {
System.out.println(coordinate2String(point) + " IS in a polygon");
insidePolygon++;
iterator = collection.features();
while(iterator.hasNext()) {
SimpleFeature feature = iterator.next();
//find nearest edge of the polygon
}
}
} catch(CQLException e) {
aLog.error("", e);
} catch(IOException e) {
aLog.error("", e);
} finally {
if(iterator != null) {
iterator.close();
}
}
}
现在问题:
1) 如果该点不在多边形中,我如何找到源中最近的多边形(作为 SimpleFeatureSource)?
2) 如何找到到最近的多边形边缘的距离?
非常感谢任何帮助!特别是代码示例 - 我对数学和几何有点生疏。
谢谢。
最简单的答案是使用 SpatialIndexFeatureCollection
为您完成繁重的工作,它会找到最近的多边形,然后您可以检查您是在内部还是外部。
如此简单的 class 比如:
public class NearestPolygon {
private static FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
private static GeometryFactory gf = new GeometryFactory();
private SpatialIndexFeatureCollection index;
private SimpleFeature lastMatched;
public NearestPolygon(SimpleFeatureCollection features) {
index = new SpatialIndexFeatureCollection(features.getSchema());
index.addAll(features);
}
public Point findNearestPolygon(Point p) {
final double MAX_SEARCH_DISTANCE = index.getBounds().getSpan(0);
Coordinate coordinate = p.getCoordinate();
ReferencedEnvelope search = new ReferencedEnvelope(new Envelope(coordinate),
index.getSchema().getCoordinateReferenceSystem());
search.expandBy(MAX_SEARCH_DISTANCE);
BBOX bbox = ff.bbox(ff.property(index.getSchema().getGeometryDescriptor().getName()), (BoundingBox) search);
SimpleFeatureCollection candidates = index.subCollection(bbox);
double minDist = MAX_SEARCH_DISTANCE + 1.0e-6;
Coordinate minDistPoint = null;
try (SimpleFeatureIterator itr = candidates.features()) {
while (itr.hasNext()) {
SimpleFeature feature = itr.next();
LocationIndexedLine line = new LocationIndexedLine(((MultiPolygon) feature.getDefaultGeometry()).getBoundary());
LinearLocation here = line.project(coordinate);
Coordinate point = line.extractPoint(here);
double dist = point.distance(coordinate);
if (dist < minDist) {
minDist = dist;
minDistPoint = point;
lastMatched = feature;
}
}
}
Point ret = null;
if (minDistPoint == null) {
ret = gf.createPoint((Coordinate) null);
} else {
ret = gf.createPoint(minDistPoint);
}
return ret;
}
public SimpleFeature getLastMatched() {
return lastMatched;
}
}
可以使用如下代码调用:
public static void main(String[] args) throws IOException {
String lakes = "/data/natural_earth/10m_physical/ne_10m_lakes.shp";
HashMap<String, Object> params = new HashMap<>();
params.put("url", DataUtilities.fileToURL(new File(lakes)));
DataStore ds = DataStoreFinder.getDataStore(params);
String name = ds.getTypeNames()[0];
SimpleFeatureSource source = ds.getFeatureSource(name);
SimpleFeatureCollection features = source.getFeatures();
NearestPolygon polyFinder = new NearestPolygon(features);
for (int i = 0; i < 100; i++) {
Point p = GenerateRandomData.createRandomPoint();
Point pointOnLine = polyFinder.findNearestPolygon(p);
if (!pointOnLine.isEmpty()) {
System.out.println(i+" At " + pointOnLine + " is closest to " + p);
SimpleFeature lastMatched2 = polyFinder.getLastMatched();
String attribute = (String) lastMatched2.getAttribute("name");
if(attribute.isEmpty()) {
attribute = (String) lastMatched2.getAttribute("note");
}
if (((Geometry) (lastMatched2.getDefaultGeometry())).contains(p)) {
System.out.println("is in lake " + attribute);
} else {
System.out.println("nearest lake is " + attribute);
}
}
}
}