Cesium 中实现河流流向可视化效果的技术解析
在基于 Cesium 的三维地理信息系统开发过程中,我们经常需要对特定地理要素进行可视化增强。本文将以一个实际项目中的河流流向可视化功能为例,深入解析其技术实现细节。
功能概述
startFlow 函数是实现河流流向可视化的核心方法,它通过加载 GeoJSON 数据并应用特殊的材质效果,支持MultiLinestring,在三维地球场景中呈现出动态流动的河流效果。该功能不仅增强了视觉表现力,也为用户提供了更直观的地理信息展示。
核心实现逻辑
1. 数据加载与处理
fetch(`${import.meta.env.VITE_APP_CONTEXT_PATH}JsonData/河流线数据.json`) .then(res => res.json()) .then(res => { // 处理数据并创建可视化效果 });该方法首先从服务器获取 GeoJSON 格式的河流数据,并将其转换为 JavaScript 对象。这种异步加载机制保证了页面的响应性,避免因大量数据处理导致界面卡顿。
2. 双图层设计
为了实现更好的视觉效果,该方法采用了双图层的设计模式:
基础图层 (riverLayerBase):使用静态颜色渲染河流的基本形状
流动图层 (riverLayer):应用动态材质模拟水流效果
// 基础图层处理 Cesium.GeoJsonDataSource.load(res, { /* 配置 */ }).then((uniDataSource) => { // 设置基础样式 }); // 流动图层处理 Cesium.GeoJsonDataSource.load(res, { /* 配置 */ }).then((uniDataSource) => { // 应用动态流动效果 });3. 动态材质应用
material: new Cesium.LaserPolylineTrailLinkMaterialProperty( speed, // 流速参数 color // 水流颜色 )不同河流根据其重要性设置了不同的宽度、速度和颜色参数,例如黄河、渭河和洛河都有各自专属的视觉配置。
4. 方向校正
对于方向不正确的河流线段,通过反转位置数组来修正流向:
if (item.properties.DIRECTION._value === 0) { item.polyline.positions._value.reverse(); }完整代码如下
function startFlow() { window.$loading.show(); fetch( `${ import.meta.env.VITE_APP_CONTEXT_PATH }JsonData/渭南河流流向纠正_1212.json`, {} ) .then((res) => { // 将响应数据转换为 JSON 格式 return res.json(); }) .then((res) => { console.log(res); Cesium.GeoJsonDataSource.load( res, //要加载的 url、GeoJSON 对象或 TopoJSON 对象。 { stroke: Cesium.Color.PURPLE.withAlpha(0.6), //折线和多边形轮廓的默认颜色。 //折线和多边形轮廓的默认宽度。 clampToGround: true, } ).then((uniDataSource) => { uniDataSource.entities.values.forEach((item) => { let positions; if (item.properties.DIRECTION._value === 0) { item.polyline.positions._value.reverse(); } console.log(item.polyline); let width = 3; if (item.name === "黄河") { width = 18; } else if (item.name === "渭河") { width = 10; } else if (item.name === "洛河") { width = 5; } item.polyline = { positions: item.polyline.positions, width, clampToGround: true, material: Cesium.Color.PURPLE.withAlpha(0.6), }; }); riverLayerBase = uniDataSource; viewer.dataSources.add(uniDataSource); }); Cesium.GeoJsonDataSource.load( res, //要加载的 url、GeoJSON 对象或 TopoJSON 对象。 { //折线和多边形轮廓的默认宽度。 clampToGround: true, } ).then((uniDataSource) => { uniDataSource.entities.values.forEach((item) => { let positions; if (item.properties.DIRECTION._value === 0) { item.polyline.positions._value.reverse(); } let width = 3; let color = Cesium.Color.FLORALWHITE.withAlpha(1); let speed = item.properties.LENGTH._value / 1.5; if (item.name === "黄河") { width = 9; speed = 16000; color = Cesium.Color.LIME.withAlpha(1) } else if (item.name === "渭河") { width = 7; speed = 8000; color = Cesium.Color.LIME.withAlpha(1) } else if (item.name === "洛河") { width = 5; speed = 1000; color = Cesium.Color.LIME.withAlpha(1) } console.log("河流: " + item.name + "速度:" + speed); console.log(item.properties.LENGTH); item.polyline = { positions: item.polyline.positions, width, clampToGround: true, material: new Cesium.LaserPolylineTrailLinkMaterialProperty( speed, color ), }; }); riverLayer = uniDataSource; viewer.dataSources.add( uniDataSource); setTimeout(() => { window.$loading.hide(); }, 500); }); }); }