Make the grid and the exact check agree on rotated pads, shared vias and wide nets
Rotated oval pads were built from padded corners that are not in outline order, so they fell back to their bounding box; neighbouring boxes of a rotated socket overlap, and the grid's own-pad exemption opened the overlap to the pin's net, which the exact check then refused. Pads are now the convex hull of their corners, the exact tree checks a rotated pad against that outline, and the grid blocks cells against the same outline. A via reused by a second connection of its net left that connection with no claim on the via's footprint, so ripping the first owner freed cells around a via still on the board. Footprint cells now keep every claimant. A net class wider than the default was searched as a default trace: its spread was empty below half a cell, halos were circular while the exact check compares boxes, and a rip-up route only counted what its centre crossed. The spread now covers the extra width in whole cells, halos are square, and rip-up victims include what the spread crosses. bench/diagnose.py now routes with net-class widths and hole spacing, as the CLI does.
This commit is contained in:
+9
-2
@@ -32,8 +32,10 @@ from freeroute.route.exact_router import route_board_exact
|
||||
from freeroute.route.grid_router import GridRouter, _ends_of
|
||||
from freeroute.route.pipeline import (
|
||||
_mm_to_board,
|
||||
_net_widths_board,
|
||||
_rule_clearance_dsn,
|
||||
_rule_width_dsn,
|
||||
_via_drill_board,
|
||||
_via_half_board,
|
||||
)
|
||||
|
||||
@@ -183,7 +185,7 @@ def _flood(router: GridRouter, pin, net_no: int, conns) -> tuple[int, Counter]:
|
||||
|
||||
def diagnose(
|
||||
dsn_text: str, edge_clearance_mm: float | None, resolution: int = 2, shove: bool = False,
|
||||
access_cost: float = 0.0,
|
||||
access_cost: float = 0.0, hole_to_hole_mm: float = 0.25,
|
||||
) -> dict:
|
||||
dsn = parse_dsn(dsn_text)
|
||||
names = {i + 1: n.name for i, n in enumerate(dsn.nets)}
|
||||
@@ -199,6 +201,10 @@ def diagnose(
|
||||
resolution=resolution,
|
||||
shove=shove,
|
||||
access_cost=access_cost,
|
||||
# the product's configuration: net-class widths and hole spacing
|
||||
net_widths=_net_widths_board(dsn, scale),
|
||||
via_drill=_via_drill_board(dsn, scale),
|
||||
hole_to_hole=_mm_to_board(dsn, scale, hole_to_hole_mm) or 0,
|
||||
)
|
||||
routed = seen["router"]
|
||||
best = routed._diag_best
|
||||
@@ -270,11 +276,12 @@ def main(argv: list[str] | None = None) -> int:
|
||||
ap.add_argument("--grid-resolution", type=int, default=2, metavar="K")
|
||||
ap.add_argument("--shove", action="store_true", help="as mckicad routes")
|
||||
ap.add_argument("--access-cost", type=float, default=0.0)
|
||||
ap.add_argument("--hole-to-hole", type=float, default=0.25, metavar="MM")
|
||||
ap.add_argument("--json", type=Path, help="also write the full table here")
|
||||
args = ap.parse_args(argv)
|
||||
|
||||
report = diagnose(args.dsn.read_text(), args.edge_clearance, args.grid_resolution, args.shove,
|
||||
args.access_cost)
|
||||
args.access_cost, args.hole_to_hole)
|
||||
for row in report["failures"]:
|
||||
extra = ""
|
||||
for w in row.get("walled", []):
|
||||
|
||||
Reference in New Issue
Block a user