BuildPassageSpatialIndices adds the 4.335 m reach in core-voxel units, so the broadphase reaches ~1.08 m while the sweep cutoff says 4 m. Physically-correct 2 m bounds are larger than v225's and 4.9-9.9% slower; captures at all L125 poses pixel-identical. Patch kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
94 lines
4.4 KiB
Python
94 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Render matching baseline and L129 close views of each tunnel mouth."""
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import importlib.util
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[4]
|
|
RESEARCH = Path(__file__).resolve().parent
|
|
CAPTURES = RESEARCH / "captures/L129-mouth"
|
|
SAVED = ROOT / "Saved/Linux/l129/captures/mouth-closeups"
|
|
BASE_LAYOUT = ROOT / "Saved/Linux/l125/hashes/owner4-surface-world-w12-clang.layout.json"
|
|
AFTER_LAYOUT = ROOT / "Saved/Linux/l129/hashes/owner4-surface-world-w12-clang.layout.json"
|
|
HELPER_PATH = ROOT / "Standalone/Research/WorldAssemblerM3/Linux113/RunL113Captures.py"
|
|
|
|
SPEC = importlib.util.spec_from_file_location("l113_capture_helpers", HELPER_PATH)
|
|
if SPEC is None or SPEC.loader is None:
|
|
raise SystemExit("cannot load verified capture helpers")
|
|
HELPERS = importlib.util.module_from_spec(SPEC)
|
|
SPEC.loader.exec_module(HELPERS)
|
|
|
|
HELPERS.RESEARCH = RESEARCH
|
|
HELPERS.CAPTURES = CAPTURES
|
|
HELPERS.SAVED = SAVED
|
|
HELPERS.BINARIES = {
|
|
"before": ROOT / "Saved/Linux/l125/bin/VoxelForgeCoreHeadless-l125-clang",
|
|
"after": ROOT / "Saved/Linux/l129/bin/VoxelForgeCoreHeadless-l129-clang",
|
|
}
|
|
HELPERS.RENDERERS = {
|
|
"before": ROOT / "Saved/Linux/l125/bin/VoxelForgeOffscreenCapture-l125-clang",
|
|
"after": ROOT / "Saved/Linux/l129/bin/VoxelForgeOffscreenCapture-l129-clang",
|
|
}
|
|
|
|
|
|
def main() -> int:
|
|
required = [BASE_LAYOUT, AFTER_LAYOUT, *HELPERS.BINARIES.values(),
|
|
*HELPERS.RENDERERS.values()]
|
|
if any(not path.is_file() for path in required):
|
|
raise SystemExit("missing baseline/candidate layout or capture binary")
|
|
before_layout = json.loads(BASE_LAYOUT.read_text(encoding="utf-8"))
|
|
after_layout = json.loads(AFTER_LAYOUT.read_text(encoding="utf-8"))
|
|
if before_layout["passages"] != after_layout["passages"]:
|
|
raise RuntimeError("baseline and candidate passage routes differ")
|
|
|
|
views = [view for view in HELPERS.make_views(before_layout, [],
|
|
use_derived_shape=True, use_spline=True, include_open_air=False)
|
|
if view["kind"] == "mouth"]
|
|
if len(views) != 2 * len(before_layout["passages"]):
|
|
raise RuntimeError("unexpected mouth camera count")
|
|
|
|
rows = []
|
|
CAPTURES.mkdir(parents=True, exist_ok=True)
|
|
SAVED.mkdir(parents=True, exist_ok=True)
|
|
for view in views:
|
|
for variant, layout in (("before", before_layout), ("after", after_layout)):
|
|
row = HELPERS.capture(variant, view, layout)
|
|
row["variant"] = "L125-v225" if variant == "before" else "L129-v226"
|
|
row["view"] = view["name"]
|
|
image = ROOT / "Standalone/Research/WorldAssemblerM3/Linux129" / row["capture"]
|
|
row["image_sha256"] = hashlib.sha256(image.read_bytes()).hexdigest()
|
|
rows.append(row)
|
|
|
|
index = CAPTURES / "capture-index.json"
|
|
index.write_text(json.dumps({"captures": rows}, indent=2) + "\n", encoding="utf-8")
|
|
old_rows = {row["view"]: row for row in rows if row["variant"] == "L125-v225"}
|
|
new_rows = {row["view"]: row for row in rows if row["variant"] == "L129-v226"}
|
|
html = ["<!doctype html><meta charset='utf-8'>",
|
|
"<title>L125 / L129 mouth close-ups</title>",
|
|
"<style>body{font:14px system-ui;margin:24px;background:#17191d;color:#eee}"
|
|
"section{margin:28px 0}div{display:grid;grid-template-columns:1fr 1fr;gap:12px}"
|
|
"img{width:100%;height:auto}p{color:#bbb}</style>",
|
|
"<h1>L125 v225 / L129 v226 tunnel mouths</h1>"]
|
|
for name in old_rows:
|
|
old, new = old_rows[name], new_rows[name]
|
|
old_path = os.path.relpath(RESEARCH / old["capture"], CAPTURES)
|
|
new_path = os.path.relpath(RESEARCH / new["capture"], CAPTURES)
|
|
equality = "pixel-identical" if old["image_sha256"] == new["image_sha256"] else "pixels differ"
|
|
html.extend(["<section>", f"<h2>{old['passage']} — {old['station']}</h2>",
|
|
f"<p>{equality}; {old['pixel_quality_status']} / {new['pixel_quality_status']}</p>",
|
|
"<div>", f"<figure><figcaption>L125 v225</figcaption><img src='{old_path}'></figure>",
|
|
f"<figure><figcaption>L129 v226</figcaption><img src='{new_path}'></figure>",
|
|
"</div>", "</section>"])
|
|
(CAPTURES / "COMPARE.html").write_text("\n".join(html) + "\n", encoding="utf-8")
|
|
print(f"[L129MouthCaptures] views={len(views)} paired={len(rows)//2} "
|
|
f"index={index.relative_to(ROOT)}", flush=True)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|