基于Cesium三维地图项目记录_通视分析功能的实现

时间:2022-05-24 08:43:22

实现了剖面分析功能之后,下面来看看如何实现通视分析,还是基本按照之前的思路实现;

  1. 了解软件LocaScape是怎么实现的; 
    网址如下:http://www.locaspace.cn/V3.0/help.jsp 
    基于Cesium三维地图项目记录_通视分析功能的实现

从描述中可以看出,用户交互需要点击地形图或者3DTileset模型上的两个点,通过方法获得两点坐标,然后判断这两点(带有高度坐标)间是否可透视;

  1. 解决判断可否透视方法的思路 
    1)模拟从A点到B点的一条射线,判断这条射线和地形或者模型是否有相交,如果有则透视,无,则不透视; 
    评价:这个方法从思路上是可行的,在Cesium中射线也是可以模拟出来的,不过射线和其他物体的相交检测只限于 规则图形,如平面、直线、球体、椭球体等,无法将射线与地形或模型做相交检测;所以这种思路作罢 
    2)对A点和B点之间的这条线做插值求出插值后的点数组,这些点数组的坐标高程与对应相同经纬度坐标处的高程比较可用来判断射线是否相交; 
    评价:插值求数组是可行的,高程的比较也可以实现,最终的数据展示也可以通过计算得出,故该方案可行;

  2. 执行方案,完成透视分析 
    1)首先根据起终点坐标进行插值,得到插值后的点数组(p[0]、p[1]是起终点坐标笛卡尔积cartesian)

var rad1 = Cesium.Cartographic.fromCartesian(p[0]);
var rad2 = Cesium.Cartographic.fromCartesian(p[1]);
var degree1 = {longitude:rad1.longitude / Math.PI * 180,latitude:rad1.latitude / Math.PI * 180,height:rad1.height};
var degree2 = {longitude:rad2.longitude / Math.PI * 180,latitude:rad2.latitude / Math.PI * 180,height:rad2.height};
for(var i=0;i<num;i++)
{
Cesium.Cartesian3(pl_x[i],pl_y[i],pl_height[i]);
//插值经纬度数组 和 插值高程数组、切片实际高程数组
lon[i]=Cesium.Math.lerp(degree1.longitude,degree2.longitude,0.01*(i+1));
lat[i]=Cesium.Math.lerp(degree1.latitude,degree2.latitude,0.01*(i+1));
height_lerp[i]=degree1.height-(degree1.height-degree2.height)*0.01*(i+1);
}

以上坐标数组存储插值点的经纬度和高程数据; 
2)遍历数组,判断插值点高程和模型高程的大小,若模型高程大,则未交叉,否则存在交叉;(模型高程值目前可求出但计算方法效果不好,后期需要改进)同时记录插值点是要相交的点还是已经相交要不相交的点,分别记为入点和出点;专门用objArray数组记录下来;

if(isSeen==false){
    if(i>0){
        var bhl =height_lerp[i-1];
        var bht = height_tile[i-1];
        var ht =height_tile[i];
        var hl = height_lerp[i];
        if((bhl-bht)>=0){
            if((hl-ht)<0){
                //先找到 先真后假 为入点
                var obj ={'points':[pArray[i-1],pArray[i]],'index':i,type:'in'}
                objArray.push(obj);

            };
        }
        else {
            //先假后真 为出点
            if((hl-ht)>=0){
                var obj ={'points':[pArray[i-1],pArray[i]],'index':i,type:'out'}
                objArray.push(obj);
            }
        };

    }
}

3)根据结果在Cesium球体中显示出来,下面代码为不可透视情况下编辑页面展示的代码,第一段表示用label标签显示水平距离、垂直距离、空间距离、起终点坐标信息、是否可视; 
第二段代码表示,对于可视的视线线段用红色表示,不可视的视线线段用蓝色表示; 
基于Cesium三维地图项目记录_通视分析功能的实现

//在第二点处放置一个label说明一些信息
var entity = viewer.entities.add({
    label : {
        name: 'tongshifenxi',
        show : false,
        showBackground : true,
        font : '14px monospace',
        horizontalOrigin : Cesium.HorizontalOrigin.LEFT,
        verticalOrigin : Cesium.VerticalOrigin.BOTTOM,
        pixelOffset : new Cesium.Cartesian2(15, -10)
    }
});
entity.position = p[1];
entity.label.show = true;
var length_ping = Math.sqrt(Math.pow(p[0].x-p[1].x,2)+Math.pow(p[0].y-p[1].y,2)+Math.pow(p[0].z-p[1].z,2));
var length_h = Math.abs(degree2.height-degree1.height);
var length = Math.sqrt(Math.pow(length_ping,2)+Math.pow(length_h,2));
console.log(degree1);
var text =
    '起点坐标: ' + ('   (' + degree1.longitude)+ '\u00B0' +',' +(degree1.latitude)+ '\u00B0'+',' +degree1.height+')' +
    '\n终点坐标: ' + ('   (' + degree2.longitude)+ '\u00B0' +',' +(degree2.latitude)+ '\u00B0'+',' +degree2.height+')' +
    '\n垂直距离: ' + '   ' + length_h +
    '\n水平距离: ' + '   ' + length_ping +
    '\n空间距离: ' + '   ' + length +
    '\n是否可视: ' + '   ' + '否';
entity.label.text =text;
if(!start){
    //从头开始

    var index =temp.index;
    var model = viewer.entities.add({
        name: 'polyline',
        polyline: {
            positions: Cesium.Cartesian3.fromDegreesArrayHeights([
                pArray[0][0],pArray[0][1],pArray[0][2],
                pArray[index][0],pArray[index][1],pArray[index][2]
            ]),
            width: 5,
            material: Cesium.Color.RED
            }
        });
    start = index;

}
//起点为start 暂时不会用到如果只是显示可视线段和不可视线段的话
if(start){
    console.log(pArray[start][0],pArray[start][1],pArray[start][2],
                pArray[num][0],pArray[num][1],pArray[num][2]);
    var model = viewer.entities.add({
        name: 'polyline',
        polyline: {
            positions: Cesium.Cartesian3.fromDegreesArrayHeights([
                pArray[start][0],pArray[start][1],pArray[start][2],
                pArray[num][0],pArray[num][1],pArray[num][2]
            ]),
            width: 5,
            material: Cesium.Color.BLUE
            }
        });
    break;
}

至此,透视分析的功能就实现啦~