Cesium@1.138中实现平滑曲线编辑器
/** * 平滑曲线编辑器 * 功能根据经纬度生成平滑曲线支持点击曲线显示控制点并输出属性拖拽控制点修改曲线并输出最新坐标 */ class SmoothCurveEditor { /** * 构造函数 * param {Object} Cesium - Cesium 对象 * param {Object} viewer - Cesium Viewer 实例 * param {Array} lngLatArray - 经纬度二维数组例如 [[lng1, lat1], [lng2, lat2], ...] * param {Object} options - 配置项 * param {String} options.id - 曲线实体的 ID * param {Object} options.properties - 曲线的自定义属性 * param {Function} options.onLineClick - 点击曲线时的回调函数参数为线的属性 * param {Function} options.onEditEnd - 拖拽结束时的回调函数参数为(最新经纬度数组, 线的属性) */ constructor(Cesium, viewer, lngLatArray, options {}) { this.Cesium Cesium; this.viewer viewer; // 保存配置项 this.options options; this.lineId options.id || smooth-curve- Cesium.createGuid(); this.lineProperties options.properties || {}; // 存储控制点笛卡尔坐标 this.controlPoints lngLatArray.map(lngLat Cesium.Cartesian3.fromDegrees(lngLat[0], lngLat[1]) ); // 存储拖拽点实体 this.controlPointEntities []; // 存储曲线实体 this.curveEntity null; // 缓存平滑曲线的插值点 this.interpolatedPoints []; // 拖拽状态 this.isDragging false; this.draggingIndex -1; // 事件处理器 this.handler new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); this._init(); } /** * 初始化 */ _init() { this._calcInterpolatedPoints(); this._createCurveEntity(); this._createControlPoints(); this._bindEvents(); } /** * 仅计算平滑曲线插值点并更新缓存 */ _calcInterpolatedPoints() { const Cesium this.Cesium; const points this.controlPoints; if (points.length 2) return; const times []; for (let i 0; i points.length; i) { times.push(i / (points.length - 1)); } const spline new Cesium.CatmullRomSpline({ times: times, points: points }); const interpolatedPoints []; const segments 30; for (let i 0; i points.length - 1; i) { for (let j 0; j segments; j) { const t i j / segments; interpolatedPoints.push(spline.evaluate(t / (points.length - 1))); } } interpolatedPoints.push(points[points.length - 1]); this.interpolatedPoints interpolatedPoints; } /** * 创建曲线实体支持自定义 ID 和属性 */ _createCurveEntity() { const Cesium this.Cesium; const self this; this.curveEntity this.viewer.entities.add({ id: this.lineId, // 绑定自定义属性 properties: new Cesium.PropertyBag(this.lineProperties), polyline: { positions: new Cesium.CallbackProperty(() { return self.interpolatedPoints; }, false), width: 4, material: Cesium.Color.fromBytes(0, 255, 255, 255), clampToGround: new Cesium.ConstantProperty(true) } }); } /** * 创建拖拽控制点实体初始隐藏 */ _createControlPoints() { const Cesium this.Cesium; this.controlPointEntities this.controlPoints.map((position, index) { return this.viewer.entities.add({ id: curve-control-point- index - Cesium.createGuid(), position: position, point: { pixelSize: 12, color: Cesium.Color.fromCssColorString(#FF4500).withAlpha(1.0), outlineColor: Cesium.Color.WHITE, outlineWidth: 2, show: false } }); }); } /** * 绑定鼠标事件 */ _bindEvents() { const Cesium this.Cesium; const viewer this.viewer; // 鼠标左键按下 this.handler.setInputAction((movement) { const pickedObject viewer.scene.pick(movement.position); // 1. 判断是否点击到了控制点 if (Cesium.defined(pickedObject) Cesium.defined(pickedObject.id)) { const entityId pickedObject.id.id; const index this.controlPointEntities.findIndex(e e.id entityId); if (index ! -1) { this.isDragging true; this.draggingIndex index; this.curveEntity.polyline.clampToGround.setValue(false); viewer.scene.screenSpaceCameraController.enableRotate false; viewer.scene.screenSpaceCameraController.enableTranslate false; viewer.scene.screenSpaceCameraController.enableZoom false; viewer.scene.screenSpaceCameraController.enableTilt false; return; } } // 2. 判断是否点击到了曲线本身 if (Cesium.defined(pickedObject) pickedObject.id this.curveEntity) { this._showControlPoints(true); // 触发点击回调输出线的属性 if (this.options.onLineClick) { // 将 PropertyBag 转换为普通 JS 对象输出 const props {}; const propertyNames pickedObject.id.properties.propertyNames; propertyNames.forEach(name { props[name] pickedObject.id.properties[name].getValue(); }); this.options.onLineClick(props); } } else { // 3. 点击了空白区域隐藏控制点 this._showControlPoints(false); } }, Cesium.ScreenSpaceEventType.LEFT_DOWN); // 鼠标移动拖拽更新 this.handler.setInputAction((movement) { if (this.isDragging) { const cartesian viewer.camera.pickEllipsoid( movement.endPosition, viewer.scene.globe.ellipsoid ); if (cartesian) { this.controlPoints[this.draggingIndex] cartesian; this.controlPointEntities[this.draggingIndex].position new Cesium.ConstantProperty(cartesian); this._calcInterpolatedPoints(); viewer.scene.requestRender(); } } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); // 鼠标左键抬起结束拖拽 this.handler.setInputAction(() { if (this.isDragging) { this.isDragging false; this.draggingIndex -1; this.curveEntity.polyline.clampToGround.setValue(true); viewer.scene.screenSpaceCameraController.enableRotate true; viewer.scene.screenSpaceCameraController.enableTranslate true; viewer.scene.screenSpaceCameraController.enableZoom true; viewer.scene.screenSpaceCameraController.enableTilt true; viewer.scene.requestRender(); // 触发编辑完成回调输出最新坐标和属性 if (this.options.onEditEnd) { const latestCoords this.getLngLatPositions(); const props {}; const propertyNames this.curveEntity.properties.propertyNames; propertyNames.forEach(name { props[name] this.curveEntity.properties[name].getValue(); }); this.options.onEditEnd(latestCoords, props); } } }, Cesium.ScreenSpaceEventType.LEFT_UP); } /** * 控制拖拽点的显示与隐藏 */ _showControlPoints(show) { this.controlPointEntities.forEach(entity { entity.point.show new this.Cesium.ConstantProperty(show); }); this.viewer.scene.requestRender(); } /** * 获取当前控制点的经纬度数组 */ getLngLatPositions() { const Cesium this.Cesium; const cartographics this.controlPoints.map(point Cesium.Cartographic.fromCartesian(point) ); return cartographics.map(carto [ Cesium.Math.toDegrees(carto.longitude), Cesium.Math.toDegrees(carto.latitude) ]); } /** * 销毁实例释放资源 */ destroy() { if (this.handler) { this.handler.destroy(); this.handler null; } if (this.curveEntity) { this.viewer.entities.remove(this.curveEntity); this.curveEntity null; } if (this.controlPointEntities.length 0) { this.controlPointEntities.forEach(entity { this.viewer.entities.remove(entity); }); this.controlPointEntities []; } this.interpolatedPoints []; } } export default SmoothCurveEditor;使用实例const coordsArray [ [116.39, 39.90], [116.42, 39.92], [116.45, 39.89], [116.48, 39.91] ]; const editor new SmoothCurveEditor(Cesium, viewer, coordsArray, { id: my-custom-line-id, properties: { name: 测试路段, level: 高速 }, onLineClick: (props) { console.log(点击了线属性为:, props); // 输出: 点击了线属性为: { name: 测试路段, level: 高速 } }, onEditEnd: (newCoords, props) { console.log(拖拽结束最新坐标为:, newCoords); console.log(线的属性为:, props); } });

相关新闻

WWW时间检验奖颁给唐建博士:图神经网络的十年远征与AI制药的底层逻辑

WWW时间检验奖颁给唐建博士:图神经网络的十年远征与AI制药的底层逻辑

在人工智能这个以「季度」甚至「月度」为单位刷新认知的领域,谈论「十年」是一件十分奢侈的事。技术发展得越来越快,永远有更新的亮点技术在抓住我们的眼球。也正因如此,当一项成果在提出十年之后被重新拿到聚光灯下,并被郑重授予…

2026/7/8 4:41:48阅读更多 →
【计算机Java毕业设计案例】基于 SpringBoot 的公交实时信息推送系统的设计与实现 基于小程序的公交收藏与出行规划系统(程序+文档+讲解+定制)

【计算机Java毕业设计案例】基于 SpringBoot 的公交实时信息推送系统的设计与实现 基于小程序的公交收藏与出行规划系统(程序+文档+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/8 4:36:47阅读更多 →
音视频转文字工具实测:短视频创作者效率翻倍方案

音视频转文字工具实测:短视频创作者效率翻倍方案

做短视频创作的朋友应该都有同感:每天花在「扒文案」和「拍口播」上的时间,远远超过了实际剪辑和构思的时间。尤其对于日更型创作者来说,效率就是生命线。我过去半年试了市面上主流的音视频转文字工具,最终形成了一套稳定高效的工…

2026/7/8 4:36:47阅读更多 →
Milvus-05-将文本变成向量并入库

Milvus-05-将文本变成向量并入库

文本变成向量这个操作是由大模型的embedding模型去做的,根据业界约定,如果你看到模型内部由encode开头的函数,指的就是将XXX变成向量,具体XXX是什么不一定,文本,图片,视频什么的都有可能&#x…

2026/7/8 5:36:52阅读更多 →
为什么选择drawDB而非传统数据库设计工具?

为什么选择drawDB而非传统数据库设计工具?

为什么选择drawDB而非传统数据库设计工具? 【免费下载链接】drawdb Free, simple, and intuitive online database diagram editor and SQL generator. 项目地址: https://gitcode.com/GitHub_Trending/dr/drawdb 在数据库设计领域,我们常常面临一…

2026/7/8 5:36:52阅读更多 →
智能AI招聘面试系统:HR 真正省下来的时间,藏在面试环节里

智能AI招聘面试系统:HR 真正省下来的时间,藏在面试环节里

企业花大量时间筛简历、排面试,最终候选人 Offer 接受率却不到 60%——这个问题,几乎所有规模化招聘的 HR 都遇到过。智能面试系统通过 AI 自动记录面试纪要、结构化评估候选人、统一面试官打分标准,能将面试协调时间压缩 70% 以上&#xff0…

2026/7/8 5:36:52阅读更多 →
私域直播APP开发需要多久?私域直播电商系统源码开发周期详细解析

私域直播APP开发需要多久?私域直播电商系统源码开发周期详细解析

随着私域流量运营持续升温,越来越多企业开始布局私域直播,希望借助直播带货、会员运营、社群营销等方式提升成交效率。因此,不少客户在咨询时都会问同一个问题:开发一套私域直播APP到底需要多久?事实上,开发…

2026/7/8 5:36:52阅读更多 →
真实测评含金量高的职业资格市场岗位证书有哪些?2026年市场人系统提升路径与方法指南

真实测评含金量高的职业资格市场岗位证书有哪些?2026年市场人系统提升路径与方法指南

在与许多从事市场营销和运营工作的朋友交流时,我经常会听到一种普遍的职业焦虑:“每天都在忙着追热点、写策划、盯投放,但总感觉自己像个无情的执行机器。”随着我们逐渐迈向2026年,行业的数字化转型和AI技术的普及,正…

2026/7/8 5:36:52阅读更多 →
FITK AI Assistant | 为 FastCAE 注入 AI 大脑

FITK AI Assistant | 为 FastCAE 注入 AI 大脑

一 背景与动机CAE 软件历来以「菜单繁多、操作门槛高」著称。一个工程师往往需要在数十个对话框之间穿梭,才能完成一次完整的仿真流程。能不能让工程师直接用自然语言说出意图,由 AI 去驱动软件完成操作?FITKAIAssistant 就是这样一个尝试——…

2026/7/8 5:31:51阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/8 5:12:14阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/7 2:56:31阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/8 2:26:06阅读更多 →
作为一个给团队打绩效的人,我想说几句

作为一个给团队打绩效的人,我想说几句

我每半年都会给团队成员打绩效,也会参与和 CTO 的绩效校准,所以从管理者的视角,说说这件事 首先,我先把结论告诉你:接受结果,但一定要把原因问清楚。 因为当绩效公布到你这里的时候,结果基本已…

2026/7/8 0:01:17阅读更多 →
A股股指期货:全维度解析(多表格结构化完整版)

A股股指期货:全维度解析(多表格结构化完整版)

一、基础定义与核心本质股指期货全称股票价格指数期货,是中国金融期货交易所(中金所)上市的标准化金融期货合约,交易标的为 A 股大盘指数,约定未来特定时间按约定价格现金交割指数涨跌差价,不交割一篮子股票…

2026/7/8 0:01:17阅读更多 →
iOS越狱新手指南:从困惑到掌控,3天解锁iPhone无限潜能的真实故事

iOS越狱新手指南:从困惑到掌控,3天解锁iPhone无限潜能的真实故事

iOS越狱新手指南:从困惑到掌控,3天解锁iPhone无限潜能的真实故事 【免费下载链接】Jailbreak iOS 26.4 - 26, 17 - 17.7.5 & iOS 18 - 18.7.3 Jailbreak Tools, Cydia/Sileo/Zebra Tweaks & Jailbreak News Updates || AI Jailbreak Finder &…

2026/7/8 0:01:17阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/7 5:11:21阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/7 5:11:21阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/7 5:11:21阅读更多 →