Migrate to java
This commit is contained in:
parent
1588c01b19
commit
dccc1e439d
8 changed files with 243 additions and 192 deletions
161
r5-java/src/main/java/propertymap/App.java
Normal file
161
r5-java/src/main/java/propertymap/App.java
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
package propertymap;
|
||||
|
||||
import com.conveyal.r5.analyst.FreeFormPointSet;
|
||||
import com.conveyal.r5.analyst.TravelTimeComputer;
|
||||
import com.conveyal.r5.analyst.cluster.RegionalTask;
|
||||
import com.conveyal.r5.api.util.LegMode;
|
||||
import com.conveyal.r5.api.util.TransitModes;
|
||||
import com.conveyal.r5.transit.TransportNetwork;
|
||||
import com.google.gson.Gson;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.LocalDate;
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class App {
|
||||
private static TransportNetwork network;
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
static class TravelTimeRequest {
|
||||
double[] origin; // [lat, lon]
|
||||
double[][] destinations; // [[lat, lon], ...]
|
||||
String mode; // "transit", "car", "bicycle", "walking"
|
||||
}
|
||||
|
||||
static class TravelTimeResponse {
|
||||
double[] travel_times; // minutes, -1 = unreachable
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String dataDir = System.getenv("DATA_DIR");
|
||||
if (dataDir == null) dataDir = "/data/transit";
|
||||
|
||||
String networkCacheDir = System.getenv("NETWORK_CACHE_DIR");
|
||||
if (networkCacheDir == null) networkCacheDir = "/data/network";
|
||||
|
||||
System.out.println("Loading transport network from " + dataDir);
|
||||
System.out.println("Network cache dir: " + networkCacheDir);
|
||||
|
||||
File cacheFile = new File(networkCacheDir, "network.dat");
|
||||
if (cacheFile.exists()) {
|
||||
System.out.println("Loading cached network from " + cacheFile);
|
||||
network = TransportNetwork.read(cacheFile);
|
||||
} else {
|
||||
System.out.println("Building network (first run, this takes a few minutes)...");
|
||||
network = TransportNetwork.fromDirectory(new File(dataDir));
|
||||
new File(networkCacheDir).mkdirs();
|
||||
network.write(cacheFile);
|
||||
System.out.println("Network cached to " + cacheFile);
|
||||
}
|
||||
|
||||
System.out.println("Transport network loaded successfully");
|
||||
|
||||
Javalin app = Javalin.create().start(8003);
|
||||
|
||||
app.get("/health", ctx -> ctx.result("ok"));
|
||||
|
||||
app.post("/travel-times", App::handleTravelTimes);
|
||||
|
||||
System.out.println("R5 service listening on port 8003");
|
||||
}
|
||||
|
||||
private static void handleTravelTimes(Context ctx) {
|
||||
long t0 = System.currentTimeMillis();
|
||||
|
||||
TravelTimeRequest req = gson.fromJson(ctx.body(), TravelTimeRequest.class);
|
||||
|
||||
if (req.origin == null || req.origin.length != 2) {
|
||||
ctx.status(400).result("origin must be [lat, lon]");
|
||||
return;
|
||||
}
|
||||
if (req.destinations == null || req.destinations.length == 0) {
|
||||
ctx.status(400).result("destinations must be non-empty array of [lat, lon]");
|
||||
return;
|
||||
}
|
||||
|
||||
String mode = req.mode != null ? req.mode : "transit";
|
||||
|
||||
// Build destination point set
|
||||
double[] lats = new double[req.destinations.length];
|
||||
double[] lons = new double[req.destinations.length];
|
||||
for (int i = 0; i < req.destinations.length; i++) {
|
||||
lats[i] = req.destinations[i][0];
|
||||
lons[i] = req.destinations[i][1];
|
||||
}
|
||||
|
||||
FreeFormPointSet destinations = new FreeFormPointSet(lats, lons);
|
||||
|
||||
// Build the regional task
|
||||
RegionalTask task = new RegionalTask();
|
||||
task.fromLat = req.origin[0];
|
||||
task.fromLon = req.origin[1];
|
||||
task.date = LocalDate.now();
|
||||
task.percentiles = new int[]{50};
|
||||
task.monteCarloDraws = 1;
|
||||
|
||||
switch (mode) {
|
||||
case "car":
|
||||
task.fromTime = 8 * 3600;
|
||||
task.toTime = 8 * 3600 + 60;
|
||||
task.maxTripDurationMinutes = 120;
|
||||
task.accessModes = EnumSet.of(LegMode.CAR);
|
||||
task.egressModes = EnumSet.of(LegMode.CAR);
|
||||
task.directModes = EnumSet.of(LegMode.CAR);
|
||||
task.transitModes = EnumSet.noneOf(TransitModes.class);
|
||||
break;
|
||||
case "bicycle":
|
||||
task.fromTime = 8 * 3600;
|
||||
task.toTime = 8 * 3600 + 60;
|
||||
task.maxTripDurationMinutes = 90;
|
||||
task.accessModes = EnumSet.of(LegMode.BICYCLE);
|
||||
task.egressModes = EnumSet.of(LegMode.BICYCLE);
|
||||
task.directModes = EnumSet.of(LegMode.BICYCLE);
|
||||
task.transitModes = EnumSet.noneOf(TransitModes.class);
|
||||
break;
|
||||
case "walking":
|
||||
task.fromTime = 8 * 3600;
|
||||
task.toTime = 8 * 3600 + 60;
|
||||
task.maxTripDurationMinutes = 60;
|
||||
task.accessModes = EnumSet.of(LegMode.WALK);
|
||||
task.egressModes = EnumSet.of(LegMode.WALK);
|
||||
task.directModes = EnumSet.of(LegMode.WALK);
|
||||
task.transitModes = EnumSet.noneOf(TransitModes.class);
|
||||
break;
|
||||
default: // transit
|
||||
task.fromTime = 8 * 3600;
|
||||
task.toTime = 8 * 3600 + 60; // single RAPTOR sweep
|
||||
task.maxTripDurationMinutes = 90;
|
||||
task.maxRides = 4;
|
||||
task.accessModes = EnumSet.of(LegMode.WALK);
|
||||
task.egressModes = EnumSet.of(LegMode.WALK);
|
||||
task.directModes = EnumSet.of(LegMode.WALK);
|
||||
task.transitModes = EnumSet.allOf(TransitModes.class);
|
||||
break;
|
||||
}
|
||||
|
||||
// Compute travel times
|
||||
TravelTimeComputer computer = new TravelTimeComputer(task, network, destinations);
|
||||
int[][] results = computer.computeTravelTimes();
|
||||
|
||||
// results[percentileIdx][destinationIdx] — we only have 1 percentile (index 0)
|
||||
TravelTimeResponse response = new TravelTimeResponse();
|
||||
response.travel_times = new double[req.destinations.length];
|
||||
|
||||
int[] times = results[0]; // percentile 0 (the 50th percentile)
|
||||
for (int i = 0; i < req.destinations.length; i++) {
|
||||
if (i < times.length && times[i] != Integer.MAX_VALUE) {
|
||||
response.travel_times[i] = times[i]; // already in minutes
|
||||
} else {
|
||||
response.travel_times[i] = -1; // unreachable
|
||||
}
|
||||
}
|
||||
|
||||
long elapsed = System.currentTimeMillis() - t0;
|
||||
System.out.println("Travel times (" + mode + ") computed for " + req.destinations.length +
|
||||
" destinations in " + elapsed + "ms");
|
||||
|
||||
ctx.json(response);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue