use of org.opentripplanner.routing.vertextype.TransitStop in project OpenTripPlanner by opentripplanner.
the class TransitStopsRegionsSourceImpl method getRegions.
@Override
public Iterable<Envelope> getRegions() {
List<Envelope> regions = new ArrayList<Envelope>();
for (Vertex gv : task.getGraph().getVertices()) {
if (gv instanceof TransitStop) {
Coordinate c = gv.getCoordinate();
Envelope env = new Envelope(c);
double meters_per_degree_lon_here = METERS_PER_DEGREE_LAT * Math.cos(Math.toRadians(c.y));
env.expandBy(distance / meters_per_degree_lon_here, distance / METERS_PER_DEGREE_LAT);
regions.add(env);
}
}
LOG.debug("Total regions: " + regions.size());
return regions;
}
use of org.opentripplanner.routing.vertextype.TransitStop 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.routing.vertextype.TransitStop in project OpenTripPlanner by opentripplanner.
the class GTFSPatternHopFactory method linkStopsToParentStations.
/**
* Links the vertices representing parent stops to their child stops bidirectionally. This is
* not intended to provide implicit transfers (i.e. child stop to parent station to another
* child stop) but instead to allow beginning or ending a path (itinerary) at a parent station.
*
* Currently this linking is only intended for use in the long distance path service. The
* pathparsers should ensure that it is effectively ignored in other path services, and even in
* the long distance path service anywhere but the beginning or end of a path.
*/
public void linkStopsToParentStations(Graph graph) {
for (Stop stop : _dao.getAllStops()) {
String parentStation = stop.getParentStation();
if (parentStation != null) {
TransitStop stopVertex = (TransitStop) context.stationStopNodes.get(stop);
String agencyId = stop.getId().getAgencyId();
AgencyAndId parentStationId = new AgencyAndId(agencyId, parentStation);
Stop parentStop = _dao.getStopForId(parentStationId);
if (context.stationStopNodes.get(parentStop) instanceof TransitStation) {
TransitStation parentStopVertex = (TransitStation) context.stationStopNodes.get(parentStop);
new StationStopEdge(parentStopVertex, stopVertex);
new StationStopEdge(stopVertex, parentStopVertex);
} else {
LOG.warn(graph.addBuilderAnnotation(new NonStationParentStation(stopVertex)));
}
}
}
}
use of org.opentripplanner.routing.vertextype.TransitStop in project OpenTripPlanner by opentripplanner.
the class ProfileRouter method makeSurfaces.
private void makeSurfaces() {
LOG.info("Propagating from transit stops to the street network...");
// A map to store the travel time to each vertex
TimeSurface minSurface = new TimeSurface(this);
TimeSurface avgSurface = new TimeSurface(this);
TimeSurface maxSurface = new TimeSurface(this);
// Grab a cached map of distances to street intersections from each transit stop
StopTreeCache stopTreeCache = graph.index.getStopTreeCache();
// Iterate over all nondominated rides at all clusters
for (Entry<StopCluster, Ride> entry : retainedRides.entries()) {
StopCluster cluster = entry.getKey();
Ride ride = entry.getValue();
for (Stop stop : cluster.children) {
TransitStop tstop = graph.index.stopVertexForStop.get(stop);
// Iterate over street intersections in the vicinity of this particular transit stop.
// Shift the time range at this transit stop, merging it into that for all reachable street intersections.
// FIXME stopTreeCache.getDistancesForStop(tstop);
TObjectIntMap<Vertex> distanceToVertex = null;
for (TObjectIntIterator<Vertex> iter = distanceToVertex.iterator(); iter.hasNext(); ) {
iter.advance();
Vertex vertex = iter.key();
// distance in meters over walkspeed in meters per second --> seconds
int egressWalkTimeSeconds = (int) (iter.value() / request.walkSpeed);
if (egressWalkTimeSeconds > request.maxWalkTime * 60) {
continue;
}
int propagated_min = ride.dlb + egressWalkTimeSeconds;
int propagated_max = ride.dub + egressWalkTimeSeconds;
// FIXME HACK
int propagated_avg = (int) (((long) propagated_min + propagated_max) / 2);
int existing_min = minSurface.times.get(vertex);
int existing_max = maxSurface.times.get(vertex);
int existing_avg = avgSurface.times.get(vertex);
// which is not necessarily wrong but it's a crude way to perform the combination
if (existing_min == TimeSurface.UNREACHABLE || existing_min > propagated_min) {
minSurface.times.put(vertex, propagated_min);
}
if (existing_max == TimeSurface.UNREACHABLE || existing_max > propagated_max) {
maxSurface.times.put(vertex, propagated_max);
}
if (existing_avg == TimeSurface.UNREACHABLE || existing_avg > propagated_avg) {
avgSurface.times.put(vertex, propagated_avg);
}
}
}
}
LOG.info("Done with propagation.");
/* Store the results in a field in the router object. */
timeSurfaceRangeSet = new TimeSurface.RangeSet();
timeSurfaceRangeSet.min = minSurface;
timeSurfaceRangeSet.max = maxSurface;
timeSurfaceRangeSet.avg = avgSurface;
}
use of org.opentripplanner.routing.vertextype.TransitStop in project OpenTripPlanner by opentripplanner.
the class RaptorWorkerData method findStopsNear.
/**
* find stops from a given SPT, including temporary stops. If useTimes is true, use times from the SPT, otherwise use distances
*/
public TIntIntMap findStopsNear(ShortestPathTree spt, Graph graph, boolean useTimes, float walkSpeed) {
TIntIntMap accessTimes = new TIntIntHashMap();
for (TransitStop tstop : graph.index.stopVertexForStop.values()) {
State s = spt.getState(tstop);
if (s != null) {
// note that we calculate the time based on the walk speed here rather than
// based on the time. this matches what we do in the stop tree cache.
int stopIndex = indexForStop.get(tstop.getIndex());
if (stopIndex != -1) {
if (useTimes)
accessTimes.put(stopIndex, (int) s.getElapsedTimeSeconds());
else
accessTimes.put(stopIndex, (int) (s.getWalkDistance() / walkSpeed));
}
}
}
// and handle the additional stops
for (TObjectIntIterator<AddTripPattern.TemporaryStop> it = addedStops.iterator(); it.hasNext(); ) {
it.advance();
AddTripPattern.TemporaryStop tstop = it.key();
if (tstop.sample == null) {
continue;
}
double dist = Double.POSITIVE_INFINITY;
if (tstop.sample.v0 != null) {
State s0 = spt.getState(tstop.sample.v0);
if (s0 != null) {
dist = s0.getWalkDistance() + tstop.sample.d0;
}
}
if (tstop.sample.v1 != null) {
State s1 = spt.getState(tstop.sample.v1);
if (s1 != null) {
double d1 = s1.getWalkDistance() + tstop.sample.d1;
dist = Double.isInfinite(dist) ? d1 : Math.min(d1, dist);
}
}
if (Double.isInfinite(dist))
continue;
// NB using the index in the worker data not the index in the graph!
accessTimes.put(it.value(), (int) (dist / walkSpeed));
}
return accessTimes;
}
Aggregations