From 26fdd3742ec40f14a9fde21f25d99044e5797b6c Mon Sep 17 00:00:00 2001 From: GAO <2206767478@qq.com> Date: Mon, 28 Jul 2025 16:00:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=BD=A6=E8=BE=86=E5=8A=A8?= =?UTF-8?q?=E7=94=BB=E4=BD=8D=E7=BD=AE=E6=9B=B4=E6=96=B0=E4=B8=8E=E6=96=B9?= =?UTF-8?q?=E5=90=91=E6=9B=B4=E6=96=B0=E4=B8=8D=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 2 +- .env.production | 4 +- src/components/map/OpenLayersMap.vue | 2 +- .../map/controls/VehicleAnimationSystem.vue | 66 ++++++++++++------- .../VehicleMovementControlRefactored.vue | 27 ++++++-- src/utils/test_websocket.html | 2 +- src/views/platform/index.vue | 3 +- vite.config.js | 2 +- 8 files changed, 75 insertions(+), 33 deletions(-) diff --git a/.env.development b/.env.development index dc4c90b..bd61a46 100644 --- a/.env.development +++ b/.env.development @@ -8,4 +8,4 @@ VITE_APP_ENV = 'development' VITE_APP_BASE_API = '/dev-api' # WebSocket配置 -VITE_APP_WEBSOCKET_URL=ws://10.0.0.126:8080/collision +VITE_APP_WEBSOCKET_URL=ws://10.0.0.122:8080/collision diff --git a/.env.production b/.env.production index 4b364a1..7197dd5 100644 --- a/.env.production +++ b/.env.production @@ -5,9 +5,9 @@ VITE_APP_TITLE = 青岛机场无人驾驶车辆协同云平台 VITE_APP_ENV = 'production' # 青岛机场无人驾驶车辆协同云平台/生产环境 -VITE_APP_BASE_API = 'http://10.0.0.126:8080' +VITE_APP_BASE_API = 'http://10.0.0.122:8080' -VITE_APP_WEBSOCKET_URL='ws://10.0.0.124:8080/collision' +VITE_APP_WEBSOCKET_URL='ws://10.0.0.122:8080/collision' # 是否在打包时开启压缩,支持 gzip 和 brotli VITE_BUILD_COMPRESS = gzip \ No newline at end of file diff --git a/src/components/map/OpenLayersMap.vue b/src/components/map/OpenLayersMap.vue index 7d501f9..ee5414d 100644 --- a/src/components/map/OpenLayersMap.vue +++ b/src/components/map/OpenLayersMap.vue @@ -76,7 +76,7 @@ function handleSetCategoryVisibility(type, settings) { // 注册 EPSG:4528 投影 proj4.defs( "EPSG:4528", - "+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +ellps=GRS80 +units=m +no_defs" + "+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +ellps=GRS80 +units=m +no_defs", ); register(proj4); const projection = getProjection("EPSG:4528"); diff --git a/src/components/map/controls/VehicleAnimationSystem.vue b/src/components/map/controls/VehicleAnimationSystem.vue index 15f5e08..f4d43c4 100644 --- a/src/components/map/controls/VehicleAnimationSystem.vue +++ b/src/components/map/controls/VehicleAnimationSystem.vue @@ -86,6 +86,8 @@ function updateVehicleAnimations(deltaTime) { if (!animData) return; // 确保车辆持续移动 + //这个函数检查车辆是否长时间没有收到新的位置更新, + // 如果是,则基于历史移动方向继续移动车辆,避免车辆在屏幕上突然停止。 ensureContinuousMovement(animData, vehicle, currentTime, deltaTime); // 平滑速度过渡 @@ -157,9 +159,11 @@ function updateVehicleAnimations(deltaTime) { // 更新车辆样式 if (props.getVehicleStyle) { - const currentHeading = vehicle ? vehicle.heading : 0; + // const currentHeading = vehicle ? vehicle.heading : 0; + // //优先使用动画系统内部的heading值 + const currentHeading = animData.heading !== undefined ? animData.heading : (vehicle ? vehicle.heading : 0); - if (!animData.lastHeading || Math.abs(animData.lastHeading - currentHeading) > 1) { + if (!animData.lastHeading || Math.abs(animData.lastHeading - currentHeading) > 5) { feature.setStyle(props.getVehicleStyle(id, currentSpeed, currentHeading)); animData.lastHeading = currentHeading; } @@ -182,7 +186,7 @@ function updateVehiclePathHistory(id, animData, currentTime) { } // 每150ms记录一次位置,提高记录频率 - if (!animData.lastPathRecordTime || currentTime - animData.lastPathRecordTime > 150) { + if (!animData.lastPathRecordTime || currentTime - animData.lastPathRecordTime > 100) { // 添加当前位置到历史轨迹 animData.pathHistory.push({ time: currentTime, @@ -209,23 +213,25 @@ function ensureContinuousMovement(animData, vehicle, currentTime, deltaTime) { // 简单的预测:基于最后的移动方向继续移动 if (!animData.predictionVector) { // 如果没有预测向量,使用历史轨迹的最后方向 - if (animData.pathHistory && animData.pathHistory.length >= 2) { + if (animData.pathHistory && animData.pathHistory.length >= 2) {//检查是否存在历史轨迹,并且至少有两个点 + //获取历史轨迹中最后两个点数据 const latest = animData.pathHistory[animData.pathHistory.length - 1]; const previous = animData.pathHistory[animData.pathHistory.length - 2]; - + //position:[x,y]表示车辆在地图上的平面坐标 + //计算两点之间的位移向量的向量长度 const dx = latest.position[0] - previous.position[0]; const dy = latest.position[1] - previous.position[1]; const len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { - // 创建单位方向向量 - animData.predictionVector = [dx / len, dy / len]; + // 创建单位方向向量 + animData.predictionVector = [dx / len, dy / len]; //根据历史向量的两个点创建预测向量 } else { - // 默认向前移动 + // 默认向前(上)移动 animData.predictionVector = [0, 1]; } } else { - // 默认向前移动 + // 默认向前(上)移动(没有历史轨迹数据) animData.predictionVector = [0, 1]; } } @@ -235,8 +241,22 @@ function ensureContinuousMovement(animData, vehicle, currentTime, deltaTime) { animData.targetPosition = [ animData.position[0] + animData.predictionVector[0] * moveDistance, animData.position[1] + animData.predictionVector[1] * moveDistance - ]; + ];//根据预测向量的方向和距离,设置新的目标位置 + + // ========== 关键:同步方向与预测移动方向 ========== + if (animData.predictionVector[0] !== 0 || animData.predictionVector[1] !== 0) { + // 计算预测移动方向的角度 + const moveAngle = Math.atan2(animData.predictionVector[1], animData.predictionVector[0]); + // 转换为heading值(根据地图坐标系调整) + let predictedHeading = (moveAngle * 180 / Math.PI + 72) % 360; // 72是地图旋转角度 + if (predictedHeading < 0) predictedHeading += 360; + // // 更新方向为预测方向 + animData.targetHeading = predictedHeading; + // 可以选择立即更新或逐渐更新 + // animData.heading = predictedHeading; // 立即更新 + } + // 缓慢降低速度,但保持最低速度 if (!animData.lastSpeedReduction || currentTime - animData.lastSpeedReduction > 2000) { animData.speed = Math.max(animData.speed * 0.95, MIN_SPEED); @@ -246,9 +266,9 @@ function ensureContinuousMovement(animData, vehicle, currentTime, deltaTime) { } // 基于历史轨迹预测未来路径 -function predictFuturePath(animData) { +function predictFuturePath(animData) {//animData是车辆动画数据 if (!animData.pathHistory || animData.pathHistory.length < 3) { - return null; + return null;//少于三个点无法进行有效预测 } // 获取最近的几个历史点 @@ -261,6 +281,7 @@ function predictFuturePath(animData) { let totalWeight = 0; // 从最近的点开始,给予更高权重 + //根据历史轨迹,计算一个带权重的平均运动向量,用来预测车辆未来 1~2 秒的继续移动方向与速度 for (let i = points - 2; i >= 0; i--) { const curr = history[i + 1]; const prev = history[i]; @@ -307,7 +328,7 @@ function predictFuturePath(animData) { const predictionVector = [ normalizedDx * speedFactor, normalizedDy * speedFactor - ]; + ];//生成最终的预测向量 // 计算预测位置,增加预测距离 const predictedPosition = [ @@ -318,7 +339,7 @@ function predictFuturePath(animData) { return { vector: predictionVector, position: predictedPosition - }; + };//返回预测变量和预测距离 } // 初始化车辆动画数据 @@ -344,9 +365,9 @@ function initVehicleAnimation(id, coordinates, heading, speed) { vehicleMotionHistory.value[id] = []; } -// 更新车辆动画目标 - 简化版本,专注于平滑过渡 +// 更新车辆动画目标 - 简化版本,专注于平滑过渡 接收到新的车辆位置,朝向或者速度时调用 function updateVehicleAnimationTarget(id, coordinates, heading, speed) { - const animData = vehicleAnimations.value[id] || {}; + const animData = vehicleAnimations.value[id] || {};//获取指定ID车辆的当前动画数据,如果不存在则创建空对象 const now = Date.now(); // 简化的预测向量计算 @@ -357,7 +378,7 @@ function updateVehicleAnimationTarget(id, coordinates, heading, speed) { const dx = coordinates[0] - animData.position[0]; const dy = coordinates[1] - animData.position[1]; const distance = Math.sqrt(dx * dx + dy * dy); - + //计算位移向量和距离 if (distance > 0.0001) { // 创建单位方向向量 predictionVector = [dx / distance, dy / distance]; @@ -370,7 +391,7 @@ function updateVehicleAnimationTarget(id, coordinates, heading, speed) { } else { animData.speedHistory.push(speed); if (animData.speedHistory.length > 3) { - animData.speedHistory.shift(); + animData.speedHistory.shift();//始终保留3个元素,满了则删除最早的值 } } @@ -383,7 +404,8 @@ function updateVehicleAnimationTarget(id, coordinates, heading, speed) { ...animData, targetPosition: coordinates, targetHeading: heading, - heading: animData.heading || heading, + // heading: animData.heading || heading, + heading: animData.heading !== undefined ? animData.heading : heading, position: animData.position || coordinates, speed: smoothedSpeed, lastUpdated: now, @@ -402,10 +424,10 @@ function stopAnimationLoop() { // 重置动画数据 function resetAnimations() { - vehicleAnimations.value = {}; - vehicleMotionHistory.value = {}; + vehicleAnimations.value = {};//清空所有车辆的动画数据 + vehicleMotionHistory.value = {};//清空所有车辆的运动历史轨迹 - Object.keys(props.vehicles).forEach(id => { + Object.keys(props.vehicles).forEach(id => {//基于props.vehicles对象的键值,遍历所有的车辆ID const vehicle = props.vehicles[id]; if (vehicle) { vehicleAnimations.value[id] = { diff --git a/src/components/map/controls/VehicleMovementControlRefactored.vue b/src/components/map/controls/VehicleMovementControlRefactored.vue index 9dcd41e..6dba3b6 100644 --- a/src/components/map/controls/VehicleMovementControlRefactored.vue +++ b/src/components/map/controls/VehicleMovementControlRefactored.vue @@ -1,4 +1,5 @@