@wemap/routers 12.10.8 → 12.10.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helpers/InstructionManager.d.ts +20 -0
- package/dist/helpers/InstructionManagerV1.d.ts +7 -0
- package/{index.ts → dist/index.d.ts} +1 -11
- package/dist/index.js +1 -5099
- package/dist/index.js.map +1 -1
- package/dist/src/ItineraryInfoManager.d.ts +31 -0
- package/dist/src/RoutingError.d.ts +24 -0
- package/{src/StatusCode.ts → dist/src/StatusCode.d.ts} +2 -3
- package/dist/src/Utils.d.ts +6 -0
- package/dist/src/graph/Edge.d.ts +32 -0
- package/dist/src/graph/Graph.d.ts +40 -0
- package/dist/src/graph/GraphProjection.d.ts +11 -0
- package/dist/src/graph/GraphProjectionOptions.d.ts +7 -0
- package/dist/src/graph/GraphRoute.d.ts +19 -0
- package/dist/src/graph/GraphRouter.d.ts +20 -0
- package/dist/src/graph/GraphRouterEngine.d.ts +77 -0
- package/{src/graph/GraphRouterOptions.ts → dist/src/graph/GraphRouterOptions.d.ts} +5 -7
- package/dist/src/graph/GraphRouterOptionsBuilder.d.ts +20 -0
- package/dist/src/graph/NoRouteFoundError.d.ts +12 -0
- package/dist/src/graph/Vertex.d.ts +19 -0
- package/dist/src/model/Itinerary.d.ts +81 -0
- package/dist/src/model/Leg.d.ts +66 -0
- package/dist/src/model/LevelChange.d.ts +7 -0
- package/dist/src/model/RouterRequest.d.ts +40 -0
- package/dist/src/model/Step.d.ts +42 -0
- package/dist/src/model/StepExtra.d.ts +3 -0
- package/dist/src/model/StepsBuilder.d.ts +16 -0
- package/dist/src/model/TransitMode.d.ts +5 -0
- package/{src/model/TravelMode.ts → dist/src/model/TravelMode.d.ts} +1 -2
- package/dist/src/model/generateSteps.d.ts +0 -0
- package/{src/remote/RemoteRouter.ts → dist/src/remote/RemoteRouter.d.ts} +2 -7
- package/dist/src/remote/RemoteRouterManager.d.ts +731 -0
- package/dist/src/remote/RemoteRouterUtils.d.ts +6 -0
- package/dist/src/remote/cityway/CitywayRemoteRouter.d.ts +109 -0
- package/dist/src/remote/deutsche-bahn/DeutscheBahnRemoteRouter.d.ts +31 -0
- package/dist/src/remote/geovelo/GeoveloRemoteRouter.d.ts +106 -0
- package/dist/src/remote/idfm/IdfmRemoteRouter.d.ts +123 -0
- package/dist/src/remote/navitia/NavitiaRemoteRouter.d.ts +34 -0
- package/dist/src/remote/navitia/types.d.ts +87 -0
- package/dist/src/remote/osrm/OsrmRemoteRouter.d.ts +70 -0
- package/dist/src/remote/otp/OtpRemoteRouter.d.ts +69 -0
- package/dist/src/remote/wemap-multi/WemapMultiRemoteRouter.d.ts +19 -0
- package/dist/src/types.d.ts +31 -0
- package/dist/src/wemap-multi/CustomGraphMap.d.ts +56 -0
- package/dist/src/wemap-multi/CustomGraphMapTester.d.ts +39 -0
- package/dist/src/wemap-multi/WemapMultiRouter.d.ts +14 -0
- package/dist/src/wemap-osm/OsmGraphUtils.d.ts +11 -0
- package/dist/tests/CommonTest.d.ts +8 -0
- package/package.json +11 -8
- package/assets/biocbon-bergere-rdc-network.osm +0 -163
- package/assets/bureaux-wemap-montpellier-network.osm +0 -174
- package/assets/components.osm +0 -146
- package/assets/elevator-models-4.osm +0 -89
- package/assets/elevator-models.osm +0 -354
- package/assets/exit-graph.osm +0 -25
- package/assets/gare-de-lest-network-pp-bounds.osm +0 -1613
- package/assets/gare-de-lyon-extract.osm +0 -174
- package/assets/geovelo-montpellier.json +0 -1144
- package/assets/horizontal-elevator.osm +0 -12
- package/assets/itinerary-deutsche-bahn-1.json +0 -368
- package/assets/itinerary-grenoble-otp-1.json +0 -1536
- package/assets/itinerary-grenoble-otp-2.json +0 -1092
- package/assets/itinerary-info-two-points-proj.osm +0 -39
- package/assets/itinerary-info-two-points.osm +0 -24
- package/assets/itinerary-lehavre-cityway-1.json +0 -6799
- package/assets/itinerary-lehavre-cityway-2.json +0 -2133
- package/assets/itinerary-lehavre-cityway-3.json +0 -12577
- package/assets/itinerary-lehavre-cityway-4.json +0 -1451
- package/assets/itinerary-lehavre-cityway-5.json +0 -5925
- package/assets/itinerary-lemans-navitia.json +0 -7768
- package/assets/itinerary-montpellier-osrm-3.json +0 -185
- package/assets/itinerary-montpellier-outdoor-without-steps.json +0 -110
- package/assets/itinerary-montpellier-outdoor.json +0 -513
- package/assets/itinerary-paris-idfm-2.json +0 -1838
- package/assets/itinerary-paris-idfm.json +0 -27727
- package/assets/itinerary-step-not-on-path-osrm.json +0 -457
- package/assets/itinerary-with-duplicate-nodes.json +0 -110
- package/assets/network-conveying-backward.osm +0 -74
- package/assets/network-elevator.osm +0 -48
- package/assets/network-escalators.osm +0 -50
- package/assets/network-simple.osm +0 -27
- package/assets/network-steps-same-level.osm +0 -283
- package/assets/network-with-modifiers.osm +0 -39
- package/assets/one-way.osm +0 -46
- package/assets/report-map-1.osm +0 -36
- package/assets/report-map-2.osm +0 -29
- package/assets/report-map-3.osm +0 -15
- package/assets/rr-wemap-multi-indoor-outdoor-indoor.json +0 -1352
- package/assets/rr-wemap-multi-indoor-outdoor.json +0 -145
- package/assets/rr-wemap-multi-multi-level.json +0 -262
- package/assets/rr-wemap-multi-outdoor-indoor.json +0 -145
- package/assets/rr-wemap-multi-outdoor-outdoor.json +0 -207
- package/assets/rr-wemap-multi-remote-indoor-indoor.json +0 -155
- package/assets/rr-wemap-multi-remote-indoor-outdoor-indoor.json +0 -668
- package/assets/rr-wemap-multi-remote-indoor-outdoor.json +0 -154
- package/assets/rr-wemap-multi-remote-outdoor-indoor.json +0 -179
- package/assets/rr-wemap-multi-remote-outdoor-outdoor.json +0 -109
- package/assets/stairs-and-exit.osm +0 -47
- package/helpers/InstructionManager.ts +0 -184
- package/helpers/InstructionManagerV1.ts +0 -95
- package/src/ItineraryInfoManager.spec.ts +0 -183
- package/src/ItineraryInfoManager.ts +0 -181
- package/src/RoutingError.ts +0 -60
- package/src/Utils.ts +0 -8
- package/src/graph/Edge.spec.ts +0 -32
- package/src/graph/Edge.ts +0 -64
- package/src/graph/Graph.spec.ts +0 -509
- package/src/graph/Graph.ts +0 -272
- package/src/graph/GraphProjection.ts +0 -15
- package/src/graph/GraphProjectionOptions.ts +0 -8
- package/src/graph/GraphRoute.spec.ts +0 -15
- package/src/graph/GraphRoute.ts +0 -43
- package/src/graph/GraphRouter.spec.ts +0 -317
- package/src/graph/GraphRouter.ts +0 -229
- package/src/graph/GraphRouterEngine.ts +0 -248
- package/src/graph/GraphRouterOptionsBuilder.ts +0 -98
- package/src/graph/NoRouteFoundError.ts +0 -39
- package/src/graph/Vertex.spec.ts +0 -42
- package/src/graph/Vertex.ts +0 -45
- package/src/model/Itinerary.spec.ts +0 -134
- package/src/model/Itinerary.ts +0 -370
- package/src/model/Leg.spec.ts +0 -107
- package/src/model/Leg.ts +0 -224
- package/src/model/LevelChange.spec.ts +0 -50
- package/src/model/LevelChange.ts +0 -14
- package/src/model/RouterRequest.ts +0 -33
- package/src/model/Step.spec.ts +0 -99
- package/src/model/Step.ts +0 -90
- package/src/model/StepExtra.ts +0 -1
- package/src/model/StepsBuilder.ts +0 -242
- package/src/model/TransitMode.spec.ts +0 -31
- package/src/model/TransitMode.ts +0 -28
- package/src/model/generateSteps.ts +0 -102
- package/src/remote/RemoteRouterManager.spec.ts +0 -178
- package/src/remote/RemoteRouterManager.ts +0 -72
- package/src/remote/RemoteRouterUtils.ts +0 -25
- package/src/remote/cityway/CitywayRemoteRouter.spec.ts +0 -122
- package/src/remote/cityway/CitywayRemoteRouter.ts +0 -435
- package/src/remote/deutsche-bahn/DeutscheBahnRemoteRouter.spec.ts +0 -52
- package/src/remote/deutsche-bahn/DeutscheBahnRemoteRouter.ts +0 -85
- package/src/remote/geovelo/GeoveloRemoteRouter.spec.ts +0 -54
- package/src/remote/geovelo/GeoveloRemoteRouter.ts +0 -293
- package/src/remote/idfm/IdfmRemoteRouter.spec.ts +0 -102
- package/src/remote/idfm/IdfmRemoteRouter.ts +0 -523
- package/src/remote/navitia/NavitiaRemoteRouter.spec.ts +0 -116
- package/src/remote/navitia/NavitiaRemoteRouter.ts +0 -445
- package/src/remote/navitia/types.ts +0 -73
- package/src/remote/osrm/OsrmRemoteRouter.spec.ts +0 -127
- package/src/remote/osrm/OsrmRemoteRouter.ts +0 -303
- package/src/remote/otp/OtpRemoteRouter.spec.ts +0 -103
- package/src/remote/otp/OtpRemoteRouter.ts +0 -223
- package/src/remote/wemap-multi/WemapMultiRemoteRouter.spec.ts +0 -103
- package/src/remote/wemap-multi/WemapMultiRemoteRouter.ts +0 -56
- package/src/types.ts +0 -32
- package/src/wemap-multi/CustomGraphMap.spec.ts +0 -40
- package/src/wemap-multi/CustomGraphMap.ts +0 -213
- package/src/wemap-multi/CustomGraphMapTester.spec.ts +0 -48
- package/src/wemap-multi/CustomGraphMapTester.ts +0 -90
- package/src/wemap-multi/WemapMultiRouter.spec.ts +0 -138
- package/src/wemap-multi/WemapMultiRouter.ts +0 -329
- package/src/wemap-osm/OsmGraphUtils.spec.ts +0 -165
- package/src/wemap-osm/OsmGraphUtils.ts +0 -173
- package/src/wemap-osm/OsmRouter.elevators.spec.ts +0 -106
- package/src/wemap-osm/OsmRouter.spec.ts +0 -292
- package/tests/CommonTest.ts +0 -78
- package/tsconfig.json +0 -3
- package/vite.config.ts +0 -4
package/src/graph/GraphRouter.ts
DELETED
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
import salesman from '@wemap/salesman.js';
|
|
2
|
-
|
|
3
|
-
import { Coordinates } from '@wemap/geo';
|
|
4
|
-
|
|
5
|
-
import Vertex from './Vertex.js';
|
|
6
|
-
import Edge, { EdgeProperties } from './Edge.js';
|
|
7
|
-
import GraphRoute from './GraphRoute.js';
|
|
8
|
-
import GraphRouterEngine, { GraphRouterEngineResults } from './GraphRouterEngine.js';
|
|
9
|
-
import { type GraphRouterOptions } from './GraphRouterOptions.js';
|
|
10
|
-
import GraphRouterOptionsBuilder from './GraphRouterOptionsBuilder.js';
|
|
11
|
-
|
|
12
|
-
export class GraphRouterResults extends GraphRouterEngineResults {
|
|
13
|
-
|
|
14
|
-
constructor(
|
|
15
|
-
engineResults: GraphRouterEngineResults,
|
|
16
|
-
public sourceProjection: [Coordinates, Vertex | null],
|
|
17
|
-
public targetsProjections: [Coordinates, Vertex | null][]
|
|
18
|
-
|
|
19
|
-
) {
|
|
20
|
-
super(engineResults.prev, engineResults.dist, engineResults.source, engineResults.targets, engineResults.edges);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static createEmpty(source: Coordinates, targets: Coordinates[]) {
|
|
24
|
-
const length = targets.length;
|
|
25
|
-
const engineResults = new GraphRouterEngineResults(
|
|
26
|
-
new Array(length).fill(null),
|
|
27
|
-
new Array(length).fill(Number.MAX_VALUE),
|
|
28
|
-
new Vertex(source),
|
|
29
|
-
targets.map(target => new Vertex(target)),
|
|
30
|
-
[]
|
|
31
|
-
);
|
|
32
|
-
const sourceProjection: [Coordinates, null] = [source, null];
|
|
33
|
-
const targetsProjections: [Coordinates, null][] = targets.map(target => [target, null]);
|
|
34
|
-
return new GraphRouterResults(engineResults, sourceProjection, targetsProjections);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
routeVertices(to: Coordinates | Vertex = this.targetsProjections[0][0]): Vertex[] {
|
|
38
|
-
|
|
39
|
-
if (to instanceof Vertex) {
|
|
40
|
-
return super.routeVertices(to);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const sourceVertex = this.sourceProjection[1];
|
|
44
|
-
if (!sourceVertex) return [];
|
|
45
|
-
|
|
46
|
-
const toVertex = this.targetsProjections.find(([coord]) => coord === to)?.[1];
|
|
47
|
-
if (!toVertex) return [];
|
|
48
|
-
|
|
49
|
-
return super.routeVertices(toVertex);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
weightedDistance(to: Coordinates | Vertex = this.targetsProjections[0][0]) {
|
|
53
|
-
|
|
54
|
-
if (to instanceof Vertex) {
|
|
55
|
-
return super.weightedDistance(to);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const sourceVertex = this.sourceProjection[1];
|
|
59
|
-
if (!sourceVertex) return null;
|
|
60
|
-
|
|
61
|
-
const toVertex = this.targetsProjections.find(([coord]) => coord === to)?.[1];
|
|
62
|
-
if (!toVertex) return null;
|
|
63
|
-
|
|
64
|
-
return super.weightedDistance(toVertex);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
route(to: Coordinates | Vertex = this.targetsProjections[0][0]) {
|
|
68
|
-
|
|
69
|
-
if (to instanceof Vertex) {
|
|
70
|
-
return super.route(to);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const toVertex = this.targetsProjections.find(([coord]) => coord === to)?.[1];
|
|
74
|
-
if (!toVertex) return new GraphRoute(this.sourceProjection[0], to, [], [], []);
|
|
75
|
-
|
|
76
|
-
const route = super.route(toVertex);
|
|
77
|
-
route.start = this.sourceProjection[0];
|
|
78
|
-
route.end = to;
|
|
79
|
-
return route;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
class GraphRouter extends GraphRouterEngine {
|
|
85
|
-
|
|
86
|
-
calculateShortestPathToMultipleDestinations(
|
|
87
|
-
source: Coordinates,
|
|
88
|
-
targets: Coordinates[],
|
|
89
|
-
options: GraphRouterOptions = GraphRouterOptionsBuilder.DEFAULT,
|
|
90
|
-
): GraphRouterResults {
|
|
91
|
-
|
|
92
|
-
const createdVertices = new Set<Vertex>();
|
|
93
|
-
const createdEdges = new Set<Edge>();
|
|
94
|
-
const createdVerticesByOriginalEdges: [Edge, Vertex[]][] = []
|
|
95
|
-
|
|
96
|
-
const projectionsOptions = {
|
|
97
|
-
maxDistance: options.projectionMaxDistance,
|
|
98
|
-
acceptEdgeFn: options.acceptEdgeFn,
|
|
99
|
-
useMultiLevelSegments: options.useMultiLevelSegments,
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const getOrCreateVertex = (coords: Coordinates): Vertex | null => {
|
|
103
|
-
const projection = this.graph.getProjection(coords, projectionsOptions);
|
|
104
|
-
if (projection === null) return null;
|
|
105
|
-
if (projection.nearestElement instanceof Vertex) {
|
|
106
|
-
return projection.nearestElement;
|
|
107
|
-
}
|
|
108
|
-
if (projection.nearestElement instanceof Edge) {
|
|
109
|
-
const edge = projection.nearestElement;
|
|
110
|
-
const newVertex = new Vertex(projection.coords, {
|
|
111
|
-
name: `proj on ${edge.properties.name || null} (tmp)`,
|
|
112
|
-
...(typeof edge.properties.externalId !== 'undefined' && { externalId: edge.properties.externalId })
|
|
113
|
-
});
|
|
114
|
-
newVertex.id = this.graph.vertices.length + createdVertices.size;
|
|
115
|
-
const newEdgesOptions: EdgeProperties = {
|
|
116
|
-
...edge.properties,
|
|
117
|
-
...(typeof edge.properties.externalId !== 'undefined' && { externalId: edge.properties.externalId })
|
|
118
|
-
};
|
|
119
|
-
const newEdge1 = new Edge(edge.vertex1, newVertex, newEdgesOptions);
|
|
120
|
-
const newEdge2 = new Edge(newVertex, edge.vertex2, newEdgesOptions);
|
|
121
|
-
|
|
122
|
-
createdVertices.add(newVertex);
|
|
123
|
-
createdEdges.add(newEdge1);
|
|
124
|
-
createdEdges.add(newEdge2);
|
|
125
|
-
|
|
126
|
-
const createdVerticesByOriginalEdge = createdVerticesByOriginalEdges.find(p => p[0] === edge)
|
|
127
|
-
if (!createdVerticesByOriginalEdge) {
|
|
128
|
-
createdVerticesByOriginalEdges.push([edge, [newVertex]])
|
|
129
|
-
} else {
|
|
130
|
-
createdVerticesByOriginalEdge[1].push(newVertex);
|
|
131
|
-
}
|
|
132
|
-
return newVertex;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return null; // Should never happens
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const sourceVertex = getOrCreateVertex(source);
|
|
139
|
-
if (!sourceVertex) return GraphRouterResults.createEmpty(source, targets);
|
|
140
|
-
|
|
141
|
-
const targetsProjections: [Coordinates, Vertex | null][] = targets.map(target => [target, getOrCreateVertex(target)]);
|
|
142
|
-
const targetsVertices = targetsProjections.map(([, vertex]) => vertex).filter(p => p !== null) as Vertex[];
|
|
143
|
-
|
|
144
|
-
// In some specific cases, more than one vertex is created from an original edge.
|
|
145
|
-
// And this vertices need to be connected together.
|
|
146
|
-
createdVerticesByOriginalEdges.filter(pair => pair[1].length >= 2);
|
|
147
|
-
createdVerticesByOriginalEdges.forEach(([edge, vertices]) => {
|
|
148
|
-
const newEdgesOptions: EdgeProperties = {
|
|
149
|
-
...edge.properties,
|
|
150
|
-
name: `splitted ${edge.properties.name || null} (tmp)`,
|
|
151
|
-
};
|
|
152
|
-
for (let i = 0; i < vertices.length; i++) {
|
|
153
|
-
const vertexA = vertices[i];
|
|
154
|
-
const distVertexAVertex1 = vertexA.distanceTo(edge.vertex1)
|
|
155
|
-
for (let j = i + 1; j < vertices.length; j++) {
|
|
156
|
-
const vertexB = vertices[j];
|
|
157
|
-
const distVertexBVertex1 = vertexB.distanceTo(edge.vertex1)
|
|
158
|
-
const reverse = distVertexBVertex1 < distVertexAVertex1;
|
|
159
|
-
const newEdge = !reverse
|
|
160
|
-
? new Edge(vertexA, vertexB, newEdgesOptions)
|
|
161
|
-
: new Edge(vertexB, vertexA, newEdgesOptions);
|
|
162
|
-
createdEdges.add(newEdge);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const engineResults = this.calculateShortestPathToMultipleDestinationsByVertex(
|
|
169
|
-
sourceVertex, targetsVertices, options,
|
|
170
|
-
[...this.graph.vertices, ...createdVertices],
|
|
171
|
-
[...this.graph.edges, ...createdEdges],
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
return new GraphRouterResults(engineResults, [source, sourceVertex], targetsProjections);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
calculateShortestPath(
|
|
178
|
-
source: Coordinates,
|
|
179
|
-
target: Coordinates,
|
|
180
|
-
options: GraphRouterOptions = GraphRouterOptionsBuilder.DEFAULT,
|
|
181
|
-
): GraphRouterResults {
|
|
182
|
-
return this.calculateShortestPathToMultipleDestinations(source, [target], options);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
// TODO: Verify if it works well with oneway edges
|
|
187
|
-
getShortestTrip(waypoints: Coordinates[], options?: GraphRouterOptions, tspTempCoeff = 0.99) {
|
|
188
|
-
type CustomPoint = salesman.Point & { coords: Coordinates };
|
|
189
|
-
|
|
190
|
-
const points = waypoints.map(waypoint => {
|
|
191
|
-
const point = new salesman.Point(0, 0) as CustomPoint;
|
|
192
|
-
point.coords = waypoint;
|
|
193
|
-
return point;
|
|
194
|
-
});
|
|
195
|
-
const graphRoutesCache: GraphRoute[] = [];
|
|
196
|
-
const solution = salesman.solve(points, tspTempCoeff, undefined, (p: salesman.Point, q: salesman.Point) => {
|
|
197
|
-
const route = this.calculateShortestPath(
|
|
198
|
-
(p as CustomPoint).coords,
|
|
199
|
-
(q as CustomPoint).coords,
|
|
200
|
-
options
|
|
201
|
-
).route();
|
|
202
|
-
graphRoutesCache.push(route);
|
|
203
|
-
if (!route.hasRoute) { return Number.MAX_VALUE }
|
|
204
|
-
return route.edgesWeights.reduce((acc, weight) => acc + weight, 0);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
const orderedPoints = solution.map(i => points[i]);
|
|
208
|
-
const orderedRoutes = [];
|
|
209
|
-
for (let i = 0; i < orderedPoints.length; i++) {
|
|
210
|
-
const p = orderedPoints[i] as CustomPoint;
|
|
211
|
-
const q = orderedPoints[(i + 1) % orderedPoints.length] as CustomPoint;
|
|
212
|
-
let cachedRoute = graphRoutesCache.find(route => route.start === p.coords && route.end === q.coords || route.end === p.coords && route.start === q.coords);
|
|
213
|
-
if (cachedRoute?.end === p.coords) {
|
|
214
|
-
// Need to revert route due to salesman bijectivity
|
|
215
|
-
cachedRoute = cachedRoute.reverse();
|
|
216
|
-
}
|
|
217
|
-
if (cachedRoute) {
|
|
218
|
-
orderedRoutes.push(cachedRoute);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (orderedRoutes.some(route => !route.hasRoute)) return [];
|
|
223
|
-
|
|
224
|
-
return orderedRoutes;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
export default GraphRouter;
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { ColorUtils } from '@wemap/utils';
|
|
3
|
-
import Edge from './Edge.js';
|
|
4
|
-
import Graph from './Graph.js';
|
|
5
|
-
import GraphRoute from './GraphRoute.js';
|
|
6
|
-
import { type GraphRouterOptions } from './GraphRouterOptions.js';
|
|
7
|
-
import GraphRouterOptionsBuilder from './GraphRouterOptionsBuilder.js';
|
|
8
|
-
import Vertex from './Vertex.js';
|
|
9
|
-
|
|
10
|
-
export class GraphRouterEngineResults {
|
|
11
|
-
constructor(
|
|
12
|
-
public prev: Array<Vertex | null>,
|
|
13
|
-
public dist: number[],
|
|
14
|
-
public source: Vertex,
|
|
15
|
-
public targets: Vertex[],
|
|
16
|
-
public edges: Edge[]
|
|
17
|
-
) { }
|
|
18
|
-
|
|
19
|
-
routeVertices(to = this.targets[0], list: Vertex[] = []): Vertex[] {
|
|
20
|
-
const last = this.prev[to.id];
|
|
21
|
-
if (last === null) return this.source === to ? [...list, to] : [];
|
|
22
|
-
return [...this.routeVertices(last, list), to];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
weightedDistance(to = this.targets[0]) {
|
|
26
|
-
const distance = this.dist[to.id];
|
|
27
|
-
return distance === Number.MAX_VALUE ? null : distance;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
route(to = this.targets[0]) {
|
|
31
|
-
|
|
32
|
-
const path = this.routeVertices(to);
|
|
33
|
-
|
|
34
|
-
const edges = [];
|
|
35
|
-
const edgesWeights = [];
|
|
36
|
-
for (let i = 1; i < path.length; i++) {
|
|
37
|
-
const v1 = path[i - 1];
|
|
38
|
-
const v2 = path[i];
|
|
39
|
-
const graphEdge = Edge.getEdgeByVertices(this.edges, v1, v2)!;
|
|
40
|
-
const clonedEdge = new Edge(v1, v2, Object.assign({}, graphEdge.properties));
|
|
41
|
-
const isReversed = graphEdge.vertex1 === clonedEdge.vertex2;
|
|
42
|
-
if (isReversed) {
|
|
43
|
-
clonedEdge.reverseProperties();
|
|
44
|
-
}
|
|
45
|
-
edges.push(clonedEdge);
|
|
46
|
-
edgesWeights.push(this.dist[v2.id] - this.dist[v1.id]);
|
|
47
|
-
}
|
|
48
|
-
return new GraphRoute(this.source.coords, to.coords, path, edges, edgesWeights);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
toGeoJson(graph: Graph) {
|
|
52
|
-
return {
|
|
53
|
-
type: "FeatureCollection",
|
|
54
|
-
features: [
|
|
55
|
-
...graph.vertices.map(v => {
|
|
56
|
-
const prev = this.prev[v.id];
|
|
57
|
-
const dist = this.dist[v.id];
|
|
58
|
-
const isSource = v === this.source;
|
|
59
|
-
const isTarget = this.targets.includes(v);
|
|
60
|
-
const level = v.coords.level;
|
|
61
|
-
return {
|
|
62
|
-
type: "Feature",
|
|
63
|
-
properties: {
|
|
64
|
-
id: v.id,
|
|
65
|
-
...(prev && { prev: prev.id }),
|
|
66
|
-
dist: dist === Number.MAX_VALUE ? 'infinity' : dist,
|
|
67
|
-
...(isSource && { name: 'source' }),
|
|
68
|
-
...(isTarget && { name: 'target' }),
|
|
69
|
-
...(level !== null && { level }),
|
|
70
|
-
...v.properties
|
|
71
|
-
},
|
|
72
|
-
geometry: {
|
|
73
|
-
type: 'Point',
|
|
74
|
-
coordinates: [v.coords.lng, v.coords.lat]
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}),
|
|
78
|
-
...graph.edges.map(e => {
|
|
79
|
-
const level = e.level;
|
|
80
|
-
return {
|
|
81
|
-
type: "Feature",
|
|
82
|
-
properties: {
|
|
83
|
-
id: e.id,
|
|
84
|
-
...(level !== null && { level }),
|
|
85
|
-
...e.properties
|
|
86
|
-
},
|
|
87
|
-
geometry: {
|
|
88
|
-
type: 'LineString',
|
|
89
|
-
coordinates: [
|
|
90
|
-
[e.vertex1.coords.lng, e.vertex1.coords.lat],
|
|
91
|
-
[e.vertex2.coords.lng, e.vertex2.coords.lat]
|
|
92
|
-
]
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
})
|
|
96
|
-
]
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export default class GraphRouterEngine {
|
|
102
|
-
|
|
103
|
-
disabledEdges: Set<Edge> = new Set();
|
|
104
|
-
|
|
105
|
-
constructor(public readonly graph: Graph) {
|
|
106
|
-
let vertexId = 0;
|
|
107
|
-
graph.vertices.forEach(vertex => vertex.id = vertexId++);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
calculateShortestPathToMultipleDestinationsByVertex(
|
|
111
|
-
source: Vertex,
|
|
112
|
-
targets: Vertex[],
|
|
113
|
-
options: GraphRouterOptions = GraphRouterOptionsBuilder.DEFAULT,
|
|
114
|
-
inputVertices = this.graph.vertices,
|
|
115
|
-
inputEdges = this.graph.edges
|
|
116
|
-
): GraphRouterEngineResults {
|
|
117
|
-
|
|
118
|
-
const q = new Set(inputVertices);
|
|
119
|
-
const dist = Array(q.size).fill(Number.MAX_VALUE);
|
|
120
|
-
const prev = new Array<Vertex | null>(q.size).fill(null);
|
|
121
|
-
const edges = inputEdges.filter(e => (options.acceptEdgeFn?.(e) ?? true) && !this.disabledEdges.has(e));
|
|
122
|
-
const weightEdgeFn = options.weightEdgeFn || ((edge: Edge) => edge.length);
|
|
123
|
-
|
|
124
|
-
const getVertexWithMinDistance = (vertices: Set<Vertex>): Vertex | null => {
|
|
125
|
-
let minDistance = Number.MAX_VALUE;
|
|
126
|
-
let vertex: Vertex | null = null;
|
|
127
|
-
vertices.forEach(_vertex => {
|
|
128
|
-
const distance = dist[_vertex.id];
|
|
129
|
-
if (distance <= minDistance) {
|
|
130
|
-
minDistance = distance;
|
|
131
|
-
vertex = _vertex;
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
return vertex;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const remainingNodesToFind = new Set(targets);
|
|
139
|
-
|
|
140
|
-
dist[source.id] = 0;
|
|
141
|
-
|
|
142
|
-
while (q.size > 0) {
|
|
143
|
-
const u = getVertexWithMinDistance(q)!;
|
|
144
|
-
q.delete(u);
|
|
145
|
-
|
|
146
|
-
if (targets.includes(u)) {
|
|
147
|
-
remainingNodesToFind.delete(u);
|
|
148
|
-
if (remainingNodesToFind.size === 0) {
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
edges
|
|
154
|
-
.filter(edge => edge.vertex1 == u || !edge.properties.isOneway && edge.vertex2 == u)
|
|
155
|
-
.forEach(edge => {
|
|
156
|
-
const v = u === edge.vertex1 ? edge.vertex2 : edge.vertex1;
|
|
157
|
-
const distance = weightEdgeFn(edge);
|
|
158
|
-
const alt = dist[u.id] + distance;
|
|
159
|
-
if (alt < dist[v.id]) {
|
|
160
|
-
dist[v.id] = alt;
|
|
161
|
-
prev[v.id] = u
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return new GraphRouterEngineResults(prev, dist, source, targets, edges);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
calculateShortestPathByVertex(
|
|
170
|
-
source: Vertex,
|
|
171
|
-
target: Vertex,
|
|
172
|
-
options: GraphRouterOptions = GraphRouterOptionsBuilder.DEFAULT,
|
|
173
|
-
inputVertices = this.graph.vertices,
|
|
174
|
-
inputEdges = this.graph.edges
|
|
175
|
-
): GraphRouterEngineResults {
|
|
176
|
-
return this.calculateShortestPathToMultipleDestinationsByVertex(source, [target], options, inputVertices, inputEdges);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// https://en.wikipedia.org/wiki/Component_(graph_theory)
|
|
180
|
-
calculateComponents() {
|
|
181
|
-
|
|
182
|
-
function shiftSet<T>(set: Set<T>): T {
|
|
183
|
-
const firstValue = set.values().next().value as T;
|
|
184
|
-
set.delete(firstValue);
|
|
185
|
-
return firstValue;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const verticesToTest = new Set<Vertex>(this.graph.vertices);
|
|
189
|
-
let components: Vertex[][] = [];
|
|
190
|
-
|
|
191
|
-
while (verticesToTest.size > 0) {
|
|
192
|
-
const vertexToTest = shiftSet(verticesToTest);
|
|
193
|
-
const otherVertices = this.graph.vertices.filter(v => v.id !== vertexToTest.id);
|
|
194
|
-
const result = this.calculateShortestPathToMultipleDestinationsByVertex(vertexToTest, otherVertices);
|
|
195
|
-
const reachedVertices = otherVertices.filter(ov => result.weightedDistance(ov) !== null);
|
|
196
|
-
|
|
197
|
-
components.push([vertexToTest, ...reachedVertices]);
|
|
198
|
-
reachedVertices.forEach(rv => verticesToTest.delete(rv));
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// As graph is ordered, fuse components with same vertices
|
|
202
|
-
let hasChanged;
|
|
203
|
-
do {
|
|
204
|
-
hasChanged = false;
|
|
205
|
-
for (let i = 0; i < components.length - 1; i++) {
|
|
206
|
-
const component1 = components[i];
|
|
207
|
-
for (let j = i + 1; j < components.length; j++) {
|
|
208
|
-
const component2 = components[j];
|
|
209
|
-
const componentsIntersect = component2.some(v => component1.includes(v));
|
|
210
|
-
if (componentsIntersect) {
|
|
211
|
-
component1.push(...component2);
|
|
212
|
-
components = components.filter(component => component !== component2);
|
|
213
|
-
hasChanged = true;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
} while (hasChanged)
|
|
218
|
-
|
|
219
|
-
return components.map(c => [... new Set(c)]);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
toGeoJson() {
|
|
223
|
-
const components = this.calculateComponents();
|
|
224
|
-
const features = components.map((component, i) => {
|
|
225
|
-
const edges = this.graph.edges.filter(edge => component.includes(edge.vertex1) && component.includes(edge.vertex2));
|
|
226
|
-
return {
|
|
227
|
-
"type": "Feature",
|
|
228
|
-
"geometry": {
|
|
229
|
-
"type": "MultiLineString",
|
|
230
|
-
"coordinates":
|
|
231
|
-
edges.map(e => [
|
|
232
|
-
[e.vertex1.coords.lng, e.vertex1.coords.lat],
|
|
233
|
-
[e.vertex2.coords.lng, e.vertex2.coords.lat],
|
|
234
|
-
])
|
|
235
|
-
},
|
|
236
|
-
"properties": {
|
|
237
|
-
"stroke": '#' + ColorUtils.getQualitativeColor(i).toString(16)
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
return {
|
|
243
|
-
"type": "FeatureCollection",
|
|
244
|
-
"features": features
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import Edge from './Edge.js';
|
|
2
|
-
import { getDurationFromLength } from '../Utils.js';
|
|
3
|
-
import { GraphRouterOptionsJson, type GraphRouterOptions } from './GraphRouterOptions.js';
|
|
4
|
-
|
|
5
|
-
export default class GraphRouterOptionsBuilder {
|
|
6
|
-
|
|
7
|
-
public avoidStairs = false;
|
|
8
|
-
public avoidEscalators = false;
|
|
9
|
-
public avoidElevators = false;
|
|
10
|
-
public avoidMovingWalkways = false;
|
|
11
|
-
public avoidTicketRestrictedAreas = false;
|
|
12
|
-
public useMultiLevelSegments = false;
|
|
13
|
-
public projectionMaxDistance?: number;
|
|
14
|
-
|
|
15
|
-
static DEFAULT = new GraphRouterOptionsBuilder().build();
|
|
16
|
-
static WITHOUT_STAIRS = new GraphRouterOptionsBuilder().setAvoidStairs(true).build();
|
|
17
|
-
|
|
18
|
-
setAvoidStairs(avoidStairs: boolean) {
|
|
19
|
-
this.avoidStairs = avoidStairs;
|
|
20
|
-
return this;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
setAvoidEscalators(avoidEscalators: boolean) {
|
|
24
|
-
this.avoidEscalators = avoidEscalators;
|
|
25
|
-
return this;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
setAvoidElevators(avoidElevators: boolean) {
|
|
29
|
-
this.avoidElevators = avoidElevators;
|
|
30
|
-
return this;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
setAvoidMovingWalkways(avoidMovingWalkways: boolean) {
|
|
34
|
-
this.avoidMovingWalkways = avoidMovingWalkways;
|
|
35
|
-
return this;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
setAvoidTicketRestrictedAreas(avoidTicketRestrictedAreas: boolean) {
|
|
39
|
-
this.avoidTicketRestrictedAreas = avoidTicketRestrictedAreas;
|
|
40
|
-
return this;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
setUseMultiLevelSegments(useMultiLevelSegments: boolean) {
|
|
44
|
-
this.useMultiLevelSegments = useMultiLevelSegments;
|
|
45
|
-
return this;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
static fromJson(options: GraphRouterOptionsJson) {
|
|
49
|
-
const builder = new GraphRouterOptionsBuilder();
|
|
50
|
-
Object.assign(builder, options);
|
|
51
|
-
return builder.build();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
build(): GraphRouterOptions {
|
|
55
|
-
|
|
56
|
-
const weightEdgeFn = (edge: Edge) => {
|
|
57
|
-
if (edge.properties.isElevator) {
|
|
58
|
-
return 90;
|
|
59
|
-
}
|
|
60
|
-
let duration = getDurationFromLength(edge.length, 4);
|
|
61
|
-
if (edge.properties.areStairs) {
|
|
62
|
-
duration *= 3;
|
|
63
|
-
} else if (edge.properties.areEscalators) {
|
|
64
|
-
duration *= 1.5;
|
|
65
|
-
} else if (edge.properties.isMovingWalkway) {
|
|
66
|
-
duration *= 0.8;
|
|
67
|
-
}
|
|
68
|
-
return duration;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const acceptEdgeFn = (edge: Edge) => {
|
|
72
|
-
|
|
73
|
-
if (this.avoidStairs && edge.properties.areStairs) return false;
|
|
74
|
-
if (this.avoidEscalators && edge.properties.areEscalators) return false;
|
|
75
|
-
if (this.avoidElevators && edge.properties.isElevator) return false;
|
|
76
|
-
if (this.avoidMovingWalkways && edge.properties.isMovingWalkway) return false;
|
|
77
|
-
if (this.avoidTicketRestrictedAreas && edge.properties.needTicket) return false;
|
|
78
|
-
|
|
79
|
-
return true;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
return {
|
|
83
|
-
input: {
|
|
84
|
-
avoidStairs: this.avoidStairs,
|
|
85
|
-
avoidEscalators: this.avoidEscalators,
|
|
86
|
-
avoidElevators: this.avoidElevators,
|
|
87
|
-
avoidMovingWalkways: this.avoidMovingWalkways,
|
|
88
|
-
avoidTicketRestrictedAreas: this.avoidTicketRestrictedAreas,
|
|
89
|
-
projectionMaxDistance: this.projectionMaxDistance
|
|
90
|
-
},
|
|
91
|
-
weightEdgeFn,
|
|
92
|
-
acceptEdgeFn,
|
|
93
|
-
projectionMaxDistance: this.projectionMaxDistance,
|
|
94
|
-
useMultiLevelSegments: this.useMultiLevelSegments
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Coordinates } from '@wemap/geo';
|
|
2
|
-
|
|
3
|
-
import Vertex from './Vertex.js';
|
|
4
|
-
|
|
5
|
-
class NoRouteFoundError extends Error {
|
|
6
|
-
|
|
7
|
-
constructor(
|
|
8
|
-
public start: Vertex | Coordinates,
|
|
9
|
-
public end: Vertex | Coordinates | (Coordinates | Vertex)[],
|
|
10
|
-
public details: string | null = null
|
|
11
|
-
) { super(); }
|
|
12
|
-
|
|
13
|
-
get startStr() {
|
|
14
|
-
if (this.start instanceof Vertex) {
|
|
15
|
-
return `Vertex ${this.start.coords.toString()}`;
|
|
16
|
-
}
|
|
17
|
-
return this.start.toString();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
get endStr() {
|
|
21
|
-
if (this.end instanceof Vertex) {
|
|
22
|
-
return `Vertex ${this.end.coords.toString()}`;
|
|
23
|
-
}
|
|
24
|
-
if (Array.isArray(this.end)) {
|
|
25
|
-
return this.end.map(p => p instanceof Vertex ? p.coords.toString() : p.toString()).join(',');
|
|
26
|
-
}
|
|
27
|
-
return this.end.toString();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
get message() {
|
|
31
|
-
let message = `No route found from ${this.startStr} to ${this.endStr}.`;
|
|
32
|
-
if (this.details) {
|
|
33
|
-
message += ` Details: ${this.details}`;
|
|
34
|
-
}
|
|
35
|
-
return message;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export default NoRouteFoundError;
|
package/src/graph/Vertex.spec.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import chai from 'chai';
|
|
2
|
-
|
|
3
|
-
import { Coordinates } from '@wemap/geo';
|
|
4
|
-
|
|
5
|
-
import Vertex from './Vertex.js';
|
|
6
|
-
|
|
7
|
-
const { expect } = chai;
|
|
8
|
-
|
|
9
|
-
describe('Vertex', () => {
|
|
10
|
-
|
|
11
|
-
it('creation', () => {
|
|
12
|
-
|
|
13
|
-
expect(() => new Vertex(new Coordinates(0, 0))).not.throw(Error);
|
|
14
|
-
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const pos1 = new Coordinates(45, 5);
|
|
19
|
-
const pos2 = new Coordinates(46, 5);
|
|
20
|
-
const vertex1 = new Vertex(pos1);
|
|
21
|
-
const vertex2 = new Vertex(pos2);
|
|
22
|
-
|
|
23
|
-
it('distanceTo', () => {
|
|
24
|
-
expect(vertex1.distanceTo(vertex2)).equals(pos1.distanceTo(pos2));
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('bearingTo', () => {
|
|
28
|
-
expect(vertex1.bearingTo(vertex2)).equals(pos1.bearingTo(pos2));
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('toJson / fromJson', () => {
|
|
32
|
-
|
|
33
|
-
const vertex = new Vertex(pos1);
|
|
34
|
-
|
|
35
|
-
const jsonVertex = vertex.toJson();
|
|
36
|
-
expect(jsonVertex).deep.equals({ id: -1, coords: [45, 5] });
|
|
37
|
-
|
|
38
|
-
const vertexBis = Vertex.fromJson(jsonVertex);
|
|
39
|
-
expect(vertexBis.coords.equals(vertex.coords)).true;
|
|
40
|
-
expect(vertexBis.id).equals(vertex.id);
|
|
41
|
-
});
|
|
42
|
-
});
|