Skip to content

Commit 2e25a3d

Browse files
committed
Add option to fine-tweak V-cuts
1 parent a0c1e44 commit 2e25a3d

File tree

5 files changed

+91
-44
lines changed

5 files changed

+91
-44
lines changed

docs/panelization/cli.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,15 @@ Use mousebites to
339339
- `offset` - specify the offset, positive offset puts the cuts into the board,
340340
negative puts the cuts into the tabs
341341
- `layer` - specify the layer to render V-cuts on.
342+
- `linewidth` - specify linewidth
343+
- `endprolongation` - prolongation of the cut line from the board line on the
344+
side without text.
345+
- `textprolongation` - the same as above, just on the text side
346+
- `textoffset` - offset of the text from the cut line
347+
- `template` - a string template for text to render. Can contain variables
348+
listed below, e.g., `V-CUT {pos_mm}`.
349+
- `pos_mm`, `pos_inch` – position of the V-cut from the panel origin
350+
- `pos_inv_mm`, `pos_inv_inch` – inverted position of the V-cut from the panel origin
342351

343352
#### Layer
344353

@@ -349,6 +358,7 @@ design.
349358
- `layer` - specify the layer to render the cuts on.
350359
- `prolong` - distance for tangential prolongation of the cuts. It has the same
351360
meaning as mousebites.
361+
- `linewidth` - width of line to render
352362

353363
#### Plugin
354364

kikit/panelize.py

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import re
2424
import fnmatch
2525
from collections import OrderedDict
26+
from dataclasses import dataclass
2627

2728
from kikit import substrate
2829
from kikit import units
@@ -33,7 +34,7 @@
3334
from kikit.sexpr import isElement, parseSexprF, SExpr, Atom, findNode, parseSexprListF
3435
from kikit.annotations import AnnotationReader, TabAnnotation
3536
from kikit.drc import DrcExclusion, readBoardDrcExclusions, serializeExclusion
36-
from kikit.units import mm, deg
37+
from kikit.units import mm, deg, inch
3738
from kikit.pcbnew_utils import increaseZonePriorities
3839

3940
class PanelError(RuntimeError):
@@ -454,6 +455,19 @@ def bakeTextVars(board: pcbnew.BOARD) -> None:
454455
else:
455456
drawing.SetText(drawing.GetShownText())
456457

458+
@dataclass
459+
class VCutSettings:
460+
lineWidth: KiLength = fromMm(0.4)
461+
textThickness: KiLength = fromMm(0.4)
462+
textSize: KiLength = fromMm(2)
463+
endProlongation: KiLength = fromMm(3)
464+
textProlongation: KiLength = fromMm(3)
465+
layer: Layer = Layer.Cmts_User
466+
textTemplate: str = "V-CUT {pos_mm}"
467+
textOffset: KiLength = fromMm(3)
468+
clearance: KiLength = 0
469+
470+
457471
class Panel:
458472
"""
459473
Basic interface for panel building. Instance of this class represents a
@@ -482,8 +496,7 @@ def __init__(self, panelFilename):
482496
self.backboneLines = []
483497
self.hVCuts = set() # Keep V-cuts as numbers and append them just before saving
484498
self.vVCuts = set() # to make them truly span the whole panel
485-
self.vCutLayer = Layer.Cmts_User
486-
self.vCutClearance = 0
499+
self.vCutSettings = VCutSettings()
487500
self.copperLayerCount = None
488501
self.renderedMousebiteCounter = 0
489502
self.zonesToRefill = pcbnew.ZONES()
@@ -591,7 +604,7 @@ def save(self, reconstructArcs: bool=False, refillAllZones: bool=False,
591604
fillBoard.Remove(edge)
592605
for edge in panelEdges:
593606
fillBoard.Add(edge)
594-
if self.vCutLayer == Layer.Edge_Cuts:
607+
if self.vCutSettings.layer == Layer.Edge_Cuts:
595608
vcuts = self._renderVCutH() + self._renderVCutV()
596609
for cut, _ in vcuts:
597610
fillBoard.Add(cut)
@@ -1170,81 +1183,75 @@ def addVCutV(self, pos):
11701183
"""
11711184
self.vVCuts.add(pos)
11721185

1173-
def setVCutLayer(self, layer):
1174-
"""
1175-
Set layer on which the V-Cuts will be rendered
1176-
"""
1177-
self.vCutLayer = layer
1178-
1179-
def setVCutClearance(self, clearance):
1180-
"""
1181-
Set V-cut clearance
1182-
"""
1183-
self.vCutClearance = clearance
1184-
1185-
def _setVCutSegmentStyle(self, segment, layer):
1186+
def _setVCutSegmentStyle(self, segment):
11861187
segment.SetShape(STROKE_T.S_SEGMENT)
1187-
segment.SetLayer(layer)
1188-
segment.SetWidth(int(0.4 * mm))
1189-
1190-
def _setVCutLabelStyle(self, label, layer):
1191-
label.SetText("V-CUT")
1192-
label.SetLayer(layer)
1193-
label.SetTextThickness(int(0.4 * mm))
1194-
label.SetTextSize(toKiCADPoint((2 * mm, 2 * mm)))
1188+
segment.SetLayer(self.vCutSettings.layer)
1189+
segment.SetWidth(self.vCutSettings.lineWidth)
1190+
1191+
def _setVCutLabelStyle(self, label, origin, position):
1192+
variables = {
1193+
"pos_mm": f"{(position - origin) / mm:.2f} mm",
1194+
"pos_inv_mm": f"{(origin - position) / mm:.2f} mm",
1195+
"pos_inch": f"{(position - origin) / inch:.3f} mm",
1196+
"pos_inv_inch": f"{(origin - position) / inch:.3f} mm",
1197+
}
1198+
label.SetText(self.vCutSettings.textTemplate.format(**variables))
1199+
label.SetLayer(self.vCutSettings.layer)
1200+
label.SetTextThickness(self.vCutSettings.textThickness)
1201+
label.SetTextSize(toKiCADPoint((self.vCutSettings.textSize, self.vCutSettings.textSize)))
11951202
label.SetHorizJustify(EDA_TEXT_HJUSTIFY_T.GR_TEXT_HJUSTIFY_LEFT)
11961203

11971204
def _renderVCutV(self):
11981205
""" return list of PCB_SHAPE V-Cuts """
11991206
bBox = self.boardSubstrate.boundingBox()
1200-
minY, maxY = bBox.GetY() - fromMm(3), bBox.GetY() + bBox.GetHeight() + fromMm(3)
1207+
minY, maxY = bBox.GetY() - self.vCutSettings.textProlongation, bBox.GetY() + bBox.GetHeight() + self.vCutSettings.endProlongation
12011208
segments = []
12021209
for cut in self.vVCuts:
12031210
segment = pcbnew.PCB_SHAPE()
1204-
self._setVCutSegmentStyle(segment, self.vCutLayer)
1211+
self._setVCutSegmentStyle(segment)
12051212
segment.SetStart(toKiCADPoint((cut, minY)))
12061213
segment.SetEnd(toKiCADPoint((cut, maxY)))
12071214

12081215
keepout = None
1209-
if self.vCutClearance != 0:
1216+
if self.vCutSettings.clearance != 0:
12101217
keepout = shapely.geometry.box(
1211-
cut - self.vCutClearance / 2,
1218+
cut - self.vCutSettings.clearance / 2,
12121219
bBox.GetY(),
1213-
cut + self.vCutClearance / 2,
1220+
cut + self.vCutSettings.clearance / 2,
12141221
bBox.GetY() + bBox.GetHeight())
12151222
segments.append((segment, keepout))
12161223

12171224
label = pcbnew.PCB_TEXT(segment)
1218-
self._setVCutLabelStyle(label, self.vCutLayer)
1219-
label.SetPosition(toKiCADPoint((cut, minY - fromMm(3))))
1225+
self._setVCutLabelStyle(label, self.getAuxiliaryOrigin()[0], cut)
1226+
label.SetPosition(toKiCADPoint((cut, minY - self.vCutSettings.textOffset)))
12201227
label.SetTextAngle(fromDegrees(90))
12211228
segments.append((label, None))
12221229
return segments
12231230

12241231
def _renderVCutH(self):
12251232
""" return list of PCB_SHAPE V-Cuts """
12261233
bBox = self.boardSubstrate.boundingBox()
1227-
minX, maxX = bBox.GetX() - fromMm(3), bBox.GetX() + bBox.GetWidth() + fromMm(3)
1234+
minX, maxX = bBox.GetX() - self.vCutSettings.endProlongation, bBox.GetX() + bBox.GetWidth() + self.vCutSettings.textProlongation
12281235
segments = []
12291236
for cut in self.hVCuts:
12301237
segment = pcbnew.PCB_SHAPE()
1231-
self._setVCutSegmentStyle(segment, self.vCutLayer)
1238+
self._setVCutSegmentStyle(segment)
12321239
segment.SetStart(toKiCADPoint((minX, cut)))
12331240
segment.SetEnd(toKiCADPoint((maxX, cut)))
12341241

12351242
keepout = None
1236-
if self.vCutClearance != 0:
1243+
if self.vCutSettings.clearance != 0:
12371244
keepout = shapely.geometry.box(
12381245
bBox.GetX(),
1239-
cut - self.vCutClearance / 2,
1246+
cut - self.vCutSettings.clearance / 2,
12401247
bBox.GetX() + bBox.GetWidth(),
1241-
cut + self.vCutClearance / 2)
1248+
cut + self.vCutSettings.clearance / 2)
12421249
segments.append((segment, keepout))
12431250

12441251

12451252
label = pcbnew.PCB_TEXT(segment)
1246-
self._setVCutLabelStyle(label, self.vCutLayer)
1247-
label.SetPosition(toKiCADPoint((maxX + fromMm(3), cut)))
1253+
self._setVCutLabelStyle(label, self.getAuxiliaryOrigin()[1], cut)
1254+
label.SetPosition(toKiCADPoint((maxX + self.vCutSettings.textOffset, cut)))
12481255
segments.append((label, None))
12491256
return segments
12501257

@@ -1549,7 +1556,7 @@ def makeMouseBites(self, cuts, diameter, spacing, offset=fromMm(0.25),
15491556
ref=f"KiKit_MB_{self.renderedMousebiteCounter}_{i+1}",
15501557
excludedFromPos=True)
15511558

1552-
def makeCutsToLayer(self, cuts, layer=Layer.Cmts_User, prolongation=fromMm(0)):
1559+
def makeCutsToLayer(self, cuts, layer=Layer.Cmts_User, prolongation=fromMm(0), width=fromMm(0.3)):
15531560
"""
15541561
Take a list of cuts and render them as lines on given layer. The cuts
15551562
can be prolonged just like with mousebites.
@@ -1566,7 +1573,7 @@ def makeCutsToLayer(self, cuts, layer=Layer.Cmts_User, prolongation=fromMm(0)):
15661573
segment.SetLayer(layer)
15671574
segment.SetStart(toKiCADPoint(a))
15681575
segment.SetEnd(toKiCADPoint(b))
1569-
segment.SetWidth(fromMm(0.3))
1576+
segment.SetWidth(width)
15701577
self.board.Add(segment)
15711578

15721579
def addNPTHole(self, position: VECTOR2I, diameter: KiLength,

kikit/panelize_ui_impl.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -367,14 +367,16 @@ def makeCuts(properties, panel, cuts, ignoreOffset):
367367
return
368368
if type == "vcuts":
369369
panel.makeVCuts(cuts, properties["cutcurves"], offset)
370-
panel.setVCutLayer(properties["layer"])
371-
panel.setVCutClearance(properties["clearance"])
370+
panel.vCutSettings.layer = properties["layer"]
371+
panel.vCutSettings.clerance = properties["clearance"]
372+
panel.vCutSettings.lineThickness = properties["linewidth"]
372373
elif type == "mousebites":
373374
panel.makeMouseBites(cuts, properties["drill"],
374375
properties["spacing"], offset, properties["prolong"])
375376
elif type == "layer":
376377
panel.makeCutsToLayer(cuts,
377-
layer=properties["layer"], prolongation=properties["prolong"])
378+
layer=properties["layer"], prolongation=properties["prolong"],
379+
width=properties["linewidth"])
378380
else:
379381
raise PresetError(f"Unknown type '{type}' of cuts specification.")
380382
except KeyError as e:

kikit/panelize_ui_sections.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,27 @@ def ppTabs(section):
439439
"cutcurves": SBool(
440440
typeIn(["vcuts", "plugin"]),
441441
"Approximate curves with straight cut"),
442+
"linewidth": SLength(
443+
typeIn(["vcuts", "layer", "plugin"]),
444+
"Line width to plot cuts with"),
445+
"textthickness": SLength(
446+
typeIn(["vcuts", "plugin"]),
447+
"Text thickness for width"),
448+
"textsize": SLength(
449+
typeIn(["vcuts", "plugin"]),
450+
"Text size for vcuts"),
451+
"endprolongation": SLength(
452+
typeIn(["vcuts", "plugin"]),
453+
"Prolongation on the end of V-CUT without text"),
454+
"textprolongation": SLength(
455+
typeIn(["vcuts", "plugin"]),
456+
"Prolongation of the text size of V-CUT"),
457+
"textoffset": SLength(
458+
typeIn(["vcuts", "plugin"]),
459+
"Text offset from the V-CUT"),
460+
"template": SStr(
461+
typeIn(["vcuts", "plugin"]),
462+
"Text template for the V-CUT"),
442463
"layer": SLayer(
443464
typeIn(["vcuts", "layer", "plugin"]),
444465
"Specify layer for the drawings"),

kikit/resources/panelizePresets/default.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@
5050
"type": "none",
5151
"clearance": "0mm",
5252
"cutcurves": false,
53+
"linewidth": "0.3mm",
54+
"textthickness": "0.3mm",
55+
"textsize": "2mm",
56+
"endprolongation": "3mm",
57+
"textprolongation": "3mm",
58+
"textoffset": "3mm",
59+
"template": "V-CUT",
5360
"layer": "Cmts.User",
5461
"offset": "0mm",
5562
"prolong": "0mm",

0 commit comments

Comments
 (0)