GIS-3D:绘制

前言

Cesium中,可使用Entity绘制一些图形,包括点、线、圆形、长方形、不规则图形等,从而满足我们在实际开发中的需要,比如绘制电子围栏。

一、绘制点

原理:监听鼠标点击事件,在点击后的坐标出添加点位Entity

  initEventHandlers() {
    this.handler = new Cesium.ScreenSpaceEventHandler(
      this.viewer?.scene.canvas,
    );

    // 左键点击添加点
    this.handler.setInputAction((event: any) => {
      if (!this.isDrawing) return;

      // 使用pick函数获取点击位置的实际位置
      const cartesian = this.viewer?.scene.pickPosition(event.position);
      if (Cesium.defined(cartesian)) {
        // 将笛卡尔坐标转换为经纬度坐标
        const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        const longitude = Cesium.Math.toDegrees(cartographic.longitude);
        const latitude = Cesium.Math.toDegrees(cartographic.latitude);
        const height = cartographic.height;

        const position = Cesium.Cartesian3.fromDegrees(
          longitude,
          latitude,
          height,
        );
        this.addPosition(position);
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    // 右键点击结束绘制
    this.handler.setInputAction(() => {
      if (this.isDrawing) {
        this.finishDrawing();
      }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  }
  addPosition(position: any) {
    const entity = new Cesium.Entity({
      position,
      point: {
        color: Cesium.Color.RED,
        pixelSize: 5,
      },
    });
    this.viewer?.entities.add(entity);
    this.drawnPoints.push(entity);
  }

二、绘制线

原理:监听鼠标的点击事件,将鼠标点击位置的坐标进行保存,通过保存的所有点位绘制出路线Entity

  /**
   * 初始化鼠标事件处理器
   */
  initEventHandlers() {
    this.handler = new Cesium.ScreenSpaceEventHandler(
      this.viewer?.scene.canvas,
    );

    // 左键点击添加点
    this.handler.setInputAction((event: any) => {
      if (!this.isDrawing) return;

      // 使用pick函数获取点击位置的实际位置
      const cartesian = this.viewer?.scene.pickPosition(event.position);
      if (Cesium.defined(cartesian)) {
        // 将笛卡尔坐标转换为经纬度坐标
        const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        const longitude = Cesium.Math.toDegrees(cartographic.longitude);
        const latitude = Cesium.Math.toDegrees(cartographic.latitude);
        const height = cartographic.height;
        const position = Cesium.Cartesian3.fromDegrees(
          longitude,
          latitude,
          height,
        );
        this.lastPoint = position;
        if (this.currentLine) {
          // 增加点位
          this.currentLine.addPoint(position);
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

    // 右键点击结束绘制
    this.handler.setInputAction(() => {
      if (this.isDrawing) {
        this.finishDrawing();
      }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

  /**
   * 开始绘制(对外暴露的API)
   */
  startDrawing() {
    // 重置当前绘制状态,保留历史绘制结果
    this.currentLine = new LineObject();
    const lineInstance = this.createLineInstance();
    // 将路线添加到地图上
    this.viewer?.entities.add(lineInstance  as Cesium.Entity);
  }
  // 创建路线
  createLineInstance() {
    this.key = `line-${dayjs().valueOf()}`;
    this.lineInstance = new Cesium.Entity({
      id: this.key,
      name: '画线',
      polyline: {
        // 使用CallbackProperty允许我们在用户点击时动态更新线段的位置
        positions: new Cesium.CallbackProperty(() => {
          return this.polylinePoints;
        }, false),
        width: 2,
        material: Cesium.Color.RED,
      },
    });
  }

三、绘制圆

原理:监听鼠标左键的点击事件,将点击的坐标确定为圆的圆心坐标;监测鼠标的移动事件,将鼠标移动的距离确定圆的半径。根据圆心坐标和半径绘制圆


  /**
   * 初始化鼠标事件处理器
   */
  initEventHandlers() {
    this.handler = new Cesium.ScreenSpaceEventHandler(
      this.viewer?.scene.canvas,
    );

    // 左键点击添加点
    this.handler.setInputAction((event: any) => {
      if (!this.isDrawing) return;

      // 使用pick函数获取点击位置的实际位置
      const cartesian = this.viewer?.scene.pickPosition(event.position);
      if (Cesium.defined(cartesian)) {
        // 将笛卡尔坐标转换为经纬度坐标
        const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        const longitude = Cesium.Math.toDegrees(cartographic.longitude);
        const latitude = Cesium.Math.toDegrees(cartographic.latitude);
        const height = cartographic.height;
        const position = Cesium.Cartesian3.fromDegrees(
          longitude,
          latitude,
          height,
        );
        if (this.currentCircle) {
          // 设置当前圆的圆心
          this.currentCircle.resetCenterPoint(position);
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

    // 右键点击结束绘制
    this.handler.setInputAction(() => {
      if (this.isDrawing) {
        this.finishDrawing();
      }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

    // 鼠标移动更新预览线/面
    this.handler.setInputAction((event: any) => {
      if (!this.isDrawing) return;

      // 使用pick函数获取点击位置的实际位置
      const cartesian = this.viewer?.scene.pickPosition(event.endPosition);

      if (Cesium.defined(cartesian)) {
        // 将笛卡尔坐标转换为经纬度坐标
        const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        const longitude = Cesium.Math.toDegrees(cartographic.longitude);
        const latitude = Cesium.Math.toDegrees(cartographic.latitude);
        const height = cartographic.height;
        const position = Cesium.Cartesian3.fromDegrees(
          longitude,
          latitude,
          height,
        );
        if (this.currentCircle?.centerPoint) {
          const distance = Cesium.Cartesian3.distance(
            this.currentCircle?.centerPoint,
            position,
          );
          this.currentCircle.resetRadius(distance);
        }
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  }
  /**
   * 开始绘制(对外暴露的API)
   */
  startDrawing() {
    // 重置当前绘制状态,保留历史绘制结果
    this.isDrawing = true;
    this.currentCircle = new CircleObject();
    this.currentCircle.createCircleInstance();
    this.viewer?.entities.add(
      this.currentCircle.circleInstance as Cesium.Entity,
    );
  }
  // CircleObject类内,创建圆Entity
  createCircleInstance() {
    this.key = `circle-${dayjs().valueOf()}`;
    this.circleInstance = new Cesium.Entity({
      id: this.key,
      name: '画圆',
      ellipse: {
        semiMinorAxis: new Cesium.CallbackProperty(() => {
          return this.currentRadius;
        }, false),
        semiMajorAxis: new Cesium.CallbackProperty(() => {
          return this.currentRadius;
        }, false),
        material: Cesium.Color.BLUE.withAlpha(0.2),
        outline: true,
        outlineColor: Cesium.Color.RED,
        outlineWidth: 2,
        fill: true, // 为true时只显示轮廓线
      },
    });
  } 

四、绘制矩形

原理:监听鼠标左侧点击事件,确定矩形的一个点坐标;监听鼠标移动事件,监听移动结束后的鼠标的点的坐标,来确定矩形的另一个点坐标;通过两个点坐标作为矩形的一对对焦来绘制矩形。

  /**
   * 初始化鼠标事件处理器
   */
  initEventHandlers() {
    this.handler = new Cesium.ScreenSpaceEventHandler(
      this.viewer?.scene.canvas,
    );

    // 左键点击添加点
    this.handler.setInputAction((event: any) => {
      if (!this.isDrawing) return;

      // 使用pick函数获取点击位置的实际位置
      const cartesian = this.viewer?.scene.pickPosition(event.position);
      if (Cesium.defined(cartesian)) {
        // 将笛卡尔坐标转换为经纬度坐标
        const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        const longitude = Cesium.Math.toDegrees(cartographic.longitude);
        const latitude = Cesium.Math.toDegrees(cartographic.latitude);
        if (this.currentRect) {
          // 设置矩形左上角点
          this.currentRect.resetTopLeftPoint(longitude, latitude);
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    // 右键点击结束绘制
    this.handler.setInputAction(() => {
      if (this.isDrawing) {
        this.finishDrawing();
      }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

    // 鼠标移动更新预览线/面
    this.handler.setInputAction((event: any) => {
      if (!this.isDrawing) return;
      // 使用pick函数获取点击位置的实际位置
      const cartesian = this.viewer?.scene.pickPosition(event.endPosition);

      if (Cesium.defined(cartesian)) {
        // 将笛卡尔坐标转换为经纬度坐标
        const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        const longitude = Cesium.Math.toDegrees(cartographic.longitude);
        const latitude = Cesium.Math.toDegrees(cartographic.latitude);
        if (this.currentRect && this.currentRect.startLat) {
          this.currentRect.resetBottomRightPoint(longitude, latitude);
        }
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  }
  /**
   * 开始绘制(对外暴露的API)
   */
  startDrawing() {
    // 重置当前绘制状态,保留历史绘制结果
    this.isDrawing = true;
    this.currentRect = new RectObject();
    this.currentRect.createRectInstance();
    this.viewer?.entities.add(this.currentRect.rectInstance as Cesium.Entity);
  }
  // RectObject中创建矩形对象
  createRectInstance() {
    this.key = `circle-${dayjs().valueOf()}`;
    this.rectInstance = new Cesium.Entity({
      id: this.key,
      name: '画矩形',
      rectangle: {
        coordinates: new Cesium.CallbackProperty(() => {
          if (
            !this.startLng ||
            !this.startLat ||
            !this.endLng ||
            !this.endLat
          ) {
            return;
          }
          // 西
          const west = Math.min(this.startLng, this.endLng);
          // 东
          const east = Math.max(this.startLng, this.endLng);
          // 南
          const south = Math.min(this.startLat, this.endLat);
          // 北
          const north = Math.max(this.startLat, this.endLat);
          return Cesium.Rectangle.fromDegrees(west, south, east, north);
        }, false),
        material: Cesium.Color.BLUE.withAlpha(0.2),
        outline: true,
        outlineColor: Cesium.Color.RED,
        outlineWidth: 2,
        fill: true, // 为true时只显示轮廓线
      },
    });
  }

五、绘制不规则图形

原理:监听鼠标的左侧点击事件,将点击的坐标进行保存;通过点击的坐标的数据,绘制一个不规则图形。


  /**
   * 初始化鼠标事件处理器
   */
  initEventHandlers() {
    this.handler = new Cesium.ScreenSpaceEventHandler(
      this.viewer?.scene.canvas,
    );

    // 左键点击添加点
    this.handler.setInputAction((event: any) => {
      if (!this.isDrawing) return;

      // 使用pick函数获取点击位置的实际位置
      const cartesian = this.viewer?.scene.pickPosition(event.position);
      if (Cesium.defined(cartesian)) {
        // 将笛卡尔坐标转换为经纬度坐标
        const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        const longitude = Cesium.Math.toDegrees(cartographic.longitude);
        const latitude = Cesium.Math.toDegrees(cartographic.latitude);
        const height = cartographic.height;
        const position = Cesium.Cartesian3.fromDegrees(
          longitude,
          latitude,
          height,
        );
        if (this.currentPolygon) {
          this.currentPolygon.resetPointHeight(height);
          this.currentPolygon.addPoint(position);
          if (this.currentPolygon.polygonPoints.length === 1) {
            this.currentPolygon.addPoint(position.clone());
          }
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

    // 右键点击结束绘制
    this.handler.setInputAction(() => {
      if (this.isDrawing) {
        this.finishDrawing();
        if (
          this.currentPolygon &&
          this.currentPolygon.polygonPoints.length > 0
        ) {
          const position = this.currentPolygon.polygonPoints[0];
          this.currentPolygon.addPoint(position);
        }
      }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  }
  /**
   * 开始绘制(对外暴露的API)
   */
  startDrawing() {
    // 重置当前绘制状态,保留历史绘制结果
    this.isDrawing = true;
    this.currentPolygon = new PolygonObject();
    this.currentPolygon.createPoygonInstance();
    this.viewer?.entities.add(
      this.currentPolygon.polygonInstance as Cesium.Entity,
    );
  }

  // 创建不规则图形对象
  createPoygonInstance() {
    this.key = `polygon-${dayjs().valueOf()}`;
    this.polygonInstance = new Cesium.Entity({
      id: this.key,
      name: '画多边形',
      polygon: {
        hierarchy: new Cesium.CallbackProperty(() => {
          return new Cesium.PolygonHierarchy(this.polygonPoints);
        }, false),
        material: Cesium.Color.BLUE.withAlpha(0.2),
        perPositionHeight: false, // true:不贴地/false:贴地
        outline: true,
        outlineColor: Cesium.Color.CYAN,
        outlineWidth: 2,
        height: undefined,
        extrudedHeight: undefined,
      },
    });
  }

六、源代码

demo

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容