Handle citygml-tools directory outputs and doc cjio paths
This commit is contained in:
@@ -83,7 +83,8 @@ LoD2 CityGML tiles can be converted to GLB per tile while preserving roof/wall s
|
|||||||
```bash
|
```bash
|
||||||
for f in work/cityjson/*.city.json; do
|
for f in work/cityjson/*.city.json; do
|
||||||
base="$(basename "$f" .city.json)"
|
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"
|
save "work/cityjson_tri/${base}.tri.city.json"
|
||||||
done
|
done
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ def parse_args(argv: Iterable[str] | None = None) -> argparse.Namespace:
|
|||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--pattern",
|
"--pattern",
|
||||||
default="*.city.json",
|
default="**/*.json",
|
||||||
help="Glob pattern for input files (defaults to all .city.json files).",
|
help="Glob pattern for input files (defaults to any .json under the input dir).",
|
||||||
)
|
)
|
||||||
return parser.parse_args(argv)
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
@@ -65,9 +65,26 @@ def base_name(path: Path) -> str:
|
|||||||
return name[: -len(".tri.city.json")]
|
return name[: -len(".tri.city.json")]
|
||||||
if name.endswith(".city.json"):
|
if name.endswith(".city.json"):
|
||||||
return name[: -len(".city.json")]
|
return name[: -len(".city.json")]
|
||||||
|
if name.endswith(".json"):
|
||||||
|
return name[: -len(".json")]
|
||||||
return path.stem
|
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 <name>.city.json/<name>.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]:
|
def allowed_semantic_indices(semantics: dict[str, Any], allowed_types: set[str]) -> set[int]:
|
||||||
surfaces = semantics.get("surfaces") or []
|
surfaces = semantics.get("surfaces") or []
|
||||||
return {idx for idx, surface in enumerate(surfaces) if surface.get("type") in allowed_types}
|
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:
|
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
|
written = 0
|
||||||
base = base_name(path)
|
base = base_name(path)
|
||||||
|
|
||||||
|
|||||||
@@ -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"))
|
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]:
|
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]
|
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:
|
def summarize_missing(label: str, missing: list[Path]) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user