venue-js 1.4.0-next.17 → 1.4.0-next.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,8 @@
1
+ var __create = Object.create;
1
2
  var __defProp = Object.defineProperty;
2
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
4
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
7
  var __export = (target, all) => {
6
8
  for (var name in all)
@@ -14,6 +16,14 @@ var __copyProps = (to, from, except, desc) => {
14
16
  }
15
17
  return to;
16
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
+ ));
17
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
28
 
19
29
  // src/data/index.ts
@@ -312,8 +322,8 @@ var safeFetchFeature = async (featureType, params) => {
312
322
  };
313
323
 
314
324
  // src/data/utils/geometry-validator.ts
315
- var isValidCoordinate = (point) => {
316
- return point.length === 2 && point.every((coord) => typeof coord === "number");
325
+ var isValidCoordinate = (point2) => {
326
+ return point2.length === 2 && point2.every((coord) => typeof coord === "number");
317
327
  };
318
328
  function isValidLinearRingCoordinates(ring) {
319
329
  if (ring.length < 4) {
@@ -321,16 +331,16 @@ function isValidLinearRingCoordinates(ring) {
321
331
  }
322
332
  return ring.every(isValidCoordinate) && ring[0][0] === ring[ring.length - 1][0] && ring[0][1] === ring[ring.length - 1][1];
323
333
  }
324
- var isValidPolygonCoordinates = (polygon) => {
325
- if (Array.isArray(polygon[0]) && (polygon[0].length === 0 || typeof polygon[0][0] === "number")) {
326
- return isValidLinearRingCoordinates(polygon);
334
+ var isValidPolygonCoordinates = (polygon2) => {
335
+ if (Array.isArray(polygon2[0]) && (polygon2[0].length === 0 || typeof polygon2[0][0] === "number")) {
336
+ return isValidLinearRingCoordinates(polygon2);
327
337
  }
328
- if (Array.isArray(polygon) && polygon.length > 0 && Array.isArray(polygon[0])) {
329
- if (!isValidLinearRingCoordinates(polygon[0])) {
338
+ if (Array.isArray(polygon2) && polygon2.length > 0 && Array.isArray(polygon2[0])) {
339
+ if (!isValidLinearRingCoordinates(polygon2[0])) {
330
340
  return false;
331
341
  }
332
- for (let i = 1; i < polygon.length; i++) {
333
- if (!isValidLinearRingCoordinates(polygon[i])) {
342
+ for (let i = 1; i < polygon2.length; i++) {
343
+ if (!isValidLinearRingCoordinates(polygon2[i])) {
334
344
  return false;
335
345
  }
336
346
  }
@@ -341,16 +351,16 @@ var isValidPolygonCoordinates = (polygon) => {
341
351
  var isValidMultiPolygonCoordinates = (multipolygon) => {
342
352
  return multipolygon.every(isValidPolygonCoordinates);
343
353
  };
344
- var isValidLineStringCoordinates = (lineString) => {
345
- if (!Array.isArray(lineString) || lineString.length < 2) {
354
+ var isValidLineStringCoordinates = (lineString2) => {
355
+ if (!Array.isArray(lineString2) || lineString2.length < 2) {
346
356
  return false;
347
357
  }
348
- const firstPoint = lineString[0];
349
- const lastPoint = lineString[lineString.length - 1];
358
+ const firstPoint = lineString2[0];
359
+ const lastPoint = lineString2[lineString2.length - 1];
350
360
  if (firstPoint[0] === lastPoint[0] && firstPoint[1] === lastPoint[1]) {
351
361
  return false;
352
362
  }
353
- return lineString.every(isValidCoordinate);
363
+ return lineString2.every(isValidCoordinate);
354
364
  };
355
365
  var isValidMultiPolygon = (geometry) => {
356
366
  const { type, coordinates } = geometry;
@@ -447,6 +457,19 @@ var findContainingUnit = (poi, units) => {
447
457
  );
448
458
  return unit;
449
459
  };
460
+ var findContainingUnitAtPoint = (point2, levelId, units) => {
461
+ const unit = units.find(
462
+ (unit2) => {
463
+ try {
464
+ return unit2.properties.level_id === levelId && (0, import_boolean_point_in_polygon.booleanPointInPolygon)(point2, unit2);
465
+ } catch (e) {
466
+ console.log(`Cannot find containing unit of (point: ${point2}, levelId: ${levelId}):`, e.message);
467
+ return false;
468
+ }
469
+ }
470
+ );
471
+ return unit;
472
+ };
450
473
 
451
474
  // src/data/populator/index.ts
452
475
  var createPopulator = ({
@@ -619,6 +642,19 @@ var createPopulator = ({
619
642
  }
620
643
  };
621
644
  };
645
+ const populateSection = async (section) => {
646
+ const venue = await internalFindById(section.properties.venue_id);
647
+ const level = await internalFindById(section.properties.level_id);
648
+ return {
649
+ ...section,
650
+ properties: {
651
+ ...section.properties,
652
+ venue,
653
+ level: await populateLevel(level),
654
+ ordinal: level.properties.ordinal
655
+ }
656
+ };
657
+ };
622
658
  const populateRelationship = async (relationship) => {
623
659
  const originId = relationship.properties.origin?.id;
624
660
  const destinationId = relationship.properties.destination?.id;
@@ -636,19 +672,6 @@ var createPopulator = ({
636
672
  }
637
673
  };
638
674
  };
639
- const populateSection = async (section) => {
640
- const venue = await internalFindById(section.properties.venue_id);
641
- const level = await internalFindById(section.properties.level_id);
642
- return {
643
- ...section,
644
- properties: {
645
- ...section.properties,
646
- venue,
647
- level: await populateLevel(level),
648
- ordinal: level.properties.ordinal
649
- }
650
- };
651
- };
652
675
  const populateUnit = async (unit) => {
653
676
  const venue = await internalFindById(unit.properties.venue_id);
654
677
  const level = await internalFindById(unit.properties.level_id);
@@ -696,7 +719,7 @@ var createPopulator = ({
696
719
  console.log(`error finding level`, { model3d, level });
697
720
  }
698
721
  };
699
- const populateFeature = (feature) => Promise.resolve(feature);
722
+ const populateFeature = (feature2) => Promise.resolve(feature2);
700
723
  return {
701
724
  address: populateAddress,
702
725
  building: populateBuilding,
@@ -725,1366 +748,1642 @@ var createPopulator = ({
725
748
  };
726
749
  };
727
750
 
728
- // ../../node_modules/fuse.js/dist/fuse.mjs
729
- function isArray(value) {
730
- return !Array.isArray ? getTag(value) === "[object Array]" : Array.isArray(value);
731
- }
732
- var INFINITY = 1 / 0;
733
- function baseToString(value) {
734
- if (typeof value == "string") {
735
- return value;
736
- }
737
- let result = value + "";
738
- return result == "0" && 1 / value == -INFINITY ? "-0" : result;
739
- }
740
- function toString(value) {
741
- return value == null ? "" : baseToString(value);
742
- }
743
- function isString(value) {
744
- return typeof value === "string";
745
- }
746
- function isNumber(value) {
747
- return typeof value === "number";
748
- }
749
- function isBoolean(value) {
750
- return value === true || value === false || isObjectLike(value) && getTag(value) == "[object Boolean]";
751
- }
752
- function isObject(value) {
753
- return typeof value === "object";
754
- }
755
- function isObjectLike(value) {
756
- return isObject(value) && value !== null;
757
- }
758
- function isDefined(value) {
759
- return value !== void 0 && value !== null;
760
- }
761
- function isBlank(value) {
762
- return !value.trim().length;
763
- }
764
- function getTag(value) {
765
- return value == null ? value === void 0 ? "[object Undefined]" : "[object Null]" : Object.prototype.toString.call(value);
766
- }
767
- var INCORRECT_INDEX_TYPE = "Incorrect 'index' type";
768
- var LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = (key) => `Invalid value for key ${key}`;
769
- var PATTERN_LENGTH_TOO_LARGE = (max) => `Pattern length exceeds max of ${max}.`;
770
- var MISSING_KEY_PROPERTY = (name) => `Missing ${name} property in key`;
771
- var INVALID_KEY_WEIGHT_VALUE = (key) => `Property 'weight' in key '${key}' must be a positive integer`;
772
- var hasOwn = Object.prototype.hasOwnProperty;
773
- var KeyStore = class {
774
- constructor(keys) {
775
- this._keys = [];
776
- this._keyMap = {};
777
- let totalWeight = 0;
778
- keys.forEach((key) => {
779
- let obj = createKey(key);
780
- this._keys.push(obj);
781
- this._keyMap[obj.id] = obj;
782
- totalWeight += obj.weight;
783
- });
784
- this._keys.forEach((key) => {
785
- key.weight /= totalWeight;
786
- });
787
- }
788
- get(keyId) {
789
- return this._keyMap[keyId];
790
- }
791
- keys() {
792
- return this._keys;
793
- }
794
- toJSON() {
795
- return JSON.stringify(this._keys);
751
+ // src/data/search/getSearchClient.ts
752
+ var import_fuse = __toESM(require("fuse.js"));
753
+
754
+ // src/data/search/utils/sanitizeInput.ts
755
+ var sanitizeInput = (str) => str.replace(/[\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, "").replace(/[\-–—_./()]+/g, "").normalize("NFC").trim();
756
+
757
+ // src/data/search/getSearchClient.ts
758
+ var getSearchClient = ({ occupants, amenities }) => {
759
+ const fuseAmenities = new import_fuse.default(amenities, {
760
+ threshold: 0.2,
761
+ keys: [
762
+ { name: "properties.name", "weight": 1, getFn: (obj) => Object.values(obj.properties.name || {}) },
763
+ { name: "properties.category", "weight": 1 }
764
+ ]
765
+ });
766
+ const fuseOccupants = new import_fuse.default(occupants, {
767
+ threshold: 0.25,
768
+ // 0.2 is too strict (can't find Mo-Mo Paradise with "momo" search string)
769
+ includeScore: true,
770
+ shouldSort: true,
771
+ keys: [
772
+ { name: "properties.name", "weight": 4, getFn: (obj) => Object.values(obj.properties.name || {}) },
773
+ { name: "properties.keywords", "weight": 0.5 },
774
+ { name: "properties.category", "weight": 0.25 },
775
+ { name: "properties.local_category_names", "weight": 0.25 },
776
+ { name: "properties.description", "weight": 0.25, getFn: (occ) => Object.values(occ.properties.description || {}) },
777
+ { name: "properties.unit_name", "weight": 0.25 },
778
+ { name: "properties.kiosk_name", "weight": 0.25 }
779
+ ]
780
+ });
781
+ const search = (value) => {
782
+ const sanitizedValue = sanitizeInput(value);
783
+ const matchedAmenities = fuseAmenities.search(sanitizedValue);
784
+ const matchedOccupants = fuseOccupants.search(sanitizedValue);
785
+ return [...matchedAmenities, ...matchedOccupants];
786
+ };
787
+ return {
788
+ search
789
+ };
790
+ };
791
+
792
+ // src/data/navigate/getNavigateClient.ts
793
+ var import_boolean_point_in_polygon4 = require("@turf/boolean-point-in-polygon");
794
+
795
+ // src/data/navigate/graph/prepare.ts
796
+ var import_lodash10 = __toESM(require("lodash"));
797
+ var import_node_dijkstra = __toESM(require("node-dijkstra"));
798
+ var import_distance3 = require("@turf/distance");
799
+ var import_center5 = require("@turf/center");
800
+
801
+ // src/data/navigate/graph/nodemap/createTraversalNodeMap.ts
802
+ var import_distance = require("@turf/distance");
803
+ var import_center3 = require("@turf/center");
804
+ var import_lodash3 = __toESM(require("lodash"));
805
+
806
+ // src/data/navigate/graph/constants.ts
807
+ var ROOM_BASEDISTANCE = 1e3;
808
+ var TERRACE_BASEDISTANCE = 1e3;
809
+ var ESCALATOR_BASEDISTANCE = 200;
810
+ var RAMP_BASEDISTANCE = 200;
811
+ var ELEVATOR_BASEDISTANCE = 500;
812
+ var STAIR_BASEDISTANCE = 1e5;
813
+ var BASE_POI_BASEDISTANCE = 9999999;
814
+ var DEFAULT_UNIT_BASEDISTANCE_OPTIONS = {
815
+ default: { baseDistance: 0 },
816
+ byCategory: {
817
+ room: { baseDistance: ROOM_BASEDISTANCE },
818
+ terrace: { baseDistance: TERRACE_BASEDISTANCE },
819
+ escalator: { baseDistance: ESCALATOR_BASEDISTANCE, scaleDistanceByLevel: false },
820
+ ramp: { baseDistance: RAMP_BASEDISTANCE, scaleDistanceByLevel: false },
821
+ elevator: { baseDistance: ELEVATOR_BASEDISTANCE, scaleDistanceByLevel: false },
822
+ stairs: {
823
+ baseDistance: STAIR_BASEDISTANCE,
824
+ scaleDistanceByLevel: true
825
+ },
826
+ "stairs.emergencyexit": {
827
+ baseDistance: STAIR_BASEDISTANCE,
828
+ scaleDistanceByLevel: true
829
+ }
796
830
  }
797
831
  };
798
- function createKey(key) {
799
- let path = null;
800
- let id = null;
801
- let src = null;
802
- let weight = 1;
803
- let getFn = null;
804
- if (isString(key) || isArray(key)) {
805
- src = key;
806
- path = createKeyPath(key);
807
- id = createKeyId(key);
808
- } else {
809
- if (!hasOwn.call(key, "name")) {
810
- throw new Error(MISSING_KEY_PROPERTY("name"));
832
+
833
+ // src/data/navigate/graph/utils/getDistanceOption.ts
834
+ var getDistanceOptions = (options, category) => {
835
+ if (!options) return DEFAULT_UNIT_BASEDISTANCE_OPTIONS.byCategory[category];
836
+ return (category && options.byCategory?.[category]) ?? DEFAULT_UNIT_BASEDISTANCE_OPTIONS.byCategory[category] ?? options?.default ?? DEFAULT_UNIT_BASEDISTANCE_OPTIONS.default;
837
+ };
838
+
839
+ // src/data/utils/trace.ts
840
+ var trace = (namespace, text, ms, color) => {
841
+ console.log(`[${namespace}] %c${text.padEnd(90)} ${ms !== void 0 ? `${ms.toFixed(1).padStart(6)} ms` : ``}`, color ? `color: ${color}` : void 0);
842
+ };
843
+
844
+ // src/data/navigate/graph/nodemap/createTraversalNodeMap.ts
845
+ var createTraversalNodeMap = (unitOpenings, options) => {
846
+ const { units } = options.data;
847
+ let counter = 0;
848
+ const calculateFeatureDistanceWithinUnit = (features, distanceOptions) => {
849
+ let relationshipGraph = {};
850
+ for (let currentIndex = 0; currentIndex < features.length; currentIndex++) {
851
+ const isLastItem = currentIndex + 1 === features.length;
852
+ if (isLastItem) break;
853
+ for (let j = currentIndex + 1; j < features.length; j++) {
854
+ const opening = features[currentIndex];
855
+ const feature2 = features[j];
856
+ try {
857
+ const distance5 = (0, import_distance.distance)(
858
+ (0, import_center3.center)(opening.geometry),
859
+ (0, import_center3.center)(feature2.geometry),
860
+ { units: "meters" }
861
+ ) + (distanceOptions?.baseDistance ?? 0);
862
+ if (opening.id === feature2.id) continue;
863
+ import_lodash3.default.set(relationshipGraph, `${opening.id}.${feature2.id}`, distance5);
864
+ import_lodash3.default.set(relationshipGraph, `${feature2.id}.${opening.id}`, distance5);
865
+ counter++;
866
+ } catch (error) {
867
+ continue;
868
+ }
869
+ }
811
870
  }
812
- const name = key.name;
813
- src = name;
814
- if (hasOwn.call(key, "weight")) {
815
- weight = key.weight;
816
- if (weight <= 0) {
817
- throw new Error(INVALID_KEY_WEIGHT_VALUE(name));
871
+ return relationshipGraph;
872
+ };
873
+ const t0 = performance.now();
874
+ const nodeMap = import_lodash3.default.reduce(
875
+ unitOpenings,
876
+ (acc, openings, unitId) => {
877
+ const unit = units.find((unit2) => unit2.id === unitId);
878
+ const unitDistanceOption = getDistanceOptions(options.unitDistanceOptions, unit.properties.category);
879
+ return import_lodash3.default.merge(
880
+ acc,
881
+ calculateFeatureDistanceWithinUnit(openings, unitDistanceOption)
882
+ );
883
+ },
884
+ {}
885
+ );
886
+ const t1 = performance.now();
887
+ trace("nav", ` \u2502 \u251C\u2500 add ${counter} traversal relationships`, t1 - t0);
888
+ return nodeMap;
889
+ };
890
+
891
+ // src/data/navigate/graph/nodemap/createElevatorNodeMap.ts
892
+ var import_lodash4 = __toESM(require("lodash"));
893
+ var createElevatorNodeMap = (elevatorLikeRelationships, unitOpenings, options) => {
894
+ const t0 = performance.now();
895
+ const { levels, units } = options.data;
896
+ const distanceOptions = getDistanceOptions(options.unitDistanceOptions, "elevator");
897
+ const {
898
+ baseDistance = ELEVATOR_BASEDISTANCE,
899
+ scaleDistanceByLevel = false
900
+ } = distanceOptions;
901
+ let elevatorNodeMap = {};
902
+ let counter = 0;
903
+ for (const relationship of elevatorLikeRelationships) {
904
+ try {
905
+ const {
906
+ origin: originTypeAndId,
907
+ intermediary,
908
+ destination: destinationTypeAndId
909
+ } = relationship.properties;
910
+ const origin = units.find((unit) => unit.id === originTypeAndId.id);
911
+ if (!origin) return;
912
+ const originOpenings = compact(unitOpenings[origin.id]);
913
+ const originLevel = levels.find((level) => level.id === origin.properties.level_id);
914
+ const destination = units.find((unit) => unit.id === destinationTypeAndId.id);
915
+ const destinationOpenings = unitOpenings[destination.id];
916
+ const destinationOpeningAndLevels = destinationOpenings.map((opening) => {
917
+ const level = levels.find((level2) => level2.id === destination.properties.level_id);
918
+ return { opening, level };
919
+ });
920
+ const intermediaryOpeningAndLevels = intermediary.map((unitTypeAndId) => {
921
+ const openings = unitOpenings[unitTypeAndId.id];
922
+ const unit = units.find((unit2) => unit2.id === unitTypeAndId.id);
923
+ const level = levels.find((level2) => level2.id === unit.properties.level_id);
924
+ return openings.map((opening) => ({ opening, level }));
925
+ }).flat();
926
+ const connections = compact([...intermediaryOpeningAndLevels, ...destinationOpeningAndLevels]);
927
+ if (!originOpenings || originOpenings.length === 0) return;
928
+ for (const originOpening of originOpenings) {
929
+ for (const connection of connections) {
930
+ const { opening, level } = connection;
931
+ let distance5 = baseDistance;
932
+ if (scaleDistanceByLevel) {
933
+ const originOrdinal = originLevel.properties.ordinal;
934
+ const connectionOrdinal = level.properties.ordinal;
935
+ const levelDifference = Math.abs(originOrdinal - connectionOrdinal);
936
+ if (levelDifference > 0) distance5 *= levelDifference;
937
+ }
938
+ import_lodash4.default.set(elevatorNodeMap, `${originOpening.id}.${opening.id}`, distance5);
939
+ import_lodash4.default.set(elevatorNodeMap, `${opening.id}.${originOpening.id}`, distance5);
940
+ counter++;
941
+ }
818
942
  }
943
+ } catch (err) {
944
+ console.log(err);
945
+ console.log("cannot create elevatorNodeMap for ", { relationship });
819
946
  }
820
- path = createKeyPath(name);
821
- id = createKeyId(name);
822
- getFn = key.getFn;
823
947
  }
824
- return { path, id, weight, src, getFn };
825
- }
826
- function createKeyPath(key) {
827
- return isArray(key) ? key : key.split(".");
828
- }
829
- function createKeyId(key) {
830
- return isArray(key) ? key.join(".") : key;
831
- }
832
- function get(obj, path) {
833
- let list = [];
834
- let arr = false;
835
- const deepGet = (obj2, path2, index) => {
836
- if (!isDefined(obj2)) {
837
- return;
948
+ const t1 = performance.now();
949
+ trace("nav", ` \u2502 \u251C\u2500 add ${counter} escalator relationships`, t1 - t0);
950
+ return elevatorNodeMap;
951
+ };
952
+
953
+ // src/data/navigate/graph/nodemap/createEscalatorNodeMap.ts
954
+ var import_set = __toESM(require("lodash/set"));
955
+ var createEscalatorNodeMap = (relationships, options) => {
956
+ const t0 = performance.now();
957
+ const distanceOptions = getDistanceOptions(options.unitDistanceOptions, "escalator");
958
+ let counter = 0;
959
+ let nodeMap = {};
960
+ for (const relationship of relationships) {
961
+ const {
962
+ properties: { direction, origin, destination }
963
+ } = relationship;
964
+ (0, import_set.default)(nodeMap, `${origin.id}.${destination.id}`, distanceOptions.baseDistance);
965
+ if (direction === "undirected") {
966
+ (0, import_set.default)(nodeMap, `${destination.id}.${origin.id}`, distanceOptions.baseDistance);
838
967
  }
839
- if (!path2[index]) {
840
- list.push(obj2);
841
- } else {
842
- let key = path2[index];
843
- const value = obj2[key];
844
- if (!isDefined(value)) {
845
- return;
846
- }
847
- if (index === path2.length - 1 && (isString(value) || isNumber(value) || isBoolean(value))) {
848
- list.push(toString(value));
849
- } else if (isArray(value)) {
850
- arr = true;
851
- for (let i = 0, len = value.length; i < len; i += 1) {
852
- deepGet(value[i], path2, index + 1);
968
+ counter++;
969
+ }
970
+ const t1 = performance.now();
971
+ trace("nav", ` \u2502 \u251C\u2500 add ${counter} escalator relationships`, t1 - t0);
972
+ return nodeMap;
973
+ };
974
+
975
+ // src/data/navigate/graph/nodemap/createRampNodeMap.ts
976
+ var import_set2 = __toESM(require("lodash/set"));
977
+ var createRampNodeMap = (relationships, options) => {
978
+ const t0 = performance.now();
979
+ const distanceOptions = getDistanceOptions(options.unitDistanceOptions, "ramp");
980
+ let counter = 0;
981
+ let nodeMap = {};
982
+ relationships.forEach((relationship) => {
983
+ const {
984
+ properties: { origin, destination }
985
+ } = relationship;
986
+ (0, import_set2.default)(nodeMap, `${origin.id}.${destination.id}`, distanceOptions.baseDistance);
987
+ (0, import_set2.default)(nodeMap, `${destination.id}.${origin.id}`, distanceOptions.baseDistance);
988
+ counter++;
989
+ });
990
+ const t1 = performance.now();
991
+ trace("nav", ` \u2502 \u251C\u2500 add ${counter} ramp relationships`, t1 - t0);
992
+ return nodeMap;
993
+ };
994
+
995
+ // src/data/navigate/graph/nodemap/createStairNodeMap.ts
996
+ var import_lodash6 = __toESM(require("lodash"));
997
+ var createStairNodeMap = (elevatorLikeRelationships, unitOpenings, options) => {
998
+ const t0 = performance.now();
999
+ const { levels = [], openings = [], units = [] } = options.data;
1000
+ const { baseDistance, scaleDistanceByLevel } = getDistanceOptions(options.unitDistanceOptions, "stairs");
1001
+ let elevatorNodeMap = {};
1002
+ let counter = 0;
1003
+ for (const relationship of elevatorLikeRelationships) {
1004
+ try {
1005
+ const {
1006
+ origin: { id: originId },
1007
+ intermediary,
1008
+ destination: { id: destinationId }
1009
+ } = relationship.properties;
1010
+ const origin = openings.find((opening) => opening.id === originId);
1011
+ if (!origin) return;
1012
+ const originLevel = levels.find((level) => level.id === origin.properties.level_id);
1013
+ const destination = openings.find((opening) => opening.id === destinationId);
1014
+ const destinationOpeningAndLevel = {
1015
+ opening: destination,
1016
+ level: levels.find((level) => level.id === destination.properties.level_id)
1017
+ };
1018
+ const intermediaryOpeningAndLevels = intermediary.map((unitTypeAndId) => {
1019
+ const openings2 = unitOpenings[unitTypeAndId.id];
1020
+ const unit = units.find((unit2) => unit2.id === unitTypeAndId.id);
1021
+ const level = levels.find((level2) => level2.id === unit.properties.level_id);
1022
+ return openings2.map((opening) => ({ opening, level }));
1023
+ }).flat();
1024
+ const connections = [...intermediaryOpeningAndLevels, destinationOpeningAndLevel];
1025
+ if (!origin) return;
1026
+ for (const connection of connections) {
1027
+ const { opening, level } = connection;
1028
+ let distance5 = baseDistance;
1029
+ if (scaleDistanceByLevel) {
1030
+ const originOrdinal = originLevel.properties.ordinal;
1031
+ const connectionOrdinal = level.properties.ordinal;
1032
+ const levelDifference = Math.abs(originOrdinal - connectionOrdinal);
1033
+ if (levelDifference > 0) distance5 *= levelDifference;
853
1034
  }
854
- } else if (path2.length) {
855
- deepGet(value, path2, index + 1);
1035
+ import_lodash6.default.set(elevatorNodeMap, `${origin.id}.${opening.id}`, distance5);
1036
+ import_lodash6.default.set(elevatorNodeMap, `${opening.id}.${origin.id}`, distance5);
1037
+ counter++;
856
1038
  }
1039
+ } catch (err) {
1040
+ console.warn(
1041
+ "Failed to create stairNodeMap",
1042
+ {
1043
+ relationshipId: relationship.id,
1044
+ featureType: relationship.feature_type,
1045
+ error: err instanceof Error ? err.message : err,
1046
+ stack: err instanceof Error ? err.stack : void 0
1047
+ }
1048
+ );
857
1049
  }
858
- };
859
- deepGet(obj, isString(path) ? path.split(".") : path, 0);
860
- return arr ? list : list[0];
861
- }
862
- var MatchOptions = {
863
- // Whether the matches should be included in the result set. When `true`, each record in the result
864
- // set will include the indices of the matched characters.
865
- // These can consequently be used for highlighting purposes.
866
- includeMatches: false,
867
- // When `true`, the matching function will continue to the end of a search pattern even if
868
- // a perfect match has already been located in the string.
869
- findAllMatches: false,
870
- // Minimum number of characters that must be matched before a result is considered a match
871
- minMatchCharLength: 1
1050
+ }
1051
+ const t1 = performance.now();
1052
+ trace("nav", ` \u2502 \u251C\u2500 add ${counter} stairs relationships`, t1 - t0);
1053
+ return elevatorNodeMap;
1054
+ };
1055
+
1056
+ // src/data/navigate/graph/nodemap/createOccupantNodeMap.ts
1057
+ var import_lodash7 = __toESM(require("lodash"));
1058
+ var createOccupantNodeMap = (occupants) => {
1059
+ const t0 = performance.now();
1060
+ let nodeMap = {};
1061
+ let counter = 0;
1062
+ occupants.forEach((occupant) => {
1063
+ const { unit_id, unit_ids = [], kiosk_id, kiosk_ids = [] } = occupant.properties;
1064
+ const occupantRoomIds = compact([unit_id, ...unit_ids]);
1065
+ const occupantKioskIds = compact([kiosk_id, ...kiosk_ids]);
1066
+ for (const roomId of occupantRoomIds) {
1067
+ import_lodash7.default.set(nodeMap, `${roomId}.${occupant.id}`, 1e-3);
1068
+ import_lodash7.default.set(nodeMap, `${occupant.id}.${roomId}`, 1e-3);
1069
+ counter++;
1070
+ }
1071
+ for (const kioskId of occupantKioskIds) {
1072
+ import_lodash7.default.set(nodeMap, `${kioskId}.${occupant.id}`, 1e-3);
1073
+ import_lodash7.default.set(nodeMap, `${occupant.id}.${kioskId}`, 1e-3);
1074
+ counter++;
1075
+ }
1076
+ });
1077
+ const t1 = performance.now();
1078
+ trace("nav", ` \u2502 \u251C\u2500 add ${counter} occupants relationships`, t1 - t0);
1079
+ return nodeMap;
872
1080
  };
873
- var BasicOptions = {
874
- // When `true`, the algorithm continues searching to the end of the input even if a perfect
875
- // match is found before the end of the same input.
876
- isCaseSensitive: false,
877
- // When `true`, the algorithm will ignore diacritics (accents) in comparisons
878
- ignoreDiacritics: false,
879
- // When true, the matching function will continue to the end of a search pattern even if
880
- includeScore: false,
881
- // List of properties that will be searched. This also supports nested properties.
882
- keys: [],
883
- // Whether to sort the result list, by score
884
- shouldSort: true,
885
- // Default sort function: sort by ascending score, ascending index
886
- sortFn: (a, b) => a.score === b.score ? a.idx < b.idx ? -1 : 1 : a.score < b.score ? -1 : 1
1081
+
1082
+ // src/data/navigate/graph/nodemap/createPOINodeMaps.ts
1083
+ var import_center4 = require("@turf/center");
1084
+ var import_distance2 = require("@turf/distance");
1085
+ var import_lodash9 = __toESM(require("lodash"));
1086
+ var createPOINodeMap = (features, getFeatureUnit, unitOpenings) => {
1087
+ const t0 = performance.now();
1088
+ let nodeMap = {};
1089
+ let counter = 0;
1090
+ features.forEach((feat) => {
1091
+ try {
1092
+ const locatedOnUnitId = getFeatureUnit(feat);
1093
+ const openings = unitOpenings[locatedOnUnitId];
1094
+ const center7 = (0, import_center4.center)(feat);
1095
+ for (const opening of openings) {
1096
+ try {
1097
+ const openingCenter = (0, import_center4.center)(opening);
1098
+ const dis = (0, import_distance2.distance)(center7, openingCenter, { units: "meters" }) + BASE_POI_BASEDISTANCE;
1099
+ import_lodash9.default.set(nodeMap, `${opening.id}.${feat.id}`, dis);
1100
+ import_lodash9.default.set(nodeMap, `${feat.id}.${opening.id}`, dis);
1101
+ counter++;
1102
+ } catch (err) {
1103
+ console.log(err, opening);
1104
+ }
1105
+ }
1106
+ } catch (err) {
1107
+ console.log(err);
1108
+ console.log(`cannot connect poi to openings`, err.message, { feat });
1109
+ }
1110
+ });
1111
+ const type = features.length > 0 ? features[0].feature_type : "-";
1112
+ const t1 = performance.now();
1113
+ trace("nav", ` \u2502 \u251C\u2500 add ${counter} ${type} relationships`, t1 - t0);
1114
+ return nodeMap;
887
1115
  };
888
- var FuzzyOptions = {
889
- // Approximately where in the text is the pattern expected to be found?
890
- location: 0,
891
- // At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match
892
- // (of both letters and location), a threshold of '1.0' would match anything.
893
- threshold: 0.6,
894
- // Determines how close the match must be to the fuzzy location (specified above).
895
- // An exact letter match which is 'distance' characters away from the fuzzy location
896
- // would score as a complete mismatch. A distance of '0' requires the match be at
897
- // the exact location specified, a threshold of '1000' would require a perfect match
898
- // to be within 800 characters of the fuzzy location to be found using a 0.8 threshold.
899
- distance: 100
1116
+
1117
+ // src/data/navigate/graph/utils/mergeNodeMap.ts
1118
+ var mergeNodeMap = (nodeMaps) => {
1119
+ const out = {};
1120
+ for (const nodeMap of nodeMaps) {
1121
+ for (const from in nodeMap) {
1122
+ out[from] = {
1123
+ ...out[from] ?? {},
1124
+ ...nodeMap[from]
1125
+ };
1126
+ }
1127
+ }
1128
+ return out;
900
1129
  };
901
- var AdvancedOptions = {
902
- // When `true`, it enables the use of unix-like search commands
903
- useExtendedSearch: false,
904
- // The get function to use when fetching an object's properties.
905
- // The default will search nested paths *ie foo.bar.baz*
906
- getFn: get,
907
- // When `true`, search will ignore `location` and `distance`, so it won't matter
908
- // where in the string the pattern appears.
909
- // More info: https://fusejs.io/concepts/scoring-theory.html#fuzziness-score
910
- ignoreLocation: false,
911
- // When `true`, the calculation for the relevance score (used for sorting) will
912
- // ignore the field-length norm.
913
- // More info: https://fusejs.io/concepts/scoring-theory.html#field-length-norm
914
- ignoreFieldNorm: false,
915
- // The weight to determine how much field length norm effects scoring.
916
- fieldNormWeight: 1
1130
+
1131
+ // src/data/navigate/graph/utils/createUnitOpenings.ts
1132
+ var import_uniqBy = __toESM(require("lodash/uniqBy"));
1133
+ var createUnitOpenings = (relationships, units, openings) => {
1134
+ const openingConnections = {};
1135
+ const relationshipMap = /* @__PURE__ */ new Map();
1136
+ relationships.forEach((relationship) => {
1137
+ const originId = relationship.properties.origin?.id || null;
1138
+ const destinationId = relationship.properties.destination?.id || null;
1139
+ if (!relationshipMap.has(originId)) {
1140
+ relationshipMap.set(originId, []);
1141
+ }
1142
+ if (!relationshipMap.has(destinationId)) {
1143
+ relationshipMap.set(destinationId, []);
1144
+ }
1145
+ relationshipMap.get(originId).push(relationship);
1146
+ relationshipMap.get(destinationId).push(relationship);
1147
+ });
1148
+ units.forEach((unit) => {
1149
+ const unitId = unit.id;
1150
+ const connectedRelationshop = relationshipMap.get(unitId) || [];
1151
+ const relationshipIntermediaryTypeAndId = connectedRelationshop.map(
1152
+ (relationship) => relationship.properties.intermediary[0]
1153
+ // Assuming intermediary is always an array
1154
+ );
1155
+ const relationshipIntermediary = relationshipIntermediaryTypeAndId.map(({ id }) => {
1156
+ return openings.find((opening) => opening.id === id);
1157
+ });
1158
+ openingConnections[unitId] = (0, import_uniqBy.default)(
1159
+ [...openingConnections[unitId] || [], ...relationshipIntermediary],
1160
+ "id"
1161
+ );
1162
+ });
1163
+ return openingConnections;
917
1164
  };
918
- var Config = {
919
- ...BasicOptions,
920
- ...MatchOptions,
921
- ...FuzzyOptions,
922
- ...AdvancedOptions
1165
+
1166
+ // src/data/navigate/parsers.ts
1167
+ var parseOrdinalCoordinate = (id) => {
1168
+ return id.slice(0, -1).split(",").map(Number);
923
1169
  };
924
- var SPACE = /[^ ]+/g;
925
- function norm(weight = 1, mantissa = 3) {
926
- const cache = /* @__PURE__ */ new Map();
927
- const m = Math.pow(10, mantissa);
928
- return {
929
- get(value) {
930
- const numTokens = value.match(SPACE).length;
931
- if (cache.has(numTokens)) {
932
- return cache.get(numTokens);
1170
+
1171
+ // src/data/navigate/graph/prepare.ts
1172
+ var prepareGraph = (options) => {
1173
+ const {
1174
+ data: {
1175
+ amenities = [],
1176
+ anchors = [],
1177
+ occupants = [],
1178
+ relationships = [],
1179
+ openings = [],
1180
+ units = [],
1181
+ kiosks = [],
1182
+ levels = []
1183
+ }
1184
+ } = options;
1185
+ const {
1186
+ traversal: traversalRelationships = [],
1187
+ escalator: escalatorRelationships = [],
1188
+ ramp: rampRelationships = [],
1189
+ elevator: elevatorRelationships = [],
1190
+ stairs: stairsRelationships = []
1191
+ } = import_lodash10.default.groupBy(relationships, "properties.category");
1192
+ const unitOpenings = createUnitOpenings(traversalRelationships, units, openings);
1193
+ const traversalNodeMap = createTraversalNodeMap(unitOpenings, options);
1194
+ const escalatorNodeMap = createEscalatorNodeMap(escalatorRelationships, options);
1195
+ const rampNodeMap = createRampNodeMap(rampRelationships, options);
1196
+ const elevatorNodeMap = createElevatorNodeMap(
1197
+ elevatorRelationships,
1198
+ unitOpenings,
1199
+ options
1200
+ );
1201
+ const stairNodeMap = createStairNodeMap(
1202
+ stairsRelationships,
1203
+ unitOpenings,
1204
+ options
1205
+ );
1206
+ const amenityNodeMap = createPOINodeMap(amenities, (amenity) => amenity.properties.unit_ids[0], unitOpenings);
1207
+ const anchorsNodeMap = createPOINodeMap(anchors, (anchor) => anchor.properties.unit_id, unitOpenings);
1208
+ const walkwayUnits = units.filter((unit) => unit.properties.category === "walkway");
1209
+ const kioskNodeMap = createPOINodeMap(kiosks, (kiosk) => findContainingUnit(kiosk, walkwayUnits)?.id, unitOpenings);
1210
+ const unitNodeMap = createPOINodeMap(units, (unit) => unit.id, unitOpenings);
1211
+ const occupantNodeMap = createOccupantNodeMap(occupants);
1212
+ const defaultGraph = new import_node_dijkstra.default(mergeNodeMap([
1213
+ traversalNodeMap,
1214
+ escalatorNodeMap,
1215
+ rampNodeMap,
1216
+ elevatorNodeMap,
1217
+ stairNodeMap,
1218
+ amenityNodeMap,
1219
+ anchorsNodeMap,
1220
+ kioskNodeMap,
1221
+ unitNodeMap,
1222
+ occupantNodeMap
1223
+ ]));
1224
+ const accessibleGraph = new import_node_dijkstra.default(mergeNodeMap([
1225
+ traversalNodeMap,
1226
+ rampNodeMap,
1227
+ elevatorNodeMap,
1228
+ amenityNodeMap,
1229
+ anchorsNodeMap,
1230
+ kioskNodeMap,
1231
+ unitNodeMap,
1232
+ occupantNodeMap
1233
+ ]));
1234
+ const addCoordinateOrdinalNode = (params, locatedOnUnit) => {
1235
+ const [lat, lng, ordinal] = parseOrdinalCoordinate(params);
1236
+ if (locatedOnUnit) {
1237
+ const openings2 = unitOpenings[locatedOnUnit.id];
1238
+ for (const opening of openings2) {
1239
+ const openingCenter = (0, import_center5.center)(opening);
1240
+ const dis = (0, import_distance3.distance)([lat, lng], openingCenter, { units: "meters" });
1241
+ defaultGraph.addNode(params, { [opening.id]: dis }).addNode(opening.id, { [params]: dis });
1242
+ accessibleGraph.addNode(params, { [opening.id]: dis }).addNode(opening.id, { [params]: dis });
933
1243
  }
934
- const norm2 = 1 / Math.pow(numTokens, 0.5 * weight);
935
- const n = parseFloat(Math.round(norm2 * m) / m);
936
- cache.set(numTokens, n);
937
- return n;
938
- },
939
- clear() {
940
- cache.clear();
941
1244
  }
942
1245
  };
1246
+ return { defaultGraph, accessibleGraph, unitOpenings, addCoordinateOrdinalNode };
1247
+ };
1248
+
1249
+ // src/data/navigate/steps/createStepUtils.ts
1250
+ var import_lodash12 = require("lodash");
1251
+ var import_intersectionBy = __toESM(require("lodash/intersectionBy"));
1252
+ var import_center9 = require("@turf/center");
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;
943
1341
  }
944
- var FuseIndex = class {
945
- constructor({
946
- getFn = Config.getFn,
947
- fieldNormWeight = Config.fieldNormWeight
948
- } = {}) {
949
- this.norm = norm(fieldNormWeight, 3);
950
- this.getFn = getFn;
951
- this.isCreated = false;
952
- this.setIndexRecords();
1342
+ function point(coordinates, properties, options = {}) {
1343
+ if (!coordinates) {
1344
+ throw new Error("coordinates is required");
953
1345
  }
954
- setSources(docs = []) {
955
- this.docs = docs;
1346
+ if (!Array.isArray(coordinates)) {
1347
+ throw new Error("coordinates must be an Array");
956
1348
  }
957
- setIndexRecords(records = []) {
958
- this.records = records;
1349
+ if (coordinates.length < 2) {
1350
+ throw new Error("coordinates must be at least 2 numbers long");
959
1351
  }
960
- setKeys(keys = []) {
961
- this.keys = keys;
962
- this._keysMap = {};
963
- keys.forEach((key, idx) => {
964
- this._keysMap[key.id] = idx;
965
- });
1352
+ if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) {
1353
+ throw new Error("coordinates must contain numbers");
966
1354
  }
967
- create() {
968
- if (this.isCreated || !this.docs.length) {
969
- return;
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
+ );
970
1367
  }
971
- this.isCreated = true;
972
- if (isString(this.docs[0])) {
973
- this.docs.forEach((doc, docIndex) => {
974
- this._addString(doc, docIndex);
975
- });
976
- } else {
977
- this.docs.forEach((doc, docIndex) => {
978
- this._addObject(doc, docIndex);
979
- });
1368
+ if (ring[ring.length - 1].length !== ring[0].length) {
1369
+ throw new Error("First and last Position are not equivalent.");
980
1370
  }
981
- this.norm.clear();
982
- }
983
- // Adds a doc to the end of the index
984
- add(doc) {
985
- const idx = this.size();
986
- if (isString(doc)) {
987
- this._addString(doc, idx);
988
- } else {
989
- this._addObject(doc, idx);
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
+ }
990
1375
  }
991
1376
  }
992
- // Removes the doc at the specified index of the index
993
- removeAt(idx) {
994
- this.records.splice(idx, 1);
995
- for (let i = idx, len = this.size(); i < len; i += 1) {
996
- this.records[i].i -= 1;
997
- }
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");
998
1386
  }
999
- getValueForItemAtKeyId(item, keyId) {
1000
- return item[this._keysMap[keyId]];
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;
1001
1397
  }
1002
- size() {
1003
- return this.records.length;
1398
+ if (options.bbox) {
1399
+ fc.bbox = options.bbox;
1004
1400
  }
1005
- _addString(doc, docIndex) {
1006
- if (!isDefined(doc) || isBlank(doc)) {
1007
- return;
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];
1008
1422
  }
1009
- let record = {
1010
- v: doc,
1011
- i: docIndex,
1012
- n: this.norm.get(doc)
1013
- };
1014
- this.records.push(record);
1015
- }
1016
- _addObject(doc, docIndex) {
1017
- let record = { i: docIndex, $: {} };
1018
- this.keys.forEach((key, keyIndex) => {
1019
- let value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path);
1020
- if (!isDefined(value)) {
1021
- return;
1022
- }
1023
- if (isArray(value)) {
1024
- let subRecords = [];
1025
- const stack = [{ nestedArrIndex: -1, value }];
1026
- while (stack.length) {
1027
- const { nestedArrIndex, value: value2 } = stack.pop();
1028
- if (!isDefined(value2)) {
1029
- continue;
1030
- }
1031
- if (isString(value2) && !isBlank(value2)) {
1032
- let subRecord = {
1033
- v: value2,
1034
- i: nestedArrIndex,
1035
- n: this.norm.get(value2)
1036
- };
1037
- subRecords.push(subRecord);
1038
- } else if (isArray(value2)) {
1039
- value2.forEach((item, k) => {
1040
- stack.push({
1041
- nestedArrIndex: k,
1042
- value: item
1043
- });
1044
- });
1045
- } else ;
1046
- }
1047
- record.$[keyIndex] = subRecords;
1048
- } else if (isString(value) && !isBlank(value)) {
1049
- let subRecord = {
1050
- v: value,
1051
- n: this.norm.get(value)
1052
- };
1053
- record.$[keyIndex] = subRecord;
1054
- }
1055
- });
1056
- this.records.push(record);
1057
1423
  }
1058
- toJSON() {
1059
- return {
1060
- keys: this.keys,
1061
- records: this.records
1062
- };
1424
+ if (Array.isArray(coord) && coord.length >= 2 && !Array.isArray(coord[0]) && !Array.isArray(coord[1])) {
1425
+ return [...coord];
1063
1426
  }
1064
- };
1065
- function createIndex(keys, docs, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
1066
- const myIndex = new FuseIndex({ getFn, fieldNormWeight });
1067
- myIndex.setKeys(keys.map(createKey));
1068
- myIndex.setSources(docs);
1069
- myIndex.create();
1070
- return myIndex;
1427
+ throw new Error("coord must be GeoJSON Point or an Array of numbers");
1071
1428
  }
1072
- function parseIndex(data, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
1073
- const { keys, records } = data;
1074
- const myIndex = new FuseIndex({ getFn, fieldNormWeight });
1075
- myIndex.setKeys(keys);
1076
- myIndex.setIndexRecords(records);
1077
- return myIndex;
1429
+ function getGeom(geojson) {
1430
+ if (geojson.type === "Feature") {
1431
+ return geojson.geometry;
1432
+ }
1433
+ return geojson;
1078
1434
  }
1079
- function computeScore$1(pattern, {
1080
- errors = 0,
1081
- currentLocation = 0,
1082
- expectedLocation = 0,
1083
- distance = Config.distance,
1084
- ignoreLocation = Config.ignoreLocation
1085
- } = {}) {
1086
- const accuracy = errors / pattern.length;
1087
- if (ignoreLocation) {
1088
- return accuracy;
1435
+ function getType(geojson, _name) {
1436
+ if (geojson.type === "FeatureCollection") {
1437
+ return "FeatureCollection";
1089
1438
  }
1090
- const proximity = Math.abs(expectedLocation - currentLocation);
1091
- if (!distance) {
1092
- return proximity ? 1 : accuracy;
1439
+ if (geojson.type === "GeometryCollection") {
1440
+ return "GeometryCollection";
1093
1441
  }
1094
- return accuracy + proximity / distance;
1442
+ if (geojson.type === "Feature" && geojson.geometry !== null) {
1443
+ return geojson.geometry.type;
1444
+ }
1445
+ return geojson.type;
1095
1446
  }
1096
- function convertMaskToIndices(matchmask = [], minMatchCharLength = Config.minMatchCharLength) {
1097
- let indices = [];
1098
- let start = -1;
1099
- let end = -1;
1100
- let i = 0;
1101
- for (let len = matchmask.length; i < len; i += 1) {
1102
- let match = matchmask[i];
1103
- if (match && start === -1) {
1104
- start = i;
1105
- } else if (!match && start !== -1) {
1106
- end = i - 1;
1107
- if (end - start + 1 >= minMatchCharLength) {
1108
- indices.push([start, end]);
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");
1109
1547
  }
1110
- start = -1;
1111
1548
  }
1112
1549
  }
1113
- if (matchmask[i - 1] && i - start >= minMatchCharLength) {
1114
- indices.push([start, i - 1]);
1115
- }
1116
- return indices;
1117
1550
  }
1118
- var MAX_BITS = 32;
1119
- function search(text, pattern, patternAlphabet, {
1120
- location = Config.location,
1121
- distance = Config.distance,
1122
- threshold = Config.threshold,
1123
- findAllMatches = Config.findAllMatches,
1124
- minMatchCharLength = Config.minMatchCharLength,
1125
- includeMatches = Config.includeMatches,
1126
- ignoreLocation = Config.ignoreLocation
1127
- } = {}) {
1128
- if (pattern.length > MAX_BITS) {
1129
- throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS));
1130
- }
1131
- const patternLen = pattern.length;
1132
- const textLen = text.length;
1133
- const expectedLocation = Math.max(0, Math.min(location, textLen));
1134
- let currentThreshold = threshold;
1135
- let bestLocation = expectedLocation;
1136
- const computeMatches = minMatchCharLength > 1 || includeMatches;
1137
- const matchMask = computeMatches ? Array(textLen) : [];
1138
- let index;
1139
- while ((index = text.indexOf(pattern, bestLocation)) > -1) {
1140
- let score = computeScore$1(pattern, {
1141
- currentLocation: index,
1142
- expectedLocation,
1143
- distance,
1144
- ignoreLocation
1145
- });
1146
- currentThreshold = Math.min(score, currentThreshold);
1147
- bestLocation = index + patternLen;
1148
- if (computeMatches) {
1149
- let i = 0;
1150
- while (i < patternLen) {
1151
- matchMask[index + i] = 1;
1152
- i += 1;
1153
- }
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];
1154
1561
  }
1155
- }
1156
- bestLocation = -1;
1157
- let lastBitArr = [];
1158
- let finalScore = 1;
1159
- let binMax = patternLen + textLen;
1160
- const mask = 1 << patternLen - 1;
1161
- for (let i = 0; i < patternLen; i += 1) {
1162
- let binMin = 0;
1163
- let binMid = binMax;
1164
- while (binMin < binMid) {
1165
- const score2 = computeScore$1(pattern, {
1166
- errors: i,
1167
- currentLocation: expectedLocation + binMid,
1168
- expectedLocation,
1169
- distance,
1170
- ignoreLocation
1171
- });
1172
- if (score2 <= currentThreshold) {
1173
- binMin = binMid;
1174
- } else {
1175
- binMax = binMid;
1176
- }
1177
- binMid = Math.floor((binMax - binMin) / 2 + binMin);
1178
- }
1179
- binMax = binMid;
1180
- let start = Math.max(1, expectedLocation - binMid + 1);
1181
- let finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen;
1182
- let bitArr = Array(finish + 2);
1183
- bitArr[finish + 1] = (1 << i) - 1;
1184
- for (let j = finish; j >= start; j -= 1) {
1185
- let currentLocation = j - 1;
1186
- let charMatch = patternAlphabet[text.charAt(currentLocation)];
1187
- if (computeMatches) {
1188
- matchMask[currentLocation] = +!!charMatch;
1189
- }
1190
- bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch;
1191
- if (i) {
1192
- bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];
1193
- }
1194
- if (bitArr[j] & mask) {
1195
- finalScore = computeScore$1(pattern, {
1196
- errors: i,
1197
- currentLocation,
1198
- expectedLocation,
1199
- distance,
1200
- ignoreLocation
1201
- });
1202
- if (finalScore <= currentThreshold) {
1203
- currentThreshold = finalScore;
1204
- bestLocation = currentLocation;
1205
- if (bestLocation <= expectedLocation) {
1206
- break;
1207
- }
1208
- start = Math.max(1, 2 * expectedLocation - bestLocation);
1209
- }
1210
- }
1562
+ if (result[1] > coord[1]) {
1563
+ result[1] = coord[1];
1211
1564
  }
1212
- const score = computeScore$1(pattern, {
1213
- errors: i + 1,
1214
- currentLocation: expectedLocation,
1215
- expectedLocation,
1216
- distance,
1217
- ignoreLocation
1218
- });
1219
- if (score > currentThreshold) {
1220
- break;
1565
+ if (result[2] < coord[0]) {
1566
+ result[2] = coord[0];
1221
1567
  }
1222
- lastBitArr = bitArr;
1223
- }
1224
- const result = {
1225
- isMatch: bestLocation >= 0,
1226
- // Count exact matches (those with a score of 0) to be "almost" exact
1227
- score: Math.max(1e-3, finalScore)
1228
- };
1229
- if (computeMatches) {
1230
- const indices = convertMaskToIndices(matchMask, minMatchCharLength);
1231
- if (!indices.length) {
1232
- result.isMatch = false;
1233
- } else if (includeMatches) {
1234
- result.indices = indices;
1568
+ if (result[3] < coord[1]) {
1569
+ result[3] = coord[1];
1235
1570
  }
1236
- }
1571
+ });
1237
1572
  return result;
1238
1573
  }
1239
- function createPatternAlphabet(pattern) {
1240
- let mask = {};
1241
- for (let i = 0, len = pattern.length; i < len; i += 1) {
1242
- const char = pattern.charAt(i);
1243
- mask[char] = (mask[char] || 0) | 1 << len - i - 1;
1244
- }
1245
- return mask;
1246
- }
1247
- var stripDiacritics = String.prototype.normalize ? ((str) => str.normalize("NFD").replace(/[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]/g, "")) : ((str) => str);
1248
- var BitapSearch = class {
1249
- constructor(pattern, {
1250
- location = Config.location,
1251
- threshold = Config.threshold,
1252
- distance = Config.distance,
1253
- includeMatches = Config.includeMatches,
1254
- findAllMatches = Config.findAllMatches,
1255
- minMatchCharLength = Config.minMatchCharLength,
1256
- isCaseSensitive = Config.isCaseSensitive,
1257
- ignoreDiacritics = Config.ignoreDiacritics,
1258
- ignoreLocation = Config.ignoreLocation
1259
- } = {}) {
1260
- this.options = {
1261
- location,
1262
- threshold,
1263
- distance,
1264
- includeMatches,
1265
- findAllMatches,
1266
- minMatchCharLength,
1267
- isCaseSensitive,
1268
- ignoreDiacritics,
1269
- ignoreLocation
1270
- };
1271
- pattern = isCaseSensitive ? pattern : pattern.toLowerCase();
1272
- pattern = ignoreDiacritics ? stripDiacritics(pattern) : pattern;
1273
- this.pattern = pattern;
1274
- this.chunks = [];
1275
- if (!this.pattern.length) {
1276
- return;
1277
- }
1278
- const addChunk = (pattern2, startIndex) => {
1279
- this.chunks.push({
1280
- pattern: pattern2,
1281
- alphabet: createPatternAlphabet(pattern2),
1282
- startIndex
1283
- });
1284
- };
1285
- const len = this.pattern.length;
1286
- if (len > MAX_BITS) {
1287
- let i = 0;
1288
- const remainder = len % MAX_BITS;
1289
- const end = len - remainder;
1290
- while (i < end) {
1291
- addChunk(this.pattern.substr(i, MAX_BITS), i);
1292
- i += MAX_BITS;
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;
1293
1610
  }
1294
- if (remainder) {
1295
- const startIndex = len - MAX_BITS;
1296
- addChunk(this.pattern.substr(startIndex), startIndex);
1611
+ if (e2 < dx) {
1612
+ err += dx;
1613
+ ny += sy;
1614
+ movedY = true;
1297
1615
  }
1298
- } else {
1299
- addChunk(this.pattern, 0);
1300
- }
1301
- }
1302
- searchIn(text) {
1303
- const { isCaseSensitive, ignoreDiacritics, includeMatches } = this.options;
1304
- text = isCaseSensitive ? text : text.toLowerCase();
1305
- text = ignoreDiacritics ? stripDiacritics(text) : text;
1306
- if (this.pattern === text) {
1307
- let result2 = {
1308
- isMatch: true,
1309
- score: 0
1310
- };
1311
- if (includeMatches) {
1312
- result2.indices = [[0, text.length - 1]];
1616
+ if (movedX && movedY) {
1617
+ if (!isWalkable(nx, y0) || !isWalkable(x0, ny)) return false;
1313
1618
  }
1314
- return result2;
1619
+ x0 = nx;
1620
+ y0 = ny;
1315
1621
  }
1316
- const {
1317
- location,
1318
- distance,
1319
- threshold,
1320
- findAllMatches,
1321
- minMatchCharLength,
1322
- ignoreLocation
1323
- } = this.options;
1324
- let allIndices = [];
1325
- let totalScore = 0;
1326
- let hasMatches = false;
1327
- this.chunks.forEach(({ pattern, alphabet, startIndex }) => {
1328
- const { isMatch, score, indices } = search(text, pattern, alphabet, {
1329
- location: location + startIndex,
1330
- distance,
1331
- threshold,
1332
- findAllMatches,
1333
- minMatchCharLength,
1334
- includeMatches,
1335
- ignoreLocation
1336
- });
1337
- if (isMatch) {
1338
- hasMatches = true;
1339
- }
1340
- totalScore += score;
1341
- if (isMatch && indices) {
1342
- allIndices = [...allIndices, ...indices];
1343
- }
1344
- });
1345
- let result = {
1346
- isMatch: hasMatches,
1347
- score: hasMatches ? totalScore / this.chunks.length : 1
1348
- };
1349
- if (hasMatches && includeMatches) {
1350
- result.indices = allIndices;
1351
- }
1352
- return result;
1353
- }
1354
- };
1355
- var BaseMatch = class {
1356
- constructor(pattern) {
1357
- this.pattern = pattern;
1358
- }
1359
- static isMultiMatch(pattern) {
1360
- return getMatch(pattern, this.multiRegex);
1361
- }
1362
- static isSingleMatch(pattern) {
1363
- return getMatch(pattern, this.singleRegex);
1622
+ return true;
1364
1623
  }
1365
- search() {
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;
1366
1635
  }
1367
- };
1368
- function getMatch(pattern, exp) {
1369
- const matches = pattern.match(exp);
1370
- return matches ? matches[1] : null;
1636
+ return out;
1371
1637
  }
1372
- var ExactMatch = class extends BaseMatch {
1373
- constructor(pattern) {
1374
- super(pattern);
1375
- }
1376
- static get type() {
1377
- return "exact";
1378
- }
1379
- static get multiRegex() {
1380
- return /^="(.*)"$/;
1381
- }
1382
- static get singleRegex() {
1383
- return /^=(.*)$/;
1384
- }
1385
- search(text) {
1386
- const isMatch = text === this.pattern;
1387
- return {
1388
- isMatch,
1389
- score: isMatch ? 0 : 1,
1390
- indices: [0, this.pattern.length - 1]
1391
- };
1392
- }
1393
- };
1394
- var InverseExactMatch = class extends BaseMatch {
1395
- constructor(pattern) {
1396
- super(pattern);
1397
- }
1398
- static get type() {
1399
- return "inverse-exact";
1400
- }
1401
- static get multiRegex() {
1402
- return /^!"(.*)"$/;
1403
- }
1404
- static get singleRegex() {
1405
- return /^!(.*)$/;
1406
- }
1407
- search(text) {
1408
- const index = text.indexOf(this.pattern);
1409
- const isMatch = index === -1;
1410
- return {
1411
- isMatch,
1412
- score: isMatch ? 0 : 1,
1413
- indices: [0, text.length - 1]
1414
- };
1415
- }
1416
- };
1417
- var PrefixExactMatch = class extends BaseMatch {
1418
- constructor(pattern) {
1419
- super(pattern);
1420
- }
1421
- static get type() {
1422
- return "prefix-exact";
1423
- }
1424
- static get multiRegex() {
1425
- return /^\^"(.*)"$/;
1426
- }
1427
- static get singleRegex() {
1428
- return /^\^(.*)$/;
1429
- }
1430
- search(text) {
1431
- const isMatch = text.startsWith(this.pattern);
1432
- return {
1433
- isMatch,
1434
- score: isMatch ? 0 : 1,
1435
- indices: [0, this.pattern.length - 1]
1436
- };
1437
- }
1438
- };
1439
- var InversePrefixExactMatch = class extends BaseMatch {
1440
- constructor(pattern) {
1441
- super(pattern);
1442
- }
1443
- static get type() {
1444
- return "inverse-prefix-exact";
1445
- }
1446
- static get multiRegex() {
1447
- return /^!\^"(.*)"$/;
1448
- }
1449
- static get singleRegex() {
1450
- return /^!\^(.*)$/;
1451
- }
1452
- search(text) {
1453
- const isMatch = !text.startsWith(this.pattern);
1454
- return {
1455
- isMatch,
1456
- score: isMatch ? 0 : 1,
1457
- indices: [0, text.length - 1]
1458
- };
1459
- }
1460
- };
1461
- var SuffixExactMatch = class extends BaseMatch {
1462
- constructor(pattern) {
1463
- super(pattern);
1464
- }
1465
- static get type() {
1466
- return "suffix-exact";
1467
- }
1468
- static get multiRegex() {
1469
- return /^"(.*)"\$$/;
1470
- }
1471
- static get singleRegex() {
1472
- return /^(.*)\$$/;
1473
- }
1474
- search(text) {
1475
- const isMatch = text.endsWith(this.pattern);
1476
- return {
1477
- isMatch,
1478
- score: isMatch ? 0 : 1,
1479
- indices: [text.length - this.pattern.length, text.length - 1]
1480
- };
1481
- }
1482
- };
1483
- var InverseSuffixExactMatch = class extends BaseMatch {
1484
- constructor(pattern) {
1485
- super(pattern);
1486
- }
1487
- static get type() {
1488
- return "inverse-suffix-exact";
1489
- }
1490
- static get multiRegex() {
1491
- return /^!"(.*)"\$$/;
1492
- }
1493
- static get singleRegex() {
1494
- return /^!(.*)\$$/;
1495
- }
1496
- search(text) {
1497
- const isMatch = !text.endsWith(this.pattern);
1498
- return {
1499
- isMatch,
1500
- score: isMatch ? 0 : 1,
1501
- indices: [0, text.length - 1]
1502
- };
1503
- }
1504
- };
1505
- var FuzzyMatch = class extends BaseMatch {
1506
- constructor(pattern, {
1507
- location = Config.location,
1508
- threshold = Config.threshold,
1509
- distance = Config.distance,
1510
- includeMatches = Config.includeMatches,
1511
- findAllMatches = Config.findAllMatches,
1512
- minMatchCharLength = Config.minMatchCharLength,
1513
- isCaseSensitive = Config.isCaseSensitive,
1514
- ignoreDiacritics = Config.ignoreDiacritics,
1515
- ignoreLocation = Config.ignoreLocation
1516
- } = {}) {
1517
- super(pattern);
1518
- this._bitapSearch = new BitapSearch(pattern, {
1519
- location,
1520
- threshold,
1521
- distance,
1522
- includeMatches,
1523
- findAllMatches,
1524
- minMatchCharLength,
1525
- isCaseSensitive,
1526
- ignoreDiacritics,
1527
- ignoreLocation
1528
- });
1529
- }
1530
- static get type() {
1531
- return "fuzzy";
1532
- }
1533
- static get multiRegex() {
1534
- return /^"(.*)"$/;
1535
- }
1536
- static get singleRegex() {
1537
- return /^(.*)$/;
1538
- }
1539
- search(text) {
1540
- return this._bitapSearch.searchIn(text);
1541
- }
1542
- };
1543
- var IncludeMatch = class extends BaseMatch {
1544
- constructor(pattern) {
1545
- super(pattern);
1546
- }
1547
- static get type() {
1548
- return "include";
1549
- }
1550
- static get multiRegex() {
1551
- return /^'"(.*)"$/;
1552
- }
1553
- static get singleRegex() {
1554
- return /^'(.*)$/;
1555
- }
1556
- search(text) {
1557
- let location = 0;
1558
- let index;
1559
- const indices = [];
1560
- const patternLen = this.pattern.length;
1561
- while ((index = text.indexOf(this.pattern, location)) > -1) {
1562
- location = index + patternLen;
1563
- indices.push([index, location - 1]);
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[out.length - 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[path.length - 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[out.length - 1];
1664
+ const [x1, y1] = path[i];
1665
+ if (Math.hypot(x1 - x0, y1 - y0) >= minLen) {
1666
+ out.push(path[i]);
1564
1667
  }
1565
- const isMatch = !!indices.length;
1566
- return {
1567
- isMatch,
1568
- score: isMatch ? 0 : 1,
1569
- indices
1570
- };
1571
1668
  }
1572
- };
1573
- var searchers = [
1574
- ExactMatch,
1575
- IncludeMatch,
1576
- PrefixExactMatch,
1577
- InversePrefixExactMatch,
1578
- InverseSuffixExactMatch,
1579
- SuffixExactMatch,
1580
- InverseExactMatch,
1581
- FuzzyMatch
1582
- ];
1583
- var searchersLen = searchers.length;
1584
- var SPACE_RE = / +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/;
1585
- var OR_TOKEN = "|";
1586
- function parseQuery(pattern, options = {}) {
1587
- return pattern.split(OR_TOKEN).map((item) => {
1588
- let query = item.trim().split(SPACE_RE).filter((item2) => item2 && !!item2.trim());
1589
- let results = [];
1590
- for (let i = 0, len = query.length; i < len; i += 1) {
1591
- const queryItem = query[i];
1592
- let found = false;
1593
- let idx = -1;
1594
- while (!found && ++idx < searchersLen) {
1595
- const searcher = searchers[idx];
1596
- let token = searcher.isMultiMatch(queryItem);
1597
- if (token) {
1598
- results.push(new searcher(token, options));
1599
- found = true;
1600
- }
1601
- }
1602
- if (found) {
1603
- continue;
1604
- }
1605
- idx = -1;
1606
- while (++idx < searchersLen) {
1607
- const searcher = searchers[idx];
1608
- let token = searcher.isSingleMatch(queryItem);
1609
- if (token) {
1610
- results.push(new searcher(token, options));
1611
- break;
1612
- }
1613
- }
1614
- }
1615
- return results;
1616
- });
1669
+ return out;
1617
1670
  }
1618
- var MultiMatchSet = /* @__PURE__ */ new Set([FuzzyMatch.type, IncludeMatch.type]);
1619
- var ExtendedSearch = class {
1620
- constructor(pattern, {
1621
- isCaseSensitive = Config.isCaseSensitive,
1622
- ignoreDiacritics = Config.ignoreDiacritics,
1623
- includeMatches = Config.includeMatches,
1624
- minMatchCharLength = Config.minMatchCharLength,
1625
- ignoreLocation = Config.ignoreLocation,
1626
- findAllMatches = Config.findAllMatches,
1627
- location = Config.location,
1628
- threshold = Config.threshold,
1629
- distance = Config.distance
1630
- } = {}) {
1631
- this.query = null;
1632
- this.options = {
1633
- isCaseSensitive,
1634
- ignoreDiacritics,
1635
- includeMatches,
1636
- minMatchCharLength,
1637
- findAllMatches,
1638
- ignoreLocation,
1639
- location,
1640
- threshold,
1641
- distance
1642
- };
1643
- pattern = isCaseSensitive ? pattern : pattern.toLowerCase();
1644
- pattern = ignoreDiacritics ? stripDiacritics(pattern) : pattern;
1645
- this.pattern = pattern;
1646
- this.query = parseQuery(this.pattern, this.options);
1647
- }
1648
- static condition(_, options) {
1649
- return options.useExtendedSearch;
1650
- }
1651
- searchIn(text) {
1652
- const query = this.query;
1653
- if (!query) {
1654
- return {
1655
- isMatch: false,
1656
- score: 1
1657
- };
1658
- }
1659
- const { includeMatches, isCaseSensitive, ignoreDiacritics } = this.options;
1660
- text = isCaseSensitive ? text : text.toLowerCase();
1661
- text = ignoreDiacritics ? stripDiacritics(text) : text;
1662
- let numMatches = 0;
1663
- let allIndices = [];
1664
- let totalScore = 0;
1665
- for (let i = 0, qLen = query.length; i < qLen; i += 1) {
1666
- const searchers2 = query[i];
1667
- allIndices.length = 0;
1668
- numMatches = 0;
1669
- for (let j = 0, pLen = searchers2.length; j < pLen; j += 1) {
1670
- const searcher = searchers2[j];
1671
- const { isMatch, indices, score } = searcher.search(text);
1672
- if (isMatch) {
1673
- numMatches += 1;
1674
- totalScore += score;
1675
- if (includeMatches) {
1676
- const type = searcher.constructor.type;
1677
- if (MultiMatchSet.has(type)) {
1678
- allIndices = [...allIndices, ...indices];
1679
- } else {
1680
- allIndices.push(indices);
1681
- }
1682
- }
1683
- } else {
1684
- totalScore = 0;
1685
- numMatches = 0;
1686
- allIndices.length = 0;
1687
- break;
1688
- }
1689
- }
1690
- if (numMatches) {
1691
- let result = {
1692
- isMatch: true,
1693
- score: totalScore / numMatches
1694
- };
1695
- if (includeMatches) {
1696
- result.indices = allIndices;
1697
- }
1698
- return result;
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]);
1699
1684
  }
1700
1685
  }
1701
- return {
1702
- isMatch: false,
1703
- score: 1
1704
- };
1705
1686
  }
1706
- };
1707
- var registeredSearchers = [];
1708
- function register(...args) {
1709
- registeredSearchers.push(...args);
1710
- }
1711
- function createSearcher(pattern, options) {
1712
- for (let i = 0, len = registeredSearchers.length; i < len; i += 1) {
1713
- let searcherClass = registeredSearchers[i];
1714
- if (searcherClass.condition(pattern, options)) {
1715
- return new searcherClass(pattern, options);
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
+ }
1716
1709
  }
1717
1710
  }
1718
- return new BitapSearch(pattern, options);
1711
+ return dist;
1719
1712
  }
1720
- var LogicalOperator = {
1721
- AND: "$and",
1722
- OR: "$or"
1723
- };
1724
- var KeyType = {
1725
- PATH: "$path",
1726
- PATTERN: "$val"
1727
- };
1728
- var isExpression = (query) => !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);
1729
- var isPath = (query) => !!query[KeyType.PATH];
1730
- var isLeaf = (query) => !isArray(query) && isObject(query) && !isExpression(query);
1731
- var convertToExplicit = (query) => ({
1732
- [LogicalOperator.AND]: Object.keys(query).map((key) => ({
1733
- [key]: query[key]
1734
- }))
1735
- });
1736
- function parse(query, options, { auto = true } = {}) {
1737
- const next = (query2) => {
1738
- let keys = Object.keys(query2);
1739
- const isQueryPath = isPath(query2);
1740
- if (!isQueryPath && keys.length > 1 && !isExpression(query2)) {
1741
- return next(convertToExplicit(query2));
1742
- }
1743
- if (isLeaf(query2)) {
1744
- const key = isQueryPath ? query2[KeyType.PATH] : keys[0];
1745
- const pattern = isQueryPath ? query2[KeyType.PATTERN] : query2[key];
1746
- if (!isString(pattern)) {
1747
- throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));
1748
- }
1749
- const obj = {
1750
- keyId: createKeyId(key),
1751
- pattern
1752
- };
1753
- if (auto) {
1754
- obj.searcher = createSearcher(pattern, options);
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];
1755
1728
  }
1756
- return obj;
1757
1729
  }
1758
- let node = {
1759
- children: [],
1760
- operator: keys[0]
1761
- };
1762
- keys.forEach((key) => {
1763
- const value = query2[key];
1764
- if (isArray(value)) {
1765
- value.forEach((item) => {
1766
- node.children.push(next(item));
1767
- });
1768
- }
1769
- });
1770
- return node;
1771
- };
1772
- if (!isExpression(query)) {
1773
- query = convertToExplicit(query);
1774
1730
  }
1775
- return next(query);
1731
+ return best;
1776
1732
  }
1777
- function computeScore(results, { ignoreFieldNorm = Config.ignoreFieldNorm }) {
1778
- results.forEach((result) => {
1779
- let totalScore = 1;
1780
- result.matches.forEach(({ key, norm: norm2, score }) => {
1781
- const weight = key ? key.weight : null;
1782
- totalScore *= Math.pow(
1783
- score === 0 && weight ? Number.EPSILON : score,
1784
- (weight || 1) * (ignoreFieldNorm ? 1 : norm2)
1785
- );
1786
- });
1787
- result.score = totalScore;
1788
- });
1733
+ function centerlineSnapPath(path, clearance, isWalkableCell, radius = 4) {
1734
+ const snapped = path.map((p) => snapPointToClearancePeak(p, clearance, isWalkableCell, radius));
1735
+ return snapped;
1789
1736
  }
1790
- function transformMatches(result, data) {
1791
- const matches = result.matches;
1792
- data.matches = [];
1793
- if (!isDefined(matches)) {
1794
- return;
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
+ }
1795
1804
  }
1796
- matches.forEach((match) => {
1797
- if (!isDefined(match.indices) || !match.indices.length) {
1798
- return;
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 };
1799
1814
  }
1800
- const { indices, value } = match;
1801
- let obj = {
1802
- indices,
1803
- value
1804
- };
1805
- if (match.key) {
1806
- obj.key = match.key.src;
1815
+ distEnd = (0, import_distance4.default)(pt, end);
1816
+ if (!isInsideObstacle && distEnd < minDistEnd) {
1817
+ minDistEnd = distEnd;
1818
+ closestToEnd = { x: column, y: row };
1807
1819
  }
1808
- if (match.idx > -1) {
1809
- obj.refIndex = match.idx;
1820
+ if (column < roundLoopX) {
1821
+ currentX += cellWidth;
1822
+ column++;
1823
+ continue;
1810
1824
  }
1811
- data.matches.push(obj);
1812
- });
1813
- }
1814
- function transformScore(result, data) {
1815
- data.score = result.score;
1816
- }
1817
- function format(results, docs, {
1818
- includeMatches = Config.includeMatches,
1819
- includeScore = Config.includeScore
1820
- } = {}) {
1821
- const transformers = [];
1822
- if (includeMatches) transformers.push(transformMatches);
1823
- if (includeScore) transformers.push(transformScore);
1824
- return results.map((result) => {
1825
- const { idx } = result;
1826
- const data = {
1827
- item: docs[idx],
1828
- refIndex: idx
1829
- };
1830
- if (transformers.length) {
1831
- transformers.forEach((transformer) => {
1832
- transformer(result, data);
1833
- });
1825
+ if (row < roundLoopY) {
1826
+ currentY -= cellHeight;
1827
+ currentX = west + deltaX;
1828
+ column = 0;
1829
+ row++;
1834
1830
  }
1835
- return data;
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]]);
1836
1856
  });
1857
+ path.push(endCoord);
1858
+ return (0, import_clean_coords.cleanCoords)(lineString(path));
1837
1859
  }
1838
- var Fuse = class {
1839
- constructor(docs, options = {}, index) {
1840
- this.options = { ...Config, ...options };
1841
- if (this.options.useExtendedSearch && false) {
1842
- throw new Error(EXTENDED_SEARCH_UNAVAILABLE);
1843
- }
1844
- this._keyStore = new KeyStore(this.options.keys);
1845
- this.setCollection(docs, index);
1846
- }
1847
- setCollection(docs, index) {
1848
- this._docs = docs;
1849
- if (index && !(index instanceof FuseIndex)) {
1850
- throw new Error(INCORRECT_INDEX_TYPE);
1851
- }
1852
- this._myIndex = index || createIndex(this.options.keys, this._docs, {
1853
- getFn: this.options.getFn,
1854
- fieldNormWeight: this.options.fieldNormWeight
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));
1855
1870
  });
1856
- }
1857
- add(doc) {
1858
- if (!isDefined(doc)) {
1859
- return;
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/landmark/createLandmarkUtils.ts
1932
+ var import_center6 = require("@turf/center");
1933
+ var import_distance5 = __toESM(require("@turf/distance"));
1934
+ var NEARBY_DISTANCE = 30;
1935
+ var createLandmarkUtils = (options) => {
1936
+ const { data, findByIdSync } = options;
1937
+ const { occupants } = data;
1938
+ const occupantToLandmark = (occupant) => {
1939
+ const locationType = occupant.properties.unit_id ? "unit" : "kiosk";
1940
+ const locationId = locationType === "unit" ? occupant.properties.unit_id : occupant.properties.kiosk_id;
1941
+ const location = locationType === "unit" ? findByIdSync(locationId) : findByIdSync(locationId);
1942
+ const level = findByIdSync(location.properties.level_id);
1943
+ return {
1944
+ name: occupant.properties.name,
1945
+ point: (0, import_center6.center)(location.geometry).geometry.coordinates,
1946
+ level_id: location.properties.level_id,
1947
+ is_priority: occupant.properties.is_landmark,
1948
+ ordinal: level.properties.ordinal
1949
+ };
1950
+ };
1951
+ const landmarks = [
1952
+ ...occupants.map(occupantToLandmark)
1953
+ ];
1954
+ const findNearbyLandmarks = (point2, levelId) => {
1955
+ if (point2 === null || levelId === null) return [];
1956
+ return landmarks.map((landmark) => {
1957
+ const landmarkAndDistance = {
1958
+ landmark,
1959
+ d: (0, import_distance5.default)(point2, landmark.point, { units: "meters" })
1960
+ };
1961
+ return landmarkAndDistance;
1962
+ }).filter(({ landmark, d }) => d <= NEARBY_DISTANCE && landmark.level_id === levelId).sort((a, b) => {
1963
+ const aPriority = a.landmark.is_priority ? 0 : 1;
1964
+ const bPriority = b.landmark.is_priority ? 0 : 1;
1965
+ if (aPriority !== bPriority) return aPriority - bPriority;
1966
+ return a.d - b.d;
1967
+ }).map(({ landmark }) => landmark);
1968
+ };
1969
+ const findNearestLandmark = (point2, levelId) => {
1970
+ const nearbyLandmarks = findNearbyLandmarks(point2, levelId);
1971
+ const nearestLandmark = nearbyLandmarks.length > 0 ? nearbyLandmarks[0] : null;
1972
+ return nearestLandmark;
1973
+ };
1974
+ return { findNearbyLandmarks, findNearestLandmark };
1975
+ };
1976
+
1977
+ // src/data/navigate/steps/utils/extractStartPoint.ts
1978
+ var import_center7 = require("@turf/center");
1979
+
1980
+ // src/data/navigate/steps/utils/featureIdGuard.ts
1981
+ var isOccupant = (id) => !!id && id.startsWith("occupant-");
1982
+ var isUnit = (id) => !!id && id.startsWith("unit-");
1983
+ var isKiosk = (id) => !!id && id.startsWith("kiosk-");
1984
+ var isOpening = (id) => !!id && id.startsWith("opening-");
1985
+
1986
+ // src/data/navigate/type-guard.ts
1987
+ function isCoordinateOrdinalString(id) {
1988
+ return /^-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?o$/.test(id);
1989
+ }
1990
+
1991
+ // src/data/navigate/steps/utils/extractStartPoint.ts
1992
+ var extractStartPoint = (path, options) => {
1993
+ const { findByIdSync } = options;
1994
+ const [a, b, c] = path;
1995
+ if (isOccupant(a) && isUnit(b) && isOpening(c)) {
1996
+ const occ = findByIdSync(a);
1997
+ const opening = findByIdSync(c);
1998
+ const level = findByIdSync(opening.properties.level_id);
1999
+ return [
2000
+ {
2001
+ id: occ.id,
2002
+ type: "start",
2003
+ name: occ.properties.name,
2004
+ point: (0, import_center7.center)(opening).geometry.coordinates,
2005
+ levelId: opening.properties.level_id,
2006
+ ordinal: level.properties.ordinal,
2007
+ source: { type: "opening", id: opening.id }
2008
+ },
2009
+ path.slice(3)
2010
+ ];
2011
+ }
2012
+ if (isOccupant(a) && isKiosk(b)) {
2013
+ const occ = findByIdSync(a);
2014
+ const kiosk = findByIdSync(c);
2015
+ const level = findByIdSync(kiosk.properties.level_id);
2016
+ return [
2017
+ {
2018
+ id: occ.id,
2019
+ type: "start",
2020
+ name: occ.properties.name,
2021
+ point: (0, import_center7.center)(kiosk).geometry.coordinates,
2022
+ levelId: kiosk.properties.level_id,
2023
+ ordinal: level.properties.ordinal,
2024
+ source: { type: "kiosk", id: kiosk.id }
2025
+ },
2026
+ path.slice(2)
2027
+ ];
2028
+ }
2029
+ if (isCoordinateOrdinalString(a) && isOpening(b)) {
2030
+ const [lat, lng, ordinal] = parseOrdinalCoordinate(a);
2031
+ const opening = findByIdSync(b);
2032
+ return [
2033
+ {
2034
+ id: a,
2035
+ type: "start",
2036
+ name: { en: `Your location` },
2037
+ point: [lng, lat],
2038
+ levelId: opening.properties.level_id,
2039
+ ordinal,
2040
+ source: { type: "opening", id: opening.id }
2041
+ },
2042
+ path.slice(1)
2043
+ ];
2044
+ }
2045
+ return [null, path];
2046
+ };
2047
+
2048
+ // src/data/navigate/steps/utils/extractEndPint.ts
2049
+ var import_center8 = require("@turf/center");
2050
+ var extractEndPoint = (path, options) => {
2051
+ const { findByIdSync } = options;
2052
+ const [c, b, a] = path.slice(-3);
2053
+ if (isOccupant(a) && isUnit(b) && isOpening(c)) {
2054
+ const occ = findByIdSync(a);
2055
+ const opening = findByIdSync(c);
2056
+ const level = findByIdSync(opening.properties.level_id);
2057
+ return [
2058
+ {
2059
+ id: occ.id,
2060
+ type: "end",
2061
+ name: occ.properties.name,
2062
+ point: (0, import_center8.center)(opening).geometry.coordinates,
2063
+ levelId: opening.properties.level_id,
2064
+ ordinal: level.properties.ordinal,
2065
+ source: { type: "opening", id: opening.id }
2066
+ },
2067
+ path.slice(0, -3)
2068
+ ];
2069
+ }
2070
+ if (isOccupant(a) && isKiosk(b)) {
2071
+ const occ = findByIdSync(a);
2072
+ const kiosk = findByIdSync(c);
2073
+ const level = findByIdSync(kiosk.properties.level_id);
2074
+ return [
2075
+ {
2076
+ id: occ.id,
2077
+ type: "end",
2078
+ name: occ.properties.name,
2079
+ point: (0, import_center8.center)(kiosk).geometry.coordinates,
2080
+ levelId: kiosk.properties.level_id,
2081
+ ordinal: level.properties.ordinal,
2082
+ source: { type: "kiosk", id: kiosk.id }
2083
+ },
2084
+ path.slice(0, -2)
2085
+ ];
2086
+ }
2087
+ if (isCoordinateOrdinalString(a)) {
2088
+ const [lat, lng, ordinal] = parseOrdinalCoordinate(a);
2089
+ const opening = findByIdSync(b);
2090
+ return [
2091
+ {
2092
+ id: a,
2093
+ type: "end",
2094
+ name: { en: `Your location` },
2095
+ point: [lng, lat],
2096
+ levelId: opening.properties.level_id,
2097
+ ordinal,
2098
+ source: { type: "opening", id: opening.id }
2099
+ },
2100
+ path.slice(0, -2)
2101
+ ];
2102
+ }
2103
+ return [null, path];
2104
+ };
2105
+
2106
+ // src/data/navigate/steps/utils/combineWalkwaySteps.ts
2107
+ var import_uniq = __toESM(require("lodash/uniq"));
2108
+ var combineWalkwaySteps = (steps) => {
2109
+ let result = [];
2110
+ for (let i = 0; i < steps.length; i++) {
2111
+ const thisStep = steps[i];
2112
+ if (i === steps.length - 1) {
2113
+ result.push(thisStep);
2114
+ continue;
1860
2115
  }
1861
- this._docs.push(doc);
1862
- this._myIndex.add(doc);
1863
- }
1864
- remove(predicate = () => false) {
1865
- const results = [];
1866
- for (let i = 0, len = this._docs.length; i < len; i += 1) {
1867
- const doc = this._docs[i];
1868
- if (predicate(doc, i)) {
1869
- this.removeAt(i);
1870
- i -= 1;
1871
- len -= 1;
1872
- results.push(doc);
1873
- }
2116
+ const nextStep = steps[i + 1];
2117
+ if (thisStep.intermediaryCategory === "walkway" && nextStep.intermediaryCategory === "walkway" && thisStep.from.source.type === "opening" && nextStep.from.source.type === "opening") {
2118
+ console.log({ i, len: steps.length, thisStep, nextStep });
2119
+ result.push({
2120
+ from: thisStep.from,
2121
+ to: nextStep.to,
2122
+ levelIds: (0, import_uniq.default)([...thisStep.levelIds, ...nextStep.levelIds]),
2123
+ ordinals: (0, import_uniq.default)([...thisStep.ordinals, ...nextStep.ordinals]),
2124
+ intermediaryCategory: "walkway",
2125
+ description: nextStep.description,
2126
+ path: [
2127
+ ...thisStep.path,
2128
+ ...nextStep.path
2129
+ ]
2130
+ });
2131
+ i++;
2132
+ } else {
2133
+ result.push(thisStep);
1874
2134
  }
1875
- return results;
1876
- }
1877
- removeAt(idx) {
1878
- this._docs.splice(idx, 1);
1879
- this._myIndex.removeAt(idx);
1880
- }
1881
- getIndex() {
1882
- return this._myIndex;
1883
2135
  }
1884
- search(query, { limit = -1 } = {}) {
1885
- const {
1886
- includeMatches,
1887
- includeScore,
1888
- shouldSort,
1889
- sortFn,
1890
- ignoreFieldNorm
1891
- } = this.options;
1892
- let results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query);
1893
- computeScore(results, { ignoreFieldNorm });
1894
- if (shouldSort) {
1895
- results.sort(sortFn);
2136
+ return result;
2137
+ };
2138
+
2139
+ // src/data/navigate/steps/createStepUtils.ts
2140
+ var createStepUtils = (options) => {
2141
+ const { data: { units, relationships }, findByIdSync } = options;
2142
+ const landmarkUtils = createLandmarkUtils(options);
2143
+ const stepPathUtils = createStepPathUtils({ ...options, resolution: 88e-5 });
2144
+ const findUnitBetweenOpenings = (originId, destinationId) => {
2145
+ const origin = findByIdSync(originId);
2146
+ const destination = findByIdSync(destinationId);
2147
+ const matchedOne = relationships.find((rel) => rel.properties.intermediary.map((int) => int.id).includes(origin.id));
2148
+ const matchOneUnits = [matchedOne.properties.origin, matchedOne.properties.destination];
2149
+ const matchedTwo = relationships.find((rel) => rel.properties.intermediary.map((int) => int.id).includes(destination.id));
2150
+ const matchTwoUnits = [matchedTwo.properties.origin, matchedTwo.properties.destination];
2151
+ const unitIds = (0, import_intersectionBy.default)(matchOneUnits, matchTwoUnits, "id");
2152
+ return unitIds.map(({ id }) => findByIdSync(id));
2153
+ };
2154
+ const findHorizontalIntermediary = (from, to) => {
2155
+ if (from.source.type !== "opening") {
2156
+ const unit = findContainingUnitAtPoint(from.point, from.levelId, units);
2157
+ return unit ? [unit] : [];
1896
2158
  }
1897
- if (isNumber(limit) && limit > -1) {
1898
- results = results.slice(0, limit);
2159
+ if (to.source.type !== "opening") {
2160
+ const unit = findContainingUnitAtPoint(to.point, to.levelId, units);
2161
+ return unit ? [unit] : [];
1899
2162
  }
1900
- return format(results, this._docs, {
1901
- includeMatches,
1902
- includeScore
2163
+ return findUnitBetweenOpenings(from.source.id, to.source.id);
2164
+ };
2165
+ const findVerticalIntermediary = (from, to) => {
2166
+ const firstOpeningId = from.source.id;
2167
+ const secondOpeningId = to.source.id;
2168
+ const relationship = relationships.find((rel) => {
2169
+ return rel.properties.origin?.id === firstOpeningId && rel.properties.destination?.id === secondOpeningId || rel.properties.origin?.id === secondOpeningId && rel.properties.destination?.id === firstOpeningId;
1903
2170
  });
1904
- }
1905
- _searchStringList(query) {
1906
- const searcher = createSearcher(query, this.options);
1907
- const { records } = this._myIndex;
1908
- const results = [];
1909
- records.forEach(({ v: text, i: idx, n: norm2 }) => {
1910
- if (!isDefined(text)) {
1911
- return;
1912
- }
1913
- const { isMatch, score, indices } = searcher.searchIn(text);
1914
- if (isMatch) {
1915
- results.push({
1916
- item: text,
1917
- idx,
1918
- matches: [{ score, value: text, norm: norm2, indices }]
1919
- });
1920
- }
2171
+ const intermediaryTypeAndId = relationship.properties.intermediary;
2172
+ return intermediaryTypeAndId.map(({ id }) => findByIdSync(id));
2173
+ };
2174
+ const formatCategoryLabel = (category) => {
2175
+ return (0, import_lodash12.capitalize)(category);
2176
+ };
2177
+ const getToward = (from, to, intermediary) => {
2178
+ if (to.type === "end") return to.name;
2179
+ const intermediaryIds = intermediary.map((int) => int.id);
2180
+ const relationship = relationships.find((rel) => rel.properties.intermediary.map((int) => int.id).includes(to.source.id));
2181
+ if (!relationship) return to.name;
2182
+ const candidates = [relationship.properties.origin.id, relationship.properties.destination.id];
2183
+ const nextUnitId = candidates.filter((id) => !intermediaryIds.includes(id))[0];
2184
+ if (!nextUnitId) return to.name;
2185
+ const nextUnit = findByIdSync(nextUnitId);
2186
+ return { en: formatCategoryLabel(`${nextUnit.properties.category}`) };
2187
+ };
2188
+ const toWaypoints = (path) => {
2189
+ const [startPoint, middleAndEndPoints] = extractStartPoint(path, options);
2190
+ const [endPoint, middlePoints] = extractEndPoint(middleAndEndPoints, options);
2191
+ const waypoints = middlePoints.map((openingId) => {
2192
+ const opening = findByIdSync(openingId);
2193
+ const level = findByIdSync(opening.properties.level_id);
2194
+ const coordinates = (0, import_center9.center)(opening).geometry.coordinates;
2195
+ const landmark = landmarkUtils.findNearestLandmark(coordinates, opening.properties.level_id);
2196
+ return {
2197
+ id: `${opening.properties.level_id}:${openingId}`,
2198
+ type: "between",
2199
+ point: coordinates,
2200
+ name: null,
2201
+ levelId: opening.properties.level_id,
2202
+ ordinal: level.properties.ordinal,
2203
+ hint: landmark ? { kind: "landmark", name: landmark.name } : void 0,
2204
+ source: { type: "opening", id: opening.id }
2205
+ };
1921
2206
  });
1922
- return results;
1923
- }
1924
- _searchLogical(query) {
1925
- const expression = parse(query, this.options);
1926
- const evaluate = (node, item, idx) => {
1927
- if (!node.children) {
1928
- const { keyId, searcher } = node;
1929
- const matches = this._findMatches({
1930
- key: this._keyStore.get(keyId),
1931
- value: this._myIndex.getValueForItemAtKeyId(item, keyId),
1932
- searcher
1933
- });
1934
- if (matches && matches.length) {
1935
- return [
1936
- {
1937
- idx,
1938
- item,
1939
- matches
1940
- }
1941
- ];
1942
- }
1943
- return [];
1944
- }
1945
- const res = [];
1946
- for (let i = 0, len = node.children.length; i < len; i += 1) {
1947
- const child = node.children[i];
1948
- const result = evaluate(child, item, idx);
1949
- if (result.length) {
1950
- res.push(...result);
1951
- } else if (node.operator === LogicalOperator.AND) {
1952
- return [];
1953
- }
1954
- }
1955
- return res;
2207
+ return [startPoint, ...waypoints, endPoint];
2208
+ };
2209
+ const createHorizontalStep = (from, to) => {
2210
+ const intermediary = findHorizontalIntermediary(from, to);
2211
+ const intermediaryCategories = intermediary.map((unit) => unit.properties.category);
2212
+ const intermediaryCategory = intermediaryCategories.length > 0 ? intermediaryCategories[0] : "unspecified";
2213
+ const toward = getToward(from, to, intermediary);
2214
+ const landmark = to.hint?.kind === "landmark" ? to.hint.name : null;
2215
+ const path = stepPathUtils.findStepPath(from.point, to.point, intermediary);
2216
+ const step = {
2217
+ from,
2218
+ to,
2219
+ levelIds: [from.levelId],
2220
+ ordinals: [from.ordinal],
2221
+ intermediaryCategory,
2222
+ description: describeHorizontalStep(intermediaryCategory, toward, landmark),
2223
+ path: path.map((coord) => [...coord, from.ordinal * 9])
1956
2224
  };
1957
- const records = this._myIndex.records;
1958
- const resultMap = {};
1959
- const results = [];
1960
- records.forEach(({ $: item, i: idx }) => {
1961
- if (isDefined(item)) {
1962
- let expResults = evaluate(expression, item, idx);
1963
- if (expResults.length) {
1964
- if (!resultMap[idx]) {
1965
- resultMap[idx] = { idx, item, matches: [] };
1966
- results.push(resultMap[idx]);
1967
- }
1968
- expResults.forEach(({ matches }) => {
1969
- resultMap[idx].matches.push(...matches);
1970
- });
1971
- }
1972
- }
1973
- });
1974
- return results;
1975
- }
1976
- _searchObjectList(query) {
1977
- const searcher = createSearcher(query, this.options);
1978
- const { keys, records } = this._myIndex;
1979
- const results = [];
1980
- records.forEach(({ $: item, i: idx }) => {
1981
- if (!isDefined(item)) {
1982
- return;
1983
- }
1984
- let matches = [];
1985
- keys.forEach((key, keyIndex) => {
1986
- matches.push(
1987
- ...this._findMatches({
1988
- key,
1989
- value: item[keyIndex],
1990
- searcher
1991
- })
1992
- );
1993
- });
1994
- if (matches.length) {
1995
- results.push({
1996
- idx,
1997
- item,
1998
- matches
1999
- });
2000
- }
2001
- });
2002
- return results;
2003
- }
2004
- _findMatches({ key, value, searcher }) {
2005
- if (!isDefined(value)) {
2006
- return [];
2007
- }
2008
- let matches = [];
2009
- if (isArray(value)) {
2010
- value.forEach(({ v: text, i: idx, n: norm2 }) => {
2011
- if (!isDefined(text)) {
2012
- return;
2013
- }
2014
- const { isMatch, score, indices } = searcher.searchIn(text);
2015
- if (isMatch) {
2016
- matches.push({
2017
- score,
2018
- key,
2019
- value: text,
2020
- idx,
2021
- norm: norm2,
2022
- indices
2023
- });
2024
- }
2025
- });
2026
- } else {
2027
- const { v: text, n: norm2 } = value;
2028
- const { isMatch, score, indices } = searcher.searchIn(text);
2029
- if (isMatch) {
2030
- matches.push({ score, key, value: text, norm: norm2, indices });
2031
- }
2225
+ return step;
2226
+ };
2227
+ const createVerticalStep = (from, to) => {
2228
+ const intermediary = findVerticalIntermediary(from, to);
2229
+ const intermediaryCategories = intermediary.map((unit) => unit.properties.category);
2230
+ const intermediaryCategory = intermediaryCategories.length > 0 ? intermediaryCategories[0] : "unspecified";
2231
+ const fromLevel = findByIdSync(from.levelId);
2232
+ const toLevel = findByIdSync(to.levelId);
2233
+ return {
2234
+ from,
2235
+ to,
2236
+ levelIds: [from.levelId, to.levelId],
2237
+ ordinals: [from.ordinal, to.ordinal],
2238
+ intermediaryCategory,
2239
+ description: describeVerticalStep(fromLevel, toLevel, intermediaryCategory),
2240
+ path: [
2241
+ [...from.point, from.ordinal * 9],
2242
+ [...to.point, to.ordinal * 9]
2243
+ ]
2244
+ };
2245
+ };
2246
+ const isVertical = (from, to) => {
2247
+ const fromLevel = findByIdSync(from.levelId);
2248
+ const toLevel = findByIdSync(to.levelId);
2249
+ return !!fromLevel && !!toLevel && fromLevel.properties.ordinal !== toLevel.properties.ordinal;
2250
+ };
2251
+ const toSteps = (waypoints) => {
2252
+ let steps = [];
2253
+ const t0_allSteps = performance.now();
2254
+ for (let i = 0; i < waypoints.length - 1; i++) {
2255
+ const from = waypoints[i];
2256
+ const to = waypoints[i + 1];
2257
+ const t0 = performance.now();
2258
+ const step = isVertical(from, to) ? createVerticalStep(from, to) : createHorizontalStep(from, to);
2259
+ steps.push(step);
2260
+ const t1 = performance.now();
2261
+ trace("nav", ` \u2502 \u251C\u2500 #${i} ${from.id.padEnd(25)} \u2192 ${`(${step.intermediaryCategory})`.padEnd(12)} \u2192 ${to.id}`, t1 - t0);
2262
+ trace("nav", ` \u2502 \u2502 ${step.description.text}`, void 0, "#bada55");
2032
2263
  }
2033
- return matches;
2034
- }
2264
+ const simplifySteps = combineWalkwaySteps(steps);
2265
+ const t1_allSteps = performance.now();
2266
+ trace("nav", " \u2502 \u2514\u2500 Total ", t1_allSteps - t0_allSteps);
2267
+ return simplifySteps;
2268
+ };
2269
+ return {
2270
+ // createSteps,
2271
+ toWaypoints,
2272
+ toSteps
2273
+ };
2035
2274
  };
2036
- Fuse.version = "7.1.0";
2037
- Fuse.createIndex = createIndex;
2038
- Fuse.parseIndex = parseIndex;
2039
- Fuse.config = Config;
2040
- {
2041
- Fuse.parseQuery = parse;
2042
- }
2043
- {
2044
- register(ExtendedSearch);
2045
- }
2046
2275
 
2047
- // src/data/search/utils/sanitizeInput.ts
2048
- var sanitizeInput = (str) => str.replace(/[\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, "").replace(/[\-–—_./()]+/g, "").normalize("NFC").trim();
2276
+ // src/data/navigate/utils/timeDistance.ts
2277
+ var import_length = __toESM(require("@turf/length"));
2278
+ var WALKING_SPEED = 1.4;
2279
+ var calculatePathLength = (feature2) => (0, import_length.default)(feature2, { units: "kilometers" }) * 1e3;
2280
+ var calculateTravelingDuration = (distance5) => {
2281
+ const duration = distance5 / WALKING_SPEED;
2282
+ const minutes = Math.round(duration / 60);
2283
+ return minutes > 0 ? minutes : 1;
2284
+ };
2285
+ var calculateTotalDistance = (steps = []) => {
2286
+ return steps.reduce((acc, { path }) => acc + calculatePathLength(lineString(path)), 0);
2287
+ };
2288
+ var calculateRoundedDistance = (distance5) => {
2289
+ return Math.round(distance5 - distance5 % 25);
2290
+ };
2049
2291
 
2050
- // src/data/search/getSearchClient.ts
2051
- var getSearchClient = ({ occupants, amenities }) => {
2052
- const fuseAmenities = new Fuse(amenities, {
2053
- threshold: 0.2,
2054
- keys: [
2055
- { name: "properties.name", "weight": 1, getFn: (obj) => Object.values(obj.properties.name || {}) },
2056
- { name: "properties.category", "weight": 1 }
2057
- ]
2058
- });
2059
- const fuseOccupants = new Fuse(occupants, {
2060
- threshold: 0.25,
2061
- // 0.2 is too strict (can't find Mo-Mo Paradise with "momo" search string)
2062
- includeScore: true,
2063
- shouldSort: true,
2064
- keys: [
2065
- { name: "properties.name", "weight": 4, getFn: (obj) => Object.values(obj.properties.name || {}) },
2066
- { name: "properties.keywords", "weight": 0.5 },
2067
- { name: "properties.category", "weight": 0.25 },
2068
- { name: "properties.local_category_names", "weight": 0.25 },
2069
- { name: "properties.description", "weight": 0.25, getFn: (occ) => Object.values(occ.properties.description || {}) },
2070
- { name: "properties.unit_name", "weight": 0.25 },
2071
- { name: "properties.kiosk_name", "weight": 0.25 }
2072
- ]
2073
- });
2074
- const search2 = (value) => {
2075
- const sanitizedValue = sanitizeInput(value);
2076
- const matchedAmenities = fuseAmenities.search(sanitizedValue);
2077
- const matchedOccupants = fuseOccupants.search(sanitizedValue);
2078
- return [...matchedAmenities, ...matchedOccupants];
2292
+ // src/data/navigate/utils/createFindByIdSync.ts
2293
+ var createFindByIdSync = (data) => {
2294
+ const { amenities = [], anchors = [], fixtures = [], levels = [], kiosks = [], relationships = [], occupants = [], openings = [], units } = data;
2295
+ const featureById = /* @__PURE__ */ new Map();
2296
+ const entries = [
2297
+ ...amenities,
2298
+ ...anchors,
2299
+ ...fixtures,
2300
+ ...levels,
2301
+ ...kiosks,
2302
+ ...relationships,
2303
+ ...occupants,
2304
+ ...openings,
2305
+ ...units
2306
+ ];
2307
+ for (const f of entries) featureById.set(f.id, f);
2308
+ const findByIdSync = (id) => {
2309
+ return featureById.get(id);
2310
+ };
2311
+ return { findByIdSync };
2312
+ };
2313
+
2314
+ // src/data/navigate/getNavigateClient.ts
2315
+ var getNavigateClient = (options) => {
2316
+ const { data } = options;
2317
+ const { levels, units } = data;
2318
+ trace("nav", "\u2713 prepare");
2319
+ const t0 = performance.now();
2320
+ trace("nav", " \u251C\u2500 createGraph (dijkstra)");
2321
+ const { defaultGraph, accessibleGraph, addCoordinateOrdinalNode } = prepareGraph({ data });
2322
+ const t1 = performance.now();
2323
+ trace("nav", " \u2502 \u2514\u2500 Total ", t1 - t0);
2324
+ const t2 = performance.now();
2325
+ const { findByIdSync } = createFindByIdSync(data);
2326
+ const t3 = performance.now();
2327
+ trace("nav", " \u2514\u2500 findByIdSync", t3 - t2);
2328
+ const findCoordinateOrdinalUnit = (params) => {
2329
+ const [lat, lng, ordinal] = parseOrdinalCoordinate(params);
2330
+ const levelIdsWithOrdinal = levels.filter((level) => level.properties.ordinal === ordinal).map((level) => level.id);
2331
+ const unit = units.find((unit2) => levelIdsWithOrdinal.includes(unit2.properties.level_id) && (0, import_boolean_point_in_polygon4.booleanPointInPolygon)([lat, lng], unit2));
2332
+ return unit;
2333
+ };
2334
+ const stepUtils = createStepUtils({ ...options, findByIdSync });
2335
+ const findRoute = async (routeOriginParam, routeDestinationParam, options2) => {
2336
+ if (!routeOriginParam || !routeDestinationParam) return null;
2337
+ const graph = options2?.mode === "accessible" ? accessibleGraph : defaultGraph;
2338
+ if (isCoordinateOrdinalString(routeOriginParam)) {
2339
+ const walkwayUnit = findCoordinateOrdinalUnit(routeOriginParam);
2340
+ addCoordinateOrdinalNode(routeOriginParam, walkwayUnit);
2341
+ }
2342
+ if (isCoordinateOrdinalString(routeDestinationParam)) {
2343
+ const walkwayUnit = findCoordinateOrdinalUnit(routeDestinationParam);
2344
+ addCoordinateOrdinalNode(routeDestinationParam, walkwayUnit);
2345
+ }
2346
+ try {
2347
+ trace("nav", "\u2713 findRoute", 0);
2348
+ const t02 = performance.now();
2349
+ const path = graph.path(routeOriginParam, routeDestinationParam);
2350
+ const t12 = performance.now();
2351
+ trace("nav", " \u251C\u2500 path (dijkstra)", t12 - t02);
2352
+ const waypoints = stepUtils.toWaypoints(path);
2353
+ console.log({ waypoints });
2354
+ const t22 = performance.now();
2355
+ trace("nav", " \u251C\u2500 toWaypoints", t22 - t12);
2356
+ trace("nav", " \u251C\u2500 toSteps", 0);
2357
+ const steps = stepUtils.toSteps(waypoints);
2358
+ const t32 = performance.now();
2359
+ const totalDistance = calculateTotalDistance(steps);
2360
+ const roundedDistance = calculateRoundedDistance(totalDistance);
2361
+ const duration = calculateTravelingDuration(totalDistance);
2362
+ const t4 = performance.now();
2363
+ trace("nav", " \u2514\u2500 postProcess", t4 - t32);
2364
+ return {
2365
+ // origin: routeOrigin,
2366
+ // destination: routeDestination,
2367
+ description: null,
2368
+ distance: roundedDistance,
2369
+ duration,
2370
+ steps
2371
+ };
2372
+ } catch (error) {
2373
+ console.log(error);
2374
+ throw error;
2375
+ }
2079
2376
  };
2080
2377
  return {
2081
- search: search2
2378
+ findRoute,
2379
+ findByIdSync
2082
2380
  };
2083
2381
  };
2084
2382
 
2085
2383
  // src/data/getDataClient.ts
2086
2384
  var getDataClient = (options) => {
2087
2385
  let searchClient;
2386
+ let navigateClient;
2088
2387
  const observers = /* @__PURE__ */ new Map();
2089
2388
  const queryClient = options.queryClient ?? new import_query_core.QueryClient();
2090
2389
  const { mode = "delivery", projectId, apiKey, baseUrl, previewToken } = options;
@@ -2115,17 +2414,17 @@ var getDataClient = (options) => {
2115
2414
  const internalFindById = async (id) => {
2116
2415
  if (id === null || id === void 0) return null;
2117
2416
  const featureType = id.slice(0, id.lastIndexOf("-"));
2118
- const feature = await queryClient.ensureQueryData({
2417
+ const feature2 = await queryClient.ensureQueryData({
2119
2418
  queryKey: ["_deliveryapi", featureType, id],
2120
2419
  queryFn: async () => {
2121
2420
  const features = await internalFilterByType(featureType);
2122
- const feature2 = features.find(
2421
+ const feature3 = features.find(
2123
2422
  (f) => f.id === id
2124
2423
  );
2125
- return feature2 ?? null;
2424
+ return feature3 ?? null;
2126
2425
  }
2127
2426
  });
2128
- return feature;
2427
+ return feature2;
2129
2428
  };
2130
2429
  const populator = createPopulator({ internalFindById, internalFilterByType });
2131
2430
  const registerObserver = (featureType, refetchInterval) => {
@@ -2174,8 +2473,8 @@ var getDataClient = (options) => {
2174
2473
  const createFindByIdQueryOptions = (featureType, id, params = {}, options2 = {}) => ({
2175
2474
  queryKey: [featureType, "detail", id, params],
2176
2475
  queryFn: async () => {
2177
- const feature = await internalFindById(id);
2178
- return params.populate === true ? await populator[featureType](feature) : Promise.resolve(feature);
2476
+ const feature2 = await internalFindById(id);
2477
+ return params.populate === true ? await populator[featureType](feature2) : Promise.resolve(feature2);
2179
2478
  },
2180
2479
  ...options2 ?? {}
2181
2480
  });
@@ -2193,8 +2492,8 @@ var getDataClient = (options) => {
2193
2492
  id,
2194
2493
  params
2195
2494
  );
2196
- const feature = await queryClient.ensureQueryData(findQueryOptions);
2197
- return feature;
2495
+ const feature2 = await queryClient.ensureQueryData(findQueryOptions);
2496
+ return feature2;
2198
2497
  }
2199
2498
  const searchFn = async (txt) => {
2200
2499
  if (!searchClient) {
@@ -2207,6 +2506,24 @@ var getDataClient = (options) => {
2207
2506
  }
2208
2507
  return searchClient.search(txt);
2209
2508
  };
2509
+ const navigateFn = async (origin, destination) => {
2510
+ if (!navigateClient) {
2511
+ const [levels, occupants, openings, relationships, units, fixtures, kiosks, amenities, anchors] = await Promise.all([
2512
+ filterByType("level"),
2513
+ filterByType("occupant"),
2514
+ filterByType("opening"),
2515
+ filterByType("relationship"),
2516
+ filterByType("unit"),
2517
+ filterByType("fixture"),
2518
+ filterByType("kiosk"),
2519
+ filterByType("amenity"),
2520
+ filterByType("anchor")
2521
+ ]);
2522
+ const haystack = { levels, occupants, openings, relationships, units, fixtures, kiosks, amenities, anchors };
2523
+ navigateClient = getNavigateClient({ data: haystack });
2524
+ }
2525
+ return navigateClient.findRoute(origin, destination);
2526
+ };
2210
2527
  return {
2211
2528
  projectId,
2212
2529
  queryClient,
@@ -2218,7 +2535,8 @@ var getDataClient = (options) => {
2218
2535
  _internalFindById: internalFindById,
2219
2536
  filterByType,
2220
2537
  findById,
2221
- search: searchFn
2538
+ search: searchFn,
2539
+ navigate: navigateFn
2222
2540
  };
2223
2541
  };
2224
2542
  // Annotate the CommonJS export names for ESM import in node: