Cesium 计算新坐标教程
计算新坐标 ·computerNewPoint· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么Cesium Viewer 初始化与场景配置Cesium Entity / DataSource 高层 APICesium 屏幕空间拾取交互GUI 参数调试面板效果说明本案例演示计算新坐标效果基于 WebGL 实现「计算新坐标」可视化效果附完整可运行源码核心用到 Cesium。建议先打开文首在线案例查看动态画面再对照下方源码逐步理解。核心概念Viewer封装地球、相机、图层与 clock可关闭 animation/timeline 精简 UI。Entity适合业务对象GeoJsonDataSource加载 GeoJSON 面线点。ScreenSpaceEventHandler监听点击scene.pick取 EntitypickPosition取地表坐标。dat.GUI / lil-gui 绑定 uniform 或配置对象实时调参。实现步骤创建 Viewer配置地形/影像若案例需要并设置初始相机在requestAnimationFrame循环中更新状态并 renderCesium 为viewer.render或自动渲染代码要点/**Cesium点位计算与绘制工具本工具提供交互式点位绘制功能可以根据起始点、方位角和距离计算新点位坐标并绘制在地图上使用球面三角学算法保证计算精度* 功能说明1. 用户点击绘制原始点按钮开始交互式绘制2. 在地图上点击选择起始点3. 输入方位角和距离参数4. 系统自动计算并绘制终点5. 调整视角以完整显示两个点*/// 导入模块和初始化 import * as Cesium from cesium import { GUI } from dat.gui// 获取地图容器元素 const box document.getElementById(box)// GUI控制面板 /**定义图形绘制操作对象namespace obj*/ const obj { /**绘制原始点功能 - 启动交互式绘制模式functionmemberof obj*/ 绘制原始点: () { setupInteractiveDrawing() }, };// 创建GUI控制面板并添加操作按钮 const gui new GUI(); for (const key in obj) gui.add(obj, key)// Cesium Viewer初始化 /**初始化Cesium Viewer实例type {Cesium.Viewer}*/ const viewer new Cesium.Viewer(box, { animation: false, // 不显示动画控件 baseLayerPicker: false, // 不显示图层选择器 baseLayer: Cesium.ImageryLayer.fromProviderAsync( Cesium.ArcGisMapServerImageryProvider.fromUrl(https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer) ), // 设置基础影像图层 fullscreenButton: false, // 不显示全屏按钮 timeline: false, // 不显示时间线 infoBox: false, // 不显示信息框 })// 隐藏Cesium默认的Logo信息 viewer._cesiumWidget._creditContainer.style.display none; // 添加瓦片坐标信息 viewer.imageryLayers.addImageryProvider(new Cesium.TileCoordinatesImageryProvider()); // 状态管理 /**存储已创建的实体对象用于后续操作和清理type {Array }*/ let entitys [];/**存储用户输入的距离值米用于视角调整type {number}*/ let distance;/**全局事件处理器引用用于管理交互事件type {Cesium.ScreenSpaceEventHandler}*/ let globalHandler null;// 交互功能 /**设置交互式绘制模式用户点击地图时绘制点并请求输入方位角和距离以计算新点遵循事件管理规范确保不会重复注册事件*/ function setupInteractiveDrawing() { viewer.entities.removeAll(); entitys []; // 清空实体数组 // 遵循事件管理规范在注册新事件前清除旧事件避免重复注册 if (globalHandler) { globalHandler.destroy(); globalHandler null; } // 创建屏幕空间事件处理器 globalHandler new Cesium.ScreenSpaceEventHandler(viewer.canvas);// 注册鼠标左键点击事件 globalHandler.setInputAction(function (movement) { // 获取点击位置的射线 const ray viewer.camera.getPickRay(movement.position); // 在地球上拾取点击位置 const cartesian viewer.scene.globe.pick(ray, viewer.scene);if (cartesian) { // 将笛卡尔坐标转换为地理坐标经纬度 const cartographic Cesium.Cartographic.fromCartesian(cartesian); const lon Cesium.Math.toDegrees(cartographic.longitude); const lat Cesium.Math.toDegrees(cartographic.latitude);// 绘制第一个点起始点 drawPointOnMap([lon, lat], 起点);// 遵循事件管理规范完成一次绘制后清除事件处理器 if (globalHandler) { globalHandler.destroy(); globalHandler null; } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); }/**在地图上绘制点param {Array } coordinates - 坐标 [lon, lat]param {string} name - 点的名称起点/终点*/ function drawPointOnMap(coordinates, name) { // 创建点实体并添加到Viewer中 const pointEntity viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(coordinates[0], coordinates[1]), point: { pixelSize: 15, // 点的像素大小 color: Cesium.Color.RED, // 点的颜色 outlineColor: Cesium.Color.WHITE, // 点的边框颜色 outlineWidth: 3 // 点的边框宽度 }, label: { // 根据点的索引设置标签文本 text:${name}\n[${coordinates[0].toFixed(4)}, ${coordinates[1].toFixed(4)}], font: 16px sans-serif, // 字体样式 fillColor: Cesium.Color.WHITE, // 字体颜色 outlineColor: Cesium.Color.BLACK, // 字体边框颜色 outlineWidth: 2, // 字体边框宽度 style: Cesium.LabelStyle.FILL_AND_OUTLINE, // 标签样式 verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 垂直对齐方式 pixelOffset: new Cesium.Cartesian2(0, -15) // 像素偏移量 } });// 将创建的实体添加到实体数组中便于后续管理 entitys.push(pointEntity);// 根据点的类型执行不同操作 if (name 起点) { // 如果是起点请求用户输入方位角和距离 requestAngleAndDistance(coordinates[0], coordinates[1]); } else { // 如果是终点调整视角以完整显示所有点 viewer.flyTo(entitys, { duration: 1, offset: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), range: distance * 1.5, // 根据距离调整视角范围 }, }); } }/**弹出输入框请求方位角和距离使用setTimeout确保在事件处理完成后才弹出对话框param {number} lon - 起始点经度param {number} lat - 起始点纬度*/ function requestAngleAndDistance(lon, lat) { setTimeout(() { // 弹出提示框请求用户输入 const value prompt(请输入方位角距离(km/0)\n4510 表示从正北方向顺时针45度方向,距离10公里, 4510 );// 如果用户输入了值 if (value) { // 按-分割输入值 const splitValue value.split();// 检查分割后的数组长度是否为2 if (splitValue.length 2) { // 解析方位角和距离 const angle parseFloat(splitValue[0]); distance parseFloat(splitValue[1]) * 1000; // 转换为米// 检查解析后的值是否为有效数字 if (!isNaN(angle) distance 0) { // 计算新点坐标 const newCoordinates newPointByAngleAndDistance(lon, lat, distance, angle); // 绘制新点 drawPointOnMap(newCoordinates, 终点); } else { alert(输入格式不正确请输入有效的数字); viewer.entities.removeAll(); entitys []; // 清空实体数组 } } else { alert(输入格式不正确请按照格式方位角距离); viewer.entities.removeAll(); entitys []; // 清空实体数组 } } }, 500); }/**根据起始点、距离和角度计算新坐标点位置方法1使用球面三角学的公式计算更精确但计算复杂度较高* 该方法基于球面三角学公式考虑地球曲率的影响适用于中短距离的坐标计算采用椭球体模型通过线性插值计算不同纬度的地球半径* 球面三角学原理在球面上给定一个起始点和移动方向方位角及距离可以计算出终点坐标使用了球面三角学中的正弦定律和余弦定律* param {number} lon - 起始点经度度param {number} lat - 起始点纬度度param {number} distance - 距离米param {number} angle - 方位角度正北为0度顺时针增加returns {Array } [经度, 纬度] - 新点的经纬度坐标*/ function newPointByAngleAndDistance(lon, lat, distance, angle) { // 将角度转换为弧度因为三角函数需要弧度值 let angleRad (angle * Math.PI) / 180;// 根据纬度计算地球半径地球是椭球体 // 赤道半径6378137米极地半径6356752米 // 纬度越高半径越小这里使用线性插值近似计算 let R 6378137 - ((6378137 - 6356752) * lat) / 90;// 将起始点的经纬度转换为弧度 let latRad (lat * Math.PI) / 180; let lonRad (lon * Math.PI) / 180;// 使用球面三角学公式计算新点的纬度 // 这是球面三角学中的正弦定律应用 // sin(newLat) sin(latRad)cos(distance/R) cos(latRad)sin(distance/R) * cos(angleRad) // // 原理解释 // 1. 我们在球面上从起始点(latRad, lonRad)出发沿着方位角angleRad方向移动distance距离 // 2. distance/R 是在球面上移动的弧度因为弧长半径×弧度 // 3. 这个公式考虑了 // - 起始点纬度的影响: sin(latRad) * cos(distance/R) // - 方位角的影响: cos(latRad)sin(distance/R)cos(angleRad) // 4. 最终通过反正弦函数(asin)得到新点的纬度弧度值 let newLat Math.asin( Math.sin(latRad) * Math.cos(distance / R) // 起始点纬度分量保持原有纬度的部分影响 Math.cos(latRad)Math.sin(distance / R)Math.cos(angleRad) // 方位角影响分量方位角和移动距离共同决定的纬度变化 );// 计算新点的经度 // 使用球面三角学中的公式计算经度变化 // 这里使用atan2函数确保结果在正确的象限内 // // 原理解释 // 1. atan2(y, x)函数用于计算从x轴到点(x,y)的弧度角结果范围是[-π, π] // 2. 分子部分Math.sin(angleRad)Math.sin(distance / R)Math.cos(latRad) // 表示东西向经度方向的变化分量 // 3. 分母部分Math.cos(distance / R) - Math.sin(latRad) * Math.sin(newLat) // 表示南北向纬度方向的变化分量 // 4. 将这个角度变化量加到原始经度上得到新点的经度 let newLon lonRad Math.atan2( Math.sin(angleRad)Math.sin(distance / R)Math.cos(latRad), // 东西向分量方位角和距离在经度方向的投影 Math.cos(distance / R) - Math.sin(latRad) * Math.sin(newLat) // 南北向分量考虑起始点和终点纬度影响的修正项 );// 将计算出的弧度转换回角度 newLat (newLat * 180) / Math.PI; newLon (newLon * 180) / Math.PI;return [newLon, newLat]; }完整源码GitHub小结本文提供计算新坐标完整 Cesium.js 源码与在线 Demo建议先运行案例再改 uniform/参数做二次实验更多 Cesium.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库

相关新闻

市面上专业的CD3E膜蛋白供应商口碑

市面上专业的CD3E膜蛋白供应商口碑

在免疫学研究和生物制药领域,CD3E膜蛋白作为T细胞受体复合物的关键组分,其质量和供应稳定性直接影响实验结果的可靠性。面对市场上众多供应商,如何基于真实的行业口碑做出明智选择?本文将结合多个维度,为您剖析专业供应…

2026/6/26 21:38:34阅读更多 →
怎样高效使用res-downloader:视频资源下载实战操作全面解析

怎样高效使用res-downloader:视频资源下载实战操作全面解析

怎样高效使用res-downloader:视频资源下载实战操作全面解析 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader res-d…

2026/6/26 21:38:34阅读更多 →
微信小程序逆向工程终极指南:5步快速掌握wxapkg文件完整解包技术

微信小程序逆向工程终极指南:5步快速掌握wxapkg文件完整解包技术

微信小程序逆向工程终极指南:5步快速掌握wxapkg文件完整解包技术 【免费下载链接】wxappUnpacker forked from https://github.com/qwerty472123/wxappUnpacker 项目地址: https://gitcode.com/gh_mirrors/wxappu/wxappUnpacker 微信小程序的.wxapkg文件总是…

2026/6/26 21:33:34阅读更多 →
终极打字练习指南:如何用Qwerty Learner提升英语肌肉记忆

终极打字练习指南:如何用Qwerty Learner提升英语肌肉记忆

终极打字练习指南:如何用Qwerty Learner提升英语肌肉记忆 【免费下载链接】qwerty-learner 为键盘工作者设计的单词记忆与英语肌肉记忆锻炼软件 / Words learning and English muscle memory training software designed for keyboard workers 项目地址: https://…

2026/6/26 23:03:44阅读更多 →
递归调用在单片机中的应用

递归调用在单片机中的应用

void InOrder(BinTree root) { if (root NULL)// 递归出口return; InOrder(root->lchild); // 自己调用自己,处理左子树 printf("%d ", root->data); InOrder(root- >rchild); // 自己调用自己,处理右子树 }递归的两个必备条件&…

2026/6/26 23:03:44阅读更多 →
iOS审核被拒:二进制包残留第三方支付SDK——你的App里藏着定时炸弹

iOS审核被拒:二进制包残留第三方支付SDK——你的App里藏着定时炸弹

上一期我们聊了3.1.1,核心结论是“虚拟商品必须走IAP”。但3.1.1里有一个极其隐蔽、极其容易踩的细分坑,值得单独用一期来拆解——你根本没调用支付宝/微信支付,但你的二进制包里还躺着它们的SDK,然后被苹果扫出来,直接…

2026/6/26 23:03:44阅读更多 →
现在不升级IDEA 2024.2,你将错过3个重构加速器和2个AI辅助漏洞扫描器

现在不升级IDEA 2024.2,你将错过3个重构加速器和2个AI辅助漏洞扫描器

更多请点击: https://codechina.net 第一章:IDEA 优缺点分析 IntelliJ IDEA 作为 JetBrains 推出的旗舰级 Java 集成开发环境,凭借其智能代码补全、深度框架支持与高度可定制性,在企业级开发中占据重要地位。然而,其设…

2026/6/26 23:03:44阅读更多 →
想在深圳开发小程序,当地口碑好的技术开发公司有哪些?

想在深圳开发小程序,当地口碑好的技术开发公司有哪些?

前两周帮深圳开工厂的发小找小程序开发,他咬死了就要找深圳本地的,说异地沟通肯定不靠谱,结果花了7万找了家网红工作室,3个月改了4版,连最基本的在线报价功能都做不对,最后人家直接摆烂,钱要不回…

2026/6/26 23:03:44阅读更多 →
杰理之超距不回连问题【篇】

杰理之超距不回连问题【篇】

超距后,无论是使能或者失能,都会执行对应的句柄函数conn_state_handler,当前如果没有连接,则不会回连。改为了打开可发现可连接

2026/6/26 22:58:43阅读更多 →
【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体 一文搞定到底什么是智能体【人工智能】一文搞定到底什么是智能体一. LM,WorkFlow,Agent分别有什么么不同二. Agent的思考过程是怎样的三. Agent的五个核心部分1)LLM2)Prompt3)Me…

2026/6/26 11:03:22阅读更多 →
嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

1. 嵌入式GUI控件:从原理到实战的深度解析在嵌入式系统开发中,图形用户界面(GUI)的设计与实现往往是项目从“能用”到“好用”的关键一跃。不同于资源充沛的PC或移动平台,嵌入式设备的GUI需要在有限的CPU性能、内存空间…

2026/6/26 4:15:25阅读更多 →
Google AI Studio 300美元额度的真相与实战指南

Google AI Studio 300美元额度的真相与实战指南

1. 这300美金不是“送钱”,而是Google埋下的第一道技术门槛 你看到标题里那个醒目的“$300美金”时,第一反应可能是:又一个免费额度?领完就完事?我亲手试过——这300美金根本不是红包,而是一张入场券&…

2026/6/26 9:29:01阅读更多 →
HPE (慧与) 服务器专用 ESXi 9 全套官方定制资源详解 + 完整部署升级教程

HPE (慧与) 服务器专用 ESXi 9 全套官方定制资源详解 + 完整部署升级教程

一、前言:企业运维痛点与资源价值自博通收购 VMware 之后,原 VMware 公开免费下载渠道全面关闭,企业运维人员想要获取适配 HPE 慧与服务器的 ESXi 9 原厂镜像,必须注册博通账号、绑定有效授权才能下载,无授权账号无法获…

2026/6/26 0:02:15阅读更多 →
Kotlin的@JvmStatic与@JvmField:与Java互操作的注解

Kotlin的@JvmStatic与@JvmField:与Java互操作的注解

Kotlin作为一门现代编程语言,与Java的互操作性一直是其核心优势之一。为了让Kotlin代码能够无缝对接Java,Kotlin提供了多种注解来优化互操作体验,其中JvmStatic和JvmField是两个关键注解。它们分别用于解决静态成员和字段在Java中的访问问题&…

2026/6/26 0:02:15阅读更多 →
深入解析musl libc中的mmap实现源码

深入解析musl libc中的mmap实现源码

最近在阅读musl libc源码时,发现其mmap的实现非常精妙,特分享给大家。 一、代码整体结构 这段代码实现了__mmap函数,并通过weak_alias导出为mmap。这是典型的musl libc风格——提供弱符号以便用户可以重写。 weak_alias(__mmap, mmap); 二…

2026/6/26 0:02:15阅读更多 →