Route with copper zones, and let vias into no-tracks areas
freeroute ignored the DSN's planes (KiCad's zones), so it never knew that pads in a pour are joined by it. On the rc4 power stage those pads sit inside "keep router off" areas as well, and every connection to them was dropped without a word. - Read (plane <net> <shape>) and put each zone on the board as a ConductionArea of its net. Zones are not obstacles: KiCad refills them around other nets' copper. - The grid groups each net's pads and zone pieces that copper already joins (a pad in a zone, two zones sharing a pad) and routes only between groups. A connection may end on a zone by a via inside its copper, or by a track where tracks are allowed. - wire_keepout now blocks traces only, as KiCad's "no tracks" rule area does; via_keepout only vias; keepout both, in the grid and in the exact verifier. rc4 power stage, exact engine, resolution 2: 2 unconnected, down from 8 (FreeRouting JAR: 12), no DRC errors.
This commit is contained in:
@@ -94,3 +94,47 @@ def test_heuristic_weight_bounds_route_length():
|
||||
shortest = length(1.0)
|
||||
assert shortest > 0
|
||||
assert length(2.0) <= 2.0 * shortest
|
||||
|
||||
|
||||
# --- copper zones (DSN planes) -----------------------------------------------
|
||||
# rc4 power stage: pads inside "keep router off" pours connect through the pour,
|
||||
# and freeroute, not knowing zones, dropped every such connection.
|
||||
|
||||
_ZONE = "(plane N (polygon F.Cu 0 4000 -4000 10000 -4000 10000 -10000 4000 -10000 4000 -4000))"
|
||||
_NO_TRACKS = "(wire_keepout \"pour\" (polygon F.Cu 0 4000 -4000 10000 -4000 10000 -10000 4000 -10000))"
|
||||
|
||||
|
||||
def _zone_board():
|
||||
places = "(place P1 5500 -7000 front 0) (place P2 8500 -7000 front 0) (place P3 16000 -16000 front 0)"
|
||||
return parse_dsn(_dsn(f"(component P {places})", "(net N (pins P1-1 P2-1 P3-1))", _ZONE + " " + _NO_TRACKS))
|
||||
|
||||
|
||||
def test_planes_are_read_and_are_not_obstacles():
|
||||
dsn = _zone_board()
|
||||
assert [(p.net, p.shape.layer) for p in dsn.planes] == [("N", "F.Cu")]
|
||||
board = build_board(dsn)
|
||||
assert len(board.get_conduction_areas()) == 1
|
||||
assert all(not a.is_obstacle() or a.name == "pour" for a in board.get_obstacle_areas())
|
||||
|
||||
|
||||
def test_pads_in_one_zone_need_no_route_between_them():
|
||||
from freeroute.route.grid_router import _connected_groups
|
||||
|
||||
board = build_board(_zone_board())
|
||||
pins = sorted(board.get_pins(), key=lambda p: p.component_ref)
|
||||
groups = _connected_groups(pins, board.get_conduction_areas())
|
||||
assert [sorted(p.component_ref for p in g[0]) for g in groups] == [["P1", "P2"], ["P3"]]
|
||||
|
||||
|
||||
def test_a_pad_reaches_a_zone_under_a_no_tracks_area_by_a_via():
|
||||
dsn = _zone_board()
|
||||
result, scale, names = route_dsn_board_exact(dsn)
|
||||
net = next(iter(result.routed_net_numbers))
|
||||
assert result.result.vias.get(net) # it had to drop into the zone
|
||||
board = build_board(dsn)
|
||||
pour = next(a for a in board.get_obstacle_areas() if a.name == "pour")
|
||||
f_cu = names.index("F.Cu")
|
||||
for layer, pts in result.result.wires[net]:
|
||||
if layer == f_cu: # no track runs inside the no-tracks area
|
||||
assert not any(t.contains(p) and not t.bounding_box().is_empty()
|
||||
for t in pour.tiles for p in pts[1:-1])
|
||||
|
||||
Reference in New Issue
Block a user