'Januar',
2 => 'Februar',
3 => 'Maerz',
4 => 'April',
5 => 'Mai',
6 => 'Juni',
7 => 'Juli',
8 => 'August',
9 => 'September',
10 => 'Oktober',
11 => 'November',
12 => 'Dezember',
];
$monthSkyTimes = [
1 => ['hour' => 22, 'minute' => 0],
2 => ['hour' => 22, 'minute' => 0],
3 => ['hour' => 22, 'minute' => 0],
4 => ['hour' => 23, 'minute' => 0],
5 => ['hour' => 23, 'minute' => 0],
6 => ['hour' => 23, 'minute' => 30],
7 => ['hour' => 23, 'minute' => 30],
8 => ['hour' => 23, 'minute' => 0],
9 => ['hour' => 23, 'minute' => 0],
10 => ['hour' => 23, 'minute' => 0],
11 => ['hour' => 22, 'minute' => 0],
12 => ['hour' => 22, 'minute' => 0],
];
$starData = [];
$lineStarData = [];
$constellationLines = [];
$messierData = [];
$planetData = [];
$moonData = null;
$moonPhaseEvents = [];
$moonPlanetApproaches = [];
$planetConjunctions = [];
$eclipseEvents = [];
$moonApsisEvents = [];
$sunApsisEvents = [];
$innerPlanetElongationEvents = [];
$venusPeakMagnitudeEvents = [];
$outerPlanetEvents = [];
$outerPlanetStationEvents = [];
$moonOccultations = [];
$seasonChanges = [];
$monthEventList = [];
$starDataError = null;
if (!function_exists('buildMonthOccultationStarLabel')) {
function buildMonthOccultationStarLabel(array $row): string
{
$proper = trim((string) ($row['proper'] ?? ''));
if ($proper !== '') {
return $proper;
}
$bayer = trim((string) ($row['bayer'] ?? ''));
$con = trim((string) ($row['con'] ?? ''));
if ($bayer !== '') {
return $con !== '' ? $bayer . ' ' . $con : $bayer;
}
$hip = isset($row['hip']) ? (int) $row['hip'] : 0;
return $hip > 0 ? 'HIP ' . $hip : 'Unbenannter Stern';
}
}
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,
]);
$starStmt = $pdo->query(
"SELECT hip, proper, bayer, con, spect, mag, ci, rarad, decrad
FROM star_hipparcos
WHERE mag IS NOT NULL
AND rarad IS NOT NULL
AND decrad IS NOT NULL
AND mag <= " . (float) $starDatabaseMagnitudeLimit . "
ORDER BY mag ASC"
);
while ($row = $starStmt->fetch()) {
$starData[] = [
'hip' => $row['hip'] !== null ? (int) $row['hip'] : null,
'proper' => trim((string) ($row['proper'] ?? '')),
'bayer' => trim((string) ($row['bayer'] ?? '')),
'con' => trim((string) ($row['con'] ?? '')),
'spect' => trim((string) ($row['spect'] ?? '')),
'ra' => (float) $row['rarad'],
'dec' => (float) $row['decrad'],
'mag' => (float) $row['mag'],
'ci' => $row['ci'] !== null ? (float) $row['ci'] : null,
];
}
$constellationIndex = [];
$ensureConstellation = static function (string $id) use (&$constellationIndex): void {
if (!isset($constellationIndex[$id])) {
$constellationIndex[$id] = [
'id' => $id,
'lines' => [],
'label_positions' => [],
'common_name' => [
'german' => null,
'native' => null,
'byname' => null,
],
];
}
};
$nameStmt = $pdo->query(
"SELECT constellation_id, german_name, native_name, byname
FROM constellation_names
ORDER BY constellation_id"
);
foreach ($nameStmt as $row) {
$constellationId = (string) $row['constellation_id'];
$ensureConstellation($constellationId);
$constellationIndex[$constellationId]['common_name'] = [
'german' => $row['german_name'] !== null ? (string) $row['german_name'] : null,
'native' => $row['native_name'] !== null ? (string) $row['native_name'] : null,
'byname' => $row['byname'] !== null ? (string) $row['byname'] : null,
];
}
$labelStmt = $pdo->query(
"SELECT constellation_id, position_index, ra_hours, dec_degrees
FROM constellation_label_positions
ORDER BY constellation_id, position_index"
);
foreach ($labelStmt as $row) {
$constellationId = (string) $row['constellation_id'];
$ensureConstellation($constellationId);
$constellationIndex[$constellationId]['label_positions'][] = [
(float) $row['ra_hours'],
(float) $row['dec_degrees'],
];
}
$lineStmt = $pdo->query(
"SELECT cl.constellation_id, cl.line_index, clp.point_index, clp.hip_number
FROM constellation_lines cl
INNER JOIN constellation_line_points clp ON clp.line_id = cl.id
ORDER BY cl.constellation_id, cl.line_index, clp.point_index"
);
foreach ($lineStmt as $row) {
$constellationId = (string) $row['constellation_id'];
$lineIndex = (int) $row['line_index'];
$ensureConstellation($constellationId);
$constellationIndex[$constellationId]['lines'][$lineIndex] ??= [];
$constellationIndex[$constellationId]['lines'][$lineIndex][] = (int) $row['hip_number'];
}
foreach ($constellationIndex as &$constellation) {
if ($constellation['lines']) {
ksort($constellation['lines']);
$constellation['lines'] = array_values($constellation['lines']);
}
}
unset($constellation);
$constellationLines = array_values($constellationIndex);
$lineStarStmt = $pdo->query(
"SELECT DISTINCT sh.hip, sh.proper, sh.bayer, sh.con, sh.spect, sh.mag, sh.ci, sh.rarad, sh.decrad
FROM constellation_line_points clp
INNER JOIN star_hipparcos sh ON sh.hip = clp.hip_number
WHERE sh.rarad IS NOT NULL
AND sh.decrad IS NOT NULL"
);
while ($row = $lineStarStmt->fetch()) {
$lineStarData[] = [
'hip' => $row['hip'] !== null ? (int) $row['hip'] : null,
'proper' => trim((string) ($row['proper'] ?? '')),
'bayer' => trim((string) ($row['bayer'] ?? '')),
'con' => trim((string) ($row['con'] ?? '')),
'spect' => trim((string) ($row['spect'] ?? '')),
'ra' => (float) $row['rarad'],
'dec' => (float) $row['decrad'],
'mag' => $row['mag'] !== null ? (float) $row['mag'] : 99.0,
'ci' => $row['ci'] !== null ? (float) $row['ci'] : null,
];
}
$messierStmt = $pdo->query(
"SELECT messier, name, object_type_abrev, ra_deg, dec_deg, v_mag, major_axis
FROM dso_objects
WHERE messier IS NOT NULL
AND messier <> ''
AND ra_deg IS NOT NULL
AND dec_deg IS NOT NULL
AND v_mag IS NOT NULL
AND v_mag <= " . (float) $messierDatabaseMagnitudeLimit . "
ORDER BY v_mag ASC, CAST(REGEXP_REPLACE(messier, '[^0-9]', '') AS UNSIGNED)"
);
while ($row = $messierStmt->fetch()) {
if (!preg_match('/(\d+)/', (string) $row['messier'], $match)) {
continue;
}
$messierData[] = [
'm' => (int) $match[1],
'name' => trim((string) ($row['name'] ?? '')),
'type' => trim((string) ($row['object_type_abrev'] ?? 'As')),
'ra' => ((float) $row['ra_deg']) / 15.0,
'dec' => (float) $row['dec_deg'],
'mag' => (float) $row['v_mag'],
'size' => $row['major_axis'] !== null ? (float) $row['major_axis'] : 8.0,
];
}
} catch (Throwable $e) {
$starDataError = $e->getMessage();
}
require __DIR__ . '/header.php';
$chartLocationName = (string) (($currentLocation['name'] ?? null) ?: 'Sternwarte Sonneberg');
$chartLatitude = isset($currentLocation['latitude']) ? (float) $currentLocation['latitude'] : 50.3547;
$chartLongitude = isset($currentLocation['longitude']) ? (float) $currentLocation['longitude'] : 11.1900;
$chartElevation = isset($currentLocation['elevation']) && $currentLocation['elevation'] !== null ? (float) $currentLocation['elevation'] : 640.0;
$chartTimezone = (string) (($currentLocation['timezone'] ?? null) ?: 'Europe/Berlin');
$monthTime = $monthSkyTimes[$selectedMonth];
$chartLocalTime = new DateTimeImmutable(
sprintf('%04d-%02d-15 %02d:%02d:00', $selectedYear, $selectedMonth, $monthTime['hour'], $monthTime['minute']),
new DateTimeZone($chartTimezone)
);
$chartUtcTime = $chartLocalTime->setTimezone(new DateTimeZone('UTC'));
$pythonExecutable = PHP_OS_FAMILY === 'Windows' ? 'python' : '/usr/bin/python';
$pythonScriptPath = __DIR__ . '/py/api.py';
$pythonOutput = [];
$pythonExitCode = 0;
$planetErrorText = null;
$pythonArgs = [
$pythonScriptPath,
'month_sky_context',
(string) $chartLatitude,
(string) $chartLongitude,
(string) $chartElevation,
(string) $selectedYear,
(string) $selectedMonth,
(string) $monthTime['hour'],
(string) $monthTime['minute'],
$chartTimezone,
];
$pythonCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $pythonArgs)) . ' 2>&1';
exec($pythonCommand, $pythonOutput, $pythonExitCode);
$pythonRaw = trim(implode("\n", $pythonOutput));
$pythonDecoded = json_decode($pythonRaw, true);
if (is_array($pythonDecoded) && ($pythonDecoded['ok'] ?? false)) {
if (is_array($pythonDecoded['bodies']['moon'] ?? null)) {
$moon = $pythonDecoded['bodies']['moon'];
$moonData = [
'label' => (string) ($moon['label'] ?? 'Mond'),
'az' => isset($moon['azimuth_deg']) ? (float) $moon['azimuth_deg'] : null,
'alt' => isset($moon['altitude_deg']) ? (float) $moon['altitude_deg'] : null,
'visible' => !empty($moon['visible']),
'phaseFraction' => isset($moon['phase_fraction']) ? (float) $moon['phase_fraction'] : null,
'waxing' => isset($moon['waxing']) ? (bool) $moon['waxing'] : null,
];
}
foreach (($pythonDecoded['bodies']['planets'] ?? []) as $planet) {
if (!is_array($planet)) {
continue;
}
$planetData[] = [
'key' => (string) ($planet['key'] ?? ''),
'label' => (string) ($planet['label'] ?? ''),
'az' => isset($planet['azimuth_deg']) ? (float) $planet['azimuth_deg'] : null,
'alt' => isset($planet['altitude_deg']) ? (float) $planet['altitude_deg'] : null,
'mag' => isset($planet['magnitude']) ? (float) $planet['magnitude'] : null,
'visible' => !empty($planet['visible']),
];
}
} elseif ($pythonRaw !== '') {
$planetErrorText = $pythonRaw;
}
$moonPhaseOutput = [];
$moonPhaseExitCode = 0;
$moonPhaseArgs = [
$pythonScriptPath,
'moon_phases_for_month',
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
];
$moonPhaseCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $moonPhaseArgs)) . ' 2>&1';
exec($moonPhaseCommand, $moonPhaseOutput, $moonPhaseExitCode);
$moonPhaseRaw = trim(implode("\n", $moonPhaseOutput));
$moonPhaseDecoded = json_decode($moonPhaseRaw, true);
if (is_array($moonPhaseDecoded) && ($moonPhaseDecoded['ok'] ?? false)) {
$moonPhaseEvents = is_array($moonPhaseDecoded['phases'] ?? null) ? $moonPhaseDecoded['phases'] : [];
}
$seasonOutput = [];
$seasonExitCode = 0;
$seasonArgs = [
$pythonScriptPath,
'season_changes_for_month',
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
];
$seasonCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $seasonArgs)) . ' 2>&1';
exec($seasonCommand, $seasonOutput, $seasonExitCode);
$seasonRaw = trim(implode("\n", $seasonOutput));
$seasonDecoded = json_decode($seasonRaw, true);
if (is_array($seasonDecoded) && ($seasonDecoded['ok'] ?? false)) {
$seasonChanges = is_array($seasonDecoded['changes'] ?? null) ? $seasonDecoded['changes'] : [];
}
$eclipseOutput = [];
$eclipseExitCode = 0;
$eclipseArgs = [
$pythonScriptPath,
'eclipses_for_month',
(string) $chartLatitude,
(string) $chartLongitude,
(string) $chartElevation,
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
];
$eclipseCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $eclipseArgs)) . ' 2>&1';
exec($eclipseCommand, $eclipseOutput, $eclipseExitCode);
$eclipseRaw = trim(implode("\n", $eclipseOutput));
$eclipseDecoded = json_decode($eclipseRaw, true);
if (is_array($eclipseDecoded) && ($eclipseDecoded['ok'] ?? false)) {
$eclipseEvents = is_array($eclipseDecoded['events'] ?? null) ? $eclipseDecoded['events'] : [];
}
$moonApsisOutput = [];
$moonApsisExitCode = 0;
$moonApsisArgs = [
$pythonScriptPath,
'moon_apsides_for_month',
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
];
$moonApsisCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $moonApsisArgs)) . ' 2>&1';
exec($moonApsisCommand, $moonApsisOutput, $moonApsisExitCode);
$moonApsisRaw = trim(implode("\n", $moonApsisOutput));
$moonApsisDecoded = json_decode($moonApsisRaw, true);
if (is_array($moonApsisDecoded) && ($moonApsisDecoded['ok'] ?? false)) {
$moonApsisEvents = is_array($moonApsisDecoded['events'] ?? null) ? $moonApsisDecoded['events'] : [];
}
$sunApsisOutput = [];
$sunApsisExitCode = 0;
$sunApsisArgs = [
$pythonScriptPath,
'sun_apsides_for_month',
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
];
$sunApsisCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $sunApsisArgs)) . ' 2>&1';
exec($sunApsisCommand, $sunApsisOutput, $sunApsisExitCode);
$sunApsisRaw = trim(implode("\n", $sunApsisOutput));
$sunApsisDecoded = json_decode($sunApsisRaw, true);
if (is_array($sunApsisDecoded) && ($sunApsisDecoded['ok'] ?? false)) {
$sunApsisEvents = is_array($sunApsisDecoded['events'] ?? null) ? $sunApsisDecoded['events'] : [];
}
$elongationOutput = [];
$elongationExitCode = 0;
$elongationArgs = [
$pythonScriptPath,
'inner_planet_elongations_for_month',
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
];
$elongationCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $elongationArgs)) . ' 2>&1';
exec($elongationCommand, $elongationOutput, $elongationExitCode);
$elongationRaw = trim(implode("\n", $elongationOutput));
$elongationDecoded = json_decode($elongationRaw, true);
if (is_array($elongationDecoded) && ($elongationDecoded['ok'] ?? false)) {
$innerPlanetElongationEvents = is_array($elongationDecoded['events'] ?? null) ? $elongationDecoded['events'] : [];
}
$venusPeakMagnitudeOutput = [];
$venusPeakMagnitudeExitCode = 0;
$venusPeakMagnitudeArgs = [
$pythonScriptPath,
'venus_peak_magnitude_for_month',
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
];
$venusPeakMagnitudeCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $venusPeakMagnitudeArgs)) . ' 2>&1';
exec($venusPeakMagnitudeCommand, $venusPeakMagnitudeOutput, $venusPeakMagnitudeExitCode);
$venusPeakMagnitudeRaw = trim(implode("\n", $venusPeakMagnitudeOutput));
$venusPeakMagnitudeDecoded = json_decode($venusPeakMagnitudeRaw, true);
if (is_array($venusPeakMagnitudeDecoded) && ($venusPeakMagnitudeDecoded['ok'] ?? false)) {
$venusPeakMagnitudeEvents = is_array($venusPeakMagnitudeDecoded['events'] ?? null) ? $venusPeakMagnitudeDecoded['events'] : [];
}
$outerPlanetOutput = [];
$outerPlanetExitCode = 0;
$outerPlanetArgs = [
$pythonScriptPath,
'outer_planet_events_for_month',
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
];
$outerPlanetCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $outerPlanetArgs)) . ' 2>&1';
exec($outerPlanetCommand, $outerPlanetOutput, $outerPlanetExitCode);
$outerPlanetRaw = trim(implode("\n", $outerPlanetOutput));
$outerPlanetDecoded = json_decode($outerPlanetRaw, true);
if (is_array($outerPlanetDecoded) && ($outerPlanetDecoded['ok'] ?? false)) {
$outerPlanetEvents = is_array($outerPlanetDecoded['events'] ?? null) ? $outerPlanetDecoded['events'] : [];
}
$outerPlanetStationOutput = [];
$outerPlanetStationExitCode = 0;
$outerPlanetStationArgs = [
$pythonScriptPath,
'outer_planet_stations_for_month',
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
];
$outerPlanetStationCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $outerPlanetStationArgs)) . ' 2>&1';
exec($outerPlanetStationCommand, $outerPlanetStationOutput, $outerPlanetStationExitCode);
$outerPlanetStationRaw = trim(implode("\n", $outerPlanetStationOutput));
$outerPlanetStationDecoded = json_decode($outerPlanetStationRaw, true);
if (is_array($outerPlanetStationDecoded) && ($outerPlanetStationDecoded['ok'] ?? false)) {
$outerPlanetStationEvents = is_array($outerPlanetStationDecoded['events'] ?? null) ? $outerPlanetStationDecoded['events'] : [];
}
$moonPlanetOutput = [];
$moonPlanetExitCode = 0;
$moonPlanetArgs = [
$pythonScriptPath,
'moon_planet_approaches',
(string) $chartLatitude,
(string) $chartLongitude,
(string) $chartElevation,
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
(string) $moonPlanetMaxSeparationDeg,
];
$moonPlanetCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $moonPlanetArgs)) . ' 2>&1';
exec($moonPlanetCommand, $moonPlanetOutput, $moonPlanetExitCode);
$moonPlanetRaw = trim(implode("\n", $moonPlanetOutput));
$moonPlanetDecoded = json_decode($moonPlanetRaw, true);
if (is_array($moonPlanetDecoded) && ($moonPlanetDecoded['ok'] ?? false)) {
$moonPlanetApproaches = is_array($moonPlanetDecoded['approaches'] ?? null) ? $moonPlanetDecoded['approaches'] : [];
}
$planetConjunctionOutput = [];
$planetConjunctionExitCode = 0;
$planetConjunctionArgs = [
$pythonScriptPath,
'planet_conjunctions_for_month',
(string) $chartLatitude,
(string) $chartLongitude,
(string) $chartElevation,
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
(string) $planetConjunctionMaxSeparationDeg,
];
$planetConjunctionCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $planetConjunctionArgs)) . ' 2>&1';
exec($planetConjunctionCommand, $planetConjunctionOutput, $planetConjunctionExitCode);
$planetConjunctionRaw = trim(implode("\n", $planetConjunctionOutput));
$planetConjunctionDecoded = json_decode($planetConjunctionRaw, true);
if (is_array($planetConjunctionDecoded) && ($planetConjunctionDecoded['ok'] ?? false)) {
$planetConjunctions = is_array($planetConjunctionDecoded['conjunctions'] ?? null) ? $planetConjunctionDecoded['conjunctions'] : [];
}
$moonOccultationStars = [];
try {
if (isset($pdo)) {
$stmtOccultStars = $pdo->prepare(
"SELECT hip, proper, bayer, con, mag, rarad, decrad, dist
FROM star_hipparcos
WHERE rarad IS NOT NULL
AND decrad IS NOT NULL
AND mag IS NOT NULL
AND mag <= :max_mag
ORDER BY mag ASC, proper ASC, bayer ASC, hip ASC"
);
$stmtOccultStars->execute([':max_mag' => $moonOccultationMaxMag]);
foreach ($stmtOccultStars->fetchAll() as $row) {
$moonOccultationStars[] = [
'hip' => isset($row['hip']) ? (int) $row['hip'] : 0,
'label' => buildMonthOccultationStarLabel($row),
'constellation' => trim((string) ($row['con'] ?? '')),
'mag' => isset($row['mag']) ? (float) $row['mag'] : 99.0,
'ra' => isset($row['rarad']) ? (float) $row['rarad'] * (12 / M_PI) : 0.0,
'dec' => isset($row['decrad']) ? (float) $row['decrad'] * (180 / M_PI) : 0.0,
'distLy' => isset($row['dist']) && $row['dist'] !== null && (float) $row['dist'] > 0.0
? (float) $row['dist'] * 3.26156
: 1000.0,
];
}
}
} catch (Throwable $e) {
}
if ($moonOccultationStars) {
$tempOccultationFile = tempnam(sys_get_temp_dir(), 'month_occult_');
if ($tempOccultationFile !== false) {
try {
file_put_contents($tempOccultationFile, json_encode($moonOccultationStars, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR));
$moonOccultOutput = [];
$moonOccultExitCode = 0;
$moonOccultArgs = [
$pythonScriptPath,
'moon_star_occultations_for_month',
(string) $chartLatitude,
(string) $chartLongitude,
(string) $chartElevation,
(string) $selectedYear,
(string) $selectedMonth,
$chartTimezone,
$tempOccultationFile,
];
$moonOccultCommand = $pythonExecutable . ' ' . implode(' ', array_map('escapeshellarg', $moonOccultArgs)) . ' 2>&1';
exec($moonOccultCommand, $moonOccultOutput, $moonOccultExitCode);
$moonOccultRaw = trim(implode("\n", $moonOccultOutput));
$moonOccultDecoded = json_decode($moonOccultRaw, true);
if (is_array($moonOccultDecoded) && ($moonOccultDecoded['ok'] ?? false)) {
$moonOccultations = is_array($moonOccultDecoded['results'] ?? null) ? $moonOccultDecoded['results'] : [];
}
} catch (Throwable $e) {
} finally {
if (is_file($tempOccultationFile)) {
@unlink($tempOccultationFile);
}
}
}
}
foreach ($moonPhaseEvents as $phaseEvent) {
if (!is_array($phaseEvent)) {
continue;
}
$monthEventList[] = [
'event' => (string) ($phaseEvent['label'] ?? ''),
'date' => (string) ($phaseEvent['local_date'] ?? ''),
'time' => (string) ($phaseEvent['local_time'] ?? ''),
'local_iso' => (string) ($phaseEvent['local_iso'] ?? ''),
'type' => 'moon_phase',
];
}
foreach ($seasonChanges as $seasonChange) {
if (!is_array($seasonChange)) {
continue;
}
$monthEventList[] = [
'event' => (string) ($seasonChange['label'] ?? 'Jahreszeitenwechsel'),
'date' => (string) ($seasonChange['local_date'] ?? ''),
'time' => (string) ($seasonChange['local_time'] ?? ''),
'local_iso' => (string) ($seasonChange['local_iso'] ?? ''),
'type' => 'season_change',
];
}
foreach ($eclipseEvents as $eclipseEvent) {
if (!is_array($eclipseEvent)) {
continue;
}
$monthEventList[] = [
'event' => (string) ($eclipseEvent['label'] ?? 'Finsternis'),
'date' => (string) ($eclipseEvent['local_date'] ?? ''),
'time' => (string) ($eclipseEvent['local_time'] ?? ''),
'local_iso' => (string) ($eclipseEvent['local_iso'] ?? ''),
'type' => (string) ($eclipseEvent['category'] ?? 'eclipse'),
];
}
foreach ($moonApsisEvents as $moonApsisEvent) {
if (!is_array($moonApsisEvent)) {
continue;
}
$moonApsisKind = (string) ($moonApsisEvent['kind'] ?? '');
$distanceText = isset($moonApsisEvent['distance_km'])
? number_format((float) $moonApsisEvent['distance_km'], 0, ',', '.') . ' km'
: '';
$moonApsisLabel = $moonApsisKind === 'perigee'
? 'Mond in Erdnähe (Perigäum)'
: ($moonApsisKind === 'apogee' ? 'Mond in Erdferne (Apogäum)' : (string) ($moonApsisEvent['label'] ?? 'Mondabstand'));
$monthEventList[] = [
'event' => trim($moonApsisLabel . ($distanceText !== '' ? ' (' . $distanceText . ')' : '')),
'date' => (string) ($moonApsisEvent['local_date'] ?? ''),
'time' => (string) ($moonApsisEvent['local_time'] ?? ''),
'local_iso' => (string) ($moonApsisEvent['local_iso'] ?? ''),
'type' => 'moon_apsis',
];
}
foreach ($sunApsisEvents as $sunApsisEvent) {
if (!is_array($sunApsisEvent)) {
continue;
}
$sunApsisKind = (string) ($sunApsisEvent['kind'] ?? '');
$distanceText = isset($sunApsisEvent['distance_km'])
? number_format((float) $sunApsisEvent['distance_km'], 0, ',', '.') . ' km'
: '';
$sunApsisLabel = $sunApsisKind === 'perihelion'
? 'Erde erreicht sonnennächsten Punkt (Perihel)'
: ($sunApsisKind === 'aphelion' ? 'Erde erreicht sonnenfernsten Punkt (Aphel)' : (string) ($sunApsisEvent['label'] ?? 'Sonnenabstand'));
$monthEventList[] = [
'event' => trim($sunApsisLabel . ($distanceText !== '' ? ' (' . $distanceText . ')' : '')),
'date' => (string) ($sunApsisEvent['local_date'] ?? ''),
'time' => (string) ($sunApsisEvent['local_time'] ?? ''),
'local_iso' => (string) ($sunApsisEvent['local_iso'] ?? ''),
'type' => 'sun_apsis',
];
}
foreach ($innerPlanetElongationEvents as $elongationEvent) {
if (!is_array($elongationEvent)) {
continue;
}
$elongationPlanet = (string) ($elongationEvent['planet_label'] ?? 'Planet');
$elongationKind = (string) ($elongationEvent['kind'] ?? '');
$elongationText = isset($elongationEvent['elongation_deg'])
? number_format((float) $elongationEvent['elongation_deg'], 2, ',', '') . ' Grad'
: '';
$elongationLabel = $elongationKind === 'western'
? $elongationPlanet . ' größte westliche Elongation'
: ($elongationKind === 'eastern'
? $elongationPlanet . ' größte östliche Elongation'
: (string) ($elongationEvent['label'] ?? 'Elongation'));
$monthEventList[] = [
'event' => trim($elongationLabel . ($elongationText !== '' ? ' (' . $elongationText . ')' : '')),
'date' => (string) ($elongationEvent['local_date'] ?? ''),
'time' => (string) ($elongationEvent['local_time'] ?? ''),
'local_iso' => (string) ($elongationEvent['local_iso'] ?? ''),
'type' => 'planet_elongation',
];
}
foreach ($venusPeakMagnitudeEvents as $venusPeakMagnitudeEvent) {
if (!is_array($venusPeakMagnitudeEvent)) {
continue;
}
$magnitudeText = isset($venusPeakMagnitudeEvent['mag'])
? number_format((float) $venusPeakMagnitudeEvent['mag'], 1, ',', '') . ' mag'
: '';
$monthEventList[] = [
'event' => trim('Venus in groesster Helligkeit' . ($magnitudeText !== '' ? ' (' . $magnitudeText . ')' : '')),
'date' => (string) ($venusPeakMagnitudeEvent['local_date'] ?? ''),
'time' => (string) ($venusPeakMagnitudeEvent['local_time'] ?? ''),
'local_iso' => (string) ($venusPeakMagnitudeEvent['local_iso'] ?? ''),
'type' => 'venus_peak_magnitude',
];
}
foreach ($outerPlanetEvents as $outerPlanetEvent) {
if (!is_array($outerPlanetEvent)) {
continue;
}
$monthEventList[] = [
'event' => (string) ($outerPlanetEvent['label'] ?? 'Planetenereignis'),
'date' => (string) ($outerPlanetEvent['local_date'] ?? ''),
'time' => (string) ($outerPlanetEvent['local_time'] ?? ''),
'local_iso' => (string) ($outerPlanetEvent['local_iso'] ?? ''),
'type' => 'outer_planet_event',
];
}
foreach ($outerPlanetStationEvents as $outerPlanetStationEvent) {
if (!is_array($outerPlanetStationEvent)) {
continue;
}
$stationPlanet = (string) ($outerPlanetStationEvent['planet_label'] ?? 'Planet');
$stationKind = (string) ($outerPlanetStationEvent['kind'] ?? '');
$stationLabel = $stationKind === 'retrograde'
? $stationPlanet . ' stationär, dann rückläufig'
: ($stationKind === 'prograde'
? $stationPlanet . ' stationär, dann rechtläufig'
: (string) ($outerPlanetStationEvent['label'] ?? 'Stationärer Punkt'));
$monthEventList[] = [
'event' => $stationLabel,
'date' => (string) ($outerPlanetStationEvent['local_date'] ?? ''),
'time' => (string) ($outerPlanetStationEvent['local_time'] ?? ''),
'local_iso' => (string) ($outerPlanetStationEvent['local_iso'] ?? ''),
'type' => 'outer_planet_station',
];
}
foreach ($moonPlanetApproaches as $approachEvent) {
if (!is_array($approachEvent)) {
continue;
}
$distanceText = isset($approachEvent['separation_deg'])
? number_format((float) $approachEvent['separation_deg'], 2, ',', '') . ' Grad'
: '';
$monthEventList[] = [
'event' => trim((string) ($approachEvent['label'] ?? 'Mond nahe Planet') . ($distanceText !== '' ? ' (' . $distanceText . ')' : '')),
'date' => (string) ($approachEvent['local_date'] ?? ''),
'time' => (string) ($approachEvent['local_time'] ?? ''),
'local_iso' => (string) ($approachEvent['local_iso'] ?? ''),
'type' => 'moon_planet',
];
}
foreach ($planetConjunctions as $conjunctionEvent) {
if (!is_array($conjunctionEvent)) {
continue;
}
$distanceText = isset($conjunctionEvent['separation_deg'])
? number_format((float) $conjunctionEvent['separation_deg'], 2, ',', '') . ' Grad'
: '';
$monthEventList[] = [
'event' => trim((string) ($conjunctionEvent['label'] ?? 'Planetenkonjunktion') . ($distanceText !== '' ? ' (' . $distanceText . ')' : '')),
'date' => (string) ($conjunctionEvent['local_date'] ?? ''),
'time' => (string) ($conjunctionEvent['local_time'] ?? ''),
'local_iso' => (string) ($conjunctionEvent['local_iso'] ?? ''),
'type' => 'planet_conjunction',
];
}
foreach ($moonOccultations as $occultationEvent) {
if (!is_array($occultationEvent)) {
continue;
}
$maximum = is_array($occultationEvent['maximum'] ?? null) ? $occultationEvent['maximum'] : null;
$star = is_array($occultationEvent['star'] ?? null) ? $occultationEvent['star'] : null;
if ($maximum === null || $star === null) {
continue;
}
$starLabel = (string) ($star['label'] ?? 'Stern');
$starMag = isset($star['mag']) ? number_format((float) $star['mag'], 1, ',', '') : '';
$monthEventList[] = [
'event' => 'Mond bedeckt ' . $starLabel . ($starMag !== '' ? ' (' . $starMag . ' mag)' : ''),
'date' => (string) ($maximum['local_date'] ?? ''),
'time' => (string) ($maximum['local_time'] ?? ''),
'local_iso' => (string) ($maximum['local_iso'] ?? ''),
'type' => 'moon_occultation',
];
}
usort(
$monthEventList,
static fn (array $a, array $b): int => strcmp((string) ($a['local_iso'] ?? ''), (string) ($b['local_iso'] ?? ''))
);
$chartConfig = [
'monthName' => $months[$selectedMonth],
'year' => $selectedYear,
'month' => $selectedMonth,
'location' => [
'name' => $chartLocationName,
'latitude' => $chartLatitude,
'longitude' => $chartLongitude,
'elevation' => $chartElevation,
'timezone' => $chartTimezone,
],
'localTimeLabel' => $chartLocalTime->format('d.m.Y H:i') . ' ' . $chartTimezone,
'utcTimeIso' => $chartUtcTime->format(DateTimeInterface::ATOM),
'starLimit' => $starDisplayMagnitudeLimit,
'starLabelLimit' => $starLabelMagnitudeLimit,
'messierLimit' => $messierDisplayMagnitudeLimit,
];
$chartConfigJson = json_encode($chartConfig, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$starDataJson = json_encode($starData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$lineStarDataJson = json_encode($lineStarData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$constellationLinesJson = json_encode($constellationLines, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$messierDataJson = json_encode($messierData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$planetDataJson = json_encode($planetData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$moonDataJson = json_encode($moonData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$starDataErrorJson = json_encode($starDataError, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
?>