cesium
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
244 lines (220 loc) • 9.81 kB
JavaScript
import Cartesian3 from '../Core/Cartesian3.js';
import Color from '../Core/Color.js';
import ColorGeometryInstanceAttribute from '../Core/ColorGeometryInstanceAttribute.js';
import defaultValue from '../Core/defaultValue.js';
import defined from '../Core/defined.js';
import destroyObject from '../Core/destroyObject.js';
import DeveloperError from '../Core/DeveloperError.js';
import FrustumGeometry from '../Core/FrustumGeometry.js';
import FrustumOutlineGeometry from '../Core/FrustumOutlineGeometry.js';
import GeometryInstance from '../Core/GeometryInstance.js';
import Matrix3 from '../Core/Matrix3.js';
import OrthographicFrustum from '../Core/OrthographicFrustum.js';
import OrthographicOffCenterFrustum from '../Core/OrthographicOffCenterFrustum.js';
import PerspectiveFrustum from '../Core/PerspectiveFrustum.js';
import PerspectiveOffCenterFrustum from '../Core/PerspectiveOffCenterFrustum.js';
import Quaternion from '../Core/Quaternion.js';
import PerInstanceColorAppearance from './PerInstanceColorAppearance.js';
import Primitive from './Primitive.js';
/**
* Draws the outline of the camera's view frustum.
*
* @alias DebugCameraPrimitive
* @constructor
*
* @param {Object} options Object with the following properties:
* @param {Camera} options.camera The camera.
* @param {Color} [options.color=Color.CYAN] The color of the debug outline.
* @param {Boolean} [options.updateOnChange=true] Whether the primitive updates when the underlying camera changes.
* @param {Boolean} [options.show=true] Determines if this primitive will be shown.
* @param {Object} [options.id] A user-defined object to return when the instance is picked with {@link Scene#pick}.
*
* @example
* primitives.add(new Cesium.DebugCameraPrimitive({
* camera : camera,
* color : Cesium.Color.YELLOW
* }));
*/
function DebugCameraPrimitive(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
//>>includeStart('debug', pragmas.debug);
if (!defined(options.camera)) {
throw new DeveloperError('options.camera is required.');
}
//>>includeEnd('debug');
this._camera = options.camera;
this._color = defaultValue(options.color, Color.CYAN);
this._updateOnChange = defaultValue(options.updateOnChange, true);
/**
* Determines if this primitive will be shown.
*
* @type Boolean
* @default true
*/
this.show = defaultValue(options.show, true);
/**
* User-defined value returned when the primitive is picked.
*
* @type {*}
* @default undefined
*
* @see Scene#pick
*/
this.id = options.id;
this._id = undefined;
this._outlinePrimitives = [];
this._planesPrimitives = [];
}
var scratchRight = new Cartesian3();
var scratchRotation = new Matrix3();
var scratchOrientation = new Quaternion();
var scratchPerspective = new PerspectiveFrustum();
var scratchPerspectiveOffCenter = new PerspectiveOffCenterFrustum();
var scratchOrthographic = new OrthographicFrustum();
var scratchOrthographicOffCenter = new OrthographicOffCenterFrustum();
var scratchColor = new Color();
var scratchSplits = [1.0, 100000.0];
/**
* @private
*/
DebugCameraPrimitive.prototype.update = function(frameState) {
if (!this.show) {
return;
}
var planesPrimitives = this._planesPrimitives;
var outlinePrimitives = this._outlinePrimitives;
var i;
var length;
if (this._updateOnChange) {
// Recreate the primitive every frame
length = planesPrimitives.length;
for (i = 0; i < length; ++i) {
outlinePrimitives[i] = outlinePrimitives[i] && outlinePrimitives[i].destroy();
planesPrimitives[i] = planesPrimitives[i] && planesPrimitives[i].destroy();
}
planesPrimitives.length = 0;
outlinePrimitives.length = 0;
}
if (planesPrimitives.length === 0) {
var camera = this._camera;
var cameraFrustum = camera.frustum;
var frustum;
if (cameraFrustum instanceof PerspectiveFrustum) {
frustum = scratchPerspective;
} else if (cameraFrustum instanceof PerspectiveOffCenterFrustum) {
frustum = scratchPerspectiveOffCenter;
} else if (cameraFrustum instanceof OrthographicFrustum) {
frustum = scratchOrthographic;
} else {
frustum = scratchOrthographicOffCenter;
}
frustum = cameraFrustum.clone(frustum);
var frustumSplits = frameState.frustumSplits;
var numFrustums = frustumSplits.length - 1;
if (numFrustums <= 0) {
frustumSplits = scratchSplits; // Use near and far planes if no splits created
frustumSplits[0] = this._camera.frustum.near;
frustumSplits[1] = this._camera.frustum.far;
numFrustums = 1;
}
var position = camera.positionWC;
var direction = camera.directionWC;
var up = camera.upWC;
var right = camera.rightWC;
right = Cartesian3.negate(right, scratchRight);
var rotation = scratchRotation;
Matrix3.setColumn(rotation, 0, right, rotation);
Matrix3.setColumn(rotation, 1, up, rotation);
Matrix3.setColumn(rotation, 2, direction, rotation);
var orientation = Quaternion.fromRotationMatrix(rotation, scratchOrientation);
planesPrimitives.length = outlinePrimitives.length = numFrustums;
for (i = 0; i < numFrustums; ++i) {
frustum.near = frustumSplits[i];
frustum.far = frustumSplits[i + 1];
planesPrimitives[i] = new Primitive({
geometryInstances : new GeometryInstance({
geometry : new FrustumGeometry({
origin : position,
orientation : orientation,
frustum : frustum,
_drawNearPlane : i === 0
}),
attributes : {
color : ColorGeometryInstanceAttribute.fromColor(Color.fromAlpha(this._color, 0.1, scratchColor))
},
id : this.id,
pickPrimitive : this
}),
appearance : new PerInstanceColorAppearance({
translucent : true,
flat : true
}),
asynchronous : false
});
outlinePrimitives[i] = new Primitive({
geometryInstances : new GeometryInstance({
geometry : new FrustumOutlineGeometry({
origin : position,
orientation : orientation,
frustum : frustum,
_drawNearPlane : i === 0
}),
attributes : {
color : ColorGeometryInstanceAttribute.fromColor(this._color)
},
id : this.id,
pickPrimitive : this
}),
appearance : new PerInstanceColorAppearance({
translucent : false,
flat : true
}),
asynchronous : false
});
}
}
length = planesPrimitives.length;
for (i = 0; i < length; ++i) {
outlinePrimitives[i].update(frameState);
planesPrimitives[i].update(frameState);
}
};
/**
* Returns true if this object was destroyed; otherwise, false.
* <p>
* If this object was destroyed, it should not be used; calling any function other than
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
* </p>
*
* @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
*
* @see DebugCameraPrimitive#destroy
*/
DebugCameraPrimitive.prototype.isDestroyed = function() {
return false;
};
/**
* Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
* release of WebGL resources, instead of relying on the garbage collector to destroy this object.
* <p>
* Once an object is destroyed, it should not be used; calling any function other than
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
* assign the return value (<code>undefined</code>) to the object as done in the example.
* </p>
*
* @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
*
* @example
* p = p && p.destroy();
*
* @see DebugCameraPrimitive#isDestroyed
*/
DebugCameraPrimitive.prototype.destroy = function() {
var length = this._planesPrimitives.length;
for (var i = 0; i < length; ++i) {
this._outlinePrimitives[i] = this._outlinePrimitives[i] && this._outlinePrimitives[i].destroy();
this._planesPrimitives[i] = this._planesPrimitives[i] && this._planesPrimitives[i].destroy();
}
return destroyObject(this);
};
export default DebugCameraPrimitive;