experiment: compare automatic layout against independent geometry metrics
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
"""Render recorded probe geometry for inspection; this is not a desktop screenshot.
|
||||
|
||||
Usage: python render_probe.py PROBE_STDOUT_JSONL NEW_OUTPUT_DIRECTORY
|
||||
Uses one scale across every result for each fixture; input geometry is unchanged.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
|
||||
def geometries(value, name=""):
|
||||
if not isinstance(value, dict):
|
||||
return
|
||||
if "routed_edges" in value and "projected_nodes" in value:
|
||||
yield name, value
|
||||
return
|
||||
for key, child in value.items():
|
||||
yield from geometries(child, f"{name}.{key}".strip("."))
|
||||
|
||||
|
||||
source, output = map(Path, sys.argv[1:])
|
||||
output.mkdir(parents=True, exist_ok=False)
|
||||
font = ImageFont.truetype("C:/Windows/Fonts/arial.ttf", 13)
|
||||
files = []
|
||||
for line in source.read_text(encoding="utf-8").splitlines():
|
||||
item = json.loads(line)
|
||||
fixture = item.get("fixture")
|
||||
if not fixture:
|
||||
continue
|
||||
variants = list(geometries(item))
|
||||
if not variants:
|
||||
continue
|
||||
largest_width = max(g["drawing_bounds"]["size"]["width"] for _, g in variants)
|
||||
largest_height = max(g["drawing_bounds"]["size"]["height"] for _, g in variants)
|
||||
scale = min(1.0, 1140 / max(1, largest_width), 690 / max(1, largest_height))
|
||||
for name, geometry in variants:
|
||||
canvas = Image.new("RGB", (1200, 800), "white")
|
||||
draw = ImageDraw.Draw(canvas)
|
||||
origin = geometry["drawing_bounds"]["position"]
|
||||
|
||||
def point(position):
|
||||
return (30 + (position["x"] - origin["x"]) * scale,
|
||||
70 + (position["y"] - origin["y"]) * scale)
|
||||
|
||||
def rectangle(position, size):
|
||||
x, y = point(position)
|
||||
return x, y, x + size["width"] * scale, y + size["height"] * scale
|
||||
|
||||
draw.text((20, 12), f"{fixture} / {name} | geometry only, not native UI", font=font, fill="black")
|
||||
draw.text((20, 32), f"Fixed fixture scale {scale:.4f}; text below identifies bounds, not glyph measurements", font=font, fill="black")
|
||||
for node in sorted(geometry["projected_nodes"], key=lambda n: (n["depth"], n["id"])):
|
||||
box = rectangle(node["position"], node["size"])
|
||||
draw.rectangle(box, fill="#eef2f6", outline="#687787", width=1)
|
||||
draw.text((box[0] + 3, box[1] + 3), node["id"][-5:], font=font, fill="#334155")
|
||||
for edge in geometry["routed_edges"]:
|
||||
points = [point(p) for p in edge["points"]]
|
||||
if len(points) > 1:
|
||||
draw.line(points, fill="#245c88", width=2)
|
||||
label = edge["label"]
|
||||
if label["text"]:
|
||||
box = rectangle(label["position"], label["size"])
|
||||
draw.rectangle(box, outline="#ad5715", width=1)
|
||||
target = output / f"{fixture}-{name.replace('.', '-')}.png"
|
||||
canvas.save(target)
|
||||
files.append({"name": target.name, "bytes": target.stat().st_size,
|
||||
"sha256": hashlib.sha256(target.read_bytes()).hexdigest(), "scale": scale})
|
||||
(output / "manifest.json").write_text(json.dumps({
|
||||
"input_sha256": hashlib.sha256(source.read_bytes()).hexdigest(),
|
||||
"renderer_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
|
||||
"scope": "Offline schematic of recorded core geometry; no native or font-rendering acceptance.",
|
||||
"images": files}, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"Rendered {len(files)} geometry records without modifying the probe output.")
|
||||
Reference in New Issue
Block a user