Add reference point adjuster module and requirements.txt

- Added requirements.txt with all Python dependencies
- Created new module: modules/reference_point_adjuster.py
  - Identifies reference point 5001 from ReflineStationSetup
  - Allows entering new coordinates for the reference point
  - Recalculates all dependent points using translation
  - Exports modified JXL file
- Extended GUI with new tab 'Referenzpunkt anpassen'
  - Shows current reference point coordinates
  - Input fields for new coordinates with live delta display
  - Preview transformation before applying
  - Apply transformation and export buttons
  - Detailed transformation report
- Updated README.md with new features and installation instructions
- Added test files for validation
This commit is contained in:
Developer 2026-01-18 12:11:21 +00:00
parent 6af2c0333f
commit 27489a1d94
7 changed files with 20914 additions and 7 deletions

View File

@ -44,6 +44,14 @@ Ein vollständiges Python-Programm mit grafischer Benutzeroberfläche (GUI) für
- Residuen - Residuen
- Qualitätsparametern (Sigma-0, Chi-Quadrat, RMSE) - Qualitätsparametern (Sigma-0, Chi-Quadrat, RMSE)
### 6. Referenzpunkt-Anpassung (NEU)
- Anpassung des Referenzpunktes 5001 (bei Referenzlinien-Stationierung)
- Eingabe neuer Koordinaten (X, Y, Z) für den Referenzpunkt
- Automatische Neuberechnung aller abhängigen Punkte
- Vorschau der Transformation mit allen betroffenen Punkten
- Export der transformierten JXL-Datei
- Validierung der Eingaben mit Warnungen bei problematischen Werten
## Installation ## Installation
### Voraussetzungen ### Voraussetzungen
@ -54,6 +62,14 @@ Ein vollständiges Python-Programm mit grafischer Benutzeroberfläche (GUI) für
- lxml - lxml
### Installation der Abhängigkeiten ### Installation der Abhängigkeiten
**Option 1: Mit requirements.txt (empfohlen)**
```bash
cd /home/ubuntu/trimble_geodesy
pip install -r requirements.txt
```
**Option 2: Manuelle Installation**
```bash ```bash
pip install PyQt5 numpy scipy lxml pip install PyQt5 numpy scipy lxml
``` ```
@ -72,20 +88,23 @@ python3 main.py
3. **Transformation Tab**: Koordinatensystem rotieren/verschieben 3. **Transformation Tab**: Koordinatensystem rotieren/verschieben
4. **Georeferenzierung Tab**: Mit Passpunkten transformieren 4. **Georeferenzierung Tab**: Mit Passpunkten transformieren
5. **Netzausgleichung Tab**: Netzausgleichung durchführen 5. **Netzausgleichung Tab**: Netzausgleichung durchführen
6. **Referenzpunkt anpassen Tab**: Referenzpunkt 5001 ändern und JXL neu berechnen
## Dateistruktur ## Dateistruktur
``` ```
trimble_geodesy/ trimble_geodesy/
├── main.py # Hauptprogramm mit GUI ├── main.py # Hauptprogramm mit GUI
├── requirements.txt # Python-Abhängigkeiten
├── modules/ ├── modules/
│ ├── __init__.py │ ├── __init__.py
│ ├── jxl_parser.py # JXL-Datei Parser │ ├── jxl_parser.py # JXL-Datei Parser
│ ├── cor_generator.py # COR-Datei Generator │ ├── cor_generator.py # COR-Datei Generator
│ ├── transformation.py # Koordinatentransformation │ ├── transformation.py # Koordinatentransformation
│ ├── georeferencing.py # Georeferenzierung │ ├── georeferencing.py # Georeferenzierung
│ └── network_adjustment.py # Netzausgleichung │ ├── network_adjustment.py # Netzausgleichung
├── output/ # Ausgabeverzeichnis │ └── reference_point_adjuster.py # Referenzpunkt-Anpassung (NEU)
├── output/ # Ausgabeverzeichnis
└── README.md └── README.md
``` ```

278
main.py
View File

@ -28,6 +28,7 @@ from modules.cor_generator import CORGenerator, CORPoint
from modules.transformation import CoordinateTransformer, LocalSystemTransformer from modules.transformation import CoordinateTransformer, LocalSystemTransformer
from modules.georeferencing import Georeferencer, ControlPoint from modules.georeferencing import Georeferencer, ControlPoint
from modules.network_adjustment import NetworkAdjustment from modules.network_adjustment import NetworkAdjustment
from modules.reference_point_adjuster import ReferencePointAdjuster, TransformationResult
class JXLAnalysisTab(QWidget): class JXLAnalysisTab(QWidget):
@ -948,6 +949,280 @@ class NetworkAdjustmentTab(QWidget):
QMessageBox.information(self, "Erfolg", f"Koordinaten gespeichert: {file_path}") QMessageBox.information(self, "Erfolg", f"Koordinaten gespeichert: {file_path}")
class ReferencePointAdjusterTab(QWidget):
"""Tab für Referenzpunkt-Anpassung"""
def __init__(self, parent=None):
super().__init__(parent)
self.main_window = parent
self.adjuster = ReferencePointAdjuster()
self.setup_ui()
def setup_ui(self):
layout = QVBoxLayout(self)
# Info-Gruppe
info_group = QGroupBox("Aktueller Referenzpunkt")
info_layout = QFormLayout(info_group)
self.ref_point_name = QLabel("Nicht geladen")
self.ref_point_name.setStyleSheet("font-weight: bold; font-size: 14px;")
info_layout.addRow("Punktname:", self.ref_point_name)
self.current_east = QLabel("0.000")
self.current_north = QLabel("0.000")
self.current_elev = QLabel("0.000")
info_layout.addRow("East (X):", self.current_east)
info_layout.addRow("North (Y):", self.current_north)
info_layout.addRow("Elevation (Z):", self.current_elev)
refresh_btn = QPushButton("Referenzpunkt aktualisieren")
refresh_btn.clicked.connect(self.load_reference_point)
info_layout.addRow("", refresh_btn)
layout.addWidget(info_group)
# Neue Koordinaten Gruppe
new_coords_group = QGroupBox("Neue Koordinaten für Referenzpunkt")
new_coords_layout = QGridLayout(new_coords_group)
new_coords_layout.addWidget(QLabel("East (X):"), 0, 0)
self.new_east_spin = QDoubleSpinBox()
self.new_east_spin.setRange(-10000000, 10000000)
self.new_east_spin.setDecimals(4)
self.new_east_spin.setSuffix(" m")
new_coords_layout.addWidget(self.new_east_spin, 0, 1)
new_coords_layout.addWidget(QLabel("North (Y):"), 1, 0)
self.new_north_spin = QDoubleSpinBox()
self.new_north_spin.setRange(-10000000, 10000000)
self.new_north_spin.setDecimals(4)
self.new_north_spin.setSuffix(" m")
new_coords_layout.addWidget(self.new_north_spin, 1, 1)
new_coords_layout.addWidget(QLabel("Elevation (Z):"), 2, 0)
self.new_elev_spin = QDoubleSpinBox()
self.new_elev_spin.setRange(-10000, 10000)
self.new_elev_spin.setDecimals(4)
self.new_elev_spin.setSuffix(" m")
new_coords_layout.addWidget(self.new_elev_spin, 2, 1)
# Translation anzeigen
new_coords_layout.addWidget(QLabel(""), 3, 0)
self.delta_label = QLabel("ΔX: 0.000 m | ΔY: 0.000 m | ΔZ: 0.000 m")
self.delta_label.setStyleSheet("color: blue;")
new_coords_layout.addWidget(self.delta_label, 4, 0, 1, 2)
# Koordinaten-Änderungen live berechnen
self.new_east_spin.valueChanged.connect(self.update_delta)
self.new_north_spin.valueChanged.connect(self.update_delta)
self.new_elev_spin.valueChanged.connect(self.update_delta)
layout.addWidget(new_coords_group)
# Aktionen
actions_group = QGroupBox("Aktionen")
actions_layout = QHBoxLayout(actions_group)
preview_btn = QPushButton("Vorschau berechnen")
preview_btn.clicked.connect(self.preview_transformation)
preview_btn.setStyleSheet("background-color: #4CAF50; color: white;")
actions_layout.addWidget(preview_btn)
apply_btn = QPushButton("Transformation anwenden")
apply_btn.clicked.connect(self.apply_transformation)
apply_btn.setStyleSheet("background-color: #2196F3; color: white;")
actions_layout.addWidget(apply_btn)
export_btn = QPushButton("Neue JXL exportieren")
export_btn.clicked.connect(self.export_jxl)
export_btn.setStyleSheet("background-color: #FF9800; color: white;")
actions_layout.addWidget(export_btn)
layout.addWidget(actions_group)
# Vorschau-Tabelle
preview_group = QGroupBox("Vorschau der betroffenen Punkte")
preview_layout = QVBoxLayout(preview_group)
self.preview_table = QTableWidget()
self.preview_table.setColumnCount(7)
self.preview_table.setHorizontalHeaderLabels(
["Punkt", "Alt X", "Alt Y", "Alt Z", "Neu X", "Neu Y", "Neu Z"])
self.preview_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
preview_layout.addWidget(self.preview_table)
layout.addWidget(preview_group)
# Bericht
report_group = QGroupBox("Transformationsbericht")
report_layout = QVBoxLayout(report_group)
self.report_text = QTextEdit()
self.report_text.setReadOnly(True)
self.report_text.setFont(QFont("Courier", 9))
report_layout.addWidget(self.report_text)
layout.addWidget(report_group)
def load_reference_point(self):
"""Lädt die Informationen zum Referenzpunkt"""
if not self.main_window.parser:
QMessageBox.warning(self, "Fehler",
"Bitte zuerst eine JXL-Datei im 'JXL-Analyse' Tab laden!")
return
self.adjuster.set_parser(self.main_window.parser)
info = self.adjuster.get_reference_point_info()
if not info["found"]:
QMessageBox.warning(self, "Fehler",
f"Referenzpunkt nicht gefunden: {info['message']}")
return
self.ref_point_name.setText(info["name"])
self.current_east.setText(f"{info['east']:.4f} m")
self.current_north.setText(f"{info['north']:.4f} m")
self.current_elev.setText(f"{info['elevation']:.4f} m")
# Setze aktuelle Werte als Standard für neue Koordinaten
self.new_east_spin.setValue(info['east'])
self.new_north_spin.setValue(info['north'])
self.new_elev_spin.setValue(info['elevation'])
self.main_window.statusBar().showMessage(
f"Referenzpunkt '{info['name']}' geladen")
def update_delta(self):
"""Aktualisiert die Anzeige der Verschiebung"""
if not self.adjuster.parser:
return
dx = self.new_east_spin.value() - self.adjuster.original_coords[0]
dy = self.new_north_spin.value() - self.adjuster.original_coords[1]
dz = self.new_elev_spin.value() - self.adjuster.original_coords[2]
self.delta_label.setText(
f"ΔX: {dx:+.4f} m | ΔY: {dy:+.4f} m | ΔZ: {dz:+.4f} m")
def preview_transformation(self):
"""Zeigt eine Vorschau der Transformation"""
if not self.main_window.parser:
QMessageBox.warning(self, "Fehler",
"Bitte zuerst eine JXL-Datei laden!")
return
# Validierung
valid, message = self.adjuster.validate_input(
self.new_east_spin.value(),
self.new_north_spin.value(),
self.new_elev_spin.value()
)
if not valid:
reply = QMessageBox.warning(self, "Warnung",
f"Mögliche Probleme erkannt:\n\n{message}\n\nTrotzdem fortfahren?",
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.No:
return
self.adjuster.set_new_coordinates(
self.new_east_spin.value(),
self.new_north_spin.value(),
self.new_elev_spin.value()
)
results = self.adjuster.preview_transformation()
# Tabelle aktualisieren
self.preview_table.setRowCount(len(results))
for i, result in enumerate(results):
self.preview_table.setItem(i, 0, QTableWidgetItem(result.original_point))
self.preview_table.setItem(i, 1, QTableWidgetItem(f"{result.original_coords[0]:.4f}"))
self.preview_table.setItem(i, 2, QTableWidgetItem(f"{result.original_coords[1]:.4f}"))
self.preview_table.setItem(i, 3, QTableWidgetItem(f"{result.original_coords[2]:.4f}"))
self.preview_table.setItem(i, 4, QTableWidgetItem(f"{result.new_coords[0]:.4f}"))
self.preview_table.setItem(i, 5, QTableWidgetItem(f"{result.new_coords[1]:.4f}"))
self.preview_table.setItem(i, 6, QTableWidgetItem(f"{result.new_coords[2]:.4f}"))
# Bericht aktualisieren
self.report_text.setText(self.adjuster.get_summary_report())
self.main_window.statusBar().showMessage(
f"Vorschau berechnet: {len(results)} Punkte betroffen")
def apply_transformation(self):
"""Wendet die Transformation auf die JXL-Datei an"""
if not self.main_window.parser:
QMessageBox.warning(self, "Fehler",
"Bitte zuerst eine JXL-Datei laden!")
return
if not self.adjuster.affected_points:
QMessageBox.warning(self, "Fehler",
"Bitte zuerst eine Vorschau berechnen!")
return
reply = QMessageBox.question(self, "Bestätigung",
f"Soll die Transformation auf {len(self.adjuster.affected_points)} Punkte angewendet werden?\n\n"
"Die Änderungen werden in der geladenen JXL-Datei gespeichert.",
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.No:
return
if self.adjuster.apply_transformation():
# Bericht aktualisieren
self.report_text.setText(self.adjuster.get_summary_report())
QMessageBox.information(self, "Erfolg",
"Transformation erfolgreich angewendet!\n\n"
"Die Koordinaten wurden aktualisiert.\n"
"Verwenden Sie 'Neue JXL exportieren' zum Speichern.")
self.main_window.statusBar().showMessage("Transformation angewendet")
else:
QMessageBox.critical(self, "Fehler",
"Transformation konnte nicht angewendet werden!")
def export_jxl(self):
"""Exportiert die modifizierte JXL-Datei"""
if not self.main_window.parser:
QMessageBox.warning(self, "Fehler",
"Bitte zuerst eine JXL-Datei laden!")
return
if not self.adjuster.transformation_applied:
reply = QMessageBox.warning(self, "Warnung",
"Die Transformation wurde noch nicht angewendet.\n"
"Möchten Sie die Originaldatei exportieren?",
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.No:
return
# Standard-Dateiname vorschlagen
original_path = self.main_window.parser.file_path
if original_path:
import os
base, ext = os.path.splitext(original_path)
default_name = f"{base}_transformed{ext}"
else:
default_name = "transformed.jxl"
file_path, _ = QFileDialog.getSaveFileName(
self, "JXL-Datei exportieren", default_name, "JXL Files (*.jxl)")
if file_path:
if self.adjuster.export_jxl(file_path):
QMessageBox.information(self, "Erfolg",
f"JXL-Datei exportiert:\n{file_path}")
self.main_window.statusBar().showMessage(f"Exportiert: {file_path}")
else:
QMessageBox.critical(self, "Fehler",
"Fehler beim Exportieren der JXL-Datei!")
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
"""Hauptfenster der Anwendung""" """Hauptfenster der Anwendung"""
@ -990,6 +1265,9 @@ class MainWindow(QMainWindow):
self.adjust_tab = NetworkAdjustmentTab(self) self.adjust_tab = NetworkAdjustmentTab(self)
self.tabs.addTab(self.adjust_tab, "📐 Netzausgleichung") self.tabs.addTab(self.adjust_tab, "📐 Netzausgleichung")
self.refpoint_tab = ReferencePointAdjusterTab(self)
self.tabs.addTab(self.refpoint_tab, "📍 Referenzpunkt anpassen")
layout.addWidget(self.tabs) layout.addWidget(self.tabs)
def setup_menu(self): def setup_menu(self):

View File

@ -0,0 +1,323 @@
"""
Reference Point Adjuster Module - Referenzpunkt-Anpassung für JXL-Dateien
Ermöglicht die Änderung des Referenzpunktes 5001 und Neuberechnung aller Koordinaten
"""
import xml.etree.ElementTree as ET
from dataclasses import dataclass, field
from typing import List, Dict, Optional, Tuple
import math
import copy
import os
from modules.jxl_parser import JXLParser, Point, Station
@dataclass
class TransformationResult:
"""Ergebnis der Koordinatentransformation"""
original_point: str
original_coords: Tuple[float, float, float]
new_coords: Tuple[float, float, float]
delta: Tuple[float, float, float]
class ReferencePointAdjuster:
"""Klasse zur Anpassung des Referenzpunktes und Neuberechnung der JXL-Datei"""
def __init__(self, parser: JXLParser = None):
self.parser = parser
self.reference_point_name = "5001"
self.original_coords: Tuple[float, float, float] = (0.0, 0.0, 0.0)
self.new_coords: Tuple[float, float, float] = (0.0, 0.0, 0.0)
self.affected_points: List[TransformationResult] = []
self.transformation_applied = False
def set_parser(self, parser: JXLParser):
"""Setzt den Parser für die JXL-Datei"""
self.parser = parser
self.find_reference_point()
def find_reference_point(self) -> Optional[Point]:
"""Findet den Referenzpunkt 5001 in der JXL-Datei"""
if not self.parser:
return None
# Suche nach dem Punkt mit Name "5001"
for name, point in self.parser.points.items():
if name == self.reference_point_name or name == "5001":
self.reference_point_name = name
self.original_coords = (
point.east if point.east is not None else 0.0,
point.north if point.north is not None else 0.0,
point.elevation if point.elevation is not None else 0.0
)
return point
# Falls 5001 nicht gefunden, suche nach dem ersten Punkt mit Coordinates/KeyedIn
for name, point in self.parser.points.items():
if point.method == "Coordinates" and point.survey_method == "KeyedIn":
self.reference_point_name = name
self.original_coords = (
point.east if point.east is not None else 0.0,
point.north if point.north is not None else 0.0,
point.elevation if point.elevation is not None else 0.0
)
return point
return None
def get_reference_point_info(self) -> Dict:
"""Gibt Informationen zum Referenzpunkt zurück"""
if not self.parser:
return {"found": False, "message": "Kein Parser geladen"}
point = self.find_reference_point()
if not point:
return {"found": False, "message": "Referenzpunkt nicht gefunden"}
return {
"found": True,
"name": self.reference_point_name,
"east": self.original_coords[0],
"north": self.original_coords[1],
"elevation": self.original_coords[2],
"method": point.method,
"survey_method": point.survey_method
}
def set_new_coordinates(self, east: float, north: float, elevation: float):
"""Setzt neue Koordinaten für den Referenzpunkt"""
self.new_coords = (east, north, elevation)
def calculate_translation(self) -> Tuple[float, float, float]:
"""Berechnet die Translation zwischen alten und neuen Koordinaten"""
delta_x = self.new_coords[0] - self.original_coords[0]
delta_y = self.new_coords[1] - self.original_coords[1]
delta_z = self.new_coords[2] - self.original_coords[2]
return (delta_x, delta_y, delta_z)
def preview_transformation(self) -> List[TransformationResult]:
"""Zeigt eine Vorschau der Transformation für alle betroffenen Punkte"""
if not self.parser:
return []
delta = self.calculate_translation()
results = []
for name, point in self.parser.points.items():
if point.east is None or point.north is None:
continue
original = (
point.east,
point.north,
point.elevation if point.elevation is not None else 0.0
)
new = (
original[0] + delta[0],
original[1] + delta[1],
original[2] + delta[2]
)
results.append(TransformationResult(
original_point=name,
original_coords=original,
new_coords=new,
delta=delta
))
self.affected_points = results
return results
def apply_transformation(self) -> bool:
"""Wendet die Transformation auf alle Punkte in der JXL-Datei an"""
if not self.parser or not self.parser.raw_xml:
return False
delta = self.calculate_translation()
root = self.parser.raw_xml.getroot()
fieldbook = root.find('FieldBook')
if fieldbook is None:
return False
modified_count = 0
# Durchsuche alle PointRecords und aktualisiere die Koordinaten
for element in fieldbook:
if element.tag == 'PointRecord':
modified = self._update_point_coordinates(element, delta)
if modified:
modified_count += 1
# Aktualisiere auch die internen Parser-Daten
for name, point in self.parser.points.items():
if point.east is not None:
point.east += delta[0]
if point.north is not None:
point.north += delta[1]
if point.elevation is not None:
point.elevation += delta[2]
self.transformation_applied = True
return modified_count > 0
def _update_point_coordinates(self, element: ET.Element, delta: Tuple[float, float, float]) -> bool:
"""Aktualisiert die Koordinaten eines einzelnen Punktes im XML"""
modified = False
# Grid-Koordinaten aktualisieren
grid = element.find('Grid')
if grid is not None:
modified |= self._update_grid_element(grid, delta)
# ComputedGrid-Koordinaten aktualisieren
computed_grid = element.find('ComputedGrid')
if computed_grid is not None:
modified |= self._update_grid_element(computed_grid, delta)
return modified
def _update_grid_element(self, grid: ET.Element, delta: Tuple[float, float, float]) -> bool:
"""Aktualisiert ein Grid oder ComputedGrid Element"""
modified = False
east = grid.find('East')
if east is not None and east.text:
try:
old_value = float(east.text)
new_value = old_value + delta[0]
east.text = str(new_value)
modified = True
except ValueError:
pass
north = grid.find('North')
if north is not None and north.text:
try:
old_value = float(north.text)
new_value = old_value + delta[1]
north.text = str(new_value)
modified = True
except ValueError:
pass
elevation = grid.find('Elevation')
if elevation is not None and elevation.text:
try:
old_value = float(elevation.text)
new_value = old_value + delta[2]
elevation.text = str(new_value)
modified = True
except ValueError:
pass
return modified
def export_jxl(self, output_path: str) -> bool:
"""Exportiert die modifizierte JXL-Datei"""
if not self.parser or not self.parser.raw_xml:
return False
try:
# XML mit Deklaration schreiben
tree = self.parser.raw_xml
tree.write(output_path, encoding='UTF-8', xml_declaration=True)
return True
except Exception as e:
print(f"Fehler beim Exportieren: {e}")
return False
def get_summary_report(self) -> str:
"""Erstellt einen zusammenfassenden Bericht der Transformation"""
delta = self.calculate_translation()
report = []
report.append("=" * 60)
report.append("REFERENZPUNKT-ANPASSUNG - ZUSAMMENFASSUNG")
report.append("=" * 60)
report.append("")
report.append(f"Referenzpunkt: {self.reference_point_name}")
report.append("")
report.append("Ursprüngliche Koordinaten:")
report.append(f" East (X): {self.original_coords[0]:12.4f} m")
report.append(f" North (Y): {self.original_coords[1]:12.4f} m")
report.append(f" Elevation (Z):{self.original_coords[2]:12.4f} m")
report.append("")
report.append("Neue Koordinaten:")
report.append(f" East (X): {self.new_coords[0]:12.4f} m")
report.append(f" North (Y): {self.new_coords[1]:12.4f} m")
report.append(f" Elevation (Z):{self.new_coords[2]:12.4f} m")
report.append("")
report.append("Translation (Delta):")
report.append(f" ΔX: {delta[0]:+12.4f} m")
report.append(f" ΔY: {delta[1]:+12.4f} m")
report.append(f" ΔZ: {delta[2]:+12.4f} m")
report.append("")
report.append("-" * 60)
report.append(f"Anzahl betroffener Punkte: {len(self.affected_points)}")
report.append("-" * 60)
if self.affected_points:
report.append("")
report.append(f"{'Punkt':<10} {'Alt X':>12} {'Alt Y':>12} {'Alt Z':>10} -> {'Neu X':>12} {'Neu Y':>12} {'Neu Z':>10}")
report.append("-" * 90)
for result in self.affected_points[:20]: # Max 20 Punkte anzeigen
report.append(
f"{result.original_point:<10} "
f"{result.original_coords[0]:>12.4f} "
f"{result.original_coords[1]:>12.4f} "
f"{result.original_coords[2]:>10.4f} -> "
f"{result.new_coords[0]:>12.4f} "
f"{result.new_coords[1]:>12.4f} "
f"{result.new_coords[2]:>10.4f}"
)
if len(self.affected_points) > 20:
report.append(f"... und {len(self.affected_points) - 20} weitere Punkte")
report.append("")
report.append("=" * 60)
if self.transformation_applied:
report.append("✓ Transformation wurde angewendet")
else:
report.append("⚠ Transformation noch nicht angewendet")
report.append("=" * 60)
return "\n".join(report)
def validate_input(self, east: float, north: float, elevation: float) -> Tuple[bool, str]:
"""Validiert die eingegebenen Koordinaten"""
warnings = []
# Prüfe auf extrem große Werte (möglicher Eingabefehler)
if abs(east) > 1000000:
warnings.append(f"East-Koordinate ({east}) ist sehr groß - bitte überprüfen")
if abs(north) > 1000000:
warnings.append(f"North-Koordinate ({north}) ist sehr groß - bitte überprüfen")
if abs(elevation) > 10000:
warnings.append(f"Elevation ({elevation}) ist sehr groß - bitte überprüfen")
# Berechne Translation
delta = (
east - self.original_coords[0],
north - self.original_coords[1],
elevation - self.original_coords[2]
)
# Warnung bei sehr großer Translation
total_shift = math.sqrt(delta[0]**2 + delta[1]**2)
if total_shift > 100000:
warnings.append(f"Horizontale Verschiebung ({total_shift:.1f} m) ist sehr groß")
if abs(delta[2]) > 1000:
warnings.append(f"Höhenverschiebung ({delta[2]:.1f} m) ist sehr groß")
if warnings:
return (False, "\n".join(warnings))
return (True, "Koordinaten sind plausibel")

15
requirements.txt Normal file
View File

@ -0,0 +1,15 @@
# Trimble Geodesy Tool - Python Dependencies
# Installation: pip install -r requirements.txt
# GUI Framework
PyQt5>=5.15.0
# Numerische Berechnungen
numpy>=1.21.0
scipy>=1.7.0
# XML Processing
lxml>=4.6.0
# Optional: für erweiterte Funktionen
matplotlib>=3.4.0 # Für Diagramme und Visualisierungen (optional)

View File

@ -0,0 +1,84 @@
5001,0.000,0.000,0.000
5002,0.000,11.407,-0.035
1001,22.788,13.565,-1.952
2001,0.014,11.747,-1.361
2002,20.214,30.965,-1.663
2003,33.782,13.097,-2.616
2004,20.490,-15.429,-1.438
3001,33.838,13.220,-2.575
3002,26.308,30.140,-1.903
3003,26.357,-3.293,-2.115
3004,0.048,-0.530,-3.021
3005,-0.038,6.789,-3.414
6001,-18.196,13.913,-2.176
6002,-15.677,12.648,-2.286
6003,-26.318,12.550,-2.274
6004,-24.723,13.845,-1.559
3006,1.182,13.131,1.845
3007,0.867,16.745,1.841
1002,-20.883,13.008,-1.742
2005,-13.138,18.366,-1.730
2006,-19.762,10.592,-1.668
2007,-29.788,15.304,-1.497
2008,-20.421,22.326,-1.798
3008,-13.174,11.080,-0.280
3009,-13.168,10.756,3.783
3010,-14.042,4.481,1.836
3011,-13.166,13.790,5.689
3012,-13.164,11.191,7.558
3013,-13.164,10.602,10.922
2009,-13.144,12.601,-1.895
7002,-7.487,13.193,-3.675
7001,-13.134,19.746,-0.424
3014,-10.454,12.968,-3.593
3015,-5.752,14.319,-3.597
3016,-2.168,12.842,-3.598
3017,-16.960,9.871,-1.307
3018,-13.143,8.257,-1.713
3019,-21.129,4.481,-1.106
3020,-31.198,9.253,-2.128
3021,-29.609,16.923,-2.185
3022,-30.145,21.896,-3.368
3023,-20.860,18.943,-3.376
6005,-25.633,20.878,-2.243
1003,23.070,14.027,-1.969
3024,1.188,12.854,5.607
3025,1.213,3.983,5.615
3026,-0.029,17.401,9.376
3027,0.002,9.449,13.119
3028,-0.915,16.758,13.728
3029,1.096,3.374,9.955
1004,-22.696,19.765,-1.966
6006,-48.153,24.806,-2.092
6007,-48.551,23.493,-1.983
6008,-42.900,22.586,-2.096
1005,-46.031,23.575,-1.951
2010,-40.871,25.207,-1.886
2011,-42.736,16.007,-1.438
2012,-51.007,10.054,-1.947
2013,-46.596,26.451,-1.927
3030,-41.629,20.671,-2.199
3031,-42.358,17.069,-2.207
3032,-43.915,9.539,-2.218
3033,-39.002,22.932,-3.451
1006,22.923,13.878,-1.904
3034,-2.259,19.010,16.788
3035,-2.039,11.679,17.155
3036,-2.401,0.498,16.947
1007,-21.634,18.968,-1.815
3037,-29.302,18.141,1.265
3038,-30.284,13.473,-0.502
3039,-30.223,13.843,2.923
3040,-30.164,14.114,6.326
3041,-30.261,13.648,9.537
1008,-46.567,23.450,-1.900
3042,-43.596,11.396,4.659
3043,-41.019,23.777,4.663
1009,-17.132,16.548,-1.900
3044,-31.755,22.820,14.965
3045,-33.719,12.836,14.653
3046,-34.899,6.876,14.549
3047,-31.140,9.336,8.091
3048,-29.550,17.086,8.072
3049,-28.629,21.467,8.076
3050,-30.750,11.180,1.169

10095
tests/Baumschulenstr_93.jxl Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff