-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
1,435 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
'use strict' | ||
|
||
const debug = require('debug')('gtfs-utils:compute-trajectories') | ||
const {unique: shorthash} = require('shorthash') | ||
|
||
const readTrips = require('./read-trips') | ||
const inMemoryStore = require('./lib/in-memory-store') | ||
const {STOP, STATION} = require('./lib/location-types') | ||
const readShapes = require('./read-shapes') | ||
const computeSchedules = require('./compute-schedules') | ||
const buildTrajectory = require('./lib/build-trajectory') | ||
|
||
const computeTrajectories = async function* (readFile, filters = {}, opt = {}) { | ||
if (typeof readFile !== 'function') { | ||
throw new TypeError('readFile must be a function') | ||
} | ||
const { | ||
stop: stopFilter, | ||
} = { | ||
stop: () => true, | ||
...filters, | ||
} | ||
if (typeof stopFilter !== 'function') { | ||
throw new TypeError('filters.stop must be a function') | ||
} | ||
|
||
const { | ||
createStore, | ||
} = { | ||
createStore: inMemoryStore, | ||
...opt, | ||
} | ||
|
||
debug('reading trips') | ||
const trips = await readTrips(readFile, filters, { | ||
...opt, | ||
formatTrip: t => [t.shape_id, t.service_id], | ||
}) | ||
|
||
debug('reading stop locations') | ||
const stopLocsById = createStore() // stop ID -> stop location | ||
for await (const s of await readFile('stops')) { | ||
if ( | ||
s.location_type !== undefined && s.location_type !== '' | ||
&& s.location_type !== STOP && s.location_type !== STATION | ||
) continue | ||
if (!stopFilter(s)) continue | ||
const loc = [parseFloat(s.stop_lon), parseFloat(s.stop_lat)] | ||
await stopLocsById.set(s.stop_id, loc) | ||
} | ||
|
||
debug('reading shapes') | ||
const shapesById = createStore() // shape ID -> shape | ||
// todo: only read shapes that belong to non-filtered trips | ||
for await (const [shapeId, points] of readShapes(readFile, filters)) { | ||
await shapesById.set(shapeId, points) | ||
} | ||
|
||
debug('computing schedules') | ||
const schedules = await computeSchedules(readFile, filters, opt) | ||
|
||
debug('computing trajectories') | ||
let i = 0 | ||
for await (const schedule of schedules.values()) { | ||
if (++i % 100 === 0) debug(i) | ||
|
||
// Taking only the list of stops alon into account wouldn't suffice, | ||
// as there might be two trips that visit the same stops with vastly | ||
// different timing. Same with using the list of arrivals/departures only. | ||
const temporalSig = shorthash(JSON.stringify({ | ||
stops: schedule.stops, | ||
arrivals: schedule.arrivals, | ||
departures: schedule.departures, | ||
})) | ||
|
||
for (const _ of schedule.trips) { | ||
const {tripId, start: tripStartTime} = _ | ||
const [shapeId, serviceId] = await trips.get(tripId) | ||
if (!shapeId) { | ||
// todo: is this a bug? | ||
debug('missing shape ID for trip ID', tripId) | ||
continue | ||
} | ||
if (!serviceId) { | ||
debug('missing service ID for trip ID', tripId) | ||
continue | ||
} | ||
const shape = await shapesById.get(shapeId) | ||
if (!shapeId) { | ||
// todo: is this a bug? | ||
debug('missing shape for shape ID', shapeId) | ||
continue | ||
} | ||
|
||
// todo: support headway-based (frequencies.txt) trips | ||
const tr = await buildTrajectory(shapeId, shape, schedule, stopLocsById, tripStartTime) | ||
tr.properties.tripId = tripId | ||
tr.properties.serviceId = serviceId | ||
tr.properties.id = temporalSig + '-' + shapeId | ||
yield tr | ||
} | ||
} | ||
} | ||
|
||
module.exports = computeTrajectories |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
'use strict' | ||
|
||
const readCsv = require('../read-csv') | ||
const computeTrajectories = require('../compute-trajectories') | ||
|
||
const readFile = async (file) => { | ||
return await readCsv(require.resolve('sample-gtfs-feed/gtfs/' + file + '.txt')) | ||
} | ||
|
||
;(async () => { | ||
const trajectories = await computeTrajectories(readFile) | ||
for await (const trajectory of trajectories) { | ||
console.log(trajectory) | ||
} | ||
})() | ||
.catch((err) => { | ||
console.error(err) | ||
process.exit(1) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.