Beobachtungsvorschläge rein
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/** Catalog values are server-owned; the client only supplies selection filters. */
|
||||
function observationCatalog(PDO $pdo, array $types): array
|
||||
{
|
||||
$mapping = [
|
||||
'open_clusters' => ['OCl'], 'globular_clusters' => ['GCl'],
|
||||
'galaxies' => ['G', 'GPair', 'GTrpl', 'GGroup'],
|
||||
'nebulae' => ['Neb', 'EmN', 'HII', 'RfN', 'SNR', 'Cl+N'],
|
||||
'planetary_nebulae' => ['PN'], 'double_stars' => ['**'],
|
||||
];
|
||||
$codes = [];
|
||||
foreach ($mapping as $group => $groupCodes) {
|
||||
if (in_array($group, $types, true)) {
|
||||
foreach ($groupCodes as $code) {
|
||||
$codes[$code] = $group;
|
||||
}
|
||||
}
|
||||
}
|
||||
$objects = [];
|
||||
if ($codes !== []) {
|
||||
$placeholders = implode(',', array_fill(0, count($codes), '?'));
|
||||
$stmt = $pdo->prepare("SELECT id, name, messier, object_type_abrev, ra_deg, dec_deg, major_axis, v_mag
|
||||
FROM dso_objects WHERE object_type_abrev IN ($placeholders)
|
||||
AND ra_deg IS NOT NULL AND dec_deg IS NOT NULL");
|
||||
$stmt->execute(array_keys($codes));
|
||||
foreach ($stmt as $row) {
|
||||
$messier = trim((string) ($row['messier'] ?? ''));
|
||||
$objects[] = [
|
||||
'id' => 'dso-' . $row['id'],
|
||||
'name' => $row['name'] . ($messier !== '' ? ' · M ' . $messier : ''),
|
||||
'group' => $codes[$row['object_type_abrev']],
|
||||
'ra_deg' => (float) $row['ra_deg'], 'dec_deg' => (float) $row['dec_deg'],
|
||||
// OpenNGC MajAx is in arcminutes; GUI and Python use arcseconds.
|
||||
'size_arcsec' => $row['major_axis'] !== null && (float) $row['major_axis'] > 0
|
||||
? (float) $row['major_axis'] * 60 : null,
|
||||
'magnitude' => $row['v_mag'] !== null ? (float) $row['v_mag'] : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
if (in_array('variable_stars', $types, true)) {
|
||||
$stmt = $pdo->query("SELECT id, hip, proper, var, con, ra, `dec`, mag FROM star_hipparcos
|
||||
WHERE var IS NOT NULL AND TRIM(var) <> '' AND ra IS NOT NULL AND `dec` IS NOT NULL");
|
||||
foreach ($stmt as $row) {
|
||||
$name = trim((string) ($row['proper'] ?? ''));
|
||||
$objects[] = [
|
||||
'id' => 'star-' . $row['id'], 'name' => $name !== '' ? $name : trim($row['var'] . ' ' . ($row['con'] ?? '')),
|
||||
'group' => 'variable_stars', 'ra_deg' => (float) $row['ra'] * 15,
|
||||
'dec_deg' => (float) $row['dec'], 'size_arcsec' => null,
|
||||
'magnitude' => $row['mag'] !== null ? (float) $row['mag'] : null,
|
||||
'note' => 'HIP ' . $row['hip'] . ' · Keine Minima-/Maxima-Vorhersage',
|
||||
];
|
||||
}
|
||||
}
|
||||
if (in_array('comets', $types, true)) {
|
||||
$stmt = $pdo->query('SELECT id, designation_and_name, year_of_perihelion, month_of_perihelion,
|
||||
day_of_perihelion, perihelion_dist_au, eccentricity, arg_perihelion_deg, ascending_node_deg,
|
||||
inclination_deg, absolute_magnitude_h, slope_parameter_g, epoch_date FROM comets_mpc');
|
||||
foreach ($stmt as $row) {
|
||||
$objects[] = ['id' => 'comet-' . $row['id'], 'name' => $row['designation_and_name'],
|
||||
'group' => 'comets', 'size_arcsec' => null, 'orbit' => $row,
|
||||
'note' => 'Bahnepoche: ' . ($row['epoch_date'] ?? 'unbekannt')];
|
||||
}
|
||||
}
|
||||
return $objects;
|
||||
}
|
||||
|
||||
function runObservationSuggestions(array $payload): array
|
||||
{
|
||||
$file = tempnam(sys_get_temp_dir(), 'skyview_observation_');
|
||||
if ($file === false) {
|
||||
throw new RuntimeException('Temporäre Datei konnte nicht angelegt werden.');
|
||||
}
|
||||
try {
|
||||
if (file_put_contents($file, json_encode($payload, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE)) === false) {
|
||||
throw new RuntimeException('Berechnungsdaten konnten nicht geschrieben werden.');
|
||||
}
|
||||
$candidates = PHP_OS_FAMILY === 'Windows' ? ['python', 'py'] : ['/usr/bin/python3', 'python3', 'python'];
|
||||
foreach ($candidates as $binary) {
|
||||
// Array command bypasses the shell; no user input is interpolated into a command.
|
||||
$process = @proc_open([$binary, __DIR__ . '/py/observation_suggestions_api.py', $file],
|
||||
[0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
|
||||
if (!is_resource($process)) {
|
||||
continue;
|
||||
}
|
||||
fclose($pipes[0]);
|
||||
stream_set_blocking($pipes[1], false);
|
||||
stream_set_blocking($pipes[2], false);
|
||||
$output = '';
|
||||
$errors = '';
|
||||
$deadline = microtime(true) + 90;
|
||||
$timedOut = false;
|
||||
do {
|
||||
$output .= stream_get_contents($pipes[1]);
|
||||
$errors .= stream_get_contents($pipes[2]);
|
||||
$status = proc_get_status($process);
|
||||
if (!$status['running']) {
|
||||
break;
|
||||
}
|
||||
if (microtime(true) > $deadline) {
|
||||
$timedOut = true;
|
||||
proc_terminate($process);
|
||||
break;
|
||||
}
|
||||
usleep(20000);
|
||||
} while (true);
|
||||
$output .= stream_get_contents($pipes[1]);
|
||||
$errors .= stream_get_contents($pipes[2]);
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($process);
|
||||
if ($timedOut) {
|
||||
throw new RuntimeException('Die Berechnung dauert zu lange. Bitte weniger Objekttypen auswählen.');
|
||||
}
|
||||
$decoded = json_decode($output, true);
|
||||
if (is_array($decoded) && array_key_exists('ok', $decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
error_log('Observation suggestions Python: ' . substr($errors, 0, 2000));
|
||||
}
|
||||
throw new RuntimeException('Die Berechnung ist derzeit nicht verfügbar. Bitte die Python-Installation prüfen.');
|
||||
} finally {
|
||||
@unlink($file);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user