atriusmaps-node-sdk 1.0.0 → 3.2.28
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/README.md +76 -0
- package/config/rollup.config.cjs.js +31 -0
- package/dist/cjs/_virtual/_empty_module_placeholder.js +5 -0
- package/dist/cjs/deploy/nodeEntry.js +15 -0
- package/dist/cjs/deploy/prepareSDKConfig.js +9 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/package.json.js +11 -0
- package/dist/cjs/plugins/clientAPI/src/clientAPI.js +9 -0
- package/dist/cjs/plugins/dynamicPois/src/dynamicPois.js +33 -0
- package/dist/cjs/plugins/poiDataManager/src/poiDataManager.js +36 -0
- package/dist/cjs/plugins/sdkServer/src/sdkHeadless.js +31 -0
- package/dist/cjs/plugins/sdkServer/src/sdkServer.js +13 -0
- package/dist/cjs/plugins/sdkServer/src/util.js +10 -0
- package/dist/cjs/plugins/searchService/src/poiSearch.js +28 -0
- package/dist/cjs/plugins/searchService/src/searchService.js +37 -0
- package/dist/cjs/plugins/searchService/src/searchTypeahead.js +8 -0
- package/dist/cjs/plugins/searchService/src/utils.js +13 -0
- package/dist/cjs/plugins/venueDataLoader/src/venueDataLoader.js +36 -0
- package/dist/cjs/plugins/venueDataLoader/src/venueLoadingUtils.js +34 -0
- package/dist/cjs/plugins/wayfinder/src/findRoute.js +30 -0
- package/dist/cjs/plugins/wayfinder/src/minPriorityQueue.js +5 -0
- package/dist/cjs/plugins/wayfinder/src/navGraph.js +13 -0
- package/dist/cjs/plugins/wayfinder/src/navGraphDebug.js +30 -0
- package/dist/cjs/plugins/wayfinder/src/segmentBadges.js +5 -0
- package/dist/cjs/plugins/wayfinder/src/segmentBuilder.js +32 -0
- package/dist/cjs/plugins/wayfinder/src/segmentCategories.js +5 -0
- package/dist/cjs/plugins/wayfinder/src/stepBuilder.js +10 -0
- package/dist/cjs/plugins/wayfinder/src/wayfinder.js +40 -0
- package/dist/cjs/src/app.js +44 -0
- package/dist/cjs/src/auth/Auth.js +23 -0
- package/dist/cjs/src/configs/postproc-mol-url-parms.js +9 -0
- package/dist/cjs/src/configs/postproc-stateTracking.js +31 -0
- package/dist/cjs/src/configs/sdkHeadless.json.js +47 -0
- package/dist/cjs/src/controller.js +14 -0
- package/dist/cjs/src/debugTools.js +30 -0
- package/dist/cjs/src/env.js +7 -0
- package/dist/cjs/src/extModules/bustle.js +13 -0
- package/dist/cjs/src/extModules/flexapi/src/help.js +9 -0
- package/dist/cjs/src/extModules/flexapi/src/index.js +13 -0
- package/dist/cjs/src/extModules/flexapi/src/validate.js +10 -0
- package/dist/cjs/src/extModules/geohasher.js +8 -0
- package/dist/cjs/src/extModules/log.js +7 -0
- package/dist/cjs/src/historyManager.js +7 -0
- package/dist/cjs/src/utils/bounds.js +10 -0
- package/dist/cjs/src/utils/buildStructureLookup.js +29 -0
- package/dist/cjs/src/utils/configUtils.js +8 -0
- package/dist/cjs/src/utils/dom.js +10 -0
- package/dist/cjs/src/utils/funcs.js +15 -0
- package/dist/cjs/src/utils/geodesy.js +8 -0
- package/dist/cjs/src/utils/geom.js +35 -0
- package/dist/cjs/src/utils/i18n.js +14 -0
- package/dist/cjs/src/utils/observable.js +5 -0
- package/dist/cjs/src/utils/rand.js +8 -0
- package/lib/_virtual/_empty_module_placeholder.js +1 -0
- package/lib/deploy/nodeEntry.js +1 -58
- package/lib/deploy/prepareSDKConfig.js +1 -112
- package/lib/package.json.js +1 -143
- package/lib/plugins/clientAPI/src/clientAPI.js +1 -14
- package/lib/plugins/dynamicPois/src/dynamicPois.js +1 -131
- package/lib/plugins/poiDataManager/src/poiDataManager.js +1 -207
- package/lib/plugins/sdkServer/src/sdkHeadless.js +1 -53
- package/lib/plugins/sdkServer/src/sdkServer.js +1 -211
- package/lib/plugins/sdkServer/src/util.js +1 -18
- package/lib/plugins/searchService/src/poiSearch.js +1 -39
- package/lib/plugins/searchService/src/searchService.js +1 -234
- package/lib/plugins/searchService/src/searchTypeahead.js +1 -63
- package/lib/plugins/searchService/src/utils.js +1 -30
- package/lib/plugins/venueDataLoader/src/venueDataLoader.js +1 -465
- package/lib/plugins/venueDataLoader/src/venueLoadingUtils.js +1 -84
- package/lib/plugins/wayfinder/src/findRoute.js +1 -134
- package/lib/plugins/wayfinder/src/minPriorityQueue.js +1 -89
- package/lib/plugins/wayfinder/src/navGraph.js +1 -370
- package/lib/plugins/wayfinder/src/navGraphDebug.js +1 -95
- package/lib/plugins/wayfinder/src/segmentBadges.js +1 -29
- package/lib/plugins/wayfinder/src/segmentBuilder.js +1 -241
- package/lib/plugins/wayfinder/src/segmentCategories.js +1 -30
- package/lib/plugins/wayfinder/src/stepBuilder.js +1 -236
- package/lib/plugins/wayfinder/src/wayfinder.js +1 -452
- package/lib/src/app.js +1 -150
- package/lib/src/auth/Auth.js +1 -35
- package/lib/src/configs/postproc-mol-url-parms.js +1 -58
- package/lib/src/configs/postproc-stateTracking.js +1 -40
- package/lib/src/configs/sdkHeadless.json.js +1 -42
- package/lib/src/controller.js +1 -45
- package/lib/src/debugTools.js +1 -108
- package/lib/src/env.js +1 -17
- package/lib/src/extModules/bustle.js +1 -126
- package/lib/src/extModules/flexapi/src/help.js +1 -21
- package/lib/src/extModules/flexapi/src/index.js +1 -66
- package/lib/src/extModules/flexapi/src/validate.js +1 -131
- package/lib/src/extModules/geohasher.js +1 -90
- package/lib/src/extModules/log.js +1 -70
- package/lib/src/historyManager.js +1 -30
- package/lib/src/utils/bounds.js +1 -23
- package/lib/src/utils/buildStructureLookup.js +1 -17
- package/lib/src/utils/configUtils.js +1 -61
- package/lib/src/utils/dom.js +1 -46
- package/lib/src/utils/funcs.js +1 -50
- package/lib/src/utils/geodesy.js +1 -35
- package/lib/src/utils/geom.js +1 -141
- package/lib/src/utils/i18n.js +1 -70
- package/lib/src/utils/observable.js +1 -76
- package/lib/src/utils/rand.js +1 -82
- package/package.json +23 -6
- package/lib/_virtual/_empty_module_placeholder +0 -3
|
@@ -1,134 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { SecurityLaneType } from './wayfinder.js';
|
|
3
|
-
|
|
4
|
-
const getEdgeTo = dst => node => R.find(e => e.dst === dst, node.edges);
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Returns the shortest route (or path) from start to end.
|
|
8
|
-
* @param {Object} start must include {floorId, lat, lng}
|
|
9
|
-
* @param {Object} end must include {floorId, lat, lng}
|
|
10
|
-
* @param {Object} options optional settings for choosing route
|
|
11
|
-
* @param {boolean} options.requiresAccessibility if true, only accessible routes are returned (no stairs or escalators)
|
|
12
|
-
* @returns {[nodes]} array of NavGraph nodes OR null if no route exists
|
|
13
|
-
* @throws if start or end is not defined
|
|
14
|
-
*/
|
|
15
|
-
const calculateRoute = (graph, start, end, options) => {
|
|
16
|
-
if (!start || !end)
|
|
17
|
-
throw Error('bad calculate Route request!')
|
|
18
|
-
return graph.findShortestPath(start, end, options)
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @typedef Waypoint
|
|
23
|
-
* @property {FullPosition} position
|
|
24
|
-
* @property {number} distance
|
|
25
|
-
* @property {number} eta
|
|
26
|
-
* @property {boolean} isSecurityCheckpoint
|
|
27
|
-
* @property {boolean} isPortal
|
|
28
|
-
* @property {string} portalType
|
|
29
|
-
* @property {number} levelDifference
|
|
30
|
-
* @property {boolean} isDestination
|
|
31
|
-
* @property {SecurityWaitTime|null} securityWaitTimes
|
|
32
|
-
* @property {SecurityLane|null} securityLane
|
|
33
|
-
* @property {CurvedPath|null} curvedPathForward
|
|
34
|
-
*
|
|
35
|
-
* @typedef SecurityLane
|
|
36
|
-
* @property {string} id
|
|
37
|
-
* @property {string} type
|
|
38
|
-
*
|
|
39
|
-
* @typedef FullPosition
|
|
40
|
-
* @property {string} floorId
|
|
41
|
-
* @property {string} lat
|
|
42
|
-
* @property {number} lng
|
|
43
|
-
* @property {number} ordinal
|
|
44
|
-
* @property {string} structureId
|
|
45
|
-
*
|
|
46
|
-
* @typedef {Array.<CurvedPoint>} CurvedPath
|
|
47
|
-
*
|
|
48
|
-
* @typedef CurvedPoint
|
|
49
|
-
* @property {ObjCoordinate} end
|
|
50
|
-
* @property {ObjCoordinate} in
|
|
51
|
-
* @property {ObjCoordinate} out
|
|
52
|
-
* @property {ObjCoordinate} start
|
|
53
|
-
*
|
|
54
|
-
* @typedef {{lng: number, lat: number}} ObjCoordinate
|
|
55
|
-
*
|
|
56
|
-
* Returns the shortest route (or path) from start to end.
|
|
57
|
-
* @param graph
|
|
58
|
-
* @param {Endpoint} start
|
|
59
|
-
* @param {Endpoint} destination
|
|
60
|
-
* @param {RouteOptions} options
|
|
61
|
-
* @return {{waypoints: Array.<Waypoint>}|null}
|
|
62
|
-
*/
|
|
63
|
-
// todo refactor
|
|
64
|
-
const findRoute = (graph, start, destination, options = {}) => {
|
|
65
|
-
const waypoints = [];
|
|
66
|
-
const queues = [];
|
|
67
|
-
|
|
68
|
-
let hasSecurity = false;
|
|
69
|
-
let hasImmigration = false;
|
|
70
|
-
|
|
71
|
-
const routeNodes = calculateRoute(graph, start, destination, options);
|
|
72
|
-
|
|
73
|
-
if (routeNodes === null)
|
|
74
|
-
return null
|
|
75
|
-
|
|
76
|
-
let previousRouteNode = null;
|
|
77
|
-
for (let i = 0; i < routeNodes.length; i++) {
|
|
78
|
-
const waypoint = {
|
|
79
|
-
distance: 0,
|
|
80
|
-
eta: 0
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
if (previousRouteNode) {
|
|
84
|
-
const edgeUsed = getEdgeTo(routeNodes[i].id)(previousRouteNode);
|
|
85
|
-
if (edgeUsed != null) {
|
|
86
|
-
waypoint.distance = edgeUsed.distance;
|
|
87
|
-
waypoint.eta = edgeUsed.transitTime;
|
|
88
|
-
|
|
89
|
-
if (edgeUsed.type !== 'Ground') {
|
|
90
|
-
waypoint.portalType = edgeUsed.type;
|
|
91
|
-
waypoint.isPortal = true;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (edgeUsed.o)
|
|
95
|
-
waypoint.poiId = edgeUsed.o;
|
|
96
|
-
|
|
97
|
-
if (edgeUsed.path)
|
|
98
|
-
waypoint.curvedPathForward = edgeUsed.path;
|
|
99
|
-
if (edgeUsed.securityWaitTimes) {
|
|
100
|
-
waypoint.securityWaitTimes = edgeUsed.securityWaitTimes;
|
|
101
|
-
waypoint.eta = waypoint.securityWaitTimes.queueTime;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (edgeUsed.securityLane) {
|
|
105
|
-
waypoint.securityLane = edgeUsed.securityLane;
|
|
106
|
-
waypoint.isSecurityCheckpoint = true;
|
|
107
|
-
if (edgeUsed.securityLane.type === SecurityLaneType.SECURITY)
|
|
108
|
-
hasSecurity = true;
|
|
109
|
-
if (edgeUsed.securityLane.type === SecurityLaneType.IMMIGRATION)
|
|
110
|
-
hasImmigration = true;
|
|
111
|
-
if (edgeUsed.o)
|
|
112
|
-
queues.push(edgeUsed.o);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
waypoint.levelDifference = previousRouteNode ? routeNodes[i].ordinal - previousRouteNode.ordinal : 0;
|
|
118
|
-
waypoint.position = R.omit(['edges', 'id'], { ...routeNodes[i] });
|
|
119
|
-
|
|
120
|
-
waypoints.push(waypoint);
|
|
121
|
-
|
|
122
|
-
previousRouteNode = routeNodes[i];
|
|
123
|
-
}
|
|
124
|
-
R.last(waypoints).isDestination = true;
|
|
125
|
-
|
|
126
|
-
return {
|
|
127
|
-
waypoints,
|
|
128
|
-
queues,
|
|
129
|
-
hasSecurity,
|
|
130
|
-
hasImmigration
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
export { findRoute };
|
|
1
|
+
import*as e from"ramda";import{SecurityLaneType as t}from"./wayfinder.js";const i=t=>i=>e.find((e=>e.dst===t),i.edges),r=(r,s,a,n={})=>{const o=[],u=[];let c=!1,l=!1;const d=((e,t,i,r)=>{if(!t||!i)throw Error("bad calculate Route request!");return e.findShortestPath(t,i,r)})(r,s,a,n);if(null===d)return null;let y=null;for(let r=0;r<d.length;r++){const s={distance:0,eta:0};if(y){const e=i(d[r].id)(y);null!=e&&(s.distance=e.distance,s.eta=e.transitTime,"Ground"!==e.type&&(s.portalType=e.type,s.isPortal=!0),e.o&&(s.poiId=e.o),e.path&&(s.curvedPathForward=e.path),e.securityWaitTimes&&(s.securityWaitTimes=e.securityWaitTimes,s.eta=s.securityWaitTimes.queueTime),e.securityLane&&(s.securityLane=e.securityLane,s.isSecurityCheckpoint=!0,e.securityLane.type===t.SECURITY&&(c=!0),e.securityLane.type===t.IMMIGRATION&&(l=!0),e.o&&u.push(e.o)))}s.levelDifference=y?d[r].ordinal-y.ordinal:0,s.position=e.omit(["edges","id"],{...d[r]}),o.push(s),y=d[r]}return e.last(o).isDestination=!0,{waypoints:o,queues:u,hasSecurity:c,hasImmigration:l}};export{r as findRoute};
|
|
@@ -1,89 +1 @@
|
|
|
1
|
-
class
|
|
2
|
-
constructor () {
|
|
3
|
-
this.heap = [null]; // array representation of binary heap
|
|
4
|
-
this.heapMap = {};
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
offerWithPriority (node, priority) {
|
|
8
|
-
const index = this.heap.push([node, priority]) - 1;
|
|
9
|
-
|
|
10
|
-
this.heapMap[node] = index;
|
|
11
|
-
this.bubble(index);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
raisePriority (node, priority) {
|
|
15
|
-
const index = this.heapMap[node];
|
|
16
|
-
this.heap[index][1] = priority;
|
|
17
|
-
|
|
18
|
-
this.bubble(index);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
poll () {
|
|
22
|
-
if (this.heap.length === 1) {
|
|
23
|
-
return null
|
|
24
|
-
}
|
|
25
|
-
if (this.heap.length === 2) {
|
|
26
|
-
const value = this.heap.pop()[0];
|
|
27
|
-
delete this.heapMap[value];
|
|
28
|
-
return value
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const value = this.heap[1][0];
|
|
32
|
-
delete this.heapMap[value];
|
|
33
|
-
|
|
34
|
-
this.heap[1] = this.heap.pop();
|
|
35
|
-
this.heapMap[this.heap[1][0]] = 1;
|
|
36
|
-
|
|
37
|
-
this.sink(1);
|
|
38
|
-
|
|
39
|
-
return value
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
isEmpty () {
|
|
43
|
-
return this.heap.length === 1
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
bubble (i) {
|
|
47
|
-
while (i > 1) {
|
|
48
|
-
const parentIndex = i >> 1; // floor(i/2)
|
|
49
|
-
|
|
50
|
-
if (!this.isHigherPriority(i, parentIndex)) {
|
|
51
|
-
break
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
this.swap(i, parentIndex);
|
|
55
|
-
i = parentIndex;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
sink (i) {
|
|
60
|
-
while (i * 2 < this.heap.length) {
|
|
61
|
-
const isRightChildHigherPriority = (this.heap[i * 2 + 1] === undefined)
|
|
62
|
-
? false
|
|
63
|
-
: this.isHigherPriority(i * 2 + 1, i * 2); // i*2 +1 might be null
|
|
64
|
-
const childIndex = isRightChildHigherPriority ? i * 2 + 1 : i * 2;
|
|
65
|
-
|
|
66
|
-
if (this.isHigherPriority(i, childIndex)) {
|
|
67
|
-
break
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
this.swap(i, childIndex);
|
|
71
|
-
i = childIndex;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
swap (i, j) {
|
|
76
|
-
this.heapMap[this.heap[i][0]] = j;
|
|
77
|
-
this.heapMap[this.heap[j][0]] = i;
|
|
78
|
-
|
|
79
|
-
const temp = this.heap[i];
|
|
80
|
-
this.heap[i] = this.heap[j];
|
|
81
|
-
this.heap[j] = temp;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
isHigherPriority (i, j) {
|
|
85
|
-
return this.heap[i][1] < this.heap[j][1] // lower score -> higher priority
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export default MinPriorityQueue;
|
|
1
|
+
class h{constructor(){this.heap=[null],this.heapMap={}}offerWithPriority(h,i){const t=this.heap.push([h,i])-1;this.heapMap[h]=t,this.bubble(t)}raisePriority(h,i){const t=this.heapMap[h];this.heap[t][1]=i,this.bubble(t)}poll(){if(1===this.heap.length)return null;if(2===this.heap.length){const h=this.heap.pop()[0];return delete this.heapMap[h],h}const h=this.heap[1][0];return delete this.heapMap[h],this.heap[1]=this.heap.pop(),this.heapMap[this.heap[1][0]]=1,this.sink(1),h}isEmpty(){return 1===this.heap.length}bubble(h){for(;h>1;){const i=h>>1;if(!this.isHigherPriority(h,i))break;this.swap(h,i),h=i}}sink(h){for(;2*h<this.heap.length;){const i=void 0!==this.heap[2*h+1]&&this.isHigherPriority(2*h+1,2*h)?2*h+1:2*h;if(this.isHigherPriority(h,i))break;this.swap(h,i),h=i}}swap(h,i){this.heapMap[this.heap[h][0]]=i,this.heapMap[this.heap[i][0]]=h;const t=this.heap[h];this.heap[h]=this.heap[i],this.heap[i]=t}isHigherPriority(h,i){return this.heap[h][1]<this.heap[i][1]}}export{h as default};
|
|
@@ -1,370 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { encode, calculateAdjacent } from '../../../src/extModules/geohasher.js';
|
|
3
|
-
import { distance } from '../../../src/utils/geodesy.js';
|
|
4
|
-
import MinPriorityQueue from './minPriorityQueue.js';
|
|
5
|
-
|
|
6
|
-
const DEFAULT_WALKING_SPEED_M_PER_MIN = 60;
|
|
7
|
-
const CLOSED_CHECKPOINT_EDGE_WEIGHT = 9999;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @typedef NavNode
|
|
11
|
-
* @property {number} ordinal
|
|
12
|
-
* @property {Array.<NavEdge>} edges
|
|
13
|
-
* @property {string} id
|
|
14
|
-
* @property {number} lat
|
|
15
|
-
* @property {number} lng
|
|
16
|
-
* @property {string} floorId
|
|
17
|
-
* @property {structureId} structureId
|
|
18
|
-
*
|
|
19
|
-
* @typedef NavEdge
|
|
20
|
-
* @property {string} dst - id of node at edge end
|
|
21
|
-
* @property {string} src - id of node at edge start
|
|
22
|
-
* @property {number} distance
|
|
23
|
-
* @property {string|undefined} o - id of security lane POI associated with this edge
|
|
24
|
-
* @property {CurvedPath|null} path - list of Bezier points if edge represents curve
|
|
25
|
-
* @property {boolean} isAccessible
|
|
26
|
-
* @property {boolean} isDriveway - true if edge points to POI, false if edge just connects other edges
|
|
27
|
-
* @property {number} transitTime
|
|
28
|
-
* @property {string} type
|
|
29
|
-
* @property {number} weight - value used by Dijkstra algorithm (usually edge time or distance)
|
|
30
|
-
*
|
|
31
|
-
* @param {RawNavGraph} data
|
|
32
|
-
* @param {function} floorIdToOrdinal
|
|
33
|
-
* @param {function} floorIdToStructureId
|
|
34
|
-
* @param {Array.<SecurityLane>} securityLanesMap - list of security lanes
|
|
35
|
-
* @return {Object}
|
|
36
|
-
*/
|
|
37
|
-
// todo remove dead commented code
|
|
38
|
-
function createNavGraph (data, floorIdToOrdinal, floorIdToStructureId, securityLanesMap) {
|
|
39
|
-
const nodes = { };
|
|
40
|
-
const geoDb = { };
|
|
41
|
-
let securityWaitTimes = {};
|
|
42
|
-
|
|
43
|
-
data.nodes.forEach(nodeData => {
|
|
44
|
-
const ordinal = floorIdToOrdinal(nodeData.floorId);
|
|
45
|
-
const structureId = floorIdToStructureId(nodeData.floorId);
|
|
46
|
-
const node = {
|
|
47
|
-
...pick(['id', 'lat', 'lng', 'floorId'], nodeData),
|
|
48
|
-
edges: [],
|
|
49
|
-
ordinal,
|
|
50
|
-
structureId
|
|
51
|
-
};
|
|
52
|
-
addNode(node);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
data.edges.forEach(ed => nodes[ed.s].edges.push(createEdge(ed, nodes)));
|
|
56
|
-
|
|
57
|
-
function addNode (node) {
|
|
58
|
-
const largeGeo = node.floorId + ':' + encode(node.lat, node.lng).substr(0, 7);
|
|
59
|
-
const mediumGeo = node.floorId + ':' + encode(node.lat, node.lng).substr(0, 8);
|
|
60
|
-
|
|
61
|
-
if (!geoDb[largeGeo])
|
|
62
|
-
geoDb[largeGeo] = [];
|
|
63
|
-
|
|
64
|
-
geoDb[largeGeo].push(node);
|
|
65
|
-
|
|
66
|
-
if (!geoDb[mediumGeo])
|
|
67
|
-
geoDb[mediumGeo] = [];
|
|
68
|
-
|
|
69
|
-
geoDb[mediumGeo].push(node);
|
|
70
|
-
|
|
71
|
-
nodes[node.id] = node;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function createEdge (data, nodes) {
|
|
75
|
-
const type = getEdgeType(data);
|
|
76
|
-
const isAccessible = type.toLowerCase() !== 'escalator' && type.toLowerCase() !== 'stairs';
|
|
77
|
-
// todo consider calculating edge distance with 'path' differently
|
|
78
|
-
const distance = distanceBetweenNodes(data.s, data.d, nodes);
|
|
79
|
-
const transitTime = data.l || distance / DEFAULT_WALKING_SPEED_M_PER_MIN;
|
|
80
|
-
|
|
81
|
-
const buildCurvedPath = points => points.map(point => {
|
|
82
|
-
return {
|
|
83
|
-
start: { lat: point.s[0], lng: point.s[1] },
|
|
84
|
-
out: { lat: point.o[0], lng: point.o[1] },
|
|
85
|
-
in: { lat: point.i[0], lng: point.i[1] },
|
|
86
|
-
end: { lat: point.e[0], lng: point.e[1] }
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
const path = data.p ? buildCurvedPath(data.p) : null;
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
distance,
|
|
94
|
-
dst: data.d,
|
|
95
|
-
o: data.o,
|
|
96
|
-
isAccessible,
|
|
97
|
-
isDriveway: !isNil(data.h) && !data.h,
|
|
98
|
-
src: data.s,
|
|
99
|
-
transitTime,
|
|
100
|
-
type,
|
|
101
|
-
path,
|
|
102
|
-
weight: transitTime
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function getEdgeType (data) {
|
|
107
|
-
if (data.x) return 'Security Checkpoint'
|
|
108
|
-
if (data.t === '') return 'Ground'
|
|
109
|
-
return data.t
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function findShortestPathEntry (start, end, nodes, options = {}) {
|
|
113
|
-
const startNode = findClosestNode(start.floorId, start.lat, start.lng, geoDb, nodes);
|
|
114
|
-
const endNode = findClosestNode(end.floorId, end.lat, end.lng, geoDb, nodes);
|
|
115
|
-
|
|
116
|
-
// This code section does improve performance by about 10-20%, but comes at a cost
|
|
117
|
-
// of making the caching unusable in some cases
|
|
118
|
-
// if (start.structureId === end.structureId) {
|
|
119
|
-
// options.minOrd = Math.min(start.ordinal, end.ordinal)
|
|
120
|
-
// options.maxOrd = Math.max(start.ordinal, end.ordinal)
|
|
121
|
-
// options.structureId = start.structureId
|
|
122
|
-
// }
|
|
123
|
-
return findShortestPath(startNode, endNode, nodes, securityWaitTimes, securityLanesMap, options)
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* @param {Endpoint} start - start endpoint
|
|
127
|
-
* @param {Array.<Endpoint>} destArray - list of destinations
|
|
128
|
-
* @param {RouteOptions} options extra options (such as requireAccessibility)
|
|
129
|
-
* @returns {Array.<Array.<NavNode>>} array of routes corresponding to destinations specified
|
|
130
|
-
*/
|
|
131
|
-
function findAllShortestPaths (start, destArray, options) {
|
|
132
|
-
const lat = start.lat || start.latitude; // handle bluedot location
|
|
133
|
-
const lng = start.lng || start.longitude; // handle bluedot location
|
|
134
|
-
const startNode = findClosestNode(start.floorId, lat, lng, geoDb, nodes);
|
|
135
|
-
const destNodeArray = destArray.map(dest => findClosestNode(dest.floorId, dest.lat, dest.lng, geoDb, nodes));
|
|
136
|
-
if (!startNode || !destNodeArray.length) return []
|
|
137
|
-
return findAllShortestPathsImpl(startNode, destNodeArray, nodes, securityWaitTimes, securityLanesMap, options)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function updateWithSecurityWaitTime (waitTimesData) {
|
|
141
|
-
securityWaitTimes = map(omit(['lastUpdated']), waitTimesData);
|
|
142
|
-
clearCache();
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
_nodes: nodes,
|
|
147
|
-
_geoDb: geoDb,
|
|
148
|
-
findShortestPath: (start, end, options) => findShortestPathEntry(start, end, nodes, options),
|
|
149
|
-
findAllShortestPaths,
|
|
150
|
-
floorIdToOrdinal, // todo lets get rid of this...
|
|
151
|
-
floorIdToStructureId, // todo lets get rid of this...,
|
|
152
|
-
updateWithSecurityWaitTime,
|
|
153
|
-
clearCache
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function distanceBetweenNodes (n1, n2, nodes) {
|
|
158
|
-
const node1 = nodes[n1];
|
|
159
|
-
const node2 = nodes[n2];
|
|
160
|
-
const distance$1 = distance(node1.lat, node1.lng, node2.lat, node2.lng);
|
|
161
|
-
return distance$1
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* @param {Object.<Node>} start - a node in the navGraph to start on
|
|
166
|
-
* @param {Array.<Node>} destinations - array of nodes to find path to
|
|
167
|
-
* @param {Object.<string, NavNode>} nodes - dictionary of nodes by id
|
|
168
|
-
* @param {Object.<string, SecurityWaitTime>} securityWaitTimes - map of POI id to security wait time
|
|
169
|
-
* @param {Object.<string, SecurityLane>} securityLanesMap - map of POI id to security lane
|
|
170
|
-
* @param {RouteOptions} [options={}] extra options (such as requireAccessibility)
|
|
171
|
-
* @returns {Array.<Array.<Node>>} list of shortest path to each destination
|
|
172
|
-
*/
|
|
173
|
-
function findAllShortestPathsImpl (start, destinations, nodes, securityWaitTimes = {}, securityLanesMap = {}, options = {}) {
|
|
174
|
-
// const previous = findPaths(start, start, nodes, options)
|
|
175
|
-
|
|
176
|
-
// const backtrackPath = node => buildBacktrackPath(nodes, previous, node)
|
|
177
|
-
// const poiNodeTuples = Array.from(destinations.entries())
|
|
178
|
-
|
|
179
|
-
// const poiPathTuples = poiNodeTuples.map(([poi, node]) => [poi, backtrackPath(node)])
|
|
180
|
-
// return new Map(poiPathTuples)
|
|
181
|
-
return destinations.map(d => findShortestPath(start, d, nodes, securityWaitTimes, securityLanesMap, options))
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
let cost, prev, visited, visitQueue, lastStartId, lastOptionsStr;
|
|
185
|
-
|
|
186
|
-
const clearCache = () => {
|
|
187
|
-
cost = { };
|
|
188
|
-
prev = { };
|
|
189
|
-
visited = { };
|
|
190
|
-
visitQueue = new MinPriorityQueue();
|
|
191
|
-
lastStartId = null;
|
|
192
|
-
lastOptionsStr = {};
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
// This is a temporary name during a "probation" period - then I will
|
|
196
|
-
// ditch findShortestPath and rewrite findAllShortestPaths and ditch
|
|
197
|
-
// backtrackPath, etc.
|
|
198
|
-
// NOTE: export just for testing
|
|
199
|
-
/**
|
|
200
|
-
* @param {Object<Node>} start a node in the navGraph to start on
|
|
201
|
-
* @param {Object<Node>} end a node in the navGraph to find path to
|
|
202
|
-
* @param {Object.<string, Node>} nodes dictionary of nodes by id
|
|
203
|
-
* @param {Object.<string, SecurityWaitTime>} securityWaitTimes - map of POI id to security wait time
|
|
204
|
-
* @param {Object.<string, SecurityLane>} securityLanesMap - map of POI id to security lane
|
|
205
|
-
* @param {RouteOptions} options={} extra options (such as requireAccessibility)
|
|
206
|
-
* @returns {Array.<Node>} an array of nodes that represent the shortest route from start to end. null if no route exists.
|
|
207
|
-
*/
|
|
208
|
-
function findShortestPath (start, end, nodes, securityWaitTimes = {}, securityLanesMap = {}, options = { }) {
|
|
209
|
-
if (start.id !== lastStartId || lastOptionsStr !== JSON.stringify(options)) {
|
|
210
|
-
clearCache();
|
|
211
|
-
visitQueue.offerWithPriority(start.id, 0);
|
|
212
|
-
cost[start.id] = 0;
|
|
213
|
-
visited[start.id] = true;
|
|
214
|
-
|
|
215
|
-
lastStartId = start.id;
|
|
216
|
-
lastOptionsStr = JSON.stringify(options);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// continue crawling paths - but stop once we found destination
|
|
220
|
-
while (!visitQueue.isEmpty() && !visited[end.id]) {
|
|
221
|
-
const node = nodes[visitQueue.poll()]; // pop
|
|
222
|
-
const ccost = cost[node.id]; // current cost to this node
|
|
223
|
-
for (let ei = 0; ei < node.edges.length; ei++) {
|
|
224
|
-
const e = node.edges[ei]; // next edge from this node
|
|
225
|
-
|
|
226
|
-
if (visited[e.dst])
|
|
227
|
-
continue
|
|
228
|
-
|
|
229
|
-
if (options.requiresAccessibility && !e.isAccessible) {
|
|
230
|
-
// ignore not accessible edges if we're looking for an accessible route
|
|
231
|
-
continue
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// This code section does improve performance by about 10-20%, but comes at a cost
|
|
235
|
-
// of making the caching unusable in some cases
|
|
236
|
-
// if ((options.minOrd !== undefined && nodes[e.dst].ordinal < options.minOrd) ||
|
|
237
|
-
// (options.maxOrd !== undefined && nodes[e.dst].ordinal > options.maxOrd) ||
|
|
238
|
-
// (options.structureId !== undefined && nodes[e.dst].structureId !== options.structureId))
|
|
239
|
-
// continue
|
|
240
|
-
|
|
241
|
-
let weight = e.weight;
|
|
242
|
-
if (e.o && securityWaitTimes[e.o]) {
|
|
243
|
-
const dynamicData = securityWaitTimes[e.o];
|
|
244
|
-
if (dynamicData.queueTime) weight = dynamicData.queueTime;
|
|
245
|
-
if (dynamicData.isTemporarilyClosed) weight = CLOSED_CHECKPOINT_EDGE_WEIGHT;
|
|
246
|
-
e.securityWaitTimes = dynamicData;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (e.o && securityLanesMap[e.o]) {
|
|
250
|
-
e.securityLane = securityLanesMap[e.o];
|
|
251
|
-
const { type, id } = securityLanesMap[e.o];
|
|
252
|
-
const securityLanesIds = path(['selectedSecurityLanes', type], options);
|
|
253
|
-
if (securityLanesIds && !securityLanesIds.includes(id))
|
|
254
|
-
continue
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (cost[e.dst] === undefined) {
|
|
258
|
-
prev[e.dst] = node;
|
|
259
|
-
cost[e.dst] = ccost + weight;
|
|
260
|
-
visitQueue.offerWithPriority(e.dst, ccost + weight); // add node to the toCheck array
|
|
261
|
-
} else
|
|
262
|
-
if (cost[e.dst] > (ccost + weight)) { // is this a shorter path? Relaxation...
|
|
263
|
-
// if so, update the cost and parent
|
|
264
|
-
cost[e.dst] = ccost + weight;
|
|
265
|
-
prev[e.dst] = node;
|
|
266
|
-
visitQueue.raisePriority(e.dst, ccost + weight);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
visited[node.id] = true; // we have now been selected
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (!visited[end.id]) // if we never found our endpoint, it was inaccessible
|
|
273
|
-
return null
|
|
274
|
-
|
|
275
|
-
// build the path and return it
|
|
276
|
-
const path$1 = [];
|
|
277
|
-
let node = end;
|
|
278
|
-
while (node) {
|
|
279
|
-
path$1.push(node);
|
|
280
|
-
node = prev[node.id];
|
|
281
|
-
}
|
|
282
|
-
return path$1.reverse()
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function geohashSearch (floorId, geohash, geoDb, size) {
|
|
286
|
-
const geohashPrefix = geohash.substr(0, size);
|
|
287
|
-
|
|
288
|
-
const searchGeos = [];
|
|
289
|
-
searchGeos.push(floorId + ':' + calculateAdjacent(calculateAdjacent(geohashPrefix, 'top'), 'left'));
|
|
290
|
-
searchGeos.push(floorId + ':' + calculateAdjacent(geohashPrefix, 'top'));
|
|
291
|
-
searchGeos.push(floorId + ':' + calculateAdjacent(calculateAdjacent(geohashPrefix, 'top'), 'right'));
|
|
292
|
-
searchGeos.push(floorId + ':' + calculateAdjacent(geohashPrefix, 'left'));
|
|
293
|
-
searchGeos.push(floorId + ':' + geohashPrefix);
|
|
294
|
-
searchGeos.push(floorId + ':' + calculateAdjacent(geohashPrefix, 'right'));
|
|
295
|
-
searchGeos.push(floorId + ':' + calculateAdjacent(calculateAdjacent(geohashPrefix, 'bottom'), 'left'));
|
|
296
|
-
searchGeos.push(floorId + ':' + calculateAdjacent(geohashPrefix, 'bottom'));
|
|
297
|
-
searchGeos.push(floorId + ':' + calculateAdjacent(calculateAdjacent(geohashPrefix, 'bottom'), 'right'));
|
|
298
|
-
|
|
299
|
-
const nodes = [];
|
|
300
|
-
for (let i = 0; i < searchGeos.length; i++) {
|
|
301
|
-
const nodesFound = geoDb[searchGeos[i]];
|
|
302
|
-
if (nodesFound) {
|
|
303
|
-
for (let j = 0; j < nodesFound.length; j++)
|
|
304
|
-
nodes.push(nodesFound[j]);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
return nodes
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function findNodesByGeohash (floorId, geohash, geoDb, nodes) {
|
|
312
|
-
let foundNodes = geohashSearch(floorId, geohash, geoDb, 8);
|
|
313
|
-
if (foundNodes.length > 0)
|
|
314
|
-
return foundNodes
|
|
315
|
-
|
|
316
|
-
// broaden our search a bit and try again...
|
|
317
|
-
foundNodes = geohashSearch(floorId, geohash, geoDb, 7);
|
|
318
|
-
if (foundNodes.length > 0)
|
|
319
|
-
return foundNodes
|
|
320
|
-
|
|
321
|
-
// punt!
|
|
322
|
-
return Object.values(nodes)
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* @param floorId
|
|
327
|
-
* @param lat
|
|
328
|
-
* @param lng
|
|
329
|
-
* @param geoDb
|
|
330
|
-
* @param {Object<string, NavNode>} nodes - dictionary of node id to node object
|
|
331
|
-
* @return {NavNode} - node that is on the same floor and closest to the lat,lng point
|
|
332
|
-
*/
|
|
333
|
-
function findClosestNode (floorId, lat, lng, geoDb, nodes) {
|
|
334
|
-
const cnodes = findNodesByGeohash(floorId, encode(lat, lng), geoDb, nodes);
|
|
335
|
-
|
|
336
|
-
const nodeWithDistance = [];
|
|
337
|
-
for (let i = 0; i < cnodes.length; i++) {
|
|
338
|
-
// Attached distance to each node from the origin.
|
|
339
|
-
const distance$1 = distance(lat, lng, cnodes[i].lat, cnodes[i].lng);
|
|
340
|
-
nodeWithDistance.push([cnodes[i], distance$1]);
|
|
341
|
-
}
|
|
342
|
-
// todo do not sort, just find min node
|
|
343
|
-
// Sort by distance.
|
|
344
|
-
nodeWithDistance.sort(function (a, b) { return a[1] - b[1] });
|
|
345
|
-
const nodesSortedByDistance = [];
|
|
346
|
-
for (let i = 0; i < nodeWithDistance.length; i++)
|
|
347
|
-
nodesSortedByDistance.push(nodeWithDistance[i][0]);
|
|
348
|
-
|
|
349
|
-
return nodesSortedByDistance[0]
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// A slightly slower alternative to findClosestNode (an experiment - its simpler, but slower)
|
|
353
|
-
// function findClosestNode2 (floorId, lat, lng, nodes) {
|
|
354
|
-
// return selectShortest(Object.values(nodes)
|
|
355
|
-
// .filter(n => n.floorId === floorId)
|
|
356
|
-
// .map(n => [n, getGeoDistance([n.lat, n.lng], [lat, lng])]))
|
|
357
|
-
// }
|
|
358
|
-
|
|
359
|
-
// companion to above function - it returns closest node
|
|
360
|
-
// ar is 2-dim array - ar[i][0] = node, ar[i][1] = distance
|
|
361
|
-
// TODO: use this approach in findClosestNode - no need to sort first!
|
|
362
|
-
// function selectShortest (ar) {
|
|
363
|
-
// let shortest = ar[0]
|
|
364
|
-
// for (let i = 1; i < ar.length; i++)
|
|
365
|
-
// if (ar[i][1] < shortest[1]) shortest = ar[i]
|
|
366
|
-
|
|
367
|
-
// return shortest[0]
|
|
368
|
-
// }
|
|
369
|
-
|
|
370
|
-
export { createNavGraph, findShortestPath };
|
|
1
|
+
import{pick as t,isNil as o,map as e,omit as n,path as r}from"ramda";import{encode as s,calculateAdjacent as i}from"../../../src/extModules/geohasher.js";import{distance as l}from"../../../src/utils/geodesy.js";import u from"./minPriorityQueue.js";function d(r,i,l,u){const d={},c={};let a={};return r.nodes.forEach((o=>{const e=i(o.floorId),n=l(o.floorId);!function(t){const o=t.floorId+":"+s(t.lat,t.lng).substr(0,7),e=t.floorId+":"+s(t.lat,t.lng).substr(0,8);c[o]||(c[o]=[]);c[o].push(t),c[e]||(c[e]=[]);c[e].push(t),d[t.id]=t}({...t(["id","lat","lng","floorId"],o),edges:[],ordinal:e,structureId:n})})),r.edges.forEach((t=>d[t.s].edges.push(function(t,e){const n=function(t){return t.x?"Security Checkpoint":""===t.t?"Ground":t.t}(t),r="escalator"!==n.toLowerCase()&&"stairs"!==n.toLowerCase(),s=f(t.s,t.d,e),i=t.l||s/60,l=t=>t.map((t=>({start:{lat:t.s[0],lng:t.s[1]},out:{lat:t.o[0],lng:t.o[1]},in:{lat:t.i[0],lng:t.i[1]},end:{lat:t.e[0],lng:t.e[1]}}))),u=t.p?l(t.p):null;return{distance:s,dst:t.d,o:t.o,isAccessible:r,isDriveway:!o(t.h)&&!t.h,src:t.s,transitTime:i,type:n,path:u,weight:i}}(t,d)))),{_nodes:d,_geoDb:c,findClosestNode:(t,o,e)=>w(t,o,e,c,d),findShortestPath:(t,o,e)=>function(t,o,e,n={}){return I(w(t.floorId,t.lat,t.lng,c,e),w(o.floorId,o.lat,o.lng,c,e),e,a,u,n)}(t,o,d,e),findAllShortestPaths:function(t,o,e){if(!t.floorId)throw Error("attempt to find a shortest path with null floorId");const n=t.lat||t.latitude,r=t.lng||t.longitude,s=w(t.floorId,n,r,c,d),i=o.map((t=>w(t.floorId,t.lat,t.lng,c,d)));return s&&i.length?function(t,o,e,n={},r={},s={}){return o.map((o=>{try{return I(t,o,e,n,r,s)}catch(t){return null}}))}(s,i,d,a,u,e):[]},floorIdToOrdinal:i,floorIdToStructureId:l,updateWithSecurityWaitTime:function(t){a=e(n(["lastUpdated"]),t),y()},clearCache:y}}function f(t,o,e){const n=e[t],r=e[o];return l(n.lat,n.lng,r.lat,r.lng)}let c,a,h,g,p,m;const y=()=>{c={},a={},h={},g=new u,p=null,m={}};function I(t,o,e,n={},s={},i={}){for(t.id===p&&m===JSON.stringify(i)||(y(),g.offerWithPriority(t.id,0),c[t.id]=0,h[t.id]=!0,p=t.id,m=JSON.stringify(i));!g.isEmpty()&&!h[o.id];){const t=e[g.poll()],o=c[t.id];for(let e=0;e<t.edges.length;e++){const l=t.edges[e];if(h[l.dst])continue;if(i.requiresAccessibility&&!l.isAccessible)continue;let u=l.weight;if(l.o&&n[l.o]){const t=n[l.o];t.queueTime&&(u=t.queueTime),t.isTemporarilyClosed&&(u=9999),l.securityWaitTimes=t}if(l.o&&s[l.o]){l.securityLane=s[l.o];const{type:t,id:o}=s[l.o],e=r(["selectedSecurityLanes",t],i);if(e&&!e.includes(o))continue}void 0===c[l.dst]?(a[l.dst]=t,c[l.dst]=o+u,g.offerWithPriority(l.dst,o+u)):c[l.dst]>o+u&&(c[l.dst]=o+u,a[l.dst]=t,g.raisePriority(l.dst,o+u))}h[t.id]=!0}if(!h[o.id])return null;const l=[];let u=o;for(;u;)l.push(u),u=a[u.id];return l.reverse()}function b(t,o,e,n){const r=o.substr(0,n),s=[];s.push(t+":"+i(i(r,"top"),"left")),s.push(t+":"+i(r,"top")),s.push(t+":"+i(i(r,"top"),"right")),s.push(t+":"+i(r,"left")),s.push(t+":"+r),s.push(t+":"+i(r,"right")),s.push(t+":"+i(i(r,"bottom"),"left")),s.push(t+":"+i(r,"bottom")),s.push(t+":"+i(i(r,"bottom"),"right"));const l=[];for(let t=0;t<s.length;t++){const o=e[s[t]];if(o)for(let t=0;t<o.length;t++)l.push(o[t])}return l}function w(t,o,e,n,r){const i=function(t,o,e,n){let r=b(t,o,e,8);return r.length>0?r:(r=b(t,o,e,7),r.length>0?r:null)}(t,s(o,e),n)||function(t,o,e,n){const r=Object.values(n).filter((o=>o.floorId===t)).map((t=>[t,l([t.lat,t.lng],[o,e])]));if(!r.length)throw Error(`findClosestNode2 found no nodes on floor ${t}`);return function(t){let o=t[0];for(let e=1;e<t.length;e++)t[e][1]<o[1]&&(o=t[e]);return o[0]}(r)}(t,o,e,r),u=[];for(let t=0;t<i.length;t++){const n=l(o,e,i[t].lat,i[t].lng);u.push([i[t],n])}u.sort((function(t,o){return t[1]-o[1]}));const d=[];for(let t=0;t<u.length;t++)d.push(u[t][0]);return d[0]}export{d as createNavGraph,I as findShortestPath};
|