胶州空管前端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2763 lines
84 KiB

const EPSILON14 = 0.00000000000001;
const EPSILON15 = 0.000000000000001;
const PI_OVER_TWO = Math.PI / 2.0;
const SHIFT_LEFT_12 = Math.pow(2.0, 12.0);
const TerrainQuantization = {
NONE: 0,
BITS12: 1
}
const maxShort = 32767;
const halfMaxShort = (maxShort / 2) | 0;
function defined(target) {
return target !== undefined && target !== null;
}
function defaultValue(value, defaultValue) {
if (!defined(value)) return defaultValue;
return value;
}
function lerp(p, q, time) {
return (1.0 - time) * p + time * q;
};
function clamp(value, min, max) {
return value < min ? min : value > max ? max : value;
};
function equalsEpsilon(a, b, epsilon) {
return Math.abs(a - b) <= epsilon;
}
function sign(a) {
if (a == 0) return 0;
return Math.abs(a) === a ? 1.0 : -1.0;
}
function fromSNorm(value, rangeMaximum) {
rangeMaximum = defaultValue(rangeMaximum, 255);
return (clamp(value, 0.0, rangeMaximum) / rangeMaximum) * 2.0 - 1.0;
}
function signNotZero(value) {
return value < 0.0 ? -1.0 : 1.0;
}
function mod(m, n) {
if (sign(m) == sign(n) && Math.abs(m) < Math.abs(n)) return m;
return ((m % n) + n) % n;
}
function zeroToTwoPi(angle) {
if (angle >= 0 && angle <= Math.PI * 2) {
return angle;
}
const modr = mod(angle, Math.PI * 2);
if (
Math.abs(modr) < EPSILON14 &&
Math.abs(angle) > EPSILON14
) {
return Math.PI * 2;
}
return modr;
}
function negativePiToPi(angle) {
if (angle >= -Math.PI && angle <= Math.PI) {
return angle;
}
return zeroToTwoPi(angle + Math.PI) - Math.PI;
}
function scaleToGeodeticSurface(
cartesian,
oneOverRadii,
oneOverRadiiSquared,
centerToleranceSquared,
result
) {
const positionX = cartesian.x;
const positionY = cartesian.y;
const positionZ = cartesian.z;
const oneOverRadiiX = oneOverRadii.x;
const oneOverRadiiY = oneOverRadii.y;
const oneOverRadiiZ = oneOverRadii.z;
const x2 = positionX * positionX * oneOverRadiiX * oneOverRadiiX;
const y2 = positionY * positionY * oneOverRadiiY * oneOverRadiiY;
const z2 = positionZ * positionZ * oneOverRadiiZ * oneOverRadiiZ;
// Compute the squared ellipsoid norm.
const squaredNorm = x2 + y2 + z2;
const ratio = Math.sqrt(1.0 / squaredNorm);
// As an initial approximation, assume that the radial intersection is the projection point.
const intersection = Vector3.multiplyByScalar(
cartesian,
ratio
);
// If the position is near the center, the iteration will not converge.
if (squaredNorm < centerToleranceSquared) {
return !isFinite(ratio)
? undefined
: result.copy(intersection);
}
const oneOverRadiiSquaredX = oneOverRadiiSquared.x;
const oneOverRadiiSquaredY = oneOverRadiiSquared.y;
const oneOverRadiiSquaredZ = oneOverRadiiSquared.z;
// Use the gradient at the intersection point in place of the true unit normal.
// The difference in magnitude will be absorbed in the multiplier.
const gradient = new Vector3();
gradient.x = intersection.x * oneOverRadiiSquaredX * 2.0;
gradient.y = intersection.y * oneOverRadiiSquaredY * 2.0;
gradient.z = intersection.z * oneOverRadiiSquaredZ * 2.0;
// Compute the initial guess at the normal vector multiplier, lambda.
let lambda =
((1.0 - ratio) * cartesian.length()) /
(0.5 * gradient.length());
let correction = 0.0;
let func;
let denominator;
let xMultiplier;
let yMultiplier;
let zMultiplier;
let xMultiplier2;
let yMultiplier2;
let zMultiplier2;
let xMultiplier3;
let yMultiplier3;
let zMultiplier3;
do {
lambda -= correction;
xMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredX);
yMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredY);
zMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredZ);
xMultiplier2 = xMultiplier * xMultiplier;
yMultiplier2 = yMultiplier * yMultiplier;
zMultiplier2 = zMultiplier * zMultiplier;
xMultiplier3 = xMultiplier2 * xMultiplier;
yMultiplier3 = yMultiplier2 * yMultiplier;
zMultiplier3 = zMultiplier2 * zMultiplier;
func = x2 * xMultiplier2 + y2 * yMultiplier2 + z2 * zMultiplier2 - 1.0;
// "denominator" here refers to the use of this expression in the velocity and acceleration
// computations in the sections to follow.
denominator =
x2 * xMultiplier3 * oneOverRadiiSquaredX +
y2 * yMultiplier3 * oneOverRadiiSquaredY +
z2 * zMultiplier3 * oneOverRadiiSquaredZ;
const derivative = -2.0 * denominator;
correction = func / derivative;
} while (Math.abs(func) > CesiumMath.EPSILON12);
if (!defined(result)) {
return new Vector3(
positionX * xMultiplier,
positionY * yMultiplier,
positionZ * zMultiplier
);
}
result.x = positionX * xMultiplier;
result.y = positionY * yMultiplier;
result.z = positionZ * zMultiplier;
return result;
}
class Vector3 {
constructor (x,y,z) {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
}
static midpoint(left, right, result) {
if (!defined(result)) result = new Vector3();
result.set(
(left.x + right.x) * 0.5,
(left.y + right.y) * 0.5,
(left.z + right.z) * 0.5,
);
return result;
}
static minimumByComponent(v1, v2, result) {
if (!defined(result)) result = new Vector3();
result.set(
Math.min(v1.x, v2.x),
Math.min(v1.y, v2.y),
Math.min(v1.z, v2.z)
)
return result;
}
static maximumByComponent(v1, v2, result) {
if (!defined(result)) result = new Vector3();
result.set(
Math.max(v1.x, v2.x),
Math.max(v1.y, v2.y),
Math.max(v1.z, v2.z)
);
return result;
}
static maximumComponent(v) {
return Math.max(v.x, v.y, v.z);
}
static equals(v1, v2) {
return (v1.x == v2.x &&
v1.y == v2.x &&
v1.z == v2.z);
}
static equalsEpsilon(v1, v2, epsilon) {
return (Math.abs(v1.x - v2.x) <= epsilon &&
Math.abs(v1.y - v2.y) <= epsilon &&
Math.abs(v1.z - v2.z) <= epsilon
);
}
static unpack(array, startIndex, v) {
v.x = array[startIndex];
v.y = array[startIndex + 1];
v.z = array[startIndex + 2];
}
static multiplyByScalar(v, scalar, result) {
if (!defined(result)) result = new Vector3();
result.x = v.x * scalar;
result.y = v.y * scalar;
result.z = v.z * scalar;
return result;
}
static multiplyComponents(left, right, result) {
if (!defined(result)) result = new Vector3();
result.x = left.x * right.x;
result.y = left.y * right.y;
result.z = left.z * right.z;
return result;
}
static divideByScalar(v, scalar, result) {
if (!defined(result)) result = new Vector3();
result.x = v.x / scalar;
result.y = v.y / scalar;
result.z = v.z / scalar;
return result;
}
static subtract(left, right, result) {
if (!defined(result)) {
result = new Vector3();
}
result.set(
left.x - right.x,
left.y - right.y,
left.z - right.z
);
return result;
}
static negate(v, result) {
if (!defined(result)) {
result = new Vector3();
}
result.set(
-v.x, -v.y, -v.z
);
return result;
}
negate(){
this.x = -this.x;
this.y = -this.y;
this.z = -this.z;
return this;
}
static dot(left, right) {
return left.x * right.x + left.y * right.y + left.z * right.z;
}
static cross(left, right, result) {
if (!defined(result)) result = new Vector3();
const leftX = left.x;
const leftY = left.y;
const leftZ = left.z;
const rightX = right.x;
const rightY = right.y;
const rightZ = right.z;
const x = leftY * rightZ - leftZ * rightY;
const y = leftZ * rightX - leftX * rightZ;
const z = leftX * rightY - leftY * rightX;
result.x = x;
result.y = y;
result.z = z;
return result;
}
clone() {
return new Vector3(this.x, this.y, this.z);
}
static clone(source) {
return new Vector3(source.x, source.y, source.z);
}
copy(source) {
this.set(
source.x, source.y, source.z
)
return this;
}
length() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
lengthSquare() {
return this.x * this.x + this.y * this.y + this.z * this.z;
}
normalize() {
const length = this.length() || 1;
return Vector3.divideByScalar(this, length, this);
}
set(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
static add(left, right, result) {
if (!defined(result)) result = new Vector3();
result.set(
left.x + right.x,
left.y + right.y,
left.z + right.z
);
return result;
}
static normalize(v, result) {
if (!defined(result)) result = new Vector3();
const length = v.length() || 1.0;
return Vector3.divideByScalar(v, length, result);
}
static fromCartesian4(v) {
return new Vector3(v.x, v.y, v.z);
}
}
Vector3.ZERO = Object.freeze(new Vector3(0, 0, 0))
class Vector2 {
constructor(x, y) {
this.x = x || 0;
this.y = y || 0;
}
set(x, y) {
this.x = x;
this.y = y;
}
}
class Vector4 {
constructor(x, y, z, w) {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
this.w = w || 0;
}
}
class Matrix4 {
constructor(
column0Row0,
column1Row0,
column2Row0,
column3Row0,
column0Row1,
column1Row1,
column2Row1,
column3Row1,
column0Row2,
column1Row2,
column2Row2,
column3Row2,
column0Row3,
column1Row3,
column2Row3,
column3Row3
) {
this[0] = defaultValue(column0Row0, 0.0);
this[1] = defaultValue(column0Row1, 0.0);
this[2] = defaultValue(column0Row2, 0.0);
this[3] = defaultValue(column0Row3, 0.0);
this[4] = defaultValue(column1Row0, 0.0);
this[5] = defaultValue(column1Row1, 0.0);
this[6] = defaultValue(column1Row2, 0.0);
this[7] = defaultValue(column1Row3, 0.0);
this[8] = defaultValue(column2Row0, 0.0);
this[9] = defaultValue(column2Row1, 0.0);
this[10] = defaultValue(column2Row2, 0.0);
this[11] = defaultValue(column2Row3, 0.0);
this[12] = defaultValue(column3Row0, 0.0);
this[13] = defaultValue(column3Row1, 0.0);
this[14] = defaultValue(column3Row2, 0.0);
this[15] = defaultValue(column3Row3, 0.0);
}
static multiplyByPoint(matrix, cartesian, result) {
if (!defined(result)) result = new Vector3();
const vX = cartesian.x;
const vY = cartesian.y;
const vZ = cartesian.z;
const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ + matrix[12];
const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ + matrix[13];
const z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ + matrix[14];
result.x = x;
result.y = y;
result.z = z;
return result;
}
static inverseTransformation(matrix, result) {
if (!defined(result)) result = new Matrix4();
const matrix0 = matrix[0];
const matrix1 = matrix[1];
const matrix2 = matrix[2];
const matrix4 = matrix[4];
const matrix5 = matrix[5];
const matrix6 = matrix[6];
const matrix8 = matrix[8];
const matrix9 = matrix[9];
const matrix10 = matrix[10];
const vX = matrix[12];
const vY = matrix[13];
const vZ = matrix[14];
const x = -matrix0 * vX - matrix1 * vY - matrix2 * vZ;
const y = -matrix4 * vX - matrix5 * vY - matrix6 * vZ;
const z = -matrix8 * vX - matrix9 * vY - matrix10 * vZ;
result[0] = matrix0;
result[1] = matrix4;
result[2] = matrix8;
result[3] = 0.0;
result[4] = matrix1;
result[5] = matrix5;
result[6] = matrix9;
result[7] = 0.0;
result[8] = matrix2;
result[9] = matrix6;
result[10] = matrix10;
result[11] = 0.0;
result[12] = x;
result[13] = y;
result[14] = z;
result[15] = 1.0;
return result;
}
static multiply(left, right, result) {
if (!defined(result)) {
result = new Matrix4();
}
const left0 = left[0];
const left1 = left[1];
const left2 = left[2];
const left3 = left[3];
const left4 = left[4];
const left5 = left[5];
const left6 = left[6];
const left7 = left[7];
const left8 = left[8];
const left9 = left[9];
const left10 = left[10];
const left11 = left[11];
const left12 = left[12];
const left13 = left[13];
const left14 = left[14];
const left15 = left[15];
const right0 = right[0];
const right1 = right[1];
const right2 = right[2];
const right3 = right[3];
const right4 = right[4];
const right5 = right[5];
const right6 = right[6];
const right7 = right[7];
const right8 = right[8];
const right9 = right[9];
const right10 = right[10];
const right11 = right[11];
const right12 = right[12];
const right13 = right[13];
const right14 = right[14];
const right15 = right[15];
const column0Row0 =
left0 * right0 + left4 * right1 + left8 * right2 + left12 * right3;
const column0Row1 =
left1 * right0 + left5 * right1 + left9 * right2 + left13 * right3;
const column0Row2 =
left2 * right0 + left6 * right1 + left10 * right2 + left14 * right3;
const column0Row3 =
left3 * right0 + left7 * right1 + left11 * right2 + left15 * right3;
const column1Row0 =
left0 * right4 + left4 * right5 + left8 * right6 + left12 * right7;
const column1Row1 =
left1 * right4 + left5 * right5 + left9 * right6 + left13 * right7;
const column1Row2 =
left2 * right4 + left6 * right5 + left10 * right6 + left14 * right7;
const column1Row3 =
left3 * right4 + left7 * right5 + left11 * right6 + left15 * right7;
const column2Row0 =
left0 * right8 + left4 * right9 + left8 * right10 + left12 * right11;
const column2Row1 =
left1 * right8 + left5 * right9 + left9 * right10 + left13 * right11;
const column2Row2 =
left2 * right8 + left6 * right9 + left10 * right10 + left14 * right11;
const column2Row3 =
left3 * right8 + left7 * right9 + left11 * right10 + left15 * right11;
const column3Row0 =
left0 * right12 + left4 * right13 + left8 * right14 + left12 * right15;
const column3Row1 =
left1 * right12 + left5 * right13 + left9 * right14 + left13 * right15;
const column3Row2 =
left2 * right12 + left6 * right13 + left10 * right14 + left14 * right15;
const column3Row3 =
left3 * right12 + left7 * right13 + left11 * right14 + left15 * right15;
result[0] = column0Row0;
result[1] = column0Row1;
result[2] = column0Row2;
result[3] = column0Row3;
result[4] = column1Row0;
result[5] = column1Row1;
result[6] = column1Row2;
result[7] = column1Row3;
result[8] = column2Row0;
result[9] = column2Row1;
result[10] = column2Row2;
result[11] = column2Row3;
result[12] = column3Row0;
result[13] = column3Row1;
result[14] = column3Row2;
result[15] = column3Row3;
return result;
}
static fromTranslation(translation, result) {
if (!defined(result)) {
return new Matrix4(
1.0, 0.0, 0.0, translation.x,
0.0, 1.0, 0.0, translation.y,
0.0, 0.0, 1.0, translation.z,
0.0, 0.0, 0.0, 1.0
);
}
result[0] = 1.0;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = 1.0;
result[6] = 0.0;
result[7] = 0.0;
result[8] = 0.0;
result[9] = 0.0;
result[10] = 1.0;
result[11] = 0.0;
result[12] = translation.x;
result[13] = translation.y;
result[14] = translation.z;
result[15] = 1.0;
return result;
}
static fromRotationTranslation(rotation, translation, result) {
translation = defaultValue(translation, Vector3.ZERO);
if (!defined(result)) {
return new Matrix4(
rotation[0],
rotation[3],
rotation[6],
translation.x,
rotation[1],
rotation[4],
rotation[7],
translation.y,
rotation[2],
rotation[5],
rotation[8],
translation.z,
0.0,
0.0,
0.0,
1.0
);
}
result[0] = rotation[0];
result[1] = rotation[1];
result[2] = rotation[2];
result[3] = 0.0;
result[4] = rotation[3];
result[5] = rotation[4];
result[6] = rotation[5];
result[7] = 0.0;
result[8] = rotation[6];
result[9] = rotation[7];
result[10] = rotation[8];
result[11] = 0.0;
result[12] = translation.x;
result[13] = translation.y;
result[14] = translation.z;
result[15] = 1.0;
return result;
}
static fromScale(scale, result) {
if (!defined(result)) {
return new Matrix4(
scale.x,
0.0,
0.0,
0.0,
0.0,
scale.y,
0.0,
0.0,
0.0,
0.0,
scale.z,
0.0,
0.0,
0.0,
0.0,
1.0
);
}
result[0] = scale.x;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = scale.y;
result[6] = 0.0;
result[7] = 0.0;
result[8] = 0.0;
result[9] = 0.0;
result[10] = scale.z;
result[11] = 0.0;
result[12] = 0.0;
result[13] = 0.0;
result[14] = 0.0;
result[15] = 1.0;
return result;
}
static clone(matrix, result) {
if (!defined(result)) {
return new Matrix4(
matrix[0],
matrix[4],
matrix[8],
matrix[12],
matrix[1],
matrix[5],
matrix[9],
matrix[13],
matrix[2],
matrix[6],
matrix[10],
matrix[14],
matrix[3],
matrix[7],
matrix[11],
matrix[15]
);
}
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[3];
result[4] = matrix[4];
result[5] = matrix[5];
result[6] = matrix[6];
result[7] = matrix[7];
result[8] = matrix[8];
result[9] = matrix[9];
result[10] = matrix[10];
result[11] = matrix[11];
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
return result;
}
static setTranslation(matrix, translation, result) {
if (!defined(result)) result = new Matrix4();
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[3];
result[4] = matrix[4];
result[5] = matrix[5];
result[6] = matrix[6];
result[7] = matrix[7];
result[8] = matrix[8];
result[9] = matrix[9];
result[10] = matrix[10];
result[11] = matrix[11];
result[12] = translation.x;
result[13] = translation.y;
result[14] = translation.z;
result[15] = matrix[15];
return result;
}
static getColumn(matrix, index, result) {
if (!defined(result)) result = new Vector4();
const startIndex = index * 4;
const x = matrix[startIndex];
const y = matrix[startIndex + 1];
const z = matrix[startIndex + 2];
const w = matrix[startIndex + 3];
result.x = x;
result.y = y;
result.z = z;
result.w = w;
return result;
}
}
class Matrix3 {
constructor(
column0Row0,
column1Row0,
column2Row0,
column0Row1,
column1Row1,
column2Row1,
column0Row2,
column1Row2,
column2Row2
) {
this[0] = defaultValue(column0Row0, 0.0);
this[1] = defaultValue(column0Row1, 0.0);
this[2] = defaultValue(column0Row2, 0.0);
this[3] = defaultValue(column1Row0, 0.0);
this[4] = defaultValue(column1Row1, 0.0);
this[5] = defaultValue(column1Row2, 0.0);
this[6] = defaultValue(column2Row0, 0.0);
this[7] = defaultValue(column2Row1, 0.0);
this[8] = defaultValue(column2Row2, 0.0);
}
clone() {
return new Matrix3(
this[0],
this[3],
this[6],
this[1],
this[4],
this[7],
this[2],
this[5],
this[8]
);
}
static setColumn(matrix, index, cartesian, result) {
if (!defined(result)) result = new Matrix3();
result = matrix.clone();
const startIndex = index * 3;
result[startIndex] = cartesian.x;
result[startIndex + 1] = cartesian.y;
result[startIndex + 2] = cartesian.z;
return result;
}
static multiplyByVector(matrix, cartesian, result) {
if (!defined(result)) result = new Vector3();
const vX = cartesian.x;
const vY = cartesian.y;
const vZ = cartesian.z;
const x = matrix[0] * vX + matrix[3] * vY + matrix[6] * vZ;
const y = matrix[1] * vX + matrix[4] * vY + matrix[7] * vZ;
const z = matrix[2] * vX + matrix[5] * vY + matrix[8] * vZ;
result.x = x;
result.y = y;
result.z = z;
return result;
}
static multiplyByScale(matrix, scale, result) {
if (!defined(result)) result = new Matrix3();
result[0] = matrix[0] * scale.x;
result[1] = matrix[1] * scale.x;
result[2] = matrix[2] * scale.x;
result[3] = matrix[3] * scale.y;
result[4] = matrix[4] * scale.y;
result[5] = matrix[5] * scale.y;
result[6] = matrix[6] * scale.z;
result[7] = matrix[7] * scale.z;
result[8] = matrix[8] * scale.z;
return result;
}
}
Matrix3.ZERO = Object.freeze(
new Matrix3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
);
class Rectangle {
constructor(west, south, east, north) {
this.west = west || 0;
this.south = south || 0;
this.east = east || 0;
this.north = north || 0;
}
static clone(source) {
return new Rectangle(
source.west,
source.south,
source.east,
source.north
);
}
}
class BoundingSphere {
constructor(center, radius) {
this.center = center || Vector3.ZERO;
this.radius = radius || 0;
}
static center(rectangle, result) {
if (!defined(result)) result = new Cartographic();
let east = rectangle.east;
const west = rectangle.west;
if (east < west) {
east += Math.TWO_PI;
}
const longitude = negativePiToPi((west + east) * 0.5);
const latitude = (rectangle.south + rectangle.north) * 0.5;
result.longitude = longitude;
result.latitude = latitude;
result.height = 0.0;
return result;
}
static fromPoints(positions, result) {
if (!defined(result)) result = new BoundingSphere();
if (!defined(positions) || positions.length === 0) {
result.center.copy(Vector3.ZERO);
result.radius = 0.0;
return result;
}
const currentPos = new Vector3().copy(positions[0]);
const xMin = currentPos.clone();
const yMin = currentPos.clone();
const zMin = currentPos.clone();
const xMax = currentPos.clone();
const yMax = currentPos.clone();
const zMax = currentPos.clone();
const numPositions = positions.length;
let i;
for (i = 1; i < numPositions; i++) {
currentPos.copy(positions[i])
const x = currentPos.x;
const y = currentPos.y;
const z = currentPos.z;
// Store points containing the the smallest and largest components
if (x < xMin.x) {
xMin.copy(currentPos);
}
if (x > xMax.x) {
xMin.copy(currentPos);
}
if (y < yMin.y) {
yMin.copy(currentPos);
}
if (y > yMax.y) {
yMax.copy(currentPos);
}
if (z < zMin.z) {
zMin.copy(currentPos);
}
if (z > zMax.z) {
zMax.copy(currentPos);
}
}
// Compute x-, y-, and z-spans (Squared distances b/n each component's min. and max.).
const xSpan = Vector3.subtract(xMax, xMin).lengthSquare();
const ySpan = Vector3.subtract(yMax, yMin).lengthSquare();
const zSpan = Vector3.subtract(zMax, zMin).lengthSquare();
// Set the diameter endpoints to the largest span.
let diameter1 = xMin;
let diameter2 = xMax;
let maxSpan = xSpan;
if (ySpan > maxSpan) {
maxSpan = ySpan;
diameter1 = yMin;
diameter2 = yMax;
}
if (zSpan > maxSpan) {
maxSpan = zSpan;
diameter1 = zMin;
diameter2 = zMax;
}
// Calculate the center of the initial sphere found by Ritter's algorithm
const ritterCenter = new Vector3();
ritterCenter.x = (diameter1.x + diameter2.x) * 0.5;
ritterCenter.y = (diameter1.y + diameter2.y) * 0.5;
ritterCenter.z = (diameter1.z + diameter2.z) * 0.5;
// Calculate the radius of the initial sphere found by Ritter's algorithm
let radiusSquared = Vector3.subtract(diameter2, ritterCenter).lengthSquare();
let ritterRadius = Math.sqrt(radiusSquared);
// Find the center of the sphere found using the Naive method.
const minBoxPt = new Vector3();
minBoxPt.x = xMin.x;
minBoxPt.y = yMin.y;
minBoxPt.z = zMin.z;
const maxBoxPt = new Vector3();
maxBoxPt.x = xMax.x;
maxBoxPt.y = yMax.y;
maxBoxPt.z = zMax.z;
const naiveCenter = Vector3.midpoint(minBoxPt, maxBoxPt);
// Begin 2nd pass to find naive radius and modify the ritter sphere.
let naiveRadius = 0;
for (i = 0; i < numPositions; i++) {
currentPos.copy(positions[i]);
const r = Vector3.subtract(currentPos, naiveCenter).length();
if (r > naiveRadius) {
naiveRadius = r;
}
const oldCenterToPointSquared = Vector3.subtract(currentPos, ritterCenter).lengthSquare();
if (oldCenterToPointSquared > radiusSquared) {
const oldCenterToPoint = Math.sqrt(oldCenterToPointSquared);
// Calculate new radius to include the point that lies outside
ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5;
radiusSquared = ritterRadius * ritterRadius;
// Calculate center of new Ritter sphere
const oldToNew = oldCenterToPoint - ritterRadius;
ritterCenter.x =
(ritterRadius * ritterCenter.x + oldToNew * currentPos.x) /
oldCenterToPoint;
ritterCenter.y =
(ritterRadius * ritterCenter.y + oldToNew * currentPos.y) /
oldCenterToPoint;
ritterCenter.z =
(ritterRadius * ritterCenter.z + oldToNew * currentPos.z) /
oldCenterToPoint;
}
}
if (ritterRadius < naiveRadius) {
result.center.copy(ritterCenter);
result.radius = ritterRadius;
} else {
result.center.copy(naiveCenter);
result.radius = naiveRadius;
}
return result;
}
static fromVertices(positions, center, stride, result) {
if (!defined(result)) {
result = new BoundingSphere();
}
if (!defined(positions) || positions.length === 0) {
result.center.copy(Vector3.ZERO);
result.radius = 0.0;
return result;
}
center =defaultValue(center, Vector3.ZERO);
stride = defaultValue(stride, 3);
const currentPos = new Vector3();
currentPos.x = positions[0] + center.x;
currentPos.y = positions[1] + center.y;
currentPos.z = positions[2] + center.z;
const xMin = currentPos.clone();
const yMin = currentPos.clone();
const zMin = currentPos.clone();
const xMax = currentPos.clone();
const yMax = currentPos.clone();
const zMax = currentPos.clone();
const numElements = positions.length;
let i;
for (i = 0; i < numElements; i += stride) {
const x = positions[i] + center.x;
const y = positions[i + 1] + center.y;
const z = positions[i + 2] + center.z;
currentPos.x = x;
currentPos.y = y;
currentPos.z = z;
// Store points containing the the smallest and largest components
if (x < xMin.x) {
xMin.copy(currentPos);
}
if (x > xMax.x) {
xMin.copy(currentPos);
}
if (y < yMin.y) {
yMin.copy(currentPos);
}
if (y > yMax.y) {
yMax.copy(currentPos);
}
if (z < zMin.z) {
zMin.copy(currentPos);
}
if (z > zMax.z) {
zMax.copy(currentPos);
}
}
// Compute x-, y-, and z-spans (Squared distances b/n each component's min. and max.).
const xSpan = Vector3.subtract(xMax, xMin).lengthSquare();
const ySpan = Vector3.subtract(yMax, yMin).lengthSquare();
const zSpan = Vector3.subtract(zMax, zMin).lengthSquare();
// Set the diameter endpoints to the largest span.
let diameter1 = xMin;
let diameter2 = xMax;
let maxSpan = xSpan;
if (ySpan > maxSpan) {
maxSpan = ySpan;
diameter1 = yMin;
diameter2 = yMax;
}
if (zSpan > maxSpan) {
maxSpan = zSpan;
diameter1 = zMin;
diameter2 = zMax;
}
// Calculate the center of the initial sphere found by Ritter's algorithm
const ritterCenter = new Vector3();
ritterCenter.x = (diameter1.x + diameter2.x) * 0.5;
ritterCenter.y = (diameter1.y + diameter2.y) * 0.5;
ritterCenter.z = (diameter1.z + diameter2.z) * 0.5;
// Calculate the radius of the initial sphere found by Ritter's algorithm
let radiusSquared = Vector3.subtract(diameter2, ritterCenter).lengthSquare();
let ritterRadius = Math.sqrt(radiusSquared);
// Find the center of the sphere found using the Naive method.
const minBoxPt = new Vector3();
minBoxPt.x = xMin.x;
minBoxPt.y = yMin.y;
minBoxPt.z = zMin.z;
const maxBoxPt = new Vector3();
maxBoxPt.x = xMax.x;
maxBoxPt.y = yMax.y;
maxBoxPt.z = zMax.z;
const naiveCenter = Vector3.midpoint(minBoxPt, maxBoxPt);
// Begin 2nd pass to find naive radius and modify the ritter sphere.
let naiveRadius = 0;
for (i = 0; i < numElements; i += stride) {
currentPos.x = positions[i] + center.x;
currentPos.y = positions[i + 1] + center.y;
currentPos.z = positions[i + 2] + center.z;
// Find the furthest point from the naive center to calculate the naive radius.
const r = Vector3.subtract(currentPos, naiveCenter).length();
if (r > naiveRadius) {
naiveRadius = r;
}
// Make adjustments to the Ritter Sphere to include all points.
const oldCenterToPointSquared = Vector3.subtract(currentPos, ritterCenter).lengthSquare();
if (oldCenterToPointSquared > radiusSquared) {
const oldCenterToPoint = Math.sqrt(oldCenterToPointSquared);
// Calculate new radius to include the point that lies outside
ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5;
radiusSquared = ritterRadius * ritterRadius;
// Calculate center of new Ritter sphere
const oldToNew = oldCenterToPoint - ritterRadius;
ritterCenter.x =
(ritterRadius * ritterCenter.x + oldToNew * currentPos.x) /
oldCenterToPoint;
ritterCenter.y =
(ritterRadius * ritterCenter.y + oldToNew * currentPos.y) /
oldCenterToPoint;
ritterCenter.z =
(ritterRadius * ritterCenter.z + oldToNew * currentPos.z) /
oldCenterToPoint;
}
}
if (ritterRadius < naiveRadius) {
result.center = ritterCenter.clone();
result.radius = ritterRadius;
} else {
result.center = naiveCenter.clone();
result.radius = naiveRadius;
}
return result;
}
}
class Plane {
constructor(normal, distance) {
this.normal = normal.clone();
this.distance = distance;
}
static fromPointNormal(point, normal, result) {
const distance = -Vector3.dot(normal, point);
if (!defined(result)) result = new Plane(normal, distance);
result.normal = normal.clone();
result.distance = distance;
return result;
}
static getPointDistance(plane, point) {
return Vector3.dot(plane.normal, point) + plane.distance;
}
}
class IntersectionTests {
constructor(){}
static rayPlane(ray, plane, result) {
if (!defined(result)) result = new Vector3();
const origin = ray.origin;
const direction = ray.direction;
const normal = plane.normal;
const denominator = Vector3.dot(normal, direction);
if (Math.abs(denominator) < EPSILON15) {
// Ray is parallel to plane. The ray may be in the polygon's plane.
return undefined;
}
const t = (-plane.distance - Vector3.dot(normal, origin)) / denominator;
if (t < 0) {
return undefined;
}
Vector3.multiplyByScalar(direction, t, result);
return result.add(origin);
}
}
class Ray {
constructor(origin, direction) {
this.origin = origin || new Vector3();
this.direction = direction || new Vector3();
}
}
class EllipsoidTangentPlane {
constructor(origin, ellipsoid) {
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
origin = ellipsoid.scaleToGeodeticSurface(origin);
const eastNorthUp = Transforms.eastNorthUpToFixedFrame(origin, ellipsoid);
this.ellipsoid = ellipsoid;
this.origin = origin;
this.xAxis = Vector3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 0));
this.yAxis = Vector3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 1));
const normal = Vector3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 2));
this.plane = Plane.fromPointNormal(origin, normal);
}
projectPointToNearestOnPlane(cartesian, result) {
if (!defined(result)) result = new Vector2();
const ray = new Ray();
ray.origin.copy(cartesian);
ray.direction.copy(this.plane.normal);
let intersectionPoint = IntersectionTests.rayPlane(ray, this.plane);
if (!defined(intersectionPoint)) {
ray.direction.negate();
intersectionPoint = IntersectionTests.rayPlane(ray, this.plane);
}
const v = Vector3.subtract(intersectionPoint, this.origin, intersectionPoint);
const x = Vector3.dot(this.xAxis, v);
const y = Vector3.dot(this.yAxis, v);
result.x = x;
result.y = y;
return result;
}
}
class OrientedBoundingBox {
constructor (center, halfAxes) {
this.center = defaultValue(center, Vector3.ZERO).clone();
this.halfAxes = defaultValue(halfAxes, Matrix3.ZERO).clone();
}
static fromRectangle(rectangle, minimumHeight, maximumHeight, ellipsoid, result) {
if (!defined(result)) result = new OrientedBoundingBox();
minimumHeight = defaultValue(minimumHeight, 0.0);
maximumHeight = defaultValue(maximumHeight, 0.0);
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
let minX, maxX, minY, maxY, minZ, maxZ, plane;
if (rectangle.width <= Math.PI) {
// The bounding box will be aligned with the tangent plane at the center of the rectangle.
const tangentPointCartographic = BoundingSphere.center(rectangle);
const tangentPoint = ellipsoid.cartographicToCartesian(tangentPointCartographic);
const tangentPlane = new EllipsoidTangentPlane(tangentPoint, ellipsoid);
plane = tangentPlane.plane;
// If the rectangle spans the equator, CW is instead aligned with the equator (because it sticks out the farthest at the equator).
const lonCenter = tangentPointCartographic.longitude;
const latCenter =
rectangle.south < 0.0 && rectangle.north > 0.0
? 0.0
: tangentPointCartographic.latitude;
// Compute XY extents using the rectangle at maximum height
const perimeterCartographicNC = Cartographic.fromRadians(
lonCenter,
rectangle.north,
maximumHeight,
);
const perimeterCartographicNW = Cartographic.fromRadians(
rectangle.west,
rectangle.north,
maximumHeight,
);
const perimeterCartographicCW = Cartographic.fromRadians(
rectangle.west,
latCenter,
maximumHeight,
);
const perimeterCartographicSW = Cartographic.fromRadians(
rectangle.west,
rectangle.south,
maximumHeight,
);
const perimeterCartographicSC = Cartographic.fromRadians(
lonCenter,
rectangle.south,
maximumHeight,
);
const perimeterCartesianNC = ellipsoid.cartographicToCartesian(
perimeterCartographicNC
);
let perimeterCartesianNW = ellipsoid.cartographicToCartesian(
perimeterCartographicNW
);
const perimeterCartesianCW = ellipsoid.cartographicToCartesian(
perimeterCartographicCW
);
let perimeterCartesianSW = ellipsoid.cartographicToCartesian(
perimeterCartographicSW
);
const perimeterCartesianSC = ellipsoid.cartographicToCartesian(
perimeterCartographicSC
);
const perimeterProjectedNC = tangentPlane.projectPointToNearestOnPlane(
perimeterCartesianNC
);
const perimeterProjectedNW = tangentPlane.projectPointToNearestOnPlane(
perimeterCartesianNW
);
const perimeterProjectedCW = tangentPlane.projectPointToNearestOnPlane(
perimeterCartesianCW
);
const perimeterProjectedSW = tangentPlane.projectPointToNearestOnPlane(
perimeterCartesianSW
);
const perimeterProjectedSC = tangentPlane.projectPointToNearestOnPlane(
perimeterCartesianSC
);
minX = Math.min(
perimeterProjectedNW.x,
perimeterProjectedCW.x,
perimeterProjectedSW.x
);
maxX = -minX; // symmetrical
maxY = Math.max(perimeterProjectedNW.y, perimeterProjectedNC.y);
minY = Math.min(perimeterProjectedSW.y, perimeterProjectedSC.y);
// Compute minimum Z using the rectangle at minimum height, since it will be deeper than the maximum height
perimeterCartographicNW.height = perimeterCartographicSW.height = minimumHeight;
perimeterCartesianNW = ellipsoid.cartographicToCartesian(
perimeterCartographicNW
);
perimeterCartesianSW = ellipsoid.cartographicToCartesian(
perimeterCartographicSW
);
minZ = Math.min(
Plane.getPointDistance(plane, perimeterCartesianNW),
Plane.getPointDistance(plane, perimeterCartesianSW)
);
maxZ = maximumHeight; // Since the tangent plane touches the surface at height = 0, this is okay
return OrientedBoundingBox.fromPlaneExtents(
tangentPlane.origin,
tangentPlane.xAxis,
tangentPlane.yAxis,
tangentPlane.zAxis,
minX,
maxX,
minY,
maxY,
minZ,
maxZ,
result
);
}
}
static fromPlaneExtents(
planeOrigin,
planeXAxis,
planeYAxis,
planeZAxis,
minimumX,
maximumX,
minimumY,
maximumY,
minimumZ,
maximumZ,
result
) {
if (
!defined(minimumX) ||
!defined(maximumX) ||
!defined(minimumY) ||
!defined(maximumY) ||
!defined(minimumZ) ||
!defined(maximumZ)
) {
throw new Error(
"all extents (minimum/maximum X/Y/Z) are required."
);
}
if (!defined(result)) result = new OrientedBoundingBox();
const halfAxes = result.halfAxes;
Matrix3.setColumn(halfAxes, 0, planeXAxis, halfAxes);
Matrix3.setColumn(halfAxes, 1, planeYAxis, halfAxes);
Matrix3.setColumn(halfAxes, 2, planeZAxis, halfAxes);
let centerOffset = scratchOffset;
centerOffset.x = (minimumX + maximumX) / 2.0;
centerOffset.y = (minimumY + maximumY) / 2.0;
centerOffset.z = (minimumZ + maximumZ) / 2.0;
const scale = scratchScale117;
scale.x = (maximumX - minimumX) / 2.0;
scale.y = (maximumY - minimumY) / 2.0;
scale.z = (maximumZ - minimumZ) / 2.0;
const center = result.center;
centerOffset = Matrix3.multiplyByVector(halfAxes, centerOffset, centerOffset);
Vector3.add(planeOrigin, centerOffset, center);
Matrix3.multiplyByScale(halfAxes, scale, halfAxes);
return result;
}
}
class Cartographic {
constructor(longitude, latitude, height) {
this.longitude = longitude || 0;
this.latitude = latitude || 0;
this.height = height || 0;
}
static fromRadians(longitude, latitude, height, result) {
height = defaultValue(height, 0.0);
if (!defined(result)) {
return new Cartographic(longitude, latitude, height);
}
result.longitude = longitude;
result.latitude = latitude;
result.height = height;
return result;
}
}
class Ellipsoid {
constructor(x, y, z) {
x = x || 0;
y = y || 0;
z = z || 0;
this.x = x;
this.y = y;
this.z = z;
this.radii = new Vector3(x, y, z);
this.radiiSquared = new Vector3(x * x, y * y, z * z);
this.radiiToTheFourth = new Vector3(
x * x * x * x,
y * y * y * y,
z * z * z * z
);
this.oneOverRadii = new Vector3(
x === 0.0 ? 0.0 : 1.0 / x,
y === 0.0 ? 0.0 : 1.0 / y,
z === 0.0 ? 0.0 : 1.0 / z
);
this.oneOverRadiiSquared = new Vector3(
x === 0.0 ? 0.0 : 1.0 / (x * x),
y === 0.0 ? 0.0 : 1.0 / (y * y),
z === 0.0 ? 0.0 : 1.0 / (z * z)
);
this.minimumRadius = Math.min(x, y, z);
this.maximumRadius = Math.max(x, y, z);
this.centerToleranceSquared = 0.1;
this.squaredFirstEccentricity = 1 - (z * z) / (x * x);
if (this.radiiSquared.z !== 0) {
this.squaredXOverSquaredZ = this.radiiSquared.x / this.radiiSquared.z;
}
}
static clone(source) {
return new Ellipsoid(source.x, source.y, source.z);
}
transformPositionToScaledSpace(position, result) {
if (!defined(result)) {
result = new Vector3();
}
return Vector3.multiplyComponents(position, this.oneOverRadii, result);
}
geodeticSurfaceNormal(cartesian, result) {
if (Vector3.equalsEpsilon(cartesian, Vector3.ZERO, EPSILON14)) {
return undefined;
}
if (!defined(result)) result = new Vector3();
let temp = this.oneOverRadiiSquared.clone();
result = Vector3.multiplyComponents(cartesian, temp, result);
return result.normalize();
}
cartographicToCartesian(cartographic, result) {
if (!defined(result)) result = new Vector3();
const cartographicToCartesianNormal = new Vector3();
const cartographicToCartesianK = new Vector3();
this.geodeticSurfaceNormalCartographic(cartographic, cartographicToCartesianNormal);
Vector3.multiplyComponents(this.radiiSquared, cartographicToCartesianNormal, cartographicToCartesianK);
const gamma = Math.sqrt(Vector3.dot(cartographicToCartesianNormal, cartographicToCartesianK));
Vector3.divideByScalar(cartographicToCartesianK, gamma, cartographicToCartesianK);
Vector3.multiplyByScalar(cartographicToCartesianNormal, cartographic.height, cartographicToCartesianNormal);
return Vector3.add(cartographicToCartesianK, cartographicToCartesianNormal, result);
}
geodeticSurfaceNormalCartographic(cartographic, result) {
if (!defined(result)) result = new Vector3();
const longitude = cartographic.longitude;
const latitude = cartographic.latitude;
const cosLatitude = Math.cos(latitude);
const x = cosLatitude * Math.cos(longitude);
const y = cosLatitude * Math.sin(longitude);
const z = Math.sin(latitude);
result.set(x, y, z);
return result.normalize();
}
scaleToGeodeticSurface(cartesian, result) {
return scaleToGeodeticSurface(
cartesian,
this.oneOverRadii,
this.oneOverRadiiSquared,
this.centerToleranceSquared,
result
);
}
}
Ellipsoid.WGS84 = Object.freeze(new Ellipsoid(6378137.0, 6378137.0, 6356752.3142451793));
class EllipsoidalOccluder {
constructor(ellipsoid) {
this.ellipsoid = ellipsoid;
this.cameraPosition = new Vector3();
this.cameraPositionInScaledSpace = new Vector3();
this.distanceToLimbInScaledSquared = 0.0;
}
computeHorizonCullingPointPossiblyUnderEllipsoid(directionToPoint, positions, minimumHeight, result) {
const possiblyShrunkEllipsoid = EllipsoidalOccluder.getPossiblyShrunkEllipsoid(
this.ellipsoid,
minimumHeight
);
return computeHorizonCullingPointFromPositions(
possiblyShrunkEllipsoid,
directionToPoint,
positions,
result
);
}
static getPossiblyShrunkEllipsoid(ellipsoid, minimumHeight) {
if (defined(minimumHeight) &&
minimumHeight < 0.0 &&
ellipsoid.minimumRadius > - minimumHeight
) {
const ellipsoidShrunkRadii = new Vector3(
ellipsoid.radii.x + minimumHeight,
ellipsoid.radii.y + minimumHeight,
ellipsoid.radii.z + minimumHeight,
);
ellipsoid = new Ellipsoid(
ellipsoidShrunkRadii.x,
ellipsoidShrunkRadii.y,
ellipsoidShrunkRadii.z
);
}
return ellipsoid;
}
static computeHorizonCullingPointFromPositions(ellipsoid, directionToPoint, positions, result) {
if (!defined(result)) result = new Vector3();
const scaledSpaceDirectionToPoint = EllipsoidalOccluder.computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint);
let resultMagnitude = 0.0;
for (let i = 0, len = positions.length; i < len; ++i) {
const position = positions[i];
const candidateMagnitude = EllipsoidalOccluder.computeMagnitude(
ellipsoid,
position,
scaledSpaceDirectionToPoint
);
if (candidateMagnitude < 0.0) {
// all points should face the same direction, but this one doesn't, so return undefined
return undefined;
}
resultMagnitude = Math.max(resultMagnitude, candidateMagnitude);
}
return EllipsoidalOccluder.magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result);
}
static computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint){
if (Vector3.equals(directionToPoint, Vector3.ZERO)) {
return directionToPoint;
}
const directionToPointScratch = ellipsoid.transformPositionToScaledSpace(
directionToPoint
);
return directionToPointScratch.normalize();
}
static computeMagnitude(ellipsoid, position, scaledSpaceDirectionToPoint) {
const scaledSpacePosition = ellipsoid.transformPositionToScaledSpace(
position
);
let magnitudeSquared = scaledSpacePosition.lengthSquare();
let magnitude = scaledSpacePosition.length();
const direction = Vector3.divideByScalar(scaledSpacePosition, magnitude);
magnitudeSquared = Math.max(1.0, magnitudeSquared);
magnitude = Math.max(1.0, magnitude);
const cosAlpha = Vector3.dot(direction, scaledSpaceDirectionToPoint);
const sinAlpha = Vector3.cross(direction, scaledSpaceDirectionToPoint, direction).length()
const cosBeta = 1.0 / magnitude;
const sinBeta = Math.sqrt(magnitudeSquared - 1.0) * cosBeta;
return 1.0 / (cosAlpha * cosBeta - sinAlpha * sinBeta);
}
static magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result) {
if (resultMagnitude <= 0.0 ||
resultMagnitude === 1.0 / 0.0 ||
resultMagnitude !== resultMagnitude) {
return undefined;
}
return Vector3.multiplyByScalar(scaledSpaceDirectionToPoint, resultMagnitude, result);
}
computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid(
directionToPoint,
vertices,
stride,
center,
minimumHeight,
result
) {
const possiblyShrunkEllipsoid = EllipsoidalOccluder.getPossiblyShrunkEllipsoid(
this.ellipsoid,
minimumHeight
);
return EllipsoidalOccluder.computeHorizonCullingPointFromVertices(
possiblyShrunkEllipsoid,
directionToPoint,
vertices,
stride,
center,
result
)
}
static computeHorizonCullingPointFromVertices(
ellipsoid,
directionToPoint,
vertices,
stride,
center,
result
) {
if (!defined(result)) result = new Vector3();
stride = defaultValue(stride, 3);
center = defaultValue(center, Vector3.ZERO.clone());
const scaledSpaceDirectionToPoint = EllipsoidalOccluder.computeScaledSpaceDirectionToPoint(
ellipsoid,
directionToPoint
);
let resultMagnitude = 0.0;
const positionScratch = new Vector3();
for (let i = 0, len = vertices.length; i < len; i += stride) {
positionScratch.x = vertices[i] + center.x;
positionScratch.y = vertices[i + 1] + center.y;
positionScratch.z = vertices[i + 2] + center.z;
const candidateMagnitude = EllipsoidalOccluder.computeMagnitude(
ellipsoid,
positionScratch,
scaledSpaceDirectionToPoint
);
if (candidateMagnitude < 0.0) {
// all points should face the same direction, but this one doesn't, so return undefined
return undefined;
}
resultMagnitude = Math.max(resultMagnitude, candidateMagnitude);
}
return EllipsoidalOccluder.magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result);
}
}
class AxisAlignedBoundingBox {
constructor(minimum, maximum, center) {
this.minimum = defaultValue(minimum, Vector3.ZERO).clone();
this.maximum = defaultValue(maximum, Vector3.ZERO).clone();
if (!defined(center)) {
center = new Vector3(
(this.minimum.x + this.maximum.x) * 0.5,
(this.minimum.y + this.maximum.y) * 0.5,
(this.minimum.z + this.maximum.z) * 0.5
);
} else {
center = new Vector3(center.x, center.y, center.z);
}
this.center = center;
}
}
class AttributeCompression {
constructor(){}
static compressTextureCoordinates(textureCoordinates) {
const x = (textureCoordinates.x * 4095.0) | 0;
const y = (textureCoordinates.y * 4095.0) | 0;
return 4096 * x + y;
}
static octPackFloat(encoded) {
return 256.0 * encoded.x + encoded.y;
}
static octDecode(x, y, result) {
return AttributeCompression.octDecodeInRange(x, y, 255, result);
}
static decompressTextureCoordinates(compressed, result) {
const temp = compressed / 4096.0;
const xZeroTo4095 = Math.floor(temp);
result.x = xZeroTo4095 / 4095.0;
result.y = (compressed - xZeroTo4095 * 4096) / 4095;
return result;
}
static octDecodeInRange(x, y, rangeMax, result) {
if (x < 0 || x > rangeMax || y < 0 || y > rangeMax) {
throw new Erro(
`x and y must be unsigned normalized integers between 0 and ${rangeMax}`
);
}
if (!defined(result)) result = new Vector3();
result.x = fromSNorm(x, rangeMax);
result.y = fromSNorm(y, rangeMax);
result.z = 1.0 - (Math.abs(result.x) + Math.abs(result.y));
if (result.z < 0.0) {
const oldVX = result.x;
result.x = (1.0 - Math.abs(result.y)) * signNotZero(oldVX);
result.y = (1.0 - Math.abs(oldVX)) * signNotZero(result.y);
}
return result.normalize();
}
}
const cartesian2Scratch = new Vector2();
class TerrainEncoding {
constructor(
center,
axisAlignedBoundingBox,
minimumHeight,
maximumHeight,
fromENU,
hasVertexNormals,
hasWebMercatorT,
hasGeodeticSurfaceNormals,
exaggeration,
exaggerationRelativeHeight,
) {
let quantization = TerrainQuantization.NONE;
let toENU;
let matrix;
const cartesian3DimScratch = new Vector3();
if (
defined(axisAlignedBoundingBox) &&
defined(minimumHeight) &&
defined(maximumHeight) &&
defined(fromENU)
) {
const minimum = axisAlignedBoundingBox.minimum;
const maximum = axisAlignedBoundingBox.maximum;
const dimensions = Vector3.subtract(
maximum,
minimum,
cartesian3DimScratch
);
const hDim = maximumHeight - minimumHeight;
const maxDim = Math.max(Vector3.maximumComponent(dimensions), hDim);
if (maxDim < SHIFT_LEFT_12 - 1.0) {
quantization = TerrainQuantization.BITS12;
} else {
quantization = TerrainQuantization.NONE;
}
toENU = Matrix4.inverseTransformation(fromENU, new Matrix4());
const matrix4Scratch13T = new Matrix4();
const cartesian3Scratch13T = new Vector3();
const matrix4Scratch2 = new Matrix4();
const translation = Vector3.negate(minimum, cartesian3Scratch13T);
Matrix4.multiply(
Matrix4.fromTranslation(translation, matrix4Scratch13T),
toENU,
toENU
);
const scale = cartesian3Scratch13T;
scale.x = 1.0 / dimensions.x;
scale.y = 1.0 / dimensions.y;
scale.z = 1.0 / dimensions.z;
Matrix4.multiply(Matrix4.fromScale(scale, matrix4Scratch13T), toENU, toENU);
matrix = Matrix4.clone(fromENU);
Matrix4.setTranslation(matrix, Vector3.ZERO, matrix);
fromENU = Matrix4.clone(fromENU, new Matrix4());
const translationMatrix = Matrix4.fromTranslation(minimum, matrix4Scratch13T);
const scaleMatrix = Matrix4.fromScale(dimensions, matrix4Scratch2);
const st = Matrix4.multiply(translationMatrix, scaleMatrix, matrix4Scratch13T);
Matrix4.multiply(fromENU, st, fromENU);
Matrix4.multiply(matrix, st, matrix);
}
this.quantization = quantization;
this.minimumHeight = minimumHeight;
this.maximumHeight = maximumHeight;
this.center = defined(center) ? Vector3.clone(center) : new Vector3();
this.toScaledENU = toENU;
this.fromScaledENU = fromENU;
this.matrix = matrix;
this.hasVertexNormals = hasVertexNormals;
this.hasWebMercatorT = defaultValue(hasWebMercatorT, false);
this.hasGeodeticSurfaceNormals = defaultValue(
hasGeodeticSurfaceNormals,
false
);
this.exaggeration = defaultValue(exaggeration, 1.0);
this.exaggerationRelativeHeight = defaultValue(
exaggerationRelativeHeight,
0.0
);
this.stride = 0;
this._offsetGeodeticSurfaceNormal = 0;
this._offsetVertexNormal = 0;
this._calculateStrideAndOffsets();
}
_calculateStrideAndOffsets() {
let vertexStride = 0;
switch (this.quantization) {
case TerrainQuantization.BITS12:
vertexStride += 3;
break;
default:
vertexStride += 6;
}
if (this.hasWebMercatorT) {
vertexStride += 1;
}
if (this.hasVertexNormals) {
this._offsetVertexNormal = vertexStride;
vertexStride += 1;
}
if (this.hasGeodeticSurfaceNormals) {
this._offsetGeodeticSurfaceNormal = vertexStride;
vertexStride += 3;
}
this.stride = vertexStride;
}
encode(vertexBuffer, bufferIndex, position, uv, height, normalToPack, webMercatorT, geodeticSurfaceNormal) {
const cartesian3Scratch13T = new Vector3();
const cartesian2Scratch = new Vector2();
const u = uv.x;
const v = uv.y;
if (this.quantization === TerrainQuantization.BITS12) {
position = Matrix4.multiplyByPoint(
this.toScaledENU,
position,
cartesian3Scratch13T
);
position.x = clamp(position.x, 0.0, 1.0);
position.y = clamp(position.y, 0.0, 1.0);
position.z = clamp(position.z, 0.0, 1.0);
const hDim = this.maximumHeight - this.minimumHeight;
const h = clamp((height - this.minimumHeight) / hDim, 0.0, 1.0);
cartesian2Scratch.set(position.x, position.y);
const compressed0 = AttributeCompression.compressTextureCoordinates(
cartesian2Scratch
);
cartesian2Scratch.set(position.z, h);
const compressed1 = AttributeCompression.compressTextureCoordinates(
cartesian2Scratch
);
cartesian2Scratch.set(u, v);
const compressed2 = AttributeCompression.compressTextureCoordinates(
cartesian2Scratch
);
vertexBuffer[bufferIndex++] = compressed0;
vertexBuffer[bufferIndex++] = compressed1;
vertexBuffer[bufferIndex++] = compressed2;
if (this.hasWebMercatorT) {
cartesian2Scratch.set(webMercatorT, 0.0);
const compressed3 = AttributeCompression.compressTextureCoordinates(
cartesian2Scratch
);
vertexBuffer[bufferIndex++] = compressed3;
}
} else {
Vector3.subtract(position, this.center, cartesian3Scratch13T);
vertexBuffer[bufferIndex++] = cartesian3Scratch13T.x;
vertexBuffer[bufferIndex++] = cartesian3Scratch13T.y;
vertexBuffer[bufferIndex++] = cartesian3Scratch13T.z;
vertexBuffer[bufferIndex++] = height;
vertexBuffer[bufferIndex++] = u;
vertexBuffer[bufferIndex++] = v;
if (this.hasWebMercatorT) {
vertexBuffer[bufferIndex++] = webMercatorT;
}
}
if (this.hasVertexNormals) {
vertexBuffer[bufferIndex++] = AttributeCompression.octPackFloat(
normalToPack
);
}
if (this.hasGeodeticSurfaceNormals) {
vertexBuffer[bufferIndex++] = geodeticSurfaceNormal.x;
vertexBuffer[bufferIndex++] = geodeticSurfaceNormal.y;
vertexBuffer[bufferIndex++] = geodeticSurfaceNormal.z;
}
return bufferIndex;
}
static clone(encoding, result) {
if (!defined(encoding)) {
return undefined;
}
if (!defined(result)) {
result = new TerrainEncoding();
}
result.quantization = encoding.quantization;
result.minimumHeight = encoding.minimumHeight;
result.maximumHeight = encoding.maximumHeight;
result.center = Vector3.clone(encoding.center);
result.toScaledENU = Matrix4.clone(encoding.toScaledENU);
result.fromScaledENU = Matrix4.clone(encoding.fromScaledENU);
result.matrix = Matrix4.clone(encoding.matrix);
result.hasVertexNormals = encoding.hasVertexNormals;
result.hasWebMercatorT = encoding.hasWebMercatorT;
result.hasGeodeticSurfaceNormals = encoding.hasGeodeticSurfaceNormals;
result.exaggeration = encoding.exaggeration;
result.exaggerationRelativeHeight = encoding.exaggerationRelativeHeight;
result._calculateStrideAndOffsets();
return result;
}
decodeTextureCoordinates(buffer, index, result) {
if (!defined(result)) result = new Vector2();
index *= this.stride;
if (this.quantization === TerrainQuantization.BITS12) {
return AttributeCompression.decompressTextureCoordinates(buffer[index + 2], result);
}
result.set(buffer[index + 4], buffer[index + 5]);
return result;
}
decodeHeight(buffer, index) {
index *= this.stride;
if (this.quantization === TerrainQuantization.BITS12) {
const zh = AttributeCompression.decompressTextureCoordinates(
buffer[index + 1],
cartesian2Scratch
);
return (
zh.y * (this.maximumHeight - this.minimumHeight) + this.minimumHeight
);
}
return buffer[index + 3];
}
getOctEncodedNormal(buffer, index, result) {
if (!defined(result)) result = new Vector2();
index = index * this.stride + this._offsetVertexNormal;
const temp = buffer[index] / 256.0;
const x = Math.floor(temp);
const y = (temp - x) * 256.0;
result.set(x, y);
return result;
}
}
class IndexDatatype {
constructor() {}
static createTypedArray(numberOfVertices, indicesLengthOrArray) {
if (!defined(numberOfVertices)) {
throw new Error("numberOfVertices is required");
}
if (numberOfVertices >= 6 * 1024 * 1024) {
return new Uint32Array(indicesLengthOrArray);
}
return new Uint16Array(indicesLengthOrArray);
}
}
class Vertex {
constructor() {
this.vertexBuffer = undefined;
this.index = undefined;
this.first = undefined;
this.second = undefined;
this.ratio = undefined;
}
clone(result) {
if (!defined(result)) {
result = new Vertex();
}
result.uBuffer = this.uBuffer;
result.vBuffer = this.vBuffer;
result.heightBuffer = this.heightBuffer;
result.normalBuffer = this.normalBuffer;
result.index = this.index;
result.first = this.first;
result.second = this.second;
result.ratio = this.ratio;
return result;
}
initializeIndexed(uBuffer, vBuffer, heightBuffer, normalBuffer, index) {
this.uBuffer = uBuffer;
this.vBuffer = vBuffer;
this.heightBuffer = heightBuffer;
this.normalBuffer = normalBuffer;
this.index = index;
this.first = undefined;
this.second = undefined;
this.ratio = undefined;
}
initializeFromClipResult(clipResult, index, vertices) {
let nextIndex = index + 1;
if (clipResult[index] !== -1) {
vertices[clipResult[index]].clone(this);
} else {
this.vertexBuffer = undefined;
this.index = undefined;
this.first = vertices[clipResult[nextIndex]];
++nextIndex;
this.second = vertices[clipResult[nextIndex]];
++nextIndex;
this.ratio = clipResult[nextIndex];
++nextIndex;
}
return nextIndex;
}
getKey() {
if (this.isIndexed()) {
return this.index;
}
return JSON.stringify({
first: this.first.getKey(),
second: this.second.getKey(),
ratio: this.ratio,
});
}
isIndexed() {
return defined(this.index);
}
getH() {
if (this.isIndexed()) {
return this.heightBuffer[this.index];
}
return lerp(this.first.getH(), this.second.getH(), this.ratio);
}
getU() {
if (this.isIndexed()) {
return this.uBuffer[this.index];
}
return lerp(this.first.getU(), this.second.getU(), this.ratio);
}
getV() {
if (this.isIndexed()) {
return this.vBuffer[this.index];
}
return lerp(this.first.getV(), this.second.getV(), this.ratio);
}
getNormalX() {
if (this.isIndexed()) {
return this.normalBuffer[this.index * 2];
}
encodedScratch = lerpOctEncodedNormal(this, encodedScratch);
return encodedScratch.x;
}
getNormalY() {
if (this.isIndexed()) {
return this.normalBuffer[this.index * 2 + 1];
}
encodedScratch = lerpOctEncodedNormal(this, encodedScratch);
return encodedScratch.y;
}
}
const polygonVertices = [];
polygonVertices.push(new Vertex());
polygonVertices.push(new Vertex());
polygonVertices.push(new Vertex());
polygonVertices.push(new Vertex());
class Intersection {
constructor(){}
static clipTriangleAtAxisAlignedThreshold(threshold, keepAbove, u0, u1, u2, result) {
if (!defined(result)) result = [];
else result.length = 0;
let u0Behind, u1Behind, u2Behind;
if (keepAbove) {
u0Behind = u0 < threshold;
u1Behind = u1 < threshold;
u2Behind = u2 < threshold;
} else {
u0Behind = u0 > threshold;
u1Behind = u1 > threshold;
u2Behind = u2 > threshold;
}
const numBehind = u0Behind + u1Behind + u2Behind;
let u01Ratio, u02Ratio, u12Ratio, u10Ratio, u20Ratio, u21Ratio;
if (numBehind === 1) {
if (u0Behind) {
u01Ratio = (threshold - u0) / (u1 - u0);
u02Ratio = (threshold - u0) / (u2 - u0);
result.push(1);
result.push(2);
if (u02Ratio !== 1.0) {
result.push(-1);
result.push(0);
result.push(2);
result.push(u02Ratio);
}
if (u01Ratio !== 1.0) {
result.push(-1);
result.push(0);
result.push(1);
result.push(u01Ratio);
}
}
else if (u1Behind) {
u12Ratio = (threshold - u1) / (u2 - u1);
u10Ratio = (threshold - u1) / (u0 - u1);
result.push(2);
result.push(0);
if (u10Ratio !== 1.0) {
result.push(-1);
result.push(1);
result.push(0);
result.push(u10Ratio);
}
if (u12Ratio !== 1.0) {
result.push(-1);
result.push(1);
result.push(2);
result.push(u12Ratio);
}
}
else if (u2Behind) {
u20Ratio = (threshold - u2) / (u0 - u2);
u21Ratio = (threshold - u2) / (u1 - u2);
result.push(0);
result.push(1);
if (u21Ratio !== 1.0) {
result.push(-1);
result.push(2);
result.push(1);
result.push(u21Ratio);
}
if (u20Ratio !== 1.0) {
result.push(-1);
result.push(2);
result.push(0);
result.push(u20Ratio);
}
}
}
else if (numBehind === 2) {
if (!u0Behind && u0 !== threshold) {
u10Ratio = (threshold - u1) / (u0 - u1);
u20Ratio = (threshold - u2) / (u0 - u2);
result.push(0);
result.push(-1);
result.push(1);
result.push(0);
result.push(u10Ratio);
result.push(-1);
result.push(2);
result.push(0);
result.push(u20Ratio);
}
else if (!u1Behind && u1 !== threshold) {
u21Ratio = (threshold - u2) / (u1 - u2);
u01Ratio = (threshold - u0) / (u1 - u0);
result.push(1);
result.push(-1);
result.push(2);
result.push(1);
result.push(u21Ratio);
result.push(-1);
result.push(0);
result.push(1);
result.push(u01Ratio);
}
else if (!u2Behind && u2 !== threshold) {
u02Ratio = (threshold - u0) / (u2 - u0);
u12Ratio = (threshold - u1) / (u2 - u1);
result.push(2);
result.push(-1);
result.push(0);
result.push(2);
result.push(u02Ratio);
result.push(-1);
result.push(1);
result.push(2);
result.push(u12Ratio);
}
}
else if (numBehind !== 3) {
result.push(0);
result.push(1);
result.push(2);
}
return result;
}
}
const decodeTexCoordsScratch = new Vector2();
const octEncodedNormalScratch = new Vector3();
const uScratch = [];
const vScratch = [];
const heightScratch = [];
const indicesScratch = [];
const normalsScratch = [];
let cartographicScratch = new Cartographic();
let cartesian3Scratch = new Vector3();
let depth = -1;
const cartesianScratch1 = [new Vector3(), new Vector3()];
const cartesianScratch2 = [new Vector3(), new Vector3()];
let encodedScratch = new Vector2()
function upsampleQuantizedTerrainMesh(parameters) {
const isEastChild = parameters.isEastChild;
const isNorthChild = parameters.isNorthChild;
const name = parameters.name;
// UV坐标
// U坐标 东边的瓦片是 [32767 / 2, 32767],西边的是[0, 32767 / 2]
// V坐标 北边的瓦片是 [32767 / 2, 32767],南边的是[0, 32767 / 2]
const minU = isEastChild ? halfMaxShort : 0;
const maxU = isEastChild ? maxShort : halfMaxShort;
const minV = isNorthChild ? halfMaxShort : 0;
const maxV = isNorthChild ? maxShort : halfMaxShort;
const uBuffer = uScratch;
const vBuffer = vScratch;
const heightBuffer = heightScratch;
const normalBuffer = normalsScratch;
uBuffer.length = vBuffer.length = heightBuffer.length = normalBuffer.length = 0;
const indices = indicesScratch;
indices.length = 0;
const vertexMap = {};
// 父节点的顶点和索引(不算裙边)
const parentVertices = parameters.vertices;
let parentIndices = parameters.indices;
parentIndices = parentIndices.subarray(0, parameters.indexCountWithoutSkirts);
const encoding = TerrainEncoding.clone(parameters.encoding);
const hasVertexNormals = encoding.hasVertexNormals;
let vertexCount = 0;
const quantizedVerticeCount = parameters.vertexCountWithoutSkirts;
const parentMinimumHeight = parameters.minimumHeight;
const parentMaximumHeight = parameters.maximumHeight;
const parentUBuffer = new Array(quantizedVerticeCount);
const parentVBuffer = new Array(quantizedVerticeCount);
const parentHeightBuffer = new Array(quantizedVerticeCount);
const parentNormalBuffer = hasVertexNormals
? new Array(quantizedVerticeCount * 2)
: undefined;
const threshold = 20;
let height;
let i, n;
let u, v;
for (i = 0, n = 0; i < quantizedVerticeCount; ++i, n += 2) {
const texCoords = encoding.decodeTextureCoordinates(parentVertices, i, decodeTexCoordsScratch);
height = encoding.decodeHeight(parentVertices, i);
u = clamp((texCoords.x * maxShort) | 0, 0, maxShort);
v = clamp((texCoords.y * maxShort) | 0, 0, maxShort);
parentHeightBuffer[i] = clamp((((height - parentMinimumHeight) / (parentMaximumHeight - parentMinimumHeight)) * maxShort) | 0, 0, maxShort);
if (u < threshold) u = 0;
if (v < threshold) v = 0;
if (maxShort - u < threshold) u = maxShort;
if (maxShort - v < threshold) v = maxShort;
parentUBuffer[i] = u;
parentVBuffer[i] = v;
if (hasVertexNormals) {
const encodedNormal = encoding.getOctEncodedNormal(parentVertices, i, octEncodedNormalScratch);
parentNormalBuffer[n] = encodedNormal.x;
parentNormalBuffer[n + 1] = encodedNormal.y;
}
if (
((isEastChild && u >= halfMaxShort) || (!isEastChild && u <= halfMaxShort)) &&
((isNorthChild && v >= halfMaxShort) || (!isNorthChild && v <= halfMaxShort))
) {
vertexMap[i] = vertexCount;
uBuffer.push(u);
vBuffer.push(v);
heightBuffer.push(parentHeightBuffer[i]);
if (hasVertexNormals) {
normalBuffer.push(parentNormalBuffer[n]);
normalBuffer.push(parentNormalBuffer[n + 1]);
}
++vertexCount;
}
}
const triangleVertices = [];
triangleVertices.push(new Vertex());
triangleVertices.push(new Vertex());
triangleVertices.push(new Vertex());
const clippedTriangleVertices = [];
clippedTriangleVertices.push(new Vertex());
clippedTriangleVertices.push(new Vertex());
clippedTriangleVertices.push(new Vertex());
let clippedIndex;
let clipped2;
for (i = 0; i < parentIndices.length; i += 3) {
const i0 = parentIndices[i];
const i1 = parentIndices[i + 1];
const i2 = parentIndices[i + 2];
const u0 = parentUBuffer[i0];
const u1 = parentUBuffer[i1];
const u2 = parentUBuffer[i2];
triangleVertices[0].initializeIndexed(parentUBuffer, parentVBuffer, parentHeightBuffer, parentNormalBuffer, i0);
triangleVertices[1].initializeIndexed(parentUBuffer, parentVBuffer, parentHeightBuffer, parentNormalBuffer, i1);
triangleVertices[2].initializeIndexed(parentUBuffer, parentVBuffer, parentHeightBuffer, parentNormalBuffer, i2);
const clipped = Intersection.clipTriangleAtAxisAlignedThreshold(halfMaxShort, isEastChild, u0, u1, u2);
clippedIndex = 0;
if (clippedIndex >= clipped.length) continue;
clippedIndex = clippedTriangleVertices[0].initializeFromClipResult(clipped, clippedIndex, triangleVertices);
if (clippedIndex >= clipped.length) continue;
clippedIndex = clippedTriangleVertices[1].initializeFromClipResult(clipped, clippedIndex, triangleVertices);
if (clippedIndex >= clipped.length) continue;
clippedIndex = clippedTriangleVertices[2].initializeFromClipResult(clipped, clippedIndex, triangleVertices);
clipped2 = Intersection.clipTriangleAtAxisAlignedThreshold(halfMaxShort, isNorthChild, clippedTriangleVertices[0].getV(), clippedTriangleVertices[1].getV(), clippedTriangleVertices[2].getV());
addClippedPolygon(uBuffer, vBuffer, heightBuffer, normalBuffer, indices, vertexMap, clipped2, clippedTriangleVertices, hasVertexNormals);
if (clippedIndex < clipped.length) {
clippedTriangleVertices[2].clone(clippedTriangleVertices[1]);
clippedTriangleVertices[2].initializeFromClipResult(clipped, clippedIndex, triangleVertices);
clipped2 = Intersection.clipTriangleAtAxisAlignedThreshold(halfMaxShort, isNorthChild, clippedTriangleVertices[0].getV(), clippedTriangleVertices[1].getV(), clippedTriangleVertices[2].getV());
addClippedPolygon(uBuffer, vBuffer, heightBuffer, normalBuffer, indices, vertexMap, clipped2, clippedTriangleVertices, hasVertexNormals);
}
}
const uOffset = isEastChild ? -maxShort : 0;
const vOffset = isNorthChild ? -maxShort : 0;
const westIndices = [], southIndices = [], eastIndices = [], northIndices = [];
let minimumHeight = Number.MAX_VALUE, maximumHeight = -minimumHeight;
const cartesianVertices = [];
cartesianVertices.length = 0;
const ellipsoid = Ellipsoid.clone(parameters.ellipsoid);
const rectangle = Rectangle.clone(parameters.childRectangle);
const north = rectangle.north, south = rectangle.south, west = rectangle.west;
let east = rectangle.east;
if (east < west) east += Math.PI * 2;
for (i = 0; i < uBuffer.length; ++i) {
u = Math.round(uBuffer[i]);
if (u <= minU) {
westIndices.push(i);
u = 0;
} else if (u >= maxU) {
eastIndices.push(i);
u = maxShort;
} else {
u = u * 2 + uOffset;
}
uBuffer[i] = u;
v = Math.round(vBuffer[i]);
if (v <= minV) {
southIndices.push(i);
v = 0;
} else if (v >= maxV) {
northIndices.push(i);
v = maxShort;
} else {
v = v * 2 + vOffset;
}
vBuffer[i] = v;
height = lerp(parentMinimumHeight, parentMaximumHeight, heightBuffer[i] / maxShort);
if (height < minimumHeight) minimumHeight = height;
if (height > maximumHeight) maximumHeight = height;
heightBuffer[i] = height;
cartographicScratch.longitude = lerp(west, east, u / maxShort);
cartographicScratch.latitude = lerp(south, north, v / maxShort);
cartographicScratch.height = height;
ellipsoid.cartographicToCartesian(cartographicScratch, cartesian3Scratch);
cartesianVertices.push(cartesian3Scratch.x);
cartesianVertices.push(cartesian3Scratch.y);
cartesianVertices.push(cartesian3Scratch.z);
}
const boundingSphere = BoundingSphere.fromVertices(cartesianVertices, Vector3.ZERO, 3);
const orientedBoundingBox = OrientedBoundingBox.fromRectangle(rectangle, minimumHeight, maximumHeight, ellipsoid);
const occluder = new EllipsoidalOccluder(ellipsoid);
const horizonOcclusionPoint = occluder.computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid(boundingSphere.center, cartesianVertices, 3, boundingSphere.center, minimumHeight);
const heightRange = maximumHeight - minimumHeight;
const vertices = new Uint16Array(uBuffer.length + vBuffer.length + heightBuffer.length);
for (i = 0; i < uBuffer.length; ++i) {
vertices[i] = uBuffer[i];
}
let start = uBuffer.length;
for (i = 0; i < vBuffer.length; ++i) {
vertices[start + i] = vBuffer[i];
}
start += vBuffer.length;
for (i = 0; i < heightBuffer.length; ++i) {
vertices[start + i] = (maxShort * (heightBuffer[i] - minimumHeight)) / heightRange;
}
const indicesTypedArray = IndexDatatype.createTypedArray(uBuffer.length, indices);
let encodedNormals;
if (hasVertexNormals) {
const normalArray = new Uint8Array(normalBuffer);
encodedNormals = normalArray.buffer;
}
return {
vertices: vertices.buffer,
encodedNormals: encodedNormals,
indices: indicesTypedArray.buffer,
minimumHeight: minimumHeight,
maximumHeight: maximumHeight,
westIndices: westIndices,
southIndices: southIndices,
eastIndices: eastIndices,
northIndices: northIndices,
boundingSphere: boundingSphere,
orientedBoundingBox: orientedBoundingBox,
horizonOcclusionPoint: horizonOcclusionPoint,
name: name,
parameters: parameters
}
}
function addClippedPolygon(uBuffer, vBuffer,heightBuffer, normalBuffer, indices, vertexMap, clipped, triangleVertices, hasVertexNormals) {
if (clipped.length === 0) return;
let numVertices = 0;
let clippedIndex = 0;
while (clippedIndex < clipped.length) {
clippedIndex = polygonVertices[numVertices++].initializeFromClipResult(clipped, clippedIndex, triangleVertices);
}
for (let i = 0; i < numVertices; ++i) {
const polygonVertex = polygonVertices[i];
if (!polygonVertex.isIndexed()) {
const key = polygonVertex.getKey();
if (defined(vertexMap[key])) {
polygonVertex.newIndex = vertexMap[key];
} else {
const newIndex = uBuffer.length;
uBuffer.push(polygonVertex.getU());
vBuffer.push(polygonVertex.getV());
heightBuffer.push(polygonVertex.getH());
if (hasVertexNormals) {
normalBuffer.push(polygonVertex.getNormalX());
normalBuffer.push(polygonVertex.getNormalY());
}
polygonVertex.newIndex = newIndex;
vertexMap[key] = newIndex;
}
} else {
polygonVertex.newIndex = vertexMap[polygonVertex.index];
polygonVertex.uBuffer = uBuffer;
polygonVertex.vBuffer = vBuffer;
polygonVertex.heightBuffer = heightBuffer;
if (hasVertexNormals) {
polygonVertex.normalBuffer = normalBuffer;
}
}
}
if (numVertices === 3) {
// 三个点,组成一个三角形
indices.push(polygonVertices[0].newIndex);
indices.push(polygonVertices[1].newIndex);
indices.push(polygonVertices[2].newIndex);
} else if (numVertices === 4) {
// 四个点,组成两个三角形
indices.push(polygonVertices[0].newIndex);
indices.push(polygonVertices[1].newIndex);
indices.push(polygonVertices[2].newIndex);
indices.push(polygonVertices[0].newIndex);
indices.push(polygonVertices[2].newIndex);
indices.push(polygonVertices[3].newIndex);
}
}
function lerpOctEncodedNormal(vertex, result) {
++depth;
let first = cartesianScratch1[depth];
let second = cartesianScratch2[depth];
first = AttributeCompression.octDecode(vertex.first.getNormalX(), vertex.first.getNormalY(), first);
second = AttributeCompression.octDecode(vertex.second.getNormalX(), vertex.second.getNormalY(), second);
cartesian3Scratch = lerp(first, second, vertex.ratio);
cartesian3Scratch.normalize();
AttributeCompression.octDecode(cartesian3Scratch, result);
--depth;
return result;
}
onmessage = function(e) {
const data = e.data;
const id = data.id;
const parameters = data.parameters;
const responseData = {
id: id,
result: undefined,
error: undefined
}
return Promise.resolve(
upsampleQuantizedTerrainMesh(parameters)
).then(result => {
responseData.result = result
}).catch(e => {
if (e instanceof Error) {
responseData.error = {
name: e.name,
message: e.message,
stack: e.stack
}
} else {
responseData.error = e;
}
}).finally(() => {
postMessage(responseData);
})
}