@wemap/routers 12.0.0 → 12.2.0
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/assets/components.osm +146 -0
- package/dist/index.js +64 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -38
- package/dist/index.mjs.map +1 -1
- package/index.ts +0 -2
- package/package.json +2 -2
- package/src/graph/Edge.ts +3 -0
- package/src/graph/Graph.ts +2 -2
- package/src/graph/GraphRouter.ts +3 -1
- package/src/graph/GraphRouterEngine.ts +39 -32
- package/src/graph/Vertex.ts +1 -0
- package/src/model/Itinerary.ts +18 -14
- package/src/types.ts +1 -0
- package/src/wemap-multi/CustomNetworkMap.ts +0 -11
- package/src/wemap-osm/OsmGraphUtils.ts +5 -3
- package/src/wemap-osm/OsmRouter.spec.ts +25 -0
- package/src/wemap-osm/OsmRouterOptions.ts +0 -13
package/index.ts
CHANGED
|
@@ -23,8 +23,6 @@ export { default as NoRouteFoundError } from './src/graph/NoRouteFoundError.js';
|
|
|
23
23
|
|
|
24
24
|
/* Wemap Router */
|
|
25
25
|
export { default as OsmGraphUtils } from './src/wemap-osm/OsmGraphUtils.js';
|
|
26
|
-
export { type OsmRouterOptions } from './src/wemap-osm/OsmRouterOptions.js';
|
|
27
|
-
|
|
28
26
|
export { default as WemapMultiRouter } from './src/wemap-multi/WemapMultiRouter.js';
|
|
29
27
|
export { default as CustomNetworkMap } from './src/wemap-multi/CustomNetworkMap.js';
|
|
30
28
|
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"directory": "packages/routers"
|
|
13
13
|
},
|
|
14
14
|
"name": "@wemap/routers",
|
|
15
|
-
"version": "12.
|
|
15
|
+
"version": "12.2.0",
|
|
16
16
|
"bugs": {
|
|
17
17
|
"url": "https://github.com/wemap/wemap-modules-js/issues"
|
|
18
18
|
},
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
},
|
|
53
53
|
"./helpers/*": "./helpers/*"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "6dda458e79cb7bc9bb63de3db2d000823672c3ca"
|
|
56
56
|
}
|
package/src/graph/Edge.ts
CHANGED
package/src/graph/Graph.ts
CHANGED
|
@@ -135,6 +135,7 @@ class Graph {
|
|
|
135
135
|
toCompressedJson(): GeoGraphJson {
|
|
136
136
|
return {
|
|
137
137
|
vertices: this.vertices.map(vertex => vertex.toJson()),
|
|
138
|
+
verticesIds: this.vertices.map(vertex => vertex.id),
|
|
138
139
|
edges: this.edges.map(edge => {
|
|
139
140
|
const vertex1Idx = this.vertices.indexOf(edge.vertex1);
|
|
140
141
|
const vertex2Idx = this.vertices.indexOf(edge.vertex2);
|
|
@@ -155,8 +156,7 @@ class Graph {
|
|
|
155
156
|
vertices[jsonEdge[0]],
|
|
156
157
|
vertices[jsonEdge[1]],
|
|
157
158
|
jsonEdge.length > 2 ? jsonEdge[2] : {}
|
|
158
|
-
)
|
|
159
|
-
);
|
|
159
|
+
));
|
|
160
160
|
|
|
161
161
|
return new Graph(vertices, edges);
|
|
162
162
|
}
|
package/src/graph/GraphRouter.ts
CHANGED
|
@@ -107,12 +107,14 @@ class GraphRouter extends GraphRouterEngine {
|
|
|
107
107
|
if (projection.nearestElement instanceof Edge) {
|
|
108
108
|
const edge = projection.nearestElement;
|
|
109
109
|
const newVertex = new Vertex(projection.coords, {
|
|
110
|
-
name: `proj on ${edge.properties.name || null} (tmp)
|
|
110
|
+
name: `proj on ${edge.properties.name || null} (tmp)`,
|
|
111
|
+
...(typeof edge.properties.externalId !== 'undefined' && { externalId: edge.properties.externalId })
|
|
111
112
|
});
|
|
112
113
|
newVertex.id = this.graph.vertices.length + createdVertices.size;
|
|
113
114
|
const newEdgesOptions: EdgeProperties = {
|
|
114
115
|
...edge.properties,
|
|
115
116
|
name: `splitted ${edge.properties.name || null} (tmp)`,
|
|
117
|
+
...(typeof edge.properties.externalId !== 'undefined' && { externalId: edge.properties.externalId })
|
|
116
118
|
};
|
|
117
119
|
const newEdge1 = new Edge(edge.vertex1, newVertex, newEdgesOptions);
|
|
118
120
|
const newEdge2 = new Edge(newVertex, edge.vertex2, newEdgesOptions);
|
|
@@ -149,39 +149,7 @@ export default class GraphRouterEngine {
|
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
// edges.forEach(edge => {
|
|
153
|
-
// // if (edge.properties.isOneway) {
|
|
154
|
-
// // console.log("isOneway")
|
|
155
|
-
// // return edge.vertex1 == u
|
|
156
|
-
// // } else {
|
|
157
|
-
// // console.log(`${edge.id} => keep: ${cond} - ${JSON.stringify(edge.properties)} [f: ${firstPart}, s: ${secondPart}]`);
|
|
158
|
-
// // }
|
|
159
|
-
// // return edge.vertex1 == u || edge.vertex2 == u
|
|
160
|
-
// const firstPart = edge.vertex1 == u;
|
|
161
|
-
// const secondPart = !edge.properties.isOneway && edge.vertex2 == u;
|
|
162
|
-
// const cond = edge.vertex1 == u || !edge.properties.isOneway && edge.vertex2 == u
|
|
163
|
-
// console.log(`${edge.id} => keep: ${cond} - ${JSON.stringify(edge.properties)} [f: ${firstPart}, s: ${secondPart}]`);
|
|
164
|
-
// })
|
|
165
|
-
|
|
166
|
-
// const mEdges = edges
|
|
167
|
-
// .filter(edge => edge.vertex1 == u || !edge.properties.isOneway && edge.vertex2 == u)
|
|
168
|
-
// .map(edge => `${edge.id} - ${edge.properties.name}`)
|
|
169
|
-
// console.log('_-------_')
|
|
170
|
-
// console.log(`Processing vertex ${u.id} (${u.properties.name})`);
|
|
171
|
-
// console.log(`Calc for edges: ${mEdges}`);
|
|
172
|
-
|
|
173
|
-
// if (u.properties.name === 'p11') {
|
|
174
|
-
// console.log(u);
|
|
175
|
-
// }
|
|
176
|
-
|
|
177
|
-
|
|
178
152
|
edges
|
|
179
|
-
// .filter(edge => {
|
|
180
|
-
// if (edge.properties.isOneway) {
|
|
181
|
-
// return edge.vertex1 == u
|
|
182
|
-
// }
|
|
183
|
-
// return edge.vertex1 == u || edge.vertex2 == u
|
|
184
|
-
// })
|
|
185
153
|
.filter(edge => edge.vertex1 == u || !edge.properties.isOneway && edge.vertex2 == u)
|
|
186
154
|
.forEach(edge => {
|
|
187
155
|
const v = u === edge.vertex1 ? edge.vertex2 : edge.vertex1;
|
|
@@ -206,4 +174,43 @@ export default class GraphRouterEngine {
|
|
|
206
174
|
): GraphRouterEngineResults {
|
|
207
175
|
return this.calculateShortestPathToMultipleDestinationsByVertex(source, [target], options, inputVertices, inputEdges);
|
|
208
176
|
}
|
|
177
|
+
|
|
178
|
+
// https://en.wikipedia.org/wiki/Component_(graph_theory)
|
|
179
|
+
calculateComponents() {
|
|
180
|
+
|
|
181
|
+
function shiftSet<T>(set: Set<T>): T {
|
|
182
|
+
const firstValue = set.values().next().value as T;
|
|
183
|
+
set.delete(firstValue);
|
|
184
|
+
return firstValue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const verticesToTest = new Set<Vertex>(this.graph.vertices);
|
|
188
|
+
let components: Vertex[][] = [];
|
|
189
|
+
|
|
190
|
+
while (verticesToTest.size > 0) {
|
|
191
|
+
const vertexToTest = shiftSet(verticesToTest);
|
|
192
|
+
const otherVertices = this.graph.vertices.filter(v => v.id !== vertexToTest.id);
|
|
193
|
+
const result = this.calculateShortestPathToMultipleDestinationsByVertex(vertexToTest, otherVertices);
|
|
194
|
+
const reachedVertices = otherVertices.filter(ov => result.weightedDistance(ov) !== null);
|
|
195
|
+
|
|
196
|
+
components.push([vertexToTest, ...reachedVertices]);
|
|
197
|
+
reachedVertices.forEach(rv => verticesToTest.delete(rv));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// As graph is ordered, fuse components with same vertices
|
|
201
|
+
for (let i = 0; i < components.length - 1; i++) {
|
|
202
|
+
const component1 = components[i];
|
|
203
|
+
for (let j = i + 1; j < components.length; j++) {
|
|
204
|
+
const component2 = components[j];
|
|
205
|
+
const componentsIntersect = component2.some(v => component1.includes(v));
|
|
206
|
+
if (componentsIntersect) {
|
|
207
|
+
component1.push(...component2);
|
|
208
|
+
components = components.filter(component => component !== component2);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return components.map(c => [... new Set(c)]);
|
|
214
|
+
}
|
|
215
|
+
|
|
209
216
|
}
|
package/src/graph/Vertex.ts
CHANGED
package/src/model/Itinerary.ts
CHANGED
|
@@ -301,34 +301,38 @@ export default class Itinerary {
|
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
toGeoJson(): FeatureCollection {
|
|
304
|
-
const transformToPoint = (point: Coordinates, name?: string): Feature<Point> => ({
|
|
304
|
+
const transformToPoint = (point: Coordinates, name?: string, type?: string): Feature<Point> => ({
|
|
305
305
|
type: "Feature",
|
|
306
|
-
properties: { name, level: point.level },
|
|
306
|
+
properties: { name, level: point.level, ...(type && { type }) },
|
|
307
307
|
geometry: {
|
|
308
308
|
type: 'Point',
|
|
309
309
|
coordinates: [point.lng, point.lat]
|
|
310
310
|
}
|
|
311
311
|
});
|
|
312
|
-
const transformToMultiLineStrings = (segments: Coordinates[][], level: Level_t): Feature<MultiLineString> => {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
coordinates: segments.map(s => s.map(({ lat, lng }) => [lng, lat]))
|
|
319
|
-
}
|
|
312
|
+
const transformToMultiLineStrings = (segments: Coordinates[][], level: Level_t): Feature<MultiLineString> => ({
|
|
313
|
+
type: "Feature",
|
|
314
|
+
properties: { level, name: level?.toString() },
|
|
315
|
+
geometry: {
|
|
316
|
+
type: 'MultiLineString',
|
|
317
|
+
coordinates: segments.map(s => s.map(({ lat, lng }) => [lng, lat]))
|
|
320
318
|
}
|
|
321
|
-
}
|
|
319
|
+
});
|
|
322
320
|
|
|
323
321
|
const levelsOfItinerary = [...new Set(this.coords.map(c => Level.toString(c.level)))].map(Level.fromString);
|
|
324
322
|
const segmentsSplitted: [Level_t, Coordinates[][]][] = levelsOfItinerary.map(loi => [loi, GeoUtils.createSegmentsAtLevel(this.coords, loi, true)]);
|
|
325
323
|
const multiLineStrings = segmentsSplitted.map(([loi, segments]) => transformToMultiLineStrings(segments, loi))
|
|
324
|
+
const legsStarts = this.legs.map((leg, idx) => transformToPoint(leg.start.coords, `Leg ${idx} start`, 'leg-start'));
|
|
325
|
+
const legsEnds = this.legs.map((leg, idx) => transformToPoint(leg.end.coords, `Leg ${idx} end`, 'leg-end'));
|
|
326
|
+
const steps = this.steps.map(step => transformToPoint(step.coords, `Step ${step.number}`, 'step'))
|
|
326
327
|
return {
|
|
327
328
|
type: "FeatureCollection",
|
|
328
329
|
features: [
|
|
329
|
-
transformToPoint(this.origin, 'origin'),
|
|
330
|
-
transformToPoint(this.destination, 'destination'),
|
|
331
|
-
...multiLineStrings
|
|
330
|
+
transformToPoint(this.origin, 'origin', 'origin'),
|
|
331
|
+
transformToPoint(this.destination, 'destination', 'destination'),
|
|
332
|
+
...multiLineStrings,
|
|
333
|
+
...legsStarts,
|
|
334
|
+
...legsEnds,
|
|
335
|
+
...steps
|
|
332
336
|
]
|
|
333
337
|
};
|
|
334
338
|
}
|
package/src/types.ts
CHANGED
|
@@ -190,17 +190,6 @@ class CustomNetworkMap {
|
|
|
190
190
|
return this.router.calculateShortestPathToMultipleDestinations(start, ends, options);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
get disabledEdges() { return this.router.disabledEdges }
|
|
194
|
-
|
|
195
|
-
enableEdge(edgeId: number) {
|
|
196
|
-
const edge = this.graph.edges.find(e => e.id === edgeId);
|
|
197
|
-
return Boolean(edge && this.router.disabledEdges.delete(edge));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
disableEdge(edgeId: number) {
|
|
201
|
-
const edge = this.graph.edges.find(e => e.id === edgeId);
|
|
202
|
-
return Boolean(edge && this.router.disabledEdges.add(edge));
|
|
203
|
-
}
|
|
204
193
|
}
|
|
205
194
|
|
|
206
195
|
export default CustomNetworkMap;
|
|
@@ -24,6 +24,7 @@ export default class OsmGraphUtils {
|
|
|
24
24
|
static parseNodeProperties(osmNode: OsmNode): VertexProperties {
|
|
25
25
|
return {
|
|
26
26
|
...(osmNode.name && { name: osmNode.name }),
|
|
27
|
+
...(osmNode.id && { externalId: osmNode.id }),
|
|
27
28
|
...(osmNode.isGate && { isGate: osmNode.isGate }),
|
|
28
29
|
...(osmNode.isSubwayEntrance && { isSubwayEntrance: osmNode.isSubwayEntrance }),
|
|
29
30
|
...(osmNode.subwayEntranceRef && { subwayEntrsanceRef: osmNode.subwayEntranceRef })
|
|
@@ -33,6 +34,7 @@ export default class OsmGraphUtils {
|
|
|
33
34
|
static parseWayProperties(osmWay: OsmWay): EdgeProperties {
|
|
34
35
|
return {
|
|
35
36
|
...(osmWay.name && { name: osmWay.name }),
|
|
37
|
+
...(osmWay.id && { externalId: osmWay.id }),
|
|
36
38
|
...(osmWay.isOneway && { isOneway: osmWay.isOneway }),
|
|
37
39
|
...(osmWay.areStairs && { areStairs: osmWay.areStairs }),
|
|
38
40
|
...(osmWay.isElevator && { isElevator: osmWay.isElevator }),
|
|
@@ -143,14 +145,14 @@ export default class OsmGraphUtils {
|
|
|
143
145
|
|
|
144
146
|
entryVertices.forEach(entryVertex => {
|
|
145
147
|
const vertexCenter = getOrCreateVertex(elevatorCenterFakeOsmNode, entryVertex.coords.level);
|
|
146
|
-
edges.push(new Edge(vertexCenter, entryVertex));
|
|
148
|
+
edges.push(new Edge(vertexCenter, entryVertex, { externalId: way.id }));
|
|
147
149
|
})
|
|
148
150
|
});
|
|
149
151
|
|
|
150
152
|
|
|
151
153
|
// 4. Link elevators vertices
|
|
152
|
-
elevatorVertices.forEach(([, name, verticesOfEachLevel]) => {
|
|
153
|
-
const elevatorEdgeProps = { name, isElevator: true };
|
|
154
|
+
elevatorVertices.forEach(([id, name, verticesOfEachLevel]) => {
|
|
155
|
+
const elevatorEdgeProps = { name, isElevator: true, externalId: id };
|
|
154
156
|
// Link vertices of each level together
|
|
155
157
|
for (let i = 0; i < verticesOfEachLevel.length; i++) {
|
|
156
158
|
for (let j = i + 1; j < verticesOfEachLevel.length; j++) {
|
|
@@ -265,3 +265,28 @@ describe('OsmRouter - getTrip', () => {
|
|
|
265
265
|
expect(router.getShortestTrip([p1, p2, p3, p4, p5, p6])).is.empty;
|
|
266
266
|
});
|
|
267
267
|
});
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
describe('OsmRouter - create graph components', () => {
|
|
271
|
+
|
|
272
|
+
const networkModel = loadGraph('components.osm');
|
|
273
|
+
const router = new GraphRouter(networkModel);
|
|
274
|
+
|
|
275
|
+
const arraysEqual = <T>(a: T[], b: T[]) => JSON.stringify(a.sort()) === JSON.stringify(b.sort());
|
|
276
|
+
const findComponent = (components: Vertex[][], vertexNames: string[]) =>
|
|
277
|
+
components.find(c => arraysEqual(c.map(v => v.properties.name), vertexNames))
|
|
278
|
+
|
|
279
|
+
it('createComponents()', () => {
|
|
280
|
+
const components = router.calculateComponents();
|
|
281
|
+
|
|
282
|
+
// console.log(JSON.stringify(components.map(c => c.map(v => v.properties.name)), null, 4));
|
|
283
|
+
expect(components.length).equal(6);
|
|
284
|
+
expect(findComponent(components, ['p1', 'p2', 'p3', 'p4'])).to.be.not.undefined;
|
|
285
|
+
expect(findComponent(components, ['p11', 'p12', 'p13'])).to.be.not.undefined;
|
|
286
|
+
expect(findComponent(components, ['p13', 'p14'])).to.be.not.undefined;
|
|
287
|
+
expect(findComponent(components, ['p21', 'p22'])).to.be.not.undefined;
|
|
288
|
+
expect(findComponent(components, ['p31', 'p32', 'p32', 'p33', 'p34'])).to.be.not.undefined;
|
|
289
|
+
expect(findComponent(components, ['p41', 'p42', 'p43', 'p44', 'p45', 'p46', 'p47', 'p48'])).to.be.not.undefined;
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
});
|