cesium
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
201 lines (174 loc) • 8.47 kB
JavaScript
import BoundingSphere from './BoundingSphere.js';
import buildModuleUrl from './buildModuleUrl.js';
import Cartesian2 from './Cartesian2.js';
import Cartesian3 from './Cartesian3.js';
import Cartographic from './Cartographic.js';
import Check from './Check.js';
import defaultValue from './defaultValue.js';
import defined from './defined.js';
import DeveloperError from './DeveloperError.js';
import Ellipsoid from './Ellipsoid.js';
import GeographicTilingScheme from './GeographicTilingScheme.js';
import Rectangle from './Rectangle.js';
import Resource from './Resource.js';
var scratchDiagonalCartesianNE = new Cartesian3();
var scratchDiagonalCartesianSW = new Cartesian3();
var scratchDiagonalCartographic = new Cartographic();
var scratchCenterCartesian = new Cartesian3();
var scratchSurfaceCartesian = new Cartesian3();
var scratchBoundingSphere = new BoundingSphere();
var tilingScheme = new GeographicTilingScheme();
var scratchCorners = [new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic()];
var scratchTileXY = new Cartesian2();
/**
* A collection of functions for approximating terrain height
* @private
*/
var ApproximateTerrainHeights = {};
/**
* Initializes the minimum and maximum terrain heights
* @return {Promise}
*/
ApproximateTerrainHeights.initialize = function() {
var initPromise = ApproximateTerrainHeights._initPromise;
if (defined(initPromise)) {
return initPromise;
}
initPromise = Resource.fetchJson(buildModuleUrl('Assets/approximateTerrainHeights.json'))
.then(function(json) {
ApproximateTerrainHeights._terrainHeights = json;
});
ApproximateTerrainHeights._initPromise = initPromise;
return initPromise;
};
/**
* Computes the minimum and maximum terrain heights for a given rectangle
* @param {Rectangle} rectangle The bounding rectangle
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid
* @return {{minimumTerrainHeight: Number, maximumTerrainHeight: Number}}
*/
ApproximateTerrainHeights.getMinimumMaximumHeights = function(rectangle, ellipsoid) {
//>>includeStart('debug', pragmas.debug);
Check.defined('rectangle', rectangle);
if (!defined(ApproximateTerrainHeights._terrainHeights)) {
throw new DeveloperError('You must call ApproximateTerrainHeights.initialize and wait for the promise to resolve before using this function');
}
//>>includeEnd('debug');
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
var xyLevel = getTileXYLevel(rectangle);
// Get the terrain min/max for that tile
var minTerrainHeight = ApproximateTerrainHeights._defaultMinTerrainHeight;
var maxTerrainHeight = ApproximateTerrainHeights._defaultMaxTerrainHeight;
if (defined(xyLevel)) {
var key = xyLevel.level + '-' + xyLevel.x + '-' + xyLevel.y;
var heights = ApproximateTerrainHeights._terrainHeights[key];
if (defined(heights)) {
minTerrainHeight = heights[0];
maxTerrainHeight = heights[1];
}
// Compute min by taking the center of the NE->SW diagonal and finding distance to the surface
ellipsoid.cartographicToCartesian(Rectangle.northeast(rectangle, scratchDiagonalCartographic),
scratchDiagonalCartesianNE);
ellipsoid.cartographicToCartesian(Rectangle.southwest(rectangle, scratchDiagonalCartographic),
scratchDiagonalCartesianSW);
Cartesian3.midpoint(scratchDiagonalCartesianSW, scratchDiagonalCartesianNE, scratchCenterCartesian);
var surfacePosition = ellipsoid.scaleToGeodeticSurface(scratchCenterCartesian, scratchSurfaceCartesian);
if (defined(surfacePosition)) {
var distance = Cartesian3.distance(scratchCenterCartesian, surfacePosition);
minTerrainHeight = Math.min(minTerrainHeight, -distance);
} else {
minTerrainHeight = ApproximateTerrainHeights._defaultMinTerrainHeight;
}
}
minTerrainHeight = Math.max(ApproximateTerrainHeights._defaultMinTerrainHeight, minTerrainHeight);
return {
minimumTerrainHeight: minTerrainHeight,
maximumTerrainHeight: maxTerrainHeight
};
};
/**
* Computes the bounding sphere based on the tile heights in the rectangle
* @param {Rectangle} rectangle The bounding rectangle
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid
* @return {BoundingSphere} The result bounding sphere
*/
ApproximateTerrainHeights.getBoundingSphere = function(rectangle, ellipsoid) {
//>>includeStart('debug', pragmas.debug);
Check.defined('rectangle', rectangle);
if (!defined(ApproximateTerrainHeights._terrainHeights)) {
throw new DeveloperError('You must call ApproximateTerrainHeights.initialize and wait for the promise to resolve before using this function');
}
//>>includeEnd('debug');
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
var xyLevel = getTileXYLevel(rectangle);
// Get the terrain max for that tile
var maxTerrainHeight = ApproximateTerrainHeights._defaultMaxTerrainHeight;
if (defined(xyLevel)) {
var key = xyLevel.level + '-' + xyLevel.x + '-' + xyLevel.y;
var heights = ApproximateTerrainHeights._terrainHeights[key];
if (defined(heights)) {
maxTerrainHeight = heights[1];
}
}
var result = BoundingSphere.fromRectangle3D(rectangle, ellipsoid, 0.0);
BoundingSphere.fromRectangle3D(rectangle, ellipsoid, maxTerrainHeight, scratchBoundingSphere);
return BoundingSphere.union(result, scratchBoundingSphere, result);
};
function getTileXYLevel(rectangle) {
Cartographic.fromRadians(rectangle.east, rectangle.north, 0.0, scratchCorners[0]);
Cartographic.fromRadians(rectangle.west, rectangle.north, 0.0, scratchCorners[1]);
Cartographic.fromRadians(rectangle.east, rectangle.south, 0.0, scratchCorners[2]);
Cartographic.fromRadians(rectangle.west, rectangle.south, 0.0, scratchCorners[3]);
// Determine which tile the bounding rectangle is in
var lastLevelX = 0, lastLevelY = 0;
var currentX = 0, currentY = 0;
var maxLevel = ApproximateTerrainHeights._terrainHeightsMaxLevel;
var i;
for(i = 0; i <= maxLevel; ++i) {
var failed = false;
for(var j = 0; j < 4; ++j) {
var corner = scratchCorners[j];
tilingScheme.positionToTileXY(corner, i, scratchTileXY);
if (j === 0) {
currentX = scratchTileXY.x;
currentY = scratchTileXY.y;
} else if(currentX !== scratchTileXY.x || currentY !== scratchTileXY.y) {
failed = true;
break;
}
}
if (failed) {
break;
}
lastLevelX = currentX;
lastLevelY = currentY;
}
if (i === 0) {
return undefined;
}
return {
x : lastLevelX,
y : lastLevelY,
level : (i > maxLevel) ? maxLevel : (i - 1)
};
}
ApproximateTerrainHeights._terrainHeightsMaxLevel = 6;
ApproximateTerrainHeights._defaultMaxTerrainHeight = 9000.0;
ApproximateTerrainHeights._defaultMinTerrainHeight = -100000.0;
ApproximateTerrainHeights._terrainHeights = undefined;
ApproximateTerrainHeights._initPromise = undefined;
Object.defineProperties(ApproximateTerrainHeights, {
/**
* Determines if the terrain heights are initialized and ready to use. To initialize the terrain heights,
* call {@link ApproximateTerrainHeights#initialize} and wait for the returned promise to resolve.
* @type {Boolean}
* @readonly
* @memberof ApproximateTerrainHeights
*/
initialized: {
get: function() {
return defined(ApproximateTerrainHeights._terrainHeights);
}
}
});
export default ApproximateTerrainHeights;