PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); $searchQuery = trim((string) ($_GET['q'] ?? '')); $showMode = trim((string) ($_GET['mode'] ?? 'all')); $allowedModes = ['all', 'active']; if (!in_array($showMode, $allowedModes, true)) { $showMode = 'all'; } function h(?string $value): string { return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); } function normalizeSolarLongitude(float $value): float { $normalized = fmod($value, 360.0); if ($normalized < 0.0) { $normalized += 360.0; } return $normalized; } function currentSolarLongitude(DateTimeImmutable $dateTime): float { $julianDay = ((float) $dateTime->format('U')) / 86400.0 + 2440587.5; $daysSinceJ2000 = $julianDay - 2451545.0; $meanLongitude = normalizeSolarLongitude(280.46 + 0.9856474 * $daysSinceJ2000); $meanAnomalyRad = deg2rad(normalizeSolarLongitude(357.528 + 0.9856003 * $daysSinceJ2000)); return normalizeSolarLongitude( $meanLongitude + 1.915 * sin($meanAnomalyRad) + 0.020 * sin(2.0 * $meanAnomalyRad) ); } function fetchCurrentSolarLongitude(DateTimeZone $displayTimezone): ?float { $pythonResult = runPythonApi('current_solar_longitude', [$displayTimezone->getName()]); if (!$pythonResult['ok']) { return null; } $solarLongitude = $pythonResult['data']['result']['solar_longitude_deg'] ?? null; if (!is_numeric($solarLongitude)) { return null; } return normalizeSolarLongitude((float) $solarLongitude); } function isSolarLongitudeInRange(float $current, ?float $start, ?float $finish): bool { if ($start === null || $finish === null) { return false; } $current = normalizeSolarLongitude($current); $start = normalizeSolarLongitude($start); $finish = normalizeSolarLongitude($finish); if ($start <= $finish) { return $current >= $start && $current <= $finish; } return $current >= $start || $current <= $finish; } function solarLongitudeToUtcDate(?float $targetLongitude, int $year, DateTimeZone $displayTimezone): ?DateTimeImmutable { if ($targetLongitude === null) { return null; } static $cache = []; $cacheKey = $year . '|' . $displayTimezone->getName() . '|' . number_format((float) $targetLongitude, 6, '.', ''); if (array_key_exists($cacheKey, $cache)) { return $cache[$cacheKey]; } $pythonResult = runPythonApi('solar_longitude_to_datetime', [ (string) $targetLongitude, (string) $year, $displayTimezone->getName(), ]); if (!$pythonResult['ok']) { $cache[$cacheKey] = null; return null; } $resultData = $pythonResult['data']; $utcIso = trim((string) ($resultData['result']['utc_iso'] ?? '')); if ($utcIso === '') { $cache[$cacheKey] = null; return null; } try { $cache[$cacheKey] = new DateTimeImmutable($utcIso); } catch (Throwable $e) { $cache[$cacheKey] = null; return null; } return $cache[$cacheKey]; } function warmSolarLongitudeDateCache(array $showers, int $year, DateTimeZone $displayTimezone): void { $uniqueLongitudes = []; foreach ($showers as $shower) { foreach (['active_start_sol', 'active_finish_sol', 'peak_sol'] as $field) { if (!isset($shower[$field]) || $shower[$field] === null || $shower[$field] === '') { continue; } $key = number_format((float) $shower[$field], 6, '.', ''); $uniqueLongitudes[$key] = (float) $shower[$field]; } } foreach ($uniqueLongitudes as $solarLongitude) { solarLongitudeToUtcDate($solarLongitude, $year, $displayTimezone); } } function formatNullableNumber(mixed $value, int $decimals = 1, string $suffix = ''): string { if ($value === null || $value === '') { return '-'; } return number_format((float) $value, $decimals, ',', '.') . $suffix; } function formatSolarLongitudeWithDate(?float $solarLongitude, int $year, DateTimeZone $displayTimezone): string { if ($solarLongitude === null) { return '-'; } $label = number_format((float) $solarLongitude, 2, ',', '.') . '°'; $date = solarLongitudeToUtcDate($solarLongitude, $year, $displayTimezone); if (!$date instanceof DateTimeImmutable) { return $label; } return $label . '
' . htmlspecialchars($date->setTimezone($displayTimezone)->format('d.m.Y'), ENT_QUOTES, 'UTF-8') . ''; } $displayTimezone = new DateTimeZone(date_default_timezone_get() ?: 'Europe/Berlin'); $displayYear = (int) (new DateTimeImmutable('now', $displayTimezone))->format('Y'); $todaySolarLongitude = fetchCurrentSolarLongitude($displayTimezone) ?? currentSolarLongitude(new DateTimeImmutable('now', new DateTimeZone('UTC'))); $sql = " SELECT `id`, `shower_code`, `iau_no`, `designation`, `speed_kms`, `radiant_alpha_deg`, `radiant_delta_deg`, `parent_object`, `population_index`, `active_start_sol`, `active_finish_sol`, `peak_sol`, `zhr`, `zhr_variable`, `has_yearly_variants` FROM `meteorshowers` WHERE 1 = 1 "; $params = []; if ($searchQuery !== '') { $sql .= " AND ( `shower_code` LIKE :query OR `designation` LIKE :query OR `parent_object` LIKE :query ) "; $params[':query'] = '%' . $searchQuery . '%'; } $sql .= " ORDER BY COALESCE(`zhr`, 0) DESC, `peak_sol` IS NULL ASC, `peak_sol` ASC, `designation` ASC "; $stmt = $pdo->prepare($sql); $stmt->execute($params); $allShowers = $stmt->fetchAll(); $showers = []; $activeCount = 0; foreach ($allShowers as $shower) { $isActive = isSolarLongitudeInRange( $todaySolarLongitude, isset($shower['active_start_sol']) ? (float) $shower['active_start_sol'] : null, isset($shower['active_finish_sol']) ? (float) $shower['active_finish_sol'] : null ); if ($isActive) { $activeCount++; } $shower['is_active_now'] = $isActive; if ($showMode === 'active' && !$isActive) { continue; } $showers[] = $shower; } warmSolarLongitudeDateCache($showers, $displayYear, $displayTimezone); $topZhr = null; foreach ($allShowers as $shower) { if ($shower['zhr'] !== null) { $topZhr = (int) $shower['zhr']; break; } } require __DIR__ . '/header.php'; ?> 'Importierte Meteorströme', 'value' => (string) count($allShowers)], ['label' => 'Davon aktuell aktiv', 'value' => (string) $activeCount], ['label' => 'Höchste ZHR', 'value' => $topZhr !== null ? (string) $topZhr : '-'], ['label' => 'Aktuelle solare Länge', 'value' => number_format($todaySolarLongitude, 2, ',', '.') . '°'], ['label' => 'Datumsumrechnung', 'value' => (string) $displayYear], ]; ?>
Zurücksetzen

Liste der Meteorströme

Die Gradangaben in Aktivität und Maximum sind Werte der solaren Länge. Zusätzlich wird dafür ein Kalenderdatum im Jahr angezeigt.

Keine Meteorströme für diese Auswahl gefunden.

Status Code IAU Bezeichnung ZHR Aktivität (solare Länge) Maximum (solare Länge) Radiant vg Mutterkörper
Aktiv Inaktiv
mit Jahresvarianten
bis RA
Dec