58 lines
2.1 KiB
TypeScript
58 lines
2.1 KiB
TypeScript
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,
|
|
};
|
|
}
|