Cesium-简单通视分析

2,361 阅读2分钟

通视分析是指以某一点为观察点,研究某一区域通视情况的地形分析。利用DEM判断地形上任意两点之间是否可以互相可见的技术方法,分为视线通视分析和可视域分析,前者判断任意两点之间或者多点之间能否通视,后者对于给定的观察点,分析观察所覆盖的区域。

其中可视域是从一个或者多个观察的可以看见的地表范围。可视域分析是在栅格数据数据集上,对于给定的一个观察点,基于一定的相对高度,查找给定的范围内观察点所能通视覆盖的区域,也就是给定点的通视区域范围,分析结果是得到一个栅格数据集。在确定发射塔的位置、雷达扫描的区域、以及建立森林防火瞭望塔的时候,都会用到可视域分析。可视域分析在航海、航空以及军事方面有较为广泛的应用。

本章节首先处理这两种分析中的较为简单的通视分析,即给定的任意两点之间是否可见。

效果图

具体做法

原理:采用射线法来判别两点之间是否有其他物体所遮挡(比如Entity、Primitive、Terrain、3DTiles等)

接口API

  • Cesium.Cesium3DTileset
  • Cesium.Cartesian3
  • Cesium.Ray
  • Cesium.Scene

具体步骤
1.设置你自己的AccessToken,如果不用Ion上的网络资源可省略这步

Cesium.Ion.defaultAccessToken = 'xxxx';

2.初始化容器

var viewer = new Cesium.Viewer('cesiumContainer', {
    imageryProvider: new Cesium.UrlTemplateImageryProvider({
        url: 'http://www.google.cn/maps/vt?lyrs=s@716&x={x}&y={y}&z={z}'
    })
});

3.加载3dtiles模型,作为通视的模型

var tileset = new Cesium.Cesium3DTileset({
    url: 'http://localhost/demo/tileset.json',
});
viewer.scene.primitives.add(tileset);
tileset.readyPromise.then(function (argument) {
    viewer.camera.flyToBoundingSphere(tileset.boundingSphere);
});

4.指定观察点

// 视域点 设置观察点所在的视点高度为100m
var viewPoint = Cesium.Cartesian3.fromDegrees(x, y, 100);

5.计算目标点

本例计算距离观察点距离1km外 45°至135°之间每间隔1°共计90个点的通视情况

// 目标点集合
var destPoints = [];
// 视域点和目标点的距离
var radius = 1000; // 视距1000米
// 计算45°和135°之间的目标点
for (var i = 45; i <= 135; i++) {
    // 度数转弧度
    var radians = Cesium.Math.toRadians(i);
    // 计算目标点
    var toPoint = new Cesium.Cartesian3(viewPointWebMercator.x + radius * Math.cos(radians), viewPointWebMercator.y + radius * Math.sin(radians), 30);
    destPoints.push(Cesium.Cartographic.toCartesian(toPoint.clone()));
}

其中viewPointWebMercator对象是Cesium.WebMercatorProjection对象的实例,用于经纬度坐标和大地坐标转换

6.创建Ray对象,进行射线交互(注:待3dtiles模型加载完毕后执行,比如在页面上自己定义一个按钮,当模型加载完了后,按钮触发一个点击事件,调用一下pickFromRay方法,或者在console控制台直接执行pickFromRay方法。

for (var i = 0; i < destPoints.length; i++) {
    // 计算射线的方向,目标点left 视域点right
    var direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(destPoints[i], viewPoint, new Cesium.Cartesian3()), new Cesium.Cartesian3());
    // 建立射线
    var ray = new Cesium.Ray(viewPoint, direction);
    var result = viewer.scene.pickFromRay(ray, objectsToExclude); // 计算交互点,返回第一个
    showIntersection(result, destPoints[i], viewPoint);
}

7.处理射线交互结果

function showIntersection(result, destPoint, viewPoint) {
    // 如果是场景模型的交互点,排除交互点是地球表面
    if (Cesium.defined(result) && Cesium.defined(result.object)) {
        drawLine(result.position, viewPoint, Cesium.Color.GREEN); // 可视区域
        drawLine(result.position, destPoint, Cesium.Color.RED); // 不可视区域
    } else {
        drawLine(viewPoint, destPoint, Cesium.Color.GREEN);
    }
}

需要了解的

1.Cesium.Ray 对象

origin 是观察点 direction为方向,计算方向要注意的是从目标点朝观察点的方向

// 计算射线的方向,目标点left 视域点right
var direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(destPoints[i], viewPoint, new Cesium.Cartesian3()), new Cesium.Cartesian3());

2.Scene.prototype.pickFromRay 方法的定义(API文档中没有,需要查看cesium源码)

其中ray为上述的ray对象,objectsToExclude为可以过滤掉不用参与射线计算的对象,是primitives, entities, 或者 features的集合,比如说Scene中有一些辅助性的对象,比如坐标轴,目标点entity和观察点模型等等。(link==>)