Add MVP grid maze router and DSN->SES routing pipeline

Implements a working autorouter and the Java-free replacement for the
freerouting.jar step: dsn_text -> parse_dsn -> build_board -> route ->
write_ses.

GridRouter is a single-layer A* maze search over a uniform occupancy
grid: a cell is blocked by another net's pad (inflated by clearance +
half trace width) or a keepout; each net's ratsnest is connected pin to
pin; a routed trace then blocks other nets. The cell path becomes a
trace polyline whose endpoints are the exact pin locations. Board-unit
paths are converted back to DSN units for the SES (wire (path ...))
scopes.

This is an MVP, not a port of FreeRouting's expansion-room maze:
free-space rooms, rip-up-and-retry, multi-layer via search, and shove
are deferred (they raise quality/coverage, not the connectivity
milestone). It reaches connectivity on boards whose nets route on one
layer without crossing.

Adds tests/dsn/fixtures/simple_2net.dsn (a guaranteed-routable 2-net
board). Invariant tests: both nets route, the emitted SES parses, every
trace stays on a valid layer and within the board outline, and every
routed net's trace endpoints sit exactly on its two pads. An oracle-gated
test asserts connectivity parity with the reference FreeRouting JAR on
the simple board.
This commit is contained in:
2026-07-12 11:25:03 -06:00
parent 4220fe0cd6
commit 89c0481ccc
5 changed files with 580 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
"""Autorouting for freeroute.
An MVP grid-based maze router and the DSN-in / SES-out pipeline that makes
freeroute a Java-free replacement for the ``freerouting.jar`` step::
from freeroute.route import route
ses_text = route(dsn_text)
The router (:class:`GridRouter`) is intentionally simple — single-layer A* over
a uniform occupancy grid, enough to reach connectivity on boards whose nets
route without crossing. FreeRouting's free-space expansion-room maze, rip-up,
multi-layer via search, and shove are deferred.
"""
from __future__ import annotations
from .grid_router import GridRouter, RouteResult, route_board
from .pipeline import build_routing_result, route, route_dsn_board
__all__ = [
"GridRouter",
"RouteResult",
"route_board",
"route",
"route_dsn_board",
"build_routing_result",
]