diff --git a/config/rechtesystem.json b/config/rechtesystem.json
index 8165f9e..cf111e2 100644
--- a/config/rechtesystem.json
+++ b/config/rechtesystem.json
@@ -76,6 +76,10 @@
"label": "Sternenhimmel",
"menu_group": "Himmel & Planeten"
},
+ "drehbare_sternkarte.php": {
+ "label": "Drehbare Sternkarte",
+ "menu_group": "Himmel & Planeten"
+ },
"meteorshowers.php": {
"label": "Meteorstroeme",
"menu_group": "Himmel & Planeten"
@@ -132,6 +136,7 @@
"jupitersystem.php",
"tagbogen.php",
"sternenhimmel.php",
+ "drehbare_sternkarte.php",
"meteorshowers.php",
"geocron/index.php",
"geocron3d.php"
diff --git a/public/auth_helpers.php b/public/auth_helpers.php
index d83328a..15c706c 100644
--- a/public/auth_helpers.php
+++ b/public/auth_helpers.php
@@ -123,6 +123,7 @@ function manageablePublicPages(): array
'jupitersystem.php' => 'Jupitersystem',
'tagbogen.php' => 'Tagbogen',
'sternenhimmel.php' => 'Sternenhimmel',
+ 'drehbare_sternkarte.php' => 'Drehbare Sternkarte',
'meteorshowers.php' => 'Meteorströme',
'geocron/index.php' => 'Geocron',
'geocron3d.php' => 'Geocron 3D',
diff --git a/public/css/style.css b/public/css/style.css
index e87009f..8167aaf 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -653,7 +653,7 @@ nav a.nav-logout:hover {
position: absolute;
top: calc(100% + 0.8rem);
right: 0;
- width: 480px;
+ width: 620px;
max-width: 96vw;
display: flex;
flex-direction: column;
diff --git a/public/drehbare_sternkarte.php b/public/drehbare_sternkarte.php
new file mode 100644
index 0000000..33bd5d6
--- /dev/null
+++ b/public/drehbare_sternkarte.php
@@ -0,0 +1,1251 @@
+ []];
+$constellationDataError = null;
+$messierData = [];
+$messierDataError = null;
+$availableLocations = [];
+$starDbMagLimit = 7.4;
+$pdo = null;
+
+try {
+ $dbConfig = require __DIR__ . '/../config/database.php';
+ $dsn = sprintf(
+ 'mysql:host=%s;dbname=%s;charset=%s',
+ $dbConfig['host'],
+ $dbConfig['dbname'],
+ $dbConfig['charset'] ?? 'utf8mb4'
+ );
+ $pdo = new PDO($dsn, $dbConfig['user'], $dbConfig['pass'], [
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
+ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
+ ]);
+
+ $constellations = [];
+ $ensureConstellation = static function (string $id) use (&$constellations): void {
+ if (!isset($constellations[$id])) {
+ $constellations[$id] = [
+ 'id' => $id,
+ 'lines' => [],
+ 'label_positions' => [],
+ 'common_name' => [
+ 'german' => null,
+ 'native' => null,
+ 'byname' => null,
+ ],
+ ];
+ }
+ };
+
+ $nameStmt = $pdo->query(
+ "SELECT constellation_id, german_name, native_name, byname
+ FROM constellation_names
+ ORDER BY constellation_id"
+ );
+ foreach ($nameStmt as $row) {
+ $id = (string) $row['constellation_id'];
+ $ensureConstellation($id);
+ $constellations[$id]['common_name'] = [
+ 'german' => $row['german_name'] !== null ? (string) $row['german_name'] : null,
+ 'native' => $row['native_name'] !== null ? (string) $row['native_name'] : null,
+ 'byname' => $row['byname'] !== null ? (string) $row['byname'] : null,
+ ];
+ }
+
+ $labelStmt = $pdo->query(
+ "SELECT constellation_id, position_index, ra_hours, dec_degrees
+ FROM constellation_label_positions
+ ORDER BY constellation_id, position_index"
+ );
+ foreach ($labelStmt as $row) {
+ $id = (string) $row['constellation_id'];
+ $ensureConstellation($id);
+ $constellations[$id]['label_positions'][] = [
+ (float) $row['ra_hours'],
+ (float) $row['dec_degrees'],
+ ];
+ }
+
+ $lineStmt = $pdo->query(
+ "SELECT cl.constellation_id, cl.line_index, clp.point_index, clp.hip_number
+ FROM constellation_lines cl
+ INNER JOIN constellation_line_points clp ON clp.line_id = cl.id
+ ORDER BY cl.constellation_id, cl.line_index, clp.point_index"
+ );
+ foreach ($lineStmt as $row) {
+ $id = (string) $row['constellation_id'];
+ $lineIndex = (int) $row['line_index'];
+ $ensureConstellation($id);
+ $constellations[$id]['lines'][$lineIndex] ??= [];
+ $constellations[$id]['lines'][$lineIndex][] = (int) $row['hip_number'];
+ }
+
+ foreach ($constellations as &$constellation) {
+ if ($constellation['lines']) {
+ ksort($constellation['lines']);
+ $constellation['lines'] = array_values($constellation['lines']);
+ }
+ }
+ unset($constellation);
+
+ uasort(
+ $constellations,
+ static fn(array $a, array $b): int => strcmp($a['id'], $b['id'])
+ );
+
+ if ($starsApiRequested) {
+ $stars = [];
+ $starStmt = $pdo->query(
+ "SELECT hip, proper, bayer, con, spect, mag, ci, rarad, decrad
+ FROM star_hipparcos
+ WHERE mag IS NOT NULL
+ AND rarad IS NOT NULL
+ AND decrad IS NOT NULL
+ AND mag <= " . (float) $starDbMagLimit . "
+ ORDER BY mag ASC"
+ );
+ while ($row = $starStmt->fetch()) {
+ $stars[] = [
+ 'hip' => $row['hip'] !== null ? (int) $row['hip'] : null,
+ 'proper' => trim((string) ($row['proper'] ?? '')),
+ 'bayer' => trim((string) ($row['bayer'] ?? '')),
+ 'con' => trim((string) ($row['con'] ?? '')),
+ 'spect' => trim((string) ($row['spect'] ?? '')),
+ 'ra' => (float) $row['rarad'],
+ 'dec' => (float) $row['decrad'],
+ 'mag' => (float) $row['mag'],
+ 'ci' => $row['ci'] !== null ? (float) $row['ci'] : null,
+ ];
+ }
+
+ header('Content-Type: application/json; charset=utf-8');
+ echo json_encode([
+ 'ok' => true,
+ 'stars' => $stars,
+ ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+ exit;
+ }
+
+ $constellationData['constellations'] = array_values($constellations);
+
+ $messierStmt = $pdo->query(
+ "SELECT messier, name, object_type_abrev, ra_deg, dec_deg, v_mag, major_axis
+ FROM dso_objects
+ WHERE messier IS NOT NULL
+ AND messier <> ''
+ AND ra_deg IS NOT NULL
+ AND dec_deg IS NOT NULL
+ ORDER BY CAST(REGEXP_REPLACE(messier, '[^0-9]', '') AS UNSIGNED)"
+ );
+ while ($row = $messierStmt->fetch()) {
+ if (!preg_match('/(\d+)/', (string) $row['messier'], $m)) {
+ continue;
+ }
+ $messierData[] = [
+ 'm' => (int) $m[1],
+ 'name' => trim((string) ($row['name'] ?? '')),
+ 'type' => trim((string) ($row['object_type_abrev'] ?? 'As')),
+ 'ra' => ((float) $row['ra_deg']) / 15.0,
+ 'dec' => (float) $row['dec_deg'],
+ 'mag' => $row['v_mag'] !== null ? (float) $row['v_mag'] : 99.0,
+ 'size' => $row['major_axis'] !== null ? (float) $row['major_axis'] : 8.0,
+ ];
+ }
+
+ if ($loggedIn && isset($_SESSION['user_id'])) {
+ $locationStmt = $pdo->prepare(
+ "SELECT id, name, latitude, longitude, elevation, timezone, is_default
+ FROM app_user_locations
+ WHERE user_id = ?
+ ORDER BY is_default DESC, name ASC, id ASC"
+ );
+ $locationStmt->execute([(int) $_SESSION['user_id']]);
+ while ($row = $locationStmt->fetch()) {
+ if ($row['latitude'] === null || $row['longitude'] === null) {
+ continue;
+ }
+ $availableLocations[] = [
+ 'id' => $row['id'] !== null ? (int) $row['id'] : null,
+ 'name' => trim((string) ($row['name'] ?? 'Standort')),
+ 'latitude' => (float) $row['latitude'],
+ 'longitude' => (float) $row['longitude'],
+ 'elevation' => $row['elevation'] !== null ? (float) $row['elevation'] : 0.0,
+ 'timezone' => trim((string) ($row['timezone'] ?? 'Europe/Berlin')),
+ 'is_default' => !empty($row['is_default']),
+ ];
+ }
+ }
+} catch (Throwable $e) {
+ if ($starsApiRequested) {
+ header('Content-Type: application/json; charset=utf-8');
+ http_response_code(500);
+ echo json_encode([
+ 'ok' => false,
+ 'error' => $e->getMessage(),
+ ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+ exit;
+ }
+ $constellationDataError = $e->getMessage();
+ $messierDataError = $e->getMessage();
+}
+
+$constellationDataJson = json_encode($constellationData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+$constellationDataErrorJson = json_encode($constellationDataError, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+$messierDataJson = json_encode($messierData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+$messierDataErrorJson = json_encode($messierDataError, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+
+require __DIR__ . '/header.php';
+
+$chartLocation = [
+ 'id' => null,
+ 'name' => 'Sternwarte Sonneberg',
+ 'latitude' => 50.3547,
+ 'longitude' => 11.1900,
+ 'elevation' => 640.0,
+ 'timezone' => 'Europe/Berlin',
+];
+
+if (!empty($currentLocation) && is_array($currentLocation)) {
+ $chartLocation = [
+ 'id' => isset($currentLocation['id']) ? (int) $currentLocation['id'] : null,
+ 'name' => (string) ($currentLocation['name'] ?? 'Standard-Standort'),
+ 'latitude' => isset($currentLocation['latitude']) ? (float) $currentLocation['latitude'] : 50.3547,
+ 'longitude' => isset($currentLocation['longitude']) ? (float) $currentLocation['longitude'] : 11.1900,
+ 'elevation' => isset($currentLocation['elevation']) && $currentLocation['elevation'] !== null ? (float) $currentLocation['elevation'] : 0.0,
+ 'timezone' => trim((string) ($currentLocation['timezone'] ?? 'Europe/Berlin')),
+ ];
+}
+
+if (!$availableLocations) {
+ $availableLocations[] = [
+ 'id' => $chartLocation['id'],
+ 'name' => $chartLocation['name'],
+ 'latitude' => $chartLocation['latitude'],
+ 'longitude' => $chartLocation['longitude'],
+ 'elevation' => $chartLocation['elevation'],
+ 'timezone' => $chartLocation['timezone'],
+ 'is_default' => true,
+ ];
+}
+?>
+
+
+
+
+
+
+
+
+
Sternscheibe wird geladen…
+
Ziehen zum Drehen
+
+
+
+
+
+
+
+
diff --git a/public/header.php b/public/header.php
index e4966a1..a06cabf 100644
--- a/public/header.php
+++ b/public/header.php
@@ -138,36 +138,47 @@ if ($loggedIn && isset($_SESSION['user_id']) && $pdoHeader !== null) {
$menuGroups = [
[
- 'title' => 'Himmel & Planeten',
+ 'title' => 'Mond & Finsternisse',
'links' => [
- ['href' => 'moonphase.php', 'label' => 'Mondphase'],
- ['href' => 'moonyear.php', 'label' => 'Mondphasen-Jahresübersicht'],
- ['href' => 'planetensichtbarkeit.php', 'label' => 'Planetensichtbarkeit'],
- ['href' => 'ephemeriden.php', 'label' => 'Ephemeriden'],
- ['href' => 'comets.php', 'label' => 'Kometen'],
- ['href' => 'astronomical_conversions.php', 'label' => 'Astronomical Conversions'],
- ['href' => 'tcrb_lightcurve.php', 'label' => 'T CrB Lichtkurve'],
- ['href' => 'solarsystem.php', 'label' => 'Sonnensystem'],
- ['href' => 'mars.php', 'label' => 'Mars'],
- ['href' => 'jupitersystem.php', 'label' => 'Jupitersystem'],
- ['href' => 'tagbogen.php', 'label' => 'Tagbogen'],
- ['href' => 'sternenhimmel.php', 'label' => 'Sternenhimmel'],
- ['href' => 'satellitenhimmel.php', 'label' => 'Satellitenhimmel'],
- ['href' => 'meteorshowers.php', 'label' => 'Meteorströme'],
- ['href' => 'asteroid_temp.php', 'label' => 'Asteroid-Temperatur'],
- ['href' => 'geocron/index.php', 'label' => 'Geocron'],
- ['href' => 'geocron3d.php', 'label' => 'Geocron 3D'],
- ['href' => 'geocron3d_C.php', 'label' => 'Geocron 3D Cesium'],
- ['href' => 'universesandbox.php', 'label' => 'Universe Sandbox'],
+ ['href' => 'moonphase.php', 'label' => 'Mondphase'],
+ ['href' => 'moonyear.php', 'label' => 'Mondphasen-Jahresübersicht'],
+ ['href' => 'mondfinsternis.php', 'label' => 'Mondfinsternis'],
+ ['href' => 'sonnenfinsternis.php', 'label' => 'Sonnenfinsternis'],
+ ['href' => 'bedeckung.php', 'label' => 'Bedeckungsphänomene'],
+ ['href' => 'sternbedeckungen.php', 'label' => 'Mond-Stern-Bedeckungen'],
],
],
[
- 'title' => 'Finsternisse & Bedeckungen',
+ 'title' => 'Planeten & Sonnensystem',
'links' => [
- ['href' => 'mondfinsternis.php', 'label' => 'Mondfinsternis'],
- ['href' => 'sonnenfinsternis.php', 'label' => 'Sonnenfinsternis'],
- ['href' => 'bedeckung.php', 'label' => 'Bedeckungsphänomene'],
- ['href' => 'sternbedeckungen.php', 'label' => 'Mond-Stern-Bedeckungen'],
+ ['href' => 'planetensichtbarkeit.php', 'label' => 'Planetensichtbarkeit'],
+ ['href' => 'ephemeriden.php', 'label' => 'Ephemeriden'],
+ ['href' => 'solarsystem.php', 'label' => 'Sonnensystem'],
+ ['href' => 'mars.php', 'label' => 'Mars'],
+ ['href' => 'jupitersystem.php', 'label' => 'Jupitersystem'],
+ ['href' => 'asteroid_temp.php', 'label' => 'Asteroid-Temperatur'],
+ ],
+ ],
+ [
+ 'title' => 'Sternenhimmel & Karten',
+ 'links' => [
+ ['href' => 'sternenhimmel.php', 'label' => 'Sternenhimmel'],
+ ['href' => 'drehbare_sternkarte.php', 'label' => 'Drehbare Sternkarte'],
+ ['href' => 'satellitenhimmel.php', 'label' => 'Satellitenhimmel'],
+ ['href' => 'tagbogen.php', 'label' => 'Tagbogen'],
+ ['href' => 'meteorshowers.php', 'label' => 'Meteorströme'],
+ ['href' => 'comets.php', 'label' => 'Kometen'],
+ ],
+ ],
+ [
+ 'title' => 'Tools & Simulationen',
+ 'links' => [
+ ['href' => 'tcrb_lightcurve.php', 'label' => 'T CrB Lichtkurve'],
+ ['href' => 'astronomical_conversions.php', 'label' => 'Astronomical Conversions'],
+ ['href' => 'geocron/index.php', 'label' => 'Geocron'],
+ ['href' => 'geocron3d.php', 'label' => 'Geocron 3D'],
+ ['href' => 'geocron3d_C.php', 'label' => 'Geocron 3D Cesium'],
+ ['href' => 'universesandbox.php', 'label' => 'Universe Sandbox'],
],
],
];
diff --git a/public/monatsvorhersage.php b/public/monatsvorhersage.php
index 55f4283..37082fe 100644
--- a/public/monatsvorhersage.php
+++ b/public/monatsvorhersage.php
@@ -888,80 +888,391 @@ if (!function_exists('monthForecastBuildNarrativeText')) {
static fn (array $event): bool => in_array((string) ($event['type'] ?? ''), ['moon_phase', 'golden_handle', 'moon_planet', 'moon_planet_approach', 'moon_deep_sky', 'moon_deep_sky_approach', 'moon_occultation', 'moon_apsis'], true),
10
);
+ // Jahreszahl aus Datum entfernen (z. B. "19.04.2026" → "19.04.")
+ $shortDate = static function (string $d): string {
+ return (string) preg_replace('/\.\d{4}$/', '.', $d);
+ };
+
if ($moonEvents !== []) {
- // Chronologisch sortieren nach local_iso
$sortedMoonEvents = $moonEvents;
usort($sortedMoonEvents, static fn (array $a, array $b): int => strcmp(
(string) ($a['local_iso'] ?? $a['date'] ?? ''),
(string) ($b['local_iso'] ?? $b['date'] ?? '')
));
- // Natürlichsprachliche Liste: "Vollmond ist am 01.05., Apogäum am 05.05. und Neumond am 16.05."
- $moonParts = [];
- foreach ($sortedMoonEvents as $me) {
- $label = trim((string) ($me['event'] ?? ''));
- $date = trim((string) ($me['date'] ?? ''));
- if ($label === '' || $date === '') {
- continue;
+ $phaseEvents = array_values(array_filter($sortedMoonEvents, static fn (array $e): bool => (string) ($e['type'] ?? '') === 'moon_phase'));
+ $nonPhaseEvents = array_values(array_filter($sortedMoonEvents, static fn (array $e): bool => (string) ($e['type'] ?? '') !== 'moon_phase'));
+
+ $moonSentences = [];
+
+ // 1. Mondphasen in einem natürlichen Satz zusammenfassen
+ if ($phaseEvents !== []) {
+ $phaseParts = [];
+ foreach ($phaseEvents as $pe) {
+ $rawLabel = trim((string) ($pe['event'] ?? ''));
+ $date = trim((string) ($pe['date'] ?? ''));
+ if ($rawLabel === '' || $date === '') {
+ continue;
+ }
+ // "Mond Erstes Viertel" → "Erstes Viertel"
+ $cleanLabel = (string) preg_replace('/^Mond\s+/', '', $rawLabel);
+ $phaseParts[] = $cleanLabel . ' am ' . $shortDate($date);
}
- // "Mond bedeckt X" → "der Mond bedeckt X" für natürlicheren Satzbau
- if (str_starts_with($label, 'Mond bedeckt ')) {
- $label = 'der ' . $label;
+ if ($phaseParts !== []) {
+ $lastPhase = array_pop($phaseParts);
+ $phaseList = $phaseParts !== [] ? implode(', ', $phaseParts) . ' und ' . $lastPhase : $lastPhase;
+ $moonSentences[] = 'Die Mondphasen im Überblick: ' . $phaseList . '.';
}
- $moonParts[] = ['label' => $label, 'date' => $date];
}
- if ($moonParts !== []) {
- $moonSentenceParts = [];
- foreach ($moonParts as $idx => $part) {
- if ($idx === 0) {
- $moonSentenceParts[] = $part['label'] . ' ist am ' . $part['date'];
+ // 2. Apsis, Begegnungen und Goldener Henkel – nach Datum gruppiert
+ $byDate = [];
+ foreach ($nonPhaseEvents as $ne) {
+ $date = trim((string) ($ne['date'] ?? ''));
+ if ($date === '') {
+ continue;
+ }
+ $byDate[$date][] = $ne;
+ }
+
+ foreach ($byDate as $date => $dateEvents) {
+ $apsis = null;
+ $approaches = [];
+ $goldenHandle = null;
+ foreach ($dateEvents as $de) {
+ $type = (string) ($de['type'] ?? '');
+ if ($type === 'moon_apsis') {
+ $apsis = $de;
+ } elseif ($type === 'golden_handle') {
+ $goldenHandle = $de;
} else {
- $moonSentenceParts[] = $part['label'] . ' am ' . $part['date'];
+ $approaches[] = $de;
}
}
- $lastPart = array_pop($moonSentenceParts);
- $moonSentence = $moonSentenceParts !== []
- ? implode(', ', $moonSentenceParts) . ' und ' . $lastPart
- : $lastPart;
- $paragraphs[] = $moonSentence . '.';
+
+ $sd = $shortDate($date);
+
+ if ($goldenHandle !== null) {
+ $moonSentences[] = 'Am ' . $sd . ' zeigt der Mond den Goldenen Henkel: Ein Gebirgskamm am Mondrand leuchtet bereits im Sonnenlicht, während das Tal dahinter noch im Schatten liegt – ein lohnender Anblick schon im kleinen Teleskop.';
+ }
+
+ if ($apsis !== null) {
+ $apsisLabel = trim((string) ($apsis['event'] ?? ''));
+ // Distanz aus dem Label extrahieren: "(404.960 km)"
+ $distanceMatch = [];
+ $distanceStr = '';
+ if (preg_match('/\(([0-9.,]+\s*km)\)\s*$/', $apsisLabel, $distanceMatch)) {
+ $distanceStr = ' mit nur ' . $distanceMatch[1];
+ }
+ $isPerigee = str_contains($apsisLabel, 'Erdnähe') || str_contains($apsisLabel, 'Perigäum');
+ if ($isPerigee) {
+ $apsisText = 'Am ' . $sd . ' erreicht der Mond sein Perigäum' . $distanceStr . ' – er steht der Erde in diesem Monat am nächsten';
+ } else {
+ $apsisText = 'Am ' . $sd . ' erreicht der Mond sein Apogäum' . $distanceStr . ' – er steht der Erde in diesem Monat am fernsten';
+ }
+ if ($approaches !== []) {
+ // Begegnungen natürlich formulieren: "und zieht dabei in nur X Grad Abstand an Y vorbei"
+ $approachFragments = [];
+ foreach ($approaches as $ap) {
+ $apLabel = trim((string) ($ap['event'] ?? ''));
+ $sepMatch = [];
+ $sepStr = '';
+ if (preg_match('/\(([0-9.,]+\s*Grad)\)/', $apLabel, $sepMatch)) {
+ $apLabel = trim((string) preg_replace('/\s*\([0-9.,]+\s*Grad\)/', '', $apLabel));
+ $sepStr = ' in nur ' . $sepMatch[1] . ' Abstand';
+ }
+ if (str_starts_with($apLabel, 'Mond nahe ')) {
+ $target = substr($apLabel, strlen('Mond nahe '));
+ $approachFragments[] = $sepStr . ' an ' . $target . ' vorbei';
+ } elseif (str_starts_with($apLabel, 'Mond bedeckt ')) {
+ $target = substr($apLabel, strlen('Mond bedeckt '));
+ $approachFragments[] = ' und bedeckt dabei ' . $target;
+ } else {
+ $approachFragments[] = $sepStr !== '' ? $sepStr . ' bei ' . $apLabel : ' bei ' . $apLabel;
+ }
+ }
+ $approachClause = count($approachFragments) === 1
+ ? ' und zieht dabei' . $approachFragments[0]
+ : ' und zieht dabei' . implode(' sowie', $approachFragments);
+ $moonSentences[] = $apsisText . $approachClause . '.';
+ } else {
+ $moonSentences[] = $apsisText . '.';
+ }
+ } elseif ($approaches !== []) {
+ foreach ($approaches as $ap) {
+ $apLabel = trim((string) ($ap['event'] ?? ''));
+ $apDate = trim((string) ($ap['date'] ?? ''));
+ $sepMatch = [];
+ $sepStr = '';
+ if (preg_match('/\(([0-9.,]+\s*Grad)\)/', $apLabel, $sepMatch)) {
+ $apLabel = trim((string) preg_replace('/\s*\([0-9.,]+\s*Grad\)/', '', $apLabel));
+ $sepStr = ' in nur ' . $sepMatch[1] . ' Abstand';
+ }
+ $apSd = $shortDate($apDate !== '' ? $apDate : $date);
+ if (str_starts_with($apLabel, 'Mond nahe ')) {
+ $target = substr($apLabel, strlen('Mond nahe '));
+ $moonSentences[] = 'Am ' . $apSd . ' zieht der Mond' . $sepStr . ' an ' . $target . ' vorbei.';
+ } elseif (str_starts_with($apLabel, 'Mond bedeckt ')) {
+ $target = substr($apLabel, strlen('Mond bedeckt '));
+ $moonSentences[] = 'Am ' . $apSd . ' bedeckt der Mond ' . $target . '.';
+ } else {
+ $moonSentences[] = $apLabel . ' am ' . $apSd . ($sepStr !== '' ? ' – ' . ltrim($sepStr) : '') . '.';
+ }
+ }
+ }
+ }
+
+ if ($moonSentences !== []) {
+ $paragraphs[] = implode(' ', $moonSentences);
}
}
+ // Hilfsfunktion: natürlichen Satz aus einem Planeten-Event bauen
+ $buildPlanetSentence = static function (array $event) use ($shortDate): ?string {
+ $type = (string) ($event['type'] ?? '');
+ $label = trim((string) ($event['event'] ?? ''));
+ $date = trim((string) ($event['date'] ?? ''));
+ if ($label === '' || $date === '') {
+ return null;
+ }
+ $sd = $shortDate($date);
+
+ if ($type === 'planet_conjunction') {
+ $sepMatch = [];
+ $sep = '';
+ if (preg_match('/\(([0-9.,]+\s*Grad)\)/', $label, $sepMatch)) {
+ $sep = $sepMatch[1];
+ $label = trim((string) preg_replace('/\s*\([0-9.,]+\s*Grad\)/', '', $label));
+ }
+ if (preg_match('/^(.+?)\s+nahe\s+(.+)$/i', $label, $m)) {
+ $p1 = trim($m[1]);
+ $p2 = trim($m[2]);
+ $sepNote = $sep !== '' ? ' – der Abstand beträgt nur ' . $sep : '';
+ return 'Am ' . $sd . ' rücken ' . $p1 . ' und ' . $p2 . ' eng zusammen' . $sepNote . '.';
+ }
+ }
+
+ if ($type === 'golden_gate_of_ecliptic') {
+ $planet = '';
+ if (preg_match('/^(\S+)\s+im\s+Goldenen\s+Tor/i', $label, $m)) {
+ $planet = $m[1];
+ }
+ if ($planet !== '') {
+ return 'Am ' . $sd . ' durchquert ' . $planet . ' das Goldene Tor der Ekliptik und zieht dabei zwischen Hyaden und Plejaden hindurch – ein lohnender Anblick im Fernglas.';
+ }
+ }
+
+ if ($type === 'inner_planet_elongation') {
+ $sepMatch = [];
+ $sepStr = '';
+ if (preg_match('/\(([0-9.,]+\s*Grad)\)/', $label, $sepMatch)) {
+ $sepStr = ' (' . $sepMatch[1] . ')';
+ $label = trim((string) preg_replace('/\s*\([0-9.,]+\s*Grad\)/', '', $label));
+ }
+ $isWest = str_contains($label, 'westlich') || str_contains($label, 'West');
+ $planet = '';
+ if (preg_match('/^(\S+)\s+/', $label, $m)) {
+ $planet = $m[1];
+ }
+ $visibility = $isWest ? 'als Morgenstern am besten zu beobachten' : 'als Abendstern am besten zu beobachten';
+ return 'Am ' . $sd . ' erreicht ' . ($planet ?: 'der Planet') . ' seine größte Elongation' . $sepStr . ' und ist dann ' . $visibility . '.';
+ }
+
+ if ($type === 'venus_peak_magnitude') {
+ $magMatch = [];
+ $magStr = '';
+ if (preg_match('/\(([^)]+)\)/', $label, $magMatch)) {
+ $magStr = ' mit ' . $magMatch[1];
+ }
+ return 'Am ' . $sd . ' erreicht Venus ihre größte Helligkeit' . $magStr . ' – sie ist dann selbst in der Dämmerung kaum zu übersehen.';
+ }
+
+ if ($type === 'outer_planet_event') {
+ $planet = '';
+ if (preg_match('/^(\S+)\s+/', $label, $m)) {
+ $planet = $m[1];
+ }
+ if (str_contains($label, 'Opposition')) {
+ return 'Am ' . $sd . ' steht ' . ($planet ?: 'der Planet') . ' in Opposition – er geht bei Sonnenuntergang auf, ist die ganze Nacht sichtbar und leuchtet so hell wie selten.';
+ }
+ if (str_contains($label, 'Konjunktion')) {
+ return 'Am ' . $sd . ' steht ' . ($planet ?: 'der Planet') . ' in Konjunktion mit der Sonne und ist für einige Wochen nicht zu beobachten.';
+ }
+ if (str_contains($label, 'Quadratur')) {
+ return 'Am ' . $sd . ' befindet sich ' . ($planet ?: 'der Planet') . ' in Quadratur – er steht 90 Grad von der Sonne entfernt und ist in der ersten oder zweiten Nachthälfte gut sichtbar.';
+ }
+ }
+
+ if ($type === 'mercury_good_visibility') {
+ return 'Um den ' . $sd . ' zeigt sich Merkur günstig am Himmel und lässt sich in der Dämmerung tief über dem Horizont aufspüren.';
+ }
+
+ if ($type === 'planet_parade') {
+ return 'Am ' . $sd . ' sind mehrere Planeten gleichzeitig am Himmel zu sehen – eine seltene Planetenparade, die einen Blick Richtung Süden lohnt.';
+ }
+
+ // Fallback
+ return 'Am ' . $sd . ' ist zu beobachten: ' . $label . '.';
+ };
+
+ $buildPlanetMotionSentence = static function (array $event) use ($shortDate): ?string {
+ $type = (string) ($event['type'] ?? '');
+ $label = trim((string) ($event['event'] ?? ''));
+ $date = trim((string) ($event['date'] ?? ''));
+ if ($label === '' || $date === '') {
+ return null;
+ }
+ $sd = $shortDate($date);
+
+ if ($type === 'outer_planet_station') {
+ $planet = '';
+ $isRetrograde = str_contains($label, 'rückläufig') || str_contains($label, 'Rückläufig');
+ $isPrograde = str_contains($label, 'rechtläufig') || str_contains($label, 'Rechtläufig') || str_contains($label, 'direkt');
+ if (preg_match('/^(\S+)\s+/', $label, $m)) {
+ $planet = $m[1];
+ }
+ if ($isRetrograde) {
+ return 'Ab dem ' . $sd . ' läuft ' . ($planet ?: 'der Planet') . ' rückläufig – er bewegt sich scheinbar rückwärts vor dem Sternhintergrund, was seine Beobachtung besonders interessant macht.';
+ }
+ if ($isPrograde) {
+ return 'Ab dem ' . $sd . ' setzt ' . ($planet ?: 'der Planet') . ' seine normale Vorwärtsbewegung am Himmel wieder fort.';
+ }
+ return 'Am ' . $sd . ' wird ' . ($planet ?: 'der Planet') . ' stationär und ändert seine Bewegungsrichtung am Himmel.';
+ }
+
+ if ($type === 'planet_constellation_change') {
+ // Label-Format: "Mars wechselt vom Sternbild Wassermann in das Sternbild Fische"
+ if (preg_match('/^(.+?)\s+wechselt\s+vom\s+Sternbild\s+(.+?)\s+in\s+das\s+Sternbild\s+(.+)$/i', $label, $m)) {
+ $planet = trim($m[1]);
+ $from = trim($m[2]);
+ $to = trim($m[3]);
+ // Formulierung deterministisch variieren (nach erstem Buchstaben des Planetennamens)
+ $variant = ord($planet[0]) % 3;
+ if ($variant === 1) {
+ return 'Am ' . $sd . ' verlässt ' . $planet . ' das Sternbild ' . $from . ' und zieht weiter in das Sternbild ' . $to . '.';
+ }
+ if ($variant === 2) {
+ return 'Am ' . $sd . ' tritt ' . $planet . ' aus dem Sternbild ' . $from . ' in das Sternbild ' . $to . ' über.';
+ }
+ return 'Am ' . $sd . ' wechselt ' . $planet . ' vom Sternbild ' . $from . ' in das Sternbild ' . $to . '.';
+ }
+ // Fallback ohne "vom"-Angabe
+ if (preg_match('/^(.+?)\s+wechselt\s+(?:in\s+das\s+Sternbild\s+|ins?\s+(?:Sternbild\s+)?)(.+)$/i', $label, $m)) {
+ return 'Am ' . $sd . ' wechselt ' . trim($m[1]) . ' in das Sternbild ' . trim($m[2]) . '.';
+ }
+ }
+
+ return 'Am ' . $sd . ' ist zu beobachten: ' . $label . '.';
+ };
+
$planetObservationEvents = $findEvents(
$filteredEvents,
static fn (array $event): bool => in_array((string) ($event['type'] ?? ''), ['inner_planet_event', 'venus_peak_magnitude', 'outer_planet_event', 'planet_conjunction', 'planet_parade', 'mercury_good_visibility', 'golden_gate_of_ecliptic'], true),
5
);
if ($planetObservationEvents !== []) {
- $planetIntro = $pickRandomText([
- 'Bei den Planeten lohnt sich vor allem der Blick auf',
- 'Planetarisch besonders interessant sind in diesem Monat',
- 'Bei den Planeten stechen in diesem Monat vor allem',
- 'Einen planetaren Schwerpunkt bilden in diesem Monat',
- ], 'Bei den Planeten lohnt sich vor allem der Blick auf');
- $planetOutro = $pickRandomText([
- 'Diese Termine geben dem Monat seinen charakteristischen planetaren Akzent.',
- 'Damit bekommt der Monat einen klaren planetaren Schwerpunkt.',
- 'Solche Termine prägen den planetaren Charakter dieses Monats besonders deutlich.',
- 'Sie setzen im Monatsverlauf markante planetare Akzente.',
- ], 'Diese Termine geben dem Monat seinen charakteristischen planetaren Akzent.');
- $paragraphs[] = $planetIntro . ' ' . $describeEvents($planetObservationEvents) . '. ' . $planetOutro;
+ $planetSentences = [];
+ foreach ($planetObservationEvents as $pe) {
+ $sentence = $buildPlanetSentence($pe);
+ if ($sentence !== null) {
+ $planetSentences[] = $sentence;
+ }
+ }
+ if ($planetSentences !== []) {
+ $paragraphs[] = implode(' ', $planetSentences);
+ }
}
$planetMotionEvents = $findEvents(
$filteredEvents,
static fn (array $event): bool => in_array((string) ($event['type'] ?? ''), ['outer_planet_station', 'planet_constellation_change'], true),
- 4
+ 8
);
if ($planetMotionEvents !== []) {
- $planetMotionIntro = $pickRandomText([
- 'Im Monatsverlauf zeigen sich bei den Planeten auch auffällige Positionswechsel.',
- 'Auch in ihrer Stellung am Himmel verändern sich die Planeten in diesem Monat sichtbar.',
- 'Neben den Beobachtungshighlights fallen bei den Planeten auch einige Positionswechsel auf.',
- 'Auch die Bewegung der Planeten vor dem Sternhintergrund macht sich in diesem Monat bemerkbar.',
- ], 'Im Monatsverlauf zeigen sich bei den Planeten auch auffaellige Positionswechsel.');
- $paragraphs[] = $planetMotionIntro . ' Dazu gehören ' . $describeEvents($planetMotionEvents) . '.';
+ // Sternbild-Akkusativformen für natürliche Sätze ohne "Sternbild"-Wiederholung
+ $constellationAkk = [
+ 'Widder' => 'den Widder', 'Stier' => 'den Stier', 'Zwillinge' => 'die Zwillinge',
+ 'Krebs' => 'den Krebs', 'Löwe' => 'den Löwen', 'Jungfrau' => 'die Jungfrau',
+ 'Waage' => 'die Waage', 'Skorpion' => 'den Skorpion', 'Schütze' => 'den Schützen',
+ 'Steinbock' => 'den Steinbock', 'Wassermann' => 'den Wassermann', 'Fische' => 'die Fische',
+ 'Walfisch' => 'den Walfisch', 'Orion' => 'den Orion', 'Fuhrmann' => 'den Fuhrmann',
+ 'Stier' => 'den Stier', 'Kassiopeia' => 'die Kassiopeia', 'Andromeda' => 'die Andromeda',
+ 'Perseus' => 'den Perseus', 'Pegasus' => 'den Pegasus', 'Leier' => 'die Leier',
+ 'Schwan' => 'den Schwan', 'Adler' => 'den Adler', 'Schlange' => 'die Schlange',
+ 'Schlangenträger' => 'den Schlangenträger', 'Herkules' => 'den Herkules',
+ 'Bärenhüter' => 'den Bärenhüter', 'Großer Bär' => 'den Großen Bären',
+ 'Drache' => 'den Drachen', 'Nördliche Krone' => 'die Nördliche Krone',
+ 'Kleiner Löwe' => 'den Kleinen Löwen', 'Rabe' => 'den Raben', 'Becher' => 'den Becher',
+ 'Wasserschlange' => 'die Wasserschlange', 'Eridanus' => 'den Eridanus',
+ 'Hase' => 'den Hasen', 'Großer Hund' => 'den Großen Hund',
+ 'Kleiner Hund' => 'den Kleinen Hund', 'Einhorn' => 'das Einhorn',
+ 'Delfin' => 'den Delfin', 'Pfeil' => 'den Pfeil', 'Fuchs' => 'den Fuchs',
+ 'Kepheus' => 'den Kepheus', 'Südlicher Fisch' => 'den Südlichen Fisch',
+ 'Jagdhunde' => 'die Jagdhunde', 'Löwchen' => 'das Löwchen',
+ ];
+ $akkusativ = static function (string $name) use ($constellationAkk): string {
+ return $constellationAkk[$name] ?? 'das Sternbild ' . $name;
+ };
+
+ $stationEvents = array_values(array_filter($planetMotionEvents, static fn (array $e): bool => (string) ($e['type'] ?? '') === 'outer_planet_station'));
+ $changeEvents = array_values(array_filter($planetMotionEvents, static fn (array $e): bool => (string) ($e['type'] ?? '') === 'planet_constellation_change'));
+
+ $motionSentences = [];
+
+ // Rückläufigkeits-Ereignisse einzeln als Satz
+ foreach ($stationEvents as $se) {
+ $sentence = $buildPlanetMotionSentence($se);
+ if ($sentence !== null) {
+ $motionSentences[] = $sentence;
+ }
+ }
+
+ // Sternbild-Wechsel: nach Planet gruppieren, kompakt als eine Aussage
+ if ($changeEvents !== []) {
+ $byPlanet = [];
+ $planetOrder = [];
+ foreach ($changeEvents as $ce) {
+ $label = trim((string) ($ce['event'] ?? ''));
+ $date = trim((string) ($ce['date'] ?? ''));
+ if (!preg_match('/^(.+?)\s+wechselt\s+vom\s+Sternbild\s+(.+?)\s+in\s+das\s+Sternbild\s+(.+)$/i', $label, $m)) {
+ continue;
+ }
+ $planet = trim($m[1]);
+ $to = trim($m[3]);
+ if (!isset($byPlanet[$planet])) {
+ $byPlanet[$planet] = [];
+ $planetOrder[] = $planet;
+ }
+ $byPlanet[$planet][] = ['date' => $date, 'to' => $to];
+ }
+
+ if ($byPlanet !== []) {
+ $parts = [];
+ foreach ($planetOrder as $planet) {
+ $moves = $byPlanet[$planet];
+ if (count($moves) === 1) {
+ $parts[] = $planet . ' am ' . $shortDate($moves[0]['date']) . ' in ' . $akkusativ($moves[0]['to']);
+ } else {
+ // Mehrfacher Wechsel desselben Planeten
+ $moveParts = [];
+ foreach ($moves as $move) {
+ $moveParts[] = 'am ' . $shortDate($move['date']) . ' in ' . $akkusativ($move['to']);
+ }
+ $lastMove = array_pop($moveParts);
+ $parts[] = $planet . ' ' . ($moveParts !== [] ? implode(', ', $moveParts) . ' und dann ' . $lastMove : $lastMove);
+ }
+ }
+ $lastPart = array_pop($parts);
+ $changeText = count($byPlanet) > 1
+ ? implode(', ', $parts) . ' und ' . $lastPart
+ : $lastPart;
+ $motionSentences[] = 'Sternbildwechsel im Monatsverlauf: ' . $changeText . '.';
+ }
+ }
+
+ if ($motionSentences !== []) {
+ $paragraphs[] = implode(' ', $motionSentences);
+ }
}
$cometEvents = $findEvents(
@@ -3138,40 +3449,13 @@ async function composeExportCanvas(sourceCanvas, logoPosition, options) {
const caption = monthChartExportCaption();
if (showCaption && caption !== '') {
const padding = Math.round(exportCanvas.width * 0.024);
- const fontSize = Math.max(26, Math.round(exportCanvas.width * 0.022));
+ const fontSize = Math.max(18, Math.round(exportCanvas.width * 0.015));
exportCtx.save();
exportCtx.font = '600 ' + fontSize + 'px Rajdhani, sans-serif';
exportCtx.textAlign = 'right';
exportCtx.textBaseline = 'bottom';
-
- const metrics = exportCtx.measureText(caption);
- const textWidth = metrics.width;
- const ascent = metrics.actualBoundingBoxAscent || fontSize * 0.8;
- const descent = metrics.actualBoundingBoxDescent || fontSize * 0.2;
- const boxPadX = Math.round(fontSize * 0.45);
- const boxPadY = Math.round(fontSize * 0.3);
- const boxWidth = textWidth + boxPadX * 2;
- const boxHeight = ascent + descent + boxPadY * 2;
- const boxX = exportCanvas.width - padding - boxWidth;
- const boxY = exportCanvas.height - padding - boxHeight;
- const radius = Math.round(fontSize * 0.28);
-
- exportCtx.fillStyle = 'rgba(3, 7, 14, 0.7)';
- exportCtx.beginPath();
- exportCtx.moveTo(boxX + radius, boxY);
- exportCtx.lineTo(boxX + boxWidth - radius, boxY);
- exportCtx.quadraticCurveTo(boxX + boxWidth, boxY, boxX + boxWidth, boxY + radius);
- exportCtx.lineTo(boxX + boxWidth, boxY + boxHeight - radius);
- exportCtx.quadraticCurveTo(boxX + boxWidth, boxY + boxHeight, boxX + boxWidth - radius, boxY + boxHeight);
- exportCtx.lineTo(boxX + radius, boxY + boxHeight);
- exportCtx.quadraticCurveTo(boxX, boxY + boxHeight, boxX, boxY + boxHeight - radius);
- exportCtx.lineTo(boxX, boxY + radius);
- exportCtx.quadraticCurveTo(boxX, boxY, boxX + radius, boxY);
- exportCtx.closePath();
- exportCtx.fill();
-
exportCtx.fillStyle = 'rgba(235, 242, 255, 0.96)';
- exportCtx.fillText(caption, exportCanvas.width - padding - boxPadX, exportCanvas.height - padding - boxPadY);
+ exportCtx.fillText(caption, exportCanvas.width - padding, exportCanvas.height - padding);
exportCtx.restore();
}
@@ -3211,7 +3495,13 @@ function monthChartExportCaption() {
return '';
}
- return 'Sternhimmel für ' + String(hour).padStart(2, '0') + ':' + String(minute).padStart(2, '0') + ' Uhr';
+ const parts = String(MONTH_CHART_CONFIG.localTimeLabel || '').split(' ');
+ const date = parts[0] || '';
+ const hh = String(hour).padStart(2, '0');
+ const mm = String(minute).padStart(2, '0');
+ return date !== ''
+ ? 'Sternhimmel am ' + date + ' um ' + hh + ':' + mm + ' Uhr'
+ : 'Sternhimmel um ' + hh + ':' + mm + ' Uhr';
}
function formatGermanDate(date) {
diff --git a/public/sternenhimmel.php b/public/sternenhimmel.php
index 3b66c57..b59f318 100644
--- a/public/sternenhimmel.php
+++ b/public/sternenhimmel.php
@@ -15,8 +15,6 @@ $constellationDataError = null;
$starDataError = null;
$messierData = [];
$messierDataError = null;
-$milkyWayData = null;
-$milkyWayDataError = null;
$availableLocations = [];
$starDbMagLimit = 12.0;
@@ -236,16 +234,6 @@ try {
$messierDataError = $e->getMessage();
}
-try {
- $milkyWayPath = __DIR__ . '/js/mw.json';
- if (is_file($milkyWayPath)) {
- $milkyWayData = json_decode((string) file_get_contents($milkyWayPath), true, 512, JSON_THROW_ON_ERROR);
- }
-} catch (Throwable $e) {
- $milkyWayData = null;
- $milkyWayDataError = $e->getMessage();
-}
-
$favCometDataJson = json_encode(
$favCometData ?? [],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
@@ -271,14 +259,6 @@ $messierDataErrorJson = json_encode(
$messierDataError,
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
-$milkyWayDataJson = json_encode(
- $milkyWayData,
- JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
-);
-$milkyWayDataErrorJson = json_encode(
- $milkyWayDataError,
- JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
-);
?>
-
-
Sternbilder
@@ -522,14 +495,6 @@ const CFG_DEFAULT = {
ecliptic: {
color: 'rgba(255,175,35,0.52)', width: 1.1, dash: [5,5]
},
- milkyWay: {
- fillSoft: 'rgba(180, 208, 255, 0.018)',
- fillMain: 'rgba(210, 228, 255, 0.028)',
- stroke: 'rgba(220, 235, 255, 0.035)',
- glow: 'rgba(185, 210, 255, 0.10)',
- blur: 16,
- minPoints: 20
- },
constellations: {
color: 'rgba(100,160,220,0.38)', width: 0.8, dash: [],
colorLabels: 'rgba(120,175,230,0.50)', fontLabels: '9px Rajdhani, sans-serif'
@@ -631,7 +596,6 @@ let showAltaz = false;
let showPlanets = true;
let showSunMoon = true;
let showEclip = true;
-let showMilkyWay = true;
let showMessier = true;
let showConst = true;
let showComets = true;
@@ -654,8 +618,6 @@ const STAR_DATA_URL = 'sternenhimmel.php?stars_api=1';
const EMBEDDED_STAR_ERROR = ;
const EMBEDDED_MESSIER_DATA = ;
const EMBEDDED_MESSIER_ERROR = ;
-const EMBEDDED_MILKY_WAY_DATA = ;
-const EMBEDDED_MILKY_WAY_ERROR = ;
const MESSIER = Array.isArray(EMBEDDED_MESSIER_DATA) ? EMBEDDED_MESSIER_DATA : [];
const FAV_COMETS = ;
let constellationData = EMBEDDED_CONSTELLATION_DATA;
@@ -674,66 +636,6 @@ function buildMStyle() {
}
let M_STYLE = buildMStyle();
-function buildMilkyWayRings(data) {
- if (!data || !Array.isArray(data.features)) return [];
-
- const rings = [];
- for (const feature of data.features) {
- const geometry = feature && feature.geometry ? feature.geometry : null;
- if (!geometry) continue;
-
- const polygons = geometry.type === 'Polygon'
- ? [geometry.coordinates]
- : geometry.type === 'MultiPolygon'
- ? geometry.coordinates
- : [];
-
- for (const polygon of polygons) {
- if (!Array.isArray(polygon)) continue;
- for (const rawRing of polygon) {
- if (!Array.isArray(rawRing) || rawRing.length < CFG.milkyWay.minPoints) continue;
-
- const coords = [];
- let area = 0;
-
- for (let i = 0; i < rawRing.length; i++) {
- const point = rawRing[i];
- if (!Array.isArray(point) || point.length < 2) continue;
- const lon = Number(point[0]);
- const lat = Number(point[1]);
- if (!Number.isFinite(lon) || !Number.isFinite(lat)) continue;
-
- coords.push([lon, lat]);
-
- if (i < rawRing.length - 1) {
- const next = rawRing[i + 1];
- const lon2 = Array.isArray(next) ? Number(next[0]) : NaN;
- const lat2 = Array.isArray(next) ? Number(next[1]) : NaN;
- if (Number.isFinite(lon2) && Number.isFinite(lat2)) {
- area += (lon * lat2) - (lon2 * lat);
- }
- }
- }
-
- if (coords.length < CFG.milkyWay.minPoints) continue;
-
- const areaAbs = Math.abs(area / 2);
- if (!Number.isFinite(areaAbs)) continue;
-
- rings.push({
- coords,
- areaAbs,
- });
- }
- }
- }
-
- rings.sort((a, b) => b.areaAbs - a.areaAbs);
- return rings;
-}
-
-const MILKY_WAY_RINGS = buildMilkyWayRings(EMBEDDED_MILKY_WAY_DATA);
-
function getTime() { return liveMode ? new Date() : simTime; }
// ═══════════════════════════════════════════════════════════════════════════════
@@ -1968,7 +1870,6 @@ function render() {
ctx.fill();
ctx.clip();
- if (showMilkyWay) drawMilkyWay(date);
if (showAltaz) drawAltazGrid();
if (showEq) drawEquatorialGrid(date);
if (showEclip) drawEcliptic(date);
@@ -2303,7 +2204,6 @@ spBind('cfgPlanetsShow', () => showPlanets, v => showPlanets = v);
spBind('cfgCometsShow', () => showComets, v => showComets = v);
spBind('cfgCometsLabels', () => labelComets, v => labelComets = v);
spBind('cfgEclipShow', () => showEclip, v => showEclip = v);
-spBind('cfgMilkyWayShow', () => showMilkyWay, v => showMilkyWay = v);
spBind('cfgMessierShow', () => showMessier, v => showMessier = v);
spBind('cfgSunMoonShow', () => showSunMoon, v => showSunMoon = v);
@@ -2394,10 +2294,6 @@ if (EMBEDDED_MESSIER_ERROR) {
console.warn('Messier-Daten aus der Datenbank nicht geladen:', EMBEDDED_MESSIER_ERROR);
}
-if (EMBEDDED_MILKY_WAY_ERROR) {
- console.warn('Milchstraßen-Daten nicht geladen:', EMBEDDED_MILKY_WAY_ERROR);
-}
-
function updateStarLoadingUi(done, total) {
if (!starLoadingOverlay || !starLoadingFill || !starLoadingStatus || !starLoadingNote) return;
const safeTotal = Math.max(1, total);