use of org.opentripplanner.model.StopPattern in project OpenTripPlanner by opentripplanner.
the class GTFSPatternHopFactory method run.
/**
* Generate the edges. Assumes that there are already vertices in the graph for the stops.
*/
public void run(Graph graph) {
if (fareServiceFactory == null) {
fareServiceFactory = new DefaultFareServiceFactory();
}
fareServiceFactory.processGtfs(_dao);
// TODO: Why are we loading stops? The Javadoc above says this method assumes stops are aleady loaded.
loadStops(graph);
loadPathways(graph);
loadFeedInfo(graph);
loadAgencies(graph);
// TODO: Why is there cached "data", and why are we clearing it? Due to a general lack of comments, I have no idea.
// Perhaps it is to allow name collisions with previously loaded feeds.
clearCachedData();
/* Assign 0-based numeric codes to all GTFS service IDs. */
for (AgencyAndId serviceId : _dao.getAllServiceIds()) {
// TODO: FIX Service code collision for multiple feeds.
graph.serviceCodes.put(serviceId, graph.serviceCodes.size());
}
LOG.debug("building hops from trips");
Collection<Trip> trips = _dao.getAllTrips();
int tripCount = 0;
/* First, record which trips are used by one or more frequency entries.
* These trips will be ignored for the purposes of non-frequency routing, and
* all the frequency entries referencing the same trip can be added at once to the same
* Timetable/TripPattern.
*/
ListMultimap<Trip, Frequency> frequenciesForTrip = ArrayListMultimap.create();
for (Frequency freq : _dao.getAllFrequencies()) {
frequenciesForTrip.put(freq.getTrip(), freq);
}
/* Then loop over all trips, handling each one as a frequency-based or scheduled trip. */
int freqCount = 0;
int nonFreqCount = 0;
/* The hops don't actually exist when we build their geometries, but we have to build their geometries
* below, 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.
*
* A trip pattern actually does not have a single geometry, but one per hop, so we store an array.
* FIXME _why_ doesn't it have a single geometry?
*/
Map<TripPattern, LineString[]> geometriesByTripPattern = Maps.newHashMap();
TRIP: for (Trip trip : trips) {
if (++tripCount % 100000 == 0) {
LOG.debug("loading trips {}/{}", tripCount, trips.size());
}
// TODO: move to a validator module
if (!_calendarService.getServiceIds().contains(trip.getServiceId())) {
LOG.warn(graph.addBuilderAnnotation(new TripUndefinedService(trip)));
// Invalid trip, skip it, it will break later
continue TRIP;
}
/* Fetch the stop times for this trip. Copy the list since it's immutable. */
List<StopTime> stopTimes = new ArrayList<StopTime>(_dao.getStopTimesForTrip(trip));
/* GTFS stop times frequently contain duplicate, missing, or incorrect entries. Repair them. */
TIntList removedStopSequences = removeRepeatedStops(stopTimes);
if (!removedStopSequences.isEmpty()) {
LOG.warn(graph.addBuilderAnnotation(new RepeatedStops(trip, removedStopSequences)));
}
filterStopTimes(stopTimes, graph);
interpolateStopTimes(stopTimes);
/* If after filtering this trip does not contain at least 2 stoptimes, it does not serve any purpose. */
if (stopTimes.size() < 2) {
LOG.warn(graph.addBuilderAnnotation(new TripDegenerate(trip)));
continue TRIP;
}
/* Try to get the direction id for the trip, set to -1 if not found */
int directionId;
try {
directionId = Integer.parseInt(trip.getDirectionId());
} catch (NumberFormatException e) {
LOG.debug("Trip {} does not have direction id, defaults to -1");
directionId = -1;
}
/* Get the existing TripPattern for this filtered StopPattern, or create one. */
StopPattern stopPattern = new StopPattern(stopTimes);
TripPattern tripPattern = findOrCreateTripPattern(stopPattern, trip.getRoute(), directionId);
/* Create a TripTimes object for this list of stoptimes, which form one trip. */
TripTimes tripTimes = new TripTimes(trip, stopTimes, graph.deduplicator);
/* If this trip is referenced by one or more lines in frequencies.txt, wrap it in a FrequencyEntry. */
List<Frequency> frequencies = frequenciesForTrip.get(trip);
if (frequencies != null && !(frequencies.isEmpty())) {
for (Frequency freq : frequencies) {
tripPattern.add(new FrequencyEntry(freq, tripTimes));
freqCount++;
}
// TODO replace: createGeometry(graph, trip, stopTimes, hops);
} else /* This trip was not frequency-based. Add the TripTimes directly to the TripPattern's scheduled timetable. */
{
tripPattern.add(tripTimes);
nonFreqCount++;
}
// 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(graph, trip, stopTimes));
}
}
// end foreach TRIP
LOG.info("Added {} frequency-based and {} single-trip timetable entries.", freqCount, nonFreqCount);
graph.hasFrequencyService = graph.hasFrequencyService || freqCount > 0;
graph.hasScheduledService = graph.hasScheduledService || nonFreqCount > 0;
/* Generate unique human-readable names for all the TableTripPatterns. */
TripPattern.generateUniqueNames(tripPatterns.values());
/* Generate unique short IDs for all the TableTripPatterns. */
TripPattern.generateUniqueIds(tripPatterns.values());
/* Loop over all new TripPatterns, creating edges, setting the service codes and geometries, etc. */
for (TripPattern tripPattern : tripPatterns.values()) {
tripPattern.makePatternVerticesAndEdges(graph, context.stationStopNodes);
// Add the geometries to the hop edges.
LineString[] geom = geometriesByTripPattern.get(tripPattern);
if (geom != null) {
for (int i = 0; i < tripPattern.hopEdges.length; i++) {
tripPattern.hopEdges[i].setGeometry(geom[i]);
}
// Make a geometry for the whole TripPattern from all its constituent hops.
// This happens only if geometry is found in geometriesByTripPattern,
// because that means that geometry was created from shapes instead "as crow flies"
tripPattern.makeGeometry();
}
// TODO this could be more elegant
tripPattern.setServiceCodes(graph.serviceCodes);
/* Iterate over all stops in this pattern recording mode information. */
TraverseMode mode = GtfsLibrary.getTraverseMode(tripPattern.route);
for (TransitStop tstop : tripPattern.stopVertices) {
tstop.addMode(mode);
if (mode == TraverseMode.SUBWAY) {
tstop.setStreetToStopTime(subwayAccessTime);
}
graph.addTransitMode(mode);
}
}
/* Identify interlined trips and create the necessary edges. */
interline(tripPatterns.values(), graph);
/* Interpret the transfers explicitly defined in transfers.txt. */
loadTransfers(graph);
/* Store parent stops in graph, even if not linked. These are needed for clustering*/
for (TransitStationStop stop : context.stationStopNodes.values()) {
if (stop instanceof TransitStation) {
TransitStation parentStopVertex = (TransitStation) stop;
graph.parentStopById.put(parentStopVertex.getStopId(), parentStopVertex.getStop());
}
}
// it is already done at deserialization, but standalone mode allows using graphs without serializing them.
for (TripPattern tableTripPattern : tripPatterns.values()) {
tableTripPattern.scheduledTimetable.finish();
}
// eh?
clearCachedData();
graph.putService(FareService.class, fareServiceFactory.makeFareService());
graph.putService(OnBoardDepartService.class, new OnBoardDepartServiceImpl());
}
use of org.opentripplanner.model.StopPattern in project OpenTripPlanner by opentripplanner.
the class TimetableSnapshotSource method addTripToGraphAndBuffer.
/**
* Add a (new) trip to the graph and the buffer
*
* @param graph graph
* @param trip trip
* @param tripUpdate trip update containing stop time updates
* @param stops list of stops corresponding to stop time updates
* @param serviceDate service date of trip
* @param realTimeState real-time state of new trip
* @return true iff successful
*/
private boolean addTripToGraphAndBuffer(final String feedId, final Graph graph, final Trip trip, final TripUpdate tripUpdate, final List<Stop> stops, final ServiceDate serviceDate, final RealTimeState realTimeState) {
// Preconditions
Preconditions.checkNotNull(stops);
Preconditions.checkArgument(tripUpdate.getStopTimeUpdateCount() == stops.size(), "number of stop should match the number of stop time updates");
// Calculate seconds since epoch on GTFS midnight (noon minus 12h) of service date
final Calendar serviceCalendar = serviceDate.getAsCalendar(timeZone);
final long midnightSecondsSinceEpoch = serviceCalendar.getTimeInMillis() / MILLIS_PER_SECOND;
// Create StopTimes
final List<StopTime> stopTimes = new ArrayList<>(tripUpdate.getStopTimeUpdateCount());
for (int index = 0; index < tripUpdate.getStopTimeUpdateCount(); ++index) {
final StopTimeUpdate stopTimeUpdate = tripUpdate.getStopTimeUpdate(index);
final Stop stop = stops.get(index);
// Determine whether stop is skipped
final boolean skippedStop = isStopSkipped(stopTimeUpdate);
// Only create stop time for non-skipped stops
if (!skippedStop) {
// Create stop time
final StopTime stopTime = new StopTime();
stopTime.setTrip(trip);
stopTime.setStop(stop);
// Set arrival time
if (stopTimeUpdate.hasArrival() && stopTimeUpdate.getArrival().hasTime()) {
final long arrivalTime = stopTimeUpdate.getArrival().getTime() - midnightSecondsSinceEpoch;
if (arrivalTime < 0 || arrivalTime > MAX_ARRIVAL_DEPARTURE_TIME) {
LOG.warn("ADDED trip has invalid arrival time (compared to start date in " + "TripDescriptor), skipping.");
return false;
}
stopTime.setArrivalTime((int) arrivalTime);
}
// Set departure time
if (stopTimeUpdate.hasDeparture() && stopTimeUpdate.getDeparture().hasTime()) {
final long departureTime = stopTimeUpdate.getDeparture().getTime() - midnightSecondsSinceEpoch;
if (departureTime < 0 || departureTime > MAX_ARRIVAL_DEPARTURE_TIME) {
LOG.warn("ADDED trip has invalid departure time (compared to start date in " + "TripDescriptor), skipping.");
return false;
}
stopTime.setDepartureTime((int) departureTime);
}
// Exact time
stopTime.setTimepoint(1);
if (stopTimeUpdate.hasStopSequence()) {
stopTime.setStopSequence(stopTimeUpdate.getStopSequence());
}
// Set different pickup type for last stop
if (index == tripUpdate.getStopTimeUpdateCount() - 1) {
// No pickup available
stopTime.setPickupType(1);
} else {
// Regularly scheduled pickup
stopTime.setPickupType(0);
}
// Set different drop off type for first stop
if (index == 0) {
// No drop off available
stopTime.setDropOffType(1);
} else {
// Regularly scheduled drop off
stopTime.setDropOffType(0);
}
// Add stop time to list
stopTimes.add(stopTime);
}
}
// TODO: filter/interpolate stop times like in GTFSPatternHopFactory?
// 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.getRoute(), graph);
// Add service code to bitset of pattern if needed (using copy on write)
final int serviceCode = graph.serviceCodes.get(trip.getServiceId());
if (!pattern.getServices().get(serviceCode)) {
final BitSet services = (BitSet) pattern.getServices().clone();
services.set(serviceCode);
pattern.setServices(services);
}
// Create new trip times
final TripTimes newTripTimes = new TripTimes(trip, stopTimes, graph.deduplicator);
// TODO: should we incorporate the delay field if present?
for (int stopIndex = 0; stopIndex < newTripTimes.getNumStops(); stopIndex++) {
newTripTimes.updateArrivalTime(stopIndex, newTripTimes.getScheduledArrivalTime(stopIndex));
newTripTimes.updateDepartureTime(stopIndex, newTripTimes.getScheduledDepartureTime(stopIndex));
}
// Set service code of new trip times
newTripTimes.serviceCode = serviceCode;
// Make sure that updated trip times have the correct real time state
newTripTimes.setRealTimeState(realTimeState);
// Add new trip times to the buffer
final boolean success = buffer.update(feedId, pattern, newTripTimes, serviceDate);
return success;
}
use of org.opentripplanner.model.StopPattern in project OpenTripPlanner by opentripplanner.
the class OnBoardDepartServiceImplTest method testOnBoardDepartureTime.
@Test
public final void testOnBoardDepartureTime() {
Coordinate[] coordinates = new Coordinate[5];
coordinates[0] = new Coordinate(0.0, 0.0);
coordinates[1] = new Coordinate(0.0, 1.0);
coordinates[2] = new Coordinate(2.0, 1.0);
coordinates[3] = new Coordinate(5.0, 1.0);
coordinates[4] = new Coordinate(5.0, 5.0);
PatternDepartVertex depart = mock(PatternDepartVertex.class);
PatternArriveVertex dwell = mock(PatternArriveVertex.class);
PatternArriveVertex arrive = mock(PatternArriveVertex.class);
Graph graph = mock(Graph.class);
RoutingRequest routingRequest = mock(RoutingRequest.class);
ServiceDay serviceDay = mock(ServiceDay.class);
// You're probably not supposed to do this to mocks (access their fields directly)
// But I know of no other way to do this since the mock object has only action-free stub methods.
routingRequest.modes = new TraverseModeSet("WALK,TRANSIT");
when(graph.getTimeZone()).thenReturn(TimeZone.getTimeZone("GMT"));
GeometryFactory geometryFactory = GeometryUtils.getGeometryFactory();
CoordinateSequenceFactory coordinateSequenceFactory = geometryFactory.getCoordinateSequenceFactory();
CoordinateSequence coordinateSequence = coordinateSequenceFactory.create(coordinates);
LineString geometry = new LineString(coordinateSequence, geometryFactory);
ArrayList<Edge> hops = new ArrayList<Edge>(2);
RoutingContext routingContext = new RoutingContext(routingRequest, graph, null, arrive);
AgencyAndId agencyAndId = new AgencyAndId("Agency", "ID");
Agency agency = new Agency();
Route route = new Route();
ArrayList<StopTime> stopTimes = new ArrayList<StopTime>(3);
StopTime stopDepartTime = new StopTime();
StopTime stopDwellTime = new StopTime();
StopTime stopArriveTime = new StopTime();
Stop stopDepart = new Stop();
Stop stopDwell = new Stop();
Stop stopArrive = new Stop();
Trip trip = new Trip();
routingContext.serviceDays = new ArrayList<ServiceDay>(Collections.singletonList(serviceDay));
agency.setId(agencyAndId.getAgencyId());
route.setId(agencyAndId);
route.setAgency(agency);
stopDepart.setId(agencyAndId);
stopDwell.setId(agencyAndId);
stopArrive.setId(agencyAndId);
stopDepartTime.setStop(stopDepart);
stopDepartTime.setDepartureTime(0);
stopDwellTime.setArrivalTime(20);
stopDwellTime.setStop(stopDwell);
stopDwellTime.setDepartureTime(40);
stopArriveTime.setArrivalTime(60);
stopArriveTime.setStop(stopArrive);
stopTimes.add(stopDepartTime);
stopTimes.add(stopDwellTime);
stopTimes.add(stopArriveTime);
trip.setId(agencyAndId);
trip.setTripHeadsign("The right");
trip.setRoute(route);
TripTimes tripTimes = new TripTimes(trip, stopTimes, new Deduplicator());
StopPattern stopPattern = new StopPattern(stopTimes);
TripPattern tripPattern = new TripPattern(route, stopPattern);
TripPattern.generateUniqueIds(Arrays.asList(tripPattern));
when(depart.getTripPattern()).thenReturn(tripPattern);
when(dwell.getTripPattern()).thenReturn(tripPattern);
PatternHop patternHop0 = new PatternHop(depart, dwell, stopDepart, stopDwell, 0);
PatternHop patternHop1 = new PatternHop(dwell, arrive, stopDwell, stopArrive, 1);
hops.add(patternHop0);
hops.add(patternHop1);
when(graph.getEdges()).thenReturn(hops);
when(depart.getCoordinate()).thenReturn(new Coordinate(0, 0));
when(dwell.getCoordinate()).thenReturn(new Coordinate(0, 0));
when(arrive.getCoordinate()).thenReturn(new Coordinate(0, 0));
routingRequest.from = new GenericLocation();
routingRequest.startingTransitTripId = agencyAndId;
when(serviceDay.secondsSinceMidnight(anyInt())).thenReturn(9);
patternHop0.setGeometry(geometry);
tripPattern.add(tripTimes);
graph.index = new GraphIndex(graph);
coordinates = new Coordinate[3];
coordinates[0] = new Coordinate(3.5, 1.0);
coordinates[1] = new Coordinate(5.0, 1.0);
coordinates[2] = new Coordinate(5.0, 5.0);
coordinateSequence = coordinateSequenceFactory.create(coordinates);
geometry = new LineString(coordinateSequence, geometryFactory);
Vertex vertex = onBoardDepartServiceImpl.setupDepartOnBoard(routingContext);
Edge edge = vertex.getOutgoing().toArray(new Edge[1])[0];
assertEquals(vertex, edge.getFromVertex());
assertEquals(dwell, edge.getToVertex());
assertEquals("The right", edge.getDirection());
assertEquals(geometry, edge.getGeometry());
assertEquals(coordinates[0].x, vertex.getX(), 0.0);
assertEquals(coordinates[0].y, vertex.getY(), 0.0);
}
Aggregations