@kimap/indoor-positioning-sdk-vue2 4.2.5 → 4.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kimap/indoor-positioning-sdk-vue2",
3
- "version": "4.2.5",
3
+ "version": "4.2.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
@@ -39,10 +39,12 @@
39
39
 
40
40
  // 遍历所有图层
41
41
  floorData.layers.forEach(function (layer) {
42
- if (!layer.visible || !layer.elements) return;
42
+ // 只跳过明确设置为不可见的图层(visible === false),undefined视为可见
43
+ if (layer.visible === false || !layer.elements) return;
43
44
 
44
45
  layer.elements.forEach(function (element) {
45
- if (!element.visible) return;
46
+ // 只跳过明确设置为不可见的元素(visible === false),undefined视为可见
47
+ if (element.visible === false) return;
46
48
 
47
49
  // 检查是否可穿行
48
50
  var passable = element.passable === true;
@@ -50,19 +52,32 @@
50
52
  // 处理墙体(始终作为障碍物)
51
53
  if (element.type === 'wall') {
52
54
  if (element.points && element.points.length >= 2) {
53
- // thickness是毫米,转换为米
54
- var thickness = (element.thickness || 100) / 1000;
55
- var halfThickness = thickness / 2;
55
+ // thickness: 如果是米单位(< 1),直接使用;如果是毫米(>= 1),转换为米
56
+ var thickness = element.thickness;
57
+ if (thickness >= 1) {
58
+ thickness = thickness / 1000; // 毫米 → 米
59
+ }
60
+ var halfThickness = (thickness || 0.1) / 2;
56
61
 
57
62
  for (var i = 0; i < element.points.length - 1; i++) {
58
63
  var p1 = element.points[i];
59
64
  var p2 = element.points[i + 1];
60
65
 
61
- // 点坐标是像素,转换为米(100像素 = 1米)
62
- var x1 = p1.x / 100;
63
- var z1 = p1.y / 100;
64
- var x2 = p2.x / 100;
65
- var z2 = p2.y / 100;
66
+ // 判断坐标格式:如果有z属性,说明已经是米坐标;如果有y属性,说明是像素坐标
67
+ var x1, z1, x2, z2;
68
+ if (p1.z !== undefined) {
69
+ // 新格式:已经是米坐标
70
+ x1 = p1.x;
71
+ z1 = p1.z;
72
+ x2 = p2.x;
73
+ z2 = p2.z;
74
+ } else {
75
+ // 旧格式:像素坐标,需要转换
76
+ x1 = p1.x / 100;
77
+ z1 = p1.y / 100;
78
+ x2 = p2.x / 100;
79
+ z2 = p2.y / 100;
80
+ }
66
81
 
67
82
  // 判断墙的方向
68
83
  var dx = Math.abs(x2 - x1);
@@ -103,11 +118,21 @@
103
118
  var p1 = element.points[0];
104
119
  var p2 = element.points[1];
105
120
 
106
- // 像素转米
107
- var x1 = p1.x / 100;
108
- var z1 = p1.y / 100;
109
- var x2 = p2.x / 100;
110
- var z2 = p2.y / 100;
121
+ // 判断坐标格式
122
+ var x1, z1, x2, z2;
123
+ if (p1.z !== undefined) {
124
+ // 新格式:已经是米坐标
125
+ x1 = p1.x;
126
+ z1 = p1.z;
127
+ x2 = p2.x;
128
+ z2 = p2.z;
129
+ } else {
130
+ // 旧格式:像素坐标,需要转换
131
+ x1 = p1.x / 100;
132
+ z1 = p1.y / 100;
133
+ x2 = p2.x / 100;
134
+ z2 = p2.y / 100;
135
+ }
111
136
 
112
137
  obstacles.push({
113
138
  type: 'rectangle',
@@ -124,11 +149,24 @@
124
149
  else if (element.type === 'circle' && !passable) {
125
150
  if (element.points && element.points.length >= 1) {
126
151
  var center = element.points[0];
127
- var centerX = center.x / 100;
128
- var centerZ = center.y / 100;
129
152
 
130
- // radius是毫米,转换为米
131
- var radius = (element.radius || 500) / 1000;
153
+ // 判断坐标格式
154
+ var centerX, centerZ;
155
+ if (center.z !== undefined) {
156
+ // 新格式:已经是米坐标
157
+ centerX = center.x;
158
+ centerZ = center.z;
159
+ } else {
160
+ // 旧格式:像素坐标,需要转换
161
+ centerX = center.x / 100;
162
+ centerZ = center.y / 100;
163
+ }
164
+
165
+ // radius: 如果是米单位(< 1),直接使用;如果是毫米(>= 1),转换为米
166
+ var radius = element.radius || 0.5;
167
+ if (radius >= 1) {
168
+ radius = radius / 1000; // 毫米 → 米
169
+ }
132
170
 
133
171
  obstacles.push({
134
172
  type: 'circle',
@@ -151,8 +189,17 @@
151
189
  var points3D = [];
152
190
 
153
191
  element.points.forEach(function (p) {
154
- var x = p.x / 100;
155
- var z = p.y / 100;
192
+ // 判断坐标格式
193
+ var x, z;
194
+ if (p.z !== undefined) {
195
+ // 新格式:已经是米坐标
196
+ x = p.x;
197
+ z = p.z;
198
+ } else {
199
+ // 旧格式:像素坐标,需要转换
200
+ x = p.x / 100;
201
+ z = p.y / 100;
202
+ }
156
203
  points3D.push({ x: x, z: z });
157
204
  minX = Math.min(minX, x);
158
205
  minZ = Math.min(minZ, z);
@@ -190,6 +237,39 @@
190
237
  });
191
238
  }
192
239
  }
240
+ // 处理家具(furniture)
241
+ else if (element.type === 'furniture' && !passable) {
242
+ // 家具可能使用position或points来定义位置
243
+ var centerX, centerZ, width, depth;
244
+
245
+ if (element.position) {
246
+ // 使用position定义(米坐标)
247
+ centerX = element.position.x;
248
+ centerZ = element.position.z;
249
+ width = element.targetSize ? element.targetSize.width : 0.5;
250
+ depth = element.targetSize ? element.targetSize.depth : 0.5;
251
+ } else if (element.points && element.points.length >= 1) {
252
+ // 使用points定义(像素坐标)
253
+ var center = element.points[0];
254
+ centerX = center.x / 100;
255
+ centerZ = center.y / 100;
256
+ width = (element.width || 50) / 100;
257
+ depth = (element.depth || 50) / 100;
258
+ } else {
259
+ return; // 没有位置信息,跳过
260
+ }
261
+
262
+ var halfDiag = Math.sqrt(width * width + depth * depth) / 2;
263
+ obstacles.push({
264
+ type: 'furniture',
265
+ bounds: {
266
+ minX: centerX - halfDiag,
267
+ minZ: centerZ - halfDiag,
268
+ maxX: centerX + halfDiag,
269
+ maxZ: centerZ + halfDiag
270
+ }
271
+ });
272
+ }
193
273
  });
194
274
  });
195
275
 
@@ -228,15 +308,28 @@
228
308
 
229
309
  var obstacles = [];
230
310
 
231
- // 1. 如果有layers,使用extractObstaclesFromFloor
232
- if (kidata.layers && Array.isArray(kidata.layers)) {
311
+ // 1. 优先从kidata的floors中提取障碍物
312
+ if (kidata.floors && Array.isArray(kidata.floors)) {
313
+ console.log('KMUtil: 从kidata.floors提取障碍物,楼层数量:', kidata.floors.length);
314
+ // 使用第一个楼层的数据
315
+ if (kidata.floors.length > 0) {
316
+ var floorData = { layers: kidata.floors[0].layers };
317
+ obstacles = obstacles.concat(
318
+ KMUtil.extractObstaclesFromFloor(floorData, true)
319
+ );
320
+ }
321
+ }
322
+ // 2. 如果没有floors数据,回退到layers(兼容旧版本)
323
+ else if (kidata.layers && Array.isArray(kidata.layers)) {
324
+ console.log('KMUtil: 从kidata.layers提取障碍物(兼容模式)');
233
325
  obstacles = obstacles.concat(
234
326
  KMUtil.extractObstaclesFromFloor(kidata, true)
235
327
  );
236
328
  }
237
329
 
238
- // 2. 处理furnitures(3D模型)
330
+ // 3. 处理furnitures(3D模型)
239
331
  if (kidata.furnitures && Array.isArray(kidata.furnitures)) {
332
+ console.log('KMUtil: 从kidata.furnitures提取家具障碍物,家具数量:', kidata.furnitures.length);
240
333
  kidata.furnitures.forEach(function (furniture) {
241
334
  var passable = furniture.passable === true;
242
335
  if (passable) return;
@@ -546,39 +639,26 @@
546
639
  }
547
640
 
548
641
  /**
549
- * A*路径规划算法
550
- * @param {Object} start - 起点 {x, z}(米)
551
- * @param {Object} end - 终点 {x, z}(米)
552
- * @param {Array} obstacles - 障碍物列表
553
- * @param {number} gridSize - 网格大小(米),默认0.5米
554
- */
555
- /**
556
- * A* 路径规划(已修复水平镜像 / 三维坐标系映射)
557
- * start/end: { x, z } 世界坐标(米)
642
+ * A* 路径规划(适配你的坐标系:X 右、Z 下、单位米)
643
+ * start/end: { x, z }
558
644
  * obstacles: [{ type, bounds:{minX,minZ,maxX,maxZ} }, ...]
559
- * cellSize: 网格大小(米),默认 0.05
560
- * options: { inflationCells } 障碍膨胀(格数),默认 1
645
+ * gridSize: 每步移动距离(米),推荐 0.2〜0.5
561
646
  */
562
- function aStarPathfinding(start, end, obstacles, gridSize) {
563
- console.log('开始规划路径', obstacles)
564
- gridSize = gridSize || 0.5;
647
+ function aStarPathfinding(start, end, obstacles, gridSize = 0.2) {
648
+ const openList = [];
649
+ const closed = new Set();
565
650
 
566
- var openList = [];
567
- var closedSet = {};
568
-
569
- var startNode = {
651
+ const startNode = {
570
652
  x: start.x,
571
653
  z: start.z,
572
654
  g: 0,
573
655
  h: heuristic(start, end),
574
- f: 0,
575
- parent: null
656
+ parent: null,
576
657
  };
577
658
  startNode.f = startNode.g + startNode.h;
578
-
579
659
  openList.push(startNode);
580
660
 
581
- var directions = [
661
+ const dirs = [
582
662
  { dx: gridSize, dz: 0 },
583
663
  { dx: -gridSize, dz: 0 },
584
664
  { dx: 0, dz: gridSize },
@@ -586,97 +666,267 @@
586
666
  { dx: gridSize, dz: gridSize },
587
667
  { dx: gridSize, dz: -gridSize },
588
668
  { dx: -gridSize, dz: gridSize },
589
- { dx: -gridSize, dz: -gridSize }
669
+ { dx: -gridSize, dz: -gridSize },
590
670
  ];
591
671
 
592
- var iterations = 0;
593
- var maxIterations = 10000;
672
+ let iter = 0;
673
+ const maxIter = 20000;
594
674
 
595
- while (openList.length > 0 && iterations < maxIterations) {
596
- iterations++;
675
+ while (openList.length > 0 && iter < maxIter) {
676
+ iter++;
597
677
 
598
- // 找到f值最小的节点
599
- openList.sort(function (a, b) { return a.f - b.f; });
600
- var current = openList.shift();
678
+ // f 最小的节点
679
+ openList.sort((a, b) => a.f - b.f);
680
+ const current = openList.shift();
601
681
 
602
- // 检查是否到达终点
603
- if (Math.abs(current.x - end.x) < gridSize && Math.abs(current.z - end.z) < gridSize) {
604
- var path = [];
605
- var node = current;
682
+ const key = toKey(current, gridSize);
683
+ if (closed.has(key)) continue;
684
+ closed.add(key);
606
685
 
607
- while (node) {
608
- path.unshift({ x: node.x, z: node.z });
609
- node = node.parent;
610
- }
611
-
612
- path.push(end);
613
- return simplifyPath(path, obstacles);
686
+ // 是否到终点(误差小于 gridSize)
687
+ if (distance(current, end) <= gridSize * 1.1) {
688
+ return rebuildPath(current, end);
614
689
  }
615
690
 
616
- var key = Math.round(current.x / gridSize) + ',' + Math.round(current.z / gridSize);
617
- if (closedSet[key]) continue;
618
- closedSet[key] = true;
691
+ // 扩展邻居
692
+ for (const d of dirs) {
693
+ const nx = current.x + d.dx;
694
+ const nz = current.z + d.dz;
619
695
 
620
- // 扩展邻居节点
621
- for (var d = 0; d < directions.length; d++) {
622
- var dir = directions[d];
623
- var newX = current.x + dir.dx;
624
- var newZ = current.z + dir.dz;
696
+ const nk = `${Math.round(nx / gridSize)},${Math.round(nz / gridSize)}`;
697
+ if (closed.has(nk)) continue;
625
698
 
626
- var neighborKey = Math.round(newX / gridSize) + ',' + Math.round(newZ / gridSize);
627
- if (closedSet[neighborKey]) continue;
699
+ // 点是否落在障碍物区域
700
+ if (isPointInObstacles(nx, nz, obstacles)) continue;
628
701
 
629
- // 检查是否在障碍物内
630
- var blocked = false;
631
- for (var o = 0; o < obstacles.length; o++) {
632
- if (isPointInObstacle(newX, newZ, obstacles[o], gridSize / 2)) {
633
- blocked = true;
634
- break;
635
- }
636
- }
637
- if (blocked) continue;
638
-
639
- // 检查路径是否穿过障碍物
640
- if (pathIntersectsObstacles(current.x, current.z, newX, newZ, obstacles, gridSize / 4)) {
702
+ // 本段路径是否穿越障碍物(含斜线)
703
+ if (segmentIntersectsObstacles(current.x, current.z, nx, nz, obstacles)) {
641
704
  continue;
642
705
  }
643
706
 
644
- var g = current.g + Math.sqrt(dir.dx * dir.dx + dir.dz * dir.dz);
645
- var h = heuristic({ x: newX, z: newZ }, end);
646
- var f = g + h;
707
+ const g = current.g + Math.sqrt(d.dx * d.dx + d.dz * d.dz);
708
+ const h = heuristic({ x: nx, z: nz }, end);
647
709
 
648
- // 检查是否已在openList
649
- var existingIndex = -1;
650
- for (var e = 0; e < openList.length; e++) {
651
- if (Math.abs(openList[e].x - newX) < 0.01 && Math.abs(openList[e].z - newZ) < 0.01) {
652
- existingIndex = e;
653
- break;
654
- }
655
- }
710
+ const exist = openList.find((n) => Math.abs(n.x - nx) < 1e-3 && Math.abs(n.z - nz) < 1e-3);
656
711
 
657
- if (existingIndex >= 0 && openList[existingIndex].g <= g) {
658
- continue;
659
- }
660
-
661
- if (existingIndex >= 0) {
662
- openList.splice(existingIndex, 1);
663
- }
712
+ if (exist && exist.g <= g) continue;
713
+ if (exist) openList.splice(openList.indexOf(exist), 1);
664
714
 
665
715
  openList.push({
666
- x: newX,
667
- z: newZ,
668
- g: g,
669
- h: h,
670
- f: f,
671
- parent: current
716
+ x: nx,
717
+ z: nz,
718
+ g,
719
+ h,
720
+ f: g + h,
721
+ parent: current,
672
722
  });
673
723
  }
674
724
  }
675
725
 
676
- console.warn('A*算法未找到路径,返回直线');
726
+ console.warn("A* 未找到路径,返回直线。");
677
727
  return [start, end];
678
728
  }
679
729
 
730
+ /* ======== 工具函数 ========= */
731
+
732
+ // 曼哈顿 + 欧式启发
733
+ function heuristic(a, b) {
734
+ return Math.sqrt((a.x - b.x) ** 2 + (a.z - b.z) ** 2);
735
+ }
736
+
737
+ // 键
738
+ function toKey(n, grid) {
739
+ return `${Math.round(n.x / grid)},${Math.round(n.z / grid)}`;
740
+ }
741
+
742
+ // 回溯路径
743
+ function rebuildPath(node, end) {
744
+ const path = [];
745
+ while (node) {
746
+ path.unshift({ x: node.x, z: node.z });
747
+ node = node.parent;
748
+ }
749
+ path.push(end);
750
+ return path;
751
+ }
752
+
753
+ // 点是否在任意障碍物中
754
+ function isPointInObstacles(x, z, obstacles) {
755
+ return obstacles.some((o) => {
756
+ const b = o.bounds;
757
+ return x >= b.minX && x <= b.maxX && z >= b.minZ && z <= b.maxZ;
758
+ });
759
+ }
760
+
761
+ // 判断线段是否穿过障碍(矩形)
762
+ function segmentIntersectsObstacles(x1, z1, x2, z2, obstacles) {
763
+ return obstacles.some((o) => {
764
+ const b = o.bounds;
765
+ return segmentIntersectsRect(x1, z1, x2, z2, b);
766
+ });
767
+ }
768
+
769
+ // 线段 vs 轴对齐矩形
770
+ function segmentIntersectsRect(x1, z1, x2, z2, b) {
771
+ // 若两端点都在外侧,但线段穿过 bbox
772
+ if (lineIntersectsAABB(x1, z1, x2, z2, b)) return true;
773
+
774
+ // 若任意端点在矩形内,也算穿越
775
+ if (x1 >= b.minX && x1 <= b.maxX && z1 >= b.minZ && z1 <= b.maxZ) return true;
776
+ if (x2 >= b.minX && x2 <= b.maxX && z2 >= b.maxZ && z2 <= b.maxZ) return true;
777
+
778
+ return false;
779
+ }
780
+
781
+ // 利用 Liang–Barsky 算法判断线段与 AABB 是否相交
782
+ function lineIntersectsAABB(x1, z1, x2, z2, b) {
783
+ let t0 = 0, t1 = 1;
784
+ const dx = x2 - x1, dz = z2 - z1;
785
+
786
+ const checks = [
787
+ [-dx, x1 - b.minX],
788
+ [dx, b.maxX - x1],
789
+ [-dz, z1 - b.minZ],
790
+ [dz, b.maxZ - z1],
791
+ ];
792
+
793
+ for (const [p, q] of checks) {
794
+ if (p === 0 && q < 0) return false;
795
+ const r = q / p;
796
+ if (p < 0) { if (r > t1) return false; else if (r > t0) t0 = r; }
797
+ else if (p > 0) { if (r < t0) return false; else if (r < t1) t1 = r; }
798
+ }
799
+
800
+ return true;
801
+ }
802
+
803
+ // 距离
804
+ function distance(a, b) {
805
+ return Math.sqrt((a.x - b.x) ** 2 + (a.z - b.z) ** 2);
806
+ }
807
+
808
+ /**
809
+ * 简化路径 - 移除不必要的中间点
810
+ * 使用Douglas-Peucker算法的简化版本
811
+ * @param {Array} path - 原始路径点 [{x, z}, ...]
812
+ * @param {Array} obstacles - 障碍物列表
813
+ * @returns {Array} 简化后的路径点
814
+ */
815
+ function simplifyPath(path, obstacles) {
816
+ if (path.length <= 2) return path;
817
+
818
+ const simplified = [path[0]];
819
+ let current = 0;
820
+
821
+ // 贪心算法:尽可能跳过中间点
822
+ while (current < path.length - 1) {
823
+ let farthest = current + 1;
824
+
825
+ // 从最远的点开始尝试,看能否直接连接
826
+ for (let i = path.length - 1; i > current + 1; i--) {
827
+ const canConnect = !segmentIntersectsObstacles(
828
+ path[current].x,
829
+ path[current].z,
830
+ path[i].x,
831
+ path[i].z,
832
+ obstacles
833
+ );
834
+
835
+ if (canConnect) {
836
+ farthest = i;
837
+ break;
838
+ }
839
+ }
840
+
841
+ simplified.push(path[farthest]);
842
+ current = farthest;
843
+ }
844
+
845
+ return simplified;
846
+ }
847
+
848
+ /**
849
+ * 使用Catmull-Rom样条曲线平滑路径
850
+ * @param {Array} path - 原始路径点 [{x, z}, ...]
851
+ * @param {Object} obstacles - 障碍物列表
852
+ * @param {number} tension - 张力参数(0-1),越小越平滑,默认0.5
853
+ * @param {number} segments - 每段曲线的分段数,默认10
854
+ * @returns {Array} 平滑后的路径点
855
+ */
856
+ function smoothPath(path, obstacles, tension = 0.5, segments = 10) {
857
+ if (path.length <= 2) return path;
858
+
859
+ const smoothed = [];
860
+
861
+ // 添加起点
862
+ smoothed.push(path[0]);
863
+
864
+ // 对每个路径段进行平滑
865
+ for (let i = 0; i < path.length - 1; i++) {
866
+ const p0 = path[Math.max(0, i - 1)];
867
+ const p1 = path[i];
868
+ const p2 = path[i + 1];
869
+ const p3 = path[Math.min(path.length - 1, i + 2)];
870
+
871
+ // 生成Catmull-Rom曲线点
872
+ for (let t = 0; t < segments; t++) {
873
+ const u = t / segments;
874
+ const point = catmullRom(p0, p1, p2, p3, u, tension);
875
+
876
+ // 检查平滑后的点是否穿过障碍物
877
+ if (smoothed.length > 0) {
878
+ const lastPoint = smoothed[smoothed.length - 1];
879
+ if (!segmentIntersectsObstacles(lastPoint.x, lastPoint.z, point.x, point.z, obstacles)) {
880
+ smoothed.push(point);
881
+ } else {
882
+ // 如果穿过障碍物,使用原始路径点
883
+ if (smoothed[smoothed.length - 1] !== p1) {
884
+ smoothed.push(p1);
885
+ }
886
+ break;
887
+ }
888
+ } else {
889
+ smoothed.push(point);
890
+ }
891
+ }
892
+ }
893
+
894
+ // 添加终点
895
+ smoothed.push(path[path.length - 1]);
896
+
897
+ return smoothed;
898
+ }
899
+
900
+ /**
901
+ * Catmull-Rom样条曲线插值
902
+ * @param {Object} p0 - 控制点0
903
+ * @param {Object} p1 - 起点
904
+ * @param {Object} p2 - 终点
905
+ * @param {Object} p3 - 控制点3
906
+ * @param {number} t - 插值参数(0-1)
907
+ * @param {number} tension - 张力参数
908
+ * @returns {Object} 插值点 {x, z}
909
+ */
910
+ function catmullRom(p0, p1, p2, p3, t, tension) {
911
+ const t2 = t * t;
912
+ const t3 = t2 * t;
913
+
914
+ const v0 = (p2.x - p0.x) * tension;
915
+ const v1 = (p3.x - p1.x) * tension;
916
+ const w0 = (p2.z - p0.z) * tension;
917
+ const w1 = (p3.z - p1.z) * tension;
918
+
919
+ const x = (2 * p1.x - 2 * p2.x + v0 + v1) * t3 +
920
+ (-3 * p1.x + 3 * p2.x - 2 * v0 - v1) * t2 +
921
+ v0 * t + p1.x;
922
+
923
+ const z = (2 * p1.z - 2 * p2.z + w0 + w1) * t3 +
924
+ (-3 * p1.z + 3 * p2.z - 2 * w0 - w1) * t2 +
925
+ w0 * t + p1.z;
926
+
927
+ return { x, z };
928
+ }
929
+
680
930
 
681
931
 
682
932
  /**
@@ -724,8 +974,24 @@
724
974
  return [start, end];
725
975
  }
726
976
 
727
- // 使用A*算法规划路径(gridSize: 0.5米 = 50cm
728
- return aStarPathfinding(start, end, obstacles, 0.5);
977
+ // 使用A*算法规划路径(gridSize: 0.2米 = 20cm
978
+ const rawPath = aStarPathfinding(start, end, obstacles, 0.2);
979
+
980
+ // 如果路径只有2个点(直线),直接返回
981
+ if (rawPath.length <= 2) {
982
+ return rawPath;
983
+ }
984
+
985
+ // 第一步:简化路径,移除不必要的中间点
986
+ const simplifiedPath = simplifyPath(rawPath, obstacles);
987
+
988
+ // 第二步:平滑路径(可通过options.smoothPath控制是否启用,默认启用)
989
+ const enableSmoothing = options.smoothPath !== false;
990
+ if (enableSmoothing && simplifiedPath.length > 2) {
991
+ return smoothPath(simplifiedPath, obstacles, 0.5, 8);
992
+ }
993
+
994
+ return simplifiedPath;
729
995
  };
730
996
 
731
997
  /**