use of uk.org.siri.siri20.RecordedCall in project OpenTripPlanner by opentripplanner.
the class SiriTimetableSnapshotSource method getTripForJourney.
/**
* Finds the correct trip based on OTP-ServiceDate and SIRI-DepartureTime
* @param trips
* @param journey
* @return
*/
private Set<Trip> getTripForJourney(Set<Trip> trips, EstimatedVehicleJourney journey) {
List<RecordedCall> recordedCalls = (journey.getRecordedCalls() != null ? journey.getRecordedCalls().getRecordedCalls() : new ArrayList<>());
List<EstimatedCall> estimatedCalls = journey.getEstimatedCalls().getEstimatedCalls();
ZonedDateTime date;
int stopNumber = 1;
String firstStopId;
if (recordedCalls != null && !recordedCalls.isEmpty()) {
RecordedCall recordedCall = recordedCalls.get(0);
date = recordedCall.getAimedDepartureTime();
firstStopId = recordedCall.getStopPointRef().getValue();
} else if (estimatedCalls != null && !estimatedCalls.isEmpty()) {
EstimatedCall estimatedCall = estimatedCalls.get(0);
if (estimatedCall.getOrder() != null) {
stopNumber = estimatedCall.getOrder().intValue();
} else if (estimatedCall.getVisitNumber() != null) {
stopNumber = estimatedCall.getVisitNumber().intValue();
}
firstStopId = estimatedCall.getStopPointRef().getValue();
date = estimatedCall.getAimedDepartureTime();
} else {
return null;
}
if (date == null) {
// If no date is set - assume Realtime-data is reported for 'today'.
date = ZonedDateTime.now();
}
ServiceDate serviceDate = new ServiceDate(date.getYear(), date.getMonthValue(), date.getDayOfMonth());
int departureInSecondsSinceMidnight = calculateSecondsSinceMidnight(date);
Set<Trip> result = new HashSet<>();
for (Iterator<Trip> iterator = trips.iterator(); iterator.hasNext(); ) {
Trip trip = iterator.next();
Set<ServiceDate> serviceDatesForServiceId = routingService.getCalendarService().getServiceDatesForServiceId(trip.getServiceId());
if (serviceDatesForServiceId.contains(serviceDate)) {
TripPattern pattern = routingService.getPatternForTrip().get(trip);
if (stopNumber < pattern.stopPattern.stops.length) {
boolean firstReportedStopIsFound = false;
Stop stop = pattern.stopPattern.stops[stopNumber - 1];
if (firstStopId.equals(stop.getId().getId())) {
firstReportedStopIsFound = true;
} else {
String agencyId = stop.getId().getFeedId();
if (stop.isPartOfStation()) {
Stop alternativeStop = routingService.getStopForId(new FeedScopedId(agencyId, firstStopId));
if (stop.isPartOfSameStationAs(alternativeStop)) {
firstReportedStopIsFound = true;
}
}
}
if (firstReportedStopIsFound) {
for (TripTimes times : getCurrentTimetable(pattern, serviceDate).tripTimes) {
if (times.getScheduledDepartureTime(stopNumber - 1) == departureInSecondsSinceMidnight) {
if (routingService.getCalendarService().getServiceDatesForServiceId(times.trip.getServiceId()).contains(serviceDate)) {
result.add(times.trip);
}
}
}
}
}
}
}
if (result.size() >= 1) {
return result;
} else {
return null;
}
}
use of uk.org.siri.siri20.RecordedCall in project OpenTripPlanner by opentripplanner.
the class TimetableHelper method createModifiedStops.
/**
* Apply the SIRI ET to the appropriate TripTimes from this Timetable.
* Calculate new stoppattern based on single stop cancellations
*
* @param journey SIRI-ET EstimatedVehicleJourney
* @param routingService
* @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 static List<Stop> createModifiedStops(Timetable timetable, EstimatedVehicleJourney journey, RoutingService routingService) {
if (journey == null) {
return null;
}
EstimatedVehicleJourney.EstimatedCalls journeyEstimatedCalls = journey.getEstimatedCalls();
EstimatedVehicleJourney.RecordedCalls journeyRecordedCalls = journey.getRecordedCalls();
if (journeyEstimatedCalls == null) {
return null;
}
List<EstimatedCall> estimatedCalls = journeyEstimatedCalls.getEstimatedCalls();
List<RecordedCall> recordedCalls;
if (journeyRecordedCalls != null) {
recordedCalls = journeyRecordedCalls.getRecordedCalls();
} else {
recordedCalls = new ArrayList<>();
}
// Get all scheduled stops
Stop[] stops = timetable.pattern.stopPattern.stops;
List<Stop> modifiedStops = new ArrayList<>();
for (int i = 0; i < stops.length; i++) {
Stop stop = stops[i];
boolean foundMatch = false;
if (i < recordedCalls.size()) {
for (RecordedCall recordedCall : recordedCalls) {
// Current stop is being updated
boolean stopsMatchById = stop.getId().getId().equals(recordedCall.getStopPointRef().getValue());
if (!stopsMatchById && stop.isPartOfStation()) {
Stop alternativeStop = routingService.getStopForId(new FeedScopedId(stop.getId().getFeedId(), recordedCall.getStopPointRef().getValue()));
if (alternativeStop != null && stop.isPartOfSameStationAs(alternativeStop)) {
stopsMatchById = true;
stop = alternativeStop;
}
}
if (stopsMatchById) {
foundMatch = true;
modifiedStops.add(stop);
break;
}
}
} else {
for (EstimatedCall estimatedCall : estimatedCalls) {
// Current stop is being updated
boolean stopsMatchById = stop.getId().getId().equals(estimatedCall.getStopPointRef().getValue());
if (!stopsMatchById && stop.isPartOfStation()) {
Stop alternativeStop = routingService.getStopForId(new FeedScopedId(stop.getId().getFeedId(), estimatedCall.getStopPointRef().getValue()));
if (alternativeStop != null && stop.isPartOfSameStationAs(alternativeStop)) {
stopsMatchById = true;
stop = alternativeStop;
}
}
if (stopsMatchById) {
foundMatch = true;
modifiedStops.add(stop);
break;
}
}
}
if (!foundMatch) {
modifiedStops.add(stop);
}
}
return modifiedStops;
}
use of uk.org.siri.siri20.RecordedCall in project OpenTripPlanner by opentripplanner.
the class TimetableHelper 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 journey SIRI-ET EstimatedVehicleJourney
* @param timeZone time zone of trip update
* @param tripId
* @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 static TripTimes createUpdatedTripTimes(final Graph graph, Timetable timetable, EstimatedVehicleJourney journey, TimeZone timeZone, FeedScopedId tripId) {
if (journey == null) {
return null;
}
int tripIndex = timetable.getTripIndex(tripId);
if (tripIndex == -1) {
LOG.debug("tripId {} not found in pattern.", tripId);
return null;
}
final TripTimes existingTripTimes = timetable.getTripTimes(tripIndex);
TripTimes oldTimes = new TripTimes(existingTripTimes);
if (journey.isCancellation() != null && journey.isCancellation()) {
oldTimes.cancel();
return oldTimes;
}
EstimatedVehicleJourney.EstimatedCalls journeyEstimatedCalls = journey.getEstimatedCalls();
EstimatedVehicleJourney.RecordedCalls journeyRecordedCalls = journey.getRecordedCalls();
if (journeyEstimatedCalls == null) {
return null;
}
List<EstimatedCall> estimatedCalls = journeyEstimatedCalls.getEstimatedCalls();
List<RecordedCall> recordedCalls;
if (journeyRecordedCalls != null) {
recordedCalls = journeyRecordedCalls.getRecordedCalls();
} else {
recordedCalls = new ArrayList<>();
}
boolean stopPatternChanged = false;
Stop[] modifiedStops = timetable.pattern.stopPattern.stops;
Trip trip = getTrip(tripId, timetable);
List<StopTime> modifiedStopTimes = createModifiedStopTimes(timetable, oldTimes, journey, trip, new RoutingService(graph));
if (modifiedStopTimes == null) {
return null;
}
TripTimes newTimes = new TripTimes(trip, modifiedStopTimes, graph.deduplicator);
// Populate missing data from existing TripTimes
newTimes.serviceCode = oldTimes.serviceCode;
int callCounter = 0;
ZonedDateTime departureDate = null;
Set<Object> alreadyVisited = new HashSet<>();
boolean isJourneyPredictionInaccurate = (journey.isPredictionInaccurate() != null && journey.isPredictionInaccurate());
int departureFromPreviousStop = 0;
int lastArrivalDelay = 0;
int lastDepartureDelay = 0;
for (Stop stop : modifiedStops) {
boolean foundMatch = false;
for (RecordedCall recordedCall : recordedCalls) {
if (alreadyVisited.contains(recordedCall)) {
continue;
}
// Current stop is being updated
foundMatch = stop.getId().getId().equals(recordedCall.getStopPointRef().getValue());
if (!foundMatch && stop.isPartOfStation()) {
Stop alternativeStop = graph.index.getStopForId(new FeedScopedId(stop.getId().getFeedId(), recordedCall.getStopPointRef().getValue()));
if (alternativeStop != null && stop.isPartOfSameStationAs(alternativeStop)) {
foundMatch = true;
stopPatternChanged = true;
}
}
if (foundMatch) {
if (departureDate == null) {
departureDate = recordedCall.getAimedDepartureTime();
if (departureDate == null) {
departureDate = recordedCall.getAimedArrivalTime();
}
if (oldTimes.getDepartureTime(0) > 86400) {
// The "departure-date" for this trip is set to "yesterday" (or before) even though it actually departs "today"
// calculate number of offset-days
int dayOffsetCount = oldTimes.getDepartureTime(0) / 86400;
departureDate = departureDate.minusDays(dayOffsetCount);
}
}
// Flag as recorded
newTimes.setRecorded(callCounter, true);
if (recordedCall.isCancellation() != null) {
newTimes.setCancelledStop(callCounter, recordedCall.isCancellation());
}
newTimes.setDropoffType(callCounter, timetable.pattern.stopPattern.dropoffs[callCounter]);
newTimes.setPickupType(callCounter, timetable.pattern.stopPattern.pickups[callCounter]);
int arrivalTime = newTimes.getArrivalTime(callCounter);
int realtimeArrivalTime = arrivalTime;
if (recordedCall.getActualArrivalTime() != null) {
realtimeArrivalTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getActualArrivalTime());
} else if (recordedCall.getExpectedArrivalTime() != null) {
realtimeArrivalTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getExpectedArrivalTime());
} else if (recordedCall.getAimedArrivalTime() != null) {
realtimeArrivalTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getAimedArrivalTime());
}
int arrivalDelay = realtimeArrivalTime - arrivalTime;
newTimes.updateArrivalDelay(callCounter, arrivalDelay);
lastArrivalDelay = arrivalDelay;
int departureTime = newTimes.getDepartureTime(callCounter);
int realtimeDepartureTime = departureTime;
if (recordedCall.getActualDepartureTime() != null) {
realtimeDepartureTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getActualDepartureTime());
} else if (recordedCall.getExpectedDepartureTime() != null) {
realtimeDepartureTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getExpectedDepartureTime());
} else if (recordedCall.getAimedDepartureTime() != null) {
realtimeDepartureTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getAimedDepartureTime());
}
if (realtimeDepartureTime < realtimeArrivalTime) {
realtimeDepartureTime = realtimeArrivalTime;
}
int departureDelay = realtimeDepartureTime - departureTime;
newTimes.updateDepartureDelay(callCounter, departureDelay);
lastDepartureDelay = departureDelay;
departureFromPreviousStop = newTimes.getDepartureTime(callCounter);
alreadyVisited.add(recordedCall);
break;
}
}
if (!foundMatch) {
for (EstimatedCall estimatedCall : estimatedCalls) {
if (alreadyVisited.contains(estimatedCall)) {
continue;
}
// Current stop is being updated
foundMatch = stop.getId().getId().equals(estimatedCall.getStopPointRef().getValue());
if (!foundMatch && stop.isPartOfStation()) {
Stop alternativeStop = graph.index.getStopForId(new FeedScopedId(stop.getId().getFeedId(), estimatedCall.getStopPointRef().getValue()));
if (alternativeStop != null && stop.isPartOfSameStationAs(alternativeStop)) {
foundMatch = true;
stopPatternChanged = true;
}
}
if (foundMatch) {
if (departureDate == null) {
departureDate = estimatedCall.getAimedDepartureTime();
if (departureDate == null) {
departureDate = estimatedCall.getAimedArrivalTime();
}
}
if (estimatedCall.isCancellation() != null) {
newTimes.setCancelledStop(callCounter, estimatedCall.isCancellation());
}
boolean isCallPredictionInaccurate = estimatedCall.isPredictionInaccurate() != null && estimatedCall.isPredictionInaccurate();
// Set flag for inaccurate prediction if either call OR journey has inaccurate-flag set.
newTimes.setPredictionInaccurate(callCounter, (isJourneyPredictionInaccurate | isCallPredictionInaccurate));
// Update dropoff-/pickuptype only if status is cancelled
CallStatusEnumeration arrivalStatus = estimatedCall.getArrivalStatus();
if (arrivalStatus == CallStatusEnumeration.CANCELLED) {
newTimes.setDropoffType(callCounter, PICKDROP_NONE);
}
CallStatusEnumeration departureStatus = estimatedCall.getDepartureStatus();
if (departureStatus == CallStatusEnumeration.CANCELLED) {
newTimes.setPickupType(callCounter, PICKDROP_NONE);
}
int arrivalTime = newTimes.getArrivalTime(callCounter);
int realtimeArrivalTime = -1;
if (estimatedCall.getExpectedArrivalTime() != null) {
realtimeArrivalTime = calculateSecondsSinceMidnight(departureDate, estimatedCall.getExpectedArrivalTime());
} else if (estimatedCall.getAimedArrivalTime() != null) {
realtimeArrivalTime = calculateSecondsSinceMidnight(departureDate, estimatedCall.getAimedArrivalTime());
}
int departureTime = newTimes.getDepartureTime(callCounter);
int realtimeDepartureTime = departureTime;
if (estimatedCall.getExpectedDepartureTime() != null) {
realtimeDepartureTime = calculateSecondsSinceMidnight(departureDate, estimatedCall.getExpectedDepartureTime());
} else if (estimatedCall.getAimedDepartureTime() != null) {
realtimeDepartureTime = calculateSecondsSinceMidnight(departureDate, estimatedCall.getAimedDepartureTime());
}
if (realtimeArrivalTime == -1) {
realtimeArrivalTime = realtimeDepartureTime;
}
if (realtimeDepartureTime < realtimeArrivalTime) {
realtimeDepartureTime = realtimeArrivalTime;
}
int arrivalDelay = realtimeArrivalTime - arrivalTime;
newTimes.updateArrivalDelay(callCounter, arrivalDelay);
lastArrivalDelay = arrivalDelay;
int departureDelay = realtimeDepartureTime - departureTime;
newTimes.updateDepartureDelay(callCounter, departureDelay);
lastDepartureDelay = departureDelay;
departureFromPreviousStop = newTimes.getDepartureTime(callCounter);
alreadyVisited.add(estimatedCall);
break;
}
}
}
if (!foundMatch) {
if (timetable.pattern.stopPattern.pickups[callCounter] == PICKDROP_NONE && timetable.pattern.stopPattern.dropoffs[callCounter] == PICKDROP_NONE) {
// When newTimes contains stops without pickup/dropoff - set both arrival/departure to previous stop's departure
// This necessary to accommodate the case when delay is reduced/eliminated between to stops with pickup/dropoff, and
// multiple non-pickup/dropoff stops are in between.
newTimes.updateArrivalTime(callCounter, departureFromPreviousStop);
newTimes.updateDepartureTime(callCounter, departureFromPreviousStop);
} else {
int arrivalDelay = lastArrivalDelay;
int departureDelay = lastDepartureDelay;
if (lastArrivalDelay == 0 && lastDepartureDelay == 0) {
// No match has been found yet (i.e. still in RecordedCalls) - keep existing delays
arrivalDelay = existingTripTimes.getArrivalDelay(callCounter);
departureDelay = existingTripTimes.getDepartureDelay(callCounter);
}
newTimes.updateArrivalDelay(callCounter, arrivalDelay);
newTimes.updateDepartureDelay(callCounter, departureDelay);
}
departureFromPreviousStop = newTimes.getDepartureTime(callCounter);
}
callCounter++;
}
if (stopPatternChanged) {
// This update modified stopPattern
newTimes.setRealTimeState(RealTimeState.MODIFIED);
} else {
// This is the first update, and StopPattern has not been changed
newTimes.setRealTimeState(RealTimeState.UPDATED);
}
if (journey.isCancellation() != null && journey.isCancellation()) {
LOG.debug("Trip is cancelled");
newTimes.cancel();
}
if (!newTimes.timesIncreasing()) {
LOG.info("TripTimes are non-increasing after applying SIRI delay propagation - LineRef {}, TripId {}.", journey.getLineRef().getValue(), tripId);
return null;
}
if (newTimes.getNumStops() != timetable.pattern.stopPattern.stops.length) {
return null;
}
LOG.debug("A valid TripUpdate object was applied using the Timetable class update method.");
return newTimes;
}
use of uk.org.siri.siri20.RecordedCall in project OpenTripPlanner by opentripplanner.
the class SiriTimetableSnapshotSource method getPatternForTrip.
private TripPattern getPatternForTrip(Trip trip, EstimatedVehicleJourney journey) {
Set<ServiceDate> serviceDates = routingService.getCalendarService().getServiceDatesForServiceId(trip.getServiceId());
List<RecordedCall> recordedCalls = (journey.getRecordedCalls() != null ? journey.getRecordedCalls().getRecordedCalls() : new ArrayList<>());
List<EstimatedCall> estimatedCalls = journey.getEstimatedCalls().getEstimatedCalls();
String journeyFirstStopId;
ServiceDate journeyDate;
if (recordedCalls != null && !recordedCalls.isEmpty()) {
RecordedCall recordedCall = recordedCalls.get(0);
journeyFirstStopId = recordedCall.getStopPointRef().getValue();
journeyDate = new ServiceDate(Date.from(recordedCall.getAimedDepartureTime().toInstant()));
} else if (estimatedCalls != null && !estimatedCalls.isEmpty()) {
EstimatedCall estimatedCall = estimatedCalls.get(0);
journeyFirstStopId = estimatedCall.getStopPointRef().getValue();
journeyDate = new ServiceDate(Date.from(estimatedCall.getAimedDepartureTime().toInstant()));
} else {
return null;
}
String journeyLastStopId = estimatedCalls.get(estimatedCalls.size() - 1).getStopPointRef().getValue();
TripPattern lastAddedTripPattern = null;
if (getTimetableSnapshot() != null) {
lastAddedTripPattern = getTimetableSnapshot().getLastAddedTripPattern(trip.getId(), journeyDate);
}
TripPattern tripPattern;
if (lastAddedTripPattern != null) {
tripPattern = lastAddedTripPattern;
} else {
tripPattern = routingService.getPatternForTrip().get(trip);
}
Stop firstStop = tripPattern.getStop(0);
Stop lastStop = tripPattern.getStop(tripPattern.getStops().size() - 1);
if (serviceDates.contains(journeyDate)) {
boolean firstStopIsMatch = firstStop.getId().getId().equals(journeyFirstStopId);
boolean lastStopIsMatch = lastStop.getId().getId().equals(journeyLastStopId);
if (!firstStopIsMatch && firstStop.isPartOfStation()) {
Stop otherFirstStop = routingService.getStopForId(new FeedScopedId(firstStop.getId().getFeedId(), journeyFirstStopId));
firstStopIsMatch = firstStop.isPartOfSameStationAs(otherFirstStop);
}
if (!lastStopIsMatch && lastStop.isPartOfStation()) {
Stop otherLastStop = routingService.getStopForId(new FeedScopedId(lastStop.getId().getFeedId(), journeyLastStopId));
lastStopIsMatch = lastStop.isPartOfSameStationAs(otherLastStop);
}
if (firstStopIsMatch & lastStopIsMatch) {
// Found matches
return tripPattern;
}
return null;
}
return null;
}
Aggregations