1125 lines
34 KiB
JavaScript
1125 lines
34 KiB
JavaScript
import defined from "../Core/defined.js";
|
|
import BoundingSphere from "../Core/BoundingSphere.js";
|
|
import Cartesian2 from "../Core/Cartesian2.js";
|
|
import Cartesian3 from "../Core/Cartesian3.js";
|
|
import Cartographic from "../Core/Cartographic.js";
|
|
import Check from "../Core/Check.js";
|
|
import Ellipsoid from "../Core/Ellipsoid.js";
|
|
import CesiumMath from "../Core/Math.js";
|
|
import Matrix3 from "../Core/Matrix3.js";
|
|
import Matrix4 from "../Core/Matrix4.js";
|
|
import OrientedBoundingBox from "../Core/OrientedBoundingBox.js";
|
|
import Rectangle from "../Core/Rectangle.js";
|
|
import Transforms from "../Core/Transforms.js";
|
|
|
|
/**
|
|
* An ellipsoid {@link VoxelShape}.
|
|
*
|
|
* @alias VoxelEllipsoidShape
|
|
* @constructor
|
|
*
|
|
* @see VoxelShape
|
|
* @see VoxelBoxShape
|
|
* @see VoxelCylinderShape
|
|
* @see VoxelShapeType
|
|
*
|
|
* @private
|
|
*/
|
|
function VoxelEllipsoidShape() {
|
|
this._orientedBoundingBox = new OrientedBoundingBox();
|
|
this._boundingSphere = new BoundingSphere();
|
|
this._boundTransform = new Matrix4();
|
|
this._shapeTransform = new Matrix4();
|
|
|
|
/**
|
|
* @type {Rectangle}
|
|
* @private
|
|
*/
|
|
this._rectangle = new Rectangle();
|
|
|
|
/**
|
|
* @type {number}
|
|
* @private
|
|
*/
|
|
this._minimumHeight = VoxelEllipsoidShape.DefaultMinBounds.z;
|
|
|
|
/**
|
|
* @type {number}
|
|
* @private
|
|
*/
|
|
this._maximumHeight = VoxelEllipsoidShape.DefaultMaxBounds.z;
|
|
|
|
/**
|
|
* @type {Ellipsoid}
|
|
* @private
|
|
*/
|
|
this._ellipsoid = new Ellipsoid();
|
|
|
|
/**
|
|
* @type {Cartesian3}
|
|
* @private
|
|
*/
|
|
this._translation = new Cartesian3();
|
|
|
|
/**
|
|
* @type {Matrix3}
|
|
* @private
|
|
*/
|
|
this._rotation = new Matrix3();
|
|
|
|
/**
|
|
* UV space transformation translations (JS-only, not shader uniforms)
|
|
* Components: [longitude, latitude, height] translation
|
|
* @type {Cartesian3}
|
|
* @private
|
|
*/
|
|
this._localToShapeUvTranslate = new Cartesian3();
|
|
|
|
this._shaderUniforms = {
|
|
cameraPositionCartographic: new Cartesian3(),
|
|
ellipsoidEcToEastNorthUp: new Matrix3(),
|
|
ellipsoidRadii: new Cartesian3(),
|
|
eccentricitySquared: 0.0,
|
|
evoluteScale: new Cartesian2(),
|
|
ellipsoidCurvatureAtLatitude: new Cartesian2(),
|
|
ellipsoidInverseRadiiSquared: new Cartesian3(),
|
|
ellipsoidRenderLongitudeMinMax: new Cartesian2(),
|
|
ellipsoidShapeUvLongitudeRangeOrigin: 0.0,
|
|
ellipsoidShapeUvLongitudeMinMaxMid: new Cartesian3(),
|
|
ellipsoidLocalToShapeUvScale: new Cartesian3(),
|
|
ellipsoidRenderLatitudeSinMinMax: new Cartesian2(),
|
|
clipMinMaxHeight: new Cartesian2(),
|
|
};
|
|
|
|
this._shaderDefines = {
|
|
ELLIPSOID_HAS_RENDER_BOUNDS_LONGITUDE: undefined,
|
|
ELLIPSOID_HAS_RENDER_BOUNDS_LONGITUDE_RANGE_EQUAL_ZERO: undefined,
|
|
ELLIPSOID_HAS_RENDER_BOUNDS_LONGITUDE_RANGE_UNDER_HALF: undefined,
|
|
ELLIPSOID_HAS_RENDER_BOUNDS_LONGITUDE_RANGE_OVER_HALF: undefined,
|
|
ELLIPSOID_HAS_SHAPE_BOUNDS_LONGITUDE: undefined,
|
|
ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MAX_UNDER_HALF: undefined,
|
|
ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MAX_EQUAL_HALF: undefined,
|
|
ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MAX_OVER_HALF: undefined,
|
|
ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MIN_UNDER_HALF: undefined,
|
|
ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MIN_EQUAL_HALF: undefined,
|
|
ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MIN_OVER_HALF: undefined,
|
|
ELLIPSOID_HAS_SHAPE_BOUNDS_LATITUDE: undefined,
|
|
ELLIPSOID_INTERSECTION_INDEX_LONGITUDE: undefined,
|
|
ELLIPSOID_INTERSECTION_INDEX_LATITUDE_MAX: undefined,
|
|
ELLIPSOID_INTERSECTION_INDEX_LATITUDE_MIN: undefined,
|
|
ELLIPSOID_INTERSECTION_INDEX_HEIGHT_MAX: undefined,
|
|
ELLIPSOID_INTERSECTION_INDEX_HEIGHT_MIN: undefined,
|
|
};
|
|
|
|
this._shaderMaximumIntersectionsLength = 0; // not known until update
|
|
}
|
|
|
|
Object.defineProperties(VoxelEllipsoidShape.prototype, {
|
|
/**
|
|
* An oriented bounding box containing the bounded shape.
|
|
*
|
|
* @memberof VoxelEllipsoidShape.prototype
|
|
* @type {OrientedBoundingBox}
|
|
* @readonly
|
|
* @private
|
|
*/
|
|
orientedBoundingBox: {
|
|
get: function () {
|
|
return this._orientedBoundingBox;
|
|
},
|
|
},
|
|
|
|
/**
|
|
* A bounding sphere containing the bounded shape.
|
|
*
|
|
* @memberof VoxelEllipsoidShape.prototype
|
|
* @type {BoundingSphere}
|
|
* @readonly
|
|
* @private
|
|
*/
|
|
boundingSphere: {
|
|
get: function () {
|
|
return this._boundingSphere;
|
|
},
|
|
},
|
|
|
|
/**
|
|
* A transformation matrix containing the bounded shape.
|
|
*
|
|
* @memberof VoxelEllipsoidShape.prototype
|
|
* @type {Matrix4}
|
|
* @readonly
|
|
* @private
|
|
*/
|
|
boundTransform: {
|
|
get: function () {
|
|
return this._boundTransform;
|
|
},
|
|
},
|
|
|
|
/**
|
|
* A transformation matrix containing the shape, ignoring the bounds.
|
|
*
|
|
* @memberof VoxelEllipsoidShape.prototype
|
|
* @type {Matrix4}
|
|
* @readonly
|
|
* @private
|
|
*/
|
|
shapeTransform: {
|
|
get: function () {
|
|
return this._shapeTransform;
|
|
},
|
|
},
|
|
|
|
/**
|
|
* @memberof VoxelEllipsoidShape.prototype
|
|
* @type {Object<string, any>}
|
|
* @readonly
|
|
* @private
|
|
*/
|
|
shaderUniforms: {
|
|
get: function () {
|
|
return this._shaderUniforms;
|
|
},
|
|
},
|
|
|
|
/**
|
|
* @memberof VoxelEllipsoidShape.prototype
|
|
* @type {Object<string, any>}
|
|
* @readonly
|
|
* @private
|
|
*/
|
|
shaderDefines: {
|
|
get: function () {
|
|
return this._shaderDefines;
|
|
},
|
|
},
|
|
|
|
/**
|
|
* The maximum number of intersections against the shape for any ray direction.
|
|
* @memberof VoxelEllipsoidShape.prototype
|
|
* @type {number}
|
|
* @readonly
|
|
* @private
|
|
*/
|
|
shaderMaximumIntersectionsLength: {
|
|
get: function () {
|
|
return this._shaderMaximumIntersectionsLength;
|
|
},
|
|
},
|
|
});
|
|
|
|
const scratchActualMinBounds = new Cartesian3();
|
|
const scratchShapeMinBounds = new Cartesian3();
|
|
const scratchShapeMaxBounds = new Cartesian3();
|
|
const scratchClipMinBounds = new Cartesian3();
|
|
const scratchClipMaxBounds = new Cartesian3();
|
|
const scratchRenderMinBounds = new Cartesian3();
|
|
const scratchRenderMaxBounds = new Cartesian3();
|
|
const scratchScale = new Cartesian3();
|
|
const scratchShapeOuterExtent = new Cartesian3();
|
|
const scratchRenderOuterExtent = new Cartesian3();
|
|
const scratchRenderRectangle = new Rectangle();
|
|
|
|
/**
|
|
* Update the shape's state.
|
|
* @private
|
|
* @param {Matrix4} modelMatrix The model matrix.
|
|
* @param {Cartesian3} minBounds The minimum bounds.
|
|
* @param {Cartesian3} maxBounds The maximum bounds.
|
|
* @param {Cartesian3} [clipMinBounds=VoxelEllipsoidShape.DefaultMinBounds] The minimum clip bounds.
|
|
* @param {Cartesian3} [clipMaxBounds=VoxelEllipsoidShape.DefaultMaxBounds] The maximum clip bounds.
|
|
* @returns {boolean} Whether the shape is visible.
|
|
*/
|
|
VoxelEllipsoidShape.prototype.update = function (
|
|
modelMatrix,
|
|
minBounds,
|
|
maxBounds,
|
|
clipMinBounds,
|
|
clipMaxBounds,
|
|
) {
|
|
const { DefaultMinBounds, DefaultMaxBounds } = VoxelEllipsoidShape;
|
|
clipMinBounds = clipMinBounds ?? DefaultMinBounds;
|
|
clipMaxBounds = clipMaxBounds ?? DefaultMaxBounds;
|
|
//>>includeStart('debug', pragmas.debug);
|
|
Check.typeOf.object("modelMatrix", modelMatrix);
|
|
Check.typeOf.object("minBounds", minBounds);
|
|
Check.typeOf.object("maxBounds", maxBounds);
|
|
//>>includeEnd('debug');
|
|
|
|
const epsilonZeroScale = CesiumMath.EPSILON10;
|
|
const epsilonLongitude = CesiumMath.EPSILON10;
|
|
const epsilonLatitude = CesiumMath.EPSILON10;
|
|
const epsilonLatitudeFlat = CesiumMath.EPSILON3; // 0.001 radians = 0.05729578 degrees
|
|
|
|
// Don't let the height go below the center of the ellipsoid.
|
|
const radii = Matrix4.getScale(modelMatrix, scratchScale);
|
|
const actualMinBounds = Cartesian3.clone(
|
|
DefaultMinBounds,
|
|
scratchActualMinBounds,
|
|
);
|
|
actualMinBounds.z = -Cartesian3.minimumComponent(radii);
|
|
|
|
const shapeMinBounds = Cartesian3.clamp(
|
|
minBounds,
|
|
actualMinBounds,
|
|
DefaultMaxBounds,
|
|
scratchShapeMinBounds,
|
|
);
|
|
const shapeMaxBounds = Cartesian3.clamp(
|
|
maxBounds,
|
|
actualMinBounds,
|
|
DefaultMaxBounds,
|
|
scratchShapeMaxBounds,
|
|
);
|
|
const clampedClipMinBounds = Cartesian3.clamp(
|
|
clipMinBounds,
|
|
actualMinBounds,
|
|
DefaultMaxBounds,
|
|
scratchClipMinBounds,
|
|
);
|
|
const clampedClipMaxBounds = Cartesian3.clamp(
|
|
clipMaxBounds,
|
|
actualMinBounds,
|
|
DefaultMaxBounds,
|
|
scratchClipMaxBounds,
|
|
);
|
|
const renderMinBounds = Cartesian3.maximumByComponent(
|
|
shapeMinBounds,
|
|
clampedClipMinBounds,
|
|
scratchRenderMinBounds,
|
|
);
|
|
const renderMaxBounds = Cartesian3.minimumByComponent(
|
|
shapeMaxBounds,
|
|
clampedClipMaxBounds,
|
|
scratchRenderMaxBounds,
|
|
);
|
|
|
|
// Compute the farthest a point can be from the center of the ellipsoid.
|
|
const shapeOuterExtent = Cartesian3.add(
|
|
radii,
|
|
Cartesian3.fromElements(
|
|
shapeMaxBounds.z,
|
|
shapeMaxBounds.z,
|
|
shapeMaxBounds.z,
|
|
scratchShapeOuterExtent,
|
|
),
|
|
scratchShapeOuterExtent,
|
|
);
|
|
|
|
const renderOuterExtent = Cartesian3.add(
|
|
radii,
|
|
Cartesian3.fromElements(
|
|
renderMaxBounds.z,
|
|
renderMaxBounds.z,
|
|
renderMaxBounds.z,
|
|
scratchRenderOuterExtent,
|
|
),
|
|
scratchRenderOuterExtent,
|
|
);
|
|
|
|
// Exit early if the shape is not visible.
|
|
// Note that minLongitude may be greater than maxLongitude when crossing the 180th meridian.
|
|
if (
|
|
renderMinBounds.y > renderMaxBounds.y ||
|
|
renderMinBounds.y === DefaultMaxBounds.y ||
|
|
renderMaxBounds.y === DefaultMinBounds.y ||
|
|
renderMinBounds.z > renderMaxBounds.z ||
|
|
CesiumMath.equalsEpsilon(
|
|
renderOuterExtent,
|
|
Cartesian3.ZERO,
|
|
undefined,
|
|
epsilonZeroScale,
|
|
)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
this._rectangle = Rectangle.fromRadians(
|
|
shapeMinBounds.x,
|
|
shapeMinBounds.y,
|
|
shapeMaxBounds.x,
|
|
shapeMaxBounds.y,
|
|
);
|
|
this._translation = Matrix4.getTranslation(modelMatrix, this._translation);
|
|
this._rotation = Matrix4.getRotation(modelMatrix, this._rotation);
|
|
this._ellipsoid = Ellipsoid.fromCartesian3(radii, this._ellipsoid);
|
|
this._minimumHeight = shapeMinBounds.z;
|
|
this._maximumHeight = shapeMaxBounds.z;
|
|
|
|
const renderRectangle = Rectangle.fromRadians(
|
|
renderMinBounds.x,
|
|
renderMinBounds.y,
|
|
renderMaxBounds.x,
|
|
renderMaxBounds.y,
|
|
scratchRenderRectangle,
|
|
);
|
|
|
|
this._orientedBoundingBox = getEllipsoidChunkObb(
|
|
renderRectangle,
|
|
renderMinBounds.z,
|
|
renderMaxBounds.z,
|
|
this._ellipsoid,
|
|
this._translation,
|
|
this._rotation,
|
|
this._orientedBoundingBox,
|
|
);
|
|
|
|
this._shapeTransform = Matrix4.fromRotationTranslation(
|
|
this._rotation,
|
|
this._translation,
|
|
this._shapeTransform,
|
|
);
|
|
|
|
this._boundTransform = Matrix4.fromRotationTranslation(
|
|
this._orientedBoundingBox.halfAxes,
|
|
this._orientedBoundingBox.center,
|
|
this._boundTransform,
|
|
);
|
|
|
|
this._boundingSphere = BoundingSphere.fromOrientedBoundingBox(
|
|
this._orientedBoundingBox,
|
|
this._boundingSphere,
|
|
);
|
|
|
|
// Longitude
|
|
const defaultLongitudeRange = DefaultMaxBounds.x - DefaultMinBounds.x;
|
|
const defaultLongitudeRangeHalf = 0.5 * defaultLongitudeRange;
|
|
const renderIsLongitudeReversed = renderMaxBounds.x < renderMinBounds.x;
|
|
const renderLongitudeRange =
|
|
renderMaxBounds.x -
|
|
renderMinBounds.x +
|
|
renderIsLongitudeReversed * defaultLongitudeRange;
|
|
const renderIsLongitudeRangeZero = renderLongitudeRange <= epsilonLongitude;
|
|
const renderIsLongitudeRangeUnderHalf =
|
|
renderLongitudeRange >= defaultLongitudeRangeHalf - epsilonLongitude &&
|
|
renderLongitudeRange < defaultLongitudeRange - epsilonLongitude;
|
|
const renderIsLongitudeRangeOverHalf =
|
|
renderLongitudeRange > epsilonLongitude &&
|
|
renderLongitudeRange < defaultLongitudeRangeHalf - epsilonLongitude;
|
|
const renderHasLongitude =
|
|
renderIsLongitudeRangeZero ||
|
|
renderIsLongitudeRangeUnderHalf ||
|
|
renderIsLongitudeRangeOverHalf;
|
|
|
|
const shapeIsLongitudeReversed = shapeMaxBounds.x < shapeMinBounds.x;
|
|
const shapeLongitudeRange =
|
|
shapeMaxBounds.x -
|
|
shapeMinBounds.x +
|
|
shapeIsLongitudeReversed * defaultLongitudeRange;
|
|
const shapeIsLongitudeRangeUnderHalf =
|
|
shapeLongitudeRange > defaultLongitudeRangeHalf + epsilonLongitude &&
|
|
shapeLongitudeRange < defaultLongitudeRange - epsilonLongitude;
|
|
const shapeIsLongitudeRangeHalf =
|
|
shapeLongitudeRange >= defaultLongitudeRangeHalf - epsilonLongitude &&
|
|
shapeLongitudeRange <= defaultLongitudeRangeHalf + epsilonLongitude;
|
|
const shapeIsLongitudeRangeOverHalf =
|
|
shapeLongitudeRange < defaultLongitudeRangeHalf - epsilonLongitude;
|
|
const shapeHasLongitude =
|
|
shapeIsLongitudeRangeUnderHalf ||
|
|
shapeIsLongitudeRangeHalf ||
|
|
shapeIsLongitudeRangeOverHalf;
|
|
|
|
// Latitude
|
|
const renderIsLatitudeMaxUnderHalf = renderMaxBounds.y < -epsilonLatitudeFlat;
|
|
const renderIsLatitudeMaxHalf =
|
|
renderMaxBounds.y >= -epsilonLatitudeFlat &&
|
|
renderMaxBounds.y <= +epsilonLatitudeFlat;
|
|
const renderIsLatitudeMaxOverHalf =
|
|
renderMaxBounds.y > +epsilonLatitudeFlat &&
|
|
renderMaxBounds.y < DefaultMaxBounds.y - epsilonLatitude;
|
|
const renderHasLatitudeMax =
|
|
renderIsLatitudeMaxUnderHalf ||
|
|
renderIsLatitudeMaxHalf ||
|
|
renderIsLatitudeMaxOverHalf;
|
|
const renderIsLatitudeMinUnderHalf =
|
|
renderMinBounds.y > DefaultMinBounds.y + epsilonLatitude &&
|
|
renderMinBounds.y < -epsilonLatitudeFlat;
|
|
const renderIsLatitudeMinHalf =
|
|
renderMinBounds.y >= -epsilonLatitudeFlat &&
|
|
renderMinBounds.y <= +epsilonLatitudeFlat;
|
|
const renderIsLatitudeMinOverHalf = renderMinBounds.y > +epsilonLatitudeFlat;
|
|
const renderHasLatitudeMin =
|
|
renderIsLatitudeMinUnderHalf ||
|
|
renderIsLatitudeMinHalf ||
|
|
renderIsLatitudeMinOverHalf;
|
|
const renderHasLatitude = renderHasLatitudeMax || renderHasLatitudeMin;
|
|
|
|
const shapeLatitudeRange = shapeMaxBounds.y - shapeMinBounds.y;
|
|
const shapeIsLatitudeMaxUnderHalf = shapeMaxBounds.y < -epsilonLatitudeFlat;
|
|
const shapeIsLatitudeMaxHalf =
|
|
shapeMaxBounds.y >= -epsilonLatitudeFlat &&
|
|
shapeMaxBounds.y <= +epsilonLatitudeFlat;
|
|
const shapeIsLatitudeMaxOverHalf =
|
|
shapeMaxBounds.y > +epsilonLatitudeFlat &&
|
|
shapeMaxBounds.y < DefaultMaxBounds.y - epsilonLatitude;
|
|
const shapeHasLatitudeMax =
|
|
shapeIsLatitudeMaxUnderHalf ||
|
|
shapeIsLatitudeMaxHalf ||
|
|
shapeIsLatitudeMaxOverHalf;
|
|
const shapeIsLatitudeMinUnderHalf =
|
|
shapeMinBounds.y > DefaultMinBounds.y + epsilonLatitude &&
|
|
shapeMinBounds.y < -epsilonLatitudeFlat;
|
|
const shapeIsLatitudeMinHalf =
|
|
shapeMinBounds.y >= -epsilonLatitudeFlat &&
|
|
shapeMinBounds.y <= +epsilonLatitudeFlat;
|
|
const shapeIsLatitudeMinOverHalf = shapeMinBounds.y > +epsilonLatitudeFlat;
|
|
const shapeHasLatitudeMin =
|
|
shapeIsLatitudeMinUnderHalf ||
|
|
shapeIsLatitudeMinHalf ||
|
|
shapeIsLatitudeMinOverHalf;
|
|
const shapeHasLatitude = shapeHasLatitudeMax || shapeHasLatitudeMin;
|
|
|
|
const shaderUniforms = this._shaderUniforms;
|
|
const shaderDefines = this._shaderDefines;
|
|
|
|
// To keep things simple, clear the defines every time
|
|
for (const key in shaderDefines) {
|
|
if (shaderDefines.hasOwnProperty(key)) {
|
|
shaderDefines[key] = undefined;
|
|
}
|
|
}
|
|
|
|
shaderUniforms.ellipsoidRadii = Cartesian3.clone(
|
|
shapeOuterExtent,
|
|
shaderUniforms.ellipsoidRadii,
|
|
);
|
|
const { x: radiiX, z: radiiZ } = shaderUniforms.ellipsoidRadii;
|
|
const axisRatio = radiiZ / radiiX;
|
|
shaderUniforms.eccentricitySquared = 1.0 - axisRatio * axisRatio;
|
|
shaderUniforms.evoluteScale = Cartesian2.fromElements(
|
|
(radiiX * radiiX - radiiZ * radiiZ) / radiiX,
|
|
(radiiZ * radiiZ - radiiX * radiiX) / radiiZ,
|
|
shaderUniforms.evoluteScale,
|
|
);
|
|
|
|
// Used to compute geodetic surface normal.
|
|
shaderUniforms.ellipsoidInverseRadiiSquared = Cartesian3.divideComponents(
|
|
Cartesian3.ONE,
|
|
Cartesian3.multiplyComponents(
|
|
shaderUniforms.ellipsoidRadii,
|
|
shaderUniforms.ellipsoidRadii,
|
|
shaderUniforms.ellipsoidInverseRadiiSquared,
|
|
),
|
|
shaderUniforms.ellipsoidInverseRadiiSquared,
|
|
);
|
|
|
|
// Keep track of how many intersections there are going to be.
|
|
let intersectionCount = 0;
|
|
|
|
// Intersects outer and inner ellipsoid for the max and min height.
|
|
shaderDefines["ELLIPSOID_INTERSECTION_INDEX_HEIGHT_MAX"] = intersectionCount;
|
|
intersectionCount += 1;
|
|
shaderDefines["ELLIPSOID_INTERSECTION_INDEX_HEIGHT_MIN"] = intersectionCount;
|
|
intersectionCount += 1;
|
|
|
|
shaderUniforms.clipMinMaxHeight = Cartesian2.fromElements(
|
|
renderMinBounds.z - shapeMaxBounds.z,
|
|
renderMaxBounds.z - shapeMaxBounds.z,
|
|
shaderUniforms.clipMinMaxHeight,
|
|
);
|
|
|
|
// The percent of space that is between the inner and outer ellipsoid.
|
|
const thickness = shapeMaxBounds.z - shapeMinBounds.z;
|
|
const heightScale = thickness === 0.0 ? 0.0 : 1.0 / thickness;
|
|
|
|
// Intersects a wedge for the min and max longitude.
|
|
if (renderHasLongitude) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LONGITUDE"] = true;
|
|
shaderDefines["ELLIPSOID_INTERSECTION_INDEX_LONGITUDE"] = intersectionCount;
|
|
|
|
if (renderIsLongitudeRangeUnderHalf) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LONGITUDE_RANGE_UNDER_HALF"] =
|
|
true;
|
|
intersectionCount += 1;
|
|
} else if (renderIsLongitudeRangeOverHalf) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LONGITUDE_RANGE_OVER_HALF"] =
|
|
true;
|
|
intersectionCount += 2;
|
|
} else if (renderIsLongitudeRangeZero) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LONGITUDE_RANGE_EQUAL_ZERO"] =
|
|
true;
|
|
intersectionCount += 2;
|
|
}
|
|
|
|
shaderUniforms.ellipsoidRenderLongitudeMinMax = Cartesian2.fromElements(
|
|
renderMinBounds.x,
|
|
renderMaxBounds.x,
|
|
shaderUniforms.ellipsoidRenderLongitudeMinMax,
|
|
);
|
|
}
|
|
|
|
// Defaults are for the case where shapeLongitudeRange is zero, to avoid division by zero.
|
|
let longitudeScale = 0.0;
|
|
let longitudeOffset = 1.0;
|
|
|
|
if (shapeHasLongitude) {
|
|
shaderDefines["ELLIPSOID_HAS_SHAPE_BOUNDS_LONGITUDE"] = true;
|
|
|
|
const uvShapeMinLongitude =
|
|
(shapeMinBounds.x - DefaultMinBounds.x) / defaultLongitudeRange;
|
|
const uvShapeMaxLongitude =
|
|
(shapeMaxBounds.x - DefaultMinBounds.x) / defaultLongitudeRange;
|
|
const uvLongitudeRangeZero =
|
|
1.0 - shapeLongitudeRange / defaultLongitudeRange;
|
|
// Translate the origin of UV angles (in [0,1]) to the center of the unoccupied space
|
|
const uvLongitudeRangeOrigin =
|
|
(uvShapeMaxLongitude + 0.5 * uvLongitudeRangeZero) % 1.0;
|
|
shaderUniforms.ellipsoidShapeUvLongitudeRangeOrigin =
|
|
uvLongitudeRangeOrigin;
|
|
|
|
if (shapeLongitudeRange > epsilonLongitude) {
|
|
longitudeScale = defaultLongitudeRange / shapeLongitudeRange;
|
|
const shiftedMinLongitude = uvShapeMinLongitude - uvLongitudeRangeOrigin;
|
|
longitudeOffset =
|
|
-longitudeScale *
|
|
(shiftedMinLongitude - Math.floor(shiftedMinLongitude));
|
|
}
|
|
}
|
|
|
|
if (renderHasLatitude) {
|
|
// Intersects a cone for min latitude
|
|
if (renderHasLatitudeMin) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MIN"] = true;
|
|
shaderDefines["ELLIPSOID_INTERSECTION_INDEX_LATITUDE_MIN"] =
|
|
intersectionCount;
|
|
|
|
if (renderIsLatitudeMinUnderHalf) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MIN_UNDER_HALF"] =
|
|
true;
|
|
intersectionCount += 1;
|
|
} else if (renderIsLatitudeMinHalf) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MIN_EQUAL_HALF"] =
|
|
true;
|
|
intersectionCount += 1;
|
|
} else if (renderIsLatitudeMinOverHalf) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MIN_OVER_HALF"] =
|
|
true;
|
|
intersectionCount += 2;
|
|
}
|
|
}
|
|
|
|
// Intersects a cone for max latitude
|
|
if (renderHasLatitudeMax) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MAX"] = true;
|
|
shaderDefines["ELLIPSOID_INTERSECTION_INDEX_LATITUDE_MAX"] =
|
|
intersectionCount;
|
|
|
|
if (renderIsLatitudeMaxUnderHalf) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MAX_UNDER_HALF"] =
|
|
true;
|
|
intersectionCount += 2;
|
|
} else if (renderIsLatitudeMaxHalf) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MAX_EQUAL_HALF"] =
|
|
true;
|
|
intersectionCount += 1;
|
|
} else if (renderIsLatitudeMaxOverHalf) {
|
|
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MAX_OVER_HALF"] =
|
|
true;
|
|
intersectionCount += 1;
|
|
}
|
|
}
|
|
|
|
shaderUniforms.ellipsoidRenderLatitudeSinMinMax = Cartesian2.fromElements(
|
|
Math.sin(renderMinBounds.y),
|
|
Math.sin(renderMaxBounds.y),
|
|
shaderUniforms.ellipsoidRenderLatitudeSinMinMax,
|
|
);
|
|
}
|
|
|
|
// Defaults are for the case where shapeLatitudeRange is zero, to avoid division by zero.
|
|
let latitudeScale = 0.0;
|
|
let latitudeOffset = 1.0;
|
|
|
|
if (shapeHasLatitude) {
|
|
shaderDefines["ELLIPSOID_HAS_SHAPE_BOUNDS_LATITUDE"] = true;
|
|
|
|
if (shapeLatitudeRange > epsilonLatitude) {
|
|
const defaultLatitudeRange = DefaultMaxBounds.y - DefaultMinBounds.y;
|
|
latitudeScale = defaultLatitudeRange / shapeLatitudeRange;
|
|
latitudeOffset =
|
|
(DefaultMinBounds.y - shapeMinBounds.y) / shapeLatitudeRange;
|
|
}
|
|
}
|
|
|
|
// Store scales in shader uniforms (GPU) and translates in private property (JS-only)
|
|
shaderUniforms.ellipsoidLocalToShapeUvScale = Cartesian3.fromElements(
|
|
longitudeScale,
|
|
latitudeScale,
|
|
heightScale,
|
|
shaderUniforms.ellipsoidLocalToShapeUvScale,
|
|
);
|
|
|
|
this._localToShapeUvTranslate = Cartesian3.fromElements(
|
|
longitudeOffset,
|
|
latitudeOffset,
|
|
0.0, // Height translate not used (always 1.0 + height * scale)
|
|
this._localToShapeUvTranslate,
|
|
);
|
|
|
|
this._shaderMaximumIntersectionsLength = intersectionCount;
|
|
|
|
return true;
|
|
};
|
|
|
|
const scratchCameraPositionCartographic = new Cartographic();
|
|
const surfacePositionScratch = new Cartesian3();
|
|
const enuTransformScratch = new Matrix4();
|
|
const enuRotationScratch = new Matrix3();
|
|
/**
|
|
* Update any view-dependent transforms.
|
|
* @private
|
|
* @param {FrameState} frameState The frame state.
|
|
*/
|
|
VoxelEllipsoidShape.prototype.updateViewTransforms = function (frameState) {
|
|
const shaderUniforms = this._shaderUniforms;
|
|
const ellipsoid = this._ellipsoid;
|
|
// TODO: incorporate modelMatrix or shapeTransform here?
|
|
const cameraWC = frameState.camera.positionWC;
|
|
const cameraPositionCartographic = ellipsoid.cartesianToCartographic(
|
|
cameraWC,
|
|
scratchCameraPositionCartographic,
|
|
);
|
|
Cartesian3.fromElements(
|
|
cameraPositionCartographic.longitude,
|
|
cameraPositionCartographic.latitude,
|
|
cameraPositionCartographic.height,
|
|
shaderUniforms.cameraPositionCartographic,
|
|
);
|
|
|
|
// TODO: incorporate modelMatrix here?
|
|
const surfacePosition = Cartesian3.fromRadians(
|
|
cameraPositionCartographic.longitude,
|
|
cameraPositionCartographic.latitude,
|
|
0.0,
|
|
ellipsoid,
|
|
surfacePositionScratch,
|
|
);
|
|
|
|
shaderUniforms.ellipsoidCurvatureAtLatitude = ellipsoid.getLocalCurvature(
|
|
surfacePosition,
|
|
shaderUniforms.ellipsoidCurvatureAtLatitude,
|
|
);
|
|
|
|
const enuToWorld = Transforms.eastNorthUpToFixedFrame(
|
|
surfacePosition,
|
|
ellipsoid,
|
|
enuTransformScratch,
|
|
);
|
|
const rotateEnuToWorld = Matrix4.getRotation(enuToWorld, enuRotationScratch);
|
|
const rotateWorldToView = frameState.context.uniformState.viewRotation;
|
|
const rotateEnuToView = Matrix3.multiply(
|
|
rotateWorldToView,
|
|
rotateEnuToWorld,
|
|
enuRotationScratch,
|
|
);
|
|
// Inverse is the transpose since it's a pure rotation.
|
|
shaderUniforms.ellipsoidEcToEastNorthUp = Matrix3.transpose(
|
|
rotateEnuToView,
|
|
shaderUniforms.ellipsoidEcToEastNorthUp,
|
|
);
|
|
};
|
|
|
|
const scratchRectangle = new Rectangle();
|
|
|
|
/**
|
|
* Computes an oriented bounding box for a specified tile.
|
|
* @private
|
|
* @param {number} tileLevel The tile's level.
|
|
* @param {number} tileX The tile's x coordinate.
|
|
* @param {number} tileY The tile's y coordinate.
|
|
* @param {number} tileZ The tile's z coordinate.
|
|
* @param {OrientedBoundingBox} result The oriented bounding box that will be set to enclose the specified tile
|
|
* @returns {OrientedBoundingBox} The oriented bounding box.
|
|
*/
|
|
VoxelEllipsoidShape.prototype.computeOrientedBoundingBoxForTile = function (
|
|
tileLevel,
|
|
tileX,
|
|
tileY,
|
|
tileZ,
|
|
result,
|
|
) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
Check.typeOf.number("tileLevel", tileLevel);
|
|
Check.typeOf.number("tileX", tileX);
|
|
Check.typeOf.number("tileY", tileY);
|
|
Check.typeOf.number("tileZ", tileZ);
|
|
Check.typeOf.object("result", result);
|
|
//>>includeEnd('debug');
|
|
|
|
const sizeAtLevel = 1.0 / Math.pow(2.0, tileLevel);
|
|
const minLongitudeLerp = tileX * sizeAtLevel;
|
|
const maxLongitudeLerp = (tileX + 1) * sizeAtLevel;
|
|
const minLatitudeLerp = tileY * sizeAtLevel;
|
|
const maxLatitudeLerp = (tileY + 1) * sizeAtLevel;
|
|
const minHeightLerp = tileZ * sizeAtLevel;
|
|
const maxHeightLerp = (tileZ + 1) * sizeAtLevel;
|
|
|
|
const rectangle = Rectangle.subsection(
|
|
this._rectangle,
|
|
minLongitudeLerp,
|
|
minLatitudeLerp,
|
|
maxLongitudeLerp,
|
|
maxLatitudeLerp,
|
|
scratchRectangle,
|
|
);
|
|
|
|
const minHeight = CesiumMath.lerp(
|
|
this._minimumHeight,
|
|
this._maximumHeight,
|
|
minHeightLerp,
|
|
);
|
|
|
|
const maxHeight = CesiumMath.lerp(
|
|
this._minimumHeight,
|
|
this._maximumHeight,
|
|
maxHeightLerp,
|
|
);
|
|
|
|
return getEllipsoidChunkObb(
|
|
rectangle,
|
|
minHeight,
|
|
maxHeight,
|
|
this._ellipsoid,
|
|
this._translation,
|
|
this._rotation,
|
|
result,
|
|
);
|
|
};
|
|
|
|
const scratchQuadrantPosition = new Cartesian2();
|
|
const scratchInverseRadii = new Cartesian2();
|
|
const scratchEllipseTrigs = new Cartesian2();
|
|
const scratchEllipseGuess = new Cartesian2();
|
|
const scratchEvolute = new Cartesian2();
|
|
const scratchQ = new Cartesian2();
|
|
|
|
/**
|
|
* Find the nearest point on an ellipse and its radius.
|
|
* @param {Cartesian2} position
|
|
* @param {Cartesian2} radii
|
|
* @param {Cartesian2} evoluteScale
|
|
* @param {Cartesian3} result The Cartesian3 to store the result in. .x and .y components contain the nearest point on the ellipse, .z contains the local radius of curvature.
|
|
* @returns {Cartesian3} The nearest point on the ellipse and its radius.
|
|
* @private
|
|
*/
|
|
function nearestPointAndRadiusOnEllipse(position, radii, evoluteScale, result) {
|
|
// Map to the first quadrant
|
|
const p = Cartesian2.abs(position, scratchQuadrantPosition);
|
|
const inverseRadii = Cartesian2.fromElements(
|
|
1.0 / radii.x,
|
|
1.0 / radii.y,
|
|
scratchInverseRadii,
|
|
);
|
|
// We describe the ellipse parametrically: v = radii * vec2(cos(t), sin(t))
|
|
// but store the cos and sin of t in a vec2 for efficiency.
|
|
// Initial guess: t = pi/4
|
|
let tTrigs = Cartesian2.fromElements(
|
|
Math.SQRT1_2,
|
|
Math.SQRT1_2,
|
|
scratchEllipseTrigs,
|
|
);
|
|
// TODO: too much duplication. Move v and evolute declarations inside loop?
|
|
// Initial guess of point on ellipsoid
|
|
let v = Cartesian2.multiplyComponents(radii, tTrigs, scratchEllipseGuess);
|
|
// Center of curvature of the ellipse at v
|
|
let evolute = Cartesian2.fromElements(
|
|
evoluteScale.x * tTrigs.x * tTrigs.x * tTrigs.x,
|
|
evoluteScale.y * tTrigs.y * tTrigs.y * tTrigs.y,
|
|
scratchEvolute,
|
|
);
|
|
for (let i = 0; i < 3; ++i) {
|
|
// Find the (approximate) intersection of p - evolute with the ellipsoid.
|
|
const distance = Cartesian2.magnitude(
|
|
Cartesian2.subtract(v, evolute, scratchQ),
|
|
);
|
|
const direction = Cartesian2.normalize(
|
|
Cartesian2.subtract(p, evolute, scratchQ),
|
|
scratchQ,
|
|
);
|
|
const q = Cartesian2.multiplyByScalar(direction, distance, scratchQ);
|
|
// Update the estimate of t
|
|
tTrigs = Cartesian2.multiplyComponents(
|
|
Cartesian2.add(q, evolute, scratchEllipseTrigs),
|
|
inverseRadii,
|
|
scratchEllipseTrigs,
|
|
);
|
|
tTrigs = Cartesian2.normalize(
|
|
Cartesian2.clamp(
|
|
tTrigs,
|
|
Cartesian2.ZERO,
|
|
Cartesian2.ONE,
|
|
scratchEllipseTrigs,
|
|
),
|
|
scratchEllipseTrigs,
|
|
);
|
|
v = Cartesian2.multiplyComponents(radii, tTrigs, scratchEllipseGuess);
|
|
evolute = Cartesian2.fromElements(
|
|
evoluteScale.x * tTrigs.x * tTrigs.x * tTrigs.x,
|
|
evoluteScale.y * tTrigs.y * tTrigs.y * tTrigs.y,
|
|
scratchEvolute,
|
|
);
|
|
}
|
|
|
|
// Map back to the original quadrant
|
|
return Cartesian3.fromElements(
|
|
Math.sign(position.x) * v.x,
|
|
Math.sign(position.y) * v.y,
|
|
Cartesian2.magnitude(Cartesian2.subtract(v, evolute, scratchQ)),
|
|
result,
|
|
);
|
|
}
|
|
|
|
const scratchEllipseRadii = new Cartesian2();
|
|
const scratchEllipsePosition = new Cartesian2();
|
|
const scratchSurfacePointAndRadius = new Cartesian3();
|
|
const scratchNormal2d = new Cartesian2();
|
|
/**
|
|
* Convert a UV coordinate to the shape's UV space.
|
|
* @private
|
|
* @param {Cartesian3} positionLocal The local position to convert.
|
|
* @param {Cartesian3} result The Cartesian3 to store the result in.
|
|
* @returns {Cartesian3} The converted UV coordinate.
|
|
*/
|
|
VoxelEllipsoidShape.prototype.convertLocalToShapeUvSpace = function (
|
|
positionLocal,
|
|
result,
|
|
) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
Check.typeOf.object("positionLocal", positionLocal);
|
|
Check.typeOf.object("result", result);
|
|
//>>includeEnd('debug');
|
|
|
|
let longitude = Math.atan2(positionLocal.y, positionLocal.x);
|
|
|
|
const {
|
|
ellipsoidRadii,
|
|
evoluteScale,
|
|
ellipsoidInverseRadiiSquared,
|
|
ellipsoidShapeUvLongitudeRangeOrigin,
|
|
ellipsoidLocalToShapeUvScale,
|
|
} = this._shaderUniforms;
|
|
const localToShapeUvTranslate = this._localToShapeUvTranslate;
|
|
|
|
const distanceFromZAxis = Math.hypot(positionLocal.x, positionLocal.y);
|
|
const posEllipse = Cartesian2.fromElements(
|
|
distanceFromZAxis,
|
|
positionLocal.z,
|
|
scratchEllipsePosition,
|
|
);
|
|
const surfacePointAndRadius = nearestPointAndRadiusOnEllipse(
|
|
posEllipse,
|
|
Cartesian2.fromElements(
|
|
ellipsoidRadii.x,
|
|
ellipsoidRadii.z,
|
|
scratchEllipseRadii,
|
|
),
|
|
evoluteScale,
|
|
scratchSurfacePointAndRadius,
|
|
);
|
|
|
|
const normal2d = Cartesian2.normalize(
|
|
Cartesian2.fromElements(
|
|
surfacePointAndRadius.x * ellipsoidInverseRadiiSquared.x,
|
|
surfacePointAndRadius.y * ellipsoidInverseRadiiSquared.z,
|
|
scratchNormal2d,
|
|
),
|
|
scratchNormal2d,
|
|
);
|
|
let latitude = Math.atan2(normal2d.y, normal2d.x);
|
|
|
|
const heightSign =
|
|
Cartesian2.magnitude(posEllipse) <
|
|
Cartesian2.magnitude(surfacePointAndRadius)
|
|
? -1.0
|
|
: 1.0;
|
|
const heightVector = Cartesian2.subtract(
|
|
posEllipse,
|
|
surfacePointAndRadius,
|
|
scratchEllipsePosition,
|
|
);
|
|
let height = heightSign * Cartesian2.magnitude(heightVector);
|
|
|
|
const {
|
|
ELLIPSOID_HAS_SHAPE_BOUNDS_LONGITUDE,
|
|
ELLIPSOID_HAS_SHAPE_BOUNDS_LATITUDE,
|
|
} = this._shaderDefines;
|
|
|
|
longitude = (longitude + Math.PI) / (2.0 * Math.PI);
|
|
if (defined(ELLIPSOID_HAS_SHAPE_BOUNDS_LONGITUDE)) {
|
|
longitude -= ellipsoidShapeUvLongitudeRangeOrigin;
|
|
longitude = longitude - Math.floor(longitude);
|
|
// Scale and shift so [0, 1] covers the occupied space.
|
|
longitude =
|
|
longitude * ellipsoidLocalToShapeUvScale.x + localToShapeUvTranslate.x;
|
|
}
|
|
|
|
latitude = (latitude + Math.PI / 2.0) / Math.PI;
|
|
if (defined(ELLIPSOID_HAS_SHAPE_BOUNDS_LATITUDE)) {
|
|
// Scale and shift so [0, 1] covers the occupied space.
|
|
latitude =
|
|
latitude * ellipsoidLocalToShapeUvScale.y + localToShapeUvTranslate.y;
|
|
}
|
|
|
|
height = 1.0 + height * ellipsoidLocalToShapeUvScale.z;
|
|
|
|
return Cartesian3.fromElements(longitude, latitude, height, result);
|
|
};
|
|
|
|
const sampleSizeScratch = new Cartesian3();
|
|
const scratchTileMinBounds = new Cartesian3();
|
|
const scratchTileMaxBounds = new Cartesian3();
|
|
|
|
/**
|
|
* Computes an oriented bounding box for a specified sample within a specified tile.
|
|
* @private
|
|
* @param {SpatialNode} spatialNode The spatial node containing the sample
|
|
* @param {Cartesian3} tileDimensions The size of the tile in number of samples, before padding
|
|
* @param {Cartesian3} tileUv The sample coordinate within the tile
|
|
* @param {OrientedBoundingBox} result The oriented bounding box that will be set to enclose the specified sample
|
|
* @returns {OrientedBoundingBox} The oriented bounding box.
|
|
*/
|
|
VoxelEllipsoidShape.prototype.computeOrientedBoundingBoxForSample = function (
|
|
spatialNode,
|
|
tileDimensions,
|
|
tileUv,
|
|
result,
|
|
) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
Check.typeOf.object("spatialNode", spatialNode);
|
|
Check.typeOf.object("tileDimensions", tileDimensions);
|
|
Check.typeOf.object("tileUv", tileUv);
|
|
Check.typeOf.object("result", result);
|
|
//>>includeEnd('debug');
|
|
|
|
const tileSizeAtLevel = 1.0 / Math.pow(2.0, spatialNode.level);
|
|
const sampleSize = Cartesian3.divideComponents(
|
|
Cartesian3.ONE,
|
|
tileDimensions,
|
|
sampleSizeScratch,
|
|
);
|
|
const sampleSizeAtLevel = Cartesian3.multiplyByScalar(
|
|
sampleSize,
|
|
tileSizeAtLevel,
|
|
sampleSizeScratch,
|
|
);
|
|
|
|
const minLerp = Cartesian3.multiplyByScalar(
|
|
Cartesian3.fromElements(
|
|
spatialNode.x + tileUv.x,
|
|
spatialNode.y + tileUv.y,
|
|
spatialNode.z + tileUv.z,
|
|
scratchTileMinBounds,
|
|
),
|
|
tileSizeAtLevel,
|
|
scratchTileMinBounds,
|
|
);
|
|
const maxLerp = Cartesian3.add(
|
|
minLerp,
|
|
sampleSizeAtLevel,
|
|
scratchTileMaxBounds,
|
|
);
|
|
|
|
const rectangle = Rectangle.subsection(
|
|
this._rectangle,
|
|
minLerp.x,
|
|
minLerp.y,
|
|
maxLerp.x,
|
|
maxLerp.y,
|
|
scratchRectangle,
|
|
);
|
|
const minHeight = CesiumMath.lerp(
|
|
this._minimumHeight,
|
|
this._maximumHeight,
|
|
minLerp.z,
|
|
);
|
|
const maxHeight = CesiumMath.lerp(
|
|
this._minimumHeight,
|
|
this._maximumHeight,
|
|
maxLerp.z,
|
|
);
|
|
|
|
return getEllipsoidChunkObb(
|
|
rectangle,
|
|
minHeight,
|
|
maxHeight,
|
|
this._ellipsoid,
|
|
this._translation,
|
|
this._rotation,
|
|
result,
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Computes an {@link OrientedBoundingBox} for a subregion of the shape.
|
|
*
|
|
* @function
|
|
*
|
|
* @param {Rectangle} rectangle The rectangle.
|
|
* @param {number} minHeight The minimumZ.
|
|
* @param {number} maxHeight The maximumZ.
|
|
* @param {Ellipsoid} ellipsoid The ellipsoid.
|
|
* @param {Cartesian3} translation The translation applied to the shape
|
|
* @param {Matrix3} rotation The rotation applied to the shape
|
|
* @param {OrientedBoundingBox} result The object onto which to store the result.
|
|
* @returns {OrientedBoundingBox} The oriented bounding box that contains this subregion.
|
|
*
|
|
* @private
|
|
*/
|
|
function getEllipsoidChunkObb(
|
|
rectangle,
|
|
minHeight,
|
|
maxHeight,
|
|
ellipsoid,
|
|
translation,
|
|
rotation,
|
|
result,
|
|
) {
|
|
result = OrientedBoundingBox.fromRectangle(
|
|
rectangle,
|
|
minHeight,
|
|
maxHeight,
|
|
ellipsoid,
|
|
result,
|
|
);
|
|
result.center = Cartesian3.add(result.center, translation, result.center);
|
|
result.halfAxes = Matrix3.multiply(
|
|
result.halfAxes,
|
|
rotation,
|
|
result.halfAxes,
|
|
);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Defines the minimum bounds of the shape. Corresponds to minimum longitude, latitude, height.
|
|
* @private
|
|
* @type {Cartesian3}
|
|
* @constant
|
|
* @readonly
|
|
*/
|
|
VoxelEllipsoidShape.DefaultMinBounds = Object.freeze(
|
|
new Cartesian3(
|
|
-CesiumMath.PI,
|
|
-CesiumMath.PI_OVER_TWO,
|
|
-Ellipsoid.WGS84.minimumRadius,
|
|
),
|
|
);
|
|
|
|
/**
|
|
* Defines the maximum bounds of the shape. Corresponds to maximum longitude, latitude, height.
|
|
* @private
|
|
* @type {Cartesian3}
|
|
* @constant
|
|
* @readonly
|
|
*/
|
|
VoxelEllipsoidShape.DefaultMaxBounds = Object.freeze(
|
|
new Cartesian3(
|
|
CesiumMath.PI,
|
|
CesiumMath.PI_OVER_TWO,
|
|
10.0 * Ellipsoid.WGS84.maximumRadius,
|
|
),
|
|
);
|
|
|
|
export default VoxelEllipsoidShape;
|