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:
@@ -50,6 +50,8 @@ class TreeShape:
|
||||
#: which copper a keepout tile stops: "all", "wires" (a wire_keepout,
|
||||
#: vias allowed) or "vias" (a via_keepout)
|
||||
blocks: str = "all"
|
||||
#: False for a rule area: copper may touch it, only overlap counts
|
||||
clearance: bool = True
|
||||
|
||||
def on_layer(self, layer: int) -> bool:
|
||||
return layer in self.layers
|
||||
@@ -129,6 +131,8 @@ class ShapeSearchTree:
|
||||
|
||||
Uses a strict 2-D overlap of the ``clearance``-expanded box, so tiles
|
||||
exactly ``clearance`` apart (touching after expansion) are allowed.
|
||||
A rule area (``clearance=False``) only has to be clear of the copper
|
||||
itself.
|
||||
"""
|
||||
expanded = box.offset(clearance)
|
||||
for shape in self.overlapping(expanded):
|
||||
@@ -136,6 +140,10 @@ class ShapeSearchTree:
|
||||
continue
|
||||
if shape.blocks != "all" and shape.blocks != kind + "s":
|
||||
continue # a wire-only keepout does not stop a via, and so on
|
||||
if not shape.clearance:
|
||||
if shape.tile.overlaps(box):
|
||||
return True
|
||||
continue
|
||||
if shape.exact is not None:
|
||||
if overlaps_2d(shape.exact, expanded):
|
||||
return True
|
||||
@@ -143,6 +151,17 @@ class ShapeSearchTree:
|
||||
return True
|
||||
return False
|
||||
|
||||
def rule_area_overlap(self, box: IntBox, layer: int, kind: str = "wire") -> bool:
|
||||
"""True if ``box`` overlaps a rule area on ``layer`` that stops ``kind``."""
|
||||
for shape in self.overlapping(box):
|
||||
if shape.clearance or not shape.on_layer(layer):
|
||||
continue
|
||||
if shape.blocks != "all" and shape.blocks != kind + "s":
|
||||
continue
|
||||
if shape.tile.overlaps(box):
|
||||
return True
|
||||
return False
|
||||
|
||||
def clearance_conflict_shape(
|
||||
self, region, net_no: int, layer: int
|
||||
) -> bool:
|
||||
@@ -178,6 +197,13 @@ class ShapeSearchTree:
|
||||
continue # static input pair (e.g. pad vs pad) — not a routing DRC
|
||||
if not (shape.layers & other.layers):
|
||||
continue
|
||||
if not (shape.clearance and other.clearance):
|
||||
# a rule area: only an overlap is a violation
|
||||
mine = shape.exact if shape.exact is not None else shape.tile
|
||||
theirs = other.exact if other.exact is not None else other.tile
|
||||
if overlaps_2d(mine, theirs):
|
||||
return shape
|
||||
continue
|
||||
if shape.exact is None and other.exact is None:
|
||||
if other.tile.overlaps(expanded): # byte-identical box path
|
||||
return shape
|
||||
|
||||
Reference in New Issue
Block a user