""" Swiss Parcel (Liegenschaften) Connector Fetches parcel data from geodienste.ch OGC API Features (Amtliche Vermessung). Covers all of Switzerland. Returns GeoJSON in WGS84. Uses: geodienste.ch OGC API - RESF collection (Liegenschaften) No config override needed - this is the single working solution. """ import logging from typing import Dict, Any import requests logger = logging.getLogger(__name__) # geodienste.ch OGC API - RESF = Liegenschaften (parcels), all Switzerland # API returns WGS84 directly when bbox-crs=EPSG:2056 is used _OGC_API_BASE = "https://www.geodienste.ch/db/av_0/deu/ogcapi/collections/RESF/items" _MAX_ITEMS = 2000 _TIMEOUT = 30 class ZhWfsParcelsConnector: """ Connector for Swiss parcel (Liegenschaften) data via geodienste.ch OGC API. Returns GeoJSON FeatureCollection in WGS84. """ def __init__(self, timeout: int = _TIMEOUT): self.timeout = timeout logger.info("ZhWfsParcelsConnector initialized (geodienste.ch OGC API)") def get_parcels_by_bbox(self, bbox: str) -> Dict[str, Any]: """ Fetch parcels within bounding box. Returns GeoJSON FeatureCollection in WGS84 (EPSG:4326). Args: bbox: Bounding box as "minx,miny,maxx,maxy" in LV95 (EPSG:2056) Returns: GeoJSON FeatureCollection with geometries in WGS84 """ try: parts = [p.strip() for p in bbox.split(",")] if len(parts) != 4: raise ValueError(f"Invalid bbox: expected minx,miny,maxx,maxy, got {bbox}") minx, miny, maxx, maxy = (float(p) for p in parts) params = { "f": "json", "limit": _MAX_ITEMS, "bbox": f"{minx},{miny},{maxx},{maxy}", "bbox-crs": "http://www.opengis.net/def/crs/EPSG/0/2056", } logger.debug(f"Requesting parcels: bbox={bbox}") resp = requests.get(_OGC_API_BASE, params=params, timeout=self.timeout) if resp.status_code != 200: logger.error(f"Parcel API failed: status={resp.status_code}, body={resp.text[:500]}") return {"type": "FeatureCollection", "features": []} data = resp.json() # OGC API returns FeatureCollection in WGS84 directly features = data.get("features", []) if not features: return {"type": "FeatureCollection", "features": []} # Pass through - geodienste returns WGS84 GeoJSON result = { "type": "FeatureCollection", "features": features, } logger.info(f"Returned {len(features)} parcels in WGS84") return result except ValueError as e: logger.warning(f"Invalid bbox: {e}") raise except requests.RequestException as e: logger.error(f"Parcel API request error: {e}") return {"type": "FeatureCollection", "features": []} except Exception as e: logger.error(f"Error fetching parcels: {e}", exc_info=True) return {"type": "FeatureCollection", "features": []}