Add existing to tracked
This commit is contained in:
+476
@@ -0,0 +1,476 @@
|
||||
import Cartesian3 from "../Core/Cartesian3.js";
|
||||
import Check from "../Core/Check.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 Quaternion from "../Core/Quaternion.js";
|
||||
import TrackingReferenceFrame from "../Core/TrackingReferenceFrame.js";
|
||||
import Transforms from "../Core/Transforms.js";
|
||||
import SceneMode from "../Scene/SceneMode.js";
|
||||
import VelocityVectorProperty from "./VelocityVectorProperty.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 updateTransformOrientationScratch = new Quaternion();
|
||||
const velocityScratch = new Cartesian3();
|
||||
const rotationScratch = new Matrix3();
|
||||
const deltaTime = new JulianDate();
|
||||
const northUpAxisFactor = 1.25; // times ellipsoid's maximum radius
|
||||
|
||||
function updateTransform(
|
||||
that,
|
||||
camera,
|
||||
updateLookAt,
|
||||
saveCamera,
|
||||
positionProperty,
|
||||
velocityProperty,
|
||||
orientationProperty,
|
||||
trackingReferenceFrame,
|
||||
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;
|
||||
|
||||
let orientation;
|
||||
if (defined(orientationProperty)) {
|
||||
orientation = orientationProperty.getValue(
|
||||
time,
|
||||
updateTransformOrientationScratch,
|
||||
);
|
||||
}
|
||||
|
||||
const velocity = velocityProperty.getValue(time, velocityScratch);
|
||||
|
||||
if (
|
||||
trackingReferenceFrame === TrackingReferenceFrame.INERTIAL &&
|
||||
defined(orientation)
|
||||
) {
|
||||
Matrix4.fromTranslationQuaternionRotationScale(
|
||||
cartesian,
|
||||
orientation,
|
||||
Cartesian3.ONE,
|
||||
transform,
|
||||
);
|
||||
} else if (
|
||||
trackingReferenceFrame === TrackingReferenceFrame.VELOCITY &&
|
||||
defined(velocity)
|
||||
) {
|
||||
const rotation = Transforms.rotationMatrixFromPositionVelocity(
|
||||
cartesian,
|
||||
velocity,
|
||||
ellipsoid,
|
||||
rotationScratch,
|
||||
);
|
||||
Matrix4.fromRotationTranslation(rotation, cartesian, transform);
|
||||
} else if (
|
||||
trackingReferenceFrame === TrackingReferenceFrame.ENU ||
|
||||
!hasBasis
|
||||
) {
|
||||
Transforms.eastNorthUpToFixedFrame(cartesian, ellipsoid, transform);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
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.default] 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 = ellipsoid ?? Ellipsoid.default;
|
||||
|
||||
/**
|
||||
* 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._velocityProperty = new VelocityVectorProperty(entity.position, true);
|
||||
|
||||
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 trackingReferenceFrame = entity.trackingReferenceFrame;
|
||||
const positionProperty = entity.position;
|
||||
if (!defined(positionProperty)) {
|
||||
return;
|
||||
}
|
||||
const velocityProperty = this._velocityProperty;
|
||||
const orientationProperty = entity.orientation;
|
||||
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,
|
||||
velocityProperty,
|
||||
orientationProperty,
|
||||
trackingReferenceFrame,
|
||||
time,
|
||||
ellipsoid,
|
||||
);
|
||||
};
|
||||
export default EntityView;
|
||||
Reference in New Issue
Block a user