Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/env python
- # Copyright 2014 Lilith Bryant
- # Licence: GPLv2
- from __future__ import print_function
- import pyparsing as pp
- import re
- import sys
- import copy
- import os
- class Measurement(object):
- def __init__(self,s):
- if s.endswith("nm"):
- m=float(s[:-2])
- u="nm"
- mult=1
- elif s.endswith("mm"):
- m=float(s[:-2])
- u="mm"
- mult=1000000
- elif s.endswith("mil"):
- m=float(s[:-3])
- u="mil"
- mult=25400
- else:
- m=float(s)
- u=""
- mult=2540000
- self.units=u
- if m==int(m):
- m=int(m)
- self.raw=m
- self.nm=int(round(self.raw*mult))
- def AsNM(self,mil):
- return self.nm
- def SetNM(self,nm):
- self.nm=nm
- self.units="nm"
- self.raw=nm
- def SetMil(self,mil):
- self.nm=int(round(mil*25400))
- self.units="mil"
- self.raw=mil
- def __str__(self):
- return str(self.raw)+self.units
- class StringFlags(object):
- L=pp.Literal("(").suppress()
- R=pp.Literal(")").suppress()
- PartStart=pp.Regex(r"[^,\(\)]*")
- CSV=pp.delimitedList(PartStart)
- Part=pp.Group( PartStart + pp.Group( pp.Optional( L + CSV + R ) ) )
- Parts=pp.delimitedList(Part)
- def __init__(self,s):
- self.s=s
- All=StringFlags.Parts.parseString(s)
- self.flags=set([ PP[0] for PP in All if PP[0]!="thermal"])
- ThermalFlags=[ PP for PP in All if PP[0]=="thermal"]
- if len(ThermalFlags)==0:
- self.thermals={}
- else:
- T=set(ThermalFlags[0][1])
- self.thermals=dict( [ (i[0], (i+"!")[1] ) for i in T ] )
- def __contains__(self,s):
- if s=="thermal":
- return len(self.thermals)>0
- else:
- return s in self.flags
- def Add(self,s):
- self.flags.add(s)
- def Remove(self,s):
- if s in self.flags:
- self.flags.remove(s)
- def AddThermal(self,n,type):
- self.thermals[n]=type
- def RemoveThermal(self,n):
- if n in self.thermals:
- del self.thermals[n]
- def RemoveAllThermal(self):
- self.thermals={}
- def __str__(self):
- if self.thermals is not None and len(self.thermals)>0:
- s=[ str(i[0])+(str(i[1]).replace("!","")) for i in self.thermals.items() ]
- t="thermal("+",".join(sorted(s))+")"
- return ",".join(list(self.flags)+[t])
- else:
- return ",".join(self.flags)
- def BuildBNF(pp):
- #All ZeroOrMore things must have a setResultsName("xxx",True) for writer to work
- S=pp.Suppress
- C=pp.Combine
- G=pp.Group
- LRND=S(pp.Literal("("))
- RRND=S(pp.Literal(")"))
- LSQ=S(pp.Literal("["))
- RSQ=S(pp.Literal("]"))
- Str=pp.QuotedString('"')
- Char=pp.Regex(r"'.'")
- Meas=pp.Regex(r"-?[0-9\\.]+[a-z]*")
- Meas.setParseAction(lambda t: Measurement(t[0]))
- MeasArea=pp.Regex(r"-?[0-9\\.]+[a-z]*")
- MeasArea.setParseAction(lambda t:float(t[0]))
- Digits=pp.Regex(r"-?[0-9]+")
- Digits.setParseAction(lambda t:int(t[0]))
- Float=pp.Regex(r"-?[0-9\\.]+")
- Float.setParseAction(lambda t:float(t[0]))
- Comment=pp.Literal("#") + pp.restOfLine
- SFlags=C(Str)
- SFlags.setParseAction(lambda t: StringFlags(t[0]))
- QSFlags=SFlags
- FileVersion=pp.Keyword("FileVersion") + LSQ + Digits("Version")+ RSQ
- PCB = pp.Keyword("PCB")+ LSQ+(Str("Name")+Meas("Width")+Meas("Height"))("PCB")+RSQ
- Grid = pp.Keyword("Grid")+ LSQ+Meas("Step")+Meas("OffsetX")+Meas("OffsetY")+Digits("Visible")+RSQ
- PolyArea = pp.Keyword("PolyArea")+ LSQ+Float("Area")+RSQ
- Thermal = pp.Keyword("Thermal")+ LSQ+Float("Scale")+RSQ
- DRC = pp.Keyword("DRC")+ LSQ+ Meas("Bloat")+ Meas("Shrink")+ Meas("Line")+ Meas("Silk")+ Meas("Drill")+ Meas("Ring")+RSQ
- Flags = pp.Keyword("Flags")+ LRND+ QSFlags("Flags")+RRND
- Groups = pp.Keyword("Groups")+ LRND+ Str("Groups")+RRND
- Styles = pp.Keyword("Styles")+ LSQ+ Str("Styles")+RSQ
- Mark = pp.Keyword("Mark")+ LSQ+ Meas("X")+Meas("Y")+RSQ
- Cursor = pp.Keyword("Cursor")+ LSQ+ Meas("X")+Meas("Y")+Float("Zoom")+RSQ
- PCBAttribute = pp.Keyword("Attribute")+ LRND+ Str("AttrKey")+Str("AttrValue")+RRND
- SymbolLine = pp.Keyword("SymbolLine")+ LSQ+ Meas("X1")+Meas("Y1")+Meas("X2")+Meas("Y2")+Meas("Thickness")+RSQ
- SymContent2 = SymbolLine
- SymContent = G(SymContent2)
- SymContent=SymContent.setResultsName("Content",True)
- PCBSymbol =pp.Keyword("Symbol")+ LSQ+ Char("Char")+Meas("Delta")+RSQ +LRND+pp.ZeroOrMore(SymContent)+RRND
- Via = pp.Keyword("Via")+ LSQ+ Meas("X")+Meas("Y")+Meas("Thickness")+Meas("Clearance")+Meas("Mask")+Meas("Drill")+Str("Name")+QSFlags("SFlags")+RSQ
- Pin = pp.Keyword("Pin")+ LSQ+ Meas("rX")+Meas("rY")+Meas("Thickness")+Meas("Clearance")+Meas("Mask")+Meas("Drill")+Str("Name")+Str("Number")+QSFlags("SFlags")+RSQ
- Pad = pp.Keyword("Pad")+ LSQ+ Meas("rX1")+Meas("rY1")+Meas("rX2")+Meas("rY2")+Meas("Thickness")+Meas("Clearance")+Meas("Mask")+Str("Name")+Str("Number")+QSFlags("SFlags")+RSQ
- ElementArc = pp.Keyword("ElementArc")+ LSQ+ Meas("X")+Meas("Y")+Meas("Width")+Meas("Height")+Digits("StartAngle")+Digits("DeltaAngle")+Meas("Thickness")+RSQ
- ElementLine = pp.Keyword("ElementLine")+ LSQ+ Meas("X1")+Meas("Y1")+Meas("X2")+Meas("Y2")+Meas("Thickness")+RSQ
- ElemContent2 = PCBAttribute | Pin| Pad|ElementLine|ElementArc
- ElemContent = G(ElemContent2)
- ElemContent=ElemContent.setResultsName("Content",True)
- PCBElement = (pp.Keyword("Element")+ LSQ+ QSFlags("SFlags")+Str("Desc")+Str("Name")+Str("Value")+
- Meas("MX")+Meas("MY")+Meas("TX")+Meas("TY")+Digits("TDir")+Digits("TScale")+QSFlags("TSFlags")+RSQ
- +LRND+pp.ZeroOrMore(ElemContent)+RRND )
- Rat = pp.Keyword("Rat")+ LSQ+ Meas("X1")+Meas("Y1")+Digits("Group1")+Meas("X2")+Meas("Y2")+Digits("Group2")+QSFlags("SFlags")+RSQ
- Line = pp.Keyword("Line")+ LSQ+ Meas("X1")+Meas("Y1")+Meas("X2")+Meas("Y2")+Meas("Thickness")+Meas("Clearance")+QSFlags("SFlags")+RSQ
- Arc = pp.Keyword("Arc")+ LSQ+ Meas("X")+Meas("Y")+Meas("Width")+Meas("Height")+Meas("Thickness")+Meas("Clearance")+Digits("StartAngle")+Digits("DeltaAngle")+QSFlags("SFlags")+RSQ
- Text = pp.Keyword("Text")+ LSQ+ Meas("X")+Meas("Y")+Digits("Direction")+Meas("Scale")+Str("String")+QSFlags("SFlags")+RSQ
- PolyVertex = LSQ+Meas("X")+Meas("Y")+RSQ
- PolyVertex =PolyVertex .setResultsName("Vertex",True)
- Hole = pp.Keyword("Hole")+LRND+pp.ZeroOrMore(PolyVertex)+RRND
- PolyContent2 = PolyVertex | Hole
- PolyContent = G(PolyContent2)
- PolyContent=PolyContent.setResultsName("Content",True)
- Polygon = pp.Keyword("Polygon")+ LRND+QSFlags("SFlags")+RRND+ LRND+pp.ZeroOrMore(PolyContent)+RRND
- LayerContent2 = PCBAttribute|Line|Arc|Polygon|Text
- LayerContent = G(LayerContent2)
- LayerContent=LayerContent.setResultsName("Content",True)
- Layer = pp.Keyword("Layer")+ LRND+ Digits("LayerNum")+Str("Name")+RRND +LRND+pp.ZeroOrMore(LayerContent)+RRND
- Connect = pp.Keyword("Connect")+LRND+Str("PinPad")+RRND
- Connect =Connect .setResultsName("Connect",True)
- Net = pp.Keyword("Net")+ LRND+Str("Name")+Str("Style")+RRND+ LRND+pp.ZeroOrMore(Connect)+RRND
- Net=Net.setResultsName("Net",True)
- NetList = pp.Keyword("NetList")+ LRND+ RRND +LRND+pp.ZeroOrMore(Net)+RRND
- TopLevelThing2=Comment|FileVersion|PCB|Grid|PolyArea|Thermal|DRC|Flags|Groups|Styles|Mark|Cursor|PCBSymbol|PCBAttribute|Via|PCBElement|Rat|Layer|NetList
- TopLevelThing=G(TopLevelThing2)
- TopLevelThing=TopLevelThing.setResultsName("Content",True)
- FileGrammar=pp.ZeroOrMore( TopLevelThing )
- return FileGrammar
- ##########################
- FileGrammarParser=BuildBNF(pp)
- ##########################
- class PrintContext(object):
- def __init__(self):
- self.printargs={} # these passed to every print
- class Writer(object):
- class Expression(object):
- def __init__(self):
- self.List=False
- self.Var=None
- self.Suppress=False
- def GetCount(self):
- return 0
- def __add__(self,x):
- return Writer.ConcatExpression(self,x)
- def __or__(self,x):
- return Writer.OrExpression(self,x)
- def __call__(self,v):
- return self.setResultsName(v)
- def setResultsName(self,v,list=False):
- x=copy.copy(self)
- x.Var=v
- x.List=list
- return x
- def GetVar(self,v):
- if self.Var is None:
- return None
- else:
- return v.__getattr__(self.Var)
- def DoPrint(self,i,PC):
- raise NotImplementedError
- class ConcatExpression(Expression):
- def __init__(self,a,b=None):
- Writer.Expression.__init__(self)
- if b is None:
- self.Options=a
- elif isinstance(a,Writer.ConcatExpression):
- self.Options=a.Options+[b]
- else:
- self.Options=[a,b]
- def GetFirstLiteral(self):
- return self.Options[0].GetFirstLiteral()
- def DoPrint(self,x,PC):
- n=0
- for i in self.Options:
- v=i.GetVar(x)
- if v is None:
- c=i.GetCount()
- if c==0:
- a=i.DoPrint(x,PC)
- else:
- a=i.DoPrint(x[n],PC)
- n+=c
- else:
- a=i.DoPrint(v,PC)
- class OrExpression(Expression):
- def __init__(self,a,b=None):
- super(Writer.OrExpression,self).__init__()
- if b is None:
- self.Options=a
- elif isinstance(a,Writer.OrExpression):
- self.Options=a.Options+[b]
- else:
- self.Options=[a,b]
- def DoPrint(self,x,PC):
- #print ( [i.GetFirstLiteral() for i in self.Options] )
- Done=False
- for i in self.Options:
- if x[0]==i.GetFirstLiteral():
- i.DoPrint(x,PC)
- Done=True
- if not Done:
- self.Options[0].DoPrint(x,PC)
- class Keyword(Expression):
- def __init__(self,s):
- super(Writer.Keyword,self).__init__()
- self.s=s
- def GetCount(self):
- if self.Suppress:
- return 0
- else:
- return 1
- def GetFirstLiteral(self):
- return self.s
- def DoPrint(self,x,PC):
- print (self.s+" ",end="",**PC.printargs)
- class Literal(Expression):
- def __init__(self,s):
- super(Writer.Literal,self).__init__()
- self.s=s
- def GetCount(self):
- if self.Suppress:
- return 0
- else:
- return 1
- def GetFirstLiteral(self):
- return self.s
- def DoPrint(self,x,PC):
- print (self.s+" ",end="",**PC.printargs)
- if self.s==")" or self.s=="]":
- print ("",**PC.printargs)
- class QuotedString(Expression):
- def __init__(self,s):
- super(Writer.QuotedString,self).__init__()
- self.s=s
- def GetCount(self):
- if self.Suppress:
- return 0
- else:
- return 1
- def setParseAction(self,a):
- return self
- def DoPrint(self,x,PC):
- print ('"'+str(x)+'"'+" ",end="",**PC.printargs)
- class Regex(Expression):
- def __init__(self,r):
- super(Writer.Regex,self).__init__()
- self.r=r
- def GetCount(self):
- if self.Suppress:
- return 0
- else:
- return 1
- def setParseAction(self,a):
- return self
- def DoPrint(self,x,PC):
- print (str(x)+" ",end="",**PC.printargs)
- class Optional(Expression):
- def __init__(self,ex):
- super(Writer.Optional,self).__init__()
- self.ex=ex
- def DoPrint(self,x,PC):
- self.ex.DoPrint (str(x),PC)
- class Group(Expression):
- def __init__(self,ex):
- super(Writer.Group,self).__init__()
- self.ex=ex
- def DoPrint(self,x,PC):
- self.ex.DoPrint(x,PC)
- class ZeroOrMore(Expression):
- def __init__(self,ex):
- super(Writer.ZeroOrMore,self).__init__()
- self.ex=ex
- def DoPrint(self,x,PC):
- xx=self.ex.GetVar(x)
- if xx is None:
- print ("Structure not supported",self.ex.Var) # all ZeroOrMore must be of something named
- raise NotImplementedError
- for i in xx:
- self.ex.DoPrint(i,PC)
- class ROL(Expression):
- def __init__(self):
- self.__class__.__bases__[0].__init__(self)
- def GetCount(self):
- if self.Suppress:
- return 0
- else:
- return 1
- def DoPrint(self,x,PC):
- print(str(x),**PC.printargs)
- restOfLine=ROL()
- @staticmethod
- def Suppress(S):
- S=copy.copy(S)
- S.Suppress=True
- return S
- @staticmethod
- def Combine(S):
- return S
- Wr=BuildBNF( Writer )
- def PrintTree(x,FileNameOut=None):
- PC=PrintContext
- PC.printargs={}
- if FileNameOut!=None:
- with open(FileNameOut,"w") as f:
- PC.printargs["file"]=f
- Wr.DoPrint(x,PC)
- else:
- Wr.DoPrint(x,PC)
- ##########################
- import shapely.geometry.polygon as polygon
- import shapely.geometry.point as point
- def ToShapelyPoly(data):
- verts=[]
- for k in data.Content:
- if k[0]=="Hole":
- pass #FIXME handle this
- else:
- vx=k.X.nm
- vy=k.Y.nm
- verts.append( (vx,vy) )
- return polygon.Polygon(verts)
- ###########################
- def FixThermalsPass(FileNameIn,FileNameOut):
- with open(FileNameIn,"r") as f:
- x= FileGrammarParser.parseFile(f,parseAll=True)
- '''
- for each polygon:
- collect info
- for each pin/via:
- for each polygon:
- if intersects:
- if found and found
- +this poly layer
- else
- -this poly layer
- '''
- print ( "Loaded!",file=sys.stderr)
- # Collect all polygons
- Polys=[]
- PolysByLayer={}
- for i in x.Content:
- if i[0]=="Layer":
- layer=i.LayerNum
- for j in i.Content:
- if j[0]=="Polygon":
- p=ToShapelyPoly(j)
- p.layer=layer
- p.found=("selected" in j.SFlags)
- Polys.append(p)
- PolysByLayer.setdefault(layer,[]).append(p)
- # Look for polygon/via polygon/pin intersections
- for i in x.Content:
- if i[0]=="Element":
- mx=i.MX.nm
- my=i.MY.nm
- for j in i.Content:
- if j[0]=="Pin":
- px=j.rX.nm+mx
- py=j.rY.nm+my
- pt=point.Point(px,py)
- for p in Polys:
- if p.contains(pt):
- if p.found and "selected" in j.SFlags:
- j.SFlags.AddThermal(p.layer-1,"!")
- else:
- j.SFlags.RemoveThermal(p.layer-1)
- elif i[0]=="Via":
- px=i.X.nm
- py=i.Y.nm
- pt=point.Point(px,py)
- for p in Polys:
- if p.contains(pt):
- if p.found and "selected" in i.SFlags:
- i.SFlags.AddThermal(p.layer-1,"!")
- else:
- i.SFlags.RemoveThermal(p.layer-1)
- elif i[0]=="Layer":
- layer=i.LayerNum
- pp=PolysByLayer.get(layer,[])
- pp=[p for p in pp if p.found]
- if len(pp)>0:
- for j in i.Content:
- if j[0]=="Line":
- if "selected" in j.SFlags:
- x1=j.X1.nm
- y1=j.Y1.nm
- pt1=point.Point(x1,y1)
- x2=j.X2.nm
- y2=j.Y2.nm
- pt2=point.Point(x2,y2)
- FullyContained=False
- for p in pp:
- c1=p.contains(pt1)
- c2=p.contains(pt2)
- if c1 and c2:
- FullyContained=True
- if FullyContained:
- j.SFlags.Remove("clearline")
- else:
- j.SFlags.Add("clearline")
- PrintTree(x,FileNameOut=FileNameOut)
- Nets=[ "GND-IO","3.3V-IO","SHIELD-IO" ]
- FI=sys.argv[1]
- FO="a"+FI
- for n in Nets:
- with open("x.cmd","w") as f:
- print( "Connection(reset)", file=f )
- print( "Unselect(all)", file=f )
- print( "DeleteRats(AllRats)", file=f )
- print( "AddRats(AllRats)", file=f )
- print( "Net(select,%s)"%n, file=f )
- print( "Save()", file=f )
- print( "Quit()", file=f )
- cmd="pcb --action-script x.cmd %s" % FI
- print (n,cmd)
- os.system(cmd)
- print (FI,"->",FO)
- FixThermalsPass(FI,FO)
- FI=FO
- FO="a"+FO
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement