Honour KiCad's keepouts: keyhole rings, wire_keepout, per-tile rasterizing
On the TerraHawk rc4 power stage every engine misread the board's rule areas: - A no-track ring along the board edge arrives as one keyhole polygon, and keepout polygons were wrapped in a single convex tile, so the ring became the whole board. Split keepout polygons into convex pieces instead. - The grid engine rasterized an area by its overall bounding box, which for that ring is again the whole board; it routed nothing. Rasterize per tile. - "Keep router off" rule areas arrive as wire_keepout, which the reader did not know, so tracks ran through them (172 DRC items_not_allowed). Read it at board and image level. For now it blocks vias too, which is stricter than KiCad and cannot create a violation. - place_keepout only restricts part placement; stop treating it as copper. The oracle now runs the JAR headless; it was opening FreeRouting's GUI on the desktop for every oracle test.
This commit is contained in:
@@ -27,6 +27,7 @@ import math
|
||||
from freeroute.dsn.model import DsnBoard
|
||||
from freeroute.dsn.shapes import Circle, Path, Polygon, Rectangle, Shape
|
||||
from freeroute.geometry import FloatPoint, IntBox, IntPoint, IntVector, Simplex
|
||||
from freeroute.geometry.polygon_shape import PolygonShape
|
||||
|
||||
from .board import BasicBoard
|
||||
from .clearance import ClearanceMatrix
|
||||
@@ -219,11 +220,14 @@ def _insert_keepouts(dsn: DsnBoard, board: BasicBoard, transform: CoordinateTran
|
||||
signal_layers = [i for i, layer in enumerate(dsn.layers) if layer.is_signal]
|
||||
|
||||
for keepout in dsn.keepouts:
|
||||
# A place_keepout only restricts where parts go, not copper.
|
||||
if keepout.kind == "place_keepout":
|
||||
continue
|
||||
area = keepout.area
|
||||
if area is None or area.border is None:
|
||||
continue
|
||||
tile = _area_border_tile(area.border, transform)
|
||||
if tile is None:
|
||||
tiles = _area_border_tiles(area.border, transform)
|
||||
if not tiles:
|
||||
continue
|
||||
border_layer = area.border.layer
|
||||
if border_layer in ("signal", "pcb"):
|
||||
@@ -237,11 +241,36 @@ def _insert_keepouts(dsn: DsnBoard, board: BasicBoard, transform: CoordinateTran
|
||||
ObstacleArea(
|
||||
name=keepout.area.name,
|
||||
layer=layer_index,
|
||||
tiles=[tile],
|
||||
tiles=tiles,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _area_border_tiles(shape: Shape, transform: CoordinateTransform) -> list:
|
||||
"""Convex board tiles covering a keepout border shape.
|
||||
|
||||
Polygons are split into convex pieces rather than wrapped in one convex
|
||||
tile: KiCad exports a rule area with a hole (a no-track ring along the
|
||||
board edge, say) as a single keyhole polygon, and its convex hull is the
|
||||
whole board.
|
||||
"""
|
||||
if isinstance(shape, (Polygon, Path)):
|
||||
coords = shape.coords
|
||||
pts = [
|
||||
IntPoint(
|
||||
round(transform.dsn_to_board(coords[i])),
|
||||
round(transform.dsn_to_board(coords[i + 1])),
|
||||
)
|
||||
for i in range(0, len(coords) - 1, 2)
|
||||
]
|
||||
if len(pts) >= 3:
|
||||
pieces = [t for t in PolygonShape(pts).split_to_convex() if not t.is_empty()]
|
||||
if pieces:
|
||||
return pieces
|
||||
tile = _area_border_tile(shape, transform)
|
||||
return [tile] if tile is not None else []
|
||||
|
||||
|
||||
def _area_border_tile(shape: Shape, transform: CoordinateTransform):
|
||||
"""Convert an absolute-coordinate keepout border shape to one board tile."""
|
||||
if isinstance(shape, Rectangle):
|
||||
|
||||
Reference in New Issue
Block a user