cesium實現飛行漫游
代碼
<template>
<div>
<div class="container">
<el-button
type="primary"
size='mini'
@click="goHome"
>回到首頁</el-button>
<el-button
type="primary"
size='mini'
@click="drawLineRoad"
>繪制路線</el-button>
<el-button
type="primary"
size='mini'
@click="startFly"
>開始飛行</el-button>
<el-button
type="primary"
size='mini'
@click="stopFly"
>暫停飛行</el-button>
<el-button
type="primary"
size='mini'
@click="continueFly"
>繼續飛行</el-button>
<el-button
type="primary"
size='mini'
@click="exitFly"
>退出飛行</el-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: 6000, flytime: 1 },
{ lng: 116.812948, lat: 36.550064, height: 1000, flytime: 1 },
// height:相機高度(單位米) flytime:相機兩個標注點飛行時間(單位秒)
{ lng: 116.812948, lat: 36.560064, height: 1000, flytime: 1 },
{ lng: 116.802948, lat: 36.560064, height: 1000, flytime: 1 },
{ lng: 116.802948, lat: 36.550064, height: 1000, flytime: 1 },
],
marksIndex: 1,
pitchValue: -20,
changeCameraTime: 5,
flytime: 5,
Exection: {},
handler: {},
activeShapePoints: [],
floatingPoint: undefined,
activeShape: undefined,
drawingMode: 'line',
Exection: {},
}
},
mounted() {
//保證模型初始化
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI4MWI5NTY0Mi1iOGE3LTQ3ZTMtOGQ4OC03NThiN2VkZGI4NTYiLCJpZCI6NzY2Niwic2NvcGVzIjpbImFzbCIsImFzciIsImFzdyIsImdjIl0sImlhdCI6MTU1MDIyNTM5OX0.2Abc9p46PA9kJ3E-BaKMXiyb0rvgo7AFUR1nR78VF7c';
// 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()
});
//雙擊鼠標左鍵清除默認事件
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: {
goHome() {
this.$router.push('/');
},
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);
heading = Cesium.Math.toRadians(heading);
// 當前已經過去的時間,單位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;
const endPosition = Cesium.Cartesian3.fromDegrees(
(originLng + (marks[self.marksIndex].lng - originLng) / marks[self.marksIndex].flytime * delTime),
(originLat + (marks[self.marksIndex].lat - originLat) / marks[self.marksIndex].flytime * delTime),
marks[self.marksIndex].height
);
viewer.scene.camera.setView({
destination: endPosition,
orientation: {
heading: heading,
pitch: pitch,
}
});
if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) {
viewer.clock.onTick.removeEventListener(self.Exection);
//有個轉向的功能
self.changeCameraHeading();
}
};
viewer.clock.onTick.addEventListener(self.Exection);
},
// 相機原地定點轉向
changeCameraHeading() {
const { viewer, marks, pitchValue, changeCameraTime } = this
const self = this;
let { marksIndex } = this
let nextIndex = this.marksIndex + 1;
if (marksIndex == marks.length - 1) {
nextIndex = 0;
}
// 計算兩點之間的方向
const heading = this.bearing(marks[marksIndex].lat, marks[marksIndex].lng, marks[nextIndex].lat, marks[nextIndex].lng);
// 相機看點的角度,如果大於0那么則是從地底往上看,所以要為負值
const pitch = Cesium.Math.toRadians(pitchValue);
// 給定飛行一周所需時間,比如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);
const heading = Cesium.Math.toRadians(delTime * angle) + initialHeading;
viewer.scene.camera.setView({
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: 1000 })
}
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.WHITE,
pixelSize: 1,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
}
});
return point;
},
//初始化為線
drawShape(positionData) {
const { drawingMode, viewer } = this
var shape;
if (drawingMode === 'line') {
shape = viewer.entities.add({
polyline: {
positions: positionData,
clampToGround: true,
width: 3
}
});
}
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,
}
});
}
},
created() {
}
}
</script>
<style lang="scss" scoped >
.container {
position: absolute;
z-index: 9999;
}
</style>
本文轉自 https://blog.csdn.net/wo_buzhidao/article/details/102681925?spm=1001.2014.3001.5502,如有侵權,請聯系刪除。
