@kimap/indoor-positioning-sdk-vue2 4.2.4 → 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.4",
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,38 +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
- gridSize = gridSize || 0.5;
647
+ function aStarPathfinding(start, end, obstacles, gridSize = 0.2) {
648
+ const openList = [];
649
+ const closed = new Set();
564
650
 
565
- var openList = [];
566
- var closedSet = {};
567
-
568
- var startNode = {
651
+ const startNode = {
569
652
  x: start.x,
570
653
  z: start.z,
571
654
  g: 0,
572
655
  h: heuristic(start, end),
573
- f: 0,
574
- parent: null
656
+ parent: null,
575
657
  };
576
658
  startNode.f = startNode.g + startNode.h;
577
-
578
659
  openList.push(startNode);
579
660
 
580
- var directions = [
661
+ const dirs = [
581
662
  { dx: gridSize, dz: 0 },
582
663
  { dx: -gridSize, dz: 0 },
583
664
  { dx: 0, dz: gridSize },
@@ -585,97 +666,267 @@
585
666
  { dx: gridSize, dz: gridSize },
586
667
  { dx: gridSize, dz: -gridSize },
587
668
  { dx: -gridSize, dz: gridSize },
588
- { dx: -gridSize, dz: -gridSize }
669
+ { dx: -gridSize, dz: -gridSize },
589
670
  ];
590
671
 
591
- var iterations = 0;
592
- var maxIterations = 10000;
672
+ let iter = 0;
673
+ const maxIter = 20000;
593
674
 
594
- while (openList.length > 0 && iterations < maxIterations) {
595
- iterations++;
675
+ while (openList.length > 0 && iter < maxIter) {
676
+ iter++;
596
677
 
597
- // 找到f值最小的节点
598
- openList.sort(function (a, b) { return a.f - b.f; });
599
- var current = openList.shift();
678
+ // f 最小的节点
679
+ openList.sort((a, b) => a.f - b.f);
680
+ const current = openList.shift();
600
681
 
601
- // 检查是否到达终点
602
- if (Math.abs(current.x - end.x) < gridSize && Math.abs(current.z - end.z) < gridSize) {
603
- var path = [];
604
- var node = current;
682
+ const key = toKey(current, gridSize);
683
+ if (closed.has(key)) continue;
684
+ closed.add(key);
605
685
 
606
- while (node) {
607
- path.unshift({ x: node.x, z: node.z });
608
- node = node.parent;
609
- }
610
-
611
- path.push(end);
612
- return simplifyPath(path, obstacles);
686
+ // 是否到终点(误差小于 gridSize)
687
+ if (distance(current, end) <= gridSize * 1.1) {
688
+ return rebuildPath(current, end);
613
689
  }
614
690
 
615
- var key = Math.round(current.x / gridSize) + ',' + Math.round(current.z / gridSize);
616
- if (closedSet[key]) continue;
617
- closedSet[key] = true;
691
+ // 扩展邻居
692
+ for (const d of dirs) {
693
+ const nx = current.x + d.dx;
694
+ const nz = current.z + d.dz;
618
695
 
619
- // 扩展邻居节点
620
- for (var d = 0; d < directions.length; d++) {
621
- var dir = directions[d];
622
- var newX = current.x + dir.dx;
623
- var newZ = current.z + dir.dz;
696
+ const nk = `${Math.round(nx / gridSize)},${Math.round(nz / gridSize)}`;
697
+ if (closed.has(nk)) continue;
624
698
 
625
- var neighborKey = Math.round(newX / gridSize) + ',' + Math.round(newZ / gridSize);
626
- if (closedSet[neighborKey]) continue;
699
+ // 点是否落在障碍物区域
700
+ if (isPointInObstacles(nx, nz, obstacles)) continue;
627
701
 
628
- // 检查是否在障碍物内
629
- var blocked = false;
630
- for (var o = 0; o < obstacles.length; o++) {
631
- if (isPointInObstacle(newX, newZ, obstacles[o], gridSize / 2)) {
632
- blocked = true;
633
- break;
634
- }
635
- }
636
- if (blocked) continue;
637
-
638
- // 检查路径是否穿过障碍物
639
- if (pathIntersectsObstacles(current.x, current.z, newX, newZ, obstacles, gridSize / 4)) {
702
+ // 本段路径是否穿越障碍物(含斜线)
703
+ if (segmentIntersectsObstacles(current.x, current.z, nx, nz, obstacles)) {
640
704
  continue;
641
705
  }
642
706
 
643
- var g = current.g + Math.sqrt(dir.dx * dir.dx + dir.dz * dir.dz);
644
- var h = heuristic({ x: newX, z: newZ }, end);
645
- 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);
646
709
 
647
- // 检查是否已在openList
648
- var existingIndex = -1;
649
- for (var e = 0; e < openList.length; e++) {
650
- if (Math.abs(openList[e].x - newX) < 0.01 && Math.abs(openList[e].z - newZ) < 0.01) {
651
- existingIndex = e;
652
- break;
653
- }
654
- }
710
+ const exist = openList.find((n) => Math.abs(n.x - nx) < 1e-3 && Math.abs(n.z - nz) < 1e-3);
655
711
 
656
- if (existingIndex >= 0 && openList[existingIndex].g <= g) {
657
- continue;
658
- }
659
-
660
- if (existingIndex >= 0) {
661
- openList.splice(existingIndex, 1);
662
- }
712
+ if (exist && exist.g <= g) continue;
713
+ if (exist) openList.splice(openList.indexOf(exist), 1);
663
714
 
664
715
  openList.push({
665
- x: newX,
666
- z: newZ,
667
- g: g,
668
- h: h,
669
- f: f,
670
- parent: current
716
+ x: nx,
717
+ z: nz,
718
+ g,
719
+ h,
720
+ f: g + h,
721
+ parent: current,
671
722
  });
672
723
  }
673
724
  }
674
725
 
675
- console.warn('A*算法未找到路径,返回直线');
726
+ console.warn("A* 未找到路径,返回直线。");
676
727
  return [start, end];
677
728
  }
678
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
+
679
930
 
680
931
 
681
932
  /**
@@ -723,8 +974,24 @@
723
974
  return [start, end];
724
975
  }
725
976
 
726
- // 使用A*算法规划路径(gridSize: 0.5米 = 50cm
727
- 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;
728
995
  };
729
996
 
730
997
  /**