From 657bb38a4742917d70a547d93e4a9cba3f22fb07 Mon Sep 17 00:00:00 2001 From: easyw Date: Fri, 14 Apr 2017 16:04:57 +0200 Subject: [PATCH] kicad-PCB-2-DXF added --- README.md | 37 +- action_menu_pcb2dxf.py | 1265 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1299 insertions(+), 3 deletions(-) create mode 100644 action_menu_pcb2dxf.py 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: ![Annular Check](screenshots/annular-checker.gif) -## 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 +"""