forked from nate-parrott/subway
-
Notifications
You must be signed in to change notification settings - Fork 0
/
virtual_rider.js
116 lines (107 loc) · 3.04 KB
/
virtual_rider.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
let atStopState = (id) => "at_stop:" + id;
let onTripState = (id) => "on_trip:" + id;
let MAX_TIME = 1000 * 60;
class StateMap {
constructor() {
this.earliestRidersAtStates = {};
}
addRider(rider) {
let existing = this.earliestRidersAtStates[rider.state];
if (!existing || rider.time < existing.time) {
this.earliestRidersAtStates[rider.state] = rider;
return true;
}
return false;
}
addRiderAndTransfersByAppendingStop(oldRider, stopId, time, allTransfers) {
let direct = oldRider.byAdding(atStopState(stopId), time);
if (this.addRider(direct)) {
// add all transfers:
for (let transfer of allTransfers[stopId] || []) {
this.addRiderAndTransfersByAppendingStop(
direct,
transfer["to"],
time + transfer.time,
allTransfers
);
}
}
}
}
class Rider {
constructor(states, time) {
this.states = states; // states are strings
this.time = time;
this.state = states.length ? states[states.length - 1] : null;
}
byAdding(state, finalTime) {
return new Rider([...this.states, state], finalTime);
}
}
let _computeTravelTimes = (
startStationId,
endStationIds,
transfers,
events,
startTime
) => {
let stateMap = new StateMap();
let emptyPath = new Rider([], startTime);
stateMap.addRiderAndTransfersByAppendingStop(
emptyPath,
startStationId,
startTime,
transfers
);
// console.log(stateMap);
for (let { time, trip_id, stop_id, route_name } of events) {
// model exiting the train:
let riderOnTrain = stateMap.earliestRidersAtStates[onTripState(trip_id)];
if (riderOnTrain && riderOnTrain.time <= time) {
stateMap.addRiderAndTransfersByAppendingStop(
riderOnTrain,
stop_id,
time,
transfers
);
}
// model boarding the train:
let riderOnPlatform = stateMap.earliestRidersAtStates[atStopState(stop_id)];
if (riderOnPlatform && riderOnPlatform.time <= time) {
let riderOnTrain = riderOnPlatform.byAdding(onTripState(trip_id), time);
stateMap.addRider(riderOnTrain);
}
}
let travelTimes = {};
for (let stationId of endStationIds) {
let rider = stateMap.earliestRidersAtStates[atStopState(stationId)];
travelTimes[stationId] = rider ? rider.time - startTime : MAX_TIME;
}
return travelTimes;
};
let scheduleCache = {};
let getSchedule = (name, callback) => {
if (scheduleCache[name]) {
callback(scheduleCache[name]);
} else {
d3.json("./schedules/" + name + ".json", (schedule) => {
scheduleCache[name] = schedule;
callback(schedule);
});
}
};
let computeTravelTimes = (startStationId, scheduleName, callback) => {
getSchedule(scheduleName, (schedule) => {
callback(
_computeTravelTimes(
startStationId,
Object.keys(subway.stations),
gtfs_transfers,
schedule.events,
schedule.start_time
)
);
});
};
// let HOURS = 60 * 60;
// console.log(computeTravelTimes('127', Object.keys(subway.stations), 8*HOURS, gtfs_json, 'weekdays'));