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

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.

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()

 

Leave a Reply

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