Cesium实现不规则区域等值线,坡度坡向高程

Cesium 中获取某点的**高程(Elevation)**、**坡度(Slope)** 和 **坡向(Aspect / 方位角)**,需要结合地形数据进行计算。Cesium 提供了高精度的地形服务(如 `CesiumWorldTerrain`),我们可以利用这些数据来实现。 以下是使用 **Cesium JS 1.131+** 实现“点击地图获取某点高程坡度坡向”的完整方案。 --- ### ✅ 步骤说明 1. 启用地形(必须) 2. 获取某点经纬度对应的高程 3. 计算该点周围邻域的高程差,用于估算坡度坡向 4. 使用有限差分法(Finite Difference)计算坡度坡向 --- ### ✅ 完整代码示例 ```javascript const viewer = new Cesium.Viewer('cesiumContainer', { terrainProvider: Cesium.createWorldTerrain() // 必须启用地形 }); // 点击事件监听 const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction(async function(click) { const pickedObject = viewer.scene.pick(click.position); if (pickedObject && !Cesium.defined(pickedObject.id)) return; // 转换屏幕坐标为笛卡尔坐标 const cartesian = viewer.scene.camera.pickEllipsoid( click.position, viewer.scene.globe.ellipsoid ); if (!cartesian) { console.log("未选中地面点"); return; } // 转换为经纬度(弧度 → 度) const cartographic = Cesium.Cartographic.fromCartesian(cartesian); const lon = Cesium.Math.toDegrees(cartographic.longitude); const lat = Cesium.Math.toDegrees(cartographic.latitude); try { // 获取高程(包含地形高度) const height = await getElevation(lon, lat); const slope = await calculateSlope(lon, lat); // 坡度(角度) const aspect = await calculateAspect(lon, lat); // 坡向(0~360°) console.log(`经度: ${lon.toFixed(6)}°`); console.log(`纬度: ${lat.toFixed(6)}°`); console.log(`高程: ${height.toFixed(2)} 米`); console.log(`坡度: ${slope.toFixed(2)}°`); console.log(`坡向: ${aspect.toFixed(2)}°`); } catch (err) { console.error("计算失败:", err); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); // ==================== 工具函数 ==================== // 获取指定经纬度的高程 async function getElevation(lon, lat) { const hasTerrain = viewer.scene.mode !== Cesium.SceneMode.SCENE2D; if (!hasTerrain) throw new Error("地形未启用"); const promise = Cesium.sampleTerrainMostDetailed([ Cesium.Cartographic.fromDegrees(lon, lat) ]); const updatedTessellations = await promise; if (!updatedTessellations || updatedTessellations.length === 0) { throw new Error("无法获取地形高程"); } return updatedTessellations[0].height; } // 计算坡度(单位:度) async function calculateSlope(lon, lat, spacing = 100) { // spacing 单位:米 const { dzdx, dzdy } = await computeGradient(lon, lat, spacing); const slopeRadians = Math.atan(Math.sqrt(dzdx * dzdx + dzdy * dzdy)); return Cesium.Math.toDegrees(slopeRadians); // 转为角度 } // 计算坡向(单位:度,0=北,90=东) async function calculateAspect(lon, lat, spacing = 100) { const { dzdx, dzdy } = await computeGradient(lon, lat, spacing); if (dzdx === 0 && dzdy === 0) return 0; // 平坦区域 let aspectRadians = Math.atan2(dzdy, -dzdx); // 注意方向修正 let aspectDegrees = Cesium.Math.toDegrees(aspectRadians); // 归一化到 0~360° if (aspectDegrees < 0) aspectDegrees += 360; return aspectDegrees; } // 使用中心差分法计算梯度(dz/dx, dz/dy) async function computeGradient(lon, lat, spacing = 100) { const ellipsoid = Cesium.Ellipsoid.WGS84; // 将经纬度转为笛卡尔坐标 const center = Cesium.Cartographic.fromDegrees(lon, lat); const hCenter = await getElevation(lon, lat); // X 方向偏移(东) const lonEast = lon + Cesium.Math.toRadians(spacing / ellipsoid.maximumRadius); const lonWest = lon - Cesium.Math.toRadians(spacing / ellipsoid.maximumRadius); // Y 方向偏移(北) const latNorth = lat + Cesium.Math.toRadians(spacing / ellipsoid.maximumRadius); const latSouth = lat - Cesium.Math.toRadians(spacing / ellipsoid.maximumRadius); // 获取四个方向的高程 const [hEast, hWest, hNorth, hSouth] = await Promise.all([ getElevation(lonEast, lat), getElevation(lonWest, lat), getElevation(lon, latNorth), getElevation(lon, latSouth) ]); // 中心差分法求导 const dzdx = (hEast - hWest) / (2 * spacing); const dzdy = (hNorth - hSouth) / (2 * spacing); return { dzdx, dzdy }; } ``` --- ### 🔍 解释说明 | 概念 | 说明 | |------|------| | **高程(Elevation)** | 使用 `sampleTerrainMostDetailed()` 从当前加载的地形中采样真实地表高度 | | **坡度(Slope)** | 地表变化率,即法向量与垂直方向夹角,单位通常为“度” | | **坡向(Aspect)** | 地形最陡下降方向的水平投影方位角,0°=正北,90°=正东 | | **有限差分法** | 利用中心点周围的高程差异近似空间导数,是 GIS 中常用方法 | > ⚠️ 注意: - 需要网络连接以加载 `Cesium World Terrain` - `sampleTerrainMostDetailed` 是异步的,需等待数据加载完成 - 若地形未覆盖该区域,可能返回 `undefined` --- ### ✅ 可视化增强建议 你可以添加一个标签或弹窗显示结果: ```js viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(lon, lat, height + 10), label: { text: `高程: ${height.toFixed(1)}m\n坡度: ${slope.toFixed(1)}°`, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(0, -20) } }); ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值