Browse Source

绘制内容结算0117

zhiyuan-007 2 months ago
parent
commit
9258839d85

BIN
public/imgs/warningBackground_conflict.png


BIN
public/imgs/warningBackground_conflict_1.png


BIN
public/imgs/warningBackground_time.png


BIN
public/imgs/warningBackground_time_1.png


BIN
public/imgs/warningBackground_time_2.png


BIN
public/imgs/基本信息框-红.png


BIN
public/imgs/基本信息框-红_1 (2).png


BIN
public/imgs/基本信息框.png


BIN
src/assets/lineTexture.png


BIN
src/assets/基本信息框-红_1.png


+ 36 - 27
src/components/mapJK.vue

@@ -1403,7 +1403,8 @@ export default {
                     point:message.position_cj,
                     uavInfo: {
                       type:"safe",
-                      data:message.routeInfoVO
+                      data:message.routeInfoVO,
+                      origin:message.routeInfoVO
                     }
                   });
                 })
@@ -1448,6 +1449,8 @@ export default {
                 }
               })
               messages.forEach(message => {
+                debugger
+                message.routeInfoVO.speed = message.routeInfoVO.speed * 1 +(Math.random() * 2).toFixed(2) * 1
                 if(message.overall == "SAFE"){
                   addGraphics({
                     "id": message.uavid+'_conflict',
@@ -1466,7 +1469,8 @@ export default {
                     point:message.position_cj,
                     uavInfo: {
                       type:"safe",
-                      data:message.routeInfoVO
+                      data:message.routeInfoVO,
+                      origin:message.routeInfoVO
                     }
                   });
                 }else{
@@ -1480,13 +1484,14 @@ export default {
                       point:message.position_cj,
                       uavInfo: {
                         type:"conflict",
-                        data:message.nearestAircraft
+                        action:message.routeInfoVO.avoidanceType,
+                        data:message.routeInfoVO.avoidanceType == "wait" ?message.nearestAircraft:message.routeInfoVO,
+                        origin:message.routeInfoVO
                       }
                     });
-                    debugger
                     addGraphics({
                       id: message.uavid+'_conflict',
-                      status: "show",
+                      status:message.routeInfoVO.status == 3?"hide":"show",
                       data: {
                           "geometry": { "type": "point", "x": message.nearestAircraft.conflictPoint[0],   "y":  message.nearestAircraft.conflictPoint[1], "z": message.nearestAircraft.conflictPoint[2] },
                           "attributes": { "name": "碰撞点位" }
@@ -1494,7 +1499,7 @@ export default {
                     });
                     pathPipe({
                       "id": message.uavid+'_conflict',
-                      "status": "show",
+                      "status": message.routeInfoVO.status == 3?"hide":"show",
                       "paths":[message.nearestAircraft.conflictPath],
                       "color": "#FF0000",
                       "intensity": 1.5,
@@ -1509,7 +1514,6 @@ export default {
                       "id": message.uavid+'_conflict',
                       "status": "hide"
                     });
-                    debugger
                     if(message.noFlyZone.status != "SAFE"){
                       console.log("禁飞区预警",message);
                       flyGLTF({
@@ -1521,7 +1525,8 @@ export default {
                         point:message.position_cj,
                         uavInfo: {
                           type:"noFlyZone",
-                          data:message.noFlyZone
+                          data:message.routeInfoVO,
+                          origin:message.routeInfoVO
                         }
                       });
                     }else if(message.routeDeviate.status != "SAFE"){
@@ -1535,7 +1540,9 @@ export default {
                         point:message.position_cj,
                         uavInfo: {
                           type:"routeDeviate",
-                          data:message.routeDeviate
+                          data:message.routeDeviate,
+                          index:message.index,
+                          origin:message.routeInfoVO
                         }
                       });
                     }else if(message.electricityWarning.status != "SAFE"){
@@ -1549,7 +1556,8 @@ export default {
                         point:message.position_cj,
                         uavInfo: {
                           type:"electricityWarning",
-                          data:message.electricityWarning
+                          data:message.electricityWarning,
+                          origin:message.routeInfoVO
                         }
                       });
                     }else if(message.collision.status != "SAFE"){
@@ -1563,7 +1571,8 @@ export default {
                         point:message.position_cj,
                         uavInfo: {
                           type:"collision",
-                          data:message.collision
+                          data:message.collision,
+                          origin:message.routeInfoVO
                         }
                       });
                     }else if(message.clearZone.status != "SAFE"){
@@ -1577,22 +1586,25 @@ export default {
                         point:message.position_cj,
                         uavInfo: {
                           type:"clearZone",
-                          data:message.clearZone
+                          data:message.clearZone,
+                          origin:message.routeInfoVO
+                        }
+                      });
+                    }else{
+                      flyGLTF({
+                        id:message.id,
+                        uavid:message.uavid,
+                        status:message.routeInfoVO.status == 3?"hide":"show",
+                        //duration:message.time + 100,
+                        duration:2100,
+                        point:message.position_cj,
+                        uavInfo: {
+                          type:"safe",
+                          data:message.routeInfoVO,
+                          origin:message.routeInfoVO
                         }
                       });
                     }
-                    flyGLTF({
-                      id:message.id,
-                      uavid:message.uavid,
-                      status:message.routeInfoVO.status == 3?"hide":"show",
-                      //duration:message.time + 100,
-                      duration:2100,
-                      point:message.position_cj,
-                      uavInfo: {
-                        type:"safe",
-                        data:message.routeInfoVO
-                      }
-                    });
                   }
                 }
               })
@@ -1648,9 +1660,6 @@ export default {
       function changePointStatus(params){
         flyGLTFInstances[params.uavid].followPath(params.isFollow);
       }
-
-
-
       //ws 推送方法
       function getRealPower(params){
         const connectWebSocket = () => {

File diff suppressed because it is too large
+ 1213 - 48
src/config/routeList.json


+ 10 - 3
src/units/map/FlyGLTFEvent.js

@@ -117,14 +117,14 @@ class FlyGLTFEvent{
                 const heading = this.calculatePathHeading(currentAfterPosition,nextAfterPosition);
                 const cameraHeading = this.calculateCameraPathHeading(currentAfterPosition,nextAfterPosition);
                 //计算相机后方的偏移位置
-                const offsetDistance = 40;
+                const offsetDistance = 100;
                 const offsetX = offsetDistance * Math.cos((cameraHeading -180) * Math.PI /180);
                 const offsetY = offsetDistance * Math.sin((cameraHeading -180) * Math.PI /180);
                 //设置相机位置和视角
                 const mapPosition = [
                     currentAfterPosition[0] + offsetX,
                     currentAfterPosition[1] + offsetY,
-                    currentAfterPosition[2] + 40
+                    currentAfterPosition[2] + 60
                 ];
                 this.view.camera = {
                     position:{
@@ -135,9 +135,16 @@ class FlyGLTFEvent{
                         spatialReference:this.view.spatialReference
                     },
                     heading: heading,
-                    tilt: 50
+                    tilt: 70
                 };
             }
+            bus_1.emit('SendMessage', {
+                action:"CurrentUavInfo",
+                data:{
+                    "message": this.flyGLTFEvent.panelInfo.origin
+                }
+            })
+
 
         }, 1);
 

+ 146 - 141
src/units/threejs/flyGLTF.js

@@ -1,5 +1,7 @@
 import * as THREE from 'three';
 import {GLTFLoader} from "three/addons/loaders/GLTFLoader.js";
+import List from '../../config/routeList.json'
+import texture1 from  "../../assets/lineTexture.png";
 export const FlyGLTFClass = {
     constructor(options){
         this.webgl = options.webgl;
@@ -111,7 +113,7 @@ export const FlyGLTFClass = {
                     { text: '无人机信息: ', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 25 },
                     { text: '无人机名称:'+this.panelInfo.data.name, color: '#fff', font: '15px Arial', offsetX:40, offsetY: 50 },
                     { text: '所属企业: 美团: ', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 70 },
-                    { text: '速度: '+this.panelInfo.data.speed * 3.6+'km/h',color: '#fff',  font: '15px Arial', offsetX:40, offsetY: 90 },
+                    { text: '速度: '+Math.floor(this.panelInfo.data.speed * 3.6)+'km/h',color: '#fff',  font: '15px Arial', offsetX:40, offsetY: 90 },
                     { text: '高度: '+ this.panelInfo.data.altitude+'m', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 110 },
                     { text: '状态: 正常',color: '#fff',font: '15px Arial',  offsetX:40, offsetY: 130 }
                 ];
@@ -132,7 +134,7 @@ export const FlyGLTFClass = {
             panelGeometry.scale(-1,1,1);
             const panelMesh = new THREE.Mesh(panelGeometry, panelMaterial);
             // 将面板附加到无人机模型
-            panelMesh.position.set(0, 2, 0); // 调整面板位置到无人机上方
+            panelMesh.position.set(0, 4, 0); // 调整面板位置到无人机上方
             gltf.scene.add(panelMesh);
 
             // 保存信息面板,以便更新
@@ -190,160 +192,83 @@ export const FlyGLTFClass = {
             let typeInfo = "";
             switch (this.panelInfo.type){
                 case "conflict":
-                    backgroundImage.src = 'public/imgs/warningBackground_conflict.png'; // 替换为你的图片路径
+                    backgroundImage.src = 'public/imgs/基本信息框-红.png'; // 替换为你的图片路径
                     topImage.src = 'public/imgs/warningBackground_time.png'; // 替换为你的图片路径
                     bottomImage.src = 'public/imgs/warningBackground_conflict.png'; // 替换为你的图片路径
-                    typeInfo = "碰撞检测"
+                    typeInfo = "异常"
                     break;
                 case "electricityWarning":
-                    backgroundImage.src = 'public/imgs/warningBackground_lowbattery.png'; // 替换为你的图片路径
+                    backgroundImage.src = 'public/imgs/基本信息框-红.png'; // 替换为你的图片路径
                     typeInfo = "电池电量低"
                     break;
                 case "routeDeviate":
-                    backgroundImage.src = 'public/imgs/warningBackground_outofrange.png'; // 替换为你的图片路径
-                    typeInfo = "偏移航线"
+                    backgroundImage.src = 'public/imgs/基本信息框-红.png'; // 替换为你的图片路径
+                    typeInfo = "异常"
                     break;
                 case "noFlyZone":
-                    backgroundImage.src = 'public/imgs/warningBackground_noFlyZone.png'; // 替换为你的图片路径
-                    typeInfo = "禁飞区"
+                    backgroundImage.src = 'public/imgs/基本信息框-红.png'; // 替换为你的图片路径
+                    typeInfo = "异常"
                     break;
                 case "collision":
-                    backgroundImage.src = 'public/imgs/warningBackground_noFlyZone.png'; // 替换为你的图片路径
+                    backgroundImage.src = 'public/imgs/基本信息框-红.png'; // 替换为你的图片路径
                     typeInfo = "建筑物过近"
                     break;
                 case "clearZone":
-                    backgroundImage.src = 'public/imgs/warningBackground_noFlyZone.png'; // 替换为你的图片路径
+                    backgroundImage.src = 'public/imgs/基本信息框-红.png'; // 替换为你的图片路径
                     typeInfo = "净空区"
                     break;
                 default:
-                    backgroundImage.src = 'public/imgs/serviceBackground.png'; // 替换为你的图片路径
+                    backgroundImage.src = 'public/imgs/基本信息框.png'; // 替换为你的图片路径
                     typeInfo = "正常"
                     break;
             }
             // backgroundImage.src = 'public/imgs/serviceBackground.png'; // 替换为你的图片路径
-            if(this.panelInfo.type == "conflict"){
-                topImage.onload = () => {
-                    bottomImage.onload = () => {
-                        // 确保背景透明
-                        context.clearRect(0, 0, canvas.width, canvas.height); // 清除所有内容,包含黑色
-                        context.fillStyle = 'rgba(0, 0, 0, 0)'; // 设置透明背景
-                        context.fillRect(0, 0, canvas.width, canvas.height); // 填充透明背景
-
-                        // 绘制顶部图片
-                        const topImageHeight = canvas.height * 0.2; // 设定顶部图片高度为 canvas 高度的 20%
-                        context.drawImage(topImage, 0, 0, canvas.width, topImageHeight);
-
-                        // 绘制底部图片
-                        const bottomImageHeight = canvas.height * 0.7; // 设定底部图片高度为 canvas 高度的 20%
-                        context.drawImage(bottomImage, 0, canvas.height - bottomImageHeight, canvas.width, bottomImageHeight);
-
-                        const textInfo = [
-                            { text: '暂停飞行原地等待:' + this.panelInfo.data.waitTime +'秒', color: '#fff', font: 'bold 16px Arial', offsetX:50, offsetY: 20 },
-                            { text: '距预测撞点前方: ', color: '#fff', font: '20px Verdana', offsetX:70, offsetY: 90 },
-                            { text: Math.floor(this.panelInfo.data.danger_path_distance * 1) + '米', color: '#ff0000', font: 'bold 22px Courier New', offsetX:120, offsetY: 120  }
-                        ];
-                        // 绘制文字
-                        textInfo.forEach((line) => {
-                            context.fillStyle = line.color;
-                            context.font = line.font;
-                            context.fillText(line.text, line.offsetX, line.offsetY);
-                        });
-                        // 标记纹理需要更新
-                        texture.needsUpdate = true;
+            if(this.panelInfo.type == "conflict" && this.panelInfo.action == "wait"){
+                    topImage.onload = () => {
+                        bottomImage.onload = () => {
+                            // 确保背景透明
+                            context.clearRect(0, 0, canvas.width, canvas.height); // 清除所有内容,包含黑色
+                            context.fillStyle = 'rgba(0, 0, 0, 0)'; // 设置透明背景
+                            context.fillRect(0, 0, canvas.width, canvas.height); // 填充透明背景
+
+                            // 绘制顶部图片
+                            const topImageHeight = canvas.height * 0.2; // 设定顶部图片高度为 canvas 高度的 20%
+                            context.drawImage(topImage, 0, 0, canvas.width, topImageHeight);
+
+                            // 绘制底部图片
+                            const bottomImageHeight = canvas.height * 0.7; // 设定底部图片高度为 canvas 高度的 20%
+                            context.drawImage(bottomImage, 0, canvas.height - bottomImageHeight, canvas.width, bottomImageHeight);
+
+                            const textInfo = [
+                                { text: '暂停飞行原地等待:' + this.panelInfo.data.waitTime +'秒', color: '#fff', font: 'bold 16px Arial', offsetX:50, offsetY: 20 },
+                                { text: '距预测撞点前方: ', color: '#fff', font: '20px Verdana', offsetX:70, offsetY: 90 },
+                                { text: Math.floor(this.panelInfo.data.danger_path_distance * 1) + '米', color: '#ff0000', font: 'bold 22px Courier New', offsetX:120, offsetY: 120  }
+                            ];
+                            // 绘制文字
+                            textInfo.forEach((line) => {
+                                context.fillStyle = line.color;
+                                context.font = line.font;
+                                context.fillText(line.text, line.offsetX, line.offsetY);
+                            });
+                            // 标记纹理需要更新
+                            texture.needsUpdate = true;
+                        }
                     }
-                }
-            }else if(this.panelInfo.type == "electricityWarning"){
-                backgroundImage.onload = () => {
-                    // 确保背景透明
-                    context.clearRect(0, 0, canvas.width, canvas.height); // 清除所有内容,包含黑色
-                    context.fillStyle = 'rgba(0, 0, 0, 0)'; // 设置透明背景
-                    context.fillRect(0, 0, canvas.width, canvas.height); // 填充透明背景
-                    // 绘制背景图片,填满整个 canvas
-                    context.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
-                    const textInfo = [
-                        { text: '电量预警: ', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 25 },
-                        { text: '低电量警告: ', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 70 },
-                        { text: this.panelInfo.data.speed, color: '#fff', font: '15px Arial', offsetX:40, offsetY: 90 },
-                        { text: this.panelInfo.data.altitude, color: '#fff', font: '15px Arial', offsetX:40, offsetY: 110 },
-                        { text: this.panelInfo.data.altitude, color: '#fff', font: '15px Arial', offsetX:80, offsetY: 110 }
-                    ];
-                    // 绘制文字
-                    textInfo.forEach((line) => {
-                        context.fillStyle = line.color;
-                        context.font = line.font;
-                        context.fillText(line.text, line.offsetX, line.offsetY);
-                    });
-                    // 标记纹理需要更新
-                    texture.needsUpdate = true;
-                };
-            }else if(this.panelInfo.type == "routeDeviate"){
-                backgroundImage.onload = () => {
-                    // 确保背景透明
-                    context.clearRect(0, 0, canvas.width, canvas.height); // 清除所有内容,包含黑色
-                    context.fillStyle = 'rgba(0, 0, 0, 0)'; // 设置透明背景
-                    context.fillRect(0, 0, canvas.width, canvas.height); // 填充透明背景
-                    // 绘制背景图片,填满整个 canvas
-                    context.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
-                    const textInfo = [
-                        { text: '计划偏离: ', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 25 },
-                        { text: '偏离距离: '+this.panelInfo.data.speed * 3.6+'米', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 90 },
-                        { text: '飞行航线偏离: '+ this.panelInfo.data.altitude, color: '#fff', font: '15px Arial', offsetX:40, offsetY: 110 },
-                        { text: '无人机正在偏离计划航线飞行,预警提示请关注', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 130 }
-                    ];
-                    // 绘制文字
-                    textInfo.forEach((line) => {
-                        context.fillStyle = line.color;
-                        context.font = line.font;
-                        context.fillText(line.text, line.offsetX, line.offsetY);
-                    });
-                    // 标记纹理需要更新
-                    texture.needsUpdate = true;
-                };
-            }else if(this.panelInfo.type == "noFlyZone"){
-                backgroundImage.onload = () => {
-                    // 确保背景透明
-                    context.clearRect(0, 0, canvas.width, canvas.height); // 清除所有内容,包含黑色
-                    context.fillStyle = 'rgba(0, 0, 0, 0)'; // 设置透明背景
-                    context.fillRect(0, 0, canvas.width, canvas.height); // 填充透明背景
+                }else if(this.panelInfo.type == "routeDeviate"){
+                //获取当前下标index
+                let index  = this.panelInfo.index * 1 +Math.floor(this.panelInfo.data.distance * 1 / 10) * 5 + 1;
+                let targetPoint = [];
+                this.webgl.toRenderCoordinates(
+                    this.view,
+                    [List.originList[index].mapX, List.originList[index].mapY, List.originList[index].mapZ],
+                    0,
+                    this.view.spatialReference,
+                    targetPoint,
+                    0,
+                    1
+                );
 
-                    // 绘制背景图片,填满整个 canvas
-                    context.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
-                    const textInfo = [
-                        { text: '空域闯入-禁飞区', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 25 },
-                        { text: '已闯入禁飞区,请及时校正航线', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 90 }
-                    ];
-                    // 绘制文字
-                    textInfo.forEach((line) => {
-                        context.fillStyle = line.color;
-                        context.font = line.font;
-                        context.fillText(line.text, line.offsetX, line.offsetY);
-                    });
-                    // 标记纹理需要更新
-                    texture.needsUpdate = true;
-                };
-            }else if(this.panelInfo.type == "collision"){   //需要米数,已返回
-                backgroundImage.onload = () => {
-                    // 确保背景透明
-                    context.clearRect(0, 0, canvas.width, canvas.height); // 清除所有内容,包含黑色
-                    context.fillStyle = 'rgba(0, 0, 0, 0)'; // 设置透明背景
-                    context.fillRect(0, 0, canvas.width, canvas.height); // 填充透明背景
-                    // 绘制背景图片,填满整个 canvas
-                    context.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
-                    const textInfo = [
-                        { text: '建筑避障: ', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 25 },
-                        { text: '当前飞行轨迹距离前方建筑物实时距离: '+this.panelInfo.data.distance+'米', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 90 },
-                        { text: '请注意飞行安全', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 110 },
-                    ];
-                    // 绘制文字
-                    textInfo.forEach((line) => {
-                        context.fillStyle = line.color;
-                        context.font = line.font;
-                        context.fillText(line.text, line.offsetX, line.offsetY);
-                    });
-                    // 标记纹理需要更新
-                    texture.needsUpdate = true;
-                };
-            }else if(this.panelInfo.type == "clearZone"){
+                this.targetPosition = new THREE.Vector3(targetPoint[0], targetPoint[1], targetPoint[2]);
                 backgroundImage.onload = () => {
                     // 确保背景透明
                     context.clearRect(0, 0, canvas.width, canvas.height); // 清除所有内容,包含黑色
@@ -352,9 +277,10 @@ export const FlyGLTFClass = {
                     // 绘制背景图片,填满整个 canvas
                     context.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
                     const textInfo = [
-                        { text: '空域闯入-净空区', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 25 },
-                        { text: '当前飞行轨迹距离前方净空区实时距离: '+this.panelInfo.data.distance+'米', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 90 },
-                        { text: '请注意飞行安全', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 110 },
+                        { text: '计划偏离: ', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 25 },
+                        { text: '偏离距离: '+Math.floor(this.panelInfo.data.distance* 1) +'米', color: '#ff0000', font: 'bold 22px Courier New', offsetX:70, offsetY: 60 },
+                        { text: '无人机正在偏离计划航线飞行', color: '#fff', font: '18px Arial', offsetX:40, offsetY: 90 },
+                        { text: '请及时调整飞行路线', color: '#fff', font: '18px Arial', offsetX:40, offsetY: 120 }
                     ];
                     // 绘制文字
                     textInfo.forEach((line) => {
@@ -371,17 +297,13 @@ export const FlyGLTFClass = {
                     context.clearRect(0, 0, canvas.width, canvas.height); // 清除所有内容,包含黑色
                     context.fillStyle = 'rgba(0, 0, 0, 0)'; // 设置透明背景
                     context.fillRect(0, 0, canvas.width, canvas.height); // 填充透明背景
-
                     // 绘制背景图片,填满整个 canvas
                     context.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
-
-
-
                     const textInfo = [
                         { text: '无人机信息: ', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 25 },
                         { text: '无人机名称:'+this.panelInfo.data.name, color: '#fff', font: '15px Arial', offsetX:40, offsetY: 50 },
                         { text: '所属企业: 美团: ', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 70 },
-                        { text: '速度: '+this.panelInfo.data.speed * 3.6+'km/h', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 90 },
+                        { text: '速度: '+Math.floor(this.panelInfo.data.speed * 3.6)+'km/h', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 90 },
                         { text: '高度: '+ this.panelInfo.data.altitude+'m', color: '#fff', font: '15px Arial', offsetX:40, offsetY: 110 },
                         { text: `状态: ${typeInfo}`, color: '#fff', font: '15px Arial', offsetX:40, offsetY: 130 }
                     ];
@@ -401,6 +323,21 @@ export const FlyGLTFClass = {
     },
 
 
+    getClosestPointOnCurve(position, curve) {
+        let closestPoint = null;
+        let minDistance = Infinity;
+        const points = curve.getPoints(100);
+        points.forEach(point => {
+            const distance = position.distanceTo(point);
+            if (distance < minDistance) {
+                minDistance = distance;
+                closestPoint = point;
+            }
+        });
+        return closestPoint;
+    },
+
+
     setPathCurve(path,duration){
         this.path = path;
         this.pathProgress = 0;   // 重置路径进度
@@ -532,6 +469,74 @@ export const FlyGLTFClass = {
         //this.targetObject.rotation.x = -Math.PI/2;
         this.targetObject.rotation.y = 0;
         this.targetObject.rotation.z = -Math.PI/2;
+
+        // if (this.recommandPathLine) {
+        //     this.scene.remove(this.recommandPathLine);
+        // }
+        // if(this.panelInfo.type == "routeDeviate"){
+        //     this.updateRecommandPath();
+        // }
+
+    },
+
+    updateRecommandPath() {
+        debugger;
+        // 如果已存在曲线或管道,将其从场景中移除
+
+        let startPoint = this.pathCurve.getPointAt(this.pathProgress);
+        let endPoint = this.targetPosition;
+
+        // 创建两个点之间的中间控制点
+        const midPoint1 = new THREE.Vector3(
+            (2 * startPoint.x + endPoint.x) / 3,
+            (2 * startPoint.y + endPoint.y) / 3 + 5, // 可调整中间点的高度
+            (2 * startPoint.z + endPoint.z) / 3
+        );
+        const midPoint2 = new THREE.Vector3(
+            (startPoint.x + 2 * endPoint.x) / 3,
+            (startPoint.y + 2 * endPoint.y) / 3 + 5, // 可调整中间点的高度
+            (startPoint.z + 2 * endPoint.z) / 3
+        );
+
+        // 使用 CatmullRomCurve3 创建一条平滑曲线
+        const curve = new THREE.CatmullRomCurve3([
+            startPoint,
+            midPoint1,
+            midPoint2,
+            endPoint
+        ]);
+
+
+
+        let tubeGeometry = new THREE.TubeGeometry(curve, 20, 100, 24, false);
+        var textureLoader = new THREE.TextureLoader();
+        //设置纹理贴图
+        this.map = textureLoader.load(texture1);
+
+        this.map.wrapS = THREE.RepeatWrapping;
+        this.map.wrapT = THREE.RepeatWrapping;
+        this.map.repeat.set(20, 10);
+
+        const material = new THREE.MeshBasicMaterial({
+            color: 0xaaaaaa,
+            // map: this.map,
+            transparent: true,
+            depthWrite: false,
+            // side: 200
+            side: THREE.DoubleSide,
+            wireframeLinewidth: 20,
+        });
+
+
+        const tubeMesh = new THREE.Mesh(tubeGeometry, material);
+
+        // 将新的管道添加到场景
+        this.scene.add(tubeMesh);
+
+        // 保存当前管道对象,以便下次更新时移除
+        this.recommandPathLine = tubeMesh;
+
+        return curve; // 返回生成的曲线对象
     },