import EventBus from './eventBus' import { Cartesian3, Terrain, Viewer } from 'cesium' import getBaseConfig from '@/buildConfig/config' const { imageryProvider_stand, imageryProvider_standZh, imageryProvider_tdt_img_w, imageryProvider_tdt_cia_w } = getBaseConfig() const env = import.meta.env.VITE_APP_ENV || 'default' import { addBlueFilter } from './common' import * as Cesium from 'cesium' let smallMpaCenterDistance = null let curCameraHpr = null let proHandler = null let proController = null let proMoveFlag = null let handler = null /** * 公共的Cesium (蓝色,2d) */ // 封装的不用管 let cn = { ri: function () { return a }, LS: function () { return o }, jL: function () { return n }, } function a (e) { return null != e } function o (e, t) { return a(e) ? e : t } function n (e, t = !1) { let { longitude: i, latitude: a, height: o } = e return Cesium.Cartesian3.fromDegrees(i, a, t ? 0 : o) } export class PublicCesium { constructor(options) { this.handlerEvents = { handler: null } this.viewer = null this.init(options) } init (options) { const that = this const { dom, flatMode = true, terrain = false, mapFilter = true, layers } = options Cesium.Camera.DEFAULT_VIEW_FACTOR = -0.45 // 西南东北,默认显示中国 Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(66, 4, 135, 53.55) const viewerOptions = { infoBox: false, // 禁用沙箱,解决控制台报错 animation: false, // 左下角的动画仪表盘 baseLayerPicker: false, // 右上角的图层选择按钮 geocoder: false, // 搜索框 homeButton: false, // home按钮 sceneModePicker: false, // 模式切换按钮 timeline: false, // 底部的时间轴 navigationHelpButton: false, // 右上角的帮助按钮, selectionIndicator: false, // 是否显示选择指示器 baseLayer: false, fullscreenButton: false, } this.viewer = new Viewer(options.dom, viewerOptions) this.viewer.imageryLayers.removeAll() this.viewer._cesiumWidget._creditContainer.style.display = 'none' handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas) if (flatMode) { this.viewer.scene.screenSpaceCameraController.enableTilt = false } if (terrain) { try { Cesium.CesiumTerrainProvider.fromUrl(`${import.meta.env.VITE_APP_TERRAIN_URL}`, { requestVertexNormals: true, // 启用地形法线增强立体感 requestWaterMask: true, // 启用水体遮罩效果 }).then(terrainProvider => { this.viewer.terrainProvider = terrainProvider }) } catch (error) { console.error('地形加载失败:', error) } } if (layers) { layers.forEach(item => { this.viewer.imageryLayers.addImageryProvider(item) }) } else { if (env === 'jiangwu') { this.tcLayer = this.viewer.imageryLayers.addImageryProvider(imageryProvider_tdt_img_w) this.zjLayer = this.viewer.imageryLayers.addImageryProvider(imageryProvider_tdt_cia_w) } else { this.tcLayer = this.viewer.imageryLayers.addImageryProvider(imageryProvider_stand) this.zjLayer = this.viewer.imageryLayers.addImageryProvider(imageryProvider_standZh) } } // if (mapFilter) { // ;[this.tcLayer, this.zjLayer].forEach(item => { // item.brightness = 0.6 // 亮度(默认值) // item.contrast = 1.8 // 对比度(负值降低对比度) // item.hue = 1 // 色相(弧度值,3.0可能导致紫色) // item.saturation = 0 // 增加饱和度强化蓝色 // item.gamma = 0.3 // 伽马校正(小于1.0使颜色更鲜艳) // }) // const filterOptions = { bInvertColor: true, bFilterColor: true, filterColor: '#4e70a6' } // // 添加蓝色滤镜 // addBlueFilter(filterOptions, this.viewer) // } this.viewer.scene.screenSpaceCameraController.maximumZoomDistance = 4500000 } getViewer () { return this.viewer } viewerDestroy () { smallMpaCenterDistance = null this.viewer && this.viewer.destroy() this.viewer = null } addRightClickEvent (sid, cb) { if (this.rightClickHandler) this.removeRightClickEvent() this.rightClickHandler = new Cesium.ScreenSpaceEventHandler(this.viewer?.scene.canvas) this.rightClickHandler.setInputAction(click => { const pick = this.viewer?.scene.pick(click.position) cb(click, pick, this.viewer) }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) } // 移除鼠标右键事件 removeRightClickEvent () { if (!this.rightClickHandler) return this.rightClickHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK) this.rightClickHandler = null } // 鼠标点击事件 addLeftClickEvent (sid, cb, eventKey = 'handler') { if (this.handlerEvents.handler) this.removeLeftClickEvent() if (this.handlerEvents[eventKey]) this.removeLeftClickEvent(eventKey) this.handlerEvents[eventKey] = new Cesium.ScreenSpaceEventHandler(this.viewer?.scene.canvas) this.handlerEvents[eventKey].setInputAction(click => { const pick = this.viewer?.scene.pick(click.position) if (pick && pick.primitive && pick.primitive?.customParams?.type === '3DTileset') { return cb(click, pick, this.viewer, this.handlerEvents[eventKey]) } if (pick && pick.id && (pick.id._id === sid || pick.id._id.includes(sid))) { cb(click, pick, this.viewer, this.handlerEvents[eventKey]) } if (sid === null) { cb(click, pick, this.viewer, this.handlerEvents[eventKey]) } }, Cesium.ScreenSpaceEventType.LEFT_CLICK) } // 移除鼠标点击事件 removeLeftClickEvent (eventKey = 'handler') { if (this.handlerEvents[eventKey] == null) return this.handlerEvents[eventKey].removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK) this.handlerEvents[eventKey] = null } pointInitEvent (left_down, mouse_move, left_up) { if (!this.pointEditHandler) { this.pointEditHandler = new Cesium.ScreenSpaceEventHandler(this.viewer?.scene.canvas) } const events = { left_down, mouse_move, left_up, } this.pointEditBindEvent(events) this.pointEditBindEvent(events, Cesium.KeyboardEventModifier.CTRL) this.pointEditBindEvent(events, Cesium.KeyboardEventModifier.ALT) this.pointEditBindEvent(events, Cesium.KeyboardEventModifier.SHIFT) this.pointEditBindEvent(events, Cesium.KeyboardEventModifier.META) } pointEditBindEvent (events, e) { if (this.pointEditHandler) { this.pointEditHandler.setInputAction(events.left_down(e), Cesium.ScreenSpaceEventType.LEFT_DOWN, e) this.pointEditHandler.setInputAction(events.mouse_move(e), Cesium.ScreenSpaceEventType.MOUSE_MOVE, e) this.pointEditHandler.setInputAction(events.left_up(e), Cesium.ScreenSpaceEventType.LEFT_UP, e) } } pointUnInitEvent () { this.pointEditUnBindEvent() this.pointEditUnBindEvent(Cesium.KeyboardEventModifier.CTRL) this.pointEditUnBindEvent(Cesium.KeyboardEventModifier.ALT) this.pointEditUnBindEvent(Cesium.KeyboardEventModifier.SHIFT) this.pointEditUnBindEvent(Cesium.KeyboardEventModifier.META) this.pointEditHandler = null } pointEditUnBindEvent (e) { this.pointEditHandler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN, e) this.pointEditHandler?.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE, e) this.pointEditHandler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP, e) } setCameraMove (e) { this.setCameraAttribute(e) } setCameraAttribute (e) { let t = {} , i = !1 if (e.attitude) { let { fov: n } = e.attitude if ((0, cn.ri)(n) && this.viewer?.camera) { this.viewer.camera.frustum = new Cesium.PerspectiveFrustum({ fov: Cesium.Math.toRadians(n), aspectRatio: this.viewer?.canvas.clientWidth / this.viewer?.canvas.clientHeight, near: .1 }) } } i && this.viewer?.camera.setView(t) } setView (options) { const position = Cesium.Cartesian3.fromDegrees( Number(options.longitude), Number(options.latitude), Number(options.height || 0), ) const heading = Number(options.heading || 0) this.viewer?.camera?.setView({ destination: position, orientation: { heading: Cesium.Math.toRadians(heading >= 0 ? heading : heading + 360), // 水平旋转(偏航角) pitch: Cesium.Math.toRadians(Number(options.pitch || 0)), // 俯仰角(-90°表示俯视地心) roll: 0.0 // 翻转角 } }) this.getCameraCurPositionDistance() } getCameraCurPositionDistance () { if (!this.viewer) return // 获取相机位置 const position = this.viewer?.camera.positionCartographic const cameraLongitude = Cesium.Math.toDegrees(position.longitude) const cameraLatitude = Cesium.Math.toDegrees(position.latitude) const cameraHeight = position.height // 获取地图区域中心点位置 let mapCenterPx = { x: this.viewer?.canvas.clientWidth / 2, y: this.viewer?.canvas.clientHeight / 2 } let centerInfo = this.getMouseInfo(mapCenterPx) if (centerInfo.wgs84SurfacePosition) { const { lng, lat, alt } = centerInfo.wgs84SurfacePosition // 计算相机到中心点的距离 const cameraPosition = Cesium.Cartesian3.fromDegrees(cameraLongitude, cameraLatitude, cameraHeight) const centerPoint = Cesium.Cartesian3.fromDegrees(lng, lat, alt) const distance = Cesium.Cartesian3.distance(cameraPosition, centerPoint) smallMpaCenterDistance = distance EventBus.emit('setCameraCurPositionDistance', distance) } else { const cameraPosition = this.viewer?.camera.position const farDistance = this.viewer?.camera.frustum.far // 获取相机的远裁剪面距离 const distance = farDistance - Cesium.Cartesian3.magnitude(cameraPosition) smallMpaCenterDistance = distance EventBus.emit('setCameraCurPositionDistance', '') } } getMouseInfo (position) { let scene = this.viewer?.scene let surfaceCartesian = undefined let wgs84SurfacePosition = undefined if ( scene.mode === Cesium.SceneMode.SCENE3D && !(this.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 { wgs84SurfacePosition: wgs84SurfacePosition, } } // 左键按下事件 pro_left_down (e) { proMoveFlag = !0 } // 左键抬起事件 pro_left_up (e) { proMoveFlag = !1 } // 鹰眼鼠标移动事件 pro_mouse_move (e) { if (proMoveFlag) { this.look3D(e.startPosition, e.endPosition) const position = this.viewer.camera.positionCartographic const lng = Cesium.Math.toDegrees(position.longitude).toFixed(4) const lat = Cesium.Math.toDegrees(position.latitude).toFixed(4) const alt = (position.height / 1000).toFixed(2) // 转换为千米 // 获取方向 const heading = Cesium.Math.toDegrees(this.viewer.camera.heading).toFixed(2) const pitch = Cesium.Math.toDegrees(this.viewer.camera.pitch).toFixed(2) const roll = Cesium.Math.toDegrees(this.viewer.camera.roll).toFixed(2) curCameraHpr = { heading, pitch, roll } let newHeading = ((heading + 180) % 360) - 180 EventBus.emit('PointAirLine-setRoamPoint', { pitch: pitch, heading: newHeading >= 0 ? newHeading - 180 : newHeading + 180 }) this.getCameraCurPositionDistance() } } // 鹰眼地图相关事件 bindEvent () { this.bindProLeftDown = this.pro_left_down.bind(this) this.bindProLeftUp = this.pro_left_up.bind(this) this.bindProLeftMove = this.pro_mouse_move.bind(this) proHandler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas) proController = this.viewer.scene.screenSpaceCameraController proController.enableRotate = !1 proController.enableTilt = !1 proController.enableZoom = !1 proController.enableLook = !1 proController.enableTranslate = !1 proMoveFlag = false handler.setInputAction(this.bindProLeftDown, Cesium.ScreenSpaceEventType.LEFT_DOWN) handler.setInputAction(this.bindProLeftUp, Cesium.ScreenSpaceEventType.LEFT_UP) handler.setInputAction(this.bindProLeftMove, Cesium.ScreenSpaceEventType.MOUSE_MOVE) } unBindEvent = () => { if (proHandler) { handler.removeInputAction(this.bindProLeftDown, Cesium.ScreenSpaceEventType.LEFT_DOWN) handler.removeInputAction(this.bindProLeftUp, Cesium.ScreenSpaceEventType.LEFT_UP) handler.removeInputAction(this.bindProLeftMove, Cesium.ScreenSpaceEventType.MOUSE_MOVE) proController = null proHandler = null } } look3D (e, t, i = !1) { let r = this.viewer.camera , a = this.viewer.scene.globe.ellipsoid , s = i ? -1 : 2 , o = a.geodeticSurfaceNormal(r.position) r.look(o, this.getLookAngle(e, t, "x") * s), this.lookVertical(-this.getLookAngle(e, t, "y") * s, o) } getLookAngle (e, t, i) { let r, a let s = e[i] , o = t[i] , n = new Cesium.Cartesian2("x" === i ? s : 0, "y" === i ? s : 0) , l = new Cesium.Cartesian2("x" === i ? o : 0, "y" === i ? o : 0) , c = this.viewer.camera.getPickRay(n) , h = this.viewer.camera.getPickRay(l) if (!c || !h) return 0 this.viewer.camera.frustum instanceof Cesium.OrthographicFrustum ? (r = c.origin, a = h.origin, Cesium.Cartesian3.add(this.viewer.camera.direction, r, r), Cesium.Cartesian3.add(this.viewer.camera.direction, a, a), Cesium.Cartesian3.subtract(r, this.viewer.camera.position, r), Cesium.Cartesian3.subtract(a, this.viewer.camera.position, a), Cesium.Cartesian3.normalize(r, r), Cesium.Cartesian3.normalize(a, a)) : (r = c.direction, a = h.direction) let d = Cesium.Cartesian3.dot(r, a) , p = 0 return d < 1 && (p = Math.acos(d)), s > o ? -p : p } lookVertical (e, t) { let i = this.viewer.camera , r = this.judgeParallelAndRecalculateAngle(-e, i.direction, t) r && i.look(i.right, r) } sg (e, t) { return Cesium.Cartesian3.equalsEpsilon(e, t, Cesium.Math.EPSILON2) ? 1 : Cesium.Cartesian3.equalsEpsilon(e, Cesium.Cartesian3.negate(t, new Cesium.Cartesian3), Cesium.Math.EPSILON2) ? -1 : 0 } judgeParallelAndRecalculateAngle (e, t, i) { let r = this.sg(t, i) , a = e if (1 === r && a < 0) a = 0 else if (-1 === r && a > 0) a = 0 else if (0 === r) { let e = Cesium.Cartesian3.dot(t, i) , r = Cesium.Math.acosClamped(-e) a > 0 && a > r && (a = r - Cesium.Math.EPSILON4), r = Cesium.Math.acosClamped(e), a < 0 && -a > r && (a = -r + Cesium.Math.EPSILON4) } return a } // 添加entity addCustomImageryProviderDataSource (imageryLayers) { console.log(imageryLayers, this.viewer, '---1-') return this.viewer?.imageryLayers.addImageryProvider(imageryLayers) } showCustomImageryProviderDataSource (imageryLayers, show) { if (imageryLayers) { imageryLayers.show = show } } removeAllCustomImageryProviderDataSource (imageryLayers) { if (imageryLayers) { this.viewer?.imageryLayers.remove(imageryLayers) } } }