I am using Geotools Vector Grid on a FeatureSource (shapefile) that been projected to "AUTO:42001". Units for the map are then in one meter increments. When the FeatureSource is a large country (like India) and the grid size is set to 10km it can take around 10 minutes to generate a grid covering the country. If I set the grid size smaller the generation time can be even larger (I tried a 1km grid and it did not complete when I left it running overnight).
Is this length of time typical for the Vector Grid, or am I doing something wrong?
Is there any way to speed up the generation of the grid?
My source data is the "ne_50m_admin_0_countries.shp" file from https://www.naturalearthdata.com/downloads/50m-cultural-vectors/50m-admin-0-countries-2/
I read the file in and select the country I want using a Query, convert to the local project and the run the GridBuilder.
File file = new File("./ne_50m_admin_0_countries.shp");
FileDataStore dataStore = FileDataStoreFinder.getDataStore(file);
SimpleFeatureSource worldMapSource = dataStore.getFeatureSource();
// Select India
Filter filter = CQL.toFilter("NAME = 'India'");
Query queryIndia = new Query(worldMapSource.getSchema().getTypeName(), filter);
FeatureCollection<SimpleFeatureType, SimpleFeature> collectionIndia = worldMapSource.getFeatures(queryIndia);
SimpleFeatureSource indiaSource = DataUtilities.source(collectionIndia);
// Project india map to local projection
SimpleFeatureSource india_LOCAL = GeoProjectionHelper.convertToLocalProjection(indiaSource);
// Set the grid size (WGS84 1.0 = 1 degree ; AUTO Local 1.0 = 1 meter) and create a bounding envelope
// that is neatly aligned with the grid size
double squareWidth = 10000.0; // 10km (10km ~ 10min to generate)
SimpleFeatureSource indiaGrid_LOCAL = GridBuilder.getIntersectingGrid(india_LOCAL, squareWidth);
public class GridBuilder {
public static SimpleFeatureSource getIntersectingGrid(SimpleFeatureSource featureSource, double squareWidth) throws IOException {
ReferencedEnvelope gridBounds = Envelopes.expandToInclude( featureSource.getBounds(), squareWidth);
// Create a feature type
SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
tb.setName("grid");
tb.add(
GridFeatureBuilder.DEFAULT_GEOMETRY_ATTRIBUTE_NAME,
Polygon.class,
gridBounds.getCoordinateReferenceSystem());
tb.add("id", Integer.class);
SimpleFeatureType TYPE = tb.buildFeatureType();
// Build the grid the custom feature builder class
GridFeatureBuilder builder = new IntersectionBuilder(TYPE, featureSource);
return Grids.createSquareGrid(gridBounds, squareWidth, -1, builder);
}
}
public class IntersectionBuilder extends GridFeatureBuilder {
final FilterFactory2 ff2 = CommonFactoryFinder.getFilterFactory2();
final GeometryFactory gf = JTSFactoryFinder.getGeometryFactory();
final SimpleFeatureSource source;
int id = 0;
public IntersectionBuilder(SimpleFeatureType type, SimpleFeatureSource source) {
super(type);
this.source = source;
}
public void setAttributes(GridElement el, Map<String, Object> attributes) {
attributes.put("id", ++id);
}
@Override
public boolean getCreateFeature(GridElement el) {
// filter based on grid element geometry
Filter filter = ff2.intersects(ff2.property("the_geom"), ff2.literal(el.toGeometry()));
boolean result = false;
try {
result = !source.getFeatures(filter).isEmpty();
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
return result;
}
}
public class GeoProjectionHelper {
public static SimpleFeatureSource convertToLocalProjection(SimpleFeatureSource inputFeatureSource) throws IOException {
// extract the original CRS
CoordinateReferenceSystem origCRS = inputFeatureSource.getFeatures().getSchema().getCoordinateReferenceSystem();
// find centre coordinate of input
Coordinate inputCentre = inputFeatureSource.getBounds().centre();
// find local projection
CoordinateReferenceSystem auto = origCRS;
SimpleFeatureCollection outputFeatureCollection = inputFeatureSource.getFeatures();
if (!(origCRS instanceof ProjectedCRS)) {
String code = "AUTO:42001," + inputCentre.x + "," + inputCentre.y;
try {
auto = CRS.decode(code);
System.out.println(auto.toString());
} catch (FactoryException e) {
e.printStackTrace();
}
outputFeatureCollection = new ReprojectingFeatureCollection(inputFeatureSource.getFeatures(), auto);
}
// wrap back to SimpleFeatureSource
return DataUtilities.source( outputFeatureCollection );
}