import BoundingSphere from '../Core/BoundingSphere.js'; import BoxOutlineGeometry from '../Core/BoxOutlineGeometry.js'; import Cartesian3 from '../Core/Cartesian3.js'; import Check from '../Core/Check.js'; import ColorGeometryInstanceAttribute from '../Core/ColorGeometryInstanceAttribute.js'; import defineProperties from '../Core/defineProperties.js'; import GeometryInstance from '../Core/GeometryInstance.js'; import Matrix3 from '../Core/Matrix3.js'; import Matrix4 from '../Core/Matrix4.js'; import CesiumMath from '../Core/Math.js'; import OrientedBoundingBox from '../Core/OrientedBoundingBox.js'; import PerInstanceColorAppearance from './PerInstanceColorAppearance.js'; import Primitive from './Primitive.js'; var scratchU = new Cartesian3(); var scratchV = new Cartesian3(); var scratchW = new Cartesian3(); var scratchCartesian = new Cartesian3(); function computeMissingVector(a, b, result) { result = Cartesian3.cross(a, b, result); var magnitude = Cartesian3.magnitude(result); return Cartesian3.multiplyByScalar(result, CesiumMath.EPSILON7 / magnitude, result); } function findOrthogonalVector(a, result) { var temp = Cartesian3.normalize(a, scratchCartesian); var b = Cartesian3.equalsEpsilon(temp, Cartesian3.UNIT_X, CesiumMath.EPSILON6) ? Cartesian3.UNIT_Y : Cartesian3.UNIT_X; return computeMissingVector(a, b, result); } function checkHalfAxes(halfAxes) { var u = Matrix3.getColumn(halfAxes, 0, scratchU); var v = Matrix3.getColumn(halfAxes, 1, scratchV); var w = Matrix3.getColumn(halfAxes, 2, scratchW); var uZero = Cartesian3.equals(u, Cartesian3.ZERO); var vZero = Cartesian3.equals(v, Cartesian3.ZERO); var wZero = Cartesian3.equals(w, Cartesian3.ZERO); if (!uZero && !vZero && !wZero) { return halfAxes; } if (uZero && vZero && wZero) { halfAxes[0] = CesiumMath.EPSILON7; halfAxes[4] = CesiumMath.EPSILON7; halfAxes[8] = CesiumMath.EPSILON7; return halfAxes; } if (uZero && !vZero && !wZero) { u = computeMissingVector(v, w, u); } else if (!uZero && vZero && !wZero) { v = computeMissingVector(u, w, v); } else if (!uZero && !vZero && wZero) { w = computeMissingVector(v, u, w); } else if (!uZero) { v = findOrthogonalVector(u, v); w = computeMissingVector(v, u, w); } else if (!vZero) { u = findOrthogonalVector(v, u); w = computeMissingVector(v, u, w); } else if (!wZero) { u = findOrthogonalVector(w, u); v = computeMissingVector(w, u, v); } Matrix3.setColumn(halfAxes, 0, u, halfAxes); Matrix3.setColumn(halfAxes, 1, v, halfAxes); Matrix3.setColumn(halfAxes, 2, w, halfAxes); return halfAxes; } /** * A tile bounding volume specified as an oriented bounding box. * @alias TileOrientedBoundingBox * @constructor * * @param {Cartesian3} [center=Cartesian3.ZERO] The center of the box. * @param {Matrix3} [halfAxes=Matrix3.ZERO] The three orthogonal half-axes of the bounding box. * Equivalently, the transformation matrix, to rotate and scale a 2x2x2 * cube centered at the origin. * * @private */ function TileOrientedBoundingBox(center, halfAxes) { halfAxes = checkHalfAxes(halfAxes); this._orientedBoundingBox = new OrientedBoundingBox(center, halfAxes); this._boundingSphere = BoundingSphere.fromOrientedBoundingBox(this._orientedBoundingBox); } defineProperties(TileOrientedBoundingBox.prototype, { /** * The underlying bounding volume. * * @memberof TileOrientedBoundingBox.prototype * * @type {Object} * @readonly */ boundingVolume : { get : function() { return this._orientedBoundingBox; } }, /** * The underlying bounding sphere. * * @memberof TileOrientedBoundingBox.prototype * * @type {BoundingSphere} * @readonly */ boundingSphere : { get : function() { return this._boundingSphere; } } }); /** * Computes the distance between this bounding box and the camera attached to frameState. * * @param {FrameState} frameState The frameState to which the camera is attached. * @returns {Number} The distance between the camera and the bounding box in meters. Returns 0 if the camera is inside the bounding volume. */ TileOrientedBoundingBox.prototype.distanceToCamera = function(frameState) { //>>includeStart('debug', pragmas.debug); Check.defined('frameState', frameState); //>>includeEnd('debug'); return Math.sqrt(this._orientedBoundingBox.distanceSquaredTo(frameState.camera.positionWC)); }; /** * Determines which side of a plane this box is located. * * @param {Plane} plane The plane to test against. * @returns {Intersect} {@link Intersect.INSIDE} if the entire box is on the side of the plane * the normal is pointing, {@link Intersect.OUTSIDE} if the entire box is * on the opposite side, and {@link Intersect.INTERSECTING} if the box * intersects the plane. */ TileOrientedBoundingBox.prototype.intersectPlane = function(plane) { //>>includeStart('debug', pragmas.debug); Check.defined('plane', plane); //>>includeEnd('debug'); return this._orientedBoundingBox.intersectPlane(plane); }; /** * Update the bounding box after the tile is transformed. * * @param {Cartesian3} center The center of the box. * @param {Matrix3} halfAxes The three orthogonal half-axes of the bounding box. * Equivalently, the transformation matrix, to rotate and scale a 2x2x2 * cube centered at the origin. */ TileOrientedBoundingBox.prototype.update = function(center, halfAxes) { Cartesian3.clone(center, this._orientedBoundingBox.center); halfAxes = checkHalfAxes(halfAxes); Matrix3.clone(halfAxes, this._orientedBoundingBox.halfAxes); BoundingSphere.fromOrientedBoundingBox(this._orientedBoundingBox, this._boundingSphere); }; /** * Creates a debug primitive that shows the outline of the box. * * @param {Color} color The desired color of the primitive's mesh * @return {Primitive} */ TileOrientedBoundingBox.prototype.createDebugVolume = function(color) { //>>includeStart('debug', pragmas.debug); Check.defined('color', color); //>>includeEnd('debug'); var geometry = new BoxOutlineGeometry({ // Make a 2x2x2 cube minimum : new Cartesian3(-1.0, -1.0, -1.0), maximum : new Cartesian3(1.0, 1.0, 1.0) }); var modelMatrix = Matrix4.fromRotationTranslation(this.boundingVolume.halfAxes, this.boundingVolume.center); var instance = new GeometryInstance({ geometry : geometry, id : 'outline', modelMatrix : modelMatrix, attributes : { color : ColorGeometryInstanceAttribute.fromColor(color) } }); return new Primitive({ geometryInstances : instance, appearance : new PerInstanceColorAppearance({ translucent : false, flat : true }), asynchronous : false }); }; export default TileOrientedBoundingBox;