Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.opentripplanner.graph_builder.module;
import com.beust.jcommander.internal.Lists;
import com.beust.jcommander.internal.Sets;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.util.Comparator;
import org.locationtech.jts.geom.Coordinate;
import org.opentripplanner.common.MinMap;
import org.opentripplanner.ext.flex.trip.FlexTrip;
import org.opentripplanner.model.FlexStopLocation;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.StopLocation;
import org.opentripplanner.model.TripPattern;
import org.opentripplanner.routing.algorithm.astar.AStar;
import org.opentripplanner.routing.algorithm.astar.strategies.DurationSkipEdgeStrategy;
import org.opentripplanner.routing.algorithm.astar.strategies.TrivialRemainingWeightHeuristic;
import org.opentripplanner.routing.api.request.RoutingRequest;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.core.TraverseMode;
import org.opentripplanner.routing.edgetype.StreetEdge;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.graph.Vertex;
import org.opentripplanner.routing.graphfinder.DirectGraphFinder;
import org.opentripplanner.routing.graphfinder.NearbyStop;
import org.opentripplanner.routing.location.TemporaryStreetLocation;
import org.opentripplanner.routing.spt.DominanceFunction;
import org.opentripplanner.routing.spt.ShortestPathTree;
import org.opentripplanner.routing.vertextype.StreetVertex;
import org.opentripplanner.routing.vertextype.TransitStopVertex;
import org.opentripplanner.util.OTPFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* These library functions are used by the streetless and streetful stop linkers, and in profile transfer generation.
* TODO OTP2 Fold these into org.opentripplanner.routing.graphfinder.StreetGraphFinder
* These are not library functions, this is instantiated as an object. Define lifecycle of the object (reuse?).
* Because AStar instances should only be used once, NearbyStopFinder should only be used once.
* Ideally they could also be used in long distance mode and profile routing for the street segments.
* For each stop, it finds the closest stops on all other patterns. This reduces the number of transfer edges
* significantly compared to simple radius-constrained all-to-all stop linkage.
*/
public class NearbyStopFinder {
private static final Logger LOG = LoggerFactory.getLogger(NearbyStopFinder.class);
public final boolean useStreets;
private final Graph graph;
private final double durationLimitInSeconds;
private DirectGraphFinder directGraphFinder;
/**
* Construct a NearbyStopFinder for the given graph and search radius, choosing whether to search via the street
* network or straight line distance based on the presence of OSM street data in the graph.
*/
public NearbyStopFinder(Graph graph, double durationLimitInSeconds) {
this (graph, durationLimitInSeconds, graph.hasStreets);
}
/**
* Construct a NearbyStopFinder for the given graph and search radius.
* @param useStreets if true, search via the street network instead of using straight-line distance.
*/
public NearbyStopFinder(Graph graph, double durationLimitInSeconds, boolean useStreets) {
this.graph = graph;
this.useStreets = useStreets;
this.durationLimitInSeconds = durationLimitInSeconds;
if (!useStreets) {
// We need to accommodate straight line distance (in meters) but when streets are present we use an
// earliest arrival search, which optimizes on time. Ideally we'd specify in meters,
// but we don't have much of a choice here. Use the default walking speed to convert.
this.directGraphFinder = new DirectGraphFinder(graph);
}
}
/**
* 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 findNearbyStopsConsideringPatterns(Vertex vertex, RoutingRequest routingRequest, boolean reverseDirection) {
/* Track the closest stop on each pattern passing nearby. */
MinMap closestStopForPattern = new MinMap();
/* Track the closest stop on each flex trip nearby. */
MinMap closestStopForFlexTrip = new MinMap<>();
/* Iterate over nearby stops via the street network or using straight-line distance, depending on the graph. */
for (NearbyStop nearbyStop : findNearbyStops(vertex, routingRequest.clone(), reverseDirection)) {
StopLocation ts1 = nearbyStop.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, nearbyStop);
}
} if (OTPFeature.FlexRouting.isOn()) {
for (FlexTrip trip : graph.index.getFlexIndex().flexTripsByStop.get(ts1)) {
closestStopForFlexTrip.putMin(trip, nearbyStop);
}
}
}
/* Make a transfer from the origin stop to each destination stop that was the closest stop on any pattern. */
Set uniqueStops = Sets.newHashSet();
uniqueStops.addAll(closestStopForFlexTrip.values());
uniqueStops.addAll(closestStopForPattern.values());
return uniqueStops;
}
/**
* Return all stops within a certain radius of the given vertex, using network distance along streets.
* Use the correct method depending on whether the graph has street data or not.
* If the origin vertex is a StopVertex, the result will include it; this characteristic is essential for
* associating the correct stop with each trip pattern in the vicinity.
*/
public List findNearbyStops(
Vertex vertex, RoutingRequest routingRequest, boolean reverseDirection
) {
if (useStreets) {
return findNearbyStopsViaStreets(Set.of(vertex), reverseDirection, true, routingRequest);
}
// It make sense for the directGraphFinder to use meters as a limit, so we convert first
double limitMeters = durationLimitInSeconds * new RoutingRequest(TraverseMode.WALK).walkSpeed;
Coordinate c0 = vertex.getCoordinate();
return directGraphFinder.findClosestStops(c0.y, c0.x, limitMeters);
}
/**
* Return all stops within a certain radius of the given vertex, using network distance along streets.
* If the origin vertex is a StopVertex, the result will include it.
*
* @param originVertices the origin point of the street search
* @param reverseDirection if true the paths returned instead originate at the nearby stops and have the
* originVertex as the destination
* @param removeTempEdges after creating a new routing request and routing context, remove all the temporary
* edges that are part of that context. NOTE: this will remove _all_ temporary edges
* coming out of the origin and destination vertices, including those in any other
* RoutingContext referencing them, making routing from/to them totally impossible.
* This is a stopgap solution until we rethink the lifecycle of RoutingContext.
*/
public List findNearbyStopsViaStreets (
Set originVertices,
boolean reverseDirection,
boolean removeTempEdges,
RoutingRequest routingRequest
) {
List stopsFound = Lists.newArrayList();
/* Add the origin vertices if they are stops */
for (Vertex vertex : originVertices) {
if (vertex instanceof TransitStopVertex) {
stopsFound.add(
new NearbyStop(
(TransitStopVertex) vertex,
0,
Collections.emptyList(),
new State(vertex, routingRequest)
));
}
}
// Return only the origin vertices if there are no valid street modes
if (!routingRequest.streetSubRequestModes.isValid()) { return stopsFound; }
routingRequest.setArriveBy(reverseDirection);
if (!reverseDirection) {
routingRequest.setRoutingContext(graph, originVertices, null);
} else {
routingRequest.setRoutingContext(graph, null, originVertices);
}
routingRequest.disableRemainingWeightHeuristic = true;
routingRequest.rctx.remainingWeightHeuristic = new TrivialRemainingWeightHeuristic();
routingRequest.dominanceFunction = new DominanceFunction.MinimumWeight();
var astar = new AStar();
astar.setSkipEdgeStrategy(new DurationSkipEdgeStrategy(durationLimitInSeconds));
ShortestPathTree spt = astar.getShortestPathTree(routingRequest);
// Only used if OTPFeature.FlexRouting.isOn()
Multimap locationsMap = ArrayListMultimap.create();
if (spt != null) {
// TODO use GenericAStar and a traverseVisitor? Add an earliestArrival switch to genericAStar?
for (State state : spt.getAllStates()) {
Vertex targetVertex = state.getVertex();
if (originVertices.contains(targetVertex)) continue;
if (targetVertex instanceof TransitStopVertex && state.isFinal()) {
stopsFound.add(NearbyStop.nearbyStopForState(state, ((TransitStopVertex) targetVertex).getStop()));
}
if (OTPFeature.FlexRouting.isOn() && targetVertex instanceof StreetVertex
&& ((StreetVertex) targetVertex).flexStopLocations != null) {
for (FlexStopLocation flexStopLocation : ((StreetVertex) targetVertex).flexStopLocations) {
// This is for a simplification, so that we only return one vertex from each
// stop location. All vertices are added to the multimap, which is filtered
// below, so that only the closest vertex is added to stopsFound
if (canBoardFlex(state, reverseDirection)) {
locationsMap.put(flexStopLocation, state);
}
}
}
}
}
if (OTPFeature.FlexRouting.isOn()) {
for (var locationStates : locationsMap.asMap().entrySet()) {
FlexStopLocation flexStopLocation = locationStates.getKey();
Collection states = locationStates.getValue();
// Select the vertex from all vertices that are reachable per FlexStopLocation by taking
// the minimum walking distance
State min = Collections.min(states, Comparator.comparing(State::getWeight));
// If the best state for this FlexStopLocation is a SplitterVertex, we want to get the
// TemporaryStreetLocation instead. This allows us to reach SplitterVertices in both
// directions when routing later.
if (min.getBackState().getVertex() instanceof TemporaryStreetLocation) {
min = min.getBackState();
}
stopsFound.add(NearbyStop.nearbyStopForState(min, flexStopLocation));
}
}
if (removeTempEdges) {
routingRequest.cleanup();
}
return stopsFound;
}
public List findNearbyStopsViaStreets (
Set originVertices,
boolean reverseDirection,
boolean removeTempEdges
) {
RoutingRequest routingRequest = new RoutingRequest(TraverseMode.WALK);
return findNearbyStopsViaStreets(
originVertices,
reverseDirection,
removeTempEdges,
routingRequest
);
}
private boolean canBoardFlex(State state, boolean reverse) {
Collection edges = reverse
? state.getVertex().getIncoming()
: state.getVertex().getOutgoing();
return edges.stream().anyMatch(e ->
e instanceof StreetEdge
&& ((StreetEdge) e).getPermission().allows(TraverseMode.CAR));
}
}