Cesium专栏-测距、测面、测高

1,782 阅读3分钟

关于测量

测量是一个GIS系统最基本的,也是必备的模块,网上也有很多相关开发者分享过关于Cesium测量的技术文章,风格各异,但是大同小异,只要弄清楚了原理以及方法,其实每个人都可以写出自己的测量小工具。

测距

测距其实计算两点之间的距离,这个计算方法可以使用最原始的直角三角形求斜边的方法,但是我们也可以直接使用Cesium中Cartesian3接口的distance方法。

Cesium.Cartesian3.distance(firstPoint, secondPoint);

计算方法已经有了,我们要做的就是添砖加瓦,做成一个可供用户交互的测距,并且实时显示距离长度的效果。

// 注册鼠标左击事件
viewer.screenSpaceEventHandler.setInputAction(function (clickEvent) {
    var cartesian = viewer.scene.pickPosition(clickEvent.position);
    // 如果是第一次点击
    if (positions.length == 0) {
        addPoint(cartesian); // 存储第一个点,并在点击处绘制一个点entity
        // 同时注册鼠标移动事件
    } else {
        addPoint(cartesian); // 存储第二个点,并在点击处绘制一个点entity,测量结束,注销所有的鼠标注册事件
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);


// 注册鼠标移动事件
viewer.screenSpaceEventHandler.setInputAction(function (moveEvent) {
    var movePosition = viewer.scene.pickPosition(moveEvent.endPosition); // 鼠标移动的点
    if (positions.length == 1) {
        // 存储第二个点
        positions.push(movePosition);
        // 绘制线
        addLine(positions);
    } else {
        positions.pop(); // 移除上次鼠标经过的点
        positions.push(movePosition); // 存储这次鼠标经过的点
        // 计算中点
        var centerPoint = Cesium.Cartesian3.midpoint(positions[0], positions[1], new Cesium.Cartesian3());
        // 计算距离
        var lengthText = "距离:" + getLengthText(positions[0], positions[1]);
        // 绘制距离长度标签
        labelEntity = addLabel(centerPoint, lengthText);
    }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

测面

测面积,也就是计算至少三个点构成的任意多边形的面积,可以使用拆分三角曲面的方法计算每一个小三角形的面积,然后累加得到任意多边形的面积。由于多边形点的个数是至少3个,所以我们还要比测距多一个结束注册事件,可以双击结束,也可以右击结束。

// 注册鼠标左击事件
viewer.screenSpaceEventHandler.setInputAction(function (clickEvent) {
    var cartesian = viewer.scene.pickPosition(clickEvent.position);
    if (positions.length == 0) {
        positions.push(cartesian.clone()); //鼠标左击 添加第1个点
        addPoint(cartesian);
        // 注册鼠标移动事件
    } else if (positions.length == 2) {
        positions.pop();
        positions.push(cartesian.clone()); // 鼠标左击 添加第2个点
        addPoint(cartesian);
        addPolyGon(positions); // 绘制面
        // 注册鼠标右击结束事件

    } else if (positions.length >= 3) {
        positions.pop();
        positions.push(cartesian.clone()); // 鼠标左击 添加第3个点
        addPoint(cartesian);
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);


// 注册鼠标移动事件
viewer.screenSpaceEventHandler.setInputAction(function (moveEvent) {
    var movePosition = viewer.scene.pickPosition(moveEvent.endPosition);
    if (positions.length == 1) {
        positions.push(movePosition);
        addLine(positions);
    } else {
        positions.pop();
        positions.push(movePosition);
    }
    if (positions.length >= 3) {
        var text = "面积:" + getArea(positions);
        // 获取面积的重心
        var centerPoint = getCenterOfGravityPoint(positions);
        // 绘制label
        addLabel(centerPoint, text);
    }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);


// 注册鼠标右击结束事件
viewer.screenSpaceEventHandler.setInputAction(function (clickEvent) {

    var clickPosition = viewer.scene.pickPosition(clickEvent.position);
    positions.pop();
    positions.push(clickPosition);
    positions.push(positions[0]); // 闭合
    addPoint(clickPosition);

    // 解除注册的事件

}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

测高

测高即是在测距的基础上,计算两个点之间的空间高度,这个是对测距的一个功能扩展。

// 注册鼠标左击事件
viewer.screenSpaceEventHandler.setInputAction(function (clickEvent) {
    var cartesian = viewer.scene.pickPosition(clickEvent.position); // 坐标

    // 存储第一个点
    if (positions.length == 0) {
        positions.push(cartesian.clone());
        addPoint(cartesian);
        // 注册鼠标移动事件
    } else {
        // 存储第二个点
        positions.pop();
        positions.pop();
        positions.pop();
        var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        var height = Cesium.Cartographic.fromCartesian(positions[0]).height;
        // 得到辅助点
        var verticalPoint = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude), height);
        positions.push(verticalPoint);
        positions.push(cartesian);
        positions.push(positions[0]);
        addPoint(cartesian);
        // 移除所有注册的事件
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);


// 注册鼠标移动事件
viewer.screenSpaceEventHandler.setInputAction(function (moveEvent) {
    var movePosition = viewer.scene.pickPosition(moveEvent.endPosition); // 鼠标移动的点
    if (positions.length >= 2) {
        positions.pop();
        positions.pop();
        positions.pop();

        var cartographic = Cesium.Cartographic.fromCartesian(movePosition);
        var height = Cesium.Cartographic.fromCartesian(positions[0]).height;

        // 辅助点
        var verticalPoint = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude), height);
        positions.push(verticalPoint);
        positions.push(movePosition);
        positions.push(positions[0]);

        // 计算中点
        var centerPoint_1 = Cesium.Cartesian3.midpoint(positions[0], positions[1], new Cesium.Cartesian3());
        // 计算距离
        var lengthText_1 = "水平距离:" + getLengthText(positions[0], positions[1]);

        addLabel(centerPoint_1, lengthText_1);

        // 计算中点
        var centerPoint_2 = Cesium.Cartesian3.midpoint(positions[1], positions[2], new Cesium.Cartesian3());
        // 计算距离
        var lengthText_2 = "垂直距离:" + getLengthText(positions[1], positions[2]);

        addLabel(centerPoint_2, lengthText_2);

        // 计算中点
        var centerPoint_3 = Cesium.Cartesian3.midpoint(positions[2], positions[3], new Cesium.Cartesian3());
        // 计算距离
        var lengthText_3 = "直线距离:" + getLengthText(positions[2], positions[3]);

        addLabel(centerPoint_3, lengthText_3);

    } else {
        var verticalPoint = new Cesium.Cartesian3(movePosition.x, movePosition.y, positions[0].z);
        positions.push(verticalPoint);
        positions.push(movePosition);
        positions.push(positions[0]);
        // 绘制线
        addLine(positions);
    }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

注意

当然,上面给出的代码只是思路性的代码,其中还有一些要注意的,比如Entity和Label的显示控制啊,Polyline、Polygon、以及Point的动态刷新实时绘制,还有所有entity的在viewer容器中的控制等等,需要进一步完善。

补充:本来这篇文章只是想给一个测量思路,由于太多订阅者联系我,让我提供一下源码,所以,在这里还是把代码放出来,当然,如果遇到版本不兼容或者有功能性错误的,可以联系我。

link==>