2025-08-11 15:24:06 +08:00
|
|
|
|
import * as Cesium from 'cesium'
|
|
|
|
|
|
import CesiumNavigation from 'cesium-navigation-es6'
|
|
|
|
|
|
import 'cesium/Build/Cesium/Widgets/widgets.css'
|
|
|
|
|
|
|
|
|
|
|
|
export default class MyCesium {
|
2025-08-26 17:32:02 +08:00
|
|
|
|
static ImageryProviderUrl = '/map/mapWX/{z}/{x}/{y}.jpg'
|
2025-08-11 15:24:06 +08:00
|
|
|
|
static RoadProviderUrl = ''
|
2025-08-26 17:32:02 +08:00
|
|
|
|
static TerrainProviderUrl = '/map/mapDem/'
|
2025-08-11 15:24:06 +08:00
|
|
|
|
static center = [116.39742, 39.90906, 2000000]
|
|
|
|
|
|
static ENTITY_TYPES = {
|
|
|
|
|
|
WARZONE: 1,
|
|
|
|
|
|
SAFEZONE: 2,
|
|
|
|
|
|
MODEL: 3,
|
|
|
|
|
|
IMAGE: 4,
|
|
|
|
|
|
ROUTE: 5,
|
|
|
|
|
|
LINE: 6, // 两个模型之间的连线
|
|
|
|
|
|
POINT_PLANNING: 7, // 规划点
|
|
|
|
|
|
GRAPHICS: 8, // 折线
|
|
|
|
|
|
AIR_ROUTE: 9, // 航路
|
|
|
|
|
|
ROAMING_PLANE: 10,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
viewer = null
|
|
|
|
|
|
// 选中模型
|
|
|
|
|
|
selectedModel = null
|
|
|
|
|
|
// 右鍵菜單
|
|
|
|
|
|
contextMenu = {
|
|
|
|
|
|
visible: false,
|
|
|
|
|
|
left: 0,
|
|
|
|
|
|
top: 0,
|
|
|
|
|
|
}
|
|
|
|
|
|
// 未完成的在地图上移动类的操作
|
|
|
|
|
|
operations = []
|
|
|
|
|
|
|
2025-08-16 10:13:46 +08:00
|
|
|
|
constructor(dom, options = {}) {
|
2025-08-11 15:24:06 +08:00
|
|
|
|
const imageryProvider = new Cesium.UrlTemplateImageryProvider({
|
|
|
|
|
|
url: window._CONFIG.ImageryProviderUrl || MyCesium.ImageryProviderUrl,
|
|
|
|
|
|
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
|
|
|
|
|
maximumLevel: 15,
|
|
|
|
|
|
})
|
|
|
|
|
|
const roadProvider = new Cesium.UrlTemplateImageryProvider({
|
|
|
|
|
|
url: window._CONFIG.RoadProviderUrl || MyCesium.RoadProviderUrl,
|
|
|
|
|
|
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
|
|
|
|
|
maximumLevel: 15,
|
|
|
|
|
|
format: 'image/png',
|
|
|
|
|
|
})
|
|
|
|
|
|
const terrainProvider = new Cesium.CesiumTerrainProvider({
|
|
|
|
|
|
url: window._CONFIG.TerrainProviderUrl || MyCesium.TerrainProviderUrl,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const viewer = new Cesium.Viewer(dom, {
|
|
|
|
|
|
shouldAnimate: true, // 粒子效果
|
|
|
|
|
|
geocoder: false, // 是否显示位置查找工具(true表示是,false表示否)
|
|
|
|
|
|
homeButton: false, // 是否显示首页位置工具
|
|
|
|
|
|
sceneModePicker: false, // 是否显示视角模式切换工具
|
|
|
|
|
|
baseLayerPicker: false, // 是杏显示默认图层选择工具
|
|
|
|
|
|
navigationHelpButton: false, // 是否显示导航帮助工具
|
|
|
|
|
|
animation: false, // 是杏显示动画工具
|
|
|
|
|
|
timeline: false, // 是否显示时间轴工具
|
|
|
|
|
|
fullscreenButton: false, // 是否显示全屏按钮工具
|
|
|
|
|
|
imageryProvider,
|
|
|
|
|
|
terrainProvider,
|
|
|
|
|
|
infoBox: false, // 是否显示信息框
|
|
|
|
|
|
selectionIndicator: false, // 是否显示选中实体时的绿框
|
|
|
|
|
|
})
|
|
|
|
|
|
this.viewer = viewer
|
|
|
|
|
|
|
2025-08-16 10:13:46 +08:00
|
|
|
|
const { center = MyCesium.center } = options
|
|
|
|
|
|
|
2025-08-11 15:24:06 +08:00
|
|
|
|
// viewer.scene.globe.depthTestAgainstTerrain = true
|
|
|
|
|
|
|
|
|
|
|
|
viewer.imageryLayers.addImageryProvider(roadProvider)
|
|
|
|
|
|
viewer.camera.setView({
|
2025-08-16 10:13:46 +08:00
|
|
|
|
destination: Cesium.Cartesian3.fromDegrees(...center),
|
2025-08-11 15:24:06 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 不显示Cesium的Logo
|
|
|
|
|
|
viewer._cesiumWidget._creditContainer.style.display = 'none'
|
|
|
|
|
|
viewer.scene.sun.show = true //太阳和月亮
|
|
|
|
|
|
viewer.scene.moon.show = true
|
|
|
|
|
|
viewer.scene.skyAtmosphere.show = true //大气层,显示天空颜色
|
|
|
|
|
|
// 设置外天空盒
|
|
|
|
|
|
viewer.scene.skyBox = new Cesium.SkyBox({
|
|
|
|
|
|
sources: {
|
|
|
|
|
|
positiveX: '/images/Standard-Cube-Map/px1.png',
|
|
|
|
|
|
negativeX: '/images/Standard-Cube-Map/nx1.png',
|
|
|
|
|
|
positiveY: '/images/Standard-Cube-Map/pz.png',
|
|
|
|
|
|
negativeY: '/images/Standard-Cube-Map/nz1.png',
|
|
|
|
|
|
positiveZ: '/images/Standard-Cube-Map/py.png',
|
|
|
|
|
|
negativeZ: '/images/Standard-Cube-Map/ny1.png',
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
viewer.scene.skyBox.show = true //天空盒
|
|
|
|
|
|
|
|
|
|
|
|
// 创建指北针小部件并将其添加到地图
|
|
|
|
|
|
new CesiumNavigation(viewer, {
|
|
|
|
|
|
// 用于在使用重置导航重置地图视图时设置默认视图控制。接受的值是Cesium.Cartographic 和Cesium.Rectangle.
|
2025-08-16 10:13:46 +08:00
|
|
|
|
defaultResetView: Cesium.Cartographic.fromDegrees(...center),
|
2025-08-11 15:24:06 +08:00
|
|
|
|
// 用于启用或禁用罗盘。true是启用罗盘,false是禁用罗盘。默认值为true。如果将选项设置为false,则罗盘将不会添加到地图中。
|
|
|
|
|
|
enableCompass: true,
|
|
|
|
|
|
// 用于启用或禁用缩放控件。true是启用,false是禁用。默认值为true。如果将选项设置为false,则缩放控件 将不会添加到地图中。
|
|
|
|
|
|
enableZoomControls: true,
|
|
|
|
|
|
// 用于启用或禁用距离图例。true是启用,false是禁用。默认值为true。如果将选项设置为false,距离图例将不会添加到地图中。
|
|
|
|
|
|
enableDistanceLegend: true,
|
|
|
|
|
|
// 用于启用或禁用指南针外环。true是启用,false是禁用。默认值为true。如果将选项设置为false,则该环将可见但无效。
|
|
|
|
|
|
enableCompassOuterRing: true,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
|
|
|
|
|
handler.setInputAction(({ position }) => {
|
|
|
|
|
|
if (this.selectedModel) {
|
|
|
|
|
|
this.deselectModel(this.selectedModel)
|
|
|
|
|
|
this.selectedModel = null
|
|
|
|
|
|
}
|
|
|
|
|
|
const pickedObject = viewer.scene.pick(position)
|
|
|
|
|
|
if (!Cesium.defined(pickedObject) || !pickedObject.id) {
|
|
|
|
|
|
window.Emit('pickedObject', null)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const entity = pickedObject.id
|
|
|
|
|
|
if (
|
|
|
|
|
|
!entity.properties ||
|
|
|
|
|
|
(entity.properties.type != MyCesium.ENTITY_TYPES.MODEL && entity.properties.type != MyCesium.ENTITY_TYPES.IMAGE)
|
|
|
|
|
|
) {
|
|
|
|
|
|
window.Emit('pickedObject', null)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
this.selectedModel = entity
|
|
|
|
|
|
this.selectModel(entity)
|
|
|
|
|
|
window.Emit('selectedModel', {
|
|
|
|
|
|
id: entity.id,
|
|
|
|
|
|
})
|
|
|
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
|
|
|
|
|
|
|
|
|
|
// 鼠标右键事件
|
|
|
|
|
|
handler.setInputAction(({ position }) => {
|
|
|
|
|
|
const pickedObject = viewer.scene.pick(position)
|
|
|
|
|
|
if (!Cesium.defined(pickedObject) || !pickedObject.id) return
|
|
|
|
|
|
const entity = pickedObject.id
|
|
|
|
|
|
const properties = entity.properties
|
|
|
|
|
|
if (
|
|
|
|
|
|
!properties ||
|
|
|
|
|
|
!properties.type ||
|
|
|
|
|
|
(properties.type != MyCesium.ENTITY_TYPES.MODEL && properties.type != MyCesium.ENTITY_TYPES.IMAGE)
|
|
|
|
|
|
) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const nomove = properties.nomove
|
|
|
|
|
|
if (selectedModel && entity.id == selectedModel.id && !(nomove && nomove.valueOf())) {
|
|
|
|
|
|
this.showContextMenu(entity)
|
|
|
|
|
|
this.cancelPreviousOperation()
|
|
|
|
|
|
}
|
|
|
|
|
|
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
|
|
|
|
|
|
|
|
|
|
|
|
// shift + 左键事件
|
|
|
|
|
|
handler.setInputAction(
|
|
|
|
|
|
({ position }) => {
|
|
|
|
|
|
const pickedObject = viewer.scene.pick(position)
|
|
|
|
|
|
if (!Cesium.defined(pickedObject) || !pickedObject.id) return
|
|
|
|
|
|
const entity = pickedObject.id
|
|
|
|
|
|
if (!entity.properties || entity.properties.type != MyCesium.ENTITY_TYPES.MODEL) return
|
|
|
|
|
|
if (this.selectedModel) {
|
|
|
|
|
|
// 找到已有的properties中的from和to是选中的两个模型的id的线
|
|
|
|
|
|
const find = viewer.entities.values.find((item) => {
|
|
|
|
|
|
const props = item.properties
|
|
|
|
|
|
if (!props || !props.type || !props.from || !props.to) return false
|
|
|
|
|
|
return (
|
|
|
|
|
|
(props.from == this.selectedModel.id && props.to == entity.id) ||
|
|
|
|
|
|
(props.from == entity.id && props.to == this.selectedModel.id)
|
|
|
|
|
|
)
|
|
|
|
|
|
})
|
|
|
|
|
|
// 如果已经有了,移除
|
|
|
|
|
|
if (find) {
|
|
|
|
|
|
viewer.entities.remove(find)
|
|
|
|
|
|
const { from, to } = find.properties
|
|
|
|
|
|
// 发送删除线的事件
|
|
|
|
|
|
window.Emit('removeLineBetwenModel', {
|
|
|
|
|
|
id: find.id,
|
|
|
|
|
|
from: from.valueOf(),
|
|
|
|
|
|
to: to.valueOf(),
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const id = Cesium.createGuid()
|
|
|
|
|
|
const currentTime = viewer.clock.currentTime
|
|
|
|
|
|
const positions = [this.selectedModel.position.getValue(currentTime), entity.position.getValue(currentTime)]
|
|
|
|
|
|
if (positions.some((item) => !item)) {
|
|
|
|
|
|
console.log('缺少位置信息')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
this.addLineBetwenModel(id, positions, selectedModel.id, entity.id)
|
|
|
|
|
|
// 发送添加线的事件
|
|
|
|
|
|
window.Emit('addLineBetwenModel', {
|
|
|
|
|
|
positions,
|
|
|
|
|
|
id,
|
|
|
|
|
|
from: selectedModel.id,
|
|
|
|
|
|
to: entity.id,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
Cesium.ScreenSpaceEventType.LEFT_CLICK,
|
|
|
|
|
|
Cesium.KeyboardEventModifier.SHIFT
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 选中模型
|
|
|
|
|
|
* @param {Cesium.Entity} entity
|
|
|
|
|
|
*/
|
|
|
|
|
|
selectModel(entity) {
|
|
|
|
|
|
if (!entity.model) return
|
|
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
|
properties: { color: _color },
|
|
|
|
|
|
} = entity
|
|
|
|
|
|
const color = _color.valueOf()
|
|
|
|
|
|
// 设置模型轮廓效果
|
|
|
|
|
|
entity.model.silhouetteSize = 2 // 轮廓线宽度
|
|
|
|
|
|
entity.model.silhouetteColor = Cesium.Color.fromCssColorString(color)
|
|
|
|
|
|
entity.label.show = true
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 取消选中模型
|
|
|
|
|
|
* @param {Cesium.Entity} entity
|
|
|
|
|
|
*/
|
|
|
|
|
|
deselectModel(entity) {
|
|
|
|
|
|
if (!entity.model) return
|
|
|
|
|
|
|
|
|
|
|
|
entity.model.silhouetteSize = 0 // 设置为0取消轮廓
|
|
|
|
|
|
entity.label.show = false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 显示右键菜单
|
|
|
|
|
|
* @param {Cesium.Entity} entity
|
|
|
|
|
|
*/
|
|
|
|
|
|
showContextMenu(entity) {
|
|
|
|
|
|
const currentTime = viewer.clock.currentTime
|
|
|
|
|
|
// 获取entity中心点的屏幕坐标
|
|
|
|
|
|
const position = entity.position.getValue(currentTime)
|
|
|
|
|
|
const screenPosition = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, position)
|
|
|
|
|
|
|
|
|
|
|
|
this.contextMenu.left = screenPosition.x + 20
|
|
|
|
|
|
this.contextMenu.top = screenPosition.y
|
|
|
|
|
|
this.contextMenu.visible = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 取消未完成的在地图上移动类的操作(划线之类的)
|
|
|
|
|
|
cancelPreviousOperation() {
|
|
|
|
|
|
this.operations.forEach((operation) => operation.clear())
|
|
|
|
|
|
this.operations = []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 在模型之间添加线
|
|
|
|
|
|
* @param id
|
|
|
|
|
|
* @param { Cesium.Cartesian3[] } positions
|
|
|
|
|
|
* @param fromId
|
|
|
|
|
|
* @param toId
|
|
|
|
|
|
*/
|
|
|
|
|
|
addLineBetwenModel(id, positions, fromId, toId) {
|
|
|
|
|
|
this.viewer.entities.add({
|
|
|
|
|
|
id,
|
|
|
|
|
|
polyline: {
|
|
|
|
|
|
positions,
|
|
|
|
|
|
width: 2,
|
|
|
|
|
|
material: new Cesium.PolylineDashMaterialProperty({
|
|
|
|
|
|
color: Cesium.Color.YELLOW,
|
|
|
|
|
|
dashLength: 20, //短划线长度
|
|
|
|
|
|
}),
|
|
|
|
|
|
clampToGround: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
type: MyCesium.ENTITY_TYPES.LINE,
|
|
|
|
|
|
from: fromId,
|
|
|
|
|
|
to: toId,
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-08-16 10:13:46 +08:00
|
|
|
|
|
|
|
|
|
|
setViewerByAllCorner(leftUp, rightUp, rightDown, leftDown) {
|
|
|
|
|
|
const [leftUpLon, leftUpLat] = leftUp
|
|
|
|
|
|
const [rightUpLon, rightUpLat] = rightUp
|
|
|
|
|
|
const [rightDownLon, rightDownLat] = rightDown
|
|
|
|
|
|
const [leftDownLon, leftDownLat] = leftDown
|
|
|
|
|
|
// 计算矩形区域的边界
|
|
|
|
|
|
const west = Math.min(leftDownLon, leftUpLon, rightDownLon, rightUpLon)
|
|
|
|
|
|
const east = Math.max(leftDownLon, leftUpLon, rightDownLon, rightUpLon)
|
|
|
|
|
|
const south = Math.min(leftDownLat, leftUpLat, rightDownLat, rightUpLat)
|
|
|
|
|
|
const north = Math.max(leftDownLat, leftUpLat, rightDownLat, rightUpLat)
|
|
|
|
|
|
// 创建矩形范围
|
|
|
|
|
|
const rectangle = Cesium.Rectangle.fromDegrees(west, south, east, north)
|
|
|
|
|
|
this.viewer.camera.setView({
|
|
|
|
|
|
destination: rectangle,
|
|
|
|
|
|
orientation: {
|
|
|
|
|
|
heading: 0.0,
|
|
|
|
|
|
pitch: -Cesium.Math.PI_OVER_TWO,
|
|
|
|
|
|
roll: 0.0,
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-08-11 15:24:06 +08:00
|
|
|
|
}
|