Cesium 管道实体
使用方法
垂直管道
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文库
大部分代码都是很简单的逻辑,大家自行查看源码即可,这里重点讲解两部分代码
- 根据中心点和半径生成圆形的函数
function computeCircle(initialPosition, radius) {
let Ea = 6378137;
let Eb = 6356725;
let positionArr = [];
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则为初始经纬度+变化经纬度=变化后的经纬度
- 对水平管道进行裁切的函数
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分别为初始点和终点
公式原理如图所示
|