Skip to content

Commit

Permalink
Street search: traverse edges which may return multiple states
Browse files Browse the repository at this point in the history
  • Loading branch information
flaktack committed Nov 7, 2024
1 parent 77475aa commit 24c7dc6
Show file tree
Hide file tree
Showing 10 changed files with 2,171 additions and 1,586 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ private FlexAccessEgress createFlexAccessEgress(
return null;
}

final var finalStateOpt = EdgeTraverser.traverseEdges(afterFlexState[0], transferEdges);
final var finalStateOpt = EdgeTraverser.traverseEdges(afterFlexState, transferEdges);

return finalStateOpt
.map(finalState -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private Optional<DirectFlexPath> createDirectGraphPath(

final State[] afterFlexState = flexEdge.traverse(accessNearbyStop.state);

var finalStateOpt = EdgeTraverser.traverseEdges(afterFlexState[0], egress.edges);
var finalStateOpt = EdgeTraverser.traverseEdges(afterFlexState, egress.edges);

if (finalStateOpt.isEmpty()) {
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.opentripplanner.astar.model.GraphPath;
import org.opentripplanner.framework.application.OTPFeature;
import org.opentripplanner.framework.geometry.GeometryUtils;
Expand Down Expand Up @@ -38,8 +39,8 @@
import org.opentripplanner.street.search.TraverseMode;
import org.opentripplanner.street.search.request.StreetSearchRequest;
import org.opentripplanner.street.search.request.StreetSearchRequestMapper;
import org.opentripplanner.street.search.state.EdgeTraverser;
import org.opentripplanner.street.search.state.State;
import org.opentripplanner.street.search.state.StateEditor;
import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate;
import org.opentripplanner.transit.model.timetable.TripOnServiceDate;
import org.opentripplanner.transit.service.TransitService;
Expand Down Expand Up @@ -360,24 +361,15 @@ private List<Leg> mapNonTransitLeg(
.build()
);
} else {
StateEditor se = new StateEditor(edges.get(0).getFromVertex(), transferStreetRequest);
se.setTimeSeconds(createZonedDateTime(pathLeg.fromTime()).toEpochSecond());

State s = se.makeState();
ArrayList<State> transferStates = new ArrayList<>();
transferStates.add(s);
for (Edge e : edges) {
var states = e.traverse(s);
if (State.isEmpty(states)) {
s = null;
} else {
transferStates.add(states[0]);
s = states[0];
}
}

State[] states = transferStates.toArray(new State[0]);
var graphPath = new GraphPath<>(states[states.length - 1]);
var legTransferSearchRequest = transferStreetRequest
.copyOf(createZonedDateTime(pathLeg.fromTime()).toInstant())
.build();
var initialStates = State.getInitialStates(
Set.of(edges.getFirst().getFromVertex()),
legTransferSearchRequest
);
var state = EdgeTraverser.traverseEdges(initialStates, edges);
var graphPath = new GraphPath<>(state.get());

Itinerary subItinerary = graphPathToItineraryMapper.generateItinerary(graphPath);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.locationtech.jts.geom.Coordinate;
import org.opentripplanner.raptor.api.model.RaptorTransfer;
import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.RaptorCostConverter;
import org.opentripplanner.routing.api.request.preference.WalkPreferences;
import org.opentripplanner.street.model.edge.Edge;
import org.opentripplanner.street.search.request.StreetSearchRequest;
import org.opentripplanner.street.search.state.EdgeTraverser;
import org.opentripplanner.street.search.state.StateEditor;
import org.opentripplanner.street.search.state.State;
import org.opentripplanner.utils.logging.Throttle;
import org.opentripplanner.utils.tostring.ToStringBuilder;
import org.slf4j.Logger;
Expand Down Expand Up @@ -84,10 +85,8 @@ public Optional<RaptorTransfer> asRaptorTransfer(StreetSearchRequest request) {
);
}

StateEditor se = new StateEditor(edges.get(0).getFromVertex(), request);
se.setTimeSeconds(0);

var state = EdgeTraverser.traverseEdges(se.makeState(), edges);
var initialStates = State.getInitialStates(Set.of(edges.getFirst().getFromVertex()), request);
var state = EdgeTraverser.traverseEdges(initialStates, edges);

return state.map(s ->
new DefaultRaptorTransfer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ public DataOverlayContext dataOverlayContext() {
return dataOverlayContext;
}

public StreetSearchRequestBuilder copyOf(Instant time) {
return copyOf(this).withStartTime(time);
}

public StreetSearchRequestBuilder copyOfReversed(Instant time) {
return copyOf(this).withStartTime(time).withArriveBy(!arriveBy);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import java.util.Collection;
import java.util.Optional;
import org.opentripplanner.astar.model.ShortestPathTree;
import org.opentripplanner.street.model.edge.Edge;
import org.opentripplanner.street.model.vertex.Vertex;
import org.opentripplanner.street.search.strategy.DominanceFunctions;

/**
* This is a very reduced version of the A* algorithm: from an initial state a number of edges are
Expand All @@ -14,24 +17,49 @@
*/
public class EdgeTraverser {

public static Optional<State> traverseEdges(final State s, final Collection<Edge> edges) {
var state = s;
public static Optional<State> traverseEdges(
final Collection<State> initialStates,
final Collection<Edge> edges
) {
return traverseEdges(initialStates.toArray(new State[0]), edges);
}

public static Optional<State> traverseEdges(
final State[] initialStates,
final Collection<Edge> edges
) {
if (edges.isEmpty()) {
return Optional.of(initialStates[0]);
}

// The shortest path tree is used to prune dominated parallel states. For example,
// CAR_PICKUP can return both a CAR/WALK state after each traversal of which only
// the optimal states need to be continued.
var dominanceFunction = new DominanceFunctions.MinimumWeight();
var spt = new ShortestPathTree<>(dominanceFunction);
for (State initialState : initialStates) {
spt.add(initialState);
}

Vertex lastVertex = null;
var isArriveBy = initialStates[0].getRequest().arriveBy();
for (Edge e : edges) {
var afterTraversal = e.traverse(state);
if (afterTraversal.length > 1) {
throw new IllegalStateException(
"Expected only a single state returned from edge %s but received %s".formatted(
e,
afterTraversal.length
)
);
}
if (State.isEmpty(afterTraversal)) {
var vertex = isArriveBy ? e.getToVertex() : e.getFromVertex();
var fromStates = spt.getStates(vertex);
if (fromStates == null || fromStates.isEmpty()) {
return Optional.empty();
} else {
state = afterTraversal[0];
}

for (State fromState : fromStates) {
var newToStates = e.traverse(fromState);
for (State newToState : newToStates) {
spt.add(newToState);
}
}

lastVertex = isArriveBy ? e.getFromVertex() : e.getToVertex();
}
return Optional.ofNullable(state);

return Optional.ofNullable(lastVertex).map(spt::getState);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public class Coordinates {

public static final Coordinate BERLIN = of(52.5212, 13.4105);
public static final Coordinate BERLIN_BRANDENBURG_GATE = of(52.51627, 13.37770);
public static final Coordinate BERLIN_FERNSEHTURM = of(52.52084, 13.40934);
public static final Coordinate BERLIN_ADMIRALBRUCKE = of(52.49526, 13.415093);
public static final Coordinate HAMBURG = of(53.5566, 10.0003);
public static final Coordinate KONGSBERG_PLATFORM_1 = of(59.67216, 9.65107);
public static final Coordinate BOSTON = of(42.36541, -71.06129);
Expand Down
Loading

0 comments on commit 24c7dc6

Please sign in to comment.