最近在基于cesium做水利项目的淹没分析 因为真实的洪水情况下,对于不同的地势来说 每个淹没区间的不同时刻水位高度肯定是不一样的 所以要求对多河段的高度做一个动态的水位上涨与下降的效果 不同河段水位高要以不一样的颜色显示 以下是其中一个河段的实现的代码参考
先看看效果吧
cesium淹没分析
初始化地图
<template>
<div class="water-page">
<div id="cesiumContainer"></div>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue";
import FloodAnalysis from "./FloodAnalysis.js";
const initMap = () => {
CesiumMap = new Cesium.Viewer("cesiumContainer", {
geocoder: false,
animation: false,
timeline: false,
infoBox: false,
baseLayerPicker: false,
fullscreenButton: false,
homeButton: false,
sceneModePicker: false,
navigationHelpButton: false,
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
}),
CreditsDisplay: false,
selectionIndicator: false,
scene3DOnly: true,
requestRenderMode: true,
terrainProvider: Cesium.createWorldTerrain({
requestVertexNormals: true,
requestWaterMask: true,
}),
terrainProvider: new Cesium.ArcGISTiledElevationTerrainProvider({
url: "https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer",
}),
});
// CesiumMap.timeline.container.style.visibility = "hidden";
CesiumMap._cesiumWidget._creditContainer.style.display = "none"; //LOGO显示
CesiumMap.scene.globe.depthTestAgainstTerrain = true;
CesiumMap.camera.setView({
destination : Cesium.Cartesian3.fromDegrees(105.5793, 30.5305127, 1000),
orientation: {
heading :0, // 相机方向指向当地东向
pitch : Cesium.Math.toRadians(-15), // 再将相机方向转向地心,此时Up方向指向当地东向
roll : 0.0
}
});
createWater();
};
/**
* 获取数据创建水面
*/
const waterColor = ref("rgba(183, 149, 75, 0.91)");
const createWater = () => {
let data = require("./flood_data.json");
let waterEntity = new FloodAnalysis(CesiumMap, {
...data,
waterColor: waterColor.value,
show: true,
});
};
onMounted(() => {
initMap();
});
</script>
<style lang="scss" scoped>
.water-page {
width: 100vw;
height: 100vh;
#cesiumContainer {
width: 100%;
height: 100%;
}
}
</style>
关键代码
/**
* @description 淹没分析函数,通过拉伸面的高度来进行分析
*/
class FloodAnalysis {
constructor(viewer, options) {
if (!viewer) throw new Error("no viewer object!");
this.viewer = viewer;
this.positions = this.CoorsFormt(options.polygon);
this.times_height = options.times_height;
this.currentIndex = 0;
this.initialHeight = this.times_height[this.currentIndex];
this.targertHeight = this.times_height[this.currentIndex + 1];
this.increaseHeight = this.targertHeight - this.initialHeight;
this.waterColor = options.waterColor;
this.show = options.show;
this.start = null;
this.init();
this.getNowHeight();
}
CoorsFormt(coors) {
let Arr = [];
coors.forEach((coor) => {
Arr.push(coor[0]);
Arr.push(coor[1]);
});
return Arr;
}
async init() {
this.viewerSET();
// this.start = Cesium.JulianDate.now(new Date());
const self = this;
this.property = this.computeFlight(this.times_height);
this.viewer.scene.globe.depthTestAgainstTerrain = true;
this.entity = this.viewer.entities.add({
show: this.show,
availability: new Cesium.TimeIntervalCollection([
new Cesium.TimeInterval({
start: this.start,
stop: Cesium.JulianDate.addMinutes(
this.start,
10 * this.times_height.length,
new Cesium.JulianDate()
),
}),
]),
polygon: {
hierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(this.positions)
),
extrudedHeight: this.property,
height:this.property,
material: Cesium.Color.fromCssColorString(this.waterColor)
},
});
}
/*
*时间水位与时间关联
*/
computeFlight(data) {
let property = new Cesium.SampledProperty(Number);
data.forEach((item, i) => {
property.addSample(
Cesium.JulianDate.addMinutes(
this.start,
10 * i,
new Cesium.JulianDate()
),
item
);
});
return property;
}
/*
*设置时间
*/
viewerSET() {
this.start = Cesium.JulianDate.fromDate(new Date());
this.start = Cesium.JulianDate.addHours(
this.start,
8,
new Cesium.JulianDate()
);
this.stop = Cesium.JulianDate.addMinutes(
this.start,
10 * this.times_height.length,
new Cesium.JulianDate()
);
this.viewer.clock.startTime = this.start.clone();
this.viewer.clock.currentTime = this.start.clone();
this.viewer.clock.stopTime = this.stop.clone();
// this.viewer.clock.multiplier = 3600
if (this.viewer.timeline)
this.viewer.timeline.zoomTo(this.start, this.stop);
this.viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
}
/**
* 获取实时水面高度
*/
getNowHeight() {
const self = this;
this.viewer.clock.onTick.addEventListener(function () {
if (self.increaseHeight > 0) {
if (self.initialHeight > self.targertHeight) {
self.currentIndex += 1;
if (self.currentIndex > self.times_height.length - 2) {
self.currentIndex = 0;
}
self.initialHeight = self.times_height[self.currentIndex];
self.targertHeight = self.times_height[self.currentIndex + 1];
self.increaseHeight = self.targertHeight - self.initialHeight;
}
}
if (self.increaseHeight < 0) {
if (self.initialHeight < self.targertHeight) {
self.currentIndex += 1;
if (self.currentIndex > self.times_height.length - 2) {
self.currentIndex = 0;
}
self.initialHeight = self.times_height[self.currentIndex];
self.targertHeight = self.times_height[self.currentIndex + 1];
self.increaseHeight = self.targertHeight - self.initialHeight;
}
}
self.initialHeight += self.increaseHeight / 100;
});
}
/**
* 改变颜色
* @param {水体颜色} val
*/
changeWaterColor(val) {
this.entity.polygon.material = val;
}
/**
* 隐藏与显示
* @param {Boolean} val
*/
changeWaterShow(val) {
this.entity.show = val;
}
destroy() {
this.viewer.entities.remove(this.entity);
delete this.entity;
delete this.positions;
delete this.initialHeight;
delete this.targertHeight;
delete this.increaseHeight;
}
}
export default FloodAnalysis;