atriusmaps-node-sdk 3.3.196 → 3.3.226

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.
Files changed (109) hide show
  1. package/dist/cjs/_virtual/_empty_module_placeholder.js +2 -2
  2. package/dist/cjs/deploy/prepareSDKConfig.js +152 -2
  3. package/dist/cjs/nodesdk/nodeEntry.js +109 -0
  4. package/dist/cjs/package.json.js +190 -14
  5. package/dist/cjs/plugins/clientAPI/src/clientAPI.js +11 -2
  6. package/dist/cjs/plugins/dynamicPois/src/dynamicPois.js +218 -21
  7. package/dist/cjs/plugins/poiDataManager/src/poiDataManager.js +292 -21
  8. package/dist/cjs/plugins/sdkServer/src/sdkHeadless.js +99 -20
  9. package/dist/cjs/plugins/sdkServer/src/sdkServer.js +219 -2
  10. package/dist/cjs/plugins/sdkServer/src/util.js +16 -3
  11. package/dist/cjs/plugins/searchService/src/poiSearch.js +57 -19
  12. package/dist/cjs/plugins/searchService/src/searchService.js +246 -21
  13. package/dist/cjs/plugins/searchService/src/searchTypeahead.js +60 -3
  14. package/dist/cjs/plugins/searchService/src/utils.js +23 -4
  15. package/dist/cjs/plugins/venueDataLoader/src/venueDataLoader.js +472 -21
  16. package/dist/cjs/plugins/venueDataLoader/src/venueLoadingUtils.js +191 -23
  17. package/dist/cjs/plugins/wayfinder/src/findRoute.js +147 -19
  18. package/dist/cjs/plugins/wayfinder/src/minPriorityQueue.js +88 -2
  19. package/dist/cjs/plugins/wayfinder/src/navGraph.js +393 -5
  20. package/dist/cjs/plugins/wayfinder/src/navGraphDebug.js +110 -20
  21. package/dist/cjs/plugins/wayfinder/src/segmentBadges.js +28 -2
  22. package/dist/cjs/plugins/wayfinder/src/segmentBuilder.js +257 -19
  23. package/dist/cjs/plugins/wayfinder/src/segmentCategories.js +29 -2
  24. package/dist/cjs/plugins/wayfinder/src/stepBuilder.js +238 -3
  25. package/dist/cjs/plugins/wayfinder/src/wayfinder.js +597 -22
  26. package/dist/cjs/src/app.js +191 -25
  27. package/dist/cjs/src/configs/postproc-mol-url-parms.js +58 -2
  28. package/dist/cjs/src/configs/postproc-stateTracking.js +53 -19
  29. package/dist/cjs/src/controller.js +43 -4
  30. package/dist/cjs/src/debugTools.js +128 -23
  31. package/dist/cjs/src/env.js +17 -2
  32. package/dist/cjs/src/extModules/bustle.js +128 -4
  33. package/dist/cjs/src/extModules/flexapi/src/help.js +23 -4
  34. package/dist/cjs/src/extModules/flexapi/src/index.js +65 -4
  35. package/dist/cjs/src/extModules/flexapi/src/validate.js +133 -5
  36. package/dist/cjs/src/extModules/geohasher.js +90 -3
  37. package/dist/cjs/src/extModules/log.js +69 -2
  38. package/dist/cjs/src/historyManager.js +29 -2
  39. package/dist/cjs/src/utils/bounds.js +22 -4
  40. package/dist/cjs/src/utils/buildStructureLookup.js +31 -19
  41. package/dist/cjs/src/utils/configUtils.js +71 -3
  42. package/dist/cjs/src/utils/dom.js +48 -5
  43. package/dist/cjs/src/utils/funcs.js +30 -3
  44. package/dist/cjs/src/utils/geodesy.js +35 -3
  45. package/dist/cjs/src/utils/geom.js +209 -27
  46. package/dist/cjs/src/utils/i18n.js +69 -5
  47. package/dist/cjs/src/utils/observable.js +73 -2
  48. package/dist/cjs/src/utils/rand.js +82 -3
  49. package/dist/nodesdk/nodeEntry.js +1 -0
  50. package/dist/package.json.js +1 -0
  51. package/dist/plugins/searchService/src/searchService.js +1 -0
  52. package/dist/plugins/venueDataLoader/src/venueDataLoader.js +1 -0
  53. package/dist/plugins/venueDataLoader/src/venueLoadingUtils.js +1 -0
  54. package/dist/src/app.js +1 -0
  55. package/package.json +13 -9
  56. package/.yarnrc.yml +0 -1
  57. package/config/rollup.config.cjs.js +0 -31
  58. package/dist/cjs/deploy/nodeEntry.js +0 -20
  59. package/dist/cjs/src/auth/Auth.js +0 -23
  60. package/lib/deploy/nodeEntry.js +0 -1
  61. package/lib/package.json.js +0 -1
  62. package/lib/plugins/searchService/src/searchService.js +0 -1
  63. package/lib/plugins/venueDataLoader/src/venueDataLoader.js +0 -1
  64. package/lib/plugins/venueDataLoader/src/venueLoadingUtils.js +0 -1
  65. package/lib/src/app.js +0 -1
  66. package/lib/src/configs/sdkHeadless.json +0 -28
  67. /package/{lib → dist}/_virtual/_empty_module_placeholder.js +0 -0
  68. /package/{lib → dist}/deploy/prepareSDKConfig.js +0 -0
  69. /package/{lib → dist}/plugins/clientAPI/src/clientAPI.js +0 -0
  70. /package/{lib → dist}/plugins/dynamicPois/src/dynamicPois.js +0 -0
  71. /package/{lib → dist}/plugins/poiDataManager/src/poiDataManager.js +0 -0
  72. /package/{lib → dist}/plugins/sdkServer/src/sdkHeadless.js +0 -0
  73. /package/{lib → dist}/plugins/sdkServer/src/sdkServer.js +0 -0
  74. /package/{lib → dist}/plugins/sdkServer/src/util.js +0 -0
  75. /package/{lib → dist}/plugins/searchService/src/poiSearch.js +0 -0
  76. /package/{lib → dist}/plugins/searchService/src/searchTypeahead.js +0 -0
  77. /package/{lib → dist}/plugins/searchService/src/utils.js +0 -0
  78. /package/{lib → dist}/plugins/wayfinder/src/findRoute.js +0 -0
  79. /package/{lib → dist}/plugins/wayfinder/src/minPriorityQueue.js +0 -0
  80. /package/{lib → dist}/plugins/wayfinder/src/navGraph.js +0 -0
  81. /package/{lib → dist}/plugins/wayfinder/src/navGraphDebug.js +0 -0
  82. /package/{lib → dist}/plugins/wayfinder/src/segmentBadges.js +0 -0
  83. /package/{lib → dist}/plugins/wayfinder/src/segmentBuilder.js +0 -0
  84. /package/{lib → dist}/plugins/wayfinder/src/segmentCategories.js +0 -0
  85. /package/{lib → dist}/plugins/wayfinder/src/stepBuilder.js +0 -0
  86. /package/{lib → dist}/plugins/wayfinder/src/wayfinder.js +0 -0
  87. /package/{lib → dist}/src/configs/postproc-mol-url-parms.js +0 -0
  88. /package/{lib → dist}/src/configs/postproc-stateTracking.js +0 -0
  89. /package/{lib → dist}/src/configs/sdkHeadless.json.js +0 -0
  90. /package/{lib → dist}/src/controller.js +0 -0
  91. /package/{lib → dist}/src/debugTools.js +0 -0
  92. /package/{lib → dist}/src/env.js +0 -0
  93. /package/{lib → dist}/src/extModules/bustle.js +0 -0
  94. /package/{lib → dist}/src/extModules/flexapi/src/help.js +0 -0
  95. /package/{lib → dist}/src/extModules/flexapi/src/index.js +0 -0
  96. /package/{lib → dist}/src/extModules/flexapi/src/validate.js +0 -0
  97. /package/{lib → dist}/src/extModules/geohasher.js +0 -0
  98. /package/{lib → dist}/src/extModules/log.js +0 -0
  99. /package/{lib → dist}/src/historyManager.js +0 -0
  100. /package/{lib → dist}/src/utils/bounds.js +0 -0
  101. /package/{lib → dist}/src/utils/buildStructureLookup.js +0 -0
  102. /package/{lib → dist}/src/utils/configUtils.js +0 -0
  103. /package/{lib → dist}/src/utils/dom.js +0 -0
  104. /package/{lib → dist}/src/utils/funcs.js +0 -0
  105. /package/{lib → dist}/src/utils/geodesy.js +0 -0
  106. /package/{lib → dist}/src/utils/geom.js +0 -0
  107. /package/{lib → dist}/src/utils/i18n.js +0 -0
  108. /package/{lib → dist}/src/utils/observable.js +0 -0
  109. /package/{lib → dist}/src/utils/rand.js +0 -0
@@ -2,13 +2,401 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var e = require('ramda');
5
+ var R = require('ramda');
6
6
  var geohasher = require('../../../src/extModules/geohasher.js');
7
7
  var geodesy = require('../../../src/utils/geodesy.js');
8
8
  var minPriorityQueue = require('./minPriorityQueue.js');
9
9
 
10
- const d=9999;function f(r,s,l,u){const d={},f={};let a={};r.nodes.forEach((o=>{const n=s(o.floorId),e$1=l(o.floorId);!function(t){const o=t.floorId+":"+geohasher.encode(t.lat,t.lng).substr(0,7),n=t.floorId+":"+geohasher.encode(t.lat,t.lng).substr(0,8);f[o]||(f[o]=[]);f[o].push(t),f[n]||(f[n]=[]);f[n].push(t),d[t.id]=t;}({...e.pick(["id","lat","lng","floorId"],o),edges:[],ordinal:n,structureId:e$1});})),r.edges.forEach((t=>d[t.s].edges.push(function(t,n){const e$1=function(t){return t.x?"Security Checkpoint":""===t.t?"Ground":t.t}(t),r="escalator"!==e$1.toLowerCase()&&"stairs"!==e$1.toLowerCase(),i=c(t.s,t.d,n),s=t.l||i/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:i,dst:t.d,o:t.o,isAccessible:r,isDriveway:!e.isNil(t.h)&&!t.h,src:t.s,transitTime:s,type:e$1,path:u,weight:s}}(t,d))));const h=t=>{if(void 0===t.floorId&&void 0===t.ordinal)throw Error("Endpoint specified in findRoute without floorId nor an ordinal");const o=t.lat||t.latitude,n=t.lng||t.longitude;return t.floorId?C(t.floorId,o,n,f,d):S(t.ordinal,o,n,d)};return {_nodes:d,_geoDb:f,findClosestNode:(t,o,n)=>C(t,o,n,f,d),findShortestPath:(t,o,n)=>function(t,o,n,e={}){return b(h(t),h(o),n,a,u,e)}(t,o,d,n),findAllShortestPaths:function(t,o,n){const e=h(t),r=o.map((t=>h(t)));return e&&r.length?function(t,o,n,e={},r={},i={}){return o.map((o=>{try{return b(t,o,n,e,r,i)}catch(t){return null}}))}(e,r,d,a,u,n):[]},floorIdToOrdinal:s,floorIdToStructureId:l,updateWithSecurityWaitTime:function(t){a=e.map(e.omit(["lastUpdated"]),t),I();},clearCache:I}}function c(t,o,n){const e=n[t],r=n[o];return geodesy.distance(e.lat,e.lng,r.lat,r.lng)}let a,h,p,g,m,y;const I=()=>{a={},h={},p={},g=new minPriorityQueue,m=null,y={};};function b(t,o,n,e$1={},i={},s={}){for(t.id===m&&y===JSON.stringify(s)||(I(),g.offerWithPriority(t.id,0),a[t.id]=0,p[t.id]=!0,m=t.id,y=JSON.stringify(s));!g.isEmpty()&&!p[o.id];){const t=n[g.poll()],o=a[t.id];for(let n=0;n<t.edges.length;n++){const l=t.edges[n];if(p[l.dst])continue;if(s.requiresAccessibility&&!l.isAccessible)continue;let u=l.weight;if(l.o&&e$1[l.o]){const t=e$1[l.o];t.queueTime&&(u=t.queueTime),t.isTemporarilyClosed&&(u=d),l.securityWaitTimes=t;}if(l.o&&i[l.o]){l.securityLane=i[l.o];const{type:t,id:o}=i[l.o],n=e.path(["selectedSecurityLanes",t],s);if(n&&!n.includes(o))continue}void 0===a[l.dst]?(h[l.dst]=t,a[l.dst]=o+u,g.offerWithPriority(l.dst,o+u)):a[l.dst]>o+u&&(a[l.dst]=o+u,h[l.dst]=t,g.raisePriority(l.dst,o+u));}p[t.id]=!0;}if(!p[o.id])return null;const l=[];let u=o;for(;u;)l.push(u),u=h[u.id];return l.reverse()}function w(t,o,n,e){const r=o.substr(0,e),i=[];i.push(t+":"+geohasher.calculateAdjacent(geohasher.calculateAdjacent(r,"top"),"left")),i.push(t+":"+geohasher.calculateAdjacent(r,"top")),i.push(t+":"+geohasher.calculateAdjacent(geohasher.calculateAdjacent(r,"top"),"right")),i.push(t+":"+geohasher.calculateAdjacent(r,"left")),i.push(t+":"+r),i.push(t+":"+geohasher.calculateAdjacent(r,"right")),i.push(t+":"+geohasher.calculateAdjacent(geohasher.calculateAdjacent(r,"bottom"),"left")),i.push(t+":"+geohasher.calculateAdjacent(r,"bottom")),i.push(t+":"+geohasher.calculateAdjacent(geohasher.calculateAdjacent(r,"bottom"),"right"));const l=[];for(let t=0;t<i.length;t++){const o=n[i[t]];if(o)for(let t=0;t<o.length;t++)l.push(o[t]);}return l}function C(t,o,n,e,r){const s=function(t,o,n,e){let r=w(t,o,n,8);return r.length>0?r:(r=w(t,o,n,7),r.length>0?r:null)}(t,geohasher.encode(o,n),e)||function(t,o,n,e){const r=Object.values(e).filter((o=>o.floorId===t)).map((t=>[t,geodesy.distance(t.lat,t.lng,o,n)]));if(!r.length)throw Error(`findClosestNodeByFloor2 found no nodes on floor ${t}`);return T(r)}(t,o,n,r),u=[];for(let t=0;t<s.length;t++){const e=geodesy.distance(o,n,s[t].lat,s[t].lng);u.push([s[t],e]);}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]}function S(t,o,n,e){const r=Object.values(e).filter((o=>o.ordinal===t)).map((t=>[t,geodesy.distance(t.lat,t.lng,o,n)]));if(!r.length)throw Error(`findClosestNodeByOrdinal found no nodes on ordinal ${t}`);return T(r)}function T(t){let o=t[0];for(let n=1;n<t.length;n++)t[n][1]<o[1]&&(o=t[n]);return o[0]}
10
+ const DEFAULT_WALKING_SPEED_M_PER_MIN = 60;
11
+ const CLOSED_CHECKPOINT_EDGE_WEIGHT = 9999;
11
12
 
12
- exports.createNavGraph = f;
13
- exports.findClosestNodeByOrdinal = S;
14
- exports.findShortestPath = b;
13
+ /**
14
+ * @typedef NavNode
15
+ * @property {number} ordinal
16
+ * @property {Array.<NavEdge>} edges
17
+ * @property {string} id
18
+ * @property {number} lat
19
+ * @property {number} lng
20
+ * @property {string} floorId
21
+ * @property {structureId} structureId
22
+ *
23
+ * @typedef NavEdge
24
+ * @property {string} dst - id of node at edge end
25
+ * @property {string} src - id of node at edge start
26
+ * @property {number} distance
27
+ * @property {string|undefined} o - id of security lane POI associated with this edge
28
+ * @property {CurvedPath|null} path - list of Bezier points if edge represents curve
29
+ * @property {boolean} isAccessible
30
+ * @property {boolean} isDriveway - true if edge points to POI, false if edge just connects other edges
31
+ * @property {number} transitTime
32
+ * @property {string} type
33
+ * @property {number} weight - value used by Dijkstra algorithm (usually edge time or distance)
34
+ *
35
+ * @param {RawNavGraph} data
36
+ * @param {function} floorIdToOrdinal
37
+ * @param {function} floorIdToStructureId
38
+ * @param {Array.<SecurityLane>} securityLanesMap - list of security lanes
39
+ * @return {Object}
40
+ */
41
+ // todo remove dead commented code
42
+ function createNavGraph (data, floorIdToOrdinal, floorIdToStructureId, securityLanesMap) {
43
+ const nodes = { };
44
+ const geoDb = { };
45
+ let securityWaitTimes = {};
46
+
47
+ data.nodes.forEach(nodeData => {
48
+ const ordinal = floorIdToOrdinal(nodeData.floorId);
49
+ const structureId = floorIdToStructureId(nodeData.floorId);
50
+ const node = {
51
+ ...R.pick(['id', 'lat', 'lng', 'floorId'], nodeData),
52
+ edges: [],
53
+ ordinal,
54
+ structureId
55
+ };
56
+ addNode(node);
57
+ });
58
+
59
+ data.edges.forEach(ed => nodes[ed.s].edges.push(createEdge(ed, nodes)));
60
+
61
+ function addNode (node) {
62
+ const largeGeo = node.floorId + ':' + geohasher.encode(node.lat, node.lng).substr(0, 7);
63
+ const mediumGeo = node.floorId + ':' + geohasher.encode(node.lat, node.lng).substr(0, 8);
64
+
65
+ if (!geoDb[largeGeo])
66
+ geoDb[largeGeo] = [];
67
+
68
+ geoDb[largeGeo].push(node);
69
+
70
+ if (!geoDb[mediumGeo])
71
+ geoDb[mediumGeo] = [];
72
+
73
+ geoDb[mediumGeo].push(node);
74
+
75
+ nodes[node.id] = node;
76
+ }
77
+
78
+ function createEdge (data, nodes) {
79
+ const type = getEdgeType(data);
80
+ const isAccessible = type.toLowerCase() !== 'escalator' && type.toLowerCase() !== 'stairs';
81
+ // todo consider calculating edge distance with 'path' differently
82
+ const distance = distanceBetweenNodes(data.s, data.d, nodes);
83
+ const transitTime = data.l || distance / DEFAULT_WALKING_SPEED_M_PER_MIN;
84
+
85
+ const buildCurvedPath = points => points.map(point => {
86
+ return {
87
+ start: { lat: point.s[0], lng: point.s[1] },
88
+ out: { lat: point.o[0], lng: point.o[1] },
89
+ in: { lat: point.i[0], lng: point.i[1] },
90
+ end: { lat: point.e[0], lng: point.e[1] }
91
+ }
92
+ });
93
+
94
+ const path = data.p ? buildCurvedPath(data.p) : null;
95
+
96
+ return {
97
+ distance,
98
+ dst: data.d,
99
+ o: data.o,
100
+ isAccessible,
101
+ isDriveway: !R.isNil(data.h) && !data.h,
102
+ src: data.s,
103
+ transitTime,
104
+ type,
105
+ path,
106
+ weight: transitTime
107
+ }
108
+ }
109
+
110
+ function getEdgeType (data) {
111
+ if (data.x) return 'Security Checkpoint'
112
+ if (data.t === '') return 'Ground'
113
+ return data.t
114
+ }
115
+
116
+ const findClosestNode = endpoint => {
117
+ if (endpoint.floorId === undefined && endpoint.ordinal === undefined) // one of these must be present
118
+ throw Error('Endpoint specified in findRoute without floorId nor an ordinal')
119
+ const lat = endpoint.lat || endpoint.latitude; // handle bluedot location
120
+ const lng = endpoint.lng || endpoint.longitude; // handle bluedot location
121
+ return endpoint.floorId
122
+ ? findClosestNodeByFloor(endpoint.floorId, lat, lng, geoDb, nodes)
123
+ : findClosestNodeByOrdinal(endpoint.ordinal, lat, lng, nodes)
124
+ };
125
+
126
+ function findShortestPathEntry (start, end, nodes, options = {}) {
127
+ const startNode = findClosestNode(start);
128
+ const endNode = findClosestNode(end);
129
+
130
+ // This code section does improve performance by about 10-20%, but comes at a cost
131
+ // of making the caching unusable in some cases
132
+ // if (start.structureId === end.structureId) {
133
+ // options.minOrd = Math.min(start.ordinal, end.ordinal)
134
+ // options.maxOrd = Math.max(start.ordinal, end.ordinal)
135
+ // options.structureId = start.structureId
136
+ // }
137
+ return findShortestPath(startNode, endNode, nodes, securityWaitTimes, securityLanesMap, options)
138
+ }
139
+ /**
140
+ * @param {Endpoint} start - start endpoint
141
+ * @param {Array.<Endpoint>} destArray - list of destinations
142
+ * @param {RouteOptions} options extra options (such as requireAccessibility)
143
+ * @returns {Array.<Array.<NavNode>>} array of routes corresponding to destinations specified
144
+ */
145
+ function findAllShortestPaths (start, destArray, options) {
146
+ const startNode = findClosestNode(start);
147
+ const destNodeArray = destArray.map(dest => findClosestNode(dest));
148
+ if (!startNode || !destNodeArray.length) return []
149
+ return findAllShortestPathsImpl(startNode, destNodeArray, nodes, securityWaitTimes, securityLanesMap, options)
150
+ }
151
+
152
+ function updateWithSecurityWaitTime (waitTimesData) {
153
+ securityWaitTimes = R.map(R.omit(['lastUpdated']), waitTimesData);
154
+ clearCache();
155
+ }
156
+
157
+ return {
158
+ _nodes: nodes,
159
+ _geoDb: geoDb,
160
+ findClosestNode: (floorId, lat, lng) => findClosestNodeByFloor(floorId, lat, lng, geoDb, nodes),
161
+ findShortestPath: (start, end, options) => findShortestPathEntry(start, end, nodes, options),
162
+ findAllShortestPaths,
163
+ floorIdToOrdinal, // todo lets get rid of this...
164
+ floorIdToStructureId, // todo lets get rid of this...,
165
+ updateWithSecurityWaitTime,
166
+ clearCache
167
+ }
168
+ }
169
+
170
+ function distanceBetweenNodes (n1, n2, nodes) {
171
+ const node1 = nodes[n1];
172
+ const node2 = nodes[n2];
173
+ const distance = geodesy.distance(node1.lat, node1.lng, node2.lat, node2.lng);
174
+ return distance
175
+ }
176
+
177
+ /**
178
+ * @param {Object.<Node>} start - a node in the navGraph to start on
179
+ * @param {Array.<Node>} destinations - array of nodes to find path to
180
+ * @param {Object.<string, NavNode>} nodes - dictionary of nodes by id
181
+ * @param {Object.<string, SecurityWaitTime>} securityWaitTimes - map of POI id to security wait time
182
+ * @param {Object.<string, SecurityLane>} securityLanesMap - map of POI id to security lane
183
+ * @param {RouteOptions} [options={}] extra options (such as requireAccessibility)
184
+ * @returns {Array.<Array.<Node>>} list of shortest path to each destination
185
+ */
186
+ function findAllShortestPathsImpl (start, destinations, nodes, securityWaitTimes = {}, securityLanesMap = {}, options = {}) {
187
+ // const previous = findPaths(start, start, nodes, options)
188
+
189
+ // const backtrackPath = node => buildBacktrackPath(nodes, previous, node)
190
+ // const poiNodeTuples = Array.from(destinations.entries())
191
+
192
+ // const poiPathTuples = poiNodeTuples.map(([poi, node]) => [poi, backtrackPath(node)])
193
+ // return new Map(poiPathTuples)
194
+ return destinations.map(d => {
195
+ try {
196
+ return findShortestPath(start, d, nodes, securityWaitTimes, securityLanesMap, options)
197
+ } catch (e) { return null }
198
+ })
199
+ }
200
+
201
+ let cost, prev, visited, visitQueue, lastStartId, lastOptionsStr;
202
+
203
+ const clearCache = () => {
204
+ cost = { };
205
+ prev = { };
206
+ visited = { };
207
+ visitQueue = new minPriorityQueue();
208
+ lastStartId = null;
209
+ lastOptionsStr = {};
210
+ };
211
+
212
+ // This is a temporary name during a "probation" period - then I will
213
+ // ditch findShortestPath and rewrite findAllShortestPaths and ditch
214
+ // backtrackPath, etc.
215
+ // NOTE: export just for testing
216
+ /**
217
+ * @param {Object<Node>} start a node in the navGraph to start on
218
+ * @param {Object<Node>} end a node in the navGraph to find path to
219
+ * @param {Object.<string, Node>} nodes dictionary of nodes by id
220
+ * @param {Object.<string, SecurityWaitTime>} securityWaitTimes - map of POI id to security wait time
221
+ * @param {Object.<string, SecurityLane>} securityLanesMap - map of POI id to security lane
222
+ * @param {RouteOptions} options={} extra options (such as requireAccessibility)
223
+ * @returns {Array.<Node>} an array of nodes that represent the shortest route from start to end. null if no route exists.
224
+ */
225
+ function findShortestPath (start, end, nodes, securityWaitTimes = {}, securityLanesMap = {}, options = { }) {
226
+ if (start.id !== lastStartId || lastOptionsStr !== JSON.stringify(options)) {
227
+ clearCache();
228
+ visitQueue.offerWithPriority(start.id, 0);
229
+ cost[start.id] = 0;
230
+ visited[start.id] = true;
231
+
232
+ lastStartId = start.id;
233
+ lastOptionsStr = JSON.stringify(options);
234
+ }
235
+
236
+ // continue crawling paths - but stop once we found destination
237
+ while (!visitQueue.isEmpty() && !visited[end.id]) {
238
+ const node = nodes[visitQueue.poll()]; // pop
239
+ const ccost = cost[node.id]; // current cost to this node
240
+ for (let ei = 0; ei < node.edges.length; ei++) {
241
+ const e = node.edges[ei]; // next edge from this node
242
+
243
+ if (visited[e.dst])
244
+ continue
245
+
246
+ if (options.requiresAccessibility && !e.isAccessible) {
247
+ // ignore not accessible edges if we're looking for an accessible route
248
+ continue
249
+ }
250
+
251
+ // This code section does improve performance by about 10-20%, but comes at a cost
252
+ // of making the caching unusable in some cases
253
+ // if ((options.minOrd !== undefined && nodes[e.dst].ordinal < options.minOrd) ||
254
+ // (options.maxOrd !== undefined && nodes[e.dst].ordinal > options.maxOrd) ||
255
+ // (options.structureId !== undefined && nodes[e.dst].structureId !== options.structureId))
256
+ // continue
257
+
258
+ let weight = e.weight;
259
+ if (e.o && securityWaitTimes[e.o]) {
260
+ const dynamicData = securityWaitTimes[e.o];
261
+ if (dynamicData.queueTime) weight = dynamicData.queueTime;
262
+ if (dynamicData.isTemporarilyClosed) weight = CLOSED_CHECKPOINT_EDGE_WEIGHT;
263
+ e.securityWaitTimes = dynamicData;
264
+ }
265
+
266
+ if (e.o && securityLanesMap[e.o]) {
267
+ e.securityLane = securityLanesMap[e.o];
268
+ const { type, id } = securityLanesMap[e.o];
269
+ const securityLanesIds = R.path(['selectedSecurityLanes', type], options);
270
+ if (securityLanesIds && !securityLanesIds.includes(id))
271
+ continue
272
+ }
273
+
274
+ if (cost[e.dst] === undefined) {
275
+ prev[e.dst] = node;
276
+ cost[e.dst] = ccost + weight;
277
+ visitQueue.offerWithPriority(e.dst, ccost + weight); // add node to the toCheck array
278
+ } else
279
+ if (cost[e.dst] > (ccost + weight)) { // is this a shorter path? Relaxation...
280
+ // if so, update the cost and parent
281
+ cost[e.dst] = ccost + weight;
282
+ prev[e.dst] = node;
283
+ visitQueue.raisePriority(e.dst, ccost + weight);
284
+ }
285
+ }
286
+ visited[node.id] = true; // we have now been selected
287
+ }
288
+
289
+ if (!visited[end.id]) // if we never found our endpoint, it was inaccessible
290
+ return null
291
+
292
+ // build the path and return it
293
+ const path = [];
294
+ let node = end;
295
+ while (node) {
296
+ path.push(node);
297
+ node = prev[node.id];
298
+ }
299
+ return path.reverse()
300
+ }
301
+
302
+ function geohashSearch (floorId, geohash, geoDb, size) {
303
+ const geohashPrefix = geohash.substr(0, size);
304
+
305
+ const searchGeos = [];
306
+ searchGeos.push(floorId + ':' + geohasher.calculateAdjacent(geohasher.calculateAdjacent(geohashPrefix, 'top'), 'left'));
307
+ searchGeos.push(floorId + ':' + geohasher.calculateAdjacent(geohashPrefix, 'top'));
308
+ searchGeos.push(floorId + ':' + geohasher.calculateAdjacent(geohasher.calculateAdjacent(geohashPrefix, 'top'), 'right'));
309
+ searchGeos.push(floorId + ':' + geohasher.calculateAdjacent(geohashPrefix, 'left'));
310
+ searchGeos.push(floorId + ':' + geohashPrefix);
311
+ searchGeos.push(floorId + ':' + geohasher.calculateAdjacent(geohashPrefix, 'right'));
312
+ searchGeos.push(floorId + ':' + geohasher.calculateAdjacent(geohasher.calculateAdjacent(geohashPrefix, 'bottom'), 'left'));
313
+ searchGeos.push(floorId + ':' + geohasher.calculateAdjacent(geohashPrefix, 'bottom'));
314
+ searchGeos.push(floorId + ':' + geohasher.calculateAdjacent(geohasher.calculateAdjacent(geohashPrefix, 'bottom'), 'right'));
315
+
316
+ const nodes = [];
317
+ for (let i = 0; i < searchGeos.length; i++) {
318
+ const nodesFound = geoDb[searchGeos[i]];
319
+ if (nodesFound) {
320
+ for (let j = 0; j < nodesFound.length; j++)
321
+ nodes.push(nodesFound[j]);
322
+ }
323
+ }
324
+
325
+ return nodes
326
+ }
327
+
328
+ function findNodesByGeohash (floorId, geohash, geoDb, nodes) {
329
+ let foundNodes = geohashSearch(floorId, geohash, geoDb, 8);
330
+ if (foundNodes.length > 0)
331
+ return foundNodes
332
+
333
+ // broaden our search a bit and try again...
334
+ foundNodes = geohashSearch(floorId, geohash, geoDb, 7);
335
+ if (foundNodes.length > 0)
336
+ return foundNodes
337
+
338
+ // give up and let someone else try...
339
+ return null
340
+ }
341
+
342
+ /**
343
+ * @param floorId
344
+ * @param lat
345
+ * @param lng
346
+ * @param geoDb
347
+ * @param {Object<string, NavNode>} nodes - dictionary of node id to node object
348
+ * @return {NavNode} - node that is on the same floor and closest to the lat,lng point
349
+ */
350
+ function findClosestNodeByFloor (floorId, lat, lng, geoDb, nodes) {
351
+ const cnodes = findNodesByGeohash(floorId, geohasher.encode(lat, lng), geoDb) ||
352
+ findClosestNodeByFloor2(floorId, lat, lng, nodes);
353
+
354
+ const nodeWithDistance = [];
355
+ for (let i = 0; i < cnodes.length; i++) {
356
+ // Attached distance to each node from the origin.
357
+ const distance = geodesy.distance(lat, lng, cnodes[i].lat, cnodes[i].lng);
358
+ nodeWithDistance.push([cnodes[i], distance]);
359
+ }
360
+ // todo do not sort, just find min node
361
+ // Sort by distance.
362
+ nodeWithDistance.sort(function (a, b) { return a[1] - b[1] });
363
+ const nodesSortedByDistance = [];
364
+ for (let i = 0; i < nodeWithDistance.length; i++)
365
+ nodesSortedByDistance.push(nodeWithDistance[i][0]);
366
+
367
+ return nodesSortedByDistance[0]
368
+ }
369
+
370
+ // A slightly slower alternative to findClosestNode (an experiment - its simpler, but slower)
371
+ function findClosestNodeByFloor2 (floorId, lat, lng, nodes) {
372
+ const floorNodes = Object.values(nodes)
373
+ .filter(n => n.floorId === floorId)
374
+ .map(n => [n, geodesy.distance(n.lat, n.lng, lat, lng)]);
375
+ if (!floorNodes.length)
376
+ throw Error(`findClosestNodeByFloor2 found no nodes on floor ${floorId}`)
377
+ return selectShortest(floorNodes)
378
+ }
379
+
380
+ function findClosestNodeByOrdinal (ord, lat, lng, nodes) {
381
+ const ordNodes = Object.values(nodes)
382
+ .filter(n => n.ordinal === ord)
383
+ .map(n => [n, geodesy.distance(n.lat, n.lng, lat, lng)]);
384
+ if (!ordNodes.length)
385
+ throw Error(`findClosestNodeByOrdinal found no nodes on ordinal ${ord}`)
386
+ return selectShortest(ordNodes)
387
+ }
388
+
389
+ // companion to above function - it returns closest node
390
+ // ar is 2-dim array - ar[i][0] = node, ar[i][1] = distance
391
+ // TODO: use this approach in findClosestNode - no need to sort first!
392
+ function selectShortest (ar) {
393
+ let shortest = ar[0];
394
+ for (let i = 1; i < ar.length; i++)
395
+ if (ar[i][1] < shortest[1]) shortest = ar[i];
396
+
397
+ return shortest[0]
398
+ }
399
+
400
+ exports.createNavGraph = createNavGraph;
401
+ exports.findClosestNodeByOrdinal = findClosestNodeByOrdinal;
402
+ exports.findShortestPath = findShortestPath;
@@ -2,29 +2,119 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var e$1 = require('ramda');
5
+ var R = require('ramda');
6
6
 
7
7
  function _interopNamespace(e) {
8
- if (e && e.__esModule) return e;
9
- var n = Object.create(null);
10
- if (e) {
11
- Object.keys(e).forEach(function (k) {
12
- if (k !== 'default') {
13
- var d = Object.getOwnPropertyDescriptor(e, k);
14
- Object.defineProperty(n, k, d.get ? d : {
15
- enumerable: true,
16
- get: function () { return e[k]; }
17
- });
18
- }
19
- });
20
- }
21
- n["default"] = e;
22
- return Object.freeze(n);
8
+ if (e && e.__esModule) return e;
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n["default"] = e;
22
+ return Object.freeze(n);
23
23
  }
24
24
 
25
- var e__namespace = /*#__PURE__*/_interopNamespace(e$1);
25
+ var R__namespace = /*#__PURE__*/_interopNamespace(R);
26
26
 
27
- function e(e,s){const o=Object.values(e),n=function(a,e){const s=[e],o=new Set;for(;s.length;){const e=s.splice(0,1)[0];e&&!o.has(e)&&(o.add(e),e.edges.forEach((e=>{o.has(a[e.dst])||s.push(a[e.dst]);})));}return o}(e,s||o[0]),r=o.filter((a=>!n.has(a)));return console.log(`${r.length} Orphaned nodes found from ${o.length} total`),{orphaned:r,orphanedByFloor:e__namespace.groupBy(e__namespace.prop("floorId"),r),connected:Array.from(n)}}const s=a=>({nodes:n(a),edges:r(a)}),o=e=>e__namespace.map(e__namespace.pipe(e__namespace.assoc("isOrphaned",e),e__namespace.dissoc("edges"))),n=e__namespace.pipe(e,e__namespace.pick(["connected","orphaned"]),e__namespace.evolve({connected:o(!1),orphaned:o(!0)}),e__namespace.values,e__namespace.flatten),r=a=>Object.values(a).flatMap((a=>a.edges)).map((e=>t(e,a))),t=({src:a,dst:e,type:s,isDriveway:o},n)=>({startCoordinates:[n[a].lng,n[a].lat],endCoordinates:[n[e].lng,n[e].lat],isDriveway:o,ordinal:n[a].ordinal,category:d(s),defaultStrokeColor:l(s)}),l=e__namespace.cond([[e__namespace.equals("Stairs"),e__namespace.always("#EFBC9B")],[e__namespace.equals("Elevator"),e__namespace.always("#A491D3")],[e__namespace.equals("Escalator"),e__namespace.always("#563F1B")],[e__namespace.equals("Ramp"),e__namespace.always("#DBD053")],[e__namespace.T,e__namespace.always("#FF0000")]]),d=e__namespace.cond([[e__namespace.equals("Train"),e__namespace.always("nav.train")],[e__namespace.equals("Bus"),e__namespace.always("nav.transit")],[e__namespace.equals("Security Checkpoint"),e__namespace.always("nav.secure")],[e__namespace.equals("Ground"),e__namespace.always("nav.primary")],[e__namespace.T,e__namespace.always("")]]);
27
+ /**
28
+ * Visits all nodes (breadth-first) from the nodes2visit
29
+ * array, adding them to vnodes and adding their connected
30
+ * nodes to nodes2visit - until nodes2visit is empty.
31
+ * Nothing is returned - but the vnodes array will have been
32
+ * altered.
33
+ * @param {Object.<id:node>} nodes - the node pool you wish to scan
34
+ * @param {Node} startingNode - which node to start the scan
35
+ */
36
+ function visitAll (nodes, startingNode) {
37
+ // initialize nodes2visit with the specified node to start
38
+ const nodes2visit = [startingNode];
39
+ const vnodes = new Set(); // visited nodes
28
40
 
29
- exports.enrichDebugNavGraph = s;
30
- exports.orphanTest = e;
41
+ while (nodes2visit.length) {
42
+ const node = nodes2visit.splice(0, 1)[0]; // next node to visit
43
+ if (node && !vnodes.has(node)) {
44
+ vnodes.add(node);
45
+ node.edges.forEach(edge => {
46
+ if (!vnodes.has(nodes[edge.dst]))
47
+ nodes2visit.push(nodes[edge.dst]);
48
+ });
49
+ }
50
+ }
51
+
52
+ return vnodes
53
+ }
54
+
55
+ /**
56
+ * @param {Object.<id:node>} nodes - the node pool you wish to scan
57
+ * @param {Node} [startingNode] - which node to start the scan (default: "first" node)
58
+ * @returns two arrays of nodes in an object, { orphaned, connected }
59
+ */
60
+ function orphanTest (nodes, startingNode) {
61
+ const nodesArray = Object.values(nodes); // Convert to array
62
+
63
+ const vnodes = visitAll(nodes, startingNode || nodesArray[0]); // If no node is specified, use the first one we find
64
+ const onodes = nodesArray.filter(n => !vnodes.has(n));
65
+
66
+ console.log(`${onodes.length} Orphaned nodes found from ${nodesArray.length} total`);
67
+
68
+ return { orphaned: onodes, orphanedByFloor: R__namespace.groupBy(R__namespace.prop('floorId'), onodes), connected: Array.from(vnodes) }
69
+ }
70
+
71
+ const enrichDebugNavGraph = (nodes) => ({
72
+ nodes: toOrphanedNodesArray(nodes),
73
+ edges: getNavEdgeFeatures(nodes)
74
+ });
75
+
76
+ const transformNodes = isOrphaned =>
77
+ R__namespace.map(R__namespace.pipe(R__namespace.assoc('isOrphaned', isOrphaned), R__namespace.dissoc('edges')));
78
+
79
+ const toOrphanedNodesArray = R__namespace.pipe(
80
+ orphanTest,
81
+ R__namespace.pick(['connected', 'orphaned']),
82
+ R__namespace.evolve({
83
+ connected: transformNodes(false),
84
+ orphaned: transformNodes(true)
85
+ }),
86
+ R__namespace.values,
87
+ R__namespace.flatten
88
+ );
89
+
90
+ const getNavEdgeFeatures = nodes =>
91
+ Object.values(nodes).flatMap(node => node.edges)
92
+ .map(edge => mapEdge(edge, nodes));
93
+
94
+ const mapEdge = ({ src, dst, type, isDriveway }, nodeMap) => ({
95
+ startCoordinates: [nodeMap[src].lng, nodeMap[src].lat],
96
+ endCoordinates: [nodeMap[dst].lng, nodeMap[dst].lat],
97
+ isDriveway,
98
+ ordinal: nodeMap[src].ordinal,
99
+ category: getEdgeCategory(type),
100
+ defaultStrokeColor: getStrokeColorForMissingCategory(type)
101
+ });
102
+
103
+ const getStrokeColorForMissingCategory = R__namespace.cond([
104
+ [R__namespace.equals('Stairs'), R__namespace.always('#EFBC9B')],
105
+ [R__namespace.equals('Elevator'), R__namespace.always('#A491D3')],
106
+ [R__namespace.equals('Escalator'), R__namespace.always('#563F1B')],
107
+ [R__namespace.equals('Ramp'), R__namespace.always('#DBD053')],
108
+ [R__namespace.T, R__namespace.always('#FF0000')]
109
+ ]);
110
+
111
+ const getEdgeCategory = R__namespace.cond([
112
+ [R__namespace.equals('Train'), R__namespace.always('nav.train')],
113
+ [R__namespace.equals('Bus'), R__namespace.always('nav.transit')],
114
+ [R__namespace.equals('Security Checkpoint'), R__namespace.always('nav.secure')],
115
+ [R__namespace.equals('Ground'), R__namespace.always('nav.primary')],
116
+ [R__namespace.T, R__namespace.always('')]
117
+ ]);
118
+
119
+ exports.enrichDebugNavGraph = enrichDebugNavGraph;
120
+ exports.orphanTest = orphanTest;
@@ -1,5 +1,31 @@
1
1
  'use strict';
2
2
 
3
- const n={START:"wayfinding.start",END:"wayfinding.end",WALKING_TO_SECURITY_CHECKPOINT:"wayfinding.security",ELEVATOR:"wayfinding.elevator",ELEVATOR_UP:"wayfinding.elevator.up",ELEVATOR_DOWN:"wayfinding.elevator.down",STAIRS:"wayfinding.stairs",STAIRS_UP:"wayfinding.stairs.up",STAIRS_DOWN:"wayfinding.stairs.down",ESCALATOR:"wayfinding.escalator",ESCALATOR_UP:"wayfinding.escalator.up",ESCALATOR_DOWN:"wayfinding.escalator.down",WALK:"wayfinding.movingwalkway",WALK_DOWN:"walk.movingwalkway",WALK_UP:"walk.movingwalkway",TRAIN:"wayfinding.train",TRAIN_UP:"wayfinding.train.up",TRAIN_DOWN:"wayfinding.train.down",BUS:"wayfinding.bus",BUS_UP:"wayfinding.bus.up",BUS_DOWN:"wayfinding.bus.down",SECURITY_CHECKPOINT:"wayfinding.security",RAMP:"wayfinding.ramp",RAMP_UP:"wayfinding.ramp.up",RAMP_DOWN:"wayfinding.ramp.down"};
3
+ const segmentBadges = {
4
+ START: 'wayfinding.start',
5
+ END: 'wayfinding.end',
6
+ WALKING_TO_SECURITY_CHECKPOINT: 'wayfinding.security',
7
+ ELEVATOR: 'wayfinding.elevator',
8
+ ELEVATOR_UP: 'wayfinding.elevator.up',
9
+ ELEVATOR_DOWN: 'wayfinding.elevator.down',
10
+ STAIRS: 'wayfinding.stairs',
11
+ STAIRS_UP: 'wayfinding.stairs.up',
12
+ STAIRS_DOWN: 'wayfinding.stairs.down',
13
+ ESCALATOR: 'wayfinding.escalator',
14
+ ESCALATOR_UP: 'wayfinding.escalator.up',
15
+ ESCALATOR_DOWN: 'wayfinding.escalator.down',
16
+ WALK: 'wayfinding.movingwalkway',
17
+ WALK_DOWN: 'walk.movingwalkway',
18
+ WALK_UP: 'walk.movingwalkway',
19
+ TRAIN: 'wayfinding.train',
20
+ TRAIN_UP: 'wayfinding.train.up',
21
+ TRAIN_DOWN: 'wayfinding.train.down',
22
+ BUS: 'wayfinding.bus',
23
+ BUS_UP: 'wayfinding.bus.up',
24
+ BUS_DOWN: 'wayfinding.bus.down',
25
+ SECURITY_CHECKPOINT: 'wayfinding.security',
26
+ RAMP: 'wayfinding.ramp',
27
+ RAMP_UP: 'wayfinding.ramp.up',
28
+ RAMP_DOWN: 'wayfinding.ramp.down'
29
+ };
4
30
 
5
- module.exports = n;
31
+ module.exports = segmentBadges;