diff --git a/src/main/java/com/conveyal/gtfs/error/NewGTFSErrorType.java b/src/main/java/com/conveyal/gtfs/error/NewGTFSErrorType.java index 70e2e4dd4..aa7123688 100644 --- a/src/main/java/com/conveyal/gtfs/error/NewGTFSErrorType.java +++ b/src/main/java/com/conveyal/gtfs/error/NewGTFSErrorType.java @@ -50,7 +50,9 @@ public enum NewGTFSErrorType { STOP_LOW_POPULATION_DENSITY(Priority.HIGH, "A stop is located in a geographic area with very low human population density."), STOP_NAME_MISSING(Priority.MEDIUM, "A stop does not have a name."), STOP_GEOGRAPHIC_OUTLIER(Priority.HIGH, "This stop is located very far from the middle 90% of stops in this feed."), + STOP_TIME_UNUSED(Priority.LOW, "This stop time allows neither pickup nor drop off and is not a timepoint, so it serves no purpose and should be removed from trip."), STOP_UNUSED(Priority.MEDIUM, "This stop is not referenced by any trips."), + TIMEPOINT_MISSING_TIMES(Priority.MEDIUM, "This stop time is marked as a timepoint, but is missing both arrival and departure times."), TRIP_EMPTY(Priority.HIGH, "This trip is defined but has no stop times."), TRIP_HEADSIGN_CONTAINS_ROUTE_NAME(Priority.LOW, "A trip headsign contains the route name, but should only contain information to distinguish it from other trips for the route."), TRIP_HEADSIGN_SHOULD_DESCRIBE_DESTINATION_OR_WAYPOINTS(Priority.LOW, "A trip headsign begins with 'to' or 'towards', but should begin with destination or direction and optionally include waypoints with 'via'"), diff --git a/src/main/java/com/conveyal/gtfs/validator/SpeedTripValidator.java b/src/main/java/com/conveyal/gtfs/validator/SpeedTripValidator.java index ef28671a7..31f13235f 100644 --- a/src/main/java/com/conveyal/gtfs/validator/SpeedTripValidator.java +++ b/src/main/java/com/conveyal/gtfs/validator/SpeedTripValidator.java @@ -1,6 +1,7 @@ package com.conveyal.gtfs.validator; import com.conveyal.gtfs.error.NewGTFSError; +import com.conveyal.gtfs.error.NewGTFSErrorType; import com.conveyal.gtfs.error.SQLErrorStorage; import com.conveyal.gtfs.loader.Feed; import com.conveyal.gtfs.model.Entity; @@ -47,6 +48,10 @@ public void validateTrip(Trip trip, Route route, List stopTimes, List< double distanceMeters = 0; for (int i = beginIndex + 1; i < stopTimes.size(); i++) { StopTime currStopTime = stopTimes.get(i); + if (currStopTime.pickup_type == 1 && currStopTime.drop_off_type == 1 && currStopTime.timepoint == 0) { + // stop_time allows neither pickup or drop off and is not a timepoint, so it serves no purpose. + registerError(currStopTime, NewGTFSErrorType.STOP_TIME_UNUSED); + } Stop currStop = stops.get(i); // Distance is accumulated in case times are not provided for some StopTimes. distanceMeters += fastDistance(currStop.stop_lat, currStop.stop_lon, prevStop.stop_lat, prevStop.stop_lon); @@ -54,7 +59,9 @@ public void validateTrip(Trip trip, Route route, List stopTimes, List< checkShapeDistTraveled(prevStopTime, currStopTime); if (missingBothTimes(currStopTime)) { // FixMissingTimes has already been called, so both arrival and departure time are missing. - // The spec allows this. Other than accumulating distance, skip this StopTime. + // The spec allows this. Other than accumulating distance, skip this StopTime. If this stop_time serves + // as a timepoint; however, this is considered an error. + if (currStopTime.timepoint == 1) registerError(currStopTime, NewGTFSErrorType.TIMEPOINT_MISSING_TIMES); continue; } if (currStopTime.departure_time < currStopTime.arrival_time) {