From a9dcc3679a7aed4d6360abe68a9b38f9df8e6db4 Mon Sep 17 00:00:00 2001 From: Harm Delva Date: Tue, 3 Mar 2020 19:55:57 +0100 Subject: [PATCH 1/8] Add dynamic catalogs --- src/configs/default.ts | 7 ++ src/configs/dissect.ts | 7 ++ src/configs/flexible_profile_transit.ts | 7 ++ src/configs/flexible_transit.ts | 7 ++ src/configs/geospatial_fragment.ts | 7 ++ src/configs/reduced_car.ts | 7 ++ src/configs/road_planner.ts | 7 ++ src/configs/triangle_transit.ts | 4 + src/demo.ts | 3 +- src/entities/catalog/catalog.ts | 15 ++++ src/entities/catalog/dataset.ts | 19 +++++ src/entities/catalog/dataset_distribution.ts | 13 ++++ src/fetcher/catalog/CatalogFetcherDefault.ts | 74 +++++++++++++++++++ src/fetcher/catalog/CatalogProviderDefault.ts | 34 +++++++++ src/fetcher/catalog/ICatalogFetcher.ts | 5 ++ src/fetcher/catalog/ICatalogProvider.ts | 6 ++ src/planner/configurations/Planner.ts | 20 +++++ src/types.ts | 3 + src/uri/constants.ts | 2 + 19 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 src/entities/catalog/catalog.ts create mode 100644 src/entities/catalog/dataset.ts create mode 100644 src/entities/catalog/dataset_distribution.ts create mode 100644 src/fetcher/catalog/CatalogFetcherDefault.ts create mode 100644 src/fetcher/catalog/CatalogProviderDefault.ts create mode 100644 src/fetcher/catalog/ICatalogFetcher.ts create mode 100644 src/fetcher/catalog/ICatalogProvider.ts diff --git a/src/configs/default.ts b/src/configs/default.ts index 70df166c..3f6e5d2c 100644 --- a/src/configs/default.ts +++ b/src/configs/default.ts @@ -4,6 +4,10 @@ import Context from "../Context"; import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; import RoutingPhase from "../enums/RoutingPhase"; import TravelMode from "../enums/TravelMode"; +import CatalogFetcherDefault from "../fetcher/catalog/CatalogFetcherDefault"; +import CatalogProviderDefault from "../fetcher/catalog/CatalogProviderDefault"; +import ICatalogFetcher from "../fetcher/catalog/ICatalogFetcher"; +import ICatalogProvider from "../fetcher/catalog/ICatalogProvider"; import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; import ConnectionsProviderDefault from "../fetcher/connections/ConnectionsProviderDefault"; import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; @@ -78,6 +82,9 @@ container.bind(TYPES.ReachableStopsFinder) container.bind(TYPES.ReachableStopsFinder) .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); +container.bind(TYPES.CatalogFetcher).to(CatalogFetcherDefault).inSingletonScope(); +container.bind(TYPES.CatalogProvider).to(CatalogProviderDefault).inSingletonScope(); + container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderDefault).inSingletonScope(); container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); container.bind>(TYPES.ConnectionsFetcherFactory) diff --git a/src/configs/dissect.ts b/src/configs/dissect.ts index 18d8b44e..db328309 100644 --- a/src/configs/dissect.ts +++ b/src/configs/dissect.ts @@ -5,6 +5,10 @@ import RoutableTileRegistry from "../entities/tiles/registry"; import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; import RoutingPhase from "../enums/RoutingPhase"; import TravelMode from "../enums/TravelMode"; +import CatalogFetcherDefault from "../fetcher/catalog/CatalogFetcherDefault"; +import CatalogProviderDefault from "../fetcher/catalog/CatalogProviderDefault"; +import ICatalogFetcher from "../fetcher/catalog/ICatalogFetcher"; +import ICatalogProvider from "../fetcher/catalog/ICatalogProvider"; import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; import ConnectionsProviderMerge from "../fetcher/connections/ConnectionsProviderDefault"; import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; @@ -82,6 +86,9 @@ container.bind(TYPES.ReachableStopsFinder) container.bind(TYPES.ReachableStopsFinder) .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); +container.bind(TYPES.CatalogFetcher).to(CatalogFetcherDefault).inSingletonScope(); +container.bind(TYPES.CatalogProvider).to(CatalogProviderDefault).inSingletonScope(); + container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderMerge).inSingletonScope(); container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); container.bind>(TYPES.ConnectionsFetcherFactory) diff --git a/src/configs/flexible_profile_transit.ts b/src/configs/flexible_profile_transit.ts index ea91c871..dd7a6a0a 100644 --- a/src/configs/flexible_profile_transit.ts +++ b/src/configs/flexible_profile_transit.ts @@ -3,6 +3,10 @@ import Context from "../Context"; import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; import RoutingPhase from "../enums/RoutingPhase"; import TravelMode from "../enums/TravelMode"; +import CatalogFetcherDefault from "../fetcher/catalog/CatalogFetcherDefault"; +import CatalogProviderDefault from "../fetcher/catalog/CatalogProviderDefault"; +import ICatalogFetcher from "../fetcher/catalog/ICatalogFetcher"; +import ICatalogProvider from "../fetcher/catalog/ICatalogProvider"; import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; import ConnectionsProviderDefault from "../fetcher/connections/ConnectionsProviderDefault"; import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; @@ -75,6 +79,9 @@ container.bind(TYPES.PathfinderProvider).to(PathfinderProvid container.bind(TYPES.ProfileFetcher).to(ProfileFetcherDefault).inSingletonScope(); container.bind(TYPES.ProfileProvider).to(ProfileProviderDefault).inSingletonScope(); +container.bind(TYPES.CatalogFetcher).to(CatalogFetcherDefault).inSingletonScope(); +container.bind(TYPES.CatalogProvider).to(CatalogProviderDefault).inSingletonScope(); + container.bind(TYPES.ReachableStopsFinder) .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Initial); container.bind(TYPES.ReachableStopsFinder) diff --git a/src/configs/flexible_transit.ts b/src/configs/flexible_transit.ts index 9bda734d..05c63622 100644 --- a/src/configs/flexible_transit.ts +++ b/src/configs/flexible_transit.ts @@ -3,6 +3,10 @@ import Context from "../Context"; import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; import RoutingPhase from "../enums/RoutingPhase"; import TravelMode from "../enums/TravelMode"; +import CatalogFetcherDefault from "../fetcher/catalog/CatalogFetcherDefault"; +import CatalogProviderDefault from "../fetcher/catalog/CatalogProviderDefault"; +import ICatalogFetcher from "../fetcher/catalog/ICatalogFetcher"; +import ICatalogProvider from "../fetcher/catalog/ICatalogProvider"; import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; import ConnectionsProviderDefault from "../fetcher/connections/ConnectionsProviderDefault"; import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; @@ -82,6 +86,9 @@ container.bind(TYPES.ReachableStopsFinder) container.bind(TYPES.ReachableStopsFinder) .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); +container.bind(TYPES.CatalogFetcher).to(CatalogFetcherDefault).inSingletonScope(); +container.bind(TYPES.CatalogProvider).to(CatalogProviderDefault).inSingletonScope(); + container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderDefault).inSingletonScope(); container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); container.bind>(TYPES.ConnectionsFetcherFactory) diff --git a/src/configs/geospatial_fragment.ts b/src/configs/geospatial_fragment.ts index e3364c96..a7ab0327 100644 --- a/src/configs/geospatial_fragment.ts +++ b/src/configs/geospatial_fragment.ts @@ -3,6 +3,10 @@ import Context from "../Context"; import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; import RoutingPhase from "../enums/RoutingPhase"; import TravelMode from "../enums/TravelMode"; +import CatalogFetcherDefault from "../fetcher/catalog/CatalogFetcherDefault"; +import CatalogProviderDefault from "../fetcher/catalog/CatalogProviderDefault"; +import ICatalogFetcher from "../fetcher/catalog/ICatalogFetcher"; +import ICatalogProvider from "../fetcher/catalog/ICatalogProvider"; import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; import ConnectionsProviderDefault from "../fetcher/connections/ConnectionsProviderDefault"; import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; @@ -86,6 +90,9 @@ container.bind(TYPES.ReachableStopsFinder) container.bind(TYPES.ReachableStopsFinder) .to(ReachableStopsFinderOnlySelf).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); +container.bind(TYPES.CatalogFetcher).to(CatalogFetcherDefault).inSingletonScope(); +container.bind(TYPES.CatalogProvider).to(CatalogProviderDefault).inSingletonScope(); + container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderDefault).inSingletonScope(); container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); container.bind>(TYPES.ConnectionsFetcherFactory) diff --git a/src/configs/reduced_car.ts b/src/configs/reduced_car.ts index 43b63032..20444505 100644 --- a/src/configs/reduced_car.ts +++ b/src/configs/reduced_car.ts @@ -3,6 +3,10 @@ import Context from "../Context"; import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; import RoutingPhase from "../enums/RoutingPhase"; import TravelMode from "../enums/TravelMode"; +import CatalogFetcherDefault from "../fetcher/catalog/CatalogFetcherDefault"; +import CatalogProviderDefault from "../fetcher/catalog/CatalogProviderDefault"; +import ICatalogFetcher from "../fetcher/catalog/ICatalogFetcher"; +import ICatalogProvider from "../fetcher/catalog/ICatalogProvider"; import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; import ConnectionsProviderDefault from "../fetcher/connections/ConnectionsProviderDefault"; import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; @@ -80,6 +84,9 @@ container.bind(TYPES.ReachableStopsFinder) container.bind(TYPES.ReachableStopsFinder) .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); +container.bind(TYPES.CatalogFetcher).to(CatalogFetcherDefault).inSingletonScope(); +container.bind(TYPES.CatalogProvider).to(CatalogProviderDefault).inSingletonScope(); + container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderDefault).inSingletonScope(); container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); container.bind>(TYPES.ConnectionsFetcherFactory) diff --git a/src/configs/road_planner.ts b/src/configs/road_planner.ts index 9ad2fb60..8d8f70ce 100644 --- a/src/configs/road_planner.ts +++ b/src/configs/road_planner.ts @@ -3,6 +3,10 @@ import Context from "../Context"; import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; import RoutingPhase from "../enums/RoutingPhase"; import TravelMode from "../enums/TravelMode"; +import CatalogFetcherDefault from "../fetcher/catalog/CatalogFetcherDefault"; +import CatalogProviderDefault from "../fetcher/catalog/CatalogProviderDefault"; +import ICatalogFetcher from "../fetcher/catalog/ICatalogFetcher"; +import ICatalogProvider from "../fetcher/catalog/ICatalogProvider"; import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; import ConnectionsProviderDefault from "../fetcher/connections/ConnectionsProviderDefault"; import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; @@ -78,6 +82,9 @@ container.bind(TYPES.ReachableStopsFinder) container.bind(TYPES.ReachableStopsFinder) .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); +container.bind(TYPES.CatalogFetcher).to(CatalogFetcherDefault).inSingletonScope(); +container.bind(TYPES.CatalogProvider).to(CatalogProviderDefault).inSingletonScope(); + container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderDefault).inSingletonScope(); container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); container.bind>(TYPES.ConnectionsFetcherFactory) diff --git a/src/configs/triangle_transit.ts b/src/configs/triangle_transit.ts index 0ec90715..2527241a 100644 --- a/src/configs/triangle_transit.ts +++ b/src/configs/triangle_transit.ts @@ -3,6 +3,10 @@ import Context from "../Context"; import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; import RoutingPhase from "../enums/RoutingPhase"; import TravelMode from "../enums/TravelMode"; +import CatalogFetcherDefault from "../fetcher/catalog/CatalogFetcherDefault"; +import CatalogProviderDefault from "../fetcher/catalog/CatalogProviderDefault"; +import ICatalogFetcher from "../fetcher/catalog/ICatalogFetcher"; +import ICatalogProvider from "../fetcher/catalog/ICatalogProvider"; import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; import ConnectionsProviderMerge from "../fetcher/connections/ConnectionsProviderDefault"; import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; diff --git a/src/demo.ts b/src/demo.ts index 608f3b09..0ae11611 100644 --- a/src/demo.ts +++ b/src/demo.ts @@ -7,8 +7,7 @@ import Units from "./util/Units"; export default async (logResults) => { const planner = new FlexibleProfileTransitPlanner(); - planner.addConnectionSource("https://graph.irail.be/sncb/connections"); - planner.addStopSource("https://irail.be/stations/NMBS"); + await planner.addCatalogSource("https://graph.irail.be/sncb/catalog"); if (logResults) { let scannedConnections = 0; diff --git a/src/entities/catalog/catalog.ts b/src/entities/catalog/catalog.ts new file mode 100644 index 00000000..618f6cee --- /dev/null +++ b/src/entities/catalog/catalog.ts @@ -0,0 +1,15 @@ +import { Dataset } from "./dataset"; + +export class Catalog { + public static create(id: string) { + return new Catalog(id); + } + + public id: string; + public datasets: Dataset[]; + public publisher: any; + + constructor(id: string) { + this.id = id; + } +} diff --git a/src/entities/catalog/dataset.ts b/src/entities/catalog/dataset.ts new file mode 100644 index 00000000..b2b93ba0 --- /dev/null +++ b/src/entities/catalog/dataset.ts @@ -0,0 +1,19 @@ +import DatasetDistribution from "./dataset_distribution"; + +export class Dataset { + public static create(id: string) { + return new Dataset(id); + } + + public id: string; + public subject: string; + public description: string; + public title: string; + public area: string; + public rights: string; + public distributions: DatasetDistribution[]; + + constructor(id: string) { + this.id = id; + } +} diff --git a/src/entities/catalog/dataset_distribution.ts b/src/entities/catalog/dataset_distribution.ts new file mode 100644 index 00000000..829fee2f --- /dev/null +++ b/src/entities/catalog/dataset_distribution.ts @@ -0,0 +1,13 @@ +export default class DatasetDistribution { + public static create(id: string) { + return new DatasetDistribution(id); + } + + public id: string; + public accessUrl: string; + public mediatypes: string[]; + + constructor(id: string) { + this.id = id; + } +} diff --git a/src/fetcher/catalog/CatalogFetcherDefault.ts b/src/fetcher/catalog/CatalogFetcherDefault.ts new file mode 100644 index 00000000..f7caf36c --- /dev/null +++ b/src/fetcher/catalog/CatalogFetcherDefault.ts @@ -0,0 +1,74 @@ +import { inject, injectable } from "inversify"; +import LDFetch from "ldfetch"; +import { Catalog } from "../../entities/catalog/catalog"; +import { Dataset } from "../../entities/catalog/dataset"; +import DatasetDistribution from "../../entities/catalog/dataset_distribution"; +import { LDLoader } from "../../loader/ldloader"; +import { ThingView } from "../../loader/views/single"; +import TYPES from "../../types"; +import { DCAT, DCT } from "../../uri/constants"; +import URI from "../../uri/uri"; +import ICatalogFetcher from "./ICatalogFetcher"; + +@injectable() +export default class CatalogFetcherDefault implements ICatalogFetcher { + + protected ldFetch: LDFetch; + protected ldLoader: LDLoader; + + constructor( + @inject(TYPES.LDFetch) ldFetch: LDFetch, + ) { + this.ldFetch = ldFetch; + this.ldLoader = new LDLoader(); + + // unordered collections + this.ldLoader.defineCollection(URI.inNS(DCAT, "distribution")); + this.ldLoader.defineCollection(URI.inNS(DCAT, "dataset")); + this.ldLoader.defineCollection(URI.inNS(DCAT, "mediaType")); + } + + public async get(url: string): Promise { + const rdfThing = await this.ldFetch.get(url); + const triples = rdfThing.triples; + + const [profile] = this.ldLoader.process(triples, [ + this.getView(), + ]); + + profile.id = url; + + return profile; + } + + protected getView() { + const view = new ThingView(Catalog.create); + view.addFilter((entity) => + entity[URI.inNS(DCAT, "dataset")] !== undefined, + ); + view.addMapping(URI.inNS(DCT, "publisher"), "publisher"); + view.addMapping(URI.inNS(DCAT, "dataset"), "datasets", this.getDatasetView()); + return view; + } + + protected getDatasetView() { + const view = new ThingView(Dataset.create); + view.addFilter((entity) => + entity[URI.inNS(DCAT, "distribution")] !== undefined, + ); + view.addMapping(URI.inNS(DCT, "subject"), "subject"); + view.addMapping(URI.inNS(DCT, "description"), "description"); + view.addMapping(URI.inNS(DCT, "title"), "title"); + view.addMapping(URI.inNS(DCT, "spatial"), "area"); + view.addMapping(URI.inNS(DCAT, "accessRights"), "rights"); + view.addMapping(URI.inNS(DCAT, "distribution"), "distributions", this.getDistributionView()); + return view; + } + + protected getDistributionView() { + const view = new ThingView(DatasetDistribution.create); + view.addMapping(URI.inNS(DCAT, "accessURL"), "accessUrl"); + view.addMapping(URI.inNS(DCAT, "mediaType"), "mediatypes"); + return view; + } +} diff --git a/src/fetcher/catalog/CatalogProviderDefault.ts b/src/fetcher/catalog/CatalogProviderDefault.ts new file mode 100644 index 00000000..88d3f30e --- /dev/null +++ b/src/fetcher/catalog/CatalogProviderDefault.ts @@ -0,0 +1,34 @@ +import { inject, injectable } from "inversify"; +import { Catalog } from "../../entities/catalog/catalog"; +import TYPES from "../../types"; +import ICatalogFetcher from "./ICatalogFetcher"; +import ICatalogProvider from "./ICatalogProvider"; + +interface ICatalogMap { + [label: string]: Promise; +} + +@injectable() +export default class CatalogProviderDefault implements ICatalogProvider { + + private catalogs: ICatalogMap; + private fetcher: ICatalogFetcher; + + constructor( + @inject(TYPES.CatalogFetcher) fetcher: ICatalogFetcher, + ) { + this.catalogs = {}; + this.fetcher = fetcher; + } + + public getCatalog(catalogId: string): Promise { + if (this.catalogs[catalogId] === undefined) { + this.catalogs[catalogId] = this.fetcher.get(catalogId); + } + return this.catalogs[catalogId]; + } + + public getCatalogs(): Promise { + return Promise.all(Object.values(this.catalogs)); + } +} diff --git a/src/fetcher/catalog/ICatalogFetcher.ts b/src/fetcher/catalog/ICatalogFetcher.ts new file mode 100644 index 00000000..6e2dffd4 --- /dev/null +++ b/src/fetcher/catalog/ICatalogFetcher.ts @@ -0,0 +1,5 @@ +import { Catalog } from "../../entities/catalog/catalog"; + +export default interface ICatalogFetcher { + get(url: string): Promise; +} diff --git a/src/fetcher/catalog/ICatalogProvider.ts b/src/fetcher/catalog/ICatalogProvider.ts new file mode 100644 index 00000000..53b29f82 --- /dev/null +++ b/src/fetcher/catalog/ICatalogProvider.ts @@ -0,0 +1,6 @@ +import { Catalog } from "../../entities/catalog/catalog"; + +export default interface ICatalogProvider { + getCatalog(catalogId: string): Promise; + getCatalogs(): Promise; +} diff --git a/src/planner/configurations/Planner.ts b/src/planner/configurations/Planner.ts index 63d54b20..bb3a74b9 100644 --- a/src/planner/configurations/Planner.ts +++ b/src/planner/configurations/Planner.ts @@ -7,6 +7,7 @@ import Context from "../../Context"; import TravelMode from "../../enums/TravelMode"; import EventBus from "../../events/EventBus"; import EventType from "../../events/EventType"; +import ICatalogProvider from "../../fetcher/catalog/ICatalogProvider"; import IConnectionsProvider from "../../fetcher/connections/IConnectionsProvider"; import ProfileProvider from "../../fetcher/profiles/ProfileProviderDefault"; import IStop from "../../fetcher/stops/IStop"; @@ -37,6 +38,7 @@ export default abstract class Planner { private connectionsProvider: IConnectionsProvider; private stopsProvider: IStopsProvider; private locationResolver: ILocationResolver; + private catalogProvider: ICatalogProvider; /** * Initializes a new Planner @@ -52,6 +54,7 @@ export default abstract class Planner { this.eventBus = EventBus.getInstance(); this.roadPlanner = container.get(TYPES.RoadPlanner); this.connectionsProvider = container.get(TYPES.ConnectionsProvider); + this.catalogProvider = container.get(TYPES.CatalogProvider); this.stopsProvider = container.get(TYPES.StopsProvider); this.locationResolver = container.get(TYPES.LocationResolver); @@ -74,6 +77,23 @@ export default abstract class Planner { return this.stopsProvider.getSources(); } + public async addCatalogSource(accessUrl: string) { + const catalog = await this.catalogProvider.getCatalog(accessUrl); + for (const dataset of catalog.datasets) { + for (const distribution of dataset.distributions) { + if (dataset.subject === "lc:Connection") { + this.connectionsProvider.addConnectionSource( + { accessUrl: distribution.accessUrl, travelMode: TravelMode.Train }, + ); + } else if (dataset.subject === "gtfs:Stop") { + this.stopsProvider.addStopSource( + { accessUrl: distribution.accessUrl }, + ); + } + } + } + } + public async completePath(path: IPath): Promise { const completePath = Path.create(); diff --git a/src/types.ts b/src/types.ts index d7fe4eaa..a97adb4c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,6 +14,9 @@ const TYPES = { HypermediaTreeProvider: Symbol("HypermediaTreeProvider"), HypermediaTreeFetcherFactory: Symbol("HypermediaTreeFetcherFactory"), + CatalogFetcher: Symbol("CatalogFetcher"), + CatalogProvider: Symbol("CatalogProvider"), + ConnectionsProvider: Symbol("ConnectionsProvider"), ConnectionsFetcher: Symbol("ConnectionsFetcher"), ConnectionsFetcherFactory: Symbol("ConnectionsFetcherFactory"), diff --git a/src/uri/constants.ts b/src/uri/constants.ts index a645d9a9..e6c1d383 100644 --- a/src/uri/constants.ts +++ b/src/uri/constants.ts @@ -10,3 +10,5 @@ export const PLANNER = "https://planner.js.org/terms#"; export const PROFILE = "https://w3id.org/openplannerteam/profile#"; export const TREE = "https://w3id.org/tree#"; export const LC = "http://semweb.mmlab.be/ns/linkedconnections#"; +export const DCAT = "http://www.w3.org/ns/dcat#"; +export const DCT = "http://purl.org/dc/terms/"; From 04a6da8ddf5b28af6fda03be0f8a393d31c65dbe Mon Sep 17 00:00:00 2001 From: Harm Delva Date: Thu, 19 Mar 2020 13:12:46 +0100 Subject: [PATCH 2/8] Clean up Routable Tile fetching --- src/analytics/isochrones/visualize.ts | 8 +- src/entities/profile/CharacteresticProfile.ts | 18 +--- src/entities/profile/DynamicProfile.ts | 36 +++---- src/entities/profile/PedestrianProfile.ts | 97 ------------------- src/entities/tiles/node.ts | 7 +- src/entities/tiles/way.ts | 37 +++---- .../profiles/ProfileProviderDefault.ts | 1 - .../tiles/RoutableTileFetcherDefault.ts | 94 ------------------ .../tiles/RoutableTileFetcherExtended.ts | 56 ----------- src/fetcher/tiles/RoutableTileFetcherRaw.ts | 54 ++++++----- 10 files changed, 67 insertions(+), 341 deletions(-) delete mode 100644 src/entities/profile/PedestrianProfile.ts delete mode 100644 src/fetcher/tiles/RoutableTileFetcherDefault.ts delete mode 100644 src/fetcher/tiles/RoutableTileFetcherExtended.ts diff --git a/src/analytics/isochrones/visualize.ts b/src/analytics/isochrones/visualize.ts index 9d4eda28..9844e629 100644 --- a/src/analytics/isochrones/visualize.ts +++ b/src/analytics/isochrones/visualize.ts @@ -73,10 +73,10 @@ export function visualizeIsochrone(registry: RoutableTileRegistry, pathTree: IPa } } - nodes.push({ latitude: 90, longitude: 180, id: "1" }); - nodes.push({ latitude: -90, longitude: 180, id: "2" }); - nodes.push({ latitude: 90, longitude: -180, id: "3" }); - nodes.push({ latitude: -90, longitude: -180, id: "4" }); + nodes.push({ latitude: 90, longitude: 180, id: "1", definedTags: {}, freeformTags: [] }); + nodes.push({ latitude: -90, longitude: 180, id: "2", definedTags: {}, freeformTags: [] }); + nodes.push({ latitude: 90, longitude: -180, id: "3", definedTags: {}, freeformTags: [] }); + nodes.push({ latitude: -90, longitude: -180, id: "4", definedTags: {}, freeformTags: [] }); costs["1"] = Infinity; costs["2"] = Infinity; diff --git a/src/entities/profile/CharacteresticProfile.ts b/src/entities/profile/CharacteresticProfile.ts index 472fb383..b82e0c90 100644 --- a/src/entities/profile/CharacteresticProfile.ts +++ b/src/entities/profile/CharacteresticProfile.ts @@ -69,22 +69,6 @@ export default class CharacteristicProfile extends DynamicProfile { } private getWayCharacteristic(way: RoutableTileWay) { - return way.reachable + - way.accessRestrictions + - way.bicycleAccessRestrictions + - way.constructionKind + - way.crossingKind + - way.cyclewayKind + - way.footwayKind + - way.highwayKind + - way.maxSpeed + - way.motorVehicleAccessRestrictions + - way.motorcarAccessRestrictions + - way.onewayBicycleKind + - way.onewayKind + - way.smoothnessKind + - way.surfaceKind + - way.trackType + - way.vehicleAccessRestrictions; + return way.reachable + Object.values(way.definedTags).join(); } } diff --git a/src/entities/profile/DynamicProfile.ts b/src/entities/profile/DynamicProfile.ts index 0e077c45..a0d44144 100644 --- a/src/entities/profile/DynamicProfile.ts +++ b/src/entities/profile/DynamicProfile.ts @@ -1,4 +1,3 @@ -import getOsmTagMapping from "../../enums/OSMTags"; import { DistanceM, DurationMs } from "../../interfaces/units"; import Geo from "../../util/Geo"; import { RoutableTileNode } from "../tiles/node"; @@ -22,12 +21,9 @@ export default class DynamicProfile extends Profile { public maxSpeed: number; public usePublicTransport: boolean; - private mapping; - constructor(url: string) { super(); this.id = url; - this.mapping = getOsmTagMapping(); this.accessRules = []; this.onewayRules = []; @@ -50,8 +46,7 @@ export default class DynamicProfile extends Profile { if (rule.conclusion.isOneway !== undefined) { // should always be the case, but just in case if (rule.condition !== undefined) { - const field = this.mapping[rule.condition.predicate]; - if (way[field] === rule.condition.object) { + if (way.definedTags[rule.condition.predicate] === rule.condition.object) { return rule.conclusion.isOneway; } } else { @@ -66,8 +61,7 @@ export default class DynamicProfile extends Profile { if (rule.conclusion.hasAccess !== undefined) { // should always be the case, but just in case if (rule.condition !== undefined) { - const field = this.mapping[rule.condition.predicate]; - if (way[field] === rule.condition.object) { + if (way.definedTags[rule.condition.predicate] === rule.condition.object) { return rule.conclusion.hasAccess; } } else { @@ -92,8 +86,7 @@ export default class DynamicProfile extends Profile { if (rule.conclusion.speed !== undefined) { // should always be the case, but just in case if (rule.condition !== undefined) { - const field = this.mapping[rule.condition.predicate]; - if (way[field] === rule.condition.object) { + if (way.definedTags[rule.condition.predicate] === rule.condition.object) { if (typeof (rule.conclusion.speed) === "number") { return Math.min(rule.conclusion.speed, speedLimit); } @@ -125,8 +118,7 @@ export default class DynamicProfile extends Profile { if (rule.conclusion.priority !== undefined) { // should always be the case, but just in case if (rule.condition !== undefined) { - const field = this.mapping[rule.condition.predicate]; - if (way[field] === rule.condition.object) { + if (way.definedTags[rule.condition.predicate] === rule.condition.object) { return 1 - (rule.conclusion.priority - 1); } } else { @@ -141,12 +133,16 @@ export default class DynamicProfile extends Profile { } public isObstacle(node: RoutableTileNode): boolean { + if (!node.definedTags) { + // not a real OSM node, we're probably embedding a location onto the network + return false; + } + for (const rule of this.obstacleRules) { if (rule.conclusion.isObstacle !== undefined) { // should always be the case, but just in case if (rule.condition !== undefined) { - const field = this.mapping[rule.condition.predicate]; - if (node[field] === rule.condition.object) { + if (node.definedTags[rule.condition.predicate] === rule.condition.object) { return rule.conclusion.isObstacle; } } else { @@ -157,17 +153,23 @@ export default class DynamicProfile extends Profile { } public getObstacleTime(node: RoutableTileNode): DurationMs { + if (!node.definedTags) { + // not a real OSM node, we're probably embedding a location onto the network + return 0; + } + for (const rule of this.obstacleTimeRules) { if (rule.conclusion.obstacleTime !== undefined) { // should always be the case, but just in case if (rule.condition !== undefined) { - const field = this.mapping[rule.condition.predicate]; - if (node[field] && rule.condition.object === undefined) { + const field = rule.condition.predicate; + if (node.definedTags[field] && rule.condition.object === undefined) { return rule.conclusion.obstacleTime * 1000; } - if (node[field] === rule.condition.object && rule.condition.object !== undefined) { + if (node.definedTags[field] === rule.condition.object && rule.condition.object !== undefined) { return rule.conclusion.obstacleTime * 1000; } + } else { return rule.conclusion.obstacleTime * 1000; } diff --git a/src/entities/profile/PedestrianProfile.ts b/src/entities/profile/PedestrianProfile.ts deleted file mode 100644 index ffc6dfc8..00000000 --- a/src/entities/profile/PedestrianProfile.ts +++ /dev/null @@ -1,97 +0,0 @@ -import Highway from "../../enums/Highway"; -import { DistanceM, DurationMs } from "../../interfaces/units"; -import Geo from "../../util/Geo"; -import { RoutableTileNode } from "../tiles/node"; -import { RoutableTileWay } from "../tiles/way"; -import Profile from "./Profile"; - -export default class PedestrianProfile extends Profile { - public getID(): string { - return "PEDESTRIAN"; - } - - public isOneWay(way: RoutableTileWay): boolean { - return false; - } - - public hasAccess(way: RoutableTileWay): boolean { - if (way.highwayKind === Highway.Motorway) { - return false; - } else if (way.highwayKind === Highway.MotorwayLink) { - return false; - } else if (way.highwayKind === Highway.Trunk) { - return false; - } else if (way.highwayKind === Highway.TrunkLink) { - return false; - } - - return true; - } - - public getDefaultSpeed() { - return 5; - } - - public getMaxSpeed() { - return this.getDefaultSpeed(); - } - - public getSpeed(way: RoutableTileWay) { - return this.getDefaultSpeed(); - } - - public getDistance(from: RoutableTileNode, to: RoutableTileNode, way: RoutableTileWay): DistanceM { - return Geo.getDistanceBetweenLocations(from, to); - } - - public getDuration(from: RoutableTileNode, to: RoutableTileNode, way: RoutableTileWay): DurationMs { - const distance = this.getDistance(from, to, way) / 1000; // km - const speed = 5; // km/h - const time = distance / speed; // h - return time * 60 * 60 * 1000; // ms - } - - public getMultiplier(way: RoutableTileWay): number { - if (way.highwayKind === Highway.Motorway) { - return 1.3; - } else if (way.highwayKind === Highway.MotorwayLink) { - return 1.3; - } else if (way.highwayKind === Highway.Trunk) { - return 1.3; - } else if (way.highwayKind === Highway.TrunkLink) { - return 1.3; - } else if (way.highwayKind === Highway.Service) { - return 1.1; - } else if (way.highwayKind === Highway.Tertiary) { - return 1.1; - } else if (way.highwayKind === Highway.TertiaryLink) { - return 1.1; - } else if (way.highwayKind === Highway.Secondary) { - return 1.1; - } else if (way.highwayKind === Highway.SecondaryLink) { - return 1.1; - } else if (way.highwayKind === Highway.Primary) { - return 1.1; - } else if (way.highwayKind === Highway.PrimaryLink) { - return 1.1; - } else if (way.highwayKind === Highway.LivingStreet) { - return 0.8; - } else if (way.highwayKind === Highway.Footway) { - return 0.8; - } - - return 1; - } - - public getCost(from: RoutableTileNode, to: RoutableTileNode, way: RoutableTileWay): number { - return this.getMultiplier(way) * this.getDuration(from, to, way); - } - - public isObstacle(node: RoutableTileNode): boolean { - return false; - } - - public getObstacleTime(node: RoutableTileNode): DurationMs { - return 0; - } -} diff --git a/src/entities/tiles/node.ts b/src/entities/tiles/node.ts index 9125ed19..9093c896 100644 --- a/src/entities/tiles/node.ts +++ b/src/entities/tiles/node.ts @@ -12,12 +12,13 @@ export class RoutableTileNode implements ILocation { public longitude: number; public id: string; - public barrierKind?: Barrier; - public highwayKind?: Highway; - public crossingKind?: Crossing; + public definedTags: object; + public freeformTags: string[]; constructor(id: string) { this.id = id; + this.definedTags = {}; + this.freeformTags = []; } } diff --git a/src/entities/tiles/way.ts b/src/entities/tiles/way.ts index 4e348113..e8007230 100644 --- a/src/entities/tiles/way.ts +++ b/src/entities/tiles/way.ts @@ -1,13 +1,3 @@ -import Access from "../../enums/Access"; -import Construction from "../../enums/Construction"; -import Crossing from "../../enums/Crossing"; -import Cycleway from "../../enums/Cycleway"; -import Footway from "../../enums/Footway"; -import Highway from "../../enums/Highway"; -import Oneway from "../../enums/Oneway"; -import Smoothness from "../../enums/Smoothness"; -import Surface from "../../enums/Surface"; -import TrackType from "../../enums/TrackType"; import Edge from "./edge"; export class RoutableTileWay { @@ -20,27 +10,16 @@ export class RoutableTileWay { public weights?: number[][]; // distances between the nodes in the segments public name: string; public reachable?: boolean; // not part of OSM but a result of preprocessing, do not use this (yet) + public maxSpeed?: number; - public accessRestrictions?: Access; - public bicycleAccessRestrictions?: Access; - public constructionKind?: Construction; - public crossingKind?: Crossing; - public cyclewayKind?: Cycleway; - public footwayKind?: Footway; - public highwayKind: Highway; - public maxSpeed: number; - public motorVehicleAccessRestrictions?: Access; - public motorcarAccessRestrictions?: Access; - public onewayBicycleKind?: Oneway; - public onewayKind?: Oneway; - public smoothnessKind?: Smoothness; - public surfaceKind?: Surface; - public trackType?: TrackType; - public vehicleAccessRestrictions?: Access; + public definedTags: object; + public freeformTags: string[]; constructor(id: string) { this.id = id; this.weights = [[]]; + this.definedTags = {}; + this.freeformTags = []; } public mergeDefinitions(other: RoutableTileWay): RoutableTileWay { @@ -48,6 +27,8 @@ export class RoutableTileWay { // copy data fields Object.assign(result, this); Object.assign(result, other); + const definedTags = Object.assign({}, this.definedTags, other.definedTags); + result.definedTags = definedTags; // special cases if (this.reachable === false || other.reachable === false) { result.reachable = false; @@ -60,6 +41,10 @@ export class RoutableTileWay { result.weights = []; result.weights = result.weights.concat(this.weights); result.weights = result.weights.concat(other.weights); + + result.freeformTags = []; + result.freeformTags = result.freeformTags.concat(this.freeformTags); + result.freeformTags = result.freeformTags.concat(other.freeformTags); return result; } diff --git a/src/fetcher/profiles/ProfileProviderDefault.ts b/src/fetcher/profiles/ProfileProviderDefault.ts index a6123b44..18014527 100644 --- a/src/fetcher/profiles/ProfileProviderDefault.ts +++ b/src/fetcher/profiles/ProfileProviderDefault.ts @@ -1,5 +1,4 @@ import { inject, injectable } from "inversify"; -import PedestrianProfile from "../../entities/profile/PedestrianProfile"; import Profile from "../../entities/profile/Profile"; import TYPES from "../../types"; import IProfileFetcher from "./IProfileFetcher"; diff --git a/src/fetcher/tiles/RoutableTileFetcherDefault.ts b/src/fetcher/tiles/RoutableTileFetcherDefault.ts deleted file mode 100644 index 603cbd6c..00000000 --- a/src/fetcher/tiles/RoutableTileFetcherDefault.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { inject, injectable } from "inversify"; -import LDFetch from "ldfetch"; -import { IRoutableTileNodeIndex, RoutableTileNode } from "../../entities/tiles/node"; -import RoutableTileRegistry from "../../entities/tiles/registry"; -import { RoutableTile } from "../../entities/tiles/tile"; -import { IRoutableTileWayIndex, RoutableTileWay } from "../../entities/tiles/way"; -import getOsmTagMapping from "../../enums/OSMTags"; -import { LDLoader } from "../../loader/ldloader"; -import { IndexThingView } from "../../loader/views"; -import PathfinderProvider from "../../pathfinding/PathfinderProvider"; -import TYPES from "../../types"; -import { GEO, OSM, RDF, RDFS } from "../../uri/constants"; -import URI from "../../uri/uri"; -import IRoutableTileFetcher from "./IRoutableTileFetcher"; - -@injectable() -export default class RoutableTileFetcherDefault implements IRoutableTileFetcher { - - protected ldFetch: LDFetch; - protected ldLoader: LDLoader; - protected pathfinderProvider: PathfinderProvider; - protected routableTileRegistry: RoutableTileRegistry; - - constructor( - @inject(TYPES.LDFetch) ldFetch: LDFetch, - @inject(TYPES.PathfinderProvider) pathfinderProvider: PathfinderProvider, - ) { - this.ldFetch = ldFetch; - this.ldLoader = new LDLoader(); - this.ldLoader.defineCollection(URI.inNS(OSM, "hasNodes")); // unordered collection - this.pathfinderProvider = pathfinderProvider; - this.routableTileRegistry = RoutableTileRegistry.getInstance(); - } - - public async get(url: string): Promise { - const rdfThing = await this.ldFetch.get(url); - const triples = rdfThing.triples; - - let nodes: IRoutableTileNodeIndex; - let ways: IRoutableTileWayIndex; - - [nodes, ways] = this.ldLoader.process(triples, [ - this.getNodesView(), - this.getWaysView(), - ]); - - return this.processTileData(url, nodes, ways); - } - - protected processTileData(url: string, nodes: IRoutableTileNodeIndex, ways: IRoutableTileWayIndex) { - this.pathfinderProvider.registerEdges(ways, nodes); - - for (const node of Object.values(nodes)) { - this.routableTileRegistry.registerNode(node); - } - - for (const way of Object.values(ways)) { - this.routableTileRegistry.registerWay(way); - } - - return new RoutableTile(url, new Set(Object.keys(nodes)), new Set(Object.keys(ways))); - } - - protected getNodesView() { - const nodesView = new IndexThingView(RoutableTileNode.create); - nodesView.addFilter((entity) => - entity[URI.inNS(GEO, "lat")] !== undefined && entity[URI.inNS(GEO, "long")] !== undefined, - ); - nodesView.addMapping(URI.inNS(GEO, "lat"), "latitude"); - nodesView.addMapping(URI.inNS(GEO, "long"), "longitude"); - - for (const [tag, field] of Object.entries(getOsmTagMapping())) { - nodesView.addMapping(tag, field); - } - - return nodesView; - } - - protected getWaysView() { - const waysView = new IndexThingView(RoutableTileWay.create); - waysView.addFilter((entity) => - entity[URI.inNS(RDF, "type")] === URI.inNS(OSM, "Way"), - ); - - waysView.addMapping(URI.inNS(OSM, "hasNodes"), "segments"); - waysView.addMapping(URI.inNS(OSM, "name"), "name"); - - for (const [tag, field] of Object.entries(getOsmTagMapping())) { - waysView.addMapping(tag, field); - } - - return waysView; - } -} diff --git a/src/fetcher/tiles/RoutableTileFetcherExtended.ts b/src/fetcher/tiles/RoutableTileFetcherExtended.ts deleted file mode 100644 index f88dda90..00000000 --- a/src/fetcher/tiles/RoutableTileFetcherExtended.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { inject, injectable } from "inversify"; -import LDFetch from "ldfetch"; -import { RoutableTile } from "../../entities/tiles/tile"; -import PathfinderProvider from "../../pathfinding/PathfinderProvider"; -import TYPES from "../../types"; -import { ROUTE } from "../../uri/constants"; -import URI from "../../uri/uri"; -import RoutableTileFetcherDefault from "./RoutableTileFetcherDefault"; - -@injectable() -export default class RoutableTileFetcherExtended extends RoutableTileFetcherDefault { - - constructor( - @inject(TYPES.LDFetch) ldFetch: LDFetch, - @inject(TYPES.PathfinderProvider) pathfinder: PathfinderProvider, - ) { - super(ldFetch, pathfinder); - } - - public async get(url: string): Promise { - const lolJs = url.split("/"); - const tileX = lolJs[lolJs.length - 2]; - const tileY = lolJs[lolJs.length - 1]; - const otherUrl = `https://www.hdelva.be/tiles/inferred/${tileX}/${tileY}`; - - const basePromise = this.ldFetch.get(url); - const otherPromise = this.ldFetch.get(otherUrl); - - const baseResponse = await basePromise; - const baseTriples = baseResponse.triples; - - let otherTriples = []; - try { - const otherResponse = await otherPromise; - otherTriples = otherResponse.triples; - - this.ldLoader.disambiguateBlankNodes(baseTriples, "base"); - this.ldLoader.disambiguateBlankNodes(otherTriples, "other"); - } catch { - // not that important - } - - const [nodes, ways] = this.ldLoader.process(baseTriples.concat(otherTriples), [ - this.getNodesView(), - this.getWaysView(), - ]); - - return this.processTileData(url, nodes, ways); - } - - protected getWaysView() { - const original = super.getWaysView(); - original.addMapping(URI.inNS(ROUTE, "reachable"), "reachable"); - return original; - } -} diff --git a/src/fetcher/tiles/RoutableTileFetcherRaw.ts b/src/fetcher/tiles/RoutableTileFetcherRaw.ts index 1a67c63f..ded0c89d 100644 --- a/src/fetcher/tiles/RoutableTileFetcherRaw.ts +++ b/src/fetcher/tiles/RoutableTileFetcherRaw.ts @@ -25,25 +25,6 @@ export default class RoutableTileFetcherRaw implements IRoutableTileFetcher { ) { this.pathfinderProvider = pathfinderProvider; this.routableTileRegistry = RoutableTileRegistry.getInstance(); - this.mapping = {}; - - this.mapping["osm:barrier"] = "barrierKind"; - this.mapping["osm:access"] = "accessRestrictions"; - this.mapping["osm:bicycle"] = "bicycleAccessRestrictions"; - this.mapping["osm:construction"] = "constructionKind"; - this.mapping["osm:crossing"] = "crossingKind"; - this.mapping["osm:cycleway"] = "cyclewayKind"; - this.mapping["osm:footway"] = "footwayKind"; - this.mapping["osm:highway"] = "highwayKind"; - this.mapping["osm:maxspeed"] = "maxSpeed"; - this.mapping["osm:motor_vehicle"] = "motorVehicleAccessRestrictions"; - this.mapping["osm:motorcar"] = "motorcarAccessRestrictions"; - this.mapping["osm:oneway_bicycle"] = "onewayBicycleKind"; - this.mapping["osm:oneway"] = "onewayKind"; - this.mapping["osm:smoothness"] = "smoothnessKind"; - this.mapping["osm:surface"] = "surfaceKind"; - this.mapping["osm:tracktype"] = "trackType"; - this.mapping["osm:vehicle"] = "vehicleAccessRestrictions"; } public async get(url: string): Promise { @@ -93,7 +74,7 @@ export default class RoutableTileFetcherRaw implements IRoutableTileFetcher { return parseInt(response.headers.get("content-length"), 10); } else { try { - return response.body._chunkSize; + return response.body._outOffset; } catch (e) { // } @@ -120,9 +101,18 @@ export default class RoutableTileFetcherRaw implements IRoutableTileFetcher { node.latitude = parseFloat(blob["geo:lat"]); node.longitude = parseFloat(blob["geo:long"]); - for (const [tag, field] of Object.entries(this.mapping)) { - if (blob[tag] && !node[field]) { - node[field] = URI.fakeExpand(OSM, blob[tag]); + for (const [key, value] of Object.entries(blob)) { + if (key === "osm:hasTag") { + node.freeformTags = value as string[]; + } else if (key.indexOf("osm:") === 0) { + const expandedKey = URI.fakeExpand(OSM, key); + + if (value.toString().indexOf("osm:") === 0) { + const expandedValue = URI.fakeExpand(OSM, value.toString()); + node.definedTags[expandedKey] = expandedValue; + } else { + node.definedTags[expandedKey] = value; + } } } @@ -145,9 +135,21 @@ export default class RoutableTileFetcherRaw implements IRoutableTileFetcher { way.name = blob["osm:name"]; - for (const [tag, field] of Object.entries(this.mapping)) { - if (blob[tag] && !way[field]) { - way[field] = URI.fakeExpand(OSM, blob[tag]); + for (const [key, value] of Object.entries(blob)) { + if (key === "osm:hasNodes" || key === "osm:hasWeights") { + // not tags, these are our own properties + continue; + } else if (key === "osm:hasTag") { + way.freeformTags = value as string[]; + } else if (key.indexOf("osm:") === 0) { + const expandedKey = URI.fakeExpand(OSM, key); + + if (value.toString().indexOf("osm:") === 0) { + const expandedValue = URI.fakeExpand(OSM, value.toString()); + way.definedTags[expandedKey] = expandedValue; + } else { + way.definedTags[expandedKey] = value; + } } } From c2c362ccf69ebd2ae30ccc4db3c7f42b5a85ce08 Mon Sep 17 00:00:00 2001 From: Harm Delva Date: Thu, 19 Mar 2020 13:56:39 +0100 Subject: [PATCH 3/8] Add way identifiers of the ways used on a path --- src/interfaces/IStep.ts | 1 + src/pathfinding/PathfinderProvider.ts | 2 +- src/pathfinding/bidirdijkstra/BidirDijkstraInstance.ts | 6 ++++++ src/pathfinding/dijkstra/DijkstraInstance.ts | 3 +++ src/pathfinding/graph.ts | 7 ++++--- src/planner/Step.ts | 2 ++ src/planner/public-transport/JourneyExtractorProfile.ts | 2 ++ src/planner/road/RoadPlannerPathfinding.ts | 1 + 8 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/interfaces/IStep.ts b/src/interfaces/IStep.ts index 86f05e64..060430c8 100644 --- a/src/interfaces/IStep.ts +++ b/src/interfaces/IStep.ts @@ -5,6 +5,7 @@ import { DistanceM, DurationMs } from "./units"; export default interface IStep { startLocation: ILocation; stopLocation: ILocation; + through?: string; startTime?: Date; stopTime?: Date; duration: IProbabilisticValue; diff --git a/src/pathfinding/PathfinderProvider.ts b/src/pathfinding/PathfinderProvider.ts index 8cb5c1a2..7cbffc4f 100644 --- a/src/pathfinding/PathfinderProvider.ts +++ b/src/pathfinding/PathfinderProvider.ts @@ -228,7 +228,7 @@ export default class PathfinderProvider { distance = distance || profile.getDistance(from, to, way); const duration = profile.getDuration(from, to, way); const cost = profile.getCost(from, to, way); - graph.addEdge(Geo.getId(from), Geo.getId(to), distance, duration, cost); + graph.addEdge(Geo.getId(from), Geo.getId(to), way.id, distance, duration, cost); } private segmentDistToPoint(segA: ILocation, segB: ILocation, p: ILocation): number { diff --git a/src/pathfinding/bidirdijkstra/BidirDijkstraInstance.ts b/src/pathfinding/bidirdijkstra/BidirDijkstraInstance.ts index ffc3257d..603b3fc6 100644 --- a/src/pathfinding/bidirdijkstra/BidirDijkstraInstance.ts +++ b/src/pathfinding/bidirdijkstra/BidirDijkstraInstance.ts @@ -132,11 +132,13 @@ export class BidirDijkstraInstance implements IShortestPathInstance { while (this.backwardParents[currentPosition] !== undefined) { let nextEdge; let nextPositionCost = Infinity; + let way; for (const edge of this.graph.getAdjacencyList()[currentPosition]) { if (this.getBackwardCost(edge.node) < nextPositionCost) { nextPositionCost = this.getBackwardCost(edge.node); nextEdge = edge; + way = edge.through; } } @@ -147,6 +149,7 @@ export class BidirDijkstraInstance implements IShortestPathInstance { backwardSteps.push({ from: this.graph.getLabel(currentPosition), to: this.graph.getLabel(nextEdge.node), + through: way, distance: nextEdge.distance, duration: nextEdge.duration, }); @@ -158,11 +161,13 @@ export class BidirDijkstraInstance implements IShortestPathInstance { while (this.forwardParents[currentPosition] !== undefined) { let nextEdge; let nextPositionCost = Infinity; + let way; for (const edge of this.graph.getReverseAdjacencyList()[currentPosition]) { if (this.getForwardCost(edge.node) < nextPositionCost) { nextPositionCost = this.getForwardCost(edge.node); nextEdge = edge; + way = edge.through; } } @@ -173,6 +178,7 @@ export class BidirDijkstraInstance implements IShortestPathInstance { forwardSteps.push({ from: this.graph.getLabel(nextEdge.node), to: this.graph.getLabel(currentPosition), + through: way, distance: nextEdge.distance, duration: nextEdge.duration, }); diff --git a/src/pathfinding/dijkstra/DijkstraInstance.ts b/src/pathfinding/dijkstra/DijkstraInstance.ts index 73ece385..2bfe9e03 100644 --- a/src/pathfinding/dijkstra/DijkstraInstance.ts +++ b/src/pathfinding/dijkstra/DijkstraInstance.ts @@ -117,11 +117,13 @@ export class DijkstraInstance implements IShortestPathInstance { while (!isNaN(this.previousNodes[currentPosition])) { let nextEdge; let nextPositionCost = Infinity; + let way; for (const edge of this.graph.getReverseAdjacencyList()[currentPosition]) { if (this.getCost(edge.node) < nextPositionCost) { nextPositionCost = this.getCost(edge.node); nextEdge = edge; + way = edge.through; } } @@ -134,6 +136,7 @@ export class DijkstraInstance implements IShortestPathInstance { to: this.graph.getLabel(currentPosition), distance: nextEdge.distance, duration: nextEdge.duration, + through: way, }); currentPosition = nextEdge.node; diff --git a/src/pathfinding/graph.ts b/src/pathfinding/graph.ts index 0b19dcc1..b7b36dd7 100644 --- a/src/pathfinding/graph.ts +++ b/src/pathfinding/graph.ts @@ -3,6 +3,7 @@ interface IEdge { distance: number; duration: number; cost: number; + through: string; } interface INodeMap { @@ -30,11 +31,11 @@ export default class PathfindingGraph { this.breakPoints = {}; } - public addEdge(from: string, to: string, distance: number, duration: number, cost: number) { + public addEdge(from: string, to: string, through: string, distance: number, duration: number, cost: number) { const fromIndex = this.getNodeIndex(from); const toIndex = this.getNodeIndex(to); - this.adjacencyList[fromIndex].push({ node: toIndex, distance, cost, duration }); - this.reverseAdjacencyList[toIndex].push({ node: fromIndex, distance, cost, duration }); + this.adjacencyList[fromIndex].push({ node: toIndex, through, distance, cost, duration }); + this.reverseAdjacencyList[toIndex].push({ node: fromIndex, through, distance, cost, duration }); } public getNodeMap() { diff --git a/src/planner/Step.ts b/src/planner/Step.ts index 550fa261..609194cd 100644 --- a/src/planner/Step.ts +++ b/src/planner/Step.ts @@ -15,6 +15,7 @@ export default class Step implements IStep { startLocation: ILocation, stopLocation: ILocation, duration: IProbabilisticValue, + through?: string, // string identifier of a way, route, ... that was taken startTime?: Date, stopTime?: Date, distance?: DistanceM, @@ -26,6 +27,7 @@ export default class Step implements IStep { startTime, stopTime, distance, + through, ); } diff --git a/src/planner/public-transport/JourneyExtractorProfile.ts b/src/planner/public-transport/JourneyExtractorProfile.ts index 430dde1f..6ecc4483 100644 --- a/src/planner/public-transport/JourneyExtractorProfile.ts +++ b/src/planner/public-transport/JourneyExtractorProfile.ts @@ -164,6 +164,7 @@ export default class JourneyExtractorProfile implements IJourneyExtractor { { minimum: transferDepartureTime - departureTime, }, + null, new Date(departureTime - timeToSubtract), new Date(transferDepartureTime - timeToSubtract), ); @@ -220,6 +221,7 @@ export default class JourneyExtractorProfile implements IJourneyExtractor { { minimum: arrivalTime.getTime() - transferArrivalTime.getTime(), }, + null, transferArrivalTime, arrivalTime, ); diff --git a/src/planner/road/RoadPlannerPathfinding.ts b/src/planner/road/RoadPlannerPathfinding.ts index 8910a400..2f967c8d 100644 --- a/src/planner/road/RoadPlannerPathfinding.ts +++ b/src/planner/road/RoadPlannerPathfinding.ts @@ -113,6 +113,7 @@ export default class RoadPlannerPathfinding implements IRoadPlanner { steps.push({ startLocation: from, stopLocation: to, + through: step.through, duration: { average: step.duration }, distance: step.distance, }); From f72fc4565cf668671d164e77ec372e3a417005f2 Mon Sep 17 00:00:00 2001 From: Harm Delva Date: Thu, 19 Mar 2020 14:17:27 +0100 Subject: [PATCH 4/8] Add context to paths --- src/interfaces/IPath.ts | 3 +++ src/planner/Path.ts | 17 ++++++++++++++++- src/planner/road/RoadPlannerPathfinding.ts | 7 ++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/interfaces/IPath.ts b/src/interfaces/IPath.ts index 1ad1f2c7..0900e09a 100644 --- a/src/interfaces/IPath.ts +++ b/src/interfaces/IPath.ts @@ -5,6 +5,9 @@ import { DurationMs } from "./units"; export default interface IPath { legs: ILeg[]; + addToContext(id: string, value: any); + getFromContext(id: string): any; + getDepartureTime(query: IQuery): Date; getArrivalTime(query: IQuery): Date; getTravelTime(query: IQuery): DurationMs; diff --git a/src/planner/Path.ts b/src/planner/Path.ts index 0272719d..6fdd0ca9 100644 --- a/src/planner/Path.ts +++ b/src/planner/Path.ts @@ -33,10 +33,25 @@ export default class Path implements IPath { }); } + public context: object; // lookup table with relevant data public legs: ILeg[]; - constructor(legs: ILeg[]) { + constructor(legs: ILeg[], context?: object) { this.legs = legs; + + if (context) { + this.context = context; + } else { + this.context = {}; + } + } + + public addToContext(id: string, value: any) { + this.context[id] = value; + } + + public getFromContext(id: string): any { + return this.context[id]; } public prependLeg(leg: ILeg) { diff --git a/src/planner/road/RoadPlannerPathfinding.ts b/src/planner/road/RoadPlannerPathfinding.ts index 2f967c8d..61dfa149 100644 --- a/src/planner/road/RoadPlannerPathfinding.ts +++ b/src/planner/road/RoadPlannerPathfinding.ts @@ -107,6 +107,7 @@ export default class RoadPlannerPathfinding implements IRoadPlanner { const path = await pathfinder.queryPath(Geo.getId(start), Geo.getId(stop), maxDistance); const steps: IStep[] = []; + const context = {}; for (const step of path) { const to = await this.locationResolver.resolve(step.to); const from = await this.locationResolver.resolve(step.from); @@ -117,10 +118,14 @@ export default class RoadPlannerPathfinding implements IRoadPlanner { duration: { average: step.duration }, distance: step.distance, }); + + if (step.through) { + context[step.through] = this.registry.getWay(step.through); + } } const leg = new Leg(TravelMode.Profile, steps); - return new Path([leg]); + return new Path([leg], context); } private async fetchTile(coordinate: RoutableTileCoordinate) { From cf37dfbded44c84088d7caeef1ce9ded439b1d6c Mon Sep 17 00:00:00 2001 From: Harm Delva Date: Thu, 19 Mar 2020 14:25:30 +0100 Subject: [PATCH 5/8] Rename weights to distances - because that's what they are --- src/entities/tiles/way.ts | 14 +++++++------- src/fetcher/tiles/RoutableTileFetcherRaw.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/entities/tiles/way.ts b/src/entities/tiles/way.ts index e8007230..983f1104 100644 --- a/src/entities/tiles/way.ts +++ b/src/entities/tiles/way.ts @@ -7,7 +7,7 @@ export class RoutableTileWay { public id: string; public segments: string[][]; // ids of nodes that are part of this road - public weights?: number[][]; // distances between the nodes in the segments + public distances?: number[][]; // distances between the nodes in the segments public name: string; public reachable?: boolean; // not part of OSM but a result of preprocessing, do not use this (yet) public maxSpeed?: number; @@ -17,7 +17,7 @@ export class RoutableTileWay { constructor(id: string) { this.id = id; - this.weights = [[]]; + this.distances = [[]]; this.definedTags = {}; this.freeformTags = []; } @@ -38,9 +38,9 @@ export class RoutableTileWay { result.segments = result.segments.concat(this.segments); result.segments = result.segments.concat(other.segments); - result.weights = []; - result.weights = result.weights.concat(this.weights); - result.weights = result.weights.concat(other.weights); + result.distances = []; + result.distances = result.distances.concat(this.distances); + result.distances = result.distances.concat(other.distances); result.freeformTags = []; result.freeformTags = result.freeformTags.concat(this.freeformTags); @@ -51,10 +51,10 @@ export class RoutableTileWay { public getParts(): Edge[] { const result: Edge[] = []; for (let index = 0; index < this.segments.length; index++) { - const weights = this.weights[index]; + const distances = this.distances[index]; const segment = this.segments[index]; for (let i = 0; i < segment.length - 1; i++) { - result.push({from: segment[i], to: segment[i + 1], distance: weights[i]}); + result.push({from: segment[i], to: segment[i + 1], distance: distances[i]}); } } return result; diff --git a/src/fetcher/tiles/RoutableTileFetcherRaw.ts b/src/fetcher/tiles/RoutableTileFetcherRaw.ts index ded0c89d..5d55b083 100644 --- a/src/fetcher/tiles/RoutableTileFetcherRaw.ts +++ b/src/fetcher/tiles/RoutableTileFetcherRaw.ts @@ -130,7 +130,7 @@ export default class RoutableTileFetcherRaw implements IRoutableTileFetcher { } else { const weights = blob["osm:hasEdges"]; way.segments = [weights["osm:hasNodes"]]; - way.weights = [weights["osm:hasWeights"]]; + way.distances = [weights["osm:hasWeights"]]; } way.name = blob["osm:name"]; From 9fa859f96160f5b49619b55a2b6fed729fbf12dd Mon Sep 17 00:00:00 2001 From: Harm Delva Date: Thu, 19 Mar 2020 15:51:23 +0100 Subject: [PATCH 6/8] Make completePath implicit --- src/interfaces/IPath.ts | 2 ++ src/interfaces/IQuery.ts | 1 + src/planner/Path.ts | 8 +++++ .../configurations/FlexibleRoadPlanner.ts | 4 +++ src/planner/configurations/Planner.ts | 33 +++++++++++++++---- .../configurations/ReducedCarPlanner.ts | 4 +++ src/uri/constants.ts | 1 + 7 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/interfaces/IPath.ts b/src/interfaces/IPath.ts index 0900e09a..35b5daf7 100644 --- a/src/interfaces/IPath.ts +++ b/src/interfaces/IPath.ts @@ -5,7 +5,9 @@ import { DurationMs } from "./units"; export default interface IPath { legs: ILeg[]; + updateContext(other: object); addToContext(id: string, value: any); + getContext(): object; getFromContext(id: string): any; getDepartureTime(query: IQuery): Date; diff --git a/src/interfaces/IQuery.ts b/src/interfaces/IQuery.ts index cd1223d9..cc22a874 100644 --- a/src/interfaces/IQuery.ts +++ b/src/interfaces/IQuery.ts @@ -21,4 +21,5 @@ export default interface IQuery { maximumTransfers?: number; maximumTravelDuration?: DurationMs; excludedTravelModes?: TravelMode[]; + minimized?: boolean; // contain all details, or only start/stop locations? } diff --git a/src/planner/Path.ts b/src/planner/Path.ts index 6fdd0ca9..08afb92d 100644 --- a/src/planner/Path.ts +++ b/src/planner/Path.ts @@ -46,10 +46,18 @@ export default class Path implements IPath { } } + public updateContext(other: object) { + this.context = Object.assign(this.context, other); + } + public addToContext(id: string, value: any) { this.context[id] = value; } + public getContext(): object { + return this.context; + } + public getFromContext(id: string): any { return this.context[id]; } diff --git a/src/planner/configurations/FlexibleRoadPlanner.ts b/src/planner/configurations/FlexibleRoadPlanner.ts index 69170c52..af6b489d 100644 --- a/src/planner/configurations/FlexibleRoadPlanner.ts +++ b/src/planner/configurations/FlexibleRoadPlanner.ts @@ -13,4 +13,8 @@ export default class FlexibleRoadPlanner extends Planner { query.roadNetworkOnly = true; return super.query(query); } + + public async completePath(path: IPath): Promise { + return path; + } } diff --git a/src/planner/configurations/Planner.ts b/src/planner/configurations/Planner.ts index bb3a74b9..a18314a2 100644 --- a/src/planner/configurations/Planner.ts +++ b/src/planner/configurations/Planner.ts @@ -1,4 +1,4 @@ -import { AsyncIterator } from "asynciterator"; +import { AsyncIterator, BufferedIterator } from "asynciterator"; import { PromiseProxyIterator } from "asynciterator-promiseproxy"; import { EventEmitter } from "events"; import { IConnectionsSourceConfig, IStopsSourceConfig } from "../../Catalog"; @@ -18,6 +18,8 @@ import IQuery from "../../interfaces/IQuery"; import ILocationResolver from "../../query-runner/ILocationResolver"; import IQueryRunner from "../../query-runner/IQueryRunner"; import TYPES from "../../types"; +import { GTFS, LC } from "../../uri/constants"; +import URI from "../../uri/uri"; import Iterators from "../../util/Iterators"; import Units from "../../util/Units"; import Path from "../Path"; @@ -81,11 +83,11 @@ export default abstract class Planner { const catalog = await this.catalogProvider.getCatalog(accessUrl); for (const dataset of catalog.datasets) { for (const distribution of dataset.distributions) { - if (dataset.subject === "lc:Connection") { + if (dataset.subject === URI.inNS(LC, "Connection")) { this.connectionsProvider.addConnectionSource( { accessUrl: distribution.accessUrl, travelMode: TravelMode.Train }, ); - } else if (dataset.subject === "gtfs:Stop") { + } else if (dataset.subject === URI.inNS(GTFS, "Stop")) { this.stopsProvider.addStopSource( { accessUrl: distribution.accessUrl }, ); @@ -117,6 +119,7 @@ export default abstract class Planner { for (const walkingLeg of walkingPaths[0].legs) { completePath.appendLeg(walkingLeg); } + completePath.updateContext(walkingPaths[0].getContext()); walkingDeparture = null; walkingDestination = null; @@ -136,6 +139,7 @@ export default abstract class Planner { for (const walkingLeg of walkingPaths[0].legs) { completePath.appendLeg(walkingLeg); } + completePath.updateContext(walkingPaths[0].getContext()); walkingDeparture = null; walkingDestination = null; @@ -153,19 +157,34 @@ export default abstract class Planner { this.eventBus.emit(EventType.Query, query); query.profileID = this.activeProfileID; - const iterator = new PromiseProxyIterator(() => this.queryRunner.run(query)); + const pathIterator = new PromiseProxyIterator(() => this.queryRunner.run(query)); this.eventBus.once(EventType.AbortQuery, () => { - iterator.close(); + pathIterator.close(); }); - iterator.on("error", (e) => { + pathIterator.on("error", (e) => { if (e && e.eventType) { this.eventBus.emit(e.eventType, e.message); } }); - return iterator; + if (query.minimized) { + return pathIterator; + } + + const completeIterator: BufferedIterator = new BufferedIterator(); + + pathIterator.on("data", async (path) => { + const completePath = await this.completePath(path); + completeIterator._push(completePath); + + if (pathIterator.closed) { + completeIterator.close(); + } + }); + + return completeIterator; } public prefetchStops(): void { diff --git a/src/planner/configurations/ReducedCarPlanner.ts b/src/planner/configurations/ReducedCarPlanner.ts index d0134577..c0ef53dc 100644 --- a/src/planner/configurations/ReducedCarPlanner.ts +++ b/src/planner/configurations/ReducedCarPlanner.ts @@ -14,4 +14,8 @@ export default class TransitCarPlanner extends Planner { query.roadNetworkOnly = true; return super.query(query); } + + public async completePath(path: IPath): Promise { + return path; + } } diff --git a/src/uri/constants.ts b/src/uri/constants.ts index e6c1d383..8b62064d 100644 --- a/src/uri/constants.ts +++ b/src/uri/constants.ts @@ -12,3 +12,4 @@ export const TREE = "https://w3id.org/tree#"; export const LC = "http://semweb.mmlab.be/ns/linkedconnections#"; export const DCAT = "http://www.w3.org/ns/dcat#"; export const DCT = "http://purl.org/dc/terms/"; +export const GTFS = "http://vocab.gtfs.org/terms#"; From cdcd30348d3a23655629fc03737beab0b5b8d79c Mon Sep 17 00:00:00 2001 From: Harm Delva Date: Thu, 19 Mar 2020 16:10:13 +0100 Subject: [PATCH 7/8] Smash some bugs --- src/demo.ts | 3 +- .../ld-fetch/StopsFetcherLDFetch.test.ts | 14 +++----- .../stops/ld-fetch/StopsFetcherLDFetch.ts | 1 + .../tiles/RoutableTileFetcherDefault.test.ts | 36 ------------------- .../ReachableStopsFinderBirdsEye.test.ts | 10 ++---- 5 files changed, 9 insertions(+), 55 deletions(-) delete mode 100644 src/fetcher/tiles/RoutableTileFetcherDefault.test.ts diff --git a/src/demo.ts b/src/demo.ts index 0ae11611..608f3b09 100644 --- a/src/demo.ts +++ b/src/demo.ts @@ -7,7 +7,8 @@ import Units from "./util/Units"; export default async (logResults) => { const planner = new FlexibleProfileTransitPlanner(); - await planner.addCatalogSource("https://graph.irail.be/sncb/catalog"); + planner.addConnectionSource("https://graph.irail.be/sncb/connections"); + planner.addStopSource("https://irail.be/stations/NMBS"); if (logResults) { let scannedConnections = 0; diff --git a/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.test.ts b/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.test.ts index 14e10cf9..a8c4a273 100644 --- a/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.test.ts +++ b/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.test.ts @@ -3,18 +3,12 @@ import LDFetch from "ldfetch"; import IStop from "../IStop"; import StopsFetcherLDFetch from "./StopsFetcherLDFetch"; -const DE_LIJN_STOPS_URLS = [ - "http://openplanner.ilabt.imec.be/delijn/Antwerpen/stops", - "http://openplanner.ilabt.imec.be/delijn/Oost-Vlaanderen/stops", - "http://openplanner.ilabt.imec.be/delijn/West-Vlaanderen/stops", - "http://openplanner.ilabt.imec.be/delijn/Vlaams-Brabant/stops", - "http://openplanner.ilabt.imec.be/delijn/Limburg/stops", -]; +const DE_LIJN_STOPS_URL = "http://openplanner.ilabt.imec.be/delijn/stops"; const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); const deLijnFetcher = new StopsFetcherLDFetch(ldFetch); -deLijnFetcher.setAccessUrl(DE_LIJN_STOPS_URLS[2]); +deLijnFetcher.setAccessUrl(DE_LIJN_STOPS_URL); const nmbsFetcher = new StopsFetcherLDFetch(ldFetch); nmbsFetcher.setAccessUrl("https://irail.be/stations/NMBS"); @@ -25,7 +19,7 @@ test("[StopsFetcherLDFetch] De Lijn first stop", async () => { const stop: IStop = await deLijnFetcher.getStopById("https://data.delijn.be/stops/590009"); expect(stop).toBeDefined(); - expect(stop.name).toEqual("De Vierweg"); + expect(stop.name).toEqual("Moorslede De Vierweg"); }); // test("[StopsFetcherLDFetch] De Lijn second stop", async () => { @@ -39,7 +33,7 @@ test("[StopsFetcherLDFetch] De Lijn second stop", async () => { const stop: IStop = await deLijnFetcher.getStopById("https://data.delijn.be/stops/500050"); expect(stop).toBeDefined(); - expect(stop.name).toEqual("Station perron 10"); + expect(stop.name).toEqual("Brugge Station perron 10"); }); test("[StopsFetcherLDFetch] NMBS", async () => { diff --git a/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.ts b/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.ts index d5aea3e2..a2844648 100644 --- a/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.ts +++ b/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.ts @@ -87,6 +87,7 @@ export default class StopsFetcherLDFetch implements IStopsFetcher { private transformPredicate(triple: Triple): Triple { return Rdf.transformPredicate({ "http://xmlns.com/foaf/0.1/name": "name", + "http://schema.org/name": "name", "http://www.w3.org/2003/01/geo/wgs84_pos#lat": "latitude", "http://www.w3.org/2003/01/geo/wgs84_pos#long": "longitude", }, triple); diff --git a/src/fetcher/tiles/RoutableTileFetcherDefault.test.ts b/src/fetcher/tiles/RoutableTileFetcherDefault.test.ts deleted file mode 100644 index b1136c12..00000000 --- a/src/fetcher/tiles/RoutableTileFetcherDefault.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import "jest"; -import LDFetch from "ldfetch"; -import RoutableTileRegistry from "../../entities/tiles/registry"; -import PathfinderProvider from "../../pathfinding/PathfinderProvider"; -import LocationResolverConvenience from "../../query-runner/LocationResolverConvenience"; -import ProfileFetcherDefault from "../profiles/ProfileFetcherDefault"; -import ProfileProviderDefault from "../profiles/ProfileProviderDefault"; -import RoutableTileFetcherDefault from "./RoutableTileFetcherDefault"; - -const ldfetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); -const profileProvider = new ProfileProviderDefault(new ProfileFetcherDefault(ldfetch)); -const locationResolver = new LocationResolverConvenience(null); -const fetcher = new RoutableTileFetcherDefault( - ldfetch, - new PathfinderProvider(undefined, undefined, profileProvider, locationResolver)); - -const registry = RoutableTileRegistry.getInstance(); - -test("[RoutableTileFetcherDefault] data completeness", async () => { - jest.setTimeout(15000); - - const expectedNodes: Set = new Set(); - const tile = await fetcher.get("https://tiles.openplanner.team/planet/14/8361/5482/"); - for (const wayId of tile.getWays()) { - const way = registry.getWay(wayId); - for (const segment of way.segments) { - for (const node of segment) { - expectedNodes.add(node); - } - } - } - - for (const id of expectedNodes) { - expect(tile.getNodes().has(id)); - } -}); diff --git a/src/planner/stops/ReachableStopsFinderBirdsEye.test.ts b/src/planner/stops/ReachableStopsFinderBirdsEye.test.ts index 18d2867e..495810f0 100644 --- a/src/planner/stops/ReachableStopsFinderBirdsEye.test.ts +++ b/src/planner/stops/ReachableStopsFinderBirdsEye.test.ts @@ -5,18 +5,12 @@ import StopsFetcherLDFetch from "../../fetcher/stops/ld-fetch/StopsFetcherLDFetc import Units from "../../util/Units"; import ReachableStopsFinderBirdsEye from "./ReachableStopsFinderBirdsEye"; -const DE_LIJN_STOPS_URLS = [ - "http://openplanner.ilabt.imec.be/delijn/Antwerpen/stops", - "http://openplanner.ilabt.imec.be/delijn/Oost-Vlaanderen/stops", - "http://openplanner.ilabt.imec.be/delijn/West-Vlaanderen/stops", - "http://openplanner.ilabt.imec.be/delijn/Vlaams-Brabant/stops", - "http://openplanner.ilabt.imec.be/delijn/Limburg/stops", -]; +const DE_LIJN_STOPS_URL = "http://openplanner.ilabt.imec.be/delijn/stops"; const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); const stopsFetcher = new StopsFetcherLDFetch(ldFetch); -stopsFetcher.setAccessUrl(DE_LIJN_STOPS_URLS[2]); +stopsFetcher.setAccessUrl(DE_LIJN_STOPS_URL); const reachableStopsFinder = new ReachableStopsFinderBirdsEye(stopsFetcher); From d6538b6b7b0b994286e4821652967bfec6be6cba Mon Sep 17 00:00:00 2001 From: Harm Delva Date: Thu, 19 Mar 2020 16:11:42 +0100 Subject: [PATCH 8/8] Unleash version 0.4.0! --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 30a548f7..ed80dfa2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plannerjs", - "version": "0.3.0", + "version": "0.4.0", "description": "The JavaScript framework for journey planning.", "main": "lib/index.js", "license": "MIT",