Cesium开发工具篇 | 04量测工具与调试面板

本节我们讲一下Cesium中常用的测量工具和针对开发人员使用的调试工具。

量测工具

量测工具可以说,不管是二维GIS还是三维GIS中都必须具备的功能,只不过是在空间上是否有贴地、是否有高度上的距离差别之分。Cesium是三维GIS引擎,所以距离量测支持直线距离、水平距离、垂直距离以及地表距离,面积量测支持水平面积、地表面积以及模型表面积等。不管是哪种类型的距离测量还是面积测量,实现思路基本是一样的,都是按照如下思路实现的。
1)点击按钮开始测量,侦听鼠标LEFT_CLICK事件,记录坐标,绘制节点和折线(多边形);
2)侦听鼠标移动事件,鼠标点击后即复制一个浮动点,在MOUSE_MOVE事件中不断更新最后一个浮动点,动态更新折线(多边形)绘制;
3)侦听鼠标右击事件,RIGHT_CLICK触发时销毁测量相关事件句柄(ScreenSpaceEventHandler),删除多余的浮动点;
4)折线(多边形)的动态绘制通过CallbackProperty属性绑定positions属性实现。

如下为实现距离量测部分核心代码:

var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      handler.setInputAction(function (movement) {
        let ray = viewer.camera.getPickRay(movement.position);
        cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        if (positions.length == 0) {
          positions.push(cartesian.clone());
        }
        positions.push(cartesian);
        //在三维场景中添加Label
        var textDisance = distance + "米";
        floatingPoint = viewer.entities.add({
          name: "空间直线距离",
          position: positions[positions.length - 1],
          point: {
            pixelSize: 5,
            color: Cesium.Color.RED,
            outlineColor: Cesium.Color.WHITE,
            outlineWidth: 2,
          },
          label: {
            text: textDisance,
            font: "18px sans-serif",
            fillColor: Cesium.Color.GOLD,
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: new Cesium.Cartesian2(20, -20),
          },
        });
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

      handler.setInputAction(function (movement) {
        let ray = viewer.camera.getPickRay(movement.endPosition);
        cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        if (positions.length >= 2) {
          if (!Cesium.defined(poly)) {
            poly = new PolyLinePrimitive(positions);
          } else {
            positions.pop();
            positions.push(cartesian);
          }
          distance = getSpaceDistance(positions);
        }
      }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

      handler.setInputAction(function (movement) {
        handler.destroy(); //关闭事件句柄
        positions.pop(); //最后一个点无效
        // viewer.entities.remove(floatingPoint);
        // tooltip.style.display = "none";
      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
      //空间两点距离计算函数
      function getSpaceDistance(positions) {
        var distance = 0;
        for (var i = 0; i < positions.length - 1; i++) {
          var point1cartographic = Cesium.Cartographic.fromCartesian(
            positions[i]
          );
          var point2cartographic = Cesium.Cartographic.fromCartesian(
            positions[i + 1]
          );
          /**根据经纬度计算出距离**/
          var geodesic = new Cesium.EllipsoidGeodesic();
          geodesic.setEndPoints(point1cartographic, point2cartographic);
          var s = geodesic.surfaceDistance;
          //返回两点之间的距离
          s = Math.sqrt(
            Math.pow(s, 2) +
              Math.pow(point2cartographic.height - point1cartographic.height, 2)
          );
          distance = distance + s;
        }
        return distance.toFixed(2);
      }

如下为实现面积测量的部分核心代码:

handler.setInputAction(function (movement) {
        let ray = viewer.camera.getPickRay(movement.position);
        cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        if (positions.length == 0) {
          positions.push(cartesian.clone());
        }
        positions.push(cartesian);
        //在三维场景中添加点
        var cartographic = Cesium.Cartographic.fromCartesian(
          positions[positions.length - 1]
        );
        var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
        var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
        var heightString = cartographic.height;
        tempPoints.push({
          lon: longitudeString,
          lat: latitudeString,
          hei: heightString,
        });
        floatingPoint = viewer.entities.add({
          name: "多边形面积",
          position: positions[positions.length - 1],
          point: {
            pixelSize: 5,
            color: Cesium.Color.RED,
            outlineColor: Cesium.Color.WHITE,
            outlineWidth: 2,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
          },
        });
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
 handler.setInputAction(function (movement) {
        handler.destroy();
        positions.pop();
        var textArea = getArea(tempPoints) + "平方公里";
        viewer.entities.add({
          name: "多边形面积",
          position: positions[positions.length - 1],
          label: {
            text: textArea,
            font: "18px sans-serif",
            fillColor: Cesium.Color.GOLD,
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: new Cesium.Cartesian2(20, -40),
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
          },
        });
      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
      //计算多边形面积
      function getArea(points) {
        var res = 0;
        //拆分三角曲面
        for (var i = 0; i < points.length - 2; i++) {
          var j = (i + 1) % points.length;
          var k = (i + 2) % points.length;
          var totalAngle = Angle(points[i], points[j], points[k]);

          var dis_temp1 = distance(positions[i], positions[j]);
          var dis_temp2 = distance(positions[j], positions[k]);
          res += dis_temp1 * dis_temp2 * Math.abs(Math.sin(totalAngle));
          console.log(res);
        }
        return (res / 1000000.0).toFixed(4);
      }

完整代码请查看gitHub地址https://github.com/ls870061011/cesium_training/blob/main/examples/3_4_1measure.html,实现的示意图如下所示。

距离测量

面积测量

调试面板

Cesium中比较常用的调试面板是用于了解Cesium渲染效果以及性能调优的CesiumInspector和用于监视3D Tiles数据的监视器Cesium3DTilesInspector。
CesiumInspector
该控件是针对开发人员来说,虽然不能提供功能的实现,但对于了解渲染效果和性能调优是非常有帮助的,特别是解决一些渲染状态下的问题时非常的有价值。使用该控件非常的简单,只需如下一行代码就能实现该控件的加载。

viewer.extend(Cesium.viewerCesiumInspectorMixin);

控件里面有很多的功能,每一个都很专业,包括渲染帧数、Primitive外包围球、Primitive参考框架、线框模式等等,这里就不一一给大家介绍了,感兴趣的同学可以自己尝试一下。

Cesium3DTilesInspector
面对大场景下的大规模、大体量的3D Tiles数据,Cesium提供了一个监视3D Tiles数据的监视器,用于监视、观察3D Tiles数据的效果。加载该空间也非常的简单,只需一行简单代码即可,结果控件展示如下:

viewer.extend(Cesium.viewerCesium3DTilesInspectorMixin);

包括3D Tiles瓦片是否可拾取;显示颜色、线框、瓦片边界范围框、瓦片内容边界范围框、观察者请求体、点云渲染等;还包括一些动态屏幕误差设置、最大屏幕误差设置、样式修改等。对3D Tiles不熟悉的可阅读3D Tiles介绍及加载这篇文章。感兴趣的同学,可以亲自尝试此控件,体验一下控件的强大。

你可能感兴趣的:(Cesium开发工具篇 | 04量测工具与调试面板)