Cesium 含水三维管道网络模拟
Cesium 管道实体
- 目的在于根据数据的点坐标生成三维管网
- 需要体现出管道内水位情况
为了展示出管道内水位,需要将管道实体透明化,此时仅仅用点、线坐标数据直接生成管网会造成视觉混乱,因此需要将管道单体化并加以处理
- 分为水平管道与垂直管道两类,在两类管道接洽时避免了重叠现象的出现
- 使用es5对象思维进行封装
使用方法
垂直管道
VerticalPipe(pipeEntityCollection, id, positions, height, pipeRadius, pipeHeight, waterHeight)
参数解释
param {DataSource}
pipeEntityCollection: 添加实体的数据源(viewer或自定义CustomDataSource)
param {String}
id: 实体id
param {Array}
positions: 实体经纬度 [经度, 纬度]
param {Number}
height: 实体据地面高度,默认为0
param {Number}
pipeRadius: 管道外径,默认外径0.8、内径为外径的2/3
param {Number}
pipeHeight: 管道高度, 默认为1.5
param {Number}
waterHeight: 管道内水高, 默认为0
水平管道
HorizontalPipe(pipeEntityCollection, id, positions, cut, status, pipeRadius)
参数解释
param {DataSource}
pipeEntityCollection: 添加实体的数据源(viewer或自定义CustomDataSource)
param {String}
id: 实体id
param {Array}
positions: 组成管道的点集合 […, 经度, 纬度, 高度, …]
param {"single" | "both" | "null"}
cut: 为避免水平管道与垂直管道重叠对水平管道进行裁切,默认不裁切
param {1 | 2 | 3 | 4}
status: 管道内水位状态, 默认为1
param {Number}
pipeRadius: 管道外径,默认为0.4、内径为外径的2/3
实际演示
生成两个垂直管道,中间由一段水平管道相连,代码与实际结果如下:
// 垂直管道
VerticalPipe(pipeEntityCollection, "node-A", [117.145668, 34.2198067], 0, null, null, 0.8);
VerticalPipe(pipeEntityCollection, "node-B", [117.1459503, 34.2195511], 0, null, null, 0.8);
// 水平管道
HorizontalPipe(pipeEntityCollection,"link",[117.1456680, 34.2198067, 0, 117.1457386, 34.2197631, 0, 117.1458055, 34.2197096, 0,117.1458516, 34.2196686, 0, 117.1459059, 34.2196069, 0, 117.1459503,34.21955110, 0],"both",2
);
可以看到,虽然垂直管道与水平管道有坐标点重叠,但是展示时两者并无叠置
源码解析
源码下载地址:Cesium垂直+水平含水管道实体-Javascript文档类资源-CSDN文库
大部分代码都是很简单的逻辑,大家自行查看源码即可,这里重点讲解两部分代码
- 根据中心点和半径生成圆形的函数
/*** 管道截面形状计算,根据中心点和半径生成圆形* @param {Array} initialPosition [经度, 纬度]* @param {Number} radius 截面半径* @returns 组成截面的点集合*/function computeCircle(initialPosition, radius) {let Ea = 6378137; // 赤道半径let Eb = 6356725; // 极半径let positionArr = [];//cesium正东是0°for (let i = 0; i <= 360; i++) {let dx = radius * Math.sin((i * Math.PI) / 180.0);let dy = radius * Math.cos((i * Math.PI) / 180.0);let ec = Eb + ((Ea - Eb) * (90.0 - initialPosition[1])) / 90.0;let ed = ec * Math.cos((initialPosition[1] * Math.PI) / 180);let BJD = initialPosition[0] + ((dx / ed) * 180.0) / Math.PI; // 圆弧点经度let BWD = initialPosition[1] + ((dy / ec) * 180.0) / Math.PI; // 圆弧点纬度positionArr.push(BJD);positionArr.push(BWD);}return positionArr;}
关于这段代码可以参照此文,这位大佬写的很好通过经纬度坐标计算距离的方法(经纬度距离计算)ZZ_躬行之的技术博客_51CTO博客
其中dx、dy为根据半径计算出的x、y偏移量
ec为地球中心到当前纬度的半径
initialPosition[1] * Math.PI) / 180是将纬度转换为弧度
而ed则是当前纬度圈的半径
dx/ed、dy/ec为经度和纬度变化值对应的弧度
BJD、BWD则为初始经纬度+变化经纬度=变化后的经纬度
- 对水平管道进行裁切的函数
/*** 避免水平管道与垂直管道重叠,重新计算初末位置* @param {"pipe" | "water"} type 管道或者水体* @param {"single" | "both" | "null"} cut 单侧裁切、两侧裁切、不裁切* @returns {Array} cartesianPositions*/function computePos(type, cut) {let waterPositions = positions.concat();let cartesianPositions;if (type == "water") {for (let i = 2; i < waterPositions.length; i += 3) {waterPositions[i] += 0.4 - 0.25;}cartesianPositions = new Cesium.Cartesian3.fromDegreesArrayHeights(waterPositions);} else if (type == "pipe") {cartesianPositions = new Cesium.Cartesian3.fromDegreesArrayHeights(positions);}const start = cartesianPositions[0];const second = cartesianPositions[1];const end = cartesianPositions[cartesianPositions.length - 1];const secondToLast = cartesianPositions[cartesianPositions.length - 2];const startLength = Math.sqrt(Math.pow(start.x - second.x, 2) + Math.pow(start.y - second.y, 2) + Math.pow(start.z - second.z, 2));const endLength = Math.sqrt(Math.pow(secondToLast.x - end.x, 2) + Math.pow(secondToLast.y - end.y, 2) + Math.pow(secondToLast.z - end.z, 2));const startOffsetX = (0.7 / startLength) * (second.x - start.x);const startOffsetY = (0.7 / startLength) * (second.y - start.y);const startOffsetZ = (0.7 / startLength) * (second.z - start.z);const endOffsetX = (0.7 / endLength) * (secondToLast.x - end.x);const endOffsetY = (0.7 / endLength) * (secondToLast.y - end.y);const endOffsetZ = (0.7 / endLength) * (secondToLast.z - end.z);if (cut == "single") {start.x += startOffsetX;start.y += startOffsetY;start.z += startOffsetZ;}if (cut == "both") {start.x += startOffsetX;start.y += startOffsetY;start.z += startOffsetZ;end.x += endOffsetX;end.y += endOffsetY;end.z += endOffsetZ;}return cartesianPositions;}
这段代码相较于上一部分则容易理解的多,核心思想为空间中的相似三角形
startLength、endLength分别为多段管道中的第一段和最后一段
start、end分别为初始点和终点
公式原理如图所示
Cesium 含水三维管道网络模拟相关推荐
- cesium 之三维场景展示篇(附源码下载)
前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 内 ...
- Cesium开源三维地球离线地图发布源码示例功能
一.概述 Cesium开源三维地球离线地图发布源码提供了地图切换.查询定位.模型加载.专题图叠加显示和测量功能等,旨在为用户提供一个可以在Cesium快速加载离线地图或在线地图的解决方案,并提供技术支 ...
- SPDA三维管道辅助设计系统
<SPDA>2006版是上海派品软件有限公司最新推出的三维管道工程设计软件的升级产品.新系统界面新颖.模型逼真,人性化设计.智能化操作.易学易懂.系统在Autodesk公司的AutoCAD ...
- 【小沐学GIS】基于Cesium实现三维数字地球Earth(CesiumJS入门安装)
文章目录 1.简介 1.1 平台 1.1.1 Cesium ion 1.1.2 CesiumJS 1.1.3 Cesium for Unity 1.1.4 Cesium for Unreal 1.1. ...
- 超图Cesium二三维切换
Viewer.Scene.mode:Number 超图上点心!这样写容易误导大家是个对象类型呢.其实是个枚举数字. Cesium.SceneMode Cesium.SceneMode.COLUMBUS ...
- cesium之三维场景展示篇
本篇实现cesium三维场景展示,效果图如下: 三维模型.gltf场景展示 倾斜摄影场景展示 详细的实现过程见:这里
- 一种新的leaflet+cesium二三维切换的解决方案
一.leaflet转cesium 比较简单, 先用leaflet的getBounds获取边界 再使用cesium的viewer.camera.setView({ destination:Cesium. ...
- Vue+Three.js实现三维管道可视化及流动模拟
最近在研究Geotoolkit过程中,发现很多三维的应用场景,用其实现起来比较复杂,就开展了利用Three.js实现海底管道流动的模拟. 推荐一个学习地址:Three.js教程,这这里的学习示例基本上 ...
- Cesium.js 三维土壤地质剖面分割挖掘
之前看过很多的三维场景下,在地表处进行挖掘分割,查看地表下的管线走向.土壤成分.地质分层的案例.最近使用Cesium.js实现了一下,在三维场景下,在地表圈画挖掘范围,然后展示剖面.界面的功能 效果 ...
最新文章
- 如何插入页面,PDF怎么插入页面
- Android 那些你所不知道的Bitmap对象详解
- python中的set和dict_Python中dict和set的用法讲解
- 软件外部接口和内部接口_java中的内部类内部接口详解
- 【斗医】【3】Web应用开发20天
- 动态规划之编辑距离问题
- 编码的奥秘:字节与十六进制
- 高精度轻量级实时语义分割网络:2K视频分割可达24.3GFLOPS和36.5FPS
- vue实现手机验证码登录
- SAP ABAP ZBA_R003 查询用户下的角色里的公司
- win7计算机电源设置在哪里设置,Win7系统如何设置电源选项
- 抖音最新风控体系研究
- mysql 创建表 create table详解
- 2021年高级维修电工证考试题库,职业技能鉴定职业资格
- html5中音频循环那个属性,HTML5音频audio属性
- 外包四年太差劲,幡然醒悟要跳槽
- 南邮 OJ 1176 高斯求和
- vue前端实现上传文件,vue 上传文件
- JAVA开源资源(非大全)
- Android面试老生常谈的 View 事件分发机制,看这一篇就够了