@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/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.0.0",
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": "90961b51b2bbbb32c4e7b64ddf19097e1d44a1df"
55
+ "gitHead": "6dda458e79cb7bc9bb63de3db2d000823672c3ca"
56
56
  }
package/src/graph/Edge.ts CHANGED
@@ -3,7 +3,10 @@ import { Level, type Level_t } from '@wemap/geo';
3
3
  import Vertex from './Vertex.js';
4
4
 
5
5
  export type EdgeProperties = {
6
+
6
7
  name?: string;
8
+ externalId?: string | number;
9
+
7
10
  isOneway?: boolean;
8
11
  areStairs?: boolean;
9
12
  isElevator?: boolean;
@@ -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
  }
@@ -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
  }
@@ -5,6 +5,7 @@ import { GraphVertexJson } from '../types.js';
5
5
  export type VertexProperties = {
6
6
 
7
7
  name?: string;
8
+ externalId?: string | number;
8
9
 
9
10
  isGate?: boolean;
10
11
  isSubwayEntrance?: boolean;
@@ -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
- return {
314
- type: "Feature",
315
- properties: { level, name: level?.toString() },
316
- geometry: {
317
- type: 'MultiLineString',
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
@@ -5,6 +5,7 @@ export type GraphVertexJson = CoordinatesCompressedJson;
5
5
 
6
6
  export type GeoGraphJson = {
7
7
  vertices: GraphVertexJson[],
8
+ verticesIds: (string | number)[],
8
9
  edges: (
9
10
  [number, number] |
10
11
  [number, number, EdgeProperties]
@@ -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
+ });
@@ -1,13 +0,0 @@
1
- // TODO: remove
2
- export type OsmRouterOptions = {
3
-
4
- useStairs?: boolean;
5
-
6
- useEscalators?: boolean;
7
-
8
- useElevators?: boolean;
9
-
10
- isTrip?: boolean;
11
-
12
- tspTempCoeff?: number;
13
- }