
org.opentripplanner.api.resource.LIsochrone Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of otp Show documentation
Show all versions of otp Show documentation
The OpenTripPlanner multimodal journey planning system
/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
package org.opentripplanner.api.resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import org.geotools.data.DefaultTransaction;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opentripplanner.analyst.core.IsochroneData;
import org.opentripplanner.analyst.request.IsoChroneRequest;
import org.opentripplanner.api.common.RoutingResource;
import org.opentripplanner.common.model.GenericLocation;
import org.opentripplanner.routing.core.RoutingRequest;
import org.opentripplanner.standalone.Router;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.io.Files;
import com.vividsolutions.jts.geom.MultiPolygon;
/**
* Return isochrone geometry as a set of GeoJSON or zipped-shapefile multi-polygons.
*
* Example of request:
*
*
* http://localhost:8080/otp-rest-servlet/ws/isochrone?routerId=bordeaux&algorithm=accSampling&fromPlace=47.059,-0.880&date=2013/10/01&time=12:00:00&maxWalkDistance=1000&mode=WALK,TRANSIT&cutoffSec=1800&cutoffSec=3600
*
*
* @author laurent
*/
@Path("/routers/{routerId}/isochrone")
public class LIsochrone extends RoutingResource {
private static final Logger LOG = LoggerFactory.getLogger(LIsochrone.class);
@QueryParam("cutoffSec")
private List cutoffSecList;
@QueryParam("maxTimeSec")
private Integer maxTimeSec;
@QueryParam("debug")
private Boolean debug;
@QueryParam("precisionMeters")
@DefaultValue("200")
private Integer precisionMeters;
@QueryParam("offRoadDistanceMeters")
@DefaultValue("150")
private Integer offRoadDistanceMeters;
@QueryParam("coordinateOrigin")
private String coordinateOrigin = null;
private static final SimpleFeatureType contourSchema = makeContourSchema();
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getGeoJsonIsochrone() throws Exception {
SimpleFeatureCollection contourFeatures = makeContourFeatures(computeIsochrone());
StringWriter writer = new StringWriter();
FeatureJSON fj = new FeatureJSON();
fj.writeFeatureCollection(contourFeatures, writer);
CacheControl cc = new CacheControl();
cc.setMaxAge(3600);
cc.setNoCache(false);
return Response.ok().entity(writer.toString()).cacheControl(cc).build();
}
@GET
@Produces("application/x-zip-compressed")
public Response getZippedShapefileIsochrone(@QueryParam("shpName") String shpName,
@QueryParam("stream") @DefaultValue("true") boolean stream) throws Exception {
SimpleFeatureCollection contourFeatures = makeContourFeatures(computeIsochrone());
/* Output the staged features to Shapefile */
final File shapeDir = Files.createTempDir();
File shapeFile = new File(shapeDir, shpName + ".shp");
LOG.debug("writing out shapefile {}", shapeFile);
ShapefileDataStore outStore = new ShapefileDataStore(shapeFile.toURI().toURL());
outStore.createSchema(contourSchema);
Transaction transaction = new DefaultTransaction("create");
SimpleFeatureStore featureStore = (SimpleFeatureStore) outStore.getFeatureSource();
featureStore.setTransaction(transaction);
try {
featureStore.addFeatures(contourFeatures);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
} finally {
transaction.close();
}
shapeDir.deleteOnExit(); // Note: the order is important
for (File f : shapeDir.listFiles())
f.deleteOnExit();
/* Zip up the shapefile components */
StreamingOutput output = new DirectoryZipper(shapeDir);
if (stream) {
return Response.ok().entity(output).build();
} else {
File zipFile = new File(shapeDir, shpName + ".zip");
OutputStream fos = new FileOutputStream(zipFile);
output.write(fos);
zipFile.deleteOnExit();
return Response.ok().entity(zipFile).build();
}
}
/**
* Create a geotools feature collection from a list of isochrones in the OTPA internal format.
* Once in a FeatureCollection, they can for example be exported as GeoJSON.
*/
public static SimpleFeatureCollection makeContourFeatures(List isochrones) {
DefaultFeatureCollection featureCollection = new DefaultFeatureCollection(null,
contourSchema);
SimpleFeatureBuilder fbuilder = new SimpleFeatureBuilder(contourSchema);
for (IsochroneData isochrone : isochrones) {
fbuilder.add(isochrone.geometry);
fbuilder.add(isochrone.cutoffSec);
featureCollection.add(fbuilder.buildFeature(null));
}
return featureCollection;
}
/**
* Generic method to compute isochrones. Parse the request, call the adequate builder, and
* return a list of generic isochrone data.
*
* @return
* @throws Exception
*/
public List computeIsochrone() throws Exception {
if (debug == null)
debug = false;
if (precisionMeters < 10)
throw new IllegalArgumentException("Too small precisionMeters: " + precisionMeters);
if (offRoadDistanceMeters < 10)
throw new IllegalArgumentException("Too small offRoadDistanceMeters: " + offRoadDistanceMeters);
IsoChroneRequest isoChroneRequest = new IsoChroneRequest(cutoffSecList);
isoChroneRequest.includeDebugGeometry = debug;
isoChroneRequest.precisionMeters = precisionMeters;
isoChroneRequest.offRoadDistanceMeters = offRoadDistanceMeters;
if (coordinateOrigin != null)
isoChroneRequest.coordinateOrigin = new GenericLocation(null, coordinateOrigin)
.getCoordinate();
RoutingRequest sptRequest = buildRequest();
if (maxTimeSec != null) {
isoChroneRequest.maxTimeSec = maxTimeSec;
} else {
isoChroneRequest.maxTimeSec = isoChroneRequest.maxCutoffSec;
}
Router router = otpServer.getRouter(routerId);
return router.isoChroneSPTRenderer.getIsochrones(isoChroneRequest, sptRequest);
}
static SimpleFeatureType makeContourSchema() {
/* Create the output feature schema. */
SimpleFeatureTypeBuilder tbuilder = new SimpleFeatureTypeBuilder();
tbuilder.setName("contours");
tbuilder.setCRS(DefaultGeographicCRS.WGS84);
// Do not use "geom" or "geometry" below, it seems to broke shapefile generation
tbuilder.add("the_geom", MultiPolygon.class);
tbuilder.add("time", Integer.class); // TODO change to something more descriptive and lowercase
return tbuilder.buildFeatureType();
}
// TODO Extract this to utility package?
private static class DirectoryZipper implements StreamingOutput {
private File directory;
DirectoryZipper(File directory) {
this.directory = directory;
}
@Override
public void write(OutputStream outStream) throws IOException {
ZipOutputStream zip = new ZipOutputStream(outStream);
for (File f : directory.listFiles()) {
zip.putNextEntry(new ZipEntry(f.getName()));
Files.copy(f, zip);
zip.closeEntry();
zip.flush();
}
zip.close();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy