use of org.opentripplanner.routing.vertextype.TransitStop in project OpenTripPlanner by opentripplanner.
the class RoundBasedProfileRouter method makeSurfaces.
/**
* analyst mode: propagate to street network
*/
private void makeSurfaces() {
LOG.info("Propagating from transit stops to the street network...");
List<State> lower = Lists.newArrayList();
List<State> upper = Lists.newArrayList();
List<State> avg = Lists.newArrayList();
RoutingRequest rr = new RoutingRequest(TraverseMode.WALK);
rr.batch = (true);
rr.from = new GenericLocation(request.fromLat, request.fromLon);
rr.setRoutingContext(graph);
rr.longDistance = true;
rr.dominanceFunction = new DominanceFunction.EarliestArrival();
rr.setNumItineraries(1);
rr.worstTime = rr.dateTime + CUTOFF_SECONDS;
long startTime = rr.dateTime;
State origin = new State(rr);
// Multi-origin Dijkstra search; preinitialize the queue with states at each transit stop
for (Collection<ProfileState> pss : retainedStates.asMap().values()) {
TransitStop tstop = null;
int lowerBound = Integer.MAX_VALUE;
int upperBound = Integer.MAX_VALUE;
for (ProfileState ps : pss) {
if (tstop == null)
tstop = ps.stop;
if (ps.lowerBound < lowerBound)
lowerBound = ps.lowerBound;
if (ps.upperBound < upperBound)
upperBound = ps.upperBound;
}
if (lowerBound == Integer.MAX_VALUE || upperBound == Integer.MAX_VALUE)
throw new IllegalStateException("Invalid bound!");
lower.add(new State(tstop, null, lowerBound + startTime, startTime, rr));
upper.add(new State(tstop, null, upperBound + startTime, startTime, rr));
// TODO extremely incorrect hack!
avg.add(new State(tstop, null, (upperBound + lowerBound) / 2 + startTime, startTime, rr));
}
// get direct trips as well
lower.add(origin);
upper.add(origin);
avg.add(origin);
// create timesurfaces
timeSurfaceRangeSet = new TimeSurface.RangeSet();
AStar astar = new AStar();
timeSurfaceRangeSet.min = new TimeSurface(astar.getShortestPathTree(rr, 20, null, lower), false);
astar = new AStar();
timeSurfaceRangeSet.max = new TimeSurface(astar.getShortestPathTree(rr, 20, null, upper), false);
astar = new AStar();
timeSurfaceRangeSet.avg = new TimeSurface(astar.getShortestPathTree(rr, 20, null, avg), false);
rr.cleanup();
LOG.info("Done with propagation.");
/* Store the results in a field in the router object. */
}
use of org.opentripplanner.routing.vertextype.TransitStop in project OpenTripPlanner by opentripplanner.
the class GTFSPatternHopFactory method loadStops.
private void loadStops(Graph graph) {
for (Stop stop : _dao.getAllStops()) {
if (context.stops.contains(stop.getId())) {
LOG.error("Skipping stop {} because we already loaded an identical ID.", stop.getId());
continue;
}
context.stops.add(stop.getId());
int locationType = stop.getLocationType();
// add a vertex representing the stop
if (locationType == 1) {
context.stationStopNodes.put(stop, new TransitStation(graph, stop));
} else {
TransitStop stopVertex = new TransitStop(graph, stop);
context.stationStopNodes.put(stop, stopVertex);
if (locationType != 2) {
// Add a vertex representing arriving at the stop
TransitStopArrive arrive = new TransitStopArrive(graph, stop, stopVertex);
// FIXME no need for this context anymore, we just put references to these nodes in the stop vertices themselves.
context.stopArriveNodes.put(stop, arrive);
stopVertex.arriveVertex = arrive;
// Add a vertex representing departing from the stop
TransitStopDepart depart = new TransitStopDepart(graph, stop, stopVertex);
// FIXME no need for this context anymore, we just put references to these nodes in the stop vertices themselves.
context.stopDepartNodes.put(stop, depart);
stopVertex.departVertex = depart;
// Add edges from arrive to stop and stop to depart
new PreAlightEdge(arrive, stopVertex);
new PreBoardEdge(stopVertex, depart);
}
}
}
}
use of org.opentripplanner.routing.vertextype.TransitStop in project OpenTripPlanner by opentripplanner.
the class GraphIndex method clusterByProximityAndName.
/**
* Cluster stops by proximity and name.
* This functionality was developed for the Washington, DC area and probably will not work anywhere else in the
* world. It depends on the exact way stops are named and the way street intersections are named in that geographic
* region and in the GTFS data sets which represent it. Based on comments, apparently it might work for TriMet
* as well.
*
* We can't use a name similarity comparison, we need exact matches. This is because many street names differ by
* only one letter or number, e.g. 34th and 35th or Avenue A and Avenue B. Therefore normalizing the names before
* the comparison is essential. The agency must provide either parent station information or a well thought out stop
* naming scheme to cluster stops -- no guessing is reasonable without that information.
*/
private void clusterByProximityAndName() {
// unique index for next parent stop
int psIdx = 0;
LOG.info("Clustering stops by geographic proximity and name...");
// Each stop without a cluster will greedily claim other stops without clusters.
for (Stop s0 : stopForId.values()) {
// skip stops that have already been claimed by a cluster
if (stopClusterForStop.containsKey(s0))
continue;
String s0normalizedName = StopNameNormalizer.normalize(s0.getName());
StopCluster cluster = new StopCluster(String.format("C%03d", psIdx++), s0normalizedName);
// LOG.info("stop {}", s0normalizedName);
// No need to explicitly add s0 to the cluster. It will be found in the spatial index query below.
Envelope env = new Envelope(new Coordinate(s0.getLon(), s0.getLat()));
env.expandBy(SphericalDistanceLibrary.metersToLonDegrees(CLUSTER_RADIUS, s0.getLat()), SphericalDistanceLibrary.metersToDegrees(CLUSTER_RADIUS));
for (TransitStop ts1 : stopSpatialIndex.query(env)) {
Stop s1 = ts1.getStop();
double geoDistance = SphericalDistanceLibrary.fastDistance(s0.getLat(), s0.getLon(), s1.getLat(), s1.getLon());
if (geoDistance < CLUSTER_RADIUS) {
String s1normalizedName = StopNameNormalizer.normalize(s1.getName());
// LOG.info(" geodist {} stringdist {}", geoDistance, stringDistance);
if (s1normalizedName.equals(s0normalizedName)) {
// Create a bidirectional relationship between the stop and its cluster
cluster.children.add(s1);
stopClusterForStop.put(s1, cluster);
}
}
}
cluster.computeCenter();
stopClusterForId.put(cluster.id, cluster);
}
}
use of org.opentripplanner.routing.vertextype.TransitStop in project OpenTripPlanner by opentripplanner.
the class AnalystProfileRouterPrototype method route.
public TimeSurface.RangeSet route() {
// NOT USED here, however FIXME this is not threadsafe, needs lock graph.index.clusterStopsAsNeeded();
LOG.info("access modes: {}", request.accessModes);
LOG.info("egress modes: {}", request.egressModes);
LOG.info("direct modes: {}", request.directModes);
// Establish search timeouts
searchBeginTime = System.currentTimeMillis();
abortTime = searchBeginTime + TIMEOUT * 1000;
// TimeWindow could constructed in the caller, which does have access to the graph index.
this.window = new TimeWindow(request.fromTime, request.toTime, graph.index.servicesRunning(request.date));
fromStops = findClosestStops(TraverseMode.WALK);
LOG.info("From patterns/stops: {}", fromStops);
/* Initialize time range tracker to begin the search. */
TimeRange.Tracker times = new TimeRange.Tracker();
for (Stop stop : fromStops.keySet()) {
times.set(stop, fromStops.get(stop));
}
Set<Stop> stopsUpdated = fromStops.keySet();
for (int round = 0; round < MAX_RIDES; round++) {
// TODO maybe even loop until no updates happen? That should happen automatically if MAX_RIDES is high enough.
/* Get all patterns passing through stops updated in the last round, then reinitialize the updated stops set. */
Set<TripPattern> patternsUpdated = uniquePatternsVisiting(stopsUpdated);
LOG.info("ROUND {} : {} stops and {} patterns to explore.", round, stopsUpdated.size(), patternsUpdated.size());
stopsUpdated = Sets.newHashSet();
/* RAPTOR style: iterate over each pattern once. */
for (TripPattern pattern : patternsUpdated) {
// checkTimeout();
TimeRange rangeBeingPropagated = null;
List<Stop> stops = pattern.getStops();
FrequencyEntry freq = pattern.getSingleFrequencyEntry();
if (freq == null)
continue;
TripTimes tt = freq.tripTimes;
int headway = freq.headway;
for (int sidx = 0; sidx < stops.size(); sidx++) {
Stop stop = stops.get(sidx);
TimeRange existingRange = times.get(stop);
TimeRange reBoardRange = (existingRange != null) ? existingRange.wait(headway) : null;
if (rangeBeingPropagated == null) {
// We do not yet have a range worth propagating
if (reBoardRange != null) {
// this is a fresh protective copy
rangeBeingPropagated = reBoardRange;
}
} else {
// We already have a range that is being propagated along the pattern.
// We are certain sidx >= 1 here because we have already boarded in a previous iteration.
TimeRange arrivalRange = rangeBeingPropagated.shift(tt.getRunningTime(sidx - 1));
if (times.add(stop, arrivalRange)) {
// The propagated time improved the best known time in some way.
stopsUpdated.add(stop);
}
// TODO handle case where arrival and departure are different
rangeBeingPropagated = arrivalRange.shift(tt.getDwellTime(sidx));
if (reBoardRange != null) {
rangeBeingPropagated.mergeIn(reBoardRange);
}
}
}
}
/* Transfer from updated stops to adjacent stops before beginning the next round.
Iterate over a protective copy because we add more stops to the updated list during iteration. */
if (!graph.hasDirectTransfers) {
throw new RuntimeException("Requires the SimpleTransfers generated in long distance mode.");
}
for (Stop stop : Lists.newArrayList(stopsUpdated)) {
Collection<Edge> outgoingEdges = graph.index.stopVertexForStop.get(stop).getOutgoing();
for (SimpleTransfer transfer : Iterables.filter(outgoingEdges, SimpleTransfer.class)) {
Stop targetStop = ((TransitStop) transfer.getToVertex()).getStop();
double walkTime = transfer.getDistance() / request.walkSpeed;
TimeRange rangeAfterTransfer = times.get(stop).shift((int) walkTime);
if (times.add(targetStop, rangeAfterTransfer)) {
stopsUpdated.add(targetStop);
}
}
}
}
LOG.info("Done with transit.");
LOG.info("Propagating from transit stops to the street network...");
// Grab a cached map of distances to street intersections from each transit stop
StopTreeCache stopTreeCache = graph.index.getStopTreeCache();
// Iterate over all stops that were reached in the transit part of the search
for (Stop stop : times) {
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.
TimeRange rangeAtTransitStop = times.get(stop);
// 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;
}
TimeRange propagatedRange = rangeAtTransitStop.shift(egressWalkTimeSeconds);
TimeRange existingTimeRange = propagatedTimes.get(vertex);
if (existingTimeRange == null) {
propagatedTimes.put(vertex, propagatedRange);
} else {
existingTimeRange.mergeIn(propagatedRange);
}
}
}
LOG.info("Done with propagation.");
TimeSurface.RangeSet result = TimeSurface.makeSurfaces(this);
LOG.info("Done making time surfaces.");
return result;
}
use of org.opentripplanner.routing.vertextype.TransitStop in project OpenTripPlanner by opentripplanner.
the class AlertPatch method remove.
public void remove(Graph graph) {
Agency agency = null;
if (feedId != null) {
Map<String, Agency> agencies = graph.index.agenciesForFeedId.get(feedId);
agency = this.agency != null ? agencies.get(this.agency) : null;
}
Route route = this.route != null ? graph.index.routeForId.get(this.route) : null;
Stop stop = this.stop != null ? graph.index.stopForId.get(this.stop) : null;
Trip trip = this.trip != null ? graph.index.tripForId.get(this.trip) : null;
if (route != null || trip != null || agency != null) {
Collection<TripPattern> tripPatterns = null;
if (trip != null) {
tripPatterns = new LinkedList<TripPattern>();
TripPattern tripPattern = graph.index.patternForTrip.get(trip);
if (tripPattern != null) {
tripPatterns.add(tripPattern);
}
} else if (route != null) {
tripPatterns = graph.index.patternsForRoute.get(route);
} else {
// Find patterns for the feed.
tripPatterns = graph.index.patternsForFeedId.get(feedId);
}
if (tripPatterns != null) {
for (TripPattern tripPattern : tripPatterns) {
if (direction != null && !direction.equals(tripPattern.getDirection())) {
continue;
}
if (directionId != -1 && directionId != tripPattern.directionId) {
continue;
}
for (int i = 0; i < tripPattern.stopPattern.stops.length; i++) {
if (stop == null || stop.equals(tripPattern.stopPattern.stops[i])) {
graph.removeAlertPatch(tripPattern.boardEdges[i], this);
graph.removeAlertPatch(tripPattern.alightEdges[i], this);
}
}
}
}
} else if (stop != null) {
TransitStop transitStop = graph.index.stopVertexForStop.get(stop);
for (Edge edge : transitStop.getOutgoing()) {
if (edge instanceof PreBoardEdge) {
graph.removeAlertPatch(edge, this);
break;
}
}
for (Edge edge : transitStop.getIncoming()) {
if (edge instanceof PreAlightEdge) {
graph.removeAlertPatch(edge, this);
break;
}
}
}
}
Aggregations