Add continuous expansion-room routing track
A third engine (engine='room') that replaces the fixed routing grid with FreeRouting's free-space rooms. Per layer, the space not occupied by items (inflated by the routing clearance) is decomposed into exact rectangles via coordinate compression (the orthogonal analogue of CompleteFreeSpaceExpansionRoom); adjacent rooms share an edge door, and a via door joins overlapping rooms on two layers. The maze search is an A* over rooms-through-doors (cost = geometric distance + via cost), so a path may cross a door anywhere along its width rather than at a quantized cell. The found room sequence is realized into an exact orthogonal Polyline through the door mid-gates and verified DRC-clean against the ShapeSearchTree, dropping the net if it cannot be made exactly clean. Maps to autoroute/: ExpansionRoom / CompleteFreeSpaceExpansionRoom (rooms), ExpansionDoor / TargetItemExpansionDoor (doors), MazeSearchAlgo / AutorouteEngine (search), LocateFoundConnectionAlgo (realization). Foundation scope: rooms are axis-aligned rectangles (not general Simplex tiles); realization uses an L-connector through door mid-gates. Any-angle rooms, optimal gate placement (true sub-cell shove), and optimization passes are follow-ups. The grid and exact tracks are unchanged; this is opt-in. Routes simple/crossing (with a via) and all four multi-pin nets of the real KiCad board, DRC-clean.
This commit is contained in:
@@ -18,6 +18,7 @@ from freeroute.ses import RoutedVia, RoutedWire, RoutingResult, write_ses
|
||||
|
||||
from .exact_router import ExactRouteResult, route_board_exact
|
||||
from .grid_router import RouteResult, route_board
|
||||
from .room_router import route_board_rooms
|
||||
|
||||
__all__ = ["route", "route_dsn_board", "build_routing_result"]
|
||||
|
||||
@@ -139,20 +140,44 @@ def build_exact_routing_result(
|
||||
return _to_routing_result(exact.result, dsn, scale, layer_names)
|
||||
|
||||
|
||||
def route_dsn_board_rooms(
|
||||
dsn: DsnBoard, *, layers: list[int] | None = None
|
||||
) -> tuple[ExactRouteResult, int, list[str]]:
|
||||
"""Route a parsed :class:`DsnBoard` with the continuous expansion-room track;
|
||||
return the result, the scale, and layer names."""
|
||||
board = build_board(dsn)
|
||||
scale = max(dsn.resolution.value, 1)
|
||||
width_board = round(_rule_width_dsn(dsn) * scale)
|
||||
clearance_board = round(_rule_clearance_dsn(dsn) * scale)
|
||||
rooms = route_board_rooms(
|
||||
board, trace_width=width_board, clearance=clearance_board, layers=layers
|
||||
)
|
||||
return rooms, scale, [layer.name for layer in dsn.layers]
|
||||
|
||||
|
||||
def build_rooms_routing_result(dsn: DsnBoard, *, layers: list[int] | None = None) -> RoutingResult:
|
||||
"""Route ``dsn`` (room track) and convert to a DSN-unit RoutingResult."""
|
||||
rooms, scale, layer_names = route_dsn_board_rooms(dsn, layers=layers)
|
||||
return _to_routing_result(rooms.result, dsn, scale, layer_names)
|
||||
|
||||
|
||||
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
|
||||
rip-up grid MVP — highest coverage, kept for backward compatibility),
|
||||
``"exact"`` (orthogonal, exact-geometry, DRC-verified — cleaner output where
|
||||
it succeeds). ``shove`` (exact engine only) tries moving existing traces
|
||||
aside to recover dropped nets.
|
||||
it succeeds), or ``"room"`` (continuous expansion-room — exact free-space
|
||||
decomposition, routes off-grid channels the grid/exact tracks cannot).
|
||||
``shove`` (exact engine only) tries moving existing traces aside.
|
||||
"""
|
||||
dsn = parse_dsn(dsn_text)
|
||||
if engine == "exact":
|
||||
result = build_exact_routing_result(dsn, layers=layers, shove=shove)
|
||||
elif engine == "room":
|
||||
result = build_rooms_routing_result(dsn, layers=layers)
|
||||
else:
|
||||
result = build_routing_result(dsn, layers=layers)
|
||||
return write_ses(dsn, result)
|
||||
|
||||
Reference in New Issue
Block a user