Cesium 测量距离

Cesium 测量距离

    • 需求
    • 分析
      • 第一种方式:使用测距 Measure
      • 第二中方式:使用 distance,自己封装
      • 第三种方式:自己封装(样式不太好)

需求

实际开发中我们经常需要用到量测工具,而Cesium没有直接提供量测功能,如何在 Cesium 中实现两点间距离测量
Cesium 测量距离_第1张图片

分析

第一种方式:使用测距 Measure

在Cesium中,可以使用Measure类进行测距操作。以下是测距的简单示例代码:

// 创建测量工具对象
var measure = new Cesium.Measure(viewer, {
    lineColor: Cesium.Color.YELLOW, // 线颜色
    lineOpacity: 1, // 线透明度
    lineOutline: true, // 线是否显示轮廓
    lineOutlineColor: Cesium.Color.BLACK, // 线轮廓颜色
    labelFont: '16px sans-serif', // 标签字体
    labelColor: Cesium.Color.BLACK, // 标签颜色
    labelOffset: new Cesium.Cartesian2(0, 20), // 标签偏移
    measureUnits: Cesium.MeasureUnits.METERS // 测量单位
});

// 开始测距
measure.startMeasure();

在按下鼠标左键开始绘制第一个点之后,测距工具将会创建一个用于显示测距结果的线段、标签等元素。测量结果将实时更新,直到鼠标左键抬起。

除了直接使用Measure类进行测距外,还可以使用Cesium.MeasureHandler类创建自定义的测距工具,这样可以根据具体需求进行更加详细的设置,例如支持多线段测量等。具体使用方法可以参考Cesium官方文档。

参考文献:

  • https://cesium.com/docs/cesiumjs-ref-doc/Measure.html
  • https://cesium.com/docs/cesiumjs-ref-doc/MeasureHandler.html

第二中方式:使用 distance,自己封装

  • 预览效果

Cesium 测量距离_第2张图片

  • 源码:
data(){
	viewer: null,
	handler: null,
	positions : [],
	entityCollection: [],
    leftClickFlag:0,//单击Flag
    centerPoint:[],//中点
    lengthText:0 , // 计算距离
},
watch: {
    leftClickFlag(val){
        if( val!==1 && val %2 == 1){
            this.addLabel(this.centerPoint, this.lengthText); 
        }
    }
},
methods:{
	 //注册鼠标事件,调用该函数实现其他方法调用
   registerEvents() {
       this.leftClickEvent();
   },

   /**
    * 添加标签
    * @param position
    * @param text
    */
   addLabel(centerPoint, text) {
       return this.viewer.entities.add(new Cesium.Entity({
           position: centerPoint,
           label: {
               text: text,
               font: '14px sans-serif',
               style: Cesium.LabelStyle.FILL_AND_OUTLINE, //FILL  FILL_AND_OUTLINE OUTLINE
               fillColor: Cesium.Color.YELLOW,
               showBackground: true, //指定标签后面背景的可见性
               backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.8), // 背景颜色
               backgroundPadding: new Cesium.Cartesian2(6, 6), //指定以像素为单位的水平和垂直背景填充padding
               pixelOffset: new Cesium.Cartesian2(0, -25),
               disableDepthTestDistance: Number.POSITIVE_INFINITY
           }
       }));
   },
   // 添加点
   addPoint(position) {
       return this.viewer.entities.add({
           position: position,
           point:{
               pixelSize: 10,
               color: Cesium.Color.YELLOW
           }
       });
   },
   // 添加线
   addLine(position) {
       const lonlat = [];
       for (let index = 0; index < position.length; index++) {
           const longitude =  Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(position[index]).longitude);
           const latitude =  Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(position[index]).latitude);
           lonlat.push(longitude,latitude);
       }
       console.log(lonlat)
       return this.viewer.entities.add({
           name: 'distance-line',
           polyline: {
               positions: Cesium.Cartesian3.fromDegreesArray(lonlat),
               width: 2,
               material: Cesium.Color.RED,
               // clampToGround: true
           }
       });
   },
   //逻辑代码如下
   getLengthText(firstPoint, secondPoint) {
       // 计算距离
       var length = Cesium.Cartesian3.distance(firstPoint, secondPoint);
       if (length > 1000) {
           length = (length / 1000).toFixed(2) + " 公里";
       } else {
           length = length.toFixed(2) + " 米";
       }
       return length;
   },
   //鼠标移动事件
   mouseMoveEvent() {
       var labelEntity = null; // 标签实体
       this.viewer.screenSpaceEventHandler.setInputAction((moveEvent) => {
       //var movePosition = this.viewer.scene.pickPosition(moveEvent.endPosition); // 鼠标移动的点
       var movePosition = this.viewer.scene.globe.pick(this.viewer.camera.getPickRay(moveEvent.endPosition), this.viewer.scene);
           if(!movePosition){
               return false;
           }
           if (this.positions.length == 2) {
               this.positions.pop();
               this.positions.push(movePosition);

               // 绘制label
               if (labelEntity) {
                   this.viewer.entities.remove(labelEntity);
                   this.entityCollection.splice(this.entityCollection.indexOf(labelEntity), 1);
               }
               // 计算中点
               this.centerPoint = Cesium.Cartesian3.midpoint(this.positions[0], this.positions[1], new Cesium.Cartesian3());
               // 计算距离
               this.lengthText = "距离:" + this.getLengthText(this.positions[0], this.positions[1]);

               labelEntity = this.addLabel(this.centerPoint, this.lengthText);
               this.entityCollection.push(labelEntity);
           } else {
               this.positions.push(movePosition);
               // 绘制线
               // this.addLine(this.positions);
           }
       }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
   },

	//左键点击事件
  leftClickEvent() {
      //单击鼠标左键画点点击事件
      this.viewer.screenSpaceEventHandler.setInputAction(e => {
          this.leftClickFlag +=1;
          this.viewer._element.style.cursor = 'default';
          // 坐标
          let position = this.viewer.scene.pickPosition(e.position);
          // 存储第一个点
          if (!position){
              return false;
          }
          if (this.positions.length == 0) { 
              this.positions.push(position.clone())
              //添加一个点
              this.addPoint(position);
              // 注册鼠标移动事件
              this.mouseMoveEvent();
          }else{
              // 存储第二个点
              this.positions.pop();
              this.positions.push(position);
              this.addPoint(position);
              this.addLine(this.positions);
              // 移出事件
              // this.viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
              // this.viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
              // this.leftClickFlag = 0;
              if(this.positions.length == 2){
                  this.positions.length = 0; //置空
                  this.leftClickFlag += 1;
              }
          }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  },
mounted(){
	this.viewer = window.viewer;
	this.fetchData();
},

第三种方式:自己封装(样式不太好)

  1. 新建一个MeasureTool.js文件,代码如下:
import Cesium from "cesium/Cesium";
import widgets from "cesium/Widgets/widgets.css";

export default {

    //测量空间直线距离
    /******************************************* */
    measureLineSpace(viewer, handler) {
        // 取消双击事件-追踪该位置
        viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

        handler = new Cesium.ScreenSpaceEventHandler(viewer.scene._imageryLayerCollection);
        var positions = [];
        var poly = null;
        // var tooltip = document.getElementById("toolTip");
        var distance = 0;
        var cartesian = null;
        var floatingPoint;
        // tooltip.style.display = "block";

        handler.setInputAction(function (movement) {
            // tooltip.style.left = movement.endPosition.x + 3 + "px";
            // tooltip.style.top = movement.endPosition.y - 25 + "px";
            // tooltip.innerHTML = '

单击开始,右击结束

';
// cartesian = viewer.scene.pickPosition(movement.endPosition); let ray = viewer.camera.getPickRay(movement.endPosition); cartesian = viewer.scene.globe.pick(ray, viewer.scene); //cartesian = viewer.scene.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid); if (positions.length >= 2) { if (!Cesium.defined(poly)) { poly = new PolyLinePrimitive(positions); } else { positions.pop(); // cartesian.y += (1 + Math.random()); positions.push(cartesian); } distance = getSpaceDistance(positions); // console.log("distance: " + distance); // tooltip.innerHTML='

'+distance+'米

';
} }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); handler.setInputAction(function (movement) { // tooltip.style.display = "none"; // cartesian = viewer.scene.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid); // cartesian = viewer.scene.pickPosition(movement.position); 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 cartographic = Cesium.Cartographic.fromCartesian(cartesian); var textDisance = distance + "米"; // console.log(textDisance + ",lng:" + cartographic.longitude/Math.PI*180.0); floatingPoint = viewer.entities.add({ name: '空间直线距离', // position: Cesium.Cartesian3.fromDegrees(cartographic.longitude / Math.PI * 180, cartographic.latitude / Math.PI * 180,cartographic.height), 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) { handler.destroy(); //关闭事件句柄 positions.pop(); //最后一个点无效 // viewer.entities.remove(floatingPoint); // tooltip.style.display = "none"; }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); var PolyLinePrimitive = (function () { function _(positions) { this.options = { name: '直线', polyline: { show: true, positions: [], material: Cesium.Color.CHARTREUSE, width: 10, clampToGround: true } }; this.positions = positions; this._init(); } _.prototype._init = function () { var _self = this; var _update = function () { return _self.positions; }; //实时更新polyline.positions this.options.polyline.positions = new Cesium.CallbackProperty(_update, false); viewer.entities.add(this.options); }; return _; })(); //空间两点距离计算函数 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; //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2))); //返回两点之间的距离 s = Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2)); distance = distance + s; } return distance.toFixed(2); } }, //****************************测量空间面积************************************************// measureAreaSpace(viewer, handler){ // 取消双击事件-追踪该位置 viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); // 鼠标事件 handler = new Cesium.ScreenSpaceEventHandler(viewer.scene._imageryLayerCollection); var positions = []; var tempPoints = []; var polygon = null; // var tooltip = document.getElementById("toolTip"); var cartesian = null; var floatingPoint;//浮动点 // tooltip.style.display = "block"; handler.setInputAction(function(movement){ // tooltip.style.left = movement.endPosition.x + 3 + "px"; // tooltip.style.top = movement.endPosition.y - 25 + "px"; // tooltip.innerHTML ='

单击开始,右击结束

';
// cartesian = viewer.scene.pickPosition(movement.endPosition); let ray = viewer.camera.getPickRay(movement.endPosition); cartesian = viewer.scene.globe.pick(ray, viewer.scene); //cartesian = viewer.scene.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid); if(positions.length >= 2){ if (!Cesium.defined(polygon)) { polygon = new PolygonPrimitive(positions); }else{ positions.pop(); // cartesian.y += (1 + Math.random()); positions.push(cartesian); } // tooltip.innerHTML='

'+distance+'米

';
} },Cesium.ScreenSpaceEventType.MOUSE_MOVE); handler.setInputAction(function(movement){ // tooltip.style.display = "none"; // cartesian = viewer.scene.pickPosition(movement.position); let ray = viewer.camera.getPickRay(movement.position); cartesian = viewer.scene.globe.pick(ray, viewer.scene); // cartesian = viewer.scene.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid); if(positions.length == 0) { positions.push(cartesian.clone()); } //positions.pop(); 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(); //tempPoints.pop(); // viewer.entities.remove(floatingPoint); // tooltip.style.display = "none"; //在三维场景中添加点 // 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}); var textArea = getArea(tempPoints) + "平方公里"; 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 // }, 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 ); var radiansPerDegree = Math.PI / 180.0;//角度转化为弧度(rad) var degreesPerRadian = 180.0 / Math.PI;//弧度转化为角度 //计算多边形面积 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); } /*角度*/ function Angle(p1, p2, p3) { var bearing21 = Bearing(p2, p1); var bearing23 = Bearing(p2, p3); var angle = bearing21 - bearing23; if (angle < 0) { angle += 360; } return angle; } /*方向*/ function Bearing(from, to) { var lat1 = from.lat * radiansPerDegree; var lon1 = from.lon * radiansPerDegree; var lat2 = to.lat * radiansPerDegree; var lon2 = to.lon * radiansPerDegree; var angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2)); if (angle < 0) { angle += Math.PI * 2.0; } angle = angle * degreesPerRadian;//角度 return angle; } var PolygonPrimitive = (function(){ function _(positions){ this.options = { name:'多边形', polygon : { hierarchy : [], // perPositionHeight : true, material : Cesium.Color.GREEN.withAlpha(0.5), // heightReference:20000 } }; this.hierarchy = positions; this._init(); } _.prototype._init = function(){ var _self = this; var _update = function(){ return _self.hierarchy; }; //实时更新polygon.hierarchy this.options.polygon.hierarchy = new Cesium.CallbackProperty(_update,false); viewer.entities.add(this.options); }; return _; })(); function distance(point1,point2){ var point1cartographic = Cesium.Cartographic.fromCartesian(point1); var point2cartographic = Cesium.Cartographic.fromCartesian(point2); /**根据经纬度计算出距离**/ var geodesic = new Cesium.EllipsoidGeodesic(); geodesic.setEndPoints(point1cartographic, point2cartographic); var s = geodesic.surfaceDistance; //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2))); //返回两点之间的距离 s = Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2)); return s; } } }
  1. 引用MeasureTool.js文件,并调用测量方法:
<template>
    <div id="cesiumContainer">

    </div>
</template>

<script>
    import MeasureTool from '../../public/js/MeasureTool'
    export default {
        name: 'CeLiang',
        components: {},
        data(){
            return{

            }
        },
        mounted() {
            let viewer = new Cesium.Viewer('cesiumContainer');
            //测量距离
            MeasureTool.measureLineSpace(viewer, null);
            //测量面积
            MeasureTool.measureAreaSpace(viewer, null);
        }
    }
</script>

<style>
    #cesiumContainer {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
    }
</style>
  1. 效果
    Cesium 测量距离_第3张图片
    Cesium 测量距离_第4张图片

你可能感兴趣的:(Cesium,开发,数据可视化)