Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions kikit/panelize.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,11 +413,15 @@ def polygonToZone(polygon, board):
zone.Outline().AddHole(linestringToKicad(boundary))
return zone

def cropZoneByPolygon(zone: pcbnew.ZONE, polygon: Polygon) -> None:
def cropZoneByPolygon(zone: pcbnew.ZONE, polygon: Polygon) -> List[pcbnew.ZONE]:
"""
Modify the zone so it is cropped by the polygon. If the zone is split into
multiple zones, return all of them. Handles holes in both the original zone
and the cropping polygon.
Crop zone by polygon. Returns the list of resulting zones.

If the intersection is a single polygon, modifies the zone in place and
returns [zone]. If the intersection produces multiple disconnected pieces
(MultiPolygon), returns a separate zone per piece — each is a duplicate of
the input zone with one piece's outline. Handles holes in both the original
zone and the cropping polygon.
"""
zoneGeom = substrate.shapePolyToShapely(zone.Outline())
if not zoneGeom.is_valid:
Expand All @@ -427,14 +431,29 @@ def cropZoneByPolygon(zone: pcbnew.ZONE, polygon: Polygon) -> None:
raise PanelError("Zone geometry is invalid")
intersection = zoneGeom.intersection(polygon)

zone.Outline().RemoveAllContours()
geoms = [intersection] if isinstance(intersection, Polygon) else intersection.geoms
geoms = ([intersection] if isinstance(intersection, Polygon)
else [g for g in intersection.geoms if hasattr(g, "exterior")])

if len(geoms) <= 1:
# Single piece (or empty) — modify zone outline in place.
zone.Outline().RemoveAllContours()
if geoms:
zone.Outline().AddOutline(linestringToKicad(geoms[0].exterior))
for hole in geoms[0].interiors:
zone.Outline().AddHole(linestringToKicad(hole))
return [zone]

# Multiple disconnected pieces — return one zone per piece so that each
# has a single outline with its centroid inside the board boundary.
result = []
for geom in geoms:
if not hasattr(geom, "exterior"):
continue
zone.Outline().AddOutline(linestringToKicad(geom.exterior))
piece = zone.Duplicate()
piece.Outline().RemoveAllContours()
piece.Outline().AddOutline(linestringToKicad(geom.exterior))
for hole in geom.interiors:
zone.Outline().AddHole(linestringToKicad(hole))
piece.Outline().AddHole(linestringToKicad(hole))
result.append(piece)
return result

def buildTabs(panel: "Panel", substrate: Substrate,
partitionLines: Union[GeometryCollection, LineString],
Expand Down Expand Up @@ -1241,8 +1260,8 @@ def f(point):
for zone in zones:
zone.Rotate(originPoint, rotationAngle)
zone.Move(translation)
cropZoneByPolygon(zone, s.exterior())
appendItem(self.board, zone, yieldMapping)
for croppedZone in cropZoneByPolygon(zone, s.exterior()):
appendItem(self.board, croppedZone, yieldMapping)

try:
exclusions = readBoardDrcExclusions(board)
Expand Down