Java GeoTools: how to find distance from a point to closest polygon in shape file

╄→尐↘猪︶ㄣ 提交于 2019-12-24 06:49:23

问题


So I have a shp-file containing a bunch of polygons. In this case, a polygon is a body of in-land water (like lakes and that kind of stuff).

My system is tracking a moving object, so in order to determine what this object is, I would like to see if this object is in water or on land AND how far it is to NEAREST shore (yes, both if it's in or out of water). I will take a sample point from the object once in a while and test it.

The system is written in Java, and I have imported GeoTools snapshot 17. But if other utils is easier to use, there is no requirements to use this.

To test if the point is IN water (that is, inside a polygon), this methods works:

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();
        }
    }
}

Now the questions:

1) If the point is NOT in a polygon, how do I find the nearest polygon in the source (being a SimpleFeatureSource)?

2) How do I find the distance to the edge of the polygon that is closest?

Any help would be highly appreciated! Especially code examples - I'm kind of rusty on math and geometry.

Thank you.


回答1:


The easiest answer is to use a SpatialIndexFeatureCollection to do the heavy lifting for you, it will find the nearest polygon, then you can check if you are inside or outside.

So a simple class like:

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;
  }
}

Can be called using some code like:

  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);
        }

      }
    }
  }


来源:https://stackoverflow.com/questions/44045598/java-geotools-how-to-find-distance-from-a-point-to-closest-polygon-in-shape-fil

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!