cesium坐标测量,高度差测量


        之前做系统需要很多图上量算的功能,由于cesium没有提供相关接口,我自己实现了,准备和大家分享(也参考了很多别人的代码,十分感谢)。因为我做的是capacitor移动端,发现点击只有Cesium.ScreenSpaceEventType.LEFT_DOWN可以用,我就放了一个按钮用来停止。一共有6个图上测量功能,这篇文章先分享坐标测量和高度测量的代码。希望大家点点关注,可以多多交流!

坐标测量

// 坐标测量类
import * as Cesium from "cesium";

export default class MeasureCoordinates {
  constructor(viewer) {
    this.viewer = viewer;
    this.initEvents();
    this.positions = [];
    this.vertexEntities = [];
    this.labelEntities = [];
    this.isMeasure = false;
  }

  // 初始化鼠标事件
  initEvents() {
    if (!this.handler_coor) {
      this.handler_coor = new Cesium.ScreenSpaceEventHandler(
        this.viewer.scene.canvas
      );
    }
    this.MeasureEndEvent = new Cesium.Event(); // 结束事件
  }

  // 激活测量工具
  activate() {
    this.deactivate(); // 确保没有重复的事件监听
    this.registerEvents();
    this.positions = [];
    this.vertexEntities = [];
    this.labelEntities = [];
    this.isMeasure = true;
  }

  registerEvents() {
    // 注册鼠标点击事件
    this.handler_coor.setInputAction((event) => {
      const position = this.viewer.scene.pickPosition(event.position);
      if (Cesium.defined(position)) {
        this.positions.push(position);
        this.createVertex(position);
        this.createLabel(position, this.getCoordinatesText(position));
      }
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

    // 注册鼠标右键事件
    // this.handler_coor.setInputAction(() => {
    //   if (this.positions.length > 0) {
    //     this.displayCoordinates();
    //   }
    //   this.deactivate();
    // }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  }

  // 停止测量工具
  deactivate() {
    if (!this.isMeasure) return;
    this.unRegisterEvents();
    this.handler_coor = null;
    this.isMeasure = false;
  }

  // 清空所有实体和标签
  clear() {
    this.vertexEntities.forEach((entity) =>
      this.viewer.entities.remove(entity)
    );
    this.labelEntities.forEach((entity) => this.viewer.entities.remove(entity));
    this.positions = [];
    this.vertexEntities = [];
    this.labelEntities = [];
  }

  // 创建点实体
  createVertex(position) {
    const vertexEntity = this.viewer.entities.add({
      position: position,
      point: {
        pixelSize: 8,
        color: Cesium.Color.RED,
      },
    });
    this.vertexEntities.push(vertexEntity);
  }

  // 创建标签
  createLabel(position, text) {
    const labelEntity = this.viewer.entities.add({
      position: position,
      label: {
        text: text,
        font: "25px sans-serif",
        fillColor: Cesium.Color.WHITE,
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 2,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        pixelOffset: new Cesium.Cartesian2(0, -20),
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
      },
    });
    this.labelEntities.push(labelEntity);
  }

  // 获取坐标信息文本
  getCoordinatesText(position) {
    const cartographic = Cesium.Cartographic.fromCartesian(position);
    const lon = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6);
    const lat = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6);
    const height = cartographic.height.toFixed(2);
    return `经度: ${lon}, 纬度: ${lat}, 高度: ${height}m`;
  }

  // 显示所有坐标信息
  displayCoordinates() {
    const coordinates = this.positions.map((position, index) => {
      const cartographic = Cesium.Cartographic.fromCartesian(position);
      const lon = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6);
      const lat = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6);
      const height = cartographic.height.toFixed(2);
      return `点${index + 1}: 经度: ${lon}, 纬度: ${lat}, 高度: ${height}m`;
    });

    console.log("测量的坐标信息:");
    coordinates.forEach((coord) => console.log(coord));
    alert(coordinates.join("\n"));
  }

  //测量结束
  measureEnd() {
    this.deactivate();
    this.MeasureEndEvent.raiseEvent(this.measureDistance); //触发结束事件 传入结果
  }

  endMeasure() {
    if (this.isMeasure) {
      this.displayCoordinates();
      this.measureEnd();
    }
  }

  //解除鼠标事件
  unRegisterEvents() {
    this.handler_coor.removeInputAction(
      Cesium.ScreenSpaceEventType.RIGHT_CLICK
    );
    this.handler_coor.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN);
    this.handler_coor.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  }
}

高度差测量
 

//高度测量类
import * as Cesium from "cesium";
export default class MeasureHeight {
  constructor(viewer) {
    this.viewer = viewer;
    this.initEvents();
    this.positions = [];
    this.vertexEntities = [];
    this.labelEntity = undefined;
    this.measureHeight = 0; //测量结果
    this.circleRadius = 1; // 默认圆半径固定为1米
  }

  //初始化事件
  initEvents() {
    if (!this.handler_hei) {
      this.handler_hei = new Cesium.ScreenSpaceEventHandler(
        this.viewer.scene.canvas
      );
    }
    this.MeasureStartEvent = new Cesium.Event(); //开始事件
    this.MeasureEndEvent = new Cesium.Event(); //结束事件
  }

  //激活
  activate() {
    this.deactivate();
    this.registerEvents(); //注册鼠标事件
    //设置鼠标状态
    this.viewer.enableCursorStyle = false;
    this.viewer._element.style.cursor = "default";
    this.isMeasure = true;
    this.circleRadius = 0.1;
    this.measureHeight = 0;
    this.positions = [];
  }

  //禁用
  deactivate() {
    if (!this.isMeasure) return;
    this.unRegisterEvents();
    this.handler_hei = null;
    this.viewer._element.style.cursor = "pointer";
    this.viewer.enableCursorStyle = true;
    this.isMeasure = false;
  }

  //清空绘制
  clear() {
    //清除线对象
    this.viewer.entities.remove(this.lineEntity);
    this.lineEntity = undefined;

    //清除文本
    this.viewer.entities.remove(this.labelEntity);
    this.labelEntity = undefined;

    //移除圆
    this.removeCircleEntity();

    //清除节点
    this.vertexEntities.forEach((item) => {
      this.viewer.entities.remove(item);
    });
    this.vertexEntities = [];
  }

  //创建线对象
  createLineEntity() {
    this.lineEntity = this.viewer.entities.add({
      polyline: {
        positions: new Cesium.CallbackProperty((e) => {
          return this.positions;
        }, false),
        width: 2,
        material: Cesium.Color.YELLOW,
        depthFailMaterial: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.RED,
        }),
      },
    });
  }

  //创建结果文本标签
  createLabel() {
    this.labelEntity = this.viewer.entities.add({
      position: new Cesium.CallbackProperty((e) => {
        return this.positions[this.positions.length - 1]; //返回最后一个点
      }, false),
      label: {
        text: "",
        scale: 0.5,
        font: "normal 40px MicroSoft YaHei",
        distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
          0,
          50000000000
        ),
        scaleByDistance: new Cesium.NearFarScalar(500, 1.5, 1500, 1.5),
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        pixelOffset: new Cesium.Cartesian2(0, -30),
        outlineWidth: 9,
        outlineColor: Cesium.Color.WHITE,
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
      },
    });
  }

  //创建线节点
  createVertex(index) {
    let vertexEntity = this.viewer.entities.add({
      position: new Cesium.CallbackProperty((e) => {
        return this.positions[index];
      }, false),
      type: "MeasureHeightVertex",
      point: {
        color: Cesium.Color.FUCHSIA,
        pixelSize: 6,
        // disableDepthTestDistance: 2000,
      },
    });
    this.vertexEntities.push(vertexEntity);
  }

  positionHeight(cartesian) {
    if (!cartesian) {
      return 0; // 默认高度
    }
    const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
    return cartographic.height; // 返回高度值
  }

  //创建圆 这样方便看出水平面的高低
  createCircleEntitiy() {
    this.circleEntity = this.viewer.entities.add({
      position: new Cesium.CallbackProperty((e) => {
        return this.positions[this.positions.length - 1]; //返回最后一个点
      }, false),
      ellipse: {
        height: new Cesium.CallbackProperty((e) => {
          return this.positionHeight(this.positions[this.positions.length - 1]);
        }, false),
        semiMinorAxis: 5, // 固定半径为5米
        semiMajorAxis: 5, // 固定半径为5米
        material: Cesium.Color.BLUE.withAlpha(0.6), // 设置颜色为蓝色并调整透明度
      },
    });
  }

  //删除圆
  removeCircleEntity() {
    this.viewer.entities.remove(this.circleEntity);
    this.circleEntity = undefined;
  }

  //注册鼠标事件
  registerEvents() {
    this.leftClickEvent();
    this.rightClickEvent();
    this.mouseMoveEvent();
  }

  //左键点击事件
  leftClickEvent() {
    //单击鼠标左键画点点击事件
    this.handler_hei.setInputAction((e) => {
      this.viewer._element.style.cursor = "default";
      let position = this.viewer.scene.pickPosition(e.position);
      if (!position) {
        const ellipsoid = this.viewer.scene.globe.ellipsoid;
        position = this.viewer.scene.camera.pickEllipsoid(
          e.position,
          ellipsoid
        );
      }
      if (!position) return;

      if (this.positions.length == 0) {
        //首次点击
        this.positions.push(position);
        this.createVertex(0);
        this.createLineEntity();
        this.createCircleEntitiy();
        this.createLabel();
      } else {
        //第二次点击结束测量
        //添加更多点
        this.positions.push(position);
        this.createVertex(this.positions.length - 1);
      }
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
  }

  //鼠标移动事件
  mouseMoveEvent() {
    this.handler_hei.setInputAction((e) => {
      if (!this.isMeasure) return;
      this.viewer._element.style.cursor = "default";
      let position = this.viewer.scene.pickPosition(e.endPosition);
      if (!position) {
        position = this.viewer.scene.camera.pickEllipsoid(
          e.startPosition,
          this.viewer.scene.globe.ellipsoid
        );
      }
      if (!position) return;
      this.handleMoveEvent(position);
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  }

  cartesian3Point3(position) {
    const c = Cesium.Cartographic.fromCartesian(position);
    const lon = Cesium.Math.toDegrees(c.longitude);
    const lat = Cesium.Math.toDegrees(c.latitude);
    return [lon, lat, c.height];
  }

  //处理鼠标移动
  handleMoveEvent(position) {
    if (this.positions.length < 1) return;
    let firstPoint = this.cartesian3Point3(this.positions[0]); //第一个点
    let movePoint = this.cartesian3Point3(position); //鼠标移动点
    const h = movePoint[2] - firstPoint[2];
    firstPoint[2] = movePoint[2];
    const twoPosition = Cesium.Cartesian3.fromDegrees(
      firstPoint[0],
      firstPoint[1],
      movePoint[2]
    );
    if (this.positions.length < 2) {
      this.positions.push(twoPosition);
      this.createVertex(1);
    } else {
      this.positions[1] = twoPosition;
      this.measureHeight = h.toFixed(3);
      this.labelEntity.label.text = "高度:" + this.measureHeight + " 米";
    }
    //计算圆的半径
    this.circleRadius = this.getDistanceH(this.positions[0], position);
  }

  cartesian3ToPoint3D(cartesian) {
    if (!cartesian) {
      return null;
    }

    const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
    const longitude = Cesium.Math.toDegrees(cartographic.longitude); // 经度
    const latitude = Cesium.Math.toDegrees(cartographic.latitude); // 纬度
    const height = cartographic.height; // 高度

    return {
      lon: longitude,
      lat: latitude,
      alt: height,
    };
  }

  // 获取半径
  getDistanceH(p1, p2) {
    if (!p1 || !p2) return 2;
    let distance = Cesium.Cartesian3.distance(p1, p2);
    let p2Car = this.cartesian3ToPoint3D(p2);
    let radius = Math.sqrt(
      Math.abs(Math.pow(distance, 2) - Math.pow(p2Car.alt, 2))
    );
    return radius;
  }

  //右键事件
  rightClickEvent() {
    this.handler_hei.setInputAction((e) => {
      if (this.isMeasure) {
        this.deactivate();
        this.clear();
      }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  }

  //测量结束
  measureEnd() {
    this.deactivate();
    this.MeasureEndEvent.raiseEvent(this.measureHeight); //触发结束事件 传入结果
  }

  endMeasure() {
    this.measureEnd();
  }

  //解除鼠标事件
  unRegisterEvents() {
    this.handler_hei.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    this.handler_hei.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN);
    this.handler_hei.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值