上一篇学习了创建实体的一些基础知识,但有时还需要我们使用鼠标进行手动绘制,这一篇就来进行鼠标绘制实体的实现(点,线,矩形,圆,多边形)。
(这里需要掌握三个知识点,一是上一篇中的创建实体、二是鼠标事件、三是回调函数)

一、鼠标事件

既然是鼠标绘制,自然离不开鼠标事件,我们需要先简单了解一下cesium的鼠标事件。

1. ScreenSpaceEventHandler:

这是Cesium中用于处理鼠标和触摸事件的主要类。需要创建一个此类的实例来开始事件监听。

let handler =newCesium.ScreenSpaceEventHandler(viewer.canvas);
handler.setInputAction(event=>{}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

上述代码示例为Cesium的canvas创建了一个新的事件处理器。

2. 常用的鼠标事件类型 (ScreenSpaceEventType):

LEFT_CLICK: 左键点击
RIGHT_CLICK: 右键点击
LEFT_DOUBLE_CLICK: 左键双击
RIGHT_DOUBLE_CLICK: 右键双击
MIDDLE_CLICK: 中键点击
MOUSE_MOVE: 鼠标移动
WHEEL: 鼠标滚轮滚动

3. 注册事件监听:

使用 setInputAction 方法可以为特定的事件类型设置回调函数。
在回调函数中的 event 对象,包含与事件相关的数据。例如,对于鼠标点击事件,可以访问 event.position 来获取鼠标点击的屏幕坐标。

handler.setInputAction(function(event){
    console.log('鼠标左键点击位置::', event.position);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

4. 关闭或销毁事件监听:

handler.destroy();//永久性销毁事件处理器,之后它不能再被使用。
handler.removeInputAction(eventType);//仅移除特定事件类型的监听(如:handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);)

二、回调函数(CallbackProperty )

我们通过鼠标事件来获取位置信息,再通过回调函数进行属性值修改。

回调函数说明

Cesium.CallbackProperty 是 Cesium.js 库中的一个特性,允许用户为属性提供一个回调函数,该函数描述了属性值如何随时间变化。这在需要动态或根据特定逻辑更改属性值的情况下特别有用,例如为实体的位置、颜色或其他属性设置动画效果。其实我们这里画线,画圆、画多边形等都是先创建不同的实体,然后根据鼠标事件获取位置坐标,动态改变其属性值,从而显示鼠标绘制的效果。

以下是 Cesium.CallbackProperty 的主要特点:

1.动态属性:

与其他静态属性不同,使用 CallbackProperty 创建的属性是动态的,它可以随时间或其它条件变化。

2.回调函数:

当需要获取属性值时,会调用提供的回调函数。这意味着每次 Cesium 请求属性值时,它都会执行这个函数。因此,你可以基于各种条件(例如当前时间)来计算和返回不同的值。

3.构造函数参数:

callback :一个回调函数,当需要属性值时会被调用。这个函数通常接收两个参数:time 和 result。time 是一个 JulianDate 对象,表示当前时间;而 result 是一个可选的参数,用于存储结果,以避免不必要的对象创建。
isConstant :一个布尔值,表示该属性是否是常数。即使属性是由回调函数定义的,也有可能总是返回相同的值。在这种情况下,可以将 isConstant 设置为 true。

举例说明:

请见“五、鼠标绘制圆”中绘制圆的代码说明。

三、鼠标绘制点

(1)主要操作及思路:

允许用户点击地球的某个位置,然后在那个位置上添加一个红色的点,用户鼠标右击,结束绘制,并返回点位置。

(2)代码:

主方法:
/**
 * 绘制点
 */DrawPoints(){returnnewPromise((resolve, reject)=>{let viewer =this.viewer;let drawnPoints =[];// 创建一个事件处理器let handler =newCesium.ScreenSpaceEventHandler(viewer.canvas);// 注册鼠标左键点击事件,用于绘制点
      handler.setInputAction(event=>{// 获取鼠标点击的笛卡尔坐标(鼠标点击位置->笛卡尔坐标)var cartesian =this.getCatesian3FromPX(event.position);// 确保坐标有效if(cartesian){// 添加点实体
              viewer.entities.add({position: cartesian,point:{color: Cesium.Color.RED,pixelSize:10}});// 获取地理坐标(经纬度)let cartographic = Cesium.Cartographic.fromCartesian(cartesian);let longitude = Cesium.Math.toDegrees(cartographic.longitude);let latitude = Cesium.Math.toDegrees(cartographic.latitude);let height=Cesium.Math.toDegrees(cartographic.height);// 将绘制的点添加到数组中
              drawnPoints.push({lng: longitude,lat: latitude,height:height });}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);// 注册鼠标右键点击事件,用于结束绘制
      handler.setInputAction(()=>{// 销毁事件处理器
          handler.destroy();// 返回所有绘制的点resolve(drawnPoints);}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);});},
调用进行位置拾取和坐标转换的方法(此处三个方法来自 ):
/**
   * 拾取位置点
   * @param {Object} px 屏幕坐标
   * @return {Object} Cartesian3 三维坐标
   */getCatesian3FromPX:function(px){if(this.viewer && px){var picks =this.viewer.scene.drillPick(px);var cartesian =null;var isOn3dtiles =false,
        isOnTerrain =false;// drillPickfor(let i in picks){let pick = picks[i];if((pick && pick.primitive instanceofCesium.Cesium3DTileFeature)||(pick && pick.primitive instanceofCesium.Cesium3DTileset)||(pick && pick.primitive instanceofCesium.Model)){//模型上拾取
          isOn3dtiles =true;}// 3dtilsetif(isOn3dtiles){this.viewer.scene.pick(px);// pick
          cartesian =this.viewer.scene.pickPosition(px);if(cartesian){let cartographic = Cesium.Cartographic.fromCartesian(cartesian);if(cartographic.height <0) cartographic.height =0;let lon = Cesium.Math.toDegrees(cartographic.longitude),
              lat = Cesium.Math.toDegrees(cartographic.latitude),
              height = cartographic.height;
            cartesian =this.transformWGS84ToCartesian({lng: lon,lat: lat,alt: height
            });}}}// 地形let boolTerrain =this.viewer.terrainProvider instanceofCesium.EllipsoidTerrainProvider;// Terrainif(!isOn3dtiles &&!boolTerrain){var ray =this.viewer.scene.camera.getPickRay(px);if(!ray)returnnull;
        cartesian =this.viewer.scene.globe.pick(ray,this.viewer.scene);
        isOnTerrain =true;}// 地球if(!isOn3dtiles &&!isOnTerrain && boolTerrain){
        cartesian =this.viewer.scene.camera.pickEllipsoid(
          px,this.viewer.scene.globe.ellipsoid
        );}if(cartesian){let position =this.transformCartesianToWGS84(cartesian);if(position.alt <0){
          cartesian =this.transformWGS84ToCartesian(position,0.1);}return cartesian;}returnfalse;}},/***
   * 坐标转换 84转笛卡尔
   * @param {Object} {lng,lat,alt} 地理坐标
   * @return {Object} Cartesian3 三维位置坐标
   */transformWGS84ToCartesian:function(position, alt){if(this.viewer){return position
        ? Cesium.Cartesian3.fromDegrees(
            position.lng || position.lon,
            position.lat,(position.alt = alt || position.alt),
            Cesium.Ellipsoid.WGS84): Cesium.Cartesian3.ZERO;}},/***
   * 坐标转换 笛卡尔转84
   * @param {Object} Cartesian3 三维位置坐标
   * @return {Object} {lng,lat,alt} 地理坐标
   */transformCartesianToWGS84:function(cartesian){if(this.viewer && cartesian){var ellipsoid = Cesium.Ellipsoid.WGS84;var cartographic = ellipsoid.cartesianToCartographic(cartesian);return{lng: Cesium.Math.toDegrees(cartographic.longitude),lat: Cesium.Math.toDegrees(cartographic.latitude),alt: cartographic.height
      };}},
getCatesian3FromPX方法说明:

该方法根据给定的屏幕坐标px,计算出对应的三维世界坐标。该三维世界坐标可以代表一个具体的点在地图上的位置。
使用drillPick方法来获取屏幕坐标点上所有的对象。如果该点上有一个或多个对象,方法会尝试从3D模型上拾取坐标。
如果拾取不在3D模型上,并且地形存在,则从地形上拾取坐标。
如果既不在3D模型上也不在地形上,则从地球椭球体上拾取坐标。
最后返回这个点的三维世界坐标,或者在无法确定时返回false。

transformWGS84ToCartesian方法说明:

该方法根据给定的地理坐标(WGS84格式)计算出相应的三维世界坐标(笛卡尔坐标)。
使用Cesium的Cartesian3.fromDegrees方法从给定的经纬度和高度计算出三维坐标。

transformCartesianToWGS84方法说明:

该方法根据给定的三维世界坐标(笛卡尔坐标)计算出相应的地理坐标(WGS84格式)。
使用Cesium的Ellipsoid.WGS84和cartesianToCartographic方法将三维世界坐标转换为地理坐标。

四、鼠标绘制线

(1)主要操作及思路:

使用左键点击事件来添加点,创建一个折线实体来表示用户点击确定的所有点之间的线段。同时每当用户移动鼠标时,显示从最后一个点击位置到当前鼠标位置的一个动态线段。

(2)代码:

/**
 * 绘制折线
 */DrawPolyline(){returnnewPromise((resolve, reject)=>{let viewer =this.viewer;let polylinePoints =[];// 临时折线实体let polylineEntity = viewer.entities.add({Id:"drawingPolyline",name:"画线",polyline:{//使用CallbackProperty允许我们在用户点击时动态更新线段的位置positions:newCesium.CallbackProperty(()=>{return polylinePoints;},false),width:2,material: Cesium.Color.RED}});// 临时动态线实体let dynamicLineEntity = viewer.entities.add({polyline:{positions:newCesium.CallbackProperty(()=>{if(lastPoint && currentMousePoint){return[lastPoint, currentMousePoint];}else{return[];}},false),width:2,material: Cesium.Color.RED.withAlpha(0.5)// 使用半透明红色,与主线区分}});let lastPoint =null;let currentMousePoint =null;// 创建事件处理器let handler =newCesium.ScreenSpaceEventHandler(viewer.canvas);// 注册鼠标左键点击事件,用于添加点和显示点
      handler.setInputAction(event=>{let cartesian =this.getCatesian3FromPX(event.position);if(cartesian){
              polylinePoints.push(cartesian);
              lastPoint = cartesian;
              viewer.entities.add({position: cartesian,point:{color: Cesium.Color.BLUE,pixelSize:10}});}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);// 鼠标移动事件,更新当前鼠标位置并重绘临时线
      handler.setInputAction(event=>{
          currentMousePoint =this.getCatesian3FromPX(event.endPosition);}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 注册鼠标左键双击点击事件,用于结束绘制
      handler.setInputAction(()=>{
          handler.destroy();
          viewer.entities.remove(dynamicLineEntity);// 移除临时线resolve(polylinePoints);}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);});},

五、鼠标绘制圆

(1)主要操作及思路:

用户首先通过单击选择圆的中心,然后通过移动鼠标选择半径。当用户双击时,绘制将完成。

(2)代码:

/**
 * 绘制圆形
 */DrawCircle(){returnnewPromise((resolve, reject)=>{let viewer =this.viewer;let centerPoint =null;let centerPointEntity =null;// 用于存储中点实体的引用let radius =10;
      viewer.scene.globe.depthTestAgainstTerrain =false;let drawingCircle = viewer.entities.add({id:"drawingCircle",name:"画圆",ellipse:{semiMinorAxis:newCesium.CallbackProperty(()=>{return radius;},false),semiMajorAxis:newCesium.CallbackProperty(()=>{return radius;},false),material: Cesium.Color.BLUE.withAlpha(0.2),outline:true,outlineColor: Cesium.Color.RED,outlineWidth:2,fill:true,//为true时只显示轮廓线}});let handler =newCesium.ScreenSpaceEventHandler(viewer.canvas);
      handler.setInputAction(event=>{var cartesian =this.getCatesian3FromPX(event.position);if(cartesian && centerPoint ===null){
              centerPoint = cartesian;
              drawingCircle.position = centerPoint;// 添加中点实体并保存其引用
              centerPointEntity = viewer.entities.add({position: cartesian,point:{color: Cesium.Color.RED,pixelSize:10}});}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
      handler.setInputAction(event=>{if(centerPoint){let cartesian =this.getCatesian3FromPX(event.endPosition);if(cartesian){let distance = Cesium.Cartesian3.distance(centerPoint, cartesian);
                  radius = distance;}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
      handler.setInputAction(()=>{if(centerPoint !==null&& radius >0){
              handler.destroy();// 关闭鼠标事件监听,结束绘制let circleCenter = Cesium.Cartographic.fromCartesian(centerPoint);let lng = Cesium.Math.toDegrees(circleCenter.longitude);let lat = Cesium.Math.toDegrees(circleCenter.latitude);resolve({center:{lng: lng,lat: lat },radius: radius
              });}}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);});},

代码说明:

我们可以看到鼠标绘制圆是如何实现的呢?首先,创建一个圆实体,即 let drawingCircle = viewer.entities.add({......}) ,其中在

ellipse:{semiMinorAxis:newCesium.CallbackProperty(()=>{return radius;},false),semiMajorAxis:newCesium.CallbackProperty(()=>{return radius;},false),...

这里使用了回调函数 CallbackProperty ,将 semiMinorAxis semiMajorAxis 绑定上了 radius ,也就是说圆的半径将根据 radius 值的变化而变化。看到这里相信你已经明白了,后面我们要做的就是根据鼠标移动来改变 radius 的值,从而改变圆的大小。即鼠标移动监听里的 radius = distance;

六、鼠标绘制矩形

(1)主要操作及思路:

首次单击选择左上角,移动鼠标调整矩形的大小,然后双击来结束绘制并保存矩形的点。通过捕获用户在地图上的鼠标操作来确定矩形的两个对角点,然后使用这两个点来定义矩形。

(2)代码:

/**
   * 绘制矩形
   */DrawRectangle(){var allPoints =[];// 设置返回值returnnewPromise((resolve, reject)=>{let viewer =this.viewer;let topLeftPoint =null;let bottomRightPoint =null;let drawingRectangle = viewer.entities.add({id:"drawingRectangle",name:"画矩形",rectangle:{coordinates:newCesium.CallbackProperty(()=>{if(topLeftPoint ===null|| bottomRightPoint ===null){return;}let west = topLeftPoint.longitude;let north = topLeftPoint.latitude;let east = bottomRightPoint.longitude;let south = bottomRightPoint.latitude;returnnewCesium.Rectangle(west, south, east, north);},false),material: Cesium.Color.BLUE.withAlpha(0.2),closeTop:true,closeBottom:false}});let handler =newCesium.ScreenSpaceEventHandler(viewer.canvas);
        handler.setInputAction(event=>{var cartesian =this.getCatesian3FromPX(event.position);if(cartesian){if(topLeftPoint ===null){
                    topLeftPoint = Cesium.Cartographic.fromCartesian(cartesian);}
                viewer.entities.add({position: cartesian,point:{color: Cesium.Color.RED,pixelSize:10}});}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
        handler.setInputAction(event=>{if(topLeftPoint){
                bottomRightPoint = Cesium.Cartographic.fromCartesian(this.getCatesian3FromPX(event.endPosition));}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
        handler.setInputAction(()=>{if(topLeftPoint !==null&& bottomRightPoint !==null){
                handler.destroy();// 关闭鼠标事件监听,结束绘制let west = Cesium.Math.toDegrees(topLeftPoint.longitude);let north = Cesium.Math.toDegrees(topLeftPoint.latitude);let east = Cesium.Math.toDegrees(bottomRightPoint.longitude);let south = Cesium.Math.toDegrees(bottomRightPoint.latitude);
                allPoints.push({lng: west,lat: north });
                allPoints.push({lng: east,lat: north });
                allPoints.push({lng: east,lat: south });
                allPoints.push({lng: west,lat: south });
                allPoints.push(allPoints[0]);// 闭合resolve(allPoints);}}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);});},

七、鼠标绘制多边形

贴地:

(1)主要操作及思路:

点击地图以定义多边形的顶点,可以随着鼠标移动看到多边形的形状实时更新,通过双击结束多边形绘制,并返回所有的顶点。

(2)代码:

主方法:
/**
   * 绘制多边形
   * @param {Object}  option
   * @param {Boolean} option.ground 是否贴地
   */DrawPolygon(option){var allPoints=[]// 设置返回值returnnewPromise((resolve, reject)=>{// 1. 获取Cesium Viewerlet viewer =this.viewer;// 2. 创建一个用于存储多边形顶点的数组let polygonPoints =[];// 3. 创建一个用于显示当前绘制中的多边形的实体let drawingPolygon = viewer.entities.add({id:"drawingPolygon",name:"画多边形",polygon:{hierarchy:newCesium.CallbackProperty(()=>{returnnewCesium.PolygonHierarchy(polygonPoints);},false),material: Cesium.Color.BLUE.withAlpha(0.2),perPositionHeight:(option&&option.ground)||false// true:不贴地/false:贴地},});// 4. 创建一个用于显示当前绘制中的线的实体let drawingLine = viewer.entities.add({id:"drawingLine",name:"画线",polyline:{positions:newCesium.CallbackProperty(()=>{return polygonPoints;},false),width:3,material: Cesium.Color.GREEN}});// 5. 监听鼠标点击事件,将点击的点添加到顶点数组中,并添加点实体let handler =newCesium.ScreenSpaceEventHandler(viewer.canvas);
    handler.setInputAction(event=>{var cartesian =this.getCatesian3FromPX(event.position);if(cartesian){// 将点坐标添加到数组中
        polygonPoints.push(cartesian.clone());// 在第一次点击时,添加一个克隆的点到数组中,用于动态更新if(polygonPoints.length ===1){
          polygonPoints.push(cartesian.clone());}// 添加点实体
        viewer.entities.add({position: cartesian,point:{color: Cesium.Color.RED,pixelSize:10}});//将三维笛卡尔坐标系点转为经纬度坐标点,并保存到点数组中let cartesian3 = cartesian.clone()// 使用Cesium.Cartographic.fromCartesian将Cartesian3对象转换为Cartographic对象let cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
         allPoints.push([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude), cartographic.height]);}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);// 6. 监听鼠标移动事件,动态更新多边形和线的形状
    handler.setInputAction(event=>{var cartesian =this.getCatesian3FromPX(event.endPosition);if(polygonPoints.length >=2){if(cartesian && cartesian.x){
          polygonPoints.pop();
          polygonPoints.push(cartesian);}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 7. 监听鼠标右键点击事件,结束绘制
    handler.setInputAction(()=>{var cartesian=polygonPoints[polygonPoints.length-1]// 添加点实体
        viewer.entities.add({position: cartesian,point:{color: Cesium.Color.RED,pixelSize:10}});
      polygonPoints.push(polygonPoints[0]);
      handler.destroy();// 关闭鼠标事件监听,结束绘制resolve(allPoints);}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);})},
调用方法:
let option ={ground:true//true:不贴地/false:贴地           };DrawPolygon(option).then(allPoints=>{// 在这里,allPoints是结束绘制后的点坐标数组var resultPoints=allPoints
        })

(3)DrawPolygon方法说明:

1,定义返回结果的方式:
var allPoints=[]returnnewPromise((resolve, reject)=>{......}

在这个方法开始时,定义了一个allPoints数组,用于存储绘制的多边形的所有顶点,并且返回一个Promise,允许在绘制结束后将这些点的坐标返回。

2,获取Cesium Viewer:
let viewer =this.viewer;

获取Cesium的Viewer实例

3,创建一个实体以显示绘制中的多边形:
let drawingPolygon = viewer.entities.add({...});

这段代码通过Cesium的entities.add方法创建一个新的实体,并将它添加到地图上。这个实体用于实时显示用户绘制的多边形。

4,创建一个实体以显示绘制中的线:
let drawingLine = viewer.entities.add({...});

创建一个实体来实时显示用户绘制的线。

5,设置鼠标点击事件的监听:
let handler =newCesium.ScreenSpaceEventHandler(viewer.canvas);
handler.setInputAction(event=>{...}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

这段代码创建一个新的ScreenSpaceEventHandler实例来监听鼠标和触摸事件。然后设置一个函数来监听左键点击事件。每当用户点击鼠标左键时,这个函数就会被调用,并将点击的位置添加到polygonPoints数组(即多边形的顶点)和allPoints数组。
需要说明的是这一段代码:

//将三维笛卡尔坐标系点转为经纬度坐标点,并保存到点数组中let cartesian3 = cartesian.clone()// 使用Cesium.Cartographic.fromCartesian将Cartesian3对象转换为Cartographic对象let cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
         allPoints.push([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude), cartographic.height]);

加上这一段只是因为,如果要对获取的点数组进行进一步使用,我更习惯使用经纬度坐标

6,设置鼠标移动事件的监听:
handler.setInputAction(event=>{...}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

当用户移动鼠标时,这个函数会被调用。它用于实时更新正在绘制的多边形和线的形状。

7,设置鼠标双击事件的监听:
handler.setInputAction(()=>{...}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

这个函数监听鼠标左键双击事件。当用户双击鼠标左键时,这个函数会被调用,表示用户完成了多边形的绘制。此时,它会添加最后一个点实体,关闭鼠标事件监听,结束绘制,并通过resolve(allPoints)将绘制的点坐标返回。

8,总说明:

这个方法允许用户通过点击和移动鼠标在Cesium地图上绘制一个多边形。在用户完成绘制(通过双击鼠标左键)后,这个方法通过Promise的resolve函数将绘制的点坐标数组allPoints返回,供其他部分的代码使用。
(比如进行填挖方的计算,将上面的点数组传到地形填挖方计算的方法,用来生成三角网)

(4)拖拽点进行形状修改

绘制完成:

拖拽点:

思路:
在完成绘制后(即在双击事件结束后),初始化一个新的鼠标事件处理器专门用于拖拽操作。在新的事件处理器中,设置监听左键按下、左键抬起和鼠标移动的事件,用于实现拖拽交互。为了在拖动点时停止地图的默认移动事件,需要在开始拖动事件时暂时禁用默认的摄像机控制,并在拖动结束后再次启用它。(保证点数组长度不变,修改拖拽点的位置)
代码:

let handler =this.globalHandler;
      handler.setInputAction(event=>{var cartesian =this.getCatesian3FromPX(event.position);if(cartesian){// 将点坐标添加到数组中
          polygonPoints.push(cartesian.clone());// 在第一次点击时,添加一个克隆的点到数组中,用于动态更新if(polygonPoints.length ===1){
            polygonPoints.push(cartesian.clone());}// 添加点实体var pointEntity = viewer.entities.add({id:"point"+ polygonPoints.length,position: cartesian,point:{color: Cesium.Color.RED,pixelSize:10}});
          pointEntities.push(pointEntity);//添加到多边形数组中let cartesian3 = cartesian.clone();// 使用Cesium.Cartographic.fromCartesian将Cartesian3对象转换为Cartographic对象let cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
          allPoints.push([
            Cesium.Math.toDegrees(cartographic.longitude),
            Cesium.Math.toDegrees(cartographic.latitude),
            cartographic.height
          ]);}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);// 6. 监听鼠标移动事件,动态更新多边形和线的形状
      handler.setInputAction(event=>{var cartesian =this.getCatesian3FromPX(event.endPosition);if(polygonPoints.length >=2){if(cartesian && cartesian.x){
            polygonPoints.pop();
            polygonPoints.push(cartesian);}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 7. 监听鼠标双击事件,结束绘制
      handler.setInputAction(()=>{var cartesian = polygonPoints[polygonPoints.length -1];
        handler.destroy();// 关闭鼠标事件监听,结束绘制// 移除因单击事件产生的最后一个点if(polygonPoints.length >1){// 去除数组中最后一个点
          polygonPoints.pop();// 返回值
          allPoints.pop();
          allPoints.push(allPoints[0]);// 闭合var endPoint = viewer.entities.getById("point"+(polygonPoints.length +1));if(endPoint){
            viewer.entities.remove(endPoint);}var startPoint = viewer.entities.getById("point1");if(startPoint){
            viewer.entities.remove(startPoint);}}resolve(allPoints);// 移除用于绘制的动态线实体
        viewer.entities.remove(drawingLine);// 以下为拖拽点改变多边形形状代码let selectedPointEntity =null;let selectedIndex =-1;var dragHandler =newCesium.ScreenSpaceEventHandler(viewer.canvas);//鼠标按下
        dragHandler.setInputAction(event=>{const pickedObject = viewer.scene.pick(event.position);if(
            Cesium.defined(pickedObject)&&
            pointEntities.includes(pickedObject.id)){
            selectedPointEntity = pickedObject.id;
            selectedIndex = pointEntities.indexOf(selectedPointEntity);// 禁用摄像机控制
            viewer.scene.screenSpaceCameraController.enableRotate =false;
            viewer.scene.screenSpaceCameraController.enableTranslate =false;
            viewer.scene.screenSpaceCameraController.enableZoom =false;
            viewer.scene.screenSpaceCameraController.enableTilt =false;
            viewer.scene.screenSpaceCameraController.enableLook =false;}}, Cesium.ScreenSpaceEventType.LEFT_DOWN);// 当鼠标移动时
        dragHandler.setInputAction(event=>{if(selectedPointEntity){const cartesian =this.getCatesian3FromPX(event.endPosition);if(cartesian && selectedIndex !==-1){
              selectedPointEntity.position = cartesian;
              polygonPoints[selectedIndex]= cartesian;// 如果当前拖动的是第一个点或是最后一个点if(selectedIndex ===0||selectedIndex===polygonPoints.length -2){
                polygonPoints[polygonPoints.length -1]= cartesian;
                pointEntities[polygonPoints.length -1].position.setValue(
                  cartesian
                );}}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 当鼠标左键抬起时
        dragHandler.setInputAction(()=>{
          selectedPointEntity =null;
          selectedIndex =-1;// 启用摄像机控制
          viewer.scene.screenSpaceCameraController.enableRotate =true;
          viewer.scene.screenSpaceCameraController.enableTranslate =true;
          viewer.scene.screenSpaceCameraController.enableZoom =true;
          viewer.scene.screenSpaceCameraController.enableTilt =true;
          viewer.scene.screenSpaceCameraController.enableLook =true;}, Cesium.ScreenSpaceEventType.LEFT_UP);}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);