/**
文件描述:空间分析方法
创建时间:2024/4/15 9:52
创建人:Zhaipeixiu
*/
import {getDistance, getElevation} from "@/utils/map/geocomputation.ts";
import {Cartesian3, Viewer} from "cesium";
import * as echarts from "echarts";
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
}
/**
* 两点间通视分析(基于最大斜率的算法)
* 返回值:通视为true,不通视为false,异常返回undefined
* @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) //断点海拔
let breakPDis = 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
}
/**
* 绘制地形剖面折线图
* @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 xData x数组
* @param yData y数组,以面积线绘制
* @param yData2 y数组,以折线绘制
*/
export const drawEchartsAirlineDetect = (xData:number[],yData:number[],yData2:number[]) => {
let myChart = echarts.init(document.getElementById('profileEChart'))
// 绘制图表
myChart.setOption({
legend:{
show: true,
type: 'plain',
top: '7%',
data:[
{
name: 'groundLine',
itemStyle: 'inherit',
lineStyle: 'inherit',
},
{
name: 'airLine',
itemStyle: 'inherit',
lineStyle: 'inherit',
}]
},
tooltip: {
show: true,
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter:'地表高度: {c0}
航线高度: {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} m',
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} m'
},
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
}
},
series: [
{
name:'groundLine',
type: 'line',
data: yData,
areaStyle: {
color: '#37a5fb',
opacity: 0.5
}
},
{
name:'airLine',
type: 'line',
data: yData2,
}
]
});
}
/**
* 绘制通视分析图 面积线和直线
* @param xData x数组,地面距离
* @param yData y数组,以面积线绘制
* @param startHeight 视线起始点高度(包含地面挂高)
* @param endHeight 视线终点高度(包含地面挂高)
*/
export const drawEchartsVisibility = (xData:number[], yData:number[],startHeight:number, endHeight:number) => {
console.group()
console.log(0, startHeight)
console.log(xData.at(-1), endHeight)
console.groupEnd()
console.log(xData)
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'
}
],
});
}