What Is Geoid Undulation and How Is It Used for Altitude Display in Gods-Eye-View
Geoid undulation represents the vertical separation between the WGS-84 reference ellipsoid and Earth's mean sea level geoid, and the Gods-Eye-View application uses this value to convert raw ellipsoidal heights from Cesium into intuitive orthometric altitudes displayed on the HUD.
In the bilawalsidhu/gods-eye-view repository, accurate altitude visualization is critical for realistic flight and terrain tracking. Because Cesium renders positions relative to the mathematical WGS-84 ellipsoid while real-world aviators reference mean sea level (MSL), the codebase implements geoid undulation correction to bridge this gap. This ensures that all altitude readouts reflect physical elevation rather than abstract geometric coordinates.
Understanding Geoid Undulation
The Ellipsoid-Geoid Separation
The geoid is the equipotential surface of Earth's gravity field that coincides with mean sea level. The WGS-84 ellipsoid is a simplified mathematical model of Earth's shape. The vertical difference between these surfaces is the geoid undulation (N), which varies globally from approximately -106 m to +85 m.
Mathematical Foundation
The relationship between ellipsoidal height (h), orthometric height (H) (height above MSL), and geoid undulation (N) follows the formula:
h = H + N
Therefore, to display altitude above mean sea level:
H = h - N
Gods-Eye-View applies this conversion in real-time to ensure the HUD presents orthometric altitudes that match real-world elevation references.
Architecture of Geoid Correction in Gods-Eye-View
The implementation spans two primary modules: the geoid data service and the HUD rendering component.
Lazy Loading the EGM96 Grid in geoid.js
The module src/data/geoid.js manages the Earth Gravitational Model 1996 (EGM96) dataset via the egm96-universal npm package. It exposes ensureGeoidReady() for asynchronous initialization and geoidHeight(latDeg, lonDeg) to query specific undulation values.
According to the source code at lines 33-40 and 50-57, the implementation lazily loads the geoid grid and computes the mean sea level offset:
// src/data/geoid.js – computes N
export async function ensureGeoidReady() {
// lazy load implementation
}
export function geoidHeight(latDeg, lonDeg) {
if (!egm96Module) {
throw new Error('geoid.js: geoidHeight() called before ensureGeoidReady() resolved …');
}
return egm96Module.meanSeaLevel(latDeg, lonDeg);
}
This asynchronous pattern prevents blocking the main thread during application startup while ensuring the geoid grid is available before altitude calculations commence.
HUD Integration and Caching in hud.js
The heads-up display in src/hud.js applies geoid correction to camera telemetry before rendering. As implemented in lines 334-342, the component queries the geoid undulation for the current camera sub-point and converts the raw ellipsoidal altitude to MSL:
// src/hud.js – altitude display logic
const geoidN = this._geoidUndulationM(latDeg, lonDeg); // N
const altMslM = ellipsoidalToMslDisplayM(altM, geoidN); // H = h – N
altEl.textContent = `ALT: ${Math.round(altMslM)}m …`;
To optimize performance during flight visualization, the HUD implements a coarse-cell caching strategy. The _geoidUndulationM method rounds latitude and longitude to 0.25-degree increments, storing the result in this._geoidN until the camera moves to a new cell. This minimizes redundant calculations while maintaining centimeter-level accuracy across the viewport.
Practical Code Examples
Computing Geoid Undulation for Any Coordinate
To obtain the geoid undulation value for a specific latitude and longitude:
import { ensureGeoidReady, geoidHeight } from './data/geoid.js';
async function getGeoidUndulation(lat, lon) {
await ensureGeoidReady(); // load EGM96 grid if not already loaded
return geoidHeight(lat, lon); // N in metres
}
// Usage
getGeoidUndulation(37.6189, -122.3750).then(N => {
console.log(`Geoid undulation at SFO: ${N.toFixed(2)} m`);
});
Converting Ellipsoidal Height to MSL
For converting raw GPS or Cesium ellipsoidal heights to orthometric display values:
import { ellipsoidalToMslDisplayM } from './data/geoid.js';
function displayAltitude(ellipsoidalHeight, lat, lon) {
const N = geoidHeight(lat, lon); // assume geoid already ready
const mslHeight = ellipsoidalToMslDisplayM(ellipsoidalHeight, N);
console.log(`Altitude above MSL: ${Math.round(mslHeight)} m`);
}
// Example with a camera at 200 m ellipsoidal height over San Francisco
displayAltitude(200, 37.6189, -122.3750);
Integrating with the Heads-Up Display
The following pattern demonstrates how the HUD class implements the correction with caching:
// Inside HUD class
_geoidUndulationM(lat, lon) {
if (!this._geoidReady) { /* trigger lazy load */ }
const key = `${Math.round(lat / 0.25)}:${Math.round(lon / 0.25)}`;
if (key !== this._geoidCellKey) {
this._geoidN = geoidHeight(lat, lon);
this._geoidCellKey = key;
}
return this._geoidN;
}
_updateCameraData() {
const altEllipsoidal = camera.positionCartographic.height;
const N = this._geoidUndulationM(lat, lon);
const altMSL = ellipsoidalToMslDisplayM(altEllipsoidal, N);
hudAltElement.textContent = `ALT: ${Math.round(altMSL)}m`;
}
This implementation ensures that geoidHeight is called only when the camera enters a new 0.25-degree grid cell, reducing computational overhead during continuous flight visualization.
Summary
- Geoid undulation quantifies the difference between the WGS-84 ellipsoid and mean sea level, ranging from approximately -106 m to +85 m globally.
- The
src/data/geoid.jsmodule lazily loads the EGM96 geoid grid viaegm96-universaland provides thegeoidHeight()function to query undulation values at specific coordinates. src/hud.jsapplies this correction usingellipsoidalToMslDisplayM()to convert Cesium's ellipsoidal heights into orthometric (MSL) altitudes for display.- The HUD implements a coarse-grid caching mechanism to optimize performance, recalculating undulation only when the camera moves into a new 0.25-degree latitude/longitude cell.
- Additional modules such as
src/data/terrainHeights.jsandsrc/data/militaryFlights.jsutilize the same geoid correction system to maintain consistency across all altitude representations.
Frequently Asked Questions
What is the difference between ellipsoidal and orthometric altitude?
Ellipsoidal altitude measures height above the mathematical WGS-84 ellipsoid, which is a smooth geometric approximation of Earth's shape. Orthometric altitude measures height above the geoid (mean sea level), representing the physical surface of the ocean extended through the continents. The difference between these two values at any given point is the geoid undulation.
How does Gods-Eye-View handle geoid data loading?
The repository implements a lazy-loading pattern in src/data/geoid.js. The ensureGeoidReady() function asynchronously initializes the EGM96 model only when first requested, preventing startup delays. Once loaded, geoidHeight() performs synchronous lookups on the geoid grid, enabling real-time altitude corrections without blocking the rendering loop.
Why is geoid undulation correction necessary for flight visualization?
Without geoid correction, altitude displays would reference the abstract WGS-84 ellipsoid rather than mean sea level. This creates significant errors in mountainous regions where geoid undulation exceeds 50 meters. Pilots and aviation systems universally reference MSL for terrain clearance and flight planning, making geoid correction essential for realistic flight tracking and terrain visualization in Gods-Eye-View.
What is the typical range of geoid undulation values?
According to the EGM96 model implementation in the repository, geoid undulation values typically range from -106 meters (where the geoid is below the ellipsoid) to +85 meters (where the geoid is above the ellipsoid). This variation depends on local gravitational anomalies and Earth's irregular mass distribution.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →