From 8aa599b3bf2c1bdc0aedbc733d8b5464fe5f9ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sun, 12 Apr 2026 10:09:22 +0200 Subject: [PATCH] Pionier 10 drin --- public/solarsystem.php | 255 +++++++++++++++++++- scripts/import/import_spacecraft_tracks.php | 9 +- 2 files changed, 260 insertions(+), 4 deletions(-) diff --git a/public/solarsystem.php b/public/solarsystem.php index b87af20..4dae715 100644 --- a/public/solarsystem.php +++ b/public/solarsystem.php @@ -11,6 +11,7 @@ $trackedCometsForJs = []; $voyager1TrackForJs = []; $voyager2TrackForJs = []; $newHorizonsTrackForJs = []; +$pioneer10TrackForJs = []; $pdo = null; $spacecraftOptionsForJs = []; @@ -279,10 +280,12 @@ if ($pdo instanceof PDO) { $voyager1TrackForJs = loadSpacecraftTrackFromDatabase($pdo, 'voyager1'); $voyager2TrackForJs = loadSpacecraftTrackFromDatabase($pdo, 'voyager2'); $newHorizonsTrackForJs = loadSpacecraftTrackFromDatabase($pdo, 'new_horizons'); + $pioneer10TrackForJs = loadSpacecraftTrackFromDatabase($pdo, 'pioneer10'); } catch (Throwable $e) { $voyager1TrackForJs = []; $voyager2TrackForJs = []; $newHorizonsTrackForJs = []; + $pioneer10TrackForJs = []; } } @@ -295,6 +298,9 @@ if ($voyager2TrackForJs !== []) { if ($newHorizonsTrackForJs !== []) { $spacecraftOptionsForJs[] = ['key' => 'new_horizons', 'label' => 'New Horizons']; } +if ($pioneer10TrackForJs !== []) { + $spacecraftOptionsForJs[] = ['key' => 'pioneer10', 'label' => 'Pioneer 10']; +} $pageTitle = 'Sonnensystem - AstroTools'; $bodyClass = 'solarsystem-page'; @@ -498,6 +504,7 @@ const SPACECRAFT_OPTIONS = ; const VOYAGER2_TRACK = ; const NEW_HORIZONS_TRACK = ; +const PIONEER10_TRACK = ; const JUPITER_MIN_VISIBLE_SIZE = 1.42; const MOON_DISPLAY_DISTANCE_MULTIPLIER = 2200; @@ -582,6 +589,8 @@ let voyager2Objects = null; let voyager2LabelElement = null; let newHorizonsObjects = null; let newHorizonsLabelElement = null; +let pioneer10Objects = null; +let pioneer10LabelElement = null; let voyagerModelTemplatePromise = null; let voyagerModelTemplate = null; const planetDynamicsCache = new Map(); @@ -602,6 +611,7 @@ let selectedSpacecraftKeys = spacecraftCheckboxes let focusedVoyager1 = false; let focusedVoyager2 = false; let focusedNewHorizons = false; +let focusedPioneer10 = false; let simDate = new Date(); let lastAnimationTime = performance.now(); let orbitRefreshCursor = 0; @@ -944,6 +954,50 @@ function getNewHorizonsPosition(date) { return null; } +function getPioneer10Position(date) { + if (!Array.isArray(PIONEER10_TRACK) || PIONEER10_TRACK.length === 0) { + return null; + } + + const targetMs = date.getTime(); + if (targetMs <= Number(PIONEER10_TRACK[0].timestampMs)) { + return PIONEER10_TRACK[0]; + } + + const lastIndex = PIONEER10_TRACK.length - 1; + if (targetMs >= Number(PIONEER10_TRACK[lastIndex].timestampMs)) { + return PIONEER10_TRACK[lastIndex]; + } + + for (let index = 0; index < lastIndex; index += 1) { + const left = PIONEER10_TRACK[index]; + const right = PIONEER10_TRACK[index + 1]; + const leftMs = Number(left.timestampMs); + const rightMs = Number(right.timestampMs); + if (targetMs < leftMs || targetMs > rightMs) { + continue; + } + + const span = Math.max(rightMs - leftMs, 1); + const factor = (targetMs - leftMs) / span; + const xAu = Number(left.xAu) + ((Number(right.xAu) - Number(left.xAu)) * factor); + const yAu = Number(left.yAu) + ((Number(right.yAu) - Number(left.yAu)) * factor); + const zAu = Number(left.zAu) + ((Number(right.zAu) - Number(left.zAu)) * factor); + const distanceAu = Math.hypot(xAu, yAu, zAu); + + return { + timestampMs: targetMs, + dateTdb: String(left.dateTdb || ''), + xAu, + yAu, + zAu, + distanceAu, + }; + } + + return null; +} + const MINOR_PLANET_COLOR_PALETTE = [ { line: '#ff6b6b', body: '#ff5a5a', emissive: '#d63b3b' }, { line: '#ff5252', body: '#ff4747', emissive: '#c62828' }, @@ -1203,6 +1257,7 @@ function clearFocus() { focusedVoyager1 = false; focusedVoyager2 = false; focusedNewHorizons = false; + focusedPioneer10 = false; cameraTarget.set(0, 0, 0); camRadiusTarget = camRadius; document.querySelectorAll('.solarsystem-planet-chip').forEach((button) => { @@ -1406,6 +1461,33 @@ function updateNewHorizonsInfoPanel() { document.getElementById('solarInfoType').textContent = 'Raumsonde | JPL Horizons CSV'; } +function updatePioneer10InfoPanel() { + const position = getPioneer10Position(simDate); + if (!position) { + infoPanel.hidden = true; + return; + } + + const earthPosition = getHelioPosition('Earth', simDate); + const earthDistanceAu = Math.hypot( + position.xAu - earthPosition.x, + position.yAu - earthPosition.y, + position.zAu - earthPosition.z + ); + + infoPanel.hidden = false; + document.getElementById('solarInfoName').textContent = 'Pioneer 10'; + document.getElementById('solarInfoName').style.color = '#f3a86f'; + document.getElementById('solarInfoDistanceAu').textContent = `${Number(position.distanceAu).toFixed(3)} AU`; + document.getElementById('solarInfoDistanceKm').textContent = `${(Number(position.distanceAu) * AU_IN_KM).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, '.')} km`; + document.getElementById('solarInfoEarthDistanceAu').textContent = `${earthDistanceAu.toFixed(3)} AU`; + document.getElementById('solarInfoEarthDistanceKm').textContent = `${(earthDistanceAu * AU_IN_KM).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, '.')} km`; + document.getElementById('solarInfoMagnitude').textContent = '--'; + document.getElementById('solarInfoPeriod').textContent = '--'; + document.getElementById('solarInfoAxis').textContent = '--'; + document.getElementById('solarInfoType').textContent = 'Raumsonde | JPL Horizons CSV'; +} + function focusPlanet(key) { focusedPlanetKey = key; focusedMinorPlanetId = null; @@ -1413,6 +1495,7 @@ function focusPlanet(key) { focusedVoyager1 = false; focusedVoyager2 = false; focusedNewHorizons = false; + focusedPioneer10 = false; document.querySelectorAll('.solarsystem-planet-chip').forEach((button) => { button.classList.toggle('is-focused', button.dataset.planet === key); }); @@ -1457,6 +1540,13 @@ function buildLabels() { newHorizonsLabelElement.style.color = '#ff9fd6'; newHorizonsLabelElement.hidden = true; labelsLayer.appendChild(newHorizonsLabelElement); + + pioneer10LabelElement = document.createElement('div'); + pioneer10LabelElement.className = 'solarsystem-planet-label'; + pioneer10LabelElement.textContent = 'Pioneer 10'; + pioneer10LabelElement.style.color = '#f3a86f'; + pioneer10LabelElement.hidden = true; + labelsLayer.appendChild(pioneer10LabelElement); } function ensureVoyager1Objects() { @@ -1722,6 +1812,101 @@ function updateNewHorizonsVisual() { } } +function ensurePioneer10Objects() { + if (pioneer10Objects || !Array.isArray(PIONEER10_TRACK) || PIONEER10_TRACK.length === 0) { + return; + } + + const orbitLine = new THREE.Line( + new THREE.BufferGeometry(), + new THREE.LineBasicMaterial({ + color: new THREE.Color('#f3a86f'), + transparent: true, + opacity: 0.8, + }) + ); + orbitLine.visible = showOrbits; + scene.add(orbitLine); + + const mesh = new THREE.Mesh( + new THREE.SphereGeometry(0.28, 20, 20), + new THREE.MeshStandardMaterial({ + color: new THREE.Color('#f7c49c'), + emissive: new THREE.Color('#bc6a2e'), + emissiveIntensity: 0.45, + roughness: 0.45, + metalness: 0.7, + }) + ); + mesh.userData.baseScale = 1; + mesh.userData.minScaleMultiplier = 1.8; + scene.add(mesh); + + pioneer10Objects = { orbitLine, mesh, labelElement: pioneer10LabelElement }; +} + +function rebuildPioneer10Track() { + ensurePioneer10Objects(); + if (!pioneer10Objects) { + return; + } + + const positions = []; + PIONEER10_TRACK.forEach((entry) => { + const display = toDisplayPosition({ + x: Number(entry.xAu), + y: Number(entry.yAu), + z: Number(entry.zAu), + r: Math.max(Number(entry.distanceAu), 1e-9), + }); + positions.push(display.x, display.y, display.z); + }); + + pioneer10Objects.orbitLine.geometry.dispose(); + pioneer10Objects.orbitLine.geometry = new THREE.BufferGeometry(); + pioneer10Objects.orbitLine.geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); + pioneer10Objects.orbitLine.visible = showOrbits; +} + +function updatePioneer10Visual() { + ensurePioneer10Objects(); + if (!pioneer10Objects) { + return; + } + + if (!isSpacecraftSelected('pioneer10')) { + pioneer10Objects.mesh.visible = false; + pioneer10Objects.orbitLine.visible = false; + if (pioneer10Objects.labelElement) { + pioneer10Objects.labelElement.hidden = true; + } + return; + } + + const position = getPioneer10Position(simDate); + if (!position) { + pioneer10Objects.mesh.visible = false; + pioneer10Objects.orbitLine.visible = false; + if (pioneer10Objects.labelElement) { + pioneer10Objects.labelElement.hidden = true; + } + return; + } + + pioneer10Objects.mesh.visible = true; + pioneer10Objects.mesh.position.copy(toDisplayPosition({ + x: Number(position.xAu), + y: Number(position.yAu), + z: Number(position.zAu), + r: Math.max(Number(position.distanceAu), 1e-9), + })); + pioneer10Objects.orbitLine.visible = showOrbits; + + if (focusedPioneer10) { + updatePioneer10InfoPanel(); + } +} + function syncSpacecraftObjects() { const selectedSpacecraftSet = getSelectedSpacecraftSet(); @@ -1752,6 +1937,15 @@ function syncSpacecraftObjects() { } } + if (pioneer10Objects) { + const isSelected = selectedSpacecraftSet.has('pioneer10'); + pioneer10Objects.mesh.visible = isSelected && pioneer10Objects.mesh.visible; + pioneer10Objects.orbitLine.visible = isSelected && showOrbits && pioneer10Objects.orbitLine.visible; + if (!isSelected && pioneer10Objects.labelElement) { + pioneer10Objects.labelElement.hidden = true; + } + } + if (focusedVoyager1 && !selectedSpacecraftSet.has('voyager1')) { clearFocus(); } @@ -1761,6 +1955,9 @@ function syncSpacecraftObjects() { if (focusedNewHorizons && !selectedSpacecraftSet.has('new_horizons')) { clearFocus(); } + if (focusedPioneer10 && !selectedSpacecraftSet.has('pioneer10')) { + clearFocus(); + } } function ensureMoonObjects() { @@ -2559,6 +2756,10 @@ function updateBodyDisplayScales() { if (newHorizonsObjects && newHorizonsObjects.mesh && newHorizonsObjects.mesh.visible) { applyMinimumDisplayScale(newHorizonsObjects.mesh, 260, 10); } + + if (pioneer10Objects && pioneer10Objects.mesh && pioneer10Objects.mesh.visible) { + applyMinimumDisplayScale(pioneer10Objects.mesh, 260, 10); + } } function updateLabels() { @@ -2684,6 +2885,20 @@ function updateLabels() { } } } + + if (pioneer10Objects && pioneer10LabelElement) { + pioneer10LabelElement.hidden = !showLabels || !pioneer10Objects.mesh.visible; + if (!pioneer10LabelElement.hidden) { + const projectedPioneer10 = pioneer10Objects.mesh.position.clone().project(camera); + if (projectedPioneer10.z > 1) { + pioneer10LabelElement.style.opacity = '0'; + } else { + pioneer10LabelElement.style.opacity = '1'; + pioneer10LabelElement.style.left = `${(projectedPioneer10.x * 0.5 + 0.5) * stageWrap.clientWidth}px`; + pioneer10LabelElement.style.top = `${(-projectedPioneer10.y * 0.5 + 0.5) * stageWrap.clientHeight}px`; + } + } + } } function pickPlanet(clientX, clientY) { @@ -2716,6 +2931,7 @@ function pickPlanet(clientX, clientY) { focusedVoyager1 = false; focusedVoyager2 = false; focusedNewHorizons = false; + focusedPioneer10 = false; document.querySelectorAll('.solarsystem-planet-chip').forEach((button) => { button.classList.remove('is-focused'); }); @@ -2740,6 +2956,7 @@ function pickPlanet(clientX, clientY) { focusedVoyager1 = false; focusedVoyager2 = false; focusedNewHorizons = false; + focusedPioneer10 = false; document.querySelectorAll('.solarsystem-planet-chip').forEach((button) => { button.classList.remove('is-focused'); }); @@ -2758,6 +2975,7 @@ function pickPlanet(clientX, clientY) { focusedVoyager1 = true; focusedVoyager2 = false; focusedNewHorizons = false; + focusedPioneer10 = false; document.querySelectorAll('.solarsystem-planet-chip').forEach((button) => { button.classList.remove('is-focused'); }); @@ -2775,6 +2993,7 @@ function pickPlanet(clientX, clientY) { focusedVoyager1 = false; focusedVoyager2 = true; focusedNewHorizons = false; + focusedPioneer10 = false; document.querySelectorAll('.solarsystem-planet-chip').forEach((button) => { button.classList.remove('is-focused'); }); @@ -2792,6 +3011,7 @@ function pickPlanet(clientX, clientY) { focusedVoyager1 = false; focusedVoyager2 = false; focusedNewHorizons = true; + focusedPioneer10 = false; document.querySelectorAll('.solarsystem-planet-chip').forEach((button) => { button.classList.remove('is-focused'); }); @@ -2800,6 +3020,24 @@ function pickPlanet(clientX, clientY) { } } + if (pioneer10Objects && pioneer10Objects.mesh.visible) { + const pioneer10Hits = raycaster.intersectObject(pioneer10Objects.mesh, true); + if (pioneer10Hits.length > 0) { + focusedPlanetKey = null; + focusedMinorPlanetId = null; + focusedCometId = null; + focusedVoyager1 = false; + focusedVoyager2 = false; + focusedNewHorizons = false; + focusedPioneer10 = true; + document.querySelectorAll('.solarsystem-planet-chip').forEach((button) => { + button.classList.remove('is-focused'); + }); + updatePioneer10InfoPanel(); + return; + } + } + if (hits.length === 0) { clearFocus(); return; @@ -2916,6 +3154,9 @@ function attachUiHandlers() { if (newHorizonsObjects) { newHorizonsObjects.orbitLine.visible = showOrbits; } + if (pioneer10Objects) { + pioneer10Objects.orbitLine.visible = showOrbits; + } if (moonOrbitLine) { moonOrbitLine.visible = showOrbits; } @@ -2966,7 +3207,7 @@ function attachUiHandlers() { }); updateMinorPlanetSummary(); - if (selectedMinorPlanetIds.length === 0 && !focusedPlanetKey && focusedMinorPlanetId === null && focusedCometId === null && !focusedVoyager1 && !focusedVoyager2 && !focusedNewHorizons) { + if (selectedMinorPlanetIds.length === 0 && !focusedPlanetKey && focusedMinorPlanetId === null && focusedCometId === null && !focusedVoyager1 && !focusedVoyager2 && !focusedNewHorizons && !focusedPioneer10) { infoPanel.hidden = true; } }); @@ -2989,7 +3230,7 @@ function attachUiHandlers() { updateCometSummary(); if (selectedCometIds.length === 0 && !focusedPlanetKey && focusedMinorPlanetId === null && focusedCometId === null) { - if (!focusedVoyager1 && !focusedVoyager2 && !focusedNewHorizons) { + if (!focusedVoyager1 && !focusedVoyager2 && !focusedNewHorizons && !focusedPioneer10) { infoPanel.hidden = true; } } @@ -3005,7 +3246,7 @@ function attachUiHandlers() { syncSpacecraftObjects(); updateSpacecraftSummary(); - if (!focusedPlanetKey && focusedMinorPlanetId === null && focusedCometId === null && !focusedVoyager1 && !focusedVoyager2 && !focusedNewHorizons) { + if (!focusedPlanetKey && focusedMinorPlanetId === null && focusedCometId === null && !focusedVoyager1 && !focusedVoyager2 && !focusedNewHorizons && !focusedPioneer10) { infoPanel.hidden = true; } }); @@ -3030,6 +3271,7 @@ function animate() { updateVoyager1Visual(); updateVoyager2Visual(); updateNewHorizonsVisual(); + updatePioneer10Visual(); // Aim shadow light from sun toward Saturn const saturnMesh = planetMeshes.get('Saturn'); @@ -3082,6 +3324,11 @@ function animate() { updateNewHorizonsInfoPanel(); } + if (focusedPioneer10 && pioneer10Objects && pioneer10Objects.mesh.visible) { + cameraTarget.lerp(pioneer10Objects.mesh.position, 0.06); + updatePioneer10InfoPanel(); + } + camRadius += (camRadiusTarget - camRadius) * 0.18; updateCamera(); updateBodyDisplayScales(); @@ -3227,6 +3474,8 @@ async function initSolarSystem() { rebuildVoyager2Track(); ensureNewHorizonsObjects(); rebuildNewHorizonsTrack(); + ensurePioneer10Objects(); + rebuildPioneer10Track(); syncSpacecraftObjects(); attachPointerControls(); attachUiHandlers(); diff --git a/scripts/import/import_spacecraft_tracks.php b/scripts/import/import_spacecraft_tracks.php index 22e1bef..ff45529 100644 --- a/scripts/import/import_spacecraft_tracks.php +++ b/scripts/import/import_spacecraft_tracks.php @@ -5,7 +5,7 @@ ini_set('display_errors', '1'); error_reporting(E_ALL); const AU_IN_KM = 149597870.7; -const IMPORT_END_TIME = '2046-04-12 00:00:00'; +const IMPORT_END_TIME = '2049-12-31 00:00:00'; $config = require __DIR__ . '/../../config/database.php'; $dsn = sprintf( @@ -71,6 +71,13 @@ $missions = [ 'start_time' => '2006-01-19 19:52:00', 'dense_stop_time' => '2017-10-19 19:52:00', ], + [ + 'key' => 'pioneer10', + 'name' => 'Pioneer 10', + 'command' => "'-23'", + 'start_time' => '1972-03-03 02:56:00', + 'dense_stop_time' => '1986-11-03 02:56:00', + ], ]; function fetchHorizonsResult(array $extraParams): string