@cesium/engine
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
215 lines (189 loc) • 5.48 kB
JavaScript
import Check from "../../Core/Check.js";
import Frozen from "../../Core/Frozen.js";
import defined from "../../Core/defined.js";
import Matrix4 from "../../Core/Matrix4.js";
import ModelArticulationStage from "./ModelArticulationStage.js";
/**
* An in-memory representation of an articulation that affects nodes in the
* {@link ModelSceneGraph}. This is defined in a model by the
* <code>AGI_articulations</code> extension.
*
* @param {object} options An object containing the following options:
* @param {ModelComponents.Articulation} options.articulation The articulation components from the 3D model.
* @param {ModelSceneGraph} options.sceneGraph The scene graph this articulation belongs to.
*
* @alias ModelArticulation
* @constructor
*
* @private
*/
function ModelArticulation(options) {
options = options ?? Frozen.EMPTY_OBJECT;
const articulation = options.articulation;
const sceneGraph = options.sceneGraph;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.articulation", articulation);
Check.typeOf.object("options.sceneGraph", sceneGraph);
//>>includeEnd('debug');
this._articulation = articulation;
this._sceneGraph = sceneGraph;
this._name = articulation.name;
this._runtimeStages = [];
this._runtimeStagesByName = {};
// Will be populated as the runtime nodes are created
this._runtimeNodes = [];
// Set to true so that the first call to
// ModelSceneGraph.applyArticulations will work.
this._dirty = true;
initialize(this);
}
Object.defineProperties(ModelArticulation.prototype, {
/**
* The internal articulation that this runtime articulation represents.
*
* @memberof ModelArticulation.prototype
* @type {ModelComponents.Articulation}
* @readonly
*
* @private
*/
articulation: {
get: function () {
return this._articulation;
},
},
/**
* The scene graph that this articulation belongs to.
*
* @memberof ModelArticulation.prototype
* @type {ModelSceneGraph}
* @readonly
*
* @private
*/
sceneGraph: {
get: function () {
return this._sceneGraph;
},
},
/**
* The name of this articulation.
*
* @memberof ModelArticulation.prototype
* @type {string}
* @readonly
*
* @private
*/
name: {
get: function () {
return this._name;
},
},
/**
* The runtime stages that belong to this articulation.
*
* @memberof ModelArticulation.prototype
* @type {ModelArticulationStage[]}
* @readonly
*
* @private
*/
runtimeStages: {
get: function () {
return this._runtimeStages;
},
},
/**
* The runtime nodes that are affected by this articulation.
*
* @memberof ModelArticulation.prototype
* @type {ModelRuntimeNode[]}
* @readonly
*
* @private
*/
runtimeNodes: {
get: function () {
return this._runtimeNodes;
},
},
});
function initialize(runtimeArticulation) {
const articulation = runtimeArticulation.articulation;
const stages = articulation.stages;
const length = stages.length;
const runtimeStages = runtimeArticulation._runtimeStages;
const runtimeStagesByName = runtimeArticulation._runtimeStagesByName;
for (let i = 0; i < length; i++) {
const stage = stages[i];
const runtimeStage = new ModelArticulationStage({
stage: stage,
runtimeArticulation: runtimeArticulation,
});
// Store the stages in an array to preserve the order in which
// they appeared in the 3D model.
runtimeStages.push(runtimeStage);
// Store the stages in a dictionary for retrieval by name.
const stageName = stage.name;
runtimeStagesByName[stageName] = runtimeStage;
}
}
/**
* Sets the current value of an articulation stage.
*
* @param {string} stageName The name of the articulation stage.
* @param {number} value The numeric value of this stage of the articulation.
*
* @private
*/
ModelArticulation.prototype.setArticulationStage = function (stageName, value) {
const stage = this._runtimeStagesByName[stageName];
if (defined(stage)) {
stage.currentValue = value;
}
};
const scratchArticulationMatrix = new Matrix4();
const scratchNodeMatrix = new Matrix4();
/**
* Applies the chain of articulation stages to the transform of each node that
* participates in the articulation. This only recomputes the node transforms
* if any stage in the articulation has been modified.
* <p>
* Note that this will overwrite any existing transformations on participating
* nodes.
* </p>
*
* @private
*/
ModelArticulation.prototype.apply = function () {
if (!this._dirty) {
return;
}
this._dirty = false;
let articulationMatrix = Matrix4.clone(
Matrix4.IDENTITY,
scratchArticulationMatrix,
);
let i;
const stages = this._runtimeStages;
const stagesLength = stages.length;
// Compute the result of the articulation stages...
for (i = 0; i < stagesLength; i++) {
const stage = stages[i];
articulationMatrix = stage.applyStageToMatrix(articulationMatrix);
}
// ...then apply it to the transforms of the affected nodes.
const nodes = this._runtimeNodes;
const nodesLength = nodes.length;
for (i = 0; i < nodesLength; i++) {
const node = nodes[i];
const transform = Matrix4.multiplyTransformation(
node.originalTransform,
articulationMatrix,
scratchNodeMatrix,
);
node.transform = transform;
}
};
export default ModelArticulation;