use of org.opentripplanner.model.TripPattern in project OpenTripPlanner by opentripplanner.
the class NearbyStopFinder method findNearbyStopsConsideringPatterns.
/**
* Find all unique nearby stops that are the closest stop on some trip pattern or flex trip.
* Note that the result will include the origin vertex if it is an instance of StopVertex.
* This is intentional: we don't want to return the next stop down the line for trip patterns that pass through the
* origin vertex.
*/
public Set<StopAtDistance> findNearbyStopsConsideringPatterns(Vertex vertex, boolean reverseDirection) {
/* Track the closest stop on each pattern passing nearby. */
MinMap<TripPattern, StopAtDistance> closestStopForPattern = new MinMap<TripPattern, StopAtDistance>();
/* Track the closest stop on each flex trip nearby. */
MinMap<FlexTrip, StopAtDistance> closestStopForFlexTrip = new MinMap<>();
/* Iterate over nearby stops via the street network or using straight-line distance, depending on the graph. */
for (StopAtDistance stopAtDistance : findNearbyStops(vertex, reverseDirection)) {
StopLocation ts1 = stopAtDistance.stop;
if (ts1 instanceof Stop) {
/* Consider this destination stop as a candidate for every trip pattern passing through it. */
for (TripPattern pattern : graph.index.getPatternsForStop(ts1)) {
closestStopForPattern.putMin(pattern, stopAtDistance);
}
}
if (OTPFeature.FlexRouting.isOn()) {
for (FlexTrip trip : graph.index.getFlexIndex().flexTripsByStop.get(ts1)) {
closestStopForFlexTrip.putMin(trip, stopAtDistance);
}
}
}
/* Make a transfer from the origin stop to each destination stop that was the closest stop on any pattern. */
Set<StopAtDistance> uniqueStops = Sets.newHashSet();
uniqueStops.addAll(closestStopForFlexTrip.values());
uniqueStops.addAll(closestStopForPattern.values());
return uniqueStops;
}
use of org.opentripplanner.model.TripPattern in project OpenTripPlanner by opentripplanner.
the class GeometryAndBlockProcessor method run.
/**
* Generate the edges. Assumes that there are already vertices in the graph for the stops.
*/
@SuppressWarnings("Convert2MethodRef")
public void run(Graph graph, DataImportIssueStore issueStore) {
this.issueStore = issueStore;
fareServiceFactory.processGtfs(transitService);
/* Assign 0-based numeric codes to all GTFS service IDs. */
for (FeedScopedId serviceId : transitService.getAllServiceIds()) {
// TODO: FIX Service code collision for multiple feeds.
graph.getServiceCodes().put(serviceId, graph.getServiceCodes().size());
}
LOG.info("Processing geometries and blocks on graph...");
// Wwe have to build the hop geometries before we throw away the modified stopTimes, saving
// only the tripTimes (which don't have enough information to build a geometry). So we keep
// them here. In the current design, a trip pattern does not have a single geometry, but
// one per hop, so we store them in an array.
Map<TripPattern, LineString[]> geometriesByTripPattern = Maps.newHashMap();
Collection<TripPattern> tripPatterns = transitService.getTripPatterns();
/* Generate unique short IDs for all the TableTripPatterns. */
if (!TripPattern.idsAreUniqueAndNotNull(tripPatterns)) {
TripPattern.generateUniqueIds(tripPatterns);
}
/* Generate unique human-readable names for all the TableTripPatterns. */
TripPattern.generateUniqueNames(tripPatterns, issueStore);
/* Loop over all new TripPatterns, creating edges, setting the service codes and geometries, etc. */
ProgressTracker progress = ProgressTracker.track("Generate TripPattern geometries", 100, tripPatterns.size());
LOG.info(progress.startMessage());
for (TripPattern tripPattern : tripPatterns) {
for (Trip trip : tripPattern.getTrips()) {
// there would be a trip pattern with no geometry yet because it failed some of these tests
if (!geometriesByTripPattern.containsKey(tripPattern) && trip.getShapeId() != null && trip.getShapeId().getId() != null && !trip.getShapeId().getId().equals("")) {
// save the geometry to later be applied to the hops
geometriesByTripPattern.put(tripPattern, createGeometry(trip.getShapeId(), transitService.getStopTimesForTrip(trip)));
}
}
// Keep lambda! A method-ref would causes incorrect class and line number to be logged
progress.step(m -> LOG.info(m));
}
LOG.info(progress.completeMessage());
/* Loop over all new TripPatterns setting the service codes and geometries, etc. */
for (TripPattern tripPattern : tripPatterns) {
LineString[] hopGeometries = geometriesByTripPattern.get(tripPattern);
if (hopGeometries != null) {
// Make a single unified geometry, and also store the per-hop split geometries.
tripPattern.setHopGeometries(hopGeometries);
}
// TODO this could be more elegant
tripPattern.setServiceCodes(graph.getServiceCodes());
// Store the tripPattern in the Graph so it will be serialized and usable in routing.
graph.tripPatternForId.put(tripPattern.getId(), tripPattern);
}
/* Identify interlined trips and create the necessary edges. */
interline(tripPatterns, graph);
// it is already done at deserialization, but standalone mode allows using graphs without serializing them.
for (TripPattern tableTripPattern : tripPatterns) {
tableTripPattern.scheduledTimetable.finish();
}
graph.putService(FareService.class, fareServiceFactory.makeFareService());
}
use of org.opentripplanner.model.TripPattern in project OpenTripPlanner by opentripplanner.
the class BusRouteStreetMatcher method buildGraph.
public void buildGraph(Graph graph, HashMap<Class<?>, Object> extra, DataImportIssueStore issueStore) {
// Mapbuilder needs transit index
graph.index();
StreetMatcher matcher = new StreetMatcher(graph);
log.info("Finding corresponding street edges for trip patterns...");
// Why do we need to iterate over the routes? Why not just patterns?
Collection<Route> allRoutes = graph.index.getAllRoutes();
// Track progress
ProgressTracker progress = ProgressTracker.track("Match route to street edges", 10, allRoutes.size());
log.info(progress.startMessage());
for (Route route : allRoutes) {
for (TripPattern pattern : graph.index.getPatternsForRoute().get(route)) {
if (pattern.getMode() == TransitMode.BUS) {
/* we can only match geometry to streets on bus routes */
log.debug("Matching {}", pattern);
// that is why pattern.geometry is null in that case
if (pattern.getGeometry() == null) {
continue;
}
for (int i = 0; i < pattern.numHopGeometries(); i++) {
LineString hopGeometry = pattern.getHopGeometry(i);
List<Edge> edges = matcher.match(hopGeometry);
if (edges == null || edges.isEmpty()) {
log.warn("Could not match to street network: {}", pattern);
continue;
}
List<Coordinate> coordinates = new ArrayList<>();
for (Edge e : edges) {
coordinates.addAll(Arrays.asList(e.getGeometry().getCoordinates()));
}
Coordinate[] coordinateArray = new Coordinate[coordinates.size()];
LineString ls = GeometryUtils.getGeometryFactory().createLineString(coordinates.toArray(coordinateArray));
// Replace the hop's geometry from GTFS with that of the equivalent OSM edges.
pattern.setHopGeometry(i, ls);
}
}
}
progress.step(log::info);
}
log.info(progress.completeMessage());
}
use of org.opentripplanner.model.TripPattern 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 org.opentripplanner.model.TripPattern in project OpenTripPlanner by opentripplanner.
the class SiriTimetableSnapshotSource method addTripToGraphAndBuffer.
/**
* Add a (new) trip to the graph and the buffer
*
* @return true if successful
*/
private boolean addTripToGraphAndBuffer(final String feedId, final Graph graph, final Trip trip, final List<StopTime> stopTimes, final List<Stop> stops, TripTimes updatedTripTimes, final ServiceDate serviceDate) {
// Preconditions
Preconditions.checkNotNull(stops);
Preconditions.checkArgument(stopTimes.size() == stops.size(), "number of stop should match the number of stop time updates");
// Create StopPattern
final StopPattern stopPattern = new StopPattern(stopTimes);
// Get cached trip pattern or create one if it doesn't exist yet
final TripPattern pattern = tripPatternCache.getOrCreateTripPattern(stopPattern, trip, graph, serviceDate);
// Add service code to bitset of pattern if needed (using copy on write)
final int serviceCode = graph.getServiceCodes().get(trip.getServiceId());
if (!pattern.getServices().get(serviceCode)) {
final BitSet services = (BitSet) pattern.getServices().clone();
services.set(serviceCode);
pattern.setServices(services);
}
/*
* Update pattern with triptimes so get correct dwell times and lower bound on running times.
* New patterns only affects a single trip, previously added tripTimes is no longer valid, and is therefore removed
*/
pattern.scheduledTimetable.tripTimes.clear();
pattern.scheduledTimetable.addTripTimes(updatedTripTimes);
pattern.scheduledTimetable.finish();
// Remove trip times to avoid real time trip times being visible for ignoreRealtimeInformation queries
pattern.scheduledTimetable.tripTimes.clear();
// Add to buffer as-is to include it in the 'lastAddedTripPattern'
buffer.update(pattern, updatedTripTimes, serviceDate);
// TODO - SIRI: Add pattern to index?
// Add new trip times to the buffer
final boolean success = buffer.update(pattern, updatedTripTimes, serviceDate);
return success;
}
Aggregations