07cc5321d1
CI / Lint, typecheck, test, build (pull_request) Failing after 9s
Calculators (apps/live-map/src/calculators/): - eclipse.ts: findEclipseWindows(bodies, opts) — coarse scan with threshold-crossing detection, bisection to refine start/end, ternary search to find peak. Handles eclipse already in progress at scan-start. Uses sun = parentId===null body. - overpass.ts: findOverpasses(opts) — coarse scan for local distance minima, ternary refinement. Targets: vessel, body, ground station (lat/lon/alt → heliocentric). UI: - panels/CalculatorsPanel.tsx: collapsible bottom-center panel with two tabs. Eclipse form: observer, eclipser, from UT → 3 windows. Overpass form: observer vessel, target kind+id, max dist → 5 passes. - timeFormat.ts: shared KSP-time formatters. Live-map camera polish (apps/live-map/src/scene/): - camera.ts: CameraController — log-scale distance (z→exp(z)*1e8 m, range -3..12), spherical orbit around target, smooth lerp to selected body/vessel. Mouse wheel zooms, drag rotates, click raycasts for track toggle. Pointer-move-distance gate to distinguish click from drag. - glow.ts: additive shader-based atmospheric halo (rim-falloff fragment shader, BackSide) attached as child of body mesh. - layout.ts: bodyPositionAt now returns true heliocentric (walks parent chain); previous version returned parent-relative for non-root children which broke the eclipse calculator. Bug fix: - packages/orbital-math/src/occultation.ts: sign of projection check was inverted. `proj <= 0` correctly returns 0 (occluder behind observer), `proj > 0` triggers eclipse computation. Tests: 28 live-map tests (10 scene + 12 calculator + 6 camera), 45 total across the workspace, all passing.
29 lines
1.1 KiB
TypeScript
29 lines
1.1 KiB
TypeScript
/**
|
|
* KSP time formatting helpers — 1 KSP day = 6 hours, 1 KSP year = 426 days.
|
|
* Source: stock KSP config.
|
|
*/
|
|
|
|
const KSP_DAY_SECONDS = 6 * 3600;
|
|
const KSP_YEAR_DAYS = 426;
|
|
|
|
/** Format a UT value as "Y1 D001 12:34". */
|
|
export function formatKspTime(ut: number): string {
|
|
const totalDays = ut / KSP_DAY_SECONDS;
|
|
const year = Math.floor(totalDays / KSP_YEAR_DAYS) + 1;
|
|
const day = (Math.floor(totalDays) % KSP_YEAR_DAYS) + 1;
|
|
const secondsInDay = ut % KSP_DAY_SECONDS;
|
|
const h = Math.floor(secondsInDay / 3600);
|
|
const m = Math.floor((secondsInDay % 3600) / 60);
|
|
return `Y${year} D${String(day).padStart(3, '0')} ${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
|
|
}
|
|
|
|
/** Format a duration in seconds as a human-readable string. */
|
|
export function formatKspDuration(seconds: number): string {
|
|
const abs = Math.abs(seconds);
|
|
if (abs < 60) return `${Math.floor(abs)}s`;
|
|
if (abs < 3600) return `${Math.floor(abs / 60)}m`;
|
|
if (abs < 86400) return `${(abs / 3600).toFixed(1)}h`;
|
|
if (abs < KSP_YEAR_DAYS * KSP_DAY_SECONDS) return `${(abs / 86400).toFixed(1)}d`;
|
|
return `${(abs / (KSP_YEAR_DAYS * KSP_DAY_SECONDS)).toFixed(1)}y`;
|
|
}
|