Two connections of a net can share a via. The grid kept one owner per via cell next to the claim list, and the search and rip-up read only that owner: a route of another net through the via ripped the first user and left the second's via under the new trace. The exact check then threw one of them out. The search and rip-up now read the claim list, and the single owner is gone. The exact check also tested a via against the outline as its square box, whose corner reaches past a 45-degree chamfer where the round via does not. The grid keeps the via's centre its radius plus the edge clearance from the outline, as KiCad measures it; the exact check now does the same. kitspace_minisumo_v3 seed 4: 4 rejected connections to 0, 11 failed to 7.
44 lines
1.6 KiB
Python
44 lines
1.6 KiB
Python
"""--rollback: a rip-up that loses connections is undone, leaving no trace."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from freeroute.board import build_board
|
|
from freeroute.dsn import parse_dsn
|
|
from freeroute.route.grid_router import GridRouter
|
|
from freeroute.route.pipeline import _rule_clearance_dsn, _rule_width_dsn, route_dsn_board
|
|
|
|
FIXTURES = Path(__file__).resolve().parent.parent / "dsn" / "fixtures"
|
|
|
|
|
|
def _routed_router(name):
|
|
dsn = parse_dsn((FIXTURES / name).read_text())
|
|
s = dsn.resolution.value
|
|
router = GridRouter(
|
|
build_board(dsn),
|
|
trace_width=round(_rule_width_dsn(dsn) * s),
|
|
clearance=round(_rule_clearance_dsn(dsn) * s),
|
|
rollback=True,
|
|
)
|
|
return router, router.route()
|
|
|
|
|
|
@pytest.mark.parametrize("name", ["ripup_needed.dsn", "true_density.dsn", "kicad_routable.dsn"])
|
|
def test_occupancy_only_holds_routed_connections(name):
|
|
router, _ = _routed_router(name)
|
|
conns = router._conns
|
|
assert all(conns[i].routed for i in router._cell_owner.values())
|
|
assert all(conns[i].routed for claims in router._via_claims.values() for i in claims)
|
|
assert all(conns[i].routed for claims in router._halo.values() for i in claims)
|
|
|
|
|
|
@pytest.mark.parametrize("name", ["ripup_needed.dsn", "true_density.dsn", "kicad_routable.dsn"])
|
|
def test_rollback_never_routes_fewer_than_plain_rip_up(name):
|
|
text = (FIXTURES / name).read_text()
|
|
plain, _, _ = route_dsn_board(parse_dsn(text), rollback=False)
|
|
undo, _, _ = route_dsn_board(parse_dsn(text))
|
|
assert undo.unrouted <= plain.unrouted
|