import type { Location } from "@deadhead/content"; import { content } from "@deadhead/content"; import { locationPosition, type Position } from "@deadhead/sim"; /** * Map coordinates: the Sun at (0, 0), the edge of the map at radius 1, y down. * Real distances are compressed so the inner planets and Jupiter fit together. */ export interface MapPoint { x: number; y: number; } /** Heliocentric radius (million km) shown at the edge of the map. */ export const MAP_EDGE_MILLION_KM = 1000; /** Moons are drawn this far from their planet (map units), whatever the real distance. */ export const MOON_MAP_OFFSET = 0.04; /** * Compressed radial scale: real distance from the Sun (million km) to map * radius. Square root keeps the order (farther stays farther) while bringing * Jupiter (~780M km) within a few times Earth's (~150M km) distance. */ export function radialScale(millionKm: number): number { return Math.sqrt(Math.max(0, millionKm) / MAP_EDGE_MILLION_KM); } /** A heliocentric position on the map: same angle, compressed radius. */ export function toMapPoint(position: Position): MapPoint { const r = Math.hypot(position.x, position.y); if (r === 0) return { x: 0, y: 0 }; const k = radialScale(r) / r; // Screens grow downwards; flip y so orbits run counter-clockwise as seen from above. return { x: position.x * k, y: -position.y * k }; } /** * Where a location is drawn. A child body (the Moon) sits a fixed small * distance from its parent in its true direction, since at map scale it would * overlap it. */ export function locationMapPoint(location: Location): MapPoint { const parentId = location.orbitParent?.locationId; const parent = parentId ? content.location(parentId) : undefined; if (!parent) return toMapPoint(locationPosition(location)); const earth = locationPosition(parent); const moon = locationPosition(location); const dx = moon.x - earth.x; const dy = -(moon.y - earth.y); const length = Math.hypot(dx, dy) || 1; const base = toMapPoint(earth); return { x: base.x + (dx / length) * MOON_MAP_OFFSET, y: base.y + (dy / length) * MOON_MAP_OFFSET, }; }