diff --git a/README.md b/README.md index a68f876..77f14da 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,8 @@ LoD2 CityGML tiles can be converted to GLB per tile while preserving roof/wall s ```bash for f in work/cityjson/*.city.json; do base="$(basename "$f" .city.json)" - uv run cjio "$f" upgrade triangulate vertices_clean \ + input_json="$f/$base.json" # citygml-tools writes a .json inside the .city.json folder + uv run cjio "$input_json" upgrade triangulate vertices_clean \ save "work/cityjson_tri/${base}.tri.city.json" done ``` diff --git a/scripts/split_semantics.py b/scripts/split_semantics.py index 2bc1948..c25245f 100644 --- a/scripts/split_semantics.py +++ b/scripts/split_semantics.py @@ -41,8 +41,8 @@ def parse_args(argv: Iterable[str] | None = None) -> argparse.Namespace: ) parser.add_argument( "--pattern", - default="*.city.json", - help="Glob pattern for input files (defaults to all .city.json files).", + default="**/*.json", + help="Glob pattern for input files (defaults to any .json under the input dir).", ) return parser.parse_args(argv) @@ -65,9 +65,26 @@ def base_name(path: Path) -> str: return name[: -len(".tri.city.json")] if name.endswith(".city.json"): return name[: -len(".city.json")] + if name.endswith(".json"): + return name[: -len(".json")] return path.stem +def resolve_input_file(path: Path) -> Path | None: + """Handle both flat files and citygml-tools style output directories.""" + if path.is_file(): + return path + if path.is_dir(): + # citygml-tools writes .city.json/.json + candidate = path / f"{path.stem}.json" + if candidate.is_file(): + return candidate + matches = list(path.glob("*.json")) + if len(matches) == 1: + return matches[0] + return None + + def allowed_semantic_indices(semantics: dict[str, Any], allowed_types: set[str]) -> set[int]: surfaces = semantics.get("surfaces") or [] return {idx for idx, surface in enumerate(surfaces) if surface.get("type") in allowed_types} @@ -156,7 +173,12 @@ def filter_cityjson(cityjson: dict[str, Any], allowed_types: set[str]) -> dict[s def process_file(path: Path, targets: list[str], output_dir: Path) -> int: - cityjson = read_json(path) + resolved = resolve_input_file(path) + if not resolved: + print(f"[skip] cannot resolve CityJSON file for {path}", file=sys.stderr) + return 0 + + cityjson = read_json(resolved) written = 0 base = base_name(path) diff --git a/scripts/verify_pipeline.py b/scripts/verify_pipeline.py index 4351273..5831c61 100644 --- a/scripts/verify_pipeline.py +++ b/scripts/verify_pipeline.py @@ -86,9 +86,22 @@ def discover_tiles(raw_dir: Path, provided: Sequence[str] | None) -> list[str]: return sorted(path.stem for path in raw_dir.glob("LoD2_*.gml")) +def path_exists(path: Path) -> bool: + if path.exists(): + return True + if path.is_dir(): + return True + # citygml-tools may output a directory named *.city.json containing a *.json + if path.suffixes == [".city", ".json"]: + candidate = path / f"{path.stem}.json" + if candidate.exists(): + return True + return False + + def collect_missing(tile_ids: Sequence[str], directory: Path, pattern: str) -> list[Path]: expected = [directory / pattern.format(tile_id=tile_id) for tile_id in tile_ids] - return [path for path in expected if not path.exists()] + return [path for path in expected if not path_exists(path)] def summarize_missing(label: str, missing: list[Path]) -> str: