Route 45-degree traces on the exact track (opt-in diagonal mode)

Add diagonal=True to the exact router: after orthogonal routing, each 2-pin net
is retried as the shortest exactly-clean octilinear (0/45/90/135-degree) trace.
A dropped net is recovered; an orthogonal route is replaced only when the
diagonal is strictly shorter. Candidates are the direct 45-degree segment or the
two diagonal-plus-axis two-benders; each segment's diagonal copper is covered by
the exact octagon and its clearance checked with clearance_conflict_shape, so a
trace fits a diagonal corridor the bounding-box cover would reject.

Endpoints stay on the pads; diagonal copper is stored with its exact octagon so
later nets clear it precisely; same-net copper is ignored during the check so the
candidate is verified against every other net before the orthogonal copper is
ripped. With diagonal=False the pass is skipped and output is byte-for-byte the
orthogonal router. Threaded through route_dsn_board_exact /
build_exact_routing_result / route(engine="exact").
This commit is contained in:
2026-07-13 12:57:05 -06:00
parent 20dc5fd96a
commit 700ed06843
2 changed files with 168 additions and 6 deletions
+10 -4
View File
@@ -111,11 +111,13 @@ def route_dsn_board_exact(
max_passes: int = 10,
rip_up: bool = True,
shove: bool = False,
diagonal: bool = False,
) -> tuple[ExactRouteResult, int, list[str]]:
"""Route a parsed :class:`DsnBoard` with the exact-geometry (orthogonal,
DRC-verified) track; return the exact result, the scale, and layer names.
``shove`` enables moving existing traces aside to recover dropped nets;
``rip_up`` toggles the underlying grid's rip-up-and-retry."""
``rip_up`` toggles the underlying grid's rip-up-and-retry; ``diagonal`` enables
the 45-degree recovery pass for still-dropped 2-pin nets."""
board = build_board(dsn)
scale = max(dsn.resolution.value, 1)
width_board = round(_rule_width_dsn(dsn) * scale)
@@ -128,15 +130,18 @@ def route_dsn_board_exact(
max_passes=max_passes,
rip_up=rip_up,
shove=shove,
diagonal=diagonal,
)
return exact, scale, [layer.name for layer in dsn.layers]
def build_exact_routing_result(
dsn: DsnBoard, *, layers: list[int] | None = None, shove: bool = False
dsn: DsnBoard, *, layers: list[int] | None = None, shove: bool = False, diagonal: bool = False
) -> RoutingResult:
"""Route ``dsn`` (exact track) and convert to a DSN-unit RoutingResult."""
exact, scale, layer_names = route_dsn_board_exact(dsn, layers=layers, shove=shove)
exact, scale, layer_names = route_dsn_board_exact(
dsn, layers=layers, shove=shove, diagonal=diagonal
)
return _to_routing_result(exact.result, dsn, scale, layer_names)
@@ -177,6 +182,7 @@ def route(
engine: str = "grid",
shove: bool = False,
pack: bool = False,
diagonal: bool = False,
) -> str:
"""Route a Specctra DSN string and return the routed SES string.
@@ -190,7 +196,7 @@ def route(
"""
dsn = parse_dsn(dsn_text)
if engine == "exact":
result = build_exact_routing_result(dsn, layers=layers, shove=shove)
result = build_exact_routing_result(dsn, layers=layers, shove=shove, diagonal=diagonal)
elif engine == "room":
result = build_rooms_routing_result(dsn, layers=layers, shove=shove, pack=pack)
else: