Neue Seite fuer Mond-Planeten-Bedeckungen mit Jahresberechnung hinzufuegen

Berechnet Bedeckungen der Planeten Merkur bis Neptun durch den Mond fuer
ein ganzes Jahr am Standardstandort, inklusive Detailkarte. Ereignisse
unter dem Horizont werden weiterhin angezeigt statt gefiltert, dafuer
mit eigenem Sichtbarkeits-Hinweis.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 09:35:36 +02:00
co-authored by Claude Sonnet 5
parent 86fccdc773
commit 5652cc7e40
6 changed files with 1448 additions and 2 deletions
+155 -2
View File
@@ -5844,6 +5844,154 @@ def action_moon_star_occultations(args: list[str]) -> dict:
}
PLANET_OCCULTATION_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"),
]
def compute_moon_planet_occultations_for_range(
observer: astronomy.Observer,
utc_start: datetime,
utc_end: datetime,
tz: ZoneInfo,
) -> list[dict]:
scan_step = timedelta(hours=1)
coarse_threshold_deg = 3.0
results: list[dict] = []
for label, body, key in PLANET_OCCULTATION_DEFS:
samples: list[tuple[datetime, float]] = []
current = utc_start
while current <= utc_end:
samples.append((current, moon_planet_separation_deg(body, observer, current)))
current += scan_step
if samples[-1][0] < utc_end:
samples.append((utc_end, moon_planet_separation_deg(body, observer, utc_end)))
seen_ranges: list[tuple[datetime, datetime]] = []
for index in range(1, len(samples) - 1):
prev_t, prev_sep = samples[index - 1]
curr_t, curr_sep = samples[index]
next_t, next_sep = samples[index + 1]
if curr_sep > coarse_threshold_deg:
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_minimum_separation(body, observer, left, right)
seen_ranges.append((left, right))
overlap_fraction = moon_planet_overlap_fraction(body, observer, min_time_utc)
if overlap_fraction <= 0.0:
continue
time_value = dt_to_time(min_time_utc)
moon_eq = astronomy.Equator(astronomy.Body.Moon, time_value, observer, True, True)
planet_eq = astronomy.Equator(body, time_value, observer, True, True)
sun_eq = astronomy.Equator(astronomy.Body.Sun, time_value, observer, True, True)
moon_hor = astronomy.Horizon(time_value, observer, moon_eq.ra, moon_eq.dec, astronomy.Refraction.Normal)
planet_hor = astronomy.Horizon(time_value, observer, planet_eq.ra, planet_eq.dec, astronomy.Refraction.Normal)
sun_hor = astronomy.Horizon(time_value, observer, sun_eq.ra, sun_eq.dec, astronomy.Refraction.Normal)
below_horizon = float(moon_hor.altitude) <= 0.0 or float(planet_hor.altitude) <= 0.0
ingress_time = refine_occultation_contact(body, observer, min_time_utc, -1)
egress_time = refine_occultation_contact(body, observer, min_time_utc, 1)
duration_seconds = None
if ingress_time is not None and egress_time is not None:
duration_seconds = int(round((egress_time - ingress_time).total_seconds()))
moon_radius_deg = moon_angular_radius_deg(float(moon_eq.dist))
planet_radius_deg = planet_angular_radius_deg(body, float(planet_eq.dist))
results.append({
"planet_key": key,
"planet_label": label,
"ingress": serialize_occultation_time(ingress_time, tz),
"maximum": serialize_occultation_time(min_time_utc, tz),
"egress": serialize_occultation_time(egress_time, tz),
"partial_start": ingress_time is None,
"partial_end": egress_time is None,
"duration_seconds": duration_seconds,
"separation_arcmin": float(min_sep) * 60.0,
"moon_radius_arcmin": moon_radius_deg * 60.0,
"planet_radius_arcsec": planet_radius_deg * 3600.0,
"overlap_fraction": float(overlap_fraction),
"is_total": overlap_fraction >= 0.999,
"moon_alt_deg": float(moon_hor.altitude),
"planet_alt_deg": float(planet_hor.altitude),
"sun_alt_deg": float(sun_hor.altitude),
"below_horizon": below_horizon,
"visibility": {"key": "below_horizon", "label": "Unter Horizont"} if below_horizon
else classify_visibility(float(sun_hor.altitude)),
})
results.sort(
key=lambda item: item["maximum"]["utc_iso"] if item["maximum"] else "9999-99-99T99:99:99Z"
)
return results
def action_moon_planet_occultations_for_year(args: list[str]) -> dict:
if len(args) != 5:
fail(
"Aktion moon_planet_occultations_for_year erwartet 5 Argumente: latitude longitude elevation year timezone",
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])
except ValueError as exc:
fail("Jahr ist ungueltig.", extra={"details": str(exc), "argv": args})
timezone_name = args[4]
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, 1, 1, 0, 0, 0, tzinfo=tz)
local_end = datetime(year + 1, 1, 1, 0, 0, 0, tzinfo=tz)
utc_start = local_start.astimezone(timezone.utc)
utc_end = local_end.astimezone(timezone.utc)
results = compute_moon_planet_occultations_for_range(observer, utc_start, utc_end, tz)
return {
"ok": True,
"action": "moon_planet_occultations_for_year",
"selected": {
"year": year,
"timezone": timezone_name,
},
"observer": {
"latitude": latitude,
"longitude": longitude,
"elevation": elevation,
},
"results": results,
}
# ── satellite_passes ──────────────────────────────────────────────────────────
import math as _math
@@ -6415,7 +6563,7 @@ def action_barycenter(args: list[str]) -> dict:
def main() -> None:
if len(sys.argv) < 2:
fail("Es wurde keine Aktion uebergeben.", extra={"available_actions": ["sun_moon_rise_set", "solar_longitude_to_datetime", "current_solar_longitude", "astronomical_conversions", "comet_brightnesses", "favorite_comet_events_for_month", "moon_star_occultations", "moon_phase_details", "satellite_passes", "planet_rise_set", "planet_ephemeris", "month_sky_context", "moon_phases_for_month", "golden_handle_for_month", "season_changes_for_month", "time_changes_for_month", "moon_planet_approaches", "moon_deep_sky_approaches_for_month", "planet_bright_star_approaches_for_month", "golden_gate_of_ecliptic_for_month", "planet_conjunctions_for_month", "eclipses_for_month", "moon_apsides_for_month", "sun_apsides_for_month", "inner_planet_elongations_for_month", "venus_peak_magnitude_for_month", "outer_planet_events_for_month", "outer_planet_stations_for_month", "jupiter_moons_one_side_for_month", "mercury_good_visibility_for_month", "planet_parades_for_month", "planet_constellation_changes_for_month", "sun_constellation_changes_for_year", "sun_constellation_offset_statistics", "moon_star_occultations_for_month"]})
fail("Es wurde keine Aktion uebergeben.", extra={"available_actions": ["sun_moon_rise_set", "solar_longitude_to_datetime", "current_solar_longitude", "astronomical_conversions", "comet_brightnesses", "favorite_comet_events_for_month", "moon_star_occultations", "moon_phase_details", "satellite_passes", "planet_rise_set", "planet_ephemeris", "month_sky_context", "moon_phases_for_month", "golden_handle_for_month", "season_changes_for_month", "time_changes_for_month", "moon_planet_approaches", "moon_deep_sky_approaches_for_month", "planet_bright_star_approaches_for_month", "golden_gate_of_ecliptic_for_month", "planet_conjunctions_for_month", "eclipses_for_month", "moon_apsides_for_month", "sun_apsides_for_month", "inner_planet_elongations_for_month", "venus_peak_magnitude_for_month", "outer_planet_events_for_month", "outer_planet_stations_for_month", "jupiter_moons_one_side_for_month", "mercury_good_visibility_for_month", "planet_parades_for_month", "planet_constellation_changes_for_month", "sun_constellation_changes_for_year", "sun_constellation_offset_statistics", "moon_star_occultations_for_month", "moon_planet_occultations_for_year"]})
action = sys.argv[1]
args = sys.argv[2:]
@@ -6605,6 +6753,11 @@ def main() -> None:
print(json.dumps(result, ensure_ascii=True))
return
if action == "moon_planet_occultations_for_year":
result = action_moon_planet_occultations_for_year(args)
print(json.dumps(result, ensure_ascii=True))
return
if action == "lunar_eclipses_for_year":
result = action_lunar_eclipses_for_year(args)
print(json.dumps(result, ensure_ascii=True))
@@ -6615,7 +6768,7 @@ def main() -> None:
print(json.dumps(result, ensure_ascii=True))
return
fail("Unbekannte Aktion.", extra={"action": action, "available_actions": ["sun_moon_rise_set", "solar_longitude_to_datetime", "current_solar_longitude", "astronomical_conversions", "twilight_chart", "comet_brightnesses", "favorite_comet_events_for_month", "moon_star_occultations", "moon_phase_details", "satellite_passes", "planet_rise_set", "planet_ephemeris", "planet_visibility_chart", "month_sky_context", "moon_phases_for_month", "golden_handle_for_month", "season_changes_for_month", "time_changes_for_month", "moon_planet_approaches", "moon_deep_sky_approaches_for_month", "planet_bright_star_approaches_for_month", "golden_gate_of_ecliptic_for_month", "planet_conjunctions_for_month", "eclipses_for_month", "moon_apsides_for_month", "sun_apsides_for_month", "inner_planet_elongations_for_month", "venus_peak_magnitude_for_month", "outer_planet_events_for_month", "outer_planet_stations_for_month", "jupiter_moons_one_side_for_month", "mercury_good_visibility_for_month", "planet_parades_for_month", "planet_constellation_changes_for_month", "sun_constellation_changes_for_year", "sun_constellation_offset_statistics", "moon_star_occultations_for_month"]})
fail("Unbekannte Aktion.", extra={"action": action, "available_actions": ["sun_moon_rise_set", "solar_longitude_to_datetime", "current_solar_longitude", "astronomical_conversions", "twilight_chart", "comet_brightnesses", "favorite_comet_events_for_month", "moon_star_occultations", "moon_phase_details", "satellite_passes", "planet_rise_set", "planet_ephemeris", "planet_visibility_chart", "month_sky_context", "moon_phases_for_month", "golden_handle_for_month", "season_changes_for_month", "time_changes_for_month", "moon_planet_approaches", "moon_deep_sky_approaches_for_month", "planet_bright_star_approaches_for_month", "golden_gate_of_ecliptic_for_month", "planet_conjunctions_for_month", "eclipses_for_month", "moon_apsides_for_month", "sun_apsides_for_month", "inner_planet_elongations_for_month", "venus_peak_magnitude_for_month", "outer_planet_events_for_month", "outer_planet_stations_for_month", "jupiter_moons_one_side_for_month", "mercury_good_visibility_for_month", "planet_parades_for_month", "planet_constellation_changes_for_month", "sun_constellation_changes_for_year", "sun_constellation_offset_statistics", "moon_star_occultations_for_month", "moon_planet_occultations_for_year"]})
if __name__ == "__main__":