123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730 |
- import BoundingSphere from "./BoundingSphere.js";
- import Cartesian3 from "./Cartesian3.js";
- import defaultValue from "./defaultValue.js";
- import defined from "./defined.js";
- import DeveloperError from "./DeveloperError.js";
- import Ellipsoid from "./Ellipsoid.js";
- import CesiumMath from "./Math.js";
- import Rectangle from "./Rectangle.js";
- import Visibility from "./Visibility.js";
- /**
- * Creates an Occluder derived from an object's position and radius, as well as the camera position.
- * The occluder can be used to determine whether or not other objects are visible or hidden behind the
- * visible horizon defined by the occluder and camera position.
- *
- * @alias Occluder
- *
- * @param {BoundingSphere} occluderBoundingSphere The bounding sphere surrounding the occluder.
- * @param {Cartesian3} cameraPosition The coordinate of the viewer/camera.
- *
- * @constructor
- *
- * @example
- * // Construct an occluder one unit away from the origin with a radius of one.
- * const cameraPosition = Cesium.Cartesian3.ZERO;
- * const occluderBoundingSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -1), 1);
- * const occluder = new Cesium.Occluder(occluderBoundingSphere, cameraPosition);
- */
- function Occluder(occluderBoundingSphere, cameraPosition) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(occluderBoundingSphere)) {
- throw new DeveloperError("occluderBoundingSphere is required.");
- }
- if (!defined(cameraPosition)) {
- throw new DeveloperError("camera position is required.");
- }
- //>>includeEnd('debug');
- this._occluderPosition = Cartesian3.clone(occluderBoundingSphere.center);
- this._occluderRadius = occluderBoundingSphere.radius;
- this._horizonDistance = 0.0;
- this._horizonPlaneNormal = undefined;
- this._horizonPlanePosition = undefined;
- this._cameraPosition = undefined;
- // cameraPosition fills in the above values
- this.cameraPosition = cameraPosition;
- }
- const scratchCartesian3 = new Cartesian3();
- Object.defineProperties(Occluder.prototype, {
- /**
- * The position of the occluder.
- * @memberof Occluder.prototype
- * @type {Cartesian3}
- */
- position: {
- get: function () {
- return this._occluderPosition;
- },
- },
- /**
- * The radius of the occluder.
- * @memberof Occluder.prototype
- * @type {Number}
- */
- radius: {
- get: function () {
- return this._occluderRadius;
- },
- },
- /**
- * The position of the camera.
- * @memberof Occluder.prototype
- * @type {Cartesian3}
- */
- cameraPosition: {
- set: function (cameraPosition) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(cameraPosition)) {
- throw new DeveloperError("cameraPosition is required.");
- }
- //>>includeEnd('debug');
- cameraPosition = Cartesian3.clone(cameraPosition, this._cameraPosition);
- const cameraToOccluderVec = Cartesian3.subtract(
- this._occluderPosition,
- cameraPosition,
- scratchCartesian3
- );
- let invCameraToOccluderDistance = Cartesian3.magnitudeSquared(
- cameraToOccluderVec
- );
- const occluderRadiusSqrd = this._occluderRadius * this._occluderRadius;
- let horizonDistance;
- let horizonPlaneNormal;
- let horizonPlanePosition;
- if (invCameraToOccluderDistance > occluderRadiusSqrd) {
- horizonDistance = Math.sqrt(
- invCameraToOccluderDistance - occluderRadiusSqrd
- );
- invCameraToOccluderDistance =
- 1.0 / Math.sqrt(invCameraToOccluderDistance);
- horizonPlaneNormal = Cartesian3.multiplyByScalar(
- cameraToOccluderVec,
- invCameraToOccluderDistance,
- scratchCartesian3
- );
- const nearPlaneDistance =
- horizonDistance * horizonDistance * invCameraToOccluderDistance;
- horizonPlanePosition = Cartesian3.add(
- cameraPosition,
- Cartesian3.multiplyByScalar(
- horizonPlaneNormal,
- nearPlaneDistance,
- scratchCartesian3
- ),
- scratchCartesian3
- );
- } else {
- horizonDistance = Number.MAX_VALUE;
- }
- this._horizonDistance = horizonDistance;
- this._horizonPlaneNormal = horizonPlaneNormal;
- this._horizonPlanePosition = horizonPlanePosition;
- this._cameraPosition = cameraPosition;
- },
- },
- });
- /**
- * Creates an occluder from a bounding sphere and the camera position.
- *
- * @param {BoundingSphere} occluderBoundingSphere The bounding sphere surrounding the occluder.
- * @param {Cartesian3} cameraPosition The coordinate of the viewer/camera.
- * @param {Occluder} [result] The object onto which to store the result.
- * @returns {Occluder} The occluder derived from an object's position and radius, as well as the camera position.
- */
- Occluder.fromBoundingSphere = function (
- occluderBoundingSphere,
- cameraPosition,
- result
- ) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(occluderBoundingSphere)) {
- throw new DeveloperError("occluderBoundingSphere is required.");
- }
- if (!defined(cameraPosition)) {
- throw new DeveloperError("camera position is required.");
- }
- //>>includeEnd('debug');
- if (!defined(result)) {
- return new Occluder(occluderBoundingSphere, cameraPosition);
- }
- Cartesian3.clone(occluderBoundingSphere.center, result._occluderPosition);
- result._occluderRadius = occluderBoundingSphere.radius;
- result.cameraPosition = cameraPosition;
- return result;
- };
- const tempVecScratch = new Cartesian3();
- /**
- * Determines whether or not a point, the <code>occludee</code>, is hidden from view by the occluder.
- *
- * @param {Cartesian3} occludee The point surrounding the occludee object.
- * @returns {Boolean} <code>true</code> if the occludee is visible; otherwise <code>false</code>.
- *
- *
- * @example
- * const cameraPosition = new Cesium.Cartesian3(0, 0, 0);
- * const littleSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -1), 0.25);
- * const occluder = new Cesium.Occluder(littleSphere, cameraPosition);
- * const point = new Cesium.Cartesian3(0, 0, -3);
- * occluder.isPointVisible(point); //returns true
- *
- * @see Occluder#computeVisibility
- */
- Occluder.prototype.isPointVisible = function (occludee) {
- if (this._horizonDistance !== Number.MAX_VALUE) {
- let tempVec = Cartesian3.subtract(
- occludee,
- this._occluderPosition,
- tempVecScratch
- );
- let temp = this._occluderRadius;
- temp = Cartesian3.magnitudeSquared(tempVec) - temp * temp;
- if (temp > 0.0) {
- temp = Math.sqrt(temp) + this._horizonDistance;
- tempVec = Cartesian3.subtract(occludee, this._cameraPosition, tempVec);
- return temp * temp > Cartesian3.magnitudeSquared(tempVec);
- }
- }
- return false;
- };
- const occludeePositionScratch = new Cartesian3();
- /**
- * Determines whether or not a sphere, the <code>occludee</code>, is hidden from view by the occluder.
- *
- * @param {BoundingSphere} occludee The bounding sphere surrounding the occludee object.
- * @returns {Boolean} <code>true</code> if the occludee is visible; otherwise <code>false</code>.
- *
- *
- * @example
- * const cameraPosition = new Cesium.Cartesian3(0, 0, 0);
- * const littleSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -1), 0.25);
- * const occluder = new Cesium.Occluder(littleSphere, cameraPosition);
- * const bigSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -3), 1);
- * occluder.isBoundingSphereVisible(bigSphere); //returns true
- *
- * @see Occluder#computeVisibility
- */
- Occluder.prototype.isBoundingSphereVisible = function (occludee) {
- const occludeePosition = Cartesian3.clone(
- occludee.center,
- occludeePositionScratch
- );
- const occludeeRadius = occludee.radius;
- if (this._horizonDistance !== Number.MAX_VALUE) {
- let tempVec = Cartesian3.subtract(
- occludeePosition,
- this._occluderPosition,
- tempVecScratch
- );
- let temp = this._occluderRadius - occludeeRadius;
- temp = Cartesian3.magnitudeSquared(tempVec) - temp * temp;
- if (occludeeRadius < this._occluderRadius) {
- if (temp > 0.0) {
- temp = Math.sqrt(temp) + this._horizonDistance;
- tempVec = Cartesian3.subtract(
- occludeePosition,
- this._cameraPosition,
- tempVec
- );
- return (
- temp * temp + occludeeRadius * occludeeRadius >
- Cartesian3.magnitudeSquared(tempVec)
- );
- }
- return false;
- }
- // Prevent against the case where the occludee radius is larger than the occluder's; since this is
- // an uncommon case, the following code should rarely execute.
- if (temp > 0.0) {
- tempVec = Cartesian3.subtract(
- occludeePosition,
- this._cameraPosition,
- tempVec
- );
- const tempVecMagnitudeSquared = Cartesian3.magnitudeSquared(tempVec);
- const occluderRadiusSquared = this._occluderRadius * this._occluderRadius;
- const occludeeRadiusSquared = occludeeRadius * occludeeRadius;
- if (
- (this._horizonDistance * this._horizonDistance +
- occluderRadiusSquared) *
- occludeeRadiusSquared >
- tempVecMagnitudeSquared * occluderRadiusSquared
- ) {
- // The occludee is close enough that the occluder cannot possible occlude the occludee
- return true;
- }
- temp = Math.sqrt(temp) + this._horizonDistance;
- return temp * temp + occludeeRadiusSquared > tempVecMagnitudeSquared;
- }
- // The occludee completely encompasses the occluder
- return true;
- }
- return false;
- };
- const tempScratch = new Cartesian3();
- /**
- * Determine to what extent an occludee is visible (not visible, partially visible, or fully visible).
- *
- * @param {BoundingSphere} occludeeBS The bounding sphere of the occludee.
- * @returns {Visibility} Visibility.NONE if the occludee is not visible,
- * Visibility.PARTIAL if the occludee is partially visible, or
- * Visibility.FULL if the occludee is fully visible.
- *
- *
- * @example
- * const sphere1 = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -1.5), 0.5);
- * const sphere2 = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -2.5), 0.5);
- * const cameraPosition = new Cesium.Cartesian3(0, 0, 0);
- * const occluder = new Cesium.Occluder(sphere1, cameraPosition);
- * occluder.computeVisibility(sphere2); //returns Visibility.NONE
- *
- * @see Occluder#isVisible
- */
- Occluder.prototype.computeVisibility = function (occludeeBS) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(occludeeBS)) {
- throw new DeveloperError("occludeeBS is required.");
- }
- //>>includeEnd('debug');
- // If the occludee radius is larger than the occluders, this will return that
- // the entire ocludee is visible, even though that may not be the case, though this should
- // not occur too often.
- const occludeePosition = Cartesian3.clone(occludeeBS.center);
- const occludeeRadius = occludeeBS.radius;
- if (occludeeRadius > this._occluderRadius) {
- return Visibility.FULL;
- }
- if (this._horizonDistance !== Number.MAX_VALUE) {
- // The camera is outside the occluder
- let tempVec = Cartesian3.subtract(
- occludeePosition,
- this._occluderPosition,
- tempScratch
- );
- let temp = this._occluderRadius - occludeeRadius;
- const occluderToOccludeeDistSqrd = Cartesian3.magnitudeSquared(tempVec);
- temp = occluderToOccludeeDistSqrd - temp * temp;
- if (temp > 0.0) {
- // The occludee is not completely inside the occluder
- // Check to see if the occluder completely hides the occludee
- temp = Math.sqrt(temp) + this._horizonDistance;
- tempVec = Cartesian3.subtract(
- occludeePosition,
- this._cameraPosition,
- tempVec
- );
- const cameraToOccludeeDistSqrd = Cartesian3.magnitudeSquared(tempVec);
- if (
- temp * temp + occludeeRadius * occludeeRadius <
- cameraToOccludeeDistSqrd
- ) {
- return Visibility.NONE;
- }
- // Check to see whether the occluder is fully or partially visible
- // when the occludee does not intersect the occluder
- temp = this._occluderRadius + occludeeRadius;
- temp = occluderToOccludeeDistSqrd - temp * temp;
- if (temp > 0.0) {
- // The occludee does not intersect the occluder.
- temp = Math.sqrt(temp) + this._horizonDistance;
- return cameraToOccludeeDistSqrd <
- temp * temp + occludeeRadius * occludeeRadius
- ? Visibility.FULL
- : Visibility.PARTIAL;
- }
- //Check to see if the occluder is fully or partially visible when the occludee DOES
- //intersect the occluder
- tempVec = Cartesian3.subtract(
- occludeePosition,
- this._horizonPlanePosition,
- tempVec
- );
- return Cartesian3.dot(tempVec, this._horizonPlaneNormal) > -occludeeRadius
- ? Visibility.PARTIAL
- : Visibility.FULL;
- }
- }
- return Visibility.NONE;
- };
- const occludeePointScratch = new Cartesian3();
- /**
- * Computes a point that can be used as the occludee position to the visibility functions.
- * Use a radius of zero for the occludee radius. Typically, a user computes a bounding sphere around
- * an object that is used for visibility; however it is also possible to compute a point that if
- * seen/not seen would also indicate if an object is visible/not visible. This function is better
- * called for objects that do not move relative to the occluder and is large, such as a chunk of
- * terrain. You are better off not calling this and using the object's bounding sphere for objects
- * such as a satellite or ground vehicle.
- *
- * @param {BoundingSphere} occluderBoundingSphere The bounding sphere surrounding the occluder.
- * @param {Cartesian3} occludeePosition The point where the occludee (bounding sphere of radius 0) is located.
- * @param {Cartesian3[]} positions List of altitude points on the horizon near the surface of the occluder.
- * @returns {Object} An object containing two attributes: <code>occludeePoint</code> and <code>valid</code>
- * which is a boolean value.
- *
- * @exception {DeveloperError} <code>positions</code> must contain at least one element.
- * @exception {DeveloperError} <code>occludeePosition</code> must have a value other than <code>occluderBoundingSphere.center</code>.
- *
- * @example
- * const cameraPosition = new Cesium.Cartesian3(0, 0, 0);
- * const occluderBoundingSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -8), 2);
- * const occluder = new Cesium.Occluder(occluderBoundingSphere, cameraPosition);
- * const positions = [new Cesium.Cartesian3(-0.25, 0, -5.3), new Cesium.Cartesian3(0.25, 0, -5.3)];
- * const tileOccluderSphere = Cesium.BoundingSphere.fromPoints(positions);
- * const occludeePosition = tileOccluderSphere.center;
- * const occludeePt = Cesium.Occluder.computeOccludeePoint(occluderBoundingSphere, occludeePosition, positions);
- */
- Occluder.computeOccludeePoint = function (
- occluderBoundingSphere,
- occludeePosition,
- positions
- ) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(occluderBoundingSphere)) {
- throw new DeveloperError("occluderBoundingSphere is required.");
- }
- if (!defined(positions)) {
- throw new DeveloperError("positions is required.");
- }
- if (positions.length === 0) {
- throw new DeveloperError("positions must contain at least one element");
- }
- //>>includeEnd('debug');
- const occludeePos = Cartesian3.clone(occludeePosition);
- const occluderPosition = Cartesian3.clone(occluderBoundingSphere.center);
- const occluderRadius = occluderBoundingSphere.radius;
- const numPositions = positions.length;
- //>>includeStart('debug', pragmas.debug);
- if (Cartesian3.equals(occluderPosition, occludeePosition)) {
- throw new DeveloperError(
- "occludeePosition must be different than occluderBoundingSphere.center"
- );
- }
- //>>includeEnd('debug');
- // Compute a plane with a normal from the occluder to the occludee position.
- const occluderPlaneNormal = Cartesian3.normalize(
- Cartesian3.subtract(occludeePos, occluderPosition, occludeePointScratch),
- occludeePointScratch
- );
- const occluderPlaneD = -Cartesian3.dot(occluderPlaneNormal, occluderPosition);
- //For each position, determine the horizon intersection. Choose the position and intersection
- //that results in the greatest angle with the occcluder plane.
- const aRotationVector = Occluder._anyRotationVector(
- occluderPosition,
- occluderPlaneNormal,
- occluderPlaneD
- );
- let dot = Occluder._horizonToPlaneNormalDotProduct(
- occluderBoundingSphere,
- occluderPlaneNormal,
- occluderPlaneD,
- aRotationVector,
- positions[0]
- );
- if (!dot) {
- //The position is inside the mimimum radius, which is invalid
- return undefined;
- }
- let tempDot;
- for (let i = 1; i < numPositions; ++i) {
- tempDot = Occluder._horizonToPlaneNormalDotProduct(
- occluderBoundingSphere,
- occluderPlaneNormal,
- occluderPlaneD,
- aRotationVector,
- positions[i]
- );
- if (!tempDot) {
- //The position is inside the minimum radius, which is invalid
- return undefined;
- }
- if (tempDot < dot) {
- dot = tempDot;
- }
- }
- //Verify that the dot is not near 90 degress
- if (dot < 0.00174532836589830883577820272085) {
- return undefined;
- }
- const distance = occluderRadius / dot;
- return Cartesian3.add(
- occluderPosition,
- Cartesian3.multiplyByScalar(
- occluderPlaneNormal,
- distance,
- occludeePointScratch
- ),
- occludeePointScratch
- );
- };
- const computeOccludeePointFromRectangleScratch = [];
- /**
- * Computes a point that can be used as the occludee position to the visibility functions from a rectangle.
- *
- * @param {Rectangle} rectangle The rectangle used to create a bounding sphere.
- * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid used to determine positions of the rectangle.
- * @returns {Object} An object containing two attributes: <code>occludeePoint</code> and <code>valid</code>
- * which is a boolean value.
- */
- Occluder.computeOccludeePointFromRectangle = function (rectangle, ellipsoid) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(rectangle)) {
- throw new DeveloperError("rectangle is required.");
- }
- //>>includeEnd('debug');
- ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
- const positions = Rectangle.subsample(
- rectangle,
- ellipsoid,
- 0.0,
- computeOccludeePointFromRectangleScratch
- );
- const bs = BoundingSphere.fromPoints(positions);
- // TODO: get correct ellipsoid center
- const ellipsoidCenter = Cartesian3.ZERO;
- if (!Cartesian3.equals(ellipsoidCenter, bs.center)) {
- return Occluder.computeOccludeePoint(
- new BoundingSphere(ellipsoidCenter, ellipsoid.minimumRadius),
- bs.center,
- positions
- );
- }
- return undefined;
- };
- const tempVec0Scratch = new Cartesian3();
- Occluder._anyRotationVector = function (
- occluderPosition,
- occluderPlaneNormal,
- occluderPlaneD
- ) {
- const tempVec0 = Cartesian3.abs(occluderPlaneNormal, tempVec0Scratch);
- let majorAxis = tempVec0.x > tempVec0.y ? 0 : 1;
- if (
- (majorAxis === 0 && tempVec0.z > tempVec0.x) ||
- (majorAxis === 1 && tempVec0.z > tempVec0.y)
- ) {
- majorAxis = 2;
- }
- const tempVec = new Cartesian3();
- let tempVec1;
- if (majorAxis === 0) {
- tempVec0.x = occluderPosition.x;
- tempVec0.y = occluderPosition.y + 1.0;
- tempVec0.z = occluderPosition.z + 1.0;
- tempVec1 = Cartesian3.UNIT_X;
- } else if (majorAxis === 1) {
- tempVec0.x = occluderPosition.x + 1.0;
- tempVec0.y = occluderPosition.y;
- tempVec0.z = occluderPosition.z + 1.0;
- tempVec1 = Cartesian3.UNIT_Y;
- } else {
- tempVec0.x = occluderPosition.x + 1.0;
- tempVec0.y = occluderPosition.y + 1.0;
- tempVec0.z = occluderPosition.z;
- tempVec1 = Cartesian3.UNIT_Z;
- }
- const u =
- (Cartesian3.dot(occluderPlaneNormal, tempVec0) + occluderPlaneD) /
- -Cartesian3.dot(occluderPlaneNormal, tempVec1);
- return Cartesian3.normalize(
- Cartesian3.subtract(
- Cartesian3.add(
- tempVec0,
- Cartesian3.multiplyByScalar(tempVec1, u, tempVec),
- tempVec0
- ),
- occluderPosition,
- tempVec0
- ),
- tempVec0
- );
- };
- const posDirectionScratch = new Cartesian3();
- Occluder._rotationVector = function (
- occluderPosition,
- occluderPlaneNormal,
- occluderPlaneD,
- position,
- anyRotationVector
- ) {
- //Determine the angle between the occluder plane normal and the position direction
- let positionDirection = Cartesian3.subtract(
- position,
- occluderPosition,
- posDirectionScratch
- );
- positionDirection = Cartesian3.normalize(
- positionDirection,
- positionDirection
- );
- if (
- Cartesian3.dot(occluderPlaneNormal, positionDirection) <
- 0.99999998476912904932780850903444
- ) {
- const crossProduct = Cartesian3.cross(
- occluderPlaneNormal,
- positionDirection,
- positionDirection
- );
- const length = Cartesian3.magnitude(crossProduct);
- if (length > CesiumMath.EPSILON13) {
- return Cartesian3.normalize(crossProduct, new Cartesian3());
- }
- }
- //The occluder plane normal and the position direction are colinear. Use any
- //vector in the occluder plane as the rotation vector
- return anyRotationVector;
- };
- const posScratch1 = new Cartesian3();
- const occluerPosScratch = new Cartesian3();
- const posScratch2 = new Cartesian3();
- const horizonPlanePosScratch = new Cartesian3();
- Occluder._horizonToPlaneNormalDotProduct = function (
- occluderBS,
- occluderPlaneNormal,
- occluderPlaneD,
- anyRotationVector,
- position
- ) {
- const pos = Cartesian3.clone(position, posScratch1);
- const occluderPosition = Cartesian3.clone(
- occluderBS.center,
- occluerPosScratch
- );
- const occluderRadius = occluderBS.radius;
- //Verify that the position is outside the occluder
- let positionToOccluder = Cartesian3.subtract(
- occluderPosition,
- pos,
- posScratch2
- );
- const occluderToPositionDistanceSquared = Cartesian3.magnitudeSquared(
- positionToOccluder
- );
- const occluderRadiusSquared = occluderRadius * occluderRadius;
- if (occluderToPositionDistanceSquared < occluderRadiusSquared) {
- return false;
- }
- //Horizon parameters
- const horizonDistanceSquared =
- occluderToPositionDistanceSquared - occluderRadiusSquared;
- const horizonDistance = Math.sqrt(horizonDistanceSquared);
- const occluderToPositionDistance = Math.sqrt(
- occluderToPositionDistanceSquared
- );
- const invOccluderToPositionDistance = 1.0 / occluderToPositionDistance;
- const cosTheta = horizonDistance * invOccluderToPositionDistance;
- const horizonPlaneDistance = cosTheta * horizonDistance;
- positionToOccluder = Cartesian3.normalize(
- positionToOccluder,
- positionToOccluder
- );
- const horizonPlanePosition = Cartesian3.add(
- pos,
- Cartesian3.multiplyByScalar(
- positionToOccluder,
- horizonPlaneDistance,
- horizonPlanePosScratch
- ),
- horizonPlanePosScratch
- );
- const horizonCrossDistance = Math.sqrt(
- horizonDistanceSquared - horizonPlaneDistance * horizonPlaneDistance
- );
- //Rotate the position to occluder vector 90 degrees
- let tempVec = this._rotationVector(
- occluderPosition,
- occluderPlaneNormal,
- occluderPlaneD,
- pos,
- anyRotationVector
- );
- let horizonCrossDirection = Cartesian3.fromElements(
- tempVec.x * tempVec.x * positionToOccluder.x +
- (tempVec.x * tempVec.y - tempVec.z) * positionToOccluder.y +
- (tempVec.x * tempVec.z + tempVec.y) * positionToOccluder.z,
- (tempVec.x * tempVec.y + tempVec.z) * positionToOccluder.x +
- tempVec.y * tempVec.y * positionToOccluder.y +
- (tempVec.y * tempVec.z - tempVec.x) * positionToOccluder.z,
- (tempVec.x * tempVec.z - tempVec.y) * positionToOccluder.x +
- (tempVec.y * tempVec.z + tempVec.x) * positionToOccluder.y +
- tempVec.z * tempVec.z * positionToOccluder.z,
- posScratch1
- );
- horizonCrossDirection = Cartesian3.normalize(
- horizonCrossDirection,
- horizonCrossDirection
- );
- //Horizon positions
- const offset = Cartesian3.multiplyByScalar(
- horizonCrossDirection,
- horizonCrossDistance,
- posScratch1
- );
- tempVec = Cartesian3.normalize(
- Cartesian3.subtract(
- Cartesian3.add(horizonPlanePosition, offset, posScratch2),
- occluderPosition,
- posScratch2
- ),
- posScratch2
- );
- const dot0 = Cartesian3.dot(occluderPlaneNormal, tempVec);
- tempVec = Cartesian3.normalize(
- Cartesian3.subtract(
- Cartesian3.subtract(horizonPlanePosition, offset, tempVec),
- occluderPosition,
- tempVec
- ),
- tempVec
- );
- const dot1 = Cartesian3.dot(occluderPlaneNormal, tempVec);
- return dot0 < dot1 ? dot0 : dot1;
- };
- export default Occluder;
|