From 8730e1bf96d48b9941de1b11892165ba058f016e Mon Sep 17 00:00:00 2001 From: daniel Date: Fri, 1 May 2026 23:53:20 +0200 Subject: [PATCH] attributwertverschiebung gefixt --- functions/grenzpunkt_alkis.py | 71 +++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/functions/grenzpunkt_alkis.py b/functions/grenzpunkt_alkis.py index b01d3f5..90c6353 100644 --- a/functions/grenzpunkt_alkis.py +++ b/functions/grenzpunkt_alkis.py @@ -269,12 +269,14 @@ def _parse_alkis_gml_memory_layer( if not feat_elems: return None - # Felder aus erstem Feature ermitteln (geom_prop ausschließen) + # Felder aus ALLEN Features ermitteln (2-Pass), damit optionale Felder + # wie "istTeilVon" nicht verloren gehen, wenn sie im ersten Feature fehlen. feld_namen: List[str] = ["gml_id"] - for child in feat_elems[0]: - local = child.tag.split("}")[-1] if "}" in child.tag else child.tag - if local not in feld_namen and local != geom_prop: - feld_namen.append(local) + for feat_el in feat_elems: + for child in feat_el: + local = child.tag.split("}")[-1] if "}" in child.tag else child.tag + if local not in feld_namen and local != geom_prop: + feld_namen.append(local) # Memory-Layer anlegen mem_uri = f"Point?crs=EPSG:25833" if geom_prop else "none" @@ -1187,7 +1189,11 @@ def grenzpunkte_gemarkungsweise( # ------------------------------------------------------------------ # Schritt 2b: PunktortTA pro Gemarkung + Batching # ------------------------------------------------------------------ - alle_pta_features: List = [] + # Statt rohe QgsFeature-Objekte (positionsbasierte Attribute!) zu sammeln, + # speichern wir (geom, attrs-dict) – vollständig namensbasiert. + # Das verhindert Feldwert-Verschiebungen, wenn verschiedene Batches + # die Felder in unterschiedlicher Reihenfolge liefern. + alle_pta_records: List[Dict] = [] # {'geom': QgsGeometry, 'attrs': {name: val}} gesehene_pta_ids: set[str] = set() pta_feld_namen: List[str] = [] gehoert_zu_feld: Optional[str] = None @@ -1250,21 +1256,27 @@ def grenzpunkte_gemarkungsweise( cur_feld_namen = [f.name() for f in tmp.fields()] - if not pta_feld_namen: - pta_feld_namen = cur_feld_namen + # Globale Feldliste inkrementell um neue Felder erweitern + # (Union über alle Batches/Gemarkungen). + for n in cur_feld_namen: + if n not in pta_feld_namen: + pta_feld_namen.append(n) + + # Referenzfeld beim ersten Batch erkennen, der es enthält + if gehoert_zu_feld is None: gehoert_zu_feld = _erkenne_gehoert_zu_feld(tmp) if gehoert_zu_feld: info( "Grenzpunkte", f"Referenzfeld erkannt: '{gehoert_zu_feld}'. " - f"PunktortTA-Felder: {', '.join(pta_feld_namen)}", + f"PunktortTA-Felder bisher: {', '.join(pta_feld_namen)}", duration=5, ) - else: + elif not pta_feld_namen: warning( "Grenzpunkte (Diagnose)", "Kein Referenzfeld in AX_PunktortTA erkannt. " - "Vorhandene Felder: " + ", ".join(pta_feld_namen), + "Vorhandene Felder: " + ", ".join(cur_feld_namen), duration=15, ) @@ -1277,7 +1289,17 @@ def grenzpunkte_gemarkungsweise( continue if pta_id: gesehene_pta_ids.add(pta_id) - alle_pta_features.append(feat) + + # Attribute namensbasiert als Dict speichern – verhindert + # Positions-Verschiebung beim späteren Aufbau von punktort_layer. + _attrs: Dict[str, str] = {} + for n in cur_feld_namen: + if n: + try: + _attrs[n] = feat[n] + except Exception: + pass + alle_pta_records.append({'geom': feat.geometry(), 'attrs': _attrs}) neu += 1 if gehoert_zu_feld: @@ -1303,7 +1325,7 @@ def grenzpunkte_gemarkungsweise( ) # Abbruch wenn keine Features - if not alle_pta_features: + if not alle_pta_records: prog.close() QMessageBox.warning( tab_widget, @@ -1317,7 +1339,7 @@ def grenzpunkte_gemarkungsweise( QMessageBox.warning( tab_widget, "Kein Referenzfeld", - f"{len(alle_pta_features)} PunktortTA-Objekte geladen, " + f"{len(alle_pta_records)} PunktortTA-Objekte geladen, " f"aber kein Referenzfeld auf AX_Grenzpunkt gefunden.\n\n" f"Gesuchte Feldnamen: {', '.join(_GEHOERT_ZU_KANDIDATEN)}\n" f"Vorhandene Felder: {', '.join(pta_feld_namen)}", @@ -1328,14 +1350,31 @@ def grenzpunkte_gemarkungsweise( pr_pta = punktort_layer.dataProvider() pr_pta.addAttributes([QgsField(n, QVariant.String) for n in pta_feld_namen if n]) punktort_layer.updateFields() - pr_pta.addFeatures(alle_pta_features) + + # Features mit vollständig namensbasierter Attributzuweisung aufbauen – + # vermeidet Positions-Verschiebungen, die entstehen würden, wenn + # QgsFeatures aus tmp-Layern mit unterschiedlicher Feldreihenfolge + # positionsbasiert in punktort_layer übertragen werden. + neue_pta_features = [] + from sn_basis.functions import QgsFeature as _QgsFeature + for record in alle_pta_records: + new_f = _QgsFeature(punktort_layer.fields()) + new_f.setGeometry(record['geom']) + for n, val in record['attrs'].items(): + if n in pta_feld_namen: + try: + new_f[n] = val + except Exception: + pass + neue_pta_features.append(new_f) + pr_pta.addFeatures(neue_pta_features) punktort_layer.updateExtents() alle_gp_ids: set[str] = set() for ids in per_gemarkung_gp_ids.values(): alle_gp_ids.update(ids) - n_pta_gesamt = len(alle_pta_features) + n_pta_gesamt = len(alle_pta_records) n_gp_ids = len(alle_gp_ids) info( "Grenzpunkte",