diff --git a/functions/qgiscore_wrapper.py b/functions/qgiscore_wrapper.py index bf4f044..8387381 100644 --- a/functions/qgiscore_wrapper.py +++ b/functions/qgiscore_wrapper.py @@ -954,3 +954,79 @@ def layer_exists_in_gpkg(gpkg_path: str, layer_name: str) -> bool: pass return False + + +# --------------------------------------------------------- +# QGIS-3/4-kompatible Geometrie-Hilfsfunktionen +# --------------------------------------------------------- + +def polygon_zu_linie(geom: Any) -> Optional[Any]: + """Konvertiert ein Polygon/MultiPolygon zur Umringslinie (QGIS 3 + 4). + + In QGIS 3.x existiert ``QgsGeometry.boundary()``, in QGIS 4.x wurde sie + entfernt. Diese Funktion kapselt die Versionsunterschiede und stellt dem + Fachplugin eine stabile API bereit. + + Strategie (dreistufig): + 1. ``geom.boundary()`` – funktioniert in QGIS 3.x + 2. ``geom.convertToType(1, False)`` – ``1`` = LineGeometry-Wert, + identisch in ``QgsWkbTypes.LineGeometry`` (3.x) und + ``Qgis.GeometryType.Line`` (4.x) + 3. Manuelle Ring-Extraktion via ``asPolygon()`` / ``asMultiPolygon()`` + + ``QgsGeometry.fromPolylineXY()`` + + Parameters + ---------- + geom : + Polygon- oder MultiPolygon-``QgsGeometry``. + + Returns + ------- + Optional[QgsGeometry] + Liniengeometrie (Umring) oder ``None`` bei Fehler / leerer Eingabe. + """ + if geom is None: + return None + try: + if geom.isEmpty(): + return None + except Exception: + return None + + # Stufe 1: QGIS 3.x – .boundary() existiert und liefert alle Ringe korrekt + if hasattr(geom, "boundary"): + try: + result = geom.boundary() + if result is not None and not result.isEmpty(): + return result + except Exception: + pass + + # Stufe 2: Manuelle Ring-Extraktion (primärer QGIS-4.x-Pfad). + # convertToType(1, False) würde bei MultiPolygon nur den ersten Außenring + # zurückgeben und alle weiteren Polygone sowie Innenringe verwerfen → daher + # direkt die vollständige manuelle Extraktion als nächste Stufe. + lines = [] + try: + if geom.isMultipart(): + for polygon in geom.asMultiPolygon(): + for ring in polygon: + lines.append(QgsGeometry.fromPolylineXY(ring)) + else: + for ring in geom.asPolygon(): + lines.append(QgsGeometry.fromPolylineXY(ring)) + except Exception: + pass + if lines: + return QgsGeometry.unaryUnion(lines) + + # Stufe 3: Letzter Fallback – convertToType mit destMultipart=True, damit + # zumindest alle Außenringe eines MultiPolygons erfasst werden. + try: + result = geom.convertToType(1, True) + if result is not None and not result.isEmpty(): + return result + except Exception: + pass + + return None