2323import re
2424import fnmatch
2525from collections import OrderedDict
26+ from dataclasses import dataclass
2627
2728from kikit import substrate
2829from kikit import units
3334from kikit .sexpr import isElement , parseSexprF , SExpr , Atom , findNode , parseSexprListF
3435from kikit .annotations import AnnotationReader , TabAnnotation
3536from kikit .drc import DrcExclusion , readBoardDrcExclusions , serializeExclusion
36- from kikit .units import mm , deg
37+ from kikit .units import mm , deg , inch
3738from kikit .pcbnew_utils import increaseZonePriorities
3839
3940class 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+
457471class 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 ,
0 commit comments