Skip to content

Commit

Permalink
Create opportunity datasets from GeoJSON
Browse files Browse the repository at this point in the history
Closely mirrors the way Shapefiles are converted into grids. With GeoTools it is quite simple. It's possible to abstract common creation code between the two types but may not be necessary unless more types are added.
  • Loading branch information
trevorgerhardt committed Nov 23, 2023
1 parent 484b53d commit c39100e
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,9 @@ private OpportunityDatasetUploadStatus createOpportunityDataset(Request req, Res
} else if (uploadFormat == FileStorageFormat.SHP) {
LOG.info("Detected opportunity dataset stored as ESRI shapefile.");
pointsets.addAll(createGridsFromShapefile(fileItems, zoom, status));
} else if (uploadFormat == FileStorageFormat.GEOJSON) {
LOG.info("Detected opportunity dataset stored as GeoJSON.");
pointsets.addAll(Grid.fromGeoJson(fileItems.get(0).getInputStream(), zoom, status));
} else if (uploadFormat == FileStorageFormat.CSV) {
LOG.info("Detected opportunity dataset stored as CSV");
// Create a grid even when user has requested a freeform pointset so we have something to visualize.
Expand Down
67 changes: 67 additions & 0 deletions src/main/java/com/conveyal/r5/analyst/Grid.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.Transaction;
import org.geotools.data.geojson.GeoJSONReader;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.geotools.gce.geotiff.GeoTiffWriteParams;
Expand Down Expand Up @@ -753,6 +756,70 @@ public static List<Grid> fromShapefile (File shapefile, int zoom, ProgressListen
return new ArrayList<>(grids.values());
}

/**
* Take an `InputStream` containing GeoJson Features and turn it into an opportunity grid.
*/
public static List<Grid> fromGeoJson (InputStream geoJsonInputStream, int zoom, ProgressListener progressListener)
throws IOException {
GeoJSONReader reader = new GeoJSONReader(geoJsonInputStream);
SimpleFeatureCollection features = reader.getFeatures();
Envelope envelope = features.getBounds();

checkWgsEnvelopeSize(envelope, "Shapefile");
WebMercatorExtents extents = WebMercatorExtents.forWgsEnvelope(envelope, zoom);

int total = features.size();
if (progressListener != null) {
progressListener.setTotalItems(total);
}

AtomicInteger count = new AtomicInteger(0);
HashMap<String, Grid> grids = new HashMap<>();

SimpleFeatureIterator featureIterator = features.features();
while (featureIterator.hasNext()) {
SimpleFeature feature = featureIterator.next();
Geometry geom = (Geometry) feature.getDefaultGeometry();

for (var p : feature.getProperties()) {
var val = p.getValue();

if (!(val instanceof Number)) continue;
double numericVal = ((Number) val).doubleValue();
if (numericVal == 0) continue;

String attributeName = p.getName().getLocalPart();

Grid grid = grids.get(attributeName);
if (grid == null) {
grid = new Grid(extents);
grid.name = attributeName;
grids.put(attributeName, grid);
}

if (geom instanceof Point) {
Point point = (Point) geom;
// already in WGS 84
grid.incrementPoint(point.getY(), point.getX(), numericVal);
} else if (geom instanceof Polygon || geom instanceof MultiPolygon) {
grid.rasterize(geom, numericVal);
} else {
throw new IllegalArgumentException("Unsupported geometry type: " + geom);
}
}

int currentCount = count.incrementAndGet();
if (progressListener != null) {
progressListener.setCompletedItems(currentCount);
}
if (currentCount % 10000 == 0) {
LOG.info("{} / {} features read", human(currentCount), human(total));
}
}
reader.close();
return new ArrayList<>(grids.values());
}

@Override
public double sumTotalOpportunities() {
double totalOpportunities = 0;
Expand Down

0 comments on commit c39100e

Please sign in to comment.