一、初始化地图
<template>
<div class="cesium_map">
<div id="cesiumContainer"></div>
</div>
</template>
<script setup>
import { reactive, ref, onMounted } from "vue";
import { AutoModel } from "../../utils/Model";
// ---------------------------<<数据>>---------------------------
const me = reactive({
point: null,
});
// 点位数组
const pointArr = reactive([
{
lon: 110.645025,
lat: 22.03158,
alt: 5000,
time: null,
},
{
lon: 110.645025,
lat: 22.16643590658971,
alt: 5000,
time: null,
},
{
lon: 110.7480626299661,
lat: 22.261761037919744,
alt: 5000,
time: null,
},
{
lon: 110.8937798546077,
lat: 22.261761037919744,
alt: 5000,
time: null,
},
{
lon: 110.99674745330135,
lat: 22.16643590658971,
alt: 5000,
time: null,
},
{
lon: 110.99674745330135,
lat: 22.03158,
alt: 5000,
time: null,
},
{
lon: 110.8937798546077,
lat: 21.936190428417305,
alt: 5000,
time: null,
},
{
lon: 110.7483984431316,
lat: 21.936190428417305,
alt: 5000,
time: null,
},
{
lon: 110.645025,
lat: 22.03158,
alt: 5000,
time: null,
},
]);
// 侧向线计时器
const lineTimer = ref(null);
// 侧向线路径
const aggregate = ref(
Cesium.Cartesian3.fromDegreesArrayHeights([
110.82474250408677, 22.095133670052277, 0, 110.645025, 22.03158, 5000,
])
);
// ---------------------------<<函数>>---------------------------
// 初始化地图
const initMap = () => {
// 在线地图token
Cesium.Ion.defaultAccessToken = "map_token";
// 在线地图
let imageryProvider = new Cesium.ArcGisMapServerImageryProvider({
url: "map_url",
});
window.viewer = new Cesium.Viewer("cesiumContainer", {
geocoder: false, // 右上角 搜索
homeButton: false, // 右上角 Home
sceneModePicker: false, // 右上角 2D/3D切换
baseLayerPicker: false, // 右上角 地形
navigationHelpButton: false, // 右上角 Help
animation: false, // 左下角 圆盘动画控件
timeline: false, // 时间轴
fullscreenButton: false, // 右下角 全屏控件
vrButton: false, // 如果设置为true,将创建VRButton小部件。
scene3DOnly: false, // 每个几何实例仅以3D渲染以节省GPU内存
infoBox: false, // 隐藏点击要素后的提示信息
imageryProvider: imageryProvider, // 地图地址
shouldAnimate: true,
});
viewer._cesiumWidget._creditContainer.style.display = "none";
viewer.scene.globe.enableLighting = false;
viewer.shadows = false;
viewer.scene.globe.enableLighting = false;
Cesium.Camera.DEFAULT_VIEW_FACTOR = 0.2; // 摄像机到地图的距离放大倍数
viewer.camera.flyHome(0);
// // 调整画面精细度
viewer.resolutionScale = 1; //默认值为1.0
viewer.scene.backgroundColor = Cesium.Color.TRANSPARENT;
viewer.scene.globe.baseColor = Cesium.Color.TRANSPARENT;
// //是否开启抗锯齿
viewer.scene.fxaa = false;
viewer.scene.postProcessStages.fxaa.enabled = false;
viewer.scene.globe.showGroundAtmosphere = true;
// 设置相机位置
viewer.scene.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(
110.82474250408677,
22.095133670052277,
80000
),
orientation: {
heading: Cesium.Math.toRadians(0),
pitch: Cesium.Math.toRadians(-90),
roll: 0.0,
},
});
//取消双击事件
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
);
};
// 初始化模型
const initModel = () => {
// 请查看 “步骤三” 使用示例
};
// 初始化模型类
const initModelClass = () => {
me.point = new AutoModel(viewer, Cesium);
};
// ---------------------------<<执行>>---------------------------
// 挂载后生命周期
onMounted(() => {
initMap();
initModelClass();
initModel();
});
</script>
<style lang="less" scoped>
.cesium_map {
width: 100%;
height: 100%;
#cesiumContainer {
width: 100%;
height: 100%;
}
}
</style>
二、封装文件
// 自动运动模型
export class AutoModel {
constructor(viewer, Cesium) {
this.viewer = viewer
this.Cesium = Cesium
}
// 计算线路
calcRoute(source, startTime) {
// 取样位置 相当于一个集合
let property = new this.Cesium.SampledPositionProperty();
for (let i = 0; i < source.length; i++) {
let time = this.Cesium.JulianDate.addSeconds(
startTime,
source[i].time,
new this.Cesium.JulianDate()
);
let position = this.Cesium.Cartesian3.fromDegrees(
source[i].lon,
source[i].lat,
source[i].alt
);
// 添加位置,和时间对应
property.addSample(time, position);
}
return property;
}
// 创建模型
addModel(option, startTime, stopTime) {
let {
id,
name,
uri,
minimumPixelSize,
maximumScale,
color,
flyPath,
} = option
let property = this.calcRoute(flyPath, startTime);
this.viewer.entities.add({
id, //模型id
name, // 模型名称,这里用作模型类型,方便场景模型增删改查
// 和时间轴关联
availability: new this.Cesium.TimeIntervalCollection([
new Cesium.TimeInterval({
start: startTime,
stop: stopTime,
}),
]),
position: property, //模型位置,高度
orientation: new this.Cesium.VelocityOrientationProperty(property),
model: {
uri, //模型文件
minimumPixelSize, //模型最小像素大小
maximumScale, //模型最大像素大小
color
},
});
}
// 移动模型
moveModel(option) {
let {
flyPath,
multiplier,
clockRange
} = option
let flyTime = 0
for (let i = 0; i < flyPath.length; i++) {
flyPath[i].time = flyTime;
flyTime += 2;
}
// 起始时间
var startTime = this.Cesium.JulianDate.fromDate(new Date());
// 结束时间
var stopTime = this.Cesium.JulianDate.addSeconds(
startTime,
flyPath[flyPath.length - 1].time,
new this.Cesium.JulianDate()
);
// 设置始时钟始时间
this.viewer.clock.startTime = startTime.clone();
// 设置时钟当前时间
this.viewer.clock.currentTime = stopTime.clone();
// 设置始终停止时间
this.viewer.clock.stopTime = stopTime.clone();
// 时间速率,数字越大时间过的越快
this.viewer.clock.multiplier = multiplier;
// 时间轴
// viewer.timeline.zoomTo(start.value, stop.value);
// 循环执行,即为2,到达终止时间,重新从起点时间开始LOOP_STOP
// viewer.clock.clockRange = Cesium.ClockRange.CLAMPED;
this.viewer.clock.clockRange = clockRange;
// 创建模型
this.addModel(option, startTime, stopTime);
}
}
三、使用示例
1、代码
const initModel = () => {
let temp = ref([]);
for (let i = 0; i < pointArr.length; i++) {
// 绘制飞行线路坐标点
me.point.entitiesPoint({
id: "entitiesPoint" + i, // 点id
position: Cesium.Cartesian3.fromDegrees(
pointArr[i].lon,
pointArr[i].lat,
pointArr[i].alt
), // {lon,lat,alt}
});
temp.value.push(pointArr[i].lon, pointArr[i].lat, pointArr[i].alt);
}
// 绘制飞行线路
me.line.entitiesLine({
id: "solidLine", // 线条id***
name: "solidLine", // 线条name***
// 参数依次为[经度1, 纬度1, 高度1, 经度2, 纬度2, 高度2]
positions: Cesium.Cartesian3.fromDegreesArrayHeights(temp.value), // 线条坐标***
width: 2,
material: Cesium.Color.fromCssColorString("tomato"), // 线条材质:通过材质控制线条类型***
clampToGround: false, // 是否贴地
zIndex: 1, // clampToGround = true才生效
ddc: {
start: 0,
end: 150000000,
}, //显示在距相机的距离处的属性,多少区间内是可以显示的
show: true, // 是否显示线条
});
// 绘制测向线
me.line.entitiesLine({
id: "sideLine", // 线条id***
name: "sideLine", // 线条name
positions: new Cesium.CallbackProperty(() => {
return aggregate.value;
}, false), // 线条坐标***
material: new Cesium.StripeMaterialProperty({
evenColor: Cesium.Color.WHITE,
oddColor: Cesium.Color.TOMATO,
repeat: 3,
}),
width: 5, // 线条宽度
clampToGround: false, // 是否贴地
zIndex: 999, // 线条层级,clampToGround = true才生效
ddc: {
start: 0,
end: 150000000,
},
show: true,
});
// 绘制移动模型***
me.autoModel.moveModel({
id: "autoModel", // 模型id
name: "autoModel", // 模型name
uri: "./model/test1.GLTF", // 模型文件
minimumPixelSize: 100, // 模型最小
maximumScale: 200, // 模型最大
color: Cesium.Color.WHITE.withAlpha(1), // 模型颜色
flyPath: pointArr, // 飞行线路
multiplier: 0.2, // 飞行速度
clockRange: Cesium.ClockRange.LOOP_STOP, // 飞行效果:循环
});
};
// 更新测向线
const getCurrentPosition = () => {
if (!lineTimer.value) {
// 定时获取实体位置
lineTimer.value = setInterval(() => {
// 获取飞机模型
let plane = viewer.entities.getById("autoModel");
var planePosition = Cesium.Property.getValueOrDefault(
plane._position,
viewer.clock.currentTime,
new Cesium.Cartesian3()
);
var cartographic = Cesium.Cartographic.fromCartesian(planePosition);
var lon = Cesium.Math.toDegrees(cartographic.longitude);
var lat = Cesium.Math.toDegrees(cartographic.latitude);
aggregate.value = Cesium.Cartesian3.fromDegreesArrayHeights([
110.82474250408677,
22.095133670052277,
0,
lon,
lat,
cartographic.height,
]);
}, 10);
}
};
2、效果