terriajs
Version:
Geospatial data visualization platform.
133 lines (114 loc) • 4.1 kB
JavaScript
import CesiumMath from "terriajs-cesium/Source/Core/Math";
import defined from "terriajs-cesium/Source/Core/defined";
import loadArrayBuffer from "../../Core/loadArrayBuffer";
/**
* The Earth Gravity Model 1996 (EGM96) geoid.
* @param {String} gridFileUrl The URL of the WW15MGH.DAC file.
*/
var EarthGravityModel1996 = function (gridFileUrl) {
this.gridFileUrl = gridFileUrl;
this.data = undefined;
// These values were determined by inspecting the WW15MGH.DAC file. We hard-code them here because
// we need them available before that file finishes loading.
this.minimumHeight = -106.99;
this.maximumHeight = 85.39;
};
/**
* Determines if this class will work in the current environment. It will return false on older browsers without support
* for typed arrays.
* @return {Boolean} True if this class may be used in this environment; otherwise, false.
*/
EarthGravityModel1996.isSupported = function () {
return typeof Int16Array !== "undefined" && typeof Uint8Array !== "undefined";
};
/**
* Gets the height of EGM96 above the surface of the ellipsoid.
* @param {String} baseUrl The base URL for TerriaJS resources.
* @param {Number} longitude The longitude.
* @param {Number} latitude The latitude
* @return {Promise|Number} A promise, that, when it results The height of mean sea level above the ellipsoid at the specified location. Negative numbers indicate that mean sea level
* is below the ellipsoid.
*/
EarthGravityModel1996.prototype.getHeight = function (longitude, latitude) {
return getHeightData(this).then(function (data) {
return getHeightFromData(data, longitude, latitude);
});
};
EarthGravityModel1996.prototype.getHeights = function (cartographicArray) {
return getHeightData(this).then(function (data) {
for (var i = 0; i < cartographicArray.length; ++i) {
var cartographic = cartographicArray[i];
cartographic.height = getHeightFromData(
data,
cartographic.longitude,
cartographic.latitude
);
}
return cartographicArray;
});
};
function getHeightData(model) {
if (!defined(model.data)) {
model.data = loadArrayBuffer(model.gridFileUrl);
}
return Promise.resolve(model.data).then(function (data) {
if (!(model.data instanceof Int16Array)) {
// Data file is big-endian, all relevant platforms are little endian, so swap the byte order.
var byteView = new Uint8Array(data);
for (var k = 0; k < byteView.length; k += 2) {
var tmp = byteView[k];
byteView[k] = byteView[k + 1];
byteView[k + 1] = tmp;
}
model.data = new Int16Array(data);
}
return model.data;
});
}
function getHeightFromData(data, longitude, latitude) {
var recordIndex = (720 * (CesiumMath.PI_OVER_TWO - latitude)) / Math.PI;
if (recordIndex < 0) {
recordIndex = 0;
} else if (recordIndex > 720) {
recordIndex = 720;
}
longitude = CesiumMath.zeroToTwoPi(longitude);
var heightIndex = (1440 * longitude) / CesiumMath.TWO_PI;
if (heightIndex < 0) {
heightIndex = 0;
} else if (heightIndex > 1440) {
heightIndex = 1440;
}
var i = heightIndex | 0;
var j = recordIndex | 0;
var xMinusX1 = heightIndex - i;
var yMinusY1 = recordIndex - j;
var x2MinusX = 1.0 - xMinusX1;
var y2MinusY = 1.0 - yMinusY1;
var f11 = getHeightValue(data, j, i);
var f21 = getHeightValue(data, j, i + 1);
var f12 = getHeightValue(data, j + 1, i);
var f22 = getHeightValue(data, j + 1, i + 1);
return (
(f11 * x2MinusX * y2MinusY +
f21 * xMinusX1 * y2MinusY +
f12 * x2MinusX * yMinusY1 +
f22 * xMinusX1 * yMinusY1) /
100.0
);
}
// Heights returned by this function are in centimeters.
function getHeightValue(data, recordIndex, heightIndex) {
if (recordIndex > 720) {
recordIndex = 720;
} else if (recordIndex < 0) {
recordIndex = 0;
}
if (heightIndex > 1439) {
heightIndex -= 1440;
} else if (heightIndex < 0) {
heightIndex += 1440;
}
return data[recordIndex * 1440 + heightIndex];
}
export default EarthGravityModel1996;