VUE - Cesium 漫游

VUE - Cesium 漫游

cesium 根据输入角度设置中心点(俯仰角度):https://www.cnblogs.com/1285026182YUAN/p/16827154.html

 VUE 中创建测试页面:

<template>
  <div>
    <div class="container">
      <a-button type="primary" @click="drawLineRoad">绘制路线</a-button>
      <a-button type="primary" @click="startFly">开始飞行</a-button>
      <a-button type="primary" @click="stopFly">暂停飞行</a-button>
      <a-button type="primary" @click="continueFly">继续飞行</a-button>
      <a-button type="primary" @click="exitFly">退出飞行</a-button>

      <a-button type="primary" @click="SETP1">测试点</a-button>
      <a-button type="primary" @click="SETP2">角度俯视</a-button>
      <a-button type="primary" @click="SETP3">转换中心点</a-button>
    </div>
    <div id="cesiumContainer"></div>
  </div>
</template>
<script>
// import Cesium from 'cesium/Cesium';
// import 'cesium/Widgets/widgets.css';
export default {
  name: 'CesiumViewer',
  data() {
    return {
      TerrionUrl: '/3D-stk_terrain/rest/realspace/datas/info/data/path',
      viewer: {},
      marks: [
        { lng: 108.9423344082, lat: 34.2609052589, height: 1000, flytime: 5 },
        { lng: 116.812948, lat: 36.550064, height: 1000, flytime: 5 },
        // height:相机高度(单位米) flytime:相机两个标注点飞行时间(单位秒)
        { lng: 116.812948, lat: 36.560064, height: 1000, flytime: 5 },
        { lng: 116.802948, lat: 36.560064, height: 1000, flytime: 5 },
        { lng: 116.802948, lat: 36.550064, height: 1000, flytime: 5 },
      ], //点集
      markHight: 500, //相机高度
      marksIndex: 1, //默认节点
      pitchValue: -20, //俯仰角
      changeCameraTime: 1, //转向时间1秒
      flytime: 5, //飞行时间
      Exection: {},
      handler: {},
      activeShapePoints: [],
      floatingPoint: undefined,
      activeShape: undefined,
      drawingMode: 'line',
      Exection: {},
    };
  },
  mounted() {
    //保证模型初始化

    // const vtxfTerrainProvider = new Cesium.CesiumTerrainProvider({
    //   url: this.TerrionUrl,
    //   requestVertexNormals: true
    // });
    this.viewer = new Cesium.Viewer('cesiumContainer', {
      // scene3DOnly: true,
      // selectionIndicator: false,
      // baseLayerPicker: false,
      // geocoder: false,
      // homeButton: false,
      // sceneModePicker: false,
      // navigationHelpButton: false,
      animation: true,
      timeline: false,
      // fullscreenButton: false,
      // terrainProvider: vtxfTerrainProvider,
      selectionIndicator: false,
      infoBox: false,
      // terrainProvider: Cesium.createWorldTerrain(),
    });

    //加载底图 - BING
    let maptemp = new Cesium.BingMapsImageryProvider({
      url: 'https://dev.virtualearth.net',
      key: 'AijByCeMlw5NWcgLa3RZK61Mx0INwGjcE5InIvNBmMpuwwfMj4_sm5GkXJ_rUHPe',
      mapStyle: Cesium.BingMapsStyle.AERIAL,
    });
    maptemp.tag = 'base';
    this.viewer.imageryLayers.addImageryProvider(maptemp); //加载底图

    //双击鼠标左键清除默认事件
    this.viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
    // this.viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({
    //   url: "/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8",
    // }));

    this.initFly();
  },

  methods: {
    initFly() {
      const { viewer, marks } = this;
      // eslint-disable-next-line no-unused-vars
      const self = this;
      viewer.scene.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(marks[0].lng, marks[0].lat, marks[0].height), //定位坐标点,建议使用谷歌地球坐标位置无偏差
        duration: 1, //定位的时间间隔
      });
      this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
    },
    flyExtent() {
      const { viewer, marks, pitchValue } = this;
      const self = this;

      // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
      const pitch = Cesium.Math.toRadians(pitchValue);
      // 时间间隔2秒钟
      this.setExtentTime(marks[this.marksIndex].flytime);
      this.Exection = function TimeExecution() {
        let preIndex = self.marksIndex - 1;
        if (self.marksIndex == 0) {
          preIndex = marks.length - 1;
        }
        //计算偏航角
        let heading = self.bearing(
          marks[preIndex].lat,
          marks[preIndex].lng,
          marks[self.marksIndex].lat,
          marks[self.marksIndex].lng
        );
        // 当前已经过去的时间,单位s
        const delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime);
        const originLat = self.marksIndex == 0 ? marks[marks.length - 1].lat : marks[self.marksIndex - 1].lat;
        const originLng = self.marksIndex == 0 ? marks[marks.length - 1].lng : marks[self.marksIndex - 1].lng;

        //临时点
        let p = {
          lng: originLng + ((marks[self.marksIndex].lng - originLng) / marks[self.marksIndex].flytime) * delTime,
          lat: originLat + ((marks[self.marksIndex].lat - originLat) / marks[self.marksIndex].flytime) * delTime,
          height: marks[self.marksIndex].height,
        };

        //计算临时点对应的 相机位置
        let objp = self.getCenterLatlng(
          p.lng,
          p.lat,
          heading - 180,
          p.height / Math.tan((-pitchValue * Math.PI) / 180)
        );
        Object.assign(objp, { height: p.height });

        //定位到相机
        viewer.scene.camera.setView({
          destination: Cesium.Cartesian3.fromDegrees(objp.lng, objp.lat, objp.height),
          orientation: {
            heading: Cesium.Math.toRadians(heading),
            pitch: pitch,
          },
        });
        if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) {
          viewer.clock.onTick.removeEventListener(self.Exection);

          if (self.changeCameraTime) {
            //有转向的功能 ,传入相机当前位置
            self.changeCameraHeading(objp);
          } else {
            //无转向功能
            self.marksIndex++;
            self.flyExtent();
          }
        }
      };
      viewer.clock.onTick.addEventListener(self.Exection);
    },

    // 相机原地定点转向,objStart :相机当前位置
    changeCameraHeading(objStart) {
      const { viewer, marks, pitchValue, changeCameraTime } = this;
      const self = this;
      let { marksIndex } = this;

      let nextIndex = this.marksIndex + 1;
      if (marksIndex == marks.length - 1) {
        // nextIndex = 0;
        return;
      }
      // 计算两点之间的方向
      const heading = this.bearing(
        marks[marksIndex].lat,
        marks[marksIndex].lng,
        marks[nextIndex].lat,
        marks[nextIndex].lng
      );
      // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
      const pitch = Cesium.Math.toRadians(pitchValue);

      //记录当前点
      let p = marks[marksIndex];

      //计算最终相机位置
      let objEnd = self.getCenterLatlng(
        p.lng,
        p.lat,
        heading - 180,
        p.height / Math.tan((-pitchValue * Math.PI) / 180)
      );

      // 给定飞行一周所需时间,比如10s, 那么每秒转动度数
      const angle = (heading - Cesium.Math.toDegrees(viewer.camera.heading)) / changeCameraTime;
      // 时间间隔2秒钟
      this.setExtentTime(changeCameraTime);
      // 相机的当前heading
      const initialHeading = viewer.camera.heading;
      this.Exection = function TimeExecution() {
        // 当前已经过去的时间,单位s

        const delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime);

        //记算临时偏航角
        let heading = Cesium.Math.toRadians(delTime * angle) + initialHeading;

        //临时点,折角过大时有盲区
        let ptemp = {
          lng: objStart.lng + ((objEnd.lng - objStart.lng) / changeCameraTime) * delTime,
          lat: objStart.lat + ((objEnd.lat - objStart.lat) / changeCameraTime) * delTime,
          height: p.height,
        };

        //待测试,解决折角过大时盲区问题
        // let oob1 = Cesium.Cartesian3.fromDegrees(objStart.lng, objStart.lat, objStart.height);
        // let oob2 = Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.height);
        // let distance = Cesium.Cartesian3.distance(oob1, oob2);
        // let _roll = Cesium.Math.toRadians(0);
        // let ptemp = self.supply_getpointend(oob1, heading, pitch, _roll, distance);

        // //描绘中心点2,路径点记录,测试用
        // self.viewer.entities.add({
        //   position: Cesium.Cartesian3.fromDegrees(ptemp.lng, ptemp.lat),
        //   point: {
        //     color: Cesium.Color.YELLOW,
        //     pixelSize: 10,
        //     heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
        //     disableDepthTestDistance: Number.POSITIVE_INFINITY,
        //   },
        // });

        //定位到相机
        viewer.scene.camera.setView({
          destination: Cesium.Cartesian3.fromDegrees(ptemp.lng, ptemp.lat, ptemp.height),
          orientation: {
            heading: heading,
            pitch: pitch,
          },
        });

        if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) {
          viewer.clock.onTick.removeEventListener(self.Exection);
          self.marksIndex = ++self.marksIndex >= marks.length ? 0 : self.marksIndex;
          if (self.marksIndex != 0) {
            self.flyExtent();
          }
        }
      };
      viewer.clock.onTick.addEventListener(self.Exection);
    },

    // 设置飞行的时间到viewer的时钟里
    setExtentTime(time) {
      const { viewer } = this;
      const startTime = Cesium.JulianDate.fromDate(new Date());
      const stopTime = Cesium.JulianDate.addSeconds(startTime, time, new Cesium.JulianDate());
      viewer.clock.startTime = startTime.clone(); // 开始时间
      viewer.clock.stopTime = stopTime.clone(); // 结速时间
      viewer.clock.currentTime = startTime.clone(); // 当前时间
      viewer.clock.clockRange = Cesium.ClockRange.CLAMPED; // 行为方式-达到终止时间后停止
      viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK; // 时钟设置为当前系统时间; 忽略所有其他设置。
    },
    /** 相机视角飞行 结束 **/
    /** 飞行时 camera的方向调整(heading) 开始 **/
    // 角度转弧度
    toRadians(degrees) {
      return (degrees * Math.PI) / 180;
    },
    // 弧度转角度
    toDegrees(radians) {
      return (radians * 180) / Math.PI;
    },
    //计算偏航角
    bearing(startLat, startLng, destLat, destLng) {
      startLat = this.toRadians(startLat);
      startLng = this.toRadians(startLng);
      destLat = this.toRadians(destLat);
      destLng = this.toRadians(destLng);

      let y = Math.sin(destLng - startLng) * Math.cos(destLat);
      let x =
        Math.cos(startLat) * Math.sin(destLat) - Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng);
      let brng = Math.atan2(y, x);
      let brngDgr = this.toDegrees(brng);

      return (brngDgr + 360) % 360;
    },
    /** 飞行时 camera的方向调整(heading) 结束 **/
    /**绘制路线 */
    drawLineRoad() {
      const { handler, viewer, activeShapePoints } = this;
      const self = this;
      //鼠标左键
      handler.setInputAction(function (event) {
        var earthPosition = viewer.scene.pickPosition(event.position);
        if (Cesium.defined(earthPosition)) {
          if (activeShapePoints.length === 0) {
            self.floatingPoint = self.createPoint(earthPosition);
            activeShapePoints.push(earthPosition);
            var dynamicPositions = new Cesium.CallbackProperty(function () {
              return activeShapePoints;
            }, false);
            self.activeShape = self.drawShape(dynamicPositions); //绘制动态图
          }
          activeShapePoints.push(earthPosition);
          self.createPoint(earthPosition);
        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
      //鼠标移动
      handler.setInputAction(function (event) {
        if (Cesium.defined(self.floatingPoint)) {
          var newPosition = viewer.scene.pickPosition(event.endPosition);
          if (Cesium.defined(newPosition)) {
            self.floatingPoint.position.setValue(newPosition);
            activeShapePoints.pop();
            activeShapePoints.push(newPosition);
          }
        }
      }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
      handler.setInputAction(function () {
        self.terminateShape();
      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    },
    // Redraw the shape so it's not dynamic and remove the dynamic shape.
    terminateShape() {
      const { activeShapePoints, viewer, flytime } = this;
      activeShapePoints.pop(); //去除最后一个动态点
      if (activeShapePoints.length) {
        this.marks = [];
        for (const position of activeShapePoints) {
          const latitude = this.toDegrees(Cesium.Cartographic.fromCartesian(position).latitude);
          const longitude = this.toDegrees(Cesium.Cartographic.fromCartesian(position).longitude);
          this.marks.push({ lat: latitude, lng: longitude, flytime, height: this.markHight });
        }
        this.drawShape(activeShapePoints); //绘制最终图
      }
      viewer.entities.remove(this.floatingPoint); //去除动态点图形(当前鼠标点)
      viewer.entities.remove(this.activeShape); //去除动态图形
      this.floatingPoint = undefined;
      this.activeShape = undefined;
      this.activeShapePoints = [];
    },
    //绘制点
    createPoint(worldPosition) {
      var point = this.viewer.entities.add({
        position: worldPosition,
        point: {
          color: Cesium.Color.RED,
          pixelSize: 10,
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
      });
      return point;
    },
    //初始化为线
    drawShape(positionData) {
      const { drawingMode, viewer } = this;
      var shape;
      if (drawingMode === 'line') {
        shape = viewer.entities.add({
          polyline: {
            positions: positionData,
            clampToGround: true,
            width: 3,
            material: Cesium.Color.CHARTREUSE,
          },
        });
      }
      return shape;
    },
    //开始飞行
    startFly() {
      const { Exection } = this;
      if (Object.keys(Exection).length > 0) {
        this.exitFly();
      }
      this.flyExtent();
    },
    //停止飞行
    stopFly() {
      this.viewer.clock.shouldAnimate = false;
    },
    //继续飞行
    continueFly() {
      this.viewer.clock.shouldAnimate = true;
    },
    //退出飞行
    exitFly() {
      const { Exection, viewer, marks, pitchValue } = this;
      viewer.clock.onTick.removeEventListener(Exection);
      // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
      const pitch = Cesium.Math.toRadians(pitchValue);
      const marksIndex = 1;
      let preIndex = marksIndex - 1;
      //计算偏航角
      let heading = this.bearing(
        marks[preIndex].lat,
        marks[preIndex].lng,
        marks[marksIndex].lat,
        marks[marksIndex].lng
      );
      heading = Cesium.Math.toRadians(heading);
      const endPosition = Cesium.Cartesian3.fromDegrees(marks[0].lng, marks[0].lat, marks[0].height);
      viewer.scene.camera.setView({
        destination: endPosition,
        orientation: {
          heading: heading,
          pitch: pitch,
        },
      });
    },

    //测试点
    SETP1() {
      const { viewer } = this;

      let p = { lng: 108.9423344082, lat: 34.2609052589 }; //测试点
      let h = 1000; //高度

      //描绘点
      var point = this.viewer.entities.add({
        position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat),
        point: {
          color: Cesium.Color.RED,
          pixelSize: 10,
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
      });

      viewer.scene.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, h),
        orientation: {
          heading: Cesium.Math.toRadians(-120),
          pitch: Cesium.Math.toRadians(-90),
        },
      });
    },

    //测试点-俯视
    SETP2() {
      const { viewer } = this;

      let p = { lng: 108.9423344082, lat: 34.2609052589 }; //测试点
      let h = 1000; //高度

      viewer.scene.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, h),
        orientation: {
          heading: Cesium.Math.toRadians(-120),
          pitch: Cesium.Math.toRadians(-20),
        },
      });
    },

    // 转换中心点
    SETP3() {
      const { viewer } = this;
      let p = { lng: 108.9423344082, lat: 34.2609052589 }; //测试点
      let h = 1000; //高度

      let angle = 20; //俯视角度,默认90°,可手动更改
      let brng = -300; //heading -180
      let obj = this.getCenterLatlng(p.lng, p.lat, brng, h / Math.tan((angle * Math.PI) / 180));

      //描绘中心点2
      var point = this.viewer.entities.add({
        position: Cesium.Cartesian3.fromDegrees(obj.lng, obj.lat),
        point: {
          color: Cesium.Color.YELLOW,
          pixelSize: 10,
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
      });

      viewer.scene.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(obj.lng, obj.lat, h),
        orientation: {
          heading: Cesium.Math.toRadians(-120),
          pitch: Cesium.Math.toRadians(-20),
        },
      });
    },

    //参数 lng、lat为90俯视时的中心,bring为 heading 角度,取反方向,dist

    getCenterLatlng(lng, lat, brng, dist) {
      var a = 6378137;
      var b = 6356752.3142;
      var f = 1 / 298.257223563;

      var lon1 = lng * 1;
      var lat1 = lat * 1;
      var s = dist;
      var alpha1 = brng * (Math.PI / 180);
      var sinAlpha1 = Math.sin(alpha1);
      var cosAlpha1 = Math.cos(alpha1);
      var tanU1 = (1 - f) * Math.tan(lat1 * (Math.PI / 180));
      var cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1),
        sinU1 = tanU1 * cosU1;
      var sigma1 = Math.atan2(tanU1, cosAlpha1);
      var sinAlpha = cosU1 * sinAlpha1;
      var cosSqAlpha = 1 - sinAlpha * sinAlpha;
      var uSq = (cosSqAlpha * (a * a - b * b)) / (b * b);
      var A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
      var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
      var sigma = s / (b * A),
        sigmaP = 2 * Math.PI;
      while (Math.abs(sigma - sigmaP) > 1e-12) {
        var cos2SigmaM = Math.cos(2 * sigma1 + sigma);
        var sinSigma = Math.sin(sigma);
        var cosSigma = Math.cos(sigma);
        var deltaSigma =
          B *
          sinSigma *
          (cos2SigmaM +
            (B / 4) *
              (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
                (B / 6) * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
        sigmaP = sigma;
        sigma = s / (b * A) + deltaSigma;
      }

      var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
      var lat2 = Math.atan2(
        sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
        (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp)
      );
      var lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
      var C = (f / 16) * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
      var L =
        lambda -
        (1 - C) *
          f *
          sinAlpha *
          (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));

      var revAz = Math.atan2(sinAlpha, -tmp); // final bearing

      var lngLatObj = { lng: lon1 + L * (180 / Math.PI), lat: lat2 * (180 / Math.PI) };
      return lngLatObj;
    },

    supply_getpointend(position, heading, pitch, roll, distance) {
      var m2 = Cesium.Transforms.eastNorthUpToFixedFrame(position); //m1为局部坐标的z轴垂直于地表,局部坐标的y轴指向正北的4x4变换矩阵

      var X = Cesium.Matrix4.fromRotation(
        Cesium.Matrix3.fromRotationX(heading, new Cesium.Matrix3()),
        new Cesium.Matrix4()
      );
      var Y = Cesium.Matrix4.fromRotation(
        Cesium.Matrix3.fromRotationY(pitch, new Cesium.Matrix3()),
        new Cesium.Matrix4()
      );
      var Z = Cesium.Matrix4.fromRotation(
        Cesium.Matrix3.fromRotationZ(roll, new Cesium.Matrix3()),
        new Cesium.Matrix4()
      );

      var ROT1 = Cesium.Matrix4.multiply(Y, X, new Cesium.Matrix4());
      var ROT = Cesium.Matrix4.multiply(Z, ROT1, new Cesium.Matrix4());
      var m4 = Cesium.Matrix4.multiply(m2, ROT, new Cesium.Matrix4());
      var vZ = new Cesium.Cartesian3(1, 0, 0);
      var vZ = Cesium.Cartesian3.normalize(vZ, new Cesium.Cartesian3());
      var vZ = Cesium.Cartesian3.multiplyByScalar(vZ, distance, new Cesium.Cartesian3());
      var mpoint1 = Cesium.Matrix4.multiplyByPoint(m4, vZ, new Cesium.Cartesian3());

      return mpoint1;
    },
  },
  created() {},
};
</script>
<style scoped>
.container {
  position: absolute;
  z-index: 9999;
}
</style>

  

测试结果:

 

 

 

整理成类后:

class CesiumUtilRoam {
  constructor(_marks) {
    this.marks = _marks; //点集
    //   [
    //     // height:相机高度(单位米) flytime:相机两个标注点飞行时间(单位秒)
    //     { lng: 108.9423344082, lat: 34.2609052589, height: 1000, flytime: 5 },
    //     { lng: 116.812948, lat: 36.550064, height: 1000, flytime: 5 },
    //     { lng: 116.812948, lat: 36.560064, height: 1000, flytime: 5 },
    //     { lng: 116.802948, lat: 36.560064, height: 1000, flytime: 5 },
    //     { lng: 116.802948, lat: 36.550064, height: 1000, flytime: 5 },
    //   ];
    this.markHight = 500; //相机高度
    this.marksIndex = 1; //默认节点
    this.pitchValue = -20; //俯仰角
    this.changeCameraTime = 0; //转向时间1秒
    this.flytime = 5; //飞行时间
    this.Exection = {};
    this.activeShapePoints = [];
    this.floatingPoint = undefined;
    this.activeShape = undefined;
    this.drawingMode = 'line';
    this.x = 100;
    this.handler = new Cesium.ScreenSpaceEventHandler(window.viewer.canvas);

    viewer.scene.camera.flyTo({
      destination: Cesium.Cartesian3.fromDegrees(this.marks[0].lng, this.marks[0].lat, this.marks[0].height), //定位坐标点,建议使用谷歌地球坐标位置无偏差
      duration: 1, //定位的时间间隔
    });
  }

  /** 飞行时 camera的方向调整(heading) 结束 **/
  /**绘制路线 */
  drawLineRoad = () => {
    let self = this;

    //鼠标左键
    this.handler.setInputAction(function (event) {
      var earthPosition = viewer.scene.pickPosition(event.position);
      if (Cesium.defined(earthPosition)) {
        if (self.activeShapePoints.length === 0) {
          self.floatingPoint = createPoint(earthPosition);
          self.activeShapePoints.push(earthPosition);
          var dynamicPositions = new Cesium.CallbackProperty(function () {
            return self.activeShapePoints;
          }, false);
          self.activeShape = drawShape(dynamicPositions); //绘制动态图
        }
        self.activeShapePoints.push(earthPosition);

        createPoint(earthPosition);
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    //鼠标移动
    this.handler.setInputAction(function (event) {
      if (Cesium.defined(self.floatingPoint)) {
        var newPosition = viewer.scene.pickPosition(event.endPosition);
        if (Cesium.defined(newPosition)) {
          self.floatingPoint.position.setValue(newPosition);
          self.activeShapePoints.pop();
          self.activeShapePoints.push(newPosition);
        }
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    this.handler.setInputAction(function () {
      self.terminateShape();
      debugger;

    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  };

  terminateShape = () => {
    this.activeShapePoints.pop(); //去除最后一个动态点
    if (this.activeShapePoints.length) {
      this.marks = [];
      for (const position of this.activeShapePoints) {
        const latitude = toDegrees(Cesium.Cartographic.fromCartesian(position).latitude);
        const longitude = toDegrees(Cesium.Cartographic.fromCartesian(position).longitude);
        this.marks.push({ lat: latitude, lng: longitude, flytime: this.flytime, height: this.markHight });
      }
      drawShape(this.activeShapePoints); //绘制最终图
    }
    viewer.entities.remove(this.floatingPoint); //去除动态点图形(当前鼠标点)
    viewer.entities.remove(this.activeShape); //去除动态图形
    this.floatingPoint = undefined;
    this.activeShape = undefined;
    this.activeShapePoints = [];
  };

  //停止飞行
  stopFly = () => {
    viewer.clock.shouldAnimate = false;
  };
  //继续飞行
  continueFly = () => {
    viewer.clock.shouldAnimate = true;
  };

  //退出飞行
  exitFly = () => {
    let marks = this.marks;

    viewer.clock.onTick.removeEventListener(this.Exection);
    // // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
    // const pitch = Cesium.Math.toRadians(this.pitchValue);
    // const marksIndex = 1;
    // let preIndex = marksIndex - 1;
    // //计算偏航角
    // let heading = bearing(marks[preIndex].lat, marks[preIndex].lng, marks[marksIndex].lat, marks[marksIndex].lng);
    // heading = Cesium.Math.toRadians(heading);
    // const endPosition = Cesium.Cartesian3.fromDegrees(marks[0].lng, marks[0].lat, marks[0].height);
    // viewer.scene.camera.setView({
    //   destination: endPosition,
    //   orientation: {
    //     heading: heading,
    //     pitch: pitch,
    //   },
    // });
  };

  //开始飞行
  startFly = () => {
    // drawMarkstest(this.marks);

    if (Object.keys(this.Exection).length > 0) {
      this.exitFly();
    }
    this.flyExtent();
  };

  flyExtent = () => {
    let marks = this.marks;
    let pitchValue = this.pitchValue;
    let marksIndex = this.marksIndex;

    let self = this;

    // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
    const pitch = Cesium.Math.toRadians(pitchValue);
    // 时间间隔2秒钟

    setExtentTime(marks[marksIndex].flytime);
    this.Exection = function TimeExecution() {
      let preIndex = marksIndex - 1;
      if (marksIndex == 0) {
        preIndex = marks.length - 1;
      }
      //计算偏航角
      let heading = bearing(marks[preIndex].lat, marks[preIndex].lng, marks[marksIndex].lat, marks[marksIndex].lng);
      // 当前已经过去的时间,单位s
      const delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime);
      const originLat = marksIndex == 0 ? marks[marks.length - 1].lat : marks[marksIndex - 1].lat;
      const originLng = marksIndex == 0 ? marks[marks.length - 1].lng : marks[marksIndex - 1].lng;

      //临时点
      let p = {
        lng: originLng + ((marks[marksIndex].lng - originLng) / marks[marksIndex].flytime) * delTime,
        lat: originLat + ((marks[marksIndex].lat - originLat) / marks[marksIndex].flytime) * delTime,
        height: marks[marksIndex].height,
      };

      //计算临时点对应的 相机位置
      let objp = getCenterLatlng(p.lng, p.lat, heading - 180, p.height / Math.tan((-pitchValue * Math.PI) / 180));
      Object.assign(objp, { height: p.height });

      //定位到相机
      viewer.scene.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(objp.lng, objp.lat, objp.height),
        orientation: {
          heading: Cesium.Math.toRadians(heading),
          pitch: pitch,
        },
      });
      if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) {
        viewer.clock.onTick.removeEventListener(self.Exection);

        if (self.changeCameraTime) {
          //有转向的功能 ,传入相机当前位置
          self.changeCameraHeading(objp);
        } else {
          //无转向功能
          self.marksIndex++;
          self.flyExtent();
        }
      }
    };
    viewer.clock.onTick.addEventListener(this.Exection);
  };

  // 相机原地定点转向,objStart :相机当前位置
  changeCameraHeading = (objStart) => {
    let marks = this.marks;
    let pitchValue = this.pitchValue;
    let changeCameraTime = this.changeCameraTime;
    let marksIndex = this.marksIndex;

    let self = this;

    let nextIndex = this.marksIndex + 1;
    if (marksIndex == marks.length - 1) {
      // nextIndex = 0;
      return;
    }
    // 计算两点之间的方向
    const heading = bearing(marks[marksIndex].lat, marks[marksIndex].lng, marks[nextIndex].lat, marks[nextIndex].lng);
    // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
    const pitch = Cesium.Math.toRadians(pitchValue);

    //记录当前点
    let p = marks[marksIndex];

    //计算最终相机位置
    let objEnd = getCenterLatlng(p.lng, p.lat, heading - 180, p.height / Math.tan((-pitchValue * Math.PI) / 180));

    // 给定飞行一周所需时间,比如10s, 那么每秒转动度数
    const angle = (heading - Cesium.Math.toDegrees(viewer.camera.heading)) / changeCameraTime;
    // 时间间隔2秒钟
    setExtentTime(changeCameraTime);
    // 相机的当前heading
    const initialHeading = viewer.camera.heading;
    this.Exection = function TimeExecution() {
      // 当前已经过去的时间,单位s

      const delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime);

      //记算临时偏航角
      let heading = Cesium.Math.toRadians(delTime * angle) + initialHeading;

      //临时点,折角过大时有盲区
      let ptemp = {
        lng: objStart.lng + ((objEnd.lng - objStart.lng) / changeCameraTime) * delTime,
        lat: objStart.lat + ((objEnd.lat - objStart.lat) / changeCameraTime) * delTime,
        height: p.height,
      };

      //待测试,解决折角过大时盲区问题
      // let oob1 = Cesium.Cartesian3.fromDegrees(objStart.lng, objStart.lat, objStart.height);
      // let oob2 = Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.height);
      // let distance = Cesium.Cartesian3.distance(oob1, oob2);
      // let _roll = Cesium.Math.toRadians(0);
      // let ptemp = supply_getpointend(oob1, heading, pitch, _roll, distance);

      // //描绘中心点2,路径点记录,测试用
      // viewer.entities.add({
      //   position: Cesium.Cartesian3.fromDegrees(ptemp.lng, ptemp.lat),
      //   point: {
      //     color: Cesium.Color.YELLOW,
      //     pixelSize: 10,
      //     heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      //     disableDepthTestDistance: Number.POSITIVE_INFINITY,
      //   },
      // });

      //定位到相机
      viewer.scene.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(ptemp.lng, ptemp.lat, ptemp.height),
        orientation: {
          heading: heading,
          pitch: pitch,
        },
      });

      if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) {
        viewer.clock.onTick.removeEventListener(self.Exection);
        self.marksIndex = ++self.marksIndex >= marks.length ? 0 : self.marksIndex;
        if (self.marksIndex != 0) {
          self.flyExtent();
        }
      }
    };
    viewer.clock.onTick.addEventListener(this.Exection);
  };

  name = (params) => {
    let xx = this.x;
    xx = 3;
    console.log('xx-----' + xx);
    this.x = 500;
    console.log(params + '-----' + this.x);
  };
}

let drawMarkstest = (_marks) => {
  debugger;
  let _acsp = [];
  _marks.forEach((t) => {
    var earthPosition = Cesium.Cartesian3.fromDegrees(t.lng, t.lat, t.height);
    createPoint(earthPosition);

    _acsp.push(earthPosition);
  });

  let dynamicPositionss = new Cesium.CallbackProperty(function () {
    return _acsp;
  }, false);

  drawShape(dynamicPositionss);
};

// 设置飞行的时间到viewer的时钟里
let setExtentTime = (time) => {
  let startTime = Cesium.JulianDate.fromDate(new Date());
  let stopTime = Cesium.JulianDate.addSeconds(startTime, time, new Cesium.JulianDate());
  viewer.clock.startTime = startTime.clone(); // 开始时间
  viewer.clock.stopTime = stopTime.clone(); // 结速时间
  viewer.clock.currentTime = startTime.clone(); // 当前时间
  viewer.clock.clockRange = Cesium.ClockRange.CLAMPED; // 行为方式-达到终止时间后停止
  viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK; // 时钟设置为当前系统时间; 忽略所有其他设置。
};

//计算偏航角
let bearing = (startLat, startLng, destLat, destLng) => {
  startLat = toRadians(startLat);

  startLng = toRadians(startLng);
  destLat = toRadians(destLat);
  destLng = toRadians(destLng);

  let y = Math.sin(destLng - startLng) * Math.cos(destLat);
  let x =
    Math.cos(startLat) * Math.sin(destLat) - Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng);
  let brng = Math.atan2(y, x);
  let brngDgr = toDegrees(brng);

  return (brngDgr + 360) % 360;
};

/** 相机视角飞行 结束 **/
/** 飞行时 camera的方向调整(heading) 开始 **/
// 角度转弧度
let toRadians = (degrees) => {
  return (degrees * Math.PI) / 180;
};
// 弧度转角度
let toDegrees = (radians) => {
  return (radians * 180) / Math.PI;
};

//参数 lng、lat为90俯视时的中心,bring为 heading 角度,取反方向,dist

let getCenterLatlng = (lng, lat, brng, dist) => {
  var a = 6378137;
  var b = 6356752.3142;
  var f = 1 / 298.257223563;

  var lon1 = lng * 1;
  var lat1 = lat * 1;
  var s = dist;
  var alpha1 = brng * (Math.PI / 180);
  var sinAlpha1 = Math.sin(alpha1);
  var cosAlpha1 = Math.cos(alpha1);
  var tanU1 = (1 - f) * Math.tan(lat1 * (Math.PI / 180));
  var cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1),
    sinU1 = tanU1 * cosU1;
  var sigma1 = Math.atan2(tanU1, cosAlpha1);
  var sinAlpha = cosU1 * sinAlpha1;
  var cosSqAlpha = 1 - sinAlpha * sinAlpha;
  var uSq = (cosSqAlpha * (a * a - b * b)) / (b * b);
  var A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
  var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
  var sigma = s / (b * A),
    sigmaP = 2 * Math.PI;
  while (Math.abs(sigma - sigmaP) > 1e-12) {
    var cos2SigmaM = Math.cos(2 * sigma1 + sigma);
    var sinSigma = Math.sin(sigma);
    var cosSigma = Math.cos(sigma);
    var deltaSigma =
      B *
      sinSigma *
      (cos2SigmaM +
        (B / 4) *
          (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
            (B / 6) * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
    sigmaP = sigma;
    sigma = s / (b * A) + deltaSigma;
  }

  var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
  var lat2 = Math.atan2(
    sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
    (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp)
  );
  var lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
  var C = (f / 16) * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
  var L =
    lambda -
    (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));

  var revAz = Math.atan2(sinAlpha, -tmp); // final bearing

  var lngLatObj = { lng: lon1 + L * (180 / Math.PI), lat: lat2 * (180 / Math.PI) };
  return lngLatObj;
};

//绘制点
let createPoint = (worldPosition) => {
  var point = viewer.entities.add({
    position: worldPosition,
    point: {
      color: Cesium.Color.RED,
      pixelSize: 10,
      // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 页面会报错,An error occurred while rendering , rendering has stopped
      // disableDepthTestDistance: Number.POSITIVE_INFINITY,
    },
  });
  return point;
};

//初始化为线
let drawShape = (positionData) => {
  var shape = viewer.entities.add({
    polyline: {
      positions: positionData,
      clampToGround: true,
      width: 3,
      material: Cesium.Color.CHARTREUSE,
    },
  });

  return shape;
};

let supply_getpointend = (position, heading, pitch, roll, distance) => {
  var m2 = Cesium.Transforms.eastNorthUpToFixedFrame(position); //m1为局部坐标的z轴垂直于地表,局部坐标的y轴指向正北的4x4变换矩阵

  var X = Cesium.Matrix4.fromRotation(
    Cesium.Matrix3.fromRotationX(heading, new Cesium.Matrix3()),
    new Cesium.Matrix4()
  );
  var Y = Cesium.Matrix4.fromRotation(Cesium.Matrix3.fromRotationY(pitch, new Cesium.Matrix3()), new Cesium.Matrix4());
  var Z = Cesium.Matrix4.fromRotation(Cesium.Matrix3.fromRotationZ(roll, new Cesium.Matrix3()), new Cesium.Matrix4());

  var ROT1 = Cesium.Matrix4.multiply(Y, X, new Cesium.Matrix4());
  var ROT = Cesium.Matrix4.multiply(Z, ROT1, new Cesium.Matrix4());
  var m4 = Cesium.Matrix4.multiply(m2, ROT, new Cesium.Matrix4());
  var vZ = new Cesium.Cartesian3(1, 0, 0);
  var vZ = Cesium.Cartesian3.normalize(vZ, new Cesium.Cartesian3());
  var vZ = Cesium.Cartesian3.multiplyByScalar(vZ, distance, new Cesium.Cartesian3());
  var mpoint1 = Cesium.Matrix4.multiplyByPoint(m4, vZ, new Cesium.Cartesian3());

  return mpoint1;
};

export default CesiumUtilRoam;

 

 

 

 调用方式 :

      <a-tooltip placement="bottom">
        <template slot="title">
          <span>漫游</span>
        </template>
        <div class="svgbox" @click="toggleRoam">
          <roam-svg :color="isRoam ? 'orange' : 'grey'" alt="light" />
        </div>
      </a-tooltip>


   <div class="tbox" style="margin-left: 50px">
      <a-button type="primary" @click="flyDraw">绘制</a-button>
      <a-button type="primary" @click="flyStart">开始</a-button>
      <a-button type="primary" @click="flyStop">暂停</a-button>
      <a-button type="primary" @click="flyContinue">继续</a-button>
      <a-button type="primary" @click="flyExit"> 停止</a-button>
    </div>

 

 

<script>
import RoamSvg from '@/assets/icons/tool/roam.svg?inline';
import CesiumUtilRoam from './utils/cesiumUtilRoam';
var _cesiumUtilRoam = null;
export default {
  components: { RoamSvg  },
  data() {
    return {
      isRoam: false,
    };
  },   
  methods: { 
    toggleRoam() {
      this.isRoam = !this.isRoam;
      let marks = [
        { lng: 108.9423344082, lat: 34.2609052589, height: 1000, flytime: 5 },
        { lng: 116.812948, lat: 36.550064, height: 1000, flytime: 5 },
        { lng: 116.812948, lat: 36.560064, height: 1000, flytime: 5 },
        { lng: 116.802948, lat: 36.560064, height: 1000, flytime: 5 },
        { lng: 116.802948, lat: 36.550064, height: 1000, flytime: 5 },
      ];
      if (this.isRoam) {
        _cesiumUtilRoam = new CesiumUtilRoam(marks);
      } else {
        _cesiumUtilRoam = null;
      }
    },

    flyDraw() {
      if (_cesiumUtilRoam) _cesiumUtilRoam.drawLineRoad();
    },

    flyStart() {
      if (_cesiumUtilRoam) _cesiumUtilRoam.startFly();
    },

    flyStop() {
      if (_cesiumUtilRoam) _cesiumUtilRoam.stopFly();
    },
    flyContinue() {
      if (_cesiumUtilRoam) _cesiumUtilRoam.continueFly();
    },
    flyExit() {
      if (_cesiumUtilRoam) _cesiumUtilRoam.exitFly();
    },
  },
};
</script>

 

 

 结果同上。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

参考:https://www.cnblogs.com/1285026182YUAN/p/16827154.html

 

posted @ 2022-10-25 16:18  无心々菜  阅读(1276)  评论(0编辑  收藏  举报