| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 | import Cartesian3 from "../Core/Cartesian3.js";import Check from "../Core/Check.js";import defaultValue from "../Core/defaultValue.js";import defined from "../Core/defined.js";import Ellipsoid from "../Core/Ellipsoid.js";import HeadingPitchRange from "../Core/HeadingPitchRange.js";import JulianDate from "../Core/JulianDate.js";import CesiumMath from "../Core/Math.js";import Matrix3 from "../Core/Matrix3.js";import Matrix4 from "../Core/Matrix4.js";import Transforms from "../Core/Transforms.js";import SceneMode from "../Scene/SceneMode.js";const updateTransformMatrix3Scratch1 = new Matrix3();const updateTransformMatrix3Scratch2 = new Matrix3();const updateTransformMatrix3Scratch3 = new Matrix3();const updateTransformMatrix4Scratch = new Matrix4();const updateTransformCartesian3Scratch1 = new Cartesian3();const updateTransformCartesian3Scratch2 = new Cartesian3();const updateTransformCartesian3Scratch3 = new Cartesian3();const updateTransformCartesian3Scratch4 = new Cartesian3();const updateTransformCartesian3Scratch5 = new Cartesian3();const updateTransformCartesian3Scratch6 = new Cartesian3();const deltaTime = new JulianDate();const northUpAxisFactor = 1.25; // times ellipsoid's maximum radiusfunction updateTransform(  that,  camera,  updateLookAt,  saveCamera,  positionProperty,  time,  ellipsoid) {  const mode = that.scene.mode;  let cartesian = positionProperty.getValue(time, that._lastCartesian);  if (defined(cartesian)) {    let hasBasis = false;    let invertVelocity = false;    let xBasis;    let yBasis;    let zBasis;    if (mode === SceneMode.SCENE3D) {      // The time delta was determined based on how fast satellites move compared to vehicles near the surface.      // Slower moving vehicles will most likely default to east-north-up, while faster ones will be VVLH.      JulianDate.addSeconds(time, 0.001, deltaTime);      let deltaCartesian = positionProperty.getValue(        deltaTime,        updateTransformCartesian3Scratch1      );      // If no valid position at (time + 0.001), sample at (time - 0.001) and invert the vector      if (!defined(deltaCartesian)) {        JulianDate.addSeconds(time, -0.001, deltaTime);        deltaCartesian = positionProperty.getValue(          deltaTime,          updateTransformCartesian3Scratch1        );        invertVelocity = true;      }      if (defined(deltaCartesian)) {        let toInertial = Transforms.computeFixedToIcrfMatrix(          time,          updateTransformMatrix3Scratch1        );        let toInertialDelta = Transforms.computeFixedToIcrfMatrix(          deltaTime,          updateTransformMatrix3Scratch2        );        let toFixed;        if (!defined(toInertial) || !defined(toInertialDelta)) {          toFixed = Transforms.computeTemeToPseudoFixedMatrix(            time,            updateTransformMatrix3Scratch3          );          toInertial = Matrix3.transpose(            toFixed,            updateTransformMatrix3Scratch1          );          toInertialDelta = Transforms.computeTemeToPseudoFixedMatrix(            deltaTime,            updateTransformMatrix3Scratch2          );          Matrix3.transpose(toInertialDelta, toInertialDelta);        } else {          toFixed = Matrix3.transpose(            toInertial,            updateTransformMatrix3Scratch3          );        }        const inertialCartesian = Matrix3.multiplyByVector(          toInertial,          cartesian,          updateTransformCartesian3Scratch5        );        const inertialDeltaCartesian = Matrix3.multiplyByVector(          toInertialDelta,          deltaCartesian,          updateTransformCartesian3Scratch6        );        Cartesian3.subtract(          inertialCartesian,          inertialDeltaCartesian,          updateTransformCartesian3Scratch4        );        const inertialVelocity =          Cartesian3.magnitude(updateTransformCartesian3Scratch4) * 1000.0; // meters/sec        const mu = CesiumMath.GRAVITATIONALPARAMETER; // m^3 / sec^2        const semiMajorAxis =          -mu /          (inertialVelocity * inertialVelocity -            (2 * mu) / Cartesian3.magnitude(inertialCartesian));        if (          semiMajorAxis < 0 ||          semiMajorAxis > northUpAxisFactor * ellipsoid.maximumRadius        ) {          // North-up viewing from deep space.          // X along the nadir          xBasis = updateTransformCartesian3Scratch2;          Cartesian3.normalize(cartesian, xBasis);          Cartesian3.negate(xBasis, xBasis);          // Z is North          zBasis = Cartesian3.clone(            Cartesian3.UNIT_Z,            updateTransformCartesian3Scratch3          );          // Y is along the cross of z and x (right handed basis / in the direction of motion)          yBasis = Cartesian3.cross(            zBasis,            xBasis,            updateTransformCartesian3Scratch1          );          if (Cartesian3.magnitude(yBasis) > CesiumMath.EPSILON7) {            Cartesian3.normalize(xBasis, xBasis);            Cartesian3.normalize(yBasis, yBasis);            zBasis = Cartesian3.cross(              xBasis,              yBasis,              updateTransformCartesian3Scratch3            );            Cartesian3.normalize(zBasis, zBasis);            hasBasis = true;          }        } else if (          !Cartesian3.equalsEpsilon(            cartesian,            deltaCartesian,            CesiumMath.EPSILON7          )        ) {          // Approximation of VVLH (Vehicle Velocity Local Horizontal) with the Z-axis flipped.          // Z along the position          zBasis = updateTransformCartesian3Scratch2;          Cartesian3.normalize(inertialCartesian, zBasis);          Cartesian3.normalize(inertialDeltaCartesian, inertialDeltaCartesian);          // Y is along the angular momentum vector (e.g. "orbit normal")          yBasis = Cartesian3.cross(            zBasis,            inertialDeltaCartesian,            updateTransformCartesian3Scratch3          );          if (invertVelocity) {            yBasis = Cartesian3.multiplyByScalar(yBasis, -1, yBasis);          }          if (            !Cartesian3.equalsEpsilon(              yBasis,              Cartesian3.ZERO,              CesiumMath.EPSILON7            )          ) {            // X is along the cross of y and z (right handed basis / in the direction of motion)            xBasis = Cartesian3.cross(              yBasis,              zBasis,              updateTransformCartesian3Scratch1            );            Matrix3.multiplyByVector(toFixed, xBasis, xBasis);            Matrix3.multiplyByVector(toFixed, yBasis, yBasis);            Matrix3.multiplyByVector(toFixed, zBasis, zBasis);            Cartesian3.normalize(xBasis, xBasis);            Cartesian3.normalize(yBasis, yBasis);            Cartesian3.normalize(zBasis, zBasis);            hasBasis = true;          }        }      }    }    if (defined(that.boundingSphere)) {      cartesian = that.boundingSphere.center;    }    let position;    let direction;    let up;    if (saveCamera) {      position = Cartesian3.clone(        camera.position,        updateTransformCartesian3Scratch4      );      direction = Cartesian3.clone(        camera.direction,        updateTransformCartesian3Scratch5      );      up = Cartesian3.clone(camera.up, updateTransformCartesian3Scratch6);    }    const transform = updateTransformMatrix4Scratch;    if (hasBasis) {      transform[0] = xBasis.x;      transform[1] = xBasis.y;      transform[2] = xBasis.z;      transform[3] = 0.0;      transform[4] = yBasis.x;      transform[5] = yBasis.y;      transform[6] = yBasis.z;      transform[7] = 0.0;      transform[8] = zBasis.x;      transform[9] = zBasis.y;      transform[10] = zBasis.z;      transform[11] = 0.0;      transform[12] = cartesian.x;      transform[13] = cartesian.y;      transform[14] = cartesian.z;      transform[15] = 0.0;    } else {      // Stationary or slow-moving, low-altitude objects use East-North-Up.      Transforms.eastNorthUpToFixedFrame(cartesian, ellipsoid, transform);    }    camera._setTransform(transform);    if (saveCamera) {      Cartesian3.clone(position, camera.position);      Cartesian3.clone(direction, camera.direction);      Cartesian3.clone(up, camera.up);      Cartesian3.cross(direction, up, camera.right);    }  }  if (updateLookAt) {    const offset =      mode === SceneMode.SCENE2D ||      Cartesian3.equals(that._offset3D, Cartesian3.ZERO)        ? undefined        : that._offset3D;    camera.lookAtTransform(camera.transform, offset);  }}/** * A utility object for tracking an entity with the camera. * @alias EntityView * @constructor * * @param {Entity} entity The entity to track with the camera. * @param {Scene} scene The scene to use. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use for orienting the camera. */function EntityView(entity, scene, ellipsoid) {  //>>includeStart('debug', pragmas.debug);  Check.defined("entity", entity);  Check.defined("scene", scene);  //>>includeEnd('debug');  /**   * The entity to track with the camera.   * @type {Entity}   */  this.entity = entity;  /**   * The scene in which to track the object.   * @type {Scene}   */  this.scene = scene;  /**   * The ellipsoid to use for orienting the camera.   * @type {Ellipsoid}   */  this.ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);  /**   * The bounding sphere of the object.   * @type {BoundingSphere}   */  this.boundingSphere = undefined;  // Shadow copies of the objects so we can detect changes.  this._lastEntity = undefined;  this._mode = undefined;  this._lastCartesian = new Cartesian3();  this._defaultOffset3D = undefined;  this._offset3D = new Cartesian3();}// STATIC properties defined here, not per-instance.Object.defineProperties(EntityView, {  /**   * Gets or sets a camera offset that will be used to   * initialize subsequent EntityViews.   * @memberof EntityView   * @type {Cartesian3}   */  defaultOffset3D: {    get: function () {      return this._defaultOffset3D;    },    set: function (vector) {      this._defaultOffset3D = Cartesian3.clone(vector, new Cartesian3());    },  },});// Initialize the static property.EntityView.defaultOffset3D = new Cartesian3(-14000, 3500, 3500);const scratchHeadingPitchRange = new HeadingPitchRange();const scratchCartesian = new Cartesian3();/** * Should be called each animation frame to update the camera * to the latest settings. * @param {JulianDate} time The current animation time. * @param {BoundingSphere} [boundingSphere] bounding sphere of the object. */EntityView.prototype.update = function (time, boundingSphere) {  //>>includeStart('debug', pragmas.debug);  Check.defined("time", time);  //>>includeEnd('debug');  const scene = this.scene;  const ellipsoid = this.ellipsoid;  const sceneMode = scene.mode;  if (sceneMode === SceneMode.MORPHING) {    return;  }  const entity = this.entity;  const positionProperty = entity.position;  if (!defined(positionProperty)) {    return;  }  const objectChanged = entity !== this._lastEntity;  const sceneModeChanged = sceneMode !== this._mode;  const camera = scene.camera;  let updateLookAt = objectChanged || sceneModeChanged;  let saveCamera = true;  if (objectChanged) {    const viewFromProperty = entity.viewFrom;    const hasViewFrom = defined(viewFromProperty);    if (!hasViewFrom && defined(boundingSphere)) {      // The default HPR is not ideal for high altitude objects so      // we scale the pitch as we get further from the earth for a more      // downward view.      scratchHeadingPitchRange.pitch = -CesiumMath.PI_OVER_FOUR;      scratchHeadingPitchRange.range = 0;      const position = positionProperty.getValue(time, scratchCartesian);      if (defined(position)) {        const factor =          2 -          1 /            Math.max(              1,              Cartesian3.magnitude(position) / ellipsoid.maximumRadius            );        scratchHeadingPitchRange.pitch *= factor;      }      camera.viewBoundingSphere(boundingSphere, scratchHeadingPitchRange);      this.boundingSphere = boundingSphere;      updateLookAt = false;      saveCamera = false;    } else if (      !hasViewFrom ||      !defined(viewFromProperty.getValue(time, this._offset3D))    ) {      Cartesian3.clone(EntityView._defaultOffset3D, this._offset3D);    }  } else if (!sceneModeChanged && this._mode !== SceneMode.SCENE2D) {    Cartesian3.clone(camera.position, this._offset3D);  }  this._lastEntity = entity;  this._mode = sceneMode;  updateTransform(    this,    camera,    updateLookAt,    saveCamera,    positionProperty,    time,    ellipsoid  );};export default EntityView;
 |