How to Calculate Off‑Nadir Angle from Camera Pitch in CesiumJS
To calculate the off‑nadir angle in CesiumJS, convert the camera pitch from radians to degrees, add 90°, and clamp the result to a minimum of 0°, mapping a pitch of ‑90° (nadir) to 0° off‑nadir and 0° pitch to 90° off‑nadir.
The gods‑eye‑view repository demonstrates how to derive precise sensor telemetry from CesiumJS camera states, including the transformation of camera pitch into the off‑nadir angle required for aerial imaging metadata. Understanding how to calculate off‑nadir angle from camera pitch in CesiumJS enables accurate ground‑sample distance estimates and sensor orientation displays in geospatial visualization tools.
Understanding CesiumJS Camera Pitch Conventions
In CesiumJS, the camera pitch follows the right‑hand rule within the local east‑north‑up frame. A pitch of ‑90° indicates the camera is pointing straight down toward the Earth’s center (the nadir direction), while a pitch of 0° orients the camera toward the horizon. Positive pitch values tilt the camera above the horizon toward the zenith.
This convention means the pitch value represents an angular offset from the horizontal plane, where negative values look downward. The off‑nadir angle (ONA) represents the deviation from vertical, requiring a transformation to convert the Cesium pitch to a standard 0°–90° sensor angle used in photogrammetry.
The Off‑Nadir Angle Formula
The conversion from CesiumJS pitch to off‑nadir angle follows a three‑step arithmetic process:
- Retrieve the pitch from
camera.pitch, which is stored in radians. - Convert to degrees using
Cesium.Math.toDegrees()to obtain a signed decimal value. - Add 90° and clamp the result with
Math.max(0, 90 + pitchDeg)to ensure the angle never drops below 0°.
This calculation maps the camera’s orientation to the standard off‑nadir definition: 0° ONA when looking straight down and 90° ONA at the horizon. The clamp ensures that if the camera pitch momentarily registers less than ‑90° (beyond straight down), the result floors at 0° rather than returning a negative value.
Implementation in the Gods Eye View HUD
According to the bilawalsidhu/gods-eye-view source code, the logic resides in src/hud.js within the IntelHUD._updateCameraData method. This method executes each frame to update the heads‑up display telemetry, retrieving the camera pitch, applying the conversion formula, and injecting the formatted result into the DOM:
// src/hud.js – lines 54‑60
const pitchDeg = Cesium.Math.toDegrees(camera.pitch);
const ona = Math.max(0, 90 + pitchDeg);
const onaEl = document.getElementById('hud-ona');
if (onaEl) onaEl.textContent = `ONA: ${ona.toFixed(1)}°`;
This code runs inside the HUD’s update loop, ensuring the off‑nadir angle displayed alongside GSD (Ground Sample Distance) and NIIRS ratings remains synchronized with the current camera orientation.
Practical Code Examples
Stand‑Alone Calculation
For custom geospatial tools that need to compute the off‑nadir angle without the full HUD, extract the pitch from the viewer’s camera and apply the same transformation used in the gods‑eye‑view repository:
// Compute off‑nadir angle from Cesium camera pitch
function computeOffNadir(camera) {
const pitchDeg = Cesium.Math.toDegrees(camera.pitch); // e.g., -30°
const offNadir = Math.max(0, 90 + pitchDeg); // → 60°
return offNadir;
}
// Usage with a Cesium viewer instance
const ona = computeOffNadir(viewer.camera);
console.log(`Off‑nadir angle: ${ona.toFixed(1)}°`);
Integrating into a Custom HUD
To display the ONA in a custom interface that updates every frame, register a callback with the scene’s post‑render event and format the output for your UI elements:
function updateHUD() {
const pitchDeg = Cesium.Math.toDegrees(viewer.camera.pitch);
const offNadir = Math.max(0, 90 + pitchDeg);
document.getElementById('my-ona').textContent = `ONA: ${offNadir.toFixed(1)}°`;
}
// Update once per render loop
viewer.scene.postRender.addEventListener(updateHUD);
Both snippets follow the arithmetic defined in src/hud.js, ensuring consistency with the built‑in telemetry display.
Summary
- CesiumJS pitch uses radians where ‑90° is nadir (straight down) and 0° is the horizon.
- Off‑nadir angle is calculated by adding 90° to the pitch (in degrees) and clamping to 0° minimum.
- The implementation resides in
src/hud.jsinside theIntelHUD._updateCameraDatamethod. - Use
Cesium.Math.toDegrees()to convert from radians before applying the offset. - Clamp with
Math.max(0, ...)to prevent negative angles when the camera pitch exceeds ‑90°.
Frequently Asked Questions
What is the off‑nadir angle in CesiumJS aerial mapping?
The off‑nadir angle (ONA) is the angular deviation between the camera’s optical axis and the vertical (nadir) direction. In aerial mapping workflows using CesiumJS, this angle determines the tilt of the sensor relative to the ground, directly affecting ground coverage and image distortion calculations.
Why add 90 degrees to the camera pitch?
CesiumJS defines 0° pitch as the horizon and ‑90° pitch as straight down (nadir). Since off‑nadir angle is defined as 0° when looking straight down and 90° at the horizon, adding 90° to the Cesium pitch value reconciles these coordinate systems. For example, a pitch of ‑45° becomes 45° off‑nadir.
Where is the ONA calculation implemented in the gods‑eye‑view repository?
The calculation is implemented in src/hud.js within the IntelHUD._updateCameraData method (lines 54‑60). This method reads camera.pitch, converts it to degrees using Cesium.Math.toDegrees, computes the off‑nadir value, and updates the DOM element with ID hud-ona to display the telemetry.
Why is the off‑nadir angle clamped to 0°?
The Math.max(0, ...) clamp prevents negative off‑nadir angles when the camera pitch drops below ‑90° (beyond straight down), which can occur during rapid camera animations or specific orientation constraints. While pitch values above the horizon produce results greater than 90°, the clamp ensures the minimum value remains 0° for all downward‑looking orientations.
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 →