diff --git a/config/rechtesystem.json b/config/rechtesystem.json index e1e679d..c8dbffc 100644 --- a/config/rechtesystem.json +++ b/config/rechtesystem.json @@ -44,6 +44,10 @@ "label": "Planetensichtbarkeit", "menu_group": "Himmel & Planeten" }, + "comets.php": { + "label": "Kometen", + "menu_group": "Himmel & Planeten" + }, "astronomical_conversions.php": { "label": "Astronomical Conversions", "menu_group": "Himmel & Planeten" @@ -116,6 +120,7 @@ "links": [ "moonphase.php", "planetensichtbarkeit.php", + "comets.php", "astronomical_conversions.php", "tcrb_lightcurve.php", "solarsystem.php", diff --git a/public/auth_helpers.php b/public/auth_helpers.php index b0f3ecd..e3a79d1 100644 --- a/public/auth_helpers.php +++ b/public/auth_helpers.php @@ -58,6 +58,7 @@ function manageablePublicPages(): array 'my_favorites.php' => 'Favoriten', 'moonphase.php' => 'Mondphase', 'planetensichtbarkeit.php' => 'Planetensichtbarkeit', + 'comets.php' => 'Kometen', 'astronomical_conversions.php' => 'Astronomical Conversions', 'tcrb_lightcurve.php' => 'T CrB Lichtkurve', 'solarsystem.php' => 'Sonnensystem', diff --git a/public/comets.php b/public/comets.php new file mode 100644 index 0000000..ddd5cda --- /dev/null +++ b/public/comets.php @@ -0,0 +1,511 @@ + 12 || $dayValue <= 0) { + return null; + } + + $day = (int) floor($dayValue); + if ($day < 1 || $day > 31) { + return null; + } + + $fractionalDay = $dayValue - $day; + $seconds = (int) round($fractionalDay * 86400); + + try { + $date = new DateTimeImmutable(sprintf('%04d-%02d-%02d 00:00:00', $year, $month, $day), new DateTimeZone('UTC')); + } catch (Throwable $e) { + return null; + } + + return $date->modify(sprintf('+%d seconds', $seconds)); +} + +function classifyOrbitType(string $orbitType): string +{ + return match (strtoupper(trim($orbitType))) { + 'P' => 'Periodisch', + 'C' => 'Nicht periodisch', + 'I' => 'Interstellar', + 'D' => 'Verschollen / zerfallen', + 'A' => 'Asteroidal', + default => trim($orbitType) !== '' ? trim($orbitType) : '-', + }; +} + +function estimatePerihelMagnitude(?float $absoluteMagnitudeH, ?float $perihelionDistanceAu): ?float +{ + if ($absoluteMagnitudeH === null || !is_finite($absoluteMagnitudeH) || $perihelionDistanceAu === null || !is_finite($perihelionDistanceAu) || $perihelionDistanceAu <= 0.0) { + return null; + } + + $heliocentricDistance = max(0.05, $perihelionDistanceAu); + $geocentricDistance = max(0.2, abs(1.0 - $perihelionDistanceAu)); + + return $absoluteMagnitudeH + + (5.0 * log10($geocentricDistance)) + + (10.0 * log10($heliocentricDistance)); +} + +$config = require __DIR__ . '/../config/database.php'; +$dsn = sprintf( + 'mysql:host=%s;dbname=%s;charset=%s', + $config['host'], + $config['dbname'], + $config['charset'] ?? 'utf8mb4' +); + +$pdo = new PDO( + $dsn, + $config['user'], + $config['pass'], + [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + ] +); + +$userId = isset($_SESSION['user_id']) ? (int) $_SESSION['user_id'] : 0; +$today = new DateTimeImmutable('today', new DateTimeZone('UTC')); +$windowStart = $today->modify('-180 days'); +$windowEnd = $today->modify('+365 days'); +$queryYearMin = (int) $windowStart->format('Y') - 1; +$queryYearMax = (int) $windowEnd->format('Y') + 1; + +$stmtComets = $pdo->prepare(" + SELECT + c.*, + CASE WHEN auc.`comet_id` IS NULL THEN 0 ELSE 1 END AS `is_tracked`, + CASE WHEN auc.`is_favorite` = 1 THEN 1 ELSE 0 END AS `is_favorite` + FROM `comets_mpc` c + LEFT JOIN `app_user_comets` auc + ON auc.`comet_id` = c.`id` + AND auc.`user_id` = :user_id + WHERE c.`year_of_perihelion` BETWEEN :year_min AND :year_max + OR auc.`comet_id` IS NOT NULL + ORDER BY c.`year_of_perihelion` ASC, c.`month_of_perihelion` ASC, c.`day_of_perihelion` ASC, c.`designation_and_name` ASC +"); +$stmtComets->execute([ + ':user_id' => $userId, + ':year_min' => $queryYearMin, + ':year_max' => $queryYearMax, +]); + +$allComets = []; +$trackedComets = []; +$interestingComets = []; + +foreach ($stmtComets as $row) { + $perihelionDate = buildPerihelionDate($row); + $daysFromToday = $perihelionDate ? (int) floor(($perihelionDate->getTimestamp() - $today->getTimestamp()) / 86400) : null; + + $row['perihelion_date_object'] = $perihelionDate; + $row['perihelion_date_display'] = $perihelionDate ? $perihelionDate->setTimezone(new DateTimeZone('Europe/Berlin'))->format('d.m.Y H:i') . ' UTC' : '-'; + $row['days_from_today'] = $daysFromToday; + $row['orbit_type_label'] = classifyOrbitType((string) ($row['orbit_type'] ?? '')); + $row['absolute_magnitude_display'] = isset($row['absolute_magnitude_h']) && $row['absolute_magnitude_h'] !== null + ? formatDecimalGerman((float) $row['absolute_magnitude_h'], 1) + : '-'; + $row['slope_parameter_display'] = isset($row['slope_parameter_g']) && $row['slope_parameter_g'] !== null + ? formatDecimalGerman((float) $row['slope_parameter_g'], 1) + : '-'; + $row['perihelion_dist_display'] = formatDecimalGerman(isset($row['perihelion_dist_au']) ? (float) $row['perihelion_dist_au'] : null, 3); + $row['eccentricity_display'] = formatDecimalGerman(isset($row['eccentricity']) ? (float) $row['eccentricity'] : null, 4); + $row['inclination_display'] = formatDecimalGerman(isset($row['inclination_deg']) ? (float) $row['inclination_deg'] : null, 2); + $estimatedPerihelMagnitude = estimatePerihelMagnitude( + isset($row['absolute_magnitude_h']) && $row['absolute_magnitude_h'] !== null ? (float) $row['absolute_magnitude_h'] : null, + isset($row['perihelion_dist_au']) && $row['perihelion_dist_au'] !== null ? (float) $row['perihelion_dist_au'] : null + ); + $row['estimated_perihel_magnitude'] = $estimatedPerihelMagnitude; + $row['estimated_perihel_magnitude_display'] = $estimatedPerihelMagnitude !== null + ? formatDecimalGerman($estimatedPerihelMagnitude, 1) + : '-'; + + $allComets[] = $row; + + if ((int) ($row['is_tracked'] ?? 0) === 1) { + $trackedComets[] = $row; + } + + if ($perihelionDate !== null && $perihelionDate >= $windowStart && $perihelionDate <= $windowEnd) { + $interestingComets[] = $row; + } +} + +usort($trackedComets, static function (array $left, array $right): int { + $favoriteCompare = ((int) $right['is_favorite']) <=> ((int) $left['is_favorite']); + if ($favoriteCompare !== 0) { + return $favoriteCompare; + } + + return ((int) ($left['days_from_today'] ?? PHP_INT_MAX)) <=> ((int) ($right['days_from_today'] ?? PHP_INT_MAX)); +}); + +usort($interestingComets, static function (array $left, array $right): int { + $leftDistance = abs((int) ($left['days_from_today'] ?? PHP_INT_MAX)); + $rightDistance = abs((int) ($right['days_from_today'] ?? PHP_INT_MAX)); + if ($leftDistance !== $rightDistance) { + return $leftDistance <=> $rightDistance; + } + + return strcmp((string) $left['designation_and_name'], (string) $right['designation_and_name']); +}); + +$interestingComets = array_slice($interestingComets, 0, 24); +$orbitTypeCounts = []; +foreach ($allComets as $comet) { + $orbitKey = (string) ($comet['orbit_type'] ?? '?'); + $orbitTypeCounts[$orbitKey] = ($orbitTypeCounts[$orbitKey] ?? 0) + 1; +} +arsort($orbitTypeCounts); +?> + + + + +
+ Diese erste Version liest die vorhandenen Kometen direkt aus comets_mpc und hebt Objekte hervor,
+ deren Perihel zwischen = h($windowStart->format('d.m.Y')) ?> und
+ = h($windowEnd->format('d.m.Y')) ?> liegt.
+ Nutzer-Favoriten aus app_user_comets werden zusaetzlich separat gezeigt.
+
+ Die Spalte m grob ist eine sehr einfache Helligkeitsschaetzung nahe dem Perihel
+ auf Basis von MPC-H und q. Sie ist nur als Orientierung gedacht.
+
Du hast aktuell noch keine Kometen in deinen Favoriten. In Favoriten kannst du welche markieren.
+ +| Komet | +Typ | +Perihel | +Abstand | +m grob | +
|---|---|---|---|---|
|
+ = h((string) $comet['designation_and_name']) ?>
+
+ |
+ = h((string) $comet['orbit_type_label']) ?> | += h((string) $comet['perihelion_date_display']) ?> | += h($daysLabel) ?> | += h((string) $comet['estimated_perihel_magnitude_display']) ?> | +
Sortiert nach Naehe zum heutigen Datum bezogen auf den Periheldurchgang.
+ +Im aktuellen Zeitfenster wurden keine Kometen gefunden.
+ +| Komet | +Typ | +Perihel | +Abstand | +m grob | +H | +G | +
|---|---|---|---|---|---|---|
|
+ = h((string) $comet['designation_and_name']) ?>
+
+ |
+ = h((string) $comet['orbit_type_label']) ?> | += h((string) $comet['perihelion_date_display']) ?> | += h($daysLabel) ?> | += h((string) $comet['estimated_perihel_magnitude_display']) ?> | += h((string) $comet['absolute_magnitude_display']) ?> | += h((string) $comet['slope_parameter_display']) ?> | +