geoidundolation und export

This commit is contained in:
2026-02-06 21:01:48 +01:00
parent 4340205f45
commit 75d41bd21b
5 changed files with 343 additions and 365 deletions

File diff suppressed because it is too large Load Diff

116
Export.py
View File

@@ -1,5 +1,6 @@
import csv import csv
from datetime import datetime from datetime import datetime
from Koordinatentransformationen import Transformationen
import numpy as np import numpy as np
import os import os
import pandas as pd import pandas as pd
@@ -61,6 +62,83 @@ class Export:
zeile_als_text.append(eintrag_text) zeile_als_text.append(eintrag_text)
writer.writerow(zeile_als_text) writer.writerow(zeile_als_text)
@staticmethod
def erzeuge_ergebnis_datenframes(
pfad_datenbank,
pfad_tif_quasigeoidundulation,
dict_koordinaten_ausgleichungsergebnis
):
"""
Erzeugt Ergebnis-DataFrames für ausgeglichene Koordinaten in ECEF (XYZ) und UTM.
Die Funktion nimmt ein Dictionary mit ausgeglichenen geozentrisch-kartesischen Koordinaten
(ECEF/XYZ) entgegen, transformiert diese über die Transformationen-Klasse nach ETRS89/UTM
(inkl. Höhenangabe; optional unter Nutzung einer Quasigeoidundulations-Datei) und erstellt
zwei tabellarische Ergebnisdarstellungen:
- df_x_final: Geozentrische Koordinaten X/Y/Z [m],
- df_utm_final: UTM-Koordinaten (Rechtswert/Hochwert/Höhe) [m].
:param pfad_datenbank: Pfad zur SQLite-Datenbank (für Koordinaten-/Transformationszugriffe).
:type pfad_datenbank: str
:param pfad_tif_quasigeoidundulation: Pfad zu Quasigeoidundulationsdaten als GeoTIFF (optional, für Höhen/PROJ).
:type pfad_tif_quasigeoidundulution: str | None
:param dict_koordinaten_ausgleichungsergebnis: Dictionary der ausgeglichenen ECEF-Koordinaten je Punkt.
:type dict_koordinaten_ausgleichungsergebnis: dict
:return: Tuple aus DataFrame der ECEF-Koordinaten (XYZ) und DataFrame der UTM-Koordinaten.
:rtype: tuple[pandas.DataFrame, pandas.DataFrame]
"""
# Transformation initialisieren
trafos = Transformationen(pfad_datenbank)
dict_koordinaten_utm = trafos.ecef_to_utm(
dict_koordinaten_ausgleichungsergebnis,
pfad_tif_quasigeoidundulation
)
namen = list(dict_koordinaten_ausgleichungsergebnis.keys())
# SymPy-Matrizen zu Liste
koordinaten_liste = []
for k in namen:
matrix_werte = dict_koordinaten_ausgleichungsergebnis[k]
koordinaten_liste.append([
float(matrix_werte[0]),
float(matrix_werte[1]),
float(matrix_werte[2])
])
# DataFrame geozentrisch
df_x_final = pd.DataFrame(
koordinaten_liste,
columns=['X [m]', 'Y [m]', 'Z [m]'],
index=namen
)
df_x_final.index.name = 'Punktnummer'
# DataFrame UTM
utm_flach = {
k: np.array(v).flatten().tolist()
for k, v in dict_koordinaten_utm.items()
}
df_utm_final = pd.DataFrame.from_dict(
utm_flach,
orient='index',
columns=['Rechtswert [m]', 'Hochwert [m]', 'Höhe [m]']
)
df_utm_final.index.name = 'Punktnummer'
# Zahlenformatierung
df_x_final = df_x_final.map(lambda val: f"{val:.4f}")
df_utm_final = df_utm_final.map(lambda val: f"{val:.4f}")
return df_x_final, df_utm_final
def speichere_html_protokoll(metadaten: dict, ergebnisse: dict) -> None: def speichere_html_protokoll(metadaten: dict, ergebnisse: dict) -> None:
"""Erzeugt ein HTML-Protokoll der Ausgleichungsergebnisse und speichert es als Datei. """Erzeugt ein HTML-Protokoll der Ausgleichungsergebnisse und speichert es als Datei.
@@ -79,7 +157,6 @@ class Export:
:return: None :return: None
:rtype: None :rtype: None
""" """
for key in ergebnisse: for key in ergebnisse:
wert = ergebnisse[key] wert = ergebnisse[key]
@@ -92,7 +169,7 @@ class Export:
elif isinstance(wert, dict): elif isinstance(wert, dict):
ergebnisse[key] = pd.DataFrame([wert]) ergebnisse[key] = pd.DataFrame([wert])
# Pfad für den Ordner erstellen # Pfad für den Ordner
ordner = "Protokolle" ordner = "Protokolle"
if not os.path.exists(ordner): if not os.path.exists(ordner):
os.makedirs(ordner) os.makedirs(ordner)
@@ -100,7 +177,7 @@ class Export:
dateiname = f"{ordner}/Protokoll_{metadaten['projekt']}.html" dateiname = f"{ordner}/Protokoll_{metadaten['projekt']}.html"
abs_path = os.path.abspath(dateiname) abs_path = os.path.abspath(dateiname)
# HTML Inhalt zusammenbauen # HTML Inhalt
html_content = f""" html_content = f"""
<!DOCTYPE html> <!DOCTYPE html>
<html lang="de"> <html lang="de">
@@ -211,39 +288,6 @@ class Export:
<h3 id="koordinaten_utm">13. Koordinaten UTM</h3> <h3 id="koordinaten_utm">13. Koordinaten UTM</h3>
{ergebnisse['df_koordinaten_utm'].to_html(index=True)} {ergebnisse['df_koordinaten_utm'].to_html(index=True)}
<h3>1. Globaltest</h3>
{ergebnisse['df_globaltest'].to_html(index=False)}
<h3>2. Redundanzanteile</h3>
{ergebnisse['df_redundanz'].to_html(index=False)}
<h3>2. Lokaltest (data snooping)</h3>
{ergebnisse['df_lokaltest'].to_html(index=False)}
<h3>2. Varianzkomponentenschätzung</h3>
{ergebnisse['df_vks'].to_html(index=False)}
<h3>2. Äussere Zuverlässigkeit</h3>
{ergebnisse['df_aeussere_zuver'].to_html(index=False)}
<h3>2. Standardabweichungen und Helmert'scher Punktfehler</h3>
{ergebnisse['df_punktfehler'].to_html(index=False)}
<h3>3. Standardellipsen</h3>
{ergebnisse['df_ellipsen'].to_html(index=False)}
<h3>3. Konfidenzellipsen</h3>
{ergebnisse['df_konfidenzellipsen'].to_html(index=False)}
<h3>3. Konfidenzellipsen im ENU-System</h3>
{ergebnisse['df_konfidenzellipsen_enu'].to_html(index=False)}
<h3>3. Koordinaten Geozentrisch Kartesisch</h3>
{ergebnisse['df_koordinaten_geozentrisch_kartesisch'].to_html(index=True)}
<h3>3. Koordinaten UTM</h3>
{ergebnisse['df_koordinaten_utm'].to_html(index=True)}
<div class="footer"> <div class="footer">
Erstellt automatisch am {datetime.now().strftime('%d.%m.%Y um %H:%M:%S')} Erstellt automatisch am {datetime.now().strftime('%d.%m.%Y um %H:%M:%S')}
</div> </div>

View File

@@ -28,7 +28,7 @@ class FunktionalesModell:
2) In jeder Iteration Substituieren der Symbolischen Matrizen in Numerische np.asarrays 2) In jeder Iteration Substituieren der Symbolischen Matrizen in Numerische np.asarrays
""" """
def __init__(self, pfad_datenbank: str, a: float, b: float, pfad_tif_quasigeoidundolation: str = None) -> None: def __init__(self, pfad_datenbank: str, a: float, b: float, pfad_tif_quasigeoidundulation: str = None) -> None:
"""Initialisiert das funktionale Modell. """Initialisiert das funktionale Modell.
Legt die Ellipsoidparameter a und b fest, initialisiert Hilfsklassen (Berechnungen, Datenbankzugriff, Transformationen) Legt die Ellipsoidparameter a und b fest, initialisiert Hilfsklassen (Berechnungen, Datenbankzugriff, Transformationen)
@@ -40,8 +40,8 @@ class FunktionalesModell:
:type a: float :type a: float
:param b: Kleine Halbachse b des Referenzellipsoids in Meter. :param b: Kleine Halbachse b des Referenzellipsoids in Meter.
:type b: float :type b: float
:param pfad_tif_quasigeoidundolation: Pfad zu Quasigeoidundulationsdaten als GeoTIFF vom BKG für Transformationen (optional). :param pfad_tif_quasigeoidundulation: Pfad zu Quasigeoidundulationsdaten als GeoTIFF vom BKG für Transformationen (optional).
:type pfad_tif_quasigeoidundolation: str | None :type pfad_tif_quasigeoidundulation: str | None
:return: None :return: None
:rtype: None :rtype: None
""" """
@@ -51,7 +51,7 @@ class FunktionalesModell:
self.berechnungen = Berechnungen(self.a, self.b) self.berechnungen = Berechnungen(self.a, self.b)
self.db_zugriff = Datenbankzugriff(self.pfad_datenbank) self.db_zugriff = Datenbankzugriff(self.pfad_datenbank)
self.trafos = Transformationen(pfad_datenbank) self.trafos = Transformationen(pfad_datenbank)
self.pfad_tif_quasigeoidundolation = pfad_tif_quasigeoidundolation self.pfad_tif_quasigeoidundulation = pfad_tif_quasigeoidundulation
self.substitutionen_dict = self.dict_substitutionen_uebergeordnetes_system() self.substitutionen_dict = self.dict_substitutionen_uebergeordnetes_system()
self.dict_punkt_symbole = {} self.dict_punkt_symbole = {}
self.liste_symbole_lambdify = sorted(self.substitutionen_dict.keys(), key=lambda s: str(s)) self.liste_symbole_lambdify = sorted(self.substitutionen_dict.keys(), key=lambda s: str(s))
@@ -889,7 +889,7 @@ class FunktionalesModell:
dict_koordinaten_utm = self.trafos.ecef_to_utm( dict_koordinaten_utm = self.trafos.ecef_to_utm(
dict_koordinaten_niv, dict_koordinaten_niv,
self.pfad_tif_quasigeoidundolation) self.pfad_tif_quasigeoidundulation)
# Zuweisen der Symbole zu dem jeweiligen numerischen Wert. Gespeichert wird dies in einem Dictionary. # Zuweisen der Symbole zu dem jeweiligen numerischen Wert. Gespeichert wird dies in einem Dictionary.
substitutionen = {} substitutionen = {}

View File

@@ -350,7 +350,7 @@ class Transformationen:
]) ])
return dict_transformiert return dict_transformiert
def utm_to_XYZ(self, pfad_tif_quasigeoidundolation: str, liste_utm: list) -> dict[Any, Any]: def utm_to_XYZ(self, pfad_tif_quasigeoidundulation: str, liste_utm: list) -> dict[Any, Any]:
"""Rechnet UTM-Koordinaten (ETRS89 / UTM + DHHN2016) in ECEF-Koordinaten (ETRS89 geozentrisch-kartesisch) um. """Rechnet UTM-Koordinaten (ETRS89 / UTM + DHHN2016) in ECEF-Koordinaten (ETRS89 geozentrisch-kartesisch) um.
Es wird ein PROJ-Transformer von: Es wird ein PROJ-Transformer von:
@@ -361,15 +361,15 @@ class Transformationen:
initialisiert. Zusätzlich wird ein BKG-GeoTIFF (Quasigeoidunndulation) in den PROJ-Datenpfad eingebunden, initialisiert. Zusätzlich wird ein BKG-GeoTIFF (Quasigeoidunndulation) in den PROJ-Datenpfad eingebunden,
indem eine Kopie mit dem erwarteten Dateinamen "de_bkg_gcg2016.tif" im selben Ordner erzeugt wird. indem eine Kopie mit dem erwarteten Dateinamen "de_bkg_gcg2016.tif" im selben Ordner erzeugt wird.
:param pfad_tif_quasigeoidundolation: Pfad zur BKG-GeoTIFF-Datei (Quasigeoidundulation). :param pfad_tif_quasigeoidundulation: Pfad zur BKG-GeoTIFF-Datei (Quasigeoidundulation).
:type pfad_tif_quasigeoidundolation: str :type pfad_tif_quasigeoidundulation: str
:param liste_utm: Liste von UTM-Koordinaten in der Form [(punktnummer, E, N, Normalhoehe), ...]. :param liste_utm: Liste von UTM-Koordinaten in der Form [(punktnummer, E, N, Normalhoehe), ...].
:type liste_utm: list :type liste_utm: list
:return: Dictionary {punktnummer: sp.Matrix([X, Y, Z])} mit ECEF-Koordinaten (Meter). :return: Dictionary {punktnummer: sp.Matrix([X, Y, Z])} mit ECEF-Koordinaten (Meter).
:rtype: dict[Any, Any] :rtype: dict[Any, Any]
""" """
# tif vom BKG zur Quasigeoidundolation übergeben # tif vom BKG zur Quasigeoidundulation übergeben
pfad_gcg_tif = Path(pfad_tif_quasigeoidundolation) pfad_gcg_tif = Path(pfad_tif_quasigeoidundulation)
pfad_gcg_tif_proj = pfad_gcg_tif.with_name("de_bkg_gcg2016.tif") pfad_gcg_tif_proj = pfad_gcg_tif.with_name("de_bkg_gcg2016.tif")
# Kopie des TIF anlegen (Dies ist voraussetzung für die Transformer-Bibliothek # Kopie des TIF anlegen (Dies ist voraussetzung für die Transformer-Bibliothek
@@ -423,7 +423,7 @@ class Transformationen:
:rtype: dict :rtype: dict
""" """
# Kopie des TIF vom BKG mit der Quasigeoidundolation erstellen # Kopie des TIF vom BKG mit der Quasigeoidundulation erstellen
pfad_gcg_tif = Path(pfad_gcg_tif).resolve() pfad_gcg_tif = Path(pfad_gcg_tif).resolve()
pfad_proj_grid = pfad_gcg_tif.with_name("de_bkg_gcg2016.tif") pfad_proj_grid = pfad_gcg_tif.with_name("de_bkg_gcg2016.tif")
if ( if (

View File

@@ -26,7 +26,7 @@ class Iterationen:
Die Iteration verwendet bei weicher Lagerung eine erweiterte Kovarianzmatrix (Q_ext) inklusive Anschlusspunkten (lA_*), Die Iteration verwendet bei weicher Lagerung eine erweiterte Kovarianzmatrix (Q_ext) inklusive Anschlusspunkten (lA_*),
aus der die Gewichtsmatrix P abgeleitet wird. aus der die Gewichtsmatrix P abgeleitet wird.
""" """
def __init__(self, pfad_datenbank: str, pfad_tif_quasigeoidundolation: str, a: float, b: float) -> None: def __init__(self, pfad_datenbank: str, pfad_tif_quasigeoidundulation: str, a: float, b: float) -> None:
"""Initialisiert die Iterationssteuerung. """Initialisiert die Iterationssteuerung.
Speichert Datenbankpfade und Ellipsoidparameter, initialisiert das funktionale Modell sowie das stochastische Modell Speichert Datenbankpfade und Ellipsoidparameter, initialisiert das funktionale Modell sowie das stochastische Modell
@@ -34,8 +34,8 @@ class Iterationen:
:param pfad_datenbank: Pfad zur SQLite-Datenbank. :param pfad_datenbank: Pfad zur SQLite-Datenbank.
:type pfad_datenbank: str :type pfad_datenbank: str
:param pfad_tif_quasigeoidundolation: Pfad zum GeoTIFF der Quasigeoidundulation (BKG), benötigt für UTM/Normalhöhen in Transformationen. :param pfad_tif_quasigeoidundulation: Pfad zum GeoTIFF der Quasigeoidundulation (BKG), benötigt für UTM/Normalhöhen in Transformationen.
:type pfad_tif_quasigeoidundolation: str :type pfad_tif_quasigeoidundulation: str
:param a: Große Halbachse a des Referenzellipsoids in Meter. :param a: Große Halbachse a des Referenzellipsoids in Meter.
:type a: float :type a: float
:param b: Kleine Halbachse b des Referenzellipsoids in Meter. :param b: Kleine Halbachse b des Referenzellipsoids in Meter.
@@ -44,13 +44,13 @@ class Iterationen:
:rtype: None :rtype: None
""" """
self.pfad_datenbank = pfad_datenbank self.pfad_datenbank = pfad_datenbank
self.pfad_tif_quasigeoidundolation = pfad_tif_quasigeoidundolation self.pfad_tif_quasigeoidundulation = pfad_tif_quasigeoidundulation
self.a = a self.a = a
self.b = b self.b = b
self.stoch_modell = Stochastisches_Modell.StochastischesModell(pfad_datenbank) self.stoch_modell = Stochastisches_Modell.StochastischesModell(pfad_datenbank)
self.db_zugriff = Datenbank.Datenbankzugriff(pfad_datenbank) self.db_zugriff = Datenbank.Datenbankzugriff(pfad_datenbank)
self.fm = Funktionales_Modell.FunktionalesModell(self.pfad_datenbank, self.a, self.b, self.pfad_tif_quasigeoidundolation) self.fm = Funktionales_Modell.FunktionalesModell(self.pfad_datenbank, self.a, self.b, self.pfad_tif_quasigeoidundulation)
def ausgleichung_global(self, A, dl, Q_ext, P): def ausgleichung_global(self, A, dl, Q_ext, P):