443 lines
17 KiB
JavaScript
443 lines
17 KiB
JavaScript
|
|
defineSuite([
|
||
|
|
'Core/HeightmapTessellator',
|
||
|
|
'Core/Cartesian2',
|
||
|
|
'Core/Cartesian3',
|
||
|
|
'Core/Ellipsoid',
|
||
|
|
'Core/Math',
|
||
|
|
'Core/Rectangle',
|
||
|
|
'Core/WebMercatorProjection'
|
||
|
|
], function(
|
||
|
|
HeightmapTessellator,
|
||
|
|
Cartesian2,
|
||
|
|
Cartesian3,
|
||
|
|
Ellipsoid,
|
||
|
|
CesiumMath,
|
||
|
|
Rectangle,
|
||
|
|
WebMercatorProjection) {
|
||
|
|
'use strict';
|
||
|
|
|
||
|
|
it('throws when heightmap is not provided', function() {
|
||
|
|
expect(function() {
|
||
|
|
HeightmapTessellator.computeVertices();
|
||
|
|
}).toThrowDeveloperError();
|
||
|
|
|
||
|
|
expect(function() {
|
||
|
|
HeightmapTessellator.computeVertices({
|
||
|
|
width : 2,
|
||
|
|
height : 2,
|
||
|
|
vertices : [],
|
||
|
|
nativeRectangle : {
|
||
|
|
west : 10.0,
|
||
|
|
south : 20.0,
|
||
|
|
east : 20.0,
|
||
|
|
north : 30.0
|
||
|
|
},
|
||
|
|
skirtHeight : 10.0
|
||
|
|
});
|
||
|
|
}).toThrowDeveloperError();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('throws when width or height is not provided', function() {
|
||
|
|
expect(function() {
|
||
|
|
HeightmapTessellator.computeVertices({
|
||
|
|
heightmap : [1.0, 2.0, 3.0, 4.0],
|
||
|
|
height : 2,
|
||
|
|
vertices : [],
|
||
|
|
nativeRectangle : {
|
||
|
|
west : 10.0,
|
||
|
|
south : 20.0,
|
||
|
|
east : 20.0,
|
||
|
|
north : 30.0
|
||
|
|
},
|
||
|
|
skirtHeight : 10.0
|
||
|
|
});
|
||
|
|
}).toThrowDeveloperError();
|
||
|
|
|
||
|
|
expect(function() {
|
||
|
|
HeightmapTessellator.computeVertices({
|
||
|
|
heightmap : [1.0, 2.0, 3.0, 4.0],
|
||
|
|
width : 2,
|
||
|
|
vertices : [],
|
||
|
|
nativeRectangle : {
|
||
|
|
west : 10.0,
|
||
|
|
south : 20.0,
|
||
|
|
east : 20.0,
|
||
|
|
north : 30.0
|
||
|
|
},
|
||
|
|
skirtHeight : 10.0
|
||
|
|
});
|
||
|
|
}).toThrowDeveloperError();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('throws when nativeRectangle is not provided', function() {
|
||
|
|
expect(function() {
|
||
|
|
HeightmapTessellator.computeVertices({
|
||
|
|
heightmap : [1.0, 2.0, 3.0, 4.0],
|
||
|
|
width : 2,
|
||
|
|
height : 2,
|
||
|
|
vertices : [],
|
||
|
|
skirtHeight : 10.0
|
||
|
|
});
|
||
|
|
}).toThrowDeveloperError();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('throws when skirtHeight is not provided', function() {
|
||
|
|
expect(function() {
|
||
|
|
HeightmapTessellator.computeVertices({
|
||
|
|
heightmap : [1.0, 2.0, 3.0, 4.0],
|
||
|
|
width : 2,
|
||
|
|
height : 2,
|
||
|
|
vertices : [],
|
||
|
|
nativeRectangle : {
|
||
|
|
west : 10.0,
|
||
|
|
south : 20.0,
|
||
|
|
east : 20.0,
|
||
|
|
north : 30.0
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}).toThrowDeveloperError();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('creates mesh without skirt', function() {
|
||
|
|
var width = 3;
|
||
|
|
var height = 3;
|
||
|
|
var options = {
|
||
|
|
heightmap : [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
|
||
|
|
width : width,
|
||
|
|
height : height,
|
||
|
|
skirtHeight : 0.0,
|
||
|
|
nativeRectangle : {
|
||
|
|
west : 10.0,
|
||
|
|
south : 30.0,
|
||
|
|
east : 20.0,
|
||
|
|
north : 40.0
|
||
|
|
},
|
||
|
|
rectangle : new Rectangle(
|
||
|
|
CesiumMath.toRadians(10.0),
|
||
|
|
CesiumMath.toRadians(30.0),
|
||
|
|
CesiumMath.toRadians(20.0),
|
||
|
|
CesiumMath.toRadians(40.0))
|
||
|
|
};
|
||
|
|
var results = HeightmapTessellator.computeVertices(options);
|
||
|
|
var vertices = results.vertices;
|
||
|
|
|
||
|
|
var ellipsoid = Ellipsoid.WGS84;
|
||
|
|
var nativeRectangle = options.nativeRectangle;
|
||
|
|
|
||
|
|
for (var j = 0; j < height; ++j) {
|
||
|
|
var latitude = CesiumMath.lerp(nativeRectangle.north, nativeRectangle.south, j / (height - 1));
|
||
|
|
latitude = CesiumMath.toRadians(latitude);
|
||
|
|
for (var i = 0; i < width; ++i) {
|
||
|
|
var longitude = CesiumMath.lerp(nativeRectangle.west, nativeRectangle.east, i / (width - 1));
|
||
|
|
longitude = CesiumMath.toRadians(longitude);
|
||
|
|
|
||
|
|
var heightSample = options.heightmap[j * width + i];
|
||
|
|
|
||
|
|
var expectedVertexPosition = ellipsoid.cartographicToCartesian({
|
||
|
|
longitude : longitude,
|
||
|
|
latitude : latitude,
|
||
|
|
height : heightSample
|
||
|
|
});
|
||
|
|
|
||
|
|
var index = (j * width + i) * 6;
|
||
|
|
var vertexPosition = new Cartesian3(vertices[index], vertices[index + 1], vertices[index + 2]);
|
||
|
|
|
||
|
|
expect(vertexPosition).toEqualEpsilon(expectedVertexPosition, 1.0);
|
||
|
|
expect(vertices[index + 3]).toEqual(heightSample);
|
||
|
|
expect(vertices[index + 4]).toEqualEpsilon(i / (width - 1), CesiumMath.EPSILON7);
|
||
|
|
expect(vertices[index + 5]).toEqualEpsilon(1.0 - j / (height - 1), CesiumMath.EPSILON7);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it('creates mesh with skirt', function() {
|
||
|
|
var width = 3;
|
||
|
|
var height = 3;
|
||
|
|
var options = {
|
||
|
|
heightmap : [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
|
||
|
|
width : width,
|
||
|
|
height : height,
|
||
|
|
skirtHeight : 10.0,
|
||
|
|
nativeRectangle : {
|
||
|
|
west : 10.0,
|
||
|
|
east : 20.0,
|
||
|
|
south : 30.0,
|
||
|
|
north : 40.0
|
||
|
|
}
|
||
|
|
};
|
||
|
|
var results = HeightmapTessellator.computeVertices(options);
|
||
|
|
var vertices = results.vertices;
|
||
|
|
|
||
|
|
var ellipsoid = Ellipsoid.WGS84;
|
||
|
|
var nativeRectangle = options.nativeRectangle;
|
||
|
|
|
||
|
|
for (var j = -1; j <= height; ++j) {
|
||
|
|
var realJ = CesiumMath.clamp(j, 0, height - 1);
|
||
|
|
var latitude = CesiumMath.lerp(nativeRectangle.north, nativeRectangle.south, realJ / (height - 1));
|
||
|
|
latitude = CesiumMath.toRadians(latitude);
|
||
|
|
for (var i = -1; i <= width; ++i) {
|
||
|
|
var realI = CesiumMath.clamp(i, 0, width - 1);
|
||
|
|
var longitude = CesiumMath.lerp(nativeRectangle.west, nativeRectangle.east, realI / (width - 1));
|
||
|
|
longitude = CesiumMath.toRadians(longitude);
|
||
|
|
|
||
|
|
var heightSample = options.heightmap[realJ * width + realI];
|
||
|
|
|
||
|
|
if (realI !== i || realJ !== j) {
|
||
|
|
heightSample -= options.skirtHeight;
|
||
|
|
}
|
||
|
|
|
||
|
|
var expectedVertexPosition = ellipsoid.cartographicToCartesian({
|
||
|
|
longitude : longitude,
|
||
|
|
latitude : latitude,
|
||
|
|
height : heightSample
|
||
|
|
});
|
||
|
|
|
||
|
|
var index = ((j + 1) * (width + 2) + i + 1) * 6;
|
||
|
|
var vertexPosition = new Cartesian3(vertices[index], vertices[index + 1], vertices[index + 2]);
|
||
|
|
|
||
|
|
expect(vertexPosition).toEqualEpsilon(expectedVertexPosition, 1.0);
|
||
|
|
expect(vertices[index + 3]).toEqual(heightSample);
|
||
|
|
expect(vertices[index + 4]).toEqualEpsilon(realI / (width - 1), CesiumMath.EPSILON7);
|
||
|
|
expect(vertices[index + 5]).toEqualEpsilon(1.0 - realJ / (height - 1), CesiumMath.EPSILON7);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it('creates quantized mesh', function() {
|
||
|
|
var width = 3;
|
||
|
|
var height = 3;
|
||
|
|
var options = {
|
||
|
|
heightmap : [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
|
||
|
|
width : width,
|
||
|
|
height : height,
|
||
|
|
skirtHeight : 10.0,
|
||
|
|
nativeRectangle : {
|
||
|
|
west : 0.01,
|
||
|
|
east : 0.02,
|
||
|
|
south : 0.01,
|
||
|
|
north : 0.02
|
||
|
|
}
|
||
|
|
};
|
||
|
|
var results = HeightmapTessellator.computeVertices(options);
|
||
|
|
var vertices = results.vertices;
|
||
|
|
|
||
|
|
var ellipsoid = Ellipsoid.WGS84;
|
||
|
|
var nativeRectangle = options.nativeRectangle;
|
||
|
|
|
||
|
|
for (var j = -1; j <= height; ++j) {
|
||
|
|
var realJ = CesiumMath.clamp(j, 0, height - 1);
|
||
|
|
var latitude = CesiumMath.lerp(nativeRectangle.north, nativeRectangle.south, realJ / (height - 1));
|
||
|
|
latitude = CesiumMath.toRadians(latitude);
|
||
|
|
for (var i = -1; i <= width; ++i) {
|
||
|
|
var realI = CesiumMath.clamp(i, 0, width - 1);
|
||
|
|
var longitude = CesiumMath.lerp(nativeRectangle.west, nativeRectangle.east, realI / (width - 1));
|
||
|
|
longitude = CesiumMath.toRadians(longitude);
|
||
|
|
|
||
|
|
var heightSample = options.heightmap[realJ * width + realI];
|
||
|
|
|
||
|
|
if (realI !== i || realJ !== j) {
|
||
|
|
heightSample -= options.skirtHeight;
|
||
|
|
}
|
||
|
|
|
||
|
|
var index = ((j + 1) * (width + 2) + i + 1);
|
||
|
|
var expectedVertexPosition = ellipsoid.cartographicToCartesian({
|
||
|
|
longitude : longitude,
|
||
|
|
latitude : latitude,
|
||
|
|
height : heightSample
|
||
|
|
});
|
||
|
|
expect(results.encoding.decodePosition(vertices, index)).toEqualEpsilon(expectedVertexPosition, 1.0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it('tessellates web mercator heightmaps', function() {
|
||
|
|
var width = 3;
|
||
|
|
var height = 3;
|
||
|
|
var options = {
|
||
|
|
heightmap : [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
|
||
|
|
width : width,
|
||
|
|
height : height,
|
||
|
|
skirtHeight : 0.0,
|
||
|
|
nativeRectangle : {
|
||
|
|
west : 1000000.0,
|
||
|
|
east : 2000000.0,
|
||
|
|
south : 3000000.0,
|
||
|
|
north : 4000000.0
|
||
|
|
},
|
||
|
|
isGeographic : false
|
||
|
|
};
|
||
|
|
var results = HeightmapTessellator.computeVertices(options);
|
||
|
|
var vertices = results.vertices;
|
||
|
|
|
||
|
|
var ellipsoid = Ellipsoid.WGS84;
|
||
|
|
var projection = new WebMercatorProjection(ellipsoid);
|
||
|
|
var nativeRectangle = options.nativeRectangle;
|
||
|
|
|
||
|
|
var geographicSouthwest = projection.unproject(new Cartesian2(nativeRectangle.west, nativeRectangle.south));
|
||
|
|
var geographicNortheast = projection.unproject(new Cartesian2(nativeRectangle.east, nativeRectangle.north));
|
||
|
|
|
||
|
|
for (var j = 0; j < height; ++j) {
|
||
|
|
var y = CesiumMath.lerp(nativeRectangle.north, nativeRectangle.south, j / (height - 1));
|
||
|
|
for (var i = 0; i < width; ++i) {
|
||
|
|
var x = CesiumMath.lerp(nativeRectangle.west, nativeRectangle.east, i / (width - 1));
|
||
|
|
|
||
|
|
var latLon = projection.unproject(new Cartesian2(x, y));
|
||
|
|
var longitude = latLon.longitude;
|
||
|
|
var latitude = latLon.latitude;
|
||
|
|
|
||
|
|
var heightSample = options.heightmap[j * width + i];
|
||
|
|
|
||
|
|
var expectedVertexPosition = ellipsoid.cartographicToCartesian({
|
||
|
|
longitude : longitude,
|
||
|
|
latitude : latitude,
|
||
|
|
height : heightSample
|
||
|
|
});
|
||
|
|
|
||
|
|
var index = (j * width + i) * 6;
|
||
|
|
var vertexPosition = new Cartesian3(vertices[index], vertices[index + 1], vertices[index + 2]);
|
||
|
|
|
||
|
|
var expectedU = (longitude - geographicSouthwest.longitude) / (geographicNortheast.longitude - geographicSouthwest.longitude);
|
||
|
|
var expectedV = (latitude - geographicSouthwest.latitude) / (geographicNortheast.latitude - geographicSouthwest.latitude);
|
||
|
|
|
||
|
|
expect(vertexPosition).toEqualEpsilon(expectedVertexPosition, 1.0);
|
||
|
|
expect(vertices[index + 3]).toEqual(heightSample);
|
||
|
|
expect(vertices[index + 4]).toEqualEpsilon(expectedU, CesiumMath.EPSILON7);
|
||
|
|
expect(vertices[index + 5]).toEqualEpsilon(expectedV, CesiumMath.EPSILON7);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it('supports multi-element little endian heights', function() {
|
||
|
|
var width = 3;
|
||
|
|
var height = 3;
|
||
|
|
var options = {
|
||
|
|
heightmap : [1.0, 2.0, 100.0,
|
||
|
|
3.0, 4.0, 100.0,
|
||
|
|
5.0, 6.0, 100.0,
|
||
|
|
7.0, 8.0, 100.0,
|
||
|
|
9.0, 10.0, 100.0,
|
||
|
|
11.0, 12.0, 100.0,
|
||
|
|
13.0, 14.0, 100.0,
|
||
|
|
15.0, 16.0, 100.0,
|
||
|
|
17.0, 18.0, 100.0],
|
||
|
|
width : width,
|
||
|
|
height : height,
|
||
|
|
skirtHeight : 0.0,
|
||
|
|
nativeRectangle : {
|
||
|
|
west : 10.0,
|
||
|
|
south : 30.0,
|
||
|
|
east : 20.0,
|
||
|
|
north : 40.0
|
||
|
|
},
|
||
|
|
rectangle : new Rectangle(
|
||
|
|
CesiumMath.toRadians(10.0),
|
||
|
|
CesiumMath.toRadians(30.0),
|
||
|
|
CesiumMath.toRadians(20.0),
|
||
|
|
CesiumMath.toRadians(40.0)),
|
||
|
|
structure : {
|
||
|
|
stride : 3,
|
||
|
|
elementsPerHeight : 2,
|
||
|
|
elementMultiplier : 10
|
||
|
|
}
|
||
|
|
};
|
||
|
|
var results = HeightmapTessellator.computeVertices(options);
|
||
|
|
var vertices = results.vertices;
|
||
|
|
|
||
|
|
var ellipsoid = Ellipsoid.WGS84;
|
||
|
|
var nativeRectangle = options.nativeRectangle;
|
||
|
|
|
||
|
|
for (var j = 0; j < height; ++j) {
|
||
|
|
var latitude = CesiumMath.lerp(nativeRectangle.north, nativeRectangle.south, j / (height - 1));
|
||
|
|
latitude = CesiumMath.toRadians(latitude);
|
||
|
|
for (var i = 0; i < width; ++i) {
|
||
|
|
var longitude = CesiumMath.lerp(nativeRectangle.west, nativeRectangle.east, i / (width - 1));
|
||
|
|
longitude = CesiumMath.toRadians(longitude);
|
||
|
|
|
||
|
|
var heightSampleIndex = (j * width + i) * options.structure.stride;
|
||
|
|
var heightSample = options.heightmap[heightSampleIndex] + options.heightmap[heightSampleIndex + 1] * 10.0;
|
||
|
|
|
||
|
|
var expectedVertexPosition = ellipsoid.cartographicToCartesian({
|
||
|
|
longitude : longitude,
|
||
|
|
latitude : latitude,
|
||
|
|
height : heightSample
|
||
|
|
});
|
||
|
|
|
||
|
|
var index = (j * width + i) * 6;
|
||
|
|
var vertexPosition = new Cartesian3(vertices[index], vertices[index + 1], vertices[index + 2]);
|
||
|
|
|
||
|
|
expect(vertexPosition).toEqualEpsilon(expectedVertexPosition, 1.0);
|
||
|
|
expect(vertices[index + 3]).toEqual(heightSample);
|
||
|
|
expect(vertices[index + 4]).toEqualEpsilon(i / (width - 1), CesiumMath.EPSILON7);
|
||
|
|
expect(vertices[index + 5]).toEqualEpsilon(1.0 - j / (height - 1), CesiumMath.EPSILON7);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it('supports multi-element big endian heights', function() {
|
||
|
|
var width = 3;
|
||
|
|
var height = 3;
|
||
|
|
var options = {
|
||
|
|
heightmap : [1.0, 2.0, 100.0,
|
||
|
|
3.0, 4.0, 100.0,
|
||
|
|
5.0, 6.0, 100.0,
|
||
|
|
7.0, 8.0, 100.0,
|
||
|
|
9.0, 10.0, 100.0,
|
||
|
|
11.0, 12.0, 100.0,
|
||
|
|
13.0, 14.0, 100.0,
|
||
|
|
15.0, 16.0, 100.0,
|
||
|
|
17.0, 18.0, 100.0],
|
||
|
|
width : width,
|
||
|
|
height : height,
|
||
|
|
skirtHeight : 0.0,
|
||
|
|
nativeRectangle : {
|
||
|
|
west : 10.0,
|
||
|
|
south : 30.0,
|
||
|
|
east : 20.0,
|
||
|
|
north : 40.0
|
||
|
|
},
|
||
|
|
rectangle : new Rectangle(
|
||
|
|
CesiumMath.toRadians(10.0),
|
||
|
|
CesiumMath.toRadians(30.0),
|
||
|
|
CesiumMath.toRadians(20.0),
|
||
|
|
CesiumMath.toRadians(40.0)),
|
||
|
|
structure : {
|
||
|
|
stride : 3,
|
||
|
|
elementsPerHeight : 2,
|
||
|
|
elementMultiplier : 10,
|
||
|
|
isBigEndian : true
|
||
|
|
}
|
||
|
|
};
|
||
|
|
var results = HeightmapTessellator.computeVertices(options);
|
||
|
|
var vertices = results.vertices;
|
||
|
|
|
||
|
|
var ellipsoid = Ellipsoid.WGS84;
|
||
|
|
var nativeRectangle = options.nativeRectangle;
|
||
|
|
|
||
|
|
for (var j = 0; j < height; ++j) {
|
||
|
|
var latitude = CesiumMath.lerp(nativeRectangle.north, nativeRectangle.south, j / (height - 1));
|
||
|
|
latitude = CesiumMath.toRadians(latitude);
|
||
|
|
for (var i = 0; i < width; ++i) {
|
||
|
|
var longitude = CesiumMath.lerp(nativeRectangle.west, nativeRectangle.east, i / (width - 1));
|
||
|
|
longitude = CesiumMath.toRadians(longitude);
|
||
|
|
|
||
|
|
var heightSampleIndex = (j * width + i) * options.structure.stride;
|
||
|
|
var heightSample = options.heightmap[heightSampleIndex] * 10.0 + options.heightmap[heightSampleIndex + 1];
|
||
|
|
|
||
|
|
var expectedVertexPosition = ellipsoid.cartographicToCartesian({
|
||
|
|
longitude : longitude,
|
||
|
|
latitude : latitude,
|
||
|
|
height : heightSample
|
||
|
|
});
|
||
|
|
|
||
|
|
var index = (j * width + i) * 6;
|
||
|
|
var vertexPosition = new Cartesian3(vertices[index], vertices[index + 1], vertices[index + 2]);
|
||
|
|
|
||
|
|
expect(vertexPosition).toEqualEpsilon(expectedVertexPosition, 1.0);
|
||
|
|
expect(vertices[index + 3]).toEqual(heightSample);
|
||
|
|
expect(vertices[index + 4]).toEqualEpsilon(i / (width - 1), CesiumMath.EPSILON7);
|
||
|
|
expect(vertices[index + 5]).toEqualEpsilon(1.0 - j / (height - 1), CesiumMath.EPSILON7);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|