当前位置: 首页 > article >正文

Cesium 热力图:从原理到实战,打造三维空间数据可视化利器

1. 为什么需要Cesium热力图当你在处理地理空间数据时经常会遇到这样的场景手上有成百上千个带有经纬度和数值的坐标点比如气象站的温度数据、共享单车的分布密度、城市人口热力分布等。如果直接在三维地图上用点标记展示密密麻麻的点会让地图变得杂乱无章根本看不出数据的分布规律。这时候热力图就派上用场了。它能将这些离散的点数据转化为连续的色彩渐变区域用颜色深浅直观展示数据密度和强度。比如在智慧城市项目中我们经常用热力图来展示人流密度、交通拥堵程度等。红色区域表示高密度蓝色区域表示低密度一眼就能看出重点区域在哪里。传统二维地图的热力图实现已经比较成熟但放到三维地球场景中就面临几个挑战如何将平面canvas绘制的热力图贴到三维球体表面经纬度坐标与热力图像素坐标的转换热力图在三维场景中的性能优化Cesium作为最流行的三维地理可视化引擎原生并没有提供热力图功能。但通过结合heatmap.js这个专门的热力图库我们可以完美解决这个问题。下面我就带你从原理到代码一步步实现这个功能。2. 核心原理Canvas转材质贴图2.1 heatmap.js的工作原理heatmap.js是一个轻量级的热力图生成库它的核心原理其实很简单创建一个canvas画布根据传入的点坐标和值在canvas上绘制半透明渐变圆点通过模糊和叠加算法生成平滑的热力效果它的输入数据格式是这样的{ x: 100, // 像素x坐标 y: 150, // 像素y坐标 value: 80 // 该点的值 }但我们的地理数据通常是这样的{ lnglat: [116.404, 39.915], // 经纬度 value: 80 }2.2 Cesium的材质系统Cesium支持将图片作为材质贴到各种几何体上。关键方法是new Cesium.ImageMaterialProperty({ image: canvas.toDataURL() // 将canvas转为图片URL })所以整体思路就很清晰了用heatmap.js在canvas上生成热力图将canvas转为图片URL作为材质应用到Cesium的Polygon上2.3 两种实现方式对比在实际项目中通常有两种实现方案方案优点缺点适用场景Entity/Polygon材质可随地形起伏支持3D效果性能较差数据量大时卡顿小范围高精度展示ImageryLayer性能好支持大数据量只能平面展示无法3D大范围概览本文主要介绍第一种方式因为它更灵活能实现更复杂的三维效果。3. 关键实现经纬度到像素坐标的转换3.1 边界计算算法要实现热力图的准确定位首先需要确定热力图覆盖的地理范围。我们通过以下步骤计算边界遍历所有点找到最小/最大经纬度将经纬度范围适当扩展防止边缘被裁剪计算四个角点的笛卡尔坐标getBound(positions) { // 计算最小最大经纬度 let minLat Number.MAX_VALUE, maxLat Number.MIN_VALUE; let minLng Number.MAX_VALUE, maxLng Number.MIN_VALUE; positions.forEach(pos { const carto Cesium.Cartographic.fromCartesian(pos); if(carto.longitude minLng) minLng carto.longitude; if(carto.longitude maxLng) maxLng carto.longitude; if(carto.latitude minLat) minLat carto.latitude; if(carto.latitude maxLat) maxLat carto.latitude; }); // 扩展边界 const latDiff maxLat - minLat; const lngDiff maxLng - minLng; minLat - latDiff * 0.1; maxLat latDiff * 0.1; minLng - lngDiff * 0.1; maxLng lngDiff * 0.1; // 返回四个角点 return { leftTop: Cesium.Cartesian3.fromDegrees(minLng, maxLat), leftBottom: Cesium.Cartesian3.fromDegrees(minLng, minLat), rightTop: Cesium.Cartesian3.fromDegrees(maxLng, maxLat), rightBottom: Cesium.Cartesian3.fromDegrees(maxLng, minLat) }; }3.2 坐标转换算法有了边界后我们需要将每个点的经纬度转换为热力图的像素坐标计算点在边界矩形内的相对位置将相对位置映射到canvas尺寸const bound this.getBound(positions); const width Cesium.Cartesian3.distance(bound.rightTop, bound.leftTop); const height Cesium.Cartesian3.distance(bound.leftBottom, bound.leftTop); // 计算x/y轴单位向量 const xAxis Cesium.Cartesian3.subtract(bound.rightTop, bound.leftTop, new Cesium.Cartesian3()); Cesium.Cartesian3.normalize(xAxis, xAxis); const yAxis Cesium.Cartesian3.subtract(bound.leftBottom, bound.leftTop, new Cesium.Cartesian3()); Cesium.Cartesian3.normalize(yAxis, yAxis); // 坐标转换 const point positions[i]; const offset Cesium.Cartesian3.subtract(point, bound.leftTop, new Cesium.Cartesian3()); const x Cesium.Cartesian3.dot(offset, xAxis) / width * canvasWidth; const y Cesium.Cartesian3.dot(offset, yAxis) / height * canvasHeight;这个算法确保了无论地图如何缩放旋转热力图都能正确对应到地理位置上。4. 完整实现与性能优化4.1 Heatmap类的封装基于上述原理我们可以封装一个完整的Heatmap类class CesiumHeatmap { constructor(viewer, options) { this.viewer viewer; this.options options; this.points options.points || []; this.canvasSize options.canvasSize || 512; // 初始化heatmap.js this.initHeatmap(); // 创建热力图 this.createHeatmap(); } initHeatmap() { this.container document.createElement(div); this.viewer.container.appendChild(this.container); this.heatmap h337.create({ container: this.container, radius: this.options.radius || 25, maxOpacity: 0.6, minOpacity: 0, blur: 0.8 }); } createHeatmap() { // 计算边界 const bounds this.calculateBounds(); // 转换坐标 const heatmapData this.convertToHeatmapData(bounds); // 设置数据 this.heatmap.setData({ max: this.options.maxValue || 100, min: this.options.minValue || 0, data: heatmapData }); // 创建多边形 this.createPolygon(bounds); } // 其他方法同上... }4.2 性能优化技巧在实际使用中我总结了几点性能优化经验合理设置canvas尺寸通常512x512就能满足大部分需求过大会降低性能数据采样当点数超过1000时建议先进行空间网格聚合动态更新如果数据需要频繁更新可以复用同一个Heatmap实例update(newPoints) { this.points newPoints; const bounds this.calculateBounds(); const heatmapData this.convertToHeatmapData(bounds); this.heatmap.setData({data: heatmapData}); // 更新多边形材质 this.polygon.polygon.material new Cesium.ImageMaterialProperty({ image: this.heatmap.getDataURL() }); }销毁资源不再使用时务必清理DOM和Entitydestroy() { this.viewer.entities.remove(this.polygon); this.container.remove(); this.heatmap null; }4.3 常见问题解决热力图边缘被裁剪怎么办适当扩大计算边界范围确保边界扩展系数足够我通常用0.1-0.2热力图显示模糊怎么处理检查canvas尺寸是否足够调整heatmap.js的radius和blur参数确保材质图片质量material: new Cesium.ImageMaterialProperty({ image: canvas.toDataURL(image/png, 1.0) // 最高质量 })数据更新后热力图不刷新确保调用了heatmap.setData()检查材质是否重新赋值确认Entity的material属性是可变的避免直接使用字符串URL5. 进阶三维热力图实现除了二维的热力图我们还可以实现真正的三维热力图效果。核心思路是使用Primitive API创建自定义几何体在顶点着色器中处理热力值使用同样的热力图作为纹理贴图关键代码结构const primitive new Cesium.Primitive({ geometryInstances: new Cesium.GeometryInstance({ geometry: new Cesium.PolygonGeometry({ polygonHierarchy: new Cesium.PolygonHierarchy(positions), extrudedHeight: 1000 // 设置高度 }) }), appearance: new Cesium.MaterialAppearance({ material: new Cesium.Material({ fabric: { type: Heatmap3D, uniforms: { heatmapTexture: heatmapCanvas.toDataURL(), minValue: 0, maxValue: 100 }, source: ...自定义着色器代码... } }) }) });在着色器中我们可以根据高度和热力值混合颜色实现立体热力效果。这种三维热力图特别适合展示大气污染、地质勘探等需要高度维度的数据。6. 实战案例城市人口热力图最后通过一个实际案例演示如何使用。假设我们要展示某城市的人口密度// 模拟数据 const populationData []; for(let i0; i500; i) { populationData.push({ lnglat: [ 116.3 Math.random() * 0.5, // 经度范围 39.8 Math.random() * 0.4 // 纬度范围 ], value: Math.random() * 100 // 人口密度值 }); } // 创建热力图 const heatmap new CesiumHeatmap(viewer, { points: populationData, canvasSize: 512, radius: 30, gradient: { 0.1: blue, 0.5: cyan, 0.7: lime, 0.9: yellow, 1.0: red } }); // 点击查看数值 viewer.screenSpaceEventHandler.setInputAction(movement { const picked viewer.scene.pick(movement.endPosition); if(picked picked.id heatmap.polygon) { // 显示当前区域的人口密度 console.log(当前区域人口密度:, picked.properties.density); } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);这个案例展示了完整的实现流程包括数据准备、热力图创建和交互处理。你可以根据实际需求调整参数比如修改渐变颜色、调整半径大小等。

相关文章:

Cesium 热力图:从原理到实战,打造三维空间数据可视化利器

1. 为什么需要Cesium热力图? 当你在处理地理空间数据时,经常会遇到这样的场景:手上有成百上千个带有经纬度和数值的坐标点,比如气象站的温度数据、共享单车的分布密度、城市人口热力分布等。如果直接在三维地图上用点标记展示&…...

README文档自动化生成工具的技术实现指南

README文档自动化生成工具的技术实现指南 【免费下载链接】readme-md-generator 📄 CLI that generates beautiful README.md files 项目地址: https://gitcode.com/gh_mirrors/re/readme-md-generator 在开源项目日益增多的今天,项目文档的质量直…...

如何用AI智能翻译漫画:5分钟掌握专业级本地化工具

如何用AI智能翻译漫画:5分钟掌握专业级本地化工具 【免费下载链接】BallonsTranslator 深度学习辅助漫画翻译工具, 支持一键机翻和简单的图像/文本编辑 | Yet another computer-aided comic/manga translation tool powered by deeplearning 项目地址: https://gi…...

运维面试必问的10个K8s问题

在运维岗位的面试中,Kubernetes(K8s)作为容器编排的主流技术,常常是面试官重点考察的内容。以下是运维面试中可能会被问到的10个K8s相关问题及其详细解答,帮助你更好地准备面试。1. 请简要介绍一下Kubernetes及其核心功…...

QTableWidget 表格组件磷

7.1 初识三维模型 7.1.1 三维模型的数据载体 随着计算机图形技术的发展,我们或多或少都会见过或者听说过三维模型。笔者始终记得小时候第一次在电视上看到三维动画《变形金刚:超能勇士》的震撼感受;而现在我们已经可以在手机上玩三维游戏《王…...

从零构建五子棋AI:C++实现中的博弈树搜索与剪枝优化

1. 五子棋AI的基本原理 五子棋是一种双人策略型棋类游戏,玩家通过在棋盘上交替落子,先形成五子连线的一方获胜。要让计算机学会下五子棋,我们需要教会它如何评估棋局并做出最佳决策。这就像教一个小朋友下棋,只不过我们用的是代码…...

掌握AI专著撰写技巧,借助工具,轻松打造高质量学术专著

学术专著创作困境与AI工具解决方案 许多学者在撰写学术专著时,常常面临着“有限的精力”与“无限的需求”之间的矛盾。写一本专著通常需要耗费3到5年,甚至更长的时间,而研究者在日常生活中还要兼顾教学、科研和学术交流等多重任务&#xff0…...

用Docker一键部署OpenMVS开发环境(Ubuntu 18.04 LTS版)

基于Docker的OpenMVS开发环境快速部署指南 在三维重建和计算机视觉领域,OpenMVS作为一套开源的Multi-View Stereo系统,因其强大的功能和灵活性而广受欢迎。然而,传统的本地安装方式往往面临依赖管理复杂、环境配置繁琐、系统兼容性等问题&…...

告别裸奔开发:手把手教你用英飞凌Traveo II SDL7.5.0快速点亮第一个LED

从零到一:Traveo II SDL7.5.0开发环境搭建与LED控制实战 第一次接触英飞凌Traveo II这类车规级MCU时,许多开发者会被其多核架构和丰富的外设资源所震撼——这就像突然从自行车换到了F1赛车,兴奋之余又担心无从下手。作为过来人,我…...

WinDiskWriter:macOS上一键搞定Windows启动盘制作的终极指南

WinDiskWriter:macOS上一键搞定Windows启动盘制作的终极指南 【免费下载链接】windiskwriter 🖥 Windows Bootable USB creator for macOS. 🛠 Patches Windows 11 to bypass TPM and Secure Boot requirements. 👾 UEFI & Le…...

番茄小说下载器完整指南:免费工具让你永久保存心爱小说

番茄小说下载器完整指南:免费工具让你永久保存心爱小说 【免费下载链接】fanqienovel-downloader 下载番茄小说 项目地址: https://gitcode.com/gh_mirrors/fa/fanqienovel-downloader 还在为网络不稳定时无法阅读番茄小说而烦恼吗?fanqienovel-d…...

iOS种子下载终极指南:用iTorrent在iPhone上轻松搞定BT下载的3个技巧

iOS种子下载终极指南:用iTorrent在iPhone上轻松搞定BT下载的3个技巧 【免费下载链接】iTorrent Torrent client for iOS 16 项目地址: https://gitcode.com/gh_mirrors/it/iTorrent 你是否曾经在iPhone上想下载种子文件,却发现iOS系统限制太多&am…...

终极动态壁纸指南:让Linux桌面随时辰自动变换的完整教程

终极动态壁纸指南:让Linux桌面随时辰自动变换的完整教程 【免费下载链接】dynamic-wallpaper A simple bash script to set wallpapers according to current time, using cron job scheduler. 项目地址: https://gitcode.com/gh_mirrors/dy/dynamic-wallpaper …...

Linus的认识和基于win11家庭版与低版本vm不兼容问题的解决

在虚拟的世界中演练千遍,只为了那愿景成真 1.计算机的历史和linus的出世 要从头开始学习linus自然要学习他从何而来。求根溯源,来自那一自我实现的预言———摩尔定律。 集成电路上可容纳的晶体管数量,大约每隔18-24个月便会增加一倍&#xf…...

实战解析 | 第七弹:PiPER集成LeRobot运动控制平滑优化

1. 从机械臂抖动问题说起 第一次看到PiPER机械臂执行任务时的抖动画面,让我想起新手司机开手动挡汽车的情景——明明想平稳起步,却总是一顿一顿的往前窜。这种运动不流畅的问题在模仿学习场景中尤为常见,特别是当我们把LeRobot的ACT算法移植到…...

如何用Tomodoro网页番茄钟打破分心魔咒:专业级时间管理工具全解析

如何用Tomodoro网页番茄钟打破分心魔咒:专业级时间管理工具全解析 【免费下载链接】tomodoro A pomodoro web app with PIP mode, white noise generation, tasks and more! 项目地址: https://gitcode.com/gh_mirrors/to/tomodoro 你是否曾陷入这样的困境&a…...

当你的数据库学习遇到瓶颈时,Chinook数据库如何成为你的跨平台解决方案?

当你的数据库学习遇到瓶颈时,Chinook数据库如何成为你的跨平台解决方案? 【免费下载链接】chinook-database Sample database for SQL Server, Oracle, MySQL, PostgreSQL, SQLite, DB2 项目地址: https://gitcode.com/gh_mirrors/ch/chinook-database…...

求二维数组行优先和列优先的顺序存储的数组元素A[i][j] 的存储地址公式

行优先通用公式:列优先通用公式:数组定义:行数 列数 每个元素占 L 字节注意:以下特例的解法,通用公式仍然可以解决,只要把改成0或改成0即可。如果出现(特例和通用例子同时出现&…...

编程语言特性中的并发模型内存管理与生态比较

编程语言特性中的并发模型、内存管理与生态比较 在当今多核处理器和分布式系统盛行的时代,编程语言的并发模型、内存管理机制以及生态系统的成熟度直接影响开发效率和性能表现。不同语言在这些特性上的设计差异,决定了它们适用的场景和开发体验。本文将…...

微信小程序的大学生心理健康测试职位推荐系统

目录同行可拿货,招校园代理 ,本人源头供货商功能模块划分系统特色功能辅助功能设计项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作同行可拿货,招校园代理 ,本人源头供货商 功能模块划分 心理健康测试模块 提供标准化心理量表…...

HC-05蓝牙模块AT模式配置全攻略:用STM32CubeIDE的串口调试功能搞定(免USB转TTL)

HC-05蓝牙模块AT模式配置全攻略:用STM32CubeIDE的串口调试功能搞定(免USB转TTL) 当你手头只有一块STM32开发板和HC-05蓝牙模块,却需要快速配置模块参数时,传统方法要求额外的USB转TTL工具往往成为绊脚石。本文将揭示如…...

Leather Dress Collection详细步骤:从SD1.5环境搭建到12个皮装模型调用

Leather Dress Collection详细步骤:从SD1.5环境搭建到12个皮装模型调用 1. 项目介绍 Leather Dress Collection是一个基于Stable Diffusion 1.5的LoRA模型集合,专门用于生成各种皮革服装风格的图像。这个集合包含了12个精心训练的LoRA模型,…...

如何用Ai2Psd脚本快速实现AI到PSD的无损转换?终极解决方案揭秘

如何用Ai2Psd脚本快速实现AI到PSD的无损转换?终极解决方案揭秘 【免费下载链接】ai-to-psd A script for prepare export of vector objects from Adobe Illustrator to Photoshop 项目地址: https://gitcode.com/gh_mirrors/ai/ai-to-psd 你是否曾经遇到过这…...

告别算法地狱:用XVF3800麦克风阵列,5天搞定智能音箱语音前端

告别算法地狱:用XVF3800麦克风阵列5天打造智能音箱语音前端 当硬件工程师第一次接到"两个月内交付带远场语音交互的智能音箱原型"的需求时,大多数人会陷入算法恐惧——波束成形、回声消除、噪声抑制这些专业术语就像横亘在面前的喜马拉雅山脉。…...

C语言为什么是程序员的最爱?有什么不同吗

C语言作为一门古老而经典的编程语言,长久以来一直受到程序员们的热爱和推崇。在计算机科学的发展过程中,C语言不仅成为了众多编程语言的基石,更因其简洁、高效和灵活性而成为程序员们的首选。本文将探讨C语言为何成为程序员的最爱&#xff0c…...

Vue3后台管理系统开发革命:如何用vue-admin-box实现零门槛企业级应用

Vue3后台管理系统开发革命:如何用vue-admin-box实现零门槛企业级应用 【免费下载链接】vue-admin-box vue3,vite,element-plus中后台管理系统,集成四套基础模板,大量可利用组件,模板页面 项目地址: https://gitcode.com/gh_mirr…...

NSudo权限管理工具实战指南:突破Windows权限限制的专业解决方案

NSudo权限管理工具实战指南:突破Windows权限限制的专业解决方案 【免费下载链接】NSudo [Deprecated, work in progress alternative: https://github.com/M2Team/NanaRun] Series of System Administration Tools 项目地址: https://gitcode.com/gh_mirrors/ns/N…...

SBTI(Silly Big Personality Test)

SBTI 傻大人格测试,性格测评,这是个数学游戏。因为我们知道了题库,算法,结果,想要什么结果就什么结果。 题库: 计分 结论 性格测评2026 复杂指标测算:诚信评级评价;还有教育方面教育…...

【锂离子电池电化学阻抗谱】用于计算不同充电状态下锂离子电池的宽带电化学阻抗谱研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

Pixel Dimension Fissioner 集成Codex实战:代码生成与智能补全应用

Pixel Dimension Fissioner 集成Codex实战:代码生成与智能补全应用 1. 引言:当AI代码助手遇上智能维度解析 最近在开发一个电商后台系统时,我发现自己每天要写大量重复的CRUD代码。更头疼的是,每次修改数据库字段后,…...