cesium vue2 绘制立体几何区域

在这里插入图片描述

<script lang="ts">
import { defineComponent } from "vue";
import { getDictItemsByCode } from "/@/utils/dict";
const riskLevel = getDictItemsByCode("risk_level");
// console.log("riskLevel", riskLevel);
// 模型地址
const publicPath = import.meta.env.VITE_PUBLIC_PATH || "/";
const glbModelUrl = publicPath + "tiles/NiangQiang_v11_nomap.glb";
export default defineComponent({
  props: {
    config: {
      type: Object,
      default: () => {},
    },
    // 是否开始绘制
    isDrawing: {
      type: Boolean,
      default: false,
    },
    recordRowData: {
      type: Object,
      default: () => {},
    },
    areaPositionData: {
      type: Array,
      default: () => [],
    },
  },
  emits: {
    // "update:modelValue": null,
  },
  data() {
    return {
      viewer: "",
      floatingPoint: undefined,
      activeShape: undefined,
      activeShapePointsLatlng: [],
      activeShapePoints: [],
      drawColor: "",
      primitiveArray: [], //primitive的集合
      recordData: {}, //表格行数据
    };
  },
  // 监听isDrawing
  watch: {
    isDrawing(newVal, oldValue) {
      if (newVal && newVal !== oldValue) {
        this.startDraw();
      }
    },
    // 监听recordRowData
    recordRowData: {
      async handler(newValue) {
        this.recordData = newValue;
        // 重绘之前删除之前的
        if (newValue?.isDraw) {
          this.deleteArea(newValue);
        }
        // 在数据改变时执行逻辑
        if (newValue.csys) {
          this.drawColor = await this.hexToRGBA(newValue.csys, 0.3);
        } else {
          this.drawColor = await this.hexToRGBA("#ffffff", 0.3);
        }
      },
      immediate: true,
      deep: true,
    },
    // 监听areaPositionData绘制原有区域
    areaPositionData: {
      handler(newValue, oldvalue) {
        console.log("newValue", newValue);
        // 在数据改变时执行逻辑
        if ( newValue !== oldvalue && newValue !== '' && newValue!==null ) {
          this.drawArea(newValue);
        }
      },
      immediate: true, // 立即执行一次
      deep: true, // 深度监听
    },
  },
  mounted() {
    this.initMap();
    this.registerMouseEvents()
  },
  beforeDestroy() {
    if (this.viewer) {
      this.viewer.destroy();
    }
  },
  methods: {
    initMap(): Promise<Promise<void>> {
      Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1OTNiNTAyYi0yYjMyLTQ1NzMtYmQ5Ni0xMjM1NzgyZDFlNjQiLCJpZCI6MjI1ODY0LCJpYXQiOjE3MTk5MDY2MDZ9.elYgczKeh0tP-JmSb09PDHxcM38TIHbMRNovaYzckpE';
      this.viewer = new Cesium.Viewer("cesiumContainer", {
        animation: false, //左下角的动画仪表盘
        baseLayerPicker: false, //右上角的图层选择按钮
        geocoder: false, //搜索框
        homeButton: false, //home按钮
        sceneModePicker: false, //模式切换按钮
        timeline: false, //底部的时间轴
        navigationHelpButton: false, //右上角的帮助按钮,
        fullscreenButton: false, //右下角的全屏按钮
        selectionIndicator: false, // 去掉聚焦
        infoBox: false,
      });
      this.viewer.scene.skyBox.destroy();
      this.viewer.scene.skyBox = undefined;
      this.viewer.scene.globe.show = false;
      this.viewer.scene.backgroundColor = new Cesium.Color(0.5, 0.5, 0.5, 1);
      this.viewer.scene.globe.baseColor = new Cesium.Color(0.5, 0.5, 0.5, 1);
      this.viewer.scene.debugShowFramesPerSecond = false; //显示帧率
      this.viewer._cesiumWidget._creditContainer.style.display = "none";
      this.viewer.scene.debugShowFramesPerSecond = false; //显示帧率
      this.viewer._cesiumWidget._creditContainer.style.display = "none";
      this.viewer.scene.light = new Cesium.DirectionalLight({
        direction: new Cesium.Cartesian3(0.354925, -0.890918, -0.283358)
      })
      this.createModel(0);
    },
    // 创建模型
    createModel(height) {
      this.viewer.entities.removeAll();
      // 3D笛卡尔点,参数 x、y、z
      const position = Cesium.Cartesian3.fromDegrees(
        106.303956, 32.847126,
        height
      );
      // 将实体添加到集合中
      const entity = this.viewer.entities.add({
        name: "model-factory",
        position: position,
        id: 'model-factory',
        // orientation: orientation, // 设置方向
        model: {
          uri: glbModelUrl, // 获取或设置字符串Property,该字符串指定glTF资产的URI。
          minimumPixelSize: 128, // 获取或设置数字属性,指定近似最小值模型的像素大小,与缩放无关。这可以用来确保即使观看者缩小视图,模型仍然可见。当 0.0 时,没有强制执行最小大小。
          maximumScale: 20000, // 获取或设置数字属性,该属性指定最大比例模型的大小
          zIndex: 1,
          scale: 2.0,
        },
      });
      const origin = entity.position.getValue()
      const heading = Cesium.Math.toRadians(52)
      const pitch = Cesium.Math.toRadians(0)
      const roll = Cesium.Math.toRadians(0)
      const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
      const orientation = Cesium.Transforms.headingPitchRollQuaternion(origin, hpr)
      entity.orientation = orientation
      // this.viewer.trackedEntity = entity; // 聚焦模型
      this.viewer.camera.flyTo({  //106.301116, 32.850026
          destination: Cesium.Cartesian3.fromDegrees(106.306016, 32.850226, 220), // 经纬度以及相机离地高度
          orientation: {
              heading: Cesium.Math.toRadians(200), // 航向角
              pitch: Cesium.Math.toRadians(-25), // 俯仰角
              roll: 0.02 // 距中心的距离,以米为单位
          },
          duration: 0.5 // 飞行时间
      })
    },
    resetModel(){
      const modelEntity = this.viewer.entities.getById('model-factory');
      if (modelEntity) {
        this.viewer.entities.remove(modelEntity);
        this.createModel(0);
      }
    },
    // 颜色hex转rgba
    hexToRGBA(hex, alpha) {
      const r = parseInt(hex.substring(1, 3), 16);
      const g = parseInt(hex.substring(3, 5), 16);
      const b = parseInt(hex.substring(5, 7), 16);
      return "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")";
    },
    createPoint(position) {
      const point = this.viewer.entities.add({
        position: position,
        point: {
          color: Cesium.Color.WHITE,
          outlineColor: Cesium.Color.RED,
          outlineWidth: 0.5,
          pixelSize: 8,
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
          zIndex: 2,
        },
      });
      return point;
    },
    drawGraphic(positionData) {
      // 绘制图形
      let shape = null;
      shape = this.viewer.entities.add({
        polygon: {
          hierarchy: positionData,
          material: new Cesium.ColorMaterialProperty(Cesium.Color.WHITE.withAlpha(0.7)),
        },
      });
      return shape;
    },
    startDraw() {
      this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas);
      const that = this;
      // this.viewer.scene.globe.depthTestAgainstTerrain = true //深度检测
      //鼠标左键
      this.handler.setInputAction(async function (event) {
        //点击获取经纬度坐标
        const earthPosition = that.viewer.scene.pickPosition(event.position);
        if (Cesium.defined(earthPosition)) {
          if (that.activeShapePointsLatlng.length === 0) {
            that.floatingPoint = that.createPoint(earthPosition);
            that.activeShapePointsLatlng.push(earthPosition);
            const dynamicPositions = new Cesium.CallbackProperty(function () {
              return new Cesium.PolygonHierarchy(that.activeShapePointsLatlng);
            }, false);
            //绘制动态图
            that.activeShape = await that.drawGraphic(dynamicPositions);
          }
          that.activeShapePointsLatlng.push(earthPosition);
          that.activeShapePoints.push(that.createPoint(earthPosition));
        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

      //鼠标移动
      that.handler.setInputAction(function (event) {
        if (Cesium.defined(that.floatingPoint)) {
          const newPosition = that.viewer.scene.pickPosition(event.endPosition);
          if (Cesium.defined(newPosition)) {
            that.floatingPoint.position.setValue(newPosition);
            that.activeShapePointsLatlng.pop();
            that.activeShapePointsLatlng.push(newPosition);
          }
        }
      }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

      //鼠标右键移除动态图层
      that.handler.setInputAction(function (event) {
        that.terminateShape(that.activeShapePointsLatlng);
        that.$emit("getClick", that.coordinateList); // 抛出的事件
        that.resetModel();
      }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
      this.registerMouseEvents()
    },
    async terminateShape(dataItem) {
      let that = this;
      let data = dataItem.map((item) => {
        const cartographic = Cesium.Cartographic.fromCartesian(item);
        const x = Cesium.Math.toDegrees(cartographic.longitude);
        const y = Cesium.Math.toDegrees(cartographic.latitude);
        return {
          x,
          y,
        };
      });
      // console.log(data, '转换');
      data.push({ x: data[0].x, y: data[0].y }); // 保持第一个点的坐标和最后一个坐标是一致的
      const list = data.map((item) => {
        return Cesium.Cartesian3.fromDegrees(item.x, item.y);
      });
      // console.log(list, '转换');

      // 创建一个多边形
      let polygon = new Cesium.PolygonGeometry({
        polygonHierarchy: new Cesium.PolygonHierarchy(list),
        extrudedHeight: Number(this.recordData.gd) * 12.5 ?? 15 * 12.5, // 高度为15
      });
      // 创建一个 GeometryInstance
      let geometryInstance = new Cesium.GeometryInstance({
        geometry: polygon,
        id: that.recordData,
      });
      // 设置材质translucent
      const color = Cesium.Color.fromCssColorString(this.drawColor);
      // 创建 Primitive
      that.primitive = new Cesium.Primitive({
        name: this.recordData.id?.name ?? Date.now(),
        geometryInstances: geometryInstance,
        appearance: new Cesium.MaterialAppearance({
          material: new Cesium.Material({
            fabric: {
              type: "Color",
              uniforms: {
                color,
              },
            },
          }),
          translucent: true,
          closed: true,
        }),
      });
      // 将 Primitive 添加到场景中
      that.viewer.scene.primitives.add(that.primitive);
      that.primitiveArray.push(that.primitive);
      that.coordinateList = data; // 存放绘制的图形坐标
      //移除节点
      if (that.activeShapePoints.length) {
        that.activeShapePoints.filter((point) => {
          that.viewer.entities.remove(point);
        });
      }
      this.$emit("drawEnd", list);
      that.viewer.entities.remove(that.floatingPoint); //去除动态点图形(当前鼠标点)
      that.viewer.entities.remove(that.activeShape); //去除动态图形
      that.floatingPoint = undefined;
      that.activeShape = undefined;
      that.activeShapePointsLatlng = [];
      that.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); // 图形绘制完成以后销毁 鼠标点击事件
    },
    // 删除区域
    deleteArea(areaData) {
      try {
        if (this.primitiveArray.length > 0) {
          this.primitiveArray.forEach((e) => {
            // console.log('e', e);
            // console.log('e._insta nceIds', e._instanceIds)
            // console.log('e._instanceIds[0]-id', e._instanceIds[0]['id'])
            if(!e) return;
            // 删除单个区域
            if (e._instanceIds && e._instanceIds.length > 0 && e._instanceIds[0] && e._instanceIds[0]['id'] && e._instanceIds[0]['id'] == areaData.id) {
              !Array.isArray(areaData) && this.viewer.scene.primitives.remove(e);
            } else {
              // 删除全部
              Array.isArray(areaData) && this.viewer.scene.primitives.remove(e);
            }
          });
        }
      } catch (error) {
        console.log(error);
      }
    },
    // 绘制区域
    async drawArea(areaPositionData) {
      const that = this;
      // 清除之前的区域
      that.primitiveArray && that.primitiveArray.length > 0 && await that.deleteArea(areaPositionData);
      // 绘制原有区域
      areaPositionData && areaPositionData.lenth > 0
        areaPositionData.forEach(async (item) => {
          // const fxdj = item.gyfxdj ?? item.kzfxdj ?? 0; // 获取方向
          const fxdjColor = item["csys"]
            ? await this.hexToRGBA(item["csys"], 0.3)
            : "rgb(255, 255, 255, 0)";
          // 判断是否有数据并且格式为[{x: 1, y: 1}]形式
          if (item.wzxx && item.wzxx.length > 0 && !Array.isArray(item.wzxx[0])) {
            let polygon = new Cesium.PolygonGeometry({
              polygonHierarchy: new Cesium.PolygonHierarchy(item.wzxx),
              extrudedHeight: item.height ? Number(item.height) * 12.5 : 15 * 12.5, // 高度为15
            });
            // 创建一个 GeometryInstance
            let geometryInstance = new Cesium.GeometryInstance({
              geometry: polygon,
              id: item,
            });
            // const color = Cesium.Color.fromCssColorString('rgba(255, 0, 0, 0.5)');
            const color = Cesium.Color.fromCssColorString(fxdjColor);
            // 创建 Primitive
            that.primitive = new Cesium.Primitive({
              geometryInstances: geometryInstance,
              appearance: new Cesium.MaterialAppearance({
                translucent: true,
                closed: true,
                material: new Cesium.Material({
                  fabric: {
                    type: "Color",
                    uniforms: {
                      color,
                    },
                  },
                }),
              }),
            });
            // 将 Primitive 添加到场景中
            that.viewer.scene.primitives.add(that.primitive);
            that.primitiveArray.push(that.primitive);
          }
        });
    },
    // 添加弹窗
    registerMouseEvents() {
      const that = this;
      that.handler && that.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
      const infoBox = document.createElement('div');
      infoBox.className = 'infoBox';
      that.viewer.container.appendChild(infoBox);
      // 鼠标左键按下事件
      that.viewer.screenSpaceEventHandler.setInputAction(async function(movement) {
        const pickedObject = that.viewer.scene.pick(movement.endPosition);
        console.log('pickedObject', pickedObject)
        if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id) && Cesium.defined(pickedObject.id) && typeof pickedObject.id === 'object' && typeof pickedObject.id.id === 'string' && pickedObject.id.name!= 'model-factory') {
          // const queryByIdRes = await queryById({id: pickedObject.id});
          const { name = '', fxfqmc = '', fxdj = '', pgsj = ''} = pickedObject?.id;
          const fxfqName = name && name != '' && name != null ? name : (fxfqmc ? fxfqmc : '') ;
          // console.log('fxdj', fxdj,Number(fxdj) - 1, riskLevel[Number(fxdj) - 1],riskLevel[Number(fxdj) - 1]['text'])
          const fxdjName = fxdj && riskLevel[Number(fxdj) - 1] && riskLevel[Number(fxdj) - 1]['text'] ?  riskLevel[Number(fxdj) - 1]['text']  : ''
          // 填充气泡弹窗内容
          infoBox.innerHTML = '名称:' + fxfqName  + '<br>' +
                              '风险等级:' + fxdjName  + '<br>' +
                              '评估时间:' + `${pgsj && pgsj != null && pgsj !=`` ? pgsj : '' }`;

          // 设置气泡弹窗位置
          infoBox.style.position = 'absolute';
          infoBox.style.top = movement.endPosition.y + 'px';
          infoBox.style.left = movement.endPosition.x + 'px';
          infoBox.style.display = 'block';
          // 设置背景色为白色透明度0.4
          infoBox.style.backgroundColor = 'rgba(255, 255, 255, 0.4)';
          // 设置边框样式
          infoBox.style.border = '1px solid #ccc';
          // 设置内边距
          infoBox.style.padding = '10px';
          // 设置字体样式
          infoBox.style.fontFamily = 'Arial, sans-serif';
          // 设置字体大小
          infoBox.style.fontSize = '14px';
          // 设置字体颜色
          infoBox.style.color = '#000';
        } else {
            infoBox.style.display = 'none';
        }
      }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    },
  },
});
</script>
<template>
  <!-- <div id="cesiumContainer" style="width: 100%; height: 100%"></div> -->
  <div id="cesiumContainer" style="width: 1000px; height: 710px;position: relative"></div>
  <div class="infoBox" style="display: none"></div>
</template>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值