DSDSWeb/static/js/Cesium-1.53/Specs/Core/GoogleEarthEnterpriseTerrai...

500 lines
20 KiB
JavaScript
Raw Normal View History

2024-07-11 18:02:47 +08:00
defineSuite([
'Core/GoogleEarthEnterpriseTerrainData',
'Core/Cartesian3',
'Core/Cartographic',
'Core/Ellipsoid',
'Core/GeographicTilingScheme',
'Core/Math',
'Core/Rectangle',
'Core/TerrainData',
'Core/TerrainMesh',
'ThirdParty/when'
], function(
GoogleEarthEnterpriseTerrainData,
Cartesian3,
Cartographic,
Ellipsoid,
GeographicTilingScheme,
CesiumMath,
Rectangle,
TerrainData,
TerrainMesh,
when) {
'use strict';
var sizeOfUint8 = Uint8Array.BYTES_PER_ELEMENT;
var sizeOfUint16 = Uint16Array.BYTES_PER_ELEMENT;
var sizeOfInt32 = Int32Array.BYTES_PER_ELEMENT;
var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;
var sizeOfFloat = Float32Array.BYTES_PER_ELEMENT;
var sizeOfDouble = Float64Array.BYTES_PER_ELEMENT;
var toEarthRadii = 1.0 / 6371010.0;
function getBuffer(tilingScheme, x, y, level) {
var rectangle = tilingScheme.tileXYToRectangle(x, y, level);
var center = Rectangle.center(rectangle);
var southwest = Rectangle.southwest(rectangle);
var stepX = CesiumMath.toDegrees(rectangle.width / 2) / 180.0;
var stepY = CesiumMath.toDegrees(rectangle.height / 2) / 180.0;
// 2 Uint8s: x and y values in units of step
var pointSize = 2 * sizeOfUint8 + sizeOfFloat;
// 3 shorts
var faceSize = 3 * sizeOfUint16;
// Doubles: OriginX, OriginY, SizeX, SizeY
// Int32s: numPoints, numFaces, level
// 4 corner points
// 2 face (3 shorts)
var quadSize = 4 * sizeOfDouble + 3 * sizeOfInt32 + 4 * pointSize + 2 * faceSize;
// QuadSize + size of each quad
var totalSize = 4 * (quadSize + sizeOfUint32);
var buf = new ArrayBuffer(totalSize);
var dv = new DataView(buf);
var altitudeStart = 0;
var offset = 0;
for (var i = 0; i < 4; ++i) {
altitudeStart = 0;
dv.setUint32(offset, quadSize, true);
offset += sizeOfUint32;
// Origin
var xOrigin = southwest.longitude;
var yOrigin = southwest.latitude;
if ((i & 2) !== 0) { // Top row
if ((i & 1) === 0) { // NE
xOrigin = center.longitude;
altitudeStart = 10;
}
yOrigin = center.latitude;
} else if ((i & 1) !== 0) { // SE
xOrigin = center.longitude;
altitudeStart = 10;
}
dv.setFloat64(offset, CesiumMath.toDegrees(xOrigin) / 180.0, true);
offset += sizeOfDouble;
dv.setFloat64(offset, CesiumMath.toDegrees(yOrigin) / 180.0, true);
offset += sizeOfDouble;
// Step - Each step is a degree
dv.setFloat64(offset, stepX, true);
offset += sizeOfDouble;
dv.setFloat64(offset, stepY, true);
offset += sizeOfDouble;
// NumPoints
dv.setInt32(offset, 4, true);
offset += sizeOfInt32;
// NumFaces
dv.setInt32(offset, 2, true);
offset += sizeOfInt32;
// Level
dv.setInt32(offset, 0, true);
offset += sizeOfInt32;
// Points
var j;
for (j = 0; j < 4; ++j) {
var xPos = 0;
var yPos = 0;
var altitude = altitudeStart;
if (j & 1) {
++xPos;
altitude += 10;
}
if (j & 2) {
++yPos;
}
dv.setUint8(offset++, xPos);
dv.setUint8(offset++, yPos);
dv.setFloat32(offset, altitude * toEarthRadii, true);
offset += sizeOfFloat;
}
// Faces
var indices = [0, 1, 2, 1, 3, 2];
for (j = 0; j < indices.length; ++j) {
dv.setUint16(offset, indices[j], true);
offset += sizeOfUint16;
}
}
return buf;
}
it('conforms to TerrainData interface', function() {
expect(GoogleEarthEnterpriseTerrainData).toConformToInterface(TerrainData);
});
describe('upsample', function() {
it('works for all four children of a simple quad', function() {
var maxShort = 32767;
var tilingScheme = new GeographicTilingScheme();
var buffer = getBuffer(tilingScheme, 0, 0, 0);
var data = new GoogleEarthEnterpriseTerrainData({
buffer : buffer,
childTileMask : 15,
negativeAltitudeExponentBias : 32,
negativeElevationThreshold : CesiumMath.EPSILON12
});
tilingScheme = new GeographicTilingScheme();
var childRectangles = [
tilingScheme.tileXYToRectangle(0, 0, 1),
tilingScheme.tileXYToRectangle(1, 0, 1),
tilingScheme.tileXYToRectangle(0, 1, 1),
tilingScheme.tileXYToRectangle(1, 1, 1)
];
return when(data.createMesh(tilingScheme, 0, 0, 0, 1)).then(function() {
var swPromise = data.upsample(tilingScheme, 0, 0, 0, 0, 0, 1);
var sePromise = data.upsample(tilingScheme, 0, 0, 0, 1, 0, 1);
var nwPromise = data.upsample(tilingScheme, 0, 0, 0, 0, 1, 1);
var nePromise = data.upsample(tilingScheme, 0, 0, 0, 1, 1, 1);
return when.join(swPromise, sePromise, nwPromise, nePromise);
}).then(function(upsampleResults) {
expect(upsampleResults.length).toBe(4);
for (var i = 0; i < upsampleResults.length; ++i) {
var upsampled = upsampleResults[i];
expect(upsampled).toBeDefined();
var uBuffer = upsampled._uValues;
var vBuffer = upsampled._vValues;
var ib = upsampled._indices;
var heights = upsampled._heightValues;
expect(uBuffer.length).toBe(4);
expect(vBuffer.length).toBe(4);
expect(heights.length).toBe(4);
expect(ib.length).toBe(6);
var rectangle = childRectangles[i];
var north = 0;
var south = 0;
var east = 0;
var west = 0;
var index, u, v;
for (var j = 0; j < ib.length; ++j) {
index = ib[j];
u = (uBuffer[index] / maxShort) * rectangle.width + rectangle.west;
v = (vBuffer[index] / maxShort) * rectangle.height + rectangle.south;
if (CesiumMath.equalsEpsilon(u, rectangle.west, CesiumMath.EPSILON7)) {
++west;
} else if (CesiumMath.equalsEpsilon(u, rectangle.east, CesiumMath.EPSILON7)) {
++east;
}
if (CesiumMath.equalsEpsilon(v, rectangle.south, CesiumMath.EPSILON7)) {
++south;
} else if (CesiumMath.equalsEpsilon(v, rectangle.north, CesiumMath.EPSILON7)) {
++north;
}
}
// Each one is made up of 2 triangles
expect(north).toEqual(3);
expect(south).toEqual(3);
expect(east).toEqual(3);
expect(west).toEqual(3);
// Each side of quad has 2 edge points
expect(upsampled._westIndices.length).toEqual(2);
expect(upsampled._southIndices.length).toEqual(2);
expect(upsampled._eastIndices.length).toEqual(2);
expect(upsampled._northIndices.length).toEqual(2);
}
});
});
});
describe('createMesh', function() {
var data;
var tilingScheme;
var buffer;
beforeEach(function() {
tilingScheme = new GeographicTilingScheme();
buffer = getBuffer(tilingScheme, 0, 0, 0);
data = new GoogleEarthEnterpriseTerrainData({
buffer : buffer,
childTileMask : 15,
negativeAltitudeExponentBias : 32,
negativeElevationThreshold : CesiumMath.EPSILON12
});
});
it('requires tilingScheme', function() {
expect(function() {
data.createMesh(undefined, 0, 0, 0);
}).toThrowDeveloperError();
});
it('requires x', function() {
expect(function() {
data.createMesh(tilingScheme, undefined, 0, 0);
}).toThrowDeveloperError();
});
it('requires y', function() {
expect(function() {
data.createMesh(tilingScheme, 0, undefined, 0);
}).toThrowDeveloperError();
});
it('requires level', function() {
expect(function() {
data.createMesh(tilingScheme, 0, 0, undefined);
}).toThrowDeveloperError();
});
it('creates specified vertices plus skirt vertices', function() {
var rectangle = tilingScheme.tileXYToRectangle(0, 0, 0);
var wgs84 = Ellipsoid.WGS84;
return data.createMesh(tilingScheme, 0, 0, 0).then(function(mesh) {
expect(mesh).toBeInstanceOf(TerrainMesh);
expect(mesh.vertices.length).toBe(17 * mesh.encoding.getStride()); // 9 regular + 8 skirt vertices
expect(mesh.indices.length).toBe(4 * 6 * 3); // 2 regular + 4 skirt triangles per quad
expect(mesh.minimumHeight).toBe(0);
expect(mesh.maximumHeight).toBeCloseTo(20, 5);
var encoding = mesh.encoding;
var cartesian = new Cartesian3();
var cartographic = new Cartographic();
var count = mesh.vertices.length / mesh.encoding.getStride();
for (var i = 0; i < count; ++i) {
var height = encoding.decodeHeight(mesh.vertices, i);
if (i < 9) { // Original vertices
expect(height).toBeBetween(0, 20);
// Only test on original positions as the skirts angle outward
encoding.decodePosition(mesh.vertices, i, cartesian);
wgs84.cartesianToCartographic(cartesian, cartographic);
cartographic.longitude = CesiumMath.convertLongitudeRange(cartographic.longitude);
expect(Rectangle.contains(rectangle, cartographic)).toBe(true);
} else { // Skirts
expect(height).toBeBetween(-1000, -980);
}
}
});
});
it('exaggerates mesh', function() {
return data.createMesh(tilingScheme, 0, 0, 0, 2).then(function(mesh) {
expect(mesh).toBeInstanceOf(TerrainMesh);
expect(mesh.vertices.length).toBe(17 * mesh.encoding.getStride()); // 9 regular + 8 skirt vertices
expect(mesh.indices.length).toBe(4 * 6 * 3); // 2 regular + 4 skirt triangles per quad
expect(mesh.minimumHeight).toBe(0);
expect(mesh.maximumHeight).toBeCloseTo(40, 5);
var encoding = mesh.encoding;
var count = mesh.vertices.length / mesh.encoding.getStride();
for (var i = 0; i < count; ++i) {
var height = encoding.decodeHeight(mesh.vertices, i);
if (i < 9) { // Original vertices
expect(height).toBeBetween(0, 40);
} else { // Skirts
expect(height).toBeBetween(-1000, -960);
}
}
});
});
});
describe('interpolateHeight', function() {
var tilingScheme;
var rectangle;
var mesh;
beforeEach(function() {
tilingScheme = new GeographicTilingScheme();
rectangle = tilingScheme.tileXYToRectangle(7, 6, 5);
var buffer = getBuffer(tilingScheme, 7, 6, 5);
mesh = new GoogleEarthEnterpriseTerrainData({
buffer : buffer,
childTileMask : 15,
negativeAltitudeExponentBias : 32,
negativeElevationThreshold : CesiumMath.EPSILON12
});
});
it('clamps coordinates if given a position outside the mesh', function() {
expect(mesh.interpolateHeight(rectangle, 0.0, 0.0)).toBe(mesh.interpolateHeight(rectangle, rectangle.east, rectangle.south));
});
it('returns a height interpolated from the correct triangle', function() {
// position in the northwest quadrant of the tile.
var longitude = rectangle.west + (rectangle.east - rectangle.west) * 0.25;
var latitude = rectangle.south + (rectangle.north - rectangle.south) * 0.75;
var result = mesh.interpolateHeight(rectangle, longitude, latitude);
expect(result).toBeBetween(0.0, 10.0);
// position in the southeast quadrant of the tile.
longitude = rectangle.west + (rectangle.east - rectangle.west) * 0.75;
latitude = rectangle.south + (rectangle.north - rectangle.south) * 0.25;
result = mesh.interpolateHeight(rectangle, longitude, latitude);
expect(result).toBeBetween(10.0, 20.0);
// position on the line between the southwest and northeast corners.
longitude = rectangle.west + (rectangle.east - rectangle.west) * 0.5;
latitude = rectangle.south + (rectangle.north - rectangle.south) * 0.5;
result = mesh.interpolateHeight(rectangle, longitude, latitude);
expect(result).toEqualEpsilon(10.0, 1e-6);
});
});
describe('isChildAvailable', function() {
var data;
beforeEach(function() {
data = new GoogleEarthEnterpriseTerrainData({
buffer : new ArrayBuffer(1),
childTileMask : 15,
negativeAltitudeExponentBias : 32,
negativeElevationThreshold : CesiumMath.EPSILON12
});
});
it('requires thisX', function() {
expect(function() {
data.isChildAvailable(undefined, 0, 0, 0);
}).toThrowDeveloperError();
});
it('requires thisY', function() {
expect(function() {
data.isChildAvailable(0, undefined, 0, 0);
}).toThrowDeveloperError();
});
it('requires childX', function() {
expect(function() {
data.isChildAvailable(0, 0, undefined, 0);
}).toThrowDeveloperError();
});
it('requires childY', function() {
expect(function() {
data.isChildAvailable(0, 0, 0, undefined);
}).toThrowDeveloperError();
});
it('returns true for all children when child mask is not explicitly specified', function() {
data = new GoogleEarthEnterpriseTerrainData({
buffer : new ArrayBuffer(1),
negativeAltitudeExponentBias : 32,
negativeElevationThreshold : CesiumMath.EPSILON12
});
expect(data.isChildAvailable(10, 20, 20, 40)).toBe(true);
expect(data.isChildAvailable(10, 20, 21, 40)).toBe(true);
expect(data.isChildAvailable(10, 20, 20, 41)).toBe(true);
expect(data.isChildAvailable(10, 20, 21, 41)).toBe(true);
});
it('works when only southwest child is available', function() {
data = new GoogleEarthEnterpriseTerrainData({
buffer : new ArrayBuffer(1),
childTileMask : 1,
negativeAltitudeExponentBias : 32,
negativeElevationThreshold : CesiumMath.EPSILON12
});
expect(data.isChildAvailable(10, 20, 20, 40)).toBe(false);
expect(data.isChildAvailable(10, 20, 21, 40)).toBe(false);
expect(data.isChildAvailable(10, 20, 20, 41)).toBe(true);
expect(data.isChildAvailable(10, 20, 21, 41)).toBe(false);
});
it('works when only southeast child is available', function() {
data = new GoogleEarthEnterpriseTerrainData({
buffer : new ArrayBuffer(1),
childTileMask : 2,
negativeAltitudeExponentBias : 32,
negativeElevationThreshold : CesiumMath.EPSILON12
});
expect(data.isChildAvailable(10, 20, 20, 40)).toBe(false);
expect(data.isChildAvailable(10, 20, 21, 40)).toBe(false);
expect(data.isChildAvailable(10, 20, 20, 41)).toBe(false);
expect(data.isChildAvailable(10, 20, 21, 41)).toBe(true);
});
it('works when only northeast child is available', function() {
data = new GoogleEarthEnterpriseTerrainData({
buffer : new ArrayBuffer(1),
childTileMask : 4,
negativeAltitudeExponentBias : 32,
negativeElevationThreshold : CesiumMath.EPSILON12
});
expect(data.isChildAvailable(10, 20, 20, 40)).toBe(false);
expect(data.isChildAvailable(10, 20, 21, 40)).toBe(true);
expect(data.isChildAvailable(10, 20, 20, 41)).toBe(false);
expect(data.isChildAvailable(10, 20, 21, 41)).toBe(false);
});
it('works when only northwest child is available', function() {
data = new GoogleEarthEnterpriseTerrainData({
buffer : new ArrayBuffer(1),
childTileMask : 8,
negativeAltitudeExponentBias : 32,
negativeElevationThreshold : CesiumMath.EPSILON12
});
expect(data.isChildAvailable(10, 20, 20, 40)).toBe(true);
expect(data.isChildAvailable(10, 20, 21, 40)).toBe(false);
expect(data.isChildAvailable(10, 20, 20, 41)).toBe(false);
expect(data.isChildAvailable(10, 20, 21, 41)).toBe(false);
});
});
it('requires buffer', function() {
expect(function() {
/*eslint-disable no-unused-vars*/
var data = new GoogleEarthEnterpriseTerrainData({
childTileMask : 8,
negativeAltitudeExponentBias : 32,
negativeElevationThreshold : CesiumMath.EPSILON12
});
/*eslint-enable no-unused-vars*/
}).toThrowDeveloperError();
});
it('requires negativeAltitudeExponentBias', function() {
expect(function() {
/*eslint-disable no-unused-vars*/
var data = new GoogleEarthEnterpriseTerrainData({
buffer : new ArrayBuffer(1),
childTileMask : 8,
negativeElevationThreshold : CesiumMath.EPSILON12
});
/*eslint-enable no-unused-vars*/
}).toThrowDeveloperError();
});
it('requires negativeElevationThreshold', function() {
expect(function() {
/*eslint-disable no-unused-vars*/
var data = new GoogleEarthEnterpriseTerrainData({
buffer : new ArrayBuffer(1),
childTileMask : 8,
negativeAltitudeExponentBias : 32
});
/*eslint-enable no-unused-vars*/
}).toThrowDeveloperError();
});
});