VUE - Cesium 漫游
VUE - Cesium 漫游
cesium 根据输入角度设置中心点(俯仰角度):https://www.cnblogs.com/1285026182YUAN/p/16827154.html
VUE 中创建测试页面:
<template> <div> <div class="container"> <a-button type="primary" @click="drawLineRoad">绘制路线</a-button> <a-button type="primary" @click="startFly">开始飞行</a-button> <a-button type="primary" @click="stopFly">暂停飞行</a-button> <a-button type="primary" @click="continueFly">继续飞行</a-button> <a-button type="primary" @click="exitFly">退出飞行</a-button> <a-button type="primary" @click="SETP1">测试点</a-button> <a-button type="primary" @click="SETP2">角度俯视</a-button> <a-button type="primary" @click="SETP3">转换中心点</a-button> </div> <div id="cesiumContainer"></div> </div> </template> <script> // import Cesium from 'cesium/Cesium'; // import 'cesium/Widgets/widgets.css'; export default { name: 'CesiumViewer', data() { return { TerrionUrl: '/3D-stk_terrain/rest/realspace/datas/info/data/path', viewer: {}, marks: [ { lng: 108.9423344082, lat: 34.2609052589, height: 1000, flytime: 5 }, { lng: 116.812948, lat: 36.550064, height: 1000, flytime: 5 }, // height:相机高度(单位米) flytime:相机两个标注点飞行时间(单位秒) { lng: 116.812948, lat: 36.560064, height: 1000, flytime: 5 }, { lng: 116.802948, lat: 36.560064, height: 1000, flytime: 5 }, { lng: 116.802948, lat: 36.550064, height: 1000, flytime: 5 }, ], //点集 markHight: 500, //相机高度 marksIndex: 1, //默认节点 pitchValue: -20, //俯仰角 changeCameraTime: 1, //转向时间1秒 flytime: 5, //飞行时间 Exection: {}, handler: {}, activeShapePoints: [], floatingPoint: undefined, activeShape: undefined, drawingMode: 'line', Exection: {}, }; }, mounted() { //保证模型初始化 // const vtxfTerrainProvider = new Cesium.CesiumTerrainProvider({ // url: this.TerrionUrl, // requestVertexNormals: true // }); this.viewer = new Cesium.Viewer('cesiumContainer', { // scene3DOnly: true, // selectionIndicator: false, // baseLayerPicker: false, // geocoder: false, // homeButton: false, // sceneModePicker: false, // navigationHelpButton: false, animation: true, timeline: false, // fullscreenButton: false, // terrainProvider: vtxfTerrainProvider, selectionIndicator: false, infoBox: false, // terrainProvider: Cesium.createWorldTerrain(), }); //加载底图 - BING let maptemp = new Cesium.BingMapsImageryProvider({ url: 'https://dev.virtualearth.net', key: 'AijByCeMlw5NWcgLa3RZK61Mx0INwGjcE5InIvNBmMpuwwfMj4_sm5GkXJ_rUHPe', mapStyle: Cesium.BingMapsStyle.AERIAL, }); maptemp.tag = 'base'; this.viewer.imageryLayers.addImageryProvider(maptemp); //加载底图 //双击鼠标左键清除默认事件 this.viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); // this.viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({ // url: "/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8", // })); this.initFly(); }, methods: { initFly() { const { viewer, marks } = this; // eslint-disable-next-line no-unused-vars const self = this; viewer.scene.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(marks[0].lng, marks[0].lat, marks[0].height), //定位坐标点,建议使用谷歌地球坐标位置无偏差 duration: 1, //定位的时间间隔 }); this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); }, flyExtent() { const { viewer, marks, pitchValue } = this; const self = this; // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值 const pitch = Cesium.Math.toRadians(pitchValue); // 时间间隔2秒钟 this.setExtentTime(marks[this.marksIndex].flytime); this.Exection = function TimeExecution() { let preIndex = self.marksIndex - 1; if (self.marksIndex == 0) { preIndex = marks.length - 1; } //计算偏航角 let heading = self.bearing( marks[preIndex].lat, marks[preIndex].lng, marks[self.marksIndex].lat, marks[self.marksIndex].lng ); // 当前已经过去的时间,单位s const delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime); const originLat = self.marksIndex == 0 ? marks[marks.length - 1].lat : marks[self.marksIndex - 1].lat; const originLng = self.marksIndex == 0 ? marks[marks.length - 1].lng : marks[self.marksIndex - 1].lng; //临时点 let p = { lng: originLng + ((marks[self.marksIndex].lng - originLng) / marks[self.marksIndex].flytime) * delTime, lat: originLat + ((marks[self.marksIndex].lat - originLat) / marks[self.marksIndex].flytime) * delTime, height: marks[self.marksIndex].height, }; //计算临时点对应的 相机位置 let objp = self.getCenterLatlng( p.lng, p.lat, heading - 180, p.height / Math.tan((-pitchValue * Math.PI) / 180) ); Object.assign(objp, { height: p.height }); //定位到相机 viewer.scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(objp.lng, objp.lat, objp.height), orientation: { heading: Cesium.Math.toRadians(heading), pitch: pitch, }, }); if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) { viewer.clock.onTick.removeEventListener(self.Exection); if (self.changeCameraTime) { //有转向的功能 ,传入相机当前位置 self.changeCameraHeading(objp); } else { //无转向功能 self.marksIndex++; self.flyExtent(); } } }; viewer.clock.onTick.addEventListener(self.Exection); }, // 相机原地定点转向,objStart :相机当前位置 changeCameraHeading(objStart) { const { viewer, marks, pitchValue, changeCameraTime } = this; const self = this; let { marksIndex } = this; let nextIndex = this.marksIndex + 1; if (marksIndex == marks.length - 1) { // nextIndex = 0; return; } // 计算两点之间的方向 const heading = this.bearing( marks[marksIndex].lat, marks[marksIndex].lng, marks[nextIndex].lat, marks[nextIndex].lng ); // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值 const pitch = Cesium.Math.toRadians(pitchValue); //记录当前点 let p = marks[marksIndex]; //计算最终相机位置 let objEnd = self.getCenterLatlng( p.lng, p.lat, heading - 180, p.height / Math.tan((-pitchValue * Math.PI) / 180) ); // 给定飞行一周所需时间,比如10s, 那么每秒转动度数 const angle = (heading - Cesium.Math.toDegrees(viewer.camera.heading)) / changeCameraTime; // 时间间隔2秒钟 this.setExtentTime(changeCameraTime); // 相机的当前heading const initialHeading = viewer.camera.heading; this.Exection = function TimeExecution() { // 当前已经过去的时间,单位s const delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime); //记算临时偏航角 let heading = Cesium.Math.toRadians(delTime * angle) + initialHeading; //临时点,折角过大时有盲区 let ptemp = { lng: objStart.lng + ((objEnd.lng - objStart.lng) / changeCameraTime) * delTime, lat: objStart.lat + ((objEnd.lat - objStart.lat) / changeCameraTime) * delTime, height: p.height, }; //待测试,解决折角过大时盲区问题 // let oob1 = Cesium.Cartesian3.fromDegrees(objStart.lng, objStart.lat, objStart.height); // let oob2 = Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.height); // let distance = Cesium.Cartesian3.distance(oob1, oob2); // let _roll = Cesium.Math.toRadians(0); // let ptemp = self.supply_getpointend(oob1, heading, pitch, _roll, distance); // //描绘中心点2,路径点记录,测试用 // self.viewer.entities.add({ // position: Cesium.Cartesian3.fromDegrees(ptemp.lng, ptemp.lat), // point: { // color: Cesium.Color.YELLOW, // pixelSize: 10, // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // disableDepthTestDistance: Number.POSITIVE_INFINITY, // }, // }); //定位到相机 viewer.scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(ptemp.lng, ptemp.lat, ptemp.height), orientation: { heading: heading, pitch: pitch, }, }); if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) { viewer.clock.onTick.removeEventListener(self.Exection); self.marksIndex = ++self.marksIndex >= marks.length ? 0 : self.marksIndex; if (self.marksIndex != 0) { self.flyExtent(); } } }; viewer.clock.onTick.addEventListener(self.Exection); }, // 设置飞行的时间到viewer的时钟里 setExtentTime(time) { const { viewer } = this; const startTime = Cesium.JulianDate.fromDate(new Date()); const stopTime = Cesium.JulianDate.addSeconds(startTime, time, new Cesium.JulianDate()); viewer.clock.startTime = startTime.clone(); // 开始时间 viewer.clock.stopTime = stopTime.clone(); // 结速时间 viewer.clock.currentTime = startTime.clone(); // 当前时间 viewer.clock.clockRange = Cesium.ClockRange.CLAMPED; // 行为方式-达到终止时间后停止 viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK; // 时钟设置为当前系统时间; 忽略所有其他设置。 }, /** 相机视角飞行 结束 **/ /** 飞行时 camera的方向调整(heading) 开始 **/ // 角度转弧度 toRadians(degrees) { return (degrees * Math.PI) / 180; }, // 弧度转角度 toDegrees(radians) { return (radians * 180) / Math.PI; }, //计算偏航角 bearing(startLat, startLng, destLat, destLng) { startLat = this.toRadians(startLat); startLng = this.toRadians(startLng); destLat = this.toRadians(destLat); destLng = this.toRadians(destLng); let y = Math.sin(destLng - startLng) * Math.cos(destLat); let x = Math.cos(startLat) * Math.sin(destLat) - Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng); let brng = Math.atan2(y, x); let brngDgr = this.toDegrees(brng); return (brngDgr + 360) % 360; }, /** 飞行时 camera的方向调整(heading) 结束 **/ /**绘制路线 */ drawLineRoad() { const { handler, viewer, activeShapePoints } = this; const self = this; //鼠标左键 handler.setInputAction(function (event) { var earthPosition = viewer.scene.pickPosition(event.position); if (Cesium.defined(earthPosition)) { if (activeShapePoints.length === 0) { self.floatingPoint = self.createPoint(earthPosition); activeShapePoints.push(earthPosition); var dynamicPositions = new Cesium.CallbackProperty(function () { return activeShapePoints; }, false); self.activeShape = self.drawShape(dynamicPositions); //绘制动态图 } activeShapePoints.push(earthPosition); self.createPoint(earthPosition); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); //鼠标移动 handler.setInputAction(function (event) { if (Cesium.defined(self.floatingPoint)) { var newPosition = viewer.scene.pickPosition(event.endPosition); if (Cesium.defined(newPosition)) { self.floatingPoint.position.setValue(newPosition); activeShapePoints.pop(); activeShapePoints.push(newPosition); } } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); handler.setInputAction(function () { self.terminateShape(); }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); }, // Redraw the shape so it's not dynamic and remove the dynamic shape. terminateShape() { const { activeShapePoints, viewer, flytime } = this; activeShapePoints.pop(); //去除最后一个动态点 if (activeShapePoints.length) { this.marks = []; for (const position of activeShapePoints) { const latitude = this.toDegrees(Cesium.Cartographic.fromCartesian(position).latitude); const longitude = this.toDegrees(Cesium.Cartographic.fromCartesian(position).longitude); this.marks.push({ lat: latitude, lng: longitude, flytime, height: this.markHight }); } this.drawShape(activeShapePoints); //绘制最终图 } viewer.entities.remove(this.floatingPoint); //去除动态点图形(当前鼠标点) viewer.entities.remove(this.activeShape); //去除动态图形 this.floatingPoint = undefined; this.activeShape = undefined; this.activeShapePoints = []; }, //绘制点 createPoint(worldPosition) { var point = this.viewer.entities.add({ position: worldPosition, point: { color: Cesium.Color.RED, pixelSize: 10, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, disableDepthTestDistance: Number.POSITIVE_INFINITY, }, }); return point; }, //初始化为线 drawShape(positionData) { const { drawingMode, viewer } = this; var shape; if (drawingMode === 'line') { shape = viewer.entities.add({ polyline: { positions: positionData, clampToGround: true, width: 3, material: Cesium.Color.CHARTREUSE, }, }); } return shape; }, //开始飞行 startFly() { const { Exection } = this; if (Object.keys(Exection).length > 0) { this.exitFly(); } this.flyExtent(); }, //停止飞行 stopFly() { this.viewer.clock.shouldAnimate = false; }, //继续飞行 continueFly() { this.viewer.clock.shouldAnimate = true; }, //退出飞行 exitFly() { const { Exection, viewer, marks, pitchValue } = this; viewer.clock.onTick.removeEventListener(Exection); // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值 const pitch = Cesium.Math.toRadians(pitchValue); const marksIndex = 1; let preIndex = marksIndex - 1; //计算偏航角 let heading = this.bearing( marks[preIndex].lat, marks[preIndex].lng, marks[marksIndex].lat, marks[marksIndex].lng ); heading = Cesium.Math.toRadians(heading); const endPosition = Cesium.Cartesian3.fromDegrees(marks[0].lng, marks[0].lat, marks[0].height); viewer.scene.camera.setView({ destination: endPosition, orientation: { heading: heading, pitch: pitch, }, }); }, //测试点 SETP1() { const { viewer } = this; let p = { lng: 108.9423344082, lat: 34.2609052589 }; //测试点 let h = 1000; //高度 //描绘点 var point = this.viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat), point: { color: Cesium.Color.RED, pixelSize: 10, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, disableDepthTestDistance: Number.POSITIVE_INFINITY, }, }); viewer.scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, h), orientation: { heading: Cesium.Math.toRadians(-120), pitch: Cesium.Math.toRadians(-90), }, }); }, //测试点-俯视 SETP2() { const { viewer } = this; let p = { lng: 108.9423344082, lat: 34.2609052589 }; //测试点 let h = 1000; //高度 viewer.scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, h), orientation: { heading: Cesium.Math.toRadians(-120), pitch: Cesium.Math.toRadians(-20), }, }); }, // 转换中心点 SETP3() { const { viewer } = this; let p = { lng: 108.9423344082, lat: 34.2609052589 }; //测试点 let h = 1000; //高度 let angle = 20; //俯视角度,默认90°,可手动更改 let brng = -300; //heading -180 let obj = this.getCenterLatlng(p.lng, p.lat, brng, h / Math.tan((angle * Math.PI) / 180)); //描绘中心点2 var point = this.viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(obj.lng, obj.lat), point: { color: Cesium.Color.YELLOW, pixelSize: 10, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, disableDepthTestDistance: Number.POSITIVE_INFINITY, }, }); viewer.scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(obj.lng, obj.lat, h), orientation: { heading: Cesium.Math.toRadians(-120), pitch: Cesium.Math.toRadians(-20), }, }); }, //参数 lng、lat为90俯视时的中心,bring为 heading 角度,取反方向,dist getCenterLatlng(lng, lat, brng, dist) { var a = 6378137; var b = 6356752.3142; var f = 1 / 298.257223563; var lon1 = lng * 1; var lat1 = lat * 1; var s = dist; var alpha1 = brng * (Math.PI / 180); var sinAlpha1 = Math.sin(alpha1); var cosAlpha1 = Math.cos(alpha1); var tanU1 = (1 - f) * Math.tan(lat1 * (Math.PI / 180)); var cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1), sinU1 = tanU1 * cosU1; var sigma1 = Math.atan2(tanU1, cosAlpha1); var sinAlpha = cosU1 * sinAlpha1; var cosSqAlpha = 1 - sinAlpha * sinAlpha; var uSq = (cosSqAlpha * (a * a - b * b)) / (b * b); var A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); var sigma = s / (b * A), sigmaP = 2 * Math.PI; while (Math.abs(sigma - sigmaP) > 1e-12) { var cos2SigmaM = Math.cos(2 * sigma1 + sigma); var sinSigma = Math.sin(sigma); var cosSigma = Math.cos(sigma); var deltaSigma = B * sinSigma * (cos2SigmaM + (B / 4) * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - (B / 6) * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))); sigmaP = sigma; sigma = s / (b * A) + deltaSigma; } var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1; var lat2 = Math.atan2( sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1, (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp) ); var lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1); var C = (f / 16) * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); var L = lambda - (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); var revAz = Math.atan2(sinAlpha, -tmp); // final bearing var lngLatObj = { lng: lon1 + L * (180 / Math.PI), lat: lat2 * (180 / Math.PI) }; return lngLatObj; }, supply_getpointend(position, heading, pitch, roll, distance) { var m2 = Cesium.Transforms.eastNorthUpToFixedFrame(position); //m1为局部坐标的z轴垂直于地表,局部坐标的y轴指向正北的4x4变换矩阵 var X = Cesium.Matrix4.fromRotation( Cesium.Matrix3.fromRotationX(heading, new Cesium.Matrix3()), new Cesium.Matrix4() ); var Y = Cesium.Matrix4.fromRotation( Cesium.Matrix3.fromRotationY(pitch, new Cesium.Matrix3()), new Cesium.Matrix4() ); var Z = Cesium.Matrix4.fromRotation( Cesium.Matrix3.fromRotationZ(roll, new Cesium.Matrix3()), new Cesium.Matrix4() ); var ROT1 = Cesium.Matrix4.multiply(Y, X, new Cesium.Matrix4()); var ROT = Cesium.Matrix4.multiply(Z, ROT1, new Cesium.Matrix4()); var m4 = Cesium.Matrix4.multiply(m2, ROT, new Cesium.Matrix4()); var vZ = new Cesium.Cartesian3(1, 0, 0); var vZ = Cesium.Cartesian3.normalize(vZ, new Cesium.Cartesian3()); var vZ = Cesium.Cartesian3.multiplyByScalar(vZ, distance, new Cesium.Cartesian3()); var mpoint1 = Cesium.Matrix4.multiplyByPoint(m4, vZ, new Cesium.Cartesian3()); return mpoint1; }, }, created() {}, }; </script> <style scoped> .container { position: absolute; z-index: 9999; } </style>
测试结果:
整理成类后:
class CesiumUtilRoam { constructor(_marks) { this.marks = _marks; //点集 // [ // // height:相机高度(单位米) flytime:相机两个标注点飞行时间(单位秒) // { lng: 108.9423344082, lat: 34.2609052589, height: 1000, flytime: 5 }, // { lng: 116.812948, lat: 36.550064, height: 1000, flytime: 5 }, // { lng: 116.812948, lat: 36.560064, height: 1000, flytime: 5 }, // { lng: 116.802948, lat: 36.560064, height: 1000, flytime: 5 }, // { lng: 116.802948, lat: 36.550064, height: 1000, flytime: 5 }, // ]; this.markHight = 500; //相机高度 this.marksIndex = 1; //默认节点 this.pitchValue = -20; //俯仰角 this.changeCameraTime = 0; //转向时间1秒 this.flytime = 5; //飞行时间 this.Exection = {}; this.activeShapePoints = []; this.floatingPoint = undefined; this.activeShape = undefined; this.drawingMode = 'line'; this.x = 100; this.handler = new Cesium.ScreenSpaceEventHandler(window.viewer.canvas); viewer.scene.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(this.marks[0].lng, this.marks[0].lat, this.marks[0].height), //定位坐标点,建议使用谷歌地球坐标位置无偏差 duration: 1, //定位的时间间隔 }); } /** 飞行时 camera的方向调整(heading) 结束 **/ /**绘制路线 */ drawLineRoad = () => { let self = this; //鼠标左键 this.handler.setInputAction(function (event) { var earthPosition = viewer.scene.pickPosition(event.position); if (Cesium.defined(earthPosition)) { if (self.activeShapePoints.length === 0) { self.floatingPoint = createPoint(earthPosition); self.activeShapePoints.push(earthPosition); var dynamicPositions = new Cesium.CallbackProperty(function () { return self.activeShapePoints; }, false); self.activeShape = drawShape(dynamicPositions); //绘制动态图 } self.activeShapePoints.push(earthPosition); createPoint(earthPosition); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); //鼠标移动 this.handler.setInputAction(function (event) { if (Cesium.defined(self.floatingPoint)) { var newPosition = viewer.scene.pickPosition(event.endPosition); if (Cesium.defined(newPosition)) { self.floatingPoint.position.setValue(newPosition); self.activeShapePoints.pop(); self.activeShapePoints.push(newPosition); } } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); this.handler.setInputAction(function () { self.terminateShape(); debugger; }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); }; terminateShape = () => { this.activeShapePoints.pop(); //去除最后一个动态点 if (this.activeShapePoints.length) { this.marks = []; for (const position of this.activeShapePoints) { const latitude = toDegrees(Cesium.Cartographic.fromCartesian(position).latitude); const longitude = toDegrees(Cesium.Cartographic.fromCartesian(position).longitude); this.marks.push({ lat: latitude, lng: longitude, flytime: this.flytime, height: this.markHight }); } drawShape(this.activeShapePoints); //绘制最终图 } viewer.entities.remove(this.floatingPoint); //去除动态点图形(当前鼠标点) viewer.entities.remove(this.activeShape); //去除动态图形 this.floatingPoint = undefined; this.activeShape = undefined; this.activeShapePoints = []; }; //停止飞行 stopFly = () => { viewer.clock.shouldAnimate = false; }; //继续飞行 continueFly = () => { viewer.clock.shouldAnimate = true; }; //退出飞行 exitFly = () => { let marks = this.marks; viewer.clock.onTick.removeEventListener(this.Exection); // // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值 // const pitch = Cesium.Math.toRadians(this.pitchValue); // const marksIndex = 1; // let preIndex = marksIndex - 1; // //计算偏航角 // let heading = bearing(marks[preIndex].lat, marks[preIndex].lng, marks[marksIndex].lat, marks[marksIndex].lng); // heading = Cesium.Math.toRadians(heading); // const endPosition = Cesium.Cartesian3.fromDegrees(marks[0].lng, marks[0].lat, marks[0].height); // viewer.scene.camera.setView({ // destination: endPosition, // orientation: { // heading: heading, // pitch: pitch, // }, // }); }; //开始飞行 startFly = () => { // drawMarkstest(this.marks); if (Object.keys(this.Exection).length > 0) { this.exitFly(); } this.flyExtent(); }; flyExtent = () => { let marks = this.marks; let pitchValue = this.pitchValue; let marksIndex = this.marksIndex; let self = this; // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值 const pitch = Cesium.Math.toRadians(pitchValue); // 时间间隔2秒钟 setExtentTime(marks[marksIndex].flytime); this.Exection = function TimeExecution() { let preIndex = marksIndex - 1; if (marksIndex == 0) { preIndex = marks.length - 1; } //计算偏航角 let heading = bearing(marks[preIndex].lat, marks[preIndex].lng, marks[marksIndex].lat, marks[marksIndex].lng); // 当前已经过去的时间,单位s const delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime); const originLat = marksIndex == 0 ? marks[marks.length - 1].lat : marks[marksIndex - 1].lat; const originLng = marksIndex == 0 ? marks[marks.length - 1].lng : marks[marksIndex - 1].lng; //临时点 let p = { lng: originLng + ((marks[marksIndex].lng - originLng) / marks[marksIndex].flytime) * delTime, lat: originLat + ((marks[marksIndex].lat - originLat) / marks[marksIndex].flytime) * delTime, height: marks[marksIndex].height, }; //计算临时点对应的 相机位置 let objp = getCenterLatlng(p.lng, p.lat, heading - 180, p.height / Math.tan((-pitchValue * Math.PI) / 180)); Object.assign(objp, { height: p.height }); //定位到相机 viewer.scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(objp.lng, objp.lat, objp.height), orientation: { heading: Cesium.Math.toRadians(heading), pitch: pitch, }, }); if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) { viewer.clock.onTick.removeEventListener(self.Exection); if (self.changeCameraTime) { //有转向的功能 ,传入相机当前位置 self.changeCameraHeading(objp); } else { //无转向功能 self.marksIndex++; self.flyExtent(); } } }; viewer.clock.onTick.addEventListener(this.Exection); }; // 相机原地定点转向,objStart :相机当前位置 changeCameraHeading = (objStart) => { let marks = this.marks; let pitchValue = this.pitchValue; let changeCameraTime = this.changeCameraTime; let marksIndex = this.marksIndex; let self = this; let nextIndex = this.marksIndex + 1; if (marksIndex == marks.length - 1) { // nextIndex = 0; return; } // 计算两点之间的方向 const heading = bearing(marks[marksIndex].lat, marks[marksIndex].lng, marks[nextIndex].lat, marks[nextIndex].lng); // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值 const pitch = Cesium.Math.toRadians(pitchValue); //记录当前点 let p = marks[marksIndex]; //计算最终相机位置 let objEnd = getCenterLatlng(p.lng, p.lat, heading - 180, p.height / Math.tan((-pitchValue * Math.PI) / 180)); // 给定飞行一周所需时间,比如10s, 那么每秒转动度数 const angle = (heading - Cesium.Math.toDegrees(viewer.camera.heading)) / changeCameraTime; // 时间间隔2秒钟 setExtentTime(changeCameraTime); // 相机的当前heading const initialHeading = viewer.camera.heading; this.Exection = function TimeExecution() { // 当前已经过去的时间,单位s const delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime); //记算临时偏航角 let heading = Cesium.Math.toRadians(delTime * angle) + initialHeading; //临时点,折角过大时有盲区 let ptemp = { lng: objStart.lng + ((objEnd.lng - objStart.lng) / changeCameraTime) * delTime, lat: objStart.lat + ((objEnd.lat - objStart.lat) / changeCameraTime) * delTime, height: p.height, }; //待测试,解决折角过大时盲区问题 // let oob1 = Cesium.Cartesian3.fromDegrees(objStart.lng, objStart.lat, objStart.height); // let oob2 = Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.height); // let distance = Cesium.Cartesian3.distance(oob1, oob2); // let _roll = Cesium.Math.toRadians(0); // let ptemp = supply_getpointend(oob1, heading, pitch, _roll, distance); // //描绘中心点2,路径点记录,测试用 // viewer.entities.add({ // position: Cesium.Cartesian3.fromDegrees(ptemp.lng, ptemp.lat), // point: { // color: Cesium.Color.YELLOW, // pixelSize: 10, // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // disableDepthTestDistance: Number.POSITIVE_INFINITY, // }, // }); //定位到相机 viewer.scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(ptemp.lng, ptemp.lat, ptemp.height), orientation: { heading: heading, pitch: pitch, }, }); if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) { viewer.clock.onTick.removeEventListener(self.Exection); self.marksIndex = ++self.marksIndex >= marks.length ? 0 : self.marksIndex; if (self.marksIndex != 0) { self.flyExtent(); } } }; viewer.clock.onTick.addEventListener(this.Exection); }; name = (params) => { let xx = this.x; xx = 3; console.log('xx-----' + xx); this.x = 500; console.log(params + '-----' + this.x); }; } let drawMarkstest = (_marks) => { debugger; let _acsp = []; _marks.forEach((t) => { var earthPosition = Cesium.Cartesian3.fromDegrees(t.lng, t.lat, t.height); createPoint(earthPosition); _acsp.push(earthPosition); }); let dynamicPositionss = new Cesium.CallbackProperty(function () { return _acsp; }, false); drawShape(dynamicPositionss); }; // 设置飞行的时间到viewer的时钟里 let setExtentTime = (time) => { let startTime = Cesium.JulianDate.fromDate(new Date()); let stopTime = Cesium.JulianDate.addSeconds(startTime, time, new Cesium.JulianDate()); viewer.clock.startTime = startTime.clone(); // 开始时间 viewer.clock.stopTime = stopTime.clone(); // 结速时间 viewer.clock.currentTime = startTime.clone(); // 当前时间 viewer.clock.clockRange = Cesium.ClockRange.CLAMPED; // 行为方式-达到终止时间后停止 viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK; // 时钟设置为当前系统时间; 忽略所有其他设置。 }; //计算偏航角 let bearing = (startLat, startLng, destLat, destLng) => { startLat = toRadians(startLat); startLng = toRadians(startLng); destLat = toRadians(destLat); destLng = toRadians(destLng); let y = Math.sin(destLng - startLng) * Math.cos(destLat); let x = Math.cos(startLat) * Math.sin(destLat) - Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng); let brng = Math.atan2(y, x); let brngDgr = toDegrees(brng); return (brngDgr + 360) % 360; }; /** 相机视角飞行 结束 **/ /** 飞行时 camera的方向调整(heading) 开始 **/ // 角度转弧度 let toRadians = (degrees) => { return (degrees * Math.PI) / 180; }; // 弧度转角度 let toDegrees = (radians) => { return (radians * 180) / Math.PI; }; //参数 lng、lat为90俯视时的中心,bring为 heading 角度,取反方向,dist let getCenterLatlng = (lng, lat, brng, dist) => { var a = 6378137; var b = 6356752.3142; var f = 1 / 298.257223563; var lon1 = lng * 1; var lat1 = lat * 1; var s = dist; var alpha1 = brng * (Math.PI / 180); var sinAlpha1 = Math.sin(alpha1); var cosAlpha1 = Math.cos(alpha1); var tanU1 = (1 - f) * Math.tan(lat1 * (Math.PI / 180)); var cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1), sinU1 = tanU1 * cosU1; var sigma1 = Math.atan2(tanU1, cosAlpha1); var sinAlpha = cosU1 * sinAlpha1; var cosSqAlpha = 1 - sinAlpha * sinAlpha; var uSq = (cosSqAlpha * (a * a - b * b)) / (b * b); var A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); var sigma = s / (b * A), sigmaP = 2 * Math.PI; while (Math.abs(sigma - sigmaP) > 1e-12) { var cos2SigmaM = Math.cos(2 * sigma1 + sigma); var sinSigma = Math.sin(sigma); var cosSigma = Math.cos(sigma); var deltaSigma = B * sinSigma * (cos2SigmaM + (B / 4) * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - (B / 6) * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))); sigmaP = sigma; sigma = s / (b * A) + deltaSigma; } var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1; var lat2 = Math.atan2( sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1, (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp) ); var lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1); var C = (f / 16) * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); var L = lambda - (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); var revAz = Math.atan2(sinAlpha, -tmp); // final bearing var lngLatObj = { lng: lon1 + L * (180 / Math.PI), lat: lat2 * (180 / Math.PI) }; return lngLatObj; }; //绘制点 let createPoint = (worldPosition) => { var point = viewer.entities.add({ position: worldPosition, point: { color: Cesium.Color.RED, pixelSize: 10, // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 页面会报错,An error occurred while rendering , rendering has stopped // disableDepthTestDistance: Number.POSITIVE_INFINITY, }, }); return point; }; //初始化为线 let drawShape = (positionData) => { var shape = viewer.entities.add({ polyline: { positions: positionData, clampToGround: true, width: 3, material: Cesium.Color.CHARTREUSE, }, }); return shape; }; let supply_getpointend = (position, heading, pitch, roll, distance) => { var m2 = Cesium.Transforms.eastNorthUpToFixedFrame(position); //m1为局部坐标的z轴垂直于地表,局部坐标的y轴指向正北的4x4变换矩阵 var X = Cesium.Matrix4.fromRotation( Cesium.Matrix3.fromRotationX(heading, new Cesium.Matrix3()), new Cesium.Matrix4() ); var Y = Cesium.Matrix4.fromRotation(Cesium.Matrix3.fromRotationY(pitch, new Cesium.Matrix3()), new Cesium.Matrix4()); var Z = Cesium.Matrix4.fromRotation(Cesium.Matrix3.fromRotationZ(roll, new Cesium.Matrix3()), new Cesium.Matrix4()); var ROT1 = Cesium.Matrix4.multiply(Y, X, new Cesium.Matrix4()); var ROT = Cesium.Matrix4.multiply(Z, ROT1, new Cesium.Matrix4()); var m4 = Cesium.Matrix4.multiply(m2, ROT, new Cesium.Matrix4()); var vZ = new Cesium.Cartesian3(1, 0, 0); var vZ = Cesium.Cartesian3.normalize(vZ, new Cesium.Cartesian3()); var vZ = Cesium.Cartesian3.multiplyByScalar(vZ, distance, new Cesium.Cartesian3()); var mpoint1 = Cesium.Matrix4.multiplyByPoint(m4, vZ, new Cesium.Cartesian3()); return mpoint1; }; export default CesiumUtilRoam;
调用方式 :
<a-tooltip placement="bottom"> <template slot="title"> <span>漫游</span> </template> <div class="svgbox" @click="toggleRoam"> <roam-svg :color="isRoam ? 'orange' : 'grey'" alt="light" /> </div> </a-tooltip> <div class="tbox" style="margin-left: 50px"> <a-button type="primary" @click="flyDraw">绘制</a-button> <a-button type="primary" @click="flyStart">开始</a-button> <a-button type="primary" @click="flyStop">暂停</a-button> <a-button type="primary" @click="flyContinue">继续</a-button> <a-button type="primary" @click="flyExit"> 停止</a-button> </div>
<script> import RoamSvg from '@/assets/icons/tool/roam.svg?inline'; import CesiumUtilRoam from './utils/cesiumUtilRoam'; var _cesiumUtilRoam = null; export default { components: { RoamSvg }, data() { return { isRoam: false, }; }, methods: { toggleRoam() { this.isRoam = !this.isRoam; let marks = [ { lng: 108.9423344082, lat: 34.2609052589, height: 1000, flytime: 5 }, { lng: 116.812948, lat: 36.550064, height: 1000, flytime: 5 }, { lng: 116.812948, lat: 36.560064, height: 1000, flytime: 5 }, { lng: 116.802948, lat: 36.560064, height: 1000, flytime: 5 }, { lng: 116.802948, lat: 36.550064, height: 1000, flytime: 5 }, ]; if (this.isRoam) { _cesiumUtilRoam = new CesiumUtilRoam(marks); } else { _cesiumUtilRoam = null; } }, flyDraw() { if (_cesiumUtilRoam) _cesiumUtilRoam.drawLineRoad(); }, flyStart() { if (_cesiumUtilRoam) _cesiumUtilRoam.startFly(); }, flyStop() { if (_cesiumUtilRoam) _cesiumUtilRoam.stopFly(); }, flyContinue() { if (_cesiumUtilRoam) _cesiumUtilRoam.continueFly(); }, flyExit() { if (_cesiumUtilRoam) _cesiumUtilRoam.exitFly(); }, }, }; </script>
结果同上。
参考:https://www.cnblogs.com/1285026182YUAN/p/16827154.html