Add shove-and-retry to the exact router
Before a dropped net is abandoned, the exact router (with shove=True) tries to make room by moving an existing trace aside instead: it forms a straight orthogonal candidate for the dropped net, finds the axis-aligned trace segments that cross it, and shoves each one perpendicular (via shove_segment) far enough to restore clearance. A shove is accepted only if the moved trace still connects its pads, clears every other item exactly against the ShapeSearchTree, and stays inside the board outline, so DRC-cleanliness is preserved by construction. Shoves are bounded (max_shove_depth, per-trace shove_cap) and deterministic. The dropped set now includes nets the grid failed to route, not only exact-clearance rejections, so shove can recover them. The pipeline exposes shove (and rip_up) through route_dsn_board_exact / build_exact_routing_result / route(engine='exact', shove=True); default off, so the grid track and the no-shove exact track are unchanged.
This commit is contained in:
@@ -104,10 +104,17 @@ def build_routing_result(
|
||||
|
||||
|
||||
def route_dsn_board_exact(
|
||||
dsn: DsnBoard, *, layers: list[int] | None = None, max_passes: int = 10
|
||||
dsn: DsnBoard,
|
||||
*,
|
||||
layers: list[int] | None = None,
|
||||
max_passes: int = 10,
|
||||
rip_up: bool = True,
|
||||
shove: 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."""
|
||||
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."""
|
||||
board = build_board(dsn)
|
||||
scale = max(dsn.resolution.value, 1)
|
||||
width_board = round(_rule_width_dsn(dsn) * scale)
|
||||
@@ -118,27 +125,34 @@ def route_dsn_board_exact(
|
||||
clearance=clearance_board,
|
||||
layers=layers,
|
||||
max_passes=max_passes,
|
||||
rip_up=rip_up,
|
||||
shove=shove,
|
||||
)
|
||||
return exact, scale, [layer.name for layer in dsn.layers]
|
||||
|
||||
|
||||
def build_exact_routing_result(dsn: DsnBoard, *, layers: list[int] | None = None) -> RoutingResult:
|
||||
def build_exact_routing_result(
|
||||
dsn: DsnBoard, *, layers: list[int] | None = None, shove: 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)
|
||||
exact, scale, layer_names = route_dsn_board_exact(dsn, layers=layers, shove=shove)
|
||||
return _to_routing_result(exact.result, dsn, scale, layer_names)
|
||||
|
||||
|
||||
def route(dsn_text: str, *, layers: list[int] | None = None, engine: str = "grid") -> str:
|
||||
def route(
|
||||
dsn_text: str, *, layers: list[int] | None = None, engine: str = "grid", shove: bool = False
|
||||
) -> str:
|
||||
"""Route a Specctra DSN string and return the routed SES string.
|
||||
|
||||
``engine`` selects the routing track: ``"grid"`` (default; the multi-layer
|
||||
rip-up grid MVP — highest coverage, kept for backward compatibility) or
|
||||
``"exact"`` (orthogonal, exact-geometry, DRC-verified — cleaner output where
|
||||
it succeeds, but lower coverage on dense boards).
|
||||
it succeeds). ``shove`` (exact engine only) tries moving existing traces
|
||||
aside to recover dropped nets.
|
||||
"""
|
||||
dsn = parse_dsn(dsn_text)
|
||||
if engine == "exact":
|
||||
result = build_exact_routing_result(dsn, layers=layers)
|
||||
result = build_exact_routing_result(dsn, layers=layers, shove=shove)
|
||||
else:
|
||||
result = build_routing_result(dsn, layers=layers)
|
||||
return write_ses(dsn, result)
|
||||
|
||||
Reference in New Issue
Block a user