| | |
| | | <div class="chooseModel"> |
| | | <div class="fontJust">设备列表</div> |
| | | <el-button @click="addDevice"> 新增</el-button> |
| | | <el-button @click="lineSet"> 航线设置</el-button> |
| | | <el-table |
| | | :data="tableData" |
| | | max-height = '180' |
| | | :row-key="getRowKeys" |
| | | style="width: 100%"> |
| | | <el-table-column |
| | | prop="deviceName" |
| | |
| | | <div class="fontJust">巡检点目录</div> |
| | | <el-tree |
| | | class="filter-tree" |
| | | node-key="id" |
| | | :data="treeData" |
| | | :props="defaultProps" |
| | | default-expand-all |
| | |
| | | </el-dialog> |
| | | <chooseDeviceDialog v-if="showDevice" @cancel ='cancel' @dealChooseArr="dealChooseArr" ></chooseDeviceDialog> |
| | | <chooseModelDialog v-if="showModel" @cancelModel ='cancelModel' @receiveModel="receiveModel" :deviceId="deviceId"></chooseModelDialog> |
| | | <el-drawer |
| | | title="航线设置" |
| | | :visible.sync="drawer" |
| | | direction="rtl"> |
| | | <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> |
| | | <el-form-item label="起飞爬升" prop="region"> |
| | | <el-select v-model="ruleForm.region" placeholder="请选择起飞爬升"> |
| | | <el-option label="垂直" value="垂直"></el-option> |
| | | <el-option label="倾斜" value="倾斜"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="全局航线速度" prop="region"> |
| | | <div class="speed-control"> |
| | | <el-input-number |
| | | v-model="ruleForm.speed" |
| | | :min="0" |
| | | :max="50" |
| | | :step="1" |
| | | controls-position="both" |
| | | @change="handleChange" |
| | | /> |
| | | <span class="unit">m/s</span> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="起飞速度" prop="fly"> |
| | | <div class="speed-control"> |
| | | <el-input-number |
| | | v-model="ruleForm.flySpeed" |
| | | :min="0" |
| | | :max="50" |
| | | :step="1" |
| | | controls-position="both" |
| | | @change="handleChange" |
| | | /> |
| | | <span class="unit">m/s</span> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="航点类型" prop="region1"> |
| | | <el-select v-model="ruleForm.region1" placeholder="请选择航点类型"> |
| | | <el-option label="协调转弯,不过点,提前转弯" value="协调转弯,不过点,提前转弯"></el-option> |
| | | <el-option label="直线飞行,飞行器到点停" value="直线飞行,飞行器到点停"></el-option> |
| | | <el-option label="平滑过点,提前转弯" value="平滑过点,提前转弯"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="飞行器偏航角模式" prop="region2"> |
| | | <el-select v-model="ruleForm.region2" placeholder="请选择飞行器偏航角模式"> |
| | | <el-option label="沿航线方向" value="沿航线方向"></el-option> |
| | | <el-option label="手动控制" value="手动控制"></el-option> |
| | | <el-option label="锁定当前偏航角" value="锁定当前偏航角"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="航点间云台俯仰角控制模式" prop="region3"> |
| | | <el-select v-model="ruleForm.region3" placeholder="请选择航点间云台俯仰角控制模式"> |
| | | <el-option label="手动控制" value="手动控制"></el-option> |
| | | <el-option label="依照每个航点设置" value="依照每个航点设置"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="完成动作" prop="region4"> |
| | | <el-select v-model="ruleForm.region4" placeholder="请选择完成动作"> |
| | | <el-option label="自动返航" value="自动返航"></el-option> |
| | | <el-option label="返回航线起始点悬停" value="返回航线起始点悬停"></el-option> |
| | | <el-option label="退出航线模式" value="退出航线模式"></el-option> |
| | | <el-option label="原地降落" value="原地降落"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="submitForm('ruleForm')">保存</el-button> |
| | | <el-button @click="resetForm('ruleForm')">取消</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-drawer> |
| | | </div> |
| | | </template> |
| | | <script> |
| | |
| | | import chooseDeviceDialog from './chooseDeviceDialog.vue'; |
| | | import chooseModelDialog from './chooseModelDialog.vue'; |
| | | import { obtainRealData ,buildKmz} from "@/api/system/template" |
| | | |
| | | let rotationAngle = Cesium.Math.toRadians(0) |
| | | let lastConnectPolyline |
| | | export default{ |
| | | components: { |
| | | CesiumMap, |
| | |
| | | showDevice:false, |
| | | multipleSelection: [], |
| | | showModel:false, |
| | | deviceId:null |
| | | deviceId:null, |
| | | drawer:false, |
| | | ruleForm:{ |
| | | speed:14, |
| | | flySpeed:15 |
| | | }, |
| | | |
| | | } |
| | | }, |
| | | methods:{ |
| | |
| | | this.$emit('close') |
| | | }, |
| | | flyToLocal(row){ |
| | | console.log(row) |
| | | const position = Cesium.Cartesian3.fromDegrees(row.longitude,row.latitude, row.deviceHeight); |
| | | |
| | | // rotationAngle = Cesium.Math.toRadians(row.face) || Cesium.Math.toRadians(0) |
| | | rotationAngle = Cesium.Math.toRadians(row.face) || Cesium.Math.toRadians(0) |
| | | // 设置模型方向(可选) |
| | | const heading = Cesium.Math.toRadians(row.face); // 朝东南方向 |
| | | const pitch = 0; |
| | |
| | | })); |
| | | }, |
| | | deleteData(row){ |
| | | console.log(row) |
| | | // 找到 id 为 "1" 的元素索引 |
| | | const index = this.tableData.findIndex(item => item.id === row.id); |
| | | // 如果找到了,删除该元素 |
| | | if (index !== -1) { |
| | | this.tableData.splice(index, 1); |
| | | } |
| | | const dealTreeData = this.dealTee() |
| | | this.treeData = dealTreeData |
| | | const indexTree = this.treeData.findIndex(item => item.id === row.id); |
| | | // 如果找到了,删除该元素 |
| | | if (index !== -1) { |
| | | this.treeData.splice(indexTree, 1); |
| | | } |
| | | if(this.treeData?.length >=2 && this.treeData[0]?.children?.length > 0 && this.treeData[1]?.children?.length > 0 ) { |
| | | this.dealAddHeight() |
| | | } else if(this.treeData?.length ==1) { |
| | | this.treeData.map((device,index) => { |
| | | // 确保设备有children数组 |
| | | if(index == 0) { |
| | | //第一个数据 |
| | | if (device.children && Array.isArray(device.children) && device.children.length > 0) { |
| | | // 获取最后一个空中点 |
| | | const lastChild = device.children[device.children.length - 1]; |
| | | const firstChild = device.children[0]; |
| | | // 深拷贝最后一个元素(包括嵌套的children) |
| | | const newChildJson = JSON.parse(JSON.stringify(lastChild)); |
| | | // 深拷贝最一一个元素(包括嵌套的children) |
| | | const firstChildJson = JSON.parse(JSON.stringify(firstChild)); |
| | | |
| | | if(newChildJson && newChildJson.label.includes('加高')){ |
| | | device.children?.pop(newChild); |
| | | }else if(firstChildJson && firstChildJson.label.includes('加高')) { |
| | | device.children?.shift(firstChildJson); |
| | | } |
| | | // 添加到children数组末尾 |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | const entitiesToRemove = []; |
| | | viewer.entities.values.forEach(entity => { |
| | | if (entity.id && entity.id.includes(row.id)) { |
| | | entitiesToRemove.push(entity.id); |
| | | } |
| | | }); |
| | | entitiesToRemove.forEach(id => { |
| | | viewer.entities.removeById(id); |
| | | }); |
| | | this.drawConnectionsWithLabels(this.treeData) |
| | | // console.log(this.tableData) |
| | | console.log(this.treeData) |
| | | // const dealTreeData = this.dealTee() |
| | | // console.log(dealTreeData) |
| | | // this.treeData = dealTreeData |
| | | // this.drawConnectionsWithLabels(this.treeData) |
| | | }, |
| | | chooseModel(row){ |
| | | this.deviceId = row.id |
| | |
| | | }, |
| | | receiveModel(obj){ |
| | | //deal逻辑 |
| | | console.log(obj) |
| | | let flightTemplateId =obj.modelObj.id |
| | | let deviceId = obj.deviceId |
| | | this.dealTableTemplate(obj) |
| | |
| | | let treeDealData = this.transformFlightData(res.data?.coordinateSystemVoS || []) |
| | | console.log(treeDealData) |
| | | this.dealTreeMerge(obj,treeDealData) |
| | | // const aaa = this.rotateAllPoints(this.treeData || [],res.data.longitude,res.data.latitude,res.data.height) |
| | | this.drawConnectionsWithLabels(this.treeData) |
| | | |
| | | this.rotateAllPoints(this.treeData || [],res.data.longitude,res.data.latitude,res.data.height) |
| | | console.log(this.treeData) |
| | | if(this.treeData?.length >=2 && this.treeData[0]?.children?.length > 0 && this.treeData[1]?.children?.length > 0 ) { |
| | | this.dealAddHeight() |
| | | } |
| | | console.log(this.treeData) |
| | | this.drawConnectionsWithLabels(this.treeData) |
| | | }) |
| | | // this.dealTreeMerge(obj) |
| | | }, |
| | | dealAddHeight(){ |
| | | let currentLength = this.treeData.filter(item=>item.children)?.length || 0 |
| | | console.log(this.treeData) |
| | | console.log(currentLength) |
| | | this.treeData.map((device,index) => { |
| | | // 确保设备有children数组 |
| | | if(index == 0) { |
| | | //第一个数据 |
| | | if (device.children && Array.isArray(device.children) && device.children.length > 0) { |
| | | // 获取最后一个空中点 |
| | | const lastChild = device.children[device.children.length - 1]; |
| | | // 深拷贝最后一个元素(包括嵌套的children) |
| | | const newChild = JSON.parse(JSON.stringify(lastChild)); |
| | | if(newChild.label.includes('加高')) { |
| | | |
| | | }else { |
| | | newChild.label = newChild.label + '-加高' |
| | | // 高度增加20 |
| | | // newChild.height += 20; |
| | | //塔高 - 高度 + 往上飞多少米 |
| | | newChild.height += (device.ardTowerModel?.modelHeight - newChild.height + 20) ; |
| | | console.log('push11111111111111') |
| | | // 添加到children数组末尾 |
| | | device.children.push(newChild); |
| | | } |
| | | } |
| | | } |
| | | else if(index == currentLength -1) { |
| | | if (device.children && Array.isArray(device.children) && device.children.length > 0) { |
| | | // 获取最后一个空中点 |
| | | const lastChild = device.children[0]; |
| | | // 深拷贝最一一个元素(包括嵌套的children) |
| | | const newChild = JSON.parse(JSON.stringify(lastChild)); |
| | | if(newChild.label.includes('加高')) { |
| | | }else { |
| | | newChild.label = newChild.label + '-加高第一个点' |
| | | newChild.height += (device.ardTowerModel?.modelHeight - newChild.height + 20) ; |
| | | // 添加到children数组末尾 |
| | | device.children.unshift(newChild); |
| | | } |
| | | |
| | | } |
| | | } else { |
| | | if (device.children && Array.isArray(device.children) && device.children.length > 0) { |
| | | // 获取最后一个空中点 |
| | | const firstChild = device.children[0]; |
| | | const lastChild = device.children[device.children.length - 1]; |
| | | // 深拷贝最一一个元素(包括嵌套的children) |
| | | const newFirstChild = JSON.parse(JSON.stringify(firstChild)); |
| | | const newLastChildChild = JSON.parse(JSON.stringify(lastChild)); |
| | | //高度增加20 |
| | | if(newFirstChild.label.includes('加高')) { |
| | | }else { |
| | | newFirstChild.label = newFirstChild.label + '-加高' |
| | | newFirstChild.height += (device.ardTowerModel?.modelHeight - newFirstChild.height + 20) ; |
| | | device.children.unshift(firstChild); |
| | | } |
| | | if(newLastChildChild.label.includes('加高')) { |
| | | }else { |
| | | newLastChildChild.label = newLastChildChild.label + '-加高' |
| | | newLastChildChild.height += (device.ardTowerModel?.modelHeight - newLastChildChild.height + 20) ; |
| | | device.children.push(newLastChildChild); |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | //返回数据转换树结构 |
| | | transformFlightData(data) { |
| | | console.log(data) |
| | | const result = []; |
| | | |
| | | data.forEach(item => { |
| | |
| | | } |
| | | }); |
| | | }, |
| | | generateId() { |
| | | return 'id_' + Math.random().toString(36).substring(2, 10); |
| | | }, |
| | | drawConnectionsWithLabels(devices) { |
| | | const airPoints = []; |
| | | if(lastConnectPolyline) { |
| | | viewer.entities.remove(lastConnectPolyline) |
| | | lastConnectPolyline = null |
| | | } |
| | | // 直接操作EntityCollection(推荐) |
| | | const entitiesToRemove = []; |
| | | viewer.entities.values.forEach(entity => { |
| | | if (entity.id && entity.id.includes(this.deviceId)) { |
| | | entitiesToRemove.push(entity.id); |
| | | } |
| | | }); |
| | | |
| | | entitiesToRemove.forEach(id => { |
| | | viewer.entities.removeById(id); |
| | | }); |
| | | const airPoints = []; |
| | | console.log(devices) |
| | | devices.forEach(device => { |
| | | if (!Array.isArray(device.children)) return; |
| | | |
| | | device.children.forEach(airPoint => { |
| | | // 空中点位置 |
| | | const airPos = Cesium.Cartesian3.fromDegrees( |
| | |
| | | // ✅ 添加空中点实体和 label |
| | | viewer.entities.add({ |
| | | position: airPos, |
| | | id:device.id +'airpoint' + this.generateId(), |
| | | point: { |
| | | pixelSize: 6, |
| | | color: Cesium.Color.YELLOW |
| | |
| | | |
| | | // ✅ 添加地面点实体和 label |
| | | viewer.entities.add({ |
| | | id:device.id +'groundpoint' + this.generateId(), |
| | | position: groundPos, |
| | | point: { |
| | | pixelSize: 6, |
| | |
| | | |
| | | // ✅ 蓝色虚线连接:空中点 ➜ 地面点 |
| | | viewer.entities.add({ |
| | | id:device.id +'polyline' + this.generateId(), |
| | | polyline: { |
| | | positions: [airPos, groundPos], |
| | | width: 2, |
| | |
| | | } |
| | | }); |
| | | }); |
| | | |
| | | console.log(airPoints) |
| | | // ✅ 黄色实线连接所有空中点 |
| | | if (airPoints.length > 1) { |
| | | viewer.entities.add({ |
| | | lastConnectPolyline = viewer.entities.add({ |
| | | polyline: { |
| | | positions: airPoints, |
| | | width: 3, |
| | |
| | | }, |
| | | rotateAllPoints(dataList,towerLongitude,towerLatitude,towerhHight) { |
| | | return dataList.map(item => { |
| | | console.log(item) |
| | | console.log(towerLongitude) |
| | | console.log(towerLatitude) |
| | | console.log(towerhHight) |
| | | const groundPoint = Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, item.height); |
| | | const towerPoint = Cesium.Cartesian3.fromDegrees(towerLongitude, towerLatitude, towerhHight); |
| | | let rotationAngle = Cesium.Math.toRadians(135) |
| | | // 旋转地面点本身(会变,但绕自身旋转不会移动) |
| | | const newGroundPoint = this.rotateAroundPoint( groundPoint,towerPoint, rotationAngle); |
| | | const newGroundCarto = Cesium.Cartographic.fromCartesian(newGroundPoint); |
| | | const newGround = { |
| | | ...item, |
| | | longitude: Cesium.Math.toDegrees(newGroundCarto.longitude), |
| | | latitude: Cesium.Math.toDegrees(newGroundCarto.latitude), |
| | | height: newGroundCarto.height |
| | | }; |
| | | console.log(newGround) |
| | | // 处理子空中点 |
| | | newGround.children = item.children.map(child => { |
| | | const airPoint = Cesium.Cartesian3.fromDegrees(child.longitude, child.latitude, child.height); |
| | | const rotatedAirPoint = this.rotateAroundPoint( airPoint,towerPoint, rotationAngle); |
| | | const rotatedAirCarto = Cesium.Cartographic.fromCartesian(rotatedAirPoint); |
| | | |
| | | return { |
| | | ...child, |
| | | longitude: Cesium.Math.toDegrees(rotatedAirCarto.longitude), |
| | | latitude: Cesium.Math.toDegrees(rotatedAirCarto.latitude), |
| | | height: rotatedAirCarto.height |
| | | if(!item.isDeal) { |
| | | const towerPoint = Cesium.Cartesian3.fromDegrees(towerLongitude, towerLatitude, towerhHight); |
| | | const newGround = { |
| | | ...item, |
| | | }; |
| | | }); |
| | | |
| | | return newGround; |
| | | if(item.id == this.deviceId ){ |
| | | item.isDeal = true |
| | | } |
| | | // 处理子空中点 |
| | | newGround.children = item.children?.map(child => { |
| | | const airPoint = Cesium.Cartesian3.fromDegrees(child.longitude, child.latitude, child.height); |
| | | const rotatedAirPoint = this.rotateAroundPoint( airPoint,towerPoint, rotationAngle); |
| | | const rotatedAirCarto = Cesium.Cartographic.fromCartesian(rotatedAirPoint); |
| | | child.longitude = Cesium.Math.toDegrees(rotatedAirCarto.longitude) |
| | | child.latitude = Cesium.Math.toDegrees(rotatedAirCarto.latitude) |
| | | child.height = rotatedAirCarto.height |
| | | child.children = child.children?.map(sonChild => { |
| | | const groundPoint = Cesium.Cartesian3.fromDegrees(sonChild.longitude, sonChild.latitude, sonChild.height); |
| | | const newGroundPoint = this.rotateAroundPoint( groundPoint,towerPoint, rotationAngle); |
| | | const newGroundCarto = Cesium.Cartographic.fromCartesian(newGroundPoint); |
| | | return { |
| | | ...sonChild, |
| | | longitude: Cesium.Math.toDegrees(newGroundCarto.longitude), |
| | | latitude: Cesium.Math.toDegrees(newGroundCarto.latitude), |
| | | height: newGroundCarto.height |
| | | }; |
| | | }); |
| | | }); |
| | | console.log(newGround.children) |
| | | return newGround; |
| | | } |
| | | |
| | | }); |
| | | }, |
| | | // 计算点A绕点B逆时针旋转指定角度后的新位置 |
| | | // 空中点或者地面点笛卡尔坐标 塔的笛卡尔坐标 塔的朝向值 |
| | | rotateAroundPoint(startPoint,pivotPoint,rotationAngle) { |
| | | console.log(rotationAngle) |
| | | // 创建一个从B点到本地坐标系的转换矩阵(东方向为X轴,北方向为Y轴,垂直方向为Z轴) |
| | | const transformationMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(pivotPoint); |
| | | // 获取世界坐标系到本地坐标系的转换矩阵 |
| | |
| | | const rotatedZ = localStartPoint.z; // Z轴坐标保持不变 |
| | | // 将旋转后的局部坐标转换回世界坐标系 |
| | | return Cesium.Matrix4.multiplyByPoint(transformationMatrix, new Cesium.Cartesian3(rotatedX, rotatedY, rotatedZ), new Cesium.Cartesian3()); |
| | | }, |
| | | getRowKeys(row){ |
| | | console.log(row) |
| | | return row.id +this.generateId() |
| | | }, |
| | | submit(){ |
| | | console.log(this.treeData) |
| | |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | lineSet(){ |
| | | this.drawer =true |
| | | } |
| | | } |
| | | } |