import * as Cesium from 'cesium' import CesiumNavigation from 'cesium-navigation-es6' import 'cesium/Build/Cesium/Widgets/widgets.css' const getCatesian3FromPX = (viewer, px) => { const picks = viewer.scene.drillPick(px) viewer.scene.render() let cartesian let isOn3dtiles = false for (var i = 0; i < picks.length; i++) { if (picks[i] && picks[i].primitive && picks[i].primitive instanceof Cesium.Cesium3DTileset) { //模型上拾取 isOn3dtiles = true break } } if (isOn3dtiles) { cartesian = viewer.scene.pickPosition(px) } else { var ray = viewer.camera.getPickRay(px) if (!ray) return null cartesian = viewer.scene.globe.pick(ray, viewer.scene) } return cartesian } export default class MyCesium { static ImageryProviderUrl = '/map/mapWX/{z}/{x}/{y}.jpg' static RoadProviderUrl = '' static TerrainProviderUrl = '/map/mapDem/' 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 // 未完成的在地图上移动类的操作 operations = [] // 已添加的军标 plots = [] constructor(dom, options = {}) { 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 const { center = MyCesium.center } = options // viewer.scene.globe.depthTestAgainstTerrain = true viewer.imageryLayers.addImageryProvider(roadProvider) viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(...center), }) // 不显示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. defaultResetView: Cesium.Cartographic.fromDegrees(...center), // 用于启用或禁用罗盘。true是启用罗盘,false是禁用罗盘。默认值为true。如果将选项设置为false,则罗盘将不会添加到地图中。 enableCompass: true, // 用于启用或禁用缩放控件。true是启用,false是禁用。默认值为true。如果将选项设置为false,则缩放控件 将不会添加到地图中。 enableZoomControls: true, // 用于启用或禁用距离图例。true是启用,false是禁用。默认值为true。如果将选项设置为false,距离图例将不会添加到地图中。 enableDistanceLegend: true, // 用于启用或禁用指南针外环。true是启用,false是禁用。默认值为true。如果将选项设置为false,则该环将可见但无效。 enableCompassOuterRing: true, }) } // 取消未完成的在地图上移动类的操作(划线之类的) cancelPreviousOperation() { this.operations.forEach((operation) => operation.clear()) this.operations = [] } /** * 根据四个角落坐标确定视口位置 * @param leftUp * @param rightUp * @param rightDown * @param leftDown */ setClientByAllCorner(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, }, }) } /** * 添加军标(base64图片) * @param base64 * @param x * @param y */ addPlot(base64, screenPosition) { this.cancelPreviousOperation() const position = getCatesian3FromPX(this.viewer, screenPosition) if (!position) return false const id = Cesium.createGuid() const isEnemy = false const color = 'red' const radius = 150000 const plot = { id, position, billboard: { image: base64, width: 50, height: 50, eyeOffset: new Cesium.Cartesian3(0.0, 0.0, -100000.0), // 使标记在远处看起来更大 }, ellipse: { semiMajorAxis: radius, semiMinorAxis: radius, material: Cesium.Color.fromCssColorString('transparent'), outline: true, outlineWidth: 1, outlineColor: Cesium.Color.fromCssColorString(color), height: 0, }, properties: { type: MyCesium.ENTITY_TYPES.IMAGE, color, isEnemy, radius, collisions: new Set(), }, } this.viewer.entities.add(plot) this.plots.push(plot) // 1. 将屏幕坐标转换为世界坐标(在椭球体表面) const cartesian = this.viewer.camera.pickEllipsoid(screenPosition, this.viewer.scene.globe.ellipsoid) if (Cesium.defined(cartesian)) { // 2. 将世界坐标 (Cartesian3) 转换为地理坐标 Cartographic (弧度) const cartographic = Cesium.Cartographic.fromCartesian(cartesian) // 3. 将弧度转换为度数 const longitude = Cesium.Math.toDegrees(cartographic.longitude) const latitude = Cesium.Math.toDegrees(cartographic.latitude) return { plotId: id, longitude, latitude } } } }