Konjunktionen von Planeten eingebaut
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@ $starLabelMagnitudeLimit = 2.0;
|
|||||||
$messierDatabaseMagnitudeLimit = 4.0;
|
$messierDatabaseMagnitudeLimit = 4.0;
|
||||||
$messierDisplayMagnitudeLimit = 1.0;
|
$messierDisplayMagnitudeLimit = 1.0;
|
||||||
$moonPlanetMaxSeparationDeg = 1.5;
|
$moonPlanetMaxSeparationDeg = 1.5;
|
||||||
|
$planetConjunctionMaxSeparationDeg = 1.0;
|
||||||
$moonOccultationMaxMag = 2.0;
|
$moonOccultationMaxMag = 2.0;
|
||||||
|
|
||||||
$years = range($currentYear - 2, $currentYear + 5);
|
$years = range($currentYear - 2, $currentYear + 5);
|
||||||
@@ -57,7 +58,9 @@ $planetData = [];
|
|||||||
$moonData = null;
|
$moonData = null;
|
||||||
$moonPhaseEvents = [];
|
$moonPhaseEvents = [];
|
||||||
$moonPlanetApproaches = [];
|
$moonPlanetApproaches = [];
|
||||||
|
$planetConjunctions = [];
|
||||||
$moonOccultations = [];
|
$moonOccultations = [];
|
||||||
|
$seasonChanges = [];
|
||||||
$monthEventList = [];
|
$monthEventList = [];
|
||||||
$starDataError = null;
|
$starDataError = null;
|
||||||
|
|
||||||
@@ -327,6 +330,23 @@ if (is_array($moonPhaseDecoded) && ($moonPhaseDecoded['ok'] ?? false)) {
|
|||||||
$moonPhaseEvents = is_array($moonPhaseDecoded['phases'] ?? null) ? $moonPhaseDecoded['phases'] : [];
|
$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'] : [];
|
||||||
|
}
|
||||||
|
|
||||||
$moonPlanetOutput = [];
|
$moonPlanetOutput = [];
|
||||||
$moonPlanetExitCode = 0;
|
$moonPlanetExitCode = 0;
|
||||||
$moonPlanetArgs = [
|
$moonPlanetArgs = [
|
||||||
@@ -348,6 +368,27 @@ if (is_array($moonPlanetDecoded) && ($moonPlanetDecoded['ok'] ?? false)) {
|
|||||||
$moonPlanetApproaches = is_array($moonPlanetDecoded['approaches'] ?? null) ? $moonPlanetDecoded['approaches'] : [];
|
$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 = [];
|
$moonOccultationStars = [];
|
||||||
try {
|
try {
|
||||||
if (isset($pdo)) {
|
if (isset($pdo)) {
|
||||||
@@ -427,13 +468,27 @@ foreach ($moonPhaseEvents as $phaseEvent) {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 ($moonPlanetApproaches as $approachEvent) {
|
foreach ($moonPlanetApproaches as $approachEvent) {
|
||||||
if (!is_array($approachEvent)) {
|
if (!is_array($approachEvent)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$distanceText = isset($approachEvent['separation_deg'])
|
$distanceText = isset($approachEvent['separation_deg'])
|
||||||
? number_format((float) $approachEvent['separation_deg'], 2, ',', '') . '°'
|
? number_format((float) $approachEvent['separation_deg'], 2, ',', '') . ' Grad'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
$monthEventList[] = [
|
$monthEventList[] = [
|
||||||
@@ -445,6 +500,24 @@ foreach ($moonPlanetApproaches as $approachEvent) {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
foreach ($moonOccultations as $occultationEvent) {
|
||||||
if (!is_array($occultationEvent)) {
|
if (!is_array($occultationEvent)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -459,7 +532,7 @@ foreach ($moonOccultations as $occultationEvent) {
|
|||||||
$starLabel = (string) ($star['label'] ?? 'Stern');
|
$starLabel = (string) ($star['label'] ?? 'Stern');
|
||||||
$starMag = isset($star['mag']) ? number_format((float) $star['mag'], 1, ',', '') : '';
|
$starMag = isset($star['mag']) ? number_format((float) $star['mag'], 1, ',', '') : '';
|
||||||
$monthEventList[] = [
|
$monthEventList[] = [
|
||||||
'event' => 'Mond bedeckt ' . $starLabel . ($starMag !== '' ? ' (mag ' . $starMag . ')' : ''),
|
'event' => 'Mond bedeckt ' . $starLabel . ($starMag !== '' ? ' (' . $starMag . ' mag)' : ''),
|
||||||
'date' => (string) ($maximum['local_date'] ?? ''),
|
'date' => (string) ($maximum['local_date'] ?? ''),
|
||||||
'time' => (string) ($maximum['local_time'] ?? ''),
|
'time' => (string) ($maximum['local_time'] ?? ''),
|
||||||
'local_iso' => (string) ($maximum['local_iso'] ?? ''),
|
'local_iso' => (string) ($maximum['local_iso'] ?? ''),
|
||||||
@@ -558,7 +631,7 @@ $starDataErrorJson = json_encode($starDataError, JSON_UNESCAPED_UNICODE | JSON_U
|
|||||||
<section class="monatskarte-card">
|
<section class="monatskarte-card">
|
||||||
<div class="monatskarte-header">
|
<div class="monatskarte-header">
|
||||||
<div>
|
<div>
|
||||||
<h3>Südhimmel <?= htmlspecialchars($months[$selectedMonth] . ' ' . (string) $selectedYear, ENT_QUOTES, 'UTF-8') ?></h3>
|
<h3>Südhimmel <?= htmlspecialchars($months[$selectedMonth] . ' ' . (string) $selectedYear, ENT_QUOTES, 'UTF-8') ?></h3>
|
||||||
<p id="monatskarteSouthMeta">
|
<p id="monatskarteSouthMeta">
|
||||||
<?= htmlspecialchars($chartConfig['localTimeLabel'], ENT_QUOTES, 'UTF-8') ?>,
|
<?= htmlspecialchars($chartConfig['localTimeLabel'], ENT_QUOTES, 'UTF-8') ?>,
|
||||||
<?= htmlspecialchars($chartLocationName, ENT_QUOTES, 'UTF-8') ?>
|
<?= htmlspecialchars($chartLocationName, ENT_QUOTES, 'UTF-8') ?>
|
||||||
@@ -567,25 +640,25 @@ $starDataErrorJson = json_encode($starDataError, JSON_UNESCAPED_UNICODE | JSON_U
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="monatskarte-stage monatskarte-stage-south">
|
<div class="monatskarte-stage monatskarte-stage-south">
|
||||||
<canvas id="monatskarteSouthCanvas" width="1200" height="720" aria-label="Südhimmel-Projektion"></canvas>
|
<canvas id="monatskarteSouthCanvas" width="1200" height="720" aria-label="Südhimmel-Projektion"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="monatskarte-footer">
|
<div class="monatskarte-footer">
|
||||||
<p id="monatskarteSouthStatus">Bereite Südhimmelkarte vor...</p>
|
<p id="monatskarteSouthStatus">Bereite Südhimmelkarte vor...</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="monatskarte-card">
|
<section class="monatskarte-card">
|
||||||
<div class="monatskarte-header">
|
<div class="monatskarte-header">
|
||||||
<div>
|
<div>
|
||||||
<h3>Mondphasen <?= htmlspecialchars($months[$selectedMonth] . ' ' . (string) $selectedYear, ENT_QUOTES, 'UTF-8') ?></h3>
|
<h3>Ereignisse <?= htmlspecialchars($months[$selectedMonth] . ' ' . (string) $selectedYear, ENT_QUOTES, 'UTF-8') ?></h3>
|
||||||
<p>Chronologisch für <?= htmlspecialchars($chartTimezone, ENT_QUOTES, 'UTF-8') ?></p>
|
<p>Chronologische Monatsliste fuer <?= htmlspecialchars($chartTimezone, ENT_QUOTES, 'UTF-8') ?></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="monatskarte-footer">
|
<div class="monatskarte-footer">
|
||||||
<?php if ($monthEventList): ?>
|
<?php if ($monthEventList): ?>
|
||||||
<div class="riseset-grid" style="grid-template-columns: 1.3fr 1fr 1fr; row-gap: 10px;">
|
<div class="riseset-grid" style="grid-template-columns: 1.5fr 1fr 1fr; row-gap: 10px;">
|
||||||
<span class="riseset-label riseset-dim">Ereignis</span>
|
<span class="riseset-label riseset-dim">Ereignis</span>
|
||||||
<span class="riseset-label riseset-dim">Datum</span>
|
<span class="riseset-label riseset-dim">Datum</span>
|
||||||
<span class="riseset-label riseset-dim">Uhrzeit</span>
|
<span class="riseset-label riseset-dim">Uhrzeit</span>
|
||||||
@@ -596,68 +669,11 @@ $starDataErrorJson = json_encode($starDataError, JSON_UNESCAPED_UNICODE | JSON_U
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p>Keine Mondphasen für diesen Monat gefunden.</p>
|
<p>Fuer diesen Monat wurden keine Ereignisse gefunden.</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="monatskarte-card">
|
|
||||||
<div class="monatskarte-header">
|
|
||||||
<div>
|
|
||||||
<h3>Mond nahe Planeten</h3>
|
|
||||||
<p>Maximalabstand <?= htmlspecialchars(number_format($moonPlanetMaxSeparationDeg, 1, ',', ''), ENT_QUOTES, 'UTF-8') ?>°</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="monatskarte-footer">
|
|
||||||
<?php if ($moonPlanetApproaches): ?>
|
|
||||||
<div class="riseset-grid" style="grid-template-columns: 1.5fr 1fr 1fr 1fr; row-gap: 10px;">
|
|
||||||
<span class="riseset-label riseset-dim">Ereignis</span>
|
|
||||||
<span class="riseset-label riseset-dim">Datum</span>
|
|
||||||
<span class="riseset-label riseset-dim">Uhrzeit</span>
|
|
||||||
<span class="riseset-label riseset-dim">Abstand</span>
|
|
||||||
<?php foreach ($moonPlanetApproaches as $approachEvent): ?>
|
|
||||||
<span class="riseset-val"><?= htmlspecialchars((string) ($approachEvent['label'] ?? ''), ENT_QUOTES, 'UTF-8') ?></span>
|
|
||||||
<span class="riseset-val"><?= htmlspecialchars((string) ($approachEvent['local_date'] ?? ''), ENT_QUOTES, 'UTF-8') ?></span>
|
|
||||||
<span class="riseset-val"><?= htmlspecialchars((string) ($approachEvent['local_time'] ?? ''), ENT_QUOTES, 'UTF-8') ?></span>
|
|
||||||
<span class="riseset-val"><?= htmlspecialchars(number_format((float) ($approachEvent['separation_deg'] ?? 0), 2, ',', ''), ENT_QUOTES, 'UTF-8') ?>°</span>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
<?php else: ?>
|
|
||||||
<p>Keine Mond-Planet-Nähen innerhalb von <?= htmlspecialchars(number_format($moonPlanetMaxSeparationDeg, 1, ',', ''), ENT_QUOTES, 'UTF-8') ?>° gefunden.</p>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="monatskarte-card">
|
|
||||||
<div class="monatskarte-header">
|
|
||||||
<div>
|
|
||||||
<h3>Sternbedeckungen</h3>
|
|
||||||
<p>Bis Grenzgröße <?= htmlspecialchars(number_format($moonOccultationMaxMag, 1, ',', ''), ENT_QUOTES, 'UTF-8') ?></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="monatskarte-footer">
|
|
||||||
<?php if ($moonOccultations): ?>
|
|
||||||
<div class="riseset-grid" style="grid-template-columns: 1.6fr 1fr 1fr 0.9fr; row-gap: 10px;">
|
|
||||||
<span class="riseset-label riseset-dim">Stern</span>
|
|
||||||
<span class="riseset-label riseset-dim">Datum</span>
|
|
||||||
<span class="riseset-label riseset-dim">Uhrzeit</span>
|
|
||||||
<span class="riseset-label riseset-dim">Mag</span>
|
|
||||||
<?php foreach ($moonOccultations as $occultationEvent): ?>
|
|
||||||
<?php $star = is_array($occultationEvent['star'] ?? null) ? $occultationEvent['star'] : []; ?>
|
|
||||||
<?php $maximum = is_array($occultationEvent['maximum'] ?? null) ? $occultationEvent['maximum'] : []; ?>
|
|
||||||
<span class="riseset-val"><?= htmlspecialchars((string) ($star['label'] ?? ''), ENT_QUOTES, 'UTF-8') ?></span>
|
|
||||||
<span class="riseset-val"><?= htmlspecialchars((string) ($maximum['local_date'] ?? ''), ENT_QUOTES, 'UTF-8') ?></span>
|
|
||||||
<span class="riseset-val"><?= htmlspecialchars((string) ($maximum['local_time'] ?? ''), ENT_QUOTES, 'UTF-8') ?></span>
|
|
||||||
<span class="riseset-val"><?= htmlspecialchars(number_format((float) ($star['mag'] ?? 0), 1, ',', ''), ENT_QUOTES, 'UTF-8') ?></span>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
<?php else: ?>
|
|
||||||
<p>Keine Sternbedeckungen bis Magnitude <?= htmlspecialchars(number_format($moonOccultationMaxMag, 1, ',', ''), ENT_QUOTES, 'UTF-8') ?> gefunden.</p>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -1265,18 +1281,18 @@ const MONTH_CHART_ERROR = <?= $starDataErrorJson ?: 'null' ?>;
|
|||||||
|
|
||||||
drawDirectionLabel(0, 'Norden', 18, '600 13px Rajdhani, sans-serif', 0.78);
|
drawDirectionLabel(0, 'Norden', 18, '600 13px Rajdhani, sans-serif', 0.78);
|
||||||
drawDirectionLabel(90, 'Westen', 22, '600 13px Rajdhani, sans-serif', 0.78);
|
drawDirectionLabel(90, 'Westen', 22, '600 13px Rajdhani, sans-serif', 0.78);
|
||||||
drawDirectionLabel(180, 'Süden', 18, '600 13px Rajdhani, sans-serif', 0.78);
|
drawDirectionLabel(180, 'Süden', 18, '600 13px Rajdhani, sans-serif', 0.78);
|
||||||
drawDirectionLabel(270, 'Osten', 22, '600 13px Rajdhani, sans-serif', 0.78);
|
drawDirectionLabel(270, 'Osten', 22, '600 13px Rajdhani, sans-serif', 0.78);
|
||||||
|
|
||||||
drawDirectionLabel(45, 'Nordosten', 18, '600 11px Rajdhani, sans-serif', 0.64);
|
drawDirectionLabel(45, 'Nordosten', 18, '600 11px Rajdhani, sans-serif', 0.64);
|
||||||
drawDirectionLabel(315, 'Nordwesten', 18, '600 11px Rajdhani, sans-serif', 0.64);
|
drawDirectionLabel(315, 'Nordwesten', 18, '600 11px Rajdhani, sans-serif', 0.64);
|
||||||
drawDirectionLabel(135, 'Südosten', 18, '600 11px Rajdhani, sans-serif', 0.64);
|
drawDirectionLabel(135, 'Südosten', 18, '600 11px Rajdhani, sans-serif', 0.64);
|
||||||
drawDirectionLabel(225, 'Südwesten', 18, '600 11px Rajdhani, sans-serif', 0.64);
|
drawDirectionLabel(225, 'Südwesten', 18, '600 11px Rajdhani, sans-serif', 0.64);
|
||||||
|
|
||||||
ctx.fillStyle = 'rgba(214, 226, 255, 0.62)';
|
ctx.fillStyle = 'rgba(214, 226, 255, 0.62)';
|
||||||
ctx.font = '600 11px Rajdhani, sans-serif';
|
ctx.font = '600 11px Rajdhani, sans-serif';
|
||||||
ctx.fillText('60°', cx, cy - radius * 0.66 - 6);
|
ctx.fillText('60°', cx, cy - radius * 0.66 - 6);
|
||||||
ctx.fillText('30°', cx, cy - radius * 0.33 - 6);
|
ctx.fillText('30°', cx, cy - radius * 0.33 - 6);
|
||||||
ctx.fillText('Zenit', cx, cy);
|
ctx.fillText('Zenit', cx, cy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2356,9 +2372,9 @@ const MONTH_CHART_ERROR = <?= $starDataErrorJson ?: 'null' ?>;
|
|||||||
|
|
||||||
const directionLabels = [
|
const directionLabels = [
|
||||||
{ az: 90, text: 'Osten' },
|
{ az: 90, text: 'Osten' },
|
||||||
{ az: 135, text: 'Südosten' },
|
{ az: 135, text: 'Südosten' },
|
||||||
{ az: 180, text: 'Süden' },
|
{ az: 180, text: 'Süden' },
|
||||||
{ az: 225, text: 'Südwesten' },
|
{ az: 225, text: 'Südwesten' },
|
||||||
{ az: 270, text: 'Westen' },
|
{ az: 270, text: 'Westen' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -2384,7 +2400,7 @@ const MONTH_CHART_ERROR = <?= $starDataErrorJson ?: 'null' ?>;
|
|||||||
ctx.font = '600 11px Rajdhani, sans-serif';
|
ctx.font = '600 11px Rajdhani, sans-serif';
|
||||||
ctx.textAlign = 'left';
|
ctx.textAlign = 'left';
|
||||||
ctx.textBaseline = 'middle';
|
ctx.textBaseline = 'middle';
|
||||||
ctx.fillText(`${alt}°`, pt.x + 8, pt.y);
|
ctx.fillText(`${alt}°`, pt.x + 8, pt.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2569,7 +2585,7 @@ const MONTH_CHART_ERROR = <?= $starDataErrorJson ?: 'null' ?>;
|
|||||||
drawMoon(width, height);
|
drawMoon(width, height);
|
||||||
drawPlanets(width, height);
|
drawPlanets(width, height);
|
||||||
drawStars(width, height);
|
drawStars(width, height);
|
||||||
statusEl.textContent = 'Südhimmel für ' + MONTH_CHART_CONFIG.localTimeLabel;
|
statusEl.textContent = 'Südhimmel für ' + MONTH_CHART_CONFIG.localTimeLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeCanvas();
|
resizeCanvas();
|
||||||
|
|||||||
Binary file not shown.
+226
-2
@@ -466,6 +466,66 @@ def action_moon_phases_for_month(args: list[str]) -> dict:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def action_season_changes_for_month(args: list[str]) -> dict:
|
||||||
|
if len(args) != 3:
|
||||||
|
fail(
|
||||||
|
"Aktion season_changes_for_month erwartet 3 Argumente: year month timezone",
|
||||||
|
extra={"argv": args},
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
year = int(args[0])
|
||||||
|
month = int(args[1])
|
||||||
|
except ValueError as exc:
|
||||||
|
fail("Jahr oder Monat sind ungueltig.", extra={"details": str(exc), "argv": args})
|
||||||
|
|
||||||
|
if month < 1 or month > 12:
|
||||||
|
fail("Monat muss zwischen 1 und 12 liegen.", extra={"month": month})
|
||||||
|
|
||||||
|
timezone_name = args[2]
|
||||||
|
try:
|
||||||
|
tz = ZoneInfo(timezone_name)
|
||||||
|
except Exception as exc:
|
||||||
|
fail("Zeitzone ist ungueltig oder auf dem Server nicht verfuegbar.", extra={"details": str(exc)})
|
||||||
|
|
||||||
|
season_info = astronomy.Seasons(year)
|
||||||
|
season_defs = [
|
||||||
|
("Fruehlingsanfang", season_info.mar_equinox, "march_equinox"),
|
||||||
|
("Sommeranfang", season_info.jun_solstice, "june_solstice"),
|
||||||
|
("Herbstanfang", season_info.sep_equinox, "september_equinox"),
|
||||||
|
("Winteranfang", season_info.dec_solstice, "december_solstice"),
|
||||||
|
]
|
||||||
|
|
||||||
|
changes = []
|
||||||
|
for label, time_value, key in season_defs:
|
||||||
|
dt_utc = time_to_datetime(time_value)
|
||||||
|
local_dt = dt_utc.astimezone(tz)
|
||||||
|
if local_dt.year != year or local_dt.month != month:
|
||||||
|
continue
|
||||||
|
|
||||||
|
changes.append({
|
||||||
|
"key": key,
|
||||||
|
"label": label,
|
||||||
|
"utc_iso": dt_utc.isoformat().replace("+00:00", "Z"),
|
||||||
|
"local_iso": local_dt.isoformat(),
|
||||||
|
"local_date": local_dt.strftime("%d.%m.%Y"),
|
||||||
|
"local_time": local_dt.strftime("%H:%M"),
|
||||||
|
})
|
||||||
|
|
||||||
|
changes.sort(key=lambda item: item["local_iso"])
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ok": True,
|
||||||
|
"action": "season_changes_for_month",
|
||||||
|
"selected": {
|
||||||
|
"year": year,
|
||||||
|
"month": month,
|
||||||
|
"timezone": timezone_name,
|
||||||
|
},
|
||||||
|
"changes": changes,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def moon_planet_separation_deg(
|
def moon_planet_separation_deg(
|
||||||
body: astronomy.Body,
|
body: astronomy.Body,
|
||||||
observer: astronomy.Observer,
|
observer: astronomy.Observer,
|
||||||
@@ -477,6 +537,18 @@ def moon_planet_separation_deg(
|
|||||||
return spherical_separation_deg(float(moon_eq.ra), float(moon_eq.dec), float(body_eq.ra), float(body_eq.dec))
|
return spherical_separation_deg(float(moon_eq.ra), float(moon_eq.dec), float(body_eq.ra), float(body_eq.dec))
|
||||||
|
|
||||||
|
|
||||||
|
def planet_pair_separation_deg(
|
||||||
|
body_a: astronomy.Body,
|
||||||
|
body_b: astronomy.Body,
|
||||||
|
observer: astronomy.Observer,
|
||||||
|
dt_utc: datetime,
|
||||||
|
) -> float:
|
||||||
|
time_value = dt_to_time(dt_utc)
|
||||||
|
eq_a = astronomy.Equator(body_a, time_value, observer, True, True)
|
||||||
|
eq_b = astronomy.Equator(body_b, time_value, observer, True, True)
|
||||||
|
return spherical_separation_deg(float(eq_a.ra), float(eq_a.dec), float(eq_b.ra), float(eq_b.dec))
|
||||||
|
|
||||||
|
|
||||||
def refine_minimum_separation(
|
def refine_minimum_separation(
|
||||||
body: astronomy.Body,
|
body: astronomy.Body,
|
||||||
observer: astronomy.Observer,
|
observer: astronomy.Observer,
|
||||||
@@ -501,6 +573,31 @@ def refine_minimum_separation(
|
|||||||
return best, moon_planet_separation_deg(body, observer, best)
|
return best, moon_planet_separation_deg(body, observer, best)
|
||||||
|
|
||||||
|
|
||||||
|
def refine_planet_pair_minimum_separation(
|
||||||
|
body_a: astronomy.Body,
|
||||||
|
body_b: astronomy.Body,
|
||||||
|
observer: astronomy.Observer,
|
||||||
|
left_utc: datetime,
|
||||||
|
right_utc: datetime,
|
||||||
|
) -> tuple[datetime, float]:
|
||||||
|
left = left_utc
|
||||||
|
right = right_utc
|
||||||
|
|
||||||
|
for _ in range(32):
|
||||||
|
span = (right - left) / 3
|
||||||
|
m1 = left + span
|
||||||
|
m2 = right - span
|
||||||
|
f1 = planet_pair_separation_deg(body_a, body_b, observer, m1)
|
||||||
|
f2 = planet_pair_separation_deg(body_a, body_b, observer, m2)
|
||||||
|
if f1 <= f2:
|
||||||
|
right = m2
|
||||||
|
else:
|
||||||
|
left = m1
|
||||||
|
|
||||||
|
best = left + (right - left) / 2
|
||||||
|
return best, planet_pair_separation_deg(body_a, body_b, observer, best)
|
||||||
|
|
||||||
|
|
||||||
def action_moon_planet_approaches(args: list[str]) -> dict:
|
def action_moon_planet_approaches(args: list[str]) -> dict:
|
||||||
if len(args) != 7:
|
if len(args) != 7:
|
||||||
fail(
|
fail(
|
||||||
@@ -612,6 +709,123 @@ def action_moon_planet_approaches(args: list[str]) -> dict:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def action_planet_conjunctions_for_month(args: list[str]) -> dict:
|
||||||
|
if len(args) != 7:
|
||||||
|
fail(
|
||||||
|
"Aktion planet_conjunctions_for_month erwartet 7 Argumente: latitude longitude elevation year month timezone max_sep_deg",
|
||||||
|
extra={"argv": args},
|
||||||
|
)
|
||||||
|
|
||||||
|
latitude = parse_float(args[0], "Latitude")
|
||||||
|
longitude = parse_float(args[1], "Longitude")
|
||||||
|
elevation = parse_float(args[2], "Elevation")
|
||||||
|
|
||||||
|
try:
|
||||||
|
year = int(args[3])
|
||||||
|
month = int(args[4])
|
||||||
|
except ValueError as exc:
|
||||||
|
fail("Jahr oder Monat sind ungueltig.", extra={"details": str(exc), "argv": args})
|
||||||
|
|
||||||
|
if month < 1 or month > 12:
|
||||||
|
fail("Monat muss zwischen 1 und 12 liegen.", extra={"month": month})
|
||||||
|
|
||||||
|
timezone_name = args[5]
|
||||||
|
max_sep_deg = parse_float(args[6], "Maximalabstand")
|
||||||
|
|
||||||
|
try:
|
||||||
|
tz = ZoneInfo(timezone_name)
|
||||||
|
except Exception as exc:
|
||||||
|
fail("Zeitzone ist ungueltig oder auf dem Server nicht verfuegbar.", extra={"details": str(exc)})
|
||||||
|
|
||||||
|
observer = astronomy.Observer(latitude, longitude, elevation)
|
||||||
|
local_start = datetime(year, month, 1, 0, 0, 0, tzinfo=tz)
|
||||||
|
if month == 12:
|
||||||
|
local_end = datetime(year + 1, 1, 1, 0, 0, 0, tzinfo=tz)
|
||||||
|
else:
|
||||||
|
local_end = datetime(year, month + 1, 1, 0, 0, 0, tzinfo=tz)
|
||||||
|
|
||||||
|
utc_start = local_start.astimezone(timezone.utc)
|
||||||
|
utc_end = local_end.astimezone(timezone.utc)
|
||||||
|
scan_step = timedelta(hours=1)
|
||||||
|
coarse_threshold = max_sep_deg + 1.0
|
||||||
|
|
||||||
|
planet_defs = [
|
||||||
|
("Merkur", astronomy.Body.Mercury, "mercury"),
|
||||||
|
("Venus", astronomy.Body.Venus, "venus"),
|
||||||
|
("Mars", astronomy.Body.Mars, "mars"),
|
||||||
|
("Jupiter", astronomy.Body.Jupiter, "jupiter"),
|
||||||
|
("Saturn", astronomy.Body.Saturn, "saturn"),
|
||||||
|
("Uranus", astronomy.Body.Uranus, "uranus"),
|
||||||
|
("Neptun", astronomy.Body.Neptune, "neptune"),
|
||||||
|
]
|
||||||
|
|
||||||
|
conjunctions = []
|
||||||
|
for left_index in range(len(planet_defs) - 1):
|
||||||
|
left_label, left_body, left_key = planet_defs[left_index]
|
||||||
|
for right_index in range(left_index + 1, len(planet_defs)):
|
||||||
|
right_label, right_body, right_key = planet_defs[right_index]
|
||||||
|
|
||||||
|
samples: list[tuple[datetime, float]] = []
|
||||||
|
current = utc_start
|
||||||
|
while current <= utc_end:
|
||||||
|
samples.append((current, planet_pair_separation_deg(left_body, right_body, observer, current)))
|
||||||
|
current += scan_step
|
||||||
|
if samples[-1][0] < utc_end:
|
||||||
|
samples.append((utc_end, planet_pair_separation_deg(left_body, right_body, observer, utc_end)))
|
||||||
|
|
||||||
|
seen_ranges: list[tuple[datetime, datetime]] = []
|
||||||
|
for index in range(1, len(samples) - 1):
|
||||||
|
curr_t, curr_sep = samples[index]
|
||||||
|
prev_sep = samples[index - 1][1]
|
||||||
|
next_sep = samples[index + 1][1]
|
||||||
|
|
||||||
|
if curr_sep > coarse_threshold:
|
||||||
|
continue
|
||||||
|
if curr_sep > prev_sep or curr_sep > next_sep:
|
||||||
|
continue
|
||||||
|
|
||||||
|
left = max(utc_start, curr_t - scan_step)
|
||||||
|
right = min(utc_end, curr_t + scan_step)
|
||||||
|
|
||||||
|
if any(not (right <= seen_left or left >= seen_right) for seen_left, seen_right in seen_ranges):
|
||||||
|
continue
|
||||||
|
|
||||||
|
min_time_utc, min_sep = refine_planet_pair_minimum_separation(left_body, right_body, observer, left, right)
|
||||||
|
local_dt = min_time_utc.astimezone(tz)
|
||||||
|
if local_dt.year != year or local_dt.month != month:
|
||||||
|
continue
|
||||||
|
if min_sep > max_sep_deg:
|
||||||
|
continue
|
||||||
|
|
||||||
|
seen_ranges.append((left, right))
|
||||||
|
conjunctions.append({
|
||||||
|
"planet_a_key": left_key,
|
||||||
|
"planet_a_label": left_label,
|
||||||
|
"planet_b_key": right_key,
|
||||||
|
"planet_b_label": right_label,
|
||||||
|
"label": f"{left_label} nahe {right_label}",
|
||||||
|
"separation_deg": float(min_sep),
|
||||||
|
"utc_iso": min_time_utc.isoformat().replace("+00:00", "Z"),
|
||||||
|
"local_iso": local_dt.isoformat(),
|
||||||
|
"local_date": local_dt.strftime("%d.%m.%Y"),
|
||||||
|
"local_time": local_dt.strftime("%H:%M"),
|
||||||
|
})
|
||||||
|
|
||||||
|
conjunctions.sort(key=lambda item: item["local_iso"])
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ok": True,
|
||||||
|
"action": "planet_conjunctions_for_month",
|
||||||
|
"selected": {
|
||||||
|
"year": year,
|
||||||
|
"month": month,
|
||||||
|
"timezone": timezone_name,
|
||||||
|
"max_separation_deg": max_sep_deg,
|
||||||
|
},
|
||||||
|
"conjunctions": conjunctions,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def action_moon_star_occultations_for_month(args: list[str]) -> dict:
|
def action_moon_star_occultations_for_month(args: list[str]) -> dict:
|
||||||
if len(args) != 7:
|
if len(args) != 7:
|
||||||
fail(
|
fail(
|
||||||
@@ -1668,7 +1882,7 @@ def action_satellite_passes(args: list[str]) -> dict:
|
|||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
fail("Es wurde keine Aktion uebergeben.", extra={"available_actions": ["sun_moon_rise_set", "moon_star_occultations", "moon_phase_details", "satellite_passes", "planet_rise_set", "month_sky_context", "moon_phases_for_month", "moon_planet_approaches", "moon_star_occultations_for_month"]})
|
fail("Es wurde keine Aktion uebergeben.", extra={"available_actions": ["sun_moon_rise_set", "moon_star_occultations", "moon_phase_details", "satellite_passes", "planet_rise_set", "month_sky_context", "moon_phases_for_month", "season_changes_for_month", "moon_planet_approaches", "planet_conjunctions_for_month", "moon_star_occultations_for_month"]})
|
||||||
|
|
||||||
action = sys.argv[1]
|
action = sys.argv[1]
|
||||||
args = sys.argv[2:]
|
args = sys.argv[2:]
|
||||||
@@ -1683,6 +1897,11 @@ def main() -> None:
|
|||||||
print(json.dumps(result, ensure_ascii=False))
|
print(json.dumps(result, ensure_ascii=False))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if action == "season_changes_for_month":
|
||||||
|
result = action_season_changes_for_month(args)
|
||||||
|
print(json.dumps(result, ensure_ascii=False))
|
||||||
|
return
|
||||||
|
|
||||||
if action == "moon_phase_details":
|
if action == "moon_phase_details":
|
||||||
result = action_moon_phase_details(args)
|
result = action_moon_phase_details(args)
|
||||||
print(json.dumps(result, ensure_ascii=False))
|
print(json.dumps(result, ensure_ascii=False))
|
||||||
@@ -1713,12 +1932,17 @@ def main() -> None:
|
|||||||
print(json.dumps(result, ensure_ascii=False))
|
print(json.dumps(result, ensure_ascii=False))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if action == "planet_conjunctions_for_month":
|
||||||
|
result = action_planet_conjunctions_for_month(args)
|
||||||
|
print(json.dumps(result, ensure_ascii=False))
|
||||||
|
return
|
||||||
|
|
||||||
if action == "moon_star_occultations_for_month":
|
if action == "moon_star_occultations_for_month":
|
||||||
result = action_moon_star_occultations_for_month(args)
|
result = action_moon_star_occultations_for_month(args)
|
||||||
print(json.dumps(result, ensure_ascii=False))
|
print(json.dumps(result, ensure_ascii=False))
|
||||||
return
|
return
|
||||||
|
|
||||||
fail("Unbekannte Aktion.", extra={"action": action, "available_actions": ["sun_moon_rise_set", "moon_star_occultations", "moon_phase_details", "satellite_passes", "planet_rise_set", "month_sky_context", "moon_phases_for_month", "moon_planet_approaches", "moon_star_occultations_for_month"]})
|
fail("Unbekannte Aktion.", extra={"action": action, "available_actions": ["sun_moon_rise_set", "moon_star_occultations", "moon_phase_details", "satellite_passes", "planet_rise_set", "month_sky_context", "moon_phases_for_month", "season_changes_for_month", "moon_planet_approaches", "planet_conjunctions_for_month", "moon_star_occultations_for_month"]})
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user