@cesium/engine
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
244 lines (214 loc) • 6.44 kB
JavaScript
import Cartesian3 from "../Core/Cartesian3.js";
import Cartographic from "../Core/Cartographic.js";
import Check from "../Core/Check.js";
import defined from "../Core/defined.js";
import destroyObject from "../Core/destroyObject.js";
import Event from "../Core/Event.js";
import Iso8601 from "../Core/Iso8601.js";
import JulianDate from "../Core/JulianDate.js";
import CesiumMath from "../Core/Math.js";
import HeightReference, {
isHeightReferenceRelative,
} from "../Scene/HeightReference.js";
import Property from "./Property.js";
const scratchPosition = new Cartesian3();
/**
* @private
*/
function TerrainOffsetProperty(
scene,
positionProperty,
heightReferenceProperty,
extrudedHeightReferenceProperty,
) {
//>>includeStart('debug', pragmas.debug);
Check.defined("scene", scene);
Check.defined("positionProperty", positionProperty);
//>>includeEnd('debug');
this._scene = scene;
this._heightReference = heightReferenceProperty;
this._extrudedHeightReference = extrudedHeightReferenceProperty;
this._positionProperty = positionProperty;
this._position = new Cartesian3();
this._cartographicPosition = new Cartographic();
this._normal = new Cartesian3();
this._definitionChanged = new Event();
this._terrainHeight = 0;
this._removeCallbackFunc = undefined;
this._removeEventListener = undefined;
this._removeModeListener = undefined;
const that = this;
if (defined(scene.globe)) {
this._removeEventListener = scene.terrainProviderChanged.addEventListener(
function () {
that._updateClamping();
},
);
this._removeModeListener = scene.morphComplete.addEventListener(
function () {
that._updateClamping();
},
);
}
if (positionProperty.isConstant) {
const position = positionProperty.getValue(
Iso8601.MINIMUM_VALUE,
scratchPosition,
);
if (
!defined(position) ||
Cartesian3.equals(position, Cartesian3.ZERO) ||
!defined(scene.globe)
) {
return;
}
this._position = Cartesian3.clone(position, this._position);
this._updateClamping();
this._normal = scene.ellipsoid.geodeticSurfaceNormal(
position,
this._normal,
);
}
}
Object.defineProperties(TerrainOffsetProperty.prototype, {
/**
* Gets a value indicating if this property is constant.
* @memberof TerrainOffsetProperty.prototype
*
* @type {boolean}
* @readonly
*/
isConstant: {
get: function () {
return false;
},
},
/**
* Gets the event that is raised whenever the definition of this property changes.
* @memberof TerrainOffsetProperty.prototype
*
* @type {Event}
* @readonly
*/
definitionChanged: {
get: function () {
return this._definitionChanged;
},
},
});
/**
* @private
*/
TerrainOffsetProperty.prototype._updateClamping = function () {
if (defined(this._removeCallbackFunc)) {
this._removeCallbackFunc();
}
const scene = this._scene;
const position = this._position;
if (Cartesian3.equals(position, Cartesian3.ZERO)) {
this._terrainHeight = 0;
return;
}
const ellipsoid = scene.ellipsoid;
const cartographicPosition = ellipsoid.cartesianToCartographic(
position,
this._cartographicPosition,
);
const height = scene.getHeight(cartographicPosition, this._heightReference);
if (defined(height)) {
this._terrainHeight = height;
} else {
this._terrainHeight = 0;
}
const updateFunction = (clampedPosition) => {
this._terrainHeight = clampedPosition.height;
this.definitionChanged.raiseEvent();
};
this._removeCallbackFunc = scene.updateHeight(
cartographicPosition,
updateFunction,
this._heightReference,
);
};
const timeScratch = new JulianDate();
/**
* Gets the height relative to the terrain based on the positions.
*
* @param {JulianDate} [time=JulianDate.now()] The time for which to retrieve the value. If omitted, the current system time is used.
* @param {object} [result] The object to store the value into, if omitted, a new instance is created and returned.
* @returns {Cartesian3} The offset
*/
TerrainOffsetProperty.prototype.getValue = function (time, result) {
if (!defined(time)) {
time = JulianDate.now(timeScratch);
}
const heightReference = Property.getValueOrDefault(
this._heightReference,
time,
HeightReference.NONE,
);
const extrudedHeightReference = Property.getValueOrDefault(
this._extrudedHeightReference,
time,
HeightReference.NONE,
);
if (
heightReference === HeightReference.NONE &&
!isHeightReferenceRelative(extrudedHeightReference)
) {
this._position = Cartesian3.clone(Cartesian3.ZERO, this._position);
return Cartesian3.clone(Cartesian3.ZERO, result);
}
if (this._positionProperty.isConstant) {
return Cartesian3.multiplyByScalar(
this._normal,
this._terrainHeight,
result,
);
}
const scene = this._scene;
const position = this._positionProperty.getValue(time, scratchPosition);
if (
!defined(position) ||
Cartesian3.equals(position, Cartesian3.ZERO) ||
!defined(scene.globe)
) {
return Cartesian3.clone(Cartesian3.ZERO, result);
}
if (
Cartesian3.equalsEpsilon(this._position, position, CesiumMath.EPSILON10)
) {
return Cartesian3.multiplyByScalar(
this._normal,
this._terrainHeight,
result,
);
}
this._position = Cartesian3.clone(position, this._position);
this._updateClamping();
const normal = scene.ellipsoid.geodeticSurfaceNormal(position, this._normal);
return Cartesian3.multiplyByScalar(normal, this._terrainHeight, result);
};
TerrainOffsetProperty.prototype.isDestroyed = function () {
return false;
};
TerrainOffsetProperty.prototype.destroy = function () {
if (defined(this._removeEventListener)) {
this._removeEventListener();
}
if (defined(this._removeModeListener)) {
this._removeModeListener();
}
if (defined(this._removeCallbackFunc)) {
this._removeCallbackFunc();
}
return destroyObject(this);
};
/**
* A function which creates one or more providers.
* @callback TerrainOffsetProperty.PositionFunction
* @param {JulianDate} time The clock time at which to retrieve the position
* @param {Cartesian3} result The result position
* @returns {Cartesian3} The position at which to do the terrain height check
*/
export default TerrainOffsetProperty;