|
@@ -44,10 +44,12 @@ import GeoJSON from "ol/format/GeoJSON";
|
|
|
import { Vector as VectorSource } from "ol/source";
|
|
import { Vector as VectorSource } from "ol/source";
|
|
|
import LineString from "ol/geom/LineString";
|
|
import LineString from "ol/geom/LineString";
|
|
|
import Feature from "ol/Feature";
|
|
import Feature from "ol/Feature";
|
|
|
-import { Icon, Style, Stroke, Fill, Text } from "ol/style";
|
|
|
|
|
|
|
+import { Icon, Style, Stroke, Fill, Text, Circle } from "ol/style";
|
|
|
import Point from "ol/geom/Point";
|
|
import Point from "ol/geom/Point";
|
|
|
|
|
+import MultiPoint from "ol/geom/MultiPoint";
|
|
|
import { fromLonLat, toLonLat } from 'ol/proj';
|
|
import { fromLonLat, toLonLat } from 'ol/proj';
|
|
|
import { easeInOut, easeOut } from 'ol/easing';
|
|
import { easeInOut, easeOut } from 'ol/easing';
|
|
|
|
|
+import { getPointcloud } from '@/api/map';
|
|
|
|
|
|
|
|
export default {
|
|
export default {
|
|
|
name: 'OlMap',
|
|
name: 'OlMap',
|
|
@@ -181,6 +183,16 @@ export default {
|
|
|
isShowRobot: {
|
|
isShowRobot: {
|
|
|
type: Boolean,
|
|
type: Boolean,
|
|
|
default: true
|
|
default: true
|
|
|
|
|
+ },
|
|
|
|
|
+ // 是否显示点云
|
|
|
|
|
+ showPointcloud: {
|
|
|
|
|
+ type: Boolean,
|
|
|
|
|
+ default: false
|
|
|
|
|
+ },
|
|
|
|
|
+ // 是否显示路网线段
|
|
|
|
|
+ showRoadNetwork: {
|
|
|
|
|
+ type: Boolean,
|
|
|
|
|
+ default: true
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
data() {
|
|
data() {
|
|
@@ -220,6 +232,7 @@ export default {
|
|
|
draw: null,
|
|
draw: null,
|
|
|
snap: null,
|
|
snap: null,
|
|
|
roadmap_src: null,
|
|
roadmap_src: null,
|
|
|
|
|
+ roadmapLayer: null, // 路网图层引用
|
|
|
// 下面四个数据用于记录当前地图中各类元素当前最大id值(绘图新元素起始id使用)
|
|
// 下面四个数据用于记录当前地图中各类元素当前最大id值(绘图新元素起始id使用)
|
|
|
maxPointIdNum: 0,
|
|
maxPointIdNum: 0,
|
|
|
maxLineIdNum: 0,
|
|
maxLineIdNum: 0,
|
|
@@ -231,14 +244,17 @@ export default {
|
|
|
// 轨迹相关
|
|
// 轨迹相关
|
|
|
trajectorySource: null, // 轨迹图层source
|
|
trajectorySource: null, // 轨迹图层source
|
|
|
currentTrajectory: null, // 当前轨迹数据
|
|
currentTrajectory: null, // 当前轨迹数据
|
|
|
- trajectoryProgress: 0 // 轨迹进度
|
|
|
|
|
|
|
+ trajectoryProgress: 0, // 轨迹进度
|
|
|
|
|
+ // 点云相关
|
|
|
|
|
+ pointcloudLayer: null, // 点云图层
|
|
|
|
|
+ pointcloudTimer: null // 点云更新定时器
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
computed: {
|
|
computed: {
|
|
|
url() {
|
|
url() {
|
|
|
// return this.fileUrl + this.deptId + "/" + "map" + "/" + this.robotCode + "/" + this.mapName;
|
|
// return this.fileUrl + this.deptId + "/" + "map" + "/" + this.robotCode + "/" + this.mapName;
|
|
|
// return 'http://101.35.49.102:9000/prod/102/map/HJ-326/sh02'
|
|
// return 'http://101.35.49.102:9000/prod/102/map/HJ-326/sh02'
|
|
|
- return 'http://192.168.0.120:8086'
|
|
|
|
|
|
|
+ return 'http://192.168.0.102:8086'
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
|
|
@@ -324,6 +340,35 @@ export default {
|
|
|
const mapElement = document.querySelector('.tileMap');
|
|
const mapElement = document.querySelector('.tileMap');
|
|
|
mapElement.style.cursor = 'default'; // 恢复默认鼠标样式
|
|
mapElement.style.cursor = 'default'; // 恢复默认鼠标样式
|
|
|
}
|
|
}
|
|
|
|
|
+ },
|
|
|
|
|
+ // 点云显示控制
|
|
|
|
|
+ showPointcloud(newVal) {
|
|
|
|
|
+ if (this.pointcloudLayer) {
|
|
|
|
|
+ this.pointcloudLayer.setVisible(newVal);
|
|
|
|
|
+ if (newVal) {
|
|
|
|
|
+ // 开启点云时启动定时器
|
|
|
|
|
+ this.startPointcloudUpdate();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 关闭点云时清除定时器
|
|
|
|
|
+ this.stopPointcloudUpdate();
|
|
|
|
|
+ // 清空点云数据
|
|
|
|
|
+ const features = this.pointcloudLayer.getSource().getFeatures();
|
|
|
|
|
+ if (features.length > 0) {
|
|
|
|
|
+ features[0].setGeometry(new MultiPoint([]));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // 路网显示控制
|
|
|
|
|
+ showRoadNetwork(newVal, oldVal) {
|
|
|
|
|
+ console.log(`showRoadNetwork watch触发: ${oldVal} -> ${newVal}`);
|
|
|
|
|
+ // 使用图层级别的可见性控制,而不是修改样式
|
|
|
|
|
+ if (this.roadmapLayer) {
|
|
|
|
|
+ this.roadmapLayer.setVisible(newVal);
|
|
|
|
|
+ console.log(`✅ 路网图层可见性已设置为: ${newVal}`);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.warn(`⚠️ roadmapLayer 不存在,无法设置可见性`);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
|
|
@@ -497,27 +542,37 @@ export default {
|
|
|
that.currentPlace = pixel;
|
|
that.currentPlace = pixel;
|
|
|
// currentCoordinate此数组为[id,x,y,z]
|
|
// currentCoordinate此数组为[id,x,y,z]
|
|
|
}
|
|
}
|
|
|
- // 导航页面初始化位置逻辑
|
|
|
|
|
|
|
+ // 导航页面初始化位置逻辑(参考robot_map_editor实现)
|
|
|
if (this.poseInitEnable) {
|
|
if (this.poseInitEnable) {
|
|
|
let feature = this.map.forEachFeatureAtPixel(evt.pixel, (feature) => feature);
|
|
let feature = this.map.forEachFeatureAtPixel(evt.pixel, (feature) => feature);
|
|
|
let coord;
|
|
let coord;
|
|
|
- let nid = feature.getId ? feature.getId() : null;
|
|
|
|
|
|
|
+ // 修复:只有在 feature 存在且有 getId 方法时才调用
|
|
|
|
|
+ let nid = (feature && feature.getId) ? feature.getId() : null;
|
|
|
if (feature && feature.getGeometry().getType() == 'Point') {
|
|
if (feature && feature.getGeometry().getType() == 'Point') {
|
|
|
// 如果不为空并且是点位,则直接取这个点位的坐标
|
|
// 如果不为空并且是点位,则直接取这个点位的坐标
|
|
|
coord = feature.getGeometry().getCoordinates();
|
|
coord = feature.getGeometry().getCoordinates();
|
|
|
} else {
|
|
} else {
|
|
|
- // 选取画布坐标
|
|
|
|
|
|
|
+ // 选取画布坐标(包括空白区域和其他类型的feature)
|
|
|
coord = evt.coordinate;
|
|
coord = evt.coordinate;
|
|
|
}
|
|
}
|
|
|
if (!isDrawing) {
|
|
if (!isDrawing) {
|
|
|
- // 记录起点
|
|
|
|
|
|
|
+ // 第一次点击:记录起点
|
|
|
startPoint = coord;
|
|
startPoint = coord;
|
|
|
isDrawing = true;
|
|
isDrawing = true;
|
|
|
|
|
+ // 显示提示信息
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: '起点已设置,请点击第二个位置确定机器人朝向(或右键取消)',
|
|
|
|
|
+ type: 'info',
|
|
|
|
|
+ duration: 3000
|
|
|
|
|
+ });
|
|
|
} else {
|
|
} else {
|
|
|
- // 结束绘制,计算航向角并清理预览
|
|
|
|
|
|
|
+ // 第二次点击:结束绘制,计算航向角并发送
|
|
|
this.completeDrawing(startPoint, coord, nid);
|
|
this.completeDrawing(startPoint, coord, nid);
|
|
|
- this.roadmap_src.removeFeature(this.arrowFeature)
|
|
|
|
|
- this.arrowFeature = null;
|
|
|
|
|
|
|
+ // 清理预览要素
|
|
|
|
|
+ if (this.arrowFeature) {
|
|
|
|
|
+ this.roadmap_src.removeFeature(this.arrowFeature);
|
|
|
|
|
+ this.arrowFeature = null;
|
|
|
|
|
+ }
|
|
|
isDrawing = false;
|
|
isDrawing = false;
|
|
|
startPoint = null;
|
|
startPoint = null;
|
|
|
}
|
|
}
|
|
@@ -535,24 +590,25 @@ export default {
|
|
|
if (isDrawing && startPoint) {
|
|
if (isDrawing && startPoint) {
|
|
|
const endPoint = evt.coordinate;
|
|
const endPoint = evt.coordinate;
|
|
|
|
|
|
|
|
- // 动态预览虚线
|
|
|
|
|
|
|
+ // 动态预览虚线(参考robot_map_editor的实现风格)
|
|
|
if (!this.previewFeature) {
|
|
if (!this.previewFeature) {
|
|
|
- // 创建线段 Feature
|
|
|
|
|
|
|
+ // 创建线段 Feature - 使用渐变色和更醒目的样式
|
|
|
const line = new LineString([startPoint, endPoint]);
|
|
const line = new LineString([startPoint, endPoint]);
|
|
|
this.previewFeature = new Feature(line);
|
|
this.previewFeature = new Feature(line);
|
|
|
this.previewFeature.setStyle(
|
|
this.previewFeature.setStyle(
|
|
|
new Style({
|
|
new Style({
|
|
|
stroke: new Stroke({
|
|
stroke: new Stroke({
|
|
|
- color: 'rgba(216,30,6, 1)',
|
|
|
|
|
- width: 4,
|
|
|
|
|
|
|
+ color: 'rgba(255, 50, 50, 0.8)', // 更鲜艳的红色
|
|
|
|
|
+ width: 5,
|
|
|
|
|
+ lineDash: [10, 5], // 添加虚线效果,更易识别
|
|
|
}),
|
|
}),
|
|
|
})
|
|
})
|
|
|
);
|
|
);
|
|
|
this.roadmap_src.addFeature(this.previewFeature);
|
|
this.roadmap_src.addFeature(this.previewFeature);
|
|
|
|
|
|
|
|
- // 创建自定义箭头 Feature
|
|
|
|
|
|
|
+ // 创建自定义箭头 Feature - 改进箭头绘制逻辑
|
|
|
this.arrowFeature = new Feature({
|
|
this.arrowFeature = new Feature({
|
|
|
- geometry: new LineString([startPoint, endPoint]), // 起点和终点
|
|
|
|
|
|
|
+ geometry: new LineString([startPoint, endPoint]),
|
|
|
});
|
|
});
|
|
|
this.arrowFeature.setStyle(
|
|
this.arrowFeature.setStyle(
|
|
|
new Style({
|
|
new Style({
|
|
@@ -563,40 +619,52 @@ export default {
|
|
|
const [startX, startY] = pixelCoordinates[0];
|
|
const [startX, startY] = pixelCoordinates[0];
|
|
|
const [endX, endY] = pixelCoordinates[1];
|
|
const [endX, endY] = pixelCoordinates[1];
|
|
|
|
|
|
|
|
- // 计算箭头方向的向量
|
|
|
|
|
|
|
+ // 计算箭头方向
|
|
|
const dx = endX - startX;
|
|
const dx = endX - startX;
|
|
|
const dy = endY - startY;
|
|
const dy = endY - startY;
|
|
|
|
|
+ const length = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果线段太短,不绘制箭头
|
|
|
|
|
+ if (length < 10) return;
|
|
|
|
|
+
|
|
|
const angle = Math.atan2(dy, dx);
|
|
const angle = Math.atan2(dy, dx);
|
|
|
|
|
|
|
|
- // 箭头的偏移量(箭头位置前移)
|
|
|
|
|
- const offsetFactor = 20; // 向前移动的像素距离,调整为更大的值
|
|
|
|
|
- const arrowTipX = endX + offsetFactor * Math.cos(angle);
|
|
|
|
|
- const arrowTipY = endY + offsetFactor * Math.sin(angle);
|
|
|
|
|
-
|
|
|
|
|
- // 绘制线段(去掉箭头部分前的线段,确保箭头前没有多余线段)
|
|
|
|
|
|
|
+ // 箭头参数(参考robot_map_editor的比例)
|
|
|
|
|
+ const arrowLength = 25; // 箭头长度
|
|
|
|
|
+ const arrowAngle = Math.PI / 6; // 箭头张角(30度)
|
|
|
|
|
+
|
|
|
|
|
+ // 箭头尖端位置(在终点)
|
|
|
|
|
+ const tipX = endX;
|
|
|
|
|
+ const tipY = endY;
|
|
|
|
|
+
|
|
|
|
|
+ // 计算箭头两侧的点
|
|
|
|
|
+ const leftX = tipX - arrowLength * Math.cos(angle - arrowAngle);
|
|
|
|
|
+ const leftY = tipY - arrowLength * Math.sin(angle - arrowAngle);
|
|
|
|
|
+ const rightX = tipX - arrowLength * Math.cos(angle + arrowAngle);
|
|
|
|
|
+ const rightY = tipY - arrowLength * Math.sin(angle + arrowAngle);
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制实心箭头
|
|
|
context.beginPath();
|
|
context.beginPath();
|
|
|
- context.moveTo(startX, startY);
|
|
|
|
|
- context.lineTo(arrowTipX, arrowTipY);
|
|
|
|
|
- context.strokeStyle = 'rgba(216,30,6,1)';
|
|
|
|
|
- context.lineWidth = 4;
|
|
|
|
|
|
|
+ context.moveTo(tipX, tipY);
|
|
|
|
|
+ context.lineTo(leftX, leftY);
|
|
|
|
|
+ context.lineTo(rightX, rightY);
|
|
|
|
|
+ context.closePath();
|
|
|
|
|
+ context.fillStyle = 'rgba(255, 50, 50, 0.9)';
|
|
|
|
|
+ context.fill();
|
|
|
|
|
+
|
|
|
|
|
+ // 添加箭头边框,使其更清晰
|
|
|
|
|
+ context.strokeStyle = 'rgba(200, 0, 0, 1)';
|
|
|
|
|
+ context.lineWidth = 2;
|
|
|
context.stroke();
|
|
context.stroke();
|
|
|
-
|
|
|
|
|
- // 绘制箭头(调整箭头起始位置,避免露出前面的一段线)
|
|
|
|
|
- const arrowLength = 20; // 增大箭头长度
|
|
|
|
|
- const arrowWidth = 10; // 增大箭头宽度
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 在起点绘制一个小圆点作为起始标记
|
|
|
context.beginPath();
|
|
context.beginPath();
|
|
|
- context.moveTo(arrowTipX, arrowTipY);
|
|
|
|
|
- context.lineTo(
|
|
|
|
|
- arrowTipX - arrowLength * Math.cos(angle - Math.PI / 6),
|
|
|
|
|
- arrowTipY - arrowLength * Math.sin(angle - Math.PI / 6)
|
|
|
|
|
- );
|
|
|
|
|
- context.lineTo(
|
|
|
|
|
- arrowTipX - arrowLength * Math.cos(angle + Math.PI / 6),
|
|
|
|
|
- arrowTipY - arrowLength * Math.sin(angle + Math.PI / 6)
|
|
|
|
|
- );
|
|
|
|
|
- context.lineTo(arrowTipX, arrowTipY);
|
|
|
|
|
- context.fillStyle = 'rgba(216,30,6,1)';
|
|
|
|
|
|
|
+ context.arc(startX, startY, 6, 0, 2 * Math.PI);
|
|
|
|
|
+ context.fillStyle = 'rgba(50, 150, 255, 0.8)';
|
|
|
context.fill();
|
|
context.fill();
|
|
|
|
|
+ context.strokeStyle = 'rgba(0, 100, 200, 1)';
|
|
|
|
|
+ context.lineWidth = 2;
|
|
|
|
|
+ context.stroke();
|
|
|
},
|
|
},
|
|
|
})
|
|
})
|
|
|
);
|
|
);
|
|
@@ -605,13 +673,13 @@ export default {
|
|
|
// 更新动态虚线坐标
|
|
// 更新动态虚线坐标
|
|
|
this.previewFeature.getGeometry().setCoordinates([startPoint, endPoint]);
|
|
this.previewFeature.getGeometry().setCoordinates([startPoint, endPoint]);
|
|
|
|
|
|
|
|
- // 更新箭头的坐标(箭头样式自动绘制)
|
|
|
|
|
|
|
+ // 更新箭头的坐标(箭头样式自动重绘)
|
|
|
this.arrowFeature.getGeometry().setCoordinates([startPoint, endPoint]);
|
|
this.arrowFeature.getGeometry().setCoordinates([startPoint, endPoint]);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
- // 箭头鼠标右键事件
|
|
|
|
|
|
|
+ // 箭头鼠标右键事件(取消初始化)
|
|
|
this.map.on('contextmenu', (evt) => {
|
|
this.map.on('contextmenu', (evt) => {
|
|
|
// 如果正在初始化,则取消初始化
|
|
// 如果正在初始化,则取消初始化
|
|
|
if (this.poseInitEnable && isDrawing) {
|
|
if (this.poseInitEnable && isDrawing) {
|
|
@@ -629,6 +697,12 @@ export default {
|
|
|
// 重置绘制状态
|
|
// 重置绘制状态
|
|
|
isDrawing = false;
|
|
isDrawing = false;
|
|
|
startPoint = null;
|
|
startPoint = null;
|
|
|
|
|
+ // 显示取消提示
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: '位姿初始化已取消',
|
|
|
|
|
+ type: 'warning',
|
|
|
|
|
+ duration: 2000
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -653,6 +727,10 @@ export default {
|
|
|
}),
|
|
}),
|
|
|
});
|
|
});
|
|
|
this.map.addLayer(this.baseLayer);
|
|
this.map.addLayer(this.baseLayer);
|
|
|
|
|
+
|
|
|
|
|
+ // 创建点云图层
|
|
|
|
|
+ this.initPointcloudLayer();
|
|
|
|
|
+
|
|
|
// this.map.addLayer(
|
|
// this.map.addLayer(
|
|
|
// new TileLayer({
|
|
// new TileLayer({
|
|
|
// source: new SrcXYZ({
|
|
// source: new SrcXYZ({
|
|
@@ -735,16 +813,22 @@ export default {
|
|
|
if (this.roadmap_src) {
|
|
if (this.roadmap_src) {
|
|
|
console.log('initRoad: 清除现有features');
|
|
console.log('initRoad: 清除现有features');
|
|
|
this.roadmap_src.clear();
|
|
this.roadmap_src.clear();
|
|
|
|
|
+ // 确保图层可见性与prop一致
|
|
|
|
|
+ if (this.roadmapLayer) {
|
|
|
|
|
+ this.roadmapLayer.setVisible(this.showRoadNetwork);
|
|
|
|
|
+ console.log(`路网图层可见性更新为: ${this.showRoadNetwork}`);
|
|
|
|
|
+ }
|
|
|
} else {
|
|
} else {
|
|
|
// 只有在第一次初始化时才创建新的VectorSource和图层
|
|
// 只有在第一次初始化时才创建新的VectorSource和图层
|
|
|
console.log('initRoad: 创建新的VectorSource和图层');
|
|
console.log('initRoad: 创建新的VectorSource和图层');
|
|
|
this.roadmap_src = new VectorSource();
|
|
this.roadmap_src = new VectorSource();
|
|
|
- this.map.addLayer(
|
|
|
|
|
- new VectorLayer({
|
|
|
|
|
- source: this.roadmap_src,
|
|
|
|
|
- style: this.customizedStyle,
|
|
|
|
|
- })
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ this.roadmapLayer = new VectorLayer({
|
|
|
|
|
+ source: this.roadmap_src,
|
|
|
|
|
+ style: this.customizedStyle,
|
|
|
|
|
+ visible: this.showRoadNetwork // 使用prop的初始值
|
|
|
|
|
+ });
|
|
|
|
|
+ this.map.addLayer(this.roadmapLayer);
|
|
|
|
|
+ console.log(`路网图层初始可见性: ${this.showRoadNetwork}`);
|
|
|
}
|
|
}
|
|
|
// 将geojson_data转换成openlayers的features
|
|
// 将geojson_data转换成openlayers的features
|
|
|
var features = new GeoJSON().readFeatures(geojson_data);
|
|
var features = new GeoJSON().readFeatures(geojson_data);
|
|
@@ -769,17 +853,66 @@ export default {
|
|
|
features[idx].getGeometry().getType() === "MultiPoint" &&
|
|
features[idx].getGeometry().getType() === "MultiPoint" &&
|
|
|
features[idx].getProperties().id.startsWith("b_")
|
|
features[idx].getProperties().id.startsWith("b_")
|
|
|
) {
|
|
) {
|
|
|
- // 获取离散化的贝塞尔曲线,genBezierPointsByControlPoints函数《GeoJSON路网数据结构说明》文档中有,这里不再重复
|
|
|
|
|
|
|
+ // 🔧 保存原始控制点(来自GeoJSON的MultiPoint坐标)
|
|
|
|
|
+ const controlPoints = features[idx].getGeometry().getCoordinates();
|
|
|
|
|
+ features[idx].set('bezierControlPoints', controlPoints);
|
|
|
|
|
+
|
|
|
|
|
+ // 获取离散化的贝塞尔曲线,genBezierPointsByControlPoints函数
|
|
|
var newBezierPoints = this.genBezierPointsByControlPoints(
|
|
var newBezierPoints = this.genBezierPointsByControlPoints(
|
|
|
- features[idx].getGeometry().getCoordinates(),
|
|
|
|
|
|
|
+ controlPoints,
|
|
|
0.01
|
|
0.01
|
|
|
);
|
|
);
|
|
|
// 将MultiPoint替换为贝塞尔LineString
|
|
// 将MultiPoint替换为贝塞尔LineString
|
|
|
features[idx].setGeometry(new LineString(newBezierPoints));
|
|
features[idx].setGeometry(new LineString(newBezierPoints));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 🔧 3. 修复普通 LineString 中的中间点问题(加载旧数据时的兼容性处理)
|
|
|
|
|
+ console.log('开始修复 LineString 中的中间点...');
|
|
|
|
|
+ let fixedLineCount = 0;
|
|
|
|
|
+ for (var idx in features) {
|
|
|
|
|
+ const feature = features[idx];
|
|
|
|
|
+ const featureId = feature.getProperties().id;
|
|
|
|
|
+
|
|
|
|
|
+ // 只处理普通直线(l_开头),不处理贝塞尔曲线(b_开头)
|
|
|
|
|
+ if (feature.getGeometry().getType() === "LineString" && featureId && featureId.startsWith("l_")) {
|
|
|
|
|
+ const coordinates = feature.getGeometry().getCoordinates();
|
|
|
|
|
+
|
|
|
|
|
+ // 如果线段包含超过2个点(即有中间点)
|
|
|
|
|
+ if (coordinates.length > 2) {
|
|
|
|
|
+ console.warn(`检测到线段 ${featureId} 包含 ${coordinates.length} 个点,正在修复为只包含起点和终点`);
|
|
|
|
|
+
|
|
|
|
|
+ // 只保留起点和终点
|
|
|
|
|
+ const fixedCoordinates = [
|
|
|
|
|
+ coordinates[0], // 起点
|
|
|
|
|
+ coordinates[coordinates.length - 1] // 终点
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ // 更新线段的坐标
|
|
|
|
|
+ feature.getGeometry().setCoordinates(fixedCoordinates);
|
|
|
|
|
+ fixedLineCount++;
|
|
|
|
|
+
|
|
|
|
|
+ console.log(`✅ 线段 ${featureId} 已修复: ${coordinates.length} 个点 -> 2 个点`);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (fixedLineCount > 0) {
|
|
|
|
|
+ console.warn(`⚠️ 共修复了 ${fixedLineCount} 条包含中间点的线段`);
|
|
|
|
|
+ console.warn(`💡 提示: 这些线段已自动修复,请保存地图以更新服务器数据`);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log('✅ 所有 LineString 格式正确,无需修复');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 将features添加到图层
|
|
// 将features添加到图层
|
|
|
this.roadmap_src.addFeatures(features);
|
|
this.roadmap_src.addFeatures(features);
|
|
|
|
|
+
|
|
|
|
|
+ // 确保路网图层的可见性与prop一致(最终保障)
|
|
|
|
|
+ if (this.roadmapLayer) {
|
|
|
|
|
+ this.roadmapLayer.setVisible(this.showRoadNetwork);
|
|
|
|
|
+ console.log(`路网加载完成,图层可见性: ${this.showRoadNetwork}`);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 路线加载完毕后将当前地图的所有元素回执到父组件
|
|
// 路线加载完毕后将当前地图的所有元素回执到父组件
|
|
|
this.elementRoadInitEnd(features);
|
|
this.elementRoadInitEnd(features);
|
|
|
},
|
|
},
|
|
@@ -1325,21 +1458,68 @@ export default {
|
|
|
let startPointId = null;
|
|
let startPointId = null;
|
|
|
let endPointId = null;
|
|
let endPointId = null;
|
|
|
|
|
|
|
|
- coordinates.forEach((coord, index) => {
|
|
|
|
|
- let pointId = this.getConnectedPointId(coord); // 判断是否已有点
|
|
|
|
|
- if (!pointId) {
|
|
|
|
|
- // 确保坐标有正确的z值,处理null值
|
|
|
|
|
- this.ensureValidCoordinate(coord);
|
|
|
|
|
- // 创建新点,并获取新创建点的ID
|
|
|
|
|
- pointId = this.createPointAtCoordinate(coord);
|
|
|
|
|
- }
|
|
|
|
|
- // 记录起点和终点的点ID
|
|
|
|
|
- if (index === 0) {
|
|
|
|
|
- startPointId = pointId;
|
|
|
|
|
- } else if (index === coordinates.length - 1) {
|
|
|
|
|
- endPointId = pointId;
|
|
|
|
|
|
|
+ // 只处理起点和终点(第一个和最后一个坐标)
|
|
|
|
|
+ const startCoord = coordinates[0];
|
|
|
|
|
+ const endCoord = coordinates[coordinates.length - 1];
|
|
|
|
|
+
|
|
|
|
|
+ // 处理起点
|
|
|
|
|
+ let startPointFeature = null;
|
|
|
|
|
+ startPointId = this.getConnectedPointId(startCoord);
|
|
|
|
|
+ if (!startPointId) {
|
|
|
|
|
+ // 确保坐标有正确的z值,处理null值
|
|
|
|
|
+ this.ensureValidCoordinate(startCoord);
|
|
|
|
|
+ // 创建新点,并获取新创建点的ID
|
|
|
|
|
+ startPointId = this.createPointAtCoordinate(startCoord);
|
|
|
|
|
+ }
|
|
|
|
|
+ startPointFeature = this.roadmap_src.getFeatureById(startPointId);
|
|
|
|
|
+
|
|
|
|
|
+ // 处理终点
|
|
|
|
|
+ let endPointFeature = null;
|
|
|
|
|
+ endPointId = this.getConnectedPointId(endCoord);
|
|
|
|
|
+ if (!endPointId) {
|
|
|
|
|
+ // 确保坐标有正确的z值,处理null值
|
|
|
|
|
+ this.ensureValidCoordinate(endCoord);
|
|
|
|
|
+ // 创建新点,并获取新创建点的ID
|
|
|
|
|
+ endPointId = this.createPointAtCoordinate(endCoord);
|
|
|
|
|
+ }
|
|
|
|
|
+ endPointFeature = this.roadmap_src.getFeatureById(endPointId);
|
|
|
|
|
+
|
|
|
|
|
+ // 检查是否起点和终点相同(避免创建0长度的线段)
|
|
|
|
|
+ if (startPointId === endPointId) {
|
|
|
|
|
+ console.warn('起点和终点相同,不创建线段');
|
|
|
|
|
+ this.map.removeInteraction(this.draw);
|
|
|
|
|
+ this.drawLine();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查是否已存在相同起点终点的线段
|
|
|
|
|
+ let lineExist = false;
|
|
|
|
|
+ const featuresAtStart = this.roadmap_src.getFeaturesAtCoordinate(startPointFeature.getGeometry().getCoordinates());
|
|
|
|
|
+ for (let i = 0; i < featuresAtStart.length; i++) {
|
|
|
|
|
+ const existingFeature = featuresAtStart[i];
|
|
|
|
|
+ if (existingFeature.getGeometry().getType() !== 'LineString') continue;
|
|
|
|
|
+
|
|
|
|
|
+ const props = existingFeature.getProperties();
|
|
|
|
|
+ if (((props.startid === startPointId) && (props.endid === endPointId)) ||
|
|
|
|
|
+ ((props.endid === startPointId) && (props.startid === endPointId))) {
|
|
|
|
|
+ console.warn('已存在相同起点终点的线段,不创建新线段');
|
|
|
|
|
+ lineExist = true;
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
- });
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (lineExist) {
|
|
|
|
|
+ this.map.removeInteraction(this.draw);
|
|
|
|
|
+ this.drawLine();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 🔧 关键修复:重新设置线段坐标为只包含起点和终点
|
|
|
|
|
+ // 使用实际点的坐标,而不是绘制过程中的所有中间点
|
|
|
|
|
+ feature.getGeometry().setCoordinates([
|
|
|
|
|
+ startPointFeature.getGeometry().getCoordinates(),
|
|
|
|
|
+ endPointFeature.getGeometry().getCoordinates()
|
|
|
|
|
+ ]);
|
|
|
|
|
|
|
|
// 设置线段的起点ID和终点ID
|
|
// 设置线段的起点ID和终点ID
|
|
|
feature.set('startid', startPointId);
|
|
feature.set('startid', startPointId);
|
|
@@ -1441,6 +1621,13 @@ export default {
|
|
|
this.draw.on('drawend', (event) => {
|
|
this.draw.on('drawend', (event) => {
|
|
|
const coordinates = event.feature.getGeometry().getCoordinates();
|
|
const coordinates = event.feature.getGeometry().getCoordinates();
|
|
|
let feature = event.feature;
|
|
let feature = event.feature;
|
|
|
|
|
+
|
|
|
|
|
+ // 曲线至少需要3个点(起点、控制点、终点)
|
|
|
|
|
+ if (coordinates.length < 3) {
|
|
|
|
|
+ console.warn('贝塞尔曲线需要至少3个点');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 获取起点和终点的坐标
|
|
// 获取起点和终点的坐标
|
|
|
const startCoord = coordinates[0];
|
|
const startCoord = coordinates[0];
|
|
|
this.ensureValidCoordinate(startCoord);
|
|
this.ensureValidCoordinate(startCoord);
|
|
@@ -1451,34 +1638,55 @@ export default {
|
|
|
let startPointId = this.getConnectedPointId(startCoord);
|
|
let startPointId = this.getConnectedPointId(startCoord);
|
|
|
let endPointId = this.getConnectedPointId(endCoord);
|
|
let endPointId = this.getConnectedPointId(endCoord);
|
|
|
|
|
|
|
|
|
|
+ let startPointFeature = null;
|
|
|
|
|
+ let endPointFeature = null;
|
|
|
|
|
+
|
|
|
// 如果起点没有对应的点,生成新的点
|
|
// 如果起点没有对应的点,生成新的点
|
|
|
if (!startPointId) {
|
|
if (!startPointId) {
|
|
|
startPointId = this.createPointAtCoordinate(startCoord);
|
|
startPointId = this.createPointAtCoordinate(startCoord);
|
|
|
}
|
|
}
|
|
|
|
|
+ startPointFeature = this.roadmap_src.getFeatureById(startPointId);
|
|
|
|
|
|
|
|
// 如果终点没有对应的点,生成新的点
|
|
// 如果终点没有对应的点,生成新的点
|
|
|
if (!endPointId) {
|
|
if (!endPointId) {
|
|
|
endPointId = this.createPointAtCoordinate(endCoord);
|
|
endPointId = this.createPointAtCoordinate(endCoord);
|
|
|
}
|
|
}
|
|
|
|
|
+ endPointFeature = this.roadmap_src.getFeatureById(endPointId);
|
|
|
|
|
|
|
|
- // 设置起点ID和终点ID
|
|
|
|
|
- feature.set('startid', startPointId);
|
|
|
|
|
- feature.set('endid', endPointId);
|
|
|
|
|
|
|
+ // 检查是否起点和终点相同
|
|
|
|
|
+ if (startPointId === endPointId) {
|
|
|
|
|
+ console.warn('贝塞尔曲线的起点和终点相同,不创建曲线');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 获取离散化的贝塞尔曲线
|
|
|
|
|
- var newBezierPoints = this.genBezierPointsByControlPoints(coordinates, 0.01);
|
|
|
|
|
- // 将MultiPoint替换为贝塞尔LineString
|
|
|
|
|
- feature.setGeometry(new LineString(newBezierPoints));
|
|
|
|
|
- // 为曲线设置唯一的 ID
|
|
|
|
|
- const featureId = 'b_' + (this.maxBowNum + 1);
|
|
|
|
|
- feature.setId(featureId);
|
|
|
|
|
- feature.set('id', featureId);
|
|
|
|
|
- // 将曲线添加到地图图层
|
|
|
|
|
- this.roadmap_src.addFeature(feature);
|
|
|
|
|
- // 设置样式
|
|
|
|
|
- feature.setStyle(this.customizedStyle(feature));
|
|
|
|
|
- // 点位数据回执父组件记录
|
|
|
|
|
- this.elementRoadDrawEnd(feature, 'b');
|
|
|
|
|
|
|
+ // 🔧 关键修复:使用实际点的坐标更新控制点数组
|
|
|
|
|
+ // 将起点和终点替换为实际点的坐标(保持3D坐标)
|
|
|
|
|
+ const controlPoints = [...coordinates];
|
|
|
|
|
+ controlPoints[0] = startPointFeature.getGeometry().getCoordinates();
|
|
|
|
|
+ controlPoints[controlPoints.length - 1] = endPointFeature.getGeometry().getCoordinates();
|
|
|
|
|
+
|
|
|
|
|
+ // 设置起点ID和终点ID
|
|
|
|
|
+ feature.set('startid', startPointId);
|
|
|
|
|
+ feature.set('endid', endPointId);
|
|
|
|
|
+
|
|
|
|
|
+ // 🔧 保存原始控制点,用于后续GeoJSON导出
|
|
|
|
|
+ // 这是关键:robot_map_editor使用单独的bguide数据源,我们使用properties保存
|
|
|
|
|
+ feature.set('bezierControlPoints', controlPoints);
|
|
|
|
|
+
|
|
|
|
|
+ // 获取离散化的贝塞尔曲线
|
|
|
|
|
+ var newBezierPoints = this.genBezierPointsByControlPoints(controlPoints, 0.01);
|
|
|
|
|
+ // 将MultiPoint替换为贝塞尔LineString
|
|
|
|
|
+ feature.setGeometry(new LineString(newBezierPoints));
|
|
|
|
|
+ // 为曲线设置唯一的 ID
|
|
|
|
|
+ const featureId = 'b_' + (this.maxBowNum + 1);
|
|
|
|
|
+ feature.setId(featureId);
|
|
|
|
|
+ feature.set('id', featureId);
|
|
|
|
|
+ // 将曲线添加到地图图层
|
|
|
|
|
+ this.roadmap_src.addFeature(feature);
|
|
|
|
|
+ // 设置样式
|
|
|
|
|
+ feature.setStyle(this.customizedStyle(feature));
|
|
|
|
|
+ // 点位数据回执父组件记录
|
|
|
|
|
+ this.elementRoadDrawEnd(feature, 'b');
|
|
|
});
|
|
});
|
|
|
},
|
|
},
|
|
|
// 绘制面
|
|
// 绘制面
|
|
@@ -1734,28 +1942,18 @@ export default {
|
|
|
if (startId === id || endId === id) {
|
|
if (startId === id || endId === id) {
|
|
|
const lineGeometry = lineFeature.getGeometry();
|
|
const lineGeometry = lineFeature.getGeometry();
|
|
|
const lineCoordinates = lineGeometry.getCoordinates();
|
|
const lineCoordinates = lineGeometry.getCoordinates();
|
|
|
- // 如果点位是线段的起点
|
|
|
|
|
- if (startId === id) {
|
|
|
|
|
- const endPoint = lineCoordinates[lineCoordinates.length - 1]; // 终点坐标
|
|
|
|
|
- const newLineCoordinates = [position]; // 新起点坐标
|
|
|
|
|
- // 遍历剩余的点,更新坐标(排除终点坐标)
|
|
|
|
|
- for (let i = 1; i < lineCoordinates.length - 1; i++) {
|
|
|
|
|
- newLineCoordinates.push([lineCoordinates[i][0] + deltaX, lineCoordinates[i][1] + deltaY]);
|
|
|
|
|
- }
|
|
|
|
|
- // 添加终点坐标不做修改
|
|
|
|
|
- newLineCoordinates.push(endPoint);
|
|
|
|
|
- // 更新线段geometry
|
|
|
|
|
- lineGeometry.setCoordinates(newLineCoordinates);
|
|
|
|
|
- lineFeature.setStyle(this.customizedStyle(lineFeature)); // 确保重新设置样式,包含箭头
|
|
|
|
|
- }
|
|
|
|
|
- // 如果点位是线段的终点
|
|
|
|
|
- else if (endId === id) {
|
|
|
|
|
- const startPoint = lineCoordinates[0]; // 起点坐标
|
|
|
|
|
- const newLineCoordinates = [startPoint]; // 新起点坐标
|
|
|
|
|
- // 遍历剩余的点,更新坐标
|
|
|
|
|
- for (let i = 1; i < lineCoordinates.length; i++) {
|
|
|
|
|
- newLineCoordinates.push([lineCoordinates[i][0] + deltaX, lineCoordinates[i][1] + deltaY]);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 🔧 关键修复:确保线段只包含起点和终点两个坐标
|
|
|
|
|
+ // 获取起点和终点的feature
|
|
|
|
|
+ const startPointFeature = this.roadmap_src.getFeatureById(startId);
|
|
|
|
|
+ const endPointFeature = this.roadmap_src.getFeatureById(endId);
|
|
|
|
|
+
|
|
|
|
|
+ if (startPointFeature && endPointFeature) {
|
|
|
|
|
+ // 使用实际点的坐标重新设置线段
|
|
|
|
|
+ const newLineCoordinates = [
|
|
|
|
|
+ startPointFeature.getGeometry().getCoordinates(),
|
|
|
|
|
+ endPointFeature.getGeometry().getCoordinates()
|
|
|
|
|
+ ];
|
|
|
// 更新线段geometry
|
|
// 更新线段geometry
|
|
|
lineGeometry.setCoordinates(newLineCoordinates);
|
|
lineGeometry.setCoordinates(newLineCoordinates);
|
|
|
lineFeature.setStyle(this.customizedStyle(lineFeature)); // 确保重新设置样式,包含箭头
|
|
lineFeature.setStyle(this.customizedStyle(lineFeature)); // 确保重新设置样式,包含箭头
|
|
@@ -1796,16 +1994,23 @@ export default {
|
|
|
},
|
|
},
|
|
|
// 完成绘制方法
|
|
// 完成绘制方法
|
|
|
completeDrawing(start, end, nid) {
|
|
completeDrawing(start, end, nid) {
|
|
|
- // 计算航向角
|
|
|
|
|
- const bearing = this.calculateBearing(start, end);
|
|
|
|
|
- // 移除预览虚线
|
|
|
|
|
|
|
+ // 参考robot_map_editor的角度计算方式
|
|
|
|
|
+ // 计算旋转角度 (注意:参数顺序是 atan2(x, y),与常规的 atan2(y, x) 不同)
|
|
|
|
|
+ const rotation = Math.atan2(end[0] - start[0], end[1] - start[1]);
|
|
|
|
|
+ // 转换为机器人坐标系的yaw角 (Math.PI / 2.0 - rotation)
|
|
|
|
|
+ const yaw = Math.PI / 2.0 - rotation;
|
|
|
|
|
+
|
|
|
|
|
+ // 移除预览虚线和箭头
|
|
|
if (this.previewFeature) {
|
|
if (this.previewFeature) {
|
|
|
this.roadmap_src.removeFeature(this.previewFeature);
|
|
this.roadmap_src.removeFeature(this.previewFeature);
|
|
|
this.previewFeature = null;
|
|
this.previewFeature = null;
|
|
|
}
|
|
}
|
|
|
- this.$emit('initNavigationResult', start, bearing.toFixed(2),nid)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 发送初始化结果,传递弧度值
|
|
|
|
|
+ this.$emit('initNavigationResult', start, yaw, nid)
|
|
|
},
|
|
},
|
|
|
- // 计算航向角
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 计算航向角(保留用于其他用途,但初始化不使用此方法)
|
|
|
calculateBearing(start, end) {
|
|
calculateBearing(start, end) {
|
|
|
const dx = end[0] - start[0];
|
|
const dx = end[0] - start[0];
|
|
|
const dy = end[1] - start[1];
|
|
const dy = end[1] - start[1];
|
|
@@ -1839,12 +2044,11 @@ export default {
|
|
|
// 初始化轨迹图层
|
|
// 初始化轨迹图层
|
|
|
this.initTrajectoryLayer();
|
|
this.initTrajectoryLayer();
|
|
|
|
|
|
|
|
- // 只有在不是强制重绘时才清除轨迹(避免重复清除)
|
|
|
|
|
- if (!options.forceRedraw) {
|
|
|
|
|
- this.clearTrajectory();
|
|
|
|
|
- // 保存轨迹数据
|
|
|
|
|
- this.currentTrajectory = trajectory;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 清除之前的轨迹(无论是规划路径还是实时轨迹都需要清除旧的)
|
|
|
|
|
+ this.clearTrajectory();
|
|
|
|
|
+
|
|
|
|
|
+ // 保存轨迹数据
|
|
|
|
|
+ this.currentTrajectory = trajectory;
|
|
|
|
|
|
|
|
this.trajectoryProgress = options.currentProgress || 0;
|
|
this.trajectoryProgress = options.currentProgress || 0;
|
|
|
|
|
|
|
@@ -2364,8 +2568,129 @@ export default {
|
|
|
|
|
|
|
|
console.log('地图已刷新');
|
|
console.log('地图已刷新');
|
|
|
}
|
|
}
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 手动设置路网可见性(用于调试)
|
|
|
|
|
+ setRoadNetworkVisible(visible) {
|
|
|
|
|
+ if (this.roadmapLayer) {
|
|
|
|
|
+ this.roadmapLayer.setVisible(visible);
|
|
|
|
|
+ console.log(`手动设置路网图层可见性: ${visible}`);
|
|
|
|
|
+ console.log(`当前图层状态:`, {
|
|
|
|
|
+ visible: this.roadmapLayer.getVisible(),
|
|
|
|
|
+ featureCount: this.roadmap_src ? this.roadmap_src.getFeatures().length : 0
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.warn('路网图层不存在');
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 点云相关方法 ====================
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化点云图层
|
|
|
|
|
+ initPointcloudLayer() {
|
|
|
|
|
+ // 创建点云图层
|
|
|
|
|
+ this.pointcloudLayer = new VectorLayer({
|
|
|
|
|
+ source: new VectorSource({
|
|
|
|
|
+ features: [new Feature({
|
|
|
|
|
+ geometry: new MultiPoint([]),
|
|
|
|
|
+ name: 'PointCloud'
|
|
|
|
|
+ })]
|
|
|
|
|
+ }),
|
|
|
|
|
+ style: new Style({
|
|
|
|
|
+ image: new Circle({
|
|
|
|
|
+ radius: 1.8,
|
|
|
|
|
+ fill: new Fill({ color: '#FF0000' })
|
|
|
|
|
+ })
|
|
|
|
|
+ }),
|
|
|
|
|
+ visible: this.showPointcloud,
|
|
|
|
|
+ zIndex: 10 // 确保点云图层显示在地图之上
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 添加到地图
|
|
|
|
|
+ this.map.addLayer(this.pointcloudLayer);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果默认开启点云,则启动更新
|
|
|
|
|
+ if (this.showPointcloud) {
|
|
|
|
|
+ this.startPointcloudUpdate();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ console.log('点云图层已初始化');
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 启动点云更新定时器
|
|
|
|
|
+ startPointcloudUpdate() {
|
|
|
|
|
+ // 先清除已有的定时器
|
|
|
|
|
+ this.stopPointcloudUpdate();
|
|
|
|
|
+
|
|
|
|
|
+ // 启动新的定时器,每800ms更新一次
|
|
|
|
|
+ this.pointcloudTimer = setInterval(() => {
|
|
|
|
|
+ // 如果图层不可见,则不更新
|
|
|
|
|
+ if (!this.pointcloudLayer || !this.pointcloudLayer.getVisible()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.updatePointcloud();
|
|
|
|
|
+ }, 800);
|
|
|
|
|
+
|
|
|
|
|
+ console.log('点云更新定时器已启动');
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 停止点云更新定时器
|
|
|
|
|
+ stopPointcloudUpdate() {
|
|
|
|
|
+ if (this.pointcloudTimer) {
|
|
|
|
|
+ clearInterval(this.pointcloudTimer);
|
|
|
|
|
+ this.pointcloudTimer = null;
|
|
|
|
|
+ console.log('点云更新定时器已停止');
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 更新点云数据
|
|
|
|
|
+ updatePointcloud() {
|
|
|
|
|
+ getPointcloud().then(response => {
|
|
|
|
|
+ if (!this.pointcloudLayer) return;
|
|
|
|
|
+
|
|
|
|
|
+ const pointcloud = response;
|
|
|
|
|
+
|
|
|
|
|
+ // 解析点云数据
|
|
|
|
|
+ // 数据格式:每12字节一个点 (3个float32: x, y, z)
|
|
|
|
|
+ const pointsCount = Math.floor(pointcloud.byteLength / 12);
|
|
|
|
|
+
|
|
|
|
|
+ if (pointsCount === 0) return;
|
|
|
|
|
+
|
|
|
|
|
+ // 创建Float32Array视图来读取数据
|
|
|
|
|
+ const float32View = new Float32Array(pointcloud, 0);
|
|
|
|
|
+ const coordinates = [];
|
|
|
|
|
+
|
|
|
|
|
+ // 提取所有点的坐标(只使用x, y,忽略z)
|
|
|
|
|
+ for (let i = 0; i < pointsCount; i++) {
|
|
|
|
|
+ const x = float32View[3 * i];
|
|
|
|
|
+ const y = float32View[3 * i + 1];
|
|
|
|
|
+ // const z = float32View[3 * i + 2]; // 2D地图不需要z坐标
|
|
|
|
|
+ coordinates.push([x, y]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 更新点云图层的几何数据
|
|
|
|
|
+ const features = this.pointcloudLayer.getSource().getFeatures();
|
|
|
|
|
+ if (features.length > 0) {
|
|
|
|
|
+ features[0].setGeometry(new MultiPoint(coordinates));
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(error => {
|
|
|
|
|
+ // 静默处理错误,避免控制台刷屏
|
|
|
|
|
+ // console.error('获取点云数据失败:', error);
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
+
|
|
|
|
|
+ beforeDestroy() {
|
|
|
|
|
+ // 清除点云更新定时器
|
|
|
|
|
+ this.stopPointcloudUpdate();
|
|
|
|
|
+
|
|
|
|
|
+ // 清除其他定时器
|
|
|
|
|
+ if (this.pathTimerId) {
|
|
|
|
|
+ clearInterval(this.pathTimerId);
|
|
|
|
|
+ this.pathTimerId = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|