Keepout exits and rule areas
A route may not leave a cell inside a wire keepout as a wire, nor reach a pin there by one: it changes layer instead, and the via goes in the pad. A pin whose every stub enters a keepout is reached by a via only. A structure keepout named rule_area... (mckicad names KiCad rule areas so) is checked for overlap only, as KiCad's DRC does, with the free ends of each wire tested for their round caps.
This commit is contained in:
@@ -254,3 +254,37 @@ def test_via_size_comes_from_the_via_padstack():
|
||||
from freeroute.route.pipeline import _via_half_board
|
||||
|
||||
assert _via_half_board(parse_dsn(_PAD_DSN), 10) == 3000 # 0.6 mm via, board units
|
||||
|
||||
|
||||
# --- rule areas: overlap only ------------------------------------------------
|
||||
|
||||
_CHANNEL_DSN = """(pcb channel.dsn
|
||||
(parser (string_quote ")) (resolution um 10) (unit um)
|
||||
(structure
|
||||
(layer F.Cu (type signal)) (layer B.Cu (type signal))
|
||||
(boundary (path pcb 0 0 0 40000 0 40000 -30000 0 -30000 0 0))
|
||||
(keepout "{name}top" (polygon signal 0 18000 0 22000 0 22000 -14750 18000 -14750))
|
||||
(keepout "{name}bottom" (polygon signal 0 18000 -15250 22000 -15250 22000 -30000 18000 -30000))
|
||||
(rule (width 250) (clearance 150)))
|
||||
(placement (component P (place P1 5000 -15000 front 0) (place P2 35000 -15000 front 0)))
|
||||
(library (image P (pin pad 1 0 0)) (padstack pad (shape (circle F.Cu 600)) (attach off)))
|
||||
(network (net N (pins P1-1 P2-1))))"""
|
||||
|
||||
|
||||
def test_a_keepout_named_rule_area_takes_no_clearance():
|
||||
named = _areas(_CHANNEL_DSN.format(name="rule_area_"))
|
||||
plain = _areas(_CHANNEL_DSN.format(name=""))
|
||||
assert named and not any(a.clearance for a in named)
|
||||
assert plain and all(a.clearance for a in plain)
|
||||
|
||||
|
||||
def _route_channel(name):
|
||||
from freeroute.route.pipeline import build_exact_routing_result
|
||||
|
||||
return build_exact_routing_result(parse_dsn(_CHANNEL_DSN.format(name=name)), resolution=2)
|
||||
|
||||
|
||||
def test_a_trace_may_run_beside_a_rule_area_closer_than_clearance():
|
||||
# the 0.5 mm channel fits a 0.25 mm trace, but not with 0.15 mm each side
|
||||
assert _route_channel("rule_area_").unrouted == []
|
||||
assert _route_channel("").unrouted != []
|
||||
|
||||
@@ -62,3 +62,37 @@ def test_has_violation_ignores_static_pad_pairs():
|
||||
# a routed trace of net 3 within clearance of pad net 1 -> violation
|
||||
tree.insert(shape(2, 3, 0, IntBox(11, 0, 20, 10), routed=True))
|
||||
assert tree.has_violation(clearance=20) is not None
|
||||
|
||||
|
||||
def test_a_rule_area_conflicts_only_on_overlap():
|
||||
tree = ShapeSearchTree()
|
||||
tree.insert(TreeShape(1, -1, frozenset({0}), IntBox(100, 0, 200, 100), clearance=False))
|
||||
near = IntBox(0, 0, 95, 100) # 5 short of the area, well inside clearance 50
|
||||
over = IntBox(0, 0, 105, 100)
|
||||
assert not tree.clearance_conflict(near, 7, 0, 50)
|
||||
assert tree.clearance_conflict(over, 7, 0, 50)
|
||||
|
||||
|
||||
def test_an_ordinary_keepout_still_needs_clearance():
|
||||
tree = ShapeSearchTree()
|
||||
tree.insert(TreeShape(1, -1, frozenset({0}), IntBox(100, 0, 200, 100)))
|
||||
assert tree.clearance_conflict(IntBox(0, 0, 95, 100), 7, 0, 50)
|
||||
|
||||
|
||||
def test_the_routed_board_check_treats_a_rule_area_the_same_way():
|
||||
tree = ShapeSearchTree()
|
||||
tree.insert(TreeShape(1, -1, frozenset({0}), IntBox(100, 0, 200, 100), clearance=False))
|
||||
tree.insert(TreeShape(2, 7, frozenset({0}), IntBox(0, 0, 95, 100), routed=True))
|
||||
assert tree.has_violation(50) is None
|
||||
tree.insert(TreeShape(3, 7, frozenset({0}), IntBox(150, 0, 160, 100), routed=True))
|
||||
assert tree.has_violation(50) is not None
|
||||
|
||||
|
||||
|
||||
def test_rule_area_overlap_sees_only_rule_areas():
|
||||
tree = ShapeSearchTree()
|
||||
tree.insert(TreeShape(1, -1, frozenset({0}), IntBox(100, 0, 200, 100), clearance=False))
|
||||
tree.insert(TreeShape(2, -1, frozenset({0}), IntBox(300, 0, 400, 100)))
|
||||
assert tree.rule_area_overlap(IntBox(90, 40, 110, 60), 0)
|
||||
assert not tree.rule_area_overlap(IntBox(290, 40, 310, 60), 0)
|
||||
assert not tree.rule_area_overlap(IntBox(90, 40, 110, 60), 1)
|
||||
|
||||
Reference in New Issue
Block a user