Cesium 轨迹巡航效果

2,536 阅读16分钟

Cesium 轨迹巡航效果

话不多说,先上图!

Jietu20250519-101743-HD.gif

在这篇文章中,我将分享如何使用 Cesium 实现一个动态的无人机巡航轨迹效果。通过该功能,我们可以模拟无人机沿着指定路径飞行,并实时展示其位置、速度、高度等信息。以下是功能的详细介绍和实现过程。

实现思路

  1. 路径绘制

  2. 动态飞行

  3. 状态更新

    • 在飞行过程中,通过 Cesium 的 JulianDate 和 Cartesian3 获取无人机的实时位置。
    • 计算无人机的速度、高度、飞行距离等信息,并通过回调函数实时更新。

核心代码

以下是实现无人机巡航轨迹的核心代码片段:

1. 路径绘制
const positions = [];
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

// 鼠标左键点击添加路径点
handler.setInputAction(function (movement) {
  const cartesian = viewer.scene.pickPosition(movement.position);
  if (cartesian) {
    positions.push(cartesian);
    if (positions.length >= 2) {
      drawPolyline(positions);
    }
  }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

// 绘制路径
function drawPolyline(positions) {
  viewer.entities.add({
    polyline: {
      positions: new Cesium.CallbackProperty(() => positions, false),
      material: new Cesium.PolylineGlowMaterialProperty({
        glowPower: 0.1,
        color: Cesium.Color.YELLOW
      }),
      width: 10,
      clampToGround: true
    }
  });
}
2. 动态飞行
const sampledPosition = new Cesium.SampledPositionProperty();
const start = Cesium.JulianDate.fromDate(new Date());
const stop = Cesium.JulianDate.addSeconds(start, 60, new Cesium.JulianDate());

// 添加路径点和时间点
positions.forEach((position, index) => {
  const time = Cesium.JulianDate.addSeconds(start, index * 10, new Cesium.JulianDate());
  sampledPosition.addSample(time, position);
});

// 添加无人机模型
viewer.entities.add({
  position: sampledPosition,
  orientation: new Cesium.VelocityOrientationProperty(sampledPosition),
  model: {
    uri: "/GroundVehicle.glb",
    scale: 1.0
  }
});

// 设置时间范围
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
viewer.clock.multiplier = 10;
3. 状态更新
function updateStatus(time) {
  const position = sampledPosition.getValue(time);
  const cartographic = Cesium.Cartographic.fromCartesian(position);
  const longitude = Cesium.Math.toDegrees(cartographic.longitude);
  const latitude = Cesium.Math.toDegrees(cartographic.latitude);
  const height = cartographic.height;

  console.log(`经度: ${longitude}, 纬度: ${latitude}, 高度: ${height}`);
}
viewer.clock.onTick.addEventListener(updateStatus);
完整代码
📄 dynamicObject.js
import core from "./Core.js";
import getPosition from "./getPosition.js";

/**
 * 创建浏览对象。
 * @constructor xp
 * @time 2022-12-25
 * @param {*} viewer
 * @param {*} cesium
 */
function dynamicObject(viewer, cesium) {
  this._viewer = viewer;
  this._cesium = cesium;
  this._core = new core();
  this._getPosition = new getPosition(this._viewer, this._cesium);
  this._entityFly = null;
}

/**
 * 这个方法用于创建浏览对象
 * @returns {Promise.<Object>} 返回一个Cesium的对象。
 *
 */
// var ploylinejl = {
//   polyline: {},
//   cameraRoll: null,
//   cameraPitch: null,
//   cameraPosition: null,
//   cameraHeading: null,
//   positions: [],
//   distance: [],
//   Totaltime: "",
//   dsq: null
// };
dynamicObject.prototype.executeFlycesium = function (method) {
  //设置浏览路径
  // var polylines = {};
  var _this = this;
  var PolyLinePrimitive = (function () {
    function execute(positions) {
      this.options = {
        polyline: {
          show: true,
          positions: [],
          material: new _this._cesium.PolylineGlowMaterialProperty({
            glowPower: 0.1,
            color: _this._cesium.Color.YELLOW
          }),
          width: 10,
          clampToGround: true
        }
      };
      this.positions = positions;
      this._init();
    }

    execute.prototype._init = function () {
      var _self = this;
      var _update = function () {
        return _self.positions;
      };
      //实时更新polyline.positions
      this.options.polyline.positions = new _this._cesium.CallbackProperty(
        _update,
        false
      );
      this.flycesium = _this._viewer.entities.add(this.options);
      _this.item = this.flycesium;
    };
    return execute;
  })();
  var handler = (this.handler = new _this._cesium.ScreenSpaceEventHandler(
    _this._viewer.scene.canvas
  ));
  var positions = [];
  // var flyceium = null;
  var distance = 0;
  var poly = undefined;
  var ploylinejl = {
    polyline: {},
    cameraRoll: null,
    cameraPitch: null,
    cameraPosition: null,
    cameraHeading: null,
    positions: [],
    distance: [],
    Totaltime: ""
  };
  //导入tool提示框
  var tooltip = this._core.CreateTooltip();
  //设置鼠标样式
  this._core.mouse(this._viewer.container, 1, window.SmartEarthRootUrl);
  handler.setInputAction(function (movement) {
    var cartesian = _this._getPosition.getMousePosition(movement);
    if (_this._core.getBrowser().pc === "pc" && positions.length == 0) {
      positions.push(cartesian.clone());
    }
    positions.push(cartesian);
    if (positions.length >= 2) {
      if (!_this._cesium.defined(poly)) {
        poly = new PolyLinePrimitive(positions);
      }
      distance = _this._core.getSpaceDistancem(positions, _this._cesium);
    }
  }, this._cesium.ScreenSpaceEventType.LEFT_CLICK);
  //鼠标移动
  handler.setInputAction(function (movement) {
    tooltip.showAt(movement.endPosition, "左键开始,右键结束!");
    var cartesian = _this._getPosition.getMousePosition(movement);
    if (positions.length >= 2) {
      if (!_this._cesium.defined(poly)) {
        poly = new PolyLinePrimitive(positions);
      } else {
        if (cartesian) {
          positions.pop();
          //cartesian.y += (1 + Math.random());
          positions.push(cartesian);
        }
      }
      distance = _this._core.getSpaceDistancem(positions, _this._cesium);
    }
  }, this._cesium.ScreenSpaceEventType.MOUSE_MOVE);
  //单击鼠标右键结束画线
  handler.setInputAction(function () {
    _this.end();
  }, this._cesium.ScreenSpaceEventType.RIGHT_CLICK);

  this.end = function (type) {
    handler.destroy();
    tooltip.show(false);
    //设置鼠标样式
    _this._core.mouse(_this._viewer.container, 0);

    _this.end = undefined;
    _this._viewer.entities.remove(_this.item);

    if (type === "cancel" || positions.length < 2) {
      return;
    }
    distance = _this._core.getSpaceDistancem(positions, _this._cesium);

    ploylinejl.polyline = poly;
    ploylinejl.positions = positions;
    ploylinejl.distance = parseFloat(distance);
    //转化成浏览对象
    _this.setFlycesium(ploylinejl, function (flyceium) {
      _this.flyceium = flyceium;
      _this.ploylinejl = ploylinejl;
      if (typeof method == "function") {
        method(flyceium);
      }
    });
  };
  return this;
};
/**
 * 设置获取浏览对象
 */
dynamicObject.prototype.setFlycesium = function (drawHelper, callback) {
  var _this = this;
  var coordinates = [];
  // var position = null;
  // var heading = null;
  // var pitch = null;
  // var roll = null;
  var maxHeight = 0;
  for (var i = 0; i < drawHelper.positions.length; i++) {
    var cartographic = _this._cesium.Cartographic.fromCartesian(
      drawHelper.positions[i]
    ); //世界坐标转地理坐标(弧度)
    var point = [
      (cartographic.longitude / Math.PI) * 180,
      (cartographic.latitude / Math.PI) * 180,
      cartographic.height
    ]; //地理坐标(弧度)转经纬度坐标
    //console.log(point);
    coordinates.push(point);
  }
  this._core.getPmfxPro(
    drawHelper.positions,
    25,
    0,
    _this._cesium,
    _this._viewer,
    data => {
      maxHeight = data.max;
      var time;
      time = (drawHelper.distance / 50).toFixed(1);
      var pathsData = {
        id: _this._core.getuid(),
        name: "新建路线",
        distance: drawHelper.distance,
        showPoint: false,
        showLine: true,
        showModel: true,
        isLoop: false,
        Totaltime: Math.round(time),
        speed: 50,
        height: (maxHeight + 200).toFixed(2),
        pitch: -20,
        range: 100,
        mode: 0,
        url: "/GroundVehicle.glb",
        geojson: {
          // orientation: {heading: heading, pitch: pitch, roll: roll},
          // position: position,
          geometry: { type: "LineString", coordinates: coordinates }
        }
      };
      callback && callback(pathsData);
    }
  );
};
/**
 * 开始浏览
 */
dynamicObject.prototype.Start = function (data, url, funs) {
  var _this = this;
  // var pathsData = data.geojson;
  if (!data.Totaltime) {
    data.Totaltime = 3000;
  }
  if (_this._entityFly) {
    _this.exit();
  }
  // _this._viewer.camera.setView({
  //     destination: pathsData.position,
  //     orientation: pathsData.orientation,
  // });
  fun = funs;
  setTimeout(function () {
    _this.executeFly3D(data, url);
  }, 200);
  return this;
};
var entityFly = null;
var entityModel = null;
//var start;
var fun = null;
var entityhd = {
  start: null,
  time: null,
  longitude: 0,
  latitude: 0,
  cameraHeight: 100,
  //timedifference: null,
  speed: 50,
  multiplier: 1,

  position: 0
};
// var stop;
var velocityVector, velocityVectorProperty, velocityOrientationProperty;
var AngleProperty, property;
var wheelAngle = 0;

/**
 * 播放路径动画
 * @param {Object} data 数据
 * @param {Object} data.geojson 路线数据
 * @param {Number} [data.lineHeight] 路线高度,默认贴地
 * @param {Boolean} [data.isLoop=false] 是否循环播放
 * @param {String} [url] 模型路径
 */
dynamicObject.prototype.executeFly3D = function (data, url) {
  var _this = this;
  var pathsData = data.geojson;
  velocityVector = new _this._cesium.Cartesian3();
  AngleProperty = new _this._cesium.SampledProperty(Number);
  property = new _this._cesium.SampledPositionProperty();

  if (pathsData && pathsData.geometry) {
    var positionA = pathsData.geometry.coordinates;
    var position = [];
    var position1 = [];
    if (positionA.length > 0) {
      for (var i = 0; i < positionA.length; i++) {
        var x = positionA[i][0];
        var y = positionA[i][1];
        var z = positionA[i][2];
        data.lineHeight !== void 0 && (z = data.lineHeight);
        position1.push(x, y, z);
        position.push({ x: x, y: y, z: z });
      }
    } else {
      return;
    }

    _this._viewer.clock.clockRange = data.isLoop
      ? _this._cesium.ClockRange.LOOP_STOP
      : _this._cesium.ClockRange.CLAMPED; //Loop at the end
    _this._viewer.clock.multiplier = data.multiplier || 1;
    _this._viewer.clock.canAnimate = false;
    _this._viewer.clock.shouldAnimate = true; //设置时间轴动态效果
    entityhd.distance = data.distance;
    entityhd.cameraHeight = data.height;
    entityhd.lineHeight = data.lineHeight;
    entityhd.pitch = data.pitch;
    entityhd.range = data.range;
    entityhd.speed = data.speed || 50;
    entityhd.Totaltime = data.distance / entityhd.speed;

    entityhd.start = _this._cesium.JulianDate.fromDate(new Date());
    entityhd.stop = _this._cesium.JulianDate.addSeconds(
      entityhd.start,
      entityhd.Totaltime,
      new _this._cesium.JulianDate()
    );
    //Make sure viewer is at the desired time.
    _this._viewer.clock.startTime = entityhd.start.clone();
    _this._viewer.clock.stopTime = entityhd.stop.clone();
    _this._viewer.clock.currentTime = entityhd.start.clone();

    var _position = _this.computeCirclularFlight(position);
    entityhd.position = _position;
    entityhd.degrees = position;
    velocityOrientationProperty = new _this._cesium.VelocityOrientationProperty(
      _position
    );

    var mode = {};
    if (url !== "") {
      mode = {
        show: _this._cesium.defaultValue(data.showModel, true),
        scale: _this._cesium.defaultValue(data.modelScale, 1),
        uri: url
      };
    } else {
      // const modelUrl = Cesium.buildModuleUrl(
      //   "Assets/GltfModels/CesiumAir/Cesium_Air.glb"
      // );
      mode = {
        show: _this._cesium.defaultValue(data.showModel, true),
        scale: _this._cesium.defaultValue(data.modelScale, 1)
        // uri: modelUrl
      };
    }
    if (data.modelData) {
      mode = _this._core.extend(mode, data.modelData);
    }
    changeFlyView = function () {};
    entityFly = _this._viewer.entities.add({
      //Set the entity availability to the same interval as the simulation time.
      availability: new _this._cesium.TimeIntervalCollection([
        new _this._cesium.TimeInterval({
          start: entityhd.start,
          stop: entityhd.stop
        })
      ]),
      position: _position,
      //Show the path as a pink line sampled in 1 second increments.
      polyline: {
        clampToGround: entityhd.lineHeight === void 0,
        positions: Cesium.Cartesian3.fromDegreesArrayHeights(position1),
        show: _this._cesium.defaultValue(data.showLine, true),
        material: new _this._cesium.PolylineGlowMaterialProperty({
          glowPower: 0.1,
          color: _this._cesium.Color.YELLOW
        }),
        width: 10
      },
      label: {
        text: new _this._cesium.CallbackProperty(updateSpeedLabel, false),
        font: "20px sans-serif",
        showBackground: false,
        distanceDisplayCondition: new _this._cesium.DistanceDisplayCondition(
          0.0,
          100.0
        ),
        eyeOffset: new _this._cesium.Cartesian3(0, 3.5, 0)
      }
    });
    // console.log(_position);

    entityModel = _this._viewer.entities.add({
      availability: new _this._cesium.TimeIntervalCollection([
        new _this._cesium.TimeInterval({
          start: entityhd.start,
          stop: entityhd.stop
        })
      ]),
      position: _position,
      orientation: velocityOrientationProperty,
      point: {
        show: _this._cesium.defaultValue(data.showPoint, false),
        color: _this._cesium.Color.RED,
        outlineColor: _this._cesium.Color.WHITE,
        outlineWidth: 2,
        pixelSize: 10
      },
      model: mode,
      billboard: data.image,
      viewFrom:
        data.viewFrom || new _this._cesium.Cartesian3(500.0, 500.0, 500.0)
    });
    entitymodels = entityFly;
    _this._viewer.trackedEntity = entityModel;
    _this._entityFly = entityFly;

    data.mode && _this.changeFlyMode(data.mode);

    // setTimeout(function () {
    //     // _this._viewer.camera.zoomOut(500.0);//缩小地图,避免底图没有数据
    //     _this._viewer.camera.zoomOut(300.0);//缩小地图,避免底图没有数据
    // }, 100);
  } else {
    return;
  }

  function updateSpeedLabel(time) {
    //alert(time);
    //entityhd.time = time;
    // var de = entitymodels;
    // var camera = _this._viewer.camera;
    if (
      _this._viewer.clock.clockRange !== 2 &&
      Cesium.JulianDate.equals(
        _this._viewer.clock.currentTime,
        _this._viewer.clock.stopTime
      )
    ) {
      entityFly.label.text = "";
      _this.exit();
      if (fun != null && typeof fun === "function") {
        fun("end");
      }
      changeFlyView = function () {};
      return;
    }
    try {
      var position = entitymodels.position.getValue(
        _this._viewer.clock.currentTime
      );
      var cartographic = _this._cesium.Cartographic.fromCartesian(position);
      //经度
      entityhd.longitude = _this._cesium.Math.toDegrees(cartographic.longitude);
      //纬度
      entityhd.latitude = _this._cesium.Math.toDegrees(cartographic.latitude);
      if (entityhd.lineHeight === void 0) {
        let height1 = _this._viewer.scene.sampleHeight(cartographic, [
          entityModel,
          entitymodels
        ]);
        let height2 = _this._viewer.scene.globe.getHeight(cartographic);
        entityModel.position = _this._cesium.Cartesian3.fromRadians(
          cartographic.longitude,
          cartographic.latitude,
          height2 > height1 ? height2 : height1
        );
      }
    } catch (er) {
      console.log(er);
    }
    try {
      velocityVectorProperty.getValue(time, velocityVector);
      changeFlyView(time);
      var metersPerSecond = _this._cesium.Cartesian3.magnitude(velocityVector);
      var kmPerHour = Math.round(metersPerSecond * 3.6);
      kmPerHour += " km/h";
      //已漫游时间
      entityhd.time = _this._cesium.JulianDate.secondsDifference(
        time,
        entityhd.start
      );
      //已漫游比例
      entityhd.ratio = entityhd.time / entityhd.Totaltime;
      //已漫游距离
      entityhd.distanceTraveled = entityhd.ratio * entityhd.distance;
      //运行速度
      entityhd.speed = kmPerHour;
      //漫游高程
      entityhd.height = cartographic.height;
      //地面高程
      entityhd.globeHeight = _this._viewer.scene.globe.getHeight(cartographic);

      if (fun != null && typeof fun === "function") {
        fun(entityhd);
      }
    } catch (er) {
      console.log(er);
    }
    return "";
  }
};

// var hpr = new Cesium.HeadingPitchRoll();
var flyPosition;
// var Quaternion = new Cesium.Quaternion();
// var _heading = 0;
var entitymodels = null;

//改变视角
var changeFlyView;

function getHeading(time) {
  wheelAngle = AngleProperty.getValue(time);
  entityhd.heading = wheelAngle;
}

function getFlyPosition(position) {
  var cartographic = Cesium.Cartographic.fromCartesian(position);
  var lon = Cesium.Math.toDegrees(cartographic.longitude);
  var lat = Cesium.Math.toDegrees(cartographic.latitude);
  return Cesium.Cartesian3.fromDegrees(lon, lat, entityhd.cameraHeight || 100);
}

/**
 * 显示点
 */
dynamicObject.prototype.showPoint = function (isShow) {
  entityModel && entityModel.point && (entityModel.point.show = isShow);
};

/**
 * 显示线
 */
dynamicObject.prototype.showLine = function (isShow) {
  entityFly && entityFly.polyline && (entityFly.polyline.show = isShow);
};

/**
 * 显示模型
 */
dynamicObject.prototype.showModel = function (isShow) {
  entityModel && entityModel.model && (entityModel.model.show = isShow);
};

//飞行高度
dynamicObject.prototype.setFlyHeight = function (height) {
  entityhd.cameraHeight = height;
};

//飞行距离
dynamicObject.prototype.setFlyDistance = function (distance) {
  entityhd.range = distance;
};

//飞行俯仰角
dynamicObject.prototype.setFlyPitch = function (pitch) {
  entityhd.pitch = pitch;
};

//飞行模式
dynamicObject.prototype.changeFlyMode = function (index) {
  var _this = this;
  switch (index) {
    case 0:
      changeFlyView = function () {};
      _this.BindingModel(true);
      break;
    case 1:
      this.BindingModel(false);
      changeFlyView = function (time) {
        getHeading(time);
        _this.exeuteVisualAngle(
          _this._cesium.Math.toRadians(entityhd.heading),
          _this._cesium.Math.toRadians(entityhd.pitch),
          entityhd.range
        );
      };
      break;
    case 2:
      this.BindingModel(false);
      changeFlyView = function (time) {
        getHeading(time);
        flyPosition = _this._entityFly.position.getValue(
          _this._viewer.clock.currentTime
        );
        if (!flyPosition) return;
        flyPosition = getFlyPosition(flyPosition);
        _this._viewer.camera.setView({
          destination: flyPosition,
          orientation: {
            heading: _this._cesium.Math.toRadians(entityhd.heading),
            pitch: _this._cesium.Math.toRadians(-90),
            roll: 0.0
          }
        });
      };
      break;
  }
};

/**
 * 加速
 */
dynamicObject.prototype.faster = function () {
  this._viewer.animation.viewModel.faster();
};

/**
 * 减速
 */
dynamicObject.prototype.slower = function () {
  // 倍率减
  this._viewer.animation.viewModel.slower();
};

/**
 * 设置倍数
 */
dynamicObject.prototype.setMultiplier = function (multiplier) {
  this._viewer.clock.multiplier = parseFloat(multiplier);
};

/**
 * 是否暂停
 */
dynamicObject.prototype.isPause = function (isPause) {
  var clockViewModel = this._viewer.clockViewModel;
  clockViewModel.shouldAnimate = !isPause;
};

/**
 * 结束飞行
 */
dynamicObject.prototype.exit = function () {
  this.isPause(true);
  this._viewer.clock.multiplier = 1;
  this.executeSignout();
  this.BindingModel(false);
  this._viewer.entities.remove(entityFly);
  this._viewer.entities.remove(entityModel);
  entityFly = null;
  entityModel = null;
  this._entityFly = null;
};

//lable回调函数
dynamicObject.prototype.updateSpeedLabel = function () {
  //if (fun && typeof fun === 'function') {
  //    fun(_this._entityFly);
  //}
  //this.entityhd = {
  //    start: null,
  //    time: null
  //};
  //this.entityhd.time = time;
  //if (this.fun != null && typeof fun === 'function') {
  //    fun(_this._entityFly);
  //}
  //return "";
};

//添加时间位置样本
dynamicObject.prototype.computeCirclularFlight = function (position) {
  var _this = this;
  velocityVectorProperty = new _this._cesium.VelocityVectorProperty(
    property,
    false
  );
  var _time, time, _position, _position1;
  for (var i = 0; i < position.length; i++) {
    if (i === 0) {
      //起点
      time = _this._cesium.JulianDate.addSeconds(
        entityhd.start,
        0,
        new _this._cesium.JulianDate()
      );
      _position = _this._cesium.Cartesian3.fromDegrees(
        position[0].x,
        position[0].y,
        entityhd.lineHeight
      );

      property.addSample(time, _position);
      //计算两点方位角
      wheelAngle = _this._core.TwoPointAzimuth(
        position[0].x,
        position[0].y,
        position[1].x,
        position[1].y
      );
      AngleProperty.addSample(time, wheelAngle);
    }
    try {
      if (i > 0 && i != position.length - 1) {
        _position = new _this._cesium.Cartesian3(
          property._property._values[i * 3 - 3],
          property._property._values[i * 3 - 2],
          property._property._values[i * 3 - 1]
        );
        _position1 = _this._cesium.Cartesian3.fromDegrees(
          position[i].x,
          position[i].y,
          _this._cesium.defaultValue(entityhd.lineHeight, position[i].z)
        );

        var positions = [
          _this._cesium.Cartographic.fromCartesian(_position),
          _this._cesium.Cartographic.fromCartesian(_position1)
        ];
        var a = new _this._cesium.EllipsoidGeodesic(positions[0], positions[1]);
        var long = a.surfaceDistance;
        time = _this._cesium.JulianDate.addSeconds(
          property._property._times[i - 1],
          0.5,
          new _this._cesium.JulianDate()
        );
        _time = _this._cesium.JulianDate.addSeconds(
          property._property._times[i - 1],
          long / entityhd.speed,
          new _this._cesium.JulianDate()
        );

        property.addSample(_time, _position1);
        //计算两点方位角
        wheelAngle = _this._core.TwoPointAzimuth(
          position[i - 1].x,
          position[i - 1].y,
          position[i].x,
          position[i].y
        );
        AngleProperty.addSample(time, wheelAngle);
        AngleProperty.addSample(_time, wheelAngle);
      }
    } catch (e) {
      console.log(e);
    }
  }
  return property;
};
/**
 * 暂停浏览
 */
dynamicObject.prototype.executePauseFly3DPaths = function () {
  var clockViewModel = this._viewer.clockViewModel;
  if (clockViewModel.shouldAnimate) {
    clockViewModel.shouldAnimate = false;
  } else if (this._viewer.clockViewModel.canAnimate) {
    clockViewModel.shouldAnimate = true;
  }
};

/**
 * 添加对象
 */
dynamicObject.prototype.changeModel = function (url) {
  entityModel.model.uri = url;
};
//浏览方式飞向视点
/**
 * 获取视野点
 */
dynamicObject.prototype.PointView = function () {
  var originalCameraLocation = {
    position: Viewer.camera.position.clone(),
    orientation: {
      heading: Viewer.camera.heading,
      pitch: Viewer.camera.pitch,
      roll: Viewer.camera.roll
    }
  };
  return originalCameraLocation;
};
/**
 * 开始浏览。
 * @param {Paths}
 * @returns {Object} 返回一个json对象。
 */
dynamicObject.prototype.PlayPaths = function () {
  var that = this;
  setInterval(function () {
    viewer.camera.setView({
      // Cesium的坐标是以地心为原点,一向指向南美洲,一向指向亚洲,一向指向北极州
      // fromDegrees()方法,将经纬度和高程转换为世界坐标
      destination: that._cesium.Cartesian3.fromDegrees(117.48, 30.67, 15000.0),
      orientation: {
        // 指向
        heading: that._cesium.Math.toRadians(90, 0),
        // 视角
        pitch: that._cesium.Math.toRadians(-90),
        roll: 0.0
      }
    });
  }, 2000);
};
/**
 * 绑定模型
 * @param {binding} 是否绑定。
 */
dynamicObject.prototype.BindingModel = function (binding) {
  if (binding) {
    this._viewer.trackedEntity = entityModel;
  } else {
    this._viewer.trackedEntity = undefined;
    this._viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
  }
};
/**
 * 改变视角
 * @returns {Object} 返回一个json对象。
 */
dynamicObject.prototype.exeuteVisualAngle = function (
  viewHeading,
  viewPitch,
  viewRange
) {
  var hpRange = { heading: null, pitch: null, range: null };
  hpRange.heading = viewHeading || this._cesium.Math.toRadians(90);
  hpRange.pitch = viewPitch || this._cesium.Math.toRadians(0);
  hpRange.range = viewRange || 1000;
  var center = this._entityFly.position.getValue(
    this._viewer.clock.currentTime
  );
  if (!center) return;
  center = getFlyPosition(center);
  var hpRanges = new this._cesium.HeadingPitchRange(
    hpRange.heading,
    hpRange.pitch,
    hpRange.range
  );
  //if (center) this._viewer.camera.lookAt(center, hpRange);
  this._viewer.camera.lookAt(center, hpRanges);
};
/**
 * 是否显示路线
 * @returns {Object} 返回一个json对象。
 */
dynamicObject.prototype.Pathshow = function (route) {
  this._entityFly.polyline.show = route;
};
/**
 * 是否显示点
 * @returns {Object} 返回一个json对象。
 */
dynamicObject.prototype.Pointshow = function (route) {
  entityModel._point.show = route;
};
/**
 * 是否显示模型
 * @returns {Object} 返回一个json对象。
 */
dynamicObject.prototype.Modelshow = function (route) {
  entityModel._model.show = route;
};
/**
 * 向前飞行漫游路径
 * @returns {Object} 返回一个json对象。
 */
dynamicObject.prototype.executePlayForwardFly3DPaths = function () {
  var clockViewModel = this._viewer.clockViewModel;
  var multiplier = clockViewModel.multiplier;
  if (multiplier < 0) {
    clockViewModel.multiplier = -multiplier;
  }
  clockViewModel.shouldAnimate = true;
};
/**
 * 向后飞行漫游路径
 */
dynamicObject.prototype.executePlayReverseFly3DPaths = function () {
  var clockViewModel = this._viewer.clockViewModel;
  var multiplier = clockViewModel.multiplier;
  if (multiplier > 0) {
    clockViewModel.multiplier = -multiplier;
  }
  clockViewModel.shouldAnimate = true;
};
/**
 * 退出飞行漫游路径
 */
dynamicObject.prototype.executeSignout = function () {
  var start = this._cesium.JulianDate.fromDate(new Date());
  this._viewer.clock.startTime = start.clone();
  var stop = this._cesium.JulianDate.addSeconds(
    start,
    86400,
    new this._cesium.JulianDate()
  );
  this._viewer.clock.stopTime = stop.clone();
  //this.cesiumViewer.entities.remove(this.entityFly);
};

/**
 * 结束当前操作
 */
dynamicObject.prototype.forceEndHanlder = function () {
  if (this.handler) {
    this.handler.destroy();
    this.handler = undefined;
  }
};
export default dynamicObject;

📄 Core.js
/**
 * 工具类
 * @constructor xp
 * @alias Core
 * @constructor
 *
 */
function Core () { }

//根据经纬度获取高度
Core.prototype.getHeightsFromLonLat = function (
  positions,
  Cesium,
  Viewer,
  callback
) {
  var camera = Viewer.camera;
  var heights = [];
  if (
    Viewer.scene &&
    Viewer.scene.terrainProvider &&
    Viewer.scene.terrainProvider._layers
  ) {
    //根据经纬度计算出地形高度。
    var promise = Cesium.sampleTerrainMostDetailed(
      Viewer.terrainProvider,
      positions
    );
    // var cameraHeight = camera.positionCartographic.height;
    Cesium.when(promise, function (updatedPositions) {
      updatedPositions.forEach(function (item) {
        heights.push(item.height);
      });
      if (typeof callback === "function") {
        callback(heights);
      }
    });
  } else {
    positions.forEach(function (p) {
      heights.push(Viewer.scene.globe.getHeight(p));
    });
    if (typeof callback === "function") {
      callback(heights);
    }
  }
};

/**
 * 创建鼠标Tooltip提示框。
 *
 * @param {*} [styleOrText] 提示框样式或文本内容
 * @param {String} [styleOrText.origin='center'] 对齐方式(center/top/bottom)
 * @param {String} [styleOrText.color='black'] 提示框颜色(black/white/yellow)
 * @param {String} [styleOrText.id=undefined] 提示框唯一id(可选)
 * @param {Object} position 显示位置
 * @param {Boolean} show 是否显示(如果为true,styleOrText必须为显示的文本内容)
 * @returns {Tooltip} Tooltip提示框。
 *
 * @example
 * sgworld.Core.CreateTooltip('这里是提示信息', {x:500, y:500}, true);
 * 或
 * tooltip = sgworld.Core.CreateTooltip();
 * tooltip.showAt({x:500, y:500}, '这里是提示信息');
 *
 * tooltip.show(false); //隐藏提示框
 * tooltip.show(true); //显示提示框
 */
Core.prototype.CreateTooltip = function (styleOrText = {}, position, show) {
  var style, _x, _y, _color, id;
  if (typeof styleOrText === "object") {
    style = styleOrText;
  }
  if (style && style.origin) {
    style.origin === "center" && ((_x = 15), (_y = -12));
    style.origin === "top" && ((_x = 15), (_y = -44));
    style.origin === "bottom" && ((_x = 15), (_y = 20));
  } else {
    (_x = 15), (_y = 20);
  }
  if (style && style.color) {
    style.color === "white" &&
      (_color = "background: rgba(255, 255, 255, 0.8);color: black;");
    style.color === "black" &&
      (_color = "background: rgba(0, 0, 0, 0.5);color: white;");
    style.color === "yellow" &&
      (_color =
        "color: black;background-color: #ffcc33;border: 1px solid white;");
  } else {
    _color = "background: rgba(0, 0, 0, 0.5);color: white;";
  }
  if (style && style.id) {
    id = "toolTip" + style.id;
  } else {
    id = "toolTip";
  }

  var tooltip = document.getElementById(id);

  if (!tooltip) {
    // 创建一个新的 div 元素
    var elementbottom = document.createElement("div");
    // 将元素添加到 .cesium-viewer 容器中
    var cesiumViewer = document.querySelector(".cesium-viewer");
    if (cesiumViewer) {
      cesiumViewer.appendChild(elementbottom);
    }

    // 构建 HTML 字符串
    var html =
      '<div id="' +
      id +
      '" style="display: none;pointer-events: none;position: absolute;z-index: 1000;opacity: 0.8;border-radius: 4px;padding: 4px 8px;white-space: nowrap;font-family:黑体;color:white;font-weight: bolder;font-size: 14px;' +
      _color +
      '"></div>';

    // 创建一个临时容器来解析 HTML 字符串
    var tempDiv = document.createElement("div");
    tempDiv.innerHTML = html;

    // 将解析后的第一个子元素(即 tooltip)添加到 .cesium-viewer 容器中
    if (cesiumViewer) {
      cesiumViewer.appendChild(tempDiv.firstElementChild);
    }

    // 获取刚刚创建的 tooltip 元素
    tooltip = document.getElementById(id);
  }
  if (show) {
    tooltip.innerHTML = styleOrText;
    tooltip.style.left = position.x + _x + "px";
    tooltip.style.top = position.y + _y + "px";
    tooltip.style.display = "block";
  } else {
    tooltip.style.display = "none";
  }
  return {
    tooltip: tooltip,
    style: style,
    showAt: function (position, text) {
      this.tooltip.innerHTML = text;
      if (this.style && this.style.origin) {
        this.style.origin === "center" &&
          ((_x = 15), (_y = -this.tooltip.offsetHeight / 2));
        this.style.origin === "top" &&
          ((_x = 15), (_y = -this.tooltip.offsetHeight - 20));
        this.style.origin === "bottom" && ((_x = 15), (_y = 20));
      } else {
        (_x = 15), (_y = -this.tooltip.offsetHeight / 2);
      }
      this.tooltip.style.left = position.x + _x + "px";
      this.tooltip.style.top = position.y + _y + "px";
      this.tooltip.style.display = "block";
    },
    show: function (show) {
      if (show) {
        this.tooltip.style.display = "block";
      } else {
        this.tooltip.style.display = "none";
      }
    }
  };
};

/**
 * 修改鼠标样式。
 *
 * @param {DOM} container html DOM节点
 * @param {Number} [cursorstyle=0] 鼠标类型(0为默认,1为使用cur图标)
 * @param {String} url cur图标路径。
 *
 * @example
 * sgworld.Core.mouse(Viewer.container, 1, 'draw.cur');
 */
Core.prototype.mouse = function (container, cursorstyle, url) {
  if (cursorstyle == 1) {
    container.style.cursor = "url(" + url + "),auto";
  } else {
    container.style.cursor = "default";
  }
};

// 判断是否为手机浏览器
Core.prototype.getBrowser = function () {
  var ua = navigator.userAgent.toLowerCase();
  var btypeInfo = (ua.match(/firefox|chrome|safari|opera/g) || "other")[0];
  if ((ua.match(/msie|trident/g) || [])[0]) {
    btypeInfo = "msie";
  }
  var pc = "";
  var prefix = "";
  var plat = "";
  //如果没有触摸事件 判定为PC
  var isTocuh =
    "ontouchstart" in window ||
    ua.indexOf("touch") !== -1 ||
    ua.indexOf("mobile") !== -1;
  if (isTocuh) {
    if (ua.indexOf("ipad") !== -1) {
      pc = "pad";
    } else if (ua.indexOf("mobile") !== -1) {
      pc = "mobile";
    } else if (ua.indexOf("android") !== -1) {
      pc = "androidPad";
    } else {
      pc = "pc";
    }
  } else {
    pc = "pc";
  }
  switch (btypeInfo) {
    case "chrome":
    case "safari":
    case "mobile":
      prefix = "webkit";
      break;
    case "msie":
      prefix = "ms";
      break;
    case "firefox":
      prefix = "Moz";
      break;
    case "opera":
      prefix = "O";
      break;
    default:
      prefix = "webkit";
      break;
  }
  plat =
    ua.indexOf("android") > 0 ? "android" : navigator.platform.toLowerCase();
  return {
    version: (ua.match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1], //版本
    plat: plat, //系统
    type: btypeInfo, //浏览器
    pc: pc,
    prefix: prefix, //前缀
    isMobile: pc == "pc" ? false : true //是否是移动端
  };
};

//空间距离测量用米
Core.prototype.getSpaceDistancem = function (positions, Cesium) {
  var distance = 0;
  for (var i = 0; i < positions.length - 1; i++) {
    var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
    var point2cartographic = Cesium.Cartographic.fromCartesian(
      positions[i + 1]
    );
    /**根据经纬度计算出距离**/
    var geodesic = new Cesium.EllipsoidGeodesic();
    geodesic.setEndPoints(point1cartographic, point2cartographic);
    var s = geodesic.surfaceDistance;
    //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2)));
    //返回两点之间的距离
    s = Math.sqrt(
      Math.pow(s, 2) +
      Math.pow(point2cartographic.height - point1cartographic.height, 2)
    );
    distance = distance + s;
  }
  return distance.toFixed(2);
};

//根据位置(Cartographic)获取3DTiles和Primitives高度
Core.prototype.get3DTileOrPrimitivesHeights = function (position, Viewer) {
  return Viewer.scene.sampleHeight(position);
};

//剖面分析
Core.prototype.getPmfxPro = function (
  _positions,
  pointSum1,
  cyjj,
  Cesium,
  viewer,
  methond
) {
  let _this = this;
  //起止点相关信息
  let pmx = {
    gcs: [],
    min: 99999,
    max: 0,
    juli: 0.0,
    cys: 0
  };
  let positions = [];
  let pointNum = [];
  //获取总间隔点数和距离
  for (let i = 0; i < _positions.length - 1; i++) {
    let julifr = _this.getSpaceDistancem(
      [_positions[i], _positions[i + 1]],
      Cesium
    );
    julifr = parseFloat(julifr);
    pmx.juli += julifr;
    if (cyjj == 0) {
    } else {
      pointSum1 = parseInt(julifr / cyjj);
    }
    pointNum.push(pointSum1);
    pmx.cys += pointSum1;
  }
  let startAnalyse = () => {
    pointNum.forEach((num, i) => {
      let startPoint = _positions[i];
      let endPoint = _positions[i + 1];
      //起点
      let scartographic = Cesium.Cartographic.fromCartesian(startPoint);
      let slongitude = Cesium.Math.toDegrees(scartographic.longitude);
      let slatitude = Cesium.Math.toDegrees(scartographic.latitude);

      //终点
      let ecartographic = Cesium.Cartographic.fromCartesian(endPoint);
      let elongitude = Cesium.Math.toDegrees(ecartographic.longitude);
      let elatitude = Cesium.Math.toDegrees(ecartographic.latitude);

      let pointSum = num; //取样点个数
      let addXTT =
        Cesium.Math.lerp(slongitude, elongitude, 1.0 / pointSum) - slongitude;
      let addYTT =
        Cesium.Math.lerp(slatitude, elatitude, 1.0 / pointSum) - slatitude;

      let Cartesian;

      i === 0 && positions.push(scartographic);
      for (let j = 0; j < pointSum; j++) {
        let longitude = slongitude + (j + 1) * addXTT;
        let latitude = slatitude + (j + 1) * addYTT;
        Cartesian = Cesium.Cartesian3.fromDegrees(longitude, latitude);
        positions.push(Cesium.Cartographic.fromCartesian(Cartesian));
      }
    });

    positions.push(
      Cesium.Cartographic.fromCartesian(_positions[_positions.length - 1])
    );

    let heightArr = [];
    pmx.allPoint = positions;
    this.getHeightsFromLonLat(positions, Cesium, viewer, function (data) {
      if (data) {
        heightArr = data;
        let changeDepthTest = viewer.scene.globe.depthTestAgainstTerrain;
        viewer.scene.globe.depthTestAgainstTerrain = true;
        for (let i = 0; i < heightArr.length; i++) {
          let modelHeight = _this.get3DTileOrPrimitivesHeights(
            positions[i],
            viewer
          );
          if (modelHeight !== undefined) {
            heightArr[i] = modelHeight;
          }
          let he = heightArr[i].toFixed(2);
          if (parseFloat(he) < parseFloat(pmx.min)) {
            pmx.min = parseFloat(he);
          }
          if (parseFloat(he) > parseFloat(pmx.max)) {
            pmx.max = parseFloat(he);
          }
          pmx.gcs.push(he);
        }
        viewer.scene.globe.depthTestAgainstTerrain = changeDepthTest;
        methond && typeof methond == "function" && methond(pmx);
      }
    });
  };
  if (pmx.cys > 1000) {
    layuiLayer &&
      layuiLayer.msg("当前采样点数过多,是否继续分析?", {
        time: 0,
        btn: ["继续", "取消"],
        btnAlign: "c",
        yes: index => {
          layuiLayer.close(index);
          setTimeout(() => {
            startAnalyse();
          }, 10);
        },
        btn2: () => {
          methond && typeof methond == "function" && methond(pmx);
        }
      });
  } else {
    setTimeout(() => {
      startAnalyse();
    }, 10);
  }
};

/**
 * 获取uuid
 */
Core.prototype.uuid = function (len, radix) {
  var chars =
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("");
  var uuid = [],
    i;
  var uuid = [],
    i;
  radix = radix || chars.length;

  if (len) {
    // Compact form
    for (i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];
  } else {
    // rfc4122, version 4 form
    var r;

    // rfc4122 requires these characters
    uuid[8] = uuid[13] = uuid[18] = uuid[23] = "-";
    uuid[14] = "4";

    // Fill in random data.  At i==19 set the high bits of clock sequence as
    // per rfc4122, sec. 4.1.5
    for (i = 0; i < 36; i++) {
      if (!uuid[i]) {
        r = 0 | (Math.random() * 16);
        uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
      }
    }
  }

  return uuid.join("");
};

Core.prototype.getuid = function () {
  // var idStr = Date.now().toString(36);
  // idStr += Math.random().toString(36).substr(3);
  // return idStr;

  // return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  //     var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
  //     return v.toString(16);
  // });

  return this.uuid(8, 16);
};

/**
 * 对象参数合并
 * @param {Object} o 对象
 * @param {Object} n 被合并的对象
 * @param {Boolean} [override=false] 是否覆盖原属性值
 * @param {Boolean} [mergeTheSame=false] 是否只合并相同属性
 */
Core.prototype.extend = function (
  o,
  n,
  override = false,
  mergeTheSame = false
) {
  for (var key in n) {
    if (mergeTheSame) {
      if (o.hasOwnProperty(key)) {
        o[key] = n[key];
      }
    } else {
      if (!o.hasOwnProperty(key) || override) {
        o[key] = n[key];
      }
    }
  }
  return o;
};

/**
 * 两点方位角
 * @param {number} lon1 起点经度
 * @param {number} lat1 起点纬度
 * @param {number} lon2 终点经度
 * @param {number} lat2 终点纬度
 */
Core.prototype.TwoPointAzimuth = function (lon1, lat1, lon2, lat2) {
  var result = 0.0;
  var getRad = function (d) {
    return (d * Math.PI) / 180.0;
  };

  var ilat1 = Math.round(0.5 + lat1 * 360000.0);
  var ilat2 = Math.round(0.5 + lat2 * 360000.0);
  var ilon1 = Math.round(0.5 + lon1 * 360000.0);
  var ilon2 = Math.round(0.5 + lon2 * 360000.0);

  lat1 = getRad(lat1);
  lon1 = getRad(lon1);
  lat2 = getRad(lat2);
  lon2 = getRad(lon2);

  if (ilat1 === ilat2 && ilon1 === ilon2) {
    return result;
  } else if (ilon1 === ilon2) {
    if (ilat1 > ilat2) result = 180.0;
  } else {
    var c = Math.acos(
      Math.sin(lat2) * Math.sin(lat1) +
      Math.cos(lat2) * Math.cos(lat1) * Math.cos(lon2 - lon1)
    );
    var A = Math.asin((Math.cos(lat2) * Math.sin(lon2 - lon1)) / Math.sin(c));
    result = (A * 180) / Math.PI;
    if (ilat2 > ilat1 && ilon2 > ilon1) {
    } else if (ilat2 < ilat1 && ilon2 < ilon1) {
      result = 180.0 - result;
    } else if (ilat2 < ilat1 && ilon2 > ilon1) {
      result = 180.0 - result;
    } else if (ilat2 > ilat1 && ilon2 < ilon1) {
      result += 360.0;
    }
  }
  return result;
};
export default Core;
📄 getPosition.js
/**
 *
 * 获取位置。
 * xp
 * @alias getPosition
 * @constructor
 *
 */

function getPosition (viewer, cesium) {
  this._viewer = viewer;
  this._cesium = cesium;
}

getPosition.prototype.getPosition = function () {
  return this._viewer.camera.position;
};

getPosition.prototype.getDegrees = function () {
  var cartographic = this._viewer.camera.positionCartographic;
  var Degrees = {
    lon: this._cesium.Math.toDegrees(cartographic.longitude),
    lat: this._cesium.Math.toDegrees(cartographic.latitude),
    height: cartographic.height
  };

  return Degrees;
};
/**
 * 获取鼠标当前世界坐标
 * @param {object} [movement] 鼠标屏幕位置
 * @param {Array/Object} [objectsToExclude] 排除的实体对象
 * @param {number} [type] 类型(0为模型优先,1为地形优先),默认模型优先
 * @param {boolean} [isAdsorption] true|false 是否吸附,默认否
 * @param {number} [distance] 吸附半径,默认30
 **/
getPosition.prototype.getMousePosition = function (
  movement,
  objectsToExclude,
  type,
  isAdsorption,
  distance
) {
  var mousePosition = movement.endPosition || movement.position || movement;
  type === undefined && (type = 0);
  isAdsorption = this._cesium.defaultValue(isAdsorption, false);
  this.defaultDepthTest === undefined &&
    (this.defaultDepthTest =
      !!this._viewer.scene.globe.depthTestAgainstTerrain);

  var ray, cartesian, _cartesian, feature;
  //this.isObjectsToExcludeShow(objectsToExclude, false);
  var width = isAdsorption ? (distance ? distance : 30) : 1;
  if (type !== 0) {
    //地形优先
    //开启深度检测
    this._viewer.scene.globe.depthTestAgainstTerrain = true;
    ray = this._viewer.camera.getPickRay(mousePosition);
    ray && (cartesian = this._viewer.scene.globe.pick(ray, this._viewer.scene));
    //isAdsorption && (mousePosition = this.getAdsorptionPosition(mousePosition, objectsToExclude));

    if (!objectsToExclude || objectsToExclude.length === 0) {
      feature = this._viewer.scene.pick(mousePosition);
      if (feature && feature.id && !this.id3DGraphic(feature.id)) {
        feature = undefined;
      }
    } else {
      feature = this._viewer.scene.drillPick(
        mousePosition,
        objectsToExclude.length,
        width,
        width
      );
      feature = this.getNotExcludedObj(feature, objectsToExclude);
    }

    if (feature && !isAdsorption) {
      this._viewer.scene.pick(mousePosition);
      _cartesian = this._viewer.scene.pickPosition(mousePosition);
      if (_cartesian) {
        cartesian = _cartesian;
      }
    } else {
      cartesian &&
        isAdsorption &&
        (_cartesian = this._getAdsorptionPosition(
          mousePosition,
          feature,
          distance
        )); //吸附
      if (_cartesian) {
        cartesian = _cartesian;
      }
    }
  } else {
    //模型优先
    if (!objectsToExclude || objectsToExclude.length === 0) {
      feature = this._viewer.scene.pick(mousePosition);
      if (feature && feature.id && !this.id3DGraphic(feature.id)) {
        feature = undefined;
      }
    } else {
      feature = this._viewer.scene.drillPick(
        mousePosition,
        (objectsToExclude &&
          objectsToExclude.length &&
          objectsToExclude.length + 1) ||
        1,
        width,
        width
      );
      feature = this.getNotExcludedObj(feature, objectsToExclude);
    }
    if (feature && !isAdsorption) {
      this._viewer.scene.pick(mousePosition);
      cartesian = this._viewer.scene.pickPosition(mousePosition);
    } else if (feature && isAdsorption) {
      this._viewer.scene.pick(mousePosition);
      cartesian = this._viewer.scene.pickPosition(mousePosition);
      _cartesian = this._getAdsorptionPosition(
        mousePosition,
        feature,
        distance
      ); //吸附
      if (_cartesian) {
        cartesian = _cartesian;
      }
    } else {
      //开启深度检测
      this._viewer.scene.globe.depthTestAgainstTerrain = true;
      ray = this._viewer.camera.getPickRay(mousePosition);
      ray &&
        (cartesian = this._viewer.scene.globe.pick(ray, this._viewer.scene));
    }
  }
  this._viewer.scene.globe.depthTestAgainstTerrain = !!this.defaultDepthTest;
  this.defaultDepthTest = undefined;

  // console.log(cartesian);
  if (!cartesian) {
    console.log("未拾取到坐标!");
    return;
  }

  return cartesian;
};
/**
 * 获取鼠标当前经纬度
 * @param {object} [movement] 鼠标屏幕位置
 * @param {Array/Object} [objectsToExclude] 排除的实体对象
 * @param {number} [type] 类型(0为模型优先,1为地形优先),默认模型优先
 * @param {boolean} [isAdsorption] true|false 是否吸附,默认否
 * @param {number} [distance] 吸附半径,默认30
 */
getPosition.prototype.getMouseDegrees = function (
  movement,
  objectsToExclude,
  type,
  isAdsorption,
  distance
) {
  var mousePosition = movement.endPosition || movement.position || movement;
  type === undefined && (type = 0);
  isAdsorption = this._cesium.defaultValue(isAdsorption, false);
  this.defaultDepthTest === undefined &&
    (this.defaultDepthTest =
      !!this._viewer.scene.globe.depthTestAgainstTerrain);

  var ray, cartesian, _cartesian, feature;
  //this.isObjectsToExcludeShow(objectsToExclude, false);
  var width = isAdsorption ? (distance ? distance : 30) : 1;
  if (type !== 0) {
    //地形优先
    //开启深度检测
    this._viewer.scene.globe.depthTestAgainstTerrain = true;
    ray = this._viewer.camera.getPickRay(mousePosition);
    ray && (cartesian = this._viewer.scene.globe.pick(ray, this._viewer.scene));
    //isAdsorption && (mousePosition = this.getAdsorptionPosition(mousePosition, objectsToExclude));

    if (!objectsToExclude || objectsToExclude.length === 0) {
      feature = this._viewer.scene.pick(mousePosition);
      if (feature && feature.id && !this.id3DGraphic(feature.id)) {
        feature = undefined;
      }
    } else {
      feature = this._viewer.scene.drillPick(
        mousePosition,
        (objectsToExclude &&
          objectsToExclude.length &&
          objectsToExclude.length + 1) ||
        1,
        width,
        width
      );
      feature = this.getNotExcludedObj(feature, objectsToExclude);
    }
    if (feature && !isAdsorption) {
      this._viewer.scene.pick(mousePosition);
      _cartesian = this._viewer.scene.pickPosition(mousePosition);
      if (_cartesian) {
        cartesian = _cartesian;
      }
    } else {
      cartesian &&
        isAdsorption &&
        (_cartesian = this._getAdsorptionPosition(
          mousePosition,
          feature,
          distance
        )); //吸附
      if (_cartesian) {
        cartesian = _cartesian;
      }
    }
  } else {
    //模型优先
    if (!objectsToExclude || objectsToExclude.length === 0) {
      feature = this._viewer.scene.pick(mousePosition);
      if (feature && feature.id && !this.id3DGraphic(feature.id)) {
        feature = undefined;
      }
    } else {
      feature = this._viewer.scene.drillPick(
        mousePosition,
        (objectsToExclude &&
          objectsToExclude.length &&
          objectsToExclude.length + 1) ||
        1,
        width,
        width
      );
      feature = this.getNotExcludedObj(feature, objectsToExclude);
    }
    if (feature && !isAdsorption) {
      this._viewer.scene.pick(mousePosition);
      cartesian = this._viewer.scene.pickPosition(mousePosition);
    } else if (feature && isAdsorption) {
      this._viewer.scene.pick(mousePosition);
      cartesian = this._viewer.scene.pickPosition(mousePosition);
      _cartesian = this._getAdsorptionPosition(
        mousePosition,
        feature,
        distance
      ); //吸附
      if (_cartesian) {
        cartesian = _cartesian;
      }
    } else {
      //开启深度检测
      this._viewer.scene.globe.depthTestAgainstTerrain = true;
      ray = this._viewer.camera.getPickRay(mousePosition);
      ray &&
        (cartesian = this._viewer.scene.globe.pick(ray, this._viewer.scene));
    }
  }
  this._viewer.scene.globe.depthTestAgainstTerrain = !!this.defaultDepthTest;
  this.defaultDepthTest = undefined;

  if (!cartesian) {
    console.log("未拾取到坐标!");
    return;
  }

  var cartographic = this._cesium.Cartographic.fromCartesian(cartesian);
  return {
    lon: this._cesium.Math.toDegrees(cartographic.longitude),
    lat: this._cesium.Math.toDegrees(cartographic.latitude),
    height: cartographic.height
  };
};

//判断是否是三维图形
getPosition.prototype.id3DGraphic = function (graphic) {
  let threeD = true;
  if (graphic.polyline || graphic.point || graphic.label || graphic.billboard) {
    threeD = false;
  } else if (graphic.polygon && graphic.polygon.extrudedHeight == undefined) {
    threeD = false;
  } else if (
    graphic.rectangle &&
    graphic.rectangle.extrudedHeight == undefined
  ) {
    threeD = false;
  } else if (graphic.ellipse && graphic.ellipse.extrudedHeight == undefined) {
    threeD = false;
  } else if (graphic.corridor && graphic.corridor.extrudedHeight == undefined) {
    threeD = false;
  }
  return threeD;
};

//吸附坐标-屏幕坐标
getPosition.prototype.getAdsorptionPosition = function (
  mousePosition,
  objectsToExclude
) {
  var dis = 5; //吸附半径
  var ave = 3; //采样数
  var object = this._viewer.scene.drillPick(
    mousePosition,
    (objectsToExclude &&
      objectsToExclude.length &&
      objectsToExclude.length + 1) ||
    3,
    dis + 3,
    dis + 3
  ); //3为默认拾取范围
  var need = false;
  for (var i = 0; i < object.length; i++) {
    if (object[i] && !this.isExcluded(object[i], objectsToExclude)) {
      need = true;
      break;
    }
  }

  if (need) {
    object = this._viewer.scene.pick(mousePosition, 1, 1);
    if (object && !this.isExcluded(object, objectsToExclude)) {
      return mousePosition;
    }
    for (var i = dis / ave; i <= dis; i += dis / ave) {
      object = this._viewer.scene.pick(
        { x: mousePosition.x + i, y: mousePosition.y },
        1,
        1
      );
      if (object && !this.isExcluded(object, objectsToExclude)) {
        return { x: mousePosition.x + i, y: mousePosition.y };
      }
    }
    for (var i = dis / ave; i <= dis; i += dis / ave) {
      object = this._viewer.scene.pick(
        { x: mousePosition.x + i, y: mousePosition.y + i },
        1,
        1
      );
      if (object && !this.isExcluded(object, objectsToExclude)) {
        return { x: mousePosition.x + i, y: mousePosition.y + i };
      }
    }
    for (var i = dis / ave; i <= dis; i += dis / ave) {
      object = this._viewer.scene.pick(
        { x: mousePosition.x, y: mousePosition.y + i },
        1,
        1
      );
      if (object && !this.isExcluded(object, objectsToExclude)) {
        return { x: mousePosition.x, y: mousePosition.y + i };
      }
    }
    for (var i = dis / ave; i <= dis; i += dis / ave) {
      object = this._viewer.scene.pick(
        { x: mousePosition.x - i, y: mousePosition.y + i },
        1,
        1
      );
      if (object && !this.isExcluded(object, objectsToExclude)) {
        return { x: mousePosition.x - i, y: mousePosition.y + i };
      }
    }
    for (var i = dis / ave; i <= dis; i += dis / ave) {
      object = this._viewer.scene.pick(
        { x: mousePosition.x - i, y: mousePosition.y },
        1,
        1
      );
      if (object && !this.isExcluded(object, objectsToExclude)) {
        return { x: mousePosition.x - i, y: mousePosition.y };
      }
    }
    for (var i = dis / ave; i <= dis; i += dis / ave) {
      object = this._viewer.scene.pick(
        { x: mousePosition.x - i, y: mousePosition.y - i },
        1,
        1
      );
      if (object && !this.isExcluded(object, objectsToExclude)) {
        return { x: mousePosition.x - i, y: mousePosition.y - i };
      }
    }
    for (var i = dis / ave; i <= dis; i += dis / ave) {
      object = this._viewer.scene.pick(
        { x: mousePosition.x, y: mousePosition.y - i },
        1,
        1
      );
      if (object && !this.isExcluded(object, objectsToExclude)) {
        return { x: mousePosition.x, y: mousePosition.y - i };
      }
    }
    for (var i = dis / ave; i <= dis; i += dis / ave) {
      object = this._viewer.scene.pick(
        { x: mousePosition.x + i, y: mousePosition.y - i },
        1,
        1
      );
      if (object && !this.isExcluded(object, objectsToExclude)) {
        return { x: mousePosition.x + i, y: mousePosition.y - i };
      }
    }
  }
  return mousePosition;
};

//吸附坐标
getPosition.prototype._getAdsorptionPosition = function (
  mousePosition,
  feature,
  distance
) {
  var dis = distance ? distance : 30; //吸附半径

  if (feature) {
    feature = this.getFeature(feature);
    var _PosArr = [];
    var CanvasCoordinates;
    for (var i = 0; i < feature.position.length; i++) {
      CanvasCoordinates = this._viewer.scene.cartesianToCanvasCoordinates(
        feature.position[i]
      );
      if (CanvasCoordinates) {
        CanvasCoordinates.index = i;
        _PosArr.push(CanvasCoordinates);
      }
    }
    var compare = function (obj1, obj2) {
      var val1 = obj1.x;
      var val2 = obj2.x;
      if (val1 < val2) {
        return -1;
      } else if (val1 > val2) {
        return 1;
      } else {
        return 0;
      }
    };
    _PosArr = _PosArr.sort(compare);
    if (_PosArr && _PosArr.length > 1) {
      //二分法算最接近下标
      var n = Math.log(_PosArr.length) / Math.log(2);
      var m = 0;
      var maxn = _PosArr.length;
      var minn = 0;
      var zd = -1;

      for (var i = 0; i < n; i++) {
        m = Math.floor((maxn + minn) / 2);
        if (mousePosition.x - _PosArr[m].x > dis) {
          minn = m;
        } else if (mousePosition.x - _PosArr[m].x < -dis) {
          maxn = m;
        } else if (Math.abs(mousePosition.x - _PosArr[m].x) < dis) {
          zd = m;
          break;
        }
      }
      if (zd !== -1) {
        for (var i = m; i < maxn; i++) {
          if (Math.abs(mousePosition.x - _PosArr[i].x) > dis) {
            maxn = i;
            break;
          }
        }
        for (var i = m; i > minn; i--) {
          if (Math.abs(mousePosition.x - _PosArr[i].x) > dis) {
            minn = i + 1;
            break;
          }
        }
        for (var i = minn; i < maxn; i++) {
          if (Math.abs(mousePosition.y - _PosArr[i].y) < dis) {
            return feature.position[_PosArr[i].index];
          }
        }
      }
    }
    if (_PosArr && _PosArr.length === 1) {
      if (
        Math.abs(mousePosition.x - _PosArr[0].x) < dis &&
        Math.abs(mousePosition.y - _PosArr[0].y) < dis
      ) {
        return feature.position[0];
      }
    }
  }
};

getPosition.prototype.getFeature = function (obj) {
  var position;
  var data = {
    position: [],
    object: []
  };
  if (obj && obj.id) {
    if (obj.id instanceof this._cesium.Entity) {
      var entity = obj.id;
      if (entity.billboard) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "billboard",
          feature: entity.billboard
        });
      }
      if (entity.box) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "box",
          feature: entity.box
        });
      }
      if (entity.corridor) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "corridor",
          feature: entity.corridor
        });
      }
      if (entity.cylinder) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "cylinder",
          feature: entity.cylinder
        });
      }
      if (entity.ellipse) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "ellipse",
          feature: entity.ellipse
        });
      }
      if (entity.ellipsoid) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "ellipsoid",
          feature: entity.ellipsoid
        });
      }
      if (entity.label) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "label",
          feature: entity.label
        });
      }
      if (entity.model) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "model",
          feature: entity.model
        });
      }
      if (entity.path) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "path",
          feature: entity.path
        });
      }
      if (entity.plane) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "plane",
          feature: entity.plane
        });
      }
      if (entity.point) {
        position = entity.position.getValue(this._viewer.clock.currentTime);
        data.position.push(position);
        data.object.push({
          type: "point",
          feature: entity.point
        });
      }
      if (entity.polygon) {
        position = entity.polygon.hierarchy.getValue(
          this._viewer.clock.currentTime
        );
        data.position = data.position.concat(position.positions);
        data.object.push({
          type: "polygon",
          feature: entity.polygon
        });
      }
      if (entity.polyline) {
        position = entity.polyline.positions.getValue(
          this._viewer.clock.currentTime
        );
        data.position = data.position.concat(position);
        data.object.push({
          type: "polyline",
          feature: entity.polyline
        });
      }
      if (entity.polylineVolume) {
        position = entity.polylineVolume.positions.getValue(
          this._viewer.clock.currentTime
        );
        data.position = data.position.concat(position);
        data.object.push({
          type: "polylineVolume",
          feature: entity.polylineVolume
        });
      }
      if (entity.rectangle) {
        position = entity.rectangle.coordinates.getValue(
          this._viewer.clock.currentTime
        );
        data.position = data.position.concat(position);
        data.object.push({
          type: "rectangle",
          feature: entity.rectangle
        });
      }
      if (entity.wall) {
        position = entity.wall.positions.getValue(
          this._viewer.clock.currentTime
        );
        data.position = data.position.concat(position);
        data.object.push({
          type: "wall",
          feature: entity.wall
        });
      }
    }
  }
  if (obj && obj.primitive) {
    if (obj.primitive instanceof this._cesium.Model) {
      position = obj.primitive.positionObj;
      data.position.push(position);
      data.object.push({
        type: "model",
        feature: obj.primitive
      });
    }
  }
  return data;
};

//是否包含对象
getPosition.prototype.isExcluded = function (object, objectsToExclude) {
  if (
    !this._cesium.defined(object) ||
    !this._cesium.defined(objectsToExclude) ||
    objectsToExclude.length === 0
  ) {
    return false;
  }
  return (
    objectsToExclude.indexOf(object) > -1 ||
    objectsToExclude.indexOf(object.primitive) > -1 ||
    objectsToExclude.indexOf(object.id) > -1
  );
};

//获取不包含的对象
getPosition.prototype.getNotExcludedObj = function (
  objectOrArr,
  objectsToExclude
) {
  if (objectOrArr.length === 0) {
    return false;
  } else if (
    !this._cesium.defined(objectsToExclude) ||
    objectsToExclude.length === 0
  ) {
    return objectOrArr;
  }
  for (var i = 0; i < objectOrArr.length; i++) {
    if (objectOrArr[i] && !this.isExcluded(objectOrArr[i], objectsToExclude)) {
      return objectOrArr[i];
    }
  }
  return false;
};

//控制对象显隐
getPosition.prototype.isObjectsToExcludeShow = function (
  objectsToExclude,
  isShow
) {
  if (
    !this._cesium.defined(objectsToExclude) ||
    objectsToExclude.length === 0
  ) {
    return;
  }
  if (objectsToExclude instanceof Array) {
    objectsToExclude.forEach(function (item) {
      item.show = isShow;
    });
  } else {
    objectsToExclude.show = isShow;
  }
};
export default getPosition;
调用方法
  
   const _dynamicObject = new dynamicObject(window.viewer, Cesium);
  
  _dynamicObject.executeFlycesium(data => {
    data.showPoint = true;
    data.showLine = true;
    data.mode = 2; // 飞行模式
    _dynamicObject.Start(data, data.url);
  });