一、简介
管道图元在Cesium中可以通过PolylineVolumeGraphics实现,但是PolylineVolumeGraphics有个问题,就是到只能实现水平管道,而当管道的点是垂直的时候,就会出现问题。
管道通常是指地下管道,一般情况下应该是通过各种专业的建模软件批量构建模型最后转为3dtiles在Cesium中使用,但是出于灵活性的考虑,有时需要自己实现动态的管道绘制,因为PolylineVolumeGraphics不能满足某些需求,所以我们需要自定义管道图元。自定义管道图元其实也比较简单,从建模的角度来看,一根管子的构造如下:
一根管子由很多个三角面构造,而这些三角面又是由多个点构成:
所以自定义管道图元的难点其实在于计算这些顶点数据,因为这些顶点是由管道的起点和终点计算而来,所以必须能够输入任意的起点和终点。
二、生成顶点数据
生成管道的顶点数据我们一般先在坐标系的原点进行顶点计算,然后经过旋转平移变换将其移动到正确的位置。
1、假定一个管道的起点和终点如下,设管道半径为30
let a = Cesium.Cartesian3.fromDegrees(121.11086303602546, 31.142151406236606, 40);
let b = Cesium.Cartesian3.fromDegrees(121.11086303602546, 31.142351406236606, 120);
2、有了起点和终点,我们可以计算出管道的长度,然后在坐标原点进行顶点生成,将其封装成一个方法
function generateVertics(start, end, radius) {
let height= Cesium.Cartesian3.distance(start, end);
let vertices = [];//生成的顶点数组
let thetaStart = 0, thetaLength = Math.PI * 2;
for (let y = 0; y <= 1; y++) {
const v = y / 1;
for (let x = 0; x <= 120; x++) {
const u = x / 120;
const theta = u * thetaLength + thetaStart;
const sinTheta = Math.sin(theta);
const cosTheta = Math.cos(theta);
let vertex = new Cesium.Cartesian3();
vertex.x = radius * sinTheta;
vertex.y = radius * cosTheta;
vertex.z = v * height;
vertices.push(vertex);
}
}
return vertices;
}
3、调用此方法,传入参数
let vs = this.generateVertics(a, b, 30);
4、查看生成的顶点数据,我们可以先将其添加到场景中显示出来
let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(a);
vs.forEach(v => {
let p = Cesium.Matrix4.multiplyByPoint(
modelMatrix,
v,
new Cesium.Cartesian3()
)
viewer.entities.add({
position: p,
point: {
pixelSize: 10,
color: Cesium.Color.BLUE
}
})
})
三、变换顶点数据
上一节我们封装了生成顶点数据的方法,因为顶点数据是在坐标系的原点构建的,所以我们需要经过旋转平移变换,将其变换到和起点终点匹配的位置,平移变换其实在上一节就做过了。
function generateVertics(start, end, radius) {
let height = Cesium.Cartesian3.distance(start, end);
let vertices = [];//生成的顶点数组
let thetaStart = 0, thetaLength = Math.PI * 2;
//旋转操作
let dir1 = new Cesium.Cartesian3(0, 0, height);
let dir2 = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3());
let angle = Cesium.Cartesian3.angleBetween(dir1, dir2);
//旋转轴
let axis = Cesium.Cartesian3.cross(dir1, dir2, new Cesium.Cartesian3());
//旋转角度
let rotation = Cesium.Quaternion.fromAxisAngle(axis, angle, new Cesium.Quaternion());
const m = Cesium.Matrix4.fromTranslationQuaternionRotationScale(
new Cesium.Cartesian3(0, 0, 0),
rotation,
new Cesium.Cartesian3(1, 1, 1),
new Cesium.Matrix4);
for (let y = 0; y <= 1; y++) {
const v = y / 1;
for (let x = 0; x <= 120; x++) {
const u = x / 120;
const theta = u * thetaLength + thetaStart;
const sinTheta = Math.sin(theta);
const cosTheta = Math.cos(theta);
let vertex = new Cesium.Cartesian3();
vertex.x = radius * sinTheta;
vertex.y = radius * cosTheta;
vertex.z = v * height;
//旋转
let resut = Cesium.Matrix4.multiplyByPoint(
m,
vertex,
new Cesium.Cartesian3()
)
//平移
Cesium.Cartesian3.add(resut, start, resut)
vertices.push(resut);
}
}
return vertices;
}
四、组装顶点数据
顶点数据生成以后,我们需要将其组装成三角面,三角面的顺序是根据索引创建的,所以我们是需要生成索引,再次改造构造顶点的方法。
function generateVertics(start, end, radius) {
let height = Cesium.Cartesian3.distance(start, end);
let vertices = [];//生成的顶点数组
let thetaStart = 0, thetaLength = Math.PI * 2;
//旋转操作
let dir1 = new Cesium.Cartesian3(0, 0, height);
let dir2 = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3());
let angle = Cesium.Cartesian3.angleBetween(dir1, dir2);
//旋转轴
let axis = Cesium.Cartesian3