Its doc comment promised a fallback to Earth radii that the function has never had. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G
77 lines
3.1 KiB
TypeScript
77 lines
3.1 KiB
TypeScript
/**
|
||
* Formatting for every physical quantity the HUD and the body cards display.
|
||
*
|
||
* Shared rather than per-component so the same measurement reads identically wherever it
|
||
* appears. The rule throughout is that precision follows magnitude — a figure is shown to the
|
||
* digits that carry information at its own scale, not to a fixed decimal count that reads as
|
||
* false precision at one end (`0.00 pc`) and loses real information at the other (`26000 pc`).
|
||
*/
|
||
|
||
/** Distance in parsecs, switching to kiloparsecs where the number would otherwise run long. */
|
||
export function formatParsecs(distancePc: number): string {
|
||
return distancePc >= 1000 ? `${(distancePc / 1000).toFixed(1)} kpc` : `${distancePc.toFixed(distancePc < 10 ? 2 : 0)} pc`;
|
||
}
|
||
|
||
/** Distance in astronomical units, for anything inside a system. */
|
||
export function formatAu(distanceAu: number): string {
|
||
if (distanceAu < 0.01) {
|
||
// Close-in exoplanets: 0.0026 AU is a real, published semi-major axis, and two decimals
|
||
// would round every hot Jupiter in the catalogue to the same `0.00`.
|
||
return `${distanceAu.toFixed(4)} AU`;
|
||
}
|
||
return distanceAu >= 100 ? `${distanceAu.toFixed(0)} AU` : `${distanceAu.toFixed(2)} AU`;
|
||
}
|
||
|
||
/**
|
||
* Orbital period in whichever unit reads naturally at its length — hours for the very short
|
||
* periods common among hot Jupiters, days up to a couple of years, then years.
|
||
*/
|
||
export function formatPeriod(days: number): string {
|
||
if (days < 1) {
|
||
return `${(days * 24).toFixed(1)} h`;
|
||
}
|
||
if (days < 700) {
|
||
return `${days.toFixed(days < 10 ? 2 : 1)} d`;
|
||
}
|
||
return `${(days / 365.25).toFixed(days / 365.25 < 100 ? 1 : 0)} yr`;
|
||
}
|
||
|
||
/** Radius in kilometres. */
|
||
export function formatRadiusKm(radiusKm: number): string {
|
||
// Grouped on both sides of the decimal threshold: 69,911 km beside a bare 6371 km reads as two
|
||
// different conventions rather than one.
|
||
const digits = radiusKm < 100 ? 1 : 0;
|
||
return `${radiusKm.toLocaleString('en-GB', { minimumFractionDigits: digits, maximumFractionDigits: digits })} km`;
|
||
}
|
||
|
||
/** Mass in Earth masses. */
|
||
export function formatMassEarth(massEarth: number): string {
|
||
if (massEarth >= 100) {
|
||
return `${massEarth.toFixed(0)} M⊕`;
|
||
}
|
||
return `${massEarth.toFixed(massEarth < 1 ? 3 : 2)} M⊕`;
|
||
}
|
||
|
||
/** Equilibrium temperature. Always a whole kelvin — the model is not good to a fraction of one. */
|
||
export function formatTemperature(kelvin: number): string {
|
||
return `${Math.round(kelvin)} K`;
|
||
}
|
||
|
||
/** Bulk density. */
|
||
export function formatDensity(gramsPerCm3: number): string {
|
||
return `${gramsPerCm3.toFixed(2)} g/cm³`;
|
||
}
|
||
|
||
/** Bolometric luminosity in solar units, which spans many orders of magnitude. */
|
||
export function formatLuminosity(solar: number): string {
|
||
if (solar >= 1000 || (solar > 0 && solar < 0.001)) {
|
||
const exponent = Math.floor(Math.log10(solar));
|
||
return `${(solar / Math.pow(10, exponent)).toFixed(1)}×10${superscript(exponent)} L☉`;
|
||
}
|
||
return `${solar.toFixed(solar < 1 ? 3 : 2)} L☉`;
|
||
}
|
||
|
||
function superscript(value: number): string {
|
||
return `${value}`.replace('-', '⁻').replace(/\d/g, (digit) => '⁰¹²³⁴⁵⁶⁷⁸⁹'[Number(digit)]);
|
||
}
|