Merge pull request #1186 from rudycelekli/contrib/gods-next-36-launch-null-coordinates-20261016

fix(launches): keep null pad and landing coordinates unknown instead of 0
This commit is contained in:
Said Turksever authored and GitHub committed 2026-10-17 17:14:19 +01:00
commit 30976f917e
4 files changed
+48 -9

No files matched your search

@@ -0,0 +1,4 @@
- Keep missing launch-pad coordinates unknown so launches use the location
fallback or stay off the map instead of appearing at 0°N 0°E. Missing stage
flight numbers no longer show "FLIGHT 0"
(Rudy Celekli, @rudycelekli, #1186).
+5
View File
@@ -791,6 +791,11 @@ and `./layers/launches`. Each owns its catalog, render state, tracking, interact
and teardown. Source adapters retain the existing CelesTrak and Launch Library
endpoints; standalone entries provide scene services and the satellite dependency.
The mission factory separates paths, replay, camera, panel, overlays and placement.
Launch Library pad coordinates retain unknown values: missing fields use the
reported location coordinates when available, and launches without a known pad
position stay off the map. Genuine zero coordinates remain valid. Undisclosed
stage coordinates, downrange distance and flight numbers remain unknown; the
mission panel omits the flight-number label when no number was reported.
Pending mission requests abort on disable/destruction and malformed launch
snapshots preserve the last accepted display. Catalog groups, propagation cadence,
tracking intent, replay timing, controls and source attribution remain unchanged.
+31
View File
@@ -677,6 +677,37 @@ test('uses Launch Library 2 pad latitude/longitude fields', () => {
assert.equal(launches[0].lon, -120.611);
});
test('null or blank pad coordinates stay unknown instead of becoming 0', () => {
const base = { net: '2026-07-20T10:00:00Z' };
for (const blank of [null, '', ' ', false]) {
assert.deepEqual(
normalizeRocketLaunches([{ ...base, id: 'blank', pad: { latitude: blank, longitude: blank } }], NOW),
[],
);
}
});
test('null pad coordinates use the location fallback instead of 0,0', () => {
const base = { net: '2026-07-20T10:00:00Z' };
const [fallback] = normalizeRocketLaunches([{ ...base, id: 'fallback',
pad: { latitude: null, longitude: null, location: { coordinates: '-80.6,28.6' } } }], NOW);
assert.equal(fallback.lat, 28.6);
assert.equal(fallback.lon, -80.6);
});
test('an undisclosed landing keeps top-level position and stage numbers unknown', () => {
const base = { net: '2026-07-20T10:00:00Z' };
const [launch] = normalizeRocketLaunches([{ ...base, id: 'landing', pad: { latitude: 1, longitude: 2 },
rocket: { launcher_stage: [{ launcher_flight_number: null,
landing: { attempt: true, latitude: null, longitude: null, downrange_distance: null,
landing_location: { latitude: null, longitude: null } } }] } }], NOW);
const [stage] = launch.recoveryStages;
assert.equal(stage.lat, null);
assert.equal(stage.lon, null);
assert.equal(stage.downrangeKm, null);
assert.equal(stage.flightNumber, null);
});
test('normalizes detailed payload and stage recovery records', () => {
const launches = normalizeRocketLaunches({ results: [{
id: 'recovery-details',
+8 -9
View File
@@ -10,6 +10,9 @@ export const UNKNOWN_LAUNCH_STATUS = msg('Unknown');
export function createModel({ state: layerState, services, parts, source }) {
function finiteCoordinate(value) {
// Number(null), Number('') and Number(false) are 0: absent is not zero.
if (value == null || typeof value === 'boolean') return null;
if (typeof value === 'string' && value.trim() === '') return null;
const number = Number(value);
return Number.isFinite(number) ? number : null;
}
@@ -184,15 +187,11 @@ export function createModel({ state: layerState, services, parts, source }) {
const pad = launch.pad || {};
const location = pad.location || {};
const coordinates = location.coordinates || '';
const [coordinateLon, coordinateLat] = String(coordinates)
.split(',')
.map(Number);
const lat = Number.isFinite(Number(pad.latitude))
? Number(pad.latitude)
: coordinateLat;
const lon = Number.isFinite(Number(pad.longitude))
? Number(pad.longitude)
: coordinateLon;
const [coordinateLon, coordinateLat] = String(coordinates).split(',');
const lat =
finiteCoordinate(pad.latitude) ?? finiteCoordinate(coordinateLat);
const lon =
finiteCoordinate(pad.longitude) ?? finiteCoordinate(coordinateLon);
const payloads = normalizePayloadFlights(launch);
return {
id: String(