修改车辆动画位置更新与方向更新不同步
This commit is contained in:
parent
e2f92ab293
commit
26fdd3742e
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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");
|
||||
|
||||
@ -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,7 +241,21 @@ 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) {
|
||||
@ -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] = {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<!-- 包含航空器路由的绘制 -->
|
||||
<!-- 气象监测站弹窗 -->
|
||||
<WeatherStationPopup
|
||||
:visible="weatherStationVisible"
|
||||
@ -51,6 +52,9 @@ import Feature from 'ol/Feature';
|
||||
import Point from 'ol/geom/Point';
|
||||
import { LineString } from 'ol/geom';
|
||||
import { transform } from 'ol/proj';
|
||||
import proj4 from 'proj4';
|
||||
import { register } from 'ol/proj/proj4.js';
|
||||
import { get as getProj } from 'ol/proj';
|
||||
import WebSocketService, { createWebSocket, resetWebSocketInstance } from '../../../utils/websocket.js';
|
||||
|
||||
// 导入子组件
|
||||
@ -89,6 +93,21 @@ const props = defineProps({
|
||||
map: Object
|
||||
});
|
||||
|
||||
// 注册 CGCS2000 / 3-degree Gauss-Kruger CM 120E (EPSG:4547)
|
||||
if (typeof window !== 'undefined' && proj4) {
|
||||
// 检查是否已经注册过该坐标系
|
||||
if (!proj4.defs('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",
|
||||
);
|
||||
console.log('已注册 EPSG:4528 坐标系');
|
||||
}
|
||||
|
||||
// 注册到 OpenLayers
|
||||
register(proj4);
|
||||
}
|
||||
console.log("注册EPSG:4528",getProj('EPSG:4528'));
|
||||
// 子组件引用
|
||||
const animationSystem = ref(null);
|
||||
const labelSystem = ref(null);
|
||||
@ -484,7 +503,7 @@ function updateVehiclePosition(vehicleData) {
|
||||
}
|
||||
|
||||
// 应用当前分类设置到新创建的车辆
|
||||
applyCurrentCategorySettings(object_id);
|
||||
// applyCurrentCategorySettings(object_id);
|
||||
} else {
|
||||
// 更新动画目标
|
||||
if (animationSystem.value) {
|
||||
@ -679,12 +698,12 @@ function parseLineStringGeometry(lineString) {
|
||||
// 更新或创建飞机路线
|
||||
function updateAircraftRoute(flightNo, coordinates, routeType, routeStatus) {
|
||||
if (!aircraftRouteSource || !props.map) return;
|
||||
|
||||
console.log('原始航线坐标:', coordinates);
|
||||
// 转换坐标系
|
||||
const projectedCoords = coordinates.map(coord =>
|
||||
transform(coord, 'EPSG:4326', props.map.getView().getProjection())
|
||||
transform(coord, 'EPSG:4528', props.map.getView().getProjection())
|
||||
);
|
||||
|
||||
console.log('处理后的坐标:', projectedCoords);
|
||||
// 获取起点和终点坐标
|
||||
const startPoint = projectedCoords[0];
|
||||
const endPoint = projectedCoords[projectedCoords.length - 1];
|
||||
|
||||
@ -104,7 +104,7 @@
|
||||
<div class="control-group">
|
||||
<label>服务器地址:</label>
|
||||
<select id="collisionServerSelect">
|
||||
<option value="ws://10.0.0.126:8080/collision">10.0.0.126:8080/collision</option>
|
||||
<option value="ws://10.0.0.122:8080/collision">10.0.0.122:8080/collision</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
@ -334,7 +334,7 @@ watch(() => mapRef.value?.map, (newMap) => {
|
||||
/* 告警统计卡片 */
|
||||
.alarm-stats-card {
|
||||
position: absolute;
|
||||
top: 177px;
|
||||
top: 23%;
|
||||
left: 28px;
|
||||
width: 246px;
|
||||
height: 147px;
|
||||
@ -348,6 +348,7 @@ watch(() => mapRef.value?.map, (newMap) => {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
.stats-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@ -32,7 +32,7 @@ export default defineConfig(({ mode, command }) => {
|
||||
// https://cn.vitejs.dev/config/#server-proxy
|
||||
'/dev-api': {
|
||||
// target: 'http://10.0.0.17:8099',//昊天
|
||||
target: 'http://10.0.0.126:8080',//田哥
|
||||
target: 'http://10.0.0.122:8080',//田哥
|
||||
changeOrigin: true,
|
||||
rewrite: (p) => p.replace(/^\/dev-api/, '')
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user