@kimap/indoor-positioning-sdk-vue2 4.3.4 → 4.3.6
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/package.json +1 -1
- package/src/KMUtil.js +77 -26
package/package.json
CHANGED
package/src/KMUtil.js
CHANGED
|
@@ -309,6 +309,12 @@
|
|
|
309
309
|
|
|
310
310
|
var obstacles = [];
|
|
311
311
|
|
|
312
|
+
// 0. 如果直接传入的是家具数组,转换为kidata格式
|
|
313
|
+
if (Array.isArray(kidata)) {
|
|
314
|
+
console.log('KMUtil: 检测到直接传入家具数组,数量:', kidata.length);
|
|
315
|
+
kidata = { furnitures: kidata };
|
|
316
|
+
}
|
|
317
|
+
|
|
312
318
|
// 1. 优先从kidata的floors中提取障碍物
|
|
313
319
|
if (kidata.floors && Array.isArray(kidata.floors)) {
|
|
314
320
|
console.log('KMUtil: 从kidata.floors提取障碍物,楼层数量:', kidata.floors.length);
|
|
@@ -644,8 +650,24 @@
|
|
|
644
650
|
* start/end: { x, z }
|
|
645
651
|
* obstacles: [{ type, bounds:{minX,minZ,maxX,maxZ} }, ...]
|
|
646
652
|
* gridSize: 每步移动距离(米),推荐 0.2〜0.5
|
|
653
|
+
* clearance: 人体安全间隙(米),障碍物会被扩大这个距离
|
|
647
654
|
*/
|
|
648
|
-
function aStarPathfinding(start, end, obstacles, gridSize = 0.2) {
|
|
655
|
+
function aStarPathfinding(start, end, obstacles, gridSize = 0.2, clearance = 0.4) {
|
|
656
|
+
// 扩大障碍物边界,考虑人体体积
|
|
657
|
+
const expandedObstacles = obstacles.map(function(obs) {
|
|
658
|
+
return {
|
|
659
|
+
type: obs.type,
|
|
660
|
+
bounds: {
|
|
661
|
+
minX: obs.bounds.minX - clearance,
|
|
662
|
+
minZ: obs.bounds.minZ - clearance,
|
|
663
|
+
maxX: obs.bounds.maxX + clearance,
|
|
664
|
+
maxZ: obs.bounds.maxZ + clearance
|
|
665
|
+
},
|
|
666
|
+
center: obs.center,
|
|
667
|
+
radius: obs.radius ? obs.radius + clearance : undefined,
|
|
668
|
+
points: obs.points
|
|
669
|
+
};
|
|
670
|
+
});
|
|
649
671
|
const openList = [];
|
|
650
672
|
const closed = new Set();
|
|
651
673
|
|
|
@@ -697,11 +719,11 @@
|
|
|
697
719
|
const nk = `${Math.round(nx / gridSize)},${Math.round(nz / gridSize)}`;
|
|
698
720
|
if (closed.has(nk)) continue;
|
|
699
721
|
|
|
700
|
-
//
|
|
701
|
-
if (isPointInObstacles(nx, nz,
|
|
722
|
+
// 点是否落在障碍物区域(使用扩大后的障碍物)
|
|
723
|
+
if (isPointInObstacles(nx, nz, expandedObstacles)) continue;
|
|
702
724
|
|
|
703
|
-
//
|
|
704
|
-
if (segmentIntersectsObstacles(current.x, current.z, nx, nz,
|
|
725
|
+
// 本段路径是否穿越障碍物(含斜线,使用扩大后的障碍物)
|
|
726
|
+
if (segmentIntersectsObstacles(current.x, current.z, nx, nz, expandedObstacles)) {
|
|
705
727
|
continue;
|
|
706
728
|
}
|
|
707
729
|
|
|
@@ -812,11 +834,25 @@
|
|
|
812
834
|
* @param {Array} obstacles - 障碍物列表
|
|
813
835
|
* @param {number} searchRadius - 搜索半径(米),默认2米
|
|
814
836
|
* @param {number} step - 搜索步长(米),默认0.1米
|
|
837
|
+
* @param {number} clearance - 人体安全间隙(米),默认0.4米
|
|
815
838
|
* @returns {Object} 可行的点 {x, z}
|
|
816
839
|
*/
|
|
817
|
-
function findNearestFreePoint(point, obstacles, searchRadius = 2, step = 0.1) {
|
|
840
|
+
function findNearestFreePoint(point, obstacles, searchRadius = 2, step = 0.1, clearance = 0.4) {
|
|
841
|
+
// 扩大障碍物边界,考虑人体体积
|
|
842
|
+
var expandedObstacles = obstacles.map(function(obs) {
|
|
843
|
+
return {
|
|
844
|
+
type: obs.type,
|
|
845
|
+
bounds: {
|
|
846
|
+
minX: obs.bounds.minX - clearance,
|
|
847
|
+
minZ: obs.bounds.minZ - clearance,
|
|
848
|
+
maxX: obs.bounds.maxX + clearance,
|
|
849
|
+
maxZ: obs.bounds.maxZ + clearance
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
});
|
|
853
|
+
|
|
818
854
|
// 如果当前点已经可行,直接返回
|
|
819
|
-
if (!isPointInObstacles(point.x, point.z,
|
|
855
|
+
if (!isPointInObstacles(point.x, point.z, expandedObstacles)) {
|
|
820
856
|
return point;
|
|
821
857
|
}
|
|
822
858
|
|
|
@@ -838,8 +874,8 @@
|
|
|
838
874
|
const testX = point.x + Math.cos(angle) * currentRadius;
|
|
839
875
|
const testZ = point.z + Math.sin(angle) * currentRadius;
|
|
840
876
|
|
|
841
|
-
//
|
|
842
|
-
if (!isPointInObstacles(testX, testZ,
|
|
877
|
+
// 检查这个点是否可行(使用扩大后的障碍物)
|
|
878
|
+
if (!isPointInObstacles(testX, testZ, expandedObstacles)) {
|
|
843
879
|
const dist = Math.sqrt(
|
|
844
880
|
(testX - point.x) ** 2 + (testZ - point.z) ** 2
|
|
845
881
|
);
|
|
@@ -866,11 +902,25 @@
|
|
|
866
902
|
* 使用Douglas-Peucker算法的简化版本
|
|
867
903
|
* @param {Array} path - 原始路径点 [{x, z}, ...]
|
|
868
904
|
* @param {Array} obstacles - 障碍物列表
|
|
905
|
+
* @param {number} clearance - 人体安全间隙(米),默认0.4米
|
|
869
906
|
* @returns {Array} 简化后的路径点
|
|
870
907
|
*/
|
|
871
|
-
function simplifyPath(path, obstacles) {
|
|
908
|
+
function simplifyPath(path, obstacles, clearance = 0.4) {
|
|
872
909
|
if (path.length <= 2) return path;
|
|
873
910
|
|
|
911
|
+
// 扩大障碍物边界,考虑人体体积
|
|
912
|
+
var expandedObstacles = obstacles.map(function(obs) {
|
|
913
|
+
return {
|
|
914
|
+
type: obs.type,
|
|
915
|
+
bounds: {
|
|
916
|
+
minX: obs.bounds.minX - clearance,
|
|
917
|
+
minZ: obs.bounds.minZ - clearance,
|
|
918
|
+
maxX: obs.bounds.maxX + clearance,
|
|
919
|
+
maxZ: obs.bounds.maxZ + clearance
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
});
|
|
923
|
+
|
|
874
924
|
const simplified = [path[0]];
|
|
875
925
|
let current = 0;
|
|
876
926
|
|
|
@@ -878,14 +928,14 @@
|
|
|
878
928
|
while (current < path.length - 1) {
|
|
879
929
|
let farthest = current + 1;
|
|
880
930
|
|
|
881
|
-
//
|
|
931
|
+
// 从最远的点开始尝试,看能否直接连接(使用扩大后的障碍物)
|
|
882
932
|
for (let i = path.length - 1; i > current + 1; i--) {
|
|
883
933
|
const canConnect = !segmentIntersectsObstacles(
|
|
884
934
|
path[current].x,
|
|
885
935
|
path[current].z,
|
|
886
936
|
path[i].x,
|
|
887
937
|
path[i].z,
|
|
888
|
-
|
|
938
|
+
expandedObstacles
|
|
889
939
|
);
|
|
890
940
|
|
|
891
941
|
if (canConnect) {
|
|
@@ -1041,9 +1091,13 @@
|
|
|
1041
1091
|
});
|
|
1042
1092
|
}
|
|
1043
1093
|
|
|
1044
|
-
//
|
|
1045
|
-
|
|
1046
|
-
const
|
|
1094
|
+
// 人体安全距离:考虑人的肩宽(约0.5米)+ 安全余量
|
|
1095
|
+
// 使用0.4米(40cm)作为最小间隙,确保人可以舒适通过
|
|
1096
|
+
const PERSON_CLEARANCE = options.clearance || 0.4;
|
|
1097
|
+
|
|
1098
|
+
// 调整起点和终点,确保它们不在障碍物内(考虑人体体积)
|
|
1099
|
+
const adjustedStart = findNearestFreePoint(start, obstacles, 2, 0.1, PERSON_CLEARANCE);
|
|
1100
|
+
const adjustedEnd = findNearestFreePoint(end, obstacles, 2, 0.1, PERSON_CLEARANCE);
|
|
1047
1101
|
|
|
1048
1102
|
// 如果起点或终点被调整了,记录日志
|
|
1049
1103
|
if (adjustedStart.x !== start.x || adjustedStart.z !== start.z) {
|
|
@@ -1052,10 +1106,10 @@
|
|
|
1052
1106
|
if (adjustedEnd.x !== end.x || adjustedEnd.z !== end.z) {
|
|
1053
1107
|
console.log(`终点已调整: (${end.x.toFixed(2)}, ${end.z.toFixed(2)}) → (${adjustedEnd.x.toFixed(2)}, ${adjustedEnd.z.toFixed(2)})`);
|
|
1054
1108
|
}
|
|
1055
|
-
|
|
1056
|
-
//
|
|
1057
|
-
const hasIntersection = pathIntersectsObstacles(adjustedStart.x, adjustedStart.z, adjustedEnd.x, adjustedEnd.z, obstacles,
|
|
1058
|
-
console.log(`🔍
|
|
1109
|
+
|
|
1110
|
+
// 检查直线是否可行
|
|
1111
|
+
const hasIntersection = pathIntersectsObstacles(adjustedStart.x, adjustedStart.z, adjustedEnd.x, adjustedEnd.z, obstacles, PERSON_CLEARANCE);
|
|
1112
|
+
console.log(`🔍 直线路径检查 (安全距离=${PERSON_CLEARANCE}m): ${hasIntersection ? '有障碍物❌' : '无障碍物✅'}`);
|
|
1059
1113
|
|
|
1060
1114
|
if (!hasIntersection) {
|
|
1061
1115
|
console.log('✅ 直线可达,返回两点路径');
|
|
@@ -1064,8 +1118,8 @@
|
|
|
1064
1118
|
|
|
1065
1119
|
console.log('🚧 需要绕行,开始A*路径规划...');
|
|
1066
1120
|
|
|
1067
|
-
// 使用A*算法规划路径(gridSize: 0.
|
|
1068
|
-
const rawPath = aStarPathfinding(adjustedStart, adjustedEnd, obstacles, 0.
|
|
1121
|
+
// 使用A*算法规划路径(gridSize: 0.3米 = 30cm,考虑人体宽度)
|
|
1122
|
+
const rawPath = aStarPathfinding(adjustedStart, adjustedEnd, obstacles, 0.3, PERSON_CLEARANCE);
|
|
1069
1123
|
console.log(`🗺️ A*原始路径: ${rawPath.length}个点`);
|
|
1070
1124
|
|
|
1071
1125
|
// 如果路径只有2个点(直线),直接返回
|
|
@@ -1074,13 +1128,10 @@
|
|
|
1074
1128
|
return rawPath;
|
|
1075
1129
|
}
|
|
1076
1130
|
|
|
1077
|
-
//
|
|
1078
|
-
const simplifiedPath = simplifyPath(rawPath, obstacles);
|
|
1131
|
+
// 第一步:简化路径,移除不必要的中间点(考虑人体体积)
|
|
1132
|
+
const simplifiedPath = simplifyPath(rawPath, obstacles, PERSON_CLEARANCE);
|
|
1079
1133
|
console.log(`📐 简化后路径: ${simplifiedPath.length}个点`);
|
|
1080
1134
|
|
|
1081
|
-
// 第二步:平滑路径(可通过options.smoothPath控制是否启用,默认启用)
|
|
1082
|
-
const ena
|
|
1083
|
-
|
|
1084
1135
|
return simplifiedPath;
|
|
1085
1136
|
};
|
|
1086
1137
|
|