Kleine PHP-Web-App zur Prüfung von Beobachtungsstandorten für Sonnen- und Mondfinsternisse.
SoFiChecker nimmt einen Ort, eine Adresse oder Koordinaten entgegen, berechnet lokale Finsterniszeiten, prüft Blickrichtung und Höhe von Sonne oder Mond und bewertet, ob Gelände oder kartierte Hindernisse die Beobachtung wahrscheinlich stören.
Damit der Projektordner übersichtlich bleibt, sind Laufzeitdateien und Hilfsskripte jetzt getrennt:
- Web-App-Laufzeit im Projektwurzelverzeichnis:
index.php,app.js,styles.css,translations.js,templates/,assets/ - lokale Hindernisdaten und Share-Daten:
data/ - Hindernis-Buildskripte:
scripts/obstacles/ - Log-Auswertung:
scripts/logs/ - lokale Entwicklungs- und Prüfhilfen:
scripts/dev/ - Testdaten und Import-Beispiele:
tests/
Für einen schlanken Linux-Deploy brauchst du im Normalfall nicht jede Hilfsdatei aus der Entwicklung mitzunehmen. Für den eigentlichen Betrieb der App sind vor allem diese Bereiche relevant:
index.phptemplates/assets/app.jsstyles.cssapp-config.jseclipse-events.jstranslations.jsannouncement-translations.jssite.webmanifestimage_og.pngimage_og.jpgimage_og.svgDATA-LICENSE.mdTHIRD-PARTY-LICENSES.mddata/obstacles/europe/
Nur wenn du direkt auf dem Server Daten nachladen oder prüfen willst, brauchst du zusätzlich:
scripts/obstacles/scripts/dev/check-php-requirements.php
Die App hilft dir bei einer sehr konkreten Frage: Ist ein bestimmter Standort für die Beobachtung einer Sonnen- oder Mondfinsternis geeignet?
Dafür beantwortet SoFiChecker unter anderem diese Punkte:
- Wann beginnen dort die relevanten Finsternisphasen?
- Wann liegt das Maximum?
- Wann geht die Sonne unter oder wie hoch steht der Mond während der Phasen?
- In welche Richtung musst du zu den wichtigen Zeitpunkten schauen?
- Wie hoch stehen Sonne oder Mond dann noch über dem Horizont?
- Gibt es Hinweise, dass Gelände, Gebäude, Industrieanlagen oder Vegetation die Sicht behindern könnten?
- Gibt es in der Nähe einen etwas höheren Ausweichpunkt?
Zusätzlich erzeugt die App eine fertige .kml-Datei für Google Earth.
Du wählst das Ereignis aus, das du prüfen willst. Die App zeigt dazu Datum, Ereignistyp und eine kurze Einordnung der Sichtbarkeit.
Du gibst eine Adresse, einen Ortsnamen oder Koordinaten ein oder klickst direkt in die Karte. Optional kannst du eine zusätzliche Beobachtungshöhe angeben, zum Beispiel für einen Aussichtspunkt, einen Turm oder eine Dachterrasse.
Per Knopfdruck startet die Analyse. Dabei werden nacheinander Standort, Zeitzone, astronomische Phasen, Geländehöhen, kartierte Hindernisse und Sichtlinien verarbeitet. Der laufende Status wird bewusst sichtbar protokolliert.
Am Ende zeigt die App das Ergebnis in einfacher Sprache an, ergänzt um Karte, Sichtprüfung, Beobachtungsphasen und Profilansichten.
Nach der Analyse kannst du das Ergebnis direkt weiter nutzen:
- die wichtigsten Beobachtungszeitpunkte lesen
- Blickrichtung und Höhe von Sonne oder Mond verstehen
- Kartenlinien und Hindernishinweise prüfen
- Horizont- und Seitenprofile vergleichen
- eine
.kml-Datei herunterladen - die Datei in Google Earth öffnen
- das Ergebnis lokal speichern
- einen Share-Link erzeugen und an andere weitergeben
- Die App ist eine vorsichtige Sichtprüfung, keine amtliche Freigabe.
- OSM-Daten können unvollständig, veraltet oder lokal lückenhaft sein.
- Nicht jedes einzelne Gebäude, jeder Baum und jede temporäre Struktur ist kartiert.
- Baumhöhen und Gebäudehöhen sind teils explizit, teils heuristisch geschätzt.
- Lokale Zugänglichkeit eines vorgeschlagenen Ausweichpunkts wird nicht rechtlich geprüft.
- Wetter, Bewölkung, Baustellen, saisonales Blattwerk und mobile Hindernisse werden nicht erfasst.
Die App verwendet für lokale Hindernisdaten aufbereitete OpenStreetMap-Daten aus Geofabrik-Extrakten.
Wichtig dafür:
- Datenquelle und Attribution: OpenStreetMap
- Quelldownloads unter anderem über Geofabrik
- Lizenz der OSM-basierten Daten: ODbL 1.0
Kurzform für die sichtbare Attribution in App, Webseite oder Begleittexten:
Kartendaten / Hindernisdaten: OpenStreetMap, ODbL 1.0
Empfohlene Links:
Ausführliche Hinweise für dieses Projekt stehen in:
DATA-LICENSE.mdTHIRD-PARTY-LICENSES.md
Dabei gilt:
DATA-LICENSE.mddokumentiert Datenquellen, Datenlizenzen und Attribution rund um OpenStreetMap, Geofabrik und lokale Hindernisdaten.THIRD-PARTY-LICENSES.mddokumentiert lokal mitgelieferte Software-Bibliotheken wieastronomy-engine,tz-lookupundMapLibre GL JS.
- Terminal im Projektordner öffnen.
- Vorschau starten:
.\start-server.ps1- Im Browser öffnen:
http://127.0.0.1:4173
Für Apache-Access-Logs gibt es jetzt das Skript scripts/logs/analyze-location-log.py.
Es sucht in Request-URLs wie /?lat=50.76380&lon=6.07527 nach Koordinaten, gruppiert sie und erzeugt eine Top-Liste der meistgenutzten Standorte.
Optional versucht es zusätzlich, per Nominatim einen sprechenden Ortsnamen zu ergänzen und legt dafür einen lokalen Cache an.
python3 ./scripts/logs/analyze-location-log.py \
/var/log/apache2/sofichecker/access.log \
/var/log/apache2/sofichecker/access.log.1 \
/var/log/apache2/sofichecker/access.log.2.gzpython3 ./scripts/logs/analyze-location-log.py --no-reverse \
/var/log/apache2/sofichecker/access.log \
/var/log/apache2/sofichecker/access.log.1python3 ./scripts/logs/analyze-location-log.py \
--output-json ./data/log-analysis/top-locations.json \
/var/log/apache2/sofichecker/access.logpython3 ./scripts/logs/analyze-location-log.py \
--output-kml ./data/log-analysis/top-locations.kml \
/var/log/apache2/sofichecker/access.log--top 100begrenzt die Zahl der Ausgabeeinträge--precision 5gruppiert nahe Koordinaten auf fünf Nachkommastellen--no-reverseunterdrückt Ortsnamen und arbeitet nur mit Koordinaten--cache-file ...setzt einen eigenen Cache-Pfad für Reverse Geocoding--nominatim-email ...hängt eine Kontaktadresse an Nominatim-Anfragen an--request-delay 1.1setzt die Pause zwischen uncached Reverse-Geocoding-Anfragen--output-kml ...schreibt die Top-Liste als KML-Datei für Google Earth
Die Standardausgabe ist tab-getrennt und enthält:
- Rang
- Trefferzahl
- Breite
- Länge
- Ortsbezeichnung oder Koordinaten-Fallback
Die Hindernisprüfung kann mit lokalen Geofabrik-Daten befüllt werden. Dafür ist kein Overpass mehr nötig.
- Linux-Server mit
bash python3- genug freier Speicherplatz für Downloads, temporäre Dateien und erzeugte Tiles
- Schreibrechte im Projektordner
Schnelltest:
python3 --version
bash --versionIm Projekt liegen dafür jetzt diese Dateien:
scripts/obstacles/build-obstacle-dataset.pyscripts/obstacles/build-obstacle-dataset.sh
Der Shell-Wrapper startet einfach den Python-Builder mit python3.
Nicht ganz Europa auf einmal laden, sondern in regionalen Paketen arbeiten.
Empfohlener Start:
luxembourggermany/berlingermany/hamburggermany/nordrhein-westfalen/koeln-regbez
Das deckt schon viele deiner bisherigen Testfälle ab, ohne sofort riesige Datenmengen zu erzeugen.
Im Projektordner:
chmod +x ./scripts/obstacles/build-obstacle-dataset.sh
./scripts/obstacles/build-obstacle-dataset.sh --clean --regions \
luxembourg \
germany/berlin \
germany/hamburg \
germany/nordrhein-westfalen/koeln-regbezWas dabei passiert:
- Geofabrik-GeoPackages werden in
data/obstacles/cache/geladen - relevante OSM-Hindernisse werden extrahiert
- JSON-Tiles werden unter
data/obstacles/europe/tiles/erzeugt - das Manifest wird nach
data/obstacles/europe/manifest.jsongeschrieben
Wenn die Zip-Dateien schon im Cache liegen und nichts neu geladen werden soll:
./scripts/obstacles/build-obstacle-dataset.sh --clean --skip-download --regions \
luxembourg \
germany/berlin \
germany/hamburg \
germany/nordrhein-westfalen/koeln-regbezDer Builder kann Regionen jetzt schrittweise hinzufügen.
Das bedeutet:
- ohne
--cleanbleiben bestehende Tiles erhalten - neue Regionen werden zu den vorhandenen Tiles und zum Manifest hinzugefügt
- du musst nicht jedes Mal erneut die komplette bisherige Regionsliste angeben
Beispiel:
./scripts/obstacles/build-obstacle-dataset.sh --regions germany/berlinWenn Berlin vorher noch nicht im Datensatz war, wird die Region jetzt zum bestehenden Bestand ergänzt.
Wichtig:
- mit
--cleanwird weiterhin ein komplett neuer Datensatz aufgebaut - ohne
--cleanarbeitet der Builder additiv - bereits installierte Regionen werden dabei standardmäßig übersprungen
- mit
--rebuild-regionskönnen vorhandene Regionen bewusst erneut verarbeitet werden
./scripts/obstacles/build-obstacle-dataset.sh --list-installedDas liest die Regionseinträge aus data/obstacles/europe/manifest.json.
./scripts/obstacles/build-obstacle-dataset.sh --list-availableDas lädt die aktuelle erste Europa-Ebene von Geofabrik und listet die dort verfügbaren Regions-Slugs auf.
./scripts/obstacles/build-obstacle-dataset.sh --list-missingDas vergleicht:
- installierte Regionen aus dem aktuellen Manifest
- verfügbare erste Europa-Ebene von Geofabrik
und gibt die noch nicht installierten Regionen aus.
Wenn du tiefer in eine Region hineinschauen willst, etwa unter germany, geht das jetzt direkt:
./scripts/obstacles/build-obstacle-dataset.sh --list-available-subregions germanyBeispiele:
./scripts/obstacles/build-obstacle-dataset.sh --list-available-subregions germany
./scripts/obstacles/build-obstacle-dataset.sh --list-available-subregions germany/nordrhein-westfalenDas listet jeweils die direkten Unterregionen der angegebenen Elternregion.
Wichtig:
- nicht jede Elternregion bietet selbst ein
latest-free.gpkg.zip - Beispiel:
germany/nordrhein-westfalenverweist für GeoPackage auf die Regierungsbezirke darunter - in solchen Fällen musst du eine passende Unterregion wie
germany/nordrhein-westfalen/koeln-regbezwählen
./scripts/obstacles/build-obstacle-dataset.sh --list-missing-subregions germanyBeispiele:
./scripts/obstacles/build-obstacle-dataset.sh --list-missing-subregions germany
./scripts/obstacles/build-obstacle-dataset.sh --list-missing-subregions germany/nordrhein-westfalenDas vergleicht:
- die direkt verfügbaren Unterregionen von Geofabrik
- mit den bereits installierten Regions-Slugs im Manifest
und gibt die direkten Unterregionen aus, die dir noch fehlen.
Wichtige Ordner:
data/obstacles/cache/enthält heruntergeladene Geofabrik-Zipsdata/obstacles/tmp/enthält nur temporäre Build-Dateiendata/obstacles/europe/tiles/enthält die produktiven Tile-Dateien
Wenn ein Lauf abgebrochen wurde, kannst du temporäre Daten gefahrlos löschen:
rm -rf data/obstacles/tmp/*Falls ein Download kaputt oder unvollständig im Cache liegt, lösche gezielt den betroffenen Regionsordner:
rm -rf data/obstacles/cache/germany/berlinDanach kann die Region sauber neu geladen werden.
Der Builder beschränkt sich bewusst auf die Hindernisse, die die App wirklich auswertet:
- Gebäude
- Industrieflächen
- Waldflächen
wood- Türme
- Schornsteine
Nicht geladen werden unter anderem:
- Straßen
- allgemeine POIs
- Wasserflächen
- sonstige Landnutzung
- ganz Europa in einem einzigen Schritt
Einzelne Regionen wie luxembourg oder germany/berlin sind gut beherrschbar.
Größere Regionen wie germany/nordrhein-westfalen/koeln-regbez sind schon deutlich schwerer.
Empfehlung für den Serverbetrieb:
- erst kleine Regionen testen
- dann in sinnvollen Paketen ausbauen
- nicht
--all-europebenutzen, solange Speicherplatz und Laufzeit nicht bewusst dafür geplant sind
Prüfe mindestens:
ls -lh data/obstacles/europe/
ls -lh data/obstacles/europe/tiles | headDas Manifest sollte danach echte Tile-Einträge enthalten und nicht mehr nur ein leeres tiles: [].
Auf den Webserver gehören nur die erzeugten Produktivdaten:
data/obstacles/europe/manifest.jsondata/obstacles/europe/tiles/
Die großen GeoPackage-Zips in data/obstacles/cache/ musst du nicht mit ausliefern, wenn der Build bereits auf dem Server selbst gelaufen ist.
Die Anwendung ist eine Single-Page-PHP-Seite:
index.phpliefert HTML und stellt zugleich kleine Proxy-Endpunkte für externe Dienste bereit.app.jsenthält Eingabelogik, astronomische Berechnung, Sichtprüfung, Karten-Rendering und KML-Erzeugung.translations.jsenthält die UI-Texte in Deutsch, Englisch und Französisch.styles.cssenthält das Layout und das Design.start-server.ps1startet lokal den eingebauten PHP-Webserver.
Wichtig:
- Die App ist nicht für reines GitHub Pages Hosting geeignet, weil sie PHP für die Proxy-Endpunkte benötigt.
- Externe Dienste werden bewusst über dieselbe
index.phpaufgerufen, damit Browser-CORS-Probleme vermieden werden und zentrale Fehlerbehandlung möglich bleibt.
- freie Adresse
- Ortsname
- bekannte Ortsbezeichnung
- Dezimal-Koordinaten
- Grad-Minuten-Sekunden-Notation
- Grad-und-dezimale-Minuten-Notation
Beispiele:
Luxemburger Straße 170, 50939 KölnDom, Köln50.88748, 6.7442953,548699076930056, 9,97875538504109445°51'32.01"N 1°15'16.62"W40°42.768'N 74°00.360'W
Die App kann Koordinaten direkt aus der URL übernehmen.
Unterstützt werden:
latlonobserverHeighthals Kurzform fürobserverHeightlangfür die UI-Sprache
Beispiel:
?lat=50.88748&lon=6.74429&observerHeight=2.5&lang=de
Koordinaten aus der URL werden nur akzeptiert, wenn sie ein enges numerisches Format erfüllen.
Für lat und lon gilt:
- nur Dezimalzahlen
- optionales führendes Minuszeichen
- maximal 24 Zeichen
- Breite nur von
-90bis90 - Länge nur von
-180bis180
Für observerHeight und h gilt:
- nur nichtnegative Dezimalzahlen
- maximal 16 Zeichen
- höchstens zwei Nachkommastellen
- Wertebereich
0bis500Meter
Ungültige Werte werden verworfen und nicht in die Analyse übernommen.
Die App berechnet für den Beobachtungsort diese Zeitpunkte:
- Beginn der Finsternis
- Maximum
- 15 Minuten nach dem Maximum
- 30 Minuten nach dem Maximum
- Ende der Finsternis
- zusätzlich kurz vor Sonnenuntergang, falls der Finsternisverlauf bis in diese Phase reicht
Für jeden dieser Zeitpunkte werden ermittelt:
- lokale Uhrzeit
- Sonnenazimut
- menschenlesbare Blickrichtung wie Westnordwest
- Sonnenhöhe über dem Horizont
- anschauliche Zusatzbeschreibung wie Daumenbreite, Faust oder Elle
Wenn ein Zeitpunkt nach Sonnenuntergang liegt, wird er nicht mehr als Beobachtungszeitpunkt verwendet.
Verwendet für:
- Umwandlung von Adresse oder Ortsname in Koordinaten
- Ermittlung einer nahegelegenen Ortsbezeichnung für die Ausgabe
Aufrufe:
?api=geocode&q=...?api=reverse&lat=...&lon=...
Externer Dienst:
- OpenStreetMap Nominatim
Abgefragte Parameter:
qlatlon- intern zusätzlich
format=jsonv2,limit=1,addressdetails=1, bei Reversezoom=18
Verwendet für:
- Geländehöhe des Beobachtungspunkts
- Geländehöhen entlang aller Sichtlinien
- Suche nach einem etwas höheren Ausweichpunkt in der Umgebung
Aufruf:
?api=elevation&dataset=...&locations=...
Externer Dienst:
- OpenTopoData
Abgefragte Parameter:
datasetlocations
Verwendete Datensätze:
eudem25mbevorzugt für Europamapzenals Fallback außerhalb dieses Bereichs
Verwendet für:
- Gebäude
- hohe Einzelbauwerke
- Industrieflächen
- Waldflächen
- Baumreihen
Aufruf:
?api=obstacles&south=...&west=...&north=...&east=...
Lokale Datenbasis:
data/obstacles/europe/manifest.json- darin referenzierte lokale Tile-Dateien
Wichtig:
- Hindernisdaten werden nicht mehr live bei Overpass abgefragt.
- Für die Sichtprüfung werden lokale Europa-Dateien serverseitig ausgelesen.
- Außerhalb Europas meldet die App bewusst, dass für diese lokale Datenbasis derzeit keine Abdeckung vorliegt.
- Wenn noch keine lokalen Datendateien installiert sind, wird das im Ergebnistext ausdrücklich genannt.
Das vermeidet Overpass-Limits, Timeouts und Abhängigkeiten von öffentlichen Drittinstanzen bei der Hindernisprüfung.
Verwendete Bibliotheken:
astronomy-enginetz-lookup
Verwendet für:
- lokale Sonnenfinsternis am 12. August 2026
- Sonnenuntergang
- Sonnenposition zu jedem Beobachtungszeitpunkt
- lokale IANA-Zeitzone des Standorts
Für die eigentlichen Berechnungen stützt sich die App auf diese Primärquellen oder Primärdokumentationen:
Verwendet für:
SearchLocalSolarEclipseSearchLunarEclipseSearchRiseSetEquatorHorizon
Offizielle Quellen:
In der App eingesetzt für:
- lokale Sonnenfinsternisse am Beobachtungsort
- globale Mondfinsternis-Phasen
- Sonnenuntergang
- topozentrische Horizontal-Koordinaten von Sonne und Mond
Verwendet für:
- freie Standortsuche per Text
- Reverse Geocoding für nahe Ortsbezeichnungen
Offizielle Quellen:
Verwendet für:
- Geländehöhen einzelner Punkte
- Geländehöhen entlang von Sichtlinien
Offizielle Quellen:
Verwendet für:
- lokale Hindernisdaten
- Gebäudegrundrisse
- Vegetation, Industrieflächen und ausgewählte
man_made-Objekte
Offizielle Quellen:
Verwendet für:
- Zuordnung von Koordinaten zu einer IANA-Zeitzone
- lokale Ausgabe mit Sommerzeit und korrekter Ortszeit
Offizielle Quellen:
Dieser Abschnitt dokumentiert die mathematischen Formeln, die in app.js tatsächlich verwendet werden. Es geht dabei nicht um allgemeine Theorie, sondern um die konkret implementierten Rechenschritte.
Wichtig:
- Eigene Geometrie-, Distanz- und Sichtlinienformeln der App werden hier vollständig dokumentiert.
- Astronomische Kernrechnungen wie Finsternissuche, topozentrische Ephemeriden, Auf- und Untergänge stammen direkt aus
astronomy-engineund werden deshalb nicht als Eigenformeln der App nachimplementiert. - Die App dokumentiert diese Bibliotheksaufrufe bewusst als Primärquelle und trennt sie von den eigenen Rechenschritten.
Verwendet in:
destinationPoint(...)
Zweck:
- Endpunkte von Peillinien
- Abtastpunkte entlang einer Sichtlinie
- KML-Bodenlinien
- KML-3D-Peilstrahlen
Formel:
angularDistance = distanceMeters / EARTH_RADIUS_METERS
bearingRad = degToRad(bearingDeg)
latRad = degToRad(lat)
lonRad = degToRad(lon)
destinationLat =
asin(
sin(latRad) * cos(angularDistance) +
cos(latRad) * sin(angularDistance) * cos(bearingRad)
)
destinationLon =
lonRad +
atan2(
sin(bearingRad) * sin(angularDistance) * cos(latRad),
cos(angularDistance) - sin(latRad) * sin(destinationLat)
)
Danach wird die Länge wieder in den Bereich -180° bis +180° normalisiert.
Verwendet in:
haversineDistance(...)
Zweck:
- Entfernung zwischen Beobachter und Hindernis
- Distanzbewertung für Hindernis-Matching
Formel:
phi1 = degToRad(lat1)
phi2 = degToRad(lat2)
deltaPhi = degToRad(lat2 - lat1)
deltaLambda = degToRad(lon2 - lon1)
a =
sin(deltaPhi / 2)^2 +
cos(phi1) * cos(phi2) * sin(deltaLambda / 2)^2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
distance = EARTH_RADIUS_METERS * c
Verwendet in:
computeBearing(...)
Zweck:
- Richtung vom Beobachter zu kartierten Hindernissen
- Vergleich zwischen Sonnen- oder Mondazimut und Hindernisrichtung
Formel:
phi1 = degToRad(lat1)
phi2 = degToRad(lat2)
lambda1 = degToRad(lon1)
lambda2 = degToRad(lon2)
y = sin(lambda2 - lambda1) * cos(phi2)
x =
cos(phi1) * sin(phi2) -
sin(phi1) * cos(phi2) * cos(lambda2 - lambda1)
bearing = normalizeBearing(radToDeg(atan2(y, x)))
Verwendet in:
angularDifferenceDegrees(...)
Zweck:
- Prüfung, ob ein Hindernis genügend nahe an der Blickrichtung liegt
Formel:
difference = abs(first - second)
if difference > 180 then difference = 360 - difference
Verwendet in:
convertGeoPointToLocalMeters(...)convertLocalMetersToGeoPoint(...)convertAzimuthToLocalVector(...)intersectLineSegments(...)
Zweck:
- Vereinfachte lokale 2D-Geometrie für Grundriss-Schnittberechnung
Formeln:
metersPerDegreeLongitude = 111320 * cos(degToRad(averageLatitude))
x = (point.lon - observer.lon) * metersPerDegreeLongitude
y = (point.lat - observer.lat) * 111320
Rückrichtung:
lat = observer.lat + (localY / 111320)
lon = observer.lon + (localX / metersPerDegreeLongitude)
Azimut-Vektor:
x = sin(azimuthRadians)
y = cos(azimuthRadians)
Verwendet in:
computeApparentAngle(...)
Zweck:
- maximalen Gelände- und Hinderniswinkel über dem lokalen Horizont bestimmen
Formel:
curvatureDrop = distanceMeters^2 / (2 * EARTH_RADIUS_METERS)
adjustedTargetElevation = targetGroundElevation + extraHeight - curvatureDrop
elevationDifference = adjustedTargetElevation - observerElevation
angleRad = atan2(elevationDifference, distanceMeters)
angleDeg = radToDeg(angleRad)
Wichtig:
- Die App berücksichtigt hier eine einfache Erdkrümmungskorrektur.
- Atmosphärische Refraktion wird in dieser eigenen Sichtlinienformel nicht zusätzlich modelliert.
Verwendet in:
calculateRayAltitudeOffset(...)
Zweck:
- 3D-Sonnenlinie mit realistischer Steigung in Google Earth
Formel:
altitudeOffset = tan(degToRad(sunAltitude)) * horizontalDistance
Verwendet in:
getSolarHorizontalCoordinates(...)getMoonHorizontalCoordinates(...)
Zweck:
- Azimut und Höhe von Sonne oder Mond zum jeweiligen Phasenzeitpunkt
Die App berechnet diese Werte nicht mit eigenen Tabellenformeln, sondern nutzt direkt:
Astronomy.Equator(...)Astronomy.Horizon(...)
Damit stammen die eigentlichen topozentrischen Himmelskoordinaten vollständig aus Astronomy Engine.
Verwendet in:
classifyVisibility(...)classifyTerrainSegment(...)
Zweck:
- Einordnung in
good,warnoderbad
Feste Schwellwerte aus der App:
VISIBILITY_MARGIN_DEGREES = 0.35
CRITICAL_MARGIN_DEGREES = 0.8
Die Sichtlinie wird konservativ bewertet über:
- Differenz zwischen Sonnenhöhe und stärkstem Geländewinkel
- Differenz zwischen Sonnenhöhe und stärkstem Hinderniswinkel
- Verfügbarkeit oder Fehlen der Hindernisdaten
Vereinfacht:
bad, wenn die Hindernisreserve<= 0.35°fälltwarn, wenn die Reserve klein ist oder Hindernisdaten fehlengood, wenn ausreichend Reserve vorhanden ist
Verwendet in:
classifyLunarAltitudeStatus(...)
Zweck:
- schnelle erste Bewertung, ob der Mond während der Phasen überhaupt sinnvoll sichtbar ist
Schwellwerte:
bad : moonAltitude <= 0°
warn : 0° < moonAltitude < 5°
good : moonAltitude >= 5°
Wichtig:
- Diese erste Mondlogik bewertet aktuell nur die Horizonthöhe des Mondes.
- Eine echte Hindernisprüfung für Mondfinsternisse ist im Codepfad noch nicht fertig.
- geografische Breite
- geografische Länge
- zusätzliche Beobachtungshöhe über dem Gelände
- Geländehöhe des Standorts
- effektive Augenhöhe des Beobachters
- Beginn der partiellen Finsternis
- Maximum
- Ende der partiellen Finsternis
- Sonnenuntergang
- lokalisierte Uhrzeiten in der IANA-Zeitzone des Standorts
- Azimut der Sonne
- Höhe der Sonne
- Peillinienlänge: ungefähr
5 km - Abtastung des Geländes entlang der Linien
- Winkel des Geländes über dem Horizont
- Winkel kartierter Hindernisse über dem Horizont
- Differenz zwischen Sonnenhöhe und größtem Hinderniswinkel
Die Analyse besteht aus mehreren Schritten.
Für jede relevante Peillinie wird ein Höhenprofil über ungefähr 5 km berechnet.
Geprüft wird:
- ob das Gelände in Blickrichtung ansteigt
- wie groß der stärkste Geländewinkel über dem Horizont ist
- wie viel Reserve zwischen Sonnenhöhe und Gelände bleibt
Zusätzlich werden lokal vorgehaltene OSM-Hindernisdaten entlang der Blickrichtung ausgewertet.
Berücksichtigt werden aktuell:
buildinglanduse=industrialman_made=towerman_made=chimneylanduse=forestnatural=woodnatural=tree_row
Wenn OSM keine explizite Höhe liefert, arbeitet die App mit vorsichtigen Heuristiken.
Beispiele:
- Türme und Schornsteine: ungefähr
35 m - Industrieflächen: ungefähr
20 m - Baumreihen: ungefähr
18 m - Waldkanten: ungefähr
20 m - Gebäude: explizite OSM-Höhe oder Schätzung aus
building:levels,roof:heightund Gebäudetyp
Bei Gebäuden werden unter anderem ausgewertet:
heightbuilding:heightroof:heightbuilding:levelsbuilding
Wenn die lokalen Datendateien Geometrien enthalten, werden diese genutzt, um:
- Gebäudegrundrisse genauer auf die Sichtlinie zu schneiden
- nahe Bauwerke realistischer zu bewerten
- nicht nur den Schwerpunkt eines Objekts zu betrachten
Die App klassifiziert jede Sichtlinie grob in:
voraussichtlich freiteilweise gefährdetwahrscheinlich verdeckt
Dabei fließen ein:
- Sonnenhöhe
- Geländewinkel
- Winkel kartierter Hindernisse
- verfügbare oder fehlende Datenabdeckung der Hindernisklassen
Wenn lokale Hindernisdaten nur teilweise oder gar nicht geladen werden konnten, wird das explizit im Ergebnistext erwähnt.
Für die Lade- und Ausgabelogik werden die Hindernisse in drei Gruppen gegliedert:
- Gebäude
- weitere Bauwerke und Industrieflächen
- Wald und Baumstrukturen
Das Ergebnis kann daher auch Teilinformationen ausgeben, zum Beispiel:
- Gebäude wurden geprüft, Vegetation konnte nicht geladen werden
- Gebäude und Bauwerke wurden geprüft, Walddaten fehlen
Die App erzeugt:
- Beobachtungspunkt
- Peillinien für die relevanten Zeitpunkte
- farbliche Bewertung der Linienabschnitte in der Karte
- hervorgehobenes Maximum
- markierte mögliche Hindernisse
- gegebenenfalls einen grün markierten höheren Ausweichpunkt
- eine fertige
.kml-Datei zum Download
Die KML enthält unter anderem:
- Beobachtungspunkt
- Peillinien mit beschrifteten Ereignissen
- Richtung und Sonnenhöhe
- hervorgehobenes Maximum
- optional den Ausweichpunkt
Für die drei auswählbaren Sonnenfinsternisse enthält die App zusätzlich kuratierte Zonendaten für:
- den Karten-Button direkt in der Ereignisauswahl
- das OSM-Popup mit Zentralzone
- den erklärenden KML-Zusatzlayer
Diese Daten liegen zentral im globalen Katalog window.SOFICHECKER_SOLAR_PATH_CATALOG in
eclipse-events.js. Pro Sonnenfinsternis werden dort gepflegt:
northLimitStringssouthLimitStringscenterLineStringsviewportsourceNamesourceUrl
Wichtige Einordnung:
- Verwendet werden die Daten nur bei Sonnenfinsternissen mit gesetztem
kmlPathKey. - Sie dienen dem erklärenden Karten- und KML-Overlay und nicht der eigentlichen Sichtprüfung am Standort.
- Gezeigt wird jeweils ein bewusst kuratierter Ausschnitt, der zur Europa-Ausrichtung der App passt.
Format der Rohdaten:
- jeder Eintrag ist eine Breite-Länge-Angabe mit Grad und Dezimalminuten
- Beispiel:
71 59.5N 023 18.8W - zuerst Breite, dann Länge
Quelle:
- kuratierte NASA-GSFC-Pfadkoordinaten aus den offiziellen Pfadtabellen der jeweiligen Sonnenfinsternis
Die Rohstrings werden in geografische Punkte umgerechnet und anschließend sowohl als Polygon für die Zone als auch als Linie für die Zentrallinie ausgegeben.
Die App erklärt die Analyse in alltagsnaher Sprache und beantwortet unter anderem:
- wann man vor Ort sein sollte
- in welche Richtung man schauen muss
- wie hoch die Sonne beim Maximum steht
- ob die Sicht wahrscheinlich frei ist
- welche Hindernisse problematisch sein könnten
- ob in der Nähe ein etwas höherer Ausweichpunkt vorgeschlagen wird
Die Statusanzeige beschreibt den Ablauf bewusst detailliert.
Typische Schritte sind:
- Eingabe prüfen
- Standort auflösen
- Geländedaten laden
- astronomische Zeiten berechnen
- Geländeprofile vorbereiten
- lokale Europa-Hindernisdaten laden
- Hindernisgeometrien vorbereiten
- einzelne Sichtlinien auswerten
- Ergebnis und KML erzeugen
Für Geocoding und Geländehöhen weist die App weiterhin bewusst darauf hin, wenn Daten von externen Drittanbietern geladen werden.
Die Seite stellt intern diese Endpunkte bereit:
?api=geocode?api=reverse?api=elevation?api=obstacles?api=share-save?api=share-load
?api=obstacles ist dabei kein externer Proxy, sondern liest lokale Europa-Dateien anhand einer angeforderten Bounding Box aus.
Der Teilen-Button kann fertige Analyseergebnisse serverseitig speichern und daraus eine kurze URL mit ?share=... erzeugen.
Wichtig dabei:
- Gespeichert wird nicht jede Analyse automatisch.
- Ein serverseitiger SQLite-Eintrag entsteht nur nach aktivem Klick auf
Teilen. - Die kurze Share-URL lädt das fertige Ergebnis später direkt wieder, ohne Neuberechnung.
- Serverseitig wird der Share-Payload mit explizitem
formatundversiongespeichert und beim Laden wieder geprüft. - Ältere bereits gespeicherte Share-Einträge ohne diese Hülle bleiben weiterhin lesbar und werden als Legacy-Format behandelt.
- Lokal speichert der Browser erfolgreiche Analysen weiterhin zusätzlich in
IndexedDB. - Jeder erfolgreiche Aufruf eines Share-Links erhöht serverseitig den Zugriffszähler und aktualisiert den letzten Aufrufzeitpunkt.
Für diese Funktion braucht der Server:
PDOpdo_sqlite- Schreibrechte auf das Share-Verzeichnis des jeweiligen Systems:
- Windows lokal:
data/shared/ - Linux-Server:
/var/lib/sofichecker/
Für Kontrolle, Statistik, Verlängern, Sperren und Löschen gibt es eine separate Verwaltungsseite:
?admin=shares
Die Seite ist per HTTP Basic Auth geschützt. Dafür müssen auf dem Server diese Umgebungsvariablen gesetzt sein:
SOFICHECKER_ADMIN_USERSOFICHECKER_ADMIN_PASSWORD
Beispiel mit Apache-Umgebung oder Systemd-Umgebung:
SOFICHECKER_ADMIN_USER=adminname
SOFICHECKER_ADMIN_PASSWORD=sehr-langes-passwort
Die Admin-Seite zeigt unter anderem:
- Anzahl aktiver, abgelaufener und gesperrter Share-Links
- gesamte Aufrufzahl
- letzter Aufruf pro Share-Link
- Verlängerung des Ablaufdatums
- Sperren, Reaktivieren und Löschen einzelner Einträge
- Sammelaktion zum Löschen abgelaufener Links
Bei Nutzung der App werden je nach Eingabe und Analyse Standortdaten an Drittanbieter übermittelt:
- Nominatim für Geocoding und Reverse Geocoding
- OpenTopoData für Geländehöhen
Übermittelt werden insbesondere:
- Suchbegriffe oder Adressen
- Koordinaten
- Punktlisten für Höhenabfragen
Bounding Boxes für Hindernisabfragen bleiben bei der lokalen Europa-Datei-Prüfung auf dem eigenen Server.
Wenn ein Nutzer aktiv auf Teilen klickt, wird das serialisierte Analyseergebnis zusätzlich auf dem eigenen Server in SQLite gespeichert, damit eine kurze Share-ID daraus erzeugt werden kann.
Die App enthält keinen Nutzer-Account-Teil. Eine kleine SQLite-Datenbank wird nur für aktiv erzeugte Share-Links und deren Verwaltungsmetadaten verwendet.
- UI-Texte liegen zentral in
translations.js. - Die Seite startet die Analyse nur nach Knopfdruck.
- Koordinaten aus URL-Parametern werden streng validiert.
- Die Hindernisprüfung liest lokale Europa-Dateien über ein Manifest in
data/obstacles/europe/manifest.json. - Der Hindernis-Endpunkt akzeptiert nur streng validierte Bounding-Box-Parameter.
- Wenn keine lokalen Europa-Dateien installiert sind, arbeitet die App weiter mit Gelände und Sonnenstand und kennzeichnet das Ergebnis vorsichtig.
- Nominatim: Adresse oder Ortsname zu Koordinaten und Ortsbezeichnung
- OpenTopoData: Geländehöhen für Punkt und Sichtlinien
- lokale Europa-Dateien: Gebäude, Industrie, Bauwerke, Wald und Baumstrukturen
- Astronomy Engine: Finsternis, Sonnenposition, Sonnenuntergang
- tz-lookup: lokale Zeitzone