venue-js 1.4.0-next.18 → 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.
- package/dist/data/index.d.mts +3 -941
- package/dist/data/index.d.ts +3 -941
- package/dist/data/index.js +1618 -1300
- package/dist/data/index.js.map +1 -1
- package/dist/data/index.mjs +1608 -1300
- package/dist/data/index.mjs.map +1 -1
- package/dist/index-C1nZyY-F.d.mts +1002 -0
- package/dist/index-C1nZyY-F.d.ts +1002 -0
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1819 -1714
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1805 -1700
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -1
package/dist/data/index.mjs
CHANGED
|
@@ -272,8 +272,8 @@ var safeFetchFeature = async (featureType, params) => {
|
|
|
272
272
|
};
|
|
273
273
|
|
|
274
274
|
// src/data/utils/geometry-validator.ts
|
|
275
|
-
var isValidCoordinate = (
|
|
276
|
-
return
|
|
275
|
+
var isValidCoordinate = (point2) => {
|
|
276
|
+
return point2.length === 2 && point2.every((coord) => typeof coord === "number");
|
|
277
277
|
};
|
|
278
278
|
function isValidLinearRingCoordinates(ring) {
|
|
279
279
|
if (ring.length < 4) {
|
|
@@ -281,16 +281,16 @@ function isValidLinearRingCoordinates(ring) {
|
|
|
281
281
|
}
|
|
282
282
|
return ring.every(isValidCoordinate) && ring[0][0] === ring[ring.length - 1][0] && ring[0][1] === ring[ring.length - 1][1];
|
|
283
283
|
}
|
|
284
|
-
var isValidPolygonCoordinates = (
|
|
285
|
-
if (Array.isArray(
|
|
286
|
-
return isValidLinearRingCoordinates(
|
|
284
|
+
var isValidPolygonCoordinates = (polygon2) => {
|
|
285
|
+
if (Array.isArray(polygon2[0]) && (polygon2[0].length === 0 || typeof polygon2[0][0] === "number")) {
|
|
286
|
+
return isValidLinearRingCoordinates(polygon2);
|
|
287
287
|
}
|
|
288
|
-
if (Array.isArray(
|
|
289
|
-
if (!isValidLinearRingCoordinates(
|
|
288
|
+
if (Array.isArray(polygon2) && polygon2.length > 0 && Array.isArray(polygon2[0])) {
|
|
289
|
+
if (!isValidLinearRingCoordinates(polygon2[0])) {
|
|
290
290
|
return false;
|
|
291
291
|
}
|
|
292
|
-
for (let i = 1; i <
|
|
293
|
-
if (!isValidLinearRingCoordinates(
|
|
292
|
+
for (let i = 1; i < polygon2.length; i++) {
|
|
293
|
+
if (!isValidLinearRingCoordinates(polygon2[i])) {
|
|
294
294
|
return false;
|
|
295
295
|
}
|
|
296
296
|
}
|
|
@@ -301,16 +301,16 @@ var isValidPolygonCoordinates = (polygon) => {
|
|
|
301
301
|
var isValidMultiPolygonCoordinates = (multipolygon) => {
|
|
302
302
|
return multipolygon.every(isValidPolygonCoordinates);
|
|
303
303
|
};
|
|
304
|
-
var isValidLineStringCoordinates = (
|
|
305
|
-
if (!Array.isArray(
|
|
304
|
+
var isValidLineStringCoordinates = (lineString2) => {
|
|
305
|
+
if (!Array.isArray(lineString2) || lineString2.length < 2) {
|
|
306
306
|
return false;
|
|
307
307
|
}
|
|
308
|
-
const firstPoint =
|
|
309
|
-
const lastPoint =
|
|
308
|
+
const firstPoint = lineString2[0];
|
|
309
|
+
const lastPoint = lineString2[lineString2.length - 1];
|
|
310
310
|
if (firstPoint[0] === lastPoint[0] && firstPoint[1] === lastPoint[1]) {
|
|
311
311
|
return false;
|
|
312
312
|
}
|
|
313
|
-
return
|
|
313
|
+
return lineString2.every(isValidCoordinate);
|
|
314
314
|
};
|
|
315
315
|
var isValidMultiPolygon = (geometry) => {
|
|
316
316
|
const { type, coordinates } = geometry;
|
|
@@ -410,6 +410,19 @@ var findContainingUnit = (poi, units) => {
|
|
|
410
410
|
);
|
|
411
411
|
return unit;
|
|
412
412
|
};
|
|
413
|
+
var findContainingUnitAtPoint = (point2, levelId, units) => {
|
|
414
|
+
const unit = units.find(
|
|
415
|
+
(unit2) => {
|
|
416
|
+
try {
|
|
417
|
+
return unit2.properties.level_id === levelId && booleanPointInPolygon(point2, unit2);
|
|
418
|
+
} catch (e) {
|
|
419
|
+
console.log(`Cannot find containing unit of (point: ${point2}, levelId: ${levelId}):`, e.message);
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
);
|
|
424
|
+
return unit;
|
|
425
|
+
};
|
|
413
426
|
|
|
414
427
|
// src/data/populator/index.ts
|
|
415
428
|
var createPopulator = ({
|
|
@@ -582,6 +595,19 @@ var createPopulator = ({
|
|
|
582
595
|
}
|
|
583
596
|
};
|
|
584
597
|
};
|
|
598
|
+
const populateSection = async (section) => {
|
|
599
|
+
const venue = await internalFindById(section.properties.venue_id);
|
|
600
|
+
const level = await internalFindById(section.properties.level_id);
|
|
601
|
+
return {
|
|
602
|
+
...section,
|
|
603
|
+
properties: {
|
|
604
|
+
...section.properties,
|
|
605
|
+
venue,
|
|
606
|
+
level: await populateLevel(level),
|
|
607
|
+
ordinal: level.properties.ordinal
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
};
|
|
585
611
|
const populateRelationship = async (relationship) => {
|
|
586
612
|
const originId = relationship.properties.origin?.id;
|
|
587
613
|
const destinationId = relationship.properties.destination?.id;
|
|
@@ -599,19 +625,6 @@ var createPopulator = ({
|
|
|
599
625
|
}
|
|
600
626
|
};
|
|
601
627
|
};
|
|
602
|
-
const populateSection = async (section) => {
|
|
603
|
-
const venue = await internalFindById(section.properties.venue_id);
|
|
604
|
-
const level = await internalFindById(section.properties.level_id);
|
|
605
|
-
return {
|
|
606
|
-
...section,
|
|
607
|
-
properties: {
|
|
608
|
-
...section.properties,
|
|
609
|
-
venue,
|
|
610
|
-
level: await populateLevel(level),
|
|
611
|
-
ordinal: level.properties.ordinal
|
|
612
|
-
}
|
|
613
|
-
};
|
|
614
|
-
};
|
|
615
628
|
const populateUnit = async (unit) => {
|
|
616
629
|
const venue = await internalFindById(unit.properties.venue_id);
|
|
617
630
|
const level = await internalFindById(unit.properties.level_id);
|
|
@@ -659,7 +672,7 @@ var createPopulator = ({
|
|
|
659
672
|
console.log(`error finding level`, { model3d, level });
|
|
660
673
|
}
|
|
661
674
|
};
|
|
662
|
-
const populateFeature = (
|
|
675
|
+
const populateFeature = (feature2) => Promise.resolve(feature2);
|
|
663
676
|
return {
|
|
664
677
|
address: populateAddress,
|
|
665
678
|
building: populateBuilding,
|
|
@@ -688,1366 +701,1642 @@ var createPopulator = ({
|
|
|
688
701
|
};
|
|
689
702
|
};
|
|
690
703
|
|
|
691
|
-
//
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
var
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
704
|
+
// src/data/search/getSearchClient.ts
|
|
705
|
+
import Fuse from "fuse.js";
|
|
706
|
+
|
|
707
|
+
// src/data/search/utils/sanitizeInput.ts
|
|
708
|
+
var sanitizeInput = (str) => str.replace(/[\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, "").replace(/[\-–—_./()]+/g, "").normalize("NFC").trim();
|
|
709
|
+
|
|
710
|
+
// src/data/search/getSearchClient.ts
|
|
711
|
+
var getSearchClient = ({ occupants, amenities }) => {
|
|
712
|
+
const fuseAmenities = new Fuse(amenities, {
|
|
713
|
+
threshold: 0.2,
|
|
714
|
+
keys: [
|
|
715
|
+
{ name: "properties.name", "weight": 1, getFn: (obj) => Object.values(obj.properties.name || {}) },
|
|
716
|
+
{ name: "properties.category", "weight": 1 }
|
|
717
|
+
]
|
|
718
|
+
});
|
|
719
|
+
const fuseOccupants = new Fuse(occupants, {
|
|
720
|
+
threshold: 0.25,
|
|
721
|
+
// 0.2 is too strict (can't find Mo-Mo Paradise with "momo" search string)
|
|
722
|
+
includeScore: true,
|
|
723
|
+
shouldSort: true,
|
|
724
|
+
keys: [
|
|
725
|
+
{ name: "properties.name", "weight": 4, getFn: (obj) => Object.values(obj.properties.name || {}) },
|
|
726
|
+
{ name: "properties.keywords", "weight": 0.5 },
|
|
727
|
+
{ name: "properties.category", "weight": 0.25 },
|
|
728
|
+
{ name: "properties.local_category_names", "weight": 0.25 },
|
|
729
|
+
{ name: "properties.description", "weight": 0.25, getFn: (occ) => Object.values(occ.properties.description || {}) },
|
|
730
|
+
{ name: "properties.unit_name", "weight": 0.25 },
|
|
731
|
+
{ name: "properties.kiosk_name", "weight": 0.25 }
|
|
732
|
+
]
|
|
733
|
+
});
|
|
734
|
+
const search = (value) => {
|
|
735
|
+
const sanitizedValue = sanitizeInput(value);
|
|
736
|
+
const matchedAmenities = fuseAmenities.search(sanitizedValue);
|
|
737
|
+
const matchedOccupants = fuseOccupants.search(sanitizedValue);
|
|
738
|
+
return [...matchedAmenities, ...matchedOccupants];
|
|
739
|
+
};
|
|
740
|
+
return {
|
|
741
|
+
search
|
|
742
|
+
};
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
// src/data/navigate/getNavigateClient.ts
|
|
746
|
+
import { booleanPointInPolygon as booleanPointInPolygon4 } from "@turf/boolean-point-in-polygon";
|
|
747
|
+
|
|
748
|
+
// src/data/navigate/graph/prepare.ts
|
|
749
|
+
import _6 from "lodash";
|
|
750
|
+
import DijstraGraph from "node-dijkstra";
|
|
751
|
+
import { distance as distance2 } from "@turf/distance";
|
|
752
|
+
import { center as turfCenter3 } from "@turf/center";
|
|
753
|
+
|
|
754
|
+
// src/data/navigate/graph/nodemap/createTraversalNodeMap.ts
|
|
755
|
+
import { distance as turfDistance } from "@turf/distance";
|
|
756
|
+
import { center as turfCenter } from "@turf/center";
|
|
757
|
+
import _ from "lodash";
|
|
758
|
+
|
|
759
|
+
// src/data/navigate/graph/constants.ts
|
|
760
|
+
var ROOM_BASEDISTANCE = 1e3;
|
|
761
|
+
var TERRACE_BASEDISTANCE = 1e3;
|
|
762
|
+
var ESCALATOR_BASEDISTANCE = 200;
|
|
763
|
+
var RAMP_BASEDISTANCE = 200;
|
|
764
|
+
var ELEVATOR_BASEDISTANCE = 500;
|
|
765
|
+
var STAIR_BASEDISTANCE = 1e5;
|
|
766
|
+
var BASE_POI_BASEDISTANCE = 9999999;
|
|
767
|
+
var DEFAULT_UNIT_BASEDISTANCE_OPTIONS = {
|
|
768
|
+
default: { baseDistance: 0 },
|
|
769
|
+
byCategory: {
|
|
770
|
+
room: { baseDistance: ROOM_BASEDISTANCE },
|
|
771
|
+
terrace: { baseDistance: TERRACE_BASEDISTANCE },
|
|
772
|
+
escalator: { baseDistance: ESCALATOR_BASEDISTANCE, scaleDistanceByLevel: false },
|
|
773
|
+
ramp: { baseDistance: RAMP_BASEDISTANCE, scaleDistanceByLevel: false },
|
|
774
|
+
elevator: { baseDistance: ELEVATOR_BASEDISTANCE, scaleDistanceByLevel: false },
|
|
775
|
+
stairs: {
|
|
776
|
+
baseDistance: STAIR_BASEDISTANCE,
|
|
777
|
+
scaleDistanceByLevel: true
|
|
778
|
+
},
|
|
779
|
+
"stairs.emergencyexit": {
|
|
780
|
+
baseDistance: STAIR_BASEDISTANCE,
|
|
781
|
+
scaleDistanceByLevel: true
|
|
782
|
+
}
|
|
759
783
|
}
|
|
760
784
|
};
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
785
|
+
|
|
786
|
+
// src/data/navigate/graph/utils/getDistanceOption.ts
|
|
787
|
+
var getDistanceOptions = (options, category) => {
|
|
788
|
+
if (!options) return DEFAULT_UNIT_BASEDISTANCE_OPTIONS.byCategory[category];
|
|
789
|
+
return (category && options.byCategory?.[category]) ?? DEFAULT_UNIT_BASEDISTANCE_OPTIONS.byCategory[category] ?? options?.default ?? DEFAULT_UNIT_BASEDISTANCE_OPTIONS.default;
|
|
790
|
+
};
|
|
791
|
+
|
|
792
|
+
// src/data/utils/trace.ts
|
|
793
|
+
var trace = (namespace, text, ms, color) => {
|
|
794
|
+
console.log(`[${namespace}] %c${text.padEnd(90)} ${ms !== void 0 ? `${ms.toFixed(1).padStart(6)} ms` : ``}`, color ? `color: ${color}` : void 0);
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
// src/data/navigate/graph/nodemap/createTraversalNodeMap.ts
|
|
798
|
+
var createTraversalNodeMap = (unitOpenings, options) => {
|
|
799
|
+
const { units } = options.data;
|
|
800
|
+
let counter = 0;
|
|
801
|
+
const calculateFeatureDistanceWithinUnit = (features, distanceOptions) => {
|
|
802
|
+
let relationshipGraph = {};
|
|
803
|
+
for (let currentIndex = 0; currentIndex < features.length; currentIndex++) {
|
|
804
|
+
const isLastItem = currentIndex + 1 === features.length;
|
|
805
|
+
if (isLastItem) break;
|
|
806
|
+
for (let j = currentIndex + 1; j < features.length; j++) {
|
|
807
|
+
const opening = features[currentIndex];
|
|
808
|
+
const feature2 = features[j];
|
|
809
|
+
try {
|
|
810
|
+
const distance5 = turfDistance(
|
|
811
|
+
turfCenter(opening.geometry),
|
|
812
|
+
turfCenter(feature2.geometry),
|
|
813
|
+
{ units: "meters" }
|
|
814
|
+
) + (distanceOptions?.baseDistance ?? 0);
|
|
815
|
+
if (opening.id === feature2.id) continue;
|
|
816
|
+
_.set(relationshipGraph, `${opening.id}.${feature2.id}`, distance5);
|
|
817
|
+
_.set(relationshipGraph, `${feature2.id}.${opening.id}`, distance5);
|
|
818
|
+
counter++;
|
|
819
|
+
} catch (error) {
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
774
823
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
824
|
+
return relationshipGraph;
|
|
825
|
+
};
|
|
826
|
+
const t0 = performance.now();
|
|
827
|
+
const nodeMap = _.reduce(
|
|
828
|
+
unitOpenings,
|
|
829
|
+
(acc, openings, unitId) => {
|
|
830
|
+
const unit = units.find((unit2) => unit2.id === unitId);
|
|
831
|
+
const unitDistanceOption = getDistanceOptions(options.unitDistanceOptions, unit.properties.category);
|
|
832
|
+
return _.merge(
|
|
833
|
+
acc,
|
|
834
|
+
calculateFeatureDistanceWithinUnit(openings, unitDistanceOption)
|
|
835
|
+
);
|
|
836
|
+
},
|
|
837
|
+
{}
|
|
838
|
+
);
|
|
839
|
+
const t1 = performance.now();
|
|
840
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} traversal relationships`, t1 - t0);
|
|
841
|
+
return nodeMap;
|
|
842
|
+
};
|
|
843
|
+
|
|
844
|
+
// src/data/navigate/graph/nodemap/createElevatorNodeMap.ts
|
|
845
|
+
import _2 from "lodash";
|
|
846
|
+
var createElevatorNodeMap = (elevatorLikeRelationships, unitOpenings, options) => {
|
|
847
|
+
const t0 = performance.now();
|
|
848
|
+
const { levels, units } = options.data;
|
|
849
|
+
const distanceOptions = getDistanceOptions(options.unitDistanceOptions, "elevator");
|
|
850
|
+
const {
|
|
851
|
+
baseDistance = ELEVATOR_BASEDISTANCE,
|
|
852
|
+
scaleDistanceByLevel = false
|
|
853
|
+
} = distanceOptions;
|
|
854
|
+
let elevatorNodeMap = {};
|
|
855
|
+
let counter = 0;
|
|
856
|
+
for (const relationship of elevatorLikeRelationships) {
|
|
857
|
+
try {
|
|
858
|
+
const {
|
|
859
|
+
origin: originTypeAndId,
|
|
860
|
+
intermediary,
|
|
861
|
+
destination: destinationTypeAndId
|
|
862
|
+
} = relationship.properties;
|
|
863
|
+
const origin = units.find((unit) => unit.id === originTypeAndId.id);
|
|
864
|
+
if (!origin) return;
|
|
865
|
+
const originOpenings = compact(unitOpenings[origin.id]);
|
|
866
|
+
const originLevel = levels.find((level) => level.id === origin.properties.level_id);
|
|
867
|
+
const destination = units.find((unit) => unit.id === destinationTypeAndId.id);
|
|
868
|
+
const destinationOpenings = unitOpenings[destination.id];
|
|
869
|
+
const destinationOpeningAndLevels = destinationOpenings.map((opening) => {
|
|
870
|
+
const level = levels.find((level2) => level2.id === destination.properties.level_id);
|
|
871
|
+
return { opening, level };
|
|
872
|
+
});
|
|
873
|
+
const intermediaryOpeningAndLevels = intermediary.map((unitTypeAndId) => {
|
|
874
|
+
const openings = unitOpenings[unitTypeAndId.id];
|
|
875
|
+
const unit = units.find((unit2) => unit2.id === unitTypeAndId.id);
|
|
876
|
+
const level = levels.find((level2) => level2.id === unit.properties.level_id);
|
|
877
|
+
return openings.map((opening) => ({ opening, level }));
|
|
878
|
+
}).flat();
|
|
879
|
+
const connections = compact([...intermediaryOpeningAndLevels, ...destinationOpeningAndLevels]);
|
|
880
|
+
if (!originOpenings || originOpenings.length === 0) return;
|
|
881
|
+
for (const originOpening of originOpenings) {
|
|
882
|
+
for (const connection of connections) {
|
|
883
|
+
const { opening, level } = connection;
|
|
884
|
+
let distance5 = baseDistance;
|
|
885
|
+
if (scaleDistanceByLevel) {
|
|
886
|
+
const originOrdinal = originLevel.properties.ordinal;
|
|
887
|
+
const connectionOrdinal = level.properties.ordinal;
|
|
888
|
+
const levelDifference = Math.abs(originOrdinal - connectionOrdinal);
|
|
889
|
+
if (levelDifference > 0) distance5 *= levelDifference;
|
|
890
|
+
}
|
|
891
|
+
_2.set(elevatorNodeMap, `${originOpening.id}.${opening.id}`, distance5);
|
|
892
|
+
_2.set(elevatorNodeMap, `${opening.id}.${originOpening.id}`, distance5);
|
|
893
|
+
counter++;
|
|
894
|
+
}
|
|
781
895
|
}
|
|
896
|
+
} catch (err) {
|
|
897
|
+
console.log(err);
|
|
898
|
+
console.log("cannot create elevatorNodeMap for ", { relationship });
|
|
782
899
|
}
|
|
783
|
-
path = createKeyPath(name);
|
|
784
|
-
id = createKeyId(name);
|
|
785
|
-
getFn = key.getFn;
|
|
786
900
|
}
|
|
787
|
-
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
let
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
901
|
+
const t1 = performance.now();
|
|
902
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} escalator relationships`, t1 - t0);
|
|
903
|
+
return elevatorNodeMap;
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
// src/data/navigate/graph/nodemap/createEscalatorNodeMap.ts
|
|
907
|
+
import set from "lodash/set";
|
|
908
|
+
var createEscalatorNodeMap = (relationships, options) => {
|
|
909
|
+
const t0 = performance.now();
|
|
910
|
+
const distanceOptions = getDistanceOptions(options.unitDistanceOptions, "escalator");
|
|
911
|
+
let counter = 0;
|
|
912
|
+
let nodeMap = {};
|
|
913
|
+
for (const relationship of relationships) {
|
|
914
|
+
const {
|
|
915
|
+
properties: { direction, origin, destination }
|
|
916
|
+
} = relationship;
|
|
917
|
+
set(nodeMap, `${origin.id}.${destination.id}`, distanceOptions.baseDistance);
|
|
918
|
+
if (direction === "undirected") {
|
|
919
|
+
set(nodeMap, `${destination.id}.${origin.id}`, distanceOptions.baseDistance);
|
|
801
920
|
}
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
921
|
+
counter++;
|
|
922
|
+
}
|
|
923
|
+
const t1 = performance.now();
|
|
924
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} escalator relationships`, t1 - t0);
|
|
925
|
+
return nodeMap;
|
|
926
|
+
};
|
|
927
|
+
|
|
928
|
+
// src/data/navigate/graph/nodemap/createRampNodeMap.ts
|
|
929
|
+
import set2 from "lodash/set";
|
|
930
|
+
var createRampNodeMap = (relationships, options) => {
|
|
931
|
+
const t0 = performance.now();
|
|
932
|
+
const distanceOptions = getDistanceOptions(options.unitDistanceOptions, "ramp");
|
|
933
|
+
let counter = 0;
|
|
934
|
+
let nodeMap = {};
|
|
935
|
+
relationships.forEach((relationship) => {
|
|
936
|
+
const {
|
|
937
|
+
properties: { origin, destination }
|
|
938
|
+
} = relationship;
|
|
939
|
+
set2(nodeMap, `${origin.id}.${destination.id}`, distanceOptions.baseDistance);
|
|
940
|
+
set2(nodeMap, `${destination.id}.${origin.id}`, distanceOptions.baseDistance);
|
|
941
|
+
counter++;
|
|
942
|
+
});
|
|
943
|
+
const t1 = performance.now();
|
|
944
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} ramp relationships`, t1 - t0);
|
|
945
|
+
return nodeMap;
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
// src/data/navigate/graph/nodemap/createStairNodeMap.ts
|
|
949
|
+
import _3 from "lodash";
|
|
950
|
+
var createStairNodeMap = (elevatorLikeRelationships, unitOpenings, options) => {
|
|
951
|
+
const t0 = performance.now();
|
|
952
|
+
const { levels = [], openings = [], units = [] } = options.data;
|
|
953
|
+
const { baseDistance, scaleDistanceByLevel } = getDistanceOptions(options.unitDistanceOptions, "stairs");
|
|
954
|
+
let elevatorNodeMap = {};
|
|
955
|
+
let counter = 0;
|
|
956
|
+
for (const relationship of elevatorLikeRelationships) {
|
|
957
|
+
try {
|
|
958
|
+
const {
|
|
959
|
+
origin: { id: originId },
|
|
960
|
+
intermediary,
|
|
961
|
+
destination: { id: destinationId }
|
|
962
|
+
} = relationship.properties;
|
|
963
|
+
const origin = openings.find((opening) => opening.id === originId);
|
|
964
|
+
if (!origin) return;
|
|
965
|
+
const originLevel = levels.find((level) => level.id === origin.properties.level_id);
|
|
966
|
+
const destination = openings.find((opening) => opening.id === destinationId);
|
|
967
|
+
const destinationOpeningAndLevel = {
|
|
968
|
+
opening: destination,
|
|
969
|
+
level: levels.find((level) => level.id === destination.properties.level_id)
|
|
970
|
+
};
|
|
971
|
+
const intermediaryOpeningAndLevels = intermediary.map((unitTypeAndId) => {
|
|
972
|
+
const openings2 = unitOpenings[unitTypeAndId.id];
|
|
973
|
+
const unit = units.find((unit2) => unit2.id === unitTypeAndId.id);
|
|
974
|
+
const level = levels.find((level2) => level2.id === unit.properties.level_id);
|
|
975
|
+
return openings2.map((opening) => ({ opening, level }));
|
|
976
|
+
}).flat();
|
|
977
|
+
const connections = [...intermediaryOpeningAndLevels, destinationOpeningAndLevel];
|
|
978
|
+
if (!origin) return;
|
|
979
|
+
for (const connection of connections) {
|
|
980
|
+
const { opening, level } = connection;
|
|
981
|
+
let distance5 = baseDistance;
|
|
982
|
+
if (scaleDistanceByLevel) {
|
|
983
|
+
const originOrdinal = originLevel.properties.ordinal;
|
|
984
|
+
const connectionOrdinal = level.properties.ordinal;
|
|
985
|
+
const levelDifference = Math.abs(originOrdinal - connectionOrdinal);
|
|
986
|
+
if (levelDifference > 0) distance5 *= levelDifference;
|
|
816
987
|
}
|
|
817
|
-
|
|
818
|
-
|
|
988
|
+
_3.set(elevatorNodeMap, `${origin.id}.${opening.id}`, distance5);
|
|
989
|
+
_3.set(elevatorNodeMap, `${opening.id}.${origin.id}`, distance5);
|
|
990
|
+
counter++;
|
|
819
991
|
}
|
|
992
|
+
} catch (err) {
|
|
993
|
+
console.warn(
|
|
994
|
+
"Failed to create stairNodeMap",
|
|
995
|
+
{
|
|
996
|
+
relationshipId: relationship.id,
|
|
997
|
+
featureType: relationship.feature_type,
|
|
998
|
+
error: err instanceof Error ? err.message : err,
|
|
999
|
+
stack: err instanceof Error ? err.stack : void 0
|
|
1000
|
+
}
|
|
1001
|
+
);
|
|
820
1002
|
}
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1003
|
+
}
|
|
1004
|
+
const t1 = performance.now();
|
|
1005
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} stairs relationships`, t1 - t0);
|
|
1006
|
+
return elevatorNodeMap;
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
// src/data/navigate/graph/nodemap/createOccupantNodeMap.ts
|
|
1010
|
+
import _4 from "lodash";
|
|
1011
|
+
var createOccupantNodeMap = (occupants) => {
|
|
1012
|
+
const t0 = performance.now();
|
|
1013
|
+
let nodeMap = {};
|
|
1014
|
+
let counter = 0;
|
|
1015
|
+
occupants.forEach((occupant) => {
|
|
1016
|
+
const { unit_id, unit_ids = [], kiosk_id, kiosk_ids = [] } = occupant.properties;
|
|
1017
|
+
const occupantRoomIds = compact([unit_id, ...unit_ids]);
|
|
1018
|
+
const occupantKioskIds = compact([kiosk_id, ...kiosk_ids]);
|
|
1019
|
+
for (const roomId of occupantRoomIds) {
|
|
1020
|
+
_4.set(nodeMap, `${roomId}.${occupant.id}`, 1e-3);
|
|
1021
|
+
_4.set(nodeMap, `${occupant.id}.${roomId}`, 1e-3);
|
|
1022
|
+
counter++;
|
|
1023
|
+
}
|
|
1024
|
+
for (const kioskId of occupantKioskIds) {
|
|
1025
|
+
_4.set(nodeMap, `${kioskId}.${occupant.id}`, 1e-3);
|
|
1026
|
+
_4.set(nodeMap, `${occupant.id}.${kioskId}`, 1e-3);
|
|
1027
|
+
counter++;
|
|
1028
|
+
}
|
|
1029
|
+
});
|
|
1030
|
+
const t1 = performance.now();
|
|
1031
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} occupants relationships`, t1 - t0);
|
|
1032
|
+
return nodeMap;
|
|
835
1033
|
};
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1034
|
+
|
|
1035
|
+
// src/data/navigate/graph/nodemap/createPOINodeMaps.ts
|
|
1036
|
+
import { center as turfCenter2 } from "@turf/center";
|
|
1037
|
+
import { distance } from "@turf/distance";
|
|
1038
|
+
import _5 from "lodash";
|
|
1039
|
+
var createPOINodeMap = (features, getFeatureUnit, unitOpenings) => {
|
|
1040
|
+
const t0 = performance.now();
|
|
1041
|
+
let nodeMap = {};
|
|
1042
|
+
let counter = 0;
|
|
1043
|
+
features.forEach((feat) => {
|
|
1044
|
+
try {
|
|
1045
|
+
const locatedOnUnitId = getFeatureUnit(feat);
|
|
1046
|
+
const openings = unitOpenings[locatedOnUnitId];
|
|
1047
|
+
const center7 = turfCenter2(feat);
|
|
1048
|
+
for (const opening of openings) {
|
|
1049
|
+
try {
|
|
1050
|
+
const openingCenter = turfCenter2(opening);
|
|
1051
|
+
const dis = distance(center7, openingCenter, { units: "meters" }) + BASE_POI_BASEDISTANCE;
|
|
1052
|
+
_5.set(nodeMap, `${opening.id}.${feat.id}`, dis);
|
|
1053
|
+
_5.set(nodeMap, `${feat.id}.${opening.id}`, dis);
|
|
1054
|
+
counter++;
|
|
1055
|
+
} catch (err) {
|
|
1056
|
+
console.log(err, opening);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
} catch (err) {
|
|
1060
|
+
console.log(err);
|
|
1061
|
+
console.log(`cannot connect poi to openings`, err.message, { feat });
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
const type = features.length > 0 ? features[0].feature_type : "-";
|
|
1065
|
+
const t1 = performance.now();
|
|
1066
|
+
trace("nav", ` \u2502 \u251C\u2500 add ${counter} ${type} relationships`, t1 - t0);
|
|
1067
|
+
return nodeMap;
|
|
850
1068
|
};
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1069
|
+
|
|
1070
|
+
// src/data/navigate/graph/utils/mergeNodeMap.ts
|
|
1071
|
+
var mergeNodeMap = (nodeMaps) => {
|
|
1072
|
+
const out = {};
|
|
1073
|
+
for (const nodeMap of nodeMaps) {
|
|
1074
|
+
for (const from in nodeMap) {
|
|
1075
|
+
out[from] = {
|
|
1076
|
+
...out[from] ?? {},
|
|
1077
|
+
...nodeMap[from]
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
return out;
|
|
863
1082
|
};
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
1083
|
+
|
|
1084
|
+
// src/data/navigate/graph/utils/createUnitOpenings.ts
|
|
1085
|
+
import uniqBy from "lodash/uniqBy";
|
|
1086
|
+
var createUnitOpenings = (relationships, units, openings) => {
|
|
1087
|
+
const openingConnections = {};
|
|
1088
|
+
const relationshipMap = /* @__PURE__ */ new Map();
|
|
1089
|
+
relationships.forEach((relationship) => {
|
|
1090
|
+
const originId = relationship.properties.origin?.id || null;
|
|
1091
|
+
const destinationId = relationship.properties.destination?.id || null;
|
|
1092
|
+
if (!relationshipMap.has(originId)) {
|
|
1093
|
+
relationshipMap.set(originId, []);
|
|
1094
|
+
}
|
|
1095
|
+
if (!relationshipMap.has(destinationId)) {
|
|
1096
|
+
relationshipMap.set(destinationId, []);
|
|
1097
|
+
}
|
|
1098
|
+
relationshipMap.get(originId).push(relationship);
|
|
1099
|
+
relationshipMap.get(destinationId).push(relationship);
|
|
1100
|
+
});
|
|
1101
|
+
units.forEach((unit) => {
|
|
1102
|
+
const unitId = unit.id;
|
|
1103
|
+
const connectedRelationshop = relationshipMap.get(unitId) || [];
|
|
1104
|
+
const relationshipIntermediaryTypeAndId = connectedRelationshop.map(
|
|
1105
|
+
(relationship) => relationship.properties.intermediary[0]
|
|
1106
|
+
// Assuming intermediary is always an array
|
|
1107
|
+
);
|
|
1108
|
+
const relationshipIntermediary = relationshipIntermediaryTypeAndId.map(({ id }) => {
|
|
1109
|
+
return openings.find((opening) => opening.id === id);
|
|
1110
|
+
});
|
|
1111
|
+
openingConnections[unitId] = uniqBy(
|
|
1112
|
+
[...openingConnections[unitId] || [], ...relationshipIntermediary],
|
|
1113
|
+
"id"
|
|
1114
|
+
);
|
|
1115
|
+
});
|
|
1116
|
+
return openingConnections;
|
|
880
1117
|
};
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
...AdvancedOptions
|
|
1118
|
+
|
|
1119
|
+
// src/data/navigate/parsers.ts
|
|
1120
|
+
var parseOrdinalCoordinate = (id) => {
|
|
1121
|
+
return id.slice(0, -1).split(",").map(Number);
|
|
886
1122
|
};
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
const
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
1123
|
+
|
|
1124
|
+
// src/data/navigate/graph/prepare.ts
|
|
1125
|
+
var prepareGraph = (options) => {
|
|
1126
|
+
const {
|
|
1127
|
+
data: {
|
|
1128
|
+
amenities = [],
|
|
1129
|
+
anchors = [],
|
|
1130
|
+
occupants = [],
|
|
1131
|
+
relationships = [],
|
|
1132
|
+
openings = [],
|
|
1133
|
+
units = [],
|
|
1134
|
+
kiosks = [],
|
|
1135
|
+
levels = []
|
|
1136
|
+
}
|
|
1137
|
+
} = options;
|
|
1138
|
+
const {
|
|
1139
|
+
traversal: traversalRelationships = [],
|
|
1140
|
+
escalator: escalatorRelationships = [],
|
|
1141
|
+
ramp: rampRelationships = [],
|
|
1142
|
+
elevator: elevatorRelationships = [],
|
|
1143
|
+
stairs: stairsRelationships = []
|
|
1144
|
+
} = _6.groupBy(relationships, "properties.category");
|
|
1145
|
+
const unitOpenings = createUnitOpenings(traversalRelationships, units, openings);
|
|
1146
|
+
const traversalNodeMap = createTraversalNodeMap(unitOpenings, options);
|
|
1147
|
+
const escalatorNodeMap = createEscalatorNodeMap(escalatorRelationships, options);
|
|
1148
|
+
const rampNodeMap = createRampNodeMap(rampRelationships, options);
|
|
1149
|
+
const elevatorNodeMap = createElevatorNodeMap(
|
|
1150
|
+
elevatorRelationships,
|
|
1151
|
+
unitOpenings,
|
|
1152
|
+
options
|
|
1153
|
+
);
|
|
1154
|
+
const stairNodeMap = createStairNodeMap(
|
|
1155
|
+
stairsRelationships,
|
|
1156
|
+
unitOpenings,
|
|
1157
|
+
options
|
|
1158
|
+
);
|
|
1159
|
+
const amenityNodeMap = createPOINodeMap(amenities, (amenity) => amenity.properties.unit_ids[0], unitOpenings);
|
|
1160
|
+
const anchorsNodeMap = createPOINodeMap(anchors, (anchor) => anchor.properties.unit_id, unitOpenings);
|
|
1161
|
+
const walkwayUnits = units.filter((unit) => unit.properties.category === "walkway");
|
|
1162
|
+
const kioskNodeMap = createPOINodeMap(kiosks, (kiosk) => findContainingUnit(kiosk, walkwayUnits)?.id, unitOpenings);
|
|
1163
|
+
const unitNodeMap = createPOINodeMap(units, (unit) => unit.id, unitOpenings);
|
|
1164
|
+
const occupantNodeMap = createOccupantNodeMap(occupants);
|
|
1165
|
+
const defaultGraph = new DijstraGraph(mergeNodeMap([
|
|
1166
|
+
traversalNodeMap,
|
|
1167
|
+
escalatorNodeMap,
|
|
1168
|
+
rampNodeMap,
|
|
1169
|
+
elevatorNodeMap,
|
|
1170
|
+
stairNodeMap,
|
|
1171
|
+
amenityNodeMap,
|
|
1172
|
+
anchorsNodeMap,
|
|
1173
|
+
kioskNodeMap,
|
|
1174
|
+
unitNodeMap,
|
|
1175
|
+
occupantNodeMap
|
|
1176
|
+
]));
|
|
1177
|
+
const accessibleGraph = new DijstraGraph(mergeNodeMap([
|
|
1178
|
+
traversalNodeMap,
|
|
1179
|
+
rampNodeMap,
|
|
1180
|
+
elevatorNodeMap,
|
|
1181
|
+
amenityNodeMap,
|
|
1182
|
+
anchorsNodeMap,
|
|
1183
|
+
kioskNodeMap,
|
|
1184
|
+
unitNodeMap,
|
|
1185
|
+
occupantNodeMap
|
|
1186
|
+
]));
|
|
1187
|
+
const addCoordinateOrdinalNode = (params, locatedOnUnit) => {
|
|
1188
|
+
const [lat, lng, ordinal] = parseOrdinalCoordinate(params);
|
|
1189
|
+
if (locatedOnUnit) {
|
|
1190
|
+
const openings2 = unitOpenings[locatedOnUnit.id];
|
|
1191
|
+
for (const opening of openings2) {
|
|
1192
|
+
const openingCenter = turfCenter3(opening);
|
|
1193
|
+
const dis = distance2([lat, lng], openingCenter, { units: "meters" });
|
|
1194
|
+
defaultGraph.addNode(params, { [opening.id]: dis }).addNode(opening.id, { [params]: dis });
|
|
1195
|
+
accessibleGraph.addNode(params, { [opening.id]: dis }).addNode(opening.id, { [params]: dis });
|
|
896
1196
|
}
|
|
897
|
-
const norm2 = 1 / Math.pow(numTokens, 0.5 * weight);
|
|
898
|
-
const n = parseFloat(Math.round(norm2 * m) / m);
|
|
899
|
-
cache.set(numTokens, n);
|
|
900
|
-
return n;
|
|
901
|
-
},
|
|
902
|
-
clear() {
|
|
903
|
-
cache.clear();
|
|
904
1197
|
}
|
|
905
1198
|
};
|
|
1199
|
+
return { defaultGraph, accessibleGraph, unitOpenings, addCoordinateOrdinalNode };
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
// src/data/navigate/steps/createStepUtils.ts
|
|
1203
|
+
import { capitalize } from "lodash";
|
|
1204
|
+
import _intersectionBy from "lodash/intersectionBy";
|
|
1205
|
+
import { center as center6 } from "@turf/center";
|
|
1206
|
+
|
|
1207
|
+
// src/data/navigate/description/describe.ts
|
|
1208
|
+
var t = (template, locale, options) => {
|
|
1209
|
+
return template.replace(`{{intermediary}}`, options.intermediary ?? "").replace(`{{toward}}`, options.toward?.[locale] ?? "").replace(`{{landmark}}`, options.landmark?.[locale] ?? "");
|
|
1210
|
+
};
|
|
1211
|
+
var describeVerticalStep = (fromLevel, toLevel, intermediary) => {
|
|
1212
|
+
const dir = fromLevel.properties.ordinal < toLevel.properties.ordinal ? "up" : "down";
|
|
1213
|
+
const template = `Take the {{intermediary}} ${dir} to {{toward}}`;
|
|
1214
|
+
return {
|
|
1215
|
+
template,
|
|
1216
|
+
text: t(template, "en", { intermediary, toward: toLevel.properties.name })
|
|
1217
|
+
};
|
|
1218
|
+
};
|
|
1219
|
+
var describeHorizontalStep = (intermediary, toward, landmark) => {
|
|
1220
|
+
const template = `Follow the path ${intermediary === "walkway" ? `along the walkway` : `through {{intermediary}}`} ${toward ? `toward {{toward}}` : ``} ${landmark ? `near {{landmark}}` : ``}`.trim();
|
|
1221
|
+
return {
|
|
1222
|
+
text: t(template, "en", { intermediary, toward, landmark }),
|
|
1223
|
+
template
|
|
1224
|
+
};
|
|
1225
|
+
};
|
|
1226
|
+
|
|
1227
|
+
// src/data/navigate/steps/path/index.ts
|
|
1228
|
+
import _7 from "lodash";
|
|
1229
|
+
|
|
1230
|
+
// src/data/navigate/constants.ts
|
|
1231
|
+
var OBSTACLE_FEATURE_TYPES = [
|
|
1232
|
+
"kiosk"
|
|
1233
|
+
/* , "fixture" */
|
|
1234
|
+
];
|
|
1235
|
+
var OBSTACLE_CATEGORIES = [
|
|
1236
|
+
"fixture.water",
|
|
1237
|
+
"fixture.stage",
|
|
1238
|
+
"nonpublic",
|
|
1239
|
+
"opentobelow",
|
|
1240
|
+
"elevator",
|
|
1241
|
+
"escalator",
|
|
1242
|
+
"stairs",
|
|
1243
|
+
"stairs.emergencyexit",
|
|
1244
|
+
"room",
|
|
1245
|
+
"unspecified",
|
|
1246
|
+
"structure",
|
|
1247
|
+
"brick",
|
|
1248
|
+
"concrete",
|
|
1249
|
+
"drywall",
|
|
1250
|
+
"glass",
|
|
1251
|
+
"wood",
|
|
1252
|
+
"column"
|
|
1253
|
+
];
|
|
1254
|
+
var WALKABLE_CATEGORY = [
|
|
1255
|
+
"walkway",
|
|
1256
|
+
"parking",
|
|
1257
|
+
"room",
|
|
1258
|
+
"terrace",
|
|
1259
|
+
"unenclosedarea",
|
|
1260
|
+
"vegetation",
|
|
1261
|
+
"unspecified"
|
|
1262
|
+
];
|
|
1263
|
+
|
|
1264
|
+
// node_modules/@turf/helpers/dist/esm/index.js
|
|
1265
|
+
var earthRadius = 63710088e-1;
|
|
1266
|
+
var factors = {
|
|
1267
|
+
centimeters: earthRadius * 100,
|
|
1268
|
+
centimetres: earthRadius * 100,
|
|
1269
|
+
degrees: 360 / (2 * Math.PI),
|
|
1270
|
+
feet: earthRadius * 3.28084,
|
|
1271
|
+
inches: earthRadius * 39.37,
|
|
1272
|
+
kilometers: earthRadius / 1e3,
|
|
1273
|
+
kilometres: earthRadius / 1e3,
|
|
1274
|
+
meters: earthRadius,
|
|
1275
|
+
metres: earthRadius,
|
|
1276
|
+
miles: earthRadius / 1609.344,
|
|
1277
|
+
millimeters: earthRadius * 1e3,
|
|
1278
|
+
millimetres: earthRadius * 1e3,
|
|
1279
|
+
nauticalmiles: earthRadius / 1852,
|
|
1280
|
+
radians: 1,
|
|
1281
|
+
yards: earthRadius * 1.0936
|
|
1282
|
+
};
|
|
1283
|
+
function feature(geom, properties, options = {}) {
|
|
1284
|
+
const feat = { type: "Feature" };
|
|
1285
|
+
if (options.id === 0 || options.id) {
|
|
1286
|
+
feat.id = options.id;
|
|
1287
|
+
}
|
|
1288
|
+
if (options.bbox) {
|
|
1289
|
+
feat.bbox = options.bbox;
|
|
1290
|
+
}
|
|
1291
|
+
feat.properties = properties || {};
|
|
1292
|
+
feat.geometry = geom;
|
|
1293
|
+
return feat;
|
|
906
1294
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
fieldNormWeight = Config.fieldNormWeight
|
|
911
|
-
} = {}) {
|
|
912
|
-
this.norm = norm(fieldNormWeight, 3);
|
|
913
|
-
this.getFn = getFn;
|
|
914
|
-
this.isCreated = false;
|
|
915
|
-
this.setIndexRecords();
|
|
1295
|
+
function point(coordinates, properties, options = {}) {
|
|
1296
|
+
if (!coordinates) {
|
|
1297
|
+
throw new Error("coordinates is required");
|
|
916
1298
|
}
|
|
917
|
-
|
|
918
|
-
|
|
1299
|
+
if (!Array.isArray(coordinates)) {
|
|
1300
|
+
throw new Error("coordinates must be an Array");
|
|
919
1301
|
}
|
|
920
|
-
|
|
921
|
-
|
|
1302
|
+
if (coordinates.length < 2) {
|
|
1303
|
+
throw new Error("coordinates must be at least 2 numbers long");
|
|
922
1304
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
this._keysMap = {};
|
|
926
|
-
keys.forEach((key, idx) => {
|
|
927
|
-
this._keysMap[key.id] = idx;
|
|
928
|
-
});
|
|
1305
|
+
if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) {
|
|
1306
|
+
throw new Error("coordinates must contain numbers");
|
|
929
1307
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1308
|
+
const geom = {
|
|
1309
|
+
type: "Point",
|
|
1310
|
+
coordinates
|
|
1311
|
+
};
|
|
1312
|
+
return feature(geom, properties, options);
|
|
1313
|
+
}
|
|
1314
|
+
function polygon(coordinates, properties, options = {}) {
|
|
1315
|
+
for (const ring of coordinates) {
|
|
1316
|
+
if (ring.length < 4) {
|
|
1317
|
+
throw new Error(
|
|
1318
|
+
"Each LinearRing of a Polygon must have 4 or more Positions."
|
|
1319
|
+
);
|
|
933
1320
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
this.docs.forEach((doc, docIndex) => {
|
|
937
|
-
this._addString(doc, docIndex);
|
|
938
|
-
});
|
|
939
|
-
} else {
|
|
940
|
-
this.docs.forEach((doc, docIndex) => {
|
|
941
|
-
this._addObject(doc, docIndex);
|
|
942
|
-
});
|
|
1321
|
+
if (ring[ring.length - 1].length !== ring[0].length) {
|
|
1322
|
+
throw new Error("First and last Position are not equivalent.");
|
|
943
1323
|
}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
const idx = this.size();
|
|
949
|
-
if (isString(doc)) {
|
|
950
|
-
this._addString(doc, idx);
|
|
951
|
-
} else {
|
|
952
|
-
this._addObject(doc, idx);
|
|
1324
|
+
for (let j = 0; j < ring[ring.length - 1].length; j++) {
|
|
1325
|
+
if (ring[ring.length - 1][j] !== ring[0][j]) {
|
|
1326
|
+
throw new Error("First and last Position are not equivalent.");
|
|
1327
|
+
}
|
|
953
1328
|
}
|
|
954
1329
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1330
|
+
const geom = {
|
|
1331
|
+
type: "Polygon",
|
|
1332
|
+
coordinates
|
|
1333
|
+
};
|
|
1334
|
+
return feature(geom, properties, options);
|
|
1335
|
+
}
|
|
1336
|
+
function lineString(coordinates, properties, options = {}) {
|
|
1337
|
+
if (coordinates.length < 2) {
|
|
1338
|
+
throw new Error("coordinates must be an array of two or more positions");
|
|
961
1339
|
}
|
|
962
|
-
|
|
963
|
-
|
|
1340
|
+
const geom = {
|
|
1341
|
+
type: "LineString",
|
|
1342
|
+
coordinates
|
|
1343
|
+
};
|
|
1344
|
+
return feature(geom, properties, options);
|
|
1345
|
+
}
|
|
1346
|
+
function featureCollection(features, options = {}) {
|
|
1347
|
+
const fc = { type: "FeatureCollection" };
|
|
1348
|
+
if (options.id) {
|
|
1349
|
+
fc.id = options.id;
|
|
964
1350
|
}
|
|
965
|
-
|
|
966
|
-
|
|
1351
|
+
if (options.bbox) {
|
|
1352
|
+
fc.bbox = options.bbox;
|
|
967
1353
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1354
|
+
fc.features = features;
|
|
1355
|
+
return fc;
|
|
1356
|
+
}
|
|
1357
|
+
function isNumber(num) {
|
|
1358
|
+
return !isNaN(num) && num !== null && !Array.isArray(num);
|
|
1359
|
+
}
|
|
1360
|
+
function isObject(input) {
|
|
1361
|
+
return input !== null && typeof input === "object" && !Array.isArray(input);
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// node_modules/@turf/invariant/dist/esm/index.js
|
|
1365
|
+
function getCoord(coord) {
|
|
1366
|
+
if (!coord) {
|
|
1367
|
+
throw new Error("coord is required");
|
|
1368
|
+
}
|
|
1369
|
+
if (!Array.isArray(coord)) {
|
|
1370
|
+
if (coord.type === "Feature" && coord.geometry !== null && coord.geometry.type === "Point") {
|
|
1371
|
+
return [...coord.geometry.coordinates];
|
|
1372
|
+
}
|
|
1373
|
+
if (coord.type === "Point") {
|
|
1374
|
+
return [...coord.coordinates];
|
|
971
1375
|
}
|
|
972
|
-
let record = {
|
|
973
|
-
v: doc,
|
|
974
|
-
i: docIndex,
|
|
975
|
-
n: this.norm.get(doc)
|
|
976
|
-
};
|
|
977
|
-
this.records.push(record);
|
|
978
|
-
}
|
|
979
|
-
_addObject(doc, docIndex) {
|
|
980
|
-
let record = { i: docIndex, $: {} };
|
|
981
|
-
this.keys.forEach((key, keyIndex) => {
|
|
982
|
-
let value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path);
|
|
983
|
-
if (!isDefined(value)) {
|
|
984
|
-
return;
|
|
985
|
-
}
|
|
986
|
-
if (isArray(value)) {
|
|
987
|
-
let subRecords = [];
|
|
988
|
-
const stack = [{ nestedArrIndex: -1, value }];
|
|
989
|
-
while (stack.length) {
|
|
990
|
-
const { nestedArrIndex, value: value2 } = stack.pop();
|
|
991
|
-
if (!isDefined(value2)) {
|
|
992
|
-
continue;
|
|
993
|
-
}
|
|
994
|
-
if (isString(value2) && !isBlank(value2)) {
|
|
995
|
-
let subRecord = {
|
|
996
|
-
v: value2,
|
|
997
|
-
i: nestedArrIndex,
|
|
998
|
-
n: this.norm.get(value2)
|
|
999
|
-
};
|
|
1000
|
-
subRecords.push(subRecord);
|
|
1001
|
-
} else if (isArray(value2)) {
|
|
1002
|
-
value2.forEach((item, k) => {
|
|
1003
|
-
stack.push({
|
|
1004
|
-
nestedArrIndex: k,
|
|
1005
|
-
value: item
|
|
1006
|
-
});
|
|
1007
|
-
});
|
|
1008
|
-
} else ;
|
|
1009
|
-
}
|
|
1010
|
-
record.$[keyIndex] = subRecords;
|
|
1011
|
-
} else if (isString(value) && !isBlank(value)) {
|
|
1012
|
-
let subRecord = {
|
|
1013
|
-
v: value,
|
|
1014
|
-
n: this.norm.get(value)
|
|
1015
|
-
};
|
|
1016
|
-
record.$[keyIndex] = subRecord;
|
|
1017
|
-
}
|
|
1018
|
-
});
|
|
1019
|
-
this.records.push(record);
|
|
1020
1376
|
}
|
|
1021
|
-
|
|
1022
|
-
return
|
|
1023
|
-
keys: this.keys,
|
|
1024
|
-
records: this.records
|
|
1025
|
-
};
|
|
1377
|
+
if (Array.isArray(coord) && coord.length >= 2 && !Array.isArray(coord[0]) && !Array.isArray(coord[1])) {
|
|
1378
|
+
return [...coord];
|
|
1026
1379
|
}
|
|
1027
|
-
|
|
1028
|
-
function createIndex(keys, docs, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
|
|
1029
|
-
const myIndex = new FuseIndex({ getFn, fieldNormWeight });
|
|
1030
|
-
myIndex.setKeys(keys.map(createKey));
|
|
1031
|
-
myIndex.setSources(docs);
|
|
1032
|
-
myIndex.create();
|
|
1033
|
-
return myIndex;
|
|
1380
|
+
throw new Error("coord must be GeoJSON Point or an Array of numbers");
|
|
1034
1381
|
}
|
|
1035
|
-
function
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
return myIndex;
|
|
1382
|
+
function getGeom(geojson) {
|
|
1383
|
+
if (geojson.type === "Feature") {
|
|
1384
|
+
return geojson.geometry;
|
|
1385
|
+
}
|
|
1386
|
+
return geojson;
|
|
1041
1387
|
}
|
|
1042
|
-
function
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
expectedLocation = 0,
|
|
1046
|
-
distance = Config.distance,
|
|
1047
|
-
ignoreLocation = Config.ignoreLocation
|
|
1048
|
-
} = {}) {
|
|
1049
|
-
const accuracy = errors / pattern.length;
|
|
1050
|
-
if (ignoreLocation) {
|
|
1051
|
-
return accuracy;
|
|
1388
|
+
function getType(geojson, _name) {
|
|
1389
|
+
if (geojson.type === "FeatureCollection") {
|
|
1390
|
+
return "FeatureCollection";
|
|
1052
1391
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
return proximity ? 1 : accuracy;
|
|
1392
|
+
if (geojson.type === "GeometryCollection") {
|
|
1393
|
+
return "GeometryCollection";
|
|
1056
1394
|
}
|
|
1057
|
-
|
|
1395
|
+
if (geojson.type === "Feature" && geojson.geometry !== null) {
|
|
1396
|
+
return geojson.geometry.type;
|
|
1397
|
+
}
|
|
1398
|
+
return geojson.type;
|
|
1058
1399
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1400
|
+
|
|
1401
|
+
// src/data/navigate/steps/path/index.ts
|
|
1402
|
+
import difference from "@turf/difference";
|
|
1403
|
+
import envelope from "@turf/envelope";
|
|
1404
|
+
import booleanOverlap from "@turf/boolean-overlap";
|
|
1405
|
+
import booleanIntersects from "@turf/boolean-intersects";
|
|
1406
|
+
|
|
1407
|
+
// ../../node_modules/@turf/meta/dist/esm/index.js
|
|
1408
|
+
function coordEach(geojson, callback, excludeWrapCoord) {
|
|
1409
|
+
if (geojson === null) return;
|
|
1410
|
+
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;
|
|
1411
|
+
for (var featureIndex = 0; featureIndex < stop; featureIndex++) {
|
|
1412
|
+
geometryMaybeCollection = isFeatureCollection ? geojson.features[featureIndex].geometry : isFeature ? geojson.geometry : geojson;
|
|
1413
|
+
isGeometryCollection = geometryMaybeCollection ? geometryMaybeCollection.type === "GeometryCollection" : false;
|
|
1414
|
+
stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
|
|
1415
|
+
for (var geomIndex = 0; geomIndex < stopG; geomIndex++) {
|
|
1416
|
+
var multiFeatureIndex = 0;
|
|
1417
|
+
var geometryIndex = 0;
|
|
1418
|
+
geometry = isGeometryCollection ? geometryMaybeCollection.geometries[geomIndex] : geometryMaybeCollection;
|
|
1419
|
+
if (geometry === null) continue;
|
|
1420
|
+
coords = geometry.coordinates;
|
|
1421
|
+
var geomType = geometry.type;
|
|
1422
|
+
wrapShrink = excludeWrapCoord && (geomType === "Polygon" || geomType === "MultiPolygon") ? 1 : 0;
|
|
1423
|
+
switch (geomType) {
|
|
1424
|
+
case null:
|
|
1425
|
+
break;
|
|
1426
|
+
case "Point":
|
|
1427
|
+
if (callback(
|
|
1428
|
+
coords,
|
|
1429
|
+
coordIndex,
|
|
1430
|
+
featureIndex,
|
|
1431
|
+
multiFeatureIndex,
|
|
1432
|
+
geometryIndex
|
|
1433
|
+
) === false)
|
|
1434
|
+
return false;
|
|
1435
|
+
coordIndex++;
|
|
1436
|
+
multiFeatureIndex++;
|
|
1437
|
+
break;
|
|
1438
|
+
case "LineString":
|
|
1439
|
+
case "MultiPoint":
|
|
1440
|
+
for (j = 0; j < coords.length; j++) {
|
|
1441
|
+
if (callback(
|
|
1442
|
+
coords[j],
|
|
1443
|
+
coordIndex,
|
|
1444
|
+
featureIndex,
|
|
1445
|
+
multiFeatureIndex,
|
|
1446
|
+
geometryIndex
|
|
1447
|
+
) === false)
|
|
1448
|
+
return false;
|
|
1449
|
+
coordIndex++;
|
|
1450
|
+
if (geomType === "MultiPoint") multiFeatureIndex++;
|
|
1451
|
+
}
|
|
1452
|
+
if (geomType === "LineString") multiFeatureIndex++;
|
|
1453
|
+
break;
|
|
1454
|
+
case "Polygon":
|
|
1455
|
+
case "MultiLineString":
|
|
1456
|
+
for (j = 0; j < coords.length; j++) {
|
|
1457
|
+
for (k = 0; k < coords[j].length - wrapShrink; k++) {
|
|
1458
|
+
if (callback(
|
|
1459
|
+
coords[j][k],
|
|
1460
|
+
coordIndex,
|
|
1461
|
+
featureIndex,
|
|
1462
|
+
multiFeatureIndex,
|
|
1463
|
+
geometryIndex
|
|
1464
|
+
) === false)
|
|
1465
|
+
return false;
|
|
1466
|
+
coordIndex++;
|
|
1467
|
+
}
|
|
1468
|
+
if (geomType === "MultiLineString") multiFeatureIndex++;
|
|
1469
|
+
if (geomType === "Polygon") geometryIndex++;
|
|
1470
|
+
}
|
|
1471
|
+
if (geomType === "Polygon") multiFeatureIndex++;
|
|
1472
|
+
break;
|
|
1473
|
+
case "MultiPolygon":
|
|
1474
|
+
for (j = 0; j < coords.length; j++) {
|
|
1475
|
+
geometryIndex = 0;
|
|
1476
|
+
for (k = 0; k < coords[j].length; k++) {
|
|
1477
|
+
for (l = 0; l < coords[j][k].length - wrapShrink; l++) {
|
|
1478
|
+
if (callback(
|
|
1479
|
+
coords[j][k][l],
|
|
1480
|
+
coordIndex,
|
|
1481
|
+
featureIndex,
|
|
1482
|
+
multiFeatureIndex,
|
|
1483
|
+
geometryIndex
|
|
1484
|
+
) === false)
|
|
1485
|
+
return false;
|
|
1486
|
+
coordIndex++;
|
|
1487
|
+
}
|
|
1488
|
+
geometryIndex++;
|
|
1489
|
+
}
|
|
1490
|
+
multiFeatureIndex++;
|
|
1491
|
+
}
|
|
1492
|
+
break;
|
|
1493
|
+
case "GeometryCollection":
|
|
1494
|
+
for (j = 0; j < geometry.geometries.length; j++)
|
|
1495
|
+
if (coordEach(geometry.geometries[j], callback, excludeWrapCoord) === false)
|
|
1496
|
+
return false;
|
|
1497
|
+
break;
|
|
1498
|
+
default:
|
|
1499
|
+
throw new Error("Unknown Geometry Type");
|
|
1072
1500
|
}
|
|
1073
|
-
start = -1;
|
|
1074
1501
|
}
|
|
1075
1502
|
}
|
|
1076
|
-
if (matchmask[i - 1] && i - start >= minMatchCharLength) {
|
|
1077
|
-
indices.push([start, i - 1]);
|
|
1078
|
-
}
|
|
1079
|
-
return indices;
|
|
1080
1503
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
if (pattern.length > MAX_BITS) {
|
|
1092
|
-
throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS));
|
|
1093
|
-
}
|
|
1094
|
-
const patternLen = pattern.length;
|
|
1095
|
-
const textLen = text.length;
|
|
1096
|
-
const expectedLocation = Math.max(0, Math.min(location, textLen));
|
|
1097
|
-
let currentThreshold = threshold;
|
|
1098
|
-
let bestLocation = expectedLocation;
|
|
1099
|
-
const computeMatches = minMatchCharLength > 1 || includeMatches;
|
|
1100
|
-
const matchMask = computeMatches ? Array(textLen) : [];
|
|
1101
|
-
let index;
|
|
1102
|
-
while ((index = text.indexOf(pattern, bestLocation)) > -1) {
|
|
1103
|
-
let score = computeScore$1(pattern, {
|
|
1104
|
-
currentLocation: index,
|
|
1105
|
-
expectedLocation,
|
|
1106
|
-
distance,
|
|
1107
|
-
ignoreLocation
|
|
1108
|
-
});
|
|
1109
|
-
currentThreshold = Math.min(score, currentThreshold);
|
|
1110
|
-
bestLocation = index + patternLen;
|
|
1111
|
-
if (computeMatches) {
|
|
1112
|
-
let i = 0;
|
|
1113
|
-
while (i < patternLen) {
|
|
1114
|
-
matchMask[index + i] = 1;
|
|
1115
|
-
i += 1;
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
bestLocation = -1;
|
|
1120
|
-
let lastBitArr = [];
|
|
1121
|
-
let finalScore = 1;
|
|
1122
|
-
let binMax = patternLen + textLen;
|
|
1123
|
-
const mask = 1 << patternLen - 1;
|
|
1124
|
-
for (let i = 0; i < patternLen; i += 1) {
|
|
1125
|
-
let binMin = 0;
|
|
1126
|
-
let binMid = binMax;
|
|
1127
|
-
while (binMin < binMid) {
|
|
1128
|
-
const score2 = computeScore$1(pattern, {
|
|
1129
|
-
errors: i,
|
|
1130
|
-
currentLocation: expectedLocation + binMid,
|
|
1131
|
-
expectedLocation,
|
|
1132
|
-
distance,
|
|
1133
|
-
ignoreLocation
|
|
1134
|
-
});
|
|
1135
|
-
if (score2 <= currentThreshold) {
|
|
1136
|
-
binMin = binMid;
|
|
1137
|
-
} else {
|
|
1138
|
-
binMax = binMid;
|
|
1139
|
-
}
|
|
1140
|
-
binMid = Math.floor((binMax - binMin) / 2 + binMin);
|
|
1504
|
+
|
|
1505
|
+
// ../../node_modules/@turf/bbox/dist/esm/index.js
|
|
1506
|
+
function bbox(geojson, options = {}) {
|
|
1507
|
+
if (geojson.bbox != null && true !== options.recompute) {
|
|
1508
|
+
return geojson.bbox;
|
|
1509
|
+
}
|
|
1510
|
+
const result = [Infinity, Infinity, -Infinity, -Infinity];
|
|
1511
|
+
coordEach(geojson, (coord) => {
|
|
1512
|
+
if (result[0] > coord[0]) {
|
|
1513
|
+
result[0] = coord[0];
|
|
1141
1514
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
let finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen;
|
|
1145
|
-
let bitArr = Array(finish + 2);
|
|
1146
|
-
bitArr[finish + 1] = (1 << i) - 1;
|
|
1147
|
-
for (let j = finish; j >= start; j -= 1) {
|
|
1148
|
-
let currentLocation = j - 1;
|
|
1149
|
-
let charMatch = patternAlphabet[text.charAt(currentLocation)];
|
|
1150
|
-
if (computeMatches) {
|
|
1151
|
-
matchMask[currentLocation] = +!!charMatch;
|
|
1152
|
-
}
|
|
1153
|
-
bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch;
|
|
1154
|
-
if (i) {
|
|
1155
|
-
bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];
|
|
1156
|
-
}
|
|
1157
|
-
if (bitArr[j] & mask) {
|
|
1158
|
-
finalScore = computeScore$1(pattern, {
|
|
1159
|
-
errors: i,
|
|
1160
|
-
currentLocation,
|
|
1161
|
-
expectedLocation,
|
|
1162
|
-
distance,
|
|
1163
|
-
ignoreLocation
|
|
1164
|
-
});
|
|
1165
|
-
if (finalScore <= currentThreshold) {
|
|
1166
|
-
currentThreshold = finalScore;
|
|
1167
|
-
bestLocation = currentLocation;
|
|
1168
|
-
if (bestLocation <= expectedLocation) {
|
|
1169
|
-
break;
|
|
1170
|
-
}
|
|
1171
|
-
start = Math.max(1, 2 * expectedLocation - bestLocation);
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1515
|
+
if (result[1] > coord[1]) {
|
|
1516
|
+
result[1] = coord[1];
|
|
1174
1517
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
currentLocation: expectedLocation,
|
|
1178
|
-
expectedLocation,
|
|
1179
|
-
distance,
|
|
1180
|
-
ignoreLocation
|
|
1181
|
-
});
|
|
1182
|
-
if (score > currentThreshold) {
|
|
1183
|
-
break;
|
|
1518
|
+
if (result[2] < coord[0]) {
|
|
1519
|
+
result[2] = coord[0];
|
|
1184
1520
|
}
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
const result = {
|
|
1188
|
-
isMatch: bestLocation >= 0,
|
|
1189
|
-
// Count exact matches (those with a score of 0) to be "almost" exact
|
|
1190
|
-
score: Math.max(1e-3, finalScore)
|
|
1191
|
-
};
|
|
1192
|
-
if (computeMatches) {
|
|
1193
|
-
const indices = convertMaskToIndices(matchMask, minMatchCharLength);
|
|
1194
|
-
if (!indices.length) {
|
|
1195
|
-
result.isMatch = false;
|
|
1196
|
-
} else if (includeMatches) {
|
|
1197
|
-
result.indices = indices;
|
|
1521
|
+
if (result[3] < coord[1]) {
|
|
1522
|
+
result[3] = coord[1];
|
|
1198
1523
|
}
|
|
1199
|
-
}
|
|
1524
|
+
});
|
|
1200
1525
|
return result;
|
|
1201
1526
|
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
if (!this.pattern.length) {
|
|
1239
|
-
return;
|
|
1240
|
-
}
|
|
1241
|
-
const addChunk = (pattern2, startIndex) => {
|
|
1242
|
-
this.chunks.push({
|
|
1243
|
-
pattern: pattern2,
|
|
1244
|
-
alphabet: createPatternAlphabet(pattern2),
|
|
1245
|
-
startIndex
|
|
1246
|
-
});
|
|
1247
|
-
};
|
|
1248
|
-
const len = this.pattern.length;
|
|
1249
|
-
if (len > MAX_BITS) {
|
|
1250
|
-
let i = 0;
|
|
1251
|
-
const remainder = len % MAX_BITS;
|
|
1252
|
-
const end = len - remainder;
|
|
1253
|
-
while (i < end) {
|
|
1254
|
-
addChunk(this.pattern.substr(i, MAX_BITS), i);
|
|
1255
|
-
i += MAX_BITS;
|
|
1256
|
-
}
|
|
1257
|
-
if (remainder) {
|
|
1258
|
-
const startIndex = len - MAX_BITS;
|
|
1259
|
-
addChunk(this.pattern.substr(startIndex), startIndex);
|
|
1260
|
-
}
|
|
1261
|
-
} else {
|
|
1262
|
-
addChunk(this.pattern, 0);
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
searchIn(text) {
|
|
1266
|
-
const { isCaseSensitive, ignoreDiacritics, includeMatches } = this.options;
|
|
1267
|
-
text = isCaseSensitive ? text : text.toLowerCase();
|
|
1268
|
-
text = ignoreDiacritics ? stripDiacritics(text) : text;
|
|
1269
|
-
if (this.pattern === text) {
|
|
1270
|
-
let result2 = {
|
|
1271
|
-
isMatch: true,
|
|
1272
|
-
score: 0
|
|
1273
|
-
};
|
|
1274
|
-
if (includeMatches) {
|
|
1275
|
-
result2.indices = [[0, text.length - 1]];
|
|
1527
|
+
var index_default = bbox;
|
|
1528
|
+
|
|
1529
|
+
// src/data/navigate/steps/path/turf/shortestPath.ts
|
|
1530
|
+
import booleanPointInPolygon3 from "@turf/boolean-point-in-polygon";
|
|
1531
|
+
import distance3 from "@turf/distance";
|
|
1532
|
+
import scale from "@turf/transform-scale";
|
|
1533
|
+
import union from "@turf/union";
|
|
1534
|
+
import bboxPolygon from "@turf/bbox-polygon";
|
|
1535
|
+
import { cleanCoords } from "@turf/clean-coords";
|
|
1536
|
+
import PF from "pathfinding";
|
|
1537
|
+
import set3 from "lodash/set";
|
|
1538
|
+
|
|
1539
|
+
// src/data/navigate/steps/path/turf/stringPull.ts
|
|
1540
|
+
function stringPull(grid, path) {
|
|
1541
|
+
const isWalkable = (x, y) => grid.isInside(x, y) && grid.isWalkableAt(x, y);
|
|
1542
|
+
function hasLOS(a, b) {
|
|
1543
|
+
let x0 = a[0], y0 = a[1];
|
|
1544
|
+
const x1 = b[0], y1 = b[1];
|
|
1545
|
+
if (!isWalkable(x0, y0) || !isWalkable(x1, y1)) return false;
|
|
1546
|
+
const dx = Math.abs(x1 - x0);
|
|
1547
|
+
const dy = Math.abs(y1 - y0);
|
|
1548
|
+
const sx = x0 < x1 ? 1 : -1;
|
|
1549
|
+
const sy = y0 < y1 ? 1 : -1;
|
|
1550
|
+
let err = dx - dy;
|
|
1551
|
+
while (true) {
|
|
1552
|
+
if (!isWalkable(x0, y0)) return false;
|
|
1553
|
+
if (x0 === x1 && y0 === y1) break;
|
|
1554
|
+
const e2 = err * 2;
|
|
1555
|
+
let nx = x0;
|
|
1556
|
+
let ny = y0;
|
|
1557
|
+
let movedX = false;
|
|
1558
|
+
let movedY = false;
|
|
1559
|
+
if (e2 > -dy) {
|
|
1560
|
+
err -= dy;
|
|
1561
|
+
nx += sx;
|
|
1562
|
+
movedX = true;
|
|
1276
1563
|
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
distance,
|
|
1282
|
-
threshold,
|
|
1283
|
-
findAllMatches,
|
|
1284
|
-
minMatchCharLength,
|
|
1285
|
-
ignoreLocation
|
|
1286
|
-
} = this.options;
|
|
1287
|
-
let allIndices = [];
|
|
1288
|
-
let totalScore = 0;
|
|
1289
|
-
let hasMatches = false;
|
|
1290
|
-
this.chunks.forEach(({ pattern, alphabet, startIndex }) => {
|
|
1291
|
-
const { isMatch, score, indices } = search(text, pattern, alphabet, {
|
|
1292
|
-
location: location + startIndex,
|
|
1293
|
-
distance,
|
|
1294
|
-
threshold,
|
|
1295
|
-
findAllMatches,
|
|
1296
|
-
minMatchCharLength,
|
|
1297
|
-
includeMatches,
|
|
1298
|
-
ignoreLocation
|
|
1299
|
-
});
|
|
1300
|
-
if (isMatch) {
|
|
1301
|
-
hasMatches = true;
|
|
1564
|
+
if (e2 < dx) {
|
|
1565
|
+
err += dx;
|
|
1566
|
+
ny += sy;
|
|
1567
|
+
movedY = true;
|
|
1302
1568
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
allIndices = [...allIndices, ...indices];
|
|
1569
|
+
if (movedX && movedY) {
|
|
1570
|
+
if (!isWalkable(nx, y0) || !isWalkable(x0, ny)) return false;
|
|
1306
1571
|
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
isMatch: hasMatches,
|
|
1310
|
-
score: hasMatches ? totalScore / this.chunks.length : 1
|
|
1311
|
-
};
|
|
1312
|
-
if (hasMatches && includeMatches) {
|
|
1313
|
-
result.indices = allIndices;
|
|
1572
|
+
x0 = nx;
|
|
1573
|
+
y0 = ny;
|
|
1314
1574
|
}
|
|
1315
|
-
return
|
|
1316
|
-
}
|
|
1317
|
-
};
|
|
1318
|
-
var BaseMatch = class {
|
|
1319
|
-
constructor(pattern) {
|
|
1320
|
-
this.pattern = pattern;
|
|
1321
|
-
}
|
|
1322
|
-
static isMultiMatch(pattern) {
|
|
1323
|
-
return getMatch(pattern, this.multiRegex);
|
|
1324
|
-
}
|
|
1325
|
-
static isSingleMatch(pattern) {
|
|
1326
|
-
return getMatch(pattern, this.singleRegex);
|
|
1575
|
+
return true;
|
|
1327
1576
|
}
|
|
1328
|
-
|
|
1577
|
+
if (path.length <= 2) return path;
|
|
1578
|
+
const out = [path[0]];
|
|
1579
|
+
let i = 0;
|
|
1580
|
+
while (i < path.length - 1) {
|
|
1581
|
+
let best = i + 1;
|
|
1582
|
+
for (let j = i + 2; j < path.length; j++) {
|
|
1583
|
+
if (hasLOS(path[i], path[j])) best = j;
|
|
1584
|
+
else break;
|
|
1585
|
+
}
|
|
1586
|
+
out.push(path[best]);
|
|
1587
|
+
i = best;
|
|
1329
1588
|
}
|
|
1330
|
-
|
|
1331
|
-
function getMatch(pattern, exp) {
|
|
1332
|
-
const matches = pattern.match(exp);
|
|
1333
|
-
return matches ? matches[1] : null;
|
|
1589
|
+
return out;
|
|
1334
1590
|
}
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
const
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
static get multiRegex() {
|
|
1365
|
-
return /^!"(.*)"$/;
|
|
1366
|
-
}
|
|
1367
|
-
static get singleRegex() {
|
|
1368
|
-
return /^!(.*)$/;
|
|
1369
|
-
}
|
|
1370
|
-
search(text) {
|
|
1371
|
-
const index = text.indexOf(this.pattern);
|
|
1372
|
-
const isMatch = index === -1;
|
|
1373
|
-
return {
|
|
1374
|
-
isMatch,
|
|
1375
|
-
score: isMatch ? 0 : 1,
|
|
1376
|
-
indices: [0, text.length - 1]
|
|
1377
|
-
};
|
|
1378
|
-
}
|
|
1379
|
-
};
|
|
1380
|
-
var PrefixExactMatch = class extends BaseMatch {
|
|
1381
|
-
constructor(pattern) {
|
|
1382
|
-
super(pattern);
|
|
1383
|
-
}
|
|
1384
|
-
static get type() {
|
|
1385
|
-
return "prefix-exact";
|
|
1386
|
-
}
|
|
1387
|
-
static get multiRegex() {
|
|
1388
|
-
return /^\^"(.*)"$/;
|
|
1389
|
-
}
|
|
1390
|
-
static get singleRegex() {
|
|
1391
|
-
return /^\^(.*)$/;
|
|
1392
|
-
}
|
|
1393
|
-
search(text) {
|
|
1394
|
-
const isMatch = text.startsWith(this.pattern);
|
|
1395
|
-
return {
|
|
1396
|
-
isMatch,
|
|
1397
|
-
score: isMatch ? 0 : 1,
|
|
1398
|
-
indices: [0, this.pattern.length - 1]
|
|
1399
|
-
};
|
|
1400
|
-
}
|
|
1401
|
-
};
|
|
1402
|
-
var InversePrefixExactMatch = class extends BaseMatch {
|
|
1403
|
-
constructor(pattern) {
|
|
1404
|
-
super(pattern);
|
|
1405
|
-
}
|
|
1406
|
-
static get type() {
|
|
1407
|
-
return "inverse-prefix-exact";
|
|
1408
|
-
}
|
|
1409
|
-
static get multiRegex() {
|
|
1410
|
-
return /^!\^"(.*)"$/;
|
|
1411
|
-
}
|
|
1412
|
-
static get singleRegex() {
|
|
1413
|
-
return /^!\^(.*)$/;
|
|
1414
|
-
}
|
|
1415
|
-
search(text) {
|
|
1416
|
-
const isMatch = !text.startsWith(this.pattern);
|
|
1417
|
-
return {
|
|
1418
|
-
isMatch,
|
|
1419
|
-
score: isMatch ? 0 : 1,
|
|
1420
|
-
indices: [0, text.length - 1]
|
|
1421
|
-
};
|
|
1422
|
-
}
|
|
1423
|
-
};
|
|
1424
|
-
var SuffixExactMatch = class extends BaseMatch {
|
|
1425
|
-
constructor(pattern) {
|
|
1426
|
-
super(pattern);
|
|
1427
|
-
}
|
|
1428
|
-
static get type() {
|
|
1429
|
-
return "suffix-exact";
|
|
1430
|
-
}
|
|
1431
|
-
static get multiRegex() {
|
|
1432
|
-
return /^"(.*)"\$$/;
|
|
1433
|
-
}
|
|
1434
|
-
static get singleRegex() {
|
|
1435
|
-
return /^(.*)\$$/;
|
|
1436
|
-
}
|
|
1437
|
-
search(text) {
|
|
1438
|
-
const isMatch = text.endsWith(this.pattern);
|
|
1439
|
-
return {
|
|
1440
|
-
isMatch,
|
|
1441
|
-
score: isMatch ? 0 : 1,
|
|
1442
|
-
indices: [text.length - this.pattern.length, text.length - 1]
|
|
1443
|
-
};
|
|
1444
|
-
}
|
|
1445
|
-
};
|
|
1446
|
-
var InverseSuffixExactMatch = class extends BaseMatch {
|
|
1447
|
-
constructor(pattern) {
|
|
1448
|
-
super(pattern);
|
|
1449
|
-
}
|
|
1450
|
-
static get type() {
|
|
1451
|
-
return "inverse-suffix-exact";
|
|
1452
|
-
}
|
|
1453
|
-
static get multiRegex() {
|
|
1454
|
-
return /^!"(.*)"\$$/;
|
|
1455
|
-
}
|
|
1456
|
-
static get singleRegex() {
|
|
1457
|
-
return /^!(.*)\$$/;
|
|
1458
|
-
}
|
|
1459
|
-
search(text) {
|
|
1460
|
-
const isMatch = !text.endsWith(this.pattern);
|
|
1461
|
-
return {
|
|
1462
|
-
isMatch,
|
|
1463
|
-
score: isMatch ? 0 : 1,
|
|
1464
|
-
indices: [0, text.length - 1]
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
};
|
|
1468
|
-
var FuzzyMatch = class extends BaseMatch {
|
|
1469
|
-
constructor(pattern, {
|
|
1470
|
-
location = Config.location,
|
|
1471
|
-
threshold = Config.threshold,
|
|
1472
|
-
distance = Config.distance,
|
|
1473
|
-
includeMatches = Config.includeMatches,
|
|
1474
|
-
findAllMatches = Config.findAllMatches,
|
|
1475
|
-
minMatchCharLength = Config.minMatchCharLength,
|
|
1476
|
-
isCaseSensitive = Config.isCaseSensitive,
|
|
1477
|
-
ignoreDiacritics = Config.ignoreDiacritics,
|
|
1478
|
-
ignoreLocation = Config.ignoreLocation
|
|
1479
|
-
} = {}) {
|
|
1480
|
-
super(pattern);
|
|
1481
|
-
this._bitapSearch = new BitapSearch(pattern, {
|
|
1482
|
-
location,
|
|
1483
|
-
threshold,
|
|
1484
|
-
distance,
|
|
1485
|
-
includeMatches,
|
|
1486
|
-
findAllMatches,
|
|
1487
|
-
minMatchCharLength,
|
|
1488
|
-
isCaseSensitive,
|
|
1489
|
-
ignoreDiacritics,
|
|
1490
|
-
ignoreLocation
|
|
1491
|
-
});
|
|
1492
|
-
}
|
|
1493
|
-
static get type() {
|
|
1494
|
-
return "fuzzy";
|
|
1495
|
-
}
|
|
1496
|
-
static get multiRegex() {
|
|
1497
|
-
return /^"(.*)"$/;
|
|
1498
|
-
}
|
|
1499
|
-
static get singleRegex() {
|
|
1500
|
-
return /^(.*)$/;
|
|
1501
|
-
}
|
|
1502
|
-
search(text) {
|
|
1503
|
-
return this._bitapSearch.searchIn(text);
|
|
1504
|
-
}
|
|
1505
|
-
};
|
|
1506
|
-
var IncludeMatch = class extends BaseMatch {
|
|
1507
|
-
constructor(pattern) {
|
|
1508
|
-
super(pattern);
|
|
1509
|
-
}
|
|
1510
|
-
static get type() {
|
|
1511
|
-
return "include";
|
|
1512
|
-
}
|
|
1513
|
-
static get multiRegex() {
|
|
1514
|
-
return /^'"(.*)"$/;
|
|
1515
|
-
}
|
|
1516
|
-
static get singleRegex() {
|
|
1517
|
-
return /^'(.*)$/;
|
|
1518
|
-
}
|
|
1519
|
-
search(text) {
|
|
1520
|
-
let location = 0;
|
|
1521
|
-
let index;
|
|
1522
|
-
const indices = [];
|
|
1523
|
-
const patternLen = this.pattern.length;
|
|
1524
|
-
while ((index = text.indexOf(this.pattern, location)) > -1) {
|
|
1525
|
-
location = index + patternLen;
|
|
1526
|
-
indices.push([index, location - 1]);
|
|
1591
|
+
|
|
1592
|
+
// src/data/navigate/steps/path/turf/pruneSmallAngle.ts
|
|
1593
|
+
function pruneSmallAngles(path, minDeg = 10) {
|
|
1594
|
+
if (path.length <= 2) return path;
|
|
1595
|
+
const out = [path[0]];
|
|
1596
|
+
for (let i = 1; i < path.length - 1; i++) {
|
|
1597
|
+
const a = out[out.length - 1];
|
|
1598
|
+
const b = path[i];
|
|
1599
|
+
const c = path[i + 1];
|
|
1600
|
+
const abx = b[0] - a[0], aby = b[1] - a[1];
|
|
1601
|
+
const bcx = c[0] - b[0], bcy = c[1] - b[1];
|
|
1602
|
+
const dot = abx * bcx + aby * bcy;
|
|
1603
|
+
const ab = Math.hypot(abx, aby);
|
|
1604
|
+
const bc = Math.hypot(bcx, bcy);
|
|
1605
|
+
const angle = Math.acos(dot / (ab * bc)) * 180 / Math.PI;
|
|
1606
|
+
if (angle > minDeg) out.push(b);
|
|
1607
|
+
}
|
|
1608
|
+
out.push(path[path.length - 1]);
|
|
1609
|
+
return out;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
// src/data/navigate/steps/path/turf/pruneShortSegments.ts
|
|
1613
|
+
function pruneShortSegments(path, minLen = 5) {
|
|
1614
|
+
const out = [path[0]];
|
|
1615
|
+
for (let i = 1; i < path.length; i++) {
|
|
1616
|
+
const [x0, y0] = out[out.length - 1];
|
|
1617
|
+
const [x1, y1] = path[i];
|
|
1618
|
+
if (Math.hypot(x1 - x0, y1 - y0) >= minLen) {
|
|
1619
|
+
out.push(path[i]);
|
|
1527
1620
|
}
|
|
1528
|
-
const isMatch = !!indices.length;
|
|
1529
|
-
return {
|
|
1530
|
-
isMatch,
|
|
1531
|
-
score: isMatch ? 0 : 1,
|
|
1532
|
-
indices
|
|
1533
|
-
};
|
|
1534
1621
|
}
|
|
1535
|
-
|
|
1536
|
-
var searchers = [
|
|
1537
|
-
ExactMatch,
|
|
1538
|
-
IncludeMatch,
|
|
1539
|
-
PrefixExactMatch,
|
|
1540
|
-
InversePrefixExactMatch,
|
|
1541
|
-
InverseSuffixExactMatch,
|
|
1542
|
-
SuffixExactMatch,
|
|
1543
|
-
InverseExactMatch,
|
|
1544
|
-
FuzzyMatch
|
|
1545
|
-
];
|
|
1546
|
-
var searchersLen = searchers.length;
|
|
1547
|
-
var SPACE_RE = / +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/;
|
|
1548
|
-
var OR_TOKEN = "|";
|
|
1549
|
-
function parseQuery(pattern, options = {}) {
|
|
1550
|
-
return pattern.split(OR_TOKEN).map((item) => {
|
|
1551
|
-
let query = item.trim().split(SPACE_RE).filter((item2) => item2 && !!item2.trim());
|
|
1552
|
-
let results = [];
|
|
1553
|
-
for (let i = 0, len = query.length; i < len; i += 1) {
|
|
1554
|
-
const queryItem = query[i];
|
|
1555
|
-
let found = false;
|
|
1556
|
-
let idx = -1;
|
|
1557
|
-
while (!found && ++idx < searchersLen) {
|
|
1558
|
-
const searcher = searchers[idx];
|
|
1559
|
-
let token = searcher.isMultiMatch(queryItem);
|
|
1560
|
-
if (token) {
|
|
1561
|
-
results.push(new searcher(token, options));
|
|
1562
|
-
found = true;
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
if (found) {
|
|
1566
|
-
continue;
|
|
1567
|
-
}
|
|
1568
|
-
idx = -1;
|
|
1569
|
-
while (++idx < searchersLen) {
|
|
1570
|
-
const searcher = searchers[idx];
|
|
1571
|
-
let token = searcher.isSingleMatch(queryItem);
|
|
1572
|
-
if (token) {
|
|
1573
|
-
results.push(new searcher(token, options));
|
|
1574
|
-
break;
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
}
|
|
1578
|
-
return results;
|
|
1579
|
-
});
|
|
1622
|
+
return out;
|
|
1580
1623
|
}
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
this.query = null;
|
|
1595
|
-
this.options = {
|
|
1596
|
-
isCaseSensitive,
|
|
1597
|
-
ignoreDiacritics,
|
|
1598
|
-
includeMatches,
|
|
1599
|
-
minMatchCharLength,
|
|
1600
|
-
findAllMatches,
|
|
1601
|
-
ignoreLocation,
|
|
1602
|
-
location,
|
|
1603
|
-
threshold,
|
|
1604
|
-
distance
|
|
1605
|
-
};
|
|
1606
|
-
pattern = isCaseSensitive ? pattern : pattern.toLowerCase();
|
|
1607
|
-
pattern = ignoreDiacritics ? stripDiacritics(pattern) : pattern;
|
|
1608
|
-
this.pattern = pattern;
|
|
1609
|
-
this.query = parseQuery(this.pattern, this.options);
|
|
1610
|
-
}
|
|
1611
|
-
static condition(_, options) {
|
|
1612
|
-
return options.useExtendedSearch;
|
|
1613
|
-
}
|
|
1614
|
-
searchIn(text) {
|
|
1615
|
-
const query = this.query;
|
|
1616
|
-
if (!query) {
|
|
1617
|
-
return {
|
|
1618
|
-
isMatch: false,
|
|
1619
|
-
score: 1
|
|
1620
|
-
};
|
|
1621
|
-
}
|
|
1622
|
-
const { includeMatches, isCaseSensitive, ignoreDiacritics } = this.options;
|
|
1623
|
-
text = isCaseSensitive ? text : text.toLowerCase();
|
|
1624
|
-
text = ignoreDiacritics ? stripDiacritics(text) : text;
|
|
1625
|
-
let numMatches = 0;
|
|
1626
|
-
let allIndices = [];
|
|
1627
|
-
let totalScore = 0;
|
|
1628
|
-
for (let i = 0, qLen = query.length; i < qLen; i += 1) {
|
|
1629
|
-
const searchers2 = query[i];
|
|
1630
|
-
allIndices.length = 0;
|
|
1631
|
-
numMatches = 0;
|
|
1632
|
-
for (let j = 0, pLen = searchers2.length; j < pLen; j += 1) {
|
|
1633
|
-
const searcher = searchers2[j];
|
|
1634
|
-
const { isMatch, indices, score } = searcher.search(text);
|
|
1635
|
-
if (isMatch) {
|
|
1636
|
-
numMatches += 1;
|
|
1637
|
-
totalScore += score;
|
|
1638
|
-
if (includeMatches) {
|
|
1639
|
-
const type = searcher.constructor.type;
|
|
1640
|
-
if (MultiMatchSet.has(type)) {
|
|
1641
|
-
allIndices = [...allIndices, ...indices];
|
|
1642
|
-
} else {
|
|
1643
|
-
allIndices.push(indices);
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
} else {
|
|
1647
|
-
totalScore = 0;
|
|
1648
|
-
numMatches = 0;
|
|
1649
|
-
allIndices.length = 0;
|
|
1650
|
-
break;
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
if (numMatches) {
|
|
1654
|
-
let result = {
|
|
1655
|
-
isMatch: true,
|
|
1656
|
-
score: totalScore / numMatches
|
|
1657
|
-
};
|
|
1658
|
-
if (includeMatches) {
|
|
1659
|
-
result.indices = allIndices;
|
|
1660
|
-
}
|
|
1661
|
-
return result;
|
|
1624
|
+
|
|
1625
|
+
// src/data/navigate/steps/path/turf/clearance.ts
|
|
1626
|
+
function buildClearanceGrid(matrix) {
|
|
1627
|
+
const h = matrix.length;
|
|
1628
|
+
const w = matrix[0].length;
|
|
1629
|
+
const INF = 1e9;
|
|
1630
|
+
const dist = Array.from({ length: h }, () => Array(w).fill(INF));
|
|
1631
|
+
const q = [];
|
|
1632
|
+
for (let y = 0; y < h; y++) {
|
|
1633
|
+
for (let x = 0; x < w; x++) {
|
|
1634
|
+
if (matrix[y][x] === 1) {
|
|
1635
|
+
dist[y][x] = 0;
|
|
1636
|
+
q.push([x, y]);
|
|
1662
1637
|
}
|
|
1663
1638
|
}
|
|
1664
|
-
return {
|
|
1665
|
-
isMatch: false,
|
|
1666
|
-
score: 1
|
|
1667
|
-
};
|
|
1668
1639
|
}
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1640
|
+
const dirs = [
|
|
1641
|
+
[1, 0],
|
|
1642
|
+
[-1, 0],
|
|
1643
|
+
[0, 1],
|
|
1644
|
+
[0, -1],
|
|
1645
|
+
[1, 1],
|
|
1646
|
+
[1, -1],
|
|
1647
|
+
[-1, 1],
|
|
1648
|
+
[-1, -1]
|
|
1649
|
+
];
|
|
1650
|
+
let qi = 0;
|
|
1651
|
+
while (qi < q.length) {
|
|
1652
|
+
const [x, y] = q[qi++];
|
|
1653
|
+
const d0 = dist[y][x];
|
|
1654
|
+
for (const [dx, dy] of dirs) {
|
|
1655
|
+
const nx = x + dx, ny = y + dy;
|
|
1656
|
+
if (nx < 0 || ny < 0 || nx >= w || ny >= h) continue;
|
|
1657
|
+
const nd = d0 + 1;
|
|
1658
|
+
if (nd < dist[ny][nx]) {
|
|
1659
|
+
dist[ny][nx] = nd;
|
|
1660
|
+
q.push([nx, ny]);
|
|
1661
|
+
}
|
|
1679
1662
|
}
|
|
1680
1663
|
}
|
|
1681
|
-
return
|
|
1664
|
+
return dist;
|
|
1682
1665
|
}
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
});
|
|
1699
|
-
function parse(query, options, { auto = true } = {}) {
|
|
1700
|
-
const next = (query2) => {
|
|
1701
|
-
let keys = Object.keys(query2);
|
|
1702
|
-
const isQueryPath = isPath(query2);
|
|
1703
|
-
if (!isQueryPath && keys.length > 1 && !isExpression(query2)) {
|
|
1704
|
-
return next(convertToExplicit(query2));
|
|
1705
|
-
}
|
|
1706
|
-
if (isLeaf(query2)) {
|
|
1707
|
-
const key = isQueryPath ? query2[KeyType.PATH] : keys[0];
|
|
1708
|
-
const pattern = isQueryPath ? query2[KeyType.PATTERN] : query2[key];
|
|
1709
|
-
if (!isString(pattern)) {
|
|
1710
|
-
throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));
|
|
1711
|
-
}
|
|
1712
|
-
const obj = {
|
|
1713
|
-
keyId: createKeyId(key),
|
|
1714
|
-
pattern
|
|
1715
|
-
};
|
|
1716
|
-
if (auto) {
|
|
1717
|
-
obj.searcher = createSearcher(pattern, options);
|
|
1666
|
+
function snapPointToClearancePeak(p, clearance, isWalkableCell, radius = 4) {
|
|
1667
|
+
const [px, py] = p;
|
|
1668
|
+
let best = p;
|
|
1669
|
+
let bestScore = clearance[py]?.[px] ?? -Infinity;
|
|
1670
|
+
for (let dy = -radius; dy <= radius; dy++) {
|
|
1671
|
+
for (let dx = -radius; dx <= radius; dx++) {
|
|
1672
|
+
const x = px + dx;
|
|
1673
|
+
const y = py + dy;
|
|
1674
|
+
if (!isWalkableCell(x, y)) continue;
|
|
1675
|
+
const score = clearance[y][x];
|
|
1676
|
+
const penalty = Math.hypot(dx, dy) * 5e-3;
|
|
1677
|
+
const finalScore = score - penalty;
|
|
1678
|
+
if (finalScore > bestScore) {
|
|
1679
|
+
bestScore = finalScore;
|
|
1680
|
+
best = [x, y];
|
|
1718
1681
|
}
|
|
1719
|
-
return obj;
|
|
1720
1682
|
}
|
|
1721
|
-
let node = {
|
|
1722
|
-
children: [],
|
|
1723
|
-
operator: keys[0]
|
|
1724
|
-
};
|
|
1725
|
-
keys.forEach((key) => {
|
|
1726
|
-
const value = query2[key];
|
|
1727
|
-
if (isArray(value)) {
|
|
1728
|
-
value.forEach((item) => {
|
|
1729
|
-
node.children.push(next(item));
|
|
1730
|
-
});
|
|
1731
|
-
}
|
|
1732
|
-
});
|
|
1733
|
-
return node;
|
|
1734
|
-
};
|
|
1735
|
-
if (!isExpression(query)) {
|
|
1736
|
-
query = convertToExplicit(query);
|
|
1737
1683
|
}
|
|
1738
|
-
return
|
|
1684
|
+
return best;
|
|
1739
1685
|
}
|
|
1740
|
-
function
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
result.matches.forEach(({ key, norm: norm2, score }) => {
|
|
1744
|
-
const weight = key ? key.weight : null;
|
|
1745
|
-
totalScore *= Math.pow(
|
|
1746
|
-
score === 0 && weight ? Number.EPSILON : score,
|
|
1747
|
-
(weight || 1) * (ignoreFieldNorm ? 1 : norm2)
|
|
1748
|
-
);
|
|
1749
|
-
});
|
|
1750
|
-
result.score = totalScore;
|
|
1751
|
-
});
|
|
1686
|
+
function centerlineSnapPath(path, clearance, isWalkableCell, radius = 4) {
|
|
1687
|
+
const snapped = path.map((p) => snapPointToClearancePeak(p, clearance, isWalkableCell, radius));
|
|
1688
|
+
return snapped;
|
|
1752
1689
|
}
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1690
|
+
|
|
1691
|
+
// src/data/navigate/steps/path/turf/shortestPath.ts
|
|
1692
|
+
function shortestPath(start, end, options) {
|
|
1693
|
+
options = options || {};
|
|
1694
|
+
if (!isObject(options)) throw new Error("options is invalid");
|
|
1695
|
+
let resolution = options.resolution;
|
|
1696
|
+
const smoothenPath = options.smoothenPath;
|
|
1697
|
+
let obstacles = options.obstacles || featureCollection([]);
|
|
1698
|
+
if (!start) throw new Error("start is required");
|
|
1699
|
+
if (!end) throw new Error("end is required");
|
|
1700
|
+
if (resolution && !isNumber(resolution) || resolution <= 0)
|
|
1701
|
+
throw new Error("options.resolution must be a number, greater than 0");
|
|
1702
|
+
const startCoord = getCoord(start);
|
|
1703
|
+
const endCoord = getCoord(end);
|
|
1704
|
+
start = point(startCoord);
|
|
1705
|
+
end = point(endCoord);
|
|
1706
|
+
switch (getType(obstacles)) {
|
|
1707
|
+
case "FeatureCollection":
|
|
1708
|
+
if (obstacles.features.length === 0)
|
|
1709
|
+
return lineString([startCoord, endCoord]);
|
|
1710
|
+
break;
|
|
1711
|
+
case "Polygon":
|
|
1712
|
+
obstacles = featureCollection([feature(getGeom(obstacles))]);
|
|
1713
|
+
break;
|
|
1714
|
+
default:
|
|
1715
|
+
throw new Error("invalid obstacles");
|
|
1716
|
+
}
|
|
1717
|
+
const collection = obstacles;
|
|
1718
|
+
collection.features.push(start, end);
|
|
1719
|
+
const box = index_default(scale(bboxPolygon(index_default(collection)), 1.15));
|
|
1720
|
+
if (!resolution) {
|
|
1721
|
+
const width = distance3([box[0], box[1]], [box[2], box[1]], options);
|
|
1722
|
+
resolution = width / 100;
|
|
1723
|
+
}
|
|
1724
|
+
collection.features.pop();
|
|
1725
|
+
collection.features.pop();
|
|
1726
|
+
const [west, south, east, north] = box;
|
|
1727
|
+
const xFraction = resolution / distance3([west, south], [east, south], options);
|
|
1728
|
+
const cellWidth = xFraction * (east - west);
|
|
1729
|
+
const yFraction = resolution / distance3([west, south], [west, north], options);
|
|
1730
|
+
const cellHeight = yFraction * (north - south);
|
|
1731
|
+
const bboxHorizontalSide = east - west;
|
|
1732
|
+
const bboxVerticalSide = north - south;
|
|
1733
|
+
const columns = Math.floor(bboxHorizontalSide / cellWidth);
|
|
1734
|
+
const rows = Math.floor(bboxVerticalSide / cellHeight);
|
|
1735
|
+
const deltaX = (bboxHorizontalSide - columns * cellWidth) / 2;
|
|
1736
|
+
const deltaY = (bboxVerticalSide - rows * cellHeight) / 2;
|
|
1737
|
+
let closestToStart = null, closestToEnd = null, minDistStart = Infinity, minDistEnd = Infinity, currentY = north - deltaY, currentX = west + deltaX, row = 0, column = 0, distStart, distEnd, pt, isInsideObstacle;
|
|
1738
|
+
const roundLoopY = Math.ceil((currentY - south) / cellHeight);
|
|
1739
|
+
const roundLoopX = Math.ceil((east - currentX) / cellWidth);
|
|
1740
|
+
let totalRounds = roundLoopX * roundLoopY;
|
|
1741
|
+
const pointMatrix = [];
|
|
1742
|
+
const matrix = [];
|
|
1743
|
+
const obstacleTotal = collection.features.length;
|
|
1744
|
+
const obstacleFeatures = collection.features;
|
|
1745
|
+
let combinedObstacle = obstacleFeatures[0];
|
|
1746
|
+
let obstacleIndex = 0;
|
|
1747
|
+
for (obstacleIndex = 0; obstacleIndex < obstacleTotal; obstacleIndex++) {
|
|
1748
|
+
const nextObstacleFeature = obstacleFeatures[obstacleIndex + 1];
|
|
1749
|
+
if (!nextObstacleFeature) continue;
|
|
1750
|
+
try {
|
|
1751
|
+
combinedObstacle = union(
|
|
1752
|
+
featureCollection([combinedObstacle, nextObstacleFeature])
|
|
1753
|
+
);
|
|
1754
|
+
} catch (e) {
|
|
1755
|
+
console.log(e);
|
|
1756
|
+
}
|
|
1758
1757
|
}
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1758
|
+
while (totalRounds--) {
|
|
1759
|
+
pt = point([currentX, currentY]);
|
|
1760
|
+
isInsideObstacle = booleanPointInPolygon3(pt, combinedObstacle);
|
|
1761
|
+
set3(matrix, `[${row}][${column}]`, isInsideObstacle ? 1 : 0);
|
|
1762
|
+
set3(pointMatrix, `[${row}][${column}]`, `${currentX}|${currentY}`);
|
|
1763
|
+
distStart = distance3(pt, start);
|
|
1764
|
+
if (!isInsideObstacle && distStart < minDistStart) {
|
|
1765
|
+
minDistStart = distStart;
|
|
1766
|
+
closestToStart = { x: column, y: row };
|
|
1762
1767
|
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
};
|
|
1768
|
-
if (match.key) {
|
|
1769
|
-
obj.key = match.key.src;
|
|
1768
|
+
distEnd = distance3(pt, end);
|
|
1769
|
+
if (!isInsideObstacle && distEnd < minDistEnd) {
|
|
1770
|
+
minDistEnd = distEnd;
|
|
1771
|
+
closestToEnd = { x: column, y: row };
|
|
1770
1772
|
}
|
|
1771
|
-
if (
|
|
1772
|
-
|
|
1773
|
+
if (column < roundLoopX) {
|
|
1774
|
+
currentX += cellWidth;
|
|
1775
|
+
column++;
|
|
1776
|
+
continue;
|
|
1773
1777
|
}
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
}
|
|
1780
|
-
function format(results, docs, {
|
|
1781
|
-
includeMatches = Config.includeMatches,
|
|
1782
|
-
includeScore = Config.includeScore
|
|
1783
|
-
} = {}) {
|
|
1784
|
-
const transformers = [];
|
|
1785
|
-
if (includeMatches) transformers.push(transformMatches);
|
|
1786
|
-
if (includeScore) transformers.push(transformScore);
|
|
1787
|
-
return results.map((result) => {
|
|
1788
|
-
const { idx } = result;
|
|
1789
|
-
const data = {
|
|
1790
|
-
item: docs[idx],
|
|
1791
|
-
refIndex: idx
|
|
1792
|
-
};
|
|
1793
|
-
if (transformers.length) {
|
|
1794
|
-
transformers.forEach((transformer) => {
|
|
1795
|
-
transformer(result, data);
|
|
1796
|
-
});
|
|
1778
|
+
if (row < roundLoopY) {
|
|
1779
|
+
currentY -= cellHeight;
|
|
1780
|
+
currentX = west + deltaX;
|
|
1781
|
+
column = 0;
|
|
1782
|
+
row++;
|
|
1797
1783
|
}
|
|
1798
|
-
|
|
1784
|
+
}
|
|
1785
|
+
const finder = new PF.AStarFinder({
|
|
1786
|
+
allowDiagonal: true,
|
|
1787
|
+
dontCrossCorners: true,
|
|
1788
|
+
heuristic: PF.Heuristic.euclidean
|
|
1789
|
+
});
|
|
1790
|
+
const grid = new PF.Grid(matrix);
|
|
1791
|
+
const startOnMatrix = [closestToStart.x, closestToStart.y];
|
|
1792
|
+
const endOnMatrix = [closestToEnd.x, closestToEnd.y];
|
|
1793
|
+
let result = finder.findPath(...startOnMatrix, ...endOnMatrix, grid);
|
|
1794
|
+
if (result.length > 0) {
|
|
1795
|
+
result = stringPull(grid, result);
|
|
1796
|
+
const clearanceGrid = buildClearanceGrid(matrix);
|
|
1797
|
+
const isWalkable = (x, y) => grid.isInside(x, y) && grid.isWalkableAt(x, y);
|
|
1798
|
+
result = centerlineSnapPath(result, clearanceGrid, isWalkable);
|
|
1799
|
+
result = stringPull(grid, result);
|
|
1800
|
+
result = pruneSmallAngles(result);
|
|
1801
|
+
result = pruneShortSegments(result);
|
|
1802
|
+
}
|
|
1803
|
+
result.pop();
|
|
1804
|
+
result.shift();
|
|
1805
|
+
const path = [startCoord];
|
|
1806
|
+
result.forEach((coord) => {
|
|
1807
|
+
const coords = pointMatrix[coord[1]][coord[0]].split("|");
|
|
1808
|
+
path.push([+coords[0], +coords[1]]);
|
|
1799
1809
|
});
|
|
1810
|
+
path.push(endCoord);
|
|
1811
|
+
return cleanCoords(lineString(path));
|
|
1800
1812
|
}
|
|
1801
|
-
var
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
this._docs = docs;
|
|
1812
|
-
if (index && !(index instanceof FuseIndex)) {
|
|
1813
|
-
throw new Error(INCORRECT_INDEX_TYPE);
|
|
1814
|
-
}
|
|
1815
|
-
this._myIndex = index || createIndex(this.options.keys, this._docs, {
|
|
1816
|
-
getFn: this.options.getFn,
|
|
1817
|
-
fieldNormWeight: this.options.fieldNormWeight
|
|
1813
|
+
var shortestPath_default = shortestPath;
|
|
1814
|
+
|
|
1815
|
+
// src/data/navigate/steps/path/index.ts
|
|
1816
|
+
var createStepPathUtils = (options) => {
|
|
1817
|
+
const resolution = options.resolution ?? 88e-5;
|
|
1818
|
+
const { units, kiosks, fixtures } = options.data;
|
|
1819
|
+
const possibleObstacleFeatures = [...units, ...kiosks, ...fixtures];
|
|
1820
|
+
const filterObstaclesByOrdinal = (levelId) => {
|
|
1821
|
+
return possibleObstacleFeatures.filter(({ feature_type, properties, geometry }) => {
|
|
1822
|
+
return properties.level_id === levelId && ["Polygon", "MultiPolygon"].includes(geometry.type) && (OBSTACLE_FEATURE_TYPES.includes(feature_type) || "category" in properties && OBSTACLE_CATEGORIES.includes(properties.category));
|
|
1818
1823
|
});
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1824
|
+
};
|
|
1825
|
+
const findObstaclesFromWalkway = (intermediaryUnit, exceptionIds = []) => {
|
|
1826
|
+
const result = featureCollection([]);
|
|
1827
|
+
if (!intermediaryUnit) return result;
|
|
1828
|
+
const walkwayLevelId = intermediaryUnit.properties.level_id;
|
|
1829
|
+
const obstacleOnLevel = filterObstaclesByOrdinal(walkwayLevelId).filter(
|
|
1830
|
+
(obstacle) => !exceptionIds.includes(obstacle.id)
|
|
1831
|
+
);
|
|
1832
|
+
const relatedObstacleWithIntermediary = obstacleOnLevel.reduce(
|
|
1833
|
+
(obstacles, feature2) => {
|
|
1834
|
+
if (
|
|
1835
|
+
// Prevent detecting itself as an obstacle
|
|
1836
|
+
// Ex. Unable to draw a line to amenity located with in a room as room is also consider as obstacle
|
|
1837
|
+
feature2.id !== intermediaryUnit.id && (booleanOverlap(intermediaryUnit, feature2) || booleanIntersects(intermediaryUnit, feature2))
|
|
1838
|
+
) {
|
|
1839
|
+
const polygons = getType(feature2) === "Polygon" ? [polygon(feature2.geometry.coordinates, { id: feature2.id })] : feature2.geometry.coordinates.map((ring) => polygon(ring, { id: feature2.id }));
|
|
1840
|
+
obstacles.push(...polygons);
|
|
1841
|
+
}
|
|
1842
|
+
return obstacles;
|
|
1843
|
+
},
|
|
1844
|
+
[]
|
|
1845
|
+
);
|
|
1846
|
+
const intermediaryExtends = envelope(intermediaryUnit);
|
|
1847
|
+
const walkwayPerimeter = difference(
|
|
1848
|
+
featureCollection([intermediaryExtends, intermediaryUnit])
|
|
1849
|
+
);
|
|
1850
|
+
result.features.push(...relatedObstacleWithIntermediary, walkwayPerimeter);
|
|
1851
|
+
return result;
|
|
1852
|
+
};
|
|
1853
|
+
const findPathOnArea = (originPoint, destinationPoint, options2) => {
|
|
1854
|
+
const { obstacles = featureCollection([]), resolution: resolution2, properties } = options2 || {};
|
|
1855
|
+
const stepPath = shortestPath_default(originPoint, destinationPoint, {
|
|
1856
|
+
obstacles,
|
|
1857
|
+
smoothenPath: false,
|
|
1858
|
+
resolution: resolution2
|
|
1859
|
+
});
|
|
1860
|
+
stepPath.properties = properties;
|
|
1861
|
+
return stepPath;
|
|
1862
|
+
};
|
|
1863
|
+
const findStepPath = (from, to, intermediaries) => {
|
|
1864
|
+
const t0 = performance.now();
|
|
1865
|
+
const relatedWalkablePlatform = intermediaries.find(
|
|
1866
|
+
(feature2) => WALKABLE_CATEGORY.includes(feature2.properties.category)
|
|
1867
|
+
);
|
|
1868
|
+
const exceptionFeatureIds = [];
|
|
1869
|
+
const obstacles = findObstaclesFromWalkway(
|
|
1870
|
+
relatedWalkablePlatform,
|
|
1871
|
+
_7.compact(exceptionFeatureIds)
|
|
1872
|
+
);
|
|
1873
|
+
const line = findPathOnArea(from, to, {
|
|
1874
|
+
resolution,
|
|
1875
|
+
obstacles
|
|
1876
|
+
});
|
|
1877
|
+
return line.geometry.coordinates;
|
|
1878
|
+
};
|
|
1879
|
+
return {
|
|
1880
|
+
findStepPath
|
|
1881
|
+
};
|
|
1882
|
+
};
|
|
1883
|
+
|
|
1884
|
+
// src/data/navigate/landmark/createLandmarkUtils.ts
|
|
1885
|
+
import { center as center3 } from "@turf/center";
|
|
1886
|
+
import distance4 from "@turf/distance";
|
|
1887
|
+
var NEARBY_DISTANCE = 30;
|
|
1888
|
+
var createLandmarkUtils = (options) => {
|
|
1889
|
+
const { data, findByIdSync } = options;
|
|
1890
|
+
const { occupants } = data;
|
|
1891
|
+
const occupantToLandmark = (occupant) => {
|
|
1892
|
+
const locationType = occupant.properties.unit_id ? "unit" : "kiosk";
|
|
1893
|
+
const locationId = locationType === "unit" ? occupant.properties.unit_id : occupant.properties.kiosk_id;
|
|
1894
|
+
const location = locationType === "unit" ? findByIdSync(locationId) : findByIdSync(locationId);
|
|
1895
|
+
const level = findByIdSync(location.properties.level_id);
|
|
1896
|
+
return {
|
|
1897
|
+
name: occupant.properties.name,
|
|
1898
|
+
point: center3(location.geometry).geometry.coordinates,
|
|
1899
|
+
level_id: location.properties.level_id,
|
|
1900
|
+
is_priority: occupant.properties.is_landmark,
|
|
1901
|
+
ordinal: level.properties.ordinal
|
|
1902
|
+
};
|
|
1903
|
+
};
|
|
1904
|
+
const landmarks = [
|
|
1905
|
+
...occupants.map(occupantToLandmark)
|
|
1906
|
+
];
|
|
1907
|
+
const findNearbyLandmarks = (point2, levelId) => {
|
|
1908
|
+
if (point2 === null || levelId === null) return [];
|
|
1909
|
+
return landmarks.map((landmark) => {
|
|
1910
|
+
const landmarkAndDistance = {
|
|
1911
|
+
landmark,
|
|
1912
|
+
d: distance4(point2, landmark.point, { units: "meters" })
|
|
1913
|
+
};
|
|
1914
|
+
return landmarkAndDistance;
|
|
1915
|
+
}).filter(({ landmark, d }) => d <= NEARBY_DISTANCE && landmark.level_id === levelId).sort((a, b) => {
|
|
1916
|
+
const aPriority = a.landmark.is_priority ? 0 : 1;
|
|
1917
|
+
const bPriority = b.landmark.is_priority ? 0 : 1;
|
|
1918
|
+
if (aPriority !== bPriority) return aPriority - bPriority;
|
|
1919
|
+
return a.d - b.d;
|
|
1920
|
+
}).map(({ landmark }) => landmark);
|
|
1921
|
+
};
|
|
1922
|
+
const findNearestLandmark = (point2, levelId) => {
|
|
1923
|
+
const nearbyLandmarks = findNearbyLandmarks(point2, levelId);
|
|
1924
|
+
const nearestLandmark = nearbyLandmarks.length > 0 ? nearbyLandmarks[0] : null;
|
|
1925
|
+
return nearestLandmark;
|
|
1926
|
+
};
|
|
1927
|
+
return { findNearbyLandmarks, findNearestLandmark };
|
|
1928
|
+
};
|
|
1929
|
+
|
|
1930
|
+
// src/data/navigate/steps/utils/extractStartPoint.ts
|
|
1931
|
+
import { center as center4 } from "@turf/center";
|
|
1932
|
+
|
|
1933
|
+
// src/data/navigate/steps/utils/featureIdGuard.ts
|
|
1934
|
+
var isOccupant = (id) => !!id && id.startsWith("occupant-");
|
|
1935
|
+
var isUnit = (id) => !!id && id.startsWith("unit-");
|
|
1936
|
+
var isKiosk = (id) => !!id && id.startsWith("kiosk-");
|
|
1937
|
+
var isOpening = (id) => !!id && id.startsWith("opening-");
|
|
1938
|
+
|
|
1939
|
+
// src/data/navigate/type-guard.ts
|
|
1940
|
+
function isCoordinateOrdinalString(id) {
|
|
1941
|
+
return /^-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?o$/.test(id);
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
// src/data/navigate/steps/utils/extractStartPoint.ts
|
|
1945
|
+
var extractStartPoint = (path, options) => {
|
|
1946
|
+
const { findByIdSync } = options;
|
|
1947
|
+
const [a, b, c] = path;
|
|
1948
|
+
if (isOccupant(a) && isUnit(b) && isOpening(c)) {
|
|
1949
|
+
const occ = findByIdSync(a);
|
|
1950
|
+
const opening = findByIdSync(c);
|
|
1951
|
+
const level = findByIdSync(opening.properties.level_id);
|
|
1952
|
+
return [
|
|
1953
|
+
{
|
|
1954
|
+
id: occ.id,
|
|
1955
|
+
type: "start",
|
|
1956
|
+
name: occ.properties.name,
|
|
1957
|
+
point: center4(opening).geometry.coordinates,
|
|
1958
|
+
levelId: opening.properties.level_id,
|
|
1959
|
+
ordinal: level.properties.ordinal,
|
|
1960
|
+
source: { type: "opening", id: opening.id }
|
|
1961
|
+
},
|
|
1962
|
+
path.slice(3)
|
|
1963
|
+
];
|
|
1964
|
+
}
|
|
1965
|
+
if (isOccupant(a) && isKiosk(b)) {
|
|
1966
|
+
const occ = findByIdSync(a);
|
|
1967
|
+
const kiosk = findByIdSync(c);
|
|
1968
|
+
const level = findByIdSync(kiosk.properties.level_id);
|
|
1969
|
+
return [
|
|
1970
|
+
{
|
|
1971
|
+
id: occ.id,
|
|
1972
|
+
type: "start",
|
|
1973
|
+
name: occ.properties.name,
|
|
1974
|
+
point: center4(kiosk).geometry.coordinates,
|
|
1975
|
+
levelId: kiosk.properties.level_id,
|
|
1976
|
+
ordinal: level.properties.ordinal,
|
|
1977
|
+
source: { type: "kiosk", id: kiosk.id }
|
|
1978
|
+
},
|
|
1979
|
+
path.slice(2)
|
|
1980
|
+
];
|
|
1981
|
+
}
|
|
1982
|
+
if (isCoordinateOrdinalString(a) && isOpening(b)) {
|
|
1983
|
+
const [lat, lng, ordinal] = parseOrdinalCoordinate(a);
|
|
1984
|
+
const opening = findByIdSync(b);
|
|
1985
|
+
return [
|
|
1986
|
+
{
|
|
1987
|
+
id: a,
|
|
1988
|
+
type: "start",
|
|
1989
|
+
name: { en: `Your location` },
|
|
1990
|
+
point: [lng, lat],
|
|
1991
|
+
levelId: opening.properties.level_id,
|
|
1992
|
+
ordinal,
|
|
1993
|
+
source: { type: "opening", id: opening.id }
|
|
1994
|
+
},
|
|
1995
|
+
path.slice(1)
|
|
1996
|
+
];
|
|
1997
|
+
}
|
|
1998
|
+
return [null, path];
|
|
1999
|
+
};
|
|
2000
|
+
|
|
2001
|
+
// src/data/navigate/steps/utils/extractEndPint.ts
|
|
2002
|
+
import { center as center5 } from "@turf/center";
|
|
2003
|
+
var extractEndPoint = (path, options) => {
|
|
2004
|
+
const { findByIdSync } = options;
|
|
2005
|
+
const [c, b, a] = path.slice(-3);
|
|
2006
|
+
if (isOccupant(a) && isUnit(b) && isOpening(c)) {
|
|
2007
|
+
const occ = findByIdSync(a);
|
|
2008
|
+
const opening = findByIdSync(c);
|
|
2009
|
+
const level = findByIdSync(opening.properties.level_id);
|
|
2010
|
+
return [
|
|
2011
|
+
{
|
|
2012
|
+
id: occ.id,
|
|
2013
|
+
type: "end",
|
|
2014
|
+
name: occ.properties.name,
|
|
2015
|
+
point: center5(opening).geometry.coordinates,
|
|
2016
|
+
levelId: opening.properties.level_id,
|
|
2017
|
+
ordinal: level.properties.ordinal,
|
|
2018
|
+
source: { type: "opening", id: opening.id }
|
|
2019
|
+
},
|
|
2020
|
+
path.slice(0, -3)
|
|
2021
|
+
];
|
|
2022
|
+
}
|
|
2023
|
+
if (isOccupant(a) && isKiosk(b)) {
|
|
2024
|
+
const occ = findByIdSync(a);
|
|
2025
|
+
const kiosk = findByIdSync(c);
|
|
2026
|
+
const level = findByIdSync(kiosk.properties.level_id);
|
|
2027
|
+
return [
|
|
2028
|
+
{
|
|
2029
|
+
id: occ.id,
|
|
2030
|
+
type: "end",
|
|
2031
|
+
name: occ.properties.name,
|
|
2032
|
+
point: center5(kiosk).geometry.coordinates,
|
|
2033
|
+
levelId: kiosk.properties.level_id,
|
|
2034
|
+
ordinal: level.properties.ordinal,
|
|
2035
|
+
source: { type: "kiosk", id: kiosk.id }
|
|
2036
|
+
},
|
|
2037
|
+
path.slice(0, -2)
|
|
2038
|
+
];
|
|
2039
|
+
}
|
|
2040
|
+
if (isCoordinateOrdinalString(a)) {
|
|
2041
|
+
const [lat, lng, ordinal] = parseOrdinalCoordinate(a);
|
|
2042
|
+
const opening = findByIdSync(b);
|
|
2043
|
+
return [
|
|
2044
|
+
{
|
|
2045
|
+
id: a,
|
|
2046
|
+
type: "end",
|
|
2047
|
+
name: { en: `Your location` },
|
|
2048
|
+
point: [lng, lat],
|
|
2049
|
+
levelId: opening.properties.level_id,
|
|
2050
|
+
ordinal,
|
|
2051
|
+
source: { type: "opening", id: opening.id }
|
|
2052
|
+
},
|
|
2053
|
+
path.slice(0, -2)
|
|
2054
|
+
];
|
|
2055
|
+
}
|
|
2056
|
+
return [null, path];
|
|
2057
|
+
};
|
|
2058
|
+
|
|
2059
|
+
// src/data/navigate/steps/utils/combineWalkwaySteps.ts
|
|
2060
|
+
import uniq from "lodash/uniq";
|
|
2061
|
+
var combineWalkwaySteps = (steps) => {
|
|
2062
|
+
let result = [];
|
|
2063
|
+
for (let i = 0; i < steps.length; i++) {
|
|
2064
|
+
const thisStep = steps[i];
|
|
2065
|
+
if (i === steps.length - 1) {
|
|
2066
|
+
result.push(thisStep);
|
|
2067
|
+
continue;
|
|
1823
2068
|
}
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
2069
|
+
const nextStep = steps[i + 1];
|
|
2070
|
+
if (thisStep.intermediaryCategory === "walkway" && nextStep.intermediaryCategory === "walkway" && thisStep.from.source.type === "opening" && nextStep.from.source.type === "opening") {
|
|
2071
|
+
console.log({ i, len: steps.length, thisStep, nextStep });
|
|
2072
|
+
result.push({
|
|
2073
|
+
from: thisStep.from,
|
|
2074
|
+
to: nextStep.to,
|
|
2075
|
+
levelIds: uniq([...thisStep.levelIds, ...nextStep.levelIds]),
|
|
2076
|
+
ordinals: uniq([...thisStep.ordinals, ...nextStep.ordinals]),
|
|
2077
|
+
intermediaryCategory: "walkway",
|
|
2078
|
+
description: nextStep.description,
|
|
2079
|
+
path: [
|
|
2080
|
+
...thisStep.path,
|
|
2081
|
+
...nextStep.path
|
|
2082
|
+
]
|
|
2083
|
+
});
|
|
2084
|
+
i++;
|
|
2085
|
+
} else {
|
|
2086
|
+
result.push(thisStep);
|
|
1837
2087
|
}
|
|
1838
|
-
return results;
|
|
1839
2088
|
}
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
2089
|
+
return result;
|
|
2090
|
+
};
|
|
2091
|
+
|
|
2092
|
+
// src/data/navigate/steps/createStepUtils.ts
|
|
2093
|
+
var createStepUtils = (options) => {
|
|
2094
|
+
const { data: { units, relationships }, findByIdSync } = options;
|
|
2095
|
+
const landmarkUtils = createLandmarkUtils(options);
|
|
2096
|
+
const stepPathUtils = createStepPathUtils({ ...options, resolution: 88e-5 });
|
|
2097
|
+
const findUnitBetweenOpenings = (originId, destinationId) => {
|
|
2098
|
+
const origin = findByIdSync(originId);
|
|
2099
|
+
const destination = findByIdSync(destinationId);
|
|
2100
|
+
const matchedOne = relationships.find((rel) => rel.properties.intermediary.map((int) => int.id).includes(origin.id));
|
|
2101
|
+
const matchOneUnits = [matchedOne.properties.origin, matchedOne.properties.destination];
|
|
2102
|
+
const matchedTwo = relationships.find((rel) => rel.properties.intermediary.map((int) => int.id).includes(destination.id));
|
|
2103
|
+
const matchTwoUnits = [matchedTwo.properties.origin, matchedTwo.properties.destination];
|
|
2104
|
+
const unitIds = _intersectionBy(matchOneUnits, matchTwoUnits, "id");
|
|
2105
|
+
return unitIds.map(({ id }) => findByIdSync(id));
|
|
2106
|
+
};
|
|
2107
|
+
const findHorizontalIntermediary = (from, to) => {
|
|
2108
|
+
if (from.source.type !== "opening") {
|
|
2109
|
+
const unit = findContainingUnitAtPoint(from.point, from.levelId, units);
|
|
2110
|
+
return unit ? [unit] : [];
|
|
1859
2111
|
}
|
|
1860
|
-
if (
|
|
1861
|
-
|
|
2112
|
+
if (to.source.type !== "opening") {
|
|
2113
|
+
const unit = findContainingUnitAtPoint(to.point, to.levelId, units);
|
|
2114
|
+
return unit ? [unit] : [];
|
|
1862
2115
|
}
|
|
1863
|
-
return
|
|
1864
|
-
|
|
1865
|
-
|
|
2116
|
+
return findUnitBetweenOpenings(from.source.id, to.source.id);
|
|
2117
|
+
};
|
|
2118
|
+
const findVerticalIntermediary = (from, to) => {
|
|
2119
|
+
const firstOpeningId = from.source.id;
|
|
2120
|
+
const secondOpeningId = to.source.id;
|
|
2121
|
+
const relationship = relationships.find((rel) => {
|
|
2122
|
+
return rel.properties.origin?.id === firstOpeningId && rel.properties.destination?.id === secondOpeningId || rel.properties.origin?.id === secondOpeningId && rel.properties.destination?.id === firstOpeningId;
|
|
1866
2123
|
});
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
2124
|
+
const intermediaryTypeAndId = relationship.properties.intermediary;
|
|
2125
|
+
return intermediaryTypeAndId.map(({ id }) => findByIdSync(id));
|
|
2126
|
+
};
|
|
2127
|
+
const formatCategoryLabel = (category) => {
|
|
2128
|
+
return capitalize(category);
|
|
2129
|
+
};
|
|
2130
|
+
const getToward = (from, to, intermediary) => {
|
|
2131
|
+
if (to.type === "end") return to.name;
|
|
2132
|
+
const intermediaryIds = intermediary.map((int) => int.id);
|
|
2133
|
+
const relationship = relationships.find((rel) => rel.properties.intermediary.map((int) => int.id).includes(to.source.id));
|
|
2134
|
+
if (!relationship) return to.name;
|
|
2135
|
+
const candidates = [relationship.properties.origin.id, relationship.properties.destination.id];
|
|
2136
|
+
const nextUnitId = candidates.filter((id) => !intermediaryIds.includes(id))[0];
|
|
2137
|
+
if (!nextUnitId) return to.name;
|
|
2138
|
+
const nextUnit = findByIdSync(nextUnitId);
|
|
2139
|
+
return { en: formatCategoryLabel(`${nextUnit.properties.category}`) };
|
|
2140
|
+
};
|
|
2141
|
+
const toWaypoints = (path) => {
|
|
2142
|
+
const [startPoint, middleAndEndPoints] = extractStartPoint(path, options);
|
|
2143
|
+
const [endPoint, middlePoints] = extractEndPoint(middleAndEndPoints, options);
|
|
2144
|
+
const waypoints = middlePoints.map((openingId) => {
|
|
2145
|
+
const opening = findByIdSync(openingId);
|
|
2146
|
+
const level = findByIdSync(opening.properties.level_id);
|
|
2147
|
+
const coordinates = center6(opening).geometry.coordinates;
|
|
2148
|
+
const landmark = landmarkUtils.findNearestLandmark(coordinates, opening.properties.level_id);
|
|
2149
|
+
return {
|
|
2150
|
+
id: `${opening.properties.level_id}:${openingId}`,
|
|
2151
|
+
type: "between",
|
|
2152
|
+
point: coordinates,
|
|
2153
|
+
name: null,
|
|
2154
|
+
levelId: opening.properties.level_id,
|
|
2155
|
+
ordinal: level.properties.ordinal,
|
|
2156
|
+
hint: landmark ? { kind: "landmark", name: landmark.name } : void 0,
|
|
2157
|
+
source: { type: "opening", id: opening.id }
|
|
2158
|
+
};
|
|
1884
2159
|
});
|
|
1885
|
-
return
|
|
1886
|
-
}
|
|
1887
|
-
|
|
1888
|
-
const
|
|
1889
|
-
const
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
matches
|
|
1903
|
-
}
|
|
1904
|
-
];
|
|
1905
|
-
}
|
|
1906
|
-
return [];
|
|
1907
|
-
}
|
|
1908
|
-
const res = [];
|
|
1909
|
-
for (let i = 0, len = node.children.length; i < len; i += 1) {
|
|
1910
|
-
const child = node.children[i];
|
|
1911
|
-
const result = evaluate(child, item, idx);
|
|
1912
|
-
if (result.length) {
|
|
1913
|
-
res.push(...result);
|
|
1914
|
-
} else if (node.operator === LogicalOperator.AND) {
|
|
1915
|
-
return [];
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
return res;
|
|
2160
|
+
return [startPoint, ...waypoints, endPoint];
|
|
2161
|
+
};
|
|
2162
|
+
const createHorizontalStep = (from, to) => {
|
|
2163
|
+
const intermediary = findHorizontalIntermediary(from, to);
|
|
2164
|
+
const intermediaryCategories = intermediary.map((unit) => unit.properties.category);
|
|
2165
|
+
const intermediaryCategory = intermediaryCategories.length > 0 ? intermediaryCategories[0] : "unspecified";
|
|
2166
|
+
const toward = getToward(from, to, intermediary);
|
|
2167
|
+
const landmark = to.hint?.kind === "landmark" ? to.hint.name : null;
|
|
2168
|
+
const path = stepPathUtils.findStepPath(from.point, to.point, intermediary);
|
|
2169
|
+
const step = {
|
|
2170
|
+
from,
|
|
2171
|
+
to,
|
|
2172
|
+
levelIds: [from.levelId],
|
|
2173
|
+
ordinals: [from.ordinal],
|
|
2174
|
+
intermediaryCategory,
|
|
2175
|
+
description: describeHorizontalStep(intermediaryCategory, toward, landmark),
|
|
2176
|
+
path: path.map((coord) => [...coord, from.ordinal * 9])
|
|
1919
2177
|
};
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
const
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
});
|
|
1957
|
-
|
|
1958
|
-
results.push({
|
|
1959
|
-
idx,
|
|
1960
|
-
item,
|
|
1961
|
-
matches
|
|
1962
|
-
});
|
|
1963
|
-
}
|
|
1964
|
-
});
|
|
1965
|
-
return results;
|
|
1966
|
-
}
|
|
1967
|
-
_findMatches({ key, value, searcher }) {
|
|
1968
|
-
if (!isDefined(value)) {
|
|
1969
|
-
return [];
|
|
1970
|
-
}
|
|
1971
|
-
let matches = [];
|
|
1972
|
-
if (isArray(value)) {
|
|
1973
|
-
value.forEach(({ v: text, i: idx, n: norm2 }) => {
|
|
1974
|
-
if (!isDefined(text)) {
|
|
1975
|
-
return;
|
|
1976
|
-
}
|
|
1977
|
-
const { isMatch, score, indices } = searcher.searchIn(text);
|
|
1978
|
-
if (isMatch) {
|
|
1979
|
-
matches.push({
|
|
1980
|
-
score,
|
|
1981
|
-
key,
|
|
1982
|
-
value: text,
|
|
1983
|
-
idx,
|
|
1984
|
-
norm: norm2,
|
|
1985
|
-
indices
|
|
1986
|
-
});
|
|
1987
|
-
}
|
|
1988
|
-
});
|
|
1989
|
-
} else {
|
|
1990
|
-
const { v: text, n: norm2 } = value;
|
|
1991
|
-
const { isMatch, score, indices } = searcher.searchIn(text);
|
|
1992
|
-
if (isMatch) {
|
|
1993
|
-
matches.push({ score, key, value: text, norm: norm2, indices });
|
|
1994
|
-
}
|
|
2178
|
+
return step;
|
|
2179
|
+
};
|
|
2180
|
+
const createVerticalStep = (from, to) => {
|
|
2181
|
+
const intermediary = findVerticalIntermediary(from, to);
|
|
2182
|
+
const intermediaryCategories = intermediary.map((unit) => unit.properties.category);
|
|
2183
|
+
const intermediaryCategory = intermediaryCategories.length > 0 ? intermediaryCategories[0] : "unspecified";
|
|
2184
|
+
const fromLevel = findByIdSync(from.levelId);
|
|
2185
|
+
const toLevel = findByIdSync(to.levelId);
|
|
2186
|
+
return {
|
|
2187
|
+
from,
|
|
2188
|
+
to,
|
|
2189
|
+
levelIds: [from.levelId, to.levelId],
|
|
2190
|
+
ordinals: [from.ordinal, to.ordinal],
|
|
2191
|
+
intermediaryCategory,
|
|
2192
|
+
description: describeVerticalStep(fromLevel, toLevel, intermediaryCategory),
|
|
2193
|
+
path: [
|
|
2194
|
+
[...from.point, from.ordinal * 9],
|
|
2195
|
+
[...to.point, to.ordinal * 9]
|
|
2196
|
+
]
|
|
2197
|
+
};
|
|
2198
|
+
};
|
|
2199
|
+
const isVertical = (from, to) => {
|
|
2200
|
+
const fromLevel = findByIdSync(from.levelId);
|
|
2201
|
+
const toLevel = findByIdSync(to.levelId);
|
|
2202
|
+
return !!fromLevel && !!toLevel && fromLevel.properties.ordinal !== toLevel.properties.ordinal;
|
|
2203
|
+
};
|
|
2204
|
+
const toSteps = (waypoints) => {
|
|
2205
|
+
let steps = [];
|
|
2206
|
+
const t0_allSteps = performance.now();
|
|
2207
|
+
for (let i = 0; i < waypoints.length - 1; i++) {
|
|
2208
|
+
const from = waypoints[i];
|
|
2209
|
+
const to = waypoints[i + 1];
|
|
2210
|
+
const t0 = performance.now();
|
|
2211
|
+
const step = isVertical(from, to) ? createVerticalStep(from, to) : createHorizontalStep(from, to);
|
|
2212
|
+
steps.push(step);
|
|
2213
|
+
const t1 = performance.now();
|
|
2214
|
+
trace("nav", ` \u2502 \u251C\u2500 #${i} ${from.id.padEnd(25)} \u2192 ${`(${step.intermediaryCategory})`.padEnd(12)} \u2192 ${to.id}`, t1 - t0);
|
|
2215
|
+
trace("nav", ` \u2502 \u2502 ${step.description.text}`, void 0, "#bada55");
|
|
1995
2216
|
}
|
|
1996
|
-
|
|
1997
|
-
|
|
2217
|
+
const simplifySteps = combineWalkwaySteps(steps);
|
|
2218
|
+
const t1_allSteps = performance.now();
|
|
2219
|
+
trace("nav", " \u2502 \u2514\u2500 Total ", t1_allSteps - t0_allSteps);
|
|
2220
|
+
return simplifySteps;
|
|
2221
|
+
};
|
|
2222
|
+
return {
|
|
2223
|
+
// createSteps,
|
|
2224
|
+
toWaypoints,
|
|
2225
|
+
toSteps
|
|
2226
|
+
};
|
|
1998
2227
|
};
|
|
1999
|
-
Fuse.version = "7.1.0";
|
|
2000
|
-
Fuse.createIndex = createIndex;
|
|
2001
|
-
Fuse.parseIndex = parseIndex;
|
|
2002
|
-
Fuse.config = Config;
|
|
2003
|
-
{
|
|
2004
|
-
Fuse.parseQuery = parse;
|
|
2005
|
-
}
|
|
2006
|
-
{
|
|
2007
|
-
register(ExtendedSearch);
|
|
2008
|
-
}
|
|
2009
2228
|
|
|
2010
|
-
// src/data/
|
|
2011
|
-
|
|
2229
|
+
// src/data/navigate/utils/timeDistance.ts
|
|
2230
|
+
import calculateLength from "@turf/length";
|
|
2231
|
+
var WALKING_SPEED = 1.4;
|
|
2232
|
+
var calculatePathLength = (feature2) => calculateLength(feature2, { units: "kilometers" }) * 1e3;
|
|
2233
|
+
var calculateTravelingDuration = (distance5) => {
|
|
2234
|
+
const duration = distance5 / WALKING_SPEED;
|
|
2235
|
+
const minutes = Math.round(duration / 60);
|
|
2236
|
+
return minutes > 0 ? minutes : 1;
|
|
2237
|
+
};
|
|
2238
|
+
var calculateTotalDistance = (steps = []) => {
|
|
2239
|
+
return steps.reduce((acc, { path }) => acc + calculatePathLength(lineString(path)), 0);
|
|
2240
|
+
};
|
|
2241
|
+
var calculateRoundedDistance = (distance5) => {
|
|
2242
|
+
return Math.round(distance5 - distance5 % 25);
|
|
2243
|
+
};
|
|
2012
2244
|
|
|
2013
|
-
// src/data/
|
|
2014
|
-
var
|
|
2015
|
-
const
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
const
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2245
|
+
// src/data/navigate/utils/createFindByIdSync.ts
|
|
2246
|
+
var createFindByIdSync = (data) => {
|
|
2247
|
+
const { amenities = [], anchors = [], fixtures = [], levels = [], kiosks = [], relationships = [], occupants = [], openings = [], units } = data;
|
|
2248
|
+
const featureById = /* @__PURE__ */ new Map();
|
|
2249
|
+
const entries = [
|
|
2250
|
+
...amenities,
|
|
2251
|
+
...anchors,
|
|
2252
|
+
...fixtures,
|
|
2253
|
+
...levels,
|
|
2254
|
+
...kiosks,
|
|
2255
|
+
...relationships,
|
|
2256
|
+
...occupants,
|
|
2257
|
+
...openings,
|
|
2258
|
+
...units
|
|
2259
|
+
];
|
|
2260
|
+
for (const f of entries) featureById.set(f.id, f);
|
|
2261
|
+
const findByIdSync = (id) => {
|
|
2262
|
+
return featureById.get(id);
|
|
2263
|
+
};
|
|
2264
|
+
return { findByIdSync };
|
|
2265
|
+
};
|
|
2266
|
+
|
|
2267
|
+
// src/data/navigate/getNavigateClient.ts
|
|
2268
|
+
var getNavigateClient = (options) => {
|
|
2269
|
+
const { data } = options;
|
|
2270
|
+
const { levels, units } = data;
|
|
2271
|
+
trace("nav", "\u2713 prepare");
|
|
2272
|
+
const t0 = performance.now();
|
|
2273
|
+
trace("nav", " \u251C\u2500 createGraph (dijkstra)");
|
|
2274
|
+
const { defaultGraph, accessibleGraph, addCoordinateOrdinalNode } = prepareGraph({ data });
|
|
2275
|
+
const t1 = performance.now();
|
|
2276
|
+
trace("nav", " \u2502 \u2514\u2500 Total ", t1 - t0);
|
|
2277
|
+
const t2 = performance.now();
|
|
2278
|
+
const { findByIdSync } = createFindByIdSync(data);
|
|
2279
|
+
const t3 = performance.now();
|
|
2280
|
+
trace("nav", " \u2514\u2500 findByIdSync", t3 - t2);
|
|
2281
|
+
const findCoordinateOrdinalUnit = (params) => {
|
|
2282
|
+
const [lat, lng, ordinal] = parseOrdinalCoordinate(params);
|
|
2283
|
+
const levelIdsWithOrdinal = levels.filter((level) => level.properties.ordinal === ordinal).map((level) => level.id);
|
|
2284
|
+
const unit = units.find((unit2) => levelIdsWithOrdinal.includes(unit2.properties.level_id) && booleanPointInPolygon4([lat, lng], unit2));
|
|
2285
|
+
return unit;
|
|
2286
|
+
};
|
|
2287
|
+
const stepUtils = createStepUtils({ ...options, findByIdSync });
|
|
2288
|
+
const findRoute = async (routeOriginParam, routeDestinationParam, options2) => {
|
|
2289
|
+
if (!routeOriginParam || !routeDestinationParam) return null;
|
|
2290
|
+
const graph = options2?.mode === "accessible" ? accessibleGraph : defaultGraph;
|
|
2291
|
+
if (isCoordinateOrdinalString(routeOriginParam)) {
|
|
2292
|
+
const walkwayUnit = findCoordinateOrdinalUnit(routeOriginParam);
|
|
2293
|
+
addCoordinateOrdinalNode(routeOriginParam, walkwayUnit);
|
|
2294
|
+
}
|
|
2295
|
+
if (isCoordinateOrdinalString(routeDestinationParam)) {
|
|
2296
|
+
const walkwayUnit = findCoordinateOrdinalUnit(routeDestinationParam);
|
|
2297
|
+
addCoordinateOrdinalNode(routeDestinationParam, walkwayUnit);
|
|
2298
|
+
}
|
|
2299
|
+
try {
|
|
2300
|
+
trace("nav", "\u2713 findRoute", 0);
|
|
2301
|
+
const t02 = performance.now();
|
|
2302
|
+
const path = graph.path(routeOriginParam, routeDestinationParam);
|
|
2303
|
+
const t12 = performance.now();
|
|
2304
|
+
trace("nav", " \u251C\u2500 path (dijkstra)", t12 - t02);
|
|
2305
|
+
const waypoints = stepUtils.toWaypoints(path);
|
|
2306
|
+
console.log({ waypoints });
|
|
2307
|
+
const t22 = performance.now();
|
|
2308
|
+
trace("nav", " \u251C\u2500 toWaypoints", t22 - t12);
|
|
2309
|
+
trace("nav", " \u251C\u2500 toSteps", 0);
|
|
2310
|
+
const steps = stepUtils.toSteps(waypoints);
|
|
2311
|
+
const t32 = performance.now();
|
|
2312
|
+
const totalDistance = calculateTotalDistance(steps);
|
|
2313
|
+
const roundedDistance = calculateRoundedDistance(totalDistance);
|
|
2314
|
+
const duration = calculateTravelingDuration(totalDistance);
|
|
2315
|
+
const t4 = performance.now();
|
|
2316
|
+
trace("nav", " \u2514\u2500 postProcess", t4 - t32);
|
|
2317
|
+
return {
|
|
2318
|
+
// origin: routeOrigin,
|
|
2319
|
+
// destination: routeDestination,
|
|
2320
|
+
description: null,
|
|
2321
|
+
distance: roundedDistance,
|
|
2322
|
+
duration,
|
|
2323
|
+
steps
|
|
2324
|
+
};
|
|
2325
|
+
} catch (error) {
|
|
2326
|
+
console.log(error);
|
|
2327
|
+
throw error;
|
|
2328
|
+
}
|
|
2042
2329
|
};
|
|
2043
2330
|
return {
|
|
2044
|
-
|
|
2331
|
+
findRoute,
|
|
2332
|
+
findByIdSync
|
|
2045
2333
|
};
|
|
2046
2334
|
};
|
|
2047
2335
|
|
|
2048
2336
|
// src/data/getDataClient.ts
|
|
2049
2337
|
var getDataClient = (options) => {
|
|
2050
2338
|
let searchClient;
|
|
2339
|
+
let navigateClient;
|
|
2051
2340
|
const observers = /* @__PURE__ */ new Map();
|
|
2052
2341
|
const queryClient = options.queryClient ?? new QueryClient();
|
|
2053
2342
|
const { mode = "delivery", projectId, apiKey, baseUrl, previewToken } = options;
|
|
@@ -2078,17 +2367,17 @@ var getDataClient = (options) => {
|
|
|
2078
2367
|
const internalFindById = async (id) => {
|
|
2079
2368
|
if (id === null || id === void 0) return null;
|
|
2080
2369
|
const featureType = id.slice(0, id.lastIndexOf("-"));
|
|
2081
|
-
const
|
|
2370
|
+
const feature2 = await queryClient.ensureQueryData({
|
|
2082
2371
|
queryKey: ["_deliveryapi", featureType, id],
|
|
2083
2372
|
queryFn: async () => {
|
|
2084
2373
|
const features = await internalFilterByType(featureType);
|
|
2085
|
-
const
|
|
2374
|
+
const feature3 = features.find(
|
|
2086
2375
|
(f) => f.id === id
|
|
2087
2376
|
);
|
|
2088
|
-
return
|
|
2377
|
+
return feature3 ?? null;
|
|
2089
2378
|
}
|
|
2090
2379
|
});
|
|
2091
|
-
return
|
|
2380
|
+
return feature2;
|
|
2092
2381
|
};
|
|
2093
2382
|
const populator = createPopulator({ internalFindById, internalFilterByType });
|
|
2094
2383
|
const registerObserver = (featureType, refetchInterval) => {
|
|
@@ -2137,8 +2426,8 @@ var getDataClient = (options) => {
|
|
|
2137
2426
|
const createFindByIdQueryOptions = (featureType, id, params = {}, options2 = {}) => ({
|
|
2138
2427
|
queryKey: [featureType, "detail", id, params],
|
|
2139
2428
|
queryFn: async () => {
|
|
2140
|
-
const
|
|
2141
|
-
return params.populate === true ? await populator[featureType](
|
|
2429
|
+
const feature2 = await internalFindById(id);
|
|
2430
|
+
return params.populate === true ? await populator[featureType](feature2) : Promise.resolve(feature2);
|
|
2142
2431
|
},
|
|
2143
2432
|
...options2 ?? {}
|
|
2144
2433
|
});
|
|
@@ -2156,8 +2445,8 @@ var getDataClient = (options) => {
|
|
|
2156
2445
|
id,
|
|
2157
2446
|
params
|
|
2158
2447
|
);
|
|
2159
|
-
const
|
|
2160
|
-
return
|
|
2448
|
+
const feature2 = await queryClient.ensureQueryData(findQueryOptions);
|
|
2449
|
+
return feature2;
|
|
2161
2450
|
}
|
|
2162
2451
|
const searchFn = async (txt) => {
|
|
2163
2452
|
if (!searchClient) {
|
|
@@ -2170,6 +2459,24 @@ var getDataClient = (options) => {
|
|
|
2170
2459
|
}
|
|
2171
2460
|
return searchClient.search(txt);
|
|
2172
2461
|
};
|
|
2462
|
+
const navigateFn = async (origin, destination) => {
|
|
2463
|
+
if (!navigateClient) {
|
|
2464
|
+
const [levels, occupants, openings, relationships, units, fixtures, kiosks, amenities, anchors] = await Promise.all([
|
|
2465
|
+
filterByType("level"),
|
|
2466
|
+
filterByType("occupant"),
|
|
2467
|
+
filterByType("opening"),
|
|
2468
|
+
filterByType("relationship"),
|
|
2469
|
+
filterByType("unit"),
|
|
2470
|
+
filterByType("fixture"),
|
|
2471
|
+
filterByType("kiosk"),
|
|
2472
|
+
filterByType("amenity"),
|
|
2473
|
+
filterByType("anchor")
|
|
2474
|
+
]);
|
|
2475
|
+
const haystack = { levels, occupants, openings, relationships, units, fixtures, kiosks, amenities, anchors };
|
|
2476
|
+
navigateClient = getNavigateClient({ data: haystack });
|
|
2477
|
+
}
|
|
2478
|
+
return navigateClient.findRoute(origin, destination);
|
|
2479
|
+
};
|
|
2173
2480
|
return {
|
|
2174
2481
|
projectId,
|
|
2175
2482
|
queryClient,
|
|
@@ -2181,7 +2488,8 @@ var getDataClient = (options) => {
|
|
|
2181
2488
|
_internalFindById: internalFindById,
|
|
2182
2489
|
filterByType,
|
|
2183
2490
|
findById,
|
|
2184
|
-
search: searchFn
|
|
2491
|
+
search: searchFn,
|
|
2492
|
+
navigate: navigateFn
|
|
2185
2493
|
};
|
|
2186
2494
|
};
|
|
2187
2495
|
export {
|