From ec67e85ab70e1c8bb7538998d70f2377507f7230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 3 Apr 2026 19:00:36 +0200 Subject: [PATCH] meteorshowers.php schnell eingebaut --- public/header.php | 1 + public/meteorshowers.php | 346 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 347 insertions(+) create mode 100644 public/meteorshowers.php diff --git a/public/header.php b/public/header.php index 98a9df9..4581fd7 100644 --- a/public/header.php +++ b/public/header.php @@ -59,6 +59,7 @@ $menuGroups = [ ['href' => 'jupitersystem.php', 'label' => 'Jupitersystem'], ['href' => 'tagbogen.php', 'label' => 'Tagbogen'], ['href' => 'sternenhimmel.php', 'label' => 'Sternenhimmel'], + ['href' => 'meteorshowers.php', 'label' => 'Meteorstroeme'], ['href' => 'geocron/index.php', 'label' => 'Geocron'], ['href' => 'geocron3d.php', 'label' => 'Geocron 3D'], ], diff --git a/public/meteorshowers.php b/public/meteorshowers.php new file mode 100644 index 0000000..2ed0a91 --- /dev/null +++ b/public/meteorshowers.php @@ -0,0 +1,346 @@ + 'Sternwarte Sonneberg', + 'latitude' => 50.3547, + 'longitude' => 11.1900, + 'elevation' => 640.0, + 'timezone' => 'Europe/Berlin', +]; +$meteorRows = []; +$pageError = null; + +function normalizeMeteorDegree(float $value): float +{ + $normalized = fmod($value, 360.0); + if ($normalized < 0.0) { + $normalized += 360.0; + } + + return $normalized; +} + +function meteorSolarLongitude(DateTimeImmutable $dateTime): float +{ + $julianDay = ((float) $dateTime->format('U')) / 86400.0 + 2440587.5; + $daysSinceJ2000 = $julianDay - 2451545.0; + $meanLongitude = normalizeMeteorDegree(280.46 + 0.9856474 * $daysSinceJ2000); + $meanAnomalyRad = deg2rad(normalizeMeteorDegree(357.528 + 0.9856003 * $daysSinceJ2000)); + + return normalizeMeteorDegree( + $meanLongitude + + 1.915 * sin($meanAnomalyRad) + + 0.020 * sin(2.0 * $meanAnomalyRad) + ); +} + +function meteorForwardDegreeDistance(float $from, float $to): float +{ + return normalizeMeteorDegree($to - $from); +} + +function meteorRadiantIsVisible(float $latitudeDeg, ?float $declinationDeg): bool +{ + if ($declinationDeg === null) { + return false; + } + + return abs($latitudeDeg - $declinationDeg) < 90.0; +} + +function findMeteorSolarLongitudeCrossing( + DateTimeImmutable $rangeStartLocal, + DateTimeImmutable $rangeEndLocal, + float $targetLongitude, + DateTimeZone $displayTimezone +): ?DateTimeImmutable { + $utc = new DateTimeZone('UTC'); + $rangeStartUtc = $rangeStartLocal->setTimezone($utc); + $rangeEndUtc = $rangeEndLocal->setTimezone($utc); + + $startLongitude = meteorSolarLongitude($rangeStartUtc); + $endLongitude = meteorSolarLongitude($rangeEndUtc); + $targetDelta = meteorForwardDegreeDistance($startLongitude, $targetLongitude); + $rangeDelta = meteorForwardDegreeDistance($startLongitude, $endLongitude); + + if ($targetDelta > $rangeDelta + 0.0001) { + return null; + } + + $low = (int) $rangeStartUtc->format('U'); + $high = (int) $rangeEndUtc->format('U'); + + for ($i = 0; $i < 40; $i++) { + $mid = (int) floor(($low + $high) / 2); + $midLongitude = meteorSolarLongitude(new DateTimeImmutable('@' . $mid)); + $midDelta = meteorForwardDegreeDistance($startLongitude, $midLongitude); + + if ($midDelta < $targetDelta) { + $low = $mid; + } else { + $high = $mid; + } + } + + return (new DateTimeImmutable('@' . $high))->setTimezone($displayTimezone); +} + +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, + ] + ); + + if ($loggedIn && isset($_SESSION['user_id'])) { + $stmtLocation = $pdo->prepare( + 'SELECT id, name, latitude, longitude, elevation, timezone + FROM app_user_locations + WHERE user_id = ? AND is_default = 1 + LIMIT 1' + ); + $stmtLocation->execute([(int) $_SESSION['user_id']]); + $userLocation = $stmtLocation->fetch(); + if (is_array($userLocation)) { + $defaultLocation = $userLocation; + $locationIsGlobal = false; + } + } + + $stmt = $pdo->query( + "SELECT designation, shower_code, radiant_delta_deg, peak_sol, zhr, zhr_variable + FROM meteorshowers + WHERE peak_sol IS NOT NULL + ORDER BY peak_sol ASC, designation ASC" + ); + $meteorRows = $stmt->fetchAll(); +} catch (Throwable $e) { + $pageError = $e->getMessage(); +} + +require __DIR__ . '/header.php'; + +$displayTimezoneName = (string) (($currentLocation['timezone'] ?? null) ?: ($defaultLocation['timezone'] ?? 'Europe/Berlin')); +$displayTimezone = new DateTimeZone($displayTimezoneName); +$displayLocationName = (string) (($currentLocation['name'] ?? null) ?: ($defaultLocation['name'] ?? 'Sternwarte Sonneberg')); +$displayLatitude = isset($currentLocation['latitude']) ? (float) $currentLocation['latitude'] : (float) $defaultLocation['latitude']; +$currentYear = (int) (new DateTimeImmutable('now', $displayTimezone))->format('Y'); +$yearStart = new DateTimeImmutable(sprintf('%04d-01-01 00:00:00', $currentYear), $displayTimezone); +$yearEnd = $yearStart->modify('+1 year'); +$meteorEvents = []; + +foreach ($meteorRows as $row) { + if (!is_array($row) || !isset($row['peak_sol'])) { + continue; + } + + $peakDateTime = findMeteorSolarLongitudeCrossing( + $yearStart, + $yearEnd, + (float) $row['peak_sol'], + $displayTimezone + ); + if (!$peakDateTime instanceof DateTimeImmutable) { + continue; + } + + $visible = meteorRadiantIsVisible( + $displayLatitude, + $row['radiant_delta_deg'] !== null ? (float) $row['radiant_delta_deg'] : null + ); + + $zhrText = '-'; + if ($row['zhr'] !== null && (int) $row['zhr'] >= 0) { + $zhrText = 'ca. ' . (int) $row['zhr']; + } elseif (trim((string) ($row['zhr_variable'] ?? '')) !== '') { + $zhrText = 'ca. ' . trim((string) $row['zhr_variable']); + } + + $meteorEvents[] = [ + 'designation' => trim((string) ($row['designation'] ?? '')), + 'shower_code' => trim((string) ($row['shower_code'] ?? '')), + 'peak' => $peakDateTime, + 'visible' => $visible, + 'visible_label' => $visible ? 'vom Standort sichtbar' : 'vom Standort nicht sichtbar', + 'zhr_text' => $zhrText, + ]; +} + +usort( + $meteorEvents, + static fn (array $a, array $b): int => $a['peak'] <=> $b['peak'] +); +?> + +
+
+
+

Meteorstroeme

+

+ Einfache Jahresliste der Meteorstrom-Maxima fuer + + in . +

+
+ + +
+ Daten konnten nicht geladen werden: +
+ +
+ Fuer das aktuelle Jahr wurden keine Meteorstrom-Daten gefunden. +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
DatumUhrzeitMeteorstromCodeZHRSichtbarkeit
format('d.m.Y'), ENT_QUOTES, 'UTF-8') ?>format('H:i'), ENT_QUOTES, 'UTF-8') ?>
+
+ +
+
+ + + +