diff --git a/src/layers/weather/shellRendering.js b/src/layers/weather/shellRendering.js index b20a3711a..bff4705ae 100644 --- a/src/layers/weather/shellRendering.js +++ b/src/layers/weather/shellRendering.js @@ -2,6 +2,7 @@ import { acquireWeatherImage } from './infraredImage.js'; import { imageryHostStatus } from './imageryHost.js'; import { WEATHER_DETAIL_SIZE, WEATHER_IMAGE_SIZES } from './source.js'; import { msg } from '../../i18n/index.js'; +import * as geo from '../../geo/index.js'; /** Metres above the ellipsoid. Lower shells draw first, so lightning draws last. */ export const WEATHER_SHELL_HEIGHTS = Object.freeze({ @@ -317,7 +318,8 @@ export function createShellSurface({ } function fitTexture(cesium, { width, height }) { - const limit = cesium.ContextLimits?.maximumTextureSize; + // Cesium's limit once its context exists; a Navara shell has no SDK. + const limit = cesium?.ContextLimits?.maximumTextureSize; // Halve, down to 1024 px wide, on devices with a smaller texture limit. while (limit > 0 && width > limit && width > 1024) { width /= 2; @@ -574,7 +576,7 @@ export function createWeatherShell({ /** Recompute the window from the camera's ground footprint; returns whether it changed. */ function computeView() { const rectangle = detailed ? viewRectangle() : null; - const degrees = cesium.Math.toDegrees; + const degrees = geo.math.toDegrees; const footprint = rectangle && { west: degrees(rectangle.west), south: degrees(rectangle.south), @@ -688,7 +690,15 @@ export function createWeatherShell({ viewer, cesium, height, - rectangle: cesium.Rectangle.fromDegrees(west, south, east, north), + // A Navara surface reads the four radians; Cesium gets its Rectangle. + rectangle: cesium + ? cesium.Rectangle.fromDegrees(west, south, east, north) + : { + west: geo.math.toRadians(west), + south: geo.math.toRadians(south), + east: geo.math.toRadians(east), + north: geo.math.toRadians(north), + }, onSettled: () => commit(frame), }); next.bounds = frame.bounds; diff --git a/src/layers/weather/shellRendering.test.mjs b/src/layers/weather/shellRendering.test.mjs index ad65dcef2..e56a57c5f 100644 --- a/src/layers/weather/shellRendering.test.mjs +++ b/src/layers/weather/shellRendering.test.mjs @@ -1502,3 +1502,42 @@ test('global infrared keeps one full-extent image; detail images halve for small }); small.shell.clear(); }); + +test('a Navara shell runs without the Cesium SDK and hands its surface the extent in radians', async () => { + const surfaces = []; + const shell = createWeatherShell({ + product: 'radar', + viewRectangle: () => ({ west: -1.8, south: 0.5, east: -1.6, north: 0.6 }), + moveEnd: { addEventListener: () => () => {} }, + requestRender: () => {}, + fetchImpl: async () => response(), + decodeImage: async () => ({ + width: 4096, + height: 2048, + close() {}, + }), + createCanvas: canvas, + createSurface: (options) => { + surfaces.push(options); + return { + setAlpha() {}, + setImage() {}, + setWindow() {}, + setDetail() {}, + setHidden() {}, + destroy() {}, + }; + }, + }); + shell.setFrame(snapshot('radar'), '2026-11-04T12:00:00Z'); + await flush(); + assert.equal(surfaces.length, 1); + assert.equal(surfaces[0].cesium, undefined); + const { bounds } = snapshot('radar'); + for (const side of ['west', 'south', 'east', 'north']) + assert.equal( + surfaces[0].rectangle[side], + Cesium.Math.toRadians(bounds[side]), + ); + shell.clear(); +});