航线管理页面UI和操作逻辑实现

devzpx
zhaipx 2 months ago
parent 15fe7ab26b
commit 30c586d9c0

@ -1,14 +1,14 @@
import {DataSource} from "cesium";
import {Cartesian3, DataSource} from "cesium";
import * as Cesium from 'cesium'
export default class RouteManageViewer {
constructor(viewer, isClose, height) {
constructor(viewer, isClose) {
this.viewer = viewer
this.scene = viewer.scene
this.routeParams = {
isClose: isClose,
height: height,
height: 0,
}
this.positions = []
this.temPositions = [] // 鼠标移动时产生的临时点
@ -16,8 +16,66 @@ export default class RouteManageViewer {
this.lineEntity = undefined // 折线元素
this.lineEntitys = [] // 折线元素数组,每完成一次航线绘制,将折线元素加入此数组
}
// -------------------------------------------//
/**
* 显示航线
* @param line Airline
*/
addAirLine(line){
let res = this.viewer.entities.getById( "航线" + line.unicode)
if(res!==undefined){
return res
}
let degreesArr = []
for (let i = 0; i < line.points.length; i++) {
let coord = new Cartesian3.fromDegrees(line.points[i].lon,line.points[i].lat,line.points[i].alt)
degreesArr.push(coord)
}
if(line.isClose)
degreesArr.push(new Cartesian3.fromDegrees(line.points[0].lon,line.points[0].lat,line.points[0].alt))
let airlineEntity = new Cesium.Entity({
name: line.name,
id: "航线" + line.unicode,
polyline: {
positions: degreesArr,
width: 3,
material: Cesium.Color.ORANGE,
clampToGround: false,
}
})
this.viewer.entities.add(airlineEntity)
degreesArr.forEach((pt,index)=>{
let vertexEntity = new Cesium.Entity({
id: line.unicode + "-航点" + index,
position: pt,
point: {
color: Cesium.Color.WHITE,
pixelSize: 6,
outlineColor: Cesium.Color.RED,
outlineWidth: 2,
disableDepthTestDistance:99000000,
// heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,
}
});
this.viewer.entities.add(vertexEntity)
})
return airlineEntity
}
/**
* 删除航线
* @param line Airline
*/
removeRoute(line){
this.viewer.entities.removeById( "航线" + line.unicode)
line.points.forEach((_,index)=>{
this.viewer.entities.removeById(line.unicode + "-航点" + index)
})
}
// -----------------绘制航线相关功能--------------------------//
//开始绘制
start() {
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)

@ -0,0 +1,13 @@
import {Airline, AirlinePoint} from "@/types/entityoptions.ts";
export function newAirlinePt() {
let pt: AirlinePoint = {alt: undefined, ch1: 0, ch2: 0, lat: undefined, lon: undefined, nPt: undefined, speed: 0}
return pt
}
export function newAirline() {
let flyLine: Airline = {
PtNum: undefined, code: undefined, isClose: false, name: "", points: [], totalDistance: undefined
}
return flyLine
}

@ -322,6 +322,11 @@ export default class MeasureViewer {
* @param line Airline
*/
showAirLine(line){
let res = this.viewer.entities.getById( "航线" + line.code + "-" +line.name,)
if(res!==undefined){
return res
}
let degreesArr = []
for (let i = 0; i < line.points.length; i++) {
let coord = new Cartesian3.fromDegrees(line.points[i].lon,line.points[i].lat,line.points[i].alt)
@ -329,10 +334,10 @@ export default class MeasureViewer {
}
if(line.isClose)
degreesArr.push(new Cartesian3.fromDegrees(line.points[0].lon,line.points[0].lat,line.points[0].alt))
let airlineEntity = new Cesium.Entity({
name: line.name,
id: line.name + line.totalDistance,
id: "航线" + line.code + "-" +line.name,
polyline: {
positions: degreesArr,
width: 3,
@ -341,21 +346,24 @@ export default class MeasureViewer {
}
})
this.viewer.entities.add(airlineEntity)
for (let pt in degreesArr) {
degreesArr.forEach((pt,index)=>{
let vertexEntity = new Cesium.Entity({
// id: "航点" + ,
id: line.code + "-航点" + index,
position: pt,
point: {
color: Cesium.Color.FUCHSIA,
pixelSize: 6,
outlineColor: Cesium.Color.RED,
outlineWidth: 2,
disableDepthTestDistance:99000000,
// heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,
}
});
this.viewer.entities.add(vertexEntity)
}
})
return airlineEntity
}
addAirplaneEntity(modelPath,StrUavTypeID){
this.viewer.scene.globe.depthTestAgainstTerrain = true;

@ -1,27 +0,0 @@
import axios from "axios";
function login(username, password)
{
return axios({
method: "POST",
url: "/onlinetest/htfp/cac/logIn",
headers: {"Content-Type": "application/json"},
data: {
username: username,
password: password,
forceLogOutOtherDeviceAccount: false
}
})
}
function requestAirline(uavID){
return axios({
method: "POST",
url: "/onlinetest/htfp/cac/queryUavBundledRouteList",
headers: [{"Content-Type": "application/json"},{"X-Authorization-With": sessionStorage.getItem("token")}],
data: {
uavId: uavID,
}
})
}
export {login, requestAirline}

@ -0,0 +1,38 @@
import {Airline, getUnicode} from "@/types/entityoptions.ts";
// let route: AirlinePoint = {alt: 0, ch1: 0, ch2: 0, lat: 0, lon: 0, nPt: 0, speed: 0}
const route: Airline = {
PtNum: 5, code: 1, isClose: false, name: "测试航线1", totalDistance: 12323,
unicode:getUnicode(),
points: [
{ lon: 120.23234234, lat: 30.232323,alt: 550, ch1: 0, ch2: 3, nPt: 1, speed: 0},
{ lon: 120.34233234, lat: 30.232312,alt: 550, ch1: 0, ch2: 3, nPt: 2, speed: 0},
{ lon: 120.23234324, lat: 30.21223,alt: 550, ch1: 0, ch2: 3, nPt: 3, speed: 0},
{ lon: 120.23289964, lat: 30.256323,alt: 550, ch1: 0, ch2: 3, nPt: 4, speed: 0},
{ lon: 120.53564234, lat: 30.132323,alt: 550, ch1: 0, ch2: 1, nPt: 5, speed: 0},
],
}
const route2: Airline = {
PtNum: 4, code: 2, isClose: true, name: "测试航线2", totalDistance: 2341234,
unicode:getUnicode(),
points: [
{ lon: 120.23234234, lat: 30.232323,alt: 550, ch1: 0, ch2: 3, nPt: 0, speed: 0},
{ lon: 120.34233234, lat: 30.232312,alt: 550, ch1: 0, ch2: 3, nPt: 1, speed: 0},
{ lon: 120.23234324, lat: 30.21223,alt: 550, ch1: 0, ch2: 3, nPt: 2, speed: 0},
{ lon: 120.53564234, lat: 30.132323,alt: 550, ch1: 2, ch2: 1, nPt: 4, speed: 0},
],
}
const route3: Airline = {
PtNum: 7, code: 3, isClose: false, name: "测试航线3", totalDistance: 3234134,
unicode:getUnicode(),
points: [
{ lon: 123.23234234, lat: 30.232323,alt: 550, ch1: 0, ch2: 3, nPt: 0, speed: 0},
{ lon: 123.34233234, lat: 30.232312,alt: 550, ch1: 0, ch2: 3, nPt: 1, speed: 0},
{ lon: 123.23234324, lat: 30.21223,alt: 550, ch1: 0, ch2: 3, nPt: 2, speed: 0},
{ lon: 123.23289964, lat: 30.256323,alt: 550, ch1: 0, ch2: 3, nPt: 3, speed: 0},
{ lon: 123.53564234, lat: 30.132323,alt: 550, ch1: 0, ch2: 1, nPt: 4, speed: 0},
{ lon: 123.53564234, lat: 30.132323,alt: 550, ch1: 0, ch2: 1, nPt: 4, speed: 0},
{ lon: 123.53564234, lat: 30.132323,alt: 550, ch1: 0, ch2: 1, nPt: 4, speed: 0},
],
}
export {route,route2,route3}

@ -1,54 +0,0 @@
import { defineAsyncComponent, render, createVNode } from "vue";
export class routeDialog {
constructor() {
this.component = defineAsyncComponent(
() => import("@/components/RouteOptions.vue"));
this.vnode = null;
this.node = null;
this.props = {
width: "40%",
height: "auto",
};
}
installRouteDialog() {
if (!this.vnode) {
const dialog = createVNode(this.component, this.props);
const container = document.createElement('div');
render(dialog, container);
this.vnode = dialog;
this.node = container.childNodes[0];
document.body.appendChild(this.node);
}
}
/**
*
* @returns {Promise<string>}
* @param points 经纬度坐标点数组
*/
show(points) {
// 发送信号,显示窗口
const event = new CustomEvent('route-dialog-show', { detail:
{ show: true, pts: points }
});
document.dispatchEvent(event);
return new Promise((resolve,reject) => {
document.addEventListener('route-dialog-confirm', event => {
if(event.detail==='cancel'){
reject('cancel')
}else{
resolve(event.detail);
}
});
})
}
}
const aDialog = new routeDialog();
/**
* 展示一个阻塞式对话框
* @returns {Promise<string>}
* @param point 经纬度坐标点数组
*/
export async function showRouteDialog(point) {
return aDialog.show(point);
}

@ -0,0 +1,39 @@
import axios from "axios";
type WeatherResponse = {
success: boolean,
code: number,
message: number,
data: any //响应数据
}
//查询未来24小时指定位置的地面气象变量信息
function query_surface_forecast(lat:number, lon: number)
{
return axios({
method: "POST",
url: "/onlinetest/htfp/weather/v1surface/querySurfaceForecast",
headers: {"Content-Type": "application/json"},
data: {
latitude: lat,
longitude: lon,
}
})
}
//查询未来24小时指定位置和高度的高空气象变量信息
function query_upper_forecast(lat:number, lon: number, level:number){
return axios({
method: "POST",
url: "/onlinetest/htfp/weather/v1upper/queryUpperForecast",
headers: {"Content-Type": "application/json"},
data: {
latitude: lat,
longitude:lon,
level: level
}
})
}
export {query_upper_forecast, query_surface_forecast}

@ -72,7 +72,7 @@ function lonlatClick() {
position: absolute;
bottom: 1px;
left: 0;
width: 100vw;
width: 100%;
height: 1.7rem;
background-color: rgba(47, 53, 60, 0.8);
color: #fff;

@ -8,7 +8,8 @@ import {defineEmits, ref} from "vue";
let emit = defineEmits(['routeDraw','cancelDraw'])
let routeParams = ref({
code: 0,
name: '',
code: 0,
isClose: false,
height: 0,
routePts: []
@ -26,6 +27,9 @@ let routeCode = [
},{
label: "任务航线4",
value: 4,
},{
label: "任务航线5",
value: 5,
}
]
const done = ()=>{
@ -59,6 +63,9 @@ const cancel = ()=>{
</n-switch>
</n-form-item>
<n-form-item label="航线名称">
<n-input v-model:value="routeParams.name" placeholder="输入名称"></n-input>
</n-form-item>
<n-form-item label="航线类型">
<n-select v-model:value="routeParams.code" :options="routeCode" />
</n-form-item>
<n-form-item label="航线高度/m">

@ -1,11 +1,370 @@
<script setup lang="ts">
import SceneViewer from "@/components/SceneViewer.vue";
import BottomBar from "@/components/BottomBar.vue";
import {ArrowBackOutline,ArrowForwardOutline,Save,Add, SaveOutline} from "@vicons/ionicons5";
import {nextTick, onMounted, ref} from "vue";
import {darkTheme, useMessage} from "naive-ui";
import {route,route2,route3} from "@/assets/js/testData.ts";
import {useRouteStore} from "@/store/RouteStore.ts";
import {Airline} from "@/types/entityoptions.ts";
import {newAirline, newAirlinePt} from "@/assets/js/TypeInitial.ts";
import * as echarts from "echarts";
import {EChartsType} from "echarts";
import {transLonlat2Car3} from "@/utils/map/geocomputation.ts";
import {drawEcharts_RouteDetection, profileAnalyse} from "@/utils/map/SpatialAnalysis.ts";
import RouteManageViewer from "@/assets/js/RouteManageViewer.js";
let myChart: EChartsType = undefined
let routeStore = useRouteStore()
let selectedRouteCode = ref(null)
let showPtList = ref(true)
let selectedRoute = ref<Airline>(newAirline())
let routesInstore = ref<{ value: string|number; label: string}[]>(null)
let routeViewer = null
let routePtNumber = ref(1)
let uiMsg = useMessage()
let PtOptions = [
{label: '删除航点', key: 'deletePt'},
{label: '插入航点', key: 'insertPt'},
]
let routeCode = [
{
label: "任务航线1",
value: 1,
},{
label: "任务航线2",
value: 2,
},{
label: "任务航线3",
value: 3,
},{
label: "任务航线4",
value: 4,
},{
label: "任务航线5",
value: 5,
}
]
onMounted(()=>{
myChart = echarts.init(document.getElementById('echarts-profile'),'dark')
routeStore.addRoute(route)
routeStore.addRoute(route2)
routeStore.addRoute(route3)
routesInstore.value = routeStore.flyRoute.map((route)=> {
return {
value: route.unicode,
label: route.name
}
})
})
// 线
function checkRoute(key:number|string){
new Promise((resolve,reject)=>{
selectedRoute.value = routeStore.flyRoute.filter(element => element.unicode === String(key))[0]
if(selectedRoute.value == null) reject('未找到航线')
routeViewer = new RouteManageViewer(window.viewer,selectedRoute.value.isClose)
window.viewer.flyTo(routeViewer.addAirLine(selectedRoute.value), {duration: 2})
setTimeout(()=>resolve('success'),2500)
}).then((result)=>{
//
let Cartain3 = transLonlat2Car3(selectedRoute.value.points)
// 1km
let res = profileAnalyse(window.viewer, Cartain3, 1000)
// 线
let orderArr = []
let hArr = []
Cartain3.forEach((_,index) => {
orderArr.push(index + 1)
hArr.push(selectedRoute.value.points[index].alt)
})
console.log(orderArr,hArr)
//
drawEcharts_RouteDetection(myChart, res.distanceArray, res.elevationArray, orderArr, hArr)
}).catch((err)=>{
uiMsg.error(err)
})
}
//
function addPtToTail() {
let newPt = newAirlinePt()
newPt.nPt = selectedRoute.value.points.at(-1).nPt + 1
selectedRoute.value.points.push(newPt)
}
//
// 1 ch2
// 2 线
// 3 store
function savePt() {
selectedRoute.value.points.forEach((pt,index) => {
pt.ch2 = 3
pt.nPt = index+1 //1
})
selectedRoute.value.points.at(-1).ch2 = 1
selectedRoute.value.PtNum = selectedRoute.value.points.length
routeStore.addRoute(selectedRoute.value)
}
/**
*
* @param key 下拉菜单key
* @param index 航点索引
*/
function handlePtSelect(key:any, index:number) {
if(key=='deletePt'){
selectedRoute.value.points.splice(index,1)
selectedRoute.value.points.forEach((pt,i) => {
pt.nPt = i+1
})
showPtList.value = false
nextTick(()=>{
showPtList.value = true
})
}
else if(key=='insertPt'){
selectedRoute.value.points.forEach((pt,i) => {
if(i>=index) pt.nPt = i + 2
})
let newPt = newAirlinePt()
newPt.nPt = index + 1
showPtList.value = false
nextTick(()=>{
selectedRoute.value.points.splice(index,0,newPt)
showPtList.value = true
})
}
}
//
function prevPtWeather() {
routePtNumber.value -= 1
//TODO: 使promise
}
//
function nextPtWeather() {
routePtNumber.value += 1
console.log(selectedRoute.value.points.length)
//TODO: 使promise
}
</script>
<template>
<n-config-provider :theme="darkTheme">
<div style="display: flex;">
<div id="left">
<n-layout style="height: 100%;">
<n-layout-header :bordered="true">
<n-popover trigger="hover">
<template #trigger>
<n-button quaternary type="success" size="large">
<template #icon>
<n-icon><ArrowBackOutline/></n-icon>
</template>
</n-button>
</template>
返回
</n-popover>
<n-popover trigger="hover">
<template #trigger>
<n-button quaternary type="success" size="large">
<template #icon>
<n-icon><Save/></n-icon>
</template>
</n-button>
</template>
保存编辑
</n-popover>
</n-layout-header>
<n-layout-content>
<n-flex vertical style="margin-left: 1.2rem; margin-top: .5rem;overflow: hidden">
<n-ellipsis><h3>航线列表</h3></n-ellipsis>
<n-radio-group v-model:value="selectedRouteCode" name="radiogroup" @update:value="checkRoute">
<n-scrollbar style="height: 20vh">
<n-space vertical>
<n-space v-for="r in routesInstore" justify="space-between"
style="margin-right: 2rem; border-bottom: #383737 1px solid">
<n-radio :key="r.value" :value="r.value">
{{ r.label }}
</n-radio>
<n-button size="small" type="error" style="height: 1.5rem; padding-top: 1px">删除</n-button>
</n-space>
</n-space>
</n-scrollbar>
</n-radio-group>
<n-divider style="margin: .2rem -.5rem"></n-divider>
<n-space vertical>
<n-space>
<n-space>
<n-ellipsis>开闭</n-ellipsis>
<n-switch v-model:value="selectedRoute.isClose" size="small">
<template #checked>
</template>
<template #unchecked>
</template>
</n-switch>
</n-space>
<n-space style="margin-left: .5rem">
<n-ellipsis>航点数</n-ellipsis>
<n-input-number :show-button="false" disabled size="tiny" style="width: 5rem"
v-model:value="selectedRoute.PtNum"></n-input-number>
</n-space>
</n-space>
<n-space>
<n-ellipsis style="width: 4rem">航线名称</n-ellipsis>
<n-input size="tiny" style="width:10rem" v-model:value="selectedRoute.name"></n-input>
</n-space>
<n-space>
<n-ellipsis style="width: 4rem">航线类型</n-ellipsis>
<n-select style="width:10rem" size="tiny" v-model:value="selectedRoute.code" :options="routeCode"/>
</n-space>
</n-space>
<n-divider style="margin: .2rem -.5rem"></n-divider>
<n-ellipsis><h3>地形剖面图</h3></n-ellipsis>
<n-space justify="start">
<n-ellipsis>采样间隔</n-ellipsis>
<n-input-number size="tiny" placeholder="默认1000米"
style="width:8vw" :min="100" :step="100">
</n-input-number>
<n-button type="success" size="tiny">重新绘图</n-button>
</n-space>
<div id="echarts-profile">
<!-- Echarts绘图区 -->
</div>
</n-flex>
</n-layout-content>
</n-layout>
</div>
<div id="map2">
<SceneViewer id="scene-viewer-route"></SceneViewer>
<BottomBar></BottomBar>
</div>
<div id="right">
<n-layout style="height: 100%">
<n-layout-header :bordered="true">
<n-space justify="center">
<n-button quaternary type="default" size="large"><h4>航点详情 {{'— '+selectedRoute.name}}</h4></n-button>
</n-space>
</n-layout-header>
<n-layout-content>
<n-flex vertical >
<n-space justify="space-around" style="margin-top:.5rem;">
<n-ellipsis style="margin-left:.2rem; width: 2rem">序号</n-ellipsis>
<n-ellipsis style="width: 5.5rem">经度</n-ellipsis>
<n-ellipsis style="width: 5.5rem">纬度</n-ellipsis>
<n-ellipsis style="width: 3rem">高度</n-ellipsis>
</n-space>
<n-scrollbar style="height: 30vh">
<div v-if="selectedRoute.points.length>0 && showPtList" >
<n-space justify="space-around" style="margin: .2rem 0" v-for="(pt,index) in selectedRoute.points" >
<n-dropdown trigger="hover" size="small" placement="top-start" :show-arrow="true"
:options="PtOptions" @select="handlePtSelect($event,index)">
<n-button secondary type="info" size="tiny" style="margin-left:.2rem; width: 1.7rem">{{ pt.nPt }}</n-button>
</n-dropdown>
<n-input-number size="tiny" v-model:value="pt.lon" :show-button="false" style="width: 5.5rem"
placeholder="经度" max="180" min="-180"></n-input-number>
<n-input-number size="tiny" v-model:value="pt.lat" :show-button="false" style="width: 5.5rem"
placeholder="纬度" max="90" min="-90"></n-input-number>
<n-input-number size="tiny" v-model:value="pt.alt" :show-button="false" style="width: 3rem"
placeholder="高度" max="12000" min="-500"></n-input-number>
</n-space>
<n-space justify="center" style="margin: .5rem 0">
<n-button type="info" size="small" @click="addPtToTail">
<template #icon>
<Add/>
</template>
添加点
</n-button>
<n-button type="info" size="small" @click="savePt">
<template #icon>
<SaveOutline/>
</template>
保存编辑
</n-button>
</n-space>
</div>
<n-space v-else justify="space-around">
<n-empty style="margin-top:3rem " description="无内容">
</n-empty>
</n-space>
</n-scrollbar>
</n-flex>
<n-divider style="margin: .2rem -.5rem"></n-divider>
<n-flex vertical style="height: 45vh; margin-left: 1rem; margin-top: .5rem;" >
<n-row><n-ellipsis><h3>气象信息</h3></n-ellipsis></n-row>
<n-space justify="space-around" class="routePtSelector">
<n-button size="small" @click="prevPtWeather" :disabled="routePtNumber<=1">
<template #icon><ArrowBackOutline/></template>
</n-button>
<n-ellipsis>航点 {{routePtNumber}}</n-ellipsis>
<n-button size="small" @click="nextPtWeather" :disabled="selectedRoute.points.length<=routePtNumber">
<template #icon><ArrowForwardOutline/></template>
</n-button>
</n-space>
</n-flex>
</n-layout-content>
</n-layout>
</div>
</div>
</n-config-provider>
</template>
<style scoped>
#left{
width: 20vw;
height: 100vh;
}
#map2 {
width: 60vw;
height: 100vh;
position: relative;
}
#right{
width: 20vw;
height: 100vh;
}
#echarts-profile{
margin-left: -1rem;
margin-top: -.5rem;
height: 40vh;
}
#scene-viewer-route {
width: 100%;
height: 100%;
overflow: hidden;
}
.routePtSelector {
width: 110%;
color: #63e2b7;
font-weight: bold;
margin-left: -1rem
}
.routePtSelector:hover{
background: rgb(24, 24, 28);
}
</style>

@ -23,6 +23,7 @@ import RouteOptions from "@/components/RouteOptions.vue";
import {useRouteStore} from "@/store/RouteStore";
import MarkerDialog from "@/components/MarkerDialog.vue";
import { useRouter, useRoute } from 'vue-router'
import {getUnicode} from "@/types/entityoptions.ts";
const router = useRouter()
const route = useRoute()
@ -77,7 +78,7 @@ function handleEditSelect(key) {
else{
// 线
router.push({
name: 'Test',
name: 'routeManage',
})
}
}
@ -283,11 +284,12 @@ function manageLayer(){
/**
* 绘制航线目前只绘制任务航线
* @param routeParams 航线属性
* @param routeParams 航线属性type:{name: string,code: number,isOpen: bool,height: number,routePts: []}
*/
function startDrawRoute(routeParams /*{code: number,isOpen: bool,height: number,routePts: []}*/) {
function startDrawRoute(routeParams) {
showRouteModal.value = false
let drawLine = new RouteManageViewer(window.viewer, routeParams.isClose, routeParams.height)
let drawLine = new RouteManageViewer(window.viewer, routeParams.isClose)
drawLine.routeParams.height = routeParams.height
drawLine.start().then(result => {
console.log(result)
// result AirlinePoint
@ -299,9 +301,10 @@ function startDrawRoute(routeParams /*{code: number,isOpen: bool,height: number,
AirlinePoints.at(-1).ch2 = 0x01;
// 线store
let aRoute = {
code: routeParams.code, PtNum: result.length, isClose: routeParams.isClose, name: "", points: AirlinePoints, totalDistance: 0
code: routeParams.code, PtNum: result.length, isClose: routeParams.isClose, unicode: getUnicode(),
name: routeParams.name, points: AirlinePoints, totalDistance: 0
}
useRouteStore().route.push(aRoute)
useRouteStore().flyRoute.push(aRoute)
// fixme: 线
}).catch(reject => {

@ -14,9 +14,9 @@ const router = createRouter({
component: ()=>import('@/components/RouteOptions.vue')
},
{
path: '/test2',
name: 'Test2',
component: ()=>import('@/components/MarkerDialog.vue')
path: '/routeManage',
name: 'routeManage',
component: ()=>import('@/components/page/RouteManagePage.vue')
}
]
});

@ -5,9 +5,20 @@ import {Airline} from "@/types/entityoptions.ts";
export const useRouteStore = defineStore('RouteStore', {
state: ()=>{
return {
route: [] as Airline[] //地图中绘制的航线用于发送给后端QT
flyRoute: [] as Airline[] //地图中绘制的航线用于发送给后端QT
}
},
actions: {
/**
* store线code
* @param route
*/
addRoute(route:Airline){
let index = this.flyRoute.findIndex((item: Airline)=>item.code===route.code)
if(index > -1){
this.flyRoute.splice(index,1);
}
this.flyRoute.push(route)
}
}
})

@ -49,6 +49,7 @@ export type AirlinePoint = {
export type Airline = {
name: string,
code: number, //航线编号
unicode: string, //航线唯一码前端有效用于图层管理、store管理和地图Entity管理
PtNum: number,
isClose: boolean,
totalDistance: number,
@ -60,3 +61,19 @@ export type routeTerrain = {
distanceArray: number[],
elevationArray: number[],
}
/**
* +
* @param len 12
*/
export function getUnicode(len:number = 12): string{
let timestamp = new Date().getTime();
/****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
let maxPos = $chars.length;
let randomStr = '';
for (let i = 0; i < len; i++) {
randomStr += $chars.charAt(Math.floor(Math.random() * maxPos));
}
return randomStr + timestamp;
}

@ -683,3 +683,129 @@ export const drawEchartsVisibility = (xData:number[], yData:number[],startHeight
],
});
}
/**
* 线
* @param myChart
* @param xData
* @param yData 线
* @param routeArr
* @param routeHeight 线线
*/
export const drawEcharts_RouteDetection = (myChart: EChartsType,xData:number[], yData:number[],
routeArr: number[], routeHeight:number[]) => {
// 绘制图表
myChart.setOption({
backgroundColor:'#101014',
grid: {
top: "17%",
right: "6%",
left:" 15%",
bottom: "20%",
},
legend: {
show: true,
type: 'plain',
top: '7%',
right: '5%',
data: [
{ //地形剖面图例
name: '地形剖面',
itemStyle: {fontSize: 14},
lineStyle: 'inherit',
},
{ //视线图例
name: '航线高度',
lineStyle: 'inherit',
itemStyle: {fontSize: 14}
}
],
selectedMode: true, //图例选择模式
inactiveColor: '#626161',
},
tooltip: {
show: true,
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter:'地表高度: {c0}<br> 航点高度:{c1}'
},
xAxis: [
{
boundaryGap : false,
min: 0,
data: xData,
nameTextStyle: {
fontWeight:'bolder',
fontSize: 10
},
axisLine:{
onZero: false,
show: true, // 是否显示坐标轴轴线
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
},
axisLabel: {
formatter: '{value}',
margin: 7,
},
},
{
position: 'bottom',
boundaryGap: false,
data: routeArr,
offset: 30,
axisTick:{ show: true, inside: true }, // 是否显示坐标轴刻度
axisLine:{
onZero: false,
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
},
axisLabel: {
formatter: '航点{value}',
margin: 7,
},
}
],
yAxis: {
type: 'value',
name: '高度/ m',
nameTextStyle: {
fontSize: 14
},
nameLocation: 'end',
position: 'left',
axisLabel: {
formatter: '{value}'
},
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
}
},
series: [
{
name:'地形剖面',
xAxisIndex: 0,
type: 'line',
data: yData,
areaStyle: {
color: '#37a5fb',
opacity: 0.5
}
},
{
name:'航线高度',
xAxisIndex: 1,
type: 'line',
data: routeHeight,
lineStyle: {
color: '#8ae73d',
}
},
],
});
}

@ -15,6 +15,7 @@ import {
Viewer
} from 'cesium'
import {Angle} from "@/utils/map/angle.ts";
import {AirlinePoint} from "@/types/entityoptions.ts";
/**
* 线
@ -184,4 +185,17 @@ export function ByDirectionAndLen(position: Cartesian3, angle:number, distance:n
return Matrix4.multiplyByPoint(matrix, new Cartesian3(0, distance, 0),
new Cartesian3());
}
/**
* 3
* @param coords
*/
export function transLonlat2Car3(coords: AirlinePoint[]):Cartesian3[] {
let coordCar3: Cartesian3[] = []
coords.forEach(coord => {
let car3 = Cartesian3.fromDegrees(coord.lon, coord.lat, coord.alt)
coordCar3.push(car3)
})
return coordCar3
}
export { getClosestPoint, isOnLineSegment, getDistance, getAzimuth, getPolygonArea }

Loading…
Cancel
Save