use of org.opentripplanner.model.TripPattern in project OpenTripPlanner by opentripplanner.
the class SiriTimetableSnapshotSource method handleModifiedTrip.
private boolean handleModifiedTrip(Graph graph, String feedId, EstimatedVehicleJourney estimatedVehicleJourney) {
// Check if EstimatedVehicleJourney is reported as NOT monitored
if (estimatedVehicleJourney.isMonitored() != null && !estimatedVehicleJourney.isMonitored()) {
// Ignore the notMonitored-flag if the journey is NOT monitored because it has been cancelled
if (estimatedVehicleJourney.isCancellation() != null && !estimatedVehicleJourney.isCancellation()) {
return false;
}
}
// Values used in logging
String operatorRef = (estimatedVehicleJourney.getOperatorRef() != null ? estimatedVehicleJourney.getOperatorRef().getValue() : null);
String vehicleModes = "" + estimatedVehicleJourney.getVehicleModes();
String lineRef = estimatedVehicleJourney.getLineRef().getValue();
String vehicleRef = (estimatedVehicleJourney.getVehicleRef() != null ? estimatedVehicleJourney.getVehicleRef().getValue() : null);
ServiceDate serviceDate = getServiceDateForEstimatedVehicleJourney(estimatedVehicleJourney);
if (serviceDate == null) {
return false;
}
Set<TripTimes> times = new HashSet<>();
Set<TripPattern> patterns = new HashSet<>();
Trip tripMatchedByServiceJourneyId = siriFuzzyTripMatcher.findTripByDatedVehicleJourneyRef(estimatedVehicleJourney);
if (tripMatchedByServiceJourneyId != null) {
/*
Found exact match
*/
TripPattern exactPattern = routingService.getPatternForTrip().get(tripMatchedByServiceJourneyId);
if (exactPattern != null) {
Timetable currentTimetable = getCurrentTimetable(exactPattern, serviceDate);
TripTimes exactUpdatedTripTimes = createUpdatedTripTimes(graph, currentTimetable, estimatedVehicleJourney, timeZone, tripMatchedByServiceJourneyId.getId());
if (exactUpdatedTripTimes != null) {
times.add(exactUpdatedTripTimes);
patterns.add(exactPattern);
} else {
LOG.info("Failed to update TripTimes for trip found by exact match {}", tripMatchedByServiceJourneyId.getId());
return false;
}
}
} else {
/*
No exact match found - search for trips based on arrival-times/stop-patterns
*/
Set<Trip> trips = siriFuzzyTripMatcher.match(estimatedVehicleJourney);
if (trips == null || trips.isEmpty()) {
LOG.debug("No trips found for EstimatedVehicleJourney. [operator={}, vehicleModes={}, lineRef={}, vehicleRef={}]", operatorRef, vehicleModes, lineRef, vehicleRef);
return false;
}
// Find the trips that best corresponds to EstimatedVehicleJourney
Set<Trip> matchingTrips = getTripForJourney(trips, estimatedVehicleJourney);
if (matchingTrips == null || matchingTrips.isEmpty()) {
LOG.debug("Found no matching trip for SIRI ET (serviceDate, departureTime). [operator={}, vehicleModes={}, lineRef={}, vehicleJourneyRef={}]", operatorRef, vehicleModes, lineRef, vehicleRef);
return false;
}
for (Trip matchingTrip : matchingTrips) {
TripPattern pattern = getPatternForTrip(matchingTrip, estimatedVehicleJourney);
if (pattern != null) {
Timetable currentTimetable = getCurrentTimetable(pattern, serviceDate);
TripTimes updatedTripTimes = createUpdatedTripTimes(graph, currentTimetable, estimatedVehicleJourney, timeZone, matchingTrip.getId());
if (updatedTripTimes != null) {
patterns.add(pattern);
times.add(updatedTripTimes);
}
}
}
}
if (patterns.isEmpty()) {
LOG.debug("Found no matching pattern for SIRI ET (firstStopId, lastStopId, numberOfStops). [operator={}, vehicleModes={}, lineRef={}, vehicleRef={}]", operatorRef, vehicleModes, lineRef, vehicleRef);
return false;
}
if (times.isEmpty()) {
return false;
}
boolean result = false;
for (TripTimes tripTimes : times) {
Trip trip = tripTimes.trip;
for (TripPattern pattern : patterns) {
if (tripTimes.getNumStops() == pattern.stopPattern.stops.length) {
if (!tripTimes.isCanceled()) {
/*
UPDATED and MODIFIED tripTimes should be handled the same way to always allow latest realtime-update
to replace previous update regardless of realtimestate
*/
cancelScheduledTrip(feedId, trip.getId().getId(), serviceDate);
// Check whether trip id has been used for previously ADDED/MODIFIED trip message and cancel
// previously created trip
cancelPreviouslyAddedTrip(feedId, trip.getId().getId(), serviceDate);
// Calculate modified stop-pattern
Timetable currentTimetable = getCurrentTimetable(pattern, serviceDate);
List<Stop> modifiedStops = createModifiedStops(currentTimetable, estimatedVehicleJourney, routingService);
List<StopTime> modifiedStopTimes = createModifiedStopTimes(currentTimetable, tripTimes, estimatedVehicleJourney, trip, routingService);
if (modifiedStops != null && modifiedStops.isEmpty()) {
tripTimes.cancel();
} else {
// Add new trip
result = result | addTripToGraphAndBuffer(feedId, graph, trip, modifiedStopTimes, modifiedStops, tripTimes, serviceDate);
}
} else {
result = result | buffer.update(pattern, tripTimes, serviceDate);
}
LOG.debug("Applied realtime data for trip {}", trip.getId().getId());
} else {
LOG.debug("Ignoring update since number of stops do not match");
}
}
}
return result;
}
use of org.opentripplanner.model.TripPattern 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;
}
use of org.opentripplanner.model.TripPattern in project OpenTripPlanner by opentripplanner.
the class TripServiceDateKey method getOrCreateTripPattern.
/**
* Get cached trip pattern or create one if it doesn't exist yet. If a trip pattern is created, vertices
* and edges for this trip pattern are also created in the graph.
*
* @param stopPattern stop pattern to retrieve/create trip pattern
* @param trip Trip containing route of new trip pattern in case a new trip pattern will be created
* @param graph graph to add vertices and edges in case a new trip pattern will be created
* @param serviceDate
* @return cached or newly created trip pattern
*/
public synchronized TripPattern getOrCreateTripPattern(@NotNull final StopPattern stopPattern, @NotNull final Trip trip, @NotNull final Graph graph, @NotNull ServiceDate serviceDate) {
// Check cache for trip pattern
StopPatternServiceDateKey key = new StopPatternServiceDateKey(stopPattern, serviceDate);
TripPattern tripPattern = cache.get(key);
// Create TripPattern if it doesn't exist yet
if (tripPattern == null) {
tripPattern = new TripPattern(trip.getRoute(), stopPattern);
// Generate unique code for trip pattern
// TODO - SIRI: Is this a good way to generate new trippPattern.id?
tripPattern.setId(new FeedScopedId(trip.getId().getFeedId(), generateUniqueTripPatternCode(tripPattern)));
// Create an empty bitset for service codes (because the new pattern does not contain any trips)
tripPattern.setServiceCodes(graph.getServiceCodes());
// Finish scheduled time table
tripPattern.scheduledTimetable.finish();
// Create vertices and edges for new TripPattern
// TODO: purge these vertices and edges once in a while?
// tripPattern.makePatternVerticesAndEdges(graph, graph.index.stopVertexForStop);
// TODO - SIRI: Add pattern to graph index?
TripPattern originalTripPattern = graph.index.getPatternForTrip().get(trip);
// Copy information from the TripPattern this is replacing
if (originalTripPattern != null) {
tripPattern.setId(originalTripPattern.getId());
tripPattern.setHopGeometriesFromPattern(originalTripPattern);
}
// Add pattern to cache
cache.put(key, tripPattern);
}
/**
* When the StopPattern is first modified (e.g. change of platform), then updated (or vice versa), the stopPattern is altered, and
* the StopPattern-object for the different states will not be equal.
*
* This causes both tripPatterns to be added to all unchanged stops along the route, which again causes duplicate results
* in departureRow-searches (one departure for "updated", one for "modified").
*
* Full example:
* Planned stops: Stop 1 - Platform 1, Stop 2 - Platform 1
*
* StopPattern #rt1: "updated" stopPattern cached in 'patternsForStop':
* - Stop 1, Platform 1
* - StopPattern #rt1
* - Stop 2, Platform 1
* - StopPattern #rt1
*
* "modified" stopPattern: Stop 1 - Platform 1, Stop 2 - Platform 2
*
* StopPattern #rt2: "modified" stopPattern cached in 'patternsForStop' will then be:
* - Stop 1, Platform 1
* - StopPattern #rt1, StopPattern #rt2
* - Stop 2, Platform 1
* - StopPattern #rt1
* - Stop 2, Platform 2
* - StopPattern #rt2
*
* Therefore, we must cleanup the duplicates by deleting the previously added (and thus outdated)
* tripPattern for all affected stops. In example above, "StopPattern #rt1" should be removed from all stops
*/
TripServiceDateKey tripServiceDateKey = new TripServiceDateKey(trip, serviceDate);
if (updatedTripPatternsForTripCache.containsKey(tripServiceDateKey)) {
/**
* Remove previously added TripPatterns for the trip currently being updated - if the stopPattern does not match
*/
TripPattern cachedTripPattern = updatedTripPatternsForTripCache.get(tripServiceDateKey);
if (cachedTripPattern != null && !tripPattern.stopPattern.equals(cachedTripPattern.stopPattern)) {
int sizeBefore = patternsForStop.values().size();
long t1 = System.currentTimeMillis();
patternsForStop.values().removeAll(Arrays.asList(cachedTripPattern));
int sizeAfter = patternsForStop.values().size();
log.info("Removed outdated TripPattern for {} stops in {} ms - tripId: {}", (sizeBefore - sizeAfter), (System.currentTimeMillis() - t1), trip.getId());
/*
TODO: Also remove previously updated - now outdated - TripPattern from cache ?
cache.remove(new StopPatternServiceDateKey(cachedTripPattern.stopPattern, serviceDate));
*/
}
}
// To make these trip patterns visible for departureRow searches.
for (Stop stop : tripPattern.getStops()) {
if (!patternsForStop.containsEntry(stop, tripPattern)) {
patternsForStop.put(stop, tripPattern);
}
}
/**
* Cache the last added tripPattern that has been used to update a specific trip
*/
updatedTripPatternsForTripCache.put(tripServiceDateKey, tripPattern);
return tripPattern;
}
use of org.opentripplanner.model.TripPattern in project OpenTripPlanner by opentripplanner.
the class LegacyGraphQLStopImpl method stopTimesForPattern.
@Override
public DataFetcher<Iterable<TripTimeShort>> stopTimesForPattern() {
return environment -> getValue(environment, stop -> {
RoutingService routingService = getRoutingService(environment);
LegacyGraphQLTypes.LegacyGraphQLStopStopTimesForPatternArgs args = new LegacyGraphQLTypes.LegacyGraphQLStopStopTimesForPatternArgs(environment.getArguments());
TripPattern pattern = routingService.getTripPatternForId(FeedScopedId.parseId(args.getLegacyGraphQLId()));
if (pattern == null) {
return null;
}
;
return routingService.stopTimesForPatternAtStop(stop, pattern, args.getLegacyGraphQLStartTime(), args.getLegacyGraphQLTimeRange(), args.getLegacyGraphQLNumberOfDepartures(), args.getLegacyGraphQLOmitNonPickups());
}, station -> null);
}
use of org.opentripplanner.model.TripPattern in project OpenTripPlanner by opentripplanner.
the class AddTransitModelEntitiesToGraph method addStopsToGraphAndGenerateStopVertexes.
private void addStopsToGraphAndGenerateStopVertexes(Graph graph) {
// Compute the set of modes for each stop based on all the TripPatterns it is part of
Map<Stop, Set<TransitMode>> stopModeMap = new HashMap<>();
for (TripPattern pattern : transitService.getTripPatterns()) {
TransitMode mode = pattern.getMode();
graph.addTransitMode(mode);
for (Stop stop : pattern.getStops()) {
Set<TransitMode> set = stopModeMap.computeIfAbsent(stop, s -> new HashSet<>());
set.add(mode);
}
}
// It is now possible for these vertices to not be connected to any edges.
for (Stop stop : transitService.getAllStops()) {
Set<TransitMode> modes = stopModeMap.get(stop);
TransitStopVertex stopVertex = new TransitStopVertex(graph, stop, modes);
if (modes != null && modes.contains(TransitMode.SUBWAY)) {
stopVertex.setStreetToStopTime(subwayAccessTime);
}
// Add stops to internal index for Pathways to be created from this map
stationElementNodes.put(stop, stopVertex);
}
}
Aggregations