"""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