import { describe, it, expect } from 'vitest'; import { inverseLogScale, logScale } from '../src/scene/layout.js'; describe('camera log-scale', () => { it('inverseLogScale undoes logScale', () => { for (const t of [-3, 0, 4, 8, 12]) { expect(inverseLogScale(logScale(t))).toBeCloseTo(t, 6); } }); it('produces distances spanning the KSP system', () => { // t = 0: 1e8 m = 100 Mm (close zoom) expect(logScale(0)).toBeCloseTo(1e8, -3); // t = 4: ~5.5e9 m (Kerbin at 13.6 Gm is just outside) expect(logScale(4)).toBeGreaterThan(1e9); // t = 10: ~22e12 m (Eeloo at 90 Gm is well inside) expect(logScale(10)).toBeGreaterThan(1e10); // t = 12: ~1.6e13 m (max zoom) expect(logScale(12)).toBeGreaterThan(1e12); }); }); describe('spherical math (used by camera)', () => { // The camera controller uses spherical coords. Test the // cartesian conversion (extracted for testability). function sphericalToCartesian(distance: number, az: number, el: number) { const sinE = Math.sin(el); const cosE = Math.cos(el); const sinA = Math.sin(az); const cosA = Math.cos(az); return { x: distance * cosE * sinA, y: distance * sinE, z: distance * cosE * cosA, }; } it('produces a point on the sphere of given radius', () => { for (const az of [0, 1, 2.5, 4.7]) { for (const el of [-0.5, 0, 0.7]) { const p = sphericalToCartesian(1e10, az, el); const d = Math.hypot(p.x, p.y, p.z); expect(d).toBeCloseTo(1e10, 4); } } }); it('azimuth=0, elevation=0 produces +Z vector', () => { const p = sphericalToCartesian(100, 0, 0); expect(p.z).toBeCloseTo(100, 6); expect(p.x).toBeCloseTo(0, 6); expect(p.y).toBeCloseTo(0, 6); }); it('azimuth=π/2, elevation=0 produces +X vector', () => { const p = sphericalToCartesian(100, Math.PI / 2, 0); expect(p.x).toBeCloseTo(100, 6); expect(p.z).toBeCloseTo(0, 6); expect(p.y).toBeCloseTo(0, 6); }); it('elevation=π/2 produces +Y vector', () => { const p = sphericalToCartesian(100, 0, Math.PI / 2); expect(p.y).toBeCloseTo(100, 6); expect(p.x).toBeCloseTo(0, 6); expect(p.z).toBeCloseTo(0, 6); }); });