import * as Cesium from 'cesium'
|
|
import takeoffImg from '@/assets/images/routePlan/pointAirLine/takeoff.svg'
|
import _, { cloneDeep, throttle } from 'lodash'
|
import { cartesian3Convert } from '@/utils/cesium/mapUtil'
|
import * as turf from '@turf/turf'
|
import { ElMessage } from 'element-plus'
|
|
import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz'
|
import { camelToSnake } from '@/utils/util'
|
|
import { boxTransformScale } from '@/utils/turfFunc'
|
|
|
function _getMouseInfo (position, viewer) {
|
let scene = viewer.scene
|
let target = scene.pick(position)
|
let cartesian = undefined
|
let surfaceCartesian = undefined
|
let wgs84Position = undefined
|
let wgs84SurfacePosition = undefined
|
if (scene.pickPositionSupported) {
|
cartesian = scene.pickPosition(position)
|
}
|
if (cartesian) {
|
let c = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian)
|
if (c) {
|
wgs84Position = {
|
lng: Cesium.Math.toDegrees(c.longitude),
|
lat: Cesium.Math.toDegrees(c.latitude),
|
alt: c.height,
|
}
|
}
|
}
|
if (scene.mode === Cesium.SceneMode.SCENE3D && !(viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider)) {
|
let ray = scene.camera.getPickRay(position)
|
surfaceCartesian = scene.globe.pick(ray, scene)
|
} else {
|
surfaceCartesian = scene.camera.pickEllipsoid(position, Cesium.Ellipsoid.WGS84)
|
}
|
if (surfaceCartesian) {
|
let c = Cesium.Ellipsoid.WGS84.cartesianToCartographic(surfaceCartesian)
|
if (c) {
|
wgs84SurfacePosition = {
|
lng: Cesium.Math.toDegrees(c.longitude),
|
lat: Cesium.Math.toDegrees(c.latitude),
|
alt: c.height,
|
}
|
}
|
}
|
|
return {
|
target: target,
|
windowPosition: position,
|
position: cartesian,
|
wgs84Position: wgs84Position,
|
surfacePosition: surfaceCartesian,
|
wgs84SurfacePosition: wgs84SurfacePosition,
|
}
|
}
|
|
let startPointEntity = null
|
// 生成起飞点
|
function generateStartPoint (movement, viewer) {
|
// 1. 获取笛卡尔坐标
|
const cartesian = viewer.scene.pickPosition(movement.endPosition)
|
if (!cartesian) return
|
// 2. 笛卡尔转为弧度
|
const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
|
// 3. 精确获取地形高度(异步)
|
Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, [cartographic])
|
.then(updatedPositions => {
|
const terrainHeight = updatedPositions[0].height
|
const position = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, terrainHeight)
|
// 4. 更新或创建点实体
|
if (startPointEntity) {
|
startPointEntity.position = position
|
} else {
|
startPointEntity = viewer.entities.add({
|
position,
|
id: 'wayline-point-start-init',
|
billboard: {
|
image: takeoffImg,
|
outlineWidth: 0,
|
width: 36,
|
height: 36,
|
scale: 1.0,
|
},
|
})
|
}
|
})
|
.catch(error => console.error("地形加载失败:", error))
|
}
|
export const createStartThrottle = throttle(generateStartPoint, 20)
|
|
// 获取起飞点位置
|
export function getStartPointLast (viewer) {
|
const point = cartesian3Convert(startPointEntity.position.getValue(), viewer) //经纬度
|
startPointEntity && viewer.entities.remove(startPointEntity)
|
return point
|
}
|
|
export function removeStartPoint (viewer) {
|
if (startPointEntity) {
|
viewer.entities.remove(startPointEntity)
|
startPointEntity = null
|
}
|
}
|
|
// 检查位置是否在合理范围内
|
export function isValidPosition (cartographic) {
|
// 检查经纬度是否在合理范围内
|
return (
|
cartographic.longitude >= -Math.PI &&
|
cartographic.longitude <= Math.PI &&
|
cartographic.latitude >= -Math.PI / 2 &&
|
cartographic.latitude <= Math.PI / 2
|
)
|
}
|
|
export class PolygonDrawer {
|
/**
|
* @param {Function} updatePosition - Position update callback function
|
* @param {Object} idShowWaringTip - Warning tip visibility flag
|
*/
|
constructor(updatePosition, idShowWaringTip) {
|
// Initialize properties
|
this.viewer = null
|
this.curPolygon = null
|
this.drawingMode = false
|
this.settingMode = false
|
this.isDragging = false
|
this.draggedEntity = null
|
this.polygonEntity = null
|
this.editPolygonPointDataSource = null
|
this.handler = null
|
this.updatePosition = updatePosition
|
this.menuPopup = null
|
this.delPolygonPoint = null
|
this.idShowWaringTip = idShowWaringTip
|
this.currentDragPointIsValid = false
|
this.currentDragPointPosition = null
|
|
// Bind methods to maintain context
|
this.handleLeftDown = this.handleLeftDown.bind(this)
|
this.handleLeftUp = this.handleLeftUp.bind(this)
|
this.handleMouseMove = this.handleMouseMove.bind(this)
|
this.handleLeftClick = this.handleLeftClick.bind(this)
|
this.handleRightClick = this.handleRightClick.bind(this)
|
this.delPolygon = this.delPolygon.bind(this)
|
this.delPoint = this.delPoint.bind(this)
|
}
|
|
// Constants for entity names and IDs
|
static ENTITY_NAMES = {
|
POLYGON: '面状航线-面',
|
POINT: '面状航线-端点',
|
POLYGON_ID: 'planar-route-polygon',
|
POINT_ID_PREFIX: 'planar-route-point-'
|
};
|
|
// Constants for colors
|
static COLORS = {
|
DEFAULT_POLYGON: Cesium.Color.fromBytes(45, 140, 240, 99),
|
DEFAULT_LINE: Cesium.Color.fromBytes(45, 140, 240, 255),
|
ERROR_POLYGON: Cesium.Color.fromCssColorString('rgba(255, 0, 0, .3)'),
|
ERROR_LINE: Cesium.Color.fromCssColorString('rgba(255, 0, 0, 1)')
|
};
|
|
/**
|
* Initialize polygon with existing positions
|
* @param {Cesium.Viewer} viewer - Cesium viewer instance
|
* @param {Array} positions - Array of position objects {lng, lat, height}
|
*/
|
initPolygon (viewer, positions) {
|
this.initHandler(viewer)
|
this.startDrawing()
|
|
positions.forEach(item => {
|
this.addPosition(
|
Cesium.Cartesian3.fromDegrees(Number(item.lng), Number(item.lat), Number(item.height)),
|
false
|
)
|
})
|
|
const newBox = boxTransformScale(positions.map(item => [item.lng, item.lat]), 5)
|
viewer.camera.flyTo({
|
destination: Cesium.Rectangle.fromDegrees(...newBox),
|
offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90), 0),
|
duration: 0.5,
|
})
|
|
this.drawingMode = false
|
this.settingMode = true
|
}
|
|
/**
|
* Start drawing a new polygon
|
*/
|
startDrawing () {
|
this.drawingMode = true
|
this.curPolygon = new Cesium.PolygonHierarchy()
|
|
if (!this.editPolygonPointDataSource) {
|
this.editPolygonPointDataSource = new Cesium.CustomDataSource('editPolygonPointDataSource')
|
this.viewer?.dataSources.add(this.editPolygonPointDataSource)
|
}
|
|
this.editPolygonPointDataSource?.entities.removeAll()
|
}
|
|
/**
|
* Add a position to the current polygon
|
* @param {Cesium.Cartesian3} position - Position to add
|
* @param {Boolean} isAdd - Whether this is an additional point (vs initial point)
|
*/
|
addPosition (position, isAdd = true) {
|
if (this.curPolygon.positions.length === 0 && isAdd) {
|
this.curPolygon.positions.push(position.clone())
|
}
|
|
this.curPolygon.positions.push(position.clone())
|
|
if (!this.polygonEntity) {
|
this.createPolygonEntity()
|
}
|
|
this.createPointEntity(position, isAdd)
|
}
|
|
/**
|
* Create the main polygon entity
|
*/
|
createPolygonEntity () {
|
this.polygonEntity = this.viewer.entities.add({
|
name: PolygonDrawer.ENTITY_NAMES.POLYGON,
|
id: PolygonDrawer.ENTITY_NAMES.POLYGON_ID,
|
polygon: {
|
hierarchy: new Cesium.CallbackProperty(() => this.curPolygon, false),
|
material: PolygonDrawer.COLORS.DEFAULT_POLYGON,
|
outline: false,
|
outlineWidth: 2,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
},
|
polyline: {
|
width: 2,
|
material: PolygonDrawer.COLORS.DEFAULT_LINE,
|
clampToGround: true,
|
positions: new Cesium.CallbackProperty(
|
() => [...this.curPolygon.positions, this.curPolygon.positions[0]],
|
false
|
)
|
},
|
})
|
}
|
|
/**
|
* Create a point entity for the polygon
|
* @param {Cesium.Cartesian3} position - Position of the point
|
* @param {Boolean} isAdd - Whether this is an additional point
|
*/
|
createPointEntity (position, isAdd) {
|
const pointIndex = isAdd ? this.curPolygon.positions.length - 2 : this.curPolygon.positions.length - 1
|
|
this.editPolygonPointDataSource.entities.add({
|
name: PolygonDrawer.ENTITY_NAMES.POINT,
|
id: `${PolygonDrawer.ENTITY_NAMES.POINT_ID_PREFIX}${pointIndex}`,
|
position: position.clone(),
|
point: {
|
pixelSize: 14,
|
color: Cesium.Color.WHITE,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
customData: {
|
ind: pointIndex,
|
},
|
})
|
}
|
|
/**
|
* Finish drawing the polygon
|
*/
|
finishDrawing () {
|
this.curPolygon.positions.pop()
|
|
if (this.curPolygon.positions.length >= 3) {
|
this.drawingMode = false
|
this.settingMode = true
|
this.editPolygonPointDataSource.entities.show = true
|
|
if (!this.curDragPointIsValid(this.curPolygon.positions)) {
|
this.idShowWaringTip.value = true
|
this.currentDragPointIsValid = true
|
this.updatePolygonAppearance(PolygonDrawer.COLORS.ERROR_POLYGON, PolygonDrawer.COLORS.ERROR_LINE)
|
} else {
|
this.idShowWaringTip.value = false
|
this.currentDragPointIsValid = false
|
this.updatePolygonAppearance(PolygonDrawer.COLORS.DEFAULT_POLYGON, PolygonDrawer.COLORS.DEFAULT_LINE)
|
}
|
|
this.updatePosition(this.curPolygon.positions)
|
}
|
}
|
|
/**
|
* Delete the current polygon
|
*/
|
delPolygon () {
|
this.removeEntities()
|
this.removeMenuPopup()
|
this.updatePosition([])
|
this.startDrawing()
|
}
|
|
/**
|
* Delete a point from the polygon
|
*/
|
delPoint () {
|
if (this.curPolygon.positions.length <= 3) {
|
this.removeMenuPopup()
|
return ElMessage.warning('端点不可少于3个')
|
}
|
if (!this.delPolygonPoint) return
|
|
this.curPolygon.positions.splice(this.delPolygonPoint.customData.ind, 1)
|
this.editPolygonPointDataSource.entities.remove(this.delPolygonPoint)
|
this.removeMenuPopup()
|
|
// Update indices of remaining points
|
this.editPolygonPointDataSource.entities.values.forEach((item, index) => {
|
item.customData.ind = index
|
})
|
|
this.updatePosition(this.curPolygon.positions)
|
}
|
|
/**
|
* Create a context menu popup
|
* @param {String} type - Type of menu ('polygon' or 'edit-point')
|
* @returns {HTMLElement} The created menu element
|
*/
|
createMenuPopup (type = 'polygon') {
|
const menuPopupVBox = document.createElement('div')
|
menuPopupVBox.id = 'planarPolygonEdit'
|
menuPopupVBox.className = 'planar-polygon-edit-tooltip'
|
|
const menuPopup = document.createElement('div')
|
menuPopup.id = 'planarPolygonEditMenu'
|
menuPopup.className = 'planar-polygon-edit-menu'
|
|
const menuItems = type === 'polygon'
|
? [{ title: '删除测区', class: 'del-planar-polygon' }]
|
: [{ title: '删除端点', class: 'del-planar-point' }]
|
|
menuItems.forEach(item => {
|
const titleDiv = document.createElement('div')
|
titleDiv.innerText = item.title
|
titleDiv.className = item.class
|
menuPopup.appendChild(titleDiv)
|
})
|
|
menuPopupVBox.appendChild(menuPopup)
|
return menuPopupVBox
|
}
|
|
/**
|
* Remove the context menu popup
|
*/
|
removeMenuPopup () {
|
if (this.menuPopup) {
|
this.menuPopup.removeEventListener('click', this.delPolygon)
|
this.menuPopup.removeEventListener('click', this.delPoint)
|
this.viewer.container.removeChild(this.menuPopup)
|
this.menuPopup = null
|
}
|
this.delPolygonPoint = null
|
}
|
|
/**
|
* Handle left mouse button down event
|
* @param {Object} movement - Mouse movement event object
|
*/
|
handleLeftDown (movement) {
|
if (!this.settingMode) return
|
|
const pickedEntity = this.viewer.scene.pick(movement.position)?.id
|
const isPoint = pickedEntity?.name === PolygonDrawer.ENTITY_NAMES.POINT
|
|
if (pickedEntity && isPoint) {
|
this.isDragging = true
|
this.draggedEntity = pickedEntity
|
this.currentDragPointPosition = this.curPolygon.positions[this.draggedEntity?.customData.ind]
|
this.disableMapControl()
|
}
|
}
|
|
/**
|
* Handle left mouse button up event
|
*/
|
handleLeftUp () {
|
if (!(this.settingMode && this.curPolygon?.positions && this.draggedEntity)) return
|
|
if (this.currentDragPointIsValid && this.isDragging) {
|
this.draggedEntity.position = this.currentDragPointPosition
|
this.curPolygon.positions[this.draggedEntity?.customData.ind] = this.currentDragPointPosition
|
|
if (!this.curDragPointIsValid(this.curPolygon.positions)) {
|
this.idShowWaringTip.value = true
|
this.currentDragPointIsValid = true
|
this.updatePolygonAppearance(PolygonDrawer.COLORS.ERROR_POLYGON, PolygonDrawer.COLORS.ERROR_LINE)
|
} else {
|
this.idShowWaringTip.value = false
|
this.currentDragPointIsValid = false
|
this.updatePolygonAppearance(PolygonDrawer.COLORS.DEFAULT_POLYGON, PolygonDrawer.COLORS.DEFAULT_LINE)
|
}
|
}
|
|
if (this.isDragging) {
|
this.updatePosition(this.curPolygon.positions)
|
this.isDragging = false
|
this.draggedEntity = null
|
this.enableMapControl()
|
}
|
}
|
|
/**
|
* Update polygon appearance
|
* @param {Cesium.Color} polygonColor - Color for the polygon
|
* @param {Cesium.Color} lineColor - Color for the outline
|
*/
|
updatePolygonAppearance (polygonColor, lineColor) {
|
this.polygonEntity.polygon.material = polygonColor
|
this.polygonEntity.polyline.material = lineColor
|
}
|
|
/**
|
* Handle left mouse click event
|
* @param {Object} click - Click event object
|
*/
|
handleLeftClick (click) {
|
this.removeMenuPopup()
|
|
const pickedAllEntity = this.viewer.scene.drillPick(click.position).filter(i => i.id)
|
const isStartPoint = pickedAllEntity.find(i => i.id.name === '起飞点')
|
const isPolygonPoint = pickedAllEntity.find(i => i.id.name === PolygonDrawer.ENTITY_NAMES.POINT)
|
const isPolygon = pickedAllEntity.find(i => i.id.name === PolygonDrawer.ENTITY_NAMES.POLYGON)
|
|
if (isStartPoint) return
|
|
if (!this.drawingMode) {
|
if (!isPolygon) {
|
this.settingMode = false
|
this.editPolygonPointDataSource.entities.show = false
|
return
|
}
|
|
if (isPolygon) {
|
this.settingMode = true
|
this.editPolygonPointDataSource.entities.show = true
|
}
|
return
|
}
|
|
|
if (this.curPolygon.positions.length < 4 && isPolygonPoint) {
|
return
|
}
|
|
if (this.curPolygon.positions.length >= 4 && isPolygonPoint) {
|
if (!this.drawingMode) return
|
|
this.finishDrawing()
|
|
return
|
}
|
|
const cartesian = this.viewer.scene.pickPosition(click.position)
|
if (!cartesian) return
|
|
this.addPosition(cartesian)
|
}
|
|
/**
|
* Handle right mouse click event
|
* @param {Object} click - Click event object
|
*/
|
handleRightClick (click) {
|
if (this.drawingMode) return
|
|
this.removeMenuPopup()
|
|
const pickedAllEntity = this.viewer.scene.drillPick(click.position).filter(i => i.id)
|
const isPolygon = pickedAllEntity.find(i => i.id.name === PolygonDrawer.ENTITY_NAMES.POLYGON)
|
const isEditPoint = pickedAllEntity.find(i => i.id.name === PolygonDrawer.ENTITY_NAMES.POINT)
|
const { position: { x, y } } = click
|
|
let pickedEntity, tooltipEvent, menuType
|
|
if (isPolygon) {
|
pickedEntity = isPolygon
|
tooltipEvent = this.delPolygon
|
menuType = 'polygon'
|
} else if (isEditPoint) {
|
pickedEntity = isEditPoint
|
tooltipEvent = this.delPoint
|
menuType = 'edit-point'
|
}
|
|
if (pickedEntity) {
|
this.delPolygonPoint = pickedEntity.id
|
this.menuPopup = this.createMenuPopup(menuType)
|
this.menuPopup.style.transform = `translate3d(${x - 10}px, ${y - 10}px, 0)`
|
this.viewer.container.appendChild(this.menuPopup)
|
this.menuPopup.addEventListener('click', tooltipEvent)
|
}
|
}
|
|
/**
|
* Handle mouse move event
|
* @param {Object} movement - Mouse movement event object
|
*/
|
handleMouseMove (movement) {
|
if (!this.drawingMode && !this.settingMode) return
|
|
const cartesian = this.viewer.scene.pickPosition(movement.endPosition)
|
if (!cartesian) return
|
|
if (this.settingMode && this.draggedEntity?.customData) {
|
this.draggedEntity.position = cartesian
|
this.curPolygon.positions[this.draggedEntity?.customData.ind] = cartesian
|
}
|
|
if (this.drawingMode && this.polygonEntity && this.curPolygon.positions.length >= 1) {
|
this.curPolygon.positions.pop()
|
this.curPolygon.positions.push(cartesian)
|
}
|
|
if ((this.settingMode && this.draggedEntity?.customData) || (this.drawingMode && this.polygonEntity && this.curPolygon.positions.length >= 3)) {
|
if (!this.curDragPointIsValid(this.curPolygon.positions)) {
|
this.idShowWaringTip.value = true
|
this.currentDragPointIsValid = true
|
this.updatePolygonAppearance(PolygonDrawer.COLORS.ERROR_POLYGON, PolygonDrawer.COLORS.ERROR_LINE)
|
} else {
|
this.idShowWaringTip.value = false
|
this.currentDragPointIsValid = false
|
this.updatePolygonAppearance(PolygonDrawer.COLORS.DEFAULT_POLYGON, PolygonDrawer.COLORS.DEFAULT_LINE)
|
}
|
}
|
}
|
|
/**
|
* Check if the current dragged point position is valid
|
* @param {Array} positions - Array of polygon positions
|
* @returns {Boolean} True if the polygon is valid (no self-intersections)
|
*/
|
curDragPointIsValid (positions) {
|
if (positions.length < 3) return true
|
|
const cartographics = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(positions)
|
const latLngPoints = cartographics.map(cartographic => [
|
Cesium.Math.toDegrees(cartographic.longitude),
|
Cesium.Math.toDegrees(cartographic.latitude)
|
])
|
|
|
const poly = turf.polygon([[...latLngPoints, latLngPoints[0]]])
|
const intersections = turf.kinks(poly)
|
|
return intersections.features.length === 0
|
}
|
|
/**
|
* Disable map controls during interaction
|
*/
|
disableMapControl () {
|
const controller = this.viewer.scene.screenSpaceCameraController
|
controller.enableRotate = false
|
controller.enableTranslate = false
|
controller.enableZoom = false
|
}
|
|
/**
|
* Enable map controls after interaction
|
*/
|
enableMapControl () {
|
const controller = this.viewer.scene.screenSpaceCameraController
|
controller.enableRotate = true
|
controller.enableTranslate = true
|
controller.enableZoom = true
|
}
|
|
/**
|
* Remove all entities
|
*/
|
removeEntities () {
|
// Remove main polygon entities
|
const entitiesIDs = this.viewer.entities.values.map(i => i.id)
|
entitiesIDs.forEach(item => {
|
if (item.includes('planar-route-')) {
|
this.viewer.entities.removeById(item)
|
}
|
})
|
|
this.settingMode = false
|
|
this.polygonEntity = null
|
this.curPolygon = null
|
|
// Remove edit points
|
if (this.editPolygonPointDataSource) {
|
this.editPolygonPointDataSource.entities.removeAll()
|
this.editPolygonPointDataSource = null
|
}
|
}
|
|
/**
|
* Initialize event handlers
|
* @param {Cesium.Viewer} viewer - Cesium viewer instance
|
*/
|
initHandler (viewer) {
|
this.viewer = viewer
|
this.startDrawing()
|
|
if (!this.handler) {
|
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
|
// Set up event handlers
|
const events = [
|
[Cesium.ScreenSpaceEventType.LEFT_DOWN, this.handleLeftDown],
|
[Cesium.ScreenSpaceEventType.LEFT_UP, this.handleLeftUp],
|
[Cesium.ScreenSpaceEventType.MOUSE_MOVE, this.handleMouseMove],
|
[Cesium.ScreenSpaceEventType.LEFT_CLICK, this.handleLeftClick],
|
[Cesium.ScreenSpaceEventType.RIGHT_CLICK, this.handleRightClick]
|
]
|
|
events.forEach(([type, handler]) => {
|
this.handler.setInputAction(handler, type)
|
})
|
}
|
}
|
|
/**
|
* Remove event handlers
|
*/
|
removeHandler () {
|
if (this.handler) {
|
const eventTypes = [
|
Cesium.ScreenSpaceEventType.LEFT_DOWN,
|
Cesium.ScreenSpaceEventType.LEFT_UP,
|
Cesium.ScreenSpaceEventType.MOUSE_MOVE,
|
Cesium.ScreenSpaceEventType.LEFT_CLICK,
|
Cesium.ScreenSpaceEventType.RIGHT_CLICK
|
]
|
|
eventTypes.forEach(type => {
|
this.handler.removeInputAction(type)
|
})
|
|
this.handler = null
|
}
|
}
|
|
/**
|
* Clean up and destroy the instance
|
*/
|
destroy () {
|
if (!this.viewer) return
|
|
this.removeMenuPopup()
|
this.removeEntities()
|
this.removeHandler()
|
this.enableMapControl()
|
}
|
}
|
|
export function disposeData (curPolygonPosition, polylinePoints, rthAltitudePoint) {
|
let data = [...curPolygonPosition]
|
data.push(curPolygonPosition[0])
|
|
let disposePolylinePoints = [...polylinePoints]
|
|
if (polylinePoints.length === 1) {
|
ElMessage.warning('当前高度过高,无法生成有效航线,请调整!')
|
|
disposePolylinePoints = [...polylinePoints, ...polylinePoints]
|
}
|
|
const polygon = turf.polygon([data.map(item => [item.lng, item.lat])])
|
|
const polygonArea = turf.area(polygon)
|
|
|
var line = turf.lineString(disposePolylinePoints.map(item => [item.longitude, item.latitude]))
|
var length = turf.length(line, { units: 'kilometers' })
|
|
const newPolylinePoints = disposePolylinePoints.map((item, index) => {
|
return Cesium.Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude), Number(item.height))
|
})
|
|
let polylineLength = 0
|
|
newPolylinePoints.forEach((item, index) => {
|
if (index == newPolylinePoints.length - 1) return
|
|
let point1 = item
|
let point2 = newPolylinePoints[index + 1]
|
|
polylineLength += Cesium.Cartesian3.distance(point1, point2)
|
})
|
|
const newRthAltitudePoint = rthAltitudePoint.map((item, index) => {
|
return Cesium.Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude), Number(item.height))
|
})
|
|
let rthLineLength = 0
|
|
newRthAltitudePoint.forEach((item, index) => {
|
if (index == newRthAltitudePoint.length - 1) return
|
|
let point1 = item
|
let point2 = newRthAltitudePoint[index + 1]
|
|
rthLineLength += Cesium.Cartesian3.distance(point1, point2)
|
})
|
|
return {
|
polygonArea,
|
polylineLength,
|
rthLineLength,
|
photoNum: polylinePoints.length * 3
|
}
|
}
|
|
export const getGsd = (globalSettings, gsdInfo) => {
|
if (_.isEmpty(gsdInfo) || !gsdInfo.image_height) {
|
ElMessage.warning('相机参数获取异常,请联系管理员!')
|
return
|
}
|
|
let w = gsdW(
|
globalSettings.relTerrainHeight,
|
gsdInfo.sensor_width,
|
gsdInfo.focal_length,
|
gsdInfo.image_width
|
)
|
let h = gsdH(
|
globalSettings.relTerrainHeight,
|
gsdInfo.sensor_height,
|
gsdInfo.focal_length,
|
gsdInfo.image_height
|
)
|
|
return w > h ? w : h
|
}
|
|
export const getGsdByH = (globalSettings, gsdInfo) => {
|
if (!gsdInfo && !gsdInfo.image_height) {
|
ElMessage.warning('相机参数获取异常,请联系管理员!')
|
return
|
}
|
|
let w = gsdW(
|
globalSettings.relTerrainHeight,
|
gsdInfo.sensor_width,
|
gsdInfo.focal_length,
|
gsdInfo.image_width
|
)
|
|
let h = gsdH(
|
globalSettings.relTerrainHeight,
|
gsdInfo.sensor_height,
|
gsdInfo.focal_length,
|
gsdInfo.image_height
|
)
|
|
if (w > h) {
|
return getHbyHW(
|
globalSettings.gsd,
|
gsdInfo.sensor_width,
|
gsdInfo.focal_length,
|
gsdInfo.image_width
|
)
|
} else {
|
return getHbyH(
|
globalSettings.gsd,
|
gsdInfo.sensor_height,
|
gsdInfo.focal_length,
|
gsdInfo.image_height
|
)
|
}
|
}
|
|
// 解析kmz文件的时候处理pointList 写在这里
|
export function handlePointListForKmz (placemark, templateType) {
|
if (!placemark?.length) return []
|
|
let list = []
|
|
if (templateType === "mapping2d") {
|
list = placemark.map(item => {
|
const [longitude, latitude] = item.point.coordinates.trim().split(',')
|
|
return {
|
longitude: longitude,
|
latitude: latitude,
|
height: 0,
|
|
speed: item.waypoint_speed
|
}
|
})
|
} else {
|
list = placemark.map(i => i.map(item => {
|
const [longitude, latitude] = item.point.coordinates.trim().split(',')
|
|
return {
|
longitude: longitude,
|
latitude: latitude,
|
height: 0,
|
|
speed: item.waypoint_speed
|
}
|
}))
|
}
|
|
return list
|
}
|
|
export async function analysisPlanarRouteKmz (kmzUrl) {
|
const res = await analyzeKmzFile(`${kmzUrl}?_t=${new Date().getTime()}`)
|
const templateXML = await res.fileInfoObj['wpmz/template.kml']
|
const waylinesXML = await res.fileInfoObj['wpmz/waylines.wpml']
|
const templateXMLJSON = XMLToJSON(templateXML)?.['Document']
|
const waylinesXMLJSON = XMLToJSON(waylinesXML)?.['Document']
|
const templateXMLObj = camelToSnake(removeTextKey(templateXMLJSON))
|
const waylinesXMLObj = camelToSnake(removeTextKey(waylinesXMLJSON))
|
|
const {
|
folder: {
|
auto_flight_speed,
|
payload_param: {
|
image_format
|
} = {},
|
placemark: {
|
direction: waylineAngle,
|
inclined_gimbal_pitch: inclined_gimbal_pitch = -45,
|
overlap: {
|
inclined_camera_overlap_h: inclined_camera_overlap_h,
|
inclined_camera_overlap_w: inclined_camera_overlap_w,
|
ortho_camera_overlap_w: side_ratio,
|
ortho_camera_overlap_h: course_ratio,
|
},
|
polygon,
|
margin: buffer_distance_meters = 0
|
},
|
template_type: templateType,
|
|
wayline_coordinate_sys_param: {
|
global_shoot_height
|
}
|
} = {},
|
mission_config: {
|
take_off_ref_point, // 参考起飞点
|
drone_info: { drone_enum_value, drone_sub_enum_value } = {},
|
payload_info: { payload_position_index, payload_enum_value, payload_sub_enum_value }
|
} = {},
|
} = templateXMLObj
|
|
const {
|
mission_config:
|
{
|
// 安全起飞高
|
take_off_security_height: rth_altitude
|
} = {},
|
folder: polygonPointFolder
|
} = waylinesXMLObj
|
|
let execute_height_mode = ''
|
let pointPlacemark
|
|
if (templateType === "mapping2d") {
|
execute_height_mode = polygonPointFolder.execute_height_mode
|
pointPlacemark = polygonPointFolder.placemark
|
} else {
|
execute_height_mode = polygonPointFolder[0].execute_height_mode
|
pointPlacemark = polygonPointFolder.map(i => i.placemark)
|
}
|
|
const [latitude, longitude, height] = take_off_ref_point.split(',').map(item => _.round(item, 6))
|
let startPoint = { latitude, longitude, height: Number.isNaN(height) ? 0 : height }
|
|
// 取出点位
|
const coordinates = polygon?.outer_boundary_is.linear_ring
|
.coordinates?.split('\n') || []
|
|
// 数组转换
|
let polygonList = coordinates.map((coordinate) =>
|
coordinate
|
.replace(/\s+/g, '')
|
.split(',')
|
.map((v) => Number(v)),
|
)
|
|
polygonList.pop()
|
|
let pointList = handlePointListForKmz(pointPlacemark, templateType)
|
|
return {
|
take_off_ref_point,
|
|
startPoint,
|
image_format,
|
templateType,
|
global_shoot_height,
|
rth_altitude,
|
auto_flight_speed,
|
|
waylineAngle,
|
|
side_ratio,
|
course_ratio,
|
|
inclined_camera_overlap_h,
|
inclined_camera_overlap_w,
|
|
inclined_gimbal_pitch,
|
|
drone_enum_value,
|
drone_sub_enum_value,
|
|
payload_position_index,
|
payload_enum_value,
|
payload_sub_enum_value,
|
|
execute_height_mode,
|
|
pointList,
|
polygonList,
|
|
buffer_distance_meters
|
}
|
}
|
|
// 计算gsd-H
|
function gsdH (height, ch, jj, ih) {
|
let one = Number((height * ch).toFixed(2))
|
let two = Number((jj * ih).toFixed(2))
|
let three = Number((one / two).toFixed(5))
|
let four = Number((three * 100).toFixed(2))
|
return four
|
}
|
|
function gsdW (height, cw, jj, iw) {
|
let one = Number((height * cw).toFixed(2))
|
let two = Number((jj * iw).toFixed(2))
|
let three = Number((one / two).toFixed(5))
|
let four = Number((three * 100).toFixed(2))
|
return four
|
}
|
|
// 计算gsd-H
|
function getHbyH (gsd, ch, jj, ih) {
|
let one = Number((jj * ih).toFixed(2))
|
let two = Number((gsd / 100).toFixed(4))
|
let three = Number((two * one).toFixed(4))
|
let four = Number((three / ch).toFixed(2))
|
return four
|
}
|
|
function getHbyHW (gsd, cw, jj, iw) {
|
let one = Number((jj * iw).toFixed(2))
|
let two = Number((gsd / 100).toFixed(4))
|
let three = Number((two * one).toFixed(4))
|
let four = Number((three / cw).toFixed(2))
|
return four
|
}
|
|
export function getNewPolygonData (data) {
|
const polygonData = data.reduce((pre, cur) => {
|
let arr = cur.data.map(i => {
|
if ('point' in i) return i.point.coordinates.split(',')
|
if ('Point' in i) {
|
if (_.isObject(i.Point.coordinates) && '#text' in i.Point.coordinates) return i.Point.coordinates['#text'].split(',')
|
return i.Point.coordinates.split(',')
|
}
|
}).map(i => turf.point([Number(i[0]), Number(i[1])]))
|
|
return pre.push(...arr), pre
|
}, [])
|
|
const hull = turf.convex(turf.featureCollection(polygonData))
|
|
return hull.geometry.coordinates[0]
|
}
|
|
export function getApiNewPolygonData (data) {
|
const polygonData = data.reduce((pre, cur) => {
|
let arr = cur.data.map(i => turf.point([Number(i.x), Number(i.y)]))
|
|
return pre.push(...arr), pre
|
}, [])
|
|
const hull = turf.convex(turf.featureCollection(polygonData))
|
|
return hull.geometry.coordinates[0]
|
}
|
|
export function getBufferPolygonData (data, meters = 0) {
|
const turfPolygonData = data.map(i => [i.lng, i.lat])
|
const polygon = turf.polygon([[...turfPolygonData, turfPolygonData[0]]])
|
|
const buffered = turf.buffer(polygon, meters, {
|
units: 'meters',
|
steps: 16
|
})
|
|
return buffered.geometry.coordinates[0]
|
}
|