Cesium 实战功能指南:三维网格剖分 + 无人机飞行仿真(开源可落地)
在 Cesium 三维 GIS、数字孪生、低空无人机仿真项目中,空域网格剖分 和动态飞行推演是高频刚需功能。很多开源项目只实现了基础的航线绘制、简单点位移动,存在功能零散、无标准化网格、无状态回调、无法业务落地等问题。
今天给大家分享一套功能全覆盖、解耦可复用、商业级可用 的 Cesium 工具类,整合5种三维空域网格剖分 、全流程无人机动态仿真 、实时状态数据回调 、网格动态可视化推演核心能力,所有功能独立可单独调用,适配绝大多数低空GIS业务场景。
一、整体功能架构
整套工具类分为两大核心功能板块,所有方法解耦独立,支持按需引入、单独调用,无需冗余依赖:
-
三维网格剖分功能:支持点、线、面、圆柱、立方体全空域剖分,自定义精度层级
-
无人机仿真推演功能:支持飞行、暂停、续飞、重置,实时数据回调+网格动态高亮
核心优势:不绑定地图、不污染全局、无硬编码配置,Vue / React / 原生 JS 项目均可直接集成。
二、核心功能一:全场景三维网格剖分
网格剖分是空域分析、航线检测、巡检覆盖统计的基础。本工具内置10级精度网格,支持从大范围概览到精细化厘米级剖分,同时内置数量限制,杜绝页面卡顿。下面逐一讲解每一项实用功能。
2.1 单点网格剖分
针对任意经纬度、高度点位,精准匹配对应的三维网格,适用于单点空域核查、点位网格定位、坐标网格映射场景。
功能效果:自动定位点位所在立体网格,高亮展示网格范围,返回网格编码、空间范围、中心点等完整数据。
对应功能实战代码(可直接运行):
javascript
// 单点网格剖分:查询指定坐标、高度对应的三维网格
// 定义目标点位坐标与高度
const pointParam = {
lat: 39.9080, // 纬度
lon: 116.3960, // 经度
alt: 120 // 高度(米)
};
// 调用工具方法,7级精度剖分
// 先通过编码解析获取网格范围
const gridCode = gridSim.encode(pointParam.lat, pointParam.lon, pointParam.alt, 7);
const gridBounds = gridSim.gridInfo(gridCode);
// 绘制单点网格并获取结果
const pointGridRes = gridSim.drawPointGrid(gridBounds);
// 打印网格完整信息
console.log('单点匹配网格数据:', pointGridRes.list);
console.log('网格编码:', gridBounds.code);
2.2 航线线状网格剖分
最常用的核心功能,传入无人机起止航线点位,自动采样整条航线,生成航线全覆盖三维网格。完美适配无人机巡检航线预演、航迹覆盖统计、航线空域筛查业务。
功能亮点:自动去重网格、精准贴合飞行路径、支持自定义网格精度,可直接用于统计整条航线的覆盖空域数量。
对应功能实战代码(可直接运行):
javascript
// 航线线状网格剖分:生成整条航线覆盖网格
// 定义航线起止点位
const lineStart = { lat: 39.9080, lon: 116.3960, alt: 120 };
const lineEnd = { lat: 39.9095, lon: 116.3980, alt: 120 };
// 7级精度剖分航线网格
const lineGridRes = gridSim.drawLineGrid(lineStart, lineEnd, 7);
// 打印航线网格结果
console.log('航线覆盖网格总数:', lineGridRes.list.length);
console.log('航线网格列表:', lineGridRes.list);
2.3 多边形面域网格剖分
支持自定义任意多边形轮廓+高度区间,实现面域立体全覆盖剖分。适用于不规则作业区域、地块巡检、自定义禁飞区网格分析。
底层采用射线法点包含算法,精准筛选多边形内部网格,剔除边缘无效网格,保证剖分结果精准无冗余。
对应功能实战代码(可直接运行):
javascript
// 多边形面域网格剖分:不规则作业区立体网格全覆盖
// 自定义多边形轮廓点位
const polygonPoints = [
{ lat: 39.9085, lon: 116.3955 },
{ lat: 39.9095, lon: 116.3975 },
{ lat: 39.9075, lon: 116.3985 },
{ lat: 39.9065, lon: 116.3965 }
];
// 定义作业高度区间
const minAlt = 80;
const maxAlt = 150;
// 7级精度剖分多边形网格
const prismGridRes = gridSim.drawPrismGrid(polygonPoints, minAlt, maxAlt, 7);
// 打印面域网格数据
console.log('多边形面域网格总数:', prismGridRes.list.length);
2.4 圆柱空域网格剖分
传入中心点、半径、高度区间,生成圆形空域网格,适配雷达扫描范围、圆形警戒空域、定点环绕飞行空域场景,是低空安防、警戒分析的核心功能。
对应功能实战代码(可直接运行):
javascript
// 圆柱空域网格剖分:圆形警戒/雷达空域网格
// 定义圆形空域参数
const cylinderCenter = { lat: 39.9080, lon: 116.3960 };
const radius = 80; // 空域半径 80米
const cylMinAlt = 60;
const cylMaxAlt = 200;
// 7级精度生成圆柱网格
const cylinderGridRes = gridSim.drawCylinderGrid(cylinderCenter, radius, cylMinAlt, cylMaxAlt, 7);
console.log('圆柱空域网格总数:', cylinderGridRes.list.length);
2.5 立方体空域网格剖分
通过经纬度极值+高度区间构建立体空域,实现规整矩形空域剖分,适用于固定作业区块、空域区块划分、批量网格统计。
对应功能实战代码(可直接运行):
javascript
// 立方体空域网格剖分:矩形规整空域批量剖分
// 定义矩形经纬度范围 & 高度范围
const cuboidParams = {
minLat: 39.9060,
maxLat: 39.9100,
minLon: 116.3940,
maxLon: 116.3990,
minAlt: 50,
maxAlt: 180
};
// 7级精度立方体网格剖分
const cuboidGridRes = gridSim.drawCuboidGrid(
cuboidParams.minLat,
cuboidParams.maxLat,
cuboidParams.minLon,
cuboidParams.maxLon,
cuboidParams.minAlt,
cuboidParams.maxAlt,
7
);
console.log('立方体空域网格总数:', cuboidGridRes.list.length);
2.6 通用功能配套
-
10级网格精度自由切换,适配不同场景精度需求
-
自动视角定位,剖分完成自动飞行至目标空域
-
网格数量上限拦截,防止超高精度剖分导致性能崩溃
-
统一返回网格编码、坐标范围、中心点数据,方便二次开发统计
三、核心功能二:无人机动态飞行仿真
摒弃网上简陋的匀速点位平移动画,基于球面真实距离计算,实现物理级贴合真实飞行的仿真效果,支持完整生命周期交互与数据回调。
3.1 全生命周期仿真控制
完整支持无人机飞行仿真全套操作,覆盖项目所有交互需求:
-
启动仿真:加载航线、生成网格、开始动态飞行
-
暂停仿真:定格当前位置,记录暂停时间
-
继续飞行:补偿暂停时长,无缝接续飞行,无位置偏移
-
重置仿真:清空场景、重置所有状态、恢复初始状态
3.2 动态网格高亮推演(特色功能)
行业可视化最优方案,全程三色网格动态切换,直观展示飞行进度:
-
未飞行网格:绿色半透明,代表待覆盖空域
-
当前飞行网格:红色高亮,实时定位无人机所在空域
-
已飞过网格:蓝色固化,记录已覆盖空域
可视化效果直观专业,可直接用于数字孪生大屏、项目演示、方案汇报。
3.3 全量实时状态回调(业务核心)
仿真全程对外抛出完整可落地的业务数据,无需二次计算,直接用于页面渲染、数据统计、日志记录、进度展示。
所有回调字段功能详解:
3.3.1 飞行进度数据
-
travelled:实时已飞行距离(米)
-
totalDistance:航线总里程(米)
-
percent:飞行完成百分比,可直接绑定进度条
3.3.2 无人机位置数据
- lat / lon / alt:实时经纬度、飞行高度,精准定位无人机空间位置
3.3.3 网格统计数据
-
currentGridCode:当前所在网格唯一编码,用于空域标识
-
currentGridIndex:当前网格序号
-
passedGrids:已覆盖网格数量
-
totalGrids:航线总网格数量
-
remainingGrids:剩余未覆盖网格数量
3.3.4 仿真状态类型
-
start:仿真启动
-
running:飞行中(实时帧更新)
-
pause:仿真暂停
-
resume:恢复飞行
-
finish:飞行完成
3.4 自定义参数配置
支持自由配置飞行高度、飞行速度、仿真速率、网格精度,适配不同无人机机型、不同巡检场景的仿真需求。
四、功能落地业务场景
这套工具所有功能均为业务落地设计,适配当下主流低空、数字孪生GIS项目:
-
无人机巡检仿真:航线预演、覆盖范围核验、飞行进度可视化
-
低空空域分析:空域网格拆分、容量统计、禁飞区冲突检测
-
数字孪生大屏:三维场景+实时数据双向联动,可视化展示航迹与空域
-
教学与方案演示:分步演示飞行逻辑、空域覆盖,支持暂停复盘
五、快速调用示例(功能实战)
极简调用方式,一键启动仿真,监听所有状态,直接对接UI交互:
javascript
// 初始化仿真工具
const gridSim = new GridSimulation(viewer);
// 自定义航线点位
const route = [
{ lat: 39.9080, lon: 116.3960 },
{ lat: 39.9095, lon: 116.3980 }
];
// 启动仿真,配置高度、速度,监听全量状态
gridSim.startSimulation(route, { alt: 120, speed: 8 }, (status) => {
// 打印实时飞行数据
console.log('飞行状态数据:', status);
// 暂停状态自定义UI提示
if(status.type === 'pause'){
document.getElementById('sim-status').innerHTML +=
'<br><i style="color:#ffa726">已暂停(点击 ▶ 开始 继续)</i>';
}
})
// 暂停仿真调用
// gridSim.pauseSim();
// 重置仿真调用
// gridSim.resetSim();
六、完整开源源码
以下为全套无删减商用级源码,包含所有网格剖分、无人机仿真、状态回调核心功能,注释完整、可直接复制集成项目:
javascript
/**
* 三维网格分析 + 无人机仿真工具类
* 核心功能:多形态三维网格剖分、无人机动态飞行仿真、全生命周期状态回调、网格高亮推演
* 适配场景:无人机巡检、低空空域分析、数字孪生航迹推演、三维GIS可视化
* 特点:解耦设计、无硬编码、高性能、可直接商用
*/
import * as Cesium from 'cesium';
/** 地球每度对应的米数常量 */
const M_PER_DEG = 111319.49079327357;
/** 10级网格精度配置(1-10级) */
const LEVELS = [
null,
{ lon: 6.0, lat: 4.0, cols: 60, rows: 22 },
{ lon: 0.5, lat: 0.5, cols: 12, rows: 8 },
{ lon: 0.25, lat: 0.25, cols: 2, rows: 2 },
{ lon: 1 / 60, lat: 1 / 60, cols: 15, rows: 15 },
{ lon: 4 / 3600, lat: 4 / 3600, cols: 15, rows: 15 },
{ lon: 2 / 3600, lat: 2 / 3600, cols: 2, rows: 2 },
{ lon: 0.25 / 3600, lat: 0.25 / 3600, cols: 8, rows: 8 },
{ lon: 1 / 32 / 3600, lat: 1 / 32 / 3600, cols: 8, rows: 8 },
{ lon: 1 / 256 / 3600, lat: 1 / 256 / 3600, cols: 8, rows: 8 },
{ lon: 1 / 2048 / 3600, lat: 1 / 2048 / 3600, cols: 8, rows: 8 }
];
/** 最大网格数量限制,性能防护 */
const MAX_GRIDS = 50000;
/** 仿真全局状态管理 */
const sim = {
running: false,
paused: false,
startMs: 0,
totalPausedMs: 0,
pauseStartMs: 0,
routeMeters: 0,
segments: [],
grids: [],
codeToIdx: new Map(),
entities: [],
drone: null,
route: null,
alt: 100,
speed: 10,
rate: 5,
level: 7,
currentIdx: -1,
lastPos: null,
onStatusUpdate: null
};
export default class GridSimulation {
constructor(viewer) {
if (!viewer) throw new Error("必须传入 Cesium Viewer 实例");
this.map = viewer;
}
// 工具方法:结果摘要生成
showResult(html) {
console.log(html);
return html;
}
listSummary(list) {
let h = '<b>共 ' + list.length + ' 个网格</b><br>';
list.slice(0, 30).forEach((g, i) => {
h += i + 1 + '. <code>' + g.code + '</code><br>';
});
if (list.length > 30) h += '... 仅显示前 30 条';
return h;
}
// 1. 单点网格剖分
drawPointGrid(bounds) {
this.clearAll();
this.drawGrid(bounds, Cesium.Color.YELLOW.withAlpha(0.5));
this.flyToGrids([bounds]);
const list = [bounds];
const html = this.showResult(this.listSummary(list));
return { list, html };
}
// 2. 航线线状网格剖分
drawLineGrid(start, end, level = 7) {
this.clearAll();
const list = this.queryLineGrids(start, end, level);
list.forEach(g => this.drawGrid(g, Cesium.Color.LIME.withAlpha(0.35)));
this.map.entities.add({
polyline: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights([
start.lon, start.lat, start.alt,
end.lon, end.lat, end.alt
]),
width: 3,
material: Cesium.Color.RED
}
});
this.flyToGrids(list);
const html = this.showResult(this.listSummary(list));
return { list, html };
}
// 3. 圆柱空域网格剖分
drawCylinderGrid(center, radius, minAlt, maxAlt, level = 7) {
this.clearAll();
const list = this.queryCylinderGrids(center, radius, minAlt, maxAlt, level);
list.forEach(g => this.drawGrid(g, Cesium.Color.ORANGE.withAlpha(0.35)));
this.map.entities.add({
position: Cesium.Cartesian3.fromDegrees(center.lon, center.lat, (minAlt + maxAlt) / 2),
cylinder: {
length: maxAlt - minAlt,
topRadius: radius,
bottomRadius: radius,
material: Cesium.Color.RED.withAlpha(0.12),
outline: true,
outlineColor: Cesium.Color.RED
}
});
this.flyToGrids(list);
const html = this.showResult(this.listSummary(list));
return { list, html };
}
// 4. 多边形面域网格剖分
drawPrismGrid(points, minAlt, maxAlt, level = 7) {
this.clearAll();
const list = this.queryPrismGrids(points, minAlt, maxAlt, level);
list.forEach(g => this.drawGrid(g, Cesium.Color.MAGENTA.withAlpha(0.35)));
const arr = [];
points.forEach(p => arr.push(p.lon, p.lat, maxAlt));
arr.push(points[0].lon, points[0].lat, maxAlt);
this.map.entities.add({
polyline: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights(arr),
width: 3,
material: Cesium.Color.RED
}
});
this.flyToGrids(list);
const html = this.showResult(this.listSummary(list));
return { list, html };
}
// 5. 立方体空域网格剖分
drawCuboidGrid(minLat, maxLat, minLon, maxLon, minAlt, maxAlt, level = 7) {
this.clearAll();
const list = this.queryCuboidGrids(minLat, maxLat, minLon, maxLon, minAlt, maxAlt, level);
list.forEach(g => this.drawGrid(g, Cesium.Color.BLUE.withAlpha(0.35)));
this.map.entities.add({
rectangle: {
coordinates: Cesium.Rectangle.fromDegrees(minLon, minLat, maxLon, maxLat),
material: Cesium.Color.RED.withAlpha(0.12),
outline: true,
outlineColor: Cesium.Color.RED,
height: minAlt,
extrudedHeight: maxAlt
}
});
this.flyToGrids(list);
const html = this.showResult(this.listSummary(list));
return { list, html };
}
// 启动无人机仿真
startSimulation(routePoints, options = {}, onStatusUpdate = null) {
if (!this.map) return;
sim.onStatusUpdate = onStatusUpdate;
// 暂停恢复逻辑
if (sim.paused) {
sim.paused = false;
sim.totalPausedMs += performance.now() - sim.pauseStartMs;
this.pushStatus('resume');
requestAnimationFrame(() => this.simTick());
return;
}
if (sim.running) return;
// 初始化配置参数
const { alt = 100, speed = 10, rate = 5, level = 7 } = options;
sim.alt = alt;
sim.speed = speed;
sim.rate = rate;
sim.level = level;
sim.lastPos = { ...routePoints[0], alt };
this.resetSim();
const pts = routePoints;
if (pts.length < 2) {
alert('航线至少需要2个点');
return;
}
// 计算航线里程与航线段
let cum = 0;
for (let i = 0; i < pts.length - 1; i++) {
const a = pts[i];
const b = pts[i + 1];
const d = this.distM(a.lat, a.lon, b.lat, b.lon);
sim.segments.push({ a, b, dist: d, start: cum });
cum += d;
}
sim.route