Skip to content

Commit

Permalink
implement delay and skipped stops on added / replacement trips
Browse files Browse the repository at this point in the history
  • Loading branch information
miklcct committed Aug 28, 2024
1 parent aed7fd2 commit b78e020
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,7 @@ private Result<UpdateSuccess, UpdateError> addTripToGraphAndBuffer(

// Create StopTimes
final List<StopTime> stopTimes = new ArrayList<>(stopTimeUpdates.size());
List<Integer> skippedStopIndices = new ArrayList<>();
for (int index = 0; index < stopTimeUpdates.size(); ++index) {
final StopTimeUpdate stopTimeUpdate = stopTimeUpdates.get(index);
final var stop = stops.get(index);
Expand All @@ -781,7 +782,11 @@ private Result<UpdateSuccess, UpdateError> addTripToGraphAndBuffer(
stopTime.setStop(stop);
// Set arrival time
if (stopTimeUpdate.hasArrival() && stopTimeUpdate.getArrival().hasTime()) {
final long arrivalTime = stopTimeUpdate.getArrival().getTime() - midnightSecondsSinceEpoch;
final int delay = stopTimeUpdate.getArrival().hasDelay()
? stopTimeUpdate.getArrival().getDelay()
: 0;
final long arrivalTime =
stopTimeUpdate.getArrival().getTime() - midnightSecondsSinceEpoch - delay;
if (arrivalTime < 0 || arrivalTime > MAX_ARRIVAL_DEPARTURE_TIME) {
debug(
trip.getId(),
Expand All @@ -794,8 +799,11 @@ private Result<UpdateSuccess, UpdateError> addTripToGraphAndBuffer(
}
// Set departure time
if (stopTimeUpdate.hasDeparture() && stopTimeUpdate.getDeparture().hasTime()) {
final int delay = stopTimeUpdate.getDeparture().hasDelay()
? stopTimeUpdate.getDeparture().getDelay()
: 0;
final long departureTime =
stopTimeUpdate.getDeparture().getTime() - midnightSecondsSinceEpoch;
stopTimeUpdate.getDeparture().getTime() - midnightSecondsSinceEpoch - delay;
if (departureTime < 0 || departureTime > MAX_ARRIVAL_DEPARTURE_TIME) {
debug(
trip.getId(),
Expand All @@ -815,14 +823,23 @@ private Result<UpdateSuccess, UpdateError> addTripToGraphAndBuffer(
stopTime.setDropOffType(added.dropOff());
// Add stop time to list
stopTimes.add(stopTime);

// Add skipped stop to list
if (
stopTimeUpdate.hasScheduleRelationship() &&
stopTimeUpdate.getScheduleRelationship() == StopTimeUpdate.ScheduleRelationship.SKIPPED
) {
skippedStopIndices.add(index);
}
}

// TODO: filter/interpolate stop times like in PatternHopFactory?

// Create StopPattern
final StopPattern stopPattern = new StopPattern(stopTimes);

final TripPattern originalTripPattern = transitEditorService.getPatternForTrip(trip);
// Create StopPattern
final StopPattern stopPattern = originalTripPattern.copyPlannedStopPattern()
.cancelStops(skippedStopIndices)
.build();
// Get cached trip pattern or create one if it doesn't exist yet
final TripPattern pattern = tripPatternCache.getOrCreateTripPattern(
stopPattern,
Expand All @@ -838,12 +855,30 @@ private Result<UpdateSuccess, UpdateError> addTripToGraphAndBuffer(
);

// Update all times to mark trip times as realtime
// TODO: should we incorporate the delay field if present?
// TODO: This is based on the proposal at https://github.com/google/transit/issues/490
for (int stopIndex = 0; stopIndex < newTripTimes.getNumStops(); stopIndex++) {
newTripTimes.updateArrivalTime(stopIndex, newTripTimes.getScheduledArrivalTime(stopIndex));
final StopTimeUpdate stopTimeUpdate = stopTimeUpdates.get(stopIndex);

if (
stopTimeUpdate.hasScheduleRelationship() &&
stopTimeUpdate.getScheduleRelationship() == StopTimeUpdate.ScheduleRelationship.SKIPPED
) {
newTripTimes.setCancelled(stopIndex);
}

final int arrivalDelay = stopTimeUpdate.hasArrival()
? stopTimeUpdate.getArrival().hasDelay() ? stopTimeUpdate.getArrival().getDelay() : 0
: 0;
final int departureDelay = stopTimeUpdate.hasDeparture()
? stopTimeUpdate.getDeparture().hasDelay() ? stopTimeUpdate.getDeparture().getDelay() : 0
: 0;
newTripTimes.updateArrivalTime(
stopIndex,
newTripTimes.getScheduledArrivalTime(stopIndex) + arrivalDelay
);
newTripTimes.updateDepartureTime(
stopIndex,
newTripTimes.getScheduledDepartureTime(stopIndex)
newTripTimes.getScheduledDepartureTime(stopIndex) + departureDelay
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ public TripUpdateBuilder addStopTime(String stopId, int minutes) {
);
}

public TripUpdateBuilder addStopTime(String stopId, int minutes, int delay) {
return addStopTime(
stopId,
minutes,
NO_VALUE,
delay,
delay,
DEFAULT_SCHEDULE_RELATIONSHIP,
null
);
}

public TripUpdateBuilder addStopTime(
String stopId,
int minutes,
StopTimeUpdate.ScheduleRelationship scheduleRelationship
) {
return addStopTime(stopId, minutes, NO_VALUE, NO_DELAY, NO_DELAY, scheduleRelationship, null);
}

public TripUpdateBuilder addStopTime(String stopId, int minutes, DropOffPickupType pickDrop) {
return addStopTime(
stopId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package org.opentripplanner.updater.trip.moduletests.addition;

import static com.google.transit.realtime.GtfsRealtime.TripDescriptor.ScheduleRelationship.ADDED;
import static com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate.ScheduleRelationship.SKIPPED;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.opentripplanner.updater.spi.UpdateResultAssertions.assertSuccess;
import static org.opentripplanner.updater.trip.BackwardsDelayPropagationType.REQUIRED_NO_DATA;
import static org.opentripplanner.updater.trip.RealtimeTestEnvironment.SERVICE_DATE;
import static org.opentripplanner.updater.trip.RealtimeTestEnvironment.STOP_A1_ID;
import static org.opentripplanner.updater.trip.RealtimeTestEnvironment.STOP_B1_ID;
Expand All @@ -16,9 +19,12 @@
import java.util.List;
import org.junit.jupiter.api.Test;
import org.opentripplanner.model.PickDrop;
import org.opentripplanner.model.Timetable;
import org.opentripplanner.model.TimetableSnapshot;
import org.opentripplanner.transit.model.basic.TransitMode;
import org.opentripplanner.transit.model.network.TripPattern;
import org.opentripplanner.transit.model.timetable.RealTimeState;
import org.opentripplanner.transit.model.timetable.TripTimes;
import org.opentripplanner.updater.spi.UpdateSuccess;
import org.opentripplanner.updater.trip.RealtimeTestEnvironment;
import org.opentripplanner.updater.trip.TripUpdateBuilder;
Expand Down Expand Up @@ -120,6 +126,54 @@ void repeatedlyAddedTripWithNewRoute() {
assertNotNull(env.getTransitService().getRouteForId(firstRoute.getId()));
}

@Test
public void addedTripWithSkippedStop() {
var env = RealtimeTestEnvironment.gtfs();
var builder = new TripUpdateBuilder(ADDED_TRIP_ID, SERVICE_DATE, ADDED, env.timeZone);
builder.addStopTime("A", 30).addStopTime("C", 40, SKIPPED).addStopTime("E", 55);
var tripUpdate = builder.build();

env.applyTripUpdate(tripUpdate);

// THEN
final TripPattern tripPattern = assertAddedTrip(ADDED_TRIP_ID, env);
assertEquals(PickDrop.SCHEDULED, tripPattern.getBoardType(0));
assertEquals(PickDrop.CANCELLED, tripPattern.getAlightType(1));
assertEquals(PickDrop.CANCELLED, tripPattern.getBoardType(1));
assertEquals(PickDrop.SCHEDULED, tripPattern.getAlightType(2));
final TimetableSnapshot snapshot = env.getTimetableSnapshot();
final Timetable forToday = snapshot.resolve(tripPattern, SERVICE_DATE);
final int forTodayAddedTripIndex = forToday.getTripIndex(ADDED_TRIP_ID);
final TripTimes tripTimes = forToday.getTripTimes(forTodayAddedTripIndex);
assertFalse(tripTimes.isCancelledStop(0));
assertTrue(tripTimes.isCancelledStop(1));
}

@Test
public void addedTripWithDelay() {
var env = RealtimeTestEnvironment.gtfs();
var builder = new TripUpdateBuilder(ADDED_TRIP_ID, SERVICE_DATE, ADDED, env.timeZone);

// A: scheduled 08:30:00
// C: scheduled 08:40:00, delay 300 seconds (actual 08:45:00)
// E: scheduled 08:55:00
builder.addStopTime("A", 30).addStopTime("C", 45, 300).addStopTime("E", 55);

var tripUpdate = builder.build();
env.applyTripUpdate(tripUpdate);

// THEN
final TripPattern tripPattern = assertAddedTrip(ADDED_TRIP_ID, env);
final TimetableSnapshot snapshot = env.getTimetableSnapshot();
final Timetable forToday = snapshot.resolve(tripPattern, SERVICE_DATE);
final int forTodayAddedTripIndex = forToday.getTripIndex(ADDED_TRIP_ID);
final TripTimes tripTimes = forToday.getTripTimes(forTodayAddedTripIndex);
assertEquals(0, tripTimes.getDepartureDelay(0));
assertEquals(30600, tripTimes.getDepartureTime(0)); // 08:30:00
assertEquals(300, tripTimes.getArrivalDelay(1));
assertEquals(31500, tripTimes.getArrivalTime(1)); // 08:45:00
}

private TripPattern assertAddedTrip(String tripId, RealtimeTestEnvironment env) {
var snapshot = env.getTimetableSnapshot();
var stopA = env.transitModel.getStopModel().getRegularStop(env.stopA1.getId());
Expand Down

0 comments on commit b78e020

Please sign in to comment.