import * as Cesium from 'cesium'
|
import * as turf from '@turf/turf'
|
import { boxTransformScale } from '@/utils/turfFunc'
|
import { ElMessage } from 'element-plus'
|
import { flyVisual, getPointPositionsHeight } from '@/utils/cesium/mapUtil'
|
|
/**
|
* 多边形绘制与编辑工具类
|
* 功能:
|
* - 绘制多边形
|
* - 拖动编辑端点
|
* - 删除端点、删除整个多边形
|
* - 多边形自交检查(避免非法几何)
|
* - 外部订阅/通知机制
|
*/
|
export class DrawPolygon {
|
constructor() {
|
// 图斑预览模式标记
|
this.isPureSpotPreview = false
|
// 是否删除测区
|
this.isDeleteTheArea = true
|
//是否可以编辑图斑
|
this.isPreviewMode = true
|
// Cesium 视图对象
|
this.viewer = null
|
// 当前绘制的多边形
|
this.curPolygon = null
|
// 绘制模式标识
|
this.drawingMode = false
|
// 编辑模式标识
|
this.editingMode = false
|
// 是否正在拖拽端点
|
this.isDragging = false
|
// 当前拖拽的点实体
|
this.draggedEntity = null
|
// 多边形实体
|
this.polygonEntity = null
|
// 存储端点的 DataSource
|
this.editPolygonDataSource = null
|
this.editPolygonPointDataSource = null
|
// 存储中点(边中点)的 DataSource:用于编辑态插入新端点
|
this.editPolygonMidPointDataSource = null
|
// 鼠标事件处理器
|
this.handler = null
|
// 右键菜单 DOM
|
this.menuPopup = null
|
// 被右键选中的点
|
this.delPolygonPoint = null
|
// 是否显示警告提示(自交)
|
this.isShowWaringTip = false
|
// 当前拖拽点是否合法
|
this.currentDragPointIsValid = false
|
// 当前拖拽点的坐标
|
this.currentDragPointPosition = null
|
|
// 事件回调函数绑定 this
|
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)
|
// 外部订阅者
|
this.listeners = []
|
}
|
|
// 实体命名常量
|
static ENTITY_NAMES = {
|
POLYGON: '区域-面',
|
POINT: '区域-端点',
|
// 编辑态中点(用于快速插入新端点)
|
MID_POINT: '区域-中点',
|
POLYGON_ID: 'planar-route-polygon',
|
POINT_ID_PREFIX: 'planar-route-point',
|
MID_POINT_ID_PREFIX: 'planar-route-mid-point',
|
}
|
|
// 颜色常量
|
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)'), // 错误(自交)线颜色
|
}
|
|
// ============ 发布订阅机制 ============
|
|
// 外部订阅数据变化
|
subscribe(key, listener) {
|
this.listeners.push({ key, listener })
|
}
|
|
// 通知订阅者
|
notify(key, data) {
|
this.listeners.filter(subscriber => subscriber.key === key).forEach(subscriber => subscriber.listener(data))
|
}
|
|
// ============ 绘制相关 ============
|
// 编辑图斑
|
editThePatch(data) {
|
this.isPreviewMode = data
|
// 关闭编辑能力时隐藏端点/中点,并清空中点,避免残留交互
|
if (!this.isPreviewMode) {
|
this.editPolygonPointDataSource && (this.editPolygonPointDataSource.entities.show = false)
|
this.editPolygonMidPointDataSource && (this.editPolygonMidPointDataSource.entities.show = false)
|
this.editPolygonMidPointDataSource?.entities?.removeAll?.()
|
return
|
}
|
|
if (this.editingMode) {
|
this.editPolygonPointDataSource && (this.editPolygonPointDataSource.entities.show = true)
|
this.editPolygonMidPointDataSource && (this.editPolygonMidPointDataSource.entities.show = true)
|
this.rebuildEditPoints()
|
this.rebuildMidPoints()
|
}
|
}
|
// 删除测区
|
deleteTheArea(data) {
|
this.isDeleteTheArea = data
|
}
|
|
// 开始绘制
|
startDrawing() {
|
this.drawingMode = true
|
this.curPolygon = new Cesium.PolygonHierarchy()
|
|
// 如果还没有 DataSource,就新建一个
|
if (!this.editPolygonDataSource) {
|
this.editPolygonDataSource = new Cesium.CustomDataSource('editPolygonDataSource')
|
this.viewer?.dataSources.add(this.editPolygonDataSource)
|
}
|
|
if (!this.editPolygonPointDataSource) {
|
this.editPolygonPointDataSource = new Cesium.CustomDataSource('editPolygonPointDataSource')
|
this.viewer?.dataSources.add(this.editPolygonPointDataSource)
|
}
|
|
// 中点数据源:编辑模式下用于“边上插点”
|
if (!this.editPolygonMidPointDataSource) {
|
this.editPolygonMidPointDataSource = new Cesium.CustomDataSource('editPolygonMidPointDataSource')
|
this.viewer?.dataSources.add(this.editPolygonMidPointDataSource)
|
}
|
|
// 清空之前的点
|
this.editPolygonDataSource?.entities.removeAll()
|
this.editPolygonPointDataSource?.entities.removeAll()
|
this.editPolygonMidPointDataSource?.entities.removeAll()
|
}
|
|
// 创建多边形实体(含边界线)
|
createPolygonEntity() {
|
this.polygonEntity = this.editPolygonDataSource.entities.add({
|
name: DrawPolygon.ENTITY_NAMES.POLYGON,
|
id: DrawPolygon.ENTITY_NAMES.POLYGON_ID,
|
polygon: {
|
hierarchy: new Cesium.CallbackProperty(() => this.curPolygon, false),
|
material: DrawPolygon.COLORS.DEFAULT_POLYGON,
|
outline: false,
|
outlineWidth: 2,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
},
|
polyline: {
|
width: 2,
|
material: DrawPolygon.COLORS.DEFAULT_LINE,
|
clampToGround: true,
|
positions: new Cesium.CallbackProperty(
|
() => [...this.curPolygon.positions, this.curPolygon.positions[0]], // 闭合线
|
false
|
),
|
},
|
})
|
}
|
|
// 创建端点实体
|
createPointEntity(position, isAdd) {
|
const pointIndex = isAdd ? this.curPolygon.positions.length - 2 : this.curPolygon.positions.length - 1
|
|
this.editPolygonPointDataSource.entities.add({
|
name: DrawPolygon.ENTITY_NAMES.POINT,
|
id: `${DrawPolygon.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, // 索引记录
|
},
|
})
|
}
|
|
createMidPointEntity(startInd, position) {
|
// 使用 CallbackProperty 让中点位置随端点拖拽实时计算
|
// startInd 表示该中点属于边:(startInd) -> (startInd + 1)
|
const updatePosition = () => {
|
const positions = this.curPolygon?.positions
|
if (!positions || positions.length < 2) return position
|
|
const n = positions.length
|
const p1 = positions[startInd]
|
const p2 = positions[(startInd + 1) % n]
|
if (!p1 || !p2) return position
|
|
return Cesium.Cartesian3.midpoint(p1, p2, new Cesium.Cartesian3())
|
}
|
|
this.editPolygonMidPointDataSource.entities.add({
|
name: DrawPolygon.ENTITY_NAMES.MID_POINT,
|
id: `${DrawPolygon.ENTITY_NAMES.MID_POINT_ID_PREFIX}${startInd}`,
|
position: new Cesium.CallbackProperty(updatePosition, false),
|
point: {
|
pixelSize: 10,
|
color: Cesium.Color.fromCssColorString('rgba(255, 255, 255, .7)'),
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
customData: {
|
startInd,
|
},
|
})
|
}
|
|
rebuildEditPoints() {
|
// 插入/删除端点后:端点实体 id 与 customData.ind 需要全量重建,保证索引与 positions 一致
|
if (!this.isPreviewMode) return
|
if (!this.editPolygonPointDataSource || !this.curPolygon?.positions) return
|
|
this.editPolygonPointDataSource.entities.removeAll()
|
this.curPolygon.positions.forEach((position, index) => {
|
this.editPolygonPointDataSource.entities.add({
|
name: DrawPolygon.ENTITY_NAMES.POINT,
|
id: `${DrawPolygon.ENTITY_NAMES.POINT_ID_PREFIX}${index}`,
|
position: position.clone(),
|
point: {
|
pixelSize: 14,
|
color: Cesium.Color.WHITE,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
customData: {
|
ind: index,
|
},
|
})
|
})
|
}
|
|
rebuildMidPoints() {
|
// 仅在“顶点数量变化/切换编辑态”时维护中点实体数量
|
// 拖拽过程中中点位置由 CallbackProperty 自动更新,不需要重建
|
if (!this.isPreviewMode) return
|
if (!this.editPolygonMidPointDataSource || !this.curPolygon?.positions) return
|
|
const positions = this.curPolygon.positions
|
const n = positions.length
|
const entities = this.editPolygonMidPointDataSource.entities
|
|
if (!this.editingMode || n < 2) {
|
entities.removeAll()
|
return
|
}
|
|
const neededIds = new Set()
|
for (let i = 0; i < n; i += 1) {
|
const id = `${DrawPolygon.ENTITY_NAMES.MID_POINT_ID_PREFIX}${i}`
|
neededIds.add(id)
|
// 缺少则补齐:保证每条边都有一个中点实体
|
if (!entities.getById(id)) {
|
const p1 = positions[i]
|
const p2 = positions[(i + 1) % n]
|
if (!p1 || !p2) continue
|
const mid = Cesium.Cartesian3.midpoint(p1, p2, new Cesium.Cartesian3())
|
this.createMidPointEntity(i, mid)
|
}
|
}
|
|
entities.values.slice().forEach(entity => {
|
if (entity?.name !== DrawPolygon.ENTITY_NAMES.MID_POINT) return
|
// 多余则移除:例如删除端点导致边数量减少
|
if (!neededIds.has(entity.id)) {
|
entities.remove(entity)
|
}
|
})
|
}
|
|
insertPointFromMidPoint(midPointEntity) {
|
// 点击中点:在对应边上插入一个新端点(白点),并立即进入拖拽态
|
if (!this.isPreviewMode) return
|
if (!this.editingMode) return
|
if (!midPointEntity?.customData) return
|
|
const startInd = midPointEntity.customData.startInd
|
// 中点位置可能是 CallbackProperty,需要取当前时刻的值
|
const positionProperty = midPointEntity.position
|
const entityPosition = positionProperty?.getValue
|
? positionProperty.getValue(Cesium.JulianDate.now())
|
: positionProperty
|
if (!entityPosition) return
|
|
// 插入到 startInd 与 startInd+1 之间
|
const insertIndex = Math.min(Math.max(startInd + 1, 0), this.curPolygon.positions.length)
|
this.curPolygon.positions.splice(insertIndex, 0, entityPosition.clone ? entityPosition.clone() : entityPosition)
|
|
this.rebuildEditPoints()
|
this.rebuildMidPoints()
|
|
const newPointEntity = this.editPolygonPointDataSource?.entities?.getById(
|
`${DrawPolygon.ENTITY_NAMES.POINT_ID_PREFIX}${insertIndex}`
|
)
|
if (newPointEntity) {
|
this.isDragging = true
|
this.draggedEntity = newPointEntity
|
this.currentDragPointPosition = this.curPolygon.positions[insertIndex]
|
this.disableMapControl()
|
}
|
this.notify('getPolygonPositions', this.curPolygon.positions)
|
}
|
// 清除不在范围内的点
|
removeLastInvalidPoint() {
|
const posLen = this.curPolygon.positions.length
|
if (posLen === 0) return
|
|
let targetPointId = ''
|
let removeCount = 0
|
|
if (posLen === 2) {
|
removeCount = 2
|
targetPointId = `${DrawPolygon.ENTITY_NAMES.POINT_ID_PREFIX}0`
|
} else if (posLen > 2) {
|
removeCount = 1
|
const pointIndex = posLen - 2
|
targetPointId = `${DrawPolygon.ENTITY_NAMES.POINT_ID_PREFIX}${pointIndex}`
|
}
|
|
this.curPolygon.positions.splice(posLen - removeCount, removeCount)
|
|
const invalidPoint = this.editPolygonPointDataSource.entities.getById(targetPointId)
|
if (invalidPoint) {
|
this.editPolygonPointDataSource.entities.remove(invalidPoint)
|
}
|
|
if (this.curPolygon.positions.length === 0 && this.polygonEntity) {
|
this.editPolygonDataSource.entities.remove(this.polygonEntity)
|
this.polygonEntity = null
|
}
|
}
|
// 添加一个点
|
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()
|
}
|
|
// 创建端点实体
|
if (this.isPreviewMode) {
|
this.createPointEntity(position, isAdd)
|
}
|
|
this.notify('getPoints', position)
|
}
|
|
// ============ 鼠标事件 ============
|
|
// 鼠标左键按下(选中端点拖动)
|
handleLeftDown(movement) {
|
if (!this.editingMode) return
|
|
const pickedEntity = this.viewer.scene.pick(movement.position)?.id
|
const isPoint = pickedEntity?.name === DrawPolygon.ENTITY_NAMES.POINT
|
const isMidPoint = pickedEntity?.name === DrawPolygon.ENTITY_NAMES.MID_POINT
|
|
if (pickedEntity && isPoint) {
|
this.isDragging = true
|
this.draggedEntity = pickedEntity
|
this.currentDragPointPosition = this.curPolygon.positions[this.draggedEntity?.customData.ind]
|
this.disableMapControl() // 禁止地图交互
|
return
|
}
|
|
if (pickedEntity && isMidPoint) {
|
this.insertPointFromMidPoint(pickedEntity)
|
}
|
}
|
|
// 鼠标左键抬起(拖拽结束)
|
handleLeftUp() {
|
if (!(this.editingMode && 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.isShowWaringTip = true
|
this.currentDragPointIsValid = true
|
this.updatePolygonAppearance(DrawPolygon.COLORS.ERROR_POLYGON, DrawPolygon.COLORS.ERROR_LINE)
|
} else {
|
this.isShowWaringTip = false
|
this.currentDragPointIsValid = false
|
this.updatePolygonAppearance(DrawPolygon.COLORS.DEFAULT_POLYGON, DrawPolygon.COLORS.DEFAULT_LINE)
|
}
|
|
this.notify('getShowWaringTip', this.isShowWaringTip)
|
}
|
|
// 拖拽结束,恢复交互
|
if (this.isDragging) {
|
this.notify('getPolygonPositions', this.curPolygon.positions)
|
this.isDragging = false
|
this.draggedEntity = null
|
this.enableMapControl()
|
this.rebuildMidPoints()
|
}
|
}
|
|
// 鼠标移动
|
handleMouseMove(movement) {
|
if (!this.drawingMode && !this.editingMode) return
|
|
const cartesian = this.viewer.scene.pickPosition(movement.endPosition)
|
if (!cartesian) return
|
|
// 编辑模式下,拖拽点实时更新
|
if (this.editingMode && 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.editingMode && this.draggedEntity?.customData) ||
|
(this.drawingMode && this.polygonEntity && this.curPolygon.positions.length >= 3)
|
) {
|
if (!this.curDragPointIsValid(this.curPolygon.positions)) {
|
this.isShowWaringTip = true
|
this.currentDragPointIsValid = true
|
this.updatePolygonAppearance(DrawPolygon.COLORS.ERROR_POLYGON, DrawPolygon.COLORS.ERROR_LINE)
|
} else {
|
this.isShowWaringTip = false
|
this.currentDragPointIsValid = false
|
this.updatePolygonAppearance(DrawPolygon.COLORS.DEFAULT_POLYGON, DrawPolygon.COLORS.DEFAULT_LINE)
|
}
|
|
this.notify('getShowWaringTip', this.isShowWaringTip)
|
}
|
}
|
|
// 鼠标左键点击
|
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 === DrawPolygon.ENTITY_NAMES.POINT)
|
const isPolygon = pickedAllEntity.find(i => i.id.name === DrawPolygon.ENTITY_NAMES.POLYGON)
|
|
if (isStartPoint) return
|
|
// 如果不是绘制模式
|
if (!this.drawingMode) {
|
if (!isPolygon) {
|
this.editingMode = false
|
this.editPolygonPointDataSource.entities.show = false
|
this.editPolygonMidPointDataSource && (this.editPolygonMidPointDataSource.entities.show = false)
|
return
|
}
|
|
if (isPolygon) {
|
this.editingMode = true
|
this.editPolygonPointDataSource.entities.show = true
|
this.editPolygonMidPointDataSource && (this.editPolygonMidPointDataSource.entities.show = true)
|
this.rebuildMidPoints()
|
}
|
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
|
|
let arr = [...this.curPolygon.positions]
|
arr.pop()
|
// 校验多边形是否自交
|
if (arr.length > 2 && !this.curDragPointIsValid([...arr, cartesian])) {
|
ElMessage.warning('测区不支持交叉绘制,请重新绘制')
|
return
|
}
|
|
this.addPosition(cartesian)
|
}
|
|
// 鼠标右键点击(弹出菜单)
|
handleRightClick(click) {
|
const that = this
|
if (that.drawingMode) return
|
|
that.removeMenuPopup()
|
|
const pickedAllEntity = that.viewer.scene.drillPick(click.position).filter(i => i.id)
|
const isPolygon = pickedAllEntity.find(i => i.id.name === DrawPolygon.ENTITY_NAMES.POLYGON)
|
const isEditPoint = pickedAllEntity.find(i => i.id.name === DrawPolygon.ENTITY_NAMES.POINT)
|
const {
|
position: { x, y },
|
} = click
|
|
let pickedEntity, tooltipEvent, menuType
|
if (isEditPoint) {
|
pickedEntity = isEditPoint
|
tooltipEvent = that.delPoint
|
menuType = 'edit-point'
|
} else if (isPolygon) {
|
pickedEntity = isPolygon
|
tooltipEvent = that.delPolygon
|
menuType = 'polygon'
|
}
|
|
if (pickedEntity && this.isDeleteTheArea) {
|
that.delPolygonPoint = pickedEntity.id
|
that.menuPopup = that.createMenuPopup(menuType)
|
that.menuPopup.style.transform = `translate3d(${x - 10}px, ${y - 10}px, 0)`
|
that.viewer.container.appendChild(that.menuPopup)
|
that.menuPopup.addEventListener('click', tooltipEvent)
|
}
|
}
|
|
// ============ 删除相关 ============
|
|
// 删除所有实体
|
removeEntities() {
|
if (this.editPolygonDataSource) {
|
this.editPolygonDataSource.entities.removeAll()
|
this.editPolygonDataSource = null
|
}
|
|
if (this.editPolygonPointDataSource) {
|
this.editPolygonPointDataSource.entities.removeAll()
|
this.editPolygonPointDataSource = null
|
}
|
|
if (this.editPolygonMidPointDataSource) {
|
this.editPolygonMidPointDataSource.entities.removeAll()
|
this.editPolygonMidPointDataSource = null
|
}
|
this.editingMode = false
|
this.polygonEntity = null
|
this.curPolygon = null
|
}
|
|
// 完成绘制
|
finishDrawing() {
|
this.curPolygon.positions.pop()
|
|
if (this.curPolygon.positions.length >= 3) {
|
this.drawingMode = false
|
this.editingMode = true
|
this.editPolygonPointDataSource.entities.show = true
|
this.editPolygonMidPointDataSource && (this.editPolygonMidPointDataSource.entities.show = true)
|
this.rebuildMidPoints()
|
|
if (!this.curDragPointIsValid(this.curPolygon.positions)) {
|
this.isShowWaringTip = true
|
this.currentDragPointIsValid = true
|
this.updatePolygonAppearance(DrawPolygon.COLORS.ERROR_POLYGON, DrawPolygon.COLORS.ERROR_LINE)
|
} else {
|
this.isShowWaringTip = false
|
this.currentDragPointIsValid = false
|
this.updatePolygonAppearance(DrawPolygon.COLORS.DEFAULT_POLYGON, DrawPolygon.COLORS.DEFAULT_LINE)
|
}
|
|
this.notify('getShowWaringTip', this.isShowWaringTip)
|
this.notify('getPolygonPositions', this.curPolygon.positions)
|
}
|
}
|
|
// 删除多边形
|
delPolygon() {
|
this.removeEntities()
|
this.removeMenuPopup()
|
this.notify('getPolygonPositions', [])
|
this.startDrawing()
|
}
|
// 删除图斑
|
delSpot() {
|
this.removeEntities()
|
this.isPreviewMode = true
|
this.startDrawing()
|
}
|
// 删除端点
|
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.removeMenuPopup()
|
this.rebuildEditPoints()
|
this.rebuildMidPoints()
|
|
this.notify('getPolygonPositions', this.curPolygon.positions)
|
}
|
|
// ============ 工具方法 ============
|
|
// 创建右键菜单
|
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)
|
})
|
this.isPreviewMode = true
|
menuPopupVBox.appendChild(menuPopup)
|
return menuPopupVBox
|
}
|
|
// 移除菜单
|
removeMenuPopup() {
|
const that = this
|
if (that.menuPopup) {
|
that.menuPopup.removeEventListener('click', that.delPolygon)
|
that.menuPopup.removeEventListener('click', that.delPoint)
|
that.viewer.container.removeChild(that.menuPopup)
|
that.menuPopup = null
|
}
|
that.delPolygonPoint = null
|
}
|
|
// 更新多边形样式(正常/错误)
|
updatePolygonAppearance(polygonColor, lineColor) {
|
this.polygonEntity.polygon.material = polygonColor
|
this.polygonEntity.polyline.material = lineColor
|
}
|
|
// 禁用地图交互
|
disableMapControl() {
|
const controller = this.viewer.scene.screenSpaceCameraController
|
controller.enableRotate = false
|
controller.enableTranslate = false
|
controller.enableZoom = false
|
}
|
|
// 启用地图交互
|
enableMapControl() {
|
const controller = this.viewer.scene.screenSpaceCameraController
|
controller.enableRotate = true
|
controller.enableTranslate = true
|
controller.enableZoom = true
|
}
|
|
// 检查多边形是否自交
|
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),
|
])
|
|
// 用 turf.js 检查自交
|
const poly = turf.polygon([[...latLngPoints, latLngPoints[0]]])
|
const intersections = turf.kinks(poly)
|
|
return intersections.features.length === 0
|
}
|
// 初始化已有多边形
|
async initPolygon(viewer, positions, isPurePreview = false) {
|
this.initHandler(viewer)
|
this.isPureSpotPreview = isPurePreview
|
this.startDrawing()
|
let newPosition = positions.map(item => {
|
return Cesium.Cartesian3.fromDegrees(Number(item.lng), Number(item.lat), Number(item?.height || 0))
|
})
|
// 预览航线的时候调用
|
if (!this.isPureSpotPreview) {
|
this.notify('getPolygonPositions', newPosition)
|
}
|
|
newPosition.forEach(item => {
|
this.addPosition(item, 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,
|
})
|
|
let pointList = await getPointPositionsHeight(positions, viewer)
|
flyVisual({ positionsData: pointList.map(item => [item.lng, item.lat, item.ASL]), viewer })
|
|
this.drawingMode = false
|
this.editingMode = true
|
this.editPolygonPointDataSource && (this.editPolygonPointDataSource.entities.show = true)
|
this.editPolygonMidPointDataSource && (this.editPolygonMidPointDataSource.entities.show = true)
|
this.rebuildMidPoints()
|
}
|
|
// 初始化事件处理器
|
initHandler(viewer) {
|
this.viewer = viewer
|
this.startDrawing()
|
|
if (!this.handler) {
|
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
|
// 注册鼠标事件
|
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)
|
})
|
}
|
}
|
|
// 移除事件处理器
|
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
|
}
|
}
|
|
/**
|
* 销毁实例,释放资源
|
*/
|
destroy() {
|
if (!this.viewer) return
|
|
this.removeMenuPopup()
|
this.removeEntities()
|
this.removeHandler()
|
this.enableMapControl()
|
}
|
}
|