views:

410

answers:

3

So I'm writing a Java app, and I've got an ESRI Shapefile which contains the borders of all the U.S. states. What I need is to be able to determine whether any given lat/lon point is within a specified distance from ANY state border line - i.e., I will not be specifying a particular border line, just need to see whether the point is close to any of them.

The solution does NOT have to be very precise at all; e.g. I don't need to be dealing with measuring perpendicular to the border, or whatever. Just checking to see if going X meters north, south, east or west would result in crossing a border would be more than sufficient. The solution DOES have to be computationally efficient, as I'll be performing a huge number of these calculations.

I'm planning to use the GeoTools library (though if there's a simpler option, I'm all for it) with the Shapefile plugin. What I don't really understand is: Once I've got the shapefile loaded into memory, how do I check to see whether I'm near a border?

Thanks! -Dan

+1  A: 

If you can somehow extract the shape for each state from the shapefile, create an envelope that is x meters on a side (with your point in the exact center) and see if those two shapes intersect, you'll be able to answer the question.

If I was using ESRI's ArcGIS Engine, I'd use an ISpatialFilter with the point defined in the geometry (possibly with a buffer) and query that against the States shapefile. Any result(s) returned would indicate that the point was near a state. I'm unfamiliar with GeoTools and, while browsing through their documentation, I didn't come across anything that looked like that type of functionality, but they must have it. You may want to look for examples of how to use GeoTools to perform spatial queries on shapefiles.

Michael Todd
+4  A: 

Assuming JTS for Geometry which is what is included in GeoTools:

public boolean pointIsClose( File file, Point targetPoint,double distance) {


  boolean ret = false;
  Map connect = new HashMap();
  connect.put("url", file.toURL());
  DataStore dataStore = DataStoreFinder.getDataStore(connect);


  FeatureSource featureSource = dataStore.getFeatureSource(typeName);
  FeatureCollection collection = featureSource.getFeatures();
  FeatureIterator iterator = collection.features();



  try {
    while (iterator.hasNext()) {
      Feature feature = iterator.next();
      Geometry sourceGeometry = feature.getDefaultGeometry();
      ret= sourceGeometry.isWithinDistance(targetPoint, distance );
    }
  } finally {
    iterator.close();
  }
  return ret;
}

The double number will have to come from the CRS which will define the units in which the calculation will be performed.

These are the geotools imports:

import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.FeatureSource;
import org.geotools.feature.Feature;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
Clint
+1  A: 

If you just want to know if point A is within X meters of a state border and X is constant and you don't care which border it is, you can precompute the negative space as a series of boxes. Then all you have to do is a contains check for each of those boxes against the point. If none of them match, you're not in the negative space.

Jherico