Files
Ger2KiCad/Ger2KiCad.py

266 lines
7.7 KiB
Python

#################################Ger2KiCad####################################
#This script allows to transform gerber files into kicad_mod files #
##############################################################################
#Author: E-Mail: #
#Martin Obermaier Martin.Obermaier@posteo.de#
##############################################################################
##############################################################################
# Imports #
##############################################################################
import gerber
import re
import numpy as np
import sys
import os
##############################################################################
# Define Classes #
##############################################################################
class Polygon:
def __init__(self):
self.vertices = []
def add_vertex(self,x,y):
self.vertices.append([x,y])
def get_vertices(self):
return self.vertices
def remove_vertex(self,x,y):
self.vertices.remove([x,y])
##############################################################################
# Variables and Constants #
##############################################################################
# Regex Filters:
MODE = r"(Mode):\s([a-z]{1,})"
SCALE = r"(Scale) Factor:\sX:\s(\d+\.\d+|\d+)\sY:\s(\d+\.\d+|\d+)"
COOR = r"(Coordinate Statement):\s([X,Y]):\s(-?\d+\.\d+|-?\d+)\s(?:(Y):\s"+\
"(-?\d+\.\d+|-?\d+))?.{1,}Lights\s(On|Off)"
RMStmtStart = r"(RegionModeStmt) type=RegionMode units=(metric|inch) mode=(on)"
RMStmtStop = r"(RegionModeStmt) type=RegionMode units=(metric|inch) mode=(off)"
EOF = r"EOF Statement"
Scale = [0.0,0.0]
offset = [0.0, 0.0]
mm = 1.0
inch = 25.4
mode = ""
##############################################################################
# Functions #
##############################################################################
def setMode(Stmt):
global mode
mode = re.search(MODE,Stmt).group(2)
print(Stmt)
def setScale(Stmt):
global Scale
Scale[0] = np.float(re.search(SCALE,Stmt).group(2));
Scale[1] = np.float(re.search(SCALE,Stmt).group(3));
print(Stmt)
print(Scale)
def new_Polygon(Stmts):
LastStmt = 0;
unit = ""
poly = Polygon()
LastCoor = [0.0,0.0]
#print(Stmts)
for cnt in range(len(Stmts)):
res = re.search(RMStmtStart,Stmts[cnt])
if res != None:
unit = res.group(2)
LastStmt = cnt+1
break
if unit == "metric":
factor = mm
else:
factor = inch
for cnt in range(LastStmt,len(Stmts)):
coor = []
res = re.search(COOR,Stmts[cnt])
if res.group(6) == "Off":
x = np.float(res.group(3))*factor
y = np.float(res.group(5))*factor
coor = [x,y]
elif res.group(6) =="On":
if res.group(2) != None and res.group(4) != None:
x = np.float(res.group(3))*factor
y = np.float(res.group(5))*factor
else:
if res.group(2) == "X":
x = np.float(res.group(3))*factor
y = LastCoor[1]
else:
y = np.float(res.group(3))*factor
x = LastCoor[0]
coor = [x,y]
coor = np.round(coor,4)
poly.add_vertex(coor[0],coor[1])
LastCoor = coor
return poly
def find_center(polygons):
xmax = np.array([], dtype=np.float64)
xmin = np.array([], dtype=np.float64)
ymax = np.array([], dtype=np.float64)
ymin = np.array([], dtype=np.float64)
for pol in polygons:
poly_coor = np.asarray(pol.get_vertices())
xmax = np.append(xmax,np.amax(poly_coor[::,0]))
xmin = np.append(xmin,np.amin(poly_coor[::,0]))
ymax = np.append(ymax,np.amax(poly_coor[::,1]))
ymin = np.append(ymin,np.amin(poly_coor[::,1]))
x_c = (np.amax(xmax)+np.amin(xmin))/2
y_c = (np.amax(ymax)+np.amin(ymin))/2
return x_c,y_c
def readGerber(file):
top_copper = gerber.read(file).statements
polygons =[]
LastStmtIndex = 0;
#Find mode statement
for cnt in range(len(top_copper)):
Stmt = str(top_copper[cnt])
if re.search(MODE,Stmt) != None:
setMode(Stmt)
LaststmtIndex = cnt;
break
if mode == "":
raise Exception("FileFormat","No Unit mode Statement found")
#Find scale factors
for cnt in range(LastStmtIndex,len(top_copper)):
Stmt = str(top_copper[cnt])
if re.search(SCALE,Stmt) != None:
setScale(Stmt)
LaststmtIndex = cnt;
break
#Find polygons factors
for cnt in range(LastStmtIndex,len(top_copper)):
Stmt = str(top_copper[cnt])
if re.search(RMStmtStart ,Stmt) != None:
PolyStmt = []
i = 0
while cnt+i < len(top_copper):
Stmt = str(top_copper[cnt+i])
if re.search(RMStmtStop ,Stmt) != None:
LaststmtIndex = cnt+i;
poly = new_Polygon(PolyStmt)
polygons.append(poly)
break
else:
PolyStmt.append(Stmt)
i+=1
return polygons
def create_kicad_poly(polygons,x_c,y_c,layer="F.Cu"):
polygon_str = ""
for pol in polygons:
poly_frame =" (fp_poly (pts"
poly_end =") (layer "+ layer +") (width 0.001))"
new_poly = poly_frame
flat_list = pol.get_vertices()
for cnt in range(len(flat_list)):
cor = flat_list[cnt]
cor_x = np.round(float(cor[0])-x_c,4)
cor_y = np.round(float(cor[1])-y_c,4)
a="(xy "+str(cor_x)+" "+str(cor_y)+")"
new_poly+=" "+a
new_poly_com=new_poly+poly_end
polygon_str += new_poly_com + "\n"
return polygon_str
def create_kicad_mod(name,polygons,libary="Default",tedit="5EF5C08B"):
kicad_file = ""
header = "(module "+libary+":"+name+" (layer F.Cu) (tedit "+tedit+\
")"+"\n"+ \
"(fp_text reference REF** (at 0.0 5.0) (layer F.SilkS) hide"+\
"\n"+ \
"(effects (font (size 1 1) (thickness 0.15)))"+"\n"+ \
")"+"\n"+ \
"(fp_text value "+name+" (at 0.0 -5.0) (layer F.Fab) hide"+\
"\n"+ \
"(effects (font (size 1 1) (thickness 0.15)))"+"\n"+\
")"+"\n"
footer = ")"
kicad_file += header;
for poly in polygons:
kicad_file += poly
kicad_file += footer
return kicad_file
##############################################################################
# Main #
##############################################################################
if len(sys.argv) != 2:
print("Wrong number of arguments")
exit()
filename = os.path.splitext(sys.argv[1])[0]
poly=readGerber(filename+'.gbr')
x_c,y_c = find_center(poly)
kicad_poly = create_kicad_poly(poly,x_c,y_c,layer="F.Cu")
output=create_kicad_mod(filename,kicad_poly)
f= open(filename+".kicad_mod","w+")
f.write(output)
f.close()
exit();
##############################################################################
# END #
##############################################################################