mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
Cesium's default Tycho-2 sky box is six 1024² JPEGs stretched 3–6× around the whole-globe view, so space read as an over-compressed JPEG (HAL-627). The scene now draws its own sky in the Scene#skyBox slot: the 9,096 stars of the Yale Bright Star Catalogue as point sprites sized in CSS pixels (magnitude → width and opacity, B−V → colour), over a soft, star-free Milky Way cube map built from ESO/S. Brunier's panorama (CC BY 4.0). Both layers share one ICRF→Earth-fixed rotation at the scene clock, with the TEME rotation filling in until Cesium's IAU 2006 tables load. Assets total 482 KB, built by scripts/build-bright-stars.mjs and scripts/build-milky-way.mjs. Frame time and the idle render governor are unchanged. Co-Authored-By: Claude Opus 5.5 <[email protected]>
159 lines
5.1 KiB
JavaScript
159 lines
5.1 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* Build src/data/local_data/sky/bright_stars.json from the Yale Bright Star
|
||
* Catalogue, 5th Revised Edition (Hoffleit & Warren 1991).
|
||
*
|
||
* Source: CDS VizieR catalogue V/50, https://cdsarc.cds.unistra.fr/viz-bin/cat/V/50
|
||
* Fetched: https://cdsarc.cds.unistra.fr/ftp/V/50/catalog.gz
|
||
* Format: fixed-width ASCII, 197 bytes per record, byte layout in
|
||
* https://cdsarc.cds.unistra.fr/ftp/V/50/ReadMe
|
||
* License: public domain (Yale University Observatory / NASA ADC); CDS asks
|
||
* for an acknowledgement, which DATA_SOURCES.md carries.
|
||
*
|
||
* Transform (deterministic):
|
||
* 1. J2000 RA/Dec (bytes 76-90), V magnitude (103-107) and B−V (110-114).
|
||
* 2. The 14 records without a J2000 position (novae and other objects later
|
||
* found not to be stars) are dropped.
|
||
* 3. RA/Dec rounded to 3 decimals of a degree (3.6″ — a fraction of a pixel
|
||
* at any field of view the globe uses), magnitudes to 2.
|
||
* 4. Missing B−V is stored as null; the renderer gives it a neutral colour.
|
||
* 5. Records keep catalogue (HR) order for a stable diff.
|
||
*
|
||
* Usage:
|
||
* node scripts/build-bright-stars.mjs [catalog | catalog.gz]
|
||
* With no argument it downloads the catalogue from CDS.
|
||
*/
|
||
|
||
import fs from 'node:fs';
|
||
import path from 'node:path';
|
||
import zlib from 'node:zlib';
|
||
import { fileURLToPath } from 'node:url';
|
||
|
||
const SOURCE_URL = 'https://cdsarc.cds.unistra.fr/ftp/V/50/catalog.gz';
|
||
const OUT = path.join(
|
||
path.dirname(fileURLToPath(import.meta.url)),
|
||
'..',
|
||
'src',
|
||
'data',
|
||
'local_data',
|
||
'sky',
|
||
'bright_stars.json',
|
||
);
|
||
|
||
/** Slice 1-based inclusive byte columns the way the CDS ReadMe numbers them. */
|
||
function columns(line, from, to) {
|
||
return line.slice(from - 1, to).trim();
|
||
}
|
||
|
||
/** Parse a fixed-width float; blank fields are null. */
|
||
function parseField(text) {
|
||
if (text === '') return null;
|
||
const value = Number(text);
|
||
return Number.isFinite(value) ? value : null;
|
||
}
|
||
|
||
/**
|
||
* Parse one BSC5 record. Returns null for records without a J2000 position
|
||
* or V magnitude.
|
||
*/
|
||
export function parseBscRecord(line) {
|
||
const hr = parseField(columns(line, 1, 4));
|
||
const raH = parseField(columns(line, 76, 77));
|
||
const raM = parseField(columns(line, 78, 79));
|
||
const raS = parseField(columns(line, 80, 83));
|
||
const sign = columns(line, 84, 84);
|
||
const deD = parseField(columns(line, 85, 86));
|
||
const deM = parseField(columns(line, 87, 88));
|
||
const deS = parseField(columns(line, 89, 90));
|
||
const vmag = parseField(columns(line, 103, 107));
|
||
const bv = parseField(columns(line, 110, 114));
|
||
if (
|
||
hr === null ||
|
||
raH === null ||
|
||
raM === null ||
|
||
raS === null ||
|
||
deD === null ||
|
||
deM === null ||
|
||
deS === null ||
|
||
vmag === null ||
|
||
(sign !== '+' && sign !== '-')
|
||
)
|
||
return null;
|
||
const raDeg = (raH + raM / 60 + raS / 3600) * 15;
|
||
const decDeg = (sign === '-' ? -1 : 1) * (deD + deM / 60 + deS / 3600);
|
||
return { hr, raDeg, decDeg, vmag, bv };
|
||
}
|
||
|
||
const round = (value, decimals) => {
|
||
const scale = 10 ** decimals;
|
||
return Math.round(value * scale) / scale;
|
||
};
|
||
|
||
/** Build the committed pack from the raw catalogue text. */
|
||
export function buildStarPack(text, { fetched = null } = {}) {
|
||
const stars = [];
|
||
let dropped = 0;
|
||
for (const line of text.split('\n')) {
|
||
if (line.trim() === '') continue;
|
||
const record = parseBscRecord(line);
|
||
if (!record) {
|
||
dropped += 1;
|
||
continue;
|
||
}
|
||
stars.push(
|
||
round(record.raDeg, 3),
|
||
round(record.decDeg, 3),
|
||
round(record.vmag, 2),
|
||
record.bv === null ? null : round(record.bv, 2),
|
||
);
|
||
}
|
||
return {
|
||
meta: {
|
||
source:
|
||
'Yale Bright Star Catalogue, 5th Revised Ed. (Hoffleit & Warren 1991), CDS V/50',
|
||
url: SOURCE_URL,
|
||
license: 'public domain',
|
||
fetched,
|
||
frame: 'ICRF/J2000, epoch 2000.0',
|
||
columns: ['raDeg', 'decDeg', 'vmag', 'bv'],
|
||
count: stars.length / 4,
|
||
dropped,
|
||
},
|
||
stars,
|
||
};
|
||
}
|
||
|
||
async function readCatalogue(file) {
|
||
if (!file) {
|
||
const response = await fetch(SOURCE_URL);
|
||
if (!response.ok) throw new Error(`${SOURCE_URL}: HTTP ${response.status}`);
|
||
return zlib
|
||
.gunzipSync(Buffer.from(await response.arrayBuffer()))
|
||
.toString('latin1');
|
||
}
|
||
const bytes = fs.readFileSync(file);
|
||
return (file.endsWith('.gz') ? zlib.gunzipSync(bytes) : bytes).toString(
|
||
'latin1',
|
||
);
|
||
}
|
||
|
||
async function main() {
|
||
const [file] = process.argv.slice(2);
|
||
const text = await readCatalogue(file);
|
||
const pack = buildStarPack(text, {
|
||
fetched: new Date().toISOString().slice(0, 10),
|
||
});
|
||
// One star per line keeps the JSON compact and the diff readable.
|
||
const rows = [];
|
||
for (let i = 0; i < pack.stars.length; i += 4)
|
||
rows.push(JSON.stringify(pack.stars.slice(i, i + 4)).slice(1, -1));
|
||
const body = `{"meta":${JSON.stringify(pack.meta)},\n"stars":[\n${rows.join(',\n')}\n]}\n`;
|
||
fs.mkdirSync(path.dirname(OUT), { recursive: true });
|
||
fs.writeFileSync(OUT, body);
|
||
console.log(
|
||
`wrote ${pack.meta.count} stars (${pack.meta.dropped} dropped) → ${path.relative(process.cwd(), OUT)} (${body.length} bytes)`,
|
||
);
|
||
}
|
||
|
||
if (process.argv[1] === fileURLToPath(import.meta.url)) await main();
|