diff --git a/package.json b/package.json
index 4420b20eec5..e52fdc52fb4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "opentripplanner",
- "version": "1.5.17",
+ "version": "1.5.20",
"description": "OpenTripPlanner (OTP) is an open source multi-modal trip planner. It depends on open data in open standard file formats (GTFS and OpenStreetMap), and includes a REST API for journey planning as well as a map-based Javascript client. OpenTripPlanner can also create travel time contour visualizations and compute accessibility indicators for planning and research applications.",
"main": "index.js",
"directories": {
@@ -18,7 +18,7 @@
"scripts": {
"deploy": "mvn deploy:deploy-file -s openmove-settings.xml -DgroupId=org.opentripplanner -DartifactId=otp -Dversion=${npm_package_version}-SNAPSHOT -Dclassifier=shaded -Dpackaging=jar -Dfile=target/otp-${npm_package_version}-SNAPSHOT-shaded.jar -Durl=https://maven.pkg.github.com/openmove/OpenTripPlanner -DrepositoryId=otp",
"build": "mvn clean package -DskipTests -s openmove-settings.xml",
- "debug": "java -Xmx5G -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:32935,suspend=y,server=y -jar target/otp-${npm_package_version}-SNAPSHOT-shaded.jar --build ../otp/otp/debug/ --inMemory "
+ "debug": "java -Xmx5G -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:32935,suspend=y,server=y -jar target/otp-${npm_package_version}-SNAPSHOT-shaded.jar --build ../otp/otp/napoli-test/ --inMemory "
},
"homepage": "https://github.com/openmove/OpenTripPlanner#readme"
}
diff --git a/pom.xml b/pom.xml
index e1ba88853b0..c5d03b56139 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
org.opentripplanner
otp
- 1.5.17-SNAPSHOT
+ 1.5.20-SNAPSHOT
jar
diff --git a/src/main/java/org/opentripplanner/index/IndexGraphQLSchema.java b/src/main/java/org/opentripplanner/index/IndexGraphQLSchema.java
index 5d68045f411..bcb4cc4a787 100644
--- a/src/main/java/org/opentripplanner/index/IndexGraphQLSchema.java
+++ b/src/main/java/org/opentripplanner/index/IndexGraphQLSchema.java
@@ -38,6 +38,7 @@
import org.opentripplanner.api.model.TripPlan;
import org.opentripplanner.api.model.VertexType;
import org.opentripplanner.api.model.WalkStep;
+import org.opentripplanner.common.geometry.SphericalDistanceLibrary;
import org.opentripplanner.common.model.P2;
import org.opentripplanner.gtfs.GtfsLibrary;
import org.opentripplanner.index.model.DestinationType;
@@ -238,6 +239,28 @@ public String parseLiteral(Object input) {
.value("WARNING", GtfsRealtime.Alert.SeverityLevel.WARNING, "Warning alerts are used when a single stop or route has a disruption that can affect user's journey, for example: All trams on a specific route are running with irregular schedules.")
.value("SEVERE", GtfsRealtime.Alert.SeverityLevel.SEVERE, "Severe alerts are used when a significant part of public transport services is affected, for example: All train services are cancelled due to technical problems.")
.build();
+
+ public static GraphQLEnumType congestionLevelEnum = GraphQLEnumType.newEnum()
+ .name("CongestionLevelType")
+ .description("Congestion level of a vehicle")
+ .value("UNKNOWN_CONGESTION_LEVEL", GtfsRealtime.VehiclePosition.CongestionLevel.UNKNOWN_CONGESTION_LEVEL, "Congestion is unknown")
+ .value("RUNNING_SMOOTHLY", GtfsRealtime.VehiclePosition.CongestionLevel.RUNNING_SMOOTHLY, "No congestion")
+ .value("STOP_AND_GO", GtfsRealtime.VehiclePosition.CongestionLevel.STOP_AND_GO, "The vehicle stop and go")
+ .value("CONGESTION", GtfsRealtime.VehiclePosition.CongestionLevel.CONGESTION, "There is a significant congestion")
+ .value("SEVERE_CONGESTION", GtfsRealtime.VehiclePosition.CongestionLevel.SEVERE_CONGESTION, "People are leaving their cars!")
+ .build();
+
+ public static GraphQLEnumType occupancyStatusEnum = GraphQLEnumType.newEnum()
+ .name("OccupancyStatusType")
+ .description("Occupancy status of a vehicle")
+ .value("EMPTY", GtfsRealtime.VehiclePosition.OccupancyStatus.EMPTY, "The vehicle is considered empty by most measures, and has few or no passengers onboard, but is still accepting passengers.")
+ .value("MANY_SEATS_AVAILABLE", GtfsRealtime.VehiclePosition.OccupancyStatus.MANY_SEATS_AVAILABLE, "The vehicle has a relatively large percentage of seats available.")
+ .value("FEW_SEATS_AVAILABLE", GtfsRealtime.VehiclePosition.OccupancyStatus.FEW_SEATS_AVAILABLE, "The vehicle has a relatively small percentage of seats available.")
+ .value("STANDING_ROOM_ONLY", GtfsRealtime.VehiclePosition.OccupancyStatus.STANDING_ROOM_ONLY, "The vehicle can currently accommodate only standing passengers.")
+ .value("CRUSHED_STANDING_ROOM_ONLY", GtfsRealtime.VehiclePosition.OccupancyStatus.CRUSHED_STANDING_ROOM_ONLY, "The vehicle can currently accommodate only standing passengers and has limited space for them.")
+ .value("FULL", GtfsRealtime.VehiclePosition.OccupancyStatus.FULL, "The vehicle is considered full by most measures, but may still be allowing passengers to board.")
+ .value("NOT_ACCEPTING_PASSENGERS", GtfsRealtime.VehiclePosition.OccupancyStatus.NOT_ACCEPTING_PASSENGERS, "The vehicle is not accepting additional passengers.")
+ .build();
private final GtfsRealtimeFuzzyTripMatcher fuzzyTripMatcher;
@@ -1221,9 +1244,16 @@ public IndexGraphQLSchema(GraphIndex index) {
vehiclePositionType = GraphQLObjectType.newObject()
.name("VehiclePosition")
.withInterface(nodeInterface)
+ .field(GraphQLFieldDefinition.newFieldDefinition()
+ .name("id")
+ .type(new GraphQLNonNull(Scalars.GraphQLID))
+ .dataFetcher(environment -> relay.toGlobalId(
+ vehiclePositionType.getName(),
+ ((RealtimeVehiclePosition) environment.getSource()).vehicleId))
+ .build())
.field(GraphQLFieldDefinition.newFieldDefinition()
.name("vehicleId")
- .type(new GraphQLNonNull(Scalars.GraphQLString))
+ .type(Scalars.GraphQLString)
.dataFetcher(environment -> ((RealtimeVehiclePosition) environment.getSource()).vehicleId)
.build())
.field(GraphQLFieldDefinition.newFieldDefinition()
@@ -1256,6 +1286,35 @@ public IndexGraphQLSchema(GraphIndex index) {
.type(Scalars.GraphQLLong)
.dataFetcher(environment -> ((RealtimeVehiclePosition) environment.getSource()).seconds)
.build())
+ .field(GraphQLFieldDefinition.newFieldDefinition()
+ .name("trip")
+ .type(tripType)
+ .dataFetcher(environment -> {
+ FeedScopedId tripId = ((RealtimeVehiclePosition) environment.getSource()).tripId;
+ return index.tripForId.get(tripId);
+ })
+ .build())
+ .field(GraphQLFieldDefinition.newFieldDefinition()
+ .name("congestionLevel")
+ .type(congestionLevelEnum)
+ .dataFetcher(environment -> {
+ return ((RealtimeVehiclePosition) environment.getSource()).congestionLevel;
+ })
+ .build())
+ .field(GraphQLFieldDefinition.newFieldDefinition()
+ .name("occupancyStatus")
+ .type(occupancyStatusEnum)
+ .dataFetcher(environment -> {
+ return ((RealtimeVehiclePosition) environment.getSource()).occupancyStatus;
+ })
+ .build())
+ .field(GraphQLFieldDefinition.newFieldDefinition()
+ .name("occupancyPercentage")
+ .type(Scalars.GraphQLInt)
+ .dataFetcher(environment -> {
+ return ((RealtimeVehiclePosition) environment.getSource()).occupancyPercentage;
+ })
+ .build())
.field(GraphQLFieldDefinition.newFieldDefinition()
.name("stoptime")
.type(stoptimeType)
@@ -1357,11 +1416,15 @@ public IndexGraphQLSchema(GraphIndex index) {
.dataFetcher(
environment -> {
Trip trip = (Trip) environment.getSource();
- return index.patternForTrip.get(trip)
+ List rtp = index.patternForTrip.get(trip)
.getVehiclePositions()
.stream()
.filter(vp -> vp.tripId.equals(trip.getId()))
.collect(Collectors.toList());
+ if(rtp.isEmpty()) {
+ return null;
+ }
+ return rtp.get(0);
}
)
.build())
@@ -1572,6 +1635,18 @@ public int compare(TripTimeShort tripTimeShort, TripTimeShort t1) {
.name("stops")
.type(new GraphQLList(new GraphQLNonNull(stopType)))
.build())
+ .field(GraphQLFieldDefinition.newFieldDefinition()
+ .name("realtimeVehiclePositions")
+ .type(new GraphQLList(vehiclePositionType))
+ .dataFetcher(
+ environment -> {
+ return ((TripPattern) environment.getSource())
+ .getVehiclePositions()
+ .stream()
+ .collect(Collectors.toList());
+ }
+ )
+ .build())
.field(GraphQLFieldDefinition.newFieldDefinition()
.name("geometry")
.type(Scalars.GraphQLString)
@@ -2868,6 +2943,57 @@ public int compare(TripTimeShort tripTimeShort, TripTimeShort t1) {
.collect(Collectors.toList())
))
.build())
+ .field(GraphQLFieldDefinition.newFieldDefinition()
+ .name("realtimeVehiclePositions")
+ .description("Get all vehicle positions for the specified graph")
+ .type(new GraphQLList(vehiclePositionType))
+ .argument(GraphQLArgument.newArgument()
+ .name("lat")
+ .description("Latitude of the location")
+ .type(Scalars.GraphQLFloat)
+ .build())
+ .argument(GraphQLArgument.newArgument()
+ .name("lon")
+ .description("Longitude of the location")
+ .type(Scalars.GraphQLFloat)
+ .build())
+ .argument(GraphQLArgument.newArgument()
+ .name("radius")
+ .description("Radius (in meters) to search for from the specidied location")
+ .type(Scalars.GraphQLInt)
+ .build())
+ .dataFetcher(environment -> {
+ return index.patternForId.values()
+ .stream()
+ .flatMap(p -> p.getVehiclePositions().stream().filter(
+ v -> {
+ Coordinate coord = null;
+ int radius = 0;
+ if(environment.getArgument("lon") != null && environment.getArgument("lat") != null && environment.getArgument("radius") != null) {
+
+ double lon = environment.getArgument("lon");
+ double lat = environment.getArgument("lat");
+ radius = Math.toIntExact(environment.getArgument("radius"));
+
+ coord = new Coordinate(lon, lat);
+ }
+ if(coord != null) {
+ double distance = SphericalDistanceLibrary.fastDistance(new Coordinate(v.lon, v.lat), coord);
+
+ if (distance < radius) {
+ return true;
+ } else {
+ return false;
+ }
+ }else {
+ return true;
+ }
+
+ }
+ ))
+ .collect(Collectors.toList());
+ })
+ .build())
.field(GraphQLFieldDefinition.newFieldDefinition()
.name("trip")
.description("Get a single trip based on its id (format is Agency:TripId)")
@@ -2951,6 +3077,38 @@ public int compare(TripTimeShort tripTimeShort, TripTimeShort t1) {
)
)
.build())
+ .field(GraphQLFieldDefinition.newFieldDefinition()
+ .name("clustersByBbox")
+ .description("Get all clusters for the specified graph in a bounding box")
+ .type(new GraphQLList(clusterType))
+ .argument(GraphQLArgument.newArgument()
+ .name("minLat")
+ .type(Scalars.GraphQLFloat)
+ .build())
+ .argument(GraphQLArgument.newArgument()
+ .name("minLon")
+ .type(Scalars.GraphQLFloat)
+ .build())
+ .argument(GraphQLArgument.newArgument()
+ .name("maxLat")
+ .type(Scalars.GraphQLFloat)
+ .build())
+ .argument(GraphQLArgument.newArgument()
+ .name("maxLon")
+ .type(Scalars.GraphQLFloat)
+ .build())
+ .dataFetcher(environment -> {
+ Envelope envelope = new Envelope(
+ new Coordinate(environment.getArgument("minLon"), environment.getArgument("minLat")),
+ new Coordinate(environment.getArgument("maxLon"), environment.getArgument("maxLat")));
+ return new ArrayList<>(
+ index.stopClusterForId.values()
+ .stream()
+ .filter(c -> envelope.contains(new Coordinate(c.lon,c.lat)))
+ .collect(Collectors.toList())
+ );
+ })
+ .build())
.field(GraphQLFieldDefinition.newFieldDefinition()
.name("cluster")
.description("Get a single cluster based on its id")
diff --git a/src/main/java/org/opentripplanner/index/model/RealtimeVehiclePosition.java b/src/main/java/org/opentripplanner/index/model/RealtimeVehiclePosition.java
index fbac97663b6..52d78f964e9 100644
--- a/src/main/java/org/opentripplanner/index/model/RealtimeVehiclePosition.java
+++ b/src/main/java/org/opentripplanner/index/model/RealtimeVehiclePosition.java
@@ -1,6 +1,7 @@
package org.opentripplanner.index.model;
import com.google.transit.realtime.GtfsRealtime.VehiclePosition.CongestionLevel;
+import com.google.transit.realtime.GtfsRealtime.VehiclePosition.OccupancyStatus;
import com.google.transit.realtime.GtfsRealtime.VehiclePosition.VehicleStopStatus;
import org.opentripplanner.model.FeedScopedId;
@@ -28,4 +29,8 @@ public class RealtimeVehiclePosition {
public int nextStopSequenceId;
public CongestionLevel congestionLevel;
+ public OccupancyStatus occupancyStatus;
+
+ public int occupancyPercentage;
+
}
diff --git a/src/main/java/org/opentripplanner/routing/edgetype/ParkAndRideEdge.java b/src/main/java/org/opentripplanner/routing/edgetype/ParkAndRideEdge.java
index 57bc99d6dd0..94e624d87f9 100644
--- a/src/main/java/org/opentripplanner/routing/edgetype/ParkAndRideEdge.java
+++ b/src/main/java/org/opentripplanner/routing/edgetype/ParkAndRideEdge.java
@@ -9,7 +9,6 @@
import org.opentripplanner.routing.vertextype.ParkAndRideVertex;
import org.locationtech.jts.geom.LineString;
-import org.opentripplanner.updater.car_park.ODHCarParkDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/org/opentripplanner/routing/impl/GraphPathFinder.java b/src/main/java/org/opentripplanner/routing/impl/GraphPathFinder.java
index fd540d03334..2e8cf261f29 100644
--- a/src/main/java/org/opentripplanner/routing/impl/GraphPathFinder.java
+++ b/src/main/java/org/opentripplanner/routing/impl/GraphPathFinder.java
@@ -53,7 +53,7 @@ public class GraphPathFinder {
private static final Logger LOG = LoggerFactory.getLogger(GraphPathFinder.class);
private static final double DEFAULT_MAX_WALK = 2000;
- private static final double CLAMP_MAX_WALK = 15000;
+ private static final double CLAMP_MAX_WALK = 150000;
Router router;
diff --git a/src/main/java/org/opentripplanner/updater/car_park/CarParkUpdater.java b/src/main/java/org/opentripplanner/updater/car_park/CarParkUpdater.java
index 3193ef6804a..79ee46931a8 100644
--- a/src/main/java/org/opentripplanner/updater/car_park/CarParkUpdater.java
+++ b/src/main/java/org/opentripplanner/updater/car_park/CarParkUpdater.java
@@ -92,6 +92,9 @@ protected void configurePolling(Graph graph, JsonNode config) throws Exception {
if (sourceType.equals("park-and-ride")) {
source = new ODHCarParkDataSource();
}
+ if (sourceType.equals("park-openmove")) {
+ source = new OMCarParkDataSource();
+ }
}
if (source == null) {
diff --git a/src/main/java/org/opentripplanner/updater/car_park/OMCarParkDataSource.java b/src/main/java/org/opentripplanner/updater/car_park/OMCarParkDataSource.java
new file mode 100644
index 00000000000..ca9e94c363a
--- /dev/null
+++ b/src/main/java/org/opentripplanner/updater/car_park/OMCarParkDataSource.java
@@ -0,0 +1,211 @@
+package org.opentripplanner.updater.car_park;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.geotools.geometry.jts.JTS;
+import org.geotools.referencing.CRS;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.LinearRing;
+import org.locationtech.jts.geom.Polygon;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+import org.opentripplanner.routing.car_park.CarPark;
+import org.opentripplanner.routing.graph.Graph;
+import org.opentripplanner.util.HttpUtils;
+import org.opentripplanner.util.NonLocalizedString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Load car parks from the ODH Park API.
+ *
+ * @author fede
+ */
+public class OMCarParkDataSource extends GenericJsonCarParkDataSource{
+
+ private static final Logger log = LoggerFactory.getLogger(ODHCarParkDataSource.class);
+
+ private GeometryFactory gf = new GeometryFactory();
+
+ public OMCarParkDataSource() {
+ super("stations");
+ }
+
+ public CarPark makeCarPark(JsonNode node) {
+ if (node.path("station_id").isMissingNode()) return null;
+
+ CarPark station = new CarPark();
+ station.id = node.path("station_id").asText();
+ station.name = new NonLocalizedString(node.path("name").asText());
+ try {
+ station.geometry = parseGeometry(node.path("geometry"));
+ station.y = station.geometry.getCentroid().getY();
+ station.x = station.geometry.getCentroid().getX();
+ //station.realTimeData = node.path("realtime").asBoolean();
+ station.maxCapacity = node.path("capacity").asInt();
+// String stationStatus = node.path("status").asText();
+// if (stationStatus.equals("INACTIVE") || stationStatus.equals("TEMPORARILY_CLOSED")) {
+// return null;
+// } else if (station.realTimeData) {
+// station.spacesAvailable = node.path("free").asInt();
+// station.spacesForecast.put(0, station.spacesAvailable);
+// } else {
+// station.spacesAvailable = station.maxCapacity;
+// station.spacesForecast.put(0, station.spacesAvailable);
+// }
+ if(node.path("free").isNull()) {
+ station.spacesAvailable = station.maxCapacity;
+ station.spacesForecast.put(0, station.spacesAvailable);
+ }else {
+ station.spacesAvailable = node.path("free").asInt();
+ station.spacesForecast.put(0, station.spacesAvailable);
+ }
+
+ if(node.has("forecasts") && node.path("forecasts").isArray()){
+ int number = 15;
+ int counter = 1;
+ for(JsonNode forecast : node.path("forecasts")){
+ int forecastInt = forecast.asInt();
+ station.spacesForecast.put((counter * number), forecastInt);
+ }
+ }
+
+ return station;
+ } catch (Exception e) {
+ log.warn("Error parsing car park " + station.id, e);
+ return null;
+ }
+ }
+
+ public boolean update() {
+ return super.update();
+ }
+
+
+ /**
+ * Note that the JSON being passed in here is for configuration of the OTP component, it's completely separate
+ * from the JSON coming in from the update source.
+ */
+ @Override
+ public void configure (Graph graph, JsonNode jsonNode) {
+ super.configure(graph, jsonNode);
+ }
+
+ // TODO: These are inlined from GeometryDeserializer
+ private Geometry parseGeometry(JsonNode root) {
+ String typeName = root.get("type").asText();
+ if(typeName.equals("Point")) {
+ Geometry sourceGeometry = this.gf.createPoint(this.parseCoordinate(root.get("coordinates")));
+
+ try {
+ CoordinateReferenceSystem sourceCRS = CRS.decode("EPSG:4326");
+ CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:3857");
+ MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS);
+ MathTransform transform2 = CRS.findMathTransform(targetCRS, sourceCRS);
+ Geometry targetGeometry = JTS.transform( sourceGeometry, transform);
+ Geometry bufferedTargetGeometry = targetGeometry.buffer(50);
+ return JTS.transform( bufferedTargetGeometry, transform2);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return sourceGeometry;
+ } else if(typeName.equals("MultiPoint")) {
+ return this.gf.createMultiPoint(this.parseLineString(root.get("coordinates")));
+ } else if(typeName.equals("LineString")) {
+ return this.gf.createLineString(this.parseLineString(root.get("coordinates")));
+ } else if(typeName.equals("MultiLineString")) {
+ return this.gf.createMultiLineString(this.parseLineStrings(root.get("coordinates")));
+ } else {
+ JsonNode arrayOfPolygons;
+ if(typeName.equals("Polygon")) {
+ arrayOfPolygons = root.get("coordinates");
+ return this.parsePolygonCoordinates(arrayOfPolygons);
+ } else if(typeName.equals("MultiPolygon")) {
+ arrayOfPolygons = root.get("coordinates");
+ return this.gf.createMultiPolygon(this.parsePolygons(arrayOfPolygons));
+ } else if(typeName.equals("GeometryCollection")) {
+ return this.gf.createGeometryCollection(this.parseGeometries(root.get("geometries")));
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
+ private Geometry[] parseGeometries(JsonNode arrayOfGeoms) {
+ Geometry[] items = new Geometry[arrayOfGeoms.size()];
+
+ for(int i = 0; i != arrayOfGeoms.size(); ++i) {
+ items[i] = this.parseGeometry(arrayOfGeoms.get(i));
+ }
+
+ return items;
+ }
+
+ private Polygon parsePolygonCoordinates(JsonNode arrayOfRings) {
+ return this.gf.createPolygon(this.parseExteriorRing(arrayOfRings), this.parseInteriorRings(arrayOfRings));
+ }
+
+ private Polygon[] parsePolygons(JsonNode arrayOfPolygons) {
+ Polygon[] polygons = new Polygon[arrayOfPolygons.size()];
+
+ for(int i = 0; i != arrayOfPolygons.size(); ++i) {
+ polygons[i] = this.parsePolygonCoordinates(arrayOfPolygons.get(i));
+ }
+
+ return polygons;
+ }
+
+ private LinearRing parseExteriorRing(JsonNode arrayOfRings) {
+ return this.gf.createLinearRing(this.parseLineString(arrayOfRings.get(0)));
+ }
+
+ private LinearRing[] parseInteriorRings(JsonNode arrayOfRings) {
+ LinearRing[] rings = new LinearRing[arrayOfRings.size() - 1];
+
+ for(int i = 1; i < arrayOfRings.size(); ++i) {
+ rings[i - 1] = this.gf.createLinearRing(this.parseLineString(arrayOfRings.get(i)));
+ }
+
+ return rings;
+ }
+
+ private Coordinate parseCoordinate(JsonNode array) {
+ return new Coordinate(array.get(0).asDouble(), array.get(1).asDouble());
+ }
+
+ private Coordinate[] parseLineString(JsonNode array) {
+ Coordinate[] points = new Coordinate[array.size()];
+
+ for(int i = 0; i != array.size(); ++i) {
+ points[i] = this.parseCoordinate(array.get(i));
+ }
+
+ return points;
+ }
+
+ private LineString[] parseLineStrings(JsonNode array) {
+ LineString[] strings = new LineString[array.size()];
+
+ for(int i = 0; i != array.size(); ++i) {
+ strings[i] = this.gf.createLineString(this.parseLineString(array.get(i)));
+ }
+
+ return strings;
+ }
+}
+
diff --git a/src/main/java/org/opentripplanner/updater/vehicle_positions/VehiclePositionPatternMatcher.java b/src/main/java/org/opentripplanner/updater/vehicle_positions/VehiclePositionPatternMatcher.java
index a88a50039e4..aaecd43cfb1 100644
--- a/src/main/java/org/opentripplanner/updater/vehicle_positions/VehiclePositionPatternMatcher.java
+++ b/src/main/java/org/opentripplanner/updater/vehicle_positions/VehiclePositionPatternMatcher.java
@@ -17,6 +17,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import java.util.UUID;
import java.util.stream.Collectors;
/**
@@ -126,6 +127,16 @@ private RealtimeVehiclePosition parseVehiclePosition(VehiclePosition vehiclePosi
}
newPosition.vehicleId = vehiclePosition.getVehicle().getId();
}
+
+ if(newPosition.vehicleId == null) {
+ if(vehiclePosition.hasTrip()) {
+ newPosition.vehicleId = vehiclePosition.getTrip().getTripId();
+ }else {
+ UUID uuid = UUID.randomUUID();
+ String uuidAsString = uuid.toString();
+ newPosition.vehicleId = uuidAsString;
+ }
+ }
if (vehiclePosition.hasCurrentStatus()) {
newPosition.stopStatus = vehiclePosition.getCurrentStatus();
@@ -134,6 +145,13 @@ private RealtimeVehiclePosition parseVehiclePosition(VehiclePosition vehiclePosi
if (vehiclePosition.hasCongestionLevel()) {
newPosition.congestionLevel = vehiclePosition.getCongestionLevel();
}
+
+ if (vehiclePosition.hasOccupancyStatus()) {
+ newPosition.occupancyStatus = vehiclePosition.getOccupancyStatus();
+ }
+ if (vehiclePosition.hasOccupancyPercentage()) {
+ newPosition.occupancyPercentage = vehiclePosition.getOccupancyPercentage();
+ }
if (vehiclePosition.hasTimestamp()) {
newPosition.seconds = vehiclePosition.getTimestamp();