Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | 12683x 1x 1x 1x 1x 1x 1x 1x 1x 16x 1x 15x 15x 15x 15x 15x 15x 15x 15x 15x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 15x 1x 28999x 1x 28998x 28998x 28998x 130991x 130991x 9226x 121765x 82506x 19772x 1x 20864x 1x 20863x 1x 20862x 961x 19901x 19901x 19901x 114280x 114280x 16684x 97596x 97596x 1329x 96267x 86547x 18572x 1x 1x 1x | import Cartesian3 from "./Cartesian3.js";
import Cartesian4 from "./Cartesian4.js";
import defined from "./defined.js";
import DeveloperError from "./DeveloperError.js";
import Intersect from "./Intersect.js";
import Plane from "./Plane.js";
/**
* The culling volume defined by planes.
*
* @alias CullingVolume
* @constructor
*
* @param {Cartesian4[]} [planes] An array of clipping planes.
*/
function CullingVolume(planes) {
/**
* Each plane is represented by a Cartesian4 object, where the x, y, and z components
* define the unit vector normal to the plane, and the w component is the distance of the
* plane from the origin.
* @type {Cartesian4[]}
* @default []
*/
this.planes = planes ?? [];
}
const faces = [new Cartesian3(), new Cartesian3(), new Cartesian3()];
Cartesian3.clone(Cartesian3.UNIT_X, faces[0]);
Cartesian3.clone(Cartesian3.UNIT_Y, faces[1]);
Cartesian3.clone(Cartesian3.UNIT_Z, faces[2]);
const scratchPlaneCenter = new Cartesian3();
const scratchPlaneNormal = new Cartesian3();
const scratchPlane = new Plane(new Cartesian3(1.0, 0.0, 0.0), 0.0);
/**
* Constructs a culling volume from a bounding sphere. Creates six planes that create a box containing the sphere.
* The planes are aligned to the x, y, and z axes in world coordinates.
*
* @param {BoundingSphere} boundingSphere The bounding sphere used to create the culling volume.
* @param {CullingVolume} [result] The object onto which to store the result.
* @returns {CullingVolume} The culling volume created from the bounding sphere.
*/
CullingVolume.fromBoundingSphere = function (boundingSphere, result) {
//>>includeStart('debug', pragmas.debug);
if (!defined(boundingSphere)) {
throw new DeveloperError("boundingSphere is required.");
}
//>>includeEnd('debug');
Eif (!defined(result)) {
result = new CullingVolume();
}
const length = faces.length;
const planes = result.planes;
planes.length = 2 * length;
const center = boundingSphere.center;
const radius = boundingSphere.radius;
let planeIndex = 0;
for (let i = 0; i < length; ++i) {
const faceNormal = faces[i];
let plane0 = planes[planeIndex];
let plane1 = planes[planeIndex + 1];
Eif (!defined(plane0)) {
plane0 = planes[planeIndex] = new Cartesian4();
}
Eif (!defined(plane1)) {
plane1 = planes[planeIndex + 1] = new Cartesian4();
}
Cartesian3.multiplyByScalar(faceNormal, -radius, scratchPlaneCenter);
Cartesian3.add(center, scratchPlaneCenter, scratchPlaneCenter);
plane0.x = faceNormal.x;
plane0.y = faceNormal.y;
plane0.z = faceNormal.z;
plane0.w = -Cartesian3.dot(faceNormal, scratchPlaneCenter);
Cartesian3.multiplyByScalar(faceNormal, radius, scratchPlaneCenter);
Cartesian3.add(center, scratchPlaneCenter, scratchPlaneCenter);
plane1.x = -faceNormal.x;
plane1.y = -faceNormal.y;
plane1.z = -faceNormal.z;
plane1.w = -Cartesian3.dot(
Cartesian3.negate(faceNormal, scratchPlaneNormal),
scratchPlaneCenter,
);
planeIndex += 2;
}
return result;
};
/**
* Determines whether a bounding volume intersects the culling volume.
*
* @param {object} boundingVolume The bounding volume whose intersection with the culling volume is to be tested.
* @returns {Intersect} Intersect.OUTSIDE, Intersect.INTERSECTING, or Intersect.INSIDE.
*/
CullingVolume.prototype.computeVisibility = function (boundingVolume) {
//>>includeStart('debug', pragmas.debug);
if (!defined(boundingVolume)) {
throw new DeveloperError("boundingVolume is required.");
}
//>>includeEnd('debug');
const planes = this.planes;
let intersecting = false;
for (let k = 0, len = planes.length; k < len; ++k) {
const result = boundingVolume.intersectPlane(
Plane.fromCartesian4(planes[k], scratchPlane),
);
if (result === Intersect.OUTSIDE) {
return Intersect.OUTSIDE;
} else if (result === Intersect.INTERSECTING) {
intersecting = true;
}
}
return intersecting ? Intersect.INTERSECTING : Intersect.INSIDE;
};
/**
* Determines whether a bounding volume intersects the culling volume.
*
* @param {object} boundingVolume The bounding volume whose intersection with the culling volume is to be tested.
* @param {number} parentPlaneMask A bit mask from the boundingVolume's parent's check against the same culling
* volume, such that if (planeMask & (1 << planeIndex) === 0), for k < 31, then
* the parent (and therefore this) volume is completely inside plane[planeIndex]
* and that plane check can be skipped.
* @returns {number} A plane mask as described above (which can be applied to this boundingVolume's children).
*
* @private
*/
CullingVolume.prototype.computeVisibilityWithPlaneMask = function (
boundingVolume,
parentPlaneMask,
) {
//>>includeStart('debug', pragmas.debug);
if (!defined(boundingVolume)) {
throw new DeveloperError("boundingVolume is required.");
}
if (!defined(parentPlaneMask)) {
throw new DeveloperError("parentPlaneMask is required.");
}
//>>includeEnd('debug');
if (
parentPlaneMask === CullingVolume.MASK_OUTSIDE ||
parentPlaneMask === CullingVolume.MASK_INSIDE
) {
// parent is completely outside or completely inside, so this child is as well.
return parentPlaneMask;
}
// Start with MASK_INSIDE (all zeros) so that after the loop, the return value can be compared with MASK_INSIDE.
// (Because if there are fewer than 31 planes, the upper bits wont be changed.)
let mask = CullingVolume.MASK_INSIDE;
const planes = this.planes;
for (let k = 0, len = planes.length; k < len; ++k) {
// For k greater than 31 (since 31 is the maximum number of INSIDE/INTERSECTING bits we can store), skip the optimization.
const flag = k < 31 ? 1 << k : 0;
if (k < 31 && (parentPlaneMask & flag) === 0) {
// boundingVolume is known to be INSIDE this plane.
continue;
}
const result = boundingVolume.intersectPlane(
Plane.fromCartesian4(planes[k], scratchPlane),
);
if (result === Intersect.OUTSIDE) {
return CullingVolume.MASK_OUTSIDE;
} else if (result === Intersect.INTERSECTING) {
mask |= flag;
}
}
return mask;
};
/**
* For plane masks (as used in {@link CullingVolume#computeVisibilityWithPlaneMask}), this special value
* represents the case where the object bounding volume is entirely outside the culling volume.
*
* @type {number}
* @private
*/
CullingVolume.MASK_OUTSIDE = 0xffffffff;
/**
* For plane masks (as used in {@link CullingVolume.prototype.computeVisibilityWithPlaneMask}), this value
* represents the case where the object bounding volume is entirely inside the culling volume.
*
* @type {number}
* @private
*/
CullingVolume.MASK_INSIDE = 0x00000000;
/**
* For plane masks (as used in {@link CullingVolume.prototype.computeVisibilityWithPlaneMask}), this value
* represents the case where the object bounding volume (may) intersect all planes of the culling volume.
*
* @type {number}
* @private
*/
CullingVolume.MASK_INDETERMINATE = 0x7fffffff;
export default CullingVolume;
|