cesium学习记录08-鼠标绘制多边形

上一篇学习了实体的一些基础知识,这一篇来学习鼠标绘制实体多边形的实现

1,结果显示

贴地:
不贴地:

2,方法全部代码:

主方法:
javascript 复制代码
 /**
   * 绘制多边形
   * @param {Object}  option
   * @param {Boolean} option.ground 是否贴地
   */ 
   DrawPolygon(option) {
    var allPoints=[]
    // 设置返回值
    return new Promise((resolve, reject) => {
    // 1. 获取Cesium Viewer
    let viewer = this.viewer;
    // 2. 创建一个用于存储多边形顶点的数组
    let polygonPoints = [];
    // 3. 创建一个用于显示当前绘制中的多边形的实体
    let drawingPolygon = viewer.entities.add({
      id: "drawingPolygon",
      name: "画多边形",
      polygon: {
        hierarchy: new Cesium.CallbackProperty(() => {
          return new Cesium.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: new Cesium.CallbackProperty(() => {
          return polygonPoints;
        }, false),
        width: 3,
        material: Cesium.Color.GREEN
      }
    });

    // 5. 监听鼠标点击事件,将点击的点添加到顶点数组中,并添加点实体
    let handler = new Cesium.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
          }
        });
      handler.destroy(); // 关闭鼠标事件监听,结束绘制
      resolve(allPoints);
    }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
  })
  },
调用进行位置拾取和转换的方法(此处三个方法来自测量插件):
javascript 复制代码
 /**
   * 拾取位置点
   * @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;
      // drillPick
      for (let i in picks) {
        let pick = picks[i];

        if (
          (pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) ||
          (pick && pick.primitive instanceof Cesium.Cesium3DTileset) ||
          (pick && pick.primitive instanceof Cesium.Model)
        ) {
          //模型上拾取
          isOn3dtiles = true;
        }
        // 3dtilset
        if (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 instanceof Cesium.EllipsoidTerrainProvider;
      // Terrain
      if (!isOn3dtiles && !boolTerrain) {
        var ray = this.viewer.scene.camera.getPickRay(px);
        if (!ray) return null;
        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;
      }
      return false;
    }
  },
  /***
   * 坐标转换 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
      };
    }
  },

3,调用方法:

javascript 复制代码
let option = {
        ground: true     //true:不贴地/false:贴地           
      };
DrawPolygon(option).then(allPoints => {
          // 在这里,allPoints是结束绘制后的点坐标数组
          var resultPoints=allPoints
        })

4,DrawPolygon方法说明:

1,定义返回结果的方式:
javascript 复制代码
var allPoints=[]
return new Promise((resolve, reject) => {
......
}

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

2,获取Cesium Viewer:
javascript 复制代码
let viewer = this.viewer;

获取Cesium的Viewer实例

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

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

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

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

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

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

需要说明的是这一段代码:

javascript 复制代码
//将三维笛卡尔坐标系点转为经纬度坐标点,并保存到点数组中
         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,设置鼠标移动事件的监听:
javascript 复制代码
handler.setInputAction(event => { ... }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

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

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

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

8,总说明:

这个方法允许用户通过点击和移动鼠标在Cesium地图上绘制一个多边形。在用户完成绘制(通过双击鼠标左键)后,这个方法通过Promise的resolve函数将绘制的点坐标数组allPoints返回,供其他部分的代码使用。

(比如进行填挖方的计算,将上面的点数组传到地形填挖方计算的方法,用来生成三角网)

5,getCatesian3FromPX方法说明:

该方法根据给定的屏幕坐标px,计算出对应的三维世界坐标。该三维世界坐标可以代表一个具体的点在地图上的位置。

使用drillPick方法来获取屏幕坐标点上所有的对象。如果该点上有一个或多个对象,方法会尝试从3D模型上拾取坐标。

如果拾取不在3D模型上,并且地形存在,则从地形上拾取坐标。

如果既不在3D模型上也不在地形上,则从地球椭球体上拾取坐标。

最后返回这个点的三维世界坐标,或者在无法确定时返回false。

6,transformWGS84ToCartesian方法说明:

该方法根据给定的地理坐标(WGS84格式)计算出相应的三维世界坐标(笛卡尔坐标)。

使用Cesium的Cartesian3.fromDegrees方法从给定的经纬度和高度计算出三维坐标。

7,transformCartesianToWGS84方法说明:

该方法根据给定的三维世界坐标(笛卡尔坐标)计算出相应的地理坐标(WGS84格式)。

使用Cesium的Ellipsoid.WGS84和cartesianToCartographic方法将三维世界坐标转换为地理坐标。

8,后续学习记录文章说明:

火星科技(Mars3D)的一些例子,自己用Cesium来实现

相关推荐
李剑一4 小时前
拿来就用!Vue3+Cesium 飞入效果封装,3D大屏多场景直接复用
前端·vue.js·cesium
曲折21 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
西岸行者6 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意6 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码6 天前
嵌入式学习路线
学习
毛小茛6 天前
计算机系统概论——校验码
学习
babe小鑫6 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms6 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下6 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。6 天前
2026.2.25监控学习
学习