@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/KMUtil.js +77 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kimap/indoor-positioning-sdk-vue2",
3
- "version": "4.3.4",
3
+ "version": "4.3.6",
4
4
  "description": "Vue2自包含室内定位SDK - 完全兼容Webpack3+Babel6 | Vue2 Self-Contained Indoor Positioning SDK",
5
5
  "main": "index.js",
6
6
  "files": [
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, obstacles)) continue;
722
+ // 点是否落在障碍物区域(使用扩大后的障碍物)
723
+ if (isPointInObstacles(nx, nz, expandedObstacles)) continue;
702
724
 
703
- // 本段路径是否穿越障碍物(含斜线)
704
- if (segmentIntersectsObstacles(current.x, current.z, nx, nz, obstacles)) {
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, obstacles)) {
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, obstacles)) {
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
- obstacles
938
+ expandedObstacles
889
939
  );
890
940
 
891
941
  if (canConnect) {
@@ -1041,9 +1091,13 @@
1041
1091
  });
1042
1092
  }
1043
1093
 
1044
- // 调整起点和终点,确保它们不在障碍物内
1045
- const adjustedStart = findNearestFreePoint(start, obstacles, 2, 0.1);
1046
- const adjustedEnd = findNearestFreePoint(end, obstacles, 2, 0.1);
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
- // 检查直线是否可行(margin: 0.1米 = 10cm)
1057
- const hasIntersection = pathIntersectsObstacles(adjustedStart.x, adjustedStart.z, adjustedEnd.x, adjustedEnd.z, obstacles, 0.1);
1058
- console.log(`🔍 直线路径检查: ${hasIntersection ? '有障碍物❌' : '无障碍物✅'}`);
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.2米 = 20cm)
1068
- const rawPath = aStarPathfinding(adjustedStart, adjustedEnd, obstacles, 0.2);
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