Check grid and room output on exact shapes and report shorts

The grid and room engines write copper they never check. After a grid or
room run the result is now put through the exact engine's geometry (its
pads, fixed copper and keepouts; wires as boxes or slanted slabs; vias as
their pads) and the report gives the shorts and clearance violations, with
examples, instead of a blanket warning. --strict exits 3 when there are any;
by default the exit status stays 0 so the JAR drop-in contract holds.

The exact engine's static-copper setup moves into insert_static_copper so
both use it; exact runs are byte-identical before and after.
This commit is contained in:
2026-10-07 20:04:04 -06:00
parent 1852df3d53
commit 74d97b601c
6 changed files with 307 additions and 40 deletions
+42
View File
@@ -0,0 +1,42 @@
"""verify_result: copper no engine checked is checked on exact shapes."""
from pathlib import Path
from rpmroute.dsn import parse_dsn
from rpmroute.route.verify import verify_result
from rpmroute.ses.model import RoutedWire, RoutingResult
FIXTURE = Path(__file__).parents[1] / "dsn" / "fixtures" / "crossing_2net.dsn"
# rule: 2000 um wide traces, 2000 um clearance; NET_A runs along y = -40000
A = RoutedWire(layer="Top", width=2000, coords=[2000, -40000, 198000, -40000])
def _check(b_wire):
result = RoutingResult()
result.add_wire("NET_A", A)
result.add_wire("NET_B", b_wire)
return verify_result(parse_dsn(FIXTURE.read_text()), result)
def test_a_crossing_on_one_layer_is_a_short():
report = _check(RoutedWire(layer="Top", width=2000, coords=[100000, -15000, 100000, -65000]))
assert report.shorts == 1 and report.clearance == 0
found = report.short_examples[0]
assert {found.net, found.other} == {"NET_A", "NET_B"} and found.layer == "Top"
assert abs(found.x_mm - 100.0) < 1.5 and abs(found.y_mm + 40.0) < 1.5
def test_copper_closer_than_the_rule_is_a_clearance_violation():
# edges 1500 um apart against a 2000 um rule
report = _check(RoutedWire(layer="Top", width=2000, coords=[50000, -36500, 150000, -36500]))
assert report.shorts == 0 and report.clearance == 1
def test_exactly_the_clearance_apart_is_clean():
report = _check(RoutedWire(layer="Top", width=2000, coords=[50000, -36000, 150000, -36000]))
assert report.clean
def test_a_crossing_on_another_layer_is_clean():
report = _check(RoutedWire(layer="Bottom", width=2000, coords=[100000, -15000, 100000, -65000]))
assert report.clean
+16 -2
View File
@@ -82,9 +82,23 @@ def test_cli_default_engine_is_exact(tmp_path):
@pytest.mark.parametrize("engine", ["grid", "room"])
def test_unchecked_engines_say_so(tmp_path, capsys, engine):
def test_unchecked_engines_are_checked_after_routing(tmp_path, capsys, engine):
assert main([str(FIXTURE), "--engine", engine, "-do", str(tmp_path / "out.ses")]) == 0
assert "does not check its copper" in capsys.readouterr().err
assert f"{engine} output checked on exact shapes: 0 short(s), 0 clearance" in capsys.readouterr().err
def test_strict_fails_a_run_whose_copper_is_not_clean(tmp_path, monkeypatch, capsys):
from rpmroute import cli
from rpmroute.route.verify import VerifyReport, Violation
bad = VerifyReport(shorts=1, short_examples=[Violation("A", "B", "F.Cu", 1.0, 2.0)])
monkeypatch.setattr(cli, "verify_result", lambda dsn, result: bad)
out = tmp_path / "out.ses"
assert main([str(FIXTURE), "--engine", "grid", "-do", str(out)]) == 0
assert main([str(FIXTURE), "--engine", "grid", "--strict", "-do", str(out)]) == 3
assert out.exists() # the session is still written
err = capsys.readouterr().err
assert "short: A x B on F.Cu at (1.00, 2.00) mm" in err and "not DRC-clean" in err
def test_the_exact_engine_does_not_warn(tmp_path, capsys):