From accec686f884744e75eb8273bcd8c6f492f855db Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Mon, 13 Jul 2026 12:57:13 -0600 Subject: [PATCH] Prove the 45-degree win: 29% shorter, DRC-clean, exact clearance load-bearing Add diagonal_win.dsn: a 45-degree pin-to-pin net with a keepout placed inside the diagonal's bounding box but clear of the true thin copper. Orthogonal routing connects it with a Manhattan-length staircase (1600000); diagonal routing replaces that with a single 45-degree trace at the ideal hypotenuse length (1131371) -- a 29% reduction -- DRC-clean via the search tree and via an independent reconstruction of the emitted 45-degree copper's clearance octagon. test_exact_clearance_is_load_bearing shows the keepout overlaps the coarse bounding box but not the exact octagon, so the exact clearance (not the box) is what lets the diagonal route. Determinism, endpoints-on-pads, valid SES, and diagonal-off-equals-orthogonal (additive, over four fixtures) are covered. --- tests/dsn/fixtures/diagonal_win.dsn | 56 ++++++++ tests/route/test_diagonal.py | 201 ++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 tests/dsn/fixtures/diagonal_win.dsn create mode 100644 tests/route/test_diagonal.py diff --git a/tests/dsn/fixtures/diagonal_win.dsn b/tests/dsn/fixtures/diagonal_win.dsn new file mode 100644 index 0000000..1fe1109 --- /dev/null +++ b/tests/dsn/fixtures/diagonal_win.dsn @@ -0,0 +1,56 @@ +(pcb "diagonal_win.dsn" + (parser + (string_quote ") + (space_in_quoted_tokens on) + (host_cad "freeroute-test") + (host_version "1.0") + ) + (resolution um 10) + (unit um) + (structure + (layer F.Cu + (type signal) + (property + (index 0) + ) + ) + (boundary + (path pcb 0 0 0 120000 0 120000 -120000 0 -120000 0 0) + ) + (keepout "corner" + (rect F.Cu 22000 -98000 40000 -80000) + ) + (rule + (width 2000) + (clearance 2000) + ) + ) + (library + (padstack Rect_Pad + (shape (rect F.Cu -1000 -1000 1000 1000)) + (attach off) + ) + (image PAD + (pin Rect_Pad 1 0 0) + ) + ) + (placement + (component PAD + (place A 20000 -20000 front 0) + (place B 100000 -100000 front 0) + ) + ) + (network + (net NET_A + (pins A-1 B-1) + ) + (class default + (rule + (width 2000) + (clearance 2000) + ) + ) + ) + (wiring + ) +) diff --git a/tests/route/test_diagonal.py b/tests/route/test_diagonal.py new file mode 100644 index 0000000..738a481 --- /dev/null +++ b/tests/route/test_diagonal.py @@ -0,0 +1,201 @@ +"""Tests for 45-degree (diagonal) routing on the exact track. + +The orthogonal exact router connects a 45-degree pin-to-pin net with a Manhattan +staircase (length ~ dx + dy). ``diagonal=True`` replaces it with a single +45-degree trace (length ~ hypot(dx, dy)) whose copper clearance is checked with +the exact integer octagon, not the coarse bounding box -- so it fits past an +obstacle that sits inside the diagonal's bounding box but clears the true thin +copper. ``diagonal_win.dsn`` places exactly such an obstacle, making the exact +clearance load-bearing rather than cosmetic. +""" + +from __future__ import annotations + +import math +from pathlib import Path + +import pytest + +from freeroute.board import build_board +from freeroute.dsn import parse_dsn +from freeroute.dsn.sexp import parse +from freeroute.geometry import IntBox, IntPoint, overlaps_2d, segment_octagon +from freeroute.route import route, route_dsn_board_exact + +FIXTURES = Path(__file__).resolve().parent.parent / "dsn" / "fixtures" +DIAGONAL_WIN = FIXTURES / "diagonal_win.dsn" +SIMPLE = FIXTURES / "simple_2net.dsn" +CROSSING = FIXTURES / "crossing_2net.dsn" +KICAD = FIXTURES / "kicad_routable.dsn" + + +def _length(result): + return sum( + math.hypot(q.x - p.x, q.y - p.y) + for _n, segs in result.result.wires.items() + for _layer, pts in segs + for p, q in zip(pts, pts[1:], strict=False) + ) + + +def _wire_key(result): + return { + n: [(layer, [(p.x, p.y) for p in pts]) for layer, pts in segs] + for n, segs in result.result.wires.items() + } + + +def _pins_by_net(fixture): + board = build_board(parse_dsn(fixture.read_text())) + out: dict[int, set[tuple[int, int]]] = {} + for pin in board.get_pins(): + for net_no in pin.net_nos: + out.setdefault(net_no, set()).add((pin.location.x, pin.location.y)) + return out + + +def _rule_clearance_board(fixture): + from freeroute.route.pipeline import _rule_clearance_dsn + + dsn = parse_dsn(fixture.read_text()) + return round(_rule_clearance_dsn(dsn) * max(dsn.resolution.value, 1)) + + +# --- the falsifiable length win ---------------------------------------------- + + +def test_orthogonal_baseline_is_manhattan_length(): + """Orthogonal (diagonal off) connects the net with a Manhattan-length route -- + the staircase the exact grid produces for a 45-degree ratsnest.""" + dsn = parse_dsn(DIAGONAL_WIN.read_text()) + ortho, _, _ = route_dsn_board_exact(dsn) + assert ortho.routed_net_numbers == {1} + # pins are 80000 x 80000 DSN units apart -> Manhattan = 160000, scaled x10 + assert _length(ortho) == pytest.approx(1_600_000.0) + + +def test_diagonal_is_strictly_shorter_and_ideal(): + """Diagonal on connects the same net with a single 45-degree trace at the ideal + hypotenuse length -- strictly shorter than the orthogonal staircase.""" + dsn = parse_dsn(DIAGONAL_WIN.read_text()) + ortho, _, _ = route_dsn_board_exact(dsn) + diag, _, _ = route_dsn_board_exact(dsn, diagonal=True) + assert diag.routed_net_numbers == {1} + ideal = math.hypot(800_000, 800_000) # board units + assert _length(diag) == pytest.approx(ideal) + assert _length(diag) < _length(ortho) + # a real, sizeable win, not a rounding artifact + assert _length(diag) / _length(ortho) < 0.72 + + +def test_diagonal_route_is_a_single_45_degree_segment(): + dsn = parse_dsn(DIAGONAL_WIN.read_text()) + diag, _, _ = route_dsn_board_exact(dsn, diagonal=True) + segs = diag.result.wires[1] + assert len(segs) == 1 + _layer, pts = segs[0] + assert len(pts) == 2 + (ax, ay), (bx, by) = (pts[0].x, pts[0].y), (pts[1].x, pts[1].y) + assert abs(bx - ax) == abs(by - ay) != 0 # exactly 45 degrees + + +def test_diagonal_endpoints_stay_on_pads(): + dsn = parse_dsn(DIAGONAL_WIN.read_text()) + diag, _, _ = route_dsn_board_exact(dsn, diagonal=True) + pins = _pins_by_net(DIAGONAL_WIN) + for net_no, segments in diag.result.wires.items(): + pts = [(p.x, p.y) for _layer, run in segments for p in run] + assert {pts[0], pts[-1]} == pins[net_no] + + +# --- DRC-clean, verified exactly and independently --------------------------- + + +def test_diagonal_is_drc_clean_via_tree(): + dsn = parse_dsn(DIAGONAL_WIN.read_text()) + clearance = _rule_clearance_board(DIAGONAL_WIN) + diag, _, _ = route_dsn_board_exact(dsn, diagonal=True) + assert diag.drc_clean + assert diag.tree.has_violation(clearance) is None + + +def test_diagonal_is_drc_clean_independently_of_the_tree(): + """Reconstruct the 45-degree copper's clearance octagon from the emitted route + and confirm it clears every different-net static copper (pads, the keepout) -- + a check that never consults the search tree the router verified against.""" + dsn = parse_dsn(DIAGONAL_WIN.read_text()) + board = build_board(dsn) + clearance = _rule_clearance_board(DIAGONAL_WIN) + half_width = 10_000 # trace_width 2000 * scale 10 / 2 + + diag, _, _ = route_dsn_board_exact(dsn, diagonal=True) + + # different-net static copper: the keepout (net -1); pads share NET_A here + obstacles = [] + for obstacle in board.get_obstacle_areas(): + for tile in obstacle.tiles: + obstacles.append(tile.bounding_box()) + + assert diag.result.wires # sanity: the diagonal net was actually emitted + conflicts = 0 + for _net_no, segments in diag.result.wires.items(): + for _layer, pts in segments: + for p, q in zip(pts, pts[1:], strict=False): + grown = segment_octagon(p, q, half_width + clearance) + for box in obstacles: + if overlaps_2d(grown, box): + conflicts += 1 + assert conflicts == 0 + + +def test_exact_clearance_is_load_bearing(): + """The keepout sits INSIDE the diagonal's bounding box (so the coarse bbox + clearance the plain router uses would reject the diagonal) yet clears the exact + octagon -- proving the octagon, not the box, is what lets the trace route.""" + a, b = IntPoint(200_000, -200_000), IntPoint(1_000_000, -1_000_000) + half_width, clearance = 10_000, 20_000 + bbox = IntBox(a.x - half_width, b.y - half_width, b.x + half_width, a.y + half_width) + keepout = IntBox(220_000, -980_000, 400_000, -800_000) + assert not keepout.intersection(bbox).is_empty() # inside the coarse cover + assert not overlaps_2d(segment_octagon(a, b, half_width + clearance), keepout) # clear exactly + + +def test_diagonal_is_deterministic(): + dsn = parse_dsn(DIAGONAL_WIN.read_text()) + a, _, _ = route_dsn_board_exact(dsn, diagonal=True) + b, _, _ = route_dsn_board_exact(dsn, diagonal=True) + assert _wire_key(a) == _wire_key(b) + assert a.routed_net_numbers == b.routed_net_numbers + + +def test_diagonal_valid_ses(): + ses = route(DIAGONAL_WIN.read_text(), engine="exact", diagonal=True) + top = parse(ses) + assert top.head == "session" + nets = top.child("routes").child("network_out").children("net") + assert {n.values()[0].text for n in nets} == {"NET_A"} + + +# --- additive: diagonal off changes nothing on the orthogonal track ---------- + + +@pytest.mark.parametrize("fixture", [DIAGONAL_WIN, SIMPLE, CROSSING, KICAD]) +def test_diagonal_off_matches_orthogonal(fixture): + dsn = parse_dsn(fixture.read_text()) + base, _, _ = route_dsn_board_exact(dsn) + off, _, _ = route_dsn_board_exact(dsn, diagonal=False) + assert _wire_key(base) == _wire_key(off) + + +@pytest.mark.parametrize("fixture", [SIMPLE, CROSSING, KICAD]) +def test_diagonal_on_keeps_existing_fixtures_clean_and_connected(fixture): + """Turning diagonal on never dirties the DRC or drops a net that orthogonal + routed -- it only ever shortens.""" + dsn = parse_dsn(fixture.read_text()) + clearance = _rule_clearance_board(fixture) + base, _, _ = route_dsn_board_exact(dsn) + on, _, _ = route_dsn_board_exact(dsn, diagonal=True) + assert on.drc_clean + assert on.tree.has_violation(clearance) is None + assert on.routed_net_numbers >= base.routed_net_numbers + assert _length(on) <= _length(base) + 1e-6