Remove building export pipeline
This commit is contained in:
11
README.md
11
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/<tile>.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/<tile>.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.
|
||||
|
||||
@@ -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_<utm>_<easting>_<northing>.gml : source building tiles
|
||||
- export_unity/tile_index.csv : manifest produced by export_heightmaps.py
|
||||
|
||||
Outputs
|
||||
- export_unity/buildings_obj/<tile_id>.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()
|
||||
Reference in New Issue
Block a user