背景
前段时间看到一篇构建隧道的文章(https://blog.csdn.net/supermapsupport/article/details/128453116),突然想到一个使用场景:隧道通常是建在山体下面,是否可以通过这种方式构建出一条贯穿山体的隧道,来模拟实际的施工方案?答案是可以,效果图如下:
一、实现思路
1、生成隧道模型
2、地形挖洞
3、把隧道模型放在洞口中
该方案的难点在于,如何根据隧道的截面坐标,将地形挖洞,使洞口与隧道模型完全吻合
由于地形服务无法做布尔运算,这里采用地形开挖方式实现,并不展示开挖底面与侧面,这样就相当于给地形裁剪一个口子,关键接口:
二、实现过程
1、构建管道模型
用鼠标绘制一条折线代表隧道的走向
然后使用iServer放样分析,输入隧道截面坐标,分析出一条带管壁厚度的隧道
var s3mInstanceColc = new Cesium.S3MInstanceCollection(scene._context);
scene.primitives.add(s3mInstanceColc);
var sqlParameter = {"loftRegion":{"type":"REGION" , "parts":[8,8], "points":[{ x: -2.5, y: 7.5},{ x: -6.5, y: 5.5 },{ x: -10.5, y: 0 },{ x: -10.5, y: -10.5 }, //隧道截面坐标,单位为米{ x: 10.5, y: -10.5 },{ x:10.5, y: 0},{ x: 6.5, y: 5.5 },{ x: 2.5, y: 7.5},{ x: -1.5, y: 6.5},{ x: 1.5, y: 6.5},{ x: 5.5, y: 4.5 },{ x: 9.5, y: 0},{ x: 9.5, y: -9.5 },{ x: -9.5, y: -9.5 },{ x: -9.5, y: 0 },{ x: -5.5, y: 4.5 }]},"loftLine":{"type":"LINE3D", "parts":[2], "points":posArray},"chamfer":"5","lonlat":"TRUE"
};
var url = "http://10.10.4.82:8090/iserver/services/spatialAnalysis-test/restjsr/spatialanalyst/geometry/3d/loft.json?returnContent=true";
var queryData = JSON.stringify(sqlParameter);$.ajax({type: "post",url: url,data: queryData,success: function (result) {var geometry = result.geometry;if (!geometry) {return;}var buffer = new Uint8Array(geometry.model).buffer;var position = geometry.position;var color = Cesium.Color.GRAY;s3mInstanceColc.add('visibleBody', {position: Cesium.Cartesian3.fromDegrees(position.x, position.y, position.z+10),color: color,attributes: 'test'}, buffer);viewer.flyTo(s3mInstanceColc);},error: function (msg) {console.log(msg);},
})
2、根据隧道给地形挖洞
2.1、去除挖洞封边效果,去除侧面与底面贴图
scene.globe.showExcavationSide = false;
scene.globe.excavationBottomTextureUrl = null;
scene.globe.excavationSideTextureUrl = null;
2.2、开挖方案
从图中可以看出,隧道口被堵死,我们需要拿到隧道与地形相交部分的节点坐标,然后将地形挖开。所以关键步骤就是如何得到相交坐标,如下图所示:
第一步获取隧道截面坐标(红色点),第二步利用隧道方向向量,绘制出基于截面坐标且平行与隧道的线段(通视分析),第三步得到线段与地形的交点(蓝色点),第四步用得到的交点坐标将地形挖开
2.3、获取截面坐标点(红色点)
①在构建隧道模型时,我们可以根据传入的平面坐标,计算每个端点与中心点的距离
②在绘制隧道走向时,我们根据绘制坐标计算出隧道的方向向量,从而获取线的角度,在这个角度基础上±90°,得到隧道垂直方向,方向+距离即可计算出目标点的世界坐标。利用不同距离得到多个点坐标,再给各个点设置高度,即可得到所有的隧道截面世界坐标。向量与角度的计算可以参考这篇文章:Cesium计算向量、角度、距离
关键代码:
this.getPointByDirectionAndLen = function (position, angle, len) {let matrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);let mz = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(angle));let rotationZ = Cesium.Matrix4.fromRotationTranslation(mz);Cesium.Matrix4.multiply(matrix, rotationZ, matrix);let result;result = Cesium.Matrix4.multiplyByPoint(matrix,new Cesium.Cartesian3(0, len, 0),new Cesium.Cartesian3());return result;
};
2.4、获取开挖点(蓝色点)
经过上面的步骤,我们已经得到隧道截面坐标(下图中C坐标)、隧道线向量(AB)。根据公式:D坐标-C坐标 = 向量AB
可以得到D坐标
得到C、D坐标后,使用通视分析(sightline)得到观察点C到目标点D,之间与地形的障碍点;依次对每个截面坐标做以上操作,即可得到所有障碍点
关键代码:
this.getBarrierArray = function (LonLatArr,sightline) {let pointA = new Cesium.Cartesian3.fromDegrees(posArray[0].x,posArray[0].y,posArray[0].z);let pointB = new Cesium.Cartesian3.fromDegrees(posArray[1].x,posArray[1].y,posArray[1].z);let index = 0;//向量ABconst positionvector = Cesium.Cartesian3.subtract(pointB, pointA, new Cesium.Cartesian3());myfun(index);let BarrierArray = [];function myfun(index){if(index < LonLatArr.length){let cart = new Cesium.Cartesian3.fromDegrees(LonLatArr[index][0], LonLatArr[index][1], LonLatArr[index][2]);let posD = {x: cart.x + positionvector.x,y: cart.y + positionvector.y,z: cart.z + positionvector.z};let thisArray = [];thisArray.push(cart);thisArray.push(posD);var name = "point" + index;sightline.viewPosition = Cartesian2toDegrees(thisArray[0]);sightline.addTargetPoint({position: Cartesian2toDegrees(thisArray[1]),name: name});setTimeout(()=>{let barrp = sightline.getBarrierPoint(name);console.log(barrp);if(!barrp.isViewer){BarrierArray.push(barrp.position.longitude * (180/Math.PI));BarrierArray.push(barrp.position.latitude * (180/Math.PI));BarrierArray.push(barrp.position.height);}sightline.removeAllTargetPoint();},30);index++;setTimeout(()=>{myfun(index)},40)}}function Cartesian2toDegrees(position) {var cartographic = Cesium.Cartographic.fromCartesian(position);var longitude = Cesium.Math.toDegrees(cartographic.longitude);var latitude = Cesium.Math.toDegrees(cartographic.latitude);var height = cartographic.height;return [longitude, latitude, height];}return BarrierArray
};
2.5、地形开挖
得到所有障碍点后,通过这些点进行地形开挖
viewer.scene.globe.addExcavationRegion({name: 'ggg',position: brruipos,height: dep,transparent: false
});
范例:
链接:https://pan.baidu.com/s/1sDwfmI6hBFIS3eCt7tBGug
提取码:6655