Ephemeriden berechnet nun auch Kleinplaneten und Kometen
This commit is contained in:
+231
-8
@@ -15,6 +15,82 @@ $headerIntroSub = '';
|
||||
|
||||
$loggedIn = isset($_SESSION['user_id']);
|
||||
$defaultLocation = null;
|
||||
$favoriteMinorplanetOptions = [];
|
||||
$favoriteCometOptions = [];
|
||||
$minorplanetPayloads = [];
|
||||
$cometPayloads = [];
|
||||
|
||||
function decodeMpcPackedDateChar(string $value): ?int
|
||||
{
|
||||
if ($value >= '0' && $value <= '9') {
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
$upper = strtoupper($value);
|
||||
if ($upper >= 'A' && $upper <= 'V') {
|
||||
return ord($upper) - ord('A') + 10;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function decodeMpcPackedDate(?string $packed): ?string
|
||||
{
|
||||
if ($packed === null || strlen($packed) !== 5) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$centuryMap = [
|
||||
'I' => 1800,
|
||||
'J' => 1900,
|
||||
'K' => 2000,
|
||||
];
|
||||
|
||||
$centuryCode = strtoupper($packed[0]);
|
||||
if (!isset($centuryMap[$centuryCode])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$yearPart = substr($packed, 1, 2);
|
||||
if (!ctype_digit($yearPart)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$month = decodeMpcPackedDateChar($packed[3]);
|
||||
$day = decodeMpcPackedDateChar($packed[4]);
|
||||
if ($month === null || $day === null || $month < 1 || $month > 12 || $day < 1 || $day > 31) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return sprintf('%04d-%02d-%02d', $centuryMap[$centuryCode] + (int) $yearPart, $month, $day);
|
||||
}
|
||||
|
||||
function buildCometPerihelionIso(array $comet): ?string
|
||||
{
|
||||
$year = isset($comet['year_of_perihelion']) ? (int) $comet['year_of_perihelion'] : 0;
|
||||
$month = isset($comet['month_of_perihelion']) ? (int) $comet['month_of_perihelion'] : 0;
|
||||
$dayValue = isset($comet['day_of_perihelion']) ? (float) $comet['day_of_perihelion'] : 0.0;
|
||||
|
||||
if ($year <= 0 || $month < 1 || $month > 12 || $dayValue <= 0.0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$day = (int) floor($dayValue);
|
||||
if ($day < 1 || $day > 31) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$fractionalDay = $dayValue - $day;
|
||||
$seconds = (int) round($fractionalDay * 86400.0);
|
||||
|
||||
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))->format('c');
|
||||
}
|
||||
|
||||
if ($loggedIn && isset($_SESSION['user_id'])) {
|
||||
try {
|
||||
@@ -37,8 +113,104 @@ if ($loggedIn && isset($_SESSION['user_id'])) {
|
||||
);
|
||||
$stmtLoc->execute([(int) $_SESSION['user_id']]);
|
||||
$defaultLocation = $stmtLoc->fetch() ?: null;
|
||||
|
||||
$stmtFavoriteMinorplanets = $pdo->prepare(
|
||||
'SELECT
|
||||
mp.id,
|
||||
mp.mp_number,
|
||||
mp.designation_text,
|
||||
mp.desig_packed,
|
||||
mp.epoch_packed,
|
||||
mp.mean_anomaly_deg,
|
||||
mp.arg_perihelion_deg,
|
||||
mp.ascending_node_deg,
|
||||
mp.inclination_deg,
|
||||
mp.eccentricity,
|
||||
mp.mean_motion_deg_per_day,
|
||||
mp.semimajor_axis_au
|
||||
FROM app_user_minorplanets aum
|
||||
INNER JOIN minorplanets_mpc mp
|
||||
ON mp.id = aum.minorplanet_id
|
||||
WHERE aum.user_id = ?
|
||||
ORDER BY aum.is_favorite DESC, mp.mp_number IS NULL ASC, mp.mp_number ASC, mp.designation_text ASC'
|
||||
);
|
||||
$stmtFavoriteMinorplanets->execute([(int) $_SESSION['user_id']]);
|
||||
foreach ($stmtFavoriteMinorplanets->fetchAll() as $minorplanet) {
|
||||
$minorplanetLabel = trim((string) ($minorplanet['designation_text'] ?? ''));
|
||||
if ($minorplanetLabel === '') {
|
||||
$minorplanetLabel = trim((string) ($minorplanet['desig_packed'] ?? ''));
|
||||
}
|
||||
if ($minorplanetLabel === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
$minorplanet['mp_number'] !== null
|
||||
&& !str_contains($minorplanetLabel, '(' . (string) $minorplanet['mp_number'] . ')')
|
||||
) {
|
||||
$minorplanetLabel = '(' . (string) $minorplanet['mp_number'] . ') ' . $minorplanetLabel;
|
||||
}
|
||||
|
||||
$bodyKey = 'minorplanet:' . (string) $minorplanet['id'];
|
||||
$favoriteMinorplanetOptions[$bodyKey] = $minorplanetLabel;
|
||||
$minorplanetPayloads[$bodyKey] = [
|
||||
'id' => (int) $minorplanet['id'],
|
||||
'designation' => $minorplanetLabel,
|
||||
'epochDateIso' => decodeMpcPackedDate((string) ($minorplanet['epoch_packed'] ?? '')),
|
||||
'meanAnomalyDeg' => isset($minorplanet['mean_anomaly_deg']) ? (float) $minorplanet['mean_anomaly_deg'] : null,
|
||||
'argPerihelionDeg' => isset($minorplanet['arg_perihelion_deg']) ? (float) $minorplanet['arg_perihelion_deg'] : null,
|
||||
'ascendingNodeDeg' => isset($minorplanet['ascending_node_deg']) ? (float) $minorplanet['ascending_node_deg'] : null,
|
||||
'inclinationDeg' => isset($minorplanet['inclination_deg']) ? (float) $minorplanet['inclination_deg'] : null,
|
||||
'eccentricity' => isset($minorplanet['eccentricity']) ? (float) $minorplanet['eccentricity'] : null,
|
||||
'meanMotionDegPerDay' => isset($minorplanet['mean_motion_deg_per_day']) ? (float) $minorplanet['mean_motion_deg_per_day'] : null,
|
||||
'semimajorAxisAu' => isset($minorplanet['semimajor_axis_au']) ? (float) $minorplanet['semimajor_axis_au'] : null,
|
||||
];
|
||||
}
|
||||
|
||||
$stmtFavoriteComets = $pdo->prepare(
|
||||
'SELECT
|
||||
c.id,
|
||||
c.designation_and_name,
|
||||
c.year_of_perihelion,
|
||||
c.month_of_perihelion,
|
||||
c.day_of_perihelion,
|
||||
c.perihelion_dist_au,
|
||||
c.eccentricity,
|
||||
c.arg_perihelion_deg,
|
||||
c.ascending_node_deg,
|
||||
c.inclination_deg
|
||||
FROM app_user_comets auc
|
||||
INNER JOIN comets_mpc c
|
||||
ON c.id = auc.comet_id
|
||||
WHERE auc.user_id = ?
|
||||
ORDER BY auc.is_favorite DESC, c.designation_and_name ASC'
|
||||
);
|
||||
$stmtFavoriteComets->execute([(int) $_SESSION['user_id']]);
|
||||
foreach ($stmtFavoriteComets->fetchAll() as $comet) {
|
||||
$cometLabel = trim((string) ($comet['designation_and_name'] ?? ''));
|
||||
if ($cometLabel === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$bodyKey = 'comet:' . (string) $comet['id'];
|
||||
$favoriteCometOptions[$bodyKey] = $cometLabel;
|
||||
$cometPayloads[$bodyKey] = [
|
||||
'id' => (int) $comet['id'],
|
||||
'designation' => $cometLabel,
|
||||
'perihelionIso' => buildCometPerihelionIso($comet),
|
||||
'perihelionDistanceAu' => isset($comet['perihelion_dist_au']) ? (float) $comet['perihelion_dist_au'] : null,
|
||||
'eccentricity' => isset($comet['eccentricity']) ? (float) $comet['eccentricity'] : null,
|
||||
'argPerihelionDeg' => isset($comet['arg_perihelion_deg']) ? (float) $comet['arg_perihelion_deg'] : null,
|
||||
'ascendingNodeDeg' => isset($comet['ascending_node_deg']) ? (float) $comet['ascending_node_deg'] : null,
|
||||
'inclinationDeg' => isset($comet['inclination_deg']) ? (float) $comet['inclination_deg'] : null,
|
||||
];
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$defaultLocation = null;
|
||||
$favoriteMinorplanetOptions = [];
|
||||
$favoriteCometOptions = [];
|
||||
$minorplanetPayloads = [];
|
||||
$cometPayloads = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +226,8 @@ $planetOptions = [
|
||||
'Neptune' => 'Neptun',
|
||||
];
|
||||
|
||||
$bodyOptions = $planetOptions + $favoriteMinorplanetOptions + $favoriteCometOptions;
|
||||
|
||||
$intervalOptions = [
|
||||
'1' => '1 Minute',
|
||||
'10' => '10 Minuten',
|
||||
@@ -77,7 +251,7 @@ $rangeUnitOptions = [
|
||||
];
|
||||
|
||||
$selectedBody = (string) ($_POST['body'] ?? 'Mercury');
|
||||
if (!isset($planetOptions[$selectedBody])) {
|
||||
if (!isset($bodyOptions[$selectedBody])) {
|
||||
$selectedBody = 'Mercury';
|
||||
}
|
||||
|
||||
@@ -174,10 +348,13 @@ $exportFormat = (string) ($_POST['export_format'] ?? '');
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if ($pageLocation === null || $pageLocation['latitude'] === null || $pageLocation['longitude'] === null) {
|
||||
$errorMessage = 'Kein gültiger Standard-Standort verfügbar. Bitte zuerst in den Einstellungen einen Standard-Standort setzen.';
|
||||
} elseif (false && (str_starts_with($selectedBody, 'comet:') || str_starts_with($selectedBody, 'minorplanet:'))) {
|
||||
$errorMessage = 'Favoriten-Kometen und Favoriten-Kleinplaneten sind jetzt in der Auswahl sichtbar. Die eigentliche Ephemeriden-Berechnung dafür binden wir als Nächstes an.';
|
||||
} elseif (!ctype_digit($rangeValueInput) || (int) $rangeValueInput < 1 || (int) $rangeValueInput > 31) {
|
||||
$errorMessage = 'Der Zeitraum muss als ganze Zahl zwischen 1 und 31 angegeben werden.';
|
||||
} else {
|
||||
$pythonResult = runEphemeridenPythonApi('planet_ephemeris', [
|
||||
$pythonAction = 'planet_ephemeris';
|
||||
$pythonArgs = [
|
||||
(string) $pageLocation['latitude'],
|
||||
(string) $pageLocation['longitude'],
|
||||
(string) $pageLocation['elevation'],
|
||||
@@ -186,7 +363,37 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$selectedInterval,
|
||||
$rangeValueInput,
|
||||
$selectedRangeUnit,
|
||||
]);
|
||||
];
|
||||
|
||||
if (isset($minorplanetPayloads[$selectedBody])) {
|
||||
$pythonAction = 'small_body_ephemeris';
|
||||
$pythonArgs = [
|
||||
(string) $pageLocation['latitude'],
|
||||
(string) $pageLocation['longitude'],
|
||||
(string) $pageLocation['elevation'],
|
||||
(string) $pageLocation['timezone'],
|
||||
'minorplanet',
|
||||
base64_encode(json_encode($minorplanetPayloads[$selectedBody], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}'),
|
||||
$selectedInterval,
|
||||
$rangeValueInput,
|
||||
$selectedRangeUnit,
|
||||
];
|
||||
} elseif (isset($cometPayloads[$selectedBody])) {
|
||||
$pythonAction = 'small_body_ephemeris';
|
||||
$pythonArgs = [
|
||||
(string) $pageLocation['latitude'],
|
||||
(string) $pageLocation['longitude'],
|
||||
(string) $pageLocation['elevation'],
|
||||
(string) $pageLocation['timezone'],
|
||||
'comet',
|
||||
base64_encode(json_encode($cometPayloads[$selectedBody], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}'),
|
||||
$selectedInterval,
|
||||
$rangeValueInput,
|
||||
$selectedRangeUnit,
|
||||
];
|
||||
}
|
||||
|
||||
$pythonResult = runEphemeridenPythonApi($pythonAction, $pythonArgs);
|
||||
|
||||
if (!$pythonResult['ok']) {
|
||||
$errorMessage = (string) (
|
||||
@@ -201,7 +408,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
if ($exportFormat === 'csv' && $ephemerisRows !== []) {
|
||||
$filename = 'ephemeriden-' . ephemeriden_slug((string) ($planetOptions[$selectedBody] ?? 'objekt')) . '.csv';
|
||||
$filename = 'ephemeriden-' . ephemeriden_slug((string) ($bodyOptions[$selectedBody] ?? 'objekt')) . '.csv';
|
||||
|
||||
header('Content-Type: text/csv; charset=utf-8');
|
||||
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
||||
@@ -335,11 +542,27 @@ require __DIR__ . '/header.php';
|
||||
<form method="post" class="ephemeriden-form">
|
||||
<div class="ephemeriden-fields-row">
|
||||
<div class="form-group">
|
||||
<label for="ephemeridenBody">Planet</label>
|
||||
<label for="ephemeridenBody">Himmelskörper</label>
|
||||
<select id="ephemeridenBody" name="body">
|
||||
<?php foreach ($planetOptions as $bodyValue => $bodyLabel): ?>
|
||||
<option value="<?= ephemeriden_h($bodyValue) ?>"<?= $bodyValue === $selectedBody ? ' selected' : '' ?>><?= ephemeriden_h($bodyLabel) ?></option>
|
||||
<?php endforeach; ?>
|
||||
<optgroup label="Sonne, Mond und Planeten">
|
||||
<?php foreach ($planetOptions as $bodyValue => $bodyLabel): ?>
|
||||
<option value="<?= ephemeriden_h($bodyValue) ?>"<?= $bodyValue === $selectedBody ? ' selected' : '' ?>><?= ephemeriden_h($bodyLabel) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</optgroup>
|
||||
<?php if ($favoriteMinorplanetOptions !== []): ?>
|
||||
<optgroup label="Meine Kleinplaneten">
|
||||
<?php foreach ($favoriteMinorplanetOptions as $bodyValue => $bodyLabel): ?>
|
||||
<option value="<?= ephemeriden_h($bodyValue) ?>"<?= $bodyValue === $selectedBody ? ' selected' : '' ?>><?= ephemeriden_h($bodyLabel) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</optgroup>
|
||||
<?php endif; ?>
|
||||
<?php if ($favoriteCometOptions !== []): ?>
|
||||
<optgroup label="Meine Kometen">
|
||||
<?php foreach ($favoriteCometOptions as $bodyValue => $bodyLabel): ?>
|
||||
<option value="<?= ephemeriden_h($bodyValue) ?>"<?= $bodyValue === $selectedBody ? ' selected' : '' ?>><?= ephemeriden_h($bodyLabel) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</optgroup>
|
||||
<?php endif; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user