venue-js 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,6 +32,7 @@ __export(data_exports, {
32
32
  ALL_FEATURE_TYPES: () => ALL_FEATURE_TYPES,
33
33
  DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
34
34
  GEOJSON_FEATURE_TYPES: () => GEOJSON_FEATURE_TYPES,
35
+ ID_PREFIX_TO_FEATURE_TYPE: () => ID_PREFIX_TO_FEATURE_TYPE,
35
36
  IMDF_FEATURE_TYPES: () => IMDF_FEATURE_TYPES,
36
37
  IMDF_UNIT_CATEGORIES: () => IMDF_UNIT_CATEGORIES,
37
38
  NONIMDF_FEATURE_TYPES: () => NONIMDF_FEATURE_TYPES,
@@ -58,6 +59,7 @@ __export(data_exports, {
58
59
  getDataClient: () => getDataClient,
59
60
  getInstructionText: () => getInstructionText,
60
61
  getNavigateClient: () => getNavigateClient,
62
+ getPointOnFeature: () => getPointOnFeature,
61
63
  getSearchClient: () => getSearchClient,
62
64
  getTurn: () => getTurn,
63
65
  matchFilter: () => matchFilter,
@@ -178,6 +180,9 @@ var ALL_FEATURE_TYPES = [
178
180
  "sponsored-content",
179
181
  "element"
180
182
  ];
183
+ var ID_PREFIX_TO_FEATURE_TYPE = {
184
+ sponsored: "sponsored-content"
185
+ };
181
186
  var defaultFeatureQueryOptionsMap = {
182
187
  // IMDF
183
188
  address: {},
@@ -241,20 +246,143 @@ function matchFilters(item, filters) {
241
246
  }
242
247
 
243
248
  // src/data/utils/findContaining.ts
244
- var import_point_on_feature = __toESM(require("@turf/point-on-feature"));
245
249
  var import_boolean_point_in_polygon = require("@turf/boolean-point-in-polygon");
246
- var findContainingUnit = (poi, units) => {
247
- const unit = units.find(
248
- (unit2) => {
249
- try {
250
- return unit2.properties.level_id === poi.properties.level_id && (0, import_boolean_point_in_polygon.booleanPointInPolygon)((0, import_point_on_feature.default)(poi), unit2);
251
- } catch (e) {
252
- console.log(`Cannot find containing unit of (${poi.id}):`, e.message);
253
- return false;
250
+ var import_intersect = require("@turf/intersect");
251
+
252
+ // node_modules/@turf/helpers/dist/esm/index.js
253
+ var earthRadius = 63710088e-1;
254
+ var factors = {
255
+ centimeters: earthRadius * 100,
256
+ centimetres: earthRadius * 100,
257
+ degrees: 360 / (2 * Math.PI),
258
+ feet: earthRadius * 3.28084,
259
+ inches: earthRadius * 39.37,
260
+ kilometers: earthRadius / 1e3,
261
+ kilometres: earthRadius / 1e3,
262
+ meters: earthRadius,
263
+ metres: earthRadius,
264
+ miles: earthRadius / 1609.344,
265
+ millimeters: earthRadius * 1e3,
266
+ millimetres: earthRadius * 1e3,
267
+ nauticalmiles: earthRadius / 1852,
268
+ radians: 1,
269
+ yards: earthRadius * 1.0936
270
+ };
271
+ function feature(geom, properties, options = {}) {
272
+ const feat = { type: "Feature" };
273
+ if (options.id === 0 || options.id) {
274
+ feat.id = options.id;
275
+ }
276
+ if (options.bbox) {
277
+ feat.bbox = options.bbox;
278
+ }
279
+ feat.properties = properties || {};
280
+ feat.geometry = geom;
281
+ return feat;
282
+ }
283
+ function point(coordinates, properties, options = {}) {
284
+ if (!coordinates) {
285
+ throw new Error("coordinates is required");
286
+ }
287
+ if (!Array.isArray(coordinates)) {
288
+ throw new Error("coordinates must be an Array");
289
+ }
290
+ if (coordinates.length < 2) {
291
+ throw new Error("coordinates must be at least 2 numbers long");
292
+ }
293
+ if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) {
294
+ throw new Error("coordinates must contain numbers");
295
+ }
296
+ const geom = {
297
+ type: "Point",
298
+ coordinates
299
+ };
300
+ return feature(geom, properties, options);
301
+ }
302
+ function polygon(coordinates, properties, options = {}) {
303
+ for (const ring of coordinates) {
304
+ if (ring.length < 4) {
305
+ throw new Error(
306
+ "Each LinearRing of a Polygon must have 4 or more Positions."
307
+ );
308
+ }
309
+ if (ring[ring.length - 1].length !== ring[0].length) {
310
+ throw new Error("First and last Position are not equivalent.");
311
+ }
312
+ for (let j = 0; j < ring[ring.length - 1].length; j++) {
313
+ if (ring[ring.length - 1][j] !== ring[0][j]) {
314
+ throw new Error("First and last Position are not equivalent.");
254
315
  }
255
316
  }
317
+ }
318
+ const geom = {
319
+ type: "Polygon",
320
+ coordinates
321
+ };
322
+ return feature(geom, properties, options);
323
+ }
324
+ function lineString(coordinates, properties, options = {}) {
325
+ if (coordinates.length < 2) {
326
+ throw new Error("coordinates must be an array of two or more positions");
327
+ }
328
+ const geom = {
329
+ type: "LineString",
330
+ coordinates
331
+ };
332
+ return feature(geom, properties, options);
333
+ }
334
+ function featureCollection(features, options = {}) {
335
+ const fc = { type: "FeatureCollection" };
336
+ if (options.id) {
337
+ fc.id = options.id;
338
+ }
339
+ if (options.bbox) {
340
+ fc.bbox = options.bbox;
341
+ }
342
+ fc.features = features;
343
+ return fc;
344
+ }
345
+ function multiLineString(coordinates, properties, options = {}) {
346
+ const geom = {
347
+ type: "MultiLineString",
348
+ coordinates
349
+ };
350
+ return feature(geom, properties, options);
351
+ }
352
+ function isNumber(num) {
353
+ return !isNaN(num) && num !== null && !Array.isArray(num);
354
+ }
355
+ function isObject(input) {
356
+ return input !== null && typeof input === "object" && !Array.isArray(input);
357
+ }
358
+
359
+ // src/data/utils/findContaining.ts
360
+ var import_center = require("@turf/center");
361
+ var import_area = require("@turf/area");
362
+ var findContainingUnit = (poi, units) => {
363
+ const sameLevelUnits = units.filter(
364
+ (unit) => unit.properties.level_id === poi.properties.level_id
256
365
  );
257
- return unit;
366
+ if (sameLevelUnits.length === 0) return null;
367
+ const hitAtCenter = sameLevelUnits.find((unit) => (0, import_boolean_point_in_polygon.booleanPointInPolygon)((0, import_center.center)(poi), unit));
368
+ if (hitAtCenter) return hitAtCenter;
369
+ let overlapCandidate = null;
370
+ let bestOverlapScore = 0;
371
+ for (const unit of sameLevelUnits) {
372
+ try {
373
+ const overlap = (0, import_intersect.intersect)(featureCollection([poi, unit]));
374
+ if (!overlap) continue;
375
+ const overlapArea = (0, import_area.area)(overlap);
376
+ if (overlapArea > bestOverlapScore) {
377
+ bestOverlapScore = overlapArea;
378
+ overlapCandidate = unit;
379
+ }
380
+ } catch (e) {
381
+ console.log(`Cannot compare POI (${poi.id}) with unit (${unit.id}):`, e.message);
382
+ }
383
+ }
384
+ if (overlapCandidate && bestOverlapScore > 0) return overlapCandidate;
385
+ return null;
258
386
  };
259
387
  var findContainingUnitAtPoint = (point3, levelId, units) => {
260
388
  const unit = units.find(
@@ -267,7 +395,17 @@ var findContainingUnitAtPoint = (point3, levelId, units) => {
267
395
  }
268
396
  }
269
397
  );
270
- return unit;
398
+ return unit ? unit : null;
399
+ };
400
+
401
+ // src/data/utils/getPointOnFeature.ts
402
+ var import_center2 = require("@turf/center");
403
+ var import_boolean_point_in_polygon2 = __toESM(require("@turf/boolean-point-in-polygon"));
404
+ var import_point_on_feature = __toESM(require("@turf/point-on-feature"));
405
+ var getPointOnFeature = (feature3) => {
406
+ const c = (0, import_center2.center)(feature3);
407
+ if ((0, import_boolean_point_in_polygon2.default)(c, feature3)) return c;
408
+ return (0, import_point_on_feature.default)(feature3);
271
409
  };
272
410
 
273
411
  // src/data/utils/trace.ts
@@ -435,8 +573,8 @@ var safeFetchFeature = async (featureType, params) => {
435
573
  var import_query_core = require("@tanstack/query-core");
436
574
 
437
575
  // src/data/populator/index.ts
438
- var import_center = require("@turf/center");
439
- var import_boolean_point_in_polygon2 = require("@turf/boolean-point-in-polygon");
576
+ var import_center3 = require("@turf/center");
577
+ var import_boolean_point_in_polygon3 = require("@turf/boolean-point-in-polygon");
440
578
  var import_lodash3 = __toESM(require("lodash"));
441
579
  var createPopulator = ({
442
580
  internalFindById,
@@ -448,7 +586,29 @@ var createPopulator = ({
448
586
  const populateFootprint = (footprint) => Promise.resolve(footprint);
449
587
  const populateGeofence = (geofence) => Promise.resolve(geofence);
450
588
  const populatePrivilege = (privilege) => Promise.resolve(privilege);
451
- const populateEvent = (event) => Promise.resolve(event);
589
+ const populateEvent = async (event) => {
590
+ const { feature_id, venue_id, local_category_ids = [] } = event.properties;
591
+ const venue = await internalFindById(venue_id);
592
+ const feature3 = await internalFindById(feature_id);
593
+ const localCategories = (await Promise.all(
594
+ local_category_ids.map((id) => internalFindById(id))
595
+ )).filter(Boolean);
596
+ const [parentCategories, subCategories] = import_lodash3.default.partition(
597
+ localCategories,
598
+ (cat) => cat?.properties.parent_id === null
599
+ );
600
+ return {
601
+ ...event,
602
+ properties: {
603
+ ...event.properties,
604
+ venue,
605
+ feature: feature3,
606
+ local_categories: localCategories,
607
+ local_parent_categories: parentCategories,
608
+ local_sub_categories: subCategories
609
+ }
610
+ };
611
+ };
452
612
  const populatePromotion = async (promotion) => {
453
613
  const { feature_id, venue_id, local_category_ids = [] } = promotion.properties;
454
614
  const venue = await internalFindById(venue_id);
@@ -472,6 +632,16 @@ var createPopulator = ({
472
632
  }
473
633
  };
474
634
  };
635
+ const populateSponsoredContent = async (sc) => {
636
+ const { venue_id, feature_id } = sc;
637
+ const venue = await internalFindById(venue_id);
638
+ const feature3 = feature_id ? await internalFindById(feature_id) : null;
639
+ return {
640
+ ...sc,
641
+ venue,
642
+ feature: feature3
643
+ };
644
+ };
475
645
  const populateAmenity = async (amenity) => {
476
646
  const units = await Promise.all(
477
647
  amenity.properties.unit_ids.map(internalFindById)
@@ -483,7 +653,7 @@ var createPopulator = ({
483
653
  const ordinalKiosks = kiosks.filter(
484
654
  (kiosk2) => kiosk2.properties.level_id === defaultLevel.id
485
655
  );
486
- const kiosk = ordinalKiosks.find((kiosk2) => (0, import_boolean_point_in_polygon2.booleanPointInPolygon)(amenity, kiosk2));
656
+ const kiosk = ordinalKiosks.find((kiosk2) => (0, import_boolean_point_in_polygon3.booleanPointInPolygon)(amenity, kiosk2));
487
657
  return {
488
658
  ...amenity,
489
659
  properties: {
@@ -502,7 +672,7 @@ var createPopulator = ({
502
672
  const venue = await internalFindById(unit.properties.venue_id);
503
673
  const level = await internalFindById(unit.properties.level_id);
504
674
  const sections = await internalFilterByType("section");
505
- const section = sections.find((section2) => (0, import_boolean_point_in_polygon2.booleanPointInPolygon)(anchor, section2));
675
+ const section = sections.find((section2) => (0, import_boolean_point_in_polygon3.booleanPointInPolygon)(anchor, section2));
506
676
  return {
507
677
  ...anchor,
508
678
  properties: {
@@ -539,7 +709,7 @@ var createPopulator = ({
539
709
  let section = null;
540
710
  if (anchor) {
541
711
  const sections = await internalFilterByType("section");
542
- section = sections.find((section2) => (0, import_boolean_point_in_polygon2.booleanPointInPolygon)(anchor, section2));
712
+ section = sections.find((section2) => (0, import_boolean_point_in_polygon3.booleanPointInPolygon)(anchor, section2));
543
713
  }
544
714
  return {
545
715
  ...kiosk,
@@ -656,7 +826,7 @@ var createPopulator = ({
656
826
  const level = await internalFindById(unit.properties.level_id);
657
827
  const sections = await internalFilterByType("section");
658
828
  try {
659
- const section = unit.geometry.type !== "MultiPolygon" ? sections.find((section2) => (0, import_boolean_point_in_polygon2.booleanPointInPolygon)((0, import_center.center)(unit), section2)) : null;
829
+ const section = unit.geometry.type !== "MultiPolygon" ? sections.find((section2) => (0, import_boolean_point_in_polygon3.booleanPointInPolygon)((0, import_center3.center)(unit), section2)) : null;
660
830
  return {
661
831
  ...unit,
662
832
  properties: {
@@ -723,7 +893,8 @@ var createPopulator = ({
723
893
  unit: populateUnit,
724
894
  venue: populateVenue,
725
895
  taxonomy: populateTaxonomy,
726
- model3d: populateModel3D
896
+ model3d: populateModel3D,
897
+ "sponsored-content": populateSponsoredContent
727
898
  };
728
899
  };
729
900
 
@@ -732,25 +903,25 @@ var import_distance = require("@turf/distance");
732
903
  var import_rhumb_bearing = require("@turf/rhumb-bearing");
733
904
 
734
905
  // ../../node_modules/@turf/rhumb-destination/node_modules/@turf/helpers/dist/esm/index.js
735
- var earthRadius = 63710088e-1;
736
- var factors = {
737
- centimeters: earthRadius * 100,
738
- centimetres: earthRadius * 100,
906
+ var earthRadius2 = 63710088e-1;
907
+ var factors2 = {
908
+ centimeters: earthRadius2 * 100,
909
+ centimetres: earthRadius2 * 100,
739
910
  degrees: 360 / (2 * Math.PI),
740
- feet: earthRadius * 3.28084,
741
- inches: earthRadius * 39.37,
742
- kilometers: earthRadius / 1e3,
743
- kilometres: earthRadius / 1e3,
744
- meters: earthRadius,
745
- metres: earthRadius,
746
- miles: earthRadius / 1609.344,
747
- millimeters: earthRadius * 1e3,
748
- millimetres: earthRadius * 1e3,
749
- nauticalmiles: earthRadius / 1852,
911
+ feet: earthRadius2 * 3.28084,
912
+ inches: earthRadius2 * 39.37,
913
+ kilometers: earthRadius2 / 1e3,
914
+ kilometres: earthRadius2 / 1e3,
915
+ meters: earthRadius2,
916
+ metres: earthRadius2,
917
+ miles: earthRadius2 / 1609.344,
918
+ millimeters: earthRadius2 * 1e3,
919
+ millimetres: earthRadius2 * 1e3,
920
+ nauticalmiles: earthRadius2 / 1852,
750
921
  radians: 1,
751
- yards: earthRadius * 1.0936
922
+ yards: earthRadius2 * 1.0936
752
923
  };
753
- function feature(geom, properties, options = {}) {
924
+ function feature2(geom, properties, options = {}) {
754
925
  const feat = { type: "Feature" };
755
926
  if (options.id === 0 || options.id) {
756
927
  feat.id = options.id;
@@ -762,7 +933,7 @@ function feature(geom, properties, options = {}) {
762
933
  feat.geometry = geom;
763
934
  return feat;
764
935
  }
765
- function point(coordinates, properties, options = {}) {
936
+ function point2(coordinates, properties, options = {}) {
766
937
  if (!coordinates) {
767
938
  throw new Error("coordinates is required");
768
939
  }
@@ -772,28 +943,28 @@ function point(coordinates, properties, options = {}) {
772
943
  if (coordinates.length < 2) {
773
944
  throw new Error("coordinates must be at least 2 numbers long");
774
945
  }
775
- if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) {
946
+ if (!isNumber2(coordinates[0]) || !isNumber2(coordinates[1])) {
776
947
  throw new Error("coordinates must contain numbers");
777
948
  }
778
949
  const geom = {
779
950
  type: "Point",
780
951
  coordinates
781
952
  };
782
- return feature(geom, properties, options);
953
+ return feature2(geom, properties, options);
783
954
  }
784
955
  function radiansToLength(radians, units = "kilometers") {
785
- const factor = factors[units];
956
+ const factor = factors2[units];
786
957
  if (!factor) {
787
958
  throw new Error(units + " units is invalid");
788
959
  }
789
960
  return radians * factor;
790
961
  }
791
- function lengthToRadians(distance6, units = "kilometers") {
792
- const factor = factors[units];
962
+ function lengthToRadians(distance7, units = "kilometers") {
963
+ const factor = factors2[units];
793
964
  if (!factor) {
794
965
  throw new Error(units + " units is invalid");
795
966
  }
796
- return distance6 / factor;
967
+ return distance7 / factor;
797
968
  }
798
969
  function degreesToRadians(degrees) {
799
970
  const normalisedDegrees = degrees % 360;
@@ -805,16 +976,16 @@ function convertLength(length, originalUnit = "kilometers", finalUnit = "kilomet
805
976
  }
806
977
  return radiansToLength(lengthToRadians(length, originalUnit), finalUnit);
807
978
  }
808
- function isNumber(num) {
979
+ function isNumber2(num) {
809
980
  return !isNaN(num) && num !== null && !Array.isArray(num);
810
981
  }
811
982
 
812
983
  // ../../node_modules/@turf/rhumb-destination/dist/esm/index.js
813
984
  var import_invariant = require("@turf/invariant");
814
- function rhumbDestination(origin, distance6, bearing, options = {}) {
815
- const wasNegativeDistance = distance6 < 0;
985
+ function rhumbDestination(origin, distance7, bearing, options = {}) {
986
+ const wasNegativeDistance = distance7 < 0;
816
987
  let distanceInMeters = convertLength(
817
- Math.abs(distance6),
988
+ Math.abs(distance7),
818
989
  options.units,
819
990
  "meters"
820
991
  );
@@ -826,11 +997,11 @@ function rhumbDestination(origin, distance6, bearing, options = {}) {
826
997
  bearing
827
998
  );
828
999
  destination[0] += destination[0] - coords[0] > 180 ? -360 : coords[0] - destination[0] > 180 ? 360 : 0;
829
- return point(destination, options.properties);
1000
+ return point2(destination, options.properties);
830
1001
  }
831
- function calculateRhumbDestination(origin, distance6, bearing, radius) {
832
- radius = radius === void 0 ? earthRadius : Number(radius);
833
- const delta = distance6 / radius;
1002
+ function calculateRhumbDestination(origin, distance7, bearing, radius) {
1003
+ radius = radius === void 0 ? earthRadius2 : Number(radius);
1004
+ const delta = distance7 / radius;
834
1005
  const lambda1 = origin[0] * Math.PI / 180;
835
1006
  const phi1 = degreesToRadians(origin[1]);
836
1007
  const theta = degreesToRadians(bearing);
@@ -851,113 +1022,6 @@ function calculateRhumbDestination(origin, distance6, bearing, radius) {
851
1022
  ];
852
1023
  }
853
1024
 
854
- // node_modules/@turf/helpers/dist/esm/index.js
855
- var earthRadius2 = 63710088e-1;
856
- var factors2 = {
857
- centimeters: earthRadius2 * 100,
858
- centimetres: earthRadius2 * 100,
859
- degrees: 360 / (2 * Math.PI),
860
- feet: earthRadius2 * 3.28084,
861
- inches: earthRadius2 * 39.37,
862
- kilometers: earthRadius2 / 1e3,
863
- kilometres: earthRadius2 / 1e3,
864
- meters: earthRadius2,
865
- metres: earthRadius2,
866
- miles: earthRadius2 / 1609.344,
867
- millimeters: earthRadius2 * 1e3,
868
- millimetres: earthRadius2 * 1e3,
869
- nauticalmiles: earthRadius2 / 1852,
870
- radians: 1,
871
- yards: earthRadius2 * 1.0936
872
- };
873
- function feature2(geom, properties, options = {}) {
874
- const feat = { type: "Feature" };
875
- if (options.id === 0 || options.id) {
876
- feat.id = options.id;
877
- }
878
- if (options.bbox) {
879
- feat.bbox = options.bbox;
880
- }
881
- feat.properties = properties || {};
882
- feat.geometry = geom;
883
- return feat;
884
- }
885
- function point2(coordinates, properties, options = {}) {
886
- if (!coordinates) {
887
- throw new Error("coordinates is required");
888
- }
889
- if (!Array.isArray(coordinates)) {
890
- throw new Error("coordinates must be an Array");
891
- }
892
- if (coordinates.length < 2) {
893
- throw new Error("coordinates must be at least 2 numbers long");
894
- }
895
- if (!isNumber2(coordinates[0]) || !isNumber2(coordinates[1])) {
896
- throw new Error("coordinates must contain numbers");
897
- }
898
- const geom = {
899
- type: "Point",
900
- coordinates
901
- };
902
- return feature2(geom, properties, options);
903
- }
904
- function polygon(coordinates, properties, options = {}) {
905
- for (const ring of coordinates) {
906
- if (ring.length < 4) {
907
- throw new Error(
908
- "Each LinearRing of a Polygon must have 4 or more Positions."
909
- );
910
- }
911
- if (ring[ring.length - 1].length !== ring[0].length) {
912
- throw new Error("First and last Position are not equivalent.");
913
- }
914
- for (let j = 0; j < ring[ring.length - 1].length; j++) {
915
- if (ring[ring.length - 1][j] !== ring[0][j]) {
916
- throw new Error("First and last Position are not equivalent.");
917
- }
918
- }
919
- }
920
- const geom = {
921
- type: "Polygon",
922
- coordinates
923
- };
924
- return feature2(geom, properties, options);
925
- }
926
- function lineString(coordinates, properties, options = {}) {
927
- if (coordinates.length < 2) {
928
- throw new Error("coordinates must be an array of two or more positions");
929
- }
930
- const geom = {
931
- type: "LineString",
932
- coordinates
933
- };
934
- return feature2(geom, properties, options);
935
- }
936
- function featureCollection(features, options = {}) {
937
- const fc = { type: "FeatureCollection" };
938
- if (options.id) {
939
- fc.id = options.id;
940
- }
941
- if (options.bbox) {
942
- fc.bbox = options.bbox;
943
- }
944
- fc.features = features;
945
- return fc;
946
- }
947
- function multiLineString(coordinates, properties, options = {}) {
948
- const geom = {
949
- type: "MultiLineString",
950
- coordinates
951
- };
952
- return feature2(geom, properties, options);
953
- }
954
- function isNumber2(num) {
955
- return !isNaN(num) && num !== null && !Array.isArray(num);
956
- }
957
- function isObject(input) {
958
- return input !== null && typeof input === "object" && !Array.isArray(input);
959
- }
960
-
961
1025
  // src/data/navigate/services/landmark/utils/outerRingsToLine.ts
962
1026
  var outerRingsToLine = (geom) => {
963
1027
  if (geom.type === "Polygon") {
@@ -984,7 +1048,7 @@ var distanceToWall = (p, wallLines) => {
984
1048
  };
985
1049
 
986
1050
  // src/data/navigate/services/landmark/utils/toLandmark.ts
987
- var import_center2 = require("@turf/center");
1051
+ var import_center4 = require("@turf/center");
988
1052
  var occupantToLandmark = (occupant, findByIdSync) => {
989
1053
  const locationType = occupant.properties.unit_id ? "unit" : "kiosk";
990
1054
  const locationId = locationType === "unit" ? occupant.properties.unit_id : occupant.properties.kiosk_id;
@@ -994,7 +1058,7 @@ var occupantToLandmark = (occupant, findByIdSync) => {
994
1058
  if (!level) return null;
995
1059
  return {
996
1060
  name: occupant.properties.name,
997
- point: (0, import_center2.center)(location.geometry).geometry.coordinates,
1061
+ point: (0, import_center4.center)(location.geometry).geometry.coordinates,
998
1062
  boundary: outerRingsToLine(location.geometry),
999
1063
  level_id: location.properties.level_id,
1000
1064
  is_priority: occupant.properties.is_landmark,
@@ -1006,7 +1070,7 @@ var unitToLandmark = (unit, findByIdSync) => {
1006
1070
  if (!level) return null;
1007
1071
  return {
1008
1072
  name: { en: unit.properties.category },
1009
- point: (0, import_center2.center)(unit.geometry).geometry.coordinates,
1073
+ point: (0, import_center4.center)(unit.geometry).geometry.coordinates,
1010
1074
  boundary: outerRingsToLine(unit.geometry),
1011
1075
  level_id: unit.properties.level_id,
1012
1076
  is_priority: false,
@@ -1018,7 +1082,7 @@ var openingToLandmark = (opening, findByIdSync) => {
1018
1082
  if (!level) return null;
1019
1083
  return {
1020
1084
  name: opening.properties.name?.en ? opening.properties.name : { en: "Entrance / Exit" },
1021
- point: (0, import_center2.center)(opening.geometry).geometry.coordinates,
1085
+ point: (0, import_center4.center)(opening.geometry).geometry.coordinates,
1022
1086
  level_id: opening.properties.level_id,
1023
1087
  is_priority: true,
1024
1088
  ordinal: level.properties.ordinal
@@ -1029,7 +1093,7 @@ var amenityToLandmark = (amenity, findByIdSync) => {
1029
1093
  if (!level) return null;
1030
1094
  return {
1031
1095
  name: amenity.properties.name ?? { en: amenity.properties.category, th: amenity.properties.category },
1032
- point: (0, import_center2.center)(amenity.geometry).geometry.coordinates,
1096
+ point: (0, import_center4.center)(amenity.geometry).geometry.coordinates,
1033
1097
  level_id: amenity.properties.level_id,
1034
1098
  is_priority: true,
1035
1099
  ordinal: level.properties.ordinal
@@ -1082,7 +1146,7 @@ var createLandmarkService = (ctx) => {
1082
1146
 
1083
1147
  // src/data/navigate/context/createNavigateContext.ts
1084
1148
  var createFindByIdSync = (data) => {
1085
- const { amenities = [], anchors = [], fixtures = [], levels = [], kiosks = [], relationships = [], occupants = [], openings = [], units } = data;
1149
+ const { amenities = [], anchors = [], fixtures = [], levels = [], kiosks = [], relationships = [], occupants = [], openings = [], sections = [], units } = data;
1086
1150
  const featureById = /* @__PURE__ */ new Map();
1087
1151
  const entries = [
1088
1152
  ...amenities,
@@ -1093,6 +1157,7 @@ var createFindByIdSync = (data) => {
1093
1157
  ...relationships,
1094
1158
  ...occupants,
1095
1159
  ...openings,
1160
+ ...sections,
1096
1161
  ...units
1097
1162
  ];
1098
1163
  for (const f of entries) featureById.set(f.id, f);
@@ -1113,17 +1178,17 @@ var createNavigateContext = (options) => {
1113
1178
  };
1114
1179
 
1115
1180
  // src/data/navigate/client.ts
1116
- var import_boolean_point_in_polygon4 = require("@turf/boolean-point-in-polygon");
1181
+ var import_boolean_point_in_polygon5 = require("@turf/boolean-point-in-polygon");
1117
1182
 
1118
1183
  // src/data/navigate/services/graph/prepare.ts
1119
- var import_lodash16 = __toESM(require("lodash"));
1184
+ var import_lodash19 = __toESM(require("lodash"));
1120
1185
  var import_node_dijkstra = __toESM(require("node-dijkstra"));
1121
- var import_distance4 = require("@turf/distance");
1122
- var import_center5 = require("@turf/center");
1186
+ var import_distance5 = require("@turf/distance");
1187
+ var import_center8 = require("@turf/center");
1123
1188
 
1124
1189
  // src/data/navigate/services/graph/nodemap/createTraversalNodeMap.ts
1125
1190
  var import_distance2 = require("@turf/distance");
1126
- var import_center3 = require("@turf/center");
1191
+ var import_center5 = require("@turf/center");
1127
1192
  var import_lodash4 = __toESM(require("lodash"));
1128
1193
 
1129
1194
  // src/data/navigate/services/graph/constants.ts
@@ -1172,14 +1237,14 @@ var createTraversalNodeMap = (unitOpenings, options) => {
1172
1237
  const opening = features[currentIndex];
1173
1238
  const feature3 = features[j];
1174
1239
  try {
1175
- const distance6 = (0, import_distance2.distance)(
1176
- (0, import_center3.center)(opening.geometry),
1177
- (0, import_center3.center)(feature3.geometry),
1240
+ const distance7 = (0, import_distance2.distance)(
1241
+ (0, import_center5.center)(opening.geometry),
1242
+ (0, import_center5.center)(feature3.geometry),
1178
1243
  { units: "meters" }
1179
1244
  ) + (distanceOptions?.baseDistance ?? 0);
1180
1245
  if (opening.id === feature3.id) continue;
1181
- import_lodash4.default.set(relationshipGraph, `${opening.id}.${feature3.id}`, distance6);
1182
- import_lodash4.default.set(relationshipGraph, `${feature3.id}.${opening.id}`, distance6);
1246
+ import_lodash4.default.set(relationshipGraph, `${opening.id}.${feature3.id}`, distance7);
1247
+ import_lodash4.default.set(relationshipGraph, `${feature3.id}.${opening.id}`, distance7);
1183
1248
  counter++;
1184
1249
  } catch (error) {
1185
1250
  continue;
@@ -1260,15 +1325,15 @@ var createElevatorNodeMap = (elevatorLikeRelationships, unitOpenings, options) =
1260
1325
  const { opening: theOpening, level: theLevel } = theConnection;
1261
1326
  if (theConnection.opening.id === otherConnection.opening.id) continue;
1262
1327
  const { opening: otherOpening, level: otherLevel } = otherConnection;
1263
- let distance6 = baseDistance;
1328
+ let distance7 = baseDistance;
1264
1329
  if (scaleDistanceByLevel && theLevel && otherLevel) {
1265
1330
  const originOrdinal = theLevel.properties.ordinal;
1266
1331
  const connectionOrdinal = otherLevel.properties.ordinal;
1267
1332
  const levelDifference = Math.abs(originOrdinal - connectionOrdinal);
1268
- if (levelDifference > 0) distance6 *= levelDifference;
1333
+ if (levelDifference > 0) distance7 *= levelDifference;
1269
1334
  }
1270
- import_lodash5.default.set(elevatorNodeMap, `${theOpening.id}.${otherOpening.id}`, distance6);
1271
- import_lodash5.default.set(elevatorNodeMap, `${otherOpening.id}.${theOpening.id}`, distance6);
1335
+ import_lodash5.default.set(elevatorNodeMap, `${theOpening.id}.${otherOpening.id}`, distance7);
1336
+ import_lodash5.default.set(elevatorNodeMap, `${otherOpening.id}.${theOpening.id}`, distance7);
1272
1337
  counter++;
1273
1338
  }
1274
1339
  }
@@ -1328,28 +1393,35 @@ var createRampNodeMap = (relationships, options) => {
1328
1393
 
1329
1394
  // src/data/navigate/services/graph/nodemap/createStairNodeMap.ts
1330
1395
  var import_lodash9 = __toESM(require("lodash"));
1331
- var createStairNodeMap = (elevatorLikeRelationships, unitOpenings, options) => {
1396
+ var createStairNodeMap = (stairLikeRelationships, unitOpenings, options) => {
1332
1397
  const t0 = performance.now();
1333
1398
  const { levels = [], openings = [], units = [] } = options.data;
1334
1399
  const { baseDistance, scaleDistanceByLevel } = getDistanceOptions(options.unitDistanceOptions, "stairs");
1335
1400
  let elevatorNodeMap = {};
1336
1401
  let counter = 0;
1337
- for (const relationship of elevatorLikeRelationships) {
1402
+ for (const relationship of stairLikeRelationships) {
1338
1403
  try {
1339
1404
  const {
1340
- origin: { id: originId },
1405
+ origin: originTypeAndId,
1406
+ // opening
1341
1407
  intermediary,
1342
- destination: { id: destinationId }
1408
+ // units
1409
+ destination: destinationTypeAndId
1410
+ // opening
1343
1411
  } = relationship.properties;
1344
- const origin = openings.find((opening) => opening.id === originId);
1345
- if (!origin) return;
1346
- const originLevel = levels.find((level) => level.id === origin.properties.level_id);
1347
- const destination = openings.find((opening) => opening.id === destinationId);
1348
- const destinationOpeningAndLevel = {
1349
- opening: destination,
1350
- level: levels.find((level) => level.id === destination.properties.level_id)
1351
- };
1352
- const intermediaryOpeningAndLevels = intermediary.map((unitTypeAndId) => {
1412
+ const origin = openings.find((opening) => opening.id === originTypeAndId.id);
1413
+ let originOpeningAndLevels = [];
1414
+ if (origin) {
1415
+ const originLevel = levels.find((level) => level.id === origin?.properties.level_id);
1416
+ originOpeningAndLevels.push({ opening: origin, level: originLevel });
1417
+ }
1418
+ const destination = openings.find((opening) => opening.id === destinationTypeAndId.id);
1419
+ let destinationOpeningAndLevels = [];
1420
+ if (destination) {
1421
+ const destinationLevel = levels.find((level) => level.id === destination?.properties.level_id);
1422
+ destinationOpeningAndLevels.push({ opening: destination, level: destinationLevel });
1423
+ }
1424
+ const intermediaryOpeningAndLevels = (intermediary || []).map((unitTypeAndId) => {
1353
1425
  const openings2 = unitOpenings[unitTypeAndId.id];
1354
1426
  const unit = units.find((unit2) => unit2.id === unitTypeAndId.id);
1355
1427
  if (!unit) return [];
@@ -1357,20 +1429,28 @@ var createStairNodeMap = (elevatorLikeRelationships, unitOpenings, options) => {
1357
1429
  if (!level) return [];
1358
1430
  return openings2.map((opening) => ({ opening, level }));
1359
1431
  }).flat();
1360
- const connections = [...intermediaryOpeningAndLevels, destinationOpeningAndLevel];
1361
- if (!origin) return;
1362
- for (const connection of connections) {
1363
- const { opening, level } = connection;
1364
- let distance6 = baseDistance;
1365
- if (scaleDistanceByLevel) {
1366
- const originOrdinal = originLevel.properties.ordinal;
1367
- const connectionOrdinal = level.properties.ordinal;
1368
- const levelDifference = Math.abs(originOrdinal - connectionOrdinal);
1369
- if (levelDifference > 0) distance6 *= levelDifference;
1432
+ const connections = compact([
1433
+ ...originOpeningAndLevels,
1434
+ ...intermediaryOpeningAndLevels,
1435
+ ...destinationOpeningAndLevels
1436
+ ]);
1437
+ if (connections.length === 0) return elevatorNodeMap;
1438
+ for (const theConnection of connections) {
1439
+ for (const otherConnection of connections) {
1440
+ const { opening: theOpening, level: theLevel } = theConnection;
1441
+ if (theConnection.opening.id === otherConnection.opening.id) continue;
1442
+ const { opening: otherOpening, level: otherLevel } = otherConnection;
1443
+ let distance7 = baseDistance;
1444
+ if (scaleDistanceByLevel && theLevel && otherLevel) {
1445
+ const originOrdinal = theLevel.properties.ordinal;
1446
+ const connectionOrdinal = otherLevel.properties.ordinal;
1447
+ const levelDifference = Math.abs(originOrdinal - connectionOrdinal);
1448
+ if (levelDifference > 0) distance7 *= levelDifference;
1449
+ }
1450
+ import_lodash9.default.set(elevatorNodeMap, `${theOpening.id}.${otherOpening.id}`, distance7);
1451
+ import_lodash9.default.set(elevatorNodeMap, `${otherOpening.id}.${theOpening.id}`, distance7);
1452
+ counter++;
1370
1453
  }
1371
- import_lodash9.default.set(elevatorNodeMap, `${origin.id}.${opening.id}`, distance6);
1372
- import_lodash9.default.set(elevatorNodeMap, `${opening.id}.${origin.id}`, distance6);
1373
- counter++;
1374
1454
  }
1375
1455
  } catch (err) {
1376
1456
  console.warn(
@@ -1390,7 +1470,7 @@ var createStairNodeMap = (elevatorLikeRelationships, unitOpenings, options) => {
1390
1470
  };
1391
1471
 
1392
1472
  // src/data/navigate/services/graph/nodemap/createOccupantNodeMap.ts
1393
- var import_lodash10 = __toESM(require("lodash"));
1473
+ var import_lodash11 = __toESM(require("lodash"));
1394
1474
  var createOccupantNodeMap = (occupants) => {
1395
1475
  const t0 = performance.now();
1396
1476
  let nodeMap = {};
@@ -1400,13 +1480,13 @@ var createOccupantNodeMap = (occupants) => {
1400
1480
  const occupantRoomIds = compact(!is_maintenance ? [unit_id, ...unit_ids] : [temp_unit_id]);
1401
1481
  const occupantKioskIds = compact(!is_maintenance ? [kiosk_id, ...kiosk_ids] : [temp_kiosk_id]);
1402
1482
  for (const roomId of occupantRoomIds) {
1403
- import_lodash10.default.set(nodeMap, `${roomId}.${occupant.id}`, 1e-3);
1404
- import_lodash10.default.set(nodeMap, `${occupant.id}.${roomId}`, 1e-3);
1483
+ import_lodash11.default.set(nodeMap, `${roomId}.${occupant.id}`, 1e-3);
1484
+ import_lodash11.default.set(nodeMap, `${occupant.id}.${roomId}`, 1e-3);
1405
1485
  counter++;
1406
1486
  }
1407
1487
  for (const kioskId of occupantKioskIds) {
1408
- import_lodash10.default.set(nodeMap, `${kioskId}.${occupant.id}`, 1e-3);
1409
- import_lodash10.default.set(nodeMap, `${occupant.id}.${kioskId}`, 1e-3);
1488
+ import_lodash11.default.set(nodeMap, `${kioskId}.${occupant.id}`, 1e-3);
1489
+ import_lodash11.default.set(nodeMap, `${occupant.id}.${kioskId}`, 1e-3);
1410
1490
  counter++;
1411
1491
  }
1412
1492
  });
@@ -1415,11 +1495,11 @@ var createOccupantNodeMap = (occupants) => {
1415
1495
  return nodeMap;
1416
1496
  };
1417
1497
 
1418
- // src/data/navigate/services/graph/nodemap/createPOINodeMaps.ts
1419
- var import_center4 = require("@turf/center");
1498
+ // src/data/navigate/services/graph/nodemap/createPoiToWalkwayOpeningNodeMap.ts
1499
+ var import_center6 = require("@turf/center");
1420
1500
  var import_distance3 = require("@turf/distance");
1421
- var import_lodash12 = __toESM(require("lodash"));
1422
- var createPOINodeMap = (features, getFeatureUnit, unitOpenings) => {
1501
+ var import_lodash13 = __toESM(require("lodash"));
1502
+ var createPoiToWalkwayOpeningNodeMap = (features, getFeatureUnit, unitOpenings) => {
1423
1503
  const t0 = performance.now();
1424
1504
  let nodeMap = {};
1425
1505
  let counter = 0;
@@ -1428,13 +1508,13 @@ var createPOINodeMap = (features, getFeatureUnit, unitOpenings) => {
1428
1508
  const locatedOnUnitId = getFeatureUnit(feat);
1429
1509
  if (locatedOnUnitId) {
1430
1510
  const openings = unitOpenings[locatedOnUnitId] ?? [];
1431
- const center4 = (0, import_center4.center)(feat);
1511
+ const center6 = (0, import_center6.center)(feat);
1432
1512
  for (const opening of openings) {
1433
1513
  try {
1434
- const openingCenter = (0, import_center4.center)(opening);
1435
- const dis = (0, import_distance3.distance)(center4, openingCenter, { units: "meters" }) + BASE_POI_BASEDISTANCE;
1436
- import_lodash12.default.set(nodeMap, `${opening.id}.${feat.id}`, dis);
1437
- import_lodash12.default.set(nodeMap, `${feat.id}.${opening.id}`, dis);
1514
+ const openingCenter = (0, import_center6.center)(opening);
1515
+ const dis = (0, import_distance3.distance)(center6, openingCenter, { units: "meters" }) + BASE_POI_BASEDISTANCE;
1516
+ import_lodash13.default.set(nodeMap, `${opening.id}.${feat.id}`, dis);
1517
+ import_lodash13.default.set(nodeMap, `${feat.id}.${opening.id}`, dis);
1438
1518
  counter++;
1439
1519
  } catch (err) {
1440
1520
  console.log(err, opening);
@@ -1452,6 +1532,35 @@ var createPOINodeMap = (features, getFeatureUnit, unitOpenings) => {
1452
1532
  return nodeMap;
1453
1533
  };
1454
1534
 
1535
+ // src/data/navigate/services/graph/nodemap/createWalkwayNodeMap.ts
1536
+ var import_lodash14 = __toESM(require("lodash"));
1537
+ var import_distance4 = require("@turf/distance");
1538
+ var import_center7 = require("@turf/center");
1539
+ var createWalkwayNodeMap = (poiOnWalkways) => {
1540
+ const t0 = performance.now();
1541
+ let nodeMap = {};
1542
+ let counter = 0;
1543
+ for (const [walkwayId, pois] of Object.entries(poiOnWalkways)) {
1544
+ if (pois.length > 1) {
1545
+ for (let i = 0; i < pois.length; i++) {
1546
+ const thisPoi = pois[i];
1547
+ for (let j = 0; j < pois.length; j++) {
1548
+ const thatPoi = pois[j];
1549
+ if (thisPoi.id !== thatPoi.id) {
1550
+ const dis = (0, import_distance4.distance)((0, import_center7.center)(thisPoi), (0, import_center7.center)(thatPoi), { units: "meters" });
1551
+ import_lodash14.default.set(nodeMap, `${thisPoi.id}.${thatPoi.id}`, dis);
1552
+ import_lodash14.default.set(nodeMap, `${thatPoi.id}.${thisPoi.id}`, dis);
1553
+ counter++;
1554
+ }
1555
+ }
1556
+ }
1557
+ }
1558
+ }
1559
+ const t1 = performance.now();
1560
+ trace("nav", ` \u2502 \u251C\u2500 add ${counter} within same walkway relationships`, t1 - t0);
1561
+ return nodeMap;
1562
+ };
1563
+
1455
1564
  // src/data/navigate/services/graph/utils/mergeNodeMap.ts
1456
1565
  var mergeNodeMap = (nodeMaps) => {
1457
1566
  const out = {};
@@ -1467,7 +1576,7 @@ var mergeNodeMap = (nodeMaps) => {
1467
1576
  };
1468
1577
 
1469
1578
  // src/data/navigate/services/graph/utils/createUnitOpenings.ts
1470
- var import_lodash13 = require("lodash");
1579
+ var import_lodash15 = require("lodash");
1471
1580
  var createUnitOpenings = (relationships, units, openings) => {
1472
1581
  const openingConnections = {};
1473
1582
  const relationshipMap = /* @__PURE__ */ new Map();
@@ -1493,7 +1602,7 @@ var createUnitOpenings = (relationships, units, openings) => {
1493
1602
  const relationshipIntermediary = relationshipIntermediaryTypeAndId.map(({ id }) => {
1494
1603
  return openings.find((opening) => !!opening && opening.id === id);
1495
1604
  });
1496
- openingConnections[unitId] = (0, import_lodash13.uniqBy)(
1605
+ openingConnections[unitId] = (0, import_lodash15.uniqBy)(
1497
1606
  [...openingConnections[unitId] || [], ...relationshipIntermediary],
1498
1607
  "id"
1499
1608
  );
@@ -1507,18 +1616,49 @@ var parseOrdinalCoordinate = (id) => {
1507
1616
  };
1508
1617
 
1509
1618
  // src/data/navigate/services/graph/utils/createUnitsKiosks.ts
1510
- var import_lodash15 = require("lodash");
1619
+ var import_lodash17 = require("lodash");
1511
1620
  var createUnitsKiosks = (units, kiosks) => {
1512
1621
  const unitsWithKiosks = {};
1513
1622
  kiosks.forEach((kiosk) => {
1514
1623
  const unitId = findContainingUnit(kiosk, units)?.id;
1515
1624
  if (!unitId) return;
1516
- const prevValues = (0, import_lodash15.get)(unitsWithKiosks, unitId, []);
1517
- (0, import_lodash15.set)(unitsWithKiosks, unitId, [...prevValues, kiosk]);
1625
+ const prevValues = (0, import_lodash17.get)(unitsWithKiosks, unitId, []);
1626
+ (0, import_lodash17.set)(unitsWithKiosks, unitId, [...prevValues, kiosk]);
1518
1627
  });
1519
1628
  return unitsWithKiosks;
1520
1629
  };
1521
1630
 
1631
+ // src/data/navigate/services/graph/utils/createUnitsAmenities.ts
1632
+ var import_lodash18 = require("lodash");
1633
+ var createUnitsAmenities = (units, amenities) => {
1634
+ const unitsWithAmenities = {};
1635
+ amenities.forEach((amenity) => {
1636
+ const unitId = findContainingUnit(amenity, units)?.id;
1637
+ if (!unitId) return;
1638
+ const prevValues = (0, import_lodash18.get)(unitsWithAmenities, unitId, []);
1639
+ (0, import_lodash18.set)(unitsWithAmenities, unitId, [...prevValues, amenity]);
1640
+ });
1641
+ return unitsWithAmenities;
1642
+ };
1643
+
1644
+ // src/data/navigate/constants.ts
1645
+ var WALKABLE_UNIT_CATEGORY = [
1646
+ "walkway",
1647
+ "parking",
1648
+ "room",
1649
+ "terrace",
1650
+ "unenclosedarea",
1651
+ "vegetation",
1652
+ "unspecified"
1653
+ ];
1654
+ var VERTICAL_TRAVERSAL_CATEGORY = [
1655
+ "elevator",
1656
+ "escalator",
1657
+ "stairs",
1658
+ "stairs.emergencyexit",
1659
+ "ramp"
1660
+ ];
1661
+
1522
1662
  // src/data/navigate/services/graph/prepare.ts
1523
1663
  var prepareGraph = (options) => {
1524
1664
  const {
@@ -1529,7 +1669,8 @@ var prepareGraph = (options) => {
1529
1669
  relationships = [],
1530
1670
  openings = [],
1531
1671
  units = [],
1532
- kiosks = []
1672
+ kiosks = [],
1673
+ sections = []
1533
1674
  }
1534
1675
  } = options;
1535
1676
  const {
@@ -1538,10 +1679,12 @@ var prepareGraph = (options) => {
1538
1679
  ramp: rampRelationships = [],
1539
1680
  elevator: elevatorRelationships = [],
1540
1681
  stairs: stairsRelationships = []
1541
- } = import_lodash16.default.groupBy(relationships, "properties.category");
1682
+ } = import_lodash19.default.groupBy(relationships, "properties.category");
1542
1683
  const unitOpenings = createUnitOpenings(traversalRelationships, units, openings);
1543
- const walkwayUnits = units.filter((unit) => unit.properties.category === "walkway");
1684
+ const walkableUnits = units.filter((unit) => WALKABLE_UNIT_CATEGORY.includes(unit.properties.category));
1685
+ const walkwayUnits = walkableUnits.filter((unit) => unit.properties.category === "walkway");
1544
1686
  const unitKiosks = createUnitsKiosks(walkwayUnits, kiosks);
1687
+ const unitAmenities = createUnitsAmenities(walkwayUnits, amenities);
1545
1688
  const traversalNodeMap = createTraversalNodeMap(unitOpenings, options);
1546
1689
  const escalatorNodeMap = createEscalatorNodeMap(escalatorRelationships, options);
1547
1690
  const rampNodeMap = createRampNodeMap(rampRelationships, options);
@@ -1555,10 +1698,26 @@ var prepareGraph = (options) => {
1555
1698
  unitOpenings,
1556
1699
  options
1557
1700
  );
1558
- const amenityNodeMap = createPOINodeMap(amenities, (amenity) => amenity.properties.unit_ids?.[0] || null, unitOpenings);
1559
- const anchorsNodeMap = createPOINodeMap(anchors, (anchor) => anchor.properties.unit_id, unitOpenings);
1560
- const kioskNodeMap = createPOINodeMap(kiosks, (kiosk) => findContainingUnit(kiosk, walkwayUnits)?.id, unitOpenings);
1561
- const unitNodeMap = createPOINodeMap(units, (unit) => unit.id, unitOpenings);
1701
+ const amenityNodeMap = createPoiToWalkwayOpeningNodeMap(amenities, (amenity) => amenity?.properties?.unit_ids?.[0] || null, unitOpenings);
1702
+ const anchorsNodeMap = createPoiToWalkwayOpeningNodeMap(anchors, (anchor) => anchor?.properties?.unit_id, unitOpenings);
1703
+ const sectionNodeMap = createPoiToWalkwayOpeningNodeMap(
1704
+ sections,
1705
+ (section) => {
1706
+ const sectionLevelId = section?.properties?.level_id;
1707
+ const displayPoint = section?.properties?.display_point;
1708
+ const unit = findContainingUnitAtPoint(displayPoint, sectionLevelId, walkableUnits) || findContainingUnit(section, walkableUnits);
1709
+ if (!unit) {
1710
+ console.warn(`[venue-js] Section ${section.id} on level ${section?.properties?.level_id} has no walkable containing unit \u2014 section will be excluded from routing.`);
1711
+ return null;
1712
+ }
1713
+ return unit.id;
1714
+ },
1715
+ unitOpenings
1716
+ );
1717
+ const kioskNodeMap = createPoiToWalkwayOpeningNodeMap(kiosks, (kiosk) => findContainingUnit(kiosk, walkwayUnits)?.id || null, unitOpenings);
1718
+ const poiOnWalkways = import_lodash19.default.mergeWith({}, unitKiosks, unitAmenities, (objValue = [], srcValue = []) => objValue.concat(srcValue));
1719
+ const walkwayNodeMap = createWalkwayNodeMap(poiOnWalkways);
1720
+ const unitNodeMap = createPoiToWalkwayOpeningNodeMap(units, (unit) => unit.id, unitOpenings);
1562
1721
  const occupantNodeMap = createOccupantNodeMap(occupants);
1563
1722
  const defaultGraph = new import_node_dijkstra.default(mergeNodeMap([
1564
1723
  traversalNodeMap,
@@ -1568,7 +1727,9 @@ var prepareGraph = (options) => {
1568
1727
  stairNodeMap,
1569
1728
  amenityNodeMap,
1570
1729
  anchorsNodeMap,
1730
+ sectionNodeMap,
1571
1731
  kioskNodeMap,
1732
+ walkwayNodeMap,
1572
1733
  unitNodeMap,
1573
1734
  occupantNodeMap
1574
1735
  ]));
@@ -1578,7 +1739,9 @@ var prepareGraph = (options) => {
1578
1739
  elevatorNodeMap,
1579
1740
  amenityNodeMap,
1580
1741
  anchorsNodeMap,
1742
+ sectionNodeMap,
1581
1743
  kioskNodeMap,
1744
+ walkwayNodeMap,
1582
1745
  unitNodeMap,
1583
1746
  occupantNodeMap
1584
1747
  ]));
@@ -1589,8 +1752,8 @@ var prepareGraph = (options) => {
1589
1752
  const kiosks2 = unitKiosks[locatedOnUnit.id] ?? [];
1590
1753
  const routingGraphs = [accessibleGraph, defaultGraph];
1591
1754
  for (const opening of openings2) {
1592
- const openingCenter = (0, import_center5.center)(opening);
1593
- const dis = (0, import_distance4.distance)([lng, lat], openingCenter, { units: "meters" });
1755
+ const openingCenter = (0, import_center8.center)(opening);
1756
+ const dis = (0, import_distance5.distance)([lng, lat], openingCenter, { units: "meters" });
1594
1757
  for (const routingGraph of routingGraphs) {
1595
1758
  const updatedCoordsNodeGraph = routingGraph?.graph?.get(params) ?? /* @__PURE__ */ new Map();
1596
1759
  updatedCoordsNodeGraph.set(opening.id, dis);
@@ -1600,8 +1763,8 @@ var prepareGraph = (options) => {
1600
1763
  }
1601
1764
  }
1602
1765
  for (const kiosk of kiosks2) {
1603
- const kioskCenter = (0, import_center5.center)(kiosk);
1604
- const dis = (0, import_distance4.distance)([lng, lat], kioskCenter, { units: "meters" });
1766
+ const kioskCenter = (0, import_center8.center)(kiosk);
1767
+ const dis = (0, import_distance5.distance)([lng, lat], kioskCenter, { units: "meters" });
1605
1768
  for (const routingGraph of routingGraphs) {
1606
1769
  const updatedCoordsNodeGraph = routingGraph?.graph?.get(params) ?? /* @__PURE__ */ new Map();
1607
1770
  updatedCoordsNodeGraph.set(kiosk.id, dis);
@@ -1619,16 +1782,16 @@ var prepareGraph = (options) => {
1619
1782
  var import_length = __toESM(require("@turf/length"));
1620
1783
  var WALKING_SPEED = 1.4;
1621
1784
  var calculatePathLength = (feature3) => (0, import_length.default)(feature3, { units: "kilometers" }) * 1e3;
1622
- var calculateTravelingDuration = (distance6) => {
1623
- const duration = distance6 / WALKING_SPEED;
1785
+ var calculateTravelingDuration = (distance7) => {
1786
+ const duration = distance7 / WALKING_SPEED;
1624
1787
  const minutes = Math.round(duration / 60);
1625
1788
  return minutes > 0 ? minutes : 1;
1626
1789
  };
1627
1790
  var calculateTotalDistance = (steps = []) => {
1628
1791
  return steps.reduce((acc, { path }) => acc + calculatePathLength(lineString(path)), 0);
1629
1792
  };
1630
- var calculateRoundedDistance = (distance6) => {
1631
- return Math.round(distance6 - distance6 % 25);
1793
+ var calculateRoundedDistance = (distance7) => {
1794
+ return Math.round(distance7 - distance7 % 25);
1632
1795
  };
1633
1796
 
1634
1797
  // src/data/navigate/type-guard.ts
@@ -1637,7 +1800,7 @@ function isCoordinateOrdinalString(id) {
1637
1800
  }
1638
1801
 
1639
1802
  // src/data/navigate/services/waypoint/createWaypointService.ts
1640
- var import_center6 = require("@turf/center");
1803
+ var import_center9 = require("@turf/center");
1641
1804
 
1642
1805
  // src/data/navigate/services/waypoint/extractEndWaypoint.ts
1643
1806
  var import_point_on_feature2 = __toESM(require("@turf/point-on-feature"));
@@ -1648,6 +1811,7 @@ var isUnit = (id) => !!id && id.startsWith("unit-");
1648
1811
  var isKiosk = (id) => !!id && id.startsWith("kiosk-");
1649
1812
  var isOpening = (id) => !!id && id.startsWith("opening-");
1650
1813
  var isAmenity = (id) => !!id && id.startsWith("amenity-");
1814
+ var isSection = (id) => !!id && id.startsWith("section-");
1651
1815
 
1652
1816
  // src/data/navigate/services/waypoint/extractEndWaypoint.ts
1653
1817
  var extractEndPoint = (path, ctx) => {
@@ -1720,6 +1884,22 @@ var extractEndPoint = (path, ctx) => {
1720
1884
  path.slice(0, -1)
1721
1885
  ];
1722
1886
  }
1887
+ if (isSection(a) && isOpening(b)) {
1888
+ const section = findByIdSync(a);
1889
+ const level = findByIdSync(section.properties.level_id);
1890
+ return [
1891
+ {
1892
+ id: a,
1893
+ type: "end",
1894
+ name: section.properties.name,
1895
+ point: (0, import_point_on_feature2.default)(section).geometry.coordinates,
1896
+ levelId: section.properties.level_id,
1897
+ ordinal: level.properties.ordinal,
1898
+ source: { type: "section", id: a }
1899
+ },
1900
+ path.slice(0, -1)
1901
+ ];
1902
+ }
1723
1903
  if (isUnit(a) && isOpening(b)) {
1724
1904
  const unit = findByIdSync(a);
1725
1905
  const opening = findByIdSync(b);
@@ -1846,6 +2026,22 @@ var extractStartPoint = (path, ctx) => {
1846
2026
  path.slice(1)
1847
2027
  ];
1848
2028
  }
2029
+ if (isSection(a) && isOpening(b)) {
2030
+ const section = findByIdSync(a);
2031
+ const level = findByIdSync(section.properties.level_id);
2032
+ return [
2033
+ {
2034
+ id: a,
2035
+ type: "start",
2036
+ name: section.properties.name,
2037
+ point: (0, import_point_on_feature3.default)(section).geometry.coordinates,
2038
+ levelId: section.properties.level_id,
2039
+ ordinal: level.properties.ordinal,
2040
+ source: { type: "section", id: a }
2041
+ },
2042
+ path.slice(1)
2043
+ ];
2044
+ }
1849
2045
  if (isUnit(a) && isOpening(b)) {
1850
2046
  const unit = findByIdSync(a);
1851
2047
  const opening = findByIdSync(b);
@@ -1907,7 +2103,7 @@ var createWaypointService = (ctx) => {
1907
2103
  const waypoints = middlePoints.map((openingId) => {
1908
2104
  const opening = findByIdSync(openingId);
1909
2105
  const level = findByIdSync(opening.properties.level_id);
1910
- const coordinates = (0, import_center6.center)(opening).geometry.coordinates;
2106
+ const coordinates = (0, import_center9.center)(opening).geometry.coordinates;
1911
2107
  return {
1912
2108
  id: `${opening.properties.level_id}:${openingId}`,
1913
2109
  type: "between",
@@ -1915,6 +2111,7 @@ var createWaypointService = (ctx) => {
1915
2111
  name: null,
1916
2112
  levelId: opening.properties.level_id,
1917
2113
  ordinal: level.properties.ordinal,
2114
+ checkpoint: opening.properties.category === "pedestrian.principal",
1918
2115
  source: { type: "opening", id: opening.id }
1919
2116
  };
1920
2117
  });
@@ -1924,53 +2121,12 @@ var createWaypointService = (ctx) => {
1924
2121
  };
1925
2122
 
1926
2123
  // src/data/navigate/services/instructions/createInstructionService.ts
1927
- var import_distance6 = require("@turf/distance");
2124
+ var import_distance7 = require("@turf/distance");
1928
2125
  var import_rhumb_bearing3 = require("@turf/rhumb-bearing");
1929
2126
 
1930
- // src/data/navigate/constants.ts
1931
- var OBSTACLE_FEATURE_TYPES = [
1932
- "kiosk"
1933
- /* , "fixture" */
1934
- ];
1935
- var OBSTACLE_CATEGORIES = [
1936
- "fixture.water",
1937
- "fixture.stage",
1938
- "nonpublic",
1939
- "opentobelow",
1940
- "elevator",
1941
- "escalator",
1942
- "stairs",
1943
- "stairs.emergencyexit",
1944
- "room",
1945
- "unspecified",
1946
- "structure",
1947
- "brick",
1948
- "concrete",
1949
- "drywall",
1950
- "glass",
1951
- "wood",
1952
- "column"
1953
- ];
1954
- var WALKABLE_CATEGORY = [
1955
- "walkway",
1956
- "parking",
1957
- "room",
1958
- "terrace",
1959
- "unenclosedarea",
1960
- "vegetation",
1961
- "unspecified"
1962
- ];
1963
- var VERTICAL_TRAVERSAL_CATEGORY = [
1964
- "elevator",
1965
- "escalator",
1966
- "stairs",
1967
- "stairs.emergencyexit",
1968
- "ramp"
1969
- ];
1970
-
1971
2127
  // src/data/navigate/services/instructions/utils/outwardOpeningBearing.ts
1972
2128
  var import_rhumb_bearing2 = require("@turf/rhumb-bearing");
1973
- var import_distance5 = require("@turf/distance");
2129
+ var import_distance6 = require("@turf/distance");
1974
2130
  var outwardOpeningBearing = (openingLine, nextPoint) => {
1975
2131
  const [p1, p2] = openingLine.coordinates;
1976
2132
  const openingBearing = (0, import_rhumb_bearing2.rhumbBearing)(p1, p2);
@@ -1986,7 +2142,7 @@ var outwardOpeningBearing = (openingLine, nextPoint) => {
1986
2142
  let minDist = Infinity;
1987
2143
  for (const b of candidates) {
1988
2144
  const testPoint = rhumbDestination(openingMid, 0.5, b, { units: "meters" }).geometry.coordinates;
1989
- const d = (0, import_distance5.distance)(nextPoint, testPoint, { units: "meters" });
2145
+ const d = (0, import_distance6.distance)(nextPoint, testPoint, { units: "meters" });
1990
2146
  if (d < minDist) {
1991
2147
  minDist = d;
1992
2148
  best = b;
@@ -2085,7 +2241,7 @@ var createInstructionService = (ctx) => {
2085
2241
  if (turn === "straight") {
2086
2242
  continue;
2087
2243
  }
2088
- const distanceFromPreviousPoint = (0, import_distance6.distance)(prevPoint, thisPoint, { units: "meters" });
2244
+ const distanceFromPreviousPoint = (0, import_distance7.distance)(prevPoint, thisPoint, { units: "meters" });
2089
2245
  if (distanceFromPreviousPoint < 20 && prevInstruction && sameDirectionalTurn(prevInstruction.turn, turn)) {
2090
2246
  const prevTurnSide = turnSide(prevInstruction.turn);
2091
2247
  const extendedTurn = getTurn(prevInstruction.bearing.from, toBearing2, prevTurnSide);
@@ -2097,7 +2253,7 @@ var createInstructionService = (ctx) => {
2097
2253
  prevInstruction.bearing.delta = angleDiff(prevInstruction.bearing.from, toBearing2);
2098
2254
  prevInstruction.turn = extendedTurn;
2099
2255
  } else {
2100
- const distanceSinceLastTurn = (0, import_distance6.distance)(prevTurnPoint, thisPoint, { units: "meters" });
2256
+ const distanceSinceLastTurn = (0, import_distance7.distance)(prevTurnPoint, thisPoint, { units: "meters" });
2101
2257
  const landmark = landmarkService.findNearestLandmark(thisPoint, ordinal);
2102
2258
  const afterTurnToward2 = landmarkService.findTowardLandmark(thisPoint, nextPoint, ordinal);
2103
2259
  const instruction = {
@@ -2133,7 +2289,7 @@ var createInstructionService = (ctx) => {
2133
2289
  };
2134
2290
 
2135
2291
  // src/data/navigate/services/steps/createStepService.ts
2136
- var import_lodash19 = require("lodash");
2292
+ var import_lodash22 = require("lodash");
2137
2293
 
2138
2294
  // src/data/navigate/services/description/describe.ts
2139
2295
  var t = (template, locale, options) => {
@@ -2149,11 +2305,17 @@ var describeVerticalStep = (fromLevel, toLevel, intermediary) => {
2149
2305
  };
2150
2306
  };
2151
2307
  var describeHorizontalStep = (intermediary, toward, landmark) => {
2152
- const template = `Follow the path ${intermediary === "walkway" ? `along the walkway` : `through {{intermediary}}`} ${toward ? `toward {{toward}}` : ``} ${!toward && landmark ? `near {{landmark}}` : ``}`.trim();
2308
+ const segments = [
2309
+ // fallback: skip "through" segment if intermediary is null/empty
2310
+ intermediary === "walkway" ? "along the walkway" : intermediary ? "through {{intermediary}}" : null,
2311
+ toward ? "toward {{toward}}" : null,
2312
+ !toward && landmark ? "near {{landmark}}" : null
2313
+ ].filter(Boolean);
2314
+ const template = `Follow the path ${segments.join(" ")}`;
2153
2315
  return {
2154
2316
  text: t(template, "en", { intermediary, toward, landmark }),
2155
2317
  template,
2156
- options: { toward, landmark }
2318
+ options: { intermediary, toward, landmark }
2157
2319
  };
2158
2320
  };
2159
2321
  var describeLastStep = () => {
@@ -2163,11 +2325,11 @@ var describeLastStep = () => {
2163
2325
  };
2164
2326
 
2165
2327
  // src/data/navigate/services/walkablepath/createWalkablePathUtils.ts
2166
- var import_lodash18 = __toESM(require("lodash"));
2328
+ var import_lodash21 = __toESM(require("lodash"));
2167
2329
  var import_invariant3 = require("@turf/invariant");
2330
+ var import_buffer = require("@turf/buffer");
2168
2331
  var import_difference = __toESM(require("@turf/difference"));
2169
2332
  var import_envelope = __toESM(require("@turf/envelope"));
2170
- var import_boolean_overlap = __toESM(require("@turf/boolean-overlap"));
2171
2333
  var import_boolean_intersects = __toESM(require("@turf/boolean-intersects"));
2172
2334
 
2173
2335
  // ../../node_modules/@turf/meta/dist/esm/index.js
@@ -2293,15 +2455,15 @@ function bbox(geojson, options = {}) {
2293
2455
  var index_default = bbox;
2294
2456
 
2295
2457
  // src/data/navigate/services/walkablepath/turf-shortest-path/v6.5.0/shortestPath.ts
2296
- var import_boolean_point_in_polygon3 = __toESM(require("@turf/boolean-point-in-polygon"));
2297
- var import_distance7 = __toESM(require("@turf/distance"));
2458
+ var import_boolean_point_in_polygon4 = __toESM(require("@turf/boolean-point-in-polygon"));
2459
+ var import_distance8 = __toESM(require("@turf/distance"));
2298
2460
  var import_transform_scale = __toESM(require("@turf/transform-scale"));
2299
2461
  var import_union = __toESM(require("@turf/union"));
2300
2462
  var import_bbox_polygon = __toESM(require("@turf/bbox-polygon"));
2301
2463
  var import_clean_coords = require("@turf/clean-coords");
2302
2464
  var import_invariant2 = require("@turf/invariant");
2303
2465
  var import_pathfinding = __toESM(require("pathfinding"));
2304
- var import_lodash17 = require("lodash");
2466
+ var import_lodash20 = require("lodash");
2305
2467
 
2306
2468
  // src/data/navigate/services/walkablepath/turf-shortest-path/utils/stringPull.ts
2307
2469
  function stringPull(grid, path) {
@@ -2356,39 +2518,6 @@ function stringPull(grid, path) {
2356
2518
  return out;
2357
2519
  }
2358
2520
 
2359
- // src/data/navigate/services/walkablepath/turf-shortest-path/utils/pruneSmallAngle.ts
2360
- function pruneSmallAngles(path, minDeg = 10) {
2361
- if (path.length <= 2) return path;
2362
- const out = [path[0]];
2363
- for (let i = 1; i < path.length - 1; i++) {
2364
- const a = out.at(-1);
2365
- const b = path[i];
2366
- const c = path[i + 1];
2367
- const abx = b[0] - a[0], aby = b[1] - a[1];
2368
- const bcx = c[0] - b[0], bcy = c[1] - b[1];
2369
- const dot = abx * bcx + aby * bcy;
2370
- const ab = Math.hypot(abx, aby);
2371
- const bc = Math.hypot(bcx, bcy);
2372
- const angle = Math.acos(dot / (ab * bc)) * 180 / Math.PI;
2373
- if (angle > minDeg) out.push(b);
2374
- }
2375
- out.push(path.at(-1));
2376
- return out;
2377
- }
2378
-
2379
- // src/data/navigate/services/walkablepath/turf-shortest-path/utils/pruneShortSegments.ts
2380
- function pruneShortSegments(path, minLen = 2) {
2381
- const out = [path[0]];
2382
- for (let i = 1; i < path.length; i++) {
2383
- const [x0, y0] = out.at(-1);
2384
- const [x1, y1] = path[i];
2385
- if (Math.hypot(x1 - x0, y1 - y0) >= minLen) {
2386
- out.push(path[i]);
2387
- }
2388
- }
2389
- return out;
2390
- }
2391
-
2392
2521
  // src/data/navigate/services/walkablepath/turf-shortest-path/utils/clearance.ts
2393
2522
  function buildClearanceGrid(matrix) {
2394
2523
  const h = matrix.length;
@@ -2440,7 +2569,7 @@ function snapPointToClearancePeak(p, clearance, isWalkableCell, radius = 4) {
2440
2569
  const y = py + dy;
2441
2570
  if (!isWalkableCell(x, y)) continue;
2442
2571
  const score = clearance[y][x];
2443
- const penalty = Math.hypot(dx, dy) * 5e-3;
2572
+ const penalty = Math.hypot(dx, dy) * 0.5;
2444
2573
  const finalScore = score - penalty;
2445
2574
  if (finalScore > bestScore) {
2446
2575
  bestScore = finalScore;
@@ -2450,8 +2579,8 @@ function snapPointToClearancePeak(p, clearance, isWalkableCell, radius = 4) {
2450
2579
  }
2451
2580
  return best;
2452
2581
  }
2453
- function centerlineSnapPath(path, clearance, isWalkableCell, radius = 4) {
2454
- const snapped = path.map((p) => snapPointToClearancePeak(p, clearance, isWalkableCell, radius));
2582
+ function centerlineSnapPath(path, clearanceGrid, isWalkableCell, radius = 4) {
2583
+ const snapped = path.map((p) => snapPointToClearancePeak(p, clearanceGrid, isWalkableCell, radius));
2455
2584
  return snapped;
2456
2585
  }
2457
2586
 
@@ -2463,19 +2592,19 @@ function shortestPath(start, end, options) {
2463
2592
  let obstacles = options.obstacles || featureCollection([]);
2464
2593
  if (!start) throw new Error("start is required");
2465
2594
  if (!end) throw new Error("end is required");
2466
- if (resolution && !isNumber2(resolution) || resolution <= 0)
2595
+ if (resolution && !isNumber(resolution) || resolution <= 0)
2467
2596
  throw new Error("options.resolution must be a number, greater than 0");
2468
2597
  const startCoord = (0, import_invariant2.getCoord)(start);
2469
2598
  const endCoord = (0, import_invariant2.getCoord)(end);
2470
- start = point2(startCoord);
2471
- end = point2(endCoord);
2599
+ start = point(startCoord);
2600
+ end = point(endCoord);
2472
2601
  switch ((0, import_invariant2.getType)(obstacles)) {
2473
2602
  case "FeatureCollection":
2474
2603
  if (obstacles.features.length === 0)
2475
2604
  return lineString([startCoord, endCoord]);
2476
2605
  break;
2477
2606
  case "Polygon":
2478
- obstacles = featureCollection([feature2((0, import_invariant2.getGeom)(obstacles))]);
2607
+ obstacles = featureCollection([feature((0, import_invariant2.getGeom)(obstacles))]);
2479
2608
  break;
2480
2609
  default:
2481
2610
  throw new Error("invalid obstacles");
@@ -2484,15 +2613,15 @@ function shortestPath(start, end, options) {
2484
2613
  collection.features.push(start, end);
2485
2614
  const box = index_default((0, import_transform_scale.default)((0, import_bbox_polygon.default)(index_default(collection)), 1.15));
2486
2615
  if (!resolution) {
2487
- const width = (0, import_distance7.default)([box[0], box[1]], [box[2], box[1]], options);
2616
+ const width = (0, import_distance8.default)([box[0], box[1]], [box[2], box[1]], options);
2488
2617
  resolution = width / 100;
2489
2618
  }
2490
2619
  collection.features.pop();
2491
2620
  collection.features.pop();
2492
2621
  const [west, south, east, north] = box;
2493
- const xFraction = resolution / (0, import_distance7.default)([west, south], [east, south], options);
2622
+ const xFraction = resolution / (0, import_distance8.default)([west, south], [east, south], options);
2494
2623
  const cellWidth = xFraction * (east - west);
2495
- const yFraction = resolution / (0, import_distance7.default)([west, south], [west, north], options);
2624
+ const yFraction = resolution / (0, import_distance8.default)([west, south], [west, north], options);
2496
2625
  const cellHeight = yFraction * (north - south);
2497
2626
  const bboxHorizontalSide = east - west;
2498
2627
  const bboxVerticalSide = north - south;
@@ -2522,16 +2651,16 @@ function shortestPath(start, end, options) {
2522
2651
  }
2523
2652
  }
2524
2653
  while (totalRounds--) {
2525
- pt = point2([currentX, currentY]);
2526
- isInsideObstacle = (0, import_boolean_point_in_polygon3.default)(pt, combinedObstacle);
2527
- (0, import_lodash17.set)(matrix, `[${row}][${column}]`, isInsideObstacle ? 1 : 0);
2528
- (0, import_lodash17.set)(pointMatrix, `[${row}][${column}]`, `${currentX}|${currentY}`);
2529
- distStart = (0, import_distance7.default)(pt, start);
2654
+ pt = point([currentX, currentY]);
2655
+ isInsideObstacle = (0, import_boolean_point_in_polygon4.default)(pt, combinedObstacle);
2656
+ (0, import_lodash20.set)(matrix, `[${row}][${column}]`, isInsideObstacle ? 1 : 0);
2657
+ (0, import_lodash20.set)(pointMatrix, `[${row}][${column}]`, `${currentX}|${currentY}`);
2658
+ distStart = (0, import_distance8.default)(pt, start);
2530
2659
  if (!isInsideObstacle && distStart < minDistStart) {
2531
2660
  minDistStart = distStart;
2532
2661
  closestToStart = { x: column, y: row };
2533
2662
  }
2534
- distEnd = (0, import_distance7.default)(pt, end);
2663
+ distEnd = (0, import_distance8.default)(pt, end);
2535
2664
  if (!isInsideObstacle && distEnd < minDistEnd) {
2536
2665
  minDistEnd = distEnd;
2537
2666
  closestToEnd = { x: column, y: row };
@@ -2562,9 +2691,6 @@ function shortestPath(start, end, options) {
2562
2691
  const clearanceGrid = buildClearanceGrid(matrix);
2563
2692
  const isWalkable = (x, y) => grid.isInside(x, y) && grid.isWalkableAt(x, y);
2564
2693
  result = centerlineSnapPath(result, clearanceGrid, isWalkable);
2565
- result = stringPull(grid, result);
2566
- result = pruneSmallAngles(result);
2567
- result = pruneShortSegments(result);
2568
2694
  }
2569
2695
  result.pop();
2570
2696
  result.shift();
@@ -2584,8 +2710,28 @@ var createWalkablePathService = (ctx, options) => {
2584
2710
  const { units = [], kiosks = [], fixtures = [] } = ctx.data;
2585
2711
  const possibleObstacleFeatures = [...units, ...kiosks, ...fixtures];
2586
2712
  const filterObstaclesByOrdinal = (levelId) => {
2587
- return possibleObstacleFeatures.filter(({ feature_type, properties, geometry }) => {
2588
- return properties.level_id === levelId && ["Polygon", "MultiPolygon"].includes(geometry.type) && (OBSTACLE_FEATURE_TYPES.includes(feature_type) || "category" in properties && OBSTACLE_CATEGORIES.includes(properties.category));
2713
+ const OBSTACLE_FEATURETYPE_AND_CATEGORIES = [
2714
+ "fixture.vegetation",
2715
+ "fixture.water",
2716
+ "fixture.stage",
2717
+ "fixture.wall",
2718
+ "kiosk",
2719
+ "unit.nonpublic",
2720
+ "unit.opentobelow",
2721
+ "unit.elevator",
2722
+ "unit.escalator",
2723
+ "unit.stairs",
2724
+ "unit.room",
2725
+ "unit.unspecified",
2726
+ "unit.structure",
2727
+ "unit.brick",
2728
+ "unit.concrete",
2729
+ "unit.drywall",
2730
+ "unit.column"
2731
+ ];
2732
+ return possibleObstacleFeatures.filter((f) => f.properties.level_id === levelId).filter(({ feature_type, properties }) => {
2733
+ const featureTypeAndCat = `${feature_type}${"category" in properties ? `.${properties.category}` : ``}`;
2734
+ return OBSTACLE_FEATURETYPE_AND_CATEGORIES.includes(featureTypeAndCat);
2589
2735
  });
2590
2736
  };
2591
2737
  const findObstaclesFromWalkway = (intermediaryUnit, exceptionIds = []) => {
@@ -2597,13 +2743,38 @@ var createWalkablePathService = (ctx, options) => {
2597
2743
  );
2598
2744
  const relatedObstacleWithIntermediary = obstacleOnLevel.reduce(
2599
2745
  (obstacles, feature3) => {
2600
- if (
2601
- // Prevent detecting itself as an obstacle
2602
- // Ex. Unable to draw a line to amenity located with in a room as room is also consider as obstacle
2603
- feature3.id !== intermediaryUnit.id && ((0, import_boolean_overlap.default)(intermediaryUnit, feature3) || (0, import_boolean_intersects.default)(intermediaryUnit, feature3))
2604
- ) {
2605
- const polygons = (0, import_invariant3.getType)(feature3) === "Polygon" ? [polygon(feature3.geometry.coordinates, { id: feature3.id })] : feature3.geometry.coordinates.map((ring) => polygon(ring, { id: feature3.id }));
2606
- obstacles.push(...polygons);
2746
+ try {
2747
+ if (
2748
+ // Prevent detecting itself as an obstacle
2749
+ // Ex. Unable to draw a line to amenity located with in a room as room is also consider as obstacle
2750
+ feature3.id !== intermediaryUnit.id && (0, import_boolean_intersects.default)(intermediaryUnit, feature3)
2751
+ ) {
2752
+ const type = (0, import_invariant3.getType)(feature3);
2753
+ switch (type) {
2754
+ case "Polygon":
2755
+ obstacles.push(feature3);
2756
+ break;
2757
+ case "MultiPolygon": {
2758
+ feature3.geometry.coordinates.map((p) => {
2759
+ const f = polygon(p, { id: feature3.id });
2760
+ obstacles.push(f);
2761
+ });
2762
+ break;
2763
+ }
2764
+ case "LineString": {
2765
+ obstacles.push((0, import_buffer.buffer)(feature3.geometry, 0.3, { units: "meters" }));
2766
+ break;
2767
+ }
2768
+ case "MultiLineString": {
2769
+ feature3.geometry.coordinates.map((line) => {
2770
+ const f = (0, import_buffer.buffer)(lineString(line), 0.3, { units: "meters" });
2771
+ obstacles.push(f);
2772
+ });
2773
+ break;
2774
+ }
2775
+ }
2776
+ }
2777
+ } catch (e) {
2607
2778
  }
2608
2779
  return obstacles;
2609
2780
  },
@@ -2627,14 +2798,13 @@ var createWalkablePathService = (ctx, options) => {
2627
2798
  return stepPath;
2628
2799
  };
2629
2800
  const findWalkablePath = (from, to, intermediaries) => {
2630
- const t0 = performance.now();
2631
2801
  const relatedWalkablePlatform = intermediaries.find(
2632
- (feature3) => WALKABLE_CATEGORY.includes(feature3.properties.category)
2802
+ (feature3) => WALKABLE_UNIT_CATEGORY.includes(feature3.properties.category)
2633
2803
  );
2634
2804
  const exceptionFeatureIds = [];
2635
2805
  const obstacles = findObstaclesFromWalkway(
2636
2806
  relatedWalkablePlatform,
2637
- import_lodash18.default.compact(exceptionFeatureIds)
2807
+ import_lodash21.default.compact(exceptionFeatureIds)
2638
2808
  );
2639
2809
  const line = findPathOnArea(from, to, {
2640
2810
  resolution,
@@ -2649,7 +2819,7 @@ var createWalkablePathService = (ctx, options) => {
2649
2819
 
2650
2820
  // src/data/navigate/services/steps/createStepService.ts
2651
2821
  var createStepService = (ctx) => {
2652
- const { data: { units, relationships }, findByIdSync, landmarkService } = ctx;
2822
+ const { data: { units, occupants = [], relationships }, findByIdSync, landmarkService } = ctx;
2653
2823
  const walkablePathUtils = createWalkablePathService(ctx, { resolution: 88e-5 });
2654
2824
  const findUnitBetweenOpenings = (originId, destinationId) => {
2655
2825
  const origin = findByIdSync(originId);
@@ -2658,7 +2828,7 @@ var createStepService = (ctx) => {
2658
2828
  const matchOneUnits = matchedOne ? [matchedOne.properties.origin, matchedOne.properties.destination] : [];
2659
2829
  const matchedTwo = relationships.find((rel) => (rel.properties.intermediary || []).map((int) => int.id).includes(destination.id));
2660
2830
  const matchTwoUnits = matchedTwo ? [matchedTwo.properties.origin, matchedTwo.properties.destination] : [];
2661
- const unitIds = (0, import_lodash19.intersectionBy)(matchOneUnits, matchTwoUnits, "id");
2831
+ const unitIds = (0, import_lodash22.intersectionBy)(matchOneUnits, matchTwoUnits, "id");
2662
2832
  return unitIds.map(({ id }) => findByIdSync(id));
2663
2833
  };
2664
2834
  const findHorizontalIntermediary = (from, to) => {
@@ -2674,7 +2844,7 @@ var createStepService = (ctx) => {
2674
2844
  };
2675
2845
  const getAdjacentUnitsByOpening = (openingId) => {
2676
2846
  const relationship = relationships.find((rel) => (rel.properties.intermediary || []).map((int) => int.id).includes(openingId));
2677
- const units2 = (0, import_lodash19.compact)([
2847
+ const units2 = (0, import_lodash22.compact)([
2678
2848
  relationship?.properties.origin.id,
2679
2849
  relationship?.properties.destination.id
2680
2850
  ]).map((unitId) => findByIdSync(unitId));
@@ -2688,11 +2858,18 @@ var createStepService = (ctx) => {
2688
2858
  const verticalUnits = [...firstAdjacentUnits, ...secondAdjacentUnits].filter((unit) => VERTICAL_TRAVERSAL_CATEGORY.includes(unit.properties.category));
2689
2859
  return verticalUnits;
2690
2860
  };
2861
+ const findOccupantForUnit = (unit) => {
2862
+ return occupants.find(
2863
+ (o) => o.properties.main_location === unit.id || (o.properties.correlated_locations ?? []).includes(unit.id)
2864
+ );
2865
+ };
2691
2866
  const createHorizontalStep = (from, to) => {
2692
2867
  const intermediary = findHorizontalIntermediary(from, to);
2693
2868
  const intermediaryCategories = intermediary.map((unit) => unit.properties.category);
2694
- const intermediaryCategory = intermediaryCategories.length > 0 ? intermediaryCategories[0] : "unspecified";
2869
+ const intermediaryCategory = intermediaryCategories.length > 0 ? intermediaryCategories[0] ?? "unspecified" : "unspecified";
2695
2870
  const intermediaryIds = intermediary.map((unit) => unit.id);
2871
+ const occupant = intermediary[0] ? findOccupantForUnit(intermediary[0]) : void 0;
2872
+ const intermediaryName = occupant?.properties.name.en ?? intermediaryCategory;
2696
2873
  const toward = landmarkService.findTowardLandmark(from.point, to.point, to.ordinal);
2697
2874
  const nearBy = landmarkService.findNearestLandmark(to.point, to.ordinal);
2698
2875
  const path = walkablePathUtils.findWalkablePath(from.point, to.point, intermediary);
@@ -2704,9 +2881,9 @@ var createStepService = (ctx) => {
2704
2881
  intermediaryCategory,
2705
2882
  intermediaryIds,
2706
2883
  description: describeHorizontalStep(
2707
- intermediaryCategory,
2708
- toward ? toward.name : null,
2709
- nearBy ? nearBy.name : null
2884
+ intermediaryName,
2885
+ toward ? toward.name : void 0,
2886
+ nearBy ? nearBy.name : void 0
2710
2887
  ),
2711
2888
  path: path.map((coord) => [...coord, from.ordinal * 9])
2712
2889
  };
@@ -2782,7 +2959,7 @@ var mergeStepsByOrdinal = (steps) => {
2782
2959
  let current = steps[0];
2783
2960
  for (let i = 1; i < steps.length; i++) {
2784
2961
  const next = steps[i];
2785
- if (arrayEqual(current.ordinals, next.ordinals)) {
2962
+ if (arrayEqual(current.ordinals, next.ordinals) && !current.to.checkpoint) {
2786
2963
  current = mergeTwoSteps(current, next);
2787
2964
  } else {
2788
2965
  out.push(current);
@@ -2810,7 +2987,7 @@ var getNavigateClient = (options) => {
2810
2987
  const findCoordinateOrdinalLocatedUnit = (params, sourceUnits = units) => {
2811
2988
  const [lng, lat, ordinal] = parseOrdinalCoordinate(params);
2812
2989
  const levelIdsWithOrdinal = levels.filter((level) => level.properties.ordinal === ordinal).map((level) => level.id);
2813
- const unit = sourceUnits.find((unit2) => levelIdsWithOrdinal.includes(unit2.properties.level_id) && (0, import_boolean_point_in_polygon4.booleanPointInPolygon)([lng, lat], unit2));
2990
+ const unit = sourceUnits.find((unit2) => levelIdsWithOrdinal.includes(unit2.properties.level_id) && (0, import_boolean_point_in_polygon5.booleanPointInPolygon)([lng, lat], unit2));
2814
2991
  return unit;
2815
2992
  };
2816
2993
  const findRoute = async (routeOriginParam, routeDestinationParam, options2) => {
@@ -2912,6 +3089,13 @@ var getSearchClient = ({ occupants, amenities }) => {
2912
3089
  };
2913
3090
 
2914
3091
  // src/data/getDataClient.ts
3092
+ var resolveFeatureTypeFromId = (id) => {
3093
+ if (id === null || id === void 0) return null;
3094
+ const featureType = id.split("-")[0];
3095
+ const override = ID_PREFIX_TO_FEATURE_TYPE[featureType];
3096
+ if (override) return override;
3097
+ return featureType || null;
3098
+ };
2915
3099
  var getDataClient = (options) => {
2916
3100
  let searchClient;
2917
3101
  let navigateClient;
@@ -2944,7 +3128,11 @@ var getDataClient = (options) => {
2944
3128
  };
2945
3129
  const internalFindById = async (id) => {
2946
3130
  if (id === null || id === void 0) return null;
2947
- const featureType = id.slice(0, id.lastIndexOf("-"));
3131
+ const featureType = resolveFeatureTypeFromId(id);
3132
+ if (!featureType) {
3133
+ console.warn(`[venue-js] Cannot resolve feature type from id "${id}"`);
3134
+ return null;
3135
+ }
2948
3136
  const feature3 = await queryClient.ensureQueryData({
2949
3137
  queryKey: ["_deliveryapi", featureType, id],
2950
3138
  queryFn: async () => {
@@ -2959,20 +3147,28 @@ var getDataClient = (options) => {
2959
3147
  };
2960
3148
  const populator = createPopulator({ internalFindById, internalFilterByType });
2961
3149
  const registerObserver = (featureType, refetchInterval) => {
2962
- if (observers.has(featureType)) {
2963
- console.warn(`Observer for ${featureType} already exists`);
2964
- const record = observers.get(featureType);
2965
- return record.observer;
3150
+ const existing = observers.get(featureType);
3151
+ if (existing) {
3152
+ if (refetchInterval === existing.refetchInterval) {
3153
+ return existing.observer;
3154
+ } else if (refetchInterval > existing.refetchInterval) {
3155
+ console.warn(`[venue-js] Observer for "${featureType}" not registered \u2014 existing observer already uses a smaller interval (${existing.refetchInterval}ms < ${refetchInterval}ms)`);
3156
+ return existing.observer;
3157
+ } else if (refetchInterval < existing.refetchInterval) {
3158
+ console.warn(`[venue-js] Observer for "${featureType}" re-registering with smaller interval (${refetchInterval}ms < ${existing.refetchInterval}ms)`);
3159
+ existing.unsubscribe();
3160
+ observers.delete(featureType);
3161
+ }
2966
3162
  }
2967
3163
  const options2 = createDeliveryApiQueryOptions(featureType);
2968
3164
  const observer = new import_query_core.QueryObserver(queryClient, {
2969
3165
  ...options2,
2970
3166
  refetchInterval
2971
3167
  });
3168
+ console.log(`[venue-js] Listening to ${featureType} changes (interval = ${refetchInterval}ms)`);
2972
3169
  const unsubscribe = observer.subscribe(() => {
2973
- console.log(`[venue-js] Listening to ${featureType} changes (interval = ${refetchInterval}ms)`);
2974
3170
  });
2975
- observers.set(featureType, { observer, unsubscribe });
3171
+ observers.set(featureType, { observer, unsubscribe, refetchInterval });
2976
3172
  return observer;
2977
3173
  };
2978
3174
  const destroyObserver = (featureType) => {
@@ -3039,7 +3235,7 @@ var getDataClient = (options) => {
3039
3235
  };
3040
3236
  const navigateFn = async (origin, destination, options2) => {
3041
3237
  if (!navigateClient) {
3042
- const [levels, occupants, openings, relationships, units, fixtures, kiosks, amenities, anchors] = await Promise.all([
3238
+ const [levels, occupants, openings, relationships, units, fixtures, kiosks, amenities, anchors, sections] = await Promise.all([
3043
3239
  filterByType("level"),
3044
3240
  filterByType("occupant"),
3045
3241
  filterByType("opening"),
@@ -3048,9 +3244,10 @@ var getDataClient = (options) => {
3048
3244
  filterByType("fixture"),
3049
3245
  filterByType("kiosk"),
3050
3246
  filterByType("amenity"),
3051
- filterByType("anchor")
3247
+ filterByType("anchor"),
3248
+ filterByType("section")
3052
3249
  ]);
3053
- const haystack = { levels, occupants, openings, relationships, units, fixtures, kiosks, amenities, anchors };
3250
+ const haystack = { levels, occupants, openings, relationships, units, fixtures, kiosks, amenities, anchors, sections };
3054
3251
  navigateClient = getNavigateClient({ data: haystack, unitDistanceOptions: options2?.unitDistanceOptions });
3055
3252
  }
3056
3253
  return navigateClient.findRoute(origin, destination, options2);
@@ -3075,6 +3272,7 @@ var getDataClient = (options) => {
3075
3272
  ALL_FEATURE_TYPES,
3076
3273
  DEFAULT_BASE_URL,
3077
3274
  GEOJSON_FEATURE_TYPES,
3275
+ ID_PREFIX_TO_FEATURE_TYPE,
3078
3276
  IMDF_FEATURE_TYPES,
3079
3277
  IMDF_UNIT_CATEGORIES,
3080
3278
  NONIMDF_FEATURE_TYPES,
@@ -3101,6 +3299,7 @@ var getDataClient = (options) => {
3101
3299
  getDataClient,
3102
3300
  getInstructionText,
3103
3301
  getNavigateClient,
3302
+ getPointOnFeature,
3104
3303
  getSearchClient,
3105
3304
  getTurn,
3106
3305
  matchFilter,