venue-js 1.4.0-next.2 → 1.4.0-next.20
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/dist/data/index.d.mts +4 -0
- package/dist/data/index.d.ts +4 -0
- package/dist/data/index.js +2573 -0
- package/dist/data/index.js.map +1 -0
- package/dist/data/index.mjs +2524 -0
- package/dist/data/index.mjs.map +1 -0
- package/dist/index-X4qpYAhF.d.mts +1025 -0
- package/dist/index-X4qpYAhF.d.ts +1025 -0
- package/dist/index.d.mts +10 -791
- package/dist/index.d.ts +10 -791
- package/dist/index.js +2182 -1060
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2169 -1050
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -1
|
@@ -0,0 +1,2573 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/data/index.ts
|
|
30
|
+
var data_exports = {};
|
|
31
|
+
__export(data_exports, {
|
|
32
|
+
ALL_FEATURE_TYPES: () => ALL_FEATURE_TYPES,
|
|
33
|
+
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
34
|
+
GEOJSON_FEATURE_TYPES: () => GEOJSON_FEATURE_TYPES,
|
|
35
|
+
IMDF_FEATURE_TYPES: () => IMDF_FEATURE_TYPES,
|
|
36
|
+
IMDF_UNIT_CATEGORIES: () => IMDF_UNIT_CATEGORIES,
|
|
37
|
+
NONIMDF_FEATURE_TYPES: () => NONIMDF_FEATURE_TYPES,
|
|
38
|
+
OccupantHelpers: () => occupant_helper_exports,
|
|
39
|
+
QueryObserver: () => import_query_core2.QueryObserver,
|
|
40
|
+
defaultFeatureQueryOptionsMap: () => defaultFeatureQueryOptionsMap,
|
|
41
|
+
fetchDeliveryApi: () => fetchDeliveryApi,
|
|
42
|
+
fetchPreviewApi: () => fetchPreviewApi,
|
|
43
|
+
getDataClient: () => getDataClient,
|
|
44
|
+
getNavigateClient: () => getNavigateClient,
|
|
45
|
+
getSearchClient: () => getSearchClient,
|
|
46
|
+
isValidCoordinate: () => isValidCoordinate,
|
|
47
|
+
isValidLineString: () => isValidLineString,
|
|
48
|
+
isValidLineStringCoordinates: () => isValidLineStringCoordinates,
|
|
49
|
+
isValidMultiPolygon: () => isValidMultiPolygon,
|
|
50
|
+
isValidMultiPolygonCoordinates: () => isValidMultiPolygonCoordinates,
|
|
51
|
+
isValidPoint: () => isValidPoint,
|
|
52
|
+
isValidPolygon: () => isValidPolygon,
|
|
53
|
+
isValidPolygonCoordinates: () => isValidPolygonCoordinates,
|
|
54
|
+
matchFilter: () => matchFilter,
|
|
55
|
+
matchFilters: () => matchFilters,
|
|
56
|
+
safeFetchFeature: () => safeFetchFeature
|
|
57
|
+
});
|
|
58
|
+
module.exports = __toCommonJS(data_exports);
|
|
59
|
+
var import_query_core2 = require("@tanstack/query-core");
|
|
60
|
+
|
|
61
|
+
// src/data/constant.ts
|
|
62
|
+
var DEFAULT_BASE_URL = "https://service.venue.in.th/api";
|
|
63
|
+
var IMDF_FEATURE_TYPES = [
|
|
64
|
+
"address",
|
|
65
|
+
"amenity",
|
|
66
|
+
"anchor",
|
|
67
|
+
"building",
|
|
68
|
+
"detail",
|
|
69
|
+
"fixture",
|
|
70
|
+
"footprint",
|
|
71
|
+
"geofence",
|
|
72
|
+
"kiosk",
|
|
73
|
+
"level",
|
|
74
|
+
"occupant",
|
|
75
|
+
"opening",
|
|
76
|
+
"relationship",
|
|
77
|
+
"section",
|
|
78
|
+
"unit",
|
|
79
|
+
"venue"
|
|
80
|
+
];
|
|
81
|
+
var IMDF_UNIT_CATEGORIES = [
|
|
82
|
+
"auditorium",
|
|
83
|
+
"brick",
|
|
84
|
+
"classroom",
|
|
85
|
+
"column",
|
|
86
|
+
"concrete",
|
|
87
|
+
"conferenceroom",
|
|
88
|
+
"drywall",
|
|
89
|
+
"elevator",
|
|
90
|
+
"escalator",
|
|
91
|
+
"fieldofplay",
|
|
92
|
+
"firstaid",
|
|
93
|
+
"fitnessroom",
|
|
94
|
+
"foodservice",
|
|
95
|
+
"footbridge",
|
|
96
|
+
"glass",
|
|
97
|
+
"huddleroom",
|
|
98
|
+
"kitchen",
|
|
99
|
+
"laboratory",
|
|
100
|
+
"library",
|
|
101
|
+
"lobby",
|
|
102
|
+
"lounge",
|
|
103
|
+
"mailroom",
|
|
104
|
+
"mothersroom",
|
|
105
|
+
"movietheater",
|
|
106
|
+
"movingwalkway",
|
|
107
|
+
"nonpublic",
|
|
108
|
+
"office",
|
|
109
|
+
"opentobelow",
|
|
110
|
+
"parking",
|
|
111
|
+
"phoneroom",
|
|
112
|
+
"platform",
|
|
113
|
+
"privatelounge",
|
|
114
|
+
"ramp",
|
|
115
|
+
"recreation",
|
|
116
|
+
"restroom",
|
|
117
|
+
"restroom.family",
|
|
118
|
+
"restroom.female",
|
|
119
|
+
"restroom.female.wheelchair",
|
|
120
|
+
"restroom.male",
|
|
121
|
+
"restroom.male.wheelchair",
|
|
122
|
+
"restroom.transgender",
|
|
123
|
+
"restroom.transgender.wheelchair",
|
|
124
|
+
"restroom.unisex",
|
|
125
|
+
"restroom.unisex.wheelchair",
|
|
126
|
+
"restroom.wheelchair",
|
|
127
|
+
"road",
|
|
128
|
+
"room",
|
|
129
|
+
"serverroom",
|
|
130
|
+
"shower",
|
|
131
|
+
"smokingarea",
|
|
132
|
+
"stairs",
|
|
133
|
+
"steps",
|
|
134
|
+
"storage",
|
|
135
|
+
"structure",
|
|
136
|
+
"terrace",
|
|
137
|
+
"theater",
|
|
138
|
+
"unenclosedarea",
|
|
139
|
+
"unspecified",
|
|
140
|
+
"vegetation",
|
|
141
|
+
"waitingroom",
|
|
142
|
+
"walkway",
|
|
143
|
+
"walkway.island",
|
|
144
|
+
"wood"
|
|
145
|
+
];
|
|
146
|
+
var NONIMDF_FEATURE_TYPES = [
|
|
147
|
+
"taxonomy",
|
|
148
|
+
"event",
|
|
149
|
+
"promotion",
|
|
150
|
+
"label",
|
|
151
|
+
"privilege"
|
|
152
|
+
];
|
|
153
|
+
var GEOJSON_FEATURE_TYPES = [
|
|
154
|
+
...IMDF_FEATURE_TYPES,
|
|
155
|
+
...NONIMDF_FEATURE_TYPES
|
|
156
|
+
];
|
|
157
|
+
var ALL_FEATURE_TYPES = [
|
|
158
|
+
...GEOJSON_FEATURE_TYPES,
|
|
159
|
+
"sponsored-content",
|
|
160
|
+
"element"
|
|
161
|
+
];
|
|
162
|
+
var defaultFeatureQueryOptionsMap = {
|
|
163
|
+
// IMDF
|
|
164
|
+
address: {},
|
|
165
|
+
amenity: {},
|
|
166
|
+
anchor: {},
|
|
167
|
+
building: {},
|
|
168
|
+
detail: { enabled: false },
|
|
169
|
+
fixture: {},
|
|
170
|
+
footprint: {},
|
|
171
|
+
geofence: { enabled: false },
|
|
172
|
+
kiosk: {},
|
|
173
|
+
level: {},
|
|
174
|
+
occupant: {
|
|
175
|
+
refetchInterval: 5 * 60 * 1e3,
|
|
176
|
+
// refresh every 5 min
|
|
177
|
+
staleTime: 5 * 60 * 1e3
|
|
178
|
+
},
|
|
179
|
+
opening: {},
|
|
180
|
+
relationship: {},
|
|
181
|
+
section: {},
|
|
182
|
+
unit: {},
|
|
183
|
+
venue: {},
|
|
184
|
+
// OTHERS GEOJSON
|
|
185
|
+
taxonomy: {},
|
|
186
|
+
privilege: {},
|
|
187
|
+
event: {},
|
|
188
|
+
promotion: {
|
|
189
|
+
refetchInterval: 0.5 * 60 * 1e3,
|
|
190
|
+
// refresh every 5 min
|
|
191
|
+
staleTime: 0.5 * 60 * 1e3
|
|
192
|
+
},
|
|
193
|
+
label: {},
|
|
194
|
+
// NON GEOJSON
|
|
195
|
+
"sponsored-content": {
|
|
196
|
+
refetchInterval: 1 * 60 * 1e3
|
|
197
|
+
// refresh every 5 min
|
|
198
|
+
},
|
|
199
|
+
element: {},
|
|
200
|
+
page: {},
|
|
201
|
+
model3d: {}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// src/data/utils/geometry-validator.ts
|
|
205
|
+
var isValidCoordinate = (point2) => {
|
|
206
|
+
return point2.length === 2 && point2.every((coord) => typeof coord === "number");
|
|
207
|
+
};
|
|
208
|
+
function isValidLinearRingCoordinates(ring) {
|
|
209
|
+
if (ring.length < 4) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
return ring.every(isValidCoordinate) && ring[0][0] === ring[ring.length - 1][0] && ring[0][1] === ring[ring.length - 1][1];
|
|
213
|
+
}
|
|
214
|
+
var isValidPolygonCoordinates = (polygon2) => {
|
|
215
|
+
if (Array.isArray(polygon2[0]) && (polygon2[0].length === 0 || typeof polygon2[0][0] === "number")) {
|
|
216
|
+
return isValidLinearRingCoordinates(polygon2);
|
|
217
|
+
}
|
|
218
|
+
if (Array.isArray(polygon2) && polygon2.length > 0 && Array.isArray(polygon2[0])) {
|
|
219
|
+
if (!isValidLinearRingCoordinates(polygon2[0])) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
for (let i = 1; i < polygon2.length; i++) {
|
|
223
|
+
if (!isValidLinearRingCoordinates(polygon2[i])) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
};
|
|
231
|
+
var isValidMultiPolygonCoordinates = (multipolygon) => {
|
|
232
|
+
return multipolygon.every(isValidPolygonCoordinates);
|
|
233
|
+
};
|
|
234
|
+
var isValidLineStringCoordinates = (lineString2) => {
|
|
235
|
+
if (!Array.isArray(lineString2) || lineString2.length < 2) {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
const firstPoint = lineString2[0];
|
|
239
|
+
const lastPoint = lineString2[lineString2.length - 1];
|
|
240
|
+
if (firstPoint[0] === lastPoint[0] && firstPoint[1] === lastPoint[1]) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
return lineString2.every(isValidCoordinate);
|
|
244
|
+
};
|
|
245
|
+
var isValidMultiPolygon = (geometry) => {
|
|
246
|
+
const { type, coordinates } = geometry;
|
|
247
|
+
return type === "MultiPolygon" && isValidMultiPolygonCoordinates(coordinates);
|
|
248
|
+
};
|
|
249
|
+
var isValidPolygon = (geometry) => {
|
|
250
|
+
const { type, coordinates } = geometry;
|
|
251
|
+
return type === "Polygon" && isValidPolygonCoordinates(coordinates);
|
|
252
|
+
};
|
|
253
|
+
var isValidLineString = (geometry) => {
|
|
254
|
+
const { type, coordinates } = geometry;
|
|
255
|
+
return type === "LineString" && isValidLineStringCoordinates(coordinates);
|
|
256
|
+
};
|
|
257
|
+
var isValidPoint = (geometry) => {
|
|
258
|
+
const { type, coordinates } = geometry;
|
|
259
|
+
return type === "Point" && isValidCoordinate(coordinates);
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// src/data/utils/match-filters.ts
|
|
263
|
+
function isInFilter(filter) {
|
|
264
|
+
return typeof filter === "object" && filter !== null && "$in" in filter && Array.isArray(filter.$in);
|
|
265
|
+
}
|
|
266
|
+
var someIntersect = (a, b) => a.some((v) => b.includes(v));
|
|
267
|
+
function matchFilter(value, filter) {
|
|
268
|
+
if (Array.isArray(value)) {
|
|
269
|
+
if (isInFilter(filter)) return someIntersect(value, filter.$in);
|
|
270
|
+
return value.includes(filter);
|
|
271
|
+
} else {
|
|
272
|
+
if (isInFilter(filter)) return filter.$in.includes(value);
|
|
273
|
+
return value === filter;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function matchFilters(item, filters) {
|
|
277
|
+
return Object.entries(filters).every(([key, filter]) => {
|
|
278
|
+
return matchFilter(item.properties[key], filter);
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/data/utils/occupant-helper.ts
|
|
283
|
+
var occupant_helper_exports = {};
|
|
284
|
+
__export(occupant_helper_exports, {
|
|
285
|
+
getOccupantCorrelatedLocations: () => getOccupantCorrelatedLocations,
|
|
286
|
+
getOccupantMainLocation: () => getOccupantMainLocation,
|
|
287
|
+
getOccupantMarkerLocations: () => getOccupantMarkerLocations
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// src/data/utils/lodash/compact.ts
|
|
291
|
+
var compact = (arr) => arr.filter((item) => Boolean(item));
|
|
292
|
+
|
|
293
|
+
// src/data/utils/occupant-helper.ts
|
|
294
|
+
var getOccupantMainLocation = (occupant) => {
|
|
295
|
+
return occupant.properties.kiosk || occupant.properties.unit;
|
|
296
|
+
};
|
|
297
|
+
var getOccupantCorrelatedLocations = (occupant) => {
|
|
298
|
+
const allCorrelatedLocations = [
|
|
299
|
+
...occupant.properties.units,
|
|
300
|
+
...occupant.properties.kiosks
|
|
301
|
+
];
|
|
302
|
+
return compact(allCorrelatedLocations);
|
|
303
|
+
};
|
|
304
|
+
var getOccupantMarkerLocations = (occupant, options) => {
|
|
305
|
+
const placementType = options?.type ? options.type : occupant.properties.show_name_on_all_units ? "ALL_LOCATIONS" : "ONCE_PER_LEVEL";
|
|
306
|
+
const mainLocation = getOccupantMainLocation(occupant);
|
|
307
|
+
const mainLocationLevel = mainLocation?.properties?.level_id;
|
|
308
|
+
const allCorrelatedLocations = getOccupantCorrelatedLocations(occupant);
|
|
309
|
+
if (placementType === "ALL_LOCATIONS") {
|
|
310
|
+
return compact([mainLocation, ...allCorrelatedLocations]);
|
|
311
|
+
}
|
|
312
|
+
const otherLevelLocations = allCorrelatedLocations.filter((f) => f.properties.level_id !== mainLocationLevel);
|
|
313
|
+
const onePerLevelLocations = [...new Map(otherLevelLocations.map((loc) => [loc.properties.level_id, loc])).values()];
|
|
314
|
+
return compact([mainLocation, ...onePerLevelLocations]);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// src/data/api/delivery-project.ts
|
|
318
|
+
async function fetchDeliveryApi(projectId, apiKey, featureType, baseUrl = DEFAULT_BASE_URL) {
|
|
319
|
+
switch (featureType) {
|
|
320
|
+
case "label":
|
|
321
|
+
case "element": {
|
|
322
|
+
const pluralFeatureType = `${featureType}s`;
|
|
323
|
+
const res = await fetch(
|
|
324
|
+
`${baseUrl}/delivery/projects/${projectId}/${pluralFeatureType}.geojson?api-key=${apiKey}`
|
|
325
|
+
);
|
|
326
|
+
if (res.status !== 200) return [];
|
|
327
|
+
const items = await res.json();
|
|
328
|
+
return items;
|
|
329
|
+
}
|
|
330
|
+
case "model3d": {
|
|
331
|
+
const res = await fetch(
|
|
332
|
+
`${baseUrl}/delivery/projects/${projectId}/${featureType}.geojson?api-key=${apiKey}`
|
|
333
|
+
);
|
|
334
|
+
if (res.status !== 200) return [];
|
|
335
|
+
const items = await res.json();
|
|
336
|
+
return items.features;
|
|
337
|
+
}
|
|
338
|
+
case "sponsored-content": {
|
|
339
|
+
const res = await fetch(
|
|
340
|
+
`${baseUrl}/delivery/projects/${projectId}/sponsored-content.json?api-key=${apiKey}`
|
|
341
|
+
);
|
|
342
|
+
if (res.status !== 200) return [];
|
|
343
|
+
const jsonRes = await res.json();
|
|
344
|
+
const items = jsonRes.data;
|
|
345
|
+
return items.map((item) => ({
|
|
346
|
+
id: item.id,
|
|
347
|
+
...item.attributes
|
|
348
|
+
}));
|
|
349
|
+
}
|
|
350
|
+
default: {
|
|
351
|
+
const res = await fetch(
|
|
352
|
+
`${baseUrl}/delivery/projects/${projectId}/imdf/${featureType}.geojson?api-key=${apiKey}`
|
|
353
|
+
);
|
|
354
|
+
if (res.status !== 200) return [];
|
|
355
|
+
const collections = await res.json();
|
|
356
|
+
return collections.features;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async function fetchPreviewApi(projectId, previewToken, featureType, baseUrl = DEFAULT_BASE_URL) {
|
|
361
|
+
switch (featureType) {
|
|
362
|
+
case "label":
|
|
363
|
+
case "element": {
|
|
364
|
+
const pluralFeatureType = `${featureType}s`;
|
|
365
|
+
const res = await fetch(
|
|
366
|
+
`${baseUrl}/preview/projects/${projectId}/${pluralFeatureType}.geojson`,
|
|
367
|
+
{
|
|
368
|
+
headers: {
|
|
369
|
+
Authorization: `Bearer ${previewToken}`
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
if (res.status !== 200) return [];
|
|
374
|
+
const items = await res.json();
|
|
375
|
+
return items;
|
|
376
|
+
}
|
|
377
|
+
case "sponsored-content": {
|
|
378
|
+
const res = await fetch(
|
|
379
|
+
`${baseUrl}/preview/projects/${projectId}/sponsored-content.json`,
|
|
380
|
+
{
|
|
381
|
+
headers: {
|
|
382
|
+
Authorization: `Bearer ${previewToken}`
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
);
|
|
386
|
+
if (res.status !== 200) return [];
|
|
387
|
+
const jsonRes = await res.json();
|
|
388
|
+
const items = jsonRes.data;
|
|
389
|
+
return items.map((item) => ({
|
|
390
|
+
id: item.id,
|
|
391
|
+
...item.attributes
|
|
392
|
+
}));
|
|
393
|
+
}
|
|
394
|
+
default: {
|
|
395
|
+
const res = await fetch(
|
|
396
|
+
`${baseUrl}/preview/projects/${projectId}/imdf/${featureType}.geojson`,
|
|
397
|
+
{
|
|
398
|
+
headers: {
|
|
399
|
+
Authorization: `Bearer ${previewToken}`
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
);
|
|
403
|
+
if (res.status !== 200) return [];
|
|
404
|
+
const collections = await res.json();
|
|
405
|
+
return collections.features;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
var safeFetchFeature = async (featureType, params) => {
|
|
410
|
+
const mode = params.mode ?? "delivery";
|
|
411
|
+
const projectId = params.projectId;
|
|
412
|
+
const apiKey = params.apiKey;
|
|
413
|
+
const previewToken = params.previewToken;
|
|
414
|
+
const baseUrl = params.baseUrl ?? DEFAULT_BASE_URL;
|
|
415
|
+
try {
|
|
416
|
+
let result = [];
|
|
417
|
+
if (mode === "delivery") {
|
|
418
|
+
result = await fetchDeliveryApi(
|
|
419
|
+
projectId,
|
|
420
|
+
apiKey,
|
|
421
|
+
featureType,
|
|
422
|
+
baseUrl
|
|
423
|
+
);
|
|
424
|
+
} else if (mode === "preview") {
|
|
425
|
+
result = await fetchPreviewApi(
|
|
426
|
+
projectId,
|
|
427
|
+
previewToken,
|
|
428
|
+
featureType,
|
|
429
|
+
baseUrl
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
return result ?? [];
|
|
433
|
+
} catch (e) {
|
|
434
|
+
return Promise.resolve([]);
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
// src/data/getDataClient.ts
|
|
439
|
+
var import_query_core = require("@tanstack/query-core");
|
|
440
|
+
|
|
441
|
+
// src/data/populator/index.ts
|
|
442
|
+
var import_center2 = require("@turf/center");
|
|
443
|
+
var import_boolean_point_in_polygon2 = require("@turf/boolean-point-in-polygon");
|
|
444
|
+
|
|
445
|
+
// src/data/utils/findContaining.ts
|
|
446
|
+
var import_center = require("@turf/center");
|
|
447
|
+
var import_boolean_point_in_polygon = require("@turf/boolean-point-in-polygon");
|
|
448
|
+
var findContainingUnit = (poi, units) => {
|
|
449
|
+
const unit = units.find(
|
|
450
|
+
(unit2) => {
|
|
451
|
+
try {
|
|
452
|
+
return unit2.properties.level_id === poi.properties.level_id && (0, import_boolean_point_in_polygon.booleanPointInPolygon)((0, import_center.center)(poi), unit2);
|
|
453
|
+
} catch (e) {
|
|
454
|
+
console.log(`Cannot find containing unit of (${poi.id}):`, e.message);
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
);
|
|
459
|
+
return unit;
|
|
460
|
+
};
|
|
461
|
+
var findContainingUnitAtPoint = (point2, levelId, units) => {
|
|
462
|
+
const unit = units.find(
|
|
463
|
+
(unit2) => {
|
|
464
|
+
try {
|
|
465
|
+
return unit2.properties.level_id === levelId && (0, import_boolean_point_in_polygon.booleanPointInPolygon)(point2, unit2);
|
|
466
|
+
} catch (e) {
|
|
467
|
+
console.log(`Cannot find containing unit of (point: ${point2}, levelId: ${levelId}):`, e.message);
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
);
|
|
472
|
+
return unit;
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
// src/data/populator/index.ts
|
|
476
|
+
var createPopulator = ({
|
|
477
|
+
internalFindById,
|
|
478
|
+
internalFilterByType
|
|
479
|
+
}) => {
|
|
480
|
+
const populateAddress = (address) => Promise.resolve(address);
|
|
481
|
+
const populateBuilding = (building) => Promise.resolve(building);
|
|
482
|
+
const populateDetail = (detail) => Promise.resolve(detail);
|
|
483
|
+
const populateFootprint = (footprint) => Promise.resolve(footprint);
|
|
484
|
+
const populateGeofence = (geofence) => Promise.resolve(geofence);
|
|
485
|
+
const populatePrivilege = (privilege) => Promise.resolve(privilege);
|
|
486
|
+
const populateEvent = (event) => Promise.resolve(event);
|
|
487
|
+
const populatePromotion = async (promotion) => {
|
|
488
|
+
const venue = await internalFindById(promotion.properties.venue_id);
|
|
489
|
+
return {
|
|
490
|
+
...promotion,
|
|
491
|
+
properties: {
|
|
492
|
+
...promotion.properties,
|
|
493
|
+
venue
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
};
|
|
497
|
+
const populateAmenity = async (amenity) => {
|
|
498
|
+
const units = await Promise.all(
|
|
499
|
+
amenity.properties.unit_ids.map(internalFindById)
|
|
500
|
+
);
|
|
501
|
+
const populatedUnits = await Promise.all(units.map(populateUnit));
|
|
502
|
+
const venue = await internalFindById(amenity.properties.venue_id);
|
|
503
|
+
const defaultLevel = populatedUnits[0].properties.level;
|
|
504
|
+
const kiosks = await internalFilterByType("kiosk");
|
|
505
|
+
const ordinalKiosks = kiosks.filter(
|
|
506
|
+
(kiosk2) => kiosk2.properties.level_id === defaultLevel.id
|
|
507
|
+
);
|
|
508
|
+
const kiosk = ordinalKiosks.find((kiosk2) => (0, import_boolean_point_in_polygon2.booleanPointInPolygon)(amenity, kiosk2));
|
|
509
|
+
return {
|
|
510
|
+
...amenity,
|
|
511
|
+
properties: {
|
|
512
|
+
...amenity.properties,
|
|
513
|
+
ordinal: defaultLevel.properties.ordinal,
|
|
514
|
+
level_name: defaultLevel.properties.name.en,
|
|
515
|
+
level: defaultLevel,
|
|
516
|
+
units: populatedUnits,
|
|
517
|
+
venue,
|
|
518
|
+
_experimental_kiosk: kiosk ? await populateKiosk(kiosk) : null
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
};
|
|
522
|
+
const populateAnchor = async (anchor) => {
|
|
523
|
+
const unit = await internalFindById(anchor.properties.unit_id);
|
|
524
|
+
const venue = await internalFindById(unit.properties.venue_id);
|
|
525
|
+
const level = await internalFindById(unit.properties.level_id);
|
|
526
|
+
const sections = await internalFilterByType("section");
|
|
527
|
+
const section = sections.find((section2) => (0, import_boolean_point_in_polygon2.booleanPointInPolygon)(anchor, section2));
|
|
528
|
+
return {
|
|
529
|
+
...anchor,
|
|
530
|
+
properties: {
|
|
531
|
+
...anchor.properties,
|
|
532
|
+
level: await populateLevel(level),
|
|
533
|
+
unit: await populateUnit(unit),
|
|
534
|
+
section: section ? await populateSection(section) : null,
|
|
535
|
+
venue: await populateVenue(venue),
|
|
536
|
+
ordinal: level.properties.ordinal
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
};
|
|
540
|
+
const populateFixture = async (fixture) => {
|
|
541
|
+
const level = await internalFindById(fixture.properties.level_id);
|
|
542
|
+
const venue = await internalFindById(fixture.properties.venue_id);
|
|
543
|
+
const anchor = await internalFindById(fixture.properties.anchor_id);
|
|
544
|
+
return {
|
|
545
|
+
...fixture,
|
|
546
|
+
properties: {
|
|
547
|
+
...fixture.properties,
|
|
548
|
+
anchor: anchor ? await populateAnchor(anchor) : null,
|
|
549
|
+
level: await populateLevel(level),
|
|
550
|
+
venue: await populateVenue(venue),
|
|
551
|
+
ordinal: level.properties.ordinal
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
};
|
|
555
|
+
const populateKiosk = async (kiosk) => {
|
|
556
|
+
const level = await internalFindById(kiosk.properties.level_id);
|
|
557
|
+
const venue = await internalFindById(kiosk.properties.venue_id);
|
|
558
|
+
const anchor = await internalFindById(kiosk.properties.anchor_id);
|
|
559
|
+
const units = await internalFilterByType("unit");
|
|
560
|
+
const unit = findContainingUnit(kiosk, units.filter((unit2) => unit2.properties.category === "walkway"));
|
|
561
|
+
let section = null;
|
|
562
|
+
if (anchor) {
|
|
563
|
+
const sections = await internalFilterByType("section");
|
|
564
|
+
section = sections.find((section2) => (0, import_boolean_point_in_polygon2.booleanPointInPolygon)(anchor, section2));
|
|
565
|
+
}
|
|
566
|
+
return {
|
|
567
|
+
...kiosk,
|
|
568
|
+
properties: {
|
|
569
|
+
...kiosk.properties,
|
|
570
|
+
anchor: anchor ? await populateAnchor(anchor) : null,
|
|
571
|
+
level: await populateLevel(level),
|
|
572
|
+
venue: await populateVenue(venue),
|
|
573
|
+
ordinal: level.properties.ordinal,
|
|
574
|
+
unit: unit ? await populateUnit(unit) : null,
|
|
575
|
+
section: section ? await populateSection(section) : null
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
};
|
|
579
|
+
const populateLevel = async (level) => {
|
|
580
|
+
const venue = await internalFindById(level.properties.venue_id);
|
|
581
|
+
return {
|
|
582
|
+
...level,
|
|
583
|
+
properties: {
|
|
584
|
+
...level.properties,
|
|
585
|
+
venue
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
};
|
|
589
|
+
const populateOccupant = async (occupant) => {
|
|
590
|
+
const {
|
|
591
|
+
anchor_id,
|
|
592
|
+
venue_id,
|
|
593
|
+
local_category_ids,
|
|
594
|
+
promotion_ids = [],
|
|
595
|
+
privilege_ids = [],
|
|
596
|
+
kiosk_id,
|
|
597
|
+
unit_id,
|
|
598
|
+
kiosk_ids = [],
|
|
599
|
+
unit_ids = []
|
|
600
|
+
} = occupant.properties;
|
|
601
|
+
const anchor = await internalFindById(anchor_id);
|
|
602
|
+
const venue = await internalFindById(venue_id);
|
|
603
|
+
const localCategories = await Promise.all(
|
|
604
|
+
local_category_ids.map(internalFindById)
|
|
605
|
+
);
|
|
606
|
+
const promotions = await Promise.all(
|
|
607
|
+
promotion_ids.map(internalFindById)
|
|
608
|
+
);
|
|
609
|
+
const privileges = await Promise.all(
|
|
610
|
+
privilege_ids.map(internalFindById)
|
|
611
|
+
);
|
|
612
|
+
const kiosk = await internalFindById(kiosk_id);
|
|
613
|
+
const unit = await internalFindById(unit_id);
|
|
614
|
+
const kiosks = await Promise.all(kiosk_ids.map(internalFindById));
|
|
615
|
+
const units = await Promise.all(unit_ids.map(internalFindById));
|
|
616
|
+
return {
|
|
617
|
+
...occupant,
|
|
618
|
+
properties: {
|
|
619
|
+
...occupant.properties,
|
|
620
|
+
anchor: anchor ? await populateAnchor(anchor) : null,
|
|
621
|
+
local_categories: await Promise.all(
|
|
622
|
+
compact(localCategories).map(populateTaxonomy)
|
|
623
|
+
),
|
|
624
|
+
venue,
|
|
625
|
+
promotions,
|
|
626
|
+
privileges,
|
|
627
|
+
kiosk: kiosk ? await populateKiosk(kiosk) : null,
|
|
628
|
+
unit: unit ? await populateUnit(unit) : null,
|
|
629
|
+
kiosks: await Promise.all(kiosks.map(populateKiosk)),
|
|
630
|
+
units: await Promise.all(units.map(populateUnit))
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
};
|
|
634
|
+
const populateOpening = async (opening) => {
|
|
635
|
+
const venue = await internalFindById(opening.properties.venue_id);
|
|
636
|
+
const level = await internalFindById(opening.properties.level_id);
|
|
637
|
+
return {
|
|
638
|
+
...opening,
|
|
639
|
+
properties: {
|
|
640
|
+
venue,
|
|
641
|
+
level: await populateLevel(level),
|
|
642
|
+
ordinal: level.properties.ordinal
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
};
|
|
646
|
+
const populateSection = async (section) => {
|
|
647
|
+
const venue = await internalFindById(section.properties.venue_id);
|
|
648
|
+
const level = await internalFindById(section.properties.level_id);
|
|
649
|
+
return {
|
|
650
|
+
...section,
|
|
651
|
+
properties: {
|
|
652
|
+
...section.properties,
|
|
653
|
+
venue,
|
|
654
|
+
level: await populateLevel(level),
|
|
655
|
+
ordinal: level.properties.ordinal
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
};
|
|
659
|
+
const populateRelationship = async (relationship) => {
|
|
660
|
+
const originId = relationship.properties.origin?.id;
|
|
661
|
+
const destinationId = relationship.properties.destination?.id;
|
|
662
|
+
const origin = originId ? await internalFindById(originId) : null;
|
|
663
|
+
const destination = destinationId ? await internalFindById(destinationId) : null;
|
|
664
|
+
const intermediary_ids = (relationship.properties.intermediary || []).map(({ id }) => id);
|
|
665
|
+
const intermediary = await Promise.all(intermediary_ids.map(internalFindById));
|
|
666
|
+
return {
|
|
667
|
+
...relationship,
|
|
668
|
+
properties: {
|
|
669
|
+
...relationship.properties,
|
|
670
|
+
origin,
|
|
671
|
+
destination,
|
|
672
|
+
intermediary
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
};
|
|
676
|
+
const populateUnit = async (unit) => {
|
|
677
|
+
const venue = await internalFindById(unit.properties.venue_id);
|
|
678
|
+
const level = await internalFindById(unit.properties.level_id);
|
|
679
|
+
const sections = await internalFilterByType("section");
|
|
680
|
+
try {
|
|
681
|
+
const section = unit.geometry.type !== "MultiPolygon" ? sections.find((section2) => (0, import_boolean_point_in_polygon2.booleanPointInPolygon)((0, import_center2.center)(unit), section2)) : null;
|
|
682
|
+
return {
|
|
683
|
+
...unit,
|
|
684
|
+
properties: {
|
|
685
|
+
...unit.properties,
|
|
686
|
+
venue,
|
|
687
|
+
ordinal: level.properties.ordinal,
|
|
688
|
+
level: await populateLevel(level),
|
|
689
|
+
section: section ? await populateSection(section) : null
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
} catch (err) {
|
|
693
|
+
console.log(`error finding section `, { unit, sections });
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
const populateVenue = (venue) => {
|
|
697
|
+
return Promise.resolve(venue);
|
|
698
|
+
};
|
|
699
|
+
const populateTaxonomy = async (taxonomy) => {
|
|
700
|
+
const venue = await internalFindById(taxonomy.properties.venue_id);
|
|
701
|
+
return {
|
|
702
|
+
...taxonomy,
|
|
703
|
+
properties: {
|
|
704
|
+
...taxonomy.properties,
|
|
705
|
+
venue: venue ? await populateVenue(venue) : null
|
|
706
|
+
}
|
|
707
|
+
};
|
|
708
|
+
};
|
|
709
|
+
const populateModel3D = async (model3d) => {
|
|
710
|
+
const level = await internalFindById(model3d.properties.level_id);
|
|
711
|
+
try {
|
|
712
|
+
return {
|
|
713
|
+
...model3d,
|
|
714
|
+
properties: {
|
|
715
|
+
...model3d.properties,
|
|
716
|
+
level: await populateLevel(level)
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
} catch (err) {
|
|
720
|
+
console.log(`error finding level`, { model3d, level });
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
const populateFeature = (feature2) => Promise.resolve(feature2);
|
|
724
|
+
return {
|
|
725
|
+
address: populateAddress,
|
|
726
|
+
building: populateBuilding,
|
|
727
|
+
detail: populateDetail,
|
|
728
|
+
fixture: populateFixture,
|
|
729
|
+
footprint: populateFootprint,
|
|
730
|
+
geofence: populateGeofence,
|
|
731
|
+
opening: populateOpening,
|
|
732
|
+
relationship: populateRelationship,
|
|
733
|
+
privilege: populatePrivilege,
|
|
734
|
+
promotion: populatePromotion,
|
|
735
|
+
event: populateEvent,
|
|
736
|
+
label: populateFeature,
|
|
737
|
+
element: populateFeature,
|
|
738
|
+
page: populateFeature,
|
|
739
|
+
amenity: populateAmenity,
|
|
740
|
+
anchor: populateAnchor,
|
|
741
|
+
kiosk: populateKiosk,
|
|
742
|
+
level: populateLevel,
|
|
743
|
+
occupant: populateOccupant,
|
|
744
|
+
section: populateSection,
|
|
745
|
+
unit: populateUnit,
|
|
746
|
+
venue: populateVenue,
|
|
747
|
+
taxonomy: populateTaxonomy,
|
|
748
|
+
model3d: populateModel3D
|
|
749
|
+
};
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
// src/data/search/getSearchClient.ts
|
|
753
|
+
var import_fuse = __toESM(require("fuse.js"));
|
|
754
|
+
|
|
755
|
+
// src/data/search/utils/sanitizeInput.ts
|
|
756
|
+
var sanitizeInput = (str) => str.replace(/[\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, "").replace(/[\-–—_./()]+/g, "").normalize("NFC").trim();
|
|
757
|
+
|
|
758
|
+
// src/data/search/getSearchClient.ts
|
|
759
|
+
var getSearchClient = ({ occupants, amenities }) => {
|
|
760
|
+
const fuseAmenities = new import_fuse.default(amenities, {
|
|
761
|
+
threshold: 0.2,
|
|
762
|
+
keys: [
|
|
763
|
+
{ name: "properties.name", "weight": 1, getFn: (obj) => Object.values(obj.properties.name || {}) },
|
|
764
|
+
{ name: "properties.category", "weight": 1 }
|
|
765
|
+
]
|
|
766
|
+
});
|
|
767
|
+
const fuseOccupants = new import_fuse.default(occupants, {
|
|
768
|
+
threshold: 0.25,
|
|
769
|
+
// 0.2 is too strict (can't find Mo-Mo Paradise with "momo" search string)
|
|
770
|
+
includeScore: true,
|
|
771
|
+
shouldSort: true,
|
|
772
|
+
keys: [
|
|
773
|
+
{ name: "properties.name", "weight": 4, getFn: (obj) => Object.values(obj.properties.name || {}) },
|
|
774
|
+
{ name: "properties.keywords", "weight": 0.5 },
|
|
775
|
+
{ name: "properties.category", "weight": 0.25 },
|
|
776
|
+
{ name: "properties.local_category_names", "weight": 0.25 },
|
|
777
|
+
{ name: "properties.description", "weight": 0.25, getFn: (occ) => Object.values(occ.properties.description || {}) },
|
|
778
|
+
{ name: "properties.unit_name", "weight": 0.25 },
|
|
779
|
+
{ name: "properties.kiosk_name", "weight": 0.25 }
|
|
780
|
+
]
|
|
781
|
+
});
|
|
782
|
+
const search = (value) => {
|
|
783
|
+
const sanitizedValue = sanitizeInput(value);
|
|
784
|
+
const matchedAmenities = fuseAmenities.search(sanitizedValue);
|
|
785
|
+
const matchedOccupants = fuseOccupants.search(sanitizedValue);
|
|
786
|
+
return [...matchedAmenities, ...matchedOccupants];
|
|
787
|
+
};
|
|
788
|
+
return {
|
|
789
|
+
search
|
|
790
|
+
};
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
// src/data/navigate/getNavigateClient.ts
|
|
794
|
+
var import_boolean_point_in_polygon4 = require("@turf/boolean-point-in-polygon");
|
|
795
|
+
|
|
796
|
+
// src/data/navigate/graph/prepare.ts
|
|
797
|
+
var import_lodash10 = __toESM(require("lodash"));
|
|
798
|
+
var import_node_dijkstra = __toESM(require("node-dijkstra"));
|
|
799
|
+
var import_distance3 = require("@turf/distance");
|
|
800
|
+
var import_center5 = require("@turf/center");
|
|
801
|
+
|
|
802
|
+
// src/data/navigate/graph/nodemap/createTraversalNodeMap.ts
|
|
803
|
+
var import_distance = require("@turf/distance");
|
|
804
|
+
var import_center3 = require("@turf/center");
|
|
805
|
+
var import_lodash3 = __toESM(require("lodash"));
|
|
806
|
+
|
|
807
|
+
// src/data/navigate/graph/constants.ts
|
|
808
|
+
var ROOM_BASEDISTANCE = 1e3;
|
|
809
|
+
var TERRACE_BASEDISTANCE = 1e3;
|
|
810
|
+
var ESCALATOR_BASEDISTANCE = 200;
|
|
811
|
+
var RAMP_BASEDISTANCE = 200;
|
|
812
|
+
var ELEVATOR_BASEDISTANCE = 500;
|
|
813
|
+
var STAIR_BASEDISTANCE = 1e5;
|
|
814
|
+
var BASE_POI_BASEDISTANCE = 9999999;
|
|
815
|
+
var DEFAULT_UNIT_BASEDISTANCE_OPTIONS = {
|
|
816
|
+
default: { baseDistance: 0 },
|
|
817
|
+
byCategory: {
|
|
818
|
+
room: { baseDistance: ROOM_BASEDISTANCE },
|
|
819
|
+
terrace: { baseDistance: TERRACE_BASEDISTANCE },
|
|
820
|
+
escalator: { baseDistance: ESCALATOR_BASEDISTANCE, scaleDistanceByLevel: false },
|
|
821
|
+
ramp: { baseDistance: RAMP_BASEDISTANCE, scaleDistanceByLevel: false },
|
|
822
|
+
elevator: { baseDistance: ELEVATOR_BASEDISTANCE, scaleDistanceByLevel: false },
|
|
823
|
+
stairs: {
|
|
824
|
+
baseDistance: STAIR_BASEDISTANCE,
|
|
825
|
+
scaleDistanceByLevel: true
|
|
826
|
+
},
|
|
827
|
+
"stairs.emergencyexit": {
|
|
828
|
+
baseDistance: STAIR_BASEDISTANCE,
|
|
829
|
+
scaleDistanceByLevel: true
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
|
|
834
|
+
// src/data/navigate/graph/utils/getDistanceOption.ts
|
|
835
|
+
var getDistanceOptions = (options, category) => {
|
|
836
|
+
if (!options) return DEFAULT_UNIT_BASEDISTANCE_OPTIONS.byCategory[category];
|
|
837
|
+
return (category && options.byCategory?.[category]) ?? DEFAULT_UNIT_BASEDISTANCE_OPTIONS.byCategory[category] ?? options?.default ?? DEFAULT_UNIT_BASEDISTANCE_OPTIONS.default;
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
// src/data/utils/trace.ts
|
|
841
|
+
var trace = (namespace, text, ms, color) => {
|
|
842
|
+
if (process.env.NODE_ENV !== "test") console.log(`[${namespace}] %c${text.padEnd(90)} ${ms !== void 0 ? `${ms.toFixed(1).padStart(6)} ms` : ``}`, color ? `color: ${color}` : void 0);
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
// src/data/navigate/graph/nodemap/createTraversalNodeMap.ts
|
|
846
|
+
var createTraversalNodeMap = (unitOpenings, options) => {
|
|
847
|
+
const { units } = options.data;
|
|
848
|
+
let counter = 0;
|
|
849
|
+
const calculateFeatureDistanceWithinUnit = (features, distanceOptions) => {
|
|
850
|
+
let relationshipGraph = {};
|
|
851
|
+
for (let currentIndex = 0; currentIndex < features.length; currentIndex++) {
|
|
852
|
+
const isLastItem = currentIndex + 1 === features.length;
|
|
853
|
+
if (isLastItem) break;
|
|
854
|
+
for (let j = currentIndex + 1; j < features.length; j++) {
|
|
855
|
+
const opening = features[currentIndex];
|
|
856
|
+
const feature2 = features[j];
|
|
857
|
+
try {
|
|
858
|
+
const distance5 = (0, import_distance.distance)(
|
|
859
|
+
(0, import_center3.center)(opening.geometry),
|
|
860
|
+
(0, import_center3.center)(feature2.geometry),
|
|
861
|
+
{ units: "meters" }
|
|
862
|
+
) + (distanceOptions?.baseDistance ?? 0);
|
|
863
|
+
if (opening.id === feature2.id) continue;
|
|
864
|
+
import_lodash3.default.set(relationshipGraph, `${opening.id}.${feature2.id}`, distance5);
|
|
865
|
+
import_lodash3.default.set(relationshipGraph, `${feature2.id}.${opening.id}`, distance5);
|
|
866
|
+
counter++;
|
|
867
|
+
} catch (error) {
|
|
868
|
+
continue;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
return relationshipGraph;
|
|
873
|
+
};
|
|
874
|
+
const t0 = performance.now();
|
|
875
|
+
const nodeMap = import_lodash3.default.reduce(
|
|
876
|
+
unitOpenings,
|
|
877
|
+
(acc, openings, unitId) => {
|
|
878
|
+
const unit = units.find((unit2) => unit2.id === unitId);
|
|
879
|
+
const unitDistanceOption = getDistanceOptions(options.unitDistanceOptions, unit.properties.category);
|
|
880
|
+
return import_lodash3.default.merge(
|
|
881
|
+
acc,
|
|
882
|
+
calculateFeatureDistanceWithinUnit(openings, unitDistanceOption)
|
|
883
|
+
);
|
|
884
|
+
},
|
|
885
|
+
{}
|
|
886
|
+
);
|
|
887
|
+
const t1 = performance.now();
|
|
888
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} traversal relationships`, t1 - t0);
|
|
889
|
+
return nodeMap;
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
// src/data/navigate/graph/nodemap/createElevatorNodeMap.ts
|
|
893
|
+
var import_lodash4 = __toESM(require("lodash"));
|
|
894
|
+
var createElevatorNodeMap = (elevatorLikeRelationships, unitOpenings, options) => {
|
|
895
|
+
const t0 = performance.now();
|
|
896
|
+
const { levels, units } = options.data;
|
|
897
|
+
const distanceOptions = getDistanceOptions(options.unitDistanceOptions, "elevator");
|
|
898
|
+
const {
|
|
899
|
+
baseDistance = ELEVATOR_BASEDISTANCE,
|
|
900
|
+
scaleDistanceByLevel = false
|
|
901
|
+
} = distanceOptions;
|
|
902
|
+
let elevatorNodeMap = {};
|
|
903
|
+
let counter = 0;
|
|
904
|
+
for (const relationship of elevatorLikeRelationships) {
|
|
905
|
+
try {
|
|
906
|
+
const {
|
|
907
|
+
origin: originTypeAndId,
|
|
908
|
+
intermediary,
|
|
909
|
+
destination: destinationTypeAndId
|
|
910
|
+
} = relationship.properties;
|
|
911
|
+
const origin = units.find((unit) => unit.id === originTypeAndId.id);
|
|
912
|
+
if (!origin) return;
|
|
913
|
+
const originOpenings = compact(unitOpenings[origin.id]);
|
|
914
|
+
const originLevel = levels.find((level) => level.id === origin.properties.level_id);
|
|
915
|
+
const destination = units.find((unit) => unit.id === destinationTypeAndId.id);
|
|
916
|
+
const destinationOpenings = unitOpenings[destination.id];
|
|
917
|
+
const destinationOpeningAndLevels = destinationOpenings.map((opening) => {
|
|
918
|
+
const level = levels.find((level2) => level2.id === destination.properties.level_id);
|
|
919
|
+
return { opening, level };
|
|
920
|
+
});
|
|
921
|
+
const intermediaryOpeningAndLevels = intermediary.map((unitTypeAndId) => {
|
|
922
|
+
const openings = unitOpenings[unitTypeAndId.id];
|
|
923
|
+
const unit = units.find((unit2) => unit2.id === unitTypeAndId.id);
|
|
924
|
+
const level = levels.find((level2) => level2.id === unit.properties.level_id);
|
|
925
|
+
return openings.map((opening) => ({ opening, level }));
|
|
926
|
+
}).flat();
|
|
927
|
+
const connections = compact([...intermediaryOpeningAndLevels, ...destinationOpeningAndLevels]);
|
|
928
|
+
if (!originOpenings || originOpenings.length === 0) return;
|
|
929
|
+
for (const originOpening of originOpenings) {
|
|
930
|
+
for (const connection of connections) {
|
|
931
|
+
const { opening, level } = connection;
|
|
932
|
+
let distance5 = baseDistance;
|
|
933
|
+
if (scaleDistanceByLevel) {
|
|
934
|
+
const originOrdinal = originLevel.properties.ordinal;
|
|
935
|
+
const connectionOrdinal = level.properties.ordinal;
|
|
936
|
+
const levelDifference = Math.abs(originOrdinal - connectionOrdinal);
|
|
937
|
+
if (levelDifference > 0) distance5 *= levelDifference;
|
|
938
|
+
}
|
|
939
|
+
import_lodash4.default.set(elevatorNodeMap, `${originOpening.id}.${opening.id}`, distance5);
|
|
940
|
+
import_lodash4.default.set(elevatorNodeMap, `${opening.id}.${originOpening.id}`, distance5);
|
|
941
|
+
counter++;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
} catch (err) {
|
|
945
|
+
console.log(err);
|
|
946
|
+
console.log("cannot create elevatorNodeMap for ", { relationship });
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
const t1 = performance.now();
|
|
950
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} escalator relationships`, t1 - t0);
|
|
951
|
+
return elevatorNodeMap;
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
// src/data/navigate/graph/nodemap/createEscalatorNodeMap.ts
|
|
955
|
+
var import_set = __toESM(require("lodash/set"));
|
|
956
|
+
var createEscalatorNodeMap = (relationships, options) => {
|
|
957
|
+
const t0 = performance.now();
|
|
958
|
+
const distanceOptions = getDistanceOptions(options.unitDistanceOptions, "escalator");
|
|
959
|
+
let counter = 0;
|
|
960
|
+
let nodeMap = {};
|
|
961
|
+
for (const relationship of relationships) {
|
|
962
|
+
const {
|
|
963
|
+
properties: { direction, origin, destination }
|
|
964
|
+
} = relationship;
|
|
965
|
+
(0, import_set.default)(nodeMap, `${origin.id}.${destination.id}`, distanceOptions.baseDistance);
|
|
966
|
+
if (direction === "undirected") {
|
|
967
|
+
(0, import_set.default)(nodeMap, `${destination.id}.${origin.id}`, distanceOptions.baseDistance);
|
|
968
|
+
}
|
|
969
|
+
counter++;
|
|
970
|
+
}
|
|
971
|
+
const t1 = performance.now();
|
|
972
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} escalator relationships`, t1 - t0);
|
|
973
|
+
return nodeMap;
|
|
974
|
+
};
|
|
975
|
+
|
|
976
|
+
// src/data/navigate/graph/nodemap/createRampNodeMap.ts
|
|
977
|
+
var import_set2 = __toESM(require("lodash/set"));
|
|
978
|
+
var createRampNodeMap = (relationships, options) => {
|
|
979
|
+
const t0 = performance.now();
|
|
980
|
+
const distanceOptions = getDistanceOptions(options.unitDistanceOptions, "ramp");
|
|
981
|
+
let counter = 0;
|
|
982
|
+
let nodeMap = {};
|
|
983
|
+
relationships.forEach((relationship) => {
|
|
984
|
+
const {
|
|
985
|
+
properties: { origin, destination }
|
|
986
|
+
} = relationship;
|
|
987
|
+
(0, import_set2.default)(nodeMap, `${origin.id}.${destination.id}`, distanceOptions.baseDistance);
|
|
988
|
+
(0, import_set2.default)(nodeMap, `${destination.id}.${origin.id}`, distanceOptions.baseDistance);
|
|
989
|
+
counter++;
|
|
990
|
+
});
|
|
991
|
+
const t1 = performance.now();
|
|
992
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} ramp relationships`, t1 - t0);
|
|
993
|
+
return nodeMap;
|
|
994
|
+
};
|
|
995
|
+
|
|
996
|
+
// src/data/navigate/graph/nodemap/createStairNodeMap.ts
|
|
997
|
+
var import_lodash6 = __toESM(require("lodash"));
|
|
998
|
+
var createStairNodeMap = (elevatorLikeRelationships, unitOpenings, options) => {
|
|
999
|
+
const t0 = performance.now();
|
|
1000
|
+
const { levels = [], openings = [], units = [] } = options.data;
|
|
1001
|
+
const { baseDistance, scaleDistanceByLevel } = getDistanceOptions(options.unitDistanceOptions, "stairs");
|
|
1002
|
+
let elevatorNodeMap = {};
|
|
1003
|
+
let counter = 0;
|
|
1004
|
+
for (const relationship of elevatorLikeRelationships) {
|
|
1005
|
+
try {
|
|
1006
|
+
const {
|
|
1007
|
+
origin: { id: originId },
|
|
1008
|
+
intermediary,
|
|
1009
|
+
destination: { id: destinationId }
|
|
1010
|
+
} = relationship.properties;
|
|
1011
|
+
const origin = openings.find((opening) => opening.id === originId);
|
|
1012
|
+
if (!origin) return;
|
|
1013
|
+
const originLevel = levels.find((level) => level.id === origin.properties.level_id);
|
|
1014
|
+
const destination = openings.find((opening) => opening.id === destinationId);
|
|
1015
|
+
const destinationOpeningAndLevel = {
|
|
1016
|
+
opening: destination,
|
|
1017
|
+
level: levels.find((level) => level.id === destination.properties.level_id)
|
|
1018
|
+
};
|
|
1019
|
+
const intermediaryOpeningAndLevels = intermediary.map((unitTypeAndId) => {
|
|
1020
|
+
const openings2 = unitOpenings[unitTypeAndId.id];
|
|
1021
|
+
const unit = units.find((unit2) => unit2.id === unitTypeAndId.id);
|
|
1022
|
+
const level = levels.find((level2) => level2.id === unit.properties.level_id);
|
|
1023
|
+
return openings2.map((opening) => ({ opening, level }));
|
|
1024
|
+
}).flat();
|
|
1025
|
+
const connections = [...intermediaryOpeningAndLevels, destinationOpeningAndLevel];
|
|
1026
|
+
if (!origin) return;
|
|
1027
|
+
for (const connection of connections) {
|
|
1028
|
+
const { opening, level } = connection;
|
|
1029
|
+
let distance5 = baseDistance;
|
|
1030
|
+
if (scaleDistanceByLevel) {
|
|
1031
|
+
const originOrdinal = originLevel.properties.ordinal;
|
|
1032
|
+
const connectionOrdinal = level.properties.ordinal;
|
|
1033
|
+
const levelDifference = Math.abs(originOrdinal - connectionOrdinal);
|
|
1034
|
+
if (levelDifference > 0) distance5 *= levelDifference;
|
|
1035
|
+
}
|
|
1036
|
+
import_lodash6.default.set(elevatorNodeMap, `${origin.id}.${opening.id}`, distance5);
|
|
1037
|
+
import_lodash6.default.set(elevatorNodeMap, `${opening.id}.${origin.id}`, distance5);
|
|
1038
|
+
counter++;
|
|
1039
|
+
}
|
|
1040
|
+
} catch (err) {
|
|
1041
|
+
console.warn(
|
|
1042
|
+
"Failed to create stairNodeMap",
|
|
1043
|
+
{
|
|
1044
|
+
relationshipId: relationship.id,
|
|
1045
|
+
featureType: relationship.feature_type,
|
|
1046
|
+
error: err instanceof Error ? err.message : err,
|
|
1047
|
+
stack: err instanceof Error ? err.stack : void 0
|
|
1048
|
+
}
|
|
1049
|
+
);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
const t1 = performance.now();
|
|
1053
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} stairs relationships`, t1 - t0);
|
|
1054
|
+
return elevatorNodeMap;
|
|
1055
|
+
};
|
|
1056
|
+
|
|
1057
|
+
// src/data/navigate/graph/nodemap/createOccupantNodeMap.ts
|
|
1058
|
+
var import_lodash7 = __toESM(require("lodash"));
|
|
1059
|
+
var createOccupantNodeMap = (occupants) => {
|
|
1060
|
+
const t0 = performance.now();
|
|
1061
|
+
let nodeMap = {};
|
|
1062
|
+
let counter = 0;
|
|
1063
|
+
occupants.forEach((occupant) => {
|
|
1064
|
+
const { unit_id, unit_ids = [], kiosk_id, kiosk_ids = [] } = occupant.properties;
|
|
1065
|
+
const occupantRoomIds = compact([unit_id, ...unit_ids]);
|
|
1066
|
+
const occupantKioskIds = compact([kiosk_id, ...kiosk_ids]);
|
|
1067
|
+
for (const roomId of occupantRoomIds) {
|
|
1068
|
+
import_lodash7.default.set(nodeMap, `${roomId}.${occupant.id}`, 1e-3);
|
|
1069
|
+
import_lodash7.default.set(nodeMap, `${occupant.id}.${roomId}`, 1e-3);
|
|
1070
|
+
counter++;
|
|
1071
|
+
}
|
|
1072
|
+
for (const kioskId of occupantKioskIds) {
|
|
1073
|
+
import_lodash7.default.set(nodeMap, `${kioskId}.${occupant.id}`, 1e-3);
|
|
1074
|
+
import_lodash7.default.set(nodeMap, `${occupant.id}.${kioskId}`, 1e-3);
|
|
1075
|
+
counter++;
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
const t1 = performance.now();
|
|
1079
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} occupants relationships`, t1 - t0);
|
|
1080
|
+
return nodeMap;
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1083
|
+
// src/data/navigate/graph/nodemap/createPOINodeMaps.ts
|
|
1084
|
+
var import_center4 = require("@turf/center");
|
|
1085
|
+
var import_distance2 = require("@turf/distance");
|
|
1086
|
+
var import_lodash9 = __toESM(require("lodash"));
|
|
1087
|
+
var createPOINodeMap = (features, getFeatureUnit, unitOpenings) => {
|
|
1088
|
+
const t0 = performance.now();
|
|
1089
|
+
let nodeMap = {};
|
|
1090
|
+
let counter = 0;
|
|
1091
|
+
features.forEach((feat) => {
|
|
1092
|
+
try {
|
|
1093
|
+
const locatedOnUnitId = getFeatureUnit(feat);
|
|
1094
|
+
const openings = unitOpenings[locatedOnUnitId];
|
|
1095
|
+
const center7 = (0, import_center4.center)(feat);
|
|
1096
|
+
for (const opening of openings) {
|
|
1097
|
+
try {
|
|
1098
|
+
const openingCenter = (0, import_center4.center)(opening);
|
|
1099
|
+
const dis = (0, import_distance2.distance)(center7, openingCenter, { units: "meters" }) + BASE_POI_BASEDISTANCE;
|
|
1100
|
+
import_lodash9.default.set(nodeMap, `${opening.id}.${feat.id}`, dis);
|
|
1101
|
+
import_lodash9.default.set(nodeMap, `${feat.id}.${opening.id}`, dis);
|
|
1102
|
+
counter++;
|
|
1103
|
+
} catch (err) {
|
|
1104
|
+
console.log(err, opening);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
} catch (err) {
|
|
1108
|
+
console.log(err);
|
|
1109
|
+
console.log(`cannot connect poi to openings`, err.message, { feat });
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
1112
|
+
const type = features.length > 0 ? features[0].feature_type : "-";
|
|
1113
|
+
const t1 = performance.now();
|
|
1114
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} ${type} relationships`, t1 - t0);
|
|
1115
|
+
return nodeMap;
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1118
|
+
// src/data/navigate/graph/utils/mergeNodeMap.ts
|
|
1119
|
+
var mergeNodeMap = (nodeMaps) => {
|
|
1120
|
+
const out = {};
|
|
1121
|
+
for (const nodeMap of nodeMaps) {
|
|
1122
|
+
for (const from in nodeMap) {
|
|
1123
|
+
out[from] = {
|
|
1124
|
+
...out[from] ?? {},
|
|
1125
|
+
...nodeMap[from]
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
return out;
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
// src/data/navigate/graph/utils/createUnitOpenings.ts
|
|
1133
|
+
var import_uniqBy = __toESM(require("lodash/uniqBy"));
|
|
1134
|
+
var createUnitOpenings = (relationships, units, openings) => {
|
|
1135
|
+
const openingConnections = {};
|
|
1136
|
+
const relationshipMap = /* @__PURE__ */ new Map();
|
|
1137
|
+
relationships.forEach((relationship) => {
|
|
1138
|
+
const originId = relationship.properties.origin?.id || null;
|
|
1139
|
+
const destinationId = relationship.properties.destination?.id || null;
|
|
1140
|
+
if (!relationshipMap.has(originId)) {
|
|
1141
|
+
relationshipMap.set(originId, []);
|
|
1142
|
+
}
|
|
1143
|
+
if (!relationshipMap.has(destinationId)) {
|
|
1144
|
+
relationshipMap.set(destinationId, []);
|
|
1145
|
+
}
|
|
1146
|
+
relationshipMap.get(originId).push(relationship);
|
|
1147
|
+
relationshipMap.get(destinationId).push(relationship);
|
|
1148
|
+
});
|
|
1149
|
+
units.forEach((unit) => {
|
|
1150
|
+
const unitId = unit.id;
|
|
1151
|
+
const connectedRelationshop = relationshipMap.get(unitId) || [];
|
|
1152
|
+
const relationshipIntermediaryTypeAndId = connectedRelationshop.map(
|
|
1153
|
+
(relationship) => relationship.properties.intermediary[0]
|
|
1154
|
+
// Assuming intermediary is always an array
|
|
1155
|
+
);
|
|
1156
|
+
const relationshipIntermediary = relationshipIntermediaryTypeAndId.map(({ id }) => {
|
|
1157
|
+
return openings.find((opening) => opening.id === id);
|
|
1158
|
+
});
|
|
1159
|
+
openingConnections[unitId] = (0, import_uniqBy.default)(
|
|
1160
|
+
[...openingConnections[unitId] || [], ...relationshipIntermediary],
|
|
1161
|
+
"id"
|
|
1162
|
+
);
|
|
1163
|
+
});
|
|
1164
|
+
return openingConnections;
|
|
1165
|
+
};
|
|
1166
|
+
|
|
1167
|
+
// src/data/navigate/parsers.ts
|
|
1168
|
+
var parseOrdinalCoordinate = (id) => {
|
|
1169
|
+
return id.slice(0, -1).split(",").map(Number);
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
// src/data/navigate/graph/prepare.ts
|
|
1173
|
+
var prepareGraph = (options) => {
|
|
1174
|
+
const {
|
|
1175
|
+
data: {
|
|
1176
|
+
amenities = [],
|
|
1177
|
+
anchors = [],
|
|
1178
|
+
occupants = [],
|
|
1179
|
+
relationships = [],
|
|
1180
|
+
openings = [],
|
|
1181
|
+
units = [],
|
|
1182
|
+
kiosks = [],
|
|
1183
|
+
levels = []
|
|
1184
|
+
}
|
|
1185
|
+
} = options;
|
|
1186
|
+
const {
|
|
1187
|
+
traversal: traversalRelationships = [],
|
|
1188
|
+
escalator: escalatorRelationships = [],
|
|
1189
|
+
ramp: rampRelationships = [],
|
|
1190
|
+
elevator: elevatorRelationships = [],
|
|
1191
|
+
stairs: stairsRelationships = []
|
|
1192
|
+
} = import_lodash10.default.groupBy(relationships, "properties.category");
|
|
1193
|
+
const unitOpenings = createUnitOpenings(traversalRelationships, units, openings);
|
|
1194
|
+
const traversalNodeMap = createTraversalNodeMap(unitOpenings, options);
|
|
1195
|
+
const escalatorNodeMap = createEscalatorNodeMap(escalatorRelationships, options);
|
|
1196
|
+
const rampNodeMap = createRampNodeMap(rampRelationships, options);
|
|
1197
|
+
const elevatorNodeMap = createElevatorNodeMap(
|
|
1198
|
+
elevatorRelationships,
|
|
1199
|
+
unitOpenings,
|
|
1200
|
+
options
|
|
1201
|
+
);
|
|
1202
|
+
const stairNodeMap = createStairNodeMap(
|
|
1203
|
+
stairsRelationships,
|
|
1204
|
+
unitOpenings,
|
|
1205
|
+
options
|
|
1206
|
+
);
|
|
1207
|
+
const amenityNodeMap = createPOINodeMap(amenities, (amenity) => amenity.properties.unit_ids[0], unitOpenings);
|
|
1208
|
+
const anchorsNodeMap = createPOINodeMap(anchors, (anchor) => anchor.properties.unit_id, unitOpenings);
|
|
1209
|
+
const walkwayUnits = units.filter((unit) => unit.properties.category === "walkway");
|
|
1210
|
+
const kioskNodeMap = createPOINodeMap(kiosks, (kiosk) => findContainingUnit(kiosk, walkwayUnits)?.id, unitOpenings);
|
|
1211
|
+
const unitNodeMap = createPOINodeMap(units, (unit) => unit.id, unitOpenings);
|
|
1212
|
+
const occupantNodeMap = createOccupantNodeMap(occupants);
|
|
1213
|
+
const defaultGraph = new import_node_dijkstra.default(mergeNodeMap([
|
|
1214
|
+
traversalNodeMap,
|
|
1215
|
+
escalatorNodeMap,
|
|
1216
|
+
rampNodeMap,
|
|
1217
|
+
elevatorNodeMap,
|
|
1218
|
+
stairNodeMap,
|
|
1219
|
+
amenityNodeMap,
|
|
1220
|
+
anchorsNodeMap,
|
|
1221
|
+
kioskNodeMap,
|
|
1222
|
+
unitNodeMap,
|
|
1223
|
+
occupantNodeMap
|
|
1224
|
+
]));
|
|
1225
|
+
const accessibleGraph = new import_node_dijkstra.default(mergeNodeMap([
|
|
1226
|
+
traversalNodeMap,
|
|
1227
|
+
rampNodeMap,
|
|
1228
|
+
elevatorNodeMap,
|
|
1229
|
+
amenityNodeMap,
|
|
1230
|
+
anchorsNodeMap,
|
|
1231
|
+
kioskNodeMap,
|
|
1232
|
+
unitNodeMap,
|
|
1233
|
+
occupantNodeMap
|
|
1234
|
+
]));
|
|
1235
|
+
const addCoordinateOrdinalNode = (params, locatedOnUnit) => {
|
|
1236
|
+
const [lat, lng, ordinal] = parseOrdinalCoordinate(params);
|
|
1237
|
+
if (locatedOnUnit) {
|
|
1238
|
+
const openings2 = unitOpenings[locatedOnUnit.id];
|
|
1239
|
+
for (const opening of openings2) {
|
|
1240
|
+
const openingCenter = (0, import_center5.center)(opening);
|
|
1241
|
+
const dis = (0, import_distance3.distance)([lat, lng], openingCenter, { units: "meters" });
|
|
1242
|
+
defaultGraph.addNode(params, { [opening.id]: dis }).addNode(opening.id, { [params]: dis });
|
|
1243
|
+
accessibleGraph.addNode(params, { [opening.id]: dis }).addNode(opening.id, { [params]: dis });
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
return { defaultGraph, accessibleGraph, unitOpenings, addCoordinateOrdinalNode };
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
// src/data/navigate/steps/createStepUtils.ts
|
|
1251
|
+
var import_lodash12 = require("lodash");
|
|
1252
|
+
var import_intersectionBy = __toESM(require("lodash/intersectionBy"));
|
|
1253
|
+
|
|
1254
|
+
// src/data/navigate/description/describe.ts
|
|
1255
|
+
var t = (template, locale, options) => {
|
|
1256
|
+
return template.replace(`{{intermediary}}`, options.intermediary ?? "").replace(`{{toward}}`, options.toward?.[locale] ?? "").replace(`{{landmark}}`, options.landmark?.[locale] ?? "");
|
|
1257
|
+
};
|
|
1258
|
+
var describeVerticalStep = (fromLevel, toLevel, intermediary) => {
|
|
1259
|
+
const dir = fromLevel.properties.ordinal < toLevel.properties.ordinal ? "up" : "down";
|
|
1260
|
+
const template = `Take the {{intermediary}} ${dir} to {{toward}}`;
|
|
1261
|
+
return {
|
|
1262
|
+
template,
|
|
1263
|
+
text: t(template, "en", { intermediary, toward: toLevel.properties.name })
|
|
1264
|
+
};
|
|
1265
|
+
};
|
|
1266
|
+
var describeHorizontalStep = (intermediary, toward, landmark) => {
|
|
1267
|
+
const template = `Follow the path ${intermediary === "walkway" ? `along the walkway` : `through {{intermediary}}`} ${toward ? `toward {{toward}}` : ``} ${landmark ? `near {{landmark}}` : ``}`.trim();
|
|
1268
|
+
return {
|
|
1269
|
+
text: t(template, "en", { intermediary, toward, landmark }),
|
|
1270
|
+
template
|
|
1271
|
+
};
|
|
1272
|
+
};
|
|
1273
|
+
|
|
1274
|
+
// src/data/navigate/steps/path/index.ts
|
|
1275
|
+
var import_lodash11 = __toESM(require("lodash"));
|
|
1276
|
+
|
|
1277
|
+
// src/data/navigate/constants.ts
|
|
1278
|
+
var OBSTACLE_FEATURE_TYPES = [
|
|
1279
|
+
"kiosk"
|
|
1280
|
+
/* , "fixture" */
|
|
1281
|
+
];
|
|
1282
|
+
var OBSTACLE_CATEGORIES = [
|
|
1283
|
+
"fixture.water",
|
|
1284
|
+
"fixture.stage",
|
|
1285
|
+
"nonpublic",
|
|
1286
|
+
"opentobelow",
|
|
1287
|
+
"elevator",
|
|
1288
|
+
"escalator",
|
|
1289
|
+
"stairs",
|
|
1290
|
+
"stairs.emergencyexit",
|
|
1291
|
+
"room",
|
|
1292
|
+
"unspecified",
|
|
1293
|
+
"structure",
|
|
1294
|
+
"brick",
|
|
1295
|
+
"concrete",
|
|
1296
|
+
"drywall",
|
|
1297
|
+
"glass",
|
|
1298
|
+
"wood",
|
|
1299
|
+
"column"
|
|
1300
|
+
];
|
|
1301
|
+
var WALKABLE_CATEGORY = [
|
|
1302
|
+
"walkway",
|
|
1303
|
+
"parking",
|
|
1304
|
+
"room",
|
|
1305
|
+
"terrace",
|
|
1306
|
+
"unenclosedarea",
|
|
1307
|
+
"vegetation",
|
|
1308
|
+
"unspecified"
|
|
1309
|
+
];
|
|
1310
|
+
|
|
1311
|
+
// node_modules/@turf/helpers/dist/esm/index.js
|
|
1312
|
+
var earthRadius = 63710088e-1;
|
|
1313
|
+
var factors = {
|
|
1314
|
+
centimeters: earthRadius * 100,
|
|
1315
|
+
centimetres: earthRadius * 100,
|
|
1316
|
+
degrees: 360 / (2 * Math.PI),
|
|
1317
|
+
feet: earthRadius * 3.28084,
|
|
1318
|
+
inches: earthRadius * 39.37,
|
|
1319
|
+
kilometers: earthRadius / 1e3,
|
|
1320
|
+
kilometres: earthRadius / 1e3,
|
|
1321
|
+
meters: earthRadius,
|
|
1322
|
+
metres: earthRadius,
|
|
1323
|
+
miles: earthRadius / 1609.344,
|
|
1324
|
+
millimeters: earthRadius * 1e3,
|
|
1325
|
+
millimetres: earthRadius * 1e3,
|
|
1326
|
+
nauticalmiles: earthRadius / 1852,
|
|
1327
|
+
radians: 1,
|
|
1328
|
+
yards: earthRadius * 1.0936
|
|
1329
|
+
};
|
|
1330
|
+
function feature(geom, properties, options = {}) {
|
|
1331
|
+
const feat = { type: "Feature" };
|
|
1332
|
+
if (options.id === 0 || options.id) {
|
|
1333
|
+
feat.id = options.id;
|
|
1334
|
+
}
|
|
1335
|
+
if (options.bbox) {
|
|
1336
|
+
feat.bbox = options.bbox;
|
|
1337
|
+
}
|
|
1338
|
+
feat.properties = properties || {};
|
|
1339
|
+
feat.geometry = geom;
|
|
1340
|
+
return feat;
|
|
1341
|
+
}
|
|
1342
|
+
function point(coordinates, properties, options = {}) {
|
|
1343
|
+
if (!coordinates) {
|
|
1344
|
+
throw new Error("coordinates is required");
|
|
1345
|
+
}
|
|
1346
|
+
if (!Array.isArray(coordinates)) {
|
|
1347
|
+
throw new Error("coordinates must be an Array");
|
|
1348
|
+
}
|
|
1349
|
+
if (coordinates.length < 2) {
|
|
1350
|
+
throw new Error("coordinates must be at least 2 numbers long");
|
|
1351
|
+
}
|
|
1352
|
+
if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) {
|
|
1353
|
+
throw new Error("coordinates must contain numbers");
|
|
1354
|
+
}
|
|
1355
|
+
const geom = {
|
|
1356
|
+
type: "Point",
|
|
1357
|
+
coordinates
|
|
1358
|
+
};
|
|
1359
|
+
return feature(geom, properties, options);
|
|
1360
|
+
}
|
|
1361
|
+
function polygon(coordinates, properties, options = {}) {
|
|
1362
|
+
for (const ring of coordinates) {
|
|
1363
|
+
if (ring.length < 4) {
|
|
1364
|
+
throw new Error(
|
|
1365
|
+
"Each LinearRing of a Polygon must have 4 or more Positions."
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
if (ring[ring.length - 1].length !== ring[0].length) {
|
|
1369
|
+
throw new Error("First and last Position are not equivalent.");
|
|
1370
|
+
}
|
|
1371
|
+
for (let j = 0; j < ring[ring.length - 1].length; j++) {
|
|
1372
|
+
if (ring[ring.length - 1][j] !== ring[0][j]) {
|
|
1373
|
+
throw new Error("First and last Position are not equivalent.");
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
const geom = {
|
|
1378
|
+
type: "Polygon",
|
|
1379
|
+
coordinates
|
|
1380
|
+
};
|
|
1381
|
+
return feature(geom, properties, options);
|
|
1382
|
+
}
|
|
1383
|
+
function lineString(coordinates, properties, options = {}) {
|
|
1384
|
+
if (coordinates.length < 2) {
|
|
1385
|
+
throw new Error("coordinates must be an array of two or more positions");
|
|
1386
|
+
}
|
|
1387
|
+
const geom = {
|
|
1388
|
+
type: "LineString",
|
|
1389
|
+
coordinates
|
|
1390
|
+
};
|
|
1391
|
+
return feature(geom, properties, options);
|
|
1392
|
+
}
|
|
1393
|
+
function featureCollection(features, options = {}) {
|
|
1394
|
+
const fc = { type: "FeatureCollection" };
|
|
1395
|
+
if (options.id) {
|
|
1396
|
+
fc.id = options.id;
|
|
1397
|
+
}
|
|
1398
|
+
if (options.bbox) {
|
|
1399
|
+
fc.bbox = options.bbox;
|
|
1400
|
+
}
|
|
1401
|
+
fc.features = features;
|
|
1402
|
+
return fc;
|
|
1403
|
+
}
|
|
1404
|
+
function isNumber(num) {
|
|
1405
|
+
return !isNaN(num) && num !== null && !Array.isArray(num);
|
|
1406
|
+
}
|
|
1407
|
+
function isObject(input) {
|
|
1408
|
+
return input !== null && typeof input === "object" && !Array.isArray(input);
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
// node_modules/@turf/invariant/dist/esm/index.js
|
|
1412
|
+
function getCoord(coord) {
|
|
1413
|
+
if (!coord) {
|
|
1414
|
+
throw new Error("coord is required");
|
|
1415
|
+
}
|
|
1416
|
+
if (!Array.isArray(coord)) {
|
|
1417
|
+
if (coord.type === "Feature" && coord.geometry !== null && coord.geometry.type === "Point") {
|
|
1418
|
+
return [...coord.geometry.coordinates];
|
|
1419
|
+
}
|
|
1420
|
+
if (coord.type === "Point") {
|
|
1421
|
+
return [...coord.coordinates];
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
if (Array.isArray(coord) && coord.length >= 2 && !Array.isArray(coord[0]) && !Array.isArray(coord[1])) {
|
|
1425
|
+
return [...coord];
|
|
1426
|
+
}
|
|
1427
|
+
throw new Error("coord must be GeoJSON Point or an Array of numbers");
|
|
1428
|
+
}
|
|
1429
|
+
function getGeom(geojson) {
|
|
1430
|
+
if (geojson.type === "Feature") {
|
|
1431
|
+
return geojson.geometry;
|
|
1432
|
+
}
|
|
1433
|
+
return geojson;
|
|
1434
|
+
}
|
|
1435
|
+
function getType(geojson, _name) {
|
|
1436
|
+
if (geojson.type === "FeatureCollection") {
|
|
1437
|
+
return "FeatureCollection";
|
|
1438
|
+
}
|
|
1439
|
+
if (geojson.type === "GeometryCollection") {
|
|
1440
|
+
return "GeometryCollection";
|
|
1441
|
+
}
|
|
1442
|
+
if (geojson.type === "Feature" && geojson.geometry !== null) {
|
|
1443
|
+
return geojson.geometry.type;
|
|
1444
|
+
}
|
|
1445
|
+
return geojson.type;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
// src/data/navigate/steps/path/index.ts
|
|
1449
|
+
var import_difference = __toESM(require("@turf/difference"));
|
|
1450
|
+
var import_envelope = __toESM(require("@turf/envelope"));
|
|
1451
|
+
var import_boolean_overlap = __toESM(require("@turf/boolean-overlap"));
|
|
1452
|
+
var import_boolean_intersects = __toESM(require("@turf/boolean-intersects"));
|
|
1453
|
+
|
|
1454
|
+
// ../../node_modules/@turf/meta/dist/esm/index.js
|
|
1455
|
+
function coordEach(geojson, callback, excludeWrapCoord) {
|
|
1456
|
+
if (geojson === null) return;
|
|
1457
|
+
var j, k, l, geometry, stopG, coords, geometryMaybeCollection, wrapShrink = 0, coordIndex = 0, isGeometryCollection, type = geojson.type, isFeatureCollection = type === "FeatureCollection", isFeature = type === "Feature", stop = isFeatureCollection ? geojson.features.length : 1;
|
|
1458
|
+
for (var featureIndex = 0; featureIndex < stop; featureIndex++) {
|
|
1459
|
+
geometryMaybeCollection = isFeatureCollection ? geojson.features[featureIndex].geometry : isFeature ? geojson.geometry : geojson;
|
|
1460
|
+
isGeometryCollection = geometryMaybeCollection ? geometryMaybeCollection.type === "GeometryCollection" : false;
|
|
1461
|
+
stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
|
|
1462
|
+
for (var geomIndex = 0; geomIndex < stopG; geomIndex++) {
|
|
1463
|
+
var multiFeatureIndex = 0;
|
|
1464
|
+
var geometryIndex = 0;
|
|
1465
|
+
geometry = isGeometryCollection ? geometryMaybeCollection.geometries[geomIndex] : geometryMaybeCollection;
|
|
1466
|
+
if (geometry === null) continue;
|
|
1467
|
+
coords = geometry.coordinates;
|
|
1468
|
+
var geomType = geometry.type;
|
|
1469
|
+
wrapShrink = excludeWrapCoord && (geomType === "Polygon" || geomType === "MultiPolygon") ? 1 : 0;
|
|
1470
|
+
switch (geomType) {
|
|
1471
|
+
case null:
|
|
1472
|
+
break;
|
|
1473
|
+
case "Point":
|
|
1474
|
+
if (callback(
|
|
1475
|
+
coords,
|
|
1476
|
+
coordIndex,
|
|
1477
|
+
featureIndex,
|
|
1478
|
+
multiFeatureIndex,
|
|
1479
|
+
geometryIndex
|
|
1480
|
+
) === false)
|
|
1481
|
+
return false;
|
|
1482
|
+
coordIndex++;
|
|
1483
|
+
multiFeatureIndex++;
|
|
1484
|
+
break;
|
|
1485
|
+
case "LineString":
|
|
1486
|
+
case "MultiPoint":
|
|
1487
|
+
for (j = 0; j < coords.length; j++) {
|
|
1488
|
+
if (callback(
|
|
1489
|
+
coords[j],
|
|
1490
|
+
coordIndex,
|
|
1491
|
+
featureIndex,
|
|
1492
|
+
multiFeatureIndex,
|
|
1493
|
+
geometryIndex
|
|
1494
|
+
) === false)
|
|
1495
|
+
return false;
|
|
1496
|
+
coordIndex++;
|
|
1497
|
+
if (geomType === "MultiPoint") multiFeatureIndex++;
|
|
1498
|
+
}
|
|
1499
|
+
if (geomType === "LineString") multiFeatureIndex++;
|
|
1500
|
+
break;
|
|
1501
|
+
case "Polygon":
|
|
1502
|
+
case "MultiLineString":
|
|
1503
|
+
for (j = 0; j < coords.length; j++) {
|
|
1504
|
+
for (k = 0; k < coords[j].length - wrapShrink; k++) {
|
|
1505
|
+
if (callback(
|
|
1506
|
+
coords[j][k],
|
|
1507
|
+
coordIndex,
|
|
1508
|
+
featureIndex,
|
|
1509
|
+
multiFeatureIndex,
|
|
1510
|
+
geometryIndex
|
|
1511
|
+
) === false)
|
|
1512
|
+
return false;
|
|
1513
|
+
coordIndex++;
|
|
1514
|
+
}
|
|
1515
|
+
if (geomType === "MultiLineString") multiFeatureIndex++;
|
|
1516
|
+
if (geomType === "Polygon") geometryIndex++;
|
|
1517
|
+
}
|
|
1518
|
+
if (geomType === "Polygon") multiFeatureIndex++;
|
|
1519
|
+
break;
|
|
1520
|
+
case "MultiPolygon":
|
|
1521
|
+
for (j = 0; j < coords.length; j++) {
|
|
1522
|
+
geometryIndex = 0;
|
|
1523
|
+
for (k = 0; k < coords[j].length; k++) {
|
|
1524
|
+
for (l = 0; l < coords[j][k].length - wrapShrink; l++) {
|
|
1525
|
+
if (callback(
|
|
1526
|
+
coords[j][k][l],
|
|
1527
|
+
coordIndex,
|
|
1528
|
+
featureIndex,
|
|
1529
|
+
multiFeatureIndex,
|
|
1530
|
+
geometryIndex
|
|
1531
|
+
) === false)
|
|
1532
|
+
return false;
|
|
1533
|
+
coordIndex++;
|
|
1534
|
+
}
|
|
1535
|
+
geometryIndex++;
|
|
1536
|
+
}
|
|
1537
|
+
multiFeatureIndex++;
|
|
1538
|
+
}
|
|
1539
|
+
break;
|
|
1540
|
+
case "GeometryCollection":
|
|
1541
|
+
for (j = 0; j < geometry.geometries.length; j++)
|
|
1542
|
+
if (coordEach(geometry.geometries[j], callback, excludeWrapCoord) === false)
|
|
1543
|
+
return false;
|
|
1544
|
+
break;
|
|
1545
|
+
default:
|
|
1546
|
+
throw new Error("Unknown Geometry Type");
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
// ../../node_modules/@turf/bbox/dist/esm/index.js
|
|
1553
|
+
function bbox(geojson, options = {}) {
|
|
1554
|
+
if (geojson.bbox != null && true !== options.recompute) {
|
|
1555
|
+
return geojson.bbox;
|
|
1556
|
+
}
|
|
1557
|
+
const result = [Infinity, Infinity, -Infinity, -Infinity];
|
|
1558
|
+
coordEach(geojson, (coord) => {
|
|
1559
|
+
if (result[0] > coord[0]) {
|
|
1560
|
+
result[0] = coord[0];
|
|
1561
|
+
}
|
|
1562
|
+
if (result[1] > coord[1]) {
|
|
1563
|
+
result[1] = coord[1];
|
|
1564
|
+
}
|
|
1565
|
+
if (result[2] < coord[0]) {
|
|
1566
|
+
result[2] = coord[0];
|
|
1567
|
+
}
|
|
1568
|
+
if (result[3] < coord[1]) {
|
|
1569
|
+
result[3] = coord[1];
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
return result;
|
|
1573
|
+
}
|
|
1574
|
+
var index_default = bbox;
|
|
1575
|
+
|
|
1576
|
+
// src/data/navigate/steps/path/turf/shortestPath.ts
|
|
1577
|
+
var import_boolean_point_in_polygon3 = __toESM(require("@turf/boolean-point-in-polygon"));
|
|
1578
|
+
var import_distance4 = __toESM(require("@turf/distance"));
|
|
1579
|
+
var import_transform_scale = __toESM(require("@turf/transform-scale"));
|
|
1580
|
+
var import_union = __toESM(require("@turf/union"));
|
|
1581
|
+
var import_bbox_polygon = __toESM(require("@turf/bbox-polygon"));
|
|
1582
|
+
var import_clean_coords = require("@turf/clean-coords");
|
|
1583
|
+
var import_pathfinding = __toESM(require("pathfinding"));
|
|
1584
|
+
var import_set3 = __toESM(require("lodash/set"));
|
|
1585
|
+
|
|
1586
|
+
// src/data/navigate/steps/path/turf/stringPull.ts
|
|
1587
|
+
function stringPull(grid, path) {
|
|
1588
|
+
const isWalkable = (x, y) => grid.isInside(x, y) && grid.isWalkableAt(x, y);
|
|
1589
|
+
function hasLOS(a, b) {
|
|
1590
|
+
let x0 = a[0], y0 = a[1];
|
|
1591
|
+
const x1 = b[0], y1 = b[1];
|
|
1592
|
+
if (!isWalkable(x0, y0) || !isWalkable(x1, y1)) return false;
|
|
1593
|
+
const dx = Math.abs(x1 - x0);
|
|
1594
|
+
const dy = Math.abs(y1 - y0);
|
|
1595
|
+
const sx = x0 < x1 ? 1 : -1;
|
|
1596
|
+
const sy = y0 < y1 ? 1 : -1;
|
|
1597
|
+
let err = dx - dy;
|
|
1598
|
+
while (true) {
|
|
1599
|
+
if (!isWalkable(x0, y0)) return false;
|
|
1600
|
+
if (x0 === x1 && y0 === y1) break;
|
|
1601
|
+
const e2 = err * 2;
|
|
1602
|
+
let nx = x0;
|
|
1603
|
+
let ny = y0;
|
|
1604
|
+
let movedX = false;
|
|
1605
|
+
let movedY = false;
|
|
1606
|
+
if (e2 > -dy) {
|
|
1607
|
+
err -= dy;
|
|
1608
|
+
nx += sx;
|
|
1609
|
+
movedX = true;
|
|
1610
|
+
}
|
|
1611
|
+
if (e2 < dx) {
|
|
1612
|
+
err += dx;
|
|
1613
|
+
ny += sy;
|
|
1614
|
+
movedY = true;
|
|
1615
|
+
}
|
|
1616
|
+
if (movedX && movedY) {
|
|
1617
|
+
if (!isWalkable(nx, y0) || !isWalkable(x0, ny)) return false;
|
|
1618
|
+
}
|
|
1619
|
+
x0 = nx;
|
|
1620
|
+
y0 = ny;
|
|
1621
|
+
}
|
|
1622
|
+
return true;
|
|
1623
|
+
}
|
|
1624
|
+
if (path.length <= 2) return path;
|
|
1625
|
+
const out = [path[0]];
|
|
1626
|
+
let i = 0;
|
|
1627
|
+
while (i < path.length - 1) {
|
|
1628
|
+
let best = i + 1;
|
|
1629
|
+
for (let j = i + 2; j < path.length; j++) {
|
|
1630
|
+
if (hasLOS(path[i], path[j])) best = j;
|
|
1631
|
+
else break;
|
|
1632
|
+
}
|
|
1633
|
+
out.push(path[best]);
|
|
1634
|
+
i = best;
|
|
1635
|
+
}
|
|
1636
|
+
return out;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
// src/data/navigate/steps/path/turf/pruneSmallAngle.ts
|
|
1640
|
+
function pruneSmallAngles(path, minDeg = 10) {
|
|
1641
|
+
if (path.length <= 2) return path;
|
|
1642
|
+
const out = [path[0]];
|
|
1643
|
+
for (let i = 1; i < path.length - 1; i++) {
|
|
1644
|
+
const a = out.at(-1);
|
|
1645
|
+
const b = path[i];
|
|
1646
|
+
const c = path[i + 1];
|
|
1647
|
+
const abx = b[0] - a[0], aby = b[1] - a[1];
|
|
1648
|
+
const bcx = c[0] - b[0], bcy = c[1] - b[1];
|
|
1649
|
+
const dot = abx * bcx + aby * bcy;
|
|
1650
|
+
const ab = Math.hypot(abx, aby);
|
|
1651
|
+
const bc = Math.hypot(bcx, bcy);
|
|
1652
|
+
const angle = Math.acos(dot / (ab * bc)) * 180 / Math.PI;
|
|
1653
|
+
if (angle > minDeg) out.push(b);
|
|
1654
|
+
}
|
|
1655
|
+
out.push(path.at(-1));
|
|
1656
|
+
return out;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
// src/data/navigate/steps/path/turf/pruneShortSegments.ts
|
|
1660
|
+
function pruneShortSegments(path, minLen = 5) {
|
|
1661
|
+
const out = [path[0]];
|
|
1662
|
+
for (let i = 1; i < path.length; i++) {
|
|
1663
|
+
const [x0, y0] = out.at(-1);
|
|
1664
|
+
const [x1, y1] = path[i];
|
|
1665
|
+
if (Math.hypot(x1 - x0, y1 - y0) >= minLen) {
|
|
1666
|
+
out.push(path[i]);
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
return out;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
// src/data/navigate/steps/path/turf/clearance.ts
|
|
1673
|
+
function buildClearanceGrid(matrix) {
|
|
1674
|
+
const h = matrix.length;
|
|
1675
|
+
const w = matrix[0].length;
|
|
1676
|
+
const INF = 1e9;
|
|
1677
|
+
const dist = Array.from({ length: h }, () => Array(w).fill(INF));
|
|
1678
|
+
const q = [];
|
|
1679
|
+
for (let y = 0; y < h; y++) {
|
|
1680
|
+
for (let x = 0; x < w; x++) {
|
|
1681
|
+
if (matrix[y][x] === 1) {
|
|
1682
|
+
dist[y][x] = 0;
|
|
1683
|
+
q.push([x, y]);
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
const dirs = [
|
|
1688
|
+
[1, 0],
|
|
1689
|
+
[-1, 0],
|
|
1690
|
+
[0, 1],
|
|
1691
|
+
[0, -1],
|
|
1692
|
+
[1, 1],
|
|
1693
|
+
[1, -1],
|
|
1694
|
+
[-1, 1],
|
|
1695
|
+
[-1, -1]
|
|
1696
|
+
];
|
|
1697
|
+
let qi = 0;
|
|
1698
|
+
while (qi < q.length) {
|
|
1699
|
+
const [x, y] = q[qi++];
|
|
1700
|
+
const d0 = dist[y][x];
|
|
1701
|
+
for (const [dx, dy] of dirs) {
|
|
1702
|
+
const nx = x + dx, ny = y + dy;
|
|
1703
|
+
if (nx < 0 || ny < 0 || nx >= w || ny >= h) continue;
|
|
1704
|
+
const nd = d0 + 1;
|
|
1705
|
+
if (nd < dist[ny][nx]) {
|
|
1706
|
+
dist[ny][nx] = nd;
|
|
1707
|
+
q.push([nx, ny]);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
return dist;
|
|
1712
|
+
}
|
|
1713
|
+
function snapPointToClearancePeak(p, clearance, isWalkableCell, radius = 4) {
|
|
1714
|
+
const [px, py] = p;
|
|
1715
|
+
let best = p;
|
|
1716
|
+
let bestScore = clearance[py]?.[px] ?? -Infinity;
|
|
1717
|
+
for (let dy = -radius; dy <= radius; dy++) {
|
|
1718
|
+
for (let dx = -radius; dx <= radius; dx++) {
|
|
1719
|
+
const x = px + dx;
|
|
1720
|
+
const y = py + dy;
|
|
1721
|
+
if (!isWalkableCell(x, y)) continue;
|
|
1722
|
+
const score = clearance[y][x];
|
|
1723
|
+
const penalty = Math.hypot(dx, dy) * 5e-3;
|
|
1724
|
+
const finalScore = score - penalty;
|
|
1725
|
+
if (finalScore > bestScore) {
|
|
1726
|
+
bestScore = finalScore;
|
|
1727
|
+
best = [x, y];
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
return best;
|
|
1732
|
+
}
|
|
1733
|
+
function centerlineSnapPath(path, clearance, isWalkableCell, radius = 4) {
|
|
1734
|
+
const snapped = path.map((p) => snapPointToClearancePeak(p, clearance, isWalkableCell, radius));
|
|
1735
|
+
return snapped;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
// src/data/navigate/steps/path/turf/shortestPath.ts
|
|
1739
|
+
function shortestPath(start, end, options) {
|
|
1740
|
+
options = options || {};
|
|
1741
|
+
if (!isObject(options)) throw new Error("options is invalid");
|
|
1742
|
+
let resolution = options.resolution;
|
|
1743
|
+
const smoothenPath = options.smoothenPath;
|
|
1744
|
+
let obstacles = options.obstacles || featureCollection([]);
|
|
1745
|
+
if (!start) throw new Error("start is required");
|
|
1746
|
+
if (!end) throw new Error("end is required");
|
|
1747
|
+
if (resolution && !isNumber(resolution) || resolution <= 0)
|
|
1748
|
+
throw new Error("options.resolution must be a number, greater than 0");
|
|
1749
|
+
const startCoord = getCoord(start);
|
|
1750
|
+
const endCoord = getCoord(end);
|
|
1751
|
+
start = point(startCoord);
|
|
1752
|
+
end = point(endCoord);
|
|
1753
|
+
switch (getType(obstacles)) {
|
|
1754
|
+
case "FeatureCollection":
|
|
1755
|
+
if (obstacles.features.length === 0)
|
|
1756
|
+
return lineString([startCoord, endCoord]);
|
|
1757
|
+
break;
|
|
1758
|
+
case "Polygon":
|
|
1759
|
+
obstacles = featureCollection([feature(getGeom(obstacles))]);
|
|
1760
|
+
break;
|
|
1761
|
+
default:
|
|
1762
|
+
throw new Error("invalid obstacles");
|
|
1763
|
+
}
|
|
1764
|
+
const collection = obstacles;
|
|
1765
|
+
collection.features.push(start, end);
|
|
1766
|
+
const box = index_default((0, import_transform_scale.default)((0, import_bbox_polygon.default)(index_default(collection)), 1.15));
|
|
1767
|
+
if (!resolution) {
|
|
1768
|
+
const width = (0, import_distance4.default)([box[0], box[1]], [box[2], box[1]], options);
|
|
1769
|
+
resolution = width / 100;
|
|
1770
|
+
}
|
|
1771
|
+
collection.features.pop();
|
|
1772
|
+
collection.features.pop();
|
|
1773
|
+
const [west, south, east, north] = box;
|
|
1774
|
+
const xFraction = resolution / (0, import_distance4.default)([west, south], [east, south], options);
|
|
1775
|
+
const cellWidth = xFraction * (east - west);
|
|
1776
|
+
const yFraction = resolution / (0, import_distance4.default)([west, south], [west, north], options);
|
|
1777
|
+
const cellHeight = yFraction * (north - south);
|
|
1778
|
+
const bboxHorizontalSide = east - west;
|
|
1779
|
+
const bboxVerticalSide = north - south;
|
|
1780
|
+
const columns = Math.floor(bboxHorizontalSide / cellWidth);
|
|
1781
|
+
const rows = Math.floor(bboxVerticalSide / cellHeight);
|
|
1782
|
+
const deltaX = (bboxHorizontalSide - columns * cellWidth) / 2;
|
|
1783
|
+
const deltaY = (bboxVerticalSide - rows * cellHeight) / 2;
|
|
1784
|
+
let closestToStart = null, closestToEnd = null, minDistStart = Infinity, minDistEnd = Infinity, currentY = north - deltaY, currentX = west + deltaX, row = 0, column = 0, distStart, distEnd, pt, isInsideObstacle;
|
|
1785
|
+
const roundLoopY = Math.ceil((currentY - south) / cellHeight);
|
|
1786
|
+
const roundLoopX = Math.ceil((east - currentX) / cellWidth);
|
|
1787
|
+
let totalRounds = roundLoopX * roundLoopY;
|
|
1788
|
+
const pointMatrix = [];
|
|
1789
|
+
const matrix = [];
|
|
1790
|
+
const obstacleTotal = collection.features.length;
|
|
1791
|
+
const obstacleFeatures = collection.features;
|
|
1792
|
+
let combinedObstacle = obstacleFeatures[0];
|
|
1793
|
+
let obstacleIndex = 0;
|
|
1794
|
+
for (obstacleIndex = 0; obstacleIndex < obstacleTotal; obstacleIndex++) {
|
|
1795
|
+
const nextObstacleFeature = obstacleFeatures[obstacleIndex + 1];
|
|
1796
|
+
if (!nextObstacleFeature) continue;
|
|
1797
|
+
try {
|
|
1798
|
+
combinedObstacle = (0, import_union.default)(
|
|
1799
|
+
featureCollection([combinedObstacle, nextObstacleFeature])
|
|
1800
|
+
);
|
|
1801
|
+
} catch (e) {
|
|
1802
|
+
console.log(e);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
while (totalRounds--) {
|
|
1806
|
+
pt = point([currentX, currentY]);
|
|
1807
|
+
isInsideObstacle = (0, import_boolean_point_in_polygon3.default)(pt, combinedObstacle);
|
|
1808
|
+
(0, import_set3.default)(matrix, `[${row}][${column}]`, isInsideObstacle ? 1 : 0);
|
|
1809
|
+
(0, import_set3.default)(pointMatrix, `[${row}][${column}]`, `${currentX}|${currentY}`);
|
|
1810
|
+
distStart = (0, import_distance4.default)(pt, start);
|
|
1811
|
+
if (!isInsideObstacle && distStart < minDistStart) {
|
|
1812
|
+
minDistStart = distStart;
|
|
1813
|
+
closestToStart = { x: column, y: row };
|
|
1814
|
+
}
|
|
1815
|
+
distEnd = (0, import_distance4.default)(pt, end);
|
|
1816
|
+
if (!isInsideObstacle && distEnd < minDistEnd) {
|
|
1817
|
+
minDistEnd = distEnd;
|
|
1818
|
+
closestToEnd = { x: column, y: row };
|
|
1819
|
+
}
|
|
1820
|
+
if (column < roundLoopX) {
|
|
1821
|
+
currentX += cellWidth;
|
|
1822
|
+
column++;
|
|
1823
|
+
continue;
|
|
1824
|
+
}
|
|
1825
|
+
if (row < roundLoopY) {
|
|
1826
|
+
currentY -= cellHeight;
|
|
1827
|
+
currentX = west + deltaX;
|
|
1828
|
+
column = 0;
|
|
1829
|
+
row++;
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
const finder = new import_pathfinding.default.AStarFinder({
|
|
1833
|
+
allowDiagonal: true,
|
|
1834
|
+
dontCrossCorners: true,
|
|
1835
|
+
heuristic: import_pathfinding.default.Heuristic.euclidean
|
|
1836
|
+
});
|
|
1837
|
+
const grid = new import_pathfinding.default.Grid(matrix);
|
|
1838
|
+
const startOnMatrix = [closestToStart.x, closestToStart.y];
|
|
1839
|
+
const endOnMatrix = [closestToEnd.x, closestToEnd.y];
|
|
1840
|
+
let result = finder.findPath(...startOnMatrix, ...endOnMatrix, grid);
|
|
1841
|
+
if (result.length > 0) {
|
|
1842
|
+
result = stringPull(grid, result);
|
|
1843
|
+
const clearanceGrid = buildClearanceGrid(matrix);
|
|
1844
|
+
const isWalkable = (x, y) => grid.isInside(x, y) && grid.isWalkableAt(x, y);
|
|
1845
|
+
result = centerlineSnapPath(result, clearanceGrid, isWalkable);
|
|
1846
|
+
result = stringPull(grid, result);
|
|
1847
|
+
result = pruneSmallAngles(result);
|
|
1848
|
+
result = pruneShortSegments(result);
|
|
1849
|
+
}
|
|
1850
|
+
result.pop();
|
|
1851
|
+
result.shift();
|
|
1852
|
+
const path = [startCoord];
|
|
1853
|
+
result.forEach((coord) => {
|
|
1854
|
+
const coords = pointMatrix[coord[1]][coord[0]].split("|");
|
|
1855
|
+
path.push([+coords[0], +coords[1]]);
|
|
1856
|
+
});
|
|
1857
|
+
path.push(endCoord);
|
|
1858
|
+
return (0, import_clean_coords.cleanCoords)(lineString(path));
|
|
1859
|
+
}
|
|
1860
|
+
var shortestPath_default = shortestPath;
|
|
1861
|
+
|
|
1862
|
+
// src/data/navigate/steps/path/index.ts
|
|
1863
|
+
var createStepPathUtils = (options) => {
|
|
1864
|
+
const resolution = options.resolution ?? 88e-5;
|
|
1865
|
+
const { units = [], kiosks = [], fixtures = [] } = options.data;
|
|
1866
|
+
const possibleObstacleFeatures = [...units, ...kiosks, ...fixtures];
|
|
1867
|
+
const filterObstaclesByOrdinal = (levelId) => {
|
|
1868
|
+
return possibleObstacleFeatures.filter(({ feature_type, properties, geometry }) => {
|
|
1869
|
+
return properties.level_id === levelId && ["Polygon", "MultiPolygon"].includes(geometry.type) && (OBSTACLE_FEATURE_TYPES.includes(feature_type) || "category" in properties && OBSTACLE_CATEGORIES.includes(properties.category));
|
|
1870
|
+
});
|
|
1871
|
+
};
|
|
1872
|
+
const findObstaclesFromWalkway = (intermediaryUnit, exceptionIds = []) => {
|
|
1873
|
+
const result = featureCollection([]);
|
|
1874
|
+
if (!intermediaryUnit) return result;
|
|
1875
|
+
const walkwayLevelId = intermediaryUnit.properties.level_id;
|
|
1876
|
+
const obstacleOnLevel = filterObstaclesByOrdinal(walkwayLevelId).filter(
|
|
1877
|
+
(obstacle) => !exceptionIds.includes(obstacle.id)
|
|
1878
|
+
);
|
|
1879
|
+
const relatedObstacleWithIntermediary = obstacleOnLevel.reduce(
|
|
1880
|
+
(obstacles, feature2) => {
|
|
1881
|
+
if (
|
|
1882
|
+
// Prevent detecting itself as an obstacle
|
|
1883
|
+
// Ex. Unable to draw a line to amenity located with in a room as room is also consider as obstacle
|
|
1884
|
+
feature2.id !== intermediaryUnit.id && ((0, import_boolean_overlap.default)(intermediaryUnit, feature2) || (0, import_boolean_intersects.default)(intermediaryUnit, feature2))
|
|
1885
|
+
) {
|
|
1886
|
+
const polygons = getType(feature2) === "Polygon" ? [polygon(feature2.geometry.coordinates, { id: feature2.id })] : feature2.geometry.coordinates.map((ring) => polygon(ring, { id: feature2.id }));
|
|
1887
|
+
obstacles.push(...polygons);
|
|
1888
|
+
}
|
|
1889
|
+
return obstacles;
|
|
1890
|
+
},
|
|
1891
|
+
[]
|
|
1892
|
+
);
|
|
1893
|
+
const intermediaryExtends = (0, import_envelope.default)(intermediaryUnit);
|
|
1894
|
+
const walkwayPerimeter = (0, import_difference.default)(
|
|
1895
|
+
featureCollection([intermediaryExtends, intermediaryUnit])
|
|
1896
|
+
);
|
|
1897
|
+
result.features.push(...relatedObstacleWithIntermediary, walkwayPerimeter);
|
|
1898
|
+
return result;
|
|
1899
|
+
};
|
|
1900
|
+
const findPathOnArea = (originPoint, destinationPoint, options2) => {
|
|
1901
|
+
const { obstacles = featureCollection([]), resolution: resolution2, properties } = options2 || {};
|
|
1902
|
+
const stepPath = shortestPath_default(originPoint, destinationPoint, {
|
|
1903
|
+
obstacles,
|
|
1904
|
+
smoothenPath: false,
|
|
1905
|
+
resolution: resolution2
|
|
1906
|
+
});
|
|
1907
|
+
stepPath.properties = properties;
|
|
1908
|
+
return stepPath;
|
|
1909
|
+
};
|
|
1910
|
+
const findStepPath = (from, to, intermediaries) => {
|
|
1911
|
+
const t0 = performance.now();
|
|
1912
|
+
const relatedWalkablePlatform = intermediaries.find(
|
|
1913
|
+
(feature2) => WALKABLE_CATEGORY.includes(feature2.properties.category)
|
|
1914
|
+
);
|
|
1915
|
+
const exceptionFeatureIds = [];
|
|
1916
|
+
const obstacles = findObstaclesFromWalkway(
|
|
1917
|
+
relatedWalkablePlatform,
|
|
1918
|
+
import_lodash11.default.compact(exceptionFeatureIds)
|
|
1919
|
+
);
|
|
1920
|
+
const line = findPathOnArea(from, to, {
|
|
1921
|
+
resolution,
|
|
1922
|
+
obstacles
|
|
1923
|
+
});
|
|
1924
|
+
return line.geometry.coordinates;
|
|
1925
|
+
};
|
|
1926
|
+
return {
|
|
1927
|
+
findStepPath
|
|
1928
|
+
};
|
|
1929
|
+
};
|
|
1930
|
+
|
|
1931
|
+
// src/data/navigate/steps/utils/combineWalkwaySteps.ts
|
|
1932
|
+
var import_uniq = __toESM(require("lodash/uniq"));
|
|
1933
|
+
var combineWalkwaySteps = (steps) => {
|
|
1934
|
+
let result = [];
|
|
1935
|
+
for (let i = 0; i < steps.length; i++) {
|
|
1936
|
+
const thisStep = steps[i];
|
|
1937
|
+
if (i === steps.length - 1) {
|
|
1938
|
+
result.push(thisStep);
|
|
1939
|
+
continue;
|
|
1940
|
+
}
|
|
1941
|
+
const nextStep = steps[i + 1];
|
|
1942
|
+
if (thisStep.intermediaryCategory === "walkway" && nextStep.intermediaryCategory === "walkway" && thisStep.from.source.type === "opening" && nextStep.from.source.type === "opening") {
|
|
1943
|
+
result.push({
|
|
1944
|
+
from: thisStep.from,
|
|
1945
|
+
to: nextStep.to,
|
|
1946
|
+
levelIds: (0, import_uniq.default)([...thisStep.levelIds, ...nextStep.levelIds]),
|
|
1947
|
+
ordinals: (0, import_uniq.default)([...thisStep.ordinals, ...nextStep.ordinals]),
|
|
1948
|
+
intermediaryCategory: "walkway",
|
|
1949
|
+
description: nextStep.description,
|
|
1950
|
+
path: [
|
|
1951
|
+
...thisStep.path,
|
|
1952
|
+
...nextStep.path
|
|
1953
|
+
]
|
|
1954
|
+
});
|
|
1955
|
+
i++;
|
|
1956
|
+
} else {
|
|
1957
|
+
result.push(thisStep);
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
return result;
|
|
1961
|
+
};
|
|
1962
|
+
|
|
1963
|
+
// src/data/navigate/steps/createStepUtils.ts
|
|
1964
|
+
var createStepUtils = (options) => {
|
|
1965
|
+
const { data: { units, relationships }, findByIdSync } = options;
|
|
1966
|
+
const stepPathUtils = createStepPathUtils({ ...options, resolution: 88e-5 });
|
|
1967
|
+
const findUnitBetweenOpenings = (originId, destinationId) => {
|
|
1968
|
+
const origin = findByIdSync(originId);
|
|
1969
|
+
const destination = findByIdSync(destinationId);
|
|
1970
|
+
const matchedOne = relationships.find((rel) => rel.properties.intermediary.map((int) => int.id).includes(origin.id));
|
|
1971
|
+
const matchOneUnits = matchedOne ? [matchedOne.properties.origin, matchedOne.properties.destination] : [];
|
|
1972
|
+
const matchedTwo = relationships.find((rel) => rel.properties.intermediary.map((int) => int.id).includes(destination.id));
|
|
1973
|
+
const matchTwoUnits = matchedTwo ? [matchedTwo.properties.origin, matchedTwo.properties.destination] : [];
|
|
1974
|
+
const unitIds = (0, import_intersectionBy.default)(matchOneUnits, matchTwoUnits, "id");
|
|
1975
|
+
return unitIds.map(({ id }) => findByIdSync(id));
|
|
1976
|
+
};
|
|
1977
|
+
const findHorizontalIntermediary = (from, to) => {
|
|
1978
|
+
if (from.source.type !== "opening") {
|
|
1979
|
+
const unit = findContainingUnitAtPoint(from.point, from.levelId, units);
|
|
1980
|
+
return unit ? [unit] : [];
|
|
1981
|
+
}
|
|
1982
|
+
if (to.source.type !== "opening") {
|
|
1983
|
+
const unit = findContainingUnitAtPoint(to.point, to.levelId, units);
|
|
1984
|
+
return unit ? [unit] : [];
|
|
1985
|
+
}
|
|
1986
|
+
return findUnitBetweenOpenings(from.source.id, to.source.id);
|
|
1987
|
+
};
|
|
1988
|
+
const findVerticalIntermediary = (from, to) => {
|
|
1989
|
+
const firstOpeningId = from.source.id;
|
|
1990
|
+
const secondOpeningId = to.source.id;
|
|
1991
|
+
const relationship = relationships.find((rel) => {
|
|
1992
|
+
return rel.properties.origin?.id === firstOpeningId && rel.properties.destination?.id === secondOpeningId || rel.properties.origin?.id === secondOpeningId && rel.properties.destination?.id === firstOpeningId;
|
|
1993
|
+
});
|
|
1994
|
+
const intermediaryTypeAndId = relationship.properties.intermediary;
|
|
1995
|
+
return intermediaryTypeAndId.map(({ id }) => findByIdSync(id));
|
|
1996
|
+
};
|
|
1997
|
+
const formatCategoryLabel = (category) => {
|
|
1998
|
+
return (0, import_lodash12.capitalize)(category);
|
|
1999
|
+
};
|
|
2000
|
+
const getNextStepIntermediary = (from, to, intermediary) => {
|
|
2001
|
+
if (to.type === "end") return to.name;
|
|
2002
|
+
const intermediaryIds = intermediary.map((int) => int.id);
|
|
2003
|
+
const relationship = relationships.find((rel) => rel.properties.intermediary.map((int) => int.id).includes(to.source.id));
|
|
2004
|
+
if (!relationship) return to.name;
|
|
2005
|
+
const candidates = [relationship.properties.origin.id, relationship.properties.destination.id];
|
|
2006
|
+
const nextUnitId = candidates.filter((id) => !intermediaryIds.includes(id))[0];
|
|
2007
|
+
if (!nextUnitId) return to.name;
|
|
2008
|
+
const nextUnit = findByIdSync(nextUnitId);
|
|
2009
|
+
return { en: formatCategoryLabel(`${nextUnit.properties.category}`) };
|
|
2010
|
+
};
|
|
2011
|
+
const createHorizontalStep = (from, to) => {
|
|
2012
|
+
const intermediary = findHorizontalIntermediary(from, to);
|
|
2013
|
+
const intermediaryCategories = intermediary.map((unit) => unit.properties.category);
|
|
2014
|
+
const intermediaryCategory = intermediaryCategories.length > 0 ? intermediaryCategories[0] : "unspecified";
|
|
2015
|
+
const toward = getNextStepIntermediary(from, to, intermediary);
|
|
2016
|
+
const landmark = to.hint?.kind === "landmark" ? to.hint.name : null;
|
|
2017
|
+
const path = stepPathUtils.findStepPath(from.point, to.point, intermediary);
|
|
2018
|
+
const step = {
|
|
2019
|
+
from,
|
|
2020
|
+
to,
|
|
2021
|
+
levelIds: [from.levelId],
|
|
2022
|
+
ordinals: [from.ordinal],
|
|
2023
|
+
intermediaryCategory,
|
|
2024
|
+
description: describeHorizontalStep(intermediaryCategory, toward, landmark),
|
|
2025
|
+
path: path.map((coord) => [...coord, from.ordinal * 9])
|
|
2026
|
+
};
|
|
2027
|
+
return step;
|
|
2028
|
+
};
|
|
2029
|
+
const createVerticalStep = (from, to) => {
|
|
2030
|
+
const intermediary = findVerticalIntermediary(from, to);
|
|
2031
|
+
const intermediaryCategories = intermediary.map((unit) => unit.properties.category);
|
|
2032
|
+
const intermediaryCategory = intermediaryCategories.length > 0 ? intermediaryCategories[0] : "unspecified";
|
|
2033
|
+
const fromLevel = findByIdSync(from.levelId);
|
|
2034
|
+
const toLevel = findByIdSync(to.levelId);
|
|
2035
|
+
return {
|
|
2036
|
+
from,
|
|
2037
|
+
to,
|
|
2038
|
+
levelIds: [from.levelId, to.levelId],
|
|
2039
|
+
ordinals: [from.ordinal, to.ordinal],
|
|
2040
|
+
intermediaryCategory,
|
|
2041
|
+
description: describeVerticalStep(fromLevel, toLevel, intermediaryCategory),
|
|
2042
|
+
path: [
|
|
2043
|
+
[...from.point, from.ordinal * 9],
|
|
2044
|
+
[...to.point, to.ordinal * 9]
|
|
2045
|
+
]
|
|
2046
|
+
};
|
|
2047
|
+
};
|
|
2048
|
+
const isVertical = (from, to) => {
|
|
2049
|
+
const fromLevel = findByIdSync(from.levelId);
|
|
2050
|
+
const toLevel = findByIdSync(to.levelId);
|
|
2051
|
+
return !!fromLevel && !!toLevel && fromLevel.properties.ordinal !== toLevel.properties.ordinal;
|
|
2052
|
+
};
|
|
2053
|
+
const toSteps = (waypoints) => {
|
|
2054
|
+
let steps = [];
|
|
2055
|
+
const t0_allSteps = performance.now();
|
|
2056
|
+
for (let i = 0; i < waypoints.length - 1; i++) {
|
|
2057
|
+
const from = waypoints[i];
|
|
2058
|
+
const to = waypoints[i + 1];
|
|
2059
|
+
const t0 = performance.now();
|
|
2060
|
+
const step = isVertical(from, to) ? createVerticalStep(from, to) : createHorizontalStep(from, to);
|
|
2061
|
+
steps.push(step);
|
|
2062
|
+
const t1 = performance.now();
|
|
2063
|
+
trace("nav", ` \u2502 \u251C\u2500 #${i} ${from.id.padEnd(25)} \u2192 ${`(${step.intermediaryCategory})`.padEnd(12)} \u2192 ${to.id}`, t1 - t0);
|
|
2064
|
+
trace("nav", ` \u2502 \u2502 ${step.description.text}`, void 0, "#bada55");
|
|
2065
|
+
}
|
|
2066
|
+
const simplifySteps = combineWalkwaySteps(steps);
|
|
2067
|
+
const t1_allSteps = performance.now();
|
|
2068
|
+
trace("nav", " \u2502 \u2514\u2500 Total ", t1_allSteps - t0_allSteps);
|
|
2069
|
+
return simplifySteps;
|
|
2070
|
+
};
|
|
2071
|
+
return {
|
|
2072
|
+
toSteps
|
|
2073
|
+
};
|
|
2074
|
+
};
|
|
2075
|
+
|
|
2076
|
+
// src/data/navigate/utils/timeDistance.ts
|
|
2077
|
+
var import_length = __toESM(require("@turf/length"));
|
|
2078
|
+
var WALKING_SPEED = 1.4;
|
|
2079
|
+
var calculatePathLength = (feature2) => (0, import_length.default)(feature2, { units: "kilometers" }) * 1e3;
|
|
2080
|
+
var calculateTravelingDuration = (distance5) => {
|
|
2081
|
+
const duration = distance5 / WALKING_SPEED;
|
|
2082
|
+
const minutes = Math.round(duration / 60);
|
|
2083
|
+
return minutes > 0 ? minutes : 1;
|
|
2084
|
+
};
|
|
2085
|
+
var calculateTotalDistance = (steps = []) => {
|
|
2086
|
+
return steps.reduce((acc, { path }) => acc + calculatePathLength(lineString(path)), 0);
|
|
2087
|
+
};
|
|
2088
|
+
var calculateRoundedDistance = (distance5) => {
|
|
2089
|
+
return Math.round(distance5 - distance5 % 25);
|
|
2090
|
+
};
|
|
2091
|
+
|
|
2092
|
+
// src/data/navigate/type-guard.ts
|
|
2093
|
+
function isCoordinateOrdinalString(id) {
|
|
2094
|
+
return /^-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?o$/.test(id);
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
// src/data/navigate/utils/createFindByIdSync.ts
|
|
2098
|
+
var createFindByIdSync = (data) => {
|
|
2099
|
+
const { amenities = [], anchors = [], fixtures = [], levels = [], kiosks = [], relationships = [], occupants = [], openings = [], units } = data;
|
|
2100
|
+
const featureById = /* @__PURE__ */ new Map();
|
|
2101
|
+
const entries = [
|
|
2102
|
+
...amenities,
|
|
2103
|
+
...anchors,
|
|
2104
|
+
...fixtures,
|
|
2105
|
+
...levels,
|
|
2106
|
+
...kiosks,
|
|
2107
|
+
...relationships,
|
|
2108
|
+
...occupants,
|
|
2109
|
+
...openings,
|
|
2110
|
+
...units
|
|
2111
|
+
];
|
|
2112
|
+
for (const f of entries) featureById.set(f.id, f);
|
|
2113
|
+
const findByIdSync = (id) => {
|
|
2114
|
+
return featureById.get(id);
|
|
2115
|
+
};
|
|
2116
|
+
return { findByIdSync };
|
|
2117
|
+
};
|
|
2118
|
+
|
|
2119
|
+
// src/data/navigate/waypoint/createWaypointUtils.ts
|
|
2120
|
+
var import_center9 = require("@turf/center");
|
|
2121
|
+
|
|
2122
|
+
// src/data/navigate/waypoint/extractEndWaypoint.ts
|
|
2123
|
+
var import_center6 = require("@turf/center");
|
|
2124
|
+
|
|
2125
|
+
// src/data/navigate/waypoint/featureIdGuard.ts
|
|
2126
|
+
var isOccupant = (id) => !!id && id.startsWith("occupant-");
|
|
2127
|
+
var isUnit = (id) => !!id && id.startsWith("unit-");
|
|
2128
|
+
var isKiosk = (id) => !!id && id.startsWith("kiosk-");
|
|
2129
|
+
var isOpening = (id) => !!id && id.startsWith("opening-");
|
|
2130
|
+
|
|
2131
|
+
// src/data/navigate/waypoint/extractEndWaypoint.ts
|
|
2132
|
+
var extractEndPoint = (path, options) => {
|
|
2133
|
+
const { findByIdSync } = options;
|
|
2134
|
+
const [c, b, a] = path.slice(-3);
|
|
2135
|
+
if (isOccupant(a) && isUnit(b) && isOpening(c)) {
|
|
2136
|
+
const occ = findByIdSync(a);
|
|
2137
|
+
const opening = findByIdSync(c);
|
|
2138
|
+
const level = findByIdSync(opening.properties.level_id);
|
|
2139
|
+
return [
|
|
2140
|
+
{
|
|
2141
|
+
id: occ.id,
|
|
2142
|
+
type: "end",
|
|
2143
|
+
name: occ.properties.name,
|
|
2144
|
+
point: (0, import_center6.center)(opening).geometry.coordinates,
|
|
2145
|
+
levelId: opening.properties.level_id,
|
|
2146
|
+
ordinal: level.properties.ordinal,
|
|
2147
|
+
source: { type: "opening", id: opening.id }
|
|
2148
|
+
},
|
|
2149
|
+
path.slice(0, -3)
|
|
2150
|
+
];
|
|
2151
|
+
}
|
|
2152
|
+
if (isOccupant(a) && isKiosk(b)) {
|
|
2153
|
+
const occ = findByIdSync(a);
|
|
2154
|
+
const kiosk = findByIdSync(b);
|
|
2155
|
+
const level = findByIdSync(kiosk.properties.level_id);
|
|
2156
|
+
return [
|
|
2157
|
+
{
|
|
2158
|
+
id: occ.id,
|
|
2159
|
+
type: "end",
|
|
2160
|
+
name: occ.properties.name,
|
|
2161
|
+
point: (0, import_center6.center)(kiosk).geometry.coordinates,
|
|
2162
|
+
levelId: kiosk.properties.level_id,
|
|
2163
|
+
ordinal: level.properties.ordinal,
|
|
2164
|
+
source: { type: "kiosk", id: kiosk.id }
|
|
2165
|
+
},
|
|
2166
|
+
path.slice(0, -2)
|
|
2167
|
+
];
|
|
2168
|
+
}
|
|
2169
|
+
if (isCoordinateOrdinalString(a) && isOpening(b)) {
|
|
2170
|
+
const [lat, lng, ordinal] = parseOrdinalCoordinate(a);
|
|
2171
|
+
const opening = findByIdSync(b);
|
|
2172
|
+
return [
|
|
2173
|
+
{
|
|
2174
|
+
id: a,
|
|
2175
|
+
type: "end",
|
|
2176
|
+
name: { en: a },
|
|
2177
|
+
point: [lng, lat],
|
|
2178
|
+
levelId: opening.properties.level_id,
|
|
2179
|
+
ordinal,
|
|
2180
|
+
source: { type: "coordinate", raw: a }
|
|
2181
|
+
},
|
|
2182
|
+
path.slice(0, -1)
|
|
2183
|
+
];
|
|
2184
|
+
}
|
|
2185
|
+
return [null, path];
|
|
2186
|
+
};
|
|
2187
|
+
|
|
2188
|
+
// src/data/navigate/waypoint/extractStartWaypoint.ts
|
|
2189
|
+
var import_center7 = require("@turf/center");
|
|
2190
|
+
var extractStartPoint = (path, options) => {
|
|
2191
|
+
const { findByIdSync } = options;
|
|
2192
|
+
const [a, b, c] = path;
|
|
2193
|
+
if (isOccupant(a) && isUnit(b) && isOpening(c)) {
|
|
2194
|
+
const occ = findByIdSync(a);
|
|
2195
|
+
const opening = findByIdSync(c);
|
|
2196
|
+
const level = findByIdSync(opening.properties.level_id);
|
|
2197
|
+
return [
|
|
2198
|
+
{
|
|
2199
|
+
id: occ.id,
|
|
2200
|
+
type: "start",
|
|
2201
|
+
name: occ.properties.name,
|
|
2202
|
+
point: (0, import_center7.center)(opening).geometry.coordinates,
|
|
2203
|
+
levelId: opening.properties.level_id,
|
|
2204
|
+
ordinal: level.properties.ordinal,
|
|
2205
|
+
source: { type: "opening", id: opening.id }
|
|
2206
|
+
},
|
|
2207
|
+
path.slice(3)
|
|
2208
|
+
];
|
|
2209
|
+
}
|
|
2210
|
+
if (isOccupant(a) && isKiosk(b)) {
|
|
2211
|
+
const occ = findByIdSync(a);
|
|
2212
|
+
const kiosk = findByIdSync(b);
|
|
2213
|
+
const level = findByIdSync(kiosk.properties.level_id);
|
|
2214
|
+
return [
|
|
2215
|
+
{
|
|
2216
|
+
id: occ.id,
|
|
2217
|
+
type: "start",
|
|
2218
|
+
name: occ.properties.name,
|
|
2219
|
+
point: (0, import_center7.center)(kiosk).geometry.coordinates,
|
|
2220
|
+
levelId: kiosk.properties.level_id,
|
|
2221
|
+
ordinal: level.properties.ordinal,
|
|
2222
|
+
source: { type: "kiosk", id: kiosk.id }
|
|
2223
|
+
},
|
|
2224
|
+
path.slice(2)
|
|
2225
|
+
];
|
|
2226
|
+
}
|
|
2227
|
+
if (isCoordinateOrdinalString(a) && isOpening(b)) {
|
|
2228
|
+
const [lat, lng, ordinal] = parseOrdinalCoordinate(a);
|
|
2229
|
+
const opening = findByIdSync(b);
|
|
2230
|
+
return [
|
|
2231
|
+
{
|
|
2232
|
+
id: a,
|
|
2233
|
+
type: "start",
|
|
2234
|
+
name: { en: a },
|
|
2235
|
+
point: [lng, lat],
|
|
2236
|
+
levelId: opening.properties.level_id,
|
|
2237
|
+
ordinal,
|
|
2238
|
+
source: { type: "coordinate", raw: a }
|
|
2239
|
+
},
|
|
2240
|
+
path.slice(1)
|
|
2241
|
+
];
|
|
2242
|
+
}
|
|
2243
|
+
return [null, path];
|
|
2244
|
+
};
|
|
2245
|
+
|
|
2246
|
+
// src/data/navigate/landmark/createLandmarkUtils.ts
|
|
2247
|
+
var import_center8 = require("@turf/center");
|
|
2248
|
+
var import_distance5 = __toESM(require("@turf/distance"));
|
|
2249
|
+
var NEARBY_DISTANCE = 30;
|
|
2250
|
+
var createLandmarkUtils = (options) => {
|
|
2251
|
+
const { data, findByIdSync } = options;
|
|
2252
|
+
const { occupants = [] } = data;
|
|
2253
|
+
const occupantToLandmark = (occupant) => {
|
|
2254
|
+
const locationType = occupant.properties.unit_id ? "unit" : "kiosk";
|
|
2255
|
+
const locationId = locationType === "unit" ? occupant.properties.unit_id : occupant.properties.kiosk_id;
|
|
2256
|
+
const location = locationType === "unit" ? findByIdSync(locationId) : findByIdSync(locationId);
|
|
2257
|
+
const level = findByIdSync(location.properties.level_id);
|
|
2258
|
+
return {
|
|
2259
|
+
name: occupant.properties.name,
|
|
2260
|
+
point: (0, import_center8.center)(location.geometry).geometry.coordinates,
|
|
2261
|
+
level_id: location.properties.level_id,
|
|
2262
|
+
is_priority: occupant.properties.is_landmark,
|
|
2263
|
+
ordinal: level.properties.ordinal
|
|
2264
|
+
};
|
|
2265
|
+
};
|
|
2266
|
+
const landmarks = [
|
|
2267
|
+
...occupants.map(occupantToLandmark)
|
|
2268
|
+
];
|
|
2269
|
+
const findNearbyLandmarks = (point2, levelId) => {
|
|
2270
|
+
if (point2 === null || levelId === null) return [];
|
|
2271
|
+
return landmarks.map((landmark) => {
|
|
2272
|
+
const landmarkAndDistance = {
|
|
2273
|
+
landmark,
|
|
2274
|
+
d: (0, import_distance5.default)(point2, landmark.point, { units: "meters" })
|
|
2275
|
+
};
|
|
2276
|
+
return landmarkAndDistance;
|
|
2277
|
+
}).filter(({ landmark, d }) => d <= NEARBY_DISTANCE && landmark.level_id === levelId).sort((a, b) => {
|
|
2278
|
+
const aPriority = a.landmark.is_priority ? 0 : 1;
|
|
2279
|
+
const bPriority = b.landmark.is_priority ? 0 : 1;
|
|
2280
|
+
if (aPriority !== bPriority) return aPriority - bPriority;
|
|
2281
|
+
return a.d - b.d;
|
|
2282
|
+
}).map(({ landmark }) => landmark);
|
|
2283
|
+
};
|
|
2284
|
+
const findNearestLandmark = (point2, levelId) => {
|
|
2285
|
+
const nearbyLandmarks = findNearbyLandmarks(point2, levelId);
|
|
2286
|
+
const nearestLandmark = nearbyLandmarks.length > 0 ? nearbyLandmarks[0] : null;
|
|
2287
|
+
return nearestLandmark;
|
|
2288
|
+
};
|
|
2289
|
+
return { findNearbyLandmarks, findNearestLandmark };
|
|
2290
|
+
};
|
|
2291
|
+
|
|
2292
|
+
// src/data/navigate/waypoint/createWaypointUtils.ts
|
|
2293
|
+
var createWaypointUtils = (options) => {
|
|
2294
|
+
const { findByIdSync } = options;
|
|
2295
|
+
const landmarkUtils = createLandmarkUtils(options);
|
|
2296
|
+
const toWaypoints = (path) => {
|
|
2297
|
+
const [startPoint, middleAndEndPoints] = extractStartPoint(path, options);
|
|
2298
|
+
const [endPoint, middlePoints] = extractEndPoint(middleAndEndPoints, options);
|
|
2299
|
+
const waypoints = middlePoints.map((openingId) => {
|
|
2300
|
+
const opening = findByIdSync(openingId);
|
|
2301
|
+
const level = findByIdSync(opening.properties.level_id);
|
|
2302
|
+
const coordinates = (0, import_center9.center)(opening).geometry.coordinates;
|
|
2303
|
+
const landmark = landmarkUtils.findNearestLandmark(coordinates, opening.properties.level_id);
|
|
2304
|
+
return {
|
|
2305
|
+
id: `${opening.properties.level_id}:${openingId}`,
|
|
2306
|
+
type: "between",
|
|
2307
|
+
point: coordinates,
|
|
2308
|
+
name: null,
|
|
2309
|
+
levelId: opening.properties.level_id,
|
|
2310
|
+
ordinal: level.properties.ordinal,
|
|
2311
|
+
hint: landmark ? { kind: "landmark", name: landmark.name } : void 0,
|
|
2312
|
+
source: { type: "opening", id: opening.id }
|
|
2313
|
+
};
|
|
2314
|
+
});
|
|
2315
|
+
return [startPoint, ...waypoints, endPoint];
|
|
2316
|
+
};
|
|
2317
|
+
return { toWaypoints };
|
|
2318
|
+
};
|
|
2319
|
+
|
|
2320
|
+
// src/data/navigate/getNavigateClient.ts
|
|
2321
|
+
var getNavigateClient = (options) => {
|
|
2322
|
+
const { data } = options;
|
|
2323
|
+
const { levels, units } = data;
|
|
2324
|
+
trace("nav", "\u2713 prepare");
|
|
2325
|
+
const t0 = performance.now();
|
|
2326
|
+
trace("nav", " \u251C\u2500 createGraph (dijkstra)");
|
|
2327
|
+
const { defaultGraph, accessibleGraph, addCoordinateOrdinalNode } = prepareGraph({ data });
|
|
2328
|
+
const t1 = performance.now();
|
|
2329
|
+
trace("nav", " \u2502 \u2514\u2500 Total ", t1 - t0);
|
|
2330
|
+
const t2 = performance.now();
|
|
2331
|
+
const { findByIdSync } = createFindByIdSync(data);
|
|
2332
|
+
const t3 = performance.now();
|
|
2333
|
+
trace("nav", " \u2514\u2500 findByIdSync", t3 - t2);
|
|
2334
|
+
const findCoordinateOrdinalUnit = (params) => {
|
|
2335
|
+
const [lat, lng, ordinal] = parseOrdinalCoordinate(params);
|
|
2336
|
+
const levelIdsWithOrdinal = levels.filter((level) => level.properties.ordinal === ordinal).map((level) => level.id);
|
|
2337
|
+
const unit = units.find((unit2) => levelIdsWithOrdinal.includes(unit2.properties.level_id) && (0, import_boolean_point_in_polygon4.booleanPointInPolygon)([lat, lng], unit2));
|
|
2338
|
+
return unit;
|
|
2339
|
+
};
|
|
2340
|
+
const stepUtils = createStepUtils({ ...options, findByIdSync });
|
|
2341
|
+
const waypointUtils = createWaypointUtils({ ...options, findByIdSync });
|
|
2342
|
+
const findRoute = async (routeOriginParam, routeDestinationParam, options2) => {
|
|
2343
|
+
if (!routeOriginParam || !routeDestinationParam) return null;
|
|
2344
|
+
const graph = options2?.mode === "accessible" ? accessibleGraph : defaultGraph;
|
|
2345
|
+
if (isCoordinateOrdinalString(routeOriginParam)) {
|
|
2346
|
+
const walkwayUnit = findCoordinateOrdinalUnit(routeOriginParam);
|
|
2347
|
+
addCoordinateOrdinalNode(routeOriginParam, walkwayUnit);
|
|
2348
|
+
}
|
|
2349
|
+
if (isCoordinateOrdinalString(routeDestinationParam)) {
|
|
2350
|
+
const walkwayUnit = findCoordinateOrdinalUnit(routeDestinationParam);
|
|
2351
|
+
addCoordinateOrdinalNode(routeDestinationParam, walkwayUnit);
|
|
2352
|
+
}
|
|
2353
|
+
try {
|
|
2354
|
+
trace("nav", "\u2713 findRoute", 0);
|
|
2355
|
+
const t02 = performance.now();
|
|
2356
|
+
const path = graph.path(routeOriginParam, routeDestinationParam);
|
|
2357
|
+
const t12 = performance.now();
|
|
2358
|
+
trace("nav", " \u251C\u2500 path (dijkstra)", t12 - t02);
|
|
2359
|
+
const waypoints = waypointUtils.toWaypoints(path);
|
|
2360
|
+
const t22 = performance.now();
|
|
2361
|
+
trace("nav", " \u251C\u2500 toWaypoints", t22 - t12);
|
|
2362
|
+
trace("nav", " \u251C\u2500 toSteps", 0);
|
|
2363
|
+
const steps = stepUtils.toSteps(waypoints);
|
|
2364
|
+
const t32 = performance.now();
|
|
2365
|
+
const totalDistance = calculateTotalDistance(steps);
|
|
2366
|
+
const roundedDistance = calculateRoundedDistance(totalDistance);
|
|
2367
|
+
const duration = calculateTravelingDuration(totalDistance);
|
|
2368
|
+
const t4 = performance.now();
|
|
2369
|
+
trace("nav", " \u2514\u2500 postProcess", t4 - t32);
|
|
2370
|
+
return {
|
|
2371
|
+
distance: roundedDistance,
|
|
2372
|
+
duration,
|
|
2373
|
+
steps
|
|
2374
|
+
};
|
|
2375
|
+
} catch (error) {
|
|
2376
|
+
console.log(error);
|
|
2377
|
+
throw error;
|
|
2378
|
+
}
|
|
2379
|
+
};
|
|
2380
|
+
return {
|
|
2381
|
+
findRoute,
|
|
2382
|
+
findByIdSync
|
|
2383
|
+
};
|
|
2384
|
+
};
|
|
2385
|
+
|
|
2386
|
+
// src/data/getDataClient.ts
|
|
2387
|
+
var getDataClient = (options) => {
|
|
2388
|
+
let searchClient;
|
|
2389
|
+
let navigateClient;
|
|
2390
|
+
const observers = /* @__PURE__ */ new Map();
|
|
2391
|
+
const queryClient = options.queryClient ?? new import_query_core.QueryClient();
|
|
2392
|
+
const { mode = "delivery", projectId, apiKey, baseUrl, previewToken } = options;
|
|
2393
|
+
if (!projectId)
|
|
2394
|
+
throw new Error(
|
|
2395
|
+
"Cannot create VenueDataClient. Reason: `projectId` is missing"
|
|
2396
|
+
);
|
|
2397
|
+
if (mode === "delivery" && !apiKey)
|
|
2398
|
+
throw new Error(
|
|
2399
|
+
"Cannot create VenueDataClient. Reason: `apiKey` is missing"
|
|
2400
|
+
);
|
|
2401
|
+
if (mode === "preview" && !previewToken)
|
|
2402
|
+
throw new Error(
|
|
2403
|
+
"Cannot create VenueDataClient. Reason: `previewToken` is missing"
|
|
2404
|
+
);
|
|
2405
|
+
const createDeliveryApiQueryOptions = (featureType) => ({
|
|
2406
|
+
queryKey: ["_deliveryapi", featureType],
|
|
2407
|
+
queryFn: () => safeFetchFeature(featureType, { mode, projectId, apiKey, previewToken, baseUrl })
|
|
2408
|
+
});
|
|
2409
|
+
const internalFilterByType = async (featureType) => {
|
|
2410
|
+
try {
|
|
2411
|
+
const features = await queryClient.ensureQueryData(createDeliveryApiQueryOptions(featureType));
|
|
2412
|
+
return features;
|
|
2413
|
+
} catch (error) {
|
|
2414
|
+
throw error;
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2417
|
+
const internalFindById = async (id) => {
|
|
2418
|
+
if (id === null || id === void 0) return null;
|
|
2419
|
+
const featureType = id.slice(0, id.lastIndexOf("-"));
|
|
2420
|
+
const feature2 = await queryClient.ensureQueryData({
|
|
2421
|
+
queryKey: ["_deliveryapi", featureType, id],
|
|
2422
|
+
queryFn: async () => {
|
|
2423
|
+
const features = await internalFilterByType(featureType);
|
|
2424
|
+
const feature3 = features.find(
|
|
2425
|
+
(f) => f.id === id
|
|
2426
|
+
);
|
|
2427
|
+
return feature3 ?? null;
|
|
2428
|
+
}
|
|
2429
|
+
});
|
|
2430
|
+
return feature2;
|
|
2431
|
+
};
|
|
2432
|
+
const populator = createPopulator({ internalFindById, internalFilterByType });
|
|
2433
|
+
const registerObserver = (featureType, refetchInterval) => {
|
|
2434
|
+
if (observers.has(featureType)) {
|
|
2435
|
+
console.warn(`Observer for ${featureType} already exists`);
|
|
2436
|
+
const record = observers.get(featureType);
|
|
2437
|
+
return record.observer;
|
|
2438
|
+
}
|
|
2439
|
+
const options2 = createDeliveryApiQueryOptions(featureType);
|
|
2440
|
+
const observer = new import_query_core.QueryObserver(queryClient, {
|
|
2441
|
+
...options2,
|
|
2442
|
+
refetchInterval
|
|
2443
|
+
});
|
|
2444
|
+
const unsubscribe = observer.subscribe(() => {
|
|
2445
|
+
console.log(`[venue-js] Listening to ${featureType} changes (interval = ${refetchInterval}ms)`);
|
|
2446
|
+
});
|
|
2447
|
+
observers.set(featureType, { observer, unsubscribe });
|
|
2448
|
+
return observer;
|
|
2449
|
+
};
|
|
2450
|
+
const destroyObserver = (featureType) => {
|
|
2451
|
+
const record = observers.get(featureType);
|
|
2452
|
+
if (!record) return;
|
|
2453
|
+
record.unsubscribe();
|
|
2454
|
+
observers.delete(featureType);
|
|
2455
|
+
};
|
|
2456
|
+
const destroyObservers = () => {
|
|
2457
|
+
observers.forEach(({ observer, unsubscribe }) => {
|
|
2458
|
+
unsubscribe();
|
|
2459
|
+
observer.destroy();
|
|
2460
|
+
});
|
|
2461
|
+
observers.clear();
|
|
2462
|
+
};
|
|
2463
|
+
const createFilterByTypeQueryOptions = (featureType, params = {}, options2 = {}) => ({
|
|
2464
|
+
queryKey: [featureType, "list", params],
|
|
2465
|
+
queryFn: async () => {
|
|
2466
|
+
const features = await internalFilterByType(featureType);
|
|
2467
|
+
const filters = params.filters ?? {};
|
|
2468
|
+
let result = features;
|
|
2469
|
+
if (params.filters) {
|
|
2470
|
+
result = features.filter((f) => matchFilters(f, filters));
|
|
2471
|
+
}
|
|
2472
|
+
return params.populate === true ? await Promise.all(result.map((f) => populator[featureType](f))) : result;
|
|
2473
|
+
},
|
|
2474
|
+
...options2 ?? {}
|
|
2475
|
+
});
|
|
2476
|
+
const createFindByIdQueryOptions = (featureType, id, params = {}, options2 = {}) => ({
|
|
2477
|
+
queryKey: [featureType, "detail", id, params],
|
|
2478
|
+
queryFn: async () => {
|
|
2479
|
+
const feature2 = await internalFindById(id);
|
|
2480
|
+
return params.populate === true ? await populator[featureType](feature2) : Promise.resolve(feature2);
|
|
2481
|
+
},
|
|
2482
|
+
...options2 ?? {}
|
|
2483
|
+
});
|
|
2484
|
+
async function filterByType(featureType, params) {
|
|
2485
|
+
const filterQueryOptions = createFilterByTypeQueryOptions(
|
|
2486
|
+
featureType,
|
|
2487
|
+
params
|
|
2488
|
+
);
|
|
2489
|
+
const features = await queryClient.ensureQueryData(filterQueryOptions);
|
|
2490
|
+
return params?.populate === true ? features : features;
|
|
2491
|
+
}
|
|
2492
|
+
async function findById(featureType, id, params) {
|
|
2493
|
+
const findQueryOptions = createFindByIdQueryOptions(
|
|
2494
|
+
featureType,
|
|
2495
|
+
id,
|
|
2496
|
+
params
|
|
2497
|
+
);
|
|
2498
|
+
const feature2 = await queryClient.ensureQueryData(findQueryOptions);
|
|
2499
|
+
return feature2;
|
|
2500
|
+
}
|
|
2501
|
+
const searchFn = async (txt) => {
|
|
2502
|
+
if (!searchClient) {
|
|
2503
|
+
const [occupants, amenities] = await Promise.all([
|
|
2504
|
+
filterByType("occupant"),
|
|
2505
|
+
filterByType("amenity")
|
|
2506
|
+
]);
|
|
2507
|
+
const haystack = { occupants, amenities };
|
|
2508
|
+
searchClient = getSearchClient(haystack);
|
|
2509
|
+
}
|
|
2510
|
+
return searchClient.search(txt);
|
|
2511
|
+
};
|
|
2512
|
+
const navigateFn = async (origin, destination) => {
|
|
2513
|
+
if (!navigateClient) {
|
|
2514
|
+
const [levels, occupants, openings, relationships, units, fixtures, kiosks, amenities, anchors] = await Promise.all([
|
|
2515
|
+
filterByType("level"),
|
|
2516
|
+
filterByType("occupant"),
|
|
2517
|
+
filterByType("opening"),
|
|
2518
|
+
filterByType("relationship"),
|
|
2519
|
+
filterByType("unit"),
|
|
2520
|
+
filterByType("fixture"),
|
|
2521
|
+
filterByType("kiosk"),
|
|
2522
|
+
filterByType("amenity"),
|
|
2523
|
+
filterByType("anchor")
|
|
2524
|
+
]);
|
|
2525
|
+
const haystack = { levels, occupants, openings, relationships, units, fixtures, kiosks, amenities, anchors };
|
|
2526
|
+
navigateClient = getNavigateClient({ data: haystack });
|
|
2527
|
+
}
|
|
2528
|
+
return navigateClient.findRoute(origin, destination);
|
|
2529
|
+
};
|
|
2530
|
+
return {
|
|
2531
|
+
projectId,
|
|
2532
|
+
queryClient,
|
|
2533
|
+
registerObserver,
|
|
2534
|
+
destroyObserver,
|
|
2535
|
+
destroyObservers,
|
|
2536
|
+
createFilterByTypeQueryOptions,
|
|
2537
|
+
createFindByIdQueryOptions,
|
|
2538
|
+
_internalFindById: internalFindById,
|
|
2539
|
+
filterByType,
|
|
2540
|
+
findById,
|
|
2541
|
+
search: searchFn,
|
|
2542
|
+
navigate: navigateFn
|
|
2543
|
+
};
|
|
2544
|
+
};
|
|
2545
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2546
|
+
0 && (module.exports = {
|
|
2547
|
+
ALL_FEATURE_TYPES,
|
|
2548
|
+
DEFAULT_BASE_URL,
|
|
2549
|
+
GEOJSON_FEATURE_TYPES,
|
|
2550
|
+
IMDF_FEATURE_TYPES,
|
|
2551
|
+
IMDF_UNIT_CATEGORIES,
|
|
2552
|
+
NONIMDF_FEATURE_TYPES,
|
|
2553
|
+
OccupantHelpers,
|
|
2554
|
+
QueryObserver,
|
|
2555
|
+
defaultFeatureQueryOptionsMap,
|
|
2556
|
+
fetchDeliveryApi,
|
|
2557
|
+
fetchPreviewApi,
|
|
2558
|
+
getDataClient,
|
|
2559
|
+
getNavigateClient,
|
|
2560
|
+
getSearchClient,
|
|
2561
|
+
isValidCoordinate,
|
|
2562
|
+
isValidLineString,
|
|
2563
|
+
isValidLineStringCoordinates,
|
|
2564
|
+
isValidMultiPolygon,
|
|
2565
|
+
isValidMultiPolygonCoordinates,
|
|
2566
|
+
isValidPoint,
|
|
2567
|
+
isValidPolygon,
|
|
2568
|
+
isValidPolygonCoordinates,
|
|
2569
|
+
matchFilter,
|
|
2570
|
+
matchFilters,
|
|
2571
|
+
safeFetchFeature
|
|
2572
|
+
});
|
|
2573
|
+
//# sourceMappingURL=index.js.map
|