src/utils/components/init-map.vue
@@ -27,11 +27,13 @@
    </div>
      <!-- 左下角倍率信息 -->
      <div class="zoom-info">
        <el-tag type="success">倍率: {{ zoomRatio.toFixed(1) }}X</el-tag>
      </div>
    </div>
    <div class="zoom-info">
        <el-tag type="success">倍率: {{ zoomRatio.toFixed(1) }}X</el-tag><br>
        <el-tag type="success">距离: {{ betweenDistance.toFixed(1) }}米</el-tag><br>
        <el-tag type="success">P: {{ cameraP }}&nbsp;&nbsp;T: {{ cameraT }} </el-tag>
    </div>
    
    
    <!-- botton -->
@@ -125,7 +127,7 @@
// let  pois = [0, 0,0] 
let holdingPosition;
let rightKeyMove = false
let  distance = 100;
let  distance = 25;
export default {
  props: {
    towerUrl: {
@@ -133,6 +135,9 @@
      default() {
        return ''
      }
    },
    deviceData: {
      type: Object,
    },
  },
  data(){
@@ -169,11 +174,17 @@
          14: '14X',
          28: '28X',
          56: '56X'
        }
        },
        betweenDistance:0,
        cameraP:0.0,
        cameraT:0.0,
        pointGround: { lon: 0, lat: 0, height: 0 },
        pointFly: { lon: 0, lat: 0, height: 0 },
    }
  },
  mounted(){
     this.initCesium();
     console.log(this.deviceData)
  },
  computed: {
    boxWidth() {
@@ -373,18 +384,41 @@
                //更新键盘事件
                _this.updateCameraMovement();
                //当前选择的id
                chooseId = crypto.randomUUID()
                // chooseId = crypto.randomUUID()
                chooseId = _this.genId()
                //创建视锥体
                let data = {
                    "altitude":  Cesium.Cartographic.fromCartesian(tagert).height,
                    "id": chooseId,
                    'name':`空中点${counter}`,
                    "latitude": Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(tagert).latitude),
                    "longitude":  Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(tagert).longitude),
                }
                const lookPoint = Cesium.Cartesian3.fromDegrees(longitude, latitude)
                const watchPoint = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(tagert).longitude), Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(tagert).latitude))
                const betweenDistanceWatch = Cesium.Cartesian3.distance(lookPoint, watchPoint)
                _this.betweenDistance = betweenDistanceWatch
                console.log(lookPoint)
                console.log(watchPoint)
                // const guanPoint1 = Cesium.Cartesian3.fromDegrees(longitude, latitude)
                console.log(viewerM.entities.getById('groundPoiId0'))
                //塔的距离和观测点的距离
                const point1 = Cesium.Cartesian3.fromDegrees(0, 0, 50);
                console.log(_this.deviceData)
                const point1 = Cesium.Cartesian3.fromDegrees(0, 0, _this.deviceData?.modelHeight || 45);
                _this.pointGround = {
                  lon:longitude,
                  lat:latitude,
                  height:height
                }
                // const point1 = Cesium.Cartesian3.fromDegrees(0, 0, 45);
                const point2 = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(tagert).longitude), Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(tagert).latitude), Cesium.Cartographic.fromCartesian(tagert).height);
                _this.pointFly = {
                  lon:Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(tagert).longitude),
                  lat:Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(tagert).latitude),
                  height:Cesium.Cartographic.fromCartesian(tagert).height
                }
                _this.createDashedLine()
                _this.createBillboard()
                // 计算距离(单位:米)
                const distanceCalculate = Cesium.Cartesian3.distance(point1, point2)
                data.distance = distanceCalculate
@@ -394,8 +428,8 @@
                setTimeout(() => {
                  viewerC.camera.changed.addEventListener(_this.onCameraChange)
                }, 100);
                //左侧树结构联动
                _this.dealTree()
                //结束右键监听
                createPinHandler.destroy();
                //结束主图联动鹰眼监听
@@ -406,6 +440,48 @@
            }
            console.log('右键点击监听已停止');
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);  // 监听右键点击
    },
    createDashedLine() {
      this.lineEntity = viewerM.entities.add({
        polyline: {
          positions: new Cesium.CallbackProperty(() => {
            return Cesium.Cartesian3.fromDegreesArrayHeights([
              this.pointGround.lon, this.pointGround.lat, this.pointGround.height,
              this.pointFly.lon, this.pointFly.lat, this.pointFly.height,
            ]);
          }, false),
          width: 3,
          material: new Cesium.PolylineDashMaterialProperty({
            color: Cesium.Color.RED,
          }),
        },
      });
    },
    createBillboard() {
      // Billboard 中点计算
      viewerM.entities.add({
        position: new Cesium.CallbackProperty(() => {
          const midLon = (this.pointGround.lon + this.pointFly.lon) / 2;
          const midLat = (this.pointGround.lat + this.pointFly.lat) / 2;
          const midHeight = (this.pointGround.height + this.pointFly.height) / 2;
          return Cesium.Cartesian3.fromDegrees(midLon, midLat, midHeight);
        }, false),
        label: {
          text: new Cesium.CallbackProperty(() => {
            return `距离: ${this.betweenDistance.toFixed(1)} m\nP: ${this.cameraP}\nT:${this.cameraT}`;
          }, false),
          font: "16px sans-serif",
          fillColor: Cesium.Color.BLACK,
          outlineColor: Cesium.Color.WHITE,
          outlineWidth: 2,
          style: Cesium.LabelStyle.FILL_AND_OUTLINE,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
          pixelOffset: new Cesium.Cartesian2(0, -20), // 向上偏移
          showBackground: true,
          backgroundColor: new Cesium.Color(1, 1, 1, 0.7),
        },
      });
    },
    azimuthtwopoi(x1, y1, x2, y2) {
      let result;
@@ -502,6 +578,7 @@
      }
    },
    onKeyUp(event) {
      console.log()
      //键盘抬起进行更新左侧空中点pin
      //获取右侧相机
      if(rightKeyMove){
@@ -527,6 +604,25 @@
        } else {
          groupEntity.position = position;
        }
        //计算两个点距离
        console.log(viewerM.entities)
        const groupEntityGround = viewerM.entities.getById("groundPoiId"+(counter-1));
        const groupPosition  = groupEntityGround.position.getValue(Cesium.JulianDate.now());
        if (groupPosition) {
            const cartographic = Cesium.Cartographic.fromCartesian(groupPosition);
            const longitude = Cesium.Math.toDegrees(cartographic.longitude);
            const latitude = Cesium.Math.toDegrees(cartographic.latitude);
            const point1 = Cesium.Cartesian3.fromDegrees(lon, lat);
            const point2 = Cesium.Cartesian3.fromDegrees(longitude, latitude);
            const gure = Cesium.Cartesian3.distance(point1, point2)
            this.betweenDistance  = gure
        }
        this.pointFly = {
          lon: lon,
          lat: lat,
          height: height
        }
        this.dealTree()
      }
      const key = event.key;
      const lower = key.toLowerCase();
@@ -693,6 +789,44 @@
      // Fly back to the initial view (home) in 1 second
      viewerC.camera.flyHome(1.0);
    },
    dealTree(){
      let allEntities = viewerM.entities.values; // 所有实体对象组成的数组
      const grouped = {};
      //所有实体对象组成的数组转换成左侧树需要的格式
      allEntities.forEach(item => {
        const match = item.id.match(/(groundPoiId|aerialPoiId)(\d+)/);
        if (match) {
          const type = match[1]; // groundPoiId or aerialPoiId
          const index = match[2];
          if (!grouped[index]) grouped[index] = {};
          grouped[index][type] = item.position;
        }
      })
      const result = Object.keys(grouped).map((key, idx) => {
        const group = grouped[key];
        const positionGround = group.groundPoiId.getValue(Cesium.JulianDate.now())
        const positionAerialPo = group.aerialPoiId.getValue(Cesium.JulianDate.now())
        const groundPos = Cesium.Cartographic.fromCartesian(positionGround);
        const aerialPos = Cesium.Cartographic.fromCartesian(positionAerialPo);
        return {
          id: this.genId(),
          label: `地面点${idx}`,
          longitude: Cesium.Math.toDegrees(groundPos.longitude),
          latitude: Cesium.Math.toDegrees(groundPos.latitude),
          height: groundPos.height,
          children: [
            {
              id: this.genId(),
              label: `空中点${idx}`,
              longitude: Cesium.Math.toDegrees(aerialPos.longitude),
              latitude: Cesium.Math.toDegrees(aerialPos.latitude),
              height: aerialPos.height
            }
          ]
        };
      });
      this.$emit('dealTreeData',result)
    },
    mergePoint(){
      let allEntities = viewerM.entities.values; // 所有实体对象组成的数组
      const grouped = {};
@@ -826,6 +960,7 @@
        // viewer.scene.primitives.add(cameraVideo);
        let pmObj = {};
        pmObj.id = data.id;
        pmObj.name = data.name;
        pmObj.primitive = cameraVideo;
        viewerM.scene.primitives.add(cameraVideo);
        preVideoScopePrimitiveArrTie.push(pmObj);
@@ -896,7 +1031,7 @@
      const heading = Cesium.Math.toDegrees(camera.heading);
      const pitch = Cesium.Math.toDegrees(camera.pitch);
      const roll = Cesium.Math.toDegrees(camera.roll);
      const point1 = Cesium.Cartesian3.fromDegrees(0, 0, 50);
      const point1 = Cesium.Cartesian3.fromDegrees(0, 0, this.deviceData?.modelHeight || 45);
      const point2 = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(position.longitude),Cesium.Math.toDegrees(position.latitude),position.height)
      
      var camResult =
@@ -916,10 +1051,12 @@
        ',' +
        roll.toFixed(1) +
        '\u00B0';
        console.log(heading)
      this.cameraP = heading.toFixed(2)
      this.cameraT = pitch.toFixed(2)
      document.getElementById('cammoveResultCon').innerHTML = camResult;
      // 计算距离(单位:米)
      const distanceBetween = Cesium.Cartesian3.distance(point1, point2)
      console.log(preVideoScopePrimitiveArrTie)
      preVideoScopePrimitiveArrTie.map((item)=>{
        if(item.id == chooseId){
          let obj = this.updateSZScope(Cesium.Math.toDegrees(position.longitude),Cesium.Math.toDegrees(position.latitude),position.height,heading,pitch,roll,this.zoomRatio,distanceBetween)
@@ -967,6 +1104,58 @@
    },
    onSliderInput(val) {
      this.zoomRatio = val;
    },
    // 计算 heading(偏航角)
    computeHeading(fromCartesian, toCartesian) {
      const transform = Cesium.Transforms.eastNorthUpToFixedFrame(fromCartesian);
      const direction = Cesium.Cartesian3.subtract(
        toCartesian,
        fromCartesian,
        new Cesium.Cartesian3()
      );
      const directionLocal = Cesium.Matrix4.multiplyByPointAsVector(
        Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4()),
        direction,
        new Cesium.Cartesian3()
      );
      Cesium.Cartesian3.normalize(directionLocal, directionLocal);
      return Math.atan2(directionLocal.x, directionLocal.y);
    },
    // 计算 pitch(俯仰角)
    computePitch(fromCartesian, toCartesian) {
      const transform = Cesium.Transforms.eastNorthUpToFixedFrame(fromCartesian);
      const direction = Cesium.Cartesian3.subtract(
        toCartesian,
        fromCartesian,
        new Cesium.Cartesian3()
      );
      const directionLocal = Cesium.Matrix4.multiplyByPointAsVector(
        Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4()),
        direction,
        new Cesium.Cartesian3()
      );
      Cesium.Cartesian3.normalize(directionLocal, directionLocal);
      return Math.asin(directionLocal.z); // z轴向上
    },
    DealVisualCone(data,node){
      if(data.children && data.children?.length > 0) {
        preVideoScopePrimitiveArrTie.map((item)=>{
          if(item.name != data.children[0].label){
            item.primitive.show = false
          }else{
             item.primitive.show = true
          }
        })
      }else {
        preVideoScopePrimitiveArrTie.map((item)=>{
          if(item.name != data.label){
            item.primitive.show = false
          }else {
            item.primitive.show = true
          }
        })
      }
    }
  }
}
@@ -1018,7 +1207,7 @@
}
.moveResult{position:absolute;z-index:2;background-color:rgba(47,53,60,1);padding:0 5px;right:50%;bottom:30px;
    border:1px solid rgba(255,255,255,.1);box-sizing:content-box;width:220px;height:30px;font-size:14px;text-align:center}
.cammoveResult{position:absolute;z-index:2;background-color:rgba(47,53,60,1);padding:0 5px;right:calc(50% - 40px);bottom:30px;
.cammoveResult{position:absolute;z-index:2;background-color:rgba(47,53,60,1);padding:0 5px;right:calc(50% - 140px);bottom:35px;
    border:1px solid rgba(255,255,255,.1);box-sizing:content-box;width:400px;height:30px;font-size:14px;text-align:center}
.moveResultCon{margin-top:4px}
.cammoveResultCon{margin-top:4px;color: white;}
@@ -1107,8 +1296,8 @@
/* 左下角倍率标签 */
.zoom-info {
  position: absolute;
  bottom: 20px;
  left: 20px;
  bottom: 35px;
  left: 340px;
}
</style>