use of com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeEvent in project OpenTripPlanner by opentripplanner.
the class Timetable method createUpdatedTripTimes.
/**
* Apply the TripUpdate to the appropriate TripTimes from this Timetable. The existing TripTimes
* must not be modified directly because they may be shared with the underlying
* scheduledTimetable, or other updated Timetables. The {@link TimetableSnapshot} performs the
* protective copying of this Timetable. It is not done in this update method to avoid
* repeatedly cloning the same Timetable when several updates are applied to it at once. We
* assume here that all trips in a timetable are from the same feed, which should always be the
* case.
*
* @param tripUpdate GTFS-RT trip update
* @param timeZone time zone of trip update
* @param updateServiceDate service date of trip update
* @return new copy of updated TripTimes after TripUpdate has been applied on TripTimes of trip
* with the id specified in the trip descriptor of the TripUpdate; null if something
* went wrong
*/
public TripTimes createUpdatedTripTimes(TripUpdate tripUpdate, TimeZone timeZone, ServiceDate updateServiceDate) {
if (tripUpdate == null) {
LOG.error("A null TripUpdate pointer was passed to the Timetable class update method.");
return null;
}
// However, we want to apply trip updates on top of *scheduled* times
if (!tripUpdate.hasTrip()) {
LOG.error("TripUpdate object has no TripDescriptor field.");
return null;
}
TripDescriptor tripDescriptor = tripUpdate.getTrip();
if (!tripDescriptor.hasTripId()) {
LOG.error("TripDescriptor object has no TripId field");
return null;
}
String tripId = tripDescriptor.getTripId();
int tripIndex = getTripIndex(tripId);
if (tripIndex == -1) {
LOG.info("tripId {} not found in pattern.", tripId);
return null;
} else {
LOG.trace("tripId {} found at index {} in timetable.", tripId, tripIndex);
}
TripTimes newTimes = new TripTimes(getTripTimes(tripIndex));
if (tripDescriptor.hasScheduleRelationship() && tripDescriptor.getScheduleRelationship() == TripDescriptor.ScheduleRelationship.CANCELED) {
newTimes.cancel();
} else {
// The GTFS-RT reference specifies that StopTimeUpdates are sorted by stop_sequence.
Iterator<StopTimeUpdate> updates = tripUpdate.getStopTimeUpdateList().iterator();
if (!updates.hasNext()) {
LOG.warn("Won't apply zero-length trip update to trip {}.", tripId);
return null;
}
StopTimeUpdate update = updates.next();
int numStops = newTimes.getNumStops();
Integer delay = null;
for (int i = 0; i < numStops; i++) {
boolean match = false;
if (update != null) {
if (update.hasStopSequence()) {
match = update.getStopSequence() == newTimes.getStopSequence(i);
} else if (update.hasStopId()) {
match = pattern.getStop(i).getId().getId().equals(update.getStopId());
}
}
if (match) {
StopTimeUpdate.ScheduleRelationship scheduleRelationship = update.hasScheduleRelationship() ? update.getScheduleRelationship() : StopTimeUpdate.ScheduleRelationship.SCHEDULED;
if (scheduleRelationship == StopTimeUpdate.ScheduleRelationship.SKIPPED) {
LOG.warn("Partially canceled trips are unsupported by this method." + " Skipping TripUpdate.");
return null;
} else if (scheduleRelationship == StopTimeUpdate.ScheduleRelationship.NO_DATA) {
newTimes.updateArrivalDelay(i, 0);
newTimes.updateDepartureDelay(i, 0);
delay = 0;
} else {
long today = updateServiceDate.getAsDate(timeZone).getTime() / 1000;
if (update.hasArrival()) {
StopTimeEvent arrival = update.getArrival();
if (arrival.hasDelay()) {
delay = arrival.getDelay();
if (arrival.hasTime()) {
newTimes.updateArrivalTime(i, (int) (arrival.getTime() - today));
} else {
newTimes.updateArrivalDelay(i, delay);
}
} else if (arrival.hasTime()) {
newTimes.updateArrivalTime(i, (int) (arrival.getTime() - today));
delay = newTimes.getArrivalDelay(i);
} else {
LOG.error("Arrival time at index {} is erroneous.", i);
return null;
}
} else {
if (delay == null) {
newTimes.updateArrivalTime(i, TripTimes.UNAVAILABLE);
} else {
newTimes.updateArrivalDelay(i, delay);
}
}
if (update.hasDeparture()) {
StopTimeEvent departure = update.getDeparture();
if (departure.hasDelay()) {
delay = departure.getDelay();
if (departure.hasTime()) {
newTimes.updateDepartureTime(i, (int) (departure.getTime() - today));
} else {
newTimes.updateDepartureDelay(i, delay);
}
} else if (departure.hasTime()) {
newTimes.updateDepartureTime(i, (int) (departure.getTime() - today));
delay = newTimes.getDepartureDelay(i);
} else {
LOG.error("Departure time at index {} is erroneous.", i);
return null;
}
} else {
if (delay == null) {
newTimes.updateDepartureTime(i, TripTimes.UNAVAILABLE);
} else {
newTimes.updateDepartureDelay(i, delay);
}
}
}
if (updates.hasNext()) {
update = updates.next();
} else {
update = null;
}
} else {
if (delay == null) {
newTimes.updateArrivalTime(i, TripTimes.UNAVAILABLE);
newTimes.updateDepartureTime(i, TripTimes.UNAVAILABLE);
} else {
newTimes.updateArrivalDelay(i, delay);
newTimes.updateDepartureDelay(i, delay);
}
}
}
if (update != null) {
LOG.error("Part of a TripUpdate object could not be applied successfully to trip {}.", tripId);
return null;
}
}
if (!newTimes.timesIncreasing()) {
LOG.error("TripTimes are non-increasing after applying GTFS-RT delay propagation to trip {}.", tripId);
return null;
}
LOG.debug("A valid TripUpdate object was applied to trip {} using the Timetable class update method.", tripId);
return newTimes;
}
use of com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeEvent in project onebusaway-application-modules by camsys.
the class GtfsRealtimeServiceImpl method getTripUpdates.
@Override
public FeedMessage getTripUpdates() {
FeedMessage.Builder feedMessage = createFeedWithDefaultHeader();
List<BlockLocation> activeBlocks = _blockStatusService.getAllActiveBlocks(SystemTime.currentTimeMillis());
for (BlockLocation activeBlock : activeBlocks) {
// Only interested in blocks with real-time data
if (!activeBlock.isPredicted())
continue;
// Only interested in blocks with a next stop
BlockStopTimeEntry nextBlockStop = activeBlock.getNextStop();
if (nextBlockStop == null)
continue;
// Only interested in blocks with a schedule deviation set
if (!activeBlock.isScheduleDeviationSet())
continue;
TripUpdate.Builder tripUpdate = TripUpdate.newBuilder();
BlockTripEntry activeBlockTrip = nextBlockStop.getTrip();
TripEntry activeTrip = activeBlockTrip.getTrip();
if (activeBlock.getTimepointPredictions() != null && activeBlock.getTimepointPredictions().size() > 0) {
// If multiple stoptime predictions were originally obtained,
// pass them through as received
List<TimepointPredictionRecord> timepointPredictions = activeBlock.getTimepointPredictions();
for (TimepointPredictionRecord tpr : timepointPredictions) {
StopTimeUpdate.Builder stopTimeUpdate = StopTimeUpdate.newBuilder();
stopTimeUpdate.setStopId(AgencyAndId.convertToString(tpr.getTimepointId()));
stopTimeUpdate.setScheduleRelationship(com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate.ScheduleRelationship.SCHEDULED);
if (tpr.getTimepointPredictedArrivalTime() != -1) {
StopTimeEvent.Builder arrivalStopTimeEvent = StopTimeEvent.newBuilder();
arrivalStopTimeEvent.setTime(tpr.getTimepointPredictedArrivalTime());
stopTimeUpdate.setArrival(arrivalStopTimeEvent);
}
if (tpr.getTimepointPredictedDepartureTime() != -1) {
StopTimeEvent.Builder departureStopTimeEvent = StopTimeEvent.newBuilder();
departureStopTimeEvent.setTime(tpr.getTimepointPredictedDepartureTime());
stopTimeUpdate.setDeparture(departureStopTimeEvent);
}
tripUpdate.addStopTimeUpdate(stopTimeUpdate);
}
} else {
// No matter what our active trip is, we let our current trip be the the
// trip of our next stop
StopTimeEntry nextStopTime = nextBlockStop.getStopTime();
StopEntry stop = nextStopTime.getStop();
StopTimeUpdate.Builder stopTimeUpdate = StopTimeUpdate.newBuilder();
stopTimeUpdate.setStopId(AgencyAndId.convertToString(stop.getId()));
stopTimeUpdate.setStopSequence(nextStopTime.getSequence());
stopTimeUpdate.setScheduleRelationship(com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate.ScheduleRelationship.SCHEDULED);
StopTimeEvent.Builder stopTimeEvent = StopTimeEvent.newBuilder();
stopTimeEvent.setDelay((int) activeBlock.getScheduleDeviation());
stopTimeUpdate.setDeparture(stopTimeEvent);
tripUpdate.addStopTimeUpdate(stopTimeUpdate);
}
AgencyAndId routeId = activeTrip.getRouteCollection().getId();
AgencyAndId tripId = activeTrip.getId();
BlockInstance blockInstance = activeBlock.getBlockInstance();
String startDate = String.format("%1$ty%1$tm%1$td", new Date(blockInstance.getServiceDate()));
TripDescriptor.Builder tripDescriptor = TripDescriptor.newBuilder();
tripDescriptor.setRouteId(AgencyAndId.convertToString(routeId));
tripDescriptor.setScheduleRelationship(ScheduleRelationship.SCHEDULED);
tripDescriptor.setStartDate(startDate);
tripDescriptor.setTripId(AgencyAndId.convertToString(tripId));
tripUpdate.setTrip(tripDescriptor);
AgencyAndId vehicleId = activeBlock.getVehicleId();
VehicleDescriptor.Builder vehicleDescriptor = VehicleDescriptor.newBuilder();
vehicleDescriptor.setId(AgencyAndId.convertToString(vehicleId));
tripUpdate.setVehicle(vehicleDescriptor);
FeedEntity.Builder feedEntity = FeedEntity.newBuilder();
feedEntity.setTripUpdate(tripUpdate);
feedEntity.setId(vehicleDescriptor.getId());
feedMessage.addEntity(feedEntity);
}
return feedMessage.build();
}
use of com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeEvent in project onebusaway-application-modules by camsys.
the class GtfsRealtimeTripLibraryTest method testStopRewriting.
@Test
public void testStopRewriting() {
StopTimeUpdate.Builder stopTimeUpdate = StopTimeUpdate.newBuilder();
stopTimeUpdate.setStopId("replaceA");
StopTimeEvent.Builder stopTimeEvent = StopTimeEvent.newBuilder();
stopTimeEvent.setDelay(180);
stopTimeUpdate.setDeparture(stopTimeEvent);
stopTimeUpdate.setStopSequence(0);
TripUpdate tripUpdate = TripUpdate.newBuilder().setTrip(TripDescriptor.newBuilder().setTripId("tripA")).setDelay(120).setTimestamp(123456789).addStopTimeUpdate(stopTimeUpdate).build();
TripEntryImpl tripA = trip("tripA");
stopTime(0, stop("stopA", 0, 0), tripA, time(7, 30), 0.0);
BlockEntryImpl blockA = block("blockA");
BlockConfigurationEntry blockConfigA = blockConfiguration(blockA, serviceIds("s1"), tripA);
BlockInstance blockInstanceA = new BlockInstance(blockConfigA, 0L);
Mockito.when(_blockCalendarService.getActiveBlocks(Mockito.eq(blockA.getId()), Mockito.anyLong(), Mockito.anyLong())).thenReturn(Collections.singletonList(blockInstanceA));
CombinedTripUpdatesAndVehiclePosition update = new CombinedTripUpdatesAndVehiclePosition();
update.block = new BlockDescriptor();
update.block.setBlockInstance(blockInstanceA);
update.tripUpdates = Collections.singletonList(tripUpdate);
StopModificationStrategy strategy = Mockito.mock(StopModificationStrategy.class);
Mockito.when(strategy.convertStopId("replaceA")).thenReturn("stopA");
_library.setStopModificationStrategy(strategy);
VehicleLocationRecord record = _library.createVehicleLocationRecordForUpdate(update);
assertEquals(123456789000L, record.getTimeOfRecord());
assertEquals(120, record.getScheduleDeviation(), 0.0);
TimepointPredictionRecord tpr = record.getTimepointPredictions().get(0);
long departure = tpr.getTimepointPredictedDepartureTime();
assertEquals(departure, time(7, 33) * 1000);
}
use of com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeEvent in project onebusaway-application-modules by camsys.
the class GtfsRealtimeTripLibraryTest method testCreateVehicleLocationRecordForUpdate_WithStopTimeUpdates.
@Test
public void testCreateVehicleLocationRecordForUpdate_WithStopTimeUpdates() {
StopTimeUpdate.Builder stopTimeUpdate = StopTimeUpdate.newBuilder();
stopTimeUpdate.setStopId("stopA");
StopTimeEvent.Builder stopTimeEvent = StopTimeEvent.newBuilder();
stopTimeEvent.setDelay(180);
stopTimeUpdate.setDeparture(stopTimeEvent);
TripUpdate tripUpdate = TripUpdate.newBuilder().setTrip(TripDescriptor.newBuilder().setTripId("tripA")).setDelay(120).setTimestamp(123456789).addStopTimeUpdate(stopTimeUpdate).build();
TripEntryImpl tripA = trip("tripA");
stopTime(0, stop("stopA", 0, 0), tripA, time(7, 30), 0.0);
BlockEntryImpl blockA = block("blockA");
BlockConfigurationEntry blockConfigA = blockConfiguration(blockA, serviceIds("s1"), tripA);
BlockInstance blockInstanceA = new BlockInstance(blockConfigA, 0L);
Mockito.when(_blockCalendarService.getActiveBlocks(Mockito.eq(blockA.getId()), Mockito.anyLong(), Mockito.anyLong())).thenReturn(Arrays.asList(blockInstanceA));
CombinedTripUpdatesAndVehiclePosition update = new CombinedTripUpdatesAndVehiclePosition();
update.block = new BlockDescriptor();
update.block.setBlockInstance(blockInstanceA);
update.tripUpdates = Arrays.asList(tripUpdate);
VehicleLocationRecord record = _library.createVehicleLocationRecordForUpdate(update);
TimepointPredictionRecord tpr = record.getTimepointPredictions().get(0);
long departure = tpr.getTimepointPredictedDepartureTime();
// 7:30 plus 3 min delay, + now we are in ms.
assertEquals(departure, time(7, 33) * 1000);
}
use of com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeEvent in project onebusaway-application-modules by camsys.
the class GtfsRealtimeRetrieverImpl method writeStopTimeUpdate.
private StopTimeUpdate writeStopTimeUpdate(StopTimeUpdateModel stum) {
if (stum == null)
return null;
StopTimeUpdate.Builder stu = StopTimeUpdate.newBuilder();
if (stum.getStopSequence() != null) {
stu.setStopSequence(stum.getStopSequence().intValue());
}
if (stum.getStopId() != null) {
String parsedStopId = parseId(stum.getStopId());
if (parsedStopId != null) {
stu.setStopId(parseId(stum.getStopId()));
} else {
// parsing failed (invalid agency-and-id) but pass along as is
stu.setStopId(stum.getStopId());
}
}
if (stum.getArrivalDelay() != null || stum.getArrivalTime() != null) {
StopTimeEvent arrival = writeStopTimeEvent(stum.getArrivalDelay(), stum.getArrivalTime(), stum.getArrivalUncertainty());
stu.setArrival(arrival);
}
if (stum.getDepartureDelay() != null || stum.getDepartureTime() != null) {
StopTimeEvent dept = writeStopTimeEvent(stum.getDepartureDelay(), stum.getDepartureTime(), stum.getDepartureUncertainty());
stu.setDeparture(dept);
}
StopTimeUpdate.ScheduleRelationship sr = StopTimeUpdate.ScheduleRelationship.valueOf(stum.getScheduleRelationship());
if (sr != null) {
stu.setScheduleRelationship(sr);
}
return stu.build();
}
Aggregations