Skip to content

Instantly share code, notes, and snippets.

@greenarrow
Created May 22, 2013 21:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save greenarrow/5631101 to your computer and use it in GitHub Desktop.
Save greenarrow/5631101 to your computer and use it in GitHub Desktop.
Incomplete gerber to OpenSCAD (PCB)
"""
GNU licence:
RepRap Gerber Plotter is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
RepRap Gerber Plotter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details. You should have received a copy of
the GNU General Public License along with File Hunter; if not, write to
the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
import math
import time # temp testing
# Define constants
FS_ABSOLUTE = 1 # coordinate modes
FS_INCREMENTAL = 2 #
const_mmPerInch = 25.4
FLASH = 1
STROKE = 2
# Class for gerber aperture. Reads line from gerber file and extracts code, type & modifiers
class aperture:
def __init__( self, paramString, units ):
#print "GA string '" + paramString + "'"
commorPos = paramString.find( ',' )
#print paramString[ 3 : commorPos - 1 ]
if len( paramString[ 3 : commorPos - 1 ] ) > 3: #better way of doing this?
#print "aperture is macro, need tostate hereh?"
self.isMacro = True
self.code = int( paramString[ 3 : 5 ] ) #not perfect
self.macroName = paramString[ 5 : commorPos ]
print "am name '" + self.macroName + "'"
else:
self.isMacro = False
self.code = int( paramString[ 3 : commorPos - 1 ] )
self.apertureType = paramString[ commorPos - 1 : commorPos ]
modString = paramString[ commorPos + 1 : -1 ]
self.modifiers = []
lastDiv = 0
divPos = modString.find( 'X' )
while divPos > 0:
self.modifiers.append( modString[ lastDiv : divPos ] )
modString = modString[ divPos + 1 : ]
lastDiv = divPos
divPos = modString.find( 'X' )
self.modifiers.append( float(modString) )
if self.apertureType == "C":
self.radius = ( float( self.modifiers[0] ) / 2 ) # convert from diameter
if units == "IN":
self.radius = self.radius * const_mmPerInch
elif self.apertureType == "R":
self.width = float( self.modifiers[0] )
self.height = float( self.modifiers[1] )
if units == "IN":
self.width = self.width * const_mmPerInch
self.height = self.height * const_mmPerInch
elif self.apertureType == "O":
self.width = float( self.modifiers[0] )
self.height = float( self.modifiers[1] )
if units == "IN":
self.width = self.width * const_mmPerInch
self.height = self.height * const_mmPerInch
else:
print "Aperture type '" + self.apertureType + "' unsupported"
#Class for gerber aperture macro
class apertureMacro:
def __init__(self, paramString, units):
print "AM", paramString
starPos = paramString.find('*')
commorPos = paramString.find(',')
self.name = paramString[ 2:starPos ]
print "name '" + self.name + "'"
self.primitiveNumber = int( paramString[ starPos + 1:commorPos ] )
print "pn '" + str(self.primitiveNumber) + "'"
if paramString[ -1: ] == "*":
remainParamString = paramString[ commorPos + 1:-1 ]
modifiers = remainParamString.split(',')
print modifiers
if self.primitiveNumber == 5:
print "polygon"
self.exposure = int( modifiers[0] )
self.numVerticies = int( modifiers[1] )
self.centreX = int( modifiers[2] )
self.centreY = int( modifiers[3] )
self.diameter = modifiers[4] #this is strange
self.rotation = float( modifiers[5] ) #in degrees
print "self.exposure", self.exposure, "self.numVerticies", self.numVerticies, "self.centreX", self.centreX, "self.centreY", self.centreY, "self.diameter", self.diameter, "self.rotation", self.rotation
else:
# Class for a gerber flash (move and flash aperture)
class gerberFlash:
def __init__(self, x, y, aperture):
self.type = FLASH
self.x, self.y, self.aperture = x, y, aperture
#print "create flash with aperture", aperture
#self.radius = self.aperture.radius
def printFlash(self):
print "FLASH", self.x, self.y, self.aperture
# Class for a gerber trace (aperture open move)
class gerberTrace:
def __init__(self, x1, y1, x2, y2, aperture):
self.type = STROKE
self.x1, self.y1, self.x2, self.y2, self.aperture = x1, y1, x2, y2, aperture
def printTrace(self):
print "TRACE", self.x1, self.y1, self.x2, self.y2, self.aperture
class gerber:
def __init__(self, fileName):
self.fileName = fileName
self.apertures = {}
self.apertureMacros = {}
self.currentAperture = False
self.currentX, self.currentY = 0, 0
self.xCoordinateOffset, self.yCoordinateOffset = 0, 0
self.xCoordinateScale, self.yCoordinateScale = 1, 1
# All flash and trace objects stored here
self.flashes = []
self.traces = []
self.debug = False # TODO pass this in
f = open( self.fileName, 'r' )
lines = f.readlines()
# Do actual parsing of file
self.parseLines(lines)
#print self.apertures
# Parse all lines of the gerber file
def parseLines( self, lines ):
for i in range( len(lines) ):
l = lines[i]
#print "Reading line '" + l[ : -1 ] + "'"
firstChr = l[ : 1 ]
lastChr = l[ -2 : -1 ]
if firstChr == "G" and lastChr == "*":
self.cmdGcode( l[ 1 : -2 ] )
elif firstChr == "D" and lastChr == "*":
self.cmdDcode( l[ 1 : -2 ] )
elif firstChr == "%" and lastChr == "%":
self.cmdParameter( l[ 1 : -2 ] )
elif firstChr == "%":
while l[ -2:-1 ] != "%":
print "j '" + l[ -1: ] + "'"
lines[i] = lines[i][ :-1] + lines[ i + 1 ]
lines.remove( lines[ i + 1 ] )
lines.append("") # to keep for loop happy
l = lines[i]
self.cmdParameter( l[ 1:-2 ] )
elif firstChr == "X" and lastChr == "*":
self.cmdMove( l[ : -2 ] )
elif firstChr == "M" and lastChr == "*":
self.cmdMisc( l[ 1 : -2 ] )
elif l[ : -1 ] == "":
pass
else:
print "Line error! '" + l[ : -1 ] + "'"
# Handle an M code
def cmdMisc( self, mstring ):
code = int( mstring[ : 2 ] )
remains = mstring[ 2: ]
# Handle a G code
def cmdGcode( self, gstring ):
code = int( gstring[ : 2 ] )
remains = gstring[ 2: ]
if code == 0:
print "Move", "[COMMAND UNSUPORTED!]"
elif code == 1:
pass
#print "Linear interpolation (1X scale)", "[COMMAND UNSUPORTED!]" #TODO ADD
elif code == 2:
print "Clockwise circular interpolation", "[COMMAND UNSUPORTED!]"
elif code == 3:
print "Counterclockwise circular interpolation", "[COMMAND UNSUPORTED!]"
elif code == 4:
# Ignore Line
#print "Comment", remains
comment = False
elif code == 10:
print "Linear interpolation (10X scale)", "[COMMAND UNSUPORTED!]"
elif code == 11:
print "Linear interpolation (0.1X scale)", "[COMMAND UNSUPORTED!]"
elif code == 12:
print "Linear interpolation (0.01X scale)", "[COMMAND UNSUPORTED!]"
elif code == 36:
print "Turn on Polygon Area Fill", "[COMMAND UNSUPORTED!]"
elif code == 37:
print "Turn off Polygon Area Fill", "[COMMAND UNSUPORTED!]"
elif code == 54:
if remains[ : 1 ] == "D":
self.selectTool( int( remains[ 1 : ] ) )
elif code == 70:
if self.debug: print "Specify inches" # why are there two ways of setting units?
self.units = "IN"
elif code == 71:
if self.debug: print "Specify millimeters"
self.units = "MM"
elif code == 74:
print "Disable 360 deg circular interpolation (single quadrant)", "[COMMAND UNSUPORTED!]"
elif code == 75:
print "Enable 360 deg circular interpolation (multiquadrant)", "[COMMAND UNSUPORTED!]" #TODO
elif code == 90:
if self.debug: print "Absolute coordinate format"
self.FSparameter = FS_ABSOLUTE
elif code == 91:
if self.debug: print "Incremental coordinate format - This mode is not supported"
self.FSparameter = FS_INCREMENTAL
else:
print "COMMAND UNKNOWN"
#Handle D code - weird eagle inconsistancy?
def cmdDcode( self, paramString ):
if self.debug: print "Tool prepare"
self.selectTool( int(paramString) )
def selectTool( self, tool ):
#print tool
self.currentAperture = self.apertures[ tool ]
#print "select tool", tool, self.currentAperture, self.currentAperture.code
#if self.debug: print " Selecting aperture", int( remains[ 1 : ] )
#print currentAperture.modifiers[0]
# Handle a parameter
def cmdParameter( self, paramString ):
#print "Parameter", paramString, paramString[ : 2]
if paramString[ : 3 ] == "ADD" and paramString[ -1 : ] == "*":
# Add a new aperture
newAperture = aperture( paramString, self.units )
self.apertures[ newAperture.code ] = newAperture
elif paramString[ :2 ] == "AM" and paramString[ -1 : ] == "*":
newApertureMacro = apertureMacro(paramString, self.units)
self.apertureMacros[ newApertureMacro.name ] = newApertureMacro
elif paramString[ :2 ] == "AS" and paramString[ -1 : ] == "*":
print "Param AS Unsuported"
elif paramString[ :2 ] == "FS" and paramString[ -1 : ] == "*":
xInt = int( paramString[5] )
xDec = int( paramString[6] )
yInt = int( paramString[8] )
yDec = int( paramString[9] )
if paramString[2] == "L":
self.xCoordinateScale = 1 / math.pow(10, xDec)
self.yCoordinateScale = -1 / math.pow(10, yDec) #not sure this is perfect
elif paramString[2] == "T":
self.xCoordinateScale = 1
self.yCoordinateScale = 1 # need to find out why some gerber have y in minus values, but do all need inverting? think this is ok now
if paramString[3] == "A":
#print "abs" #TODO
pass
elif paramString[3] == "I":
print "Incremental Coordinates not currently supported"
#print "finish this"
elif paramString[ :2 ] == "IF" and paramString[ -1 : ] == "*":
print "Param IF Unsuported"
elif paramString[ :2 ] == "IJ" and paramString[ -1 : ] == "*":
print "Param IJ Unsuported"
elif paramString[ :2 ] == "IN" and paramString[ -1 : ] == "*":
print "Param IN Unsuported"
elif paramString[ :2 ] == "IO" and paramString[ -1 : ] == "*":
print "Param IO Unsuported"
elif paramString[ : 2 ] == "IP" and paramString[ -1 : ] == "*": #TODO
print "TODO polatiry = ", paramString[ 2 : -1 ]
elif paramString[ :2 ] == "IR" and paramString[ -1 : ] == "*":
print "Param IR Unsuported"
elif paramString[ :2 ] == "KO" and paramString[ -1 : ] == "*":
print "Param KO Unsuported"
elif paramString[ :2 ] == "LN" and paramString[ -1 : ] == "*":
print "Param LN Unsuported"
elif paramString[ :2 ] == "LP" and paramString[ -1 : ] == "*": #TODO
print "Param LP Unsuported"
elif paramString[ :2 ] == "MI" and paramString[ -1 : ] == "*":
print "Param MI Unsuported"
elif paramString[ : 2 ] == "MO" and paramString[ -1 : ] == "*":
# Set units
self.units = paramString[ 2 : -1 ]
elif paramString[ :2 ] == "OF" and paramString[ -1 : ] == "*":
# Offset
aPos = paramString.find('A')
bPos = paramString.find('B')
self.xCoordinateOffset = float( paramString[ aPos + 1:bPos ] )
self.yCoordinateOffset = float( paramString[ bPos + 1:-1 ] )
elif paramString[ :2 ] == "PF" and paramString[ -1 : ] == "*":
print "Param PF Unsuported"
elif paramString[ :2 ] == "SF" and paramString[ -1 : ] == "*":
print "Param SF Unsuported"
elif paramString[ :2 ] == "SR" and paramString[ -1 : ] == "*":
print "Param SR Unsuported"
else:
print "PARAMETER UNKNOWN"
# Hande a move
def cmdMove( self, moveString ):
yPos = moveString.find( 'Y' )
dPos = moveString.find( 'D' )
x = ( float( moveString[ 1 : yPos ] ) * float(self.xCoordinateScale) ) + self.xCoordinateOffset
y = ( float( moveString[ yPos + 1 : dPos ] ) * -float(self.yCoordinateScale) ) + self.yCoordinateOffset # still need minus?
# If inches convert to mm
if self.units == "IN":
x = x * const_mmPerInch
y = y * const_mmPerInch
# Get move type (aperture open, aperture closed, flash)
d = int( moveString[ dPos + 1 : ] )
if self.debug: print "Move [", x, "mm,", y, "mm],", d
if d == 1:
#if self.currentAperture.code == 12 or self.currentAperture.code == 13: print "trace", self.currentAperture.code
self.traces.append( gerberTrace( self.currentX, self.currentY, x, y, self.currentAperture ) )
elif d == 2:
pass # no entity information required
# Move is aperture closed (pen up) type
elif d == 3:
#print "create flash with ms", moveString
self.flashes.append( gerberFlash( x, y, self.currentAperture ) )
#if self.currentAperture.code == 12 or self.currentAperture.code == 13: print "flash", self.currentAperture.code
self.currentX, self.currentY = x, y
print "Aperture macro type", self.primitiveNumber, "not handled"
# Class for a gerber flash (move and flash aperture)
class gerberFlash:
def __init__(self, x, y, aperture):
self.type = FLASH
self.x, self.y, self.aperture = x, y, aperture
#print "create flash with aperture", aperture
#self.radius = self.aperture.radius
def printFlash(self):
print "FLASH", self.x, self.y, self.aperture
# Class for a gerber trace (aperture open move)
class gerberTrace:
def __init__(self, x1, y1, x2, y2, aperture):
self.type = STROKE
self.x1, self.y1, self.x2, self.y2, self.aperture = x1, y1, x2, y2, aperture
def printTrace(self):
print "TRACE", self.x1, self.y1, self.x2, self.y2, self.aperture
class gerber:
def __init__(self, fileName):
self.fileName = fileName
self.apertures = {}
self.apertureMacros = {}
self.currentAperture = False
self.currentX, self.currentY = 0, 0
self.xCoordinateOffset, self.yCoordinateOffset = 0, 0
self.xCoordinateScale, self.yCoordinateScale = 1, 1
# All flash and trace objects stored here
self.flashes = []
self.traces = []
self.debug = False # TODO pass this in
f = open( self.fileName, 'r' )
lines = f.readlines()
# Do actual parsing of file
self.parseLines(lines)
#print self.apertures
# Parse all lines of the gerber file
def parseLines( self, lines ):
for i in range( len(lines) ):
l = lines[i]
#print "Reading line '" + l[ : -1 ] + "'"
firstChr = l[ : 1 ]
lastChr = l[ -2 : -1 ]
if firstChr == "G" and lastChr == "*":
self.cmdGcode( l[ 1 : -2 ] )
elif firstChr == "D" and lastChr == "*":
self.cmdDcode( l[ 1 : -2 ] )
elif firstChr == "%" and lastChr == "%":
self.cmdParameter( l[ 1 : -2 ] )
elif firstChr == "%":
while l[ -2:-1 ] != "%":
print "j '" + l[ -1: ] + "'"
lines[i] = lines[i][ :-1] + lines[ i + 1 ]
lines.remove( lines[ i + 1 ] )
lines.append("") # to keep for loop happy
l = lines[i]
self.cmdParameter( l[ 1:-2 ] )
elif firstChr == "X" and lastChr == "*":
self.cmdMove( l[ : -2 ] )
elif firstChr == "M" and lastChr == "*":
self.cmdMisc( l[ 1 : -2 ] )
elif l[ : -1 ] == "":
pass
else:
print "Line error! '" + l[ : -1 ] + "'"
# Handle an M code
def cmdMisc( self, mstring ):
code = int( mstring[ : 2 ] )
remains = mstring[ 2: ]
# Handle a G code
def cmdGcode( self, gstring ):
code = int( gstring[ : 2 ] )
remains = gstring[ 2: ]
if code == 0:
print "Move", "[COMMAND UNSUPORTED!]"
elif code == 1:
pass
#print "Linear interpolation (1X scale)", "[COMMAND UNSUPORTED!]" #TODO ADD
elif code == 2:
print "Clockwise circular interpolation", "[COMMAND UNSUPORTED!]"
elif code == 3:
print "Counterclockwise circular interpolation", "[COMMAND UNSUPORTED!]"
elif code == 4:
# Ignore Line
#print "Comment", remains
comment = False
elif code == 10:
print "Linear interpolation (10X scale)", "[COMMAND UNSUPORTED!]"
elif code == 11:
print "Linear interpolation (0.1X scale)", "[COMMAND UNSUPORTED!]"
elif code == 12:
print "Linear interpolation (0.01X scale)", "[COMMAND UNSUPORTED!]"
elif code == 36:
print "Turn on Polygon Area Fill", "[COMMAND UNSUPORTED!]"
elif code == 37:
print "Turn off Polygon Area Fill", "[COMMAND UNSUPORTED!]"
elif code == 54:
if remains[ : 1 ] == "D":
self.selectTool( int( remains[ 1 : ] ) )
elif code == 70:
if self.debug: print "Specify inches" # why are there two ways of setting units?
self.units = "IN"
elif code == 71:
if self.debug: print "Specify millimeters"
self.units = "MM"
elif code == 74:
print "Disable 360 deg circular interpolation (single quadrant)", "[COMMAND UNSUPORTED!]"
elif code == 75:
print "Enable 360 deg circular interpolation (multiquadrant)", "[COMMAND UNSUPORTED!]" #TODO
elif code == 90:
if self.debug: print "Absolute coordinate format"
self.FSparameter = FS_ABSOLUTE
elif code == 91:
if self.debug: print "Incremental coordinate format - This mode is not supported"
self.FSparameter = FS_INCREMENTAL
else:
print "COMMAND UNKNOWN"
#Handle D code - weird eagle inconsistancy?
def cmdDcode( self, paramString ):
if self.debug: print "Tool prepare"
self.selectTool( int(paramString) )
def selectTool( self, tool ):
#print tool
self.currentAperture = self.apertures[ tool ]
#print "select tool", tool, self.currentAperture, self.currentAperture.code
#if self.debug: print " Selecting aperture", int( remains[ 1 : ] )
#print currentAperture.modifiers[0]
# Handle a parameter
def cmdParameter( self, paramString ):
#print "Parameter", paramString, paramString[ : 2]
if paramString[ : 3 ] == "ADD" and paramString[ -1 : ] == "*":
# Add a new aperture
newAperture = aperture( paramString, self.units )
self.apertures[ newAperture.code ] = newAperture
elif paramString[ :2 ] == "AM" and paramString[ -1 : ] == "*":
newApertureMacro = apertureMacro(paramString, self.units)
self.apertureMacros[ newApertureMacro.name ] = newApertureMacro
elif paramString[ :2 ] == "AS" and paramString[ -1 : ] == "*":
print "Param AS Unsuported"
elif paramString[ :2 ] == "FS" and paramString[ -1 : ] == "*":
xInt = int( paramString[5] )
xDec = int( paramString[6] )
yInt = int( paramString[8] )
yDec = int( paramString[9] )
if paramString[2] == "L":
self.xCoordinateScale = 1 / math.pow(10, xDec)
self.yCoordinateScale = -1 / math.pow(10, yDec) #not sure this is perfect
elif paramString[2] == "T":
self.xCoordinateScale = 1
self.yCoordinateScale = 1 # need to find out why some gerber have y in minus values, but do all need inverting? think this is ok now
if paramString[3] == "A":
#print "abs" #TODO
pass
elif paramString[3] == "I":
print "Incremental Coordinates not currently supported"
#print "finish this"
elif paramString[ :2 ] == "IF" and paramString[ -1 : ] == "*":
print "Param IF Unsuported"
elif paramString[ :2 ] == "IJ" and paramString[ -1 : ] == "*":
print "Param IJ Unsuported"
elif paramString[ :2 ] == "IN" and paramString[ -1 : ] == "*":
print "Param IN Unsuported"
elif paramString[ :2 ] == "IO" and paramString[ -1 : ] == "*":
print "Param IO Unsuported"
elif paramString[ : 2 ] == "IP" and paramString[ -1 : ] == "*": #TODO
print "TODO polatiry = ", paramString[ 2 : -1 ]
elif paramString[ :2 ] == "IR" and paramString[ -1 : ] == "*":
print "Param IR Unsuported"
elif paramString[ :2 ] == "KO" and paramString[ -1 : ] == "*":
print "Param KO Unsuported"
elif paramString[ :2 ] == "LN" and paramString[ -1 : ] == "*":
print "Param LN Unsuported"
elif paramString[ :2 ] == "LP" and paramString[ -1 : ] == "*": #TODO
print "Param LP Unsuported"
elif paramString[ :2 ] == "MI" and paramString[ -1 : ] == "*":
print "Param MI Unsuported"
elif paramString[ : 2 ] == "MO" and paramString[ -1 : ] == "*":
# Set units
self.units = paramString[ 2 : -1 ]
elif paramString[ :2 ] == "OF" and paramString[ -1 : ] == "*":
# Offset
aPos = paramString.find('A')
bPos = paramString.find('B')
self.xCoordinateOffset = float( paramString[ aPos + 1:bPos ] )
self.yCoordinateOffset = float( paramString[ bPos + 1:-1 ] )
elif paramString[ :2 ] == "PF" and paramString[ -1 : ] == "*":
print "Param PF Unsuported"
elif paramString[ :2 ] == "SF" and paramString[ -1 : ] == "*":
print "Param SF Unsuported"
elif paramString[ :2 ] == "SR" and paramString[ -1 : ] == "*":
print "Param SR Unsuported"
else:
print "PARAMETER UNKNOWN"
# Hande a move
def cmdMove( self, moveString ):
yPos = moveString.find( 'Y' )
dPos = moveString.find( 'D' )
x = ( float( moveString[ 1 : yPos ] ) * float(self.xCoordinateScale) ) + self.xCoordinateOffset
y = ( float( moveString[ yPos + 1 : dPos ] ) * -float(self.yCoordinateScale) ) + self.yCoordinateOffset # still need minus?
# If inches convert to mm
if self.units == "IN":
x = x * const_mmPerInch
y = y * const_mmPerInch
# Get move type (aperture open, aperture closed, flash)
d = int( moveString[ dPos + 1 : ] )
if self.debug: print "Move [", x, "mm,", y, "mm],", d
if d == 1:
#if self.currentAperture.code == 12 or self.currentAperture.code == 13: print "trace", self.currentAperture.code
self.traces.append( gerberTrace( self.currentX, self.currentY, x, y, self.currentAperture ) )
elif d == 2:
pass # no entity information required
# Move is aperture closed (pen up) type
elif d == 3:
#print "create flash with ms", moveString
self.flashes.append( gerberFlash( x, y, self.currentAperture ) )
#if self.currentAperture.code == 12 or self.currentAperture.code == 13: print "flash", self.currentAperture.code
self.currentX, self.currentY = x, y
#!/usr/bin/env python
import sys
from gerber_lib import gerber
lib = """
function veca(a, b) = atan((b - a)[0] / (b - a)[1]);
module bar(r, a, b, endslope=false) {
d = b - a;
l = sqrt(pow(d[0], 2) + pow(d[1], 2));
theta = veca(a, b);
enslope_l = 15;
blocksize = enslope_l * 4;
echo("bar", a, b);
echo("[d, l, theta]", [d, l, theta]);
echo("w = ", r * 2);
union() {
translate(a)
circle(r, center=true);
translate(b)
circle(r, center=true);
translate(a)
translate(d / 2)
rotate(90 - theta, [0, 0, 1])
square([l, r * 2], center=true);
}
}
"""
g = gerber("noname-Back.gbl")
stream = sys.stdout
stream.write(lib)
stream.write("module layout() {\n")
stream.write("union() {\n")
# Plot all gerber flashes
for i, f in enumerate(g.flashes):
# Move is static flash type
if f.aperture.isMacro:
print "macro", f.aperture.macroName
stream.write("translate([%f, %f, 0])\n" % (f.x, f.y))
if f.aperture.apertureType == "C":
# Using circular aperture
stream.write("circle(%f, center=true);\n" % f.aperture.radius)
elif f.aperture.apertureType == "R":
# Using rectangular aperture
stream.write("square([%f, %f], center=true);\n" % (f.aperture.width,
f.aperture.height))
elif f.aperture.apertureType == "O":
pass
# TODO
#(f.aperture.width / 2, f.aperture.height / 2)
stream.write("\n")
# Plot all gerber traces
for i, t in enumerate(g.traces):
# Move is aperture open (pen down) type
if t.aperture.isMacro:
print "macro", f.aperture.macroName
if t.aperture.apertureType == "C":
# Using circular aperture
#if t.aperture.code == 12 or t.aperture.code == 13: print t.aperture.code
stream.write("bar(%f, [%f, %f], [%f, %f]);\n" % (t.aperture.radius,
t.x1, t.y1, t.x2,
t.y2))
elif t.aperture.apertureType == "R":
pass
# Using rectangular aperture
#print "TODO - rectangle transition"
stream.write("}\n")
stream.write("}\n")
stream.write("layout();\n")
G04 (created by PCBNEW-RS274X (2011-05-25)-stable) date Tue 05 Mar 2013 00:37:05 GMT*
G01*
G70*
G90*
%MOIN*%
G04 Gerber Fmt 3.4, Leading zero omitted, Abs format*
%FSLAX34Y34*%
G04 APERTURE LIST*
%ADD10C,0.006000*%
%ADD11C,0.066000*%
%ADD12C,0.189000*%
%ADD13R,0.189000X0.189000*%
%ADD14C,0.055000*%
%ADD15C,0.023600*%
G04 APERTURE END LIST*
G54D10*
G54D11*
X14000Y-15000D03*
X15000Y-15000D03*
X14000Y-11500D03*
X15000Y-11500D03*
G54D12*
X10500Y-09000D03*
G54D13*
X10500Y-11400D03*
G54D12*
X08500Y-09900D03*
G54D14*
X10000Y-13500D03*
X11000Y-13500D03*
X10000Y-15000D03*
X11000Y-15000D03*
G54D15*
X11000Y-13500D02*
X12500Y-13500D01*
X12500Y-13500D02*
X14000Y-15000D01*
X14000Y-15000D02*
X14000Y-11500D01*
X14000Y-11500D02*
X13900Y-11400D01*
X13900Y-11400D02*
X10500Y-11400D01*
X15000Y-15000D02*
X15000Y-11500D01*
X11000Y-15000D02*
X12500Y-15000D01*
X15000Y-16000D02*
X15000Y-15000D01*
X13500Y-16000D02*
X15000Y-16000D01*
X12500Y-15000D02*
X13500Y-16000D01*
M02*
@bonystedt
Copy link

Hi
Very nice program. Worked right out of the box. I understand now that I must have used it with Python 2.7, which I had it installed at that time. Now I want to run it in Python 3.3. What code changes should there be besides print() instead of print?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment