Skip to content

Commit d067df9

Browse files
committed
Insert alight-edges in preparation for graphhopper#922 graphhopper#923
1 parent ab8d693 commit d067df9

File tree

3 files changed

+111
-59
lines changed

3 files changed

+111
-59
lines changed

reader-gtfs/src/main/java/com/graphhopper/reader/gtfs/GtfsReader.java

Lines changed: 97 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ class GtfsReader {
2828
private static class EnterAndExitNodeIdWithStopId {
2929
final String stopId;
3030
final Collection<Integer> enterNodeIds;
31-
final int exitNodeId;
31+
final Collection<Integer> exitNodeIds;
3232

33-
private EnterAndExitNodeIdWithStopId(Collection<Integer> enterNodeIds, String stopId, int exitNodeId) {
33+
private EnterAndExitNodeIdWithStopId(Collection<Integer> enterNodeIds, String stopId, Collection<Integer> exitNodeIds) {
3434
this.stopId = stopId;
3535
this.enterNodeIds = enterNodeIds;
36-
this.exitNodeId = exitNodeId;
36+
this.exitNodeIds = exitNodeIds;
3737
}
3838
}
3939

@@ -66,10 +66,11 @@ private TimelineNodeIdWithTripId(int timelineNodeId, String tripId) {
6666
private final String id;
6767
private int i;
6868
private GTFSFeed feed;
69-
private TIntIntHashMap times;
70-
private SetMultimap<String, TimelineNodeIdWithTripId> stopTimelineNodes;
69+
private final TIntIntHashMap times = new TIntIntHashMap();
70+
private final SetMultimap<String, TimelineNodeIdWithTripId> departureTimelineNodes = HashMultimap.create();
71+
private final SetMultimap<String, TimelineNodeIdWithTripId> arrivalTimelineNodes = HashMultimap.create();
7172
private Collection<EnterAndExitNodeIdWithStopId> stopEnterAndExitNodes = new ArrayList<>();
72-
private SetMultimap<String, Integer> arrivals;
73+
private final SetMultimap<String, Integer> arrivals = HashMultimap.create();
7374
private final PtFlagEncoder encoder;
7475

7576
GtfsReader(String id, GraphHopperStorage ghStorage, LocationIndex walkNetworkIndex) {
@@ -87,33 +88,36 @@ public void readGraph() {
8788
gtfsStorage.getFares().putAll(feed.fares);
8889
i = graph.getNodes();
8990
buildPtNetwork();
90-
EdgeFilter filter = new EverythingButPt(encoder);
9191
for (EnterAndExitNodeIdWithStopId entry : stopEnterAndExitNodes) {
92-
QueryResult source = walkNetworkIndex.findClosest(nodeAccess.getLat(entry.exitNodeId), nodeAccess.getLon(entry.exitNodeId), filter);
9392
Stop stop = feed.stops.get(entry.stopId);
94-
int streetNode;
95-
if (!source.isValid()) {
96-
streetNode = i;
97-
nodeAccess.setNode(i++, stop.stop_lat, stop.stop_lon);
98-
graph.edge(streetNode, streetNode, 0.0, false);
99-
} else {
100-
streetNode = source.getClosestNode();
101-
}
10293
for (Integer enterNodeId : entry.enterNodeIds) {
94+
int streetNode = findStreetNodeForPlatformNode(enterNodeId);
10395
EdgeIteratorState entryEdge = graph.edge(streetNode, enterNodeId, 0.0, false);
10496
setEdgeType(entryEdge, GtfsStorage.EdgeType.ENTER_PT);
10597
entryEdge.setName(stop.stop_name);
10698
}
107-
EdgeIteratorState exitEdge = graph.edge(entry.exitNodeId, streetNode, 0.0, false);
108-
setEdgeType(exitEdge, GtfsStorage.EdgeType.EXIT_PT);
109-
exitEdge.setName(stop.stop_name);
99+
for (Integer exitNodeId : entry.exitNodeIds) {
100+
int streetNode = findStreetNodeForPlatformNode(exitNodeId);
101+
EdgeIteratorState exitEdge = graph.edge(exitNodeId, streetNode, 0.0, false);
102+
setEdgeType(exitEdge, GtfsStorage.EdgeType.EXIT_PT);
103+
exitEdge.setName(stop.stop_name);
104+
}
105+
}
106+
}
107+
108+
private int findStreetNodeForPlatformNode(int platformNodeId) {
109+
int streetNode;
110+
EdgeFilter filter = new EverythingButPt(encoder);
111+
QueryResult source = walkNetworkIndex.findClosest(nodeAccess.getLat(platformNodeId), nodeAccess.getLon(platformNodeId), filter);
112+
if (!source.isValid()) {
113+
throw new RuntimeException("Can't find street node for a platform. Did you import OSM data (or create a fake walk network)?");
114+
} else {
115+
streetNode = source.getClosestNode();
110116
}
117+
return streetNode;
111118
}
112119

113120
private void buildPtNetwork() {
114-
stopTimelineNodes = HashMultimap.create();
115-
arrivals = HashMultimap.create();
116-
times = new TIntIntHashMap();
117121
LocalDate startDate = feed.calculateStats().getStartDate();
118122
gtfsStorage.setStartDate(startDate);
119123
LocalDate endDate = feed.calculateStats().getEndDate();
@@ -173,25 +177,21 @@ private void buildPtNetwork() {
173177
edge.setFlags(encoder.setTime(edge.getFlags(), stopTime.arrival_time - prev.departure_time));
174178
gtfsStorage.getStopSequences().put(edge.getEdge(), stopTime.stop_sequence);
175179
}
176-
nodeAccess.setNode(i++, stop.stop_lat, stop.stop_lon);
177-
final int timelineNode = i - 1;
178-
nodeAccess.setAdditionalNodeField(timelineNode, NodeType.INTERNAL_PT.ordinal());
179-
times.put(timelineNode, stopTime.departure_time + time);
180-
stopTimelineNodes.put(stopTime.stop_id, new TimelineNodeIdWithTripId(timelineNode, trip.trip_id));
180+
final int departureTimelineNode = i++;
181+
nodeAccess.setNode(departureTimelineNode, stop.stop_lat, stop.stop_lon);
182+
nodeAccess.setAdditionalNodeField(departureTimelineNode, NodeType.INTERNAL_PT.ordinal());
183+
times.put(departureTimelineNode, stopTime.departure_time + time);
184+
departureTimelineNodes.put(stopTime.stop_id, new TimelineNodeIdWithTripId(departureTimelineNode, trip.trip_id));
185+
final int arrivalTimelineNode = i++;
186+
nodeAccess.setNode(arrivalTimelineNode, stop.stop_lat, stop.stop_lon);
187+
nodeAccess.setAdditionalNodeField(arrivalTimelineNode, NodeType.INTERNAL_PT.ordinal());
188+
times.put(arrivalTimelineNode, stopTime.arrival_time + time);
189+
arrivalTimelineNodes.put(stopTime.stop_id, new TimelineNodeIdWithTripId(arrivalTimelineNode, trip.trip_id));
181190
departureNode = i++;
182191
nodeAccess.setNode(departureNode, stop.stop_lat, stop.stop_lon);
183192
nodeAccess.setAdditionalNodeField(departureNode, NodeType.INTERNAL_PT.ordinal());
184193
times.put(departureNode, stopTime.departure_time + time);
185-
EdgeIteratorState edge = graph.edge(
186-
i - 2,
187-
departureNode,
188-
0.0,
189-
false);
190-
edge.setName(getRouteName(feed, trip));
191194
int dayShift = stopTime.departure_time / (24 * 60 * 60);
192-
setEdgeType(edge, GtfsStorage.EdgeType.BOARD);
193-
gtfsStorage.getStopSequences().put(edge.getEdge(), stopTime.stop_sequence);
194-
gtfsStorage.getExtraStrings().put(edge.getEdge(), trip.trip_id);
195195
BitSet validOn = getValidOn(validOnDay, dayShift);
196196
int validityId;
197197
if (gtfsStorage.getOperatingDayPatterns().containsKey(validOn)) {
@@ -200,16 +200,40 @@ private void buildPtNetwork() {
200200
validityId = gtfsStorage.getOperatingDayPatterns().size();
201201
gtfsStorage.getOperatingDayPatterns().put(validOn, validityId);
202202
}
203-
edge.setFlags(encoder.setValidityId(edge.getFlags(), validityId));
204-
edge.setFlags(encoder.setTransfers(edge.getFlags(), 1));
205-
edge = graph.edge(
206-
i - 3,
203+
204+
EdgeIteratorState boardEdge = graph.edge(
205+
departureTimelineNode,
207206
departureNode,
208207
0.0,
209208
false);
210-
edge.setName(getRouteName(feed, trip));
211-
setEdgeType(edge, GtfsStorage.EdgeType.DWELL);
212-
edge.setFlags(encoder.setTime(edge.getFlags(), stopTime.departure_time - stopTime.arrival_time));
209+
boardEdge.setName(getRouteName(feed, trip));
210+
setEdgeType(boardEdge, GtfsStorage.EdgeType.BOARD);
211+
gtfsStorage.getStopSequences().put(boardEdge.getEdge(), stopTime.stop_sequence);
212+
gtfsStorage.getExtraStrings().put(boardEdge.getEdge(), trip.trip_id);
213+
boardEdge.setFlags(encoder.setValidityId(boardEdge.getFlags(), validityId));
214+
boardEdge.setFlags(encoder.setTransfers(boardEdge.getFlags(), 1));
215+
216+
EdgeIteratorState alightEdge = graph.edge(
217+
arrivalNode,
218+
arrivalTimelineNode,
219+
0.0,
220+
false);
221+
alightEdge.setName(getRouteName(feed, trip));
222+
setEdgeType(alightEdge, GtfsStorage.EdgeType.ALIGHT);
223+
gtfsStorage.getStopSequences().put(alightEdge.getEdge(), stopTime.stop_sequence);
224+
gtfsStorage.getExtraStrings().put(alightEdge.getEdge(), trip.trip_id);
225+
alightEdge.setFlags(encoder.setValidityId(alightEdge.getFlags(), validityId));
226+
// alightEdge.setFlags(encoder.setTransfers(alightEdge.getFlags(), 1));
227+
228+
229+
EdgeIteratorState dwellEdge = graph.edge(
230+
arrivalNode,
231+
departureNode,
232+
0.0,
233+
false);
234+
dwellEdge.setName(getRouteName(feed, trip));
235+
setEdgeType(dwellEdge, GtfsStorage.EdgeType.DWELL);
236+
dwellEdge.setFlags(encoder.setTime(dwellEdge.getFlags(), stopTime.departure_time - stopTime.arrival_time));
213237
if (prev == null) {
214238
insertInboundBlockTransfers(arrivalNodes, trip, departureNode, stopTime, stop, validityId);
215239
}
@@ -223,34 +247,50 @@ private void buildPtNetwork() {
223247

224248
for (Stop stop : feed.stops.values()) {
225249
if (stop.location_type == 0) { // Only stops. Not interested in parent stations for now.
226-
nodeAccess.setNode(i++, stop.stop_lat, stop.stop_lon);
227-
int stopExitNode = i-1;
228-
nodeAccess.setAdditionalNodeField(stopExitNode, NodeType.STOP_EXIT_NODE.ordinal());
229-
for (Integer arrivalNodeId : arrivals.get(stop.stop_id)) {
230-
EdgeIteratorState leaveTimeExpandedNetworkEdge = graph.edge(arrivalNodeId, stopExitNode, 0.0, false);
231-
setEdgeType(leaveTimeExpandedNetworkEdge, GtfsStorage.EdgeType.LEAVE_TIME_EXPANDED_NETWORK);
232-
int arrivalTime = times.get(arrivalNodeId);
233-
leaveTimeExpandedNetworkEdge.setFlags(encoder.setTime(leaveTimeExpandedNetworkEdge.getFlags(), arrivalTime));
234-
}
235-
final Map<String, List<TimelineNodeIdWithTripId>> timelineNodesByRoute = stopTimelineNodes.get(stop.stop_id).stream().collect(Collectors.groupingBy(t -> feed.trips.get(t.tripId).route_id));
250+
final Map<String, List<TimelineNodeIdWithTripId>> arrivalTimelineNodesByRoute = arrivalTimelineNodes.get(stop.stop_id).stream().collect(Collectors.groupingBy(t -> feed.trips.get(t.tripId).route_id));
251+
252+
List<Integer> stopExitNodeIds = new ArrayList<>();
253+
arrivalTimelineNodesByRoute.forEach((routeId, timelineNodesWithTripId) -> {
254+
nodeAccess.setNode(i++, stop.stop_lat, stop.stop_lon);
255+
int stopExitNode = i-1;
256+
nodeAccess.setAdditionalNodeField(stopExitNode, NodeType.STOP_EXIT_NODE.ordinal());
257+
stopExitNodeIds.add(stopExitNode);
258+
NavigableSet<Fun.Tuple2<Integer, Integer>> timeNodes = new TreeSet<>();
259+
timelineNodesWithTripId.stream().map(t -> t.timelineNodeId)
260+
.forEach(nodeId -> timeNodes.add(new Fun.Tuple2<>(times.get(nodeId) % (24*60*60), nodeId)));
261+
wireUpAndAndConnectArrivalTimeline(stop, routeId,stopExitNode, timeNodes);
262+
});
263+
264+
265+
266+
final Map<String, List<TimelineNodeIdWithTripId>> departureTimelineNodesByRoute = departureTimelineNodes.get(stop.stop_id).stream().collect(Collectors.groupingBy(t -> feed.trips.get(t.tripId).route_id));
236267

237268
List<Integer> stopEnterNodeIds = new ArrayList<>();
238-
timelineNodesByRoute.forEach((routeId, timelineNodesWithTripId) -> {
269+
departureTimelineNodesByRoute.forEach((routeId, timelineNodesWithTripId) -> {
239270
nodeAccess.setNode(i++, stop.stop_lat, stop.stop_lon);
240271
int stopEnterNode = i-1;
241272
nodeAccess.setAdditionalNodeField(stopEnterNode, NodeType.STOP_ENTER_NODE.ordinal());
242273
stopEnterNodeIds.add(stopEnterNode);
243274
NavigableSet<Fun.Tuple2<Integer, Integer>> timeNodes = new TreeSet<>();
244275
timelineNodesWithTripId.stream().map(t -> t.timelineNodeId)
245276
.forEach(nodeId -> timeNodes.add(new Fun.Tuple2<>(times.get(nodeId) % (24*60*60), nodeId)));
246-
wireUpAndAndConnectTimeline(stop, routeId,stopEnterNode, timeNodes);
277+
wireUpAndAndConnectDepartureTimeline(stop, routeId,stopEnterNode, timeNodes);
247278
});
248-
stopEnterAndExitNodes.add(new EnterAndExitNodeIdWithStopId(stopEnterNodeIds, stop.stop_id, stopExitNode));
279+
stopEnterAndExitNodes.add(new EnterAndExitNodeIdWithStopId(stopEnterNodeIds, stop.stop_id, stopExitNodeIds));
249280
}
250281
}
251282
}
252283

253-
private void wireUpAndAndConnectTimeline(Stop stop, String routeId, int stopEnterNode, NavigableSet<Fun.Tuple2<Integer, Integer>> timeNodes) {
284+
private void wireUpAndAndConnectArrivalTimeline(Stop stop, String routeId, int stopExitNode, NavigableSet<Fun.Tuple2<Integer, Integer>> timeNodes) {
285+
for (Fun.Tuple2<Integer, Integer> e : timeNodes.descendingSet()) {
286+
EdgeIteratorState leaveTimeExpandedNetworkEdge = graph.edge(e.b, stopExitNode, 0.0, false);
287+
setEdgeType(leaveTimeExpandedNetworkEdge, GtfsStorage.EdgeType.LEAVE_TIME_EXPANDED_NETWORK);
288+
int arrivalTime = e.a;
289+
leaveTimeExpandedNetworkEdge.setFlags(encoder.setTime(leaveTimeExpandedNetworkEdge.getFlags(), arrivalTime));
290+
}
291+
}
292+
293+
private void wireUpAndAndConnectDepartureTimeline(Stop stop, String routeId, int stopEnterNode, NavigableSet<Fun.Tuple2<Integer, Integer>> timeNodes) {
254294
int time = 0;
255295
int prev = -1;
256296
for (Fun.Tuple2<Integer, Integer> e : timeNodes.descendingSet()) {

reader-gtfs/src/main/java/com/graphhopper/reader/gtfs/GtfsStorage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ static long traveltimeReverse(int edgeTimeValue, long latestExitTime) {
4444
private Map<String, Fare> fares;
4545

4646
enum EdgeType {
47-
HIGHWAY, ENTER_TIME_EXPANDED_NETWORK, LEAVE_TIME_EXPANDED_NETWORK, ENTER_PT, EXIT_PT, HOP, DWELL, BOARD, OVERNIGHT, TRANSFER, WAIT
47+
HIGHWAY, ENTER_TIME_EXPANDED_NETWORK, LEAVE_TIME_EXPANDED_NETWORK, ENTER_PT, EXIT_PT, HOP, DWELL, BOARD, ALIGHT, OVERNIGHT, TRANSFER, WAIT
4848
}
4949

5050
private DB data;

0 commit comments

Comments
 (0)