diff --git a/README.md b/README.md index 1976712..c1a3084 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,8 @@ This repository converts DGM1 elevation tiles into Unity-ready 16-bit PNG height - `export_unity/height_png16/` — final 16-bit PNG heightmaps for Unity import. - `export_unity/tile_index.csv` — manifest mapping tile IDs to world bounds and global min/max used for scaling. - `export_unity/ortho_jpg/` — cropped orthophoto tiles aligned to the terrain grid (JPEG + worldfiles). -- `export_unity/buildings_obj/` — per-tile clipped CityGML exports as OBJ meshes. - `export_heightmaps.py` — main export script. - `export_ortho_tiles.py` — exports orthophoto tiles from DOP JP2 inputs using the terrain manifest. -- `export_buildings.py` — clips CityGML LoD2 tiles per terrain tile and writes OBJ meshes. - `AGENTS.md` — contributor guide. ### Quick Start @@ -47,10 +45,5 @@ This repository converts DGM1 elevation tiles into Unity-ready 16-bit PNG height ``` This builds `work/dop.vrt` if missing and writes `export_unity/ortho_jpg/.jpg` + `.jgw` aligned to `tile_index.csv`. -### Buildings (CityGML LoD2 → OBJ) -1. Ensure LoD2 GML tiles live in `raw_3dgeb_lod2/` (unzipped from `3dgeblod2` bundle). -2. From `GeoData/`, run: - ```bash - python3 export_buildings.py - ``` - This clips each GML to the terrain tile footprint and exports `export_unity/buildings_obj/.obj` (EPSG:25832 coordinates). +### Buildings +The building export pipeline is temporarily disabled while we choose a mesh conversion approach (GDAL lacks a native OBJ writer). CityGML LoD2 sources remain in `raw_3dgeb_lod2/`; consider CityGML→glTF/OBJ tools (e.g., citygml-tools + cityjson2gltf) for future integration. diff --git a/export_buildings.py b/export_buildings.py deleted file mode 100644 index cb33d88..0000000 --- a/export_buildings.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -"""Clip CityGML LoD2 buildings per terrain tile and export as OBJ meshes. - -Inputs -- raw_3dgeb_lod2/LoD2___.gml : source building tiles -- export_unity/tile_index.csv : manifest produced by export_heightmaps.py - -Outputs -- export_unity/buildings_obj/.obj : clipped building geometries per tile -""" -from __future__ import annotations - -import csv -import os -from pathlib import Path - -from osgeo import gdal - -RAW_GML_DIR = Path("raw_3dgeb_lod2") -TILE_INDEX = Path("export_unity/tile_index.csv") -OUT_DIR = Path("export_unity/buildings_obj") - -OUTPUT_FORMAT = "OBJ" # glTF driver is not always available; OBJ is widely supported. - -gdal.UseExceptions() -OUT_DIR.mkdir(parents=True, exist_ok=True) - - -def gml_path_for_tile(tile_id: str) -> Path: - """Map a DGM tile id (dgm1_utm_easting_northing) to the corresponding CityGML file.""" - parts = tile_id.split("_") - if len(parts) != 4 or parts[0] != "dgm1": - raise ValueError(f"Unexpected tile_id format: {tile_id}") - utm_zone, easting, northing = parts[1:] - return RAW_GML_DIR / f"LoD2_{utm_zone}_{easting}_{northing}.gml" - - -def open_dataset(path: str, purpose: str): - """Open a dataset and fail fast with context.""" - try: - ds = gdal.OpenEx(path) - except RuntimeError as exc: - raise SystemExit(f"{purpose}: {exc}") from exc - if ds is None: - raise SystemExit(f"{purpose}: GDAL returned None for {path}") - return ds - - -def main() -> None: - if not TILE_INDEX.exists(): - raise SystemExit(f"Tile index missing: {TILE_INDEX}. Run export_heightmaps.py first.") - - written = 0 - skipped = 0 - - with TILE_INDEX.open(newline="", encoding="utf-8") as f: - reader = csv.DictReader(f) - for row in reader: - try: - tile_id = row["tile_id"] - xmin = float(row["xmin"]) - ymin = float(row["ymin"]) - xmax = float(row["xmax"]) - ymax = float(row["ymax"]) - except (KeyError, ValueError) as exc: - print(f"Skipping malformed row {row}: {exc}") - skipped += 1 - continue - - gml_path = gml_path_for_tile(tile_id) - if not gml_path.exists(): - print(f"Missing CityGML for {tile_id}: {gml_path}") - skipped += 1 - continue - - out_path = OUT_DIR / f"{tile_id}.obj" - - src_ds = open_dataset(str(gml_path), f"Could not open {gml_path}") - - opts = gdal.VectorTranslateOptions( - format=OUTPUT_FORMAT, - spatFilter=(xmin, ymin, xmax, ymax), - layerName="Building", # matches GML layer name - ) - - try: - gdal.VectorTranslate(destNameOrDestDS=str(out_path), srcDS=src_ds, options=opts) - except RuntimeError as exc: - print(f"VectorTranslate failed for {tile_id}: {exc}") - skipped += 1 - continue - - written += 1 - print(f"Wrote {out_path}") - - print(f"Summary: wrote {written} building tiles; skipped {skipped}.") - if skipped: - raise SystemExit(1) - - -if __name__ == "__main__": - main()