Converting Ellipsoid Height to MSL

I have been attempting to use the code found here https://github.com/TerriaJS/terriajs/blob/master/lib/Map/EarthGravityModel1996.js
to get MSL elevation values for locations on the globe.

However, when the code attempts to create a new Int16Array after swapping the byte order of the array buffer an error is thrown. The error is occurring in the try/catch below:

function getHeightData(model) {

if (!Cesium.defined(model.data)) {

model.data = Cesium.Resource.fetchArrayBuffer(model.gridFileUrl);

}

return Cesium.when(model.data, 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;

}

try {

model.data = new Int16Array(data);

}

catch (ex) {

console.log("getHeightData Error: " + ex.toString());

}

}

return model.data;

});

}

``

The error states: “RangeError: byte length of Int16Array should be a multiple of 2”

I also get the same error if I attempt to create a new Int16Array without swapping the byte order.

I have downloaded the WW15MGH.DAC file from several different sources (including TerriaJS), and the file looks identical from each source. So I don’t think the file is the issue.

Is there something obvious I’m missing? I’d really like to be able to read MSL elevation from Cesium.

Are you sure the web browser is receiving the WW15MGH.DAC for correctly? IIS, for example, will not server a .DAC file by default, and so you might be getting an error page instead. Or perhaps the DAC file is being incorrectly served as text. It’s binary data, so transforming line endings, for example, will corrupt it.

I’d suggest using the debugger to look at the data value you’re getting and see if it makes sense.

Kevin

Hi Kevin,

Thanks for the response! I’m pretty sure the WW15MGH.DAC file is being served/received properly. I’ve placed it on our server and set the mime type to application/octet stream.

I’ve created a Sandcastle example to show you exactly how I’ve set this up. I updated several of the method and constant references to ones that I believe are equivalent or updated in Cesium (such as the call to “loadArrayBuffer” and constants like “Cesium.Math.PI_OVER_TWO”).

I’m getting an error in Sandcastle that I’m not sure about, but at least you can all the code. Here’s the example:

Sandcastle Example

I appreciate your help with this!

By the way if you comment out line 138 the scene will finish loading. Line 138 is where the call to “getHeight” is made.

I think you need to pass the URL to Cesium.Resource.fetchArrayBuffer

model.data = Cesium.Resource.fetchArrayBuffer({url: gridFileUrl});

``

Scott

Thank you, Scott, that seems to have fixed the issue with the data file loading. Below is a link to the updated Sandcastle example which produces a result and show debugging values.

Working Sandcastle Example

However, I don’t understand the result I’m getting…

  • London Gatwick Airport (LGW) is located at LON: -0.1903 and LAT: 51.1481 and has an elevations of 203 feet MSL.
  • The “getHeight” function is returning a value of 13.61 meters (44.65 feet) at lon/lat = -0.1903 / 51.1481
    I thought that this code was supposed to return MSL elevation for the lat/lon provided. However, I see that the comments for the function state: “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.”

Does this mean that the function is returning the elevation difference between MSL and the WGS84 ellipsoid for the lat/lon provided?

Cesium reports the height above the ellipsoid at this location to be 342 feet.

And this function reports a value of 44.65 feet for this location.

How would I use this function to get the MSL in feet for this location (which should be 203)?

Am I just being dense? I appreciate any help with this!

BTW… I’m comparing output from the “getHeight” function to the results from the following sites. But it seems like more discrepancy than there should be. The sites below say the height above the ellipsoid at the LGW lat/lon is 45.58 or 45.5811 meters with a difference between the height above ellipsoid and MSL of about 16.42 meters.

http://www.unavco.org/software/geodetic-utilities/geoid-height-calculator/geoid-height-calculator.html

https://geographiclib.sourceforge.io/cgi-bin/GeoidEval

I’m assuming this difference between the height above the ellipsoid and MSL that these reports say is around 16.42 meters represents the value that should be coming from the “getHeight” function (which is 13.61 meters). Is this correct?

The 45 meter range is what I’m observing when I look at the EGM96 data in QGIS and is consistent with the values from EGM2008. Seems like there’s something wrong with the calculation.
.

The 203.0 feet elevation value I referenced earlier is the highest point of a runway or helipad at the airport, in this case the low end of runway 26L/08R. Remember too, that the EGM96 model is not the same as MSL.

I’m wondering what the “getHeight” function is intended to return…

Is it intended to return an approximation to MSL at the specified location?

Or is it intended to return the difference between the height above the ellipsoid and MSL at the specified location?

Rob,

In your Sandcastle example, you’re passing longitude and latitude in degrees to getHeight. You need to be sure to pass radians. It returns the difference between the EGM96 geoid (an approximation of MSL) and the WGS84 ellipsoid.

Kevin

Hi Kevin,

Passing the location values in the correct units makes a huge difference! Thank you!

So if I’m trying to position a GLTF model (such as a plane) using data containing altitudes in MSL… It sounds like I should add the result of the getHeight function to the MSL altitude value in order to position the object in Cesium. Is this correct?

Rob

Yep, Cesium heights are (almost) always relative to the WGS84 ellipsoid. So if your plane is flying at a certain height above mean sea level, add the result of EarthGravityModel1996.getHeight at that position to your MSL height to get a WGS84 height, and give the WGS84 height to Cesium.

Thanks, Kevin!

Kevin and/or Scott,

Do you know if anything has changed related to the use of the EGM96.getHeight function? I’m using the same WW15MGH.DAC file and the same code, but I am getting drastically different results.

The file seems to be loading fine, and I the results change when calling getHeight different locations.

If I called getHeight for the coordinates referenced in this issue: SampleTerrainDetailed return an incorrect altitude · Issue #8414 · CesiumGS/cesium · GitHub (LON: 139.6072415, LAT: 35.7139224) I’m getting a result of 162.32 meters.

I don’t understand what has changed…

REMOVED: Thought I had figured something out, but was wrong. The results I’m getting are different than before…