Querying pcbnew to generate a basic svg file

In a previous post, I gave some basic query capabilies in pcbnew. In this post, I’ll use that to generate a simple svg file.
The result looks like this:

Not the most interesting layout and a bunch of detail is missing, but I was happy to get this far. The code is hopefully self-explanatory. After the last post, I don’t really know what I can add.
The code can be found in my github

Preliminaries

I need to get each of pcbnew’s layer colors. Some of the color names are modified to match svr colors. The real answer is to get the rgb values from colorrefs, but those aren’t exposed in python today
Edit Nov 15, 2017 RGB values are now available in the form of the COLOR4D structure.
[code]
colors = board.Colors()
c4 = colors.GetLayerColor(track.GetLayer())
r = int(round(c4.r*255)
g = int(round(c4.g*255)),
b = int(round(c4.b*255))
[/code]
The colornames map below won’t work anymore.
End edit
colornames = {
 pcbnew.BLACK: 'BLACK',
 pcbnew.DARKDARKGRAY: 'DARKSLATEGRAY', # 'DARKDARKGRAY',
 pcbnew.DARKGRAY: 'DARKGRAY',
 pcbnew.LIGHTGRAY: 'LIGHTGRAY',
 pcbnew.WHITE: 'WHITE',
 pcbnew.LIGHTYELLOW: 'LIGHTYELLOW',
 pcbnew.DARKBLUE: 'DARKBLUE',
 pcbnew.DARKGREEN: 'DARKGREEN',
 pcbnew.DARKCYAN: 'DARKCYAN',
 pcbnew.DARKRED: 'DARKRED',
 pcbnew.DARKMAGENTA: 'DARKMAGENTA',
 pcbnew.DARKBROWN: 'MAROON', # 'DARKBROWN',
 pcbnew.BLUE: 'BLUE',
 pcbnew.GREEN: 'GREEN',
 pcbnew.CYAN: 'CYAN',
 pcbnew.RED: 'RED',
 pcbnew.MAGENTA: 'MAGENTA',
 pcbnew.BROWN: 'BROWN',
 pcbnew.LIGHTBLUE: 'LIGHTBLUE',
 pcbnew.LIGHTGREEN: 'LIGHTGREEN',
 pcbnew.LIGHTCYAN: 'LIGHTCYAN',
 pcbnew.LIGHTRED: 'INDIANRED', # 'LIGHTRED',
 pcbnew.LIGHTMAGENTA: 'LIGHTPINK', # 'LIGHTMAGENTA',
 pcbnew.YELLOW: 'YELLOW',
 pcbnew.PUREBLUE: 'MEDIUMBLUE', # 'PUREBLUE',
 pcbnew.PUREGREEN: 'LAWNGREEN', # 'PUREGREEN',
 pcbnew.PURECYAN: 'DARKTURQUOISE', # 'PURECYAN',
 pcbnew.PURERED: 'FIREBRICK', # 'PURERED',
 pcbnew.PUREMAGENTA: 'DARKORCHID', # PUREMAGENTA',
 pcbnew.PUREYELLOW: 'KHAKI', # PUREYELLOW'
}
padshapes = {
 pcbnew.PAD_SHAPE_CIRCLE: "PAD_SHAPE_CIRCLE",
 pcbnew.PAD_SHAPE_OVAL: "PAD_SHAPE_OVAL",
 pcbnew.PAD_SHAPE_RECT: "PAD_SHAPE_RECT",
 pcbnew.PAD_SHAPE_TRAPEZOID: "PAD_SHAPE_TRAPEZOID"
}
# new in the most recent kicad code
if hasattr(pcbnew, 'PAD_SHAPE_ROUNDRECT'):
 padshapes[pcbnew.PAD_SHAPE_ROUNDRECT] = "PAD_SHAPE_ROUNDRECT",
Now we can get to it. Need to get the board, get the boundary coordinates, and set the scale factor
board = pcbnew.GetBoard()
boardbbox = board.ComputeBoundingBox()
boardxl = boardbbox.GetX()
boardyl = boardbbox.GetY()
boardwidth = boardbbox.GetWidth()
boardheight = boardbbox.GetHeight()
# the internal coorinate space of pcbnew is 10E-6 mm. (a millionth of a mm)
# the coordinate 121550000 corresponds to 121.550000
SCALE = 1000000.0

Writing an SVG

Here is where things happen. I’m sure if kicad include the svgwrite package or if it picks it up from my python install area. I did need to install it to python to do some experiments before doing anything in Kicad.
Edit Nov 15, 2017 
Due to kicad’s change to color management (in favor of RGB over colornames), the code below is not uptodate. Go to github for the latest working version.
End edit
import sys, os
import svgwrite
print("working in the dir " + os.getcwd())
name = "output.svg"
# A4 is approximately 21x29
dwg = svgwrite.Drawing(name, size=('21cm', '29cm'), profile='full', debug=True)
dwg.viewbox(width=boardwidth, height=boardheight, minx=boardxl, miny=boardyl)
background = dwg.add(dwg.g(id='bg', stroke='white'))
background.add(dwg.rect(insert=(boardxl, boardyl), size=(boardwidth, boardheight), fill='white'))
svglayers = {}
for colorcode, colorname in colornames.items():
 layer = dwg.add(dwg.g(id='layer_'+colorname, stroke=colorname.lower(), stroke_linecap="round"))
 svglayers[colorcode] = layer
alltracks = board.GetTracks()
for track in alltracks:
 # print("{}->{}".format(track.GetStart(), track.GetEnd()))
 # print("{},{}->{},{} width {} layer {}".format(track.GetStart().x/SCALE, track.GetStart().y/SCALE,
 # track.GetEnd().x/SCALE, track.GetEnd().y/SCALE,
 # track.GetWidth()/SCALE,
 # track.GetLayer())
 # )
 layercolor = board.GetLayerColor(track.GetLayer())
 svglayers[layercolor].add(dwg.line(start=(track.GetStart().x,
 track.GetStart().y),
 end=(track.GetEnd().x,
 track.GetEnd().y),
 stroke_width=track.GetWidth()
 ))
svgpads = dwg.add(dwg.g(id='pads', stroke='red',fill='orange'))
allpads = board.GetPads()
for pad in allpads:
 mod = pad.GetParent()
 name = pad.GetPadName()
 if (0):
 print("pad {}({}) on {}({}) at {},{} shape {} size {},{}"
 .format(name,
 pad.GetNet().GetNetname(),
 mod.GetReference(),
 mod.GetValue(),
 pad.GetPosition().x, pad.GetPosition().y,
 padshapes[pad.GetShape()],
 pad.GetSize().x, pad.GetSize().y
 ))
 if (pad.GetShape() == pcbnew.PAD_SHAPE_RECT):
 if ((pad.GetOrientationDegrees()==270) | (pad.GetOrientationDegrees()==90)):
 svgpads.add(dwg.rect(insert=(pad.GetPosition().x-pad.GetSize().x/2,
 pad.GetPosition().y-pad.GetSize().y/2),
 size=(pad.GetSize().y, pad.GetSize().x)))
 else:
 svgpads.add(dwg.rect(insert=(pad.GetPosition().x-pad.GetSize().x/2,
 pad.GetPosition().y-pad.GetSize().y/2),
 size=(pad.GetSize().x, pad.GetSize().y)))
 elif (pad.GetShape() == pcbnew.PAD_SHAPE_CIRCLE):
 svgpads.add(dwg.circle(center=(pad.GetPosition().x, pad.GetPosition().y),
 r=pad.GetSize().x))
 elif (pad.GetShape() == pcbnew.PAD_SHAPE_OVAL):
 svgpads.add(dwg.ellipse(center=(pad.GetPosition().x, pad.GetPosition().y),
 r=(pad.GetSize().x/2, pad.GetSize().y/2)))
 else:
 print("unknown pad shape {}({})".format(pad.GetShape(), padshapes[pad.GetShape()]))
dwg.save()
 
Querying pcbnew to generate a basic svg file

Leave a Reply

Your email address will not be published. Required fields are marked *