diff --git a/README.md b/README.md
index 1bf79bd..b273a22 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,16 @@
# kicad-action-plugins
-kicad action plugin tools
+#### kicad action plugin tools
+- ### action_menu_annular_check.py
+A script to check for annular ring violations
+for PTH, NPTH pads and vias
+
+- ### action_menu_pcb2dxf
+A script to export technical layers of kicad PCB to DXF
+DXF generated file has single line draw as it should be for mechanical interchange (this option is missing in pcbnew plot)
+
+
+---
## action_menu_annular_check.py
A script to check for annular ring violations
for PTH, NPTH pads and vias
@@ -20,6 +30,27 @@ to change values modify:
Launch the Annular Check script in pcbnew from Tools menu:

-## todo
-- add colors to output
+### todo (annular_check)
+- add colors to output list
+
+## action_menu_pcb2dxf
+**kicadpcb2dxf**
+_dxf exporter for mechanical layers of a kicad_pcb board_
+- "Dwgs", "Cmts", "Edge", "Eco1", "Eco2", "F.Fab", "B.Fab", "F.CrtYd", "B.CrtYd"
+- the dxf generated has single line draw as it should be for mechanical interchange (this option is missing in pcbnew plot)
+
+creates DXF file of technical layers of the selected kicad pcb board
+
+(this is a part of kicad StepUp tools; please refer to kicad StepUp tools for the full licence)
+
+ kicadpcb2dxf: Copyright (c) 2015 Maurice easyw
+ dxf_parser="r12writer from ezdxf 0.7.6": Copyright (C) 2016, Manfred Moitzi with MIT License
+
+done:
+- [x] added line, circle, arc primitives
+- [x] added footprint support
+- [x] fixed negative arc case
+- [x] added text support (mirror & alignement not supported)
+- [x] added multiline text
+- [x] add quote support
diff --git a/action_menu_pcb2dxf.py b/action_menu_pcb2dxf.py
new file mode 100644
index 0000000..82e382c
--- /dev/null
+++ b/action_menu_pcb2dxf.py
@@ -0,0 +1,1265 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+## kicadpcb2dxf.py
+# creates DXF file of selected kicad pcb board
+# using r12writer from ezdxf modules included
+# this is a part of kicad StepUp tools; please refer to kicad StepUp tools
+# for the full licence
+#
+### Copyright (c) 2015 Maurice easyw@katamail.com
+#****************************************************************************
+## done:
+# gr_line, gr_circle, gr_arc
+# add footprint support fp_line, fp_circle, fp_arc
+# add text support (mirror & alignement not supported)
+# add multiline text support
+
+## todo:
+# add quote support
+# add rotation for module arcs
+
+# Purpose: fast & simple but restricted DXF R12 writer, with no in-memory drawing, and without dependencies to other
+# ezdxf modules. The created DXF file contains no HEADER, TABLES or BLOCKS section only the ENTITIES section is present.
+# Created: 14.04.2016
+# Copyright (C) 2016, Manfred Moitzi
+# License: MIT License
+from __future__ import unicode_literals
+dxf_parser="r12writer from ezdxf 0.7.6"
+__author__ = "mozman "
+
+script_name="kicadpcb2dxf"
+__author_script__="easyw Maurice"
+___version___="3.8x"
+
+from contextlib import contextmanager
+
+def rnd(x): # adjust output precision of floats by changing 'ndigits'
+ return round(x, ndigits=6)
+
+TEXT_ALIGN_FLAGS = {
+ 'LEFT': (0, 0),
+ 'CENTER': (1, 0),
+ 'RIGHT': (2, 0),
+ 'BOTTOM_LEFT': (0, 1),
+ 'BOTTOM_CENTER': (1, 1),
+ 'BOTTOM_RIGHT': (2, 1),
+ 'MIDDLE_LEFT': (0, 2),
+ 'MIDDLE_CENTER': (1, 2),
+ 'MIDDLE_RIGHT': (2, 2),
+ 'TOP_LEFT': (0, 3),
+ 'TOP_CENTER': (1, 3),
+ 'TOP_RIGHT': (2, 3),
+}
+
+
+@contextmanager
+def r12writer(stream, fixed_tables=False):
+ if hasattr(stream, 'write'):
+ writer = R12FastStreamWriter(stream, fixed_tables)
+ yield writer
+ writer.close()
+ else:
+ with open(stream, 'wt') as stream:
+ writer = R12FastStreamWriter(stream, fixed_tables)
+ yield writer
+ writer.close()
+
+
+class R12FastStreamWriter(object):
+ def __init__(self, stream, fixed_tables=False):
+ self.stream = stream
+ if fixed_tables:
+ stream.write(PREFACE)
+ stream.write("0\nSECTION\n2\nENTITIES\n") # write header
+
+ def close(self):
+ self.stream.write("0\nENDSEC\n0\nEOF\n") # write tail
+
+ def add_line(self, start, end, layer="0", color=None, linetype=None):
+ dxf = ["0\nLINE\n"]
+ dxf.append(dxf_attribs(layer, color, linetype))
+ dxf.append(dxf_vertex(start, code=10))
+ dxf.append(dxf_vertex(end, code=11))
+ self.stream.write(''.join(dxf))
+
+ def add_circle(self, center, radius, layer="0", color=None, linetype=None):
+ dxf = ["0\nCIRCLE\n"]
+ dxf.append(dxf_attribs(layer, color, linetype))
+ dxf.append(dxf_vertex(center))
+ dxf.append(dxf_tag(40, str(rnd(radius))))
+ self.stream.write(''.join(dxf))
+
+ def add_arc(self, center, radius, start=0, end=360, layer="0", color=None, linetype=None):
+ dxf = ["0\nARC\n"]
+ dxf.append(dxf_attribs(layer, color, linetype))
+ dxf.append(dxf_vertex(center))
+ dxf.append(dxf_tag(40, str(rnd(radius))))
+ dxf.append(dxf_tag(50, str(rnd(start))))
+ dxf.append(dxf_tag(51, str(rnd(end))))
+ self.stream.write(''.join(dxf))
+
+ def add_point(self, location, layer="0", color=None, linetype=None):
+ dxf = ["0\nPOINT\n"]
+ dxf.append(dxf_attribs(layer, color, linetype))
+ dxf.append(dxf_vertex(location))
+ self.stream.write(''.join(dxf))
+
+ def add_3dface(self, vertices, invisible=0, layer="0", color=None, linetype=None):
+ self._add_quadrilateral('3DFACE', vertices, invisible, layer, color, linetype)
+
+ def add_solid(self, vertices, layer="0", color=None, linetype=None):
+ self._add_quadrilateral('SOLID', vertices, 0, layer, color, linetype)
+
+ def _add_quadrilateral(self, dxftype, vertices, flags, layer, color, linetype):
+ dxf = ["0\n%s\n" % dxftype]
+ dxf.append(dxf_attribs(layer, color, linetype))
+ vertices = list(vertices)
+ if len(vertices) < 3:
+ raise ValueError("%s needs 3 ot 4 vertices." % dxftype)
+ elif len(vertices) == 3:
+ vertices.append(vertices[-1]) # double last vertex
+ dxf.extend(dxf_vertex(vertex, code) for code, vertex in enumerate(vertices, start=10))
+ if flags:
+ dxf.append(dxf_tag(70, str(flags)))
+ self.stream.write(''.join(dxf))
+
+ def add_polyline(self, vertices, layer="0", color=None, linetype=None):
+ def write_polyline(flags):
+ dxf = ["0\nPOLYLINE\n"]
+ dxf.append(dxf_attribs(layer, color, linetype))
+ dxf.append(dxf_tag(66, "1")) # entities follow
+ dxf.append(dxf_tag(70, flags))
+ self.stream.write(''.join(dxf))
+
+ polyline_flags, vertex_flags = None, None
+ for vertex in vertices:
+ if polyline_flags is None: # first vertex
+ if len(vertex) == 3: # 3d polyline
+ polyline_flags, vertex_flags = ('8', '32')
+ else: # 2d polyline
+ polyline_flags, vertex_flags = ('0', '0')
+ write_polyline(polyline_flags)
+
+ dxf = ["0\nVERTEX\n"]
+ dxf.append(dxf_attribs(layer))
+ dxf.append(dxf_tag(70, vertex_flags))
+ dxf.append(dxf_vertex(vertex))
+ self.stream.write(''.join(dxf))
+ if polyline_flags is not None:
+ self.stream.write("0\nSEQEND\n")
+
+ def add_text(self, text, insert=(0, 0), height=1., width=1., align="LEFT", rotation=0., oblique=0., style='STANDARD',
+ layer="0", color=None):
+ # text style is always STANDARD without a TABLES section
+ dxf = ["0\nTEXT\n"]
+ dxf.append(dxf_attribs(layer, color))
+ dxf.append(dxf_vertex(insert, code=10))
+ dxf.append(dxf_tag(1, str(text)))
+ dxf.append(dxf_tag(40, str(rnd(height))))
+ if width != 1.:
+ dxf.append(dxf_tag(41, str(rnd(width))))
+ if rotation != 0.:
+ dxf.append(dxf_tag(50, str(rnd(rotation))))
+ if oblique != 0.:
+ dxf.append(dxf_tag(51, str(rnd(oblique))))
+ if style != "STANDARD":
+ dxf.append(dxf_tag(7, str(style)))
+ halign, valign = TEXT_ALIGN_FLAGS[align.upper()]
+ dxf.append(dxf_tag(72, str(halign)))
+ dxf.append(dxf_tag(73, str(valign)))
+ dxf.append(dxf_vertex(insert, code=11)) # align point
+ self.stream.write(''.join(dxf))
+
+
+def dxf_attribs(layer, color=None, linetype=None):
+ dxf = ["8\n%s\n" % layer] # layer is required
+ if linetype is not None:
+ dxf.append("6\n%s\n" % linetype)
+ if color is not None:
+ if 0 <= int(color) < 257:
+ dxf.append("62\n%d\n" % color)
+ else:
+ raise ValueError("color has to be an integer in the range from 0 to 256.")
+ return "".join(dxf)
+
+
+def dxf_vertex(vertex, code=10):
+ dxf = []
+ for c in vertex:
+ dxf.append("%d\n%s\n" % (code, str(rnd(c))))
+ code += 10
+ return "".join(dxf)
+
+
+def dxf_tag(code, value):
+ return "%d\n%s\n" % (code, value)
+
+
+###################################################################
+##real python code easyw
+import sys
+reload(sys)
+sys.setdefaultencoding('utf8') #to accept utf8 chars
+import re, os
+from math import sqrt, atan2, degrees, sin, cos, radians
+
+import wx
+import pcbnew
+from pcbnew import *
+
+class pcb2dxf( pcbnew.ActionPlugin ):
+ """
+ export technical layers of kicad PCB to DXF
+ """
+
+ def defaults( self ):
+ """
+ Method defaults must be redefined
+ self.name should be the menu label to use
+ self.category should be the category (not yet used)
+ self.description should be a comprehensive description
+ of the plugin
+ """
+ self.name = "export technical layers of pcb to DXF (saved board)"
+ self.category = "export PCB"
+ self.description = "export technical layers of pcb to DXF (saved board)"
+
+ def Run( self ):
+ fileName = GetBoard().GetFileName()
+ if len(fileName)==0:
+ wx.LogMessage("a board needs to be saved/loaded!")
+ else:
+ dirpath = os.path.abspath(os.path.expanduser(fileName))
+ path, fname = os.path.split(dirpath)
+ ext = os.path.splitext(os.path.basename(fileName))[1]
+ name = os.path.splitext(os.path.basename(fileName))[0]
+
+ LogMsg="reading from "+ dirpath
+ out_filename=path+os.sep+name+".dxf"
+ LogMsg+="writing to "+out_filename
+ content=[]
+ txtFile = open(fileName,"r")
+ content = txtFile.readlines()
+ content.append(" ")
+ txtFile.close()
+
+ #wx.MessageDialog(None, 'This is a message box. ONLY TEST!', 'Test', wx.OK | wx.ICON_INFORMATION).ShowModal()
+ #wx.MessageDialog(None, 'This is a message box. ONLY TEST!', content, wx.OK | wx.ICON_INFORMATION).ShowModal()
+ #found_selected=False
+ #board = pcbnew.GetBoard()
+
+ dlg=wx.MessageBox( 'Only SAVED board file will be exported to DXF file', 'Confirm', wx.OK | wx.CANCEL | wx.ICON_INFORMATION )
+ if dlg == wx.OK:
+ if os.path.isfile(out_filename):
+ dlg=wx.MessageBox( 'Overwrite DXF file?', 'Confirm', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION )
+ if dlg == wx.YES:
+ export_dxf(content, out_filename)
+ else:
+ export_dxf(content, out_filename)
+
+
+
+
+def export_dxf(content,out_filename):
+ # quote_layer True to move all quote on special layer
+ quote_layer=False
+ align="LEFT"
+
+ with r12writer(out_filename) as dxf:
+ data=[];createTxt=0;quote_color=127;dimension=0
+ for line in content:
+ if line.strip().startswith("(at ") and not "(at (xyz" in line:
+ pos=line.split('(at ',1)[-1]
+ plcmt=pos.split(" ")
+ if len (plcmt)<=2:
+ plcmt[1]=plcmt[1].split(')')[0]
+ else:
+ plcmt[2]=plcmt[2].split(')')[0]
+ #say("getting fp offset")
+ #say (plcmt)
+ #say (plcmt[0]+" x off");say (plcmt[1]+" y off")
+ create=0
+ if "fp_line" in line:
+ if "Dwgs" in line:
+ layer=0; color=None; create=1
+ if "Cmts" in line:
+ layer="Cmts"; color=1; create=1
+ if "Edge" in line:
+ layer="Edge"; color=2; create=1
+ if "Eco1" in line:
+ layer="Eco1"; color=3; create=1
+ if "Eco2" in line:
+ layer="Eco2"; color=4; create=1
+ if "F.Fab" in line:
+ layer="FFab"; color=5; create=1
+ if "B.Fab" in line:
+ layer="BFab"; color=6; create=1
+ if "F.CrtYd" in line:
+ layer="FCrtYd"; color=7; create=1
+ if "B.CrtYd" in line:
+ layer="BCrtYd"; color=8; create=1
+ if create==1:
+ coords=line.split('(',1)[-1]
+ coords=coords.split(" ")
+ #say(coords[4]+";"+coords[5][:-1]+" "+layer)
+ #say(coords)
+ if len (plcmt)<=2:
+ xs=float(coords[2])+float(plcmt[0]);ys=-float(coords[3].split(')')[0])-float(plcmt[1])
+ xe=float(coords[5])+float(plcmt[0]);ye=-float(coords[6].split(')')[0])-float(plcmt[1])
+ else:
+ rot_angle=float(plcmt[2])
+ crx=float(plcmt[0]);cry=-float(plcmt[1])
+ xs1=float(coords[2])+float(plcmt[0]);ys1=-float(coords[3].split(')')[0])-float(plcmt[1])
+ xe1=float(coords[5])+float(plcmt[0]);ye1=-float(coords[6].split(')')[0])-float(plcmt[1])
+ r1=sqrt((crx-xs1)**2+(cry-ys1)**2)
+ base_angle1=degrees(atan2(ys1-cry, xs1-crx))
+ #say(str(rot_angle)+ " rot angle")
+ #say(str(base_angle1)+ " angle1")
+ r2=sqrt((crx-xe1)**2+(cry-ye1)**2)
+ base_angle2=degrees(atan2(ye1-cry, xe1-crx))
+ #say(str(base_angle2)+ " angle2")
+ #say(str(r1)+ " r1");say(str(r2)+ " r2")
+ #say(str(cx)+ " cx");say(str(cy)+ " cy")
+ #say (rot_angle);say (cx); say(cy)
+ xs=crx-r1*cos(radians(-rot_angle+base_angle1));ys=cry-r1*sin(radians(-rot_angle+base_angle1))
+ xe=crx-r2*cos(radians(-rot_angle+base_angle2));ye=cry-r2*sin(radians(-rot_angle+base_angle2))
+ #say(str(xs)+" xs "+str(ys)+" ys "+str(xe)+" xe "+str(ye)+" ye");
+ #xs=float(coords[4]);ys=-float(coords[5][:-1])
+ #xe=float(coords[7]);ye=-float(coords[8][:-1])
+ #say (plcmt[0]+" x off")
+ #say (str(float(plcmt[0]))+" x off")
+ #say(str(xs)+";"+str(ys)+" module")
+ #data.append(str(xs)+";"+str(ys))
+ dxf.add_line((xs,ys), (xe,ye), layer, color, linetype=None)
+ create=0
+ if "fp_circle" in line:
+ if "Dwgs" in line:
+ layer=0; color=None; create=1
+ if "Cmts" in line:
+ layer="Cmts"; color=1; create=1
+ if "Edge" in line:
+ layer="Edge"; color=2; create=1
+ if "Eco1" in line:
+ layer="Eco1"; color=3; create=1
+ if "Eco2" in line:
+ layer="Eco2"; color=4; create=1
+ if "F.Fab" in line:
+ layer="FFab"; color=5; create=1
+ if "B.Fab" in line:
+ layer="BFab"; color=6; create=1
+ if "F.CrtYd" in line:
+ layer="FCrtYd"; color=7; create=1
+ if "B.CrtYd" in line:
+ layer="BCrtYd"; color=8; create=1
+ if create==1:
+ coords=line.split('(',1)[-1]
+ coords=coords.split(" ")
+ #say(coords[4]+";"+coords[5][:-1])
+ if len (plcmt)<=2:
+ cx=float(coords[2])+float(plcmt[0]);cy=-float(coords[3].split(')')[0])-float(plcmt[1])
+ xe=float(coords[5])+float(plcmt[0]);ye=-float(coords[6].split(')')[0])-float(plcmt[1])
+ data.append(str(cx)+";"+str(cy))
+ r=sqrt((cx-xe)**2+(cy-ye)**2)
+ dxf.add_circle((cx, cy), r, layer, color, linetype=None)
+ else:
+ rot_angle=float(plcmt[2])
+ crx=float(plcmt[0]);cry=-float(plcmt[1]) #rotation point
+ ocx=float(coords[2])+float(plcmt[0]);ocy=-float(coords[3].split(')')[0])-float(plcmt[1]) #center of circle
+ xe=float(coords[5])+float(plcmt[0]);ye=-float(coords[6].split(')')[0])-float(plcmt[1])
+ r1=sqrt((crx-ocx)**2+(cry-ocy)**2)
+ base_angle1=degrees(atan2(cry-ocy, crx-ocx))
+ #say(str(rot_angle)+ " rot angle")
+ #say(str(base_angle1)+ " angle1")
+ #say(str(r1)+ " r1");say(str(r2)+ " r2")
+ #say(str(cx)+ " cx");say(str(cy)+ " cy")
+ #say (rot_angle);say (cx); say(cy)
+ ncx=crx+r1*cos(radians(-rot_angle+base_angle1));ncy=cry+r1*sin(radians(-rot_angle+base_angle1))
+ data.append(str(ncx)+";"+str(ncy))
+ r=sqrt((ocx-xe)**2+(ocy-ye)**2)
+ dxf.add_circle((ncx, ncy), r, layer, color, linetype=None)
+ #say(str(xs)+" xs "+str(ys)+" ys "+str(xe)+" xe "+str(ye)+" ye");
+
+ #cx=float(coords[4]);cy=-float(coords[5][:-1])
+ #xe=float(coords[7]);ye=-float(coords[8][:-1])
+ # data.append(str(cx)+";"+str(cy))
+ # r=sqrt((cx-xe)**2+(cy-ye)**2)
+ #dxf.add_circle((cx, cy), r, layer, color, linetype=None)
+ create=0
+ if "fp_arc" in line:
+ if "Dwgs" in line:
+ layer=0; color=None; create=1
+ if "Cmts" in line:
+ layer="Cmts"; color=1; create=1
+ if "Edge" in line:
+ layer="Edge"; color=2; create=1
+ if "Eco1" in line:
+ layer="Eco1"; color=3; create=1
+ if "Eco2" in line:
+ layer="Eco2"; color=4; create=1
+ if "F.Fab" in line:
+ layer="FFab"; color=5; create=1
+ if "B.Fab" in line:
+ layer="BFab"; color=6; create=1
+ if "F.CrtYd" in line:
+ layer="FCrtYd"; color=7; create=1
+ if "B.CrtYd" in line:
+ layer="BCrtYd"; color=8; create=1
+ if create==1:
+ coords=line.split('(',1)[-1]
+ coords=coords.split(" ")
+ #say(coords[4]+";"+coords[5][:-1])
+ cx=float(coords[2])+float(plcmt[0]);cy=-float(coords[3].split(')')[0])-float(plcmt[1])
+ xe=float(coords[5])+float(plcmt[0]);ye=-float(coords[6].split(')')[0])-float(plcmt[1])
+ #cx=float(coords[4]);cy=-float(coords[5][:-1])
+ #xe=float(coords[7]);ye=-float(coords[8][:-1])
+ arc_angle=float(coords[8].split(')')[0])
+ #arc_angle=float(coords[10][:-1])
+ #endAngle = degrees(atan2(ye-cy, xe-cx))
+ #startAngle = (endAngle-arc_angle)
+ if arc_angle<0:
+ startAngle = degrees(atan2(ye-cy, xe-cx))
+ endAngle = (startAngle-arc_angle)
+ else:
+ endAngle = degrees(atan2(ye-cy, xe-cx))
+ startAngle = (endAngle-arc_angle)
+ center = (cx, cy, 0) # int or float
+ r = sqrt((cx-xe)**2+(cy-ye)**2)
+ #say(str(startAngle)+";"+str(endAngle))
+ if len (plcmt)<=2:
+ data.append(str(cx)+";"+str(cy))
+ dxf.add_arc(center, r, startAngle, endAngle, layer, color, linetype=None)
+ else:
+ rot_angle=float(plcmt[2])
+ crx=float(plcmt[0]);cry=-float(plcmt[1]) #rotation point
+ ocx=cx; ocy=cy #center of circle
+ r1=sqrt((crx-ocx)**2+(cry-ocy)**2)
+ base_angle1=degrees(atan2(cry-ocy, crx-ocx))
+ #say(str(rot_angle)+ " rot angle")
+ #say(str(base_angle1)+ " angle1")
+ #say(str(r1)+ " r1");say(str(r2)+ " r2")
+ #say(str(cx)+ " cx");say(str(cy)+ " cy")
+ #say (rot_angle);say (cx); say(cy)
+ ncx=crx+r1*cos(radians(-rot_angle+base_angle1));ncy=cry+r1*sin(radians(-rot_angle+base_angle1))
+ data.append(str(ncx)+";"+str(ncy))
+ center = (ncx, ncy, 0) # int or float
+ r2=sqrt((crx-xe)**2+(cry-ye)**2)
+ base_angle2=degrees(atan2(cry-ye, crx-xe))
+ xe2=crx-r2*cos(radians(-rot_angle+base_angle2));ye2=cry-r2*sin(radians(-rot_angle+base_angle2))
+ if arc_angle+rot_angle>0:
+ startAngle = degrees(atan2(ye2-ncy, xe2-ncx))
+ endAngle = (startAngle-arc_angle)
+ else:
+ endAngle = degrees(atan2(ye2-ncy, xe2-ncx))
+ startAngle = (endAngle-arc_angle)
+ #r=sqrt((ocx-xe)**2+(ocy-ye)**2)
+ dxf.add_arc(center, r, startAngle, endAngle, layer, color, linetype=None)
+ #say(str(xs)+" xs "+str(ys)+" ys "+str(xe)+" xe "+str(ye)+" ye");
+ create=0
+ if "gr_line" in line:
+ if "Dwgs" in line:
+ layer=0; color=None; create=1
+ if "Cmts" in line:
+ layer="Cmts"; color=1; create=1
+ if "Edge" in line:
+ layer="Edge"; color=2; create=1
+ if "Eco1" in line:
+ layer="Eco1"; color=3; create=1
+ if "Eco2" in line:
+ layer="Eco2"; color=4; create=1
+ if "F.Fab" in line:
+ layer="FFab"; color=5; create=1
+ if "B.Fab" in line:
+ layer="BFab"; color=6; create=1
+ if "F.CrtYd" in line:
+ layer="FCrtYd"; color=7; create=1
+ if "B.CrtYd" in line:
+ layer="BCrtYd"; color=8; create=1
+ if create==1:
+ coords=line.split('(',1)[-1]
+ coords=coords.split(" ")
+ #say(coords[4]+";"+coords[5][:-1]+" "+layer)
+ #say(coords)
+ xs=float(coords[2]);ys=-float(coords[3].split(')')[0])
+ xe=float(coords[5]);ye=-float(coords[6].split(')')[0])
+ #xs=float(coords[4]);ys=-float(coords[5][:-1])
+ #xe=float(coords[7]);ye=-float(coords[8][:-1])
+ #data.append(str(xs)+";"+str(ys))
+ dxf.add_line((xs,ys), (xe,ye), layer, color, linetype=None)
+ create=0
+ if "gr_circle" in line:
+ if "Dwgs" in line:
+ layer=0; color=None; create=1
+ if "Cmts" in line:
+ layer="Cmts"; color=1; create=1
+ if "Edge" in line:
+ layer="Edge"; color=2; create=1
+ if "Eco1" in line:
+ layer="Eco1"; color=3; create=1
+ if "Eco2" in line:
+ layer="Eco2"; color=4; create=1
+ if "F.Fab" in line:
+ layer="FFab"; color=5; create=1
+ if "B.Fab" in line:
+ layer="BFab"; color=6; create=1
+ if "F.CrtYd" in line:
+ layer="FCrtYd"; color=7; create=1
+ if "B.CrtYd" in line:
+ layer="BCrtYd"; color=8; create=1
+ if create==1:
+ coords=line.split('(',1)[-1]
+ coords=coords.split(" ")
+ #say(coords[4]+";"+coords[5][:-1])
+ cx=float(coords[2]);cy=-float(coords[3].split(')')[0])
+ xe=float(coords[5]);ye=-float(coords[6].split(')')[0])
+ #cx=float(coords[4]);cy=-float(coords[5][:-1])
+ #xe=float(coords[7]);ye=-float(coords[8][:-1])
+ data.append(str(cx)+";"+str(cy))
+ r=sqrt((cx-xe)**2+(cy-ye)**2)
+ dxf.add_circle((cx, cy), r, layer, color, linetype=None)
+ create=0
+ if "gr_arc" in line:
+ if "Dwgs" in line:
+ layer=0; color=None; create=1
+ if "Cmts" in line:
+ layer="Cmts"; color=1; create=1
+ if "Edge" in line:
+ layer="Edge"; color=2; create=1
+ if "Eco1" in line:
+ layer="Eco1"; color=3; create=1
+ if "Eco2" in line:
+ layer="Eco2"; color=4; create=1
+ if "F.Fab" in line:
+ layer="FFab"; color=5; create=1
+ if "B.Fab" in line:
+ layer="BFab"; color=6; create=1
+ if "F.CrtYd" in line:
+ layer="FCrtYd"; color=7; create=1
+ if "B.CrtYd" in line:
+ layer="BCrtYd"; color=8; create=1
+ if create==1:
+ coords=line.split('(',1)[-1]
+ coords=coords.split(" ")
+ #say(coords[4]+";"+coords[5][:-1])
+ cx=float(coords[2]);cy=-float(coords[3].split(')')[0])
+ xe=float(coords[5]);ye=-float(coords[6].split(')')[0])
+ #cx=float(coords[4]);cy=-float(coords[5][:-1])
+ #xe=float(coords[7]);ye=-float(coords[8][:-1])
+ arc_angle=float(coords[8].split(')')[0])
+ #say(arc_angle)
+ #arc_angle=float(coords[10][:-1])
+ data.append(str(cx)+";"+str(cy))
+ #endAngle = degrees(atan2(ye-cy, xe-cx))
+ #startAngle = (endAngle-arc_angle)
+ if arc_angle<0:
+ startAngle = degrees(atan2(ye-cy, xe-cx))
+ endAngle = (startAngle-arc_angle)
+ else:
+ endAngle = degrees(atan2(ye-cy, xe-cx))
+ startAngle = (endAngle-arc_angle)
+ center = (cx, cy, 0) # int or float
+ r = sqrt((cx-xe)**2+(cy-ye)**2)
+ #say(str(startAngle)+";"+str(endAngle))
+ dxf.add_arc(center, r, startAngle, endAngle, layer, color, linetype=None)
+ #createTxt=0
+ if "gr_text" in line:
+ if "Dwgs" in line:
+ layer=0; color=None; createTxt=1
+ if "Cmts" in line:
+ layer="Cmts"; color=1; createTxt=1
+ if "Edge" in line:
+ layer="Edge"; color=2; createTxt=1
+ if "Eco1" in line:
+ layer="Eco1"; color=3; createTxt=1
+ if "Eco2" in line:
+ layer="Eco2"; color=4; createTxt=1
+ if "F.Fab" in line:
+ layer="FFab"; color=5; createTxt=1
+ if "B.Fab" in line:
+ layer="BFab"; color=6; createTxt=1
+ if "F.CrtYd" in line:
+ layer="FCrtYd"; color=7; createTxt=1
+ if "B.CrtYd" in line:
+ layer="BCrtYd"; color=8; createTxt=1
+ if createTxt==1:
+ #(gr_text Rotate (at 325.374 52.705 15) (layer Eco2.User)
+ line=line.strip().split("(gr_text ")[1].split("(at")
+ text=line[0].replace("\"", "").replace("\'", "")
+ #say(line[1].split(" "))
+ px=line[1].split(" ")[1];py=line[1].split(" ")[2].replace(")", "")
+ if "layer" not in line[1].split(" ")[3]:
+ rot=line[1].split(" ")[3].replace(")", "")
+ else:
+ rot="0"
+ #say(line);say(text);say(px+";"+py+";"+rot)
+ if "(effects" in line and createTxt==1:
+ createTxt=0
+ size=(line.split("(size ")[1].split(" "))
+ #say (line)
+ #sizeX=int(round(float(size[0])))
+ #sizeY=int(round(float(size[1].replace(")", ""))))
+ sizeX=(float(size[0]))
+ sizeY=(float(size[1].replace(")", "")))
+ #say(sizeX);say(sizeY)
+ text1=text.split("\\n")
+ #say (text1)
+ #say (len(text1))
+ posY=-float(py)
+ # multiline support
+ if dimension==1 and quote_layer:
+ color=quote_color
+ layer="Quote"
+ dimension=0
+ for txt in text1:
+ dxf.add_text(txt,(float(px),posY),sizeX,sizeY,align,float(rot),0.,'SIMPLEX',layer,color)
+ posY=posY-sizeY*1.3
+ align="LEFT"
+ # dxf.add_text(text,(float(px),-float(py)),sizeX,sizeY,"LEFT",float(rot),0.,'STANDARD',layer,color)
+ if "(dimension" in line:
+ dimension=1;align="MIDDLE_CENTER"
+ if "(feature" in line or "(crossbar" in line or "(arrow" in line:
+ dimension_bar=line.split("(xy")
+ #say(dimension_bar)
+ dsx=float(dimension_bar[1].split(" ")[1])
+ dsy=float(dimension_bar[1].split(" ")[2].replace(")",""))
+ dex=float(dimension_bar[2].split(" ")[1])
+ dey=float(dimension_bar[2].split(" ")[2].replace(")",""))
+ #say(str(dsx)+";"+str(dsy)+";;"+str(dex)+";"+str(dey))
+ dxf.add_line((dsx,-dsy), (dex,-dey), layer, color, linetype=None)
+ #say (data)
+
+
+ wx.MessageDialog(None, "SAVED board to dxf --> "+out_filename+" written\n\n'pcb2dxf' version: "+___version___, 'DXF exported', wx.OK | wx.ICON_INFORMATION).ShowModal()
+### end export_dxf
+
+pcb2dxf().register()
+
+PREFACE = """ 0
+SECTION
+ 2
+HEADER
+ 9
+$ACADVER
+ 1
+AC1009
+ 9
+$DWGCODEPAGE
+ 3
+ANSI_1252
+ 0
+ENDSEC
+ 0
+SECTION
+ 2
+TABLES
+ 0
+TABLE
+ 2
+LTYPE
+ 5
+431
+ 70
+20
+ 0
+LTYPE
+ 5
+40F
+ 2
+CONTINUOUS
+ 70
+0
+ 3
+Solid line
+ 72
+65
+ 73
+0
+ 40
+0.0
+ 0
+LTYPE
+ 5
+410
+ 2
+CENTER
+ 70
+0
+ 3
+Center ____ _ ____ _ ____ _ ____ _ ____ _ ____
+ 72
+65
+ 73
+4
+ 40
+2.0
+ 49
+1.25
+ 49
+-0.25
+ 49
+0.25
+ 49
+-0.25
+ 0
+LTYPE
+ 5
+411
+ 2
+DASHED
+ 70
+0
+ 3
+Dashed __ __ __ __ __ __ __ __ __ __ __ __ __ _
+ 72
+65
+ 73
+2
+ 40
+0.75
+ 49
+0.5
+ 49
+-0.25
+ 0
+LTYPE
+ 5
+412
+ 2
+PHANTOM
+ 70
+0
+ 3
+Phantom ______ __ __ ______ __ __ ______
+ 72
+65
+ 73
+6
+ 40
+2.5
+ 49
+1.25
+ 49
+-0.25
+ 49
+0.25
+ 49
+-0.25
+ 49
+0.25
+ 49
+-0.25
+ 0
+LTYPE
+ 5
+413
+ 2
+HIDDEN
+ 70
+0
+ 3
+Hidden __ __ __ __ __ __ __ __ __ __ __ __ __ __
+ 72
+65
+ 73
+2
+ 40
+9.525
+ 49
+6.345
+ 49
+-3.175
+ 0
+LTYPE
+ 5
+43B
+ 2
+CENTERX2
+ 70
+0
+ 3
+Center (2x) ________ __ ________ __ ________
+ 72
+65
+ 73
+4
+ 40
+3.5
+ 49
+2.5
+ 49
+-0.25
+ 49
+0.5
+ 49
+-0.25
+ 0
+LTYPE
+ 5
+43C
+ 2
+CENTER2
+ 70
+0
+ 3
+Center (.5x) ____ _ ____ _ ____ _ ____ _ ____
+ 72
+65
+ 73
+4
+ 40
+1.0
+ 49
+0.625
+ 49
+-0.125
+ 49
+0.125
+ 49
+-0.125
+ 0
+LTYPE
+ 5
+43D
+ 2
+DASHEDX2
+ 70
+0
+ 3
+Dashed (2x) ____ ____ ____ ____ ____ ____
+ 72
+65
+ 73
+2
+ 40
+1.2
+ 49
+1.0
+ 49
+-0.2
+ 0
+LTYPE
+ 5
+43E
+ 2
+DASHED2
+ 70
+0
+ 3
+Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ 72
+65
+ 73
+2
+ 40
+0.3
+ 49
+0.25
+ 49
+-0.05
+ 0
+LTYPE
+ 5
+43F
+ 2
+PHANTOMX2
+ 70
+0
+ 3
+Phantom (2x)____________ ____ ____ ____________
+ 72
+65
+ 73
+6
+ 40
+4.25
+ 49
+2.5
+ 49
+-0.25
+ 49
+0.5
+ 49
+-0.25
+ 49
+0.5
+ 49
+-0.25
+ 0
+LTYPE
+ 5
+440
+ 2
+PHANTOM2
+ 70
+0
+ 3
+Phantom (.5x) ___ _ _ ___ _ _ ___ _ _ ___ _ _ ___
+ 72
+65
+ 73
+6
+ 40
+1.25
+ 49
+0.625
+ 49
+-0.125
+ 49
+0.125
+ 49
+-0.125
+ 49
+0.125
+ 49
+-0.125
+ 0
+LTYPE
+ 5
+441
+ 2
+DASHDOT
+ 70
+0
+ 3
+Dash dot __ . __ . __ . __ . __ . __ . __ . __
+ 72
+65
+ 73
+4
+ 40
+1.4
+ 49
+1.0
+ 49
+-0.2
+ 49
+0.0
+ 49
+-0.2
+ 0
+LTYPE
+ 5
+442
+ 2
+DASHDOTX2
+ 70
+0
+ 3
+Dash dot (2x) ____ . ____ . ____ . ____
+ 72
+65
+ 73
+4
+ 40
+2.4
+ 49
+2.0
+ 49
+-0.2
+ 49
+0.0
+ 49
+-0.2
+ 0
+LTYPE
+ 5
+443
+ 2
+DASHDOT2
+ 70
+0
+ 3
+Dash dot (.5x) _ . _ . _ . _ . _ . _ . _ . _
+ 72
+65
+ 73
+4
+ 40
+0.7
+ 49
+0.5
+ 49
+-0.1
+ 49
+0.0
+ 49
+-0.1
+ 0
+LTYPE
+ 5
+444
+ 2
+DOT
+ 70
+0
+ 3
+Dot . . . . . . . . . . . . . . . .
+ 72
+65
+ 73
+2
+ 40
+0.2
+ 49
+0.0
+ 49
+-0.2
+ 0
+LTYPE
+ 5
+445
+ 2
+DOTX2
+ 70
+0
+ 3
+Dot (2x) . . . . . . . .
+ 72
+65
+ 73
+2
+ 40
+0.4
+ 49
+0.0
+ 49
+-0.4
+ 0
+LTYPE
+ 5
+446
+ 2
+DOT2
+ 70
+0
+ 3
+Dot (.5) . . . . . . . . . . . . . . . . . . .
+ 72
+65
+ 73
+2
+ 40
+0.1
+ 49
+0.0
+ 49
+-0.1
+ 0
+LTYPE
+ 5
+447
+ 2
+DIVIDE
+ 70
+0
+ 3
+Divide __ . . __ . . __ . . __ . . __ . . __
+ 72
+65
+ 73
+6
+ 40
+1.6
+ 49
+1.0
+ 49
+-0.2
+ 49
+0.0
+ 49
+-0.2
+ 49
+0.0
+ 49
+-0.2
+ 0
+LTYPE
+ 5
+448
+ 2
+DIVIDEX2
+ 70
+0
+ 3
+Divide (2x) ____ . . ____ . . ____ . . ____
+ 72
+65
+ 73
+6
+ 40
+2.6
+ 49
+2.0
+ 49
+-0.2
+ 49
+0.0
+ 49
+-0.2
+ 49
+0.0
+ 49
+-0.2
+ 0
+LTYPE
+ 5
+449
+ 2
+DIVIDE2
+ 70
+0
+ 3
+Divide(.5x) _ . _ . _ . _ . _ . _ . _ . _
+ 72
+65
+ 73
+6
+ 40
+0.8
+ 49
+0.5
+ 49
+-0.1
+ 49
+0.0
+ 49
+-0.1
+ 49
+0.0
+ 49
+-0.1
+ 0
+ENDTAB
+ 0
+TABLE
+ 2
+STYLE
+ 5
+433
+ 70
+18
+ 0
+STYLE
+ 5
+417
+ 2
+STANDARD
+ 70
+0
+ 40
+0.0
+ 41
+1.0
+ 50
+0.0
+ 71
+0
+ 42
+0.2
+ 3
+txt
+ 4
+
+ 0
+STYLE
+ 5
+44A
+ 2
+ARIAL
+ 70
+0
+ 40
+0.0
+ 41
+1.0
+ 50
+0.0
+ 71
+0
+ 42
+1.0
+ 3
+arial.ttf
+ 4
+
+ 0
+STYLE
+ 5
+44F
+ 2
+ARIAL_NARROW
+ 70
+0
+ 40
+0.0
+ 41
+1.0
+ 50
+0.0
+ 71
+0
+ 42
+1.0
+ 3
+arialn.ttf
+ 4
+
+ 0
+STYLE
+ 5
+453
+ 2
+ISOCPEUR
+ 70
+0
+ 40
+0.0
+ 41
+1.0
+ 50
+0.0
+ 71
+0
+ 42
+1.0
+ 3
+isocpeur.ttf
+ 4
+
+ 0
+STYLE
+ 5
+455
+ 2
+TIMES
+ 70
+0
+ 40
+0.0
+ 41
+1.0
+ 50
+0.0
+ 71
+0
+ 42
+1.0
+ 3
+times.ttf
+ 4
+
+ 0
+ENDTAB
+ 0
+TABLE
+ 2
+VIEW
+ 5
+434
+ 70
+0
+ 0
+ENDTAB
+ 0
+ENDSEC
+"""