You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
GCSGUI/src/utils/map/SpatialAnalysis.ts

689 lines
17 KiB
TypeScript

/**
2024/4/15 9:52
Zhaipeixiu
*/
import {getDistance, getElevation} from "@/utils/map/geocomputation.ts";
import {Cartesian3, Viewer} from "cesium";
import * as echarts from "echarts";
import {EChartsType} from "echarts";
import {Airline, AirlinePoint} from "@/types/entityoptions.ts";
type ProfileResult = {
distanceArray:number[],
elevationArray:number[],
}
/**
*
* @param viewer Viewer
* @param start
* @param end
* @param interval 线 m
* @return 线
*/
export function elevationProfile(viewer: Viewer, start:Cartesian3, end:Cartesian3, interval: number)
{
let breakPointsHeight:number[] = [] //断点的高程m
let distanceFromStart:number[] = [] //断点至起点的距离m
// 计算首尾点距离 m
let totalLen = getDistance(start, end) * 1000
// 获取起点高度及其与起点的距离
breakPointsHeight.push(Math.round(getElevation(viewer, start)))
distanceFromStart.push(0)
//获取中间断点的高度及其与起点的距离
if(interval > 0){
//断点数量
let breakNum = Math.floor(totalLen/interval)
// 如果采样间隔小于首尾点距离,则获取每个断点的坐标 并获取其高度
if(breakNum>=1){
for (let i = 1; i < breakNum; i++) {
let breakP = Cartesian3.lerp(start, end, i/breakNum, new Cartesian3())
breakPointsHeight.push(Math.round(getElevation(viewer, breakP))) //单位 米
distanceFromStart.push(Math.round(getDistance(start,breakP)*1000)) //单位 米
}
}
}
// 获取终点高度及其与起点的距离
breakPointsHeight.push(Math.round(getElevation(viewer, end)))
distanceFromStart.push(Math.round(totalLen))
return { distanceArray: distanceFromStart, elevationArray: breakPointsHeight }
}
/**
* 线
* @param viewer Viewer
* @param polyline 线
* @param interval 线 m
* @return 线线
*/
export function profileAnalyse(viewer: Viewer, polyline:Cartesian3[], interval: number){
let result: ProfileResult = { distanceArray:[], elevationArray:[] }
let temp_dis = 0 //每两点之间的距离
for (let i = 0; i <= polyline.length - 2; i++) {
let temp = elevationProfile(viewer, polyline[i], polyline[i+1], interval)
result.elevationArray = result.elevationArray.concat(temp.elevationArray)
temp.distanceArray.forEach(distance => {
result.distanceArray.push(distance+temp_dis)
})
if(temp.distanceArray.length > 0){
temp_dis += temp.distanceArray[temp.distanceArray.length-1]
}
}
return result
}
/**
* 线
* @param viewer Viewer
* @param route 线
* @param interval 线 m
* @return 线线
*/
export function profileAnalyse_promise(viewer: Viewer, route: Airline, interval: number){
return new Promise((resolve, reject) => {
let result: ProfileResult = { distanceArray:[], elevationArray:[] }
let polyline = []
//航线转为坐标点数组
route.points.forEach(point => {
polyline.push(Cartesian3.fromDegrees(point.lon, point.lat,point.alt))
})
let temp_dis = 0 //每两点之间的距离
for (let i = 0; i <= polyline.length - 2; i++) {
let temp = elevationProfile(viewer, polyline[i], polyline[i+1], interval)
result.elevationArray = result.elevationArray.concat(temp.elevationArray)
temp.distanceArray.forEach(distance => {
result.distanceArray.push(distance+temp_dis)
})
if(temp.distanceArray.length > 0){
temp_dis += temp.distanceArray[temp.distanceArray.length-1]
}
}
resolve(result)
})
}
/**
* <br>
* truefalseundefined
* @param viewer
* @param viewpoint
* @param target
* @param h1 m
* @param h2 m
* @param curvature
* @param breakNum 100
*/
export function visibilityAnalyse(viewer: Viewer, viewpoint:Cartesian3, target:Cartesian3,
h1:number, h2:number,curvature:boolean, breakNum = 100) {
// 获取视点高度和目标点高度
let viewpointH = getElevation(viewer, viewpoint) + h1
let targetH = getElevation(viewer, target) + h2
if (viewpointH === -9999.2024 + h1 ) {
console.log("无法获取视点海拔高度!")
return undefined
}
if (targetH === -9999.2024 + h2 ) {
console.log("无法获取目标点海拔高度!")
return undefined
}
// 计算首尾点距离 m
let totalLen = getDistance(viewpoint, target) * 1000
// 计算首尾点斜率
let visibleK = (targetH - viewpointH)/totalLen
// 逐个计算断点与视点的斜率
for (let i = 1; i <= breakNum; i++) {
let breakP = Cartesian3.lerp(viewpoint, target, i/breakNum, new Cartesian3())
let breakPH = getElevation(viewer, breakP) //断点海拔
if(breakPH == -9999.2024) return false
let breakPDis = Math.floor(getDistance(viewpoint,breakP)*1000) //断点与视点的距离
// 计算断点与视点的斜率
let breakPK = (breakPH-viewpointH)/breakPDis
if(breakPK>visibleK){
return false
}
}
if(curvature){
let Rmax = 2.898 * (Math.sqrt(h1)+Math.sqrt(h2))
if (Rmax < totalLen/1000.0) return false
}
return true
}
/**
* <br>
* truefalse
* @param profile
* @param curvature
* @param startExtraH m
* @param endExtraH m
*/
export function visibilityAnalyse2(profile: ProfileResult, curvature:boolean, startExtraH:number,endExtraH:number)
{
// 计算起点、终点的高度(海拔+挂高m
let startH = profile.elevationArray[0] + startExtraH
let endH = profile.elevationArray.at(-1) + endExtraH
// 计算首尾点斜率
let visibleK = (endH - startH)/profile.distanceArray.at(-1)
// 逐个计算断点与视点的斜率
for (let i = 1; i < profile.elevationArray.length ; i++) {
let breakPK = (profile.elevationArray[i] - startH) / profile.distanceArray[i]
if(breakPK > visibleK)
return false
}
if(curvature){
let coefficient: number = 3.57 //考虑大气折射 4.12 公司文件给出 2.898
let Rmax = coefficient * (Math.sqrt(startExtraH) + Math.sqrt(endExtraH))
if (Rmax < profile.distanceArray.at(-1)/1000.0)
return false
}
return true
}
/**
* 线
* @param xData x
* @param yData y线
*/
export function drawEchartsProfileAnalyse(xData:number[], yData:number[]) {
let myChart = echarts.init(document.getElementById('profileEChart'))
// 绘制图表
myChart.setOption({
legend: {
show: true,
type: 'plain',
top: '5%',
data:[
{
name: 'groundLine',
itemStyle: 'inherit',
lineStyle: 'inherit',
},
]
},
tooltip: {
show: true,
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter:'地表高度: {c0}'
},
xAxis: {
data: xData,
name: '距离/米',
nameTextStyle: {
fontWeight:'bolder',
fontSize: 14
},
nameLocation: 'end',
axisLine:{
onZero: false,
show: true, // 是否显示坐标轴轴线
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
},
axisLabel: {
formatter: '{value}',
margin: 5,
},
axisTick: {
show: true, // 是否显示坐标轴刻度
inside: true, // 坐标轴刻度是否朝内,默认朝外
alignWithLabel: true,
lineStyle: {
color: '#000000', //刻度线的颜色
type: 'solid', //坐标轴线线的类型solid实线类型dashed虚线类型dotted点状类型
},
}
},
yAxis: {
type: 'value',
name: '高度/米',
nameTextStyle: {
fontWeight:'bolder',
fontSize: 14
},
nameLocation: 'end',
position: 'left',
axisLabel: {
formatter: '{value}'
},
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
}
},
series: [
{
name:'groundLine',
type: 'line',
data: yData,
areaStyle: {
color: '#37a5fb',
opacity: 0.5
}
}
]
});
}
/**
*
* @param myChart ECharts
* @param xData x
* @param yData y线
* @param height 线
*/
export function drawEcharts_CollisionDetection(myChart: EChartsType, xData:number[], yData:number[], height:number) {
// 绘制图表
myChart.setOption({
legend: {
show: true,
type: 'plain',
top: '5%',
data:[
{
name: '地形',
itemStyle: 'inherit',
lineStyle: 'inherit',
},
{ //视线图例
name: '飞机高度',
lineStyle: {
type: 'dotted',
width: 3,
color: '#f8364d'
},
itemStyle: {
fontSize: 18
}
}
]
},
tooltip: {
show: true,
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter:'地表高度: {c0}'
},
xAxis: {
data: xData,
name: '距离/米',
nameTextStyle: {
fontWeight:'bolder',
fontSize: 14
},
nameLocation: 'end',
axisLine:{
onZero: false,
show: true, // 是否显示坐标轴轴线
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
},
axisLabel: {
formatter: '{value}',
margin: 5,
},
axisTick: {
show: true, // 是否显示坐标轴刻度
inside: true, // 坐标轴刻度是否朝内,默认朝外
alignWithLabel: true,
lineStyle: {
color: '#000000', //刻度线的颜色
type: 'solid', //坐标轴线线的类型solid实线类型dashed虚线类型dotted点状类型
},
}
},
yAxis: {
type: 'value',
name: '高度/米',
nameTextStyle: {
fontWeight:'bolder',
fontSize: 14
},
nameLocation: 'end',
position: 'left',
axisLabel: {
formatter: '{value}'
},
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
}
},
visualMap: {
type: 'piecewise',
show: false,
dimension: 1,
// seriesIndex: [0, 1], // 虽然可以指定多个series但是线的颜色只能设置一条
seriesIndex: [0, 1],
pieces: [{
gt: height,
color: 'red'
}, {
lt: 0,
color: 'blue'
}],
outOfRange: { // 在选中范围外 的视觉元素,这里设置在正常范围内的图形颜色
color: 'blue',
},
},
series: [
{
name:'地形',
type: 'line',
data: yData,
areaStyle: {
color: '#37a5fb',
opacity: 0.5
},
markLine: {
name: "飞机高度",
data: [
{
yAxis: height,
itemStyle: {
normal: { color: '#c60c30' }
}
}
],
symbol:['circle', 'arrow'],
label:{
formatter: "飞机高度",
show: true,
position: 'middle',
fontSize: 15,
fontWeight: 'bold',
color: '#e73d3d',
},
lineStyle: { //标注线样式
type: 'dashed',
color: 'red',
with: 10
}
},
},
{
type: 'line',
symbol: 'none',
name: '飞机高度',
color: 'transparent'
}
]
}, false);
}
/**
*
* @param myChart ECharts
* @param xData x
* @param yData y线
* @param yData2 y2线
*/
export function drawEcharts_CollisionDetection2(myChart: EChartsType, xData:number[], yData:number[], yData2: number[]) {
// 绘制图表
myChart.setOption({
legend: {
show: true,
type: 'plain',
top: '5%',
data:[
{
name: '地表高度',
itemStyle: 'inherit',
lineStyle: 'inherit',
},
{
name: '飞机高度',
lineStyle: {
type: 'dotted',
width: 3,
color: '#f8364d'
},
itemStyle: {
fontSize: 18
}
}
]
},
tooltip: {
show: true,
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter:'地表高度: {c0}<br>飞机高度: {c1}'
},
xAxis: {
data: xData,
name: '距离/米',
nameTextStyle: {
fontWeight:'bolder',
fontSize: 14
},
nameLocation: 'end',
axisLine:{
onZero: false,
show: true, // 是否显示坐标轴轴线
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
},
axisLabel: {
formatter: '{value}',
margin: 5,
},
axisTick: {
show: true, // 是否显示坐标轴刻度
inside: true, // 坐标轴刻度是否朝内,默认朝外
alignWithLabel: true,
lineStyle: {
color: '#000000', //刻度线的颜色
type: 'solid', //坐标轴线线的类型solid实线类型dashed虚线类型dotted点状类型
},
}
},
yAxis: {
max: (value:any)=>{
return Math.floor(value.max * 1.01)
},
min: (value:any)=>{
return Math.floor(value.min * 0.99)
},
type: 'value',
name: '高度/米',
nameTextStyle: {
fontWeight:'bolder',
fontSize: 14
},
nameLocation: 'end',
position: 'left',
axisLabel: {
formatter: '{value}'
},
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
}
},
series: [
{
name:'地表高度',
type: 'line',
data: yData,
areaStyle: {
color: '#37a5fb',
opacity: 0.5
},
},
{
name: '飞机高度',
type: 'line',
symbol: 'none',
color: 'red',
data: yData2,
}
]
}, false);
}
/**
* 线线
* @param xData x
* @param yData y线
* @param startHeight 线
* @param endHeight 线
*/
export const drawEchartsVisibility = (xData:number[], yData:number[],startHeight:number, endHeight:number) => {
let myChart = echarts.init(document.getElementById('profileEChart')) //Echarts-UnitTest
// 绘制图表
myChart.setOption({
legend: {
show: true,
type: 'plain',
top: '7%',
data: [
{ //地形剖面图例
name: '剖面线',
itemStyle: {
fontSize: 18
},
lineStyle: 'inherit',
},
{ //视线图例
name: '视线',
lineStyle: {
type: 'dotted',
width: 3,
color: '#f8364d'
},
itemStyle: {
fontSize: 18
}
}
],
selectedMode: false, //图例选择模式关闭
},
tooltip: {
show: true,
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter:'地表高度: {c0}'
},
xAxis: {
boundaryGap : false,
max: (value:any)=>{
return value.max * 1.01;
},
min: 0,
data: xData,
name: '距离/m',
nameTextStyle: {
fontWeight:'bolder',
fontSize: 14
},
nameLocation: 'end',
axisLine:{
onZero: false,
show: true, // 是否显示坐标轴轴线
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
},
axisLabel: {
formatter: '{value}',
margin: 5,
},
axisTick: {
show: true, // 是否显示坐标轴刻度
inside: true, // 坐标轴刻度是否朝内,默认朝外
alignWithLabel: true,
lineStyle: {
color: '#000000', //刻度线的颜色
type: 'solid', //坐标轴线线的类型solid实线类型dashed虚线类型dotted点状类型
},
}
},
yAxis: {
max: (value:any)=>{
return Math.floor(Math.max(value.max,startHeight,endHeight)*1.01)
},
min: (value:any)=>{
return Math.floor(Math.min(value.min,startHeight,endHeight)*0.99)
},
type: 'value',
name: '高度/ m',
nameTextStyle: {
fontWeight:'bolder',
fontSize: 14
},
nameLocation: 'end',
position: 'left',
axisLabel: {
formatter: '{value}'
},
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
}
},
series: [
{
name:'剖面线',
type: 'line',
data: yData,
areaStyle: {
color: '#37a5fb',
opacity: 0.5
},
markLine: {
data: [
[
{coord: ['0', startHeight.toString()]},
{coord: [xData.at(-1)?.toString(), endHeight.toString()]}
// Markline中的坐标点必须为string否则异常
]
],
symbol:['circle', 'arrow'],
label:{
formatter: "模 拟 视 线",
show: true,
position: 'middle',
fontSize: 15,
fontWeight: 'bold',
color: '#e73d3d',
},
lineStyle: { //标注线样式
type: 'dashed',
color: 'red',
with: 10
}
},
},
{ /* 视线的series */
type: 'line',
symbol: 'none',
name: '视线',
color: 'transparent'
}
],
});
}