@wemap/osm 6.0.0 → 6.2.2

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.
@@ -1,8 +1,5 @@
1
- import { Level, Coordinates, GraphRouterOptions, GraphRouter, GraphUtils, Network, GraphEdge, GraphNode, MapMatching } from '@wemap/geo';
1
+ import { Level, Coordinates } from '@wemap/geo';
2
2
  import { SaxesParser } from 'saxes';
3
- import { deg2rad, diffAngle, positiveMod, rad2deg } from '@wemap/maths';
4
- import Polyline from '@mapbox/polyline';
5
- import Logger from '@wemap/logger';
6
3
 
7
4
  class OsmElement {
8
5
 
@@ -253,1760 +250,5 @@ class OsmParser {
253
250
  }
254
251
  }
255
252
 
256
- class OsmRouterOptions extends GraphRouterOptions {
257
-
258
- /** @type {OsmRouterOptions} */
259
- static DEFAULT = new OsmRouterOptions();
260
-
261
- /**
262
- * @returns {OsmRouterOptions}
263
- */
264
- static get WITHOUT_STAIRS() {
265
- const options = new OsmRouterOptions();
266
- options.acceptEdgeFn = edge => edge.builtFrom.tags.highway !== 'steps';
267
- return options;
268
- }
269
-
270
- /**
271
- * Get route duration
272
- * @param {Number} speed in km/h
273
- */
274
- static getDurationFromLength(length, speed = 5) {
275
- return length / (speed * 1000 / 3600);
276
- }
277
-
278
- /** @type {function(GraphEdge<OsmElement>):boolean} */
279
- weightEdgeFn = edge => edge.builtFrom.isElevator ? 30 : OsmRouterOptions.getDurationFromLength(edge.length);
280
-
281
-
282
- }
283
-
284
- class OsmRouter extends GraphRouter {
285
-
286
- /**
287
- * @param {!Network<OsmElement>} network
288
- */
289
- constructor(network) {
290
- super(network);
291
- }
292
-
293
- /**
294
- * @param {Coordinates} start
295
- * @param {Coordinates} end
296
- * @param {OsmRouterOptions} options
297
- * @returns {GraphItinerary<OsmElement>}
298
- */
299
- getShortestPath(start, end, options = new OsmRouterOptions()) {
300
- return super.getShortestPath(start, end, options);
301
- }
302
-
303
- }
304
-
305
- class LevelChange {
306
-
307
- /** @type {!string} [up|down] */
308
- direction;
309
-
310
- /** @type {!number} [-2, -1, 1, ...] */
311
- difference;
312
-
313
- /** @type {?string} [elevator|conveyor|stairs] */
314
- type = null;
315
-
316
- /**
317
- * @param {GraphNode<OsmElement>} firstNode
318
- * @param {GraphNode<OsmElement>} secondNode
319
- * @returns {LevelChange}
320
- */
321
- static fromTwoNodes(firstNode, secondNode) {
322
-
323
- const levelChange = new LevelChange();
324
-
325
- const edge = GraphUtils.getEdgeByNodes(firstNode.edges, firstNode, secondNode);
326
-
327
- if (edge.builtFrom.isElevator) {
328
- levelChange.type = 'elevator';
329
- } else if (edge.builtFrom.isConveying) {
330
- levelChange.type = 'conveyor';
331
- } else if (edge.builtFrom.areStairs) {
332
- levelChange.type = 'stairs';
333
- }
334
-
335
- levelChange.difference = Level.diff(firstNode.coords.level, secondNode.coords.level);
336
- levelChange.direction = levelChange.difference > 0 ? 'up' : 'down';
337
-
338
- return levelChange;
339
- }
340
-
341
- /**
342
- * @returns {object}
343
- */
344
- toJson() {
345
- return {
346
- direction: this.direction,
347
- difference: this.difference,
348
- type: this.type
349
- };
350
- }
351
-
352
- /**
353
- * @param {object} json
354
- * @returns {LevelChange}
355
- */
356
- static fromJson(json) {
357
- const levelChange = new LevelChange();
358
- levelChange.direction = json.direction;
359
- levelChange.difference = json.difference;
360
- levelChange.type = json.type;
361
- return levelChange;
362
- }
363
- }
364
-
365
- class Step {
366
-
367
- /** @type {!boolean} */
368
- firstStep = false;
369
-
370
- /** @type {!boolean} */
371
- lastStep = false;
372
-
373
- /** @type {!number} */
374
- number;
375
-
376
- /** @type {!Coordinates} */
377
- coords = [];
378
-
379
-
380
- /** @type {!number} */
381
- angle;
382
-
383
- /** @type {!number} */
384
- previousBearing;
385
-
386
- /** @type {!number} */
387
- nextBearing;
388
-
389
-
390
- /** @type {!number} */
391
- distance;
392
-
393
- /** @type {?number} */
394
- duration = null;
395
-
396
- /** @type {?string} */
397
- name = null;
398
-
399
-
400
- /** @type {?LevelChange} */
401
- levelChange = null;
402
-
403
- /** @type {?{?subwayEntrance: boolean, ?subwayEntranceRef: string}} */
404
- extras = {};
405
-
406
- /** @type {!number} */
407
- _idCoordsInLeg = null;
408
-
409
- /**
410
- * @returns {object}
411
- */
412
- toJson() {
413
- const output = {
414
- number: this.number,
415
- coords: this.coords.toCompressedJson(),
416
- angle: this.angle,
417
- previousBearing: this.previousBearing,
418
- nextBearing: this.nextBearing,
419
- distance: this.distance,
420
- _idCoordsInLeg: this._idCoordsInLeg
421
- };
422
- if (this.firstStep) {
423
- output.firstStep = true;
424
- }
425
- if (this.lastStep) {
426
- output.lastStep = true;
427
- }
428
- if (this.duration !== null) {
429
- output.duration = this.duration;
430
- }
431
- if (this.name !== null) {
432
- output.name = this.name;
433
- }
434
- if (this.levelChange !== null) {
435
- output.levelChange = this.levelChange.toJson();
436
- }
437
- if (this.extras && Object.keys(this.extras).length !== 0) {
438
- output.extras = this.extras;
439
- }
440
- return output;
441
- }
442
-
443
- /**
444
- * @param {object} json
445
- * @returns {Step}
446
- */
447
- static fromJson(json) {
448
- const step = new Step();
449
- step.number = json.number;
450
- step.coords = Coordinates.fromCompressedJson(json.coords);
451
- step.angle = json.angle;
452
- step.previousBearing = json.previousBearing;
453
- step.nextBearing = json.nextBearing;
454
- step.distance = json.distance;
455
- step._idCoordsInLeg = json._idCoordsInLeg;
456
- if (json.firstStep) {
457
- step.firstStep = json.firstStep;
458
- }
459
- if (json.lastStep) {
460
- step.lastStep = json.lastStep;
461
- }
462
- if (json.duration) {
463
- step.duration = json.duration;
464
- }
465
- if (json.name) {
466
- step.name = json.name;
467
- }
468
- if (json.levelChange) {
469
- step.levelChange = LevelChange.fromJson(json.levelChange);
470
- }
471
- if (json.extras) {
472
- step.extras = json.extras;
473
- }
474
- return step;
475
- }
476
- }
477
-
478
- class Leg {
479
-
480
- /** @type {!string} can be WALK, BIKE, BUS, TRAM, CAR, FUNICULAR */
481
- mode;
482
-
483
- /** @type {!number} */
484
- distance;
485
-
486
- /** @type {!number} */
487
- duration;
488
-
489
- /** @type {?number} */
490
- startTime = null;
491
-
492
- /** @type {?number} */
493
- endTime = null;
494
-
495
- /** @type {!{name: ?string, coords: !Coordinates}} */
496
- from;
497
-
498
- /** @type {!{name: ?string, coords: !Coordinates}} */
499
- to;
500
-
501
- /** @type {!Coordinates[]} */
502
- coords;
503
-
504
- /** @type {?{name: !string, routeColor: ?string, routeTextColor: ?string, directionName: ?string}} */
505
- transportInfo = null;
506
-
507
- /** @type {?(Step[])} */
508
- steps = null;
509
-
510
- /**
511
- * @returns {Network}
512
- */
513
- toNetwork() {
514
- return Network.fromCoordinates([this.coords]);
515
- }
516
-
517
- /**
518
- * @returns {object}
519
- */
520
- toJson() {
521
- const output = {
522
- mode: this.mode,
523
- from: { coords: this.from.coords.toCompressedJson() },
524
- to: { coords: this.to.coords.toCompressedJson() },
525
- distance: this.distance,
526
- duration: this.duration,
527
- coords: this.coords.map(coords => coords.toCompressedJson())
528
- };
529
- if (this.from.name) {
530
- output.from.name = this.from.name;
531
- }
532
- if (this.to.name) {
533
- output.to.name = this.to.name;
534
- }
535
- if (this.startTime !== null) {
536
- output.startTime = this.startTime;
537
- }
538
- if (this.endTime !== null) {
539
- output.endTime = this.endTime;
540
- }
541
- if (this.transportInfo !== null) {
542
- output.transportInfo = this.transportInfo;
543
- }
544
- if (this.steps !== null && this.steps.length > 0) {
545
- output.steps = this.steps.map(step => step.toJson());
546
- }
547
- return output;
548
- }
549
-
550
-
551
- /**
552
- * @param {object} json
553
- * @returns {Leg}
554
- */
555
- static fromJson(json) {
556
- const leg = new Leg();
557
- leg.mode = json.mode;
558
- leg.from = { coords: Coordinates.fromCompressedJson(json.from.coords) };
559
- leg.to = { coords: Coordinates.fromCompressedJson(json.to.coords) };
560
- leg.distance = json.distance;
561
- leg.duration = json.duration;
562
- leg.coords = json.coords.map(Coordinates.fromCompressedJson);
563
- if (json.from.name) {
564
- leg.from.name = json.from.name;
565
- }
566
- if (json.to.name) {
567
- leg.to.name = json.to.name;
568
- }
569
- if (json.startTime) {
570
- leg.startTime = json.startTime;
571
- }
572
- if (json.endTime) {
573
- leg.endTime = json.endTime;
574
- }
575
- if (json.transportInfo) {
576
- leg.transportInfo = json.transportInfo;
577
- }
578
- if (json.steps) {
579
- leg.steps = json.steps.map(Step.fromJson);
580
- }
581
- return leg;
582
- }
583
-
584
- }
585
-
586
- /* eslint-disable max-statements */
587
-
588
- /**
589
- * Main attributes are:
590
- * nodes: the ordered list of Node
591
- * edges: the ordered list of Edge
592
- * start: the start point (Coordinates)
593
- * end: the end point (Coordinates)
594
- * length: the route length
595
- */
596
- class Itinerary {
597
-
598
- /** @type {!Coordinates} */
599
- from;
600
-
601
- /** @type {!Coordinates} */
602
- to;
603
-
604
- /** @type {!number} */
605
- distance;
606
-
607
- /** @type {!number} */
608
- duration;
609
-
610
- /** @type {?number} */
611
- startTime = null;
612
-
613
- /** @type {?number} */
614
- endTime = null;
615
-
616
- /** @type {!(Leg[])} */
617
- legs = [];
618
-
619
- /** @type {?Coordinates[]} */
620
- _coords = null;
621
-
622
- set coords(_) {
623
- throw new Error('Itinerary.coords cannot be set. They are calculated from Itinerary.legs.');
624
- }
625
-
626
- /** @type {!(Coordinates[])} */
627
- get coords() {
628
- if (!this._coords) {
629
- // Returns the coordinates contained in all legs and remove duplicates between array
630
- this._coords = this.legs.reduce((acc, val) => {
631
- const isDuplicate = acc.length && val.coords.length && acc[acc.length - 1].equalsTo(val.coords[0]);
632
- acc.push(...val.coords.slice(isDuplicate ? 1 : 0));
633
- return acc;
634
- }, []);
635
- }
636
- return this._coords;
637
- }
638
-
639
- set steps(_) {
640
- throw new Error('Itinerary.step cannot be set. They are calculated from Itinerary.legs.');
641
- }
642
-
643
- /** @type {!(Step[])} */
644
- get steps() {
645
- return this.legs.map(leg => leg.steps).flat();
646
- }
647
-
648
- /**
649
- * @returns {Network}
650
- */
651
- toNetwork() {
652
- return Network.fromCoordinates([this.coords]);
653
- }
654
-
655
- /**
656
- * @param {Itinerary[]} itineraries
657
- * @returns {Itinerary}
658
- */
659
- static fromItineraries(...itineraries) {
660
- const itinerary = new Itinerary();
661
- itinerary.from = itineraries[0].from;
662
- itinerary.to = itineraries[itineraries.length - 1].to;
663
- itinerary.distance = 0;
664
- itinerary.duration = 0;
665
- itinerary.legs = [];
666
-
667
- itineraries.forEach(_itinerary => {
668
- itinerary.distance += _itinerary.distance;
669
- itinerary.duration += _itinerary.duration;
670
- itinerary.legs.push(..._itinerary.legs);
671
- itinerary.legs.forEach(leg => {
672
- leg.steps[0].firstStep = false;
673
- leg.steps[leg.steps.length - 1].lastStep = false;
674
- });
675
- });
676
-
677
- itinerary.legs[0].steps[0].firstStep = true;
678
- const lastLeg = itinerary.legs[itinerary.legs.length - 1];
679
- lastLeg.steps[lastLeg.steps.length - 1].lastStep = true;
680
-
681
- return itinerary;
682
- }
683
-
684
- /**
685
- * Convert lat/lng/level points to Itinerary
686
- * @param {number[][]} points 2D points array of lat/lng/level (level is optional)
687
- * @param {Coordinates} from
688
- * @param {Coordinates} to
689
- * @param {string} mode
690
- * @returns {Itinerary}
691
- */
692
- static fromOrderedPointsArray(points, start, end) {
693
-
694
- const pointToCoordinates = point => new Coordinates(point[0], point[1], null, point[2]);
695
-
696
- return this.fromOrderedCoordinates(
697
- points.map(pointToCoordinates),
698
- pointToCoordinates(start),
699
- pointToCoordinates(end)
700
- );
701
- }
702
-
703
- /**
704
- * Convert ordered Coordinates to Itinerary
705
- * @param {Coordinates[]} points
706
- * @param {Coordinates} from
707
- * @param {Coordinates} to
708
- * @param {string} mode
709
- * @returns {Itinerary}
710
- */
711
- static fromOrderedCoordinates(points, from, to, mode = 'WALK') {
712
-
713
- const itinerary = new Itinerary();
714
- itinerary.from = from;
715
- itinerary.to = to;
716
-
717
- const leg = new Leg();
718
- leg.mode = mode;
719
- leg.from = from;
720
- leg.to = to;
721
-
722
- leg.coords = points;
723
- leg.distance = points.reduce((acc, coords, idx, arr) => {
724
- if (idx !== 0) {
725
- return acc + arr[idx - 1].distanceTo(coords);
726
- }
727
- return acc;
728
- }, 0);
729
- leg.duration = leg.distance;
730
- itinerary.legs.push(leg);
731
-
732
- itinerary.distance = leg.distance;
733
- itinerary.duration = leg.duration;
734
-
735
- return itinerary;
736
- }
737
-
738
- /**
739
- * @returns {object}
740
- */
741
- toJson() {
742
- const output = {
743
- from: this.from.toCompressedJson(),
744
- to: this.to.toCompressedJson(),
745
- distance: this.distance,
746
- duration: this.duration,
747
- legs: this.legs.map(leg => leg.toJson())
748
- };
749
- if (this.startTime !== null) {
750
- output.startTime = this.startTime;
751
- }
752
- if (this.endTime !== null) {
753
- output.endTime = this.endTime;
754
- }
755
- return output;
756
- }
757
-
758
- /**
759
- * @param {object} json
760
- * @returns {Itinerary}
761
- */
762
- static fromJson(json) {
763
- const itinerary = new Itinerary();
764
- itinerary.from = Coordinates.fromCompressedJson(json.from);
765
- itinerary.to = Coordinates.fromCompressedJson(json.to);
766
- itinerary.distance = json.distance;
767
- itinerary.duration = json.duration;
768
- itinerary.legs = json.legs.map(Leg.fromJson);
769
- if (json.startTime) {
770
- itinerary.startTime = json.startTime;
771
- }
772
- if (json.endTime) {
773
- itinerary.endTime = json.endTime;
774
- }
775
- return itinerary;
776
- }
777
- }
778
-
779
- /* eslint-disable complexity */
780
-
781
- const SKIP_STEP_ANGLE_MAX = deg2rad(20);
782
-
783
- class StepsGeneration {
784
-
785
- /**
786
- * @param {GraphItinerary<OsmElement>} itinerary
787
- * @returns {Step[]}
788
- */
789
- static fromGraphItinerary(itinerary) {
790
-
791
- const steps = [];
792
-
793
- const { start, end, nodes, edges } = itinerary;
794
-
795
- let currentStep, previousStep;
796
- let previousBearing = start.bearingTo(nodes[0].coords);
797
-
798
- for (let i = 0; i < nodes.length - 1; i++) {
799
-
800
- const isFirstStep = !currentStep;
801
-
802
- const node = nodes[i];
803
- const nextNode = nodes[i + 1];
804
- const edge = edges[i];
805
-
806
- const bearing = edge.bearing;
807
- const angle = diffAngle(previousBearing, bearing + Math.PI);
808
-
809
- let splitByAngle = Math.abs(diffAngle(Math.PI, angle)) >= SKIP_STEP_ANGLE_MAX;
810
-
811
- const splitByLevel = edge.level && edge.level.isRange
812
- && node.coords.level && !node.coords.level.isRange;
813
- splitByAngle = splitByAngle && !(node.coords.level && node.coords.level.isRange);
814
-
815
- const splitStepCondition = splitByAngle || splitByLevel;
816
-
817
- const isSubwayEntrance = node ? node.builtFrom.tags.railway === 'subway_entrance' : false;
818
-
819
- // New step creation
820
- if (isFirstStep || splitStepCondition || isSubwayEntrance) {
821
-
822
- previousStep = currentStep;
823
-
824
- currentStep = new Step();
825
- currentStep.coords = node.coords;
826
- currentStep.number = steps.length + 1;
827
- currentStep.angle = angle;
828
- currentStep.previousBearing = previousBearing;
829
- currentStep.nextBearing = bearing;
830
- currentStep.name = edge.builtFrom.tags.name || null;
831
- currentStep.distance = 0;
832
- currentStep.duration = 0;
833
-
834
- if (isSubwayEntrance) {
835
- currentStep.extras.subwayEntrance = true;
836
- currentStep.name = node.builtFrom.tags.name;
837
- if (node.builtFrom.tags.ref) {
838
- currentStep.extras.subwayEntranceRef = node.builtFrom.tags.ref;
839
- }
840
- }
841
-
842
- if (splitByLevel) {
843
- currentStep.levelChange = LevelChange.fromTwoNodes(node, nextNode);
844
- }
845
-
846
- steps.push(currentStep);
847
-
848
- if (!previousStep) {
849
- currentStep.firstStep = true;
850
- }
851
- }
852
-
853
- currentStep.distance += edge.length;
854
- currentStep.duration += itinerary.edgesWeights[i];
855
- previousBearing = bearing;
856
- }
857
-
858
- const lastNode = nodes[nodes.length - 1];
859
- const lastStep = new Step();
860
- lastStep.coords = lastNode.coords;
861
- lastStep.number = steps.length + 1;
862
- lastStep.previousBearing = previousBearing;
863
- lastStep.distance = lastNode.coords.distanceTo(end);
864
- if (!Coordinates.equalsTo(lastNode.coords, end)) {
865
- lastStep.nextBearing = lastNode.coords.bearingTo(end);
866
- lastStep.angle = diffAngle(lastStep.previousBearing, lastStep.nextBearing + Math.PI);
867
- }
868
- lastStep.lastStep = true;
869
- steps.push(lastStep);
870
-
871
- return steps;
872
- }
873
-
874
- }
875
-
876
- /**
877
- * @param {GraphItinerary<OsmElement>} graphItinerary
878
- * @param {string} mode
879
- * @returns {Leg}
880
- */
881
- function createLegFromGraphItinerary(graphItinerary, mode = 'WALK') {
882
-
883
- const leg = new Leg();
884
-
885
- leg.from = { coords: graphItinerary.start };
886
- leg.to = { coords: graphItinerary.end };
887
- leg.coords = graphItinerary.nodes.map(node => node.coords);
888
- leg.distance = graphItinerary.edges.reduce((acc, edge) => acc + edge.length, 0);
889
- leg.duration = graphItinerary.edgesWeights.reduce((acc, weight) => acc + weight, 0);
890
- leg.mode = mode;
891
- leg.steps = StepsGeneration.fromGraphItinerary(graphItinerary);
892
-
893
- return leg;
894
- }
895
-
896
- /**
897
- * @param {GraphItinerary<OsmElement>} graphItinerary
898
- * @param {string} mode
899
- * @returns {Itinerary}
900
- */
901
- function createItineraryFromGraphItinerary(graphItinerary, mode = 'WALK') {
902
-
903
- const leg = createLegFromGraphItinerary(graphItinerary, mode);
904
-
905
- const itinerary = new Itinerary();
906
-
907
- itinerary.from = graphItinerary.start;
908
- itinerary.to = graphItinerary.end;
909
- itinerary.distance = leg.distance;
910
- itinerary.duration = leg.duration;
911
- itinerary.legs.push(leg);
912
-
913
- return itinerary;
914
- }
915
-
916
- var OsmRouterUtils = /*#__PURE__*/Object.freeze({
917
- __proto__: null,
918
- createLegFromGraphItinerary: createLegFromGraphItinerary,
919
- createItineraryFromGraphItinerary: createItineraryFromGraphItinerary
920
- });
921
-
922
- const HIGHWAYS_PEDESTRIANS = ['footway', 'steps', 'pedestrian', 'living_street', 'path', 'track', 'sidewalk'];
923
-
924
- const DEFAULT_WAY_SELECTOR = way => {
925
- return HIGHWAYS_PEDESTRIANS.includes(way.tags.highway)
926
- || way.tags.footway === 'sidewalk'
927
- || way.tags.public_transport === 'platform'
928
- || way.tags.railway === 'platform';
929
- };
930
-
931
- /**
932
- * @param {Network<OsmElement>} network
933
- * @param {string} name
934
- */
935
- function getNodeByName(network, name) {
936
- return network.nodes.find(({ builtFrom }) => builtFrom.tags.name === name);
937
- }
938
-
939
- /**
940
- * @param {Network<OsmElement>} network
941
- * @param {string} name
942
- */
943
- function getEdgeByName(network, name) {
944
- return network.edges.find(({ builtFrom }) => builtFrom.tags.name === name);
945
- }
946
-
947
- /**
948
- * @param {GraphEdge<OsmElement>} edge
949
- * @param {OsmWay} way
950
- * @returns {boolean}
951
- */
952
- function manageOneWay(edge, way) {
953
-
954
- const { highway, oneway, conveying } = way.tags;
955
-
956
- edge.isOneway = Boolean((oneway === 'yes' || oneway === 'true' || oneway === '1')
957
- || (conveying && highway && ['yes', 'forward', 'backward'].includes(conveying)));
958
-
959
- if (edge.isOneway && conveying === 'backward') {
960
- const tmpNode = edge.node1;
961
- edge.node1 = edge.node2;
962
- edge.node2 = tmpNode;
963
- }
964
- }
965
-
966
- /**
967
- * @param {Network} networkModel
968
- * @param {GraphNode} node
969
- */
970
- function createNodesAndEdgesFromElevator(networkModel, node) {
971
-
972
- /** @type {GraphNode[]} */
973
- const createdNodes = [];
974
- const getOrCreateLevelNode = (level, builtFrom) => {
975
- let levelNode = createdNodes.find(({ coords }) => Level.equalsTo(level, coords.level));
976
- if (!levelNode) {
977
- levelNode = new GraphNode(node.coords.clone(), builtFrom);
978
- levelNode.coords.level = level;
979
- createdNodes.push(levelNode);
980
- networkModel.nodes.push(levelNode);
981
- }
982
- return levelNode;
983
- };
984
-
985
- // Create nodes from node.edges
986
- node.edges.forEach(edge => {
987
- if (edge.level.isRange) {
988
- throw new Error('Cannot handle this elevator edge due to ambiguity');
989
- }
990
-
991
- const levelNode = getOrCreateLevelNode(edge.level, node.builtFrom);
992
- if (edge.node1 === node) {
993
- edge.node1 = levelNode;
994
- } else {
995
- edge.node2 = levelNode;
996
- }
997
- levelNode.edges.push(edge);
998
- });
999
-
1000
- // Create edges from createdNodes
1001
- for (let i = 0; i < createdNodes.length; i++) {
1002
- for (let j = i + 1; j < createdNodes.length; j++) {
1003
-
1004
- const createdNode1 = createdNodes[i];
1005
- const createdNode2 = createdNodes[j];
1006
-
1007
- const newEdge = new GraphEdge(
1008
- createdNode1,
1009
- createdNode2,
1010
- new Level(createdNode1.coords.level.val, createdNode2.coords.level.val),
1011
- node.builtFrom
1012
- );
1013
- networkModel.edges.push(newEdge);
1014
- }
1015
- }
1016
-
1017
- // Remove the historical elevator node from the network
1018
- networkModel.nodes = networkModel.nodes.filter(_node => _node !== node);
1019
- }
1020
-
1021
-
1022
- /**
1023
- * @param {OsmModel} osmModel
1024
- * @param {function} _waySelectionFilter
1025
- * @returns {Network<OsmElement>}
1026
- */
1027
- function createNetworkFromOsmModel(
1028
- osmModel,
1029
- waySelectionFilter = DEFAULT_WAY_SELECTOR
1030
- ) {
1031
-
1032
- const networkModel = new Network();
1033
-
1034
- const nodesCreated = {};
1035
- const elevatorNodes = [];
1036
-
1037
- /**
1038
- * @param {OsmNode} osmNode
1039
- */
1040
- const getOrCreateNode = osmNode => {
1041
- let node = nodesCreated[osmNode.id];
1042
- if (!node) {
1043
- node = new GraphNode(osmNode.coords, osmNode);
1044
- nodesCreated[osmNode.id] = node;
1045
- networkModel.nodes.push(node);
1046
-
1047
- if (osmNode.tags.highway === 'elevator') {
1048
- elevatorNodes.push(node);
1049
- }
1050
- }
1051
- return node;
1052
- };
1053
-
1054
- osmModel.ways.forEach(way => {
1055
- if (!waySelectionFilter(way)) {
1056
- return;
1057
- }
1058
-
1059
- let firstNode = getOrCreateNode(way.nodes[0]);
1060
- for (let i = 1; i < way.nodes.length; i++) {
1061
- const secondNode = getOrCreateNode(way.nodes[i]);
1062
-
1063
- const edge = new GraphEdge(firstNode, secondNode, way.level, way);
1064
- manageOneWay(edge, way);
1065
- networkModel.edges.push(edge);
1066
- firstNode = secondNode;
1067
- }
1068
-
1069
- });
1070
-
1071
- elevatorNodes.forEach(node => {
1072
- // We have to clone this node for each connected edge
1073
- createNodesAndEdgesFromElevator(networkModel, node);
1074
- });
1075
-
1076
- GraphNode.generateNodesLevels(networkModel.nodes);
1077
-
1078
- return networkModel;
1079
- }
1080
-
1081
-
1082
- // /**
1083
- // * @param {GraphNode} node
1084
- // * @param {object} tags
1085
- // */
1086
- // static _applyNodePropertiesFromTags(node, tags) {
1087
- // node.name = tags.name || null;
1088
- // node.subwayEntrance = tags.railway === 'subway_entrance';
1089
- // if (node.subwayEntrance && tags.ref) {
1090
- // node.subwayEntranceRef = tags.ref;
1091
- // }
1092
- // }
1093
-
1094
- // /**
1095
- // * @param {GraphEdge} edge
1096
- // * @param {object} tags
1097
- // */
1098
- // static _applyEdgePropertiesFromTags(edge, tags) {
1099
- // const { highway, oneway, conveying, name } = tags;
1100
- // edge.name = name || null;
1101
- // edge.isStairs = highway === 'steps';
1102
- // edge.isConveying = 'conveying' in tags;
1103
- // edge.isOneway = Boolean((oneway === 'yes' || oneway === 'true' || oneway === '1')
1104
- // || (conveying && highway && ['yes', 'forward', 'backward'].includes(conveying)));
1105
-
1106
- // if (conveying === 'backward') {
1107
- // const tmpNode = edge.node1;
1108
- // edge.node1 = edge.node2;
1109
- // edge.node2 = tmpNode;
1110
- // }
1111
-
1112
- // }
1113
-
1114
- var OsmNetworkUtils = /*#__PURE__*/Object.freeze({
1115
- __proto__: null,
1116
- HIGHWAYS_PEDESTRIANS: HIGHWAYS_PEDESTRIANS,
1117
- DEFAULT_WAY_SELECTOR: DEFAULT_WAY_SELECTOR,
1118
- getNodeByName: getNodeByName,
1119
- getEdgeByName: getEdgeByName,
1120
- createNetworkFromOsmModel: createNetworkFromOsmModel
1121
- });
1122
-
1123
- class RouterResponse {
1124
-
1125
- /** @type {!string} */
1126
- routerName;
1127
-
1128
- /** @type {!Coordinates} */
1129
- from;
1130
-
1131
- /** @type {!Coordinates} */
1132
- to;
1133
-
1134
- /** @type {!(Itinerary[])} */
1135
- itineraries = [];
1136
- }
1137
-
1138
- /**
1139
- * @param {Itinerary} itinerary
1140
- */
1141
- function generateStepsMetadata(itinerary) {
1142
-
1143
- let counter = 1;
1144
-
1145
- itinerary.legs.forEach((leg, legId) => {
1146
- leg.steps.forEach((step, stepId) => {
1147
-
1148
- if (counter === 1) {
1149
- step.firstStep = true;
1150
- }
1151
- if (legId === itinerary.legs.length - 1
1152
- && stepId === leg.steps.length - 1) {
1153
- step.lastStep = true;
1154
- }
1155
-
1156
- step.number = counter++;
1157
-
1158
-
1159
- /*
1160
- * Generate previousBearing, nextBearing and angle
1161
- */
1162
-
1163
- let coordsBeforeStep;
1164
- if (step._idCoordsInLeg > 0) {
1165
- coordsBeforeStep = leg.coords[step._idCoordsInLeg - 1];
1166
- } else if (legId === 0) {
1167
- coordsBeforeStep = itinerary.from;
1168
- } else {
1169
- coordsBeforeStep = itinerary.legs[legId - 1].to.coords;
1170
- }
1171
-
1172
- let coordsAfterStep;
1173
- if (step._idCoordsInLeg !== leg.coords.length - 1) {
1174
- coordsAfterStep = leg.coords[step._idCoordsInLeg + 1];
1175
- } else if (legId === itinerary.legs.length - 1) {
1176
- coordsAfterStep = itinerary.to;
1177
- } else {
1178
- coordsAfterStep = itinerary.legs[legId + 1].from.coords;
1179
- }
1180
-
1181
- step.previousBearing = coordsBeforeStep.bearingTo(step.coords);
1182
- step.nextBearing = step.coords.bearingTo(coordsAfterStep);
1183
- step.angle = diffAngle(step.previousBearing, step.nextBearing + Math.PI);
1184
-
1185
- });
1186
- });
1187
- }
1188
-
1189
- /* eslint-disable max-statements */
1190
-
1191
- /**
1192
- * @param {Coordinates} coordinates
1193
- * @returns {object}
1194
- */
1195
- function coordinatesToJson(coordinates) {
1196
- const output = [coordinates.lng, coordinates.lat];
1197
- if (coordinates.level) {
1198
- output.push(coordinates.level.toString());
1199
- }
1200
- return output;
1201
- }
1202
-
1203
- /**
1204
- * @param {object} json
1205
- * @returns {Coordinates}
1206
- */
1207
- function jsonToCoordinates$2(json) {
1208
- const output = new Coordinates(json[1], json[0]);
1209
- if (json.length > 2) {
1210
- output.level = Level.fromString(json[2]);
1211
- }
1212
- return output;
1213
- }
1214
-
1215
- function nodesToJsonCoords(nodes) {
1216
- return nodes.map(node => coordinatesToJson(node.coords));
1217
- }
1218
-
1219
-
1220
- function getModifierFromAngle(_angle) {
1221
-
1222
- const angle = positiveMod(rad2deg(_angle), 360);
1223
-
1224
- if (angle > 0 && angle < 60) {
1225
- return 'sharp right';
1226
- }
1227
- if (angle >= 60 && angle < 140) {
1228
- return 'right';
1229
- }
1230
- if (angle >= 140 && angle < 160) {
1231
- return 'slight right';
1232
- }
1233
- if (angle >= 160 && angle <= 200) {
1234
- return 'straight';
1235
- }
1236
- if (angle > 200 && angle <= 220) {
1237
- return 'slight left';
1238
- }
1239
- if (angle > 220 && angle <= 300) {
1240
- return 'left';
1241
- }
1242
- if (angle > 300 && angle < 360) {
1243
- return 'sharp left';
1244
- }
1245
- return 'u turn';
1246
- }
1247
-
1248
-
1249
- function noRouteFoundJson(message) {
1250
- return {
1251
- 'code': 'NoRoute',
1252
- message
1253
- };
1254
- }
1255
-
1256
- /**
1257
- * @param {Itinerary} itinerary
1258
- * @returns {object}
1259
- */
1260
- function itineraryToOsrmJson(itinerary) {
1261
-
1262
- const lastLegId = itinerary.legs.length - 1;
1263
-
1264
- const jsonLegs = itinerary.legs.map(({ distance, duration, coords, steps }, idLeg) => {
1265
-
1266
- const lastStepId = steps.length - 1;
1267
-
1268
- return {
1269
- distance,
1270
- duration,
1271
- steps: steps.map((step, idStep, arr) => {
1272
-
1273
- let type = idStep === 0 && idLeg === 0 ? 'depart' : 'turn';
1274
- type = idStep === lastStepId && idLeg === lastLegId ? 'arrive' : type;
1275
-
1276
- const stepCoordsIdx = coords.findIndex(p => p.equalsTo(step.coords));
1277
- const nextStepCoordsIdx = idStep === lastStepId
1278
- ? stepCoordsIdx
1279
- : coords.findIndex(p => p.equalsTo(arr[idStep + 1].coords));
1280
-
1281
- const jsonStep = {
1282
- geometry: {
1283
- type: 'LineString',
1284
- coordinates: coords.slice(stepCoordsIdx, nextStepCoordsIdx + 1).map(coordinatesToJson)
1285
- },
1286
- distance: step.distance,
1287
- duration: step.duration,
1288
- name: step.name,
1289
- maneuver: {
1290
- bearing_before: rad2deg(step.previousBearing),
1291
- bearing_after: rad2deg(step.nextBearing),
1292
- location: coordinatesToJson(step.coords),
1293
- modifier: getModifierFromAngle(step.angle),
1294
- type
1295
- }
1296
- };
1297
- if (step.levelChange !== null) {
1298
- jsonStep.levelChange = step.levelChange.toJson();
1299
- }
1300
- if (typeof step.extras === 'object' && Object.keys(step.extras).length !== 0) {
1301
- jsonStep.extras = step.extras;
1302
- }
1303
-
1304
- return jsonStep;
1305
- })
1306
- };
1307
- });
1308
-
1309
- return {
1310
- 'code': 'Ok',
1311
- 'routes': [
1312
- {
1313
- 'geometry': {
1314
- 'type': 'LineString',
1315
- 'coordinates': itinerary.coords.map(coordinatesToJson)
1316
- },
1317
- 'legs': jsonLegs,
1318
- 'distance': itinerary.distance,
1319
- 'duration': itinerary.duration,
1320
- 'weight_name': 'routability',
1321
- 'weight': 0
1322
- }
1323
- ],
1324
- 'waypoints': []
1325
- };
1326
- }
1327
-
1328
-
1329
- /**
1330
- * @param {object} jsonSteps
1331
- * @param {Coordinates[]} legCoords
1332
- * @returns {Step[]}
1333
- */
1334
- function parseJsonSteps$1(jsonSteps, legCoords) {
1335
-
1336
- if (!jsonSteps) {
1337
- return [];
1338
- }
1339
-
1340
- return jsonSteps.map(jsonStep => {
1341
-
1342
- const step = new Step();
1343
- step.coords = jsonToCoordinates$2(jsonStep.maneuver.location);
1344
-
1345
- // Sometimes, OSRM step does not have the same coordinates than a point in legCoords.
1346
- // ex: first step of https://routing.getwemap.com/route/v1/walking/2.33222164147,48.87084765712;2.3320734,48.8730212?geometries=geojson&overview=full&steps=true
1347
- // That is why we look for the closest point.
1348
- const distances = legCoords.map(coords => coords.distanceTo(step.coords));
1349
- const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
1350
- if (idStepCoordsInLeg < 0) {
1351
- throw new Error('Osrm Parser: Cannot find step coords in leg coordinates');
1352
- }
1353
- step._idCoordsInLeg = idStepCoordsInLeg;
1354
-
1355
- step.name = jsonStep.name;
1356
- step.levelChange = jsonStep.levelChange ? LevelChange.fromJson(jsonStep.levelChange) : null;
1357
-
1358
- step.distance = jsonStep.distance;
1359
- step.duration = jsonStep.duration;
1360
-
1361
- if (jsonStep.extras && jsonStep.extras.subwayEntrance) {
1362
- step.extras.subwayEntrance = true;
1363
- if (jsonStep.extras.subwayEntranceRef) {
1364
- step.extras.subwayEntranceRef = jsonStep.extras.subwayEntranceRef;
1365
- }
1366
- }
1367
-
1368
- return step;
1369
- });
1370
- }
1371
-
1372
-
1373
- /**
1374
- * Generate multi itineraries from OSRM JSON
1375
- * @param {object} json JSON file provided by OSRM.
1376
- * @param {Coordinates} from itinerary start
1377
- * @param {Coordinates} to itinerary end
1378
- * @param {?string} routingMode [walking|driving|bicycle]
1379
- * @returns {?RouterResponse}
1380
- */
1381
- function createRouterResponseFromJson$2(json, from, to, routingMode = 'walking') {
1382
-
1383
- const { routes: jsonRoutes } = json;
1384
-
1385
- if (!jsonRoutes) {
1386
- return null;
1387
- }
1388
-
1389
- const routingModeCorrespondance = new Map();
1390
- routingModeCorrespondance.set('walking', 'WALK');
1391
- routingModeCorrespondance.set('driving', 'CAR');
1392
- routingModeCorrespondance.set('bicycle', 'BIKE');
1393
- const mode = routingModeCorrespondance.get(routingMode) || null;
1394
-
1395
- const routerResponse = new RouterResponse();
1396
- routerResponse.routerName = 'osrm';
1397
-
1398
- routerResponse.from = from;
1399
- routerResponse.to = to;
1400
-
1401
- for (const jsonItinerary of jsonRoutes) {
1402
-
1403
- const itinerary = new Itinerary();
1404
-
1405
- // itinerary.coords = jsonItinerary.geometry.coordinates.map(jsonToCoordinates);
1406
- itinerary.distance = jsonItinerary.distance;
1407
- itinerary.duration = jsonItinerary.duration;
1408
- itinerary.from = from;
1409
- itinerary.to = to;
1410
-
1411
- routerResponse.itineraries.push(itinerary);
1412
-
1413
- for (const jsonLeg of jsonItinerary.legs) {
1414
-
1415
- const leg = new Leg();
1416
-
1417
- leg.mode = mode;
1418
- leg.distance = jsonLeg.distance;
1419
- leg.duration = jsonLeg.duration;
1420
-
1421
- leg.coords = jsonLeg.steps
1422
- .map(step => step.geometry.coordinates.map(jsonToCoordinates$2))
1423
- .flat()
1424
- // Remove duplicates
1425
- .filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equalsTo(coords));
1426
-
1427
- leg.from = {
1428
- name: null,
1429
- coords: leg.coords[0]
1430
- };
1431
- leg.to = {
1432
- name: null,
1433
- coords: leg.coords[leg.coords.length - 1]
1434
- };
1435
-
1436
- leg.steps = parseJsonSteps$1(jsonLeg.steps, leg.coords);
1437
-
1438
- itinerary.legs.push(leg);
1439
- }
1440
-
1441
- // All legs have to be parsed before computing steps metadata
1442
- generateStepsMetadata(itinerary);
1443
-
1444
- }
1445
-
1446
- return routerResponse;
1447
- }
1448
-
1449
- var OsrmUtils = /*#__PURE__*/Object.freeze({
1450
- __proto__: null,
1451
- coordinatesToJson: coordinatesToJson,
1452
- jsonToCoordinates: jsonToCoordinates$2,
1453
- nodesToJsonCoords: nodesToJsonCoords,
1454
- getModifierFromAngle: getModifierFromAngle,
1455
- noRouteFoundJson: noRouteFoundJson,
1456
- itineraryToOsrmJson: itineraryToOsrmJson,
1457
- createRouterResponseFromJson: createRouterResponseFromJson$2
1458
- });
1459
-
1460
- /* eslint-disable max-statements */
1461
-
1462
- /**
1463
- * @param {object} json
1464
- * @returns {Coordinates}
1465
- */
1466
- function jsonToCoordinates$1(json) {
1467
- return new Coordinates(json.lat, json.lon);
1468
- }
1469
-
1470
- /**
1471
- * @param {object} jsonSteps
1472
- * @param {Coordinates[]} legCoords
1473
- * @returns {Step[]}
1474
- */
1475
- function parseJsonSteps(jsonSteps, legCoords) {
1476
-
1477
- if (!jsonSteps) {
1478
- return [];
1479
- }
1480
-
1481
- return jsonSteps.map(jsonStep => {
1482
-
1483
- const step = new Step();
1484
- const stepCoords = jsonToCoordinates$1(jsonStep);
1485
-
1486
- // OTP step does not have the same coordinates than a point in legCoords.
1487
- // That is why we look for the closest point.
1488
- const distances = legCoords.map(coords => coords.distanceTo(stepCoords));
1489
- const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
1490
- if (idStepCoordsInLeg < 0) {
1491
- throw new Error('OTP Parser: Cannot find closest step');
1492
- }
1493
- step.coords = legCoords[idStepCoordsInLeg];
1494
- step._idCoordsInLeg = idStepCoordsInLeg;
1495
-
1496
- step.name = jsonStep.streetName;
1497
- step.levelChange = null;
1498
-
1499
- step.distance = jsonStep.distance;
1500
-
1501
- return step;
1502
- });
1503
- }
1504
-
1505
- /**
1506
- * Generate multi itineraries from OTP JSON
1507
- * @param {object} json JSON file provided by OTP.
1508
- * @returns {?RouterResponse}
1509
- */
1510
- function createRouterResponseFromJson$1(json) {
1511
-
1512
- const { plan: jsonPlan } = json;
1513
-
1514
- if (!jsonPlan) {
1515
- return null;
1516
- }
1517
-
1518
- const routerResponse = new RouterResponse();
1519
- routerResponse.routerName = 'otp';
1520
-
1521
- routerResponse.from = jsonToCoordinates$1(jsonPlan.from);
1522
- routerResponse.to = jsonToCoordinates$1(jsonPlan.to);
1523
-
1524
- for (const jsonItinerary of jsonPlan.itineraries) {
1525
-
1526
- const itinerary = new Itinerary();
1527
-
1528
- itinerary.duration = jsonItinerary.duration;
1529
- itinerary.startTime = jsonItinerary.startTime;
1530
- itinerary.endTime = jsonItinerary.endTime;
1531
- itinerary.from = routerResponse.from;
1532
- itinerary.to = routerResponse.to;
1533
-
1534
- routerResponse.itineraries.push(itinerary);
1535
-
1536
- for (const jsonLeg of jsonItinerary.legs) {
1537
-
1538
- const leg = new Leg();
1539
-
1540
- leg.mode = jsonLeg.mode;
1541
- leg.duration = jsonLeg.duration;
1542
- leg.startTime = jsonLeg.startTime;
1543
- leg.endTime = jsonLeg.endTime;
1544
- leg.from = {
1545
- name: jsonLeg.from.name,
1546
- coords: jsonToCoordinates$1(jsonLeg.from)
1547
- };
1548
- leg.to = {
1549
- name: jsonLeg.to.name,
1550
- coords: jsonToCoordinates$1(jsonLeg.to)
1551
- };
1552
- leg.coords = Polyline.decode(jsonLeg.legGeometry.points).map(([lat, lon]) => new Coordinates(lat, lon));
1553
-
1554
- leg.steps = parseJsonSteps(jsonLeg.steps, leg.coords);
1555
-
1556
- if (leg.mode === 'BUS' || leg.mode === 'TRAM') {
1557
- leg.transportInfo = {
1558
- name: jsonLeg.route,
1559
- routeColor: jsonLeg.routeColor,
1560
- routeTextColor: jsonLeg.routeTextColor,
1561
- directionName: jsonLeg.headsign
1562
- };
1563
-
1564
- const legStep = new Step();
1565
- legStep.coords = leg.coords[0];
1566
- legStep._idCoordsInLeg = 0;
1567
- legStep.name = jsonLeg.headsign;
1568
- legStep.levelChange = null;
1569
- legStep.distance = jsonLeg.distance;
1570
- leg.steps = [legStep];
1571
- }
1572
-
1573
- // jsonLeg.distance is not reliable when compared to the array of leg coords.
1574
- // leg.distance = jsonLeg.distance;
1575
- leg.distance = leg.coords.reduce((acc, coords, idx, arr) => {
1576
- if (idx === 0) {
1577
- return acc;
1578
- }
1579
- return acc + arr[idx - 1].distanceTo(coords);
1580
- }, 0);
1581
-
1582
- itinerary.legs.push(leg);
1583
-
1584
- }
1585
-
1586
- itinerary.distance = itinerary.coords.reduce((acc, coords, idx, arr) => {
1587
- if (idx === 0) {
1588
- return acc;
1589
- }
1590
- return acc + arr[idx - 1].distanceTo(coords);
1591
- }, 0);
1592
-
1593
- // All legs have to be parsed before computing steps metadata
1594
- generateStepsMetadata(itinerary);
1595
- }
1596
-
1597
- return routerResponse;
1598
- }
1599
-
1600
- var OtpUtils = /*#__PURE__*/Object.freeze({
1601
- __proto__: null,
1602
- jsonToCoordinates: jsonToCoordinates$1,
1603
- createRouterResponseFromJson: createRouterResponseFromJson$1
1604
- });
1605
-
1606
- /* eslint-disable max-depth */
1607
-
1608
- /**
1609
- * @param {object} json
1610
- * @returns {Coordinates}
1611
- */
1612
- function jsonToCoordinates(json) {
1613
- return new Coordinates(json.Lat, json.Long);
1614
- }
1615
-
1616
- /**
1617
- * @param {string} jsonDate
1618
- * @returns {number}
1619
- */
1620
- function jsonDateToTimestamp(jsonDate) {
1621
- const [dateStr, timeStr] = jsonDate.split(' ');
1622
- const [dayStr, monthStr, yearStr] = dateStr.split('/');
1623
- const [hoursStr, minutesStr, secondsStr] = timeStr.split(':');
1624
- const date = new Date(
1625
- Number(yearStr), Number(monthStr) - 1, Number(dayStr),
1626
- Number(hoursStr), Number(minutesStr), Number(secondsStr)
1627
- );
1628
- return date.getTime();
1629
- }
1630
-
1631
- /**
1632
- * @param {string} wktGeometry
1633
- * @returns {Coordinates[]}
1634
- */
1635
- function parseWKTGeometry(wktGeometry) {
1636
- const tmpCoordsStr = wktGeometry.match(/LINESTRING \((.*)\)/i);
1637
- if (!tmpCoordsStr) {
1638
- return null;
1639
- }
1640
- return tmpCoordsStr[1].split(',').map(str => {
1641
- const sp = str.trim().split(' ');
1642
- return new Coordinates(Number(sp[1]), Number(sp[0]));
1643
- });
1644
- }
1645
-
1646
- /**
1647
- * @param {string} iso8601Duration
1648
- * @see https://stackoverflow.com/a/29153059/2239938
1649
- */
1650
- function parseDuration(iso8601Duration) {
1651
- const iso8601DurationRegex = /(-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?/;
1652
-
1653
- var matches = iso8601Duration.match(iso8601DurationRegex);
1654
-
1655
- // const sign = typeof matches[1] === 'undefined' ? '+' : '-',
1656
- const years = typeof matches[2] === 'undefined' ? 0 : Number(matches[2]);
1657
- const months = typeof matches[3] === 'undefined' ? 0 : Number(matches[3]);
1658
- const weeks = typeof matches[4] === 'undefined' ? 0 : Number(matches[4]);
1659
- const days = typeof matches[5] === 'undefined' ? 0 : Number(matches[5]);
1660
- const hours = typeof matches[6] === 'undefined' ? 0 : Number(matches[6]);
1661
- const minutes = typeof matches[7] === 'undefined' ? 0 : Number(matches[7]);
1662
- const seconds = typeof matches[8] === 'undefined' ? 0 : Number(matches[8]);
1663
-
1664
- return seconds
1665
- + minutes * 60
1666
- + hours * 3600
1667
- + days * 86400
1668
- + weeks * (86400 * 7)
1669
- + months * (86400 * 30)
1670
- + years * (86400 * 365.25);
1671
- }
1672
-
1673
- /**
1674
- * Generate multi itineraries from Cityway JSON
1675
- * @param {object} json JSON file provided by Cityway.
1676
- * @returns {?RouterResponse}
1677
- * @example https://preprod.api.lia2.cityway.fr/journeyplanner/api/opt/PlanTrips/json?DepartureLatitude=49.51509388236216&DepartureLongitude=0.09341749619366316&ArrivalLatitude=49.5067090188444&ArrivalLongitude=0.1694842115417831&DepartureType=COORDINATES&ArrivalType=COORDINATES
1678
- */
1679
- function createRouterResponseFromJson(json) {
1680
-
1681
- if (json.StatusCode !== 200 || !json.Data || !json.Data.length) {
1682
- return null;
1683
- }
1684
-
1685
- const routerResponse = new RouterResponse();
1686
- routerResponse.routerName = 'cityway';
1687
-
1688
-
1689
- // Do not know if it the best approach, but it works...
1690
- const allJsonTrips = json.Data.reduce((acc, dataObj) => {
1691
- acc.push(...dataObj.response.trips.Trip);
1692
- return acc;
1693
- }, []);
1694
-
1695
- for (const trip of allJsonTrips) {
1696
-
1697
- const itinerary = new Itinerary();
1698
-
1699
- itinerary.duration = parseDuration(trip.Duration);
1700
- itinerary.startTime = jsonDateToTimestamp(trip.Departure.Time);
1701
- itinerary.from = jsonToCoordinates(trip.Departure.Site.Position);
1702
- itinerary.endTime = jsonDateToTimestamp(trip.Arrival.Time);
1703
- itinerary.to = jsonToCoordinates(trip.Arrival.Site.Position);
1704
- routerResponse.itineraries.push(itinerary);
1705
-
1706
- for (const jsonSection of trip.sections.Section) {
1707
-
1708
- const jsonLeg = jsonSection.Leg ? jsonSection.Leg : jsonSection.PTRide;
1709
-
1710
- const leg = new Leg();
1711
-
1712
- leg.mode = jsonLeg.TransportMode;
1713
- leg.duration = parseDuration(jsonLeg.Duration);
1714
- leg.startTime = jsonDateToTimestamp(jsonLeg.Departure.Time);
1715
- leg.endTime = jsonDateToTimestamp(jsonLeg.Arrival.Time);
1716
- leg.coords = [];
1717
-
1718
- if (leg.mode === 'WALK' || leg.mode === 'BICYCLE') {
1719
-
1720
- leg.from = {
1721
- name: jsonLeg.Departure.Site.Name,
1722
- coords: jsonToCoordinates(jsonLeg.Departure.Site.Position)
1723
- };
1724
- leg.to = {
1725
- name: jsonLeg.Arrival.Site.Name,
1726
- coords: jsonToCoordinates(jsonLeg.Arrival.Site.Position)
1727
- };
1728
-
1729
- leg.steps = [];
1730
- for (const jsonPathLink of jsonLeg.pathLinks.PathLink) {
1731
- const step = new Step();
1732
- let stepCoords;
1733
- if (jsonPathLink.Geometry) {
1734
- stepCoords = parseWKTGeometry(jsonPathLink.Geometry);
1735
- } else {
1736
- stepCoords = [leg.from.coords, leg.to.coords];
1737
- }
1738
- step.coords = stepCoords[0];
1739
- step._idCoordsInLeg = leg.coords.length;
1740
- stepCoords.forEach((coords, idx) => {
1741
- if (
1742
- idx !== 0
1743
- || leg.coords.length === 0
1744
- || !leg.coords[leg.coords.length - 1].equalsTo(coords)
1745
- ) {
1746
- leg.coords.push(coords);
1747
- }
1748
- });
1749
-
1750
-
1751
- step.name = jsonPathLink.Departure.Site.Name;
1752
- step.levelChange = null;
1753
-
1754
- step.distance = jsonPathLink.Distance;
1755
-
1756
- leg.steps.push(step);
1757
- }
1758
-
1759
- } else if (leg.mode === 'BUS' || leg.mode === 'TRAMWAY' || leg.mode === 'FUNICULAR') {
1760
-
1761
- leg.from = {
1762
- name: jsonLeg.Departure.StopPlace.Name,
1763
- coords: jsonToCoordinates(jsonLeg.Departure.StopPlace.Position)
1764
- };
1765
- leg.to = {
1766
- name: jsonLeg.Arrival.StopPlace.Name,
1767
- coords: jsonToCoordinates(jsonLeg.Arrival.StopPlace.Position)
1768
- };
1769
-
1770
- let transportName = jsonLeg.Line.Number;
1771
- if (leg.mode === 'TRAMWAY') {
1772
- leg.mode = 'TRAM';
1773
- // In order to remove the "TRAM " prefix.
1774
- transportName = transportName.substr(5);
1775
- }
1776
-
1777
- leg.transportInfo = {
1778
- name: transportName,
1779
- routeColor: jsonLeg.Line.Color,
1780
- routeTextColor: jsonLeg.Line.TextColor,
1781
- directionName: jsonLeg.Destination
1782
- };
1783
-
1784
- for (const jsonStep of jsonLeg.steps.Step) {
1785
- const stepCoords = parseWKTGeometry(jsonStep.Geometry);
1786
- stepCoords.forEach((coords, idx) => {
1787
- if (
1788
- idx !== 0
1789
- || leg.coords.length === 0
1790
- || !leg.coords[leg.coords.length - 1].equalsTo(coords)
1791
- ) {
1792
- leg.coords.push(coords);
1793
- }
1794
- });
1795
- }
1796
-
1797
- const legStep = new Step();
1798
- legStep.coords = leg.coords[0];
1799
- legStep._idCoordsInLeg = 0;
1800
- legStep.name = jsonLeg.Line.Name;
1801
- legStep.levelChange = null;
1802
- legStep.distance = jsonLeg.Distance;
1803
- leg.steps = [legStep];
1804
- } else {
1805
- Logger.warn(`[CitywayParser] Unknown leg mode: ${leg.mode}`);
1806
- }
1807
-
1808
- leg.distance = leg.coords.reduce((acc, coords, idx, arr) => {
1809
- if (idx === 0) {
1810
- return acc;
1811
- }
1812
- return acc + arr[idx - 1].distanceTo(coords);
1813
- }, 0);
1814
-
1815
- itinerary.legs.push(leg);
1816
-
1817
- }
1818
-
1819
- itinerary.distance = itinerary.coords.reduce((acc, coords, idx, arr) => {
1820
- if (idx === 0) {
1821
- return acc;
1822
- }
1823
- return acc + arr[idx - 1].distanceTo(coords);
1824
- }, 0);
1825
-
1826
- // All legs have to be parsed before computing steps metadata
1827
- generateStepsMetadata(itinerary);
1828
- }
1829
-
1830
- routerResponse.from = routerResponse.itineraries[0].from;
1831
- routerResponse.to = routerResponse.itineraries[routerResponse.itineraries.length - 1].to;
1832
-
1833
- return routerResponse;
1834
- }
1835
-
1836
- var CitywayUtils = /*#__PURE__*/Object.freeze({
1837
- __proto__: null,
1838
- jsonToCoordinates: jsonToCoordinates,
1839
- createRouterResponseFromJson: createRouterResponseFromJson
1840
- });
1841
-
1842
- class ItineraryInfo {
1843
-
1844
- /** @type {Step} */
1845
- nextStep;
1846
-
1847
- /** @type {Step} */
1848
- previousStep;
1849
-
1850
- /** @type {GraphProjection} */
1851
- projection;
1852
-
1853
- /** @type {Leg} */
1854
- leg;
1855
-
1856
- /** @type {number} */
1857
- traveledDistance;
1858
-
1859
- /** @type {number} */
1860
- traveledPercentage;
1861
-
1862
- /** @type {number} */
1863
- remainingDistance;
1864
-
1865
- /** @type {number} */
1866
- remainingPercentage;
1867
-
1868
- }
1869
-
1870
- /* eslint-disable max-statements */
1871
-
1872
- class ItineraryInfoManager {
1873
-
1874
- /** @type {Itinerary} */
1875
- _itinerary;
1876
-
1877
- /** @type {Network} */
1878
- _network;
1879
-
1880
- /** @type {Network} */
1881
- _mapMatching;
1882
-
1883
- /** @type {Step[]} */
1884
- _steps;
1885
-
1886
- /** @type {Step[]} */
1887
- _coordsNextStep;
1888
-
1889
- /** @type {Step[]} */
1890
- _coordsPreviousStep;
1891
-
1892
- /** @type {number[]} */
1893
- _coordsDistanceTraveled;
1894
-
1895
- /** @type {Leg[]} */
1896
- _coordsLeg;
1897
-
1898
- /** @type {Itinerary} */
1899
- set itinerary(itinerary) {
1900
-
1901
- if (itinerary === null) {
1902
- this._itinerary = null;
1903
- return;
1904
- }
1905
-
1906
- this._itinerary = itinerary;
1907
- this._steps = itinerary.steps;
1908
- this._network = itinerary.toNetwork();
1909
- this._mapMatching = new MapMatching(this._network);
1910
-
1911
- this._coordsNextStep = new Array(itinerary.coords.length);
1912
- this._coordsPreviousStep = new Array(itinerary.coords.length);
1913
- this._coordsDistanceTraveled = new Array(itinerary.coords.length);
1914
- this._coordsLeg = new Array(itinerary.coords.length);
1915
-
1916
- let stepId = 0;
1917
- let previousStep = null;
1918
- let nextStep = this._steps[0];
1919
- let distanceTraveled = 0;
1920
-
1921
- itinerary.coords.forEach((coords, idx, arr) => {
1922
- if (stepId < this._steps.length && this._steps[stepId].coords.equalsTo(coords)) {
1923
- previousStep = this._steps[stepId];
1924
- nextStep = stepId === this._steps.length - 1 ? null : this._steps[stepId + 1];
1925
- stepId++;
1926
- }
1927
- if (idx !== 0) {
1928
- distanceTraveled += arr[idx - 1].distanceTo(coords);
1929
- }
1930
-
1931
- this._coordsNextStep[idx] = nextStep;
1932
- this._coordsPreviousStep[idx] = previousStep;
1933
- this._coordsDistanceTraveled[idx] = distanceTraveled;
1934
- this._coordsLeg[idx] = itinerary.legs.find(leg => leg.coords.includes(coords));
1935
- });
1936
- }
1937
-
1938
- /**
1939
- * @param {Coordinates} position
1940
- * @returns {ItineraryInfo}
1941
- */
1942
- getInfo(position) {
1943
-
1944
- if (!this._itinerary) {
1945
- return null;
1946
- }
1947
-
1948
- if (!(position instanceof Coordinates)) {
1949
- return null;
1950
- }
1951
-
1952
- const projection = this._mapMatching.getProjection(position);
1953
- if (!projection) {
1954
- return null;
1955
- }
1956
-
1957
- let itineraryInfo = null;
1958
-
1959
- if (projection.nearestElement instanceof GraphNode) {
1960
- const idx = this._itinerary.coords.findIndex(
1961
- coords => projection.nearestElement.coords === coords
1962
- );
1963
- if (idx === -1) {
1964
- throw new Error('ItineraryInfoManager: could not find projection in itinerary (Node)');
1965
- }
1966
-
1967
- itineraryInfo = new ItineraryInfo();
1968
- itineraryInfo.nextStep = this._coordsNextStep[idx];
1969
- itineraryInfo.previousStep = this._coordsPreviousStep[idx];
1970
- itineraryInfo.projection = projection;
1971
- itineraryInfo.leg = this._coordsLeg[idx];
1972
- itineraryInfo.traveledDistance = this._coordsDistanceTraveled[idx];
1973
- itineraryInfo.remainingDistance = this._itinerary.distance - itineraryInfo.traveledDistance;
1974
- itineraryInfo.traveledPercentage = itineraryInfo.traveledDistance / this._itinerary.distance;
1975
- itineraryInfo.remainingPercentage = itineraryInfo.remainingDistance / this._itinerary.distance;
1976
-
1977
- } else if (projection.nearestElement instanceof GraphEdge) {
1978
-
1979
- let firstNode = projection.nearestElement.node1.coords;
1980
- let idx = this._itinerary.coords.findIndex(coords => firstNode === coords);
1981
- if (idx === -1) {
1982
- throw new Error('ItineraryInfoManager: could not find projection in itinerary (Edge)');
1983
- }
1984
-
1985
- // graphEdge is not necessarly ordered. We have to look for the first point
1986
- if (idx === this._itinerary.coords.length - 1
1987
- || this._itinerary.coords[idx + 1] !== projection.nearestElement.node2.coords
1988
- ) {
1989
- firstNode = projection.nearestElement.node2.coords;
1990
- idx--;
1991
- }
1992
-
1993
- itineraryInfo = new ItineraryInfo();
1994
- itineraryInfo.nextStep = this._coordsNextStep[idx];
1995
- itineraryInfo.previousStep = this._coordsPreviousStep[idx];
1996
- itineraryInfo.projection = projection;
1997
- itineraryInfo.leg = this._coordsLeg[idx];
1998
- itineraryInfo.traveledDistance = this._coordsDistanceTraveled[idx]
1999
- + projection.projection.distanceTo(firstNode);
2000
- itineraryInfo.remainingDistance = this._itinerary.distance - itineraryInfo.traveledDistance;
2001
- itineraryInfo.traveledPercentage = itineraryInfo.traveledDistance / this._itinerary.distance;
2002
- itineraryInfo.remainingPercentage = itineraryInfo.remainingDistance / this._itinerary.distance;
2003
-
2004
- }
2005
-
2006
- return itineraryInfo;
2007
- }
2008
-
2009
- }
2010
-
2011
- export { CitywayUtils, Itinerary, ItineraryInfo, ItineraryInfoManager, Leg, LevelChange, OsmElement, OsmModel, OsmNetworkUtils, OsmNode, OsmParser, OsmRouter, OsmRouterOptions, OsmRouterUtils, OsmWay, OsrmUtils, OtpUtils, RouterResponse, Step };
253
+ export { OsmElement, OsmModel, OsmNode, OsmParser, OsmWay };
2012
254
  //# sourceMappingURL=wemap-osm.es.js.map