import { CaptureArgs } from '../core/widgets/Capture'; export interface CesiumCaptureSourceOptions { /** * Container element to host the hidden Cesium viewer. * If not provided, one is auto-created and appended to document.body. */ container?: HTMLElement; /** Cesium Ion default access token for imagery/terrain tiles */ accessToken?: string; /** * Imagery provider URL template. Falls back to Cesium Ion default * when not specified and an accessToken is provided. */ imageryUrl?: string; /** Enable terrain (requires Cesium Ion token). Default: false */ terrain?: boolean; /** Maximum cached tile count (higher = more memory, fewer re-downloads). Default: 100 */ maximumCachedTiles?: number; /** * Called during capture while waiting for tiles to load. * Receives elapsed milliseconds so the caller can show a progress indicator. */ onTileLoadProgress?: (elapsedMs: number) => void; /** Max milliseconds to wait for tile loading per capture. Default: 10000 */ tileLoadTimeoutMs?: number; /** * Use OpenStreetMap raster tiles (no Cesium Ion token required). * Strongly recommended for local dev and Storybook; default is true. * Set false to keep the Viewer default imagery (typically Cesium Ion / Bing — needs `accessToken`). */ useOpenStreetMapImagery?: boolean; } export interface CesiumCaptureSourceHandle { /** Render a globe image from the given camera parameters. Pass as Capture's imageSource. */ capture: (args: CaptureArgs) => Promise; /** Tear down the Cesium viewer, remove the hidden container, release WebGL context. */ destroy: () => void; /** Whether the viewer is initialized and ready to render. */ readonly ready: boolean; } /** * Convert ECEF meters (Unreal / game-engine format) to SDK's ECI-like km format. * * ECEF (Earth-Centered Earth-Fixed): X→0°N 0°E, Y→0°N 90°E, Z→North Pole (meters) * SDK (ECI-like): X/Z→equatorial plane, Y→North Pole (km) * * Axis mapping: SDK.x = ECEF.x / 1000 * SDK.y = ECEF.z / 1000 (ECEF Z=north → SDK Y=north) * SDK.z = ECEF.y / 1000 * * Export this so callers (e.g. MQTT handlers) can normalize at the boundary * before passing positions to CaptureArgs. */ export declare function ecefMetersToSdkPosition(ecef: [number, number, number]): [number, number, number]; /** * Convert world-frame Euler XYZ rotation + ECEF position to Cesium HPR (degrees). * * The game engine sends the camera's absolute orientation as Euler 1-2-3 * (XYZ intrinsic, right-handed, X=right Y=forward Z=up) in the ECEF world frame. * Cesium's heading/pitch/roll are relative to the local ENU (East-North-Up) frame * at the camera's geographic position, so we must: * * 1. Build the rotation matrix R from Euler XYZ (camera axes in ECEF) * 2. Extract the camera's forward (+Y) and up (+Z) vectors in ECEF * 3. Compute the ECEF→ENU rotation matrix at the camera's lat/lon * 4. Transform forward/up into the ENU frame * 5. Extract heading, pitch, roll from those ENU vectors * * @param ecefPos Camera position in ECEF meters [x, y, z] * @param eulerDeg Euler XYZ rotation in degrees [rx, ry, rz] * @returns [heading, pitch, roll] in degrees (Cesium convention) */ export declare function ecefEulerXyzToHpr(ecefPos: [number, number, number], eulerDeg: [number, number, number]): [number, number, number]; /** * Convert local-frame Euler XYZ intrinsic rotation (right-handed, degrees) * to Cesium heading/pitch/roll (degrees). * * Use this when the rotation is already relative to a local frame aligned with * ENU (e.g. manual test inputs). For world-frame ECEF rotations from Unreal, * use `ecefEulerXyzToHpr` instead — it accounts for the ENU frame at the * camera's geographic position. * * Euler XYZ: rotation[0] around X, [1] around Y, [2] around Z. * Decomposed into Cesium HPR via the rotation matrix R = Rz·Ry·Rx. */ export declare function eulerXyzToHpr(eulerDeg: [number, number, number]): [number, number, number]; /** * Compute depth-of-field blur radius in CSS pixels using the thin lens model. * * Thin lens circle of confusion (CoC) diameter: * c = |f²/N × (S - D) / (D × (S - f))| * * where: * f = focal length (mm) * N = f-number (aperture) * S = focusing distance (mm) — the plane in sharp focus * D = subject distance (mm) — actual distance to the scene * * The CoC diameter is converted to pixels via pixel_pitch, then halved to * get a blur radius. The result is clamped by the sensor's maximum * acceptable CoC (args.coc) to model physical diffraction limits. * * Returns 0 when the scene is in acceptable focus (blur < 0.5px). * Exported for unit testing. */ export declare function computeDofBlurPx(args: CaptureArgs, subjectDistanceM: number): number; /** * Creates a reusable CesiumJS capture source backed by a hidden viewer. * * The viewer is initialized once with `preserveDrawingBuffer: true` so * canvas pixels survive after `scene.render()`. All Cesium UI widgets * are disabled. The container is positioned off-screen (1x1 px) and * resized to the requested resolution on each capture. * * @param options - Configuration for the hidden viewer * @returns Handle with `capture(args)`, `destroy()`, and `ready` flag */ export declare function createCesiumCaptureSource(options?: CesiumCaptureSourceOptions): Promise;