diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..06703cd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,51 @@
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files, back
+*.cab
+*.msi
+*.msm
+*.msp
+*.bak
+
+# Windows shortcuts
+*.lnk
+
+# Python executable
+*.pyc
+
+# =========================
+# Operating System Files
+# =========================
+
+# OSX
+# =========================
+
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
diff --git a/AnnularChecker/.gitignore b/AnnularChecker/.gitignore
new file mode 100644
index 0000000..06703cd
--- /dev/null
+++ b/AnnularChecker/.gitignore
@@ -0,0 +1,51 @@
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files, back
+*.cab
+*.msi
+*.msm
+*.msp
+*.bak
+
+# Windows shortcuts
+*.lnk
+
+# Python executable
+*.pyc
+
+# =========================
+# Operating System Files
+# =========================
+
+# OSX
+# =========================
+
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
diff --git a/AnnularChecker/AnnularDlg.fbp b/AnnularChecker/AnnularDlg.fbp
new file mode 100644
index 0000000..0b33042
--- /dev/null
+++ b/AnnularChecker/AnnularDlg.fbp
@@ -0,0 +1,870 @@
+
+
+
+
+
diff --git a/AnnularChecker/AnnularDlg.py b/AnnularChecker/AnnularDlg.py
new file mode 100644
index 0000000..98a071c
--- /dev/null
+++ b/AnnularChecker/AnnularDlg.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+
+###########################################################################
+## Class AnnularDlg
+###########################################################################
+
+class AnnularDlg ( wx.Dialog ):
+
+ def __init__( self, parent ):
+ wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Annular Ring Checker", pos = wx.DefaultPosition, size = wx.Size( 380,317 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER )
+
+ self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+
+ bSizer3 = wx.BoxSizer( wx.VERTICAL )
+
+ self.m_bitmapAR = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer3.Add( self.m_bitmapAR, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 )
+
+ self.m_LabelTitle = wx.StaticText( self, wx.ID_ANY, u"Check annular ring", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_LabelTitle.Wrap( -1 )
+
+ bSizer3.Add( self.m_LabelTitle, 0, wx.ALL|wx.EXPAND, 5 )
+
+ self.m_staticline8 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
+ bSizer3.Add( self.m_staticline8, 0, wx.EXPAND |wx.ALL, 5 )
+
+ gSizer1 = wx.GridSizer( 0, 2, 0, 0 )
+
+ self.m_staticTextARV = wx.StaticText( self, wx.ID_ANY, u"AR Vias (mm)", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticTextARV.Wrap( -1 )
+
+ gSizer1.Add( self.m_staticTextARV, 0, wx.ALL, 5 )
+
+ self.m_textCtrlARV = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer1.Add( self.m_textCtrlARV, 0, wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+ self.m_staticTextARP = wx.StaticText( self, wx.ID_ANY, u"AR Pads (mm)", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticTextARP.Wrap( -1 )
+
+ gSizer1.Add( self.m_staticTextARP, 0, wx.ALL, 5 )
+
+ self.m_textCtrlARP = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer1.Add( self.m_textCtrlARP, 0, wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+ self.m_staticTextPHD = wx.StaticText( self, wx.ID_ANY, u"PH Drill margin (mm)", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticTextPHD.Wrap( -1 )
+
+ self.m_staticTextPHD.Enable( False )
+
+ gSizer1.Add( self.m_staticTextPHD, 1, wx.ALL, 5 )
+
+ self.m_textCtrlPHD = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_textCtrlPHD.Enable( False )
+
+ gSizer1.Add( self.m_textCtrlPHD, 0, wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+ self.m_checkBoxPHD = wx.CheckBox( self, wx.ID_ANY, u"use drill size as finished hole size", wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer1.Add( self.m_checkBoxPHD, 0, wx.ALL, 5 )
+
+
+ bSizer3.Add( gSizer1, 1, wx.ALIGN_CENTER|wx.ALL, 5 )
+
+ bSizer1 = wx.BoxSizer( wx.HORIZONTAL )
+
+
+ bSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 )
+
+ self.m_buttonOK = wx.Button( self, wx.ID_OK, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 )
+
+ self.m_buttonOK.SetDefault()
+ bSizer1.Add( self.m_buttonOK, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+ self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer1.Add( self.m_buttonCancel, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+
+ bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 )
+
+ bSizer4 = wx.BoxSizer( wx.VERTICAL )
+
+
+ bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 )
+
+
+ self.SetSizer( bSizer3 )
+ self.Layout()
+
+ self.Centre( wx.BOTH )
+
+ def __del__( self ):
+ pass
+
+
diff --git a/AnnularChecker/AnnularResultDlg.fbp b/AnnularChecker/AnnularResultDlg.fbp
new file mode 100644
index 0000000..5b31e95
--- /dev/null
+++ b/AnnularChecker/AnnularResultDlg.fbp
@@ -0,0 +1,356 @@
+
+
+
+
+
+ Python
+ 1
+ source_name
+ 0
+ 0
+ res
+ UTF-8
+ connect
+ AnnularResultDlg
+ 1000
+ none
+
+ 0
+ AnnularResultDlg
+
+ .
+
+ 1
+ 1
+ 1
+ 1
+ UI
+ 0
+ 0
+
+ 0
+ wxAUI_MGR_DEFAULT
+
+ wxBOTH
+
+ 1
+ 1
+ impl_virtual
+
+
+
+ 0
+ wxID_ANY
+
+
+ AnnularResultDlg
+
+ 383,521
+ wxDEFAULT_DIALOG_STYLE
+ ; forward_declare
+ Annular Checker
+
+
+
+
+
+
+ bSizer1
+ wxVERTICAL
+ none
+
+ 5
+ wxEXPAND
+ 1
+
+
+ bSizer2
+ wxVERTICAL
+ none
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticTitle
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+ wxEXPAND | wxALL
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+ -1,400
+ 1
+ m_richTextResult
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxTE_READONLY
+ ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+ wxVSCROLL|wxHSCROLL|wxNO_BORDER|wxWANTS_CHARS
+
+
+
+ 5
+ wxEXPAND
+ 1
+
+ 2
+ 0
+
+ gSizer3
+ none
+ 0
+ 0
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+
+ 0
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_ANY
+ OK
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ ok_btn
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+
+ 0
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_ANY
+ Copy Text
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ copy_btn
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AnnularChecker/AnnularResultDlg.py b/AnnularChecker/AnnularResultDlg.py
new file mode 100644
index 0000000..71d10a4
--- /dev/null
+++ b/AnnularChecker/AnnularResultDlg.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+import wx.richtext
+
+###########################################################################
+## Class AnnularResultDlg
+###########################################################################
+
+class AnnularResultDlg ( wx.Dialog ):
+
+ def __init__( self, parent ):
+ wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Annular Checker", pos = wx.DefaultPosition, size = wx.Size( 383,521 ), style = wx.DEFAULT_DIALOG_STYLE )
+
+ self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+
+ bSizer1 = wx.BoxSizer( wx.VERTICAL )
+
+ bSizer2 = wx.BoxSizer( wx.VERTICAL )
+
+ self.m_staticTitle = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticTitle.Wrap( -1 )
+
+ bSizer2.Add( self.m_staticTitle, 0, wx.ALL, 5 )
+
+ self.m_richTextResult = wx.richtext.RichTextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_READONLY|wx.VSCROLL|wx.HSCROLL|wx.NO_BORDER|wx.WANTS_CHARS )
+ self.m_richTextResult.SetMinSize( wx.Size( -1,400 ) )
+
+ bSizer2.Add( self.m_richTextResult, 1, wx.EXPAND |wx.ALL, 5 )
+
+ gSizer3 = wx.GridSizer( 0, 2, 0, 0 )
+
+ self.ok_btn = wx.Button( self, wx.ID_ANY, u"OK", wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer3.Add( self.ok_btn, 0, wx.ALL, 5 )
+
+ self.copy_btn = wx.Button( self, wx.ID_ANY, u"Copy Text", wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer3.Add( self.copy_btn, 0, wx.ALL, 5 )
+
+
+ bSizer2.Add( gSizer3, 1, wx.EXPAND, 5 )
+
+
+ bSizer1.Add( bSizer2, 1, wx.EXPAND, 5 )
+
+
+ self.SetSizer( bSizer1 )
+ self.Layout()
+
+ self.Centre( wx.BOTH )
+
+ def __del__( self ):
+ pass
+
+
diff --git a/AnnularChecker/__init__.py b/AnnularChecker/__init__.py
new file mode 100644
index 0000000..7caa4ab
--- /dev/null
+++ b/AnnularChecker/__init__.py
@@ -0,0 +1,2 @@
+from .annular_checker import annular_check
+annular_check().register()
diff --git a/AnnularChecker/annular.png b/AnnularChecker/annular.png
new file mode 100644
index 0000000..319fed8
Binary files /dev/null and b/AnnularChecker/annular.png differ
diff --git a/AnnularChecker/annular_checker.py b/AnnularChecker/annular_checker.py
new file mode 100644
index 0000000..25254e6
--- /dev/null
+++ b/AnnularChecker/annular_checker.py
@@ -0,0 +1,464 @@
+# -*- coding: utf-8 -*-
+#
+# A script to check for annular ring violations
+# both for TH pads and vias
+# requirements: KiCAD pcbnew >= 4.0
+# annular.py release "1.5.1"
+#
+# annular.py checking PCB for Annular Ring in Vias and TH Pads
+# (SMD, Connector and NPTH are skipped)
+# default Annular Ring >= 0.15 both for TH Pads and Vias
+#
+
+#### plugins errors
+#import pcbnew;pcbnew.GetWizardsBackTrace()
+
+global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V, found_violations, LogMsg, ___version___
+
+___version___="1.6.3"
+
+#wx.LogMessage("My message")
+mm_ius = 1000000.0
+# (consider always drill +0.1)
+DRL_EXTRA=0.1
+DRL_EXTRA_ius=DRL_EXTRA * mm_ius
+
+AR_SET = 0.125 #minimum annular accepted for pads
+MIN_AR_SIZE = AR_SET * mm_ius
+
+AR_SET_V = 0.125 #minimum annular accepted for vias
+MIN_AR_SIZE_V = AR_SET_V * mm_ius
+
+import sys
+import wx
+import wx.richtext
+#import subprocess
+import os
+import pcbnew
+from pcbnew import *
+# import base64
+# from wx.lib.embeddedimage import PyEmbeddedImage
+
+from . import AnnularDlg
+from . import AnnularResultDlg
+
+sys.path.append(os.path.dirname(__file__))
+
+debug = False
+def wxLogDebug(msg,dbg):
+ """printing messages only if show is omitted or True"""
+ if dbg == True:
+ wx.LogMessage(msg)
+#
+
+class AnnularResult_Dlg(AnnularResultDlg.AnnularResultDlg):
+ # from https://github.com/MitjaNemec/Kicad_action_plugins
+ # hack for new wxFormBuilder generating code incompatible with old wxPython
+ # noinspection PyMethodOverriding
+ def SetSizeHints(self, sz1, sz2):
+ if wx.__version__ < '4.0':
+ self.SetSizeHintsSz(sz1, sz2)
+ else:
+ super(AnnularResult_Dlg, self).SetSizeHints(sz1, sz2)
+
+ def onOK(self, event):
+ self.Destroy()
+ #return self.EndModal(wx.ID_OK) # if modal_result == wx.ID_OK:
+
+ def OnClickCopy(self, event):
+ self.m_richTextResult.SelectAll()
+ self.m_richTextResult.Copy()
+ #global LogMsg
+ #copy2clip(LogMsg)
+ self.copy_btn.SetLabel("Text Copied")
+
+ # def onDeleteClick(self, event):
+ # return self.EndModal(wx.ID_DELETE)
+ #
+ # def onConnectClick(self, event):
+ # return self.EndModal(wx.ID_REVERT)
+
+ def __init__(self, parent):
+ import wx
+ AnnularResultDlg.AnnularResultDlg.__init__(self, parent)
+ #self.GetSizer().Fit(self)
+ self.SetMinSize(self.GetSize())
+ #### ----- connections
+ # Connect Events
+ self.Bind(wx.EVT_BUTTON, self.onOK, self.ok_btn)
+ #self.ok_btn.Bind(wx.EVT_BUTTON, self.EndModal(wx.ID_OK))
+ self.Bind(wx.EVT_BUTTON, self.OnClickCopy, self.copy_btn)
+ self.ok_btn.SetFocus()
+ # Tooltips
+ self.copy_btn.SetToolTip( wx.ToolTip(u"Copy Text to Clipboard" ))
+ self.ok_btn.SetToolTip( wx.ToolTip(u"Exit" ))
+
+ #def onOK(self, event):
+ # return self.EndModal(wx.ID_OK) # if modal_result == wx.ID_OK:
+
+ #def onConnectClick(self, event):
+ # return self.EndModal(wx.ID_REVERT)
+
+ #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
+ #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick)
+ #if wx.__version__ < '4.0':
+ # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+ #else:
+ # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+
+class Annular_Dlg(AnnularDlg.AnnularDlg):
+ # from https://github.com/MitjaNemec/Kicad_action_plugins
+ # hack for new wxFormBuilder generating code incompatible with old wxPython
+ # noinspection PyMethodOverriding
+ def SetSizeHints(self, sz1, sz2):
+ if wx.__version__ < '4.0':
+ self.SetSizeHintsSz(sz1, sz2)
+ else:
+ super(Annular_Dlg, self).SetSizeHints(sz1, sz2)
+
+ def __init__(self, parent):
+ import wx
+ AnnularDlg.AnnularDlg.__init__(self, parent)
+ #self.GetSizer().Fit(self)
+ self.SetMinSize(self.GetSize())
+ #c1.Bind(wx.EVT_CHECKBOX, self.OntextMetric, c1)
+ #self.m_checkBoxPHD.Bind(wx.EVT_CHECKBOX, self.OnClickCheck, self.m_checkBoxPHD)
+ self.m_checkBoxPHD.Bind(wx.EVT_CHECKBOX, self.OnClickCheck)
+ self.m_bitmapAR.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./annular.png")))
+
+ #self.Bind(wx.EVT_CHECKBOX, self.OnClickCheck)
+ #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
+ #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick)
+ #if wx.__version__ < '4.0':
+ # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+ #else:
+ # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+ def OnClickCheck(self, event):
+ #self.Destroy()
+ if self.m_checkBoxPHD.IsChecked():
+ #self.Destroy()
+ self.m_staticTextPHD.Enable()
+ self.m_textCtrlPHD.Enable()
+ else:
+ self.m_staticTextPHD.Disable()
+ self.m_textCtrlPHD.Disable()
+
+ # def onDeleteClick(self, event):
+ # return self.EndModal(wx.ID_DELETE)
+ #
+ # def onConnectClick(self, event):
+ # return self.EndModal(wx.ID_REVERT)
+
+
+# Python plugin stuff
+class annular_check( pcbnew.ActionPlugin ):
+ """
+ A script to check for annular ring violations
+ both for TH pads and vias
+ requirements: KiCAD pcbnew >= 4.0
+ AR_SET minimum annular accepted for pads
+ AR_SET_V minimum annular accepted for vias
+ """
+ global ___version___
+ 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 = "Annular checker \nversion "+___version___
+ self.category = "Checking PCB"
+ self.description = "Automaticaly check annular on an existing PCB"
+ #self.pcbnew_icon_support = hasattr(self, "show_toolbar_button")
+ self.show_toolbar_button = True
+ self.icon_file_name = os.path.join(os.path.dirname(__file__), 'annular.png')
+
+ def Run( self ):
+ import sys,os
+ #mm_ius = 1000000.0
+ _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
+ #aParameters = RoundTrackDlg(None)
+ aParameters = Annular_Dlg(_pcbnew_frame)
+ aParameters.m_LabelTitle.SetLabel("Check annular ring: version: "+___version___)
+ aParameters.m_textCtrlARP.SetToolTip( wx.ToolTip(u"Annular Ring for Pads (mm)" ))
+ aParameters.m_staticTextPHD.SetToolTip( wx.ToolTip(u"Drill extra margin (mm)" ))
+ aParameters.m_textCtrlARV.SetToolTip( wx.ToolTip(u"Annular Ring for Vias (mm)" ))
+ aParameters.m_staticTextARV.SetToolTip( wx.ToolTip(u"Annular Ring for Vias (mm)" ))
+ aParameters.m_textCtrlPHD.SetToolTip( wx.ToolTip(u"Drill extra margin (mm)" ))
+ aParameters.m_staticTextARP.SetToolTip( wx.ToolTip(u"Drill extra margin (mm)" ))
+ aParameters.m_checkBoxPHD.SetToolTip( wx.ToolTip(u"use drill size as finished hole size\nadding an extra drill margin" ))
+ aParameters.m_textCtrlPHD.SetValue('0.1')
+ aParameters.m_textCtrlARP.SetValue('0.125')
+ aParameters.m_textCtrlARV.SetValue('0.125')
+ aParameters.Show()
+ modal_result = aParameters.ShowModal()
+ #import pcbnew;pcbnew.GetWizardsBackTrace()
+ if modal_result == wx.ID_OK:
+ global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V
+ phd = float(aParameters.m_textCtrlPHD.GetValue().replace(',','.'))
+ ar = float(aParameters.m_textCtrlARP.GetValue().replace(',','.'))
+ arv = float(aParameters.m_textCtrlARV.GetValue().replace(',','.'))
+ if aParameters.m_checkBoxPHD.IsChecked():
+ DRL_EXTRA=phd
+ DRL_EXTRA_ius=DRL_EXTRA * mm_ius
+ else:
+ DRL_EXTRA=0
+ DRL_EXTRA_ius=DRL_EXTRA * mm_ius
+ AR_SET = ar #minimum annular accepted for pads
+ MIN_AR_SIZE = AR_SET * mm_ius
+
+ AR_SET_V = arv #minimum annular accepted for vias
+ MIN_AR_SIZE_V = AR_SET_V * mm_ius
+ #snap2grid(gridSizeMM,use_grid_origin)
+ calculate_AR()
+ else:
+ None # Cancel
+
+
+def annring_size(pad):
+ # valid for oval pad/drills
+ annrX=(pad.GetSize()[0] - (pad.GetDrillSize()[0]+DRL_EXTRA_ius))/2
+ annrY=(pad.GetSize()[1] - (pad.GetDrillSize()[1]+DRL_EXTRA_ius))/2
+ #annr=min(pad.GetSize()) - max(pad.GetDrillSize())
+ #if annr < MIN_AR_SIZE:
+ #print annrX
+ #print annrY
+ #print pad.GetSize()[0]/mm_ius
+ #print pad.GetSize()[0]#/mm_ius
+ #print pad.GetDrillSize()[0]#/mm_ius
+ #print DRL_EXTRA_ius
+ #print pad.GetDrillSize()[0]/mm_ius
+ #print (pad.GetDrillSize()[0]+DRL_EXTRA_ius)/mm_ius
+ #print annrX/mm_ius
+ return min(annrX,annrY)
+
+def annringNP_size(pad):
+ # valid for oval pad/drills
+ annrX=(pad.GetSize()[0] - (pad.GetDrillSize()[0]))/2
+ annrY=(pad.GetSize()[1] - (pad.GetDrillSize()[1]))/2
+ #annr=min(pad.GetSize()) - max(pad.GetDrillSize())
+ #if annr < MIN_AR_SIZE:
+ #print annrX
+ #print annrY
+ #print pad.GetSize()[0]/mm_ius
+ #print pad.GetSize()[0]#/mm_ius
+ #print pad.GetDrillSize()[0]#/mm_ius
+ #print DRL_EXTRA_ius
+ #print pad.GetDrillSize()[0]/mm_ius
+ #print (pad.GetDrillSize()[0]+DRL_EXTRA_ius)/mm_ius
+ #print annrX/mm_ius
+ #return min(annrX,annrY)
+ return annrX,annrY
+
+def vias_annring_size(via):
+ # calculating via annular
+ annr=(via.GetWidth() - (via.GetDrillValue()+DRL_EXTRA_ius))/2
+ #print via.GetWidth()
+ #print via.GetDrillValue()
+ return annr
+
+def f_mm(raw):
+ return repr(raw/mm_ius)
+
+
+def calculate_AR():
+ global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V
+ board = pcbnew.GetBoard()
+ PassC=FailC=0
+ PassCV=FailCV=0
+
+ PassCN=FailCN=0
+ PassCVN=FailCVN=0
+
+ fileName = GetBoard().GetFileName()
+ if len(fileName)==0:
+ wx.LogMessage("a board needs to be saved/loaded!")
+ else:
+ found_violations=False
+ _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
+ aResult = AnnularResult_Dlg(_pcbnew_frame)
+ #import pcbnew;pcbnew.GetWizardsBackTrace()
+ writeTxt= aResult.m_richTextResult.WriteText
+ rt = aResult.m_richTextResult
+ rt.BeginItalic()
+ writeTxt("'action_menu_annular_check.py'\n")
+ #frame.m_richText1.WriteText("'action_menu_annular_check.py'\n")
+ LogMsg=""
+ msg="'action_menu_annular_check.py'\n"
+ msg+="version = "+___version___
+ writeTxt("version = "+___version___)
+ msg+="\nTesting PCB for Annular Rings\nTH Pads >= "+repr(AR_SET)+" Vias >= "+repr(AR_SET_V)+"\nPHD margin on PTH = "+ repr(DRL_EXTRA)
+ writeTxt("\nTesting PCB for Annular Rings\nTH Pads >= "+repr(AR_SET)+" Vias >= "+repr(AR_SET_V)+"\nPHD margin on PTH = "+ repr(DRL_EXTRA))
+ rt.EndItalic()
+ writeTxt('\n\n')
+ #print (msg)
+ LogMsg+=msg+'\n\n'
+
+ # print "LISTING VIAS:"
+ for item in board.GetTracks():
+ if type(item) is pcbnew.VIA:
+ pos = item.GetPosition()
+ drill = item.GetDrillValue()
+ width = item.GetWidth()
+ ARv = vias_annring_size(item)
+ if ARv < MIN_AR_SIZE_V:
+ # print("AR violation at %s." % (pad.GetPosition() / mm_ius )) Raw units, needs fixing
+ XYpair = item.GetPosition()
+ msg="AR Via violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])
+ rt.BeginTextColour('red')
+ writeTxt("AR Via violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])+'\n')
+ rt.EndTextColour()
+ #print (msg)
+ LogMsg+=msg+'\n'
+ FailCV = FailCV+1
+ else:
+ PassCV = PassCV+1
+ #print type(item)
+
+ msg="VIAS that Pass = "+repr(PassCV)+"; Fails = "+repr(FailCV)
+ if FailCV >0:
+ rt.BeginBold()
+ writeTxt("VIAS that Pass = "+repr(PassCV)+"; ")
+ if FailCV >0:
+ rt.BeginTextColour('red')
+ writeTxt("Fails = "+repr(FailCV)+'\n\n')
+ if FailCV >0:
+ rt.EndTextColour()
+ rt.EndBold()
+ print(msg)
+ LogMsg+=msg+'\n'
+
+ for module in board.GetModules():
+ try:
+ module_Pads=module.PadsList()
+ except:
+ module_Pads=module.Pads()
+ for pad in module_Pads: #print(pad.GetAttribute())
+ if pad.GetAttribute() == PAD_ATTRIB_STANDARD: #TH pad
+ ARv = annring_size(pad)
+ #print(f_mm(ARv))
+ if ARv < MIN_AR_SIZE:
+ # print("AR violation at %s." % (pad.GetPosition() / mm_ius )) Raw units, needs fixing
+ XYpair = pad.GetPosition()
+ msg="AR PTH violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])
+ rt.BeginTextColour('red')
+ writeTxt("AR PTH violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])+'\n')
+ rt.EndTextColour()
+ #print (msg)
+ LogMsg+=msg+'\n'
+ FailC = FailC+1
+ else:
+ PassC = PassC+1
+ if pad.GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED:
+ ARvX, ARvY = annringNP_size(pad)
+ #print(f_mm(ARvX));print(f_mm(ARvY))
+ if (ARvX) != 0 or ARvY != 0:
+ ARv = min(ARvX, ARvY)
+ if ARv < MIN_AR_SIZE:
+ # print("AR violation at %s." % (pad.GetPosition() / mm_ius )) Raw units, needs fixing
+ XYpair = pad.GetPosition()
+ msg="AR NPTH warning of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])
+ rt.BeginTextColour('red')
+ writeTxt("AR NPTH warning of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])+'\n')
+ rt.EndTextColour()
+ #print (msg)
+ LogMsg+=msg+'\n'
+ FailCN = FailCN+1
+ else:
+ PassCN = PassCN+1
+ else:
+ PassCN = PassCN+1
+
+ #if FailCV >0:
+ #writeTxt('\n')
+ msg = "TH PADS that Pass = "+repr(PassC)+"; Fails = "+repr(FailC)
+ if FailC >0:
+ rt.BeginBold()
+ writeTxt("TH PADS that Pass = "+repr(PassC)+"; ")
+ if FailC >0:
+ rt.BeginTextColour('red')
+ writeTxt("Fails = "+repr(FailC)+'\n')
+ if FailC >0:
+ rt.EndTextColour()
+ rt.EndBold()
+ print(msg)
+ LogMsg+=msg+'\n'
+
+ msg="NPTH PADS that Pass = "+repr(PassCN)+"; Fails = "+repr(FailCN)
+ #writeTxt('\n')
+ if FailCN >0:
+ rt.BeginBold()
+ writeTxt("NPTH PADS that Pass = "+repr(PassCN)+"; ")
+ if FailCN >0:
+ rt.BeginTextColour('red')
+ writeTxt("Fails = "+repr(FailCN)+'\n')
+ if FailC >0:
+ rt.EndTextColour()
+ rt.EndBold()
+ print(msg)
+ LogMsg+=msg+'\n'
+
+ pcbName = (os.path.splitext(GetBoard().GetFileName())[0]) #filename no ext
+ #wx.LogMessage(pcbName)#LogMsg)
+ ##wx.LogMessage(LogMsg)
+ FC=r"C:\FreeCAD\bin\freecad.exe"
+ kSU=r"C:\Cad\Progetti_K\3D-FreeCad-tools\kicad-StepUp-tools.FCMacro"
+ #subprocess.check_call([FC, kSU, pcbName])
+ ##p = subprocess.Popen([FC, kSU, pcbName])
+
+ #found_violations=False
+ if (FailC+FailCN+FailCV)>0:
+ found_violations=True
+
+ if found_violations:
+ #frame.m_staticTitle = wx.StaticText(frame, label=" Check result: (Violations found)")
+ aResult.m_staticTitle.SetLabel(" Check result: (Violations found)")
+ #self.title.SetForegroundColour('#FF0000')
+ aResult.m_staticTitle.SetBackgroundColour('#FF0000')
+ font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD)
+ aResult.m_staticTitle.SetFont(font)
+ else:
+ #frame.m_staticTitle = wx.StaticText(frame, label=" Annular Check result: OK")
+ aResult.m_staticTitle.SetLabel(" Annular Check result: OK")
+ aResult.m_staticTitle.SetBackgroundColour('#00FF00')
+ font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD)
+ aResult.m_staticTitle.SetFont(font)
+
+
+ aResult.Show()
+ #modal_result = aResult.ShowModal()
+ #if modal_result == wx.ID_OK:
+ # aResult.Destroy()
+ #if modal_result == wx.ID_OK:
+ # aResult.Destroy()
+
+
+# annular_check().register()
+if __name__ == "__main__":
+ import argparse
+
+ parser = argparse.ArgumentParser(
+ description='KiCad PCB Annular Checker')
+ parser.add_argument('file', type=str, help="KiCad PCB file")
+ args = parser.parse_args()
+ print("Loading %s" % args.file)
+ main(pcbnew.LoadBoard(args.file))
+
+else:
+ annular_check().register()
+
+
+# execfile("annular.py")
+# annular.py Testing PCB for Annular Ring >= 0.15
+# AR violation of 0.1 at XY 172.974,110.744
+# VIAS that Pass = 100 Fails = 1
+# AR violation of 0.1 at XY 172.212,110.744
+# AR violation of 0.0 at XY 154.813,96.52
+# PADS that Pass = 49 Fails = 2
+
diff --git a/AnnularChecker/annular_ico.svg b/AnnularChecker/annular_ico.svg
new file mode 100644
index 0000000..e6c157e
--- /dev/null
+++ b/AnnularChecker/annular_ico.svg
@@ -0,0 +1,214 @@
+
+
diff --git a/AnnularChecker/tkinter-test.txt b/AnnularChecker/tkinter-test.txt
new file mode 100644
index 0000000..7ea4f49
--- /dev/null
+++ b/AnnularChecker/tkinter-test.txt
@@ -0,0 +1,2 @@
+import _tkinter
+import tkSimpleDialog
\ No newline at end of file
diff --git a/FabricationPositions/.gitignore b/FabricationPositions/.gitignore
new file mode 100644
index 0000000..06703cd
--- /dev/null
+++ b/FabricationPositions/.gitignore
@@ -0,0 +1,51 @@
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files, back
+*.cab
+*.msi
+*.msm
+*.msp
+*.bak
+
+# Windows shortcuts
+*.lnk
+
+# Python executable
+*.pyc
+
+# =========================
+# Operating System Files
+# =========================
+
+# OSX
+# =========================
+
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
diff --git a/FabricationPositions/PositionsDlg.fbp b/FabricationPositions/PositionsDlg.fbp
new file mode 100644
index 0000000..6eeb1cf
--- /dev/null
+++ b/FabricationPositions/PositionsDlg.fbp
@@ -0,0 +1,553 @@
+
+
+
+
+
+ Python
+ 1
+ source_name
+ 0
+ 0
+ res
+ UTF-8
+ connect
+ PositionsDlg
+ 1000
+ none
+
+ 0
+ PositionsDlg
+
+ .
+
+ 1
+ 1
+ 1
+ 1
+ UI
+ 0
+ 0
+
+ 0
+ wxAUI_MGR_DEFAULT
+
+ wxBOTH
+
+ 1
+ 1
+ impl_virtual
+
+
+
+ 0
+ wxID_ANY
+
+
+ PositionsDlg
+
+ 499,296
+ wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER
+
+ Generating Fab Positions
+
+
+
+
+
+
+ bSizer3
+ wxVERTICAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Generating Modules Fab Positions
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_comment
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+ wxALIGN_CENTER_HORIZONTAL|wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_bitmapFab
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ ; ; forward_declare
+ 0
+
+
+
+
+
+
+
+ 5
+ wxEXPAND | wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticline2
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxLI_HORIZONTAL
+ ; ; forward_declare
+ 0
+
+
+
+
+
+
+
+ 5
+
+ 0
+
+
+ bSizer31
+ wxHORIZONTAL
+ none
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Output DIR
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticText4
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+ ; ; forward_declare
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+
+ 0
+
+ 1
+ m_textCtrlDir
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+ ; ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+ grb
+
+
+
+
+
+
+
+
+ 5
+ wxALIGN_RIGHT|wxEXPAND
+ 0
+
+
+ bSizer1
+ wxHORIZONTAL
+ none
+
+ 5
+ wxEXPAND
+ 1
+
+ 0
+ protected
+ 0
+
+
+
+ 5
+ wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+
+ 1
+
+ 1
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_OK
+ Apply
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonOK
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+
+ 0
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_CANCEL
+ Cancel
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonCancel
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND
+ 1
+
+
+ bSizer4
+ wxVERTICAL
+ none
+
+
+
+
+
+
diff --git a/FabricationPositions/PositionsDlg.py b/FabricationPositions/PositionsDlg.py
new file mode 100644
index 0000000..36cd0c3
--- /dev/null
+++ b/FabricationPositions/PositionsDlg.py
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+
+###########################################################################
+## Class PositionsDlg
+###########################################################################
+
+class PositionsDlg ( wx.Dialog ):
+
+ def __init__( self, parent ):
+ wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Generating Fab Positions", pos = wx.DefaultPosition, size = wx.Size( 499,296 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER )
+
+ self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+
+ bSizer3 = wx.BoxSizer( wx.VERTICAL )
+
+ self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Generating Modules Fab Positions", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_comment.Wrap( -1 )
+
+ bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 )
+
+ self.m_bitmapFab = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer3.Add( self.m_bitmapFab, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 )
+
+ self.m_staticline2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
+ bSizer3.Add( self.m_staticline2, 0, wx.EXPAND |wx.ALL, 5 )
+
+ bSizer31 = wx.BoxSizer( wx.HORIZONTAL )
+
+ self.m_staticText4 = wx.StaticText( self, wx.ID_ANY, u"Output DIR", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticText4.Wrap( -1 )
+
+ bSizer31.Add( self.m_staticText4, 0, wx.ALL, 5 )
+
+ self.m_textCtrlDir = wx.TextCtrl( self, wx.ID_ANY, u"grb", wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer31.Add( self.m_textCtrlDir, 0, wx.ALL|wx.EXPAND, 5 )
+
+
+ bSizer3.Add( bSizer31, 0, 0, 5 )
+
+ bSizer1 = wx.BoxSizer( wx.HORIZONTAL )
+
+
+ bSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 )
+
+ self.m_buttonOK = wx.Button( self, wx.ID_OK, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 )
+
+ self.m_buttonOK.SetDefault()
+ bSizer1.Add( self.m_buttonOK, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+ self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer1.Add( self.m_buttonCancel, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+
+ bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 )
+
+ bSizer4 = wx.BoxSizer( wx.VERTICAL )
+
+
+ bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 )
+
+
+ self.SetSizer( bSizer3 )
+ self.Layout()
+
+ self.Centre( wx.BOTH )
+
+ def __del__( self ):
+ pass
+
+
diff --git a/FabricationPositions/__init__.py b/FabricationPositions/__init__.py
new file mode 100644
index 0000000..2b343d1
--- /dev/null
+++ b/FabricationPositions/__init__.py
@@ -0,0 +1,2 @@
+from .fabrication_positions import generatePOS
+generatePOS().register()
diff --git a/FabricationPositions/fabrication.png b/FabricationPositions/fabrication.png
new file mode 100644
index 0000000..ddad942
Binary files /dev/null and b/FabricationPositions/fabrication.png differ
diff --git a/FabricationPositions/fabrication.svg b/FabricationPositions/fabrication.svg
new file mode 100644
index 0000000..fead669
--- /dev/null
+++ b/FabricationPositions/fabrication.svg
@@ -0,0 +1,100 @@
+
+
diff --git a/FabricationPositions/fabricationPositions-old.png b/FabricationPositions/fabricationPositions-old.png
new file mode 100644
index 0000000..f3bbcdb
Binary files /dev/null and b/FabricationPositions/fabricationPositions-old.png differ
diff --git a/FabricationPositions/fabricationPositions-old.svg b/FabricationPositions/fabricationPositions-old.svg
new file mode 100644
index 0000000..e3d3124
--- /dev/null
+++ b/FabricationPositions/fabricationPositions-old.svg
@@ -0,0 +1,308 @@
+
+
diff --git a/FabricationPositions/fabricationPositions.png b/FabricationPositions/fabricationPositions.png
new file mode 100644
index 0000000..2aeec47
Binary files /dev/null and b/FabricationPositions/fabricationPositions.png differ
diff --git a/FabricationPositions/fabricationPositions.svg b/FabricationPositions/fabricationPositions.svg
new file mode 100644
index 0000000..54ed9a2
--- /dev/null
+++ b/FabricationPositions/fabricationPositions.svg
@@ -0,0 +1,302 @@
+
+
diff --git a/FabricationPositions/fabrication_positions.py b/FabricationPositions/fabrication_positions.py
new file mode 100644
index 0000000..98c1eb3
--- /dev/null
+++ b/FabricationPositions/fabrication_positions.py
@@ -0,0 +1,387 @@
+# -*- coding: utf-8 -*-
+#
+# A script to generate POS file for kicad_pcb
+# requirements: KiCAD pcbnew >= 4.0
+# release "1.1.1"
+# copyright Maurice easyw
+#
+# main script from https://forum.kicad.info/t/pcba-wants-all-parts-in-the-pos-file-not-just-smd/10045/6
+#
+
+### plugins errors
+#import pcbnew
+#pcbnew.GetWizardsBackTrace()
+
+
+___version___="1.2.2"
+#wx.LogMessage("My message")
+#mm_ius = 1000000.0
+
+import sys, os
+import pcbnew
+import datetime
+import wx
+from pcbnew import *
+import base64
+from wx.lib.embeddedimage import PyEmbeddedImage
+
+"""
+execfile ("C:/kicad-wb-1602/msys64/home/userC/out3Dm/pack-x86_64/share/kicad/scripting/plugins/getpos.py")
+"""
+
+def generate_POS(dir):
+ import os
+ mm_ius = 1000000.0
+
+ my_board = pcbnew.GetBoard()
+
+ fileName = pcbnew.GetBoard().GetFileName()
+
+ 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]
+ #wx.LogMessage(dir)
+ #lsep=os.linesep
+ lsep='\n'
+
+ if len(dir)>0:
+ dir = dir.rstrip('\\').rstrip('/')
+ if not os.path.exists(path+os.sep+dir):
+ #create dir
+ os.mkdir(path+os.sep+dir)
+ dir = dir+os.sep
+ #wx.LogMessage(dir)
+ else:
+ dir = dir+os.sep
+ #LogMsg1=lsep+"reading from:" + lsep + dirpath + lsep + lsep
+ out_filename_top_SMD=path+os.sep+dir+name+"_POS_top_SMD.txt"
+ out_filename_bot_SMD=path+os.sep+dir+name+"_POS_bot_SMD.txt"
+ out_filename_top_THD=path+os.sep+dir+name+"_POS_top_THD.txt"
+ out_filename_bot_THD=path+os.sep+dir+name+"_POS_bot_THD.txt"
+ out_filename_top_VIRTUAL=path+os.sep+dir+name+"_POS_top_Virtual.txt"
+ out_filename_bot_VIRTUAL=path+os.sep+dir+name+"_POS_bot_Virtual.txt"
+ out_filename_ALL=path+os.sep+dir+name+"_POS_All.txt"
+
+ Header_1="### Module positions - created on " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M")+lsep
+ Header_1+="### Printed by pcb_positions plugin"+lsep
+ Header_1+="## Unit = mm, Angle = deg."+lsep
+ #LogMsg+="## Side : All"+lsep
+ Header_2="## Board Aux Origin: " + str(my_board.GetAuxOrigin())+lsep
+
+ Header_2+="{0:<10}".format("# Ref")+"{0:<20}".format("Val")+"{0:<20}".format("Package")+\
+ "{0:<11}".format("PosX")+"{0:<11}".format("PosY")+"{0:<8}".format(" Rot")+\
+ "{0:<10}".format(" Side")+" Type"+lsep
+ content_top_SMD=''
+ content_bot_SMD=''
+ content_top_THD=''
+ content_bot_THD=''
+ content_top_VIRTUAL=''
+ content_bot_VIRTUAL=''
+ content_ALL=''
+ SMD_pads = 0
+ TH_pads = 0
+ Virt_pads = 0
+ TH_top_cnt = 0
+ TH_bot_cnt = 0
+ SMD_top_cnt = 0
+ SMD_bot_cnt = 0
+ Virt_top_cnt = 0
+ Virt_bot_cnt = 0
+
+ bb = my_board.GetBoardEdgesBoundingBox()
+ pcb_height = bb.GetHeight() / mm_ius
+ pcb_width = bb.GetWidth() / mm_ius
+ #to add relative position to
+ #print ("Board Aux Origin: " + str(my_board.GetAuxOrigin()))
+
+ #'{0:<10} {1:<10} {2:<10}'.format(1.0, 2.2, 4.4))
+
+ tracks = my_board.GetTracks()
+ vias = []
+ for via in tracks:
+ if type(via) is pcbnew.VIA:
+ vias.append(via)
+ vias_cnt = len(vias)
+
+ for module in my_board.GetModules():
+ #print ("%s \"%s\" %s %1.3f %1.3f %1.3f %s" % ( module.GetReference(),
+ #Nchars = 20
+ # RefL = 10; ValL = 20
+
+ md=""
+ if module.GetAttributes() == 0: # PTH=0, SMD=1, Virtual = 2
+ md = "THD"
+ TH_pads+=module.GetPadCount()
+ elif module.GetAttributes() == 1:
+ md = "SMD"
+ SMD_pads+=module.GetPadCount()
+ else:
+ md = "VIRTUAL"
+ Virt_pads+=module.GetPadCount()
+
+ #Reference=str(module.GetReference()).ljust(Nchars/2)
+ #Value=str(module.GetValue()).ljust(Nchars)
+ #Package=str(module.GetFPID().GetLibItemName()).ljust(Nchars)
+ #X_POS=str(pcbnew.ToMM(module.GetPosition().x - my_board.GetAuxOrigin().x ))
+ #Y_POS=str(-1*pcbnew.ToMM(module.GetPosition().y - my_board.GetAuxOrigin().y))
+ #Rotation=str(module.GetOrientation()/10)
+ #Layer="top".ljust(Nchars) if module.GetLayer() == 0 else "bottom".ljust(Nchars)
+ #Type=md
+ Reference="{0:<10}".format(str(module.GetReference()))
+ Value = str(module.GetValue())
+ Value=(Value[:17] + '..') if len(Value) > 19 else Value
+ Value="{0:<20}".format(Value)
+ Package = str(module.GetFPID().GetLibItemName())
+ Package=(Package[:17] + '..') if len(Package) > 19 else Package
+ Package="{0:<20}".format(Package)
+ #Package="{0:<20}".format(str(module.GetFPID().GetLibItemName()))
+ X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - my_board.GetAuxOrigin().x ))
+ X_POS="{0:<11}".format(X_POS)
+ Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - my_board.GetAuxOrigin().y))
+ Y_POS="{0:<11}".format(Y_POS)
+ Rotation='{0:.1f}'.format((module.GetOrientation()/10))
+ Rotation="{0:>6}".format(Rotation)+' '
+ if module.GetLayer() == 0:
+ Layer=" top"
+ else:
+ Layer=" bottom"
+ #Side="## Side :"+Layer+lsep
+ Layer="{0:<10}".format(Layer)
+ Type=' '+md
+ content=Reference
+ content+=Value
+ content+=Package
+ content+=X_POS
+ content+=Y_POS
+ content+=Rotation
+ content+=Layer
+ content+=Type+lsep
+ if 'top' in Layer and 'SMD' in Type:
+ content_top_SMD+=content
+ SMD_top_cnt+=1
+ elif 'bot' in Layer and 'SMD' in Type:
+ content_bot_SMD+=content
+ SMD_bot_cnt+=1
+ elif 'top' in Layer and 'THD' in Type:
+ content_top_THD+=content
+ TH_top_cnt+=1
+ elif 'bot' in Layer and 'THD' in Type:
+ content_bot_THD+=content
+ TH_bot_cnt+=1
+ elif 'top' in Layer and 'VIRTUAL' in Type:
+ content_top_VIRTUAL+=content
+ Virt_top_cnt+=1
+ elif 'bot' in Layer and 'VIRTUAL' in Type:
+ content_bot_VIRTUAL+=content
+ Virt_bot_cnt+=1
+ content_ALL+=content
+ #print ("%s %s %s %1.4f %1.4f %1.4f %s %s" % ( str(module.GetReference()).ljust(Nchars),
+ # str(module.GetValue()).ljust(Nchars),
+ # str(module.GetFPID().GetLibItemName()).ljust(Nchars),
+ # pcbnew.ToMM(module.GetPosition().x - my_board.GetAuxOrigin().x ),
+ # -1*pcbnew.ToMM(module.GetPosition().y - my_board.GetAuxOrigin().y),
+ # module.GetOrientation()/10,
+ # "top".ljust(Nchars) if module.GetLayer() == 0 else "bottom".ljust(Nchars),
+ # md
+ # ))
+
+#"top" if module.GetLayer() == 0 else "bottom"
+
+ #LogMsg+="## End"+lsep
+
+ Header=Header_1+"## Side : top"+lsep+Header_2
+ content=Header+content_top_SMD+"## End"+lsep
+ with open(out_filename_top_SMD,'w') as f_out:
+ f_out.write(content)
+ Header=Header_1+"## Side : bottom"+lsep+Header_2
+ content=Header+content_bot_SMD+"## End"+lsep
+ with open(out_filename_bot_SMD,'w') as f_out:
+ f_out.write(content)
+ Header=Header_1+"## Side : top"+lsep+Header_2
+ content=Header+content_top_THD+"## End"+lsep
+ with open(out_filename_top_THD,'w') as f_out:
+ f_out.write(content)
+ Header=Header_1+"## Side : bottom"+lsep+Header_2
+ content=Header+content_bot_THD+"## End"+lsep
+ with open(out_filename_bot_THD,'w') as f_out:
+ f_out.write(content)
+ Header=Header_1+"## Side : top"+lsep+Header_2
+ content=Header+content_top_VIRTUAL+"## End"+lsep
+ with open(out_filename_top_VIRTUAL,'w') as f_out:
+ f_out.write(content)
+ Header=Header_1+"## Side : bottom"+lsep+Header_2
+ content=Header+content_bot_VIRTUAL+"## End"+lsep
+ with open(out_filename_bot_VIRTUAL,'w') as f_out:
+ f_out.write(content)
+ Header=Header_1+"## Side : ALL"+lsep+Header_2
+ content=Header+content_ALL+"## End"+lsep
+ content = content + '## '+ str(SMD_pads) + ' SMD pads' +lsep
+ content = content + '## '+ str(TH_pads) + ' TH pads' +lsep
+ content = content + '## '+ str(Virt_pads) + ' Virtual pads' +lsep
+ content = content + '## '+ str( TH_top_cnt) + ' Top TH modules' + lsep
+ content = content + '## '+ str( TH_bot_cnt) + ' Bot TH modules' + lsep
+ content = content + '## '+ str( SMD_top_cnt) + ' Top SMD modules' + lsep
+ content = content + '## '+ str( SMD_bot_cnt) + ' Bot SMD modules' + lsep
+ content = content + '## '+ str( Virt_top_cnt) + ' Top Virtual modules' + lsep
+ content = content + '## '+ str( Virt_bot_cnt) + ' Bot Virtual modules' + lsep
+
+ with open(out_filename_ALL,'w') as f_out:
+ f_out.write(content)
+
+ #with open(out_filename,'w') as f_out:
+ # f_out.write(LogMsg)
+ #LogMsg=""
+ #f = open(out_filename,'w')
+ #f.write(LogMsg)
+ #f.close()
+ LogMsg1="reading from:" + lsep + dirpath + lsep
+ LogMsg1+= lsep + 'Pads:' + lsep
+ LogMsg1+= 'SMD pads ' + str(SMD_pads) + lsep
+ LogMsg1+= 'TH pads ' + str(TH_pads) +lsep
+ LogMsg1+= 'Virtual pads ' + str(Virt_pads) + lsep
+ LogMsg1+= 'Vias ' + str( vias_cnt) + lsep
+ LogMsg1+= lsep + 'Modules:' + lsep
+ LogMsg1+= 'Top TH modules ' + str( TH_top_cnt) + lsep
+ LogMsg1+= 'Bot TH modules ' + str( TH_bot_cnt) + lsep
+ LogMsg1+= 'Top SMD modules ' + str( SMD_top_cnt) + lsep
+ LogMsg1+= 'Bot SMD modules ' + str( SMD_bot_cnt) + lsep
+ LogMsg1+= 'Top Virtual modules ' + str( Virt_top_cnt) + lsep
+ LogMsg1+= 'Bot Virtual modules ' + str( Virt_bot_cnt) + lsep
+ LogMsg1+= lsep + 'PCB Geometry:' + lsep
+ LogMsg1+= 'Pcb Height ' +'{0:.3f}'.format( pcb_height ) + 'mm, Pcb Width ' + '{0:.3f}'.format( pcb_width ) + 'mm' +lsep+'[based on Edge bounding box]' +lsep
+ LogMsg1+= lsep
+ #LogMsg1+=lsep+"reading from:" + lsep + dirpath + lsep + lsep
+ if 0:
+ LogMsg1+="written to:" + lsep + out_filename_top_SMD + lsep
+ LogMsg1+=out_filename_bot_SMD + lsep
+ LogMsg1+=out_filename_top_THD + lsep
+ LogMsg1+=out_filename_bot_THD + lsep
+ LogMsg1+=out_filename_top_VIRTUAL + lsep
+ LogMsg1+=out_filename_bot_VIRTUAL + lsep
+ LogMsg1+=out_filename_ALL + lsep
+ else:
+ LogMsg1+="written to:" + lsep + path+os.sep+dir + lsep
+
+ return LogMsg1
+ #return LogMsg1+LogMsg
+
+
+# Python plugin stuff
+from . import PositionsDlg
+
+class Positions_Dlg(PositionsDlg.PositionsDlg):
+ # from https://github.com/MitjaNemec/Kicad_action_plugins
+ # hack for new wxFormBuilder generating code incompatible with old wxPython
+ # noinspection PyMethodOverriding
+ def SetSizeHints(self, sz1, sz2):
+ if wx.__version__ < '4.0':
+ self.SetSizeHintsSz(sz1, sz2)
+ else:
+ super(Positions_Dlg, self).SetSizeHints(sz1, sz2)
+
+ #def onApplyClick(self, event):
+ # return self.EndModal(wx.ID_OK)
+ #
+ #def onCancelClick(self, event):
+ # return self.EndModal(wx.ID_CANCEL)
+
+ def __init__(self, parent):
+ import wx
+ PositionsDlg.PositionsDlg.__init__(self, parent)
+ #self.GetSizer().Fit(self)
+ self.SetMinSize(self.GetSize())
+ self.m_bitmapFab.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./fabrication.png")))
+ # self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
+ # self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick)
+ # if wx.__version__ < '4.0':
+ # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+ # else:
+ # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+#
+
+
+class generatePOS( pcbnew.ActionPlugin ):
+ """
+ A script to generate POS file for kicad_pcb
+ requirements: KiCAD pcbnew >= 4.0
+ release "1.0.1"
+
+ """
+
+ 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 = "Fabrication Footprint Position \nversion "+___version___
+ self.category = "Fabrication Output"
+ self.description = "Generate POS output for SMD, THD, Virtual\nand Board Statistics"
+ #self.SetIcon(PyEmbeddedImage(getPos_ico_b64_data).GetIcon())
+ self.icon_file_name = os.path.join(os.path.dirname(__file__), "./fabricationPositions.png")
+ self.show_toolbar_button = True
+
+ def Run( self ):
+
+ #wx.MessageDialog(self.frame,"ciao")
+ #subprocess.check_call(["C:\pathToYourProgram\yourProgram.exe", "your", "arguments", "comma", "separated"])
+ #http://stackoverflow.com/questions/1811691/running-an-outside-program-executable-in-python
+ #from https://github.com/MitjaNemec/Kicad_action_plugins
+ #hack wxFormBuilder py2/py3
+ _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
+ aParameters = Positions_Dlg(_pcbnew_frame)
+ aParameters.Show()
+ modal_result = aParameters.ShowModal()
+ if modal_result == wx.ID_OK:
+ DirName = aParameters.m_textCtrlDir.GetValue()
+ #wx.LogMessage(DirName)
+ #wx.LogMessage(LayerName+';'+str(LayerIndex)+';'+LayerStdName)
+ GenPos(DirName)
+ else:
+ None # Cancel
+
+
+def GenPos(dir):
+ def f_mm(raw):
+ return repr(raw/mm_ius)
+
+ board = pcbnew.GetBoard()
+
+ #fileName = GetBoard().GetFileName()
+ fileName = pcbnew.GetBoard().GetFileName()
+ if len(fileName)==0:
+ wx.MessageBox("a board needs to be saved/loaded!")
+ else:
+ LogMsg=''
+ # msg="'get_pos.py'"+os.linesep
+ msg="Generate POS output: version = "+___version___+os.linesep
+ #msg+="Generate POS output"+os.linesep
+ #print (msg)
+ #LogMsg=msg+'\n\n'
+
+ #print(msg)
+ LogMsg+=msg
+ reply=generate_POS(dir)
+ LogMsg+=reply
+ wx.LogMessage(LogMsg)
+
+ if 0:
+ frame = displayDialog(None)
+ #frame = wx.Frame(None)
+ frame.Center()
+ frame.setMsg(LogMsg)
+ frame.ShowModal()
+ frame.Destroy()
+ #frame = wx.wxFrame(None, 10110, 'T-Make', size=wx.wxSize(100,100),
+ # style=wx.wxSTAY_ON_TOP)
+ #frame.show()
+
+#generatePOS().register()
+
+# execfile("round_tracks.py")
+
diff --git a/MoveToLayer/.gitignore b/MoveToLayer/.gitignore
new file mode 100644
index 0000000..06703cd
--- /dev/null
+++ b/MoveToLayer/.gitignore
@@ -0,0 +1,51 @@
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files, back
+*.cab
+*.msi
+*.msm
+*.msp
+*.bak
+
+# Windows shortcuts
+*.lnk
+
+# Python executable
+*.pyc
+
+# =========================
+# Operating System Files
+# =========================
+
+# OSX
+# =========================
+
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
diff --git a/MoveToLayer/Move2LayerDlg.fbp b/MoveToLayer/Move2LayerDlg.fbp
new file mode 100644
index 0000000..dafcfc7
--- /dev/null
+++ b/MoveToLayer/Move2LayerDlg.fbp
@@ -0,0 +1,663 @@
+
+
+
+
+
+ Python
+ 1
+ source_name
+ 0
+ 0
+ res
+ UTF-8
+ connect
+ Move2LayerDlg
+ 1000
+ none
+
+ 0
+ Move2LayerDlg
+
+ .
+
+ 1
+ 1
+ 1
+ 1
+ UI
+ 0
+ 0
+
+ 0
+ wxAUI_MGR_DEFAULT
+
+ wxBOTH
+
+ 1
+ 1
+ impl_virtual
+
+
+
+ 0
+ wxID_ANY
+
+
+ Move2LayerDlg
+
+ 568,263
+ wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER
+
+ Move to Layer
+
+
+
+
+
+
+ bSizer3
+ wxVERTICAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Selected Objects will be Moved to chosen Layer
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_comment
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+
+ 0
+
+
+ bSizer31
+ wxHORIZONTAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Layer
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticTextLayer
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+ -1,-1
+ 0
+ -1,-1
+ 1
+ m_comboBoxLayer
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ -1
+ 1
+ 250,-1
+
+ ; ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+ Combo!
+
+
+
+
+
+
+ 5
+ wxALIGN_CENTER_VERTICAL|wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_bitmapLayers
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ ; ; forward_declare
+ 0
+
+
+
+
+
+
+
+ 5
+ wxALIGN_CENTER_VERTICAL|wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_bitmapDwgs
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ ; ; forward_declare
+ 0
+
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND | wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticline1
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxLI_HORIZONTAL
+ ; ; forward_declare
+ 0
+
+
+
+
+
+
+
+ 5
+ wxALIGN_RIGHT|wxEXPAND
+ 0
+
+
+ bSizer1
+ wxHORIZONTAL
+ none
+
+ 5
+ wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticText101
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+
+ 1
+
+ 1
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_OK
+ Apply
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonOK
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+
+ 0
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_CANCEL
+ Cancel
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonCancel
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND
+ 1
+
+
+ bSizer4
+ wxVERTICAL
+ none
+
+
+
+
+
+
diff --git a/MoveToLayer/Move2LayerDlg.py b/MoveToLayer/Move2LayerDlg.py
new file mode 100644
index 0000000..ad184af
--- /dev/null
+++ b/MoveToLayer/Move2LayerDlg.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+
+###########################################################################
+## Class Move2LayerDlg
+###########################################################################
+
+class Move2LayerDlg ( wx.Dialog ):
+
+ def __init__( self, parent ):
+ wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Move to Layer", pos = wx.DefaultPosition, size = wx.Size( 568,263 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER )
+
+ self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+
+ bSizer3 = wx.BoxSizer( wx.VERTICAL )
+
+ self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Selected Objects will be Moved to chosen Layer", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_comment.Wrap( -1 )
+
+ bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 )
+
+ bSizer31 = wx.BoxSizer( wx.HORIZONTAL )
+
+ self.m_staticTextLayer = wx.StaticText( self, wx.ID_ANY, u"Layer", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticTextLayer.Wrap( -1 )
+
+ bSizer31.Add( self.m_staticTextLayer, 1, wx.ALL|wx.EXPAND, 5 )
+
+ m_comboBoxLayerChoices = []
+ self.m_comboBoxLayer = wx.ComboBox( self, wx.ID_ANY, u"Combo!", wx.DefaultPosition, wx.Size( 250,-1 ), m_comboBoxLayerChoices, 0 )
+ bSizer31.Add( self.m_comboBoxLayer, 0, wx.ALL|wx.EXPAND, 5 )
+
+ self.m_bitmapLayers = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer31.Add( self.m_bitmapLayers, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+ self.m_bitmapDwgs = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer31.Add( self.m_bitmapDwgs, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+
+ bSizer3.Add( bSizer31, 0, 0, 5 )
+
+ self.m_staticline1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
+ bSizer3.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 )
+
+ bSizer1 = wx.BoxSizer( wx.HORIZONTAL )
+
+ self.m_staticText101 = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticText101.Wrap( -1 )
+
+ bSizer1.Add( self.m_staticText101, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )
+
+ self.m_buttonOK = wx.Button( self, wx.ID_OK, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 )
+
+ self.m_buttonOK.SetDefault()
+ bSizer1.Add( self.m_buttonOK, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
+
+ self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer1.Add( self.m_buttonCancel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
+
+
+ bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 )
+
+ bSizer4 = wx.BoxSizer( wx.VERTICAL )
+
+
+ bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 )
+
+
+ self.SetSizer( bSizer3 )
+ self.Layout()
+
+ self.Centre( wx.BOTH )
+
+ def __del__( self ):
+ pass
+
+
diff --git a/MoveToLayer/Move2LayerDlg.py.bak b/MoveToLayer/Move2LayerDlg.py.bak
new file mode 100644
index 0000000..3f5f403
--- /dev/null
+++ b/MoveToLayer/Move2LayerDlg.py.bak
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+
+###########################################################################
+## Class Move2LayerDlg
+###########################################################################
+
+class Move2LayerDlg ( wx.Dialog ):
+
+ def __init__( self, parent ):
+ wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Move to Layer", pos = wx.DefaultPosition, size = wx.Size( 325,190 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER )
+
+ self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+
+ bSizer3 = wx.BoxSizer( wx.VERTICAL )
+
+ self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Selected Objects to Move to chosen Layer", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_comment.Wrap( -1 )
+
+ bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 )
+
+ bSizer31 = wx.BoxSizer( wx.HORIZONTAL )
+
+ self.m_staticTextLayer = wx.StaticText( self, wx.ID_ANY, u"Layer", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticTextLayer.Wrap( -1 )
+
+ bSizer31.Add( self.m_staticTextLayer, 1, wx.ALL|wx.EXPAND, 5 )
+
+ m_comboBoxLayerChoices = []
+ self.m_comboBoxLayer = wx.ComboBox( self, wx.ID_ANY, u"Combo!", wx.DefaultPosition, wx.Size( 250,-1 ), m_comboBoxLayerChoices, 0 )
+ bSizer31.Add( self.m_comboBoxLayer, 0, wx.ALL|wx.EXPAND, 5 )
+
+
+ bSizer3.Add( bSizer31, 0, 0, 5 )
+
+ self.m_staticline1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
+ bSizer3.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 )
+
+ bSizer1 = wx.BoxSizer( wx.HORIZONTAL )
+
+ self.m_staticText101 = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticText101.Wrap( -1 )
+
+ bSizer1.Add( self.m_staticText101, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )
+
+ self.m_buttonOK = wx.Button( self, wx.ID_OK, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 )
+
+ self.m_buttonOK.SetDefault()
+ bSizer1.Add( self.m_buttonOK, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
+
+ self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer1.Add( self.m_buttonCancel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
+
+
+ bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 )
+
+
+ self.SetSizer( bSizer3 )
+ self.Layout()
+
+ self.Centre( wx.BOTH )
+
+ def __del__( self ):
+ pass
+
+
diff --git a/MoveToLayer/__init__.py b/MoveToLayer/__init__.py
new file mode 100644
index 0000000..fd5fc58
--- /dev/null
+++ b/MoveToLayer/__init__.py
@@ -0,0 +1,2 @@
+from .move_to_layer import move_to_draw_layer
+move_to_draw_layer().register()
diff --git a/MoveToLayer/add_polygon.png b/MoveToLayer/add_polygon.png
new file mode 100644
index 0000000..a2384a5
Binary files /dev/null and b/MoveToLayer/add_polygon.png differ
diff --git a/MoveToLayer/add_polygon.svg b/MoveToLayer/add_polygon.svg
new file mode 100644
index 0000000..9ab7fbc
--- /dev/null
+++ b/MoveToLayer/add_polygon.svg
@@ -0,0 +1,109 @@
+
+
diff --git a/MoveToLayer/move2layer.png b/MoveToLayer/move2layer.png
new file mode 100644
index 0000000..3e5b885
Binary files /dev/null and b/MoveToLayer/move2layer.png differ
diff --git a/MoveToLayer/move2layer.svg b/MoveToLayer/move2layer.svg
new file mode 100644
index 0000000..efa0bd3
--- /dev/null
+++ b/MoveToLayer/move2layer.svg
@@ -0,0 +1,200 @@
+
+
diff --git a/MoveToLayer/move_to_layer.py b/MoveToLayer/move_to_layer.py
new file mode 100644
index 0000000..86b0299
--- /dev/null
+++ b/MoveToLayer/move_to_layer.py
@@ -0,0 +1,162 @@
+# move_to_edge_cuts.py
+#
+# Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+#
+
+### plugins errors
+#import pcbnew
+#pcbnew.GetWizardsBackTrace()
+
+
+import wx
+import pcbnew
+from pcbnew import *
+import base64
+from wx.lib.embeddedimage import PyEmbeddedImage
+import os
+___version___="1.2.3"
+
+from . import Move2LayerDlg
+
+
+def MoveToLayer(pcb,layerId):
+ found_selected=False
+ for drw in pcb.GetDrawings():
+ if drw.IsSelected():
+ drw.SetLayer(layerId)
+ found_selected=True
+
+ if found_selected!=True:
+ LogMsg="select drawings to be moved to new layer\n"
+ LogMsg+="use GAL for selecting lines"
+ wx.LogMessage(LogMsg)
+ else:
+ pcbnew.Refresh()
+ layerName = pcbnew.GetBoard().GetLayerName(layerId)
+ LogMsg="selected drawings moved to "+layerName+" layer"
+ wx.LogMessage(LogMsg)
+#
+
+
+
+# Python plugin stuff
+
+class Move2Layer_Dlg(Move2LayerDlg.Move2LayerDlg):
+ # from https://github.com/MitjaNemec/Kicad_action_plugins
+ # hack for new wxFormBuilder generating code incompatible with old wxPython
+ # noinspection PyMethodOverriding
+ def SetSizeHints(self, sz1, sz2):
+ if wx.__version__ < '4.0':
+ self.SetSizeHintsSz(sz1, sz2)
+ else:
+ super(Move2Layer_Dlg, self).SetSizeHints(sz1, sz2)
+
+ #def onApplyClick(self, event):
+ # return self.EndModal(wx.ID_OK)
+ #
+ #def onCancelClick(self, event):
+ # return self.EndModal(wx.ID_CANCEL)
+
+ def __init__(self, parent):
+ import wx
+ Move2LayerDlg.Move2LayerDlg.__init__(self, parent)
+ #self.GetSizer().Fit(self)
+ self.SetMinSize(self.GetSize())
+
+ self.m_bitmapLayers.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./add_polygon.png")))
+ self.m_bitmapDwgs.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./move2layer.png")))
+ # self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
+ # self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick)
+ # if wx.__version__ < '4.0':
+ # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+ # else:
+ # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+#
+class move_to_draw_layer( pcbnew.ActionPlugin ):
+ """
+ A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL)
+ How to use:
+ - move to GAL
+ - select some draw objects
+ - call the plugin
+ - select the new layer
+ - selected draw objects will be moved to new layer
+ """
+
+ 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
+ """
+ import os
+ self.name = "Move Selected Drawings to chosen Layer \nversion "+___version___
+ self.category = "Modify PCB"
+ self.description = "Move Selected Drawings to chosen Layer on an existing PCB"
+ self.icon_file_name = os.path.join(os.path.dirname(__file__), "./move2layer.png")
+ self.show_toolbar_button = True
+
+ def Run( self ):
+ found_selected=False
+
+ board = pcbnew.GetBoard()
+ fileName = GetBoard().GetFileName()
+ # # dicts for converting layer name to id, used by _get_layer
+ # _std_layer_dict = {pcbnew.BOARD_GetStandardLayerName(n): n
+ # for n in range(pcbnew.PCB_LAYER_ID_COUNT)}
+ # #_std_layer_names = {s: n for n, s in _std_layer_dict.iteritems()}
+ # _std_layer_names = {s: n for n, s in _std_layer_dict.items()}
+ # _brd_layer_dict = {pcbnew.GetBoard().GetLayerName(n): n
+ # for n in range(pcbnew.PCB_LAYER_ID_COUNT)}
+ # #_std_layer_names = {s: n for n, s in _std_layer_dict.iteritems()}
+ # _brd_layer_names = {s: n for n, s in _brd_layer_dict.items()}
+
+
+ if 0: #len(fileName) == 0:
+ wx.LogMessage("A board needs to be saved/loaded\nto run the plugin!")
+ else:
+ #from https://github.com/MitjaNemec/Kicad_action_plugins
+ #hack wxFormBuilder py2/py3
+ _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
+ aParameters = Move2Layer_Dlg(_pcbnew_frame)
+ aParameters.Show()
+ for l in range(pcbnew.PCB_LAYER_ID_COUNT):
+ aParameters.m_comboBoxLayer.Append(pcbnew.GetBoard().GetLayerName(l))
+ aParameters.m_comboBoxLayer.Select(44)
+ modal_result = aParameters.ShowModal()
+ if modal_result == wx.ID_OK:
+ LayerName = aParameters.m_comboBoxLayer.GetStringSelection()
+ LayerIndex = aParameters.m_comboBoxLayer.FindString(LayerName)
+ LayerStdName = pcbnew.BOARD_GetStandardLayerName(LayerIndex)
+ #wx.LogMessage(LayerName+';'+str(LayerIndex)+';'+LayerStdName)
+ MoveToLayer(board, LayerIndex)
+ else:
+ None # Cancel
+
+ LogMsg=''
+ msg="'move to layer tool'\n"
+ msg+="version = "+___version___
+
+
+#move_to_draw_layer().register()
+
diff --git a/MoveToLayer/move_to_layer.py.bak b/MoveToLayer/move_to_layer.py.bak
new file mode 100644
index 0000000..6a1a950
--- /dev/null
+++ b/MoveToLayer/move_to_layer.py.bak
@@ -0,0 +1,154 @@
+# move_to_edge_cuts.py
+#
+# Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+#
+
+import wx
+import pcbnew
+from pcbnew import *
+import base64
+from wx.lib.embeddedimage import PyEmbeddedImage
+import os
+___version___="1.2.3"
+
+from . import Move2LayerDlg
+
+
+def MoveToLayer(pcb,layerId):
+ found_selected=False
+ for drw in pcb.GetDrawings():
+ if drw.IsSelected():
+ drw.SetLayer(layerId)
+ found_selected=True
+
+ if found_selected!=True:
+ LogMsg="select drawings to be moved to new layer\n"
+ LogMsg+="use GAL for selecting lines"
+ wx.LogMessage(LogMsg)
+ else:
+ pcbnew.Refresh()
+ layerName = pcbnew.GetBoard().GetLayerName(layerId)
+ LogMsg="selected drawings moved to "+layerName+" layer"
+ wx.LogMessage(LogMsg)
+#
+
+
+
+# Python plugin stuff
+
+class Move2Layer_Dlg(Move2LayerDlg.Move2LayerDlg):
+ # from https://github.com/MitjaNemec/Kicad_action_plugins
+ # hack for new wxFormBuilder generating code incompatible with old wxPython
+ # noinspection PyMethodOverriding
+ def SetSizeHints(self, sz1, sz2):
+ if wx.__version__ < '4.0':
+ self.SetSizeHintsSz(sz1, sz2)
+ else:
+ super(Move2Layer_Dlg, self).SetSizeHints(sz1, sz2)
+
+ #def onApplyClick(self, event):
+ # return self.EndModal(wx.ID_OK)
+ #
+ #def onCancelClick(self, event):
+ # return self.EndModal(wx.ID_CANCEL)
+
+ def __init__(self, parent):
+ import wx
+ Move2LayerDlg.Move2LayerDlg.__init__(self, parent)
+ #self.GetSizer().Fit(self)
+ self.SetMinSize(self.GetSize())
+ # self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
+ # self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick)
+ # if wx.__version__ < '4.0':
+ # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+ # else:
+ # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+#
+class move_to_draw_layer( pcbnew.ActionPlugin ):
+ """
+ A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL)
+ How to use:
+ - move to GAL
+ - select some draw objects
+ - call the plugin
+ - select the new layer
+ - selected draw objects will be moved to new layer
+ """
+
+ 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
+ """
+ import os
+ self.name = "Move Selected Drawings to chosen Layer \nversion "+___version___
+ self.category = "Modify PCB"
+ self.description = "Move Selected Drawings to chosen Layer on an existing PCB"
+ self.icon_file_name = os.path.join(os.path.dirname(__file__), "./move2layer.png")
+ self.show_toolbar_button = True
+
+ def Run( self ):
+ found_selected=False
+
+ board = pcbnew.GetBoard()
+ fileName = GetBoard().GetFileName()
+ # # dicts for converting layer name to id, used by _get_layer
+ # _std_layer_dict = {pcbnew.BOARD_GetStandardLayerName(n): n
+ # for n in range(pcbnew.PCB_LAYER_ID_COUNT)}
+ # #_std_layer_names = {s: n for n, s in _std_layer_dict.iteritems()}
+ # _std_layer_names = {s: n for n, s in _std_layer_dict.items()}
+ # _brd_layer_dict = {pcbnew.GetBoard().GetLayerName(n): n
+ # for n in range(pcbnew.PCB_LAYER_ID_COUNT)}
+ # #_std_layer_names = {s: n for n, s in _std_layer_dict.iteritems()}
+ # _brd_layer_names = {s: n for n, s in _brd_layer_dict.items()}
+
+
+ if 0: #len(fileName) == 0:
+ wx.LogMessage("A board needs to be saved/loaded\nto run the plugin!")
+ else:
+ #from https://github.com/MitjaNemec/Kicad_action_plugins
+ #hack wxFormBuilder py2/py3
+ _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
+ aParameters = Move2Layer_Dlg(_pcbnew_frame)
+ aParameters.Show()
+ for l in range(pcbnew.PCB_LAYER_ID_COUNT):
+ aParameters.m_comboBoxLayer.Append(pcbnew.GetBoard().GetLayerName(l))
+ aParameters.m_comboBoxLayer.Select(44)
+ modal_result = aParameters.ShowModal()
+ if modal_result == wx.ID_OK:
+ LayerName = aParameters.m_comboBoxLayer.GetStringSelection()
+ LayerIndex = aParameters.m_comboBoxLayer.FindString(LayerName)
+ LayerStdName = pcbnew.BOARD_GetStandardLayerName(LayerIndex)
+ #wx.LogMessage(LayerName+';'+str(LayerIndex)+';'+LayerStdName)
+ MoveToLayer(board, LayerIndex)
+ else:
+ None # Cancel
+
+ LogMsg=''
+ msg="'move to layer tool'\n"
+ msg+="version = "+___version___
+
+
+#move_to_draw_layer().register()
+
diff --git a/MoveToLayer/move_to_layer_dlg.fbp b/MoveToLayer/move_to_layer_dlg.fbp
new file mode 100644
index 0000000..66f4aa8
--- /dev/null
+++ b/MoveToLayer/move_to_layer_dlg.fbp
@@ -0,0 +1,547 @@
+
+
+
+
+
+ Python
+ 1
+ source_name
+ 0
+ 0
+ res
+ UTF-8
+ connect
+ Move2LayerDlg
+ 1000
+ none
+
+ 0
+ Move2LayerDlg
+
+ .
+
+ 1
+ 1
+ 1
+ 1
+ UI
+ 0
+ 0
+
+ 0
+ wxAUI_MGR_DEFAULT
+
+ wxBOTH
+
+ 1
+ 1
+ impl_virtual
+
+
+
+ 0
+ wxID_ANY
+
+
+ Move2LayerDlg
+
+ 568,263
+ wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER
+
+ Move to Layer
+
+
+
+
+
+
+ bSizer3
+ wxVERTICAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Selected Objects will Move to chosen Layer
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_comment
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+
+ 0
+
+
+ bSizer31
+ wxHORIZONTAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Layer
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticTextLayer
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+ -1,-1
+ 0
+ -1,-1
+ 1
+ m_comboBoxLayer
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ -1
+ 1
+ 250,-1
+
+ ; ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+ Combo!
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND | wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticline1
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxLI_HORIZONTAL
+ ; ; forward_declare
+ 0
+
+
+
+
+
+
+
+ 5
+ wxALIGN_RIGHT|wxEXPAND
+ 0
+
+
+ bSizer1
+ wxHORIZONTAL
+ none
+
+ 5
+ wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticText101
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+
+ 1
+
+ 1
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_OK
+ Apply
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonOK
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+
+ 0
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_CANCEL
+ Cancel
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonCancel
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND
+ 1
+
+
+ bSizer4
+ wxVERTICAL
+ none
+
+
+
+
+
+
diff --git a/MoveToLayer/move_to_layer_dlg.fbp.bak b/MoveToLayer/move_to_layer_dlg.fbp.bak
new file mode 100644
index 0000000..43a4da8
--- /dev/null
+++ b/MoveToLayer/move_to_layer_dlg.fbp.bak
@@ -0,0 +1,536 @@
+
+
+
+
+
+ Python
+ 1
+ source_name
+ 0
+ 0
+ res
+ UTF-8
+ connect
+ Move2LayerDlg
+ 1000
+ none
+
+ 0
+ Move2LayerDlg
+
+ .
+
+ 1
+ 1
+ 1
+ 1
+ UI
+ 0
+ 0
+
+ 0
+ wxAUI_MGR_DEFAULT
+
+ wxBOTH
+
+ 1
+ 1
+ impl_virtual
+
+
+
+ 0
+ wxID_ANY
+
+
+ Move2LayerDlg
+
+ 325,190
+ wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER
+
+ Move to Layer
+
+
+
+
+
+
+ bSizer3
+ wxVERTICAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Selected Objects will Move to chosen Layer
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_comment
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+
+ 0
+
+
+ bSizer31
+ wxHORIZONTAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Layer
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticTextLayer
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+ -1,-1
+ 0
+ -1,-1
+ 1
+ m_comboBoxLayer
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ -1
+ 1
+ 250,-1
+
+ ; ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+ Combo!
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND | wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticline1
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxLI_HORIZONTAL
+ ; ; forward_declare
+ 0
+
+
+
+
+
+
+
+ 5
+ wxALIGN_RIGHT|wxEXPAND
+ 0
+
+
+ bSizer1
+ wxHORIZONTAL
+ none
+
+ 5
+ wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticText101
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+
+ 1
+
+ 1
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_OK
+ Apply
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonOK
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+
+ 0
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_CANCEL
+ Cancel
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonCancel
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PcbToDxf/.gitignore b/PcbToDxf/.gitignore
new file mode 100644
index 0000000..06703cd
--- /dev/null
+++ b/PcbToDxf/.gitignore
@@ -0,0 +1,51 @@
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files, back
+*.cab
+*.msi
+*.msm
+*.msp
+*.bak
+
+# Windows shortcuts
+*.lnk
+
+# Python executable
+*.pyc
+
+# =========================
+# Operating System Files
+# =========================
+
+# OSX
+# =========================
+
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
diff --git a/PcbToDxf/__init__.py b/PcbToDxf/__init__.py
new file mode 100644
index 0000000..68def39
--- /dev/null
+++ b/PcbToDxf/__init__.py
@@ -0,0 +1,2 @@
+from .action_menu_pcb2dxf import pcb2dxf
+pcb2dxf().register()
diff --git a/action_menu_pcb2dxf.py b/PcbToDxf/action_menu_pcb2dxf.py
similarity index 98%
rename from action_menu_pcb2dxf.py
rename to PcbToDxf/action_menu_pcb2dxf.py
index 82e382c..035b260 100644
--- a/action_menu_pcb2dxf.py
+++ b/PcbToDxf/action_menu_pcb2dxf.py
@@ -24,13 +24,15 @@
# Created: 14.04.2016
# Copyright (C) 2016, Manfred Moitzi
# License: MIT License
+
+#import pcbnew;pcbnew.GetWizardsBackTrace()
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"
+___version___="3.8.1"
from contextlib import contextmanager
@@ -199,8 +201,12 @@ def dxf_tag(code, value):
###################################################################
##real python code easyw
import sys
-reload(sys)
-sys.setdefaultencoding('utf8') #to accept utf8 chars
+if sys.version_info[0] == 2: #if py2:
+ reload(sys)
+ sys.setdefaultencoding('utf8') #to accept utf8 chars
+#else:
+# import importlib
+# importlib.reload(sys)
import re, os
from math import sqrt, atan2, degrees, sin, cos, radians
@@ -221,9 +227,11 @@ class pcb2dxf( pcbnew.ActionPlugin ):
self.description should be a comprehensive description
of the plugin
"""
- self.name = "export technical layers of pcb to DXF (saved board)"
+ self.name = "Export pcb technical layers to DXF \nversion "+___version___
self.category = "export PCB"
self.description = "export technical layers of pcb to DXF (saved board)"
+ self.show_toolbar_button = True
+ self.icon_file_name = os.path.join(os.path.dirname(__file__), './dxf_icon.png')
def Run( self ):
fileName = GetBoard().GetFileName()
@@ -249,7 +257,7 @@ class pcb2dxf( pcbnew.ActionPlugin ):
#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 )
+ dlg=wx.MessageBox( 'Exporting technical layers of pcb to DXF\nOnly SAVED board file will be exported to DXF file\n\nversion '+___version___, '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 )
diff --git a/PcbToDxf/dxf_icon.png b/PcbToDxf/dxf_icon.png
new file mode 100644
index 0000000..dad5797
Binary files /dev/null and b/PcbToDxf/dxf_icon.png differ
diff --git a/README.md b/README.md
index 325e2b6..0c1181b 100644
--- a/README.md
+++ b/README.md
@@ -1,94 +1,71 @@
-# kicad-action-plugins
-#### 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_move_to_layer
-A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL)
-
-- ### action_positions
-A script to Generate Position Files for SMD, THD, Virtual, ALL
-
----
-## action_menu_annular_check.py
-A script to check for annular ring violations
-for PTH, NPTH pads and vias
-
-requirements: KiCAD pcbnew > 4.0 built with KICAD_SCRIPTING_ACTION_MENU option activated
-release "1.5.3"
-
-'action_menu_annular_check.py' checking PCB for Annular Ring in PTH, NPTH and Vias
-(SMD, Connector and NPTH are skipped)
-default Annular Ring >= 0.15 both for TH Pads and Vias
-to change values modify:
-
- AR_SET = 0.150 #minimum annular accepted for pads
- AR_SET_V = 0.150 #minimum annular accepted for vias
- DRL_EXTRA = 0.100 #extra drill margin size for production
-
-Launch the Annular Check script in pcbnew from Tools menu:
-
-
-### 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
-
-### todo (kicadpcb2dxf)
-- [ ] tbd
-
----
-## action_menu_move_to_layer
-A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL)
-
-requirements: KiCAD pcbnew > 4.0 built with KICAD_SCRIPTING_ACTION_MENU option activated
-release "1.1.0"
-
- A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL)
- How to use:
- - move to GAL
- - select some draw objects
- - call the plugin
- - select the new layer
- - selected draw objects will be moved to new layer
-
-Launch the 'Move Selected drawings to chosen Layer' script in pcbnew from Tools menu
-
-
-- ### action_positions
-A script to Generate Position Files for SMD, THD, Virtual, ALL
-
-The script will generate Fabrication POS files for:
-
-- SMD
-- THD
-- VIRTUAL
-- ALL
+# kicad-action-tools
+#### A suite of kicad action plugin tools
+
+- ### Annular Ring Checker
+Check your kicad_pcb for annular ring violations:
+PTH Plated Trough Hole, NPTH Non Plated Trough Hole Pads and Vias
+
+- ### Snap Selected Footprint(s) to Grid
+Tool to move the selected footprint module(s) to the Grid.
+The Modules can be easily aligned to GridOrigin or to Auxiliary Origin.
+
+- ### Fabrication Footprint Position
+Tool for the creation of the necessary files for the production of the printed circuit board.
+Generate Position Files for SMD, THD, Virtual and ALL components, referred to Auxiliary Origin.
+
+- ### Move Selected Drawings to chosen Layer
+Tool to Move Selected Drawing(s) to the chosen new Layer.
+
+- ### Export pcb technical layers to DXF
+Tool to export technical layers of kicad PCB to DXF.
+The DXF generated file has single line draw and different layers for each pcb technical layer.
+
+---
+## Annular Ring Checker
+Check your kicad_pcb for annular ring violations:
+PTH Plated Trough Hole, NPTH Non Plated Trough Hole Pads and Vias
+
+Launch the Annular Check script in pcbnew from Tools menu:
+
+
+---
+## Export pcb technical layers to DXF
+**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
+
+---
+## Move Selected Drawings to chosen Layer
+Tool to Move Selected Drawing(s) to chosen new Layer
+
+requirements: KiCAD pcbnew > 4.0 built with KICAD_SCRIPTING_ACTION_MENU option activated
+release "1.1.0"
+
+ A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL)
+ How to use:
+ - move to GAL
+ - select some draw objects
+ - call the plugin
+ - select the new layer
+ - selected draw objects will be moved to new layer
+
+Launch the 'Move Selected drawings to chosen Layer' script in pcbnew from Tools menu
+
diff --git a/Snap2Grid/.gitignore b/Snap2Grid/.gitignore
new file mode 100644
index 0000000..06703cd
--- /dev/null
+++ b/Snap2Grid/.gitignore
@@ -0,0 +1,51 @@
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files, back
+*.cab
+*.msi
+*.msm
+*.msp
+*.bak
+
+# Windows shortcuts
+*.lnk
+
+# Python executable
+*.pyc
+
+# =========================
+# Operating System Files
+# =========================
+
+# OSX
+# =========================
+
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
diff --git a/Snap2Grid/Snap2GridDlg.fbp b/Snap2Grid/Snap2GridDlg.fbp
new file mode 100644
index 0000000..723beb8
--- /dev/null
+++ b/Snap2Grid/Snap2GridDlg.fbp
@@ -0,0 +1,740 @@
+
+
+
+
+
+ Python
+ 1
+ source_name
+ 0
+ 0
+ res
+ UTF-8
+ connect
+ Snap2GridDlg
+ 1000
+ none
+
+ 0
+ Snap2GridDlg
+
+ .
+
+ 1
+ 1
+ 1
+ 1
+ UI
+ 0
+ 0
+
+ 0
+ wxAUI_MGR_DEFAULT
+
+ wxBOTH
+
+ 1
+ 1
+ impl_virtual
+
+
+
+ 0
+ wxID_ANY
+
+
+ Snap2GridDlg
+
+ 499,394
+ wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER
+
+ Snap to Grid
+
+
+
+
+
+
+ bSizer3
+ wxVERTICAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Selected Model(s) to Snap
to the Grid
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_comment
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+
+ 0
+
+
+ bSizer31
+ wxHORIZONTAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Grid
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticTextGrid
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ "1.0mm (39.37mils)" "0.5mm (19.69mils)" "0.25mm (9.84mils)" "0.1mm (3.94mils)" "2.54mm (100mils)" "1.27mm (50mils)" "0.635mm (25mils)" "0.508mm (20mils)" "0.254mm (10mils)" "0.127mm (5mils)"
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+ -1,-1
+ 0
+ -1,-1
+ 1
+ m_comboBoxGrid
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 0
+ 1
+ -1,-1
+
+ ; ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+ 1.0mm (39.37mils)
+
+
+
+
+
+
+ 5
+ wxALIGN_CENTER_VERTICAL|wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_bitmapS2G
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ ; ; forward_declare
+ 0
+
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND | wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticline1
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxLI_HORIZONTAL
+ ; ; forward_declare
+ 0
+
+
+
+
+
+
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ GridOrigin reference
+
+ 0
+
+
+ 0
+
+ 1
+ m_radioBtnGO
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+ ; ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+ 0
+
+
+
+
+
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ AuxOrigin reference
+
+ 0
+
+
+ 0
+
+ 1
+ m_radioBtnAO
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+ ; ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+ 0
+
+
+
+
+
+
+ 5
+ wxEXPAND | wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticline2
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxLI_HORIZONTAL
+ ; ; forward_declare
+ 0
+
+
+
+
+
+
+
+ 5
+ wxALIGN_RIGHT|wxEXPAND
+ 0
+
+
+ bSizer1
+ wxHORIZONTAL
+ none
+
+ 5
+ wxEXPAND
+ 1
+
+ 0
+ protected
+ 0
+
+
+
+ 5
+ wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+
+ 1
+
+ 1
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_OK
+ Apply
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonOK
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+
+ 0
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_CANCEL
+ Cancel
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonCancel
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND
+ 1
+
+
+ bSizer4
+ wxVERTICAL
+ none
+
+
+
+
+
+
diff --git a/Snap2Grid/Snap2GridDlg.py b/Snap2Grid/Snap2GridDlg.py
new file mode 100644
index 0000000..a870395
--- /dev/null
+++ b/Snap2Grid/Snap2GridDlg.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+
+###########################################################################
+## Class Snap2GridDlg
+###########################################################################
+
+class Snap2GridDlg ( wx.Dialog ):
+
+ def __init__( self, parent ):
+ wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Snap to Grid", pos = wx.DefaultPosition, size = wx.Size( 499,394 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER )
+
+ self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+
+ bSizer3 = wx.BoxSizer( wx.VERTICAL )
+
+ self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Selected Model(s) to Snap\nto the Grid", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_comment.Wrap( -1 )
+
+ bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 )
+
+ bSizer31 = wx.BoxSizer( wx.HORIZONTAL )
+
+ self.m_staticTextGrid = wx.StaticText( self, wx.ID_ANY, u"Grid", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticTextGrid.Wrap( -1 )
+
+ bSizer31.Add( self.m_staticTextGrid, 1, wx.ALL|wx.EXPAND, 5 )
+
+ m_comboBoxGridChoices = [ u"1.0mm (39.37mils)", u"0.5mm (19.69mils)", u"0.25mm (9.84mils)", u"0.1mm (3.94mils)", u"2.54mm (100mils)", u"1.27mm (50mils)", u"0.635mm (25mils)", u"0.508mm (20mils)", u"0.254mm (10mils)", u"0.127mm (5mils)" ]
+ self.m_comboBoxGrid = wx.ComboBox( self, wx.ID_ANY, u"1.0mm (39.37mils)", wx.DefaultPosition, wx.Size( -1,-1 ), m_comboBoxGridChoices, 0 )
+ self.m_comboBoxGrid.SetSelection( 0 )
+ bSizer31.Add( self.m_comboBoxGrid, 0, wx.ALL|wx.EXPAND, 5 )
+
+ self.m_bitmapS2G = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer31.Add( self.m_bitmapS2G, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+
+ bSizer3.Add( bSizer31, 0, 0, 5 )
+
+ self.m_staticline1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
+ bSizer3.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 )
+
+ self.m_radioBtnGO = wx.RadioButton( self, wx.ID_ANY, u"GridOrigin reference", wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer3.Add( self.m_radioBtnGO, 0, wx.ALL, 5 )
+
+ self.m_radioBtnAO = wx.RadioButton( self, wx.ID_ANY, u"AuxOrigin reference", wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer3.Add( self.m_radioBtnAO, 0, wx.ALL, 5 )
+
+ self.m_staticline2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
+ bSizer3.Add( self.m_staticline2, 0, wx.EXPAND |wx.ALL, 5 )
+
+ bSizer1 = wx.BoxSizer( wx.HORIZONTAL )
+
+
+ bSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 )
+
+ self.m_buttonOK = wx.Button( self, wx.ID_OK, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 )
+
+ self.m_buttonOK.SetDefault()
+ bSizer1.Add( self.m_buttonOK, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+ self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 )
+ bSizer1.Add( self.m_buttonCancel, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+
+ bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 )
+
+ bSizer4 = wx.BoxSizer( wx.VERTICAL )
+
+
+ bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 )
+
+
+ self.SetSizer( bSizer3 )
+ self.Layout()
+
+ self.Centre( wx.BOTH )
+
+ def __del__( self ):
+ pass
+
+
diff --git a/Snap2Grid/__init__.py b/Snap2Grid/__init__.py
new file mode 100644
index 0000000..07cb020
--- /dev/null
+++ b/Snap2Grid/__init__.py
@@ -0,0 +1,2 @@
+from .snap2grid import snap_to_grid
+snap_to_grid().register()
diff --git a/Snap2Grid/snap2grid.png b/Snap2Grid/snap2grid.png
new file mode 100644
index 0000000..d812a83
Binary files /dev/null and b/Snap2Grid/snap2grid.png differ
diff --git a/Snap2Grid/snap2grid.py b/Snap2Grid/snap2grid.py
new file mode 100644
index 0000000..9c68e7d
--- /dev/null
+++ b/Snap2Grid/snap2grid.py
@@ -0,0 +1,226 @@
+# -*- coding: utf-8 -*-
+#
+# A script to Snap modules to selected Grid for kicad_pcb
+# requirements: KiCAD pcbnew >= 4.0
+# copyright Maurice easyw
+#
+#
+
+#import snaptogrid; import importlib; importlib.reload(snaptogrid)
+
+### plugins errors
+#import pcbnew
+#pcbnew.GetWizardsBackTrace()
+
+__version__ = '1.0.2'
+import sys, os
+import pcbnew
+import datetime
+import wx
+from pcbnew import *
+
+use_grid_origin = True
+
+gridReference = 0.1 #1.27 #mm pcbnew.FromMM(1.0) #0.1mm
+
+gridSizeMM = gridReference
+
+from . import Snap2GridDlg
+
+sys.path.append(os.path.dirname(__file__))
+
+debug = False
+def wxLogDebug(msg,dbg):
+ """printing messages only if show is omitted or True"""
+ if dbg == True:
+ wx.LogMessage(msg)
+#
+
+class Snap2Grid_Dlg(Snap2GridDlg.Snap2GridDlg):
+ # from https://github.com/MitjaNemec/Kicad_action_plugins
+ # hack for new wxFormBuilder generating code incompatible with old wxPython
+ # noinspection PyMethodOverriding
+ def SetSizeHints(self, sz1, sz2):
+ if wx.__version__ < '4.0':
+ self.SetSizeHintsSz(sz1, sz2)
+ else:
+ super(Snap2Grid_Dlg, self).SetSizeHints(sz1, sz2)
+
+ # def onDeleteClick(self, event):
+ # return self.EndModal(wx.ID_DELETE)
+ #
+ # def onConnectClick(self, event):
+ # return self.EndModal(wx.ID_REVERT)
+
+ def __init__(self, parent):
+ import wx
+ Snap2GridDlg.Snap2GridDlg.__init__(self, parent)
+ #self.GetSizer().Fit(self)
+ self.SetMinSize(self.GetSize())
+ self.m_bitmapS2G.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./snap2grid.png")))
+ #self.SetIcon(wx.IconFromBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./snap2grid.png"))))
+ #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
+ #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick)
+ #if wx.__version__ < '4.0':
+ # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+ #else:
+ # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+ # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+
+# Python plugin stuff
+class snap_to_grid( pcbnew.ActionPlugin ):
+ """
+ A plugin to Snap modules to selected Grid for kicad_pcb
+ requirements: KiCAD pcbnew >= 4.0
+
+ """
+ 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 = "Snap Selected Footprint(s) to Grid \nversion "+__version__
+ self.category = "Modify PCB"
+ self.description = "Automaticaly Snap Selected Footprint Module(s) to Grid on an existing PCB"
+ #self.pcbnew_icon_support = hasattr(self, "show_toolbar_button")
+ self.show_toolbar_button = True
+ self.icon_file_name = os.path.join(os.path.dirname(__file__), './snap2grid.png')
+ #
+
+ def Run(self):
+ #self.pcb = GetBoard()
+ import sys,os
+ #mm_ius = 1000000.0
+ _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
+ #aParameters = RoundTrackDlg(None)
+ aParameters = Snap2Grid_Dlg(_pcbnew_frame)
+ gridIndex = aParameters.m_comboBoxGrid.FindString('0.1mm (3.94mils)')
+ aParameters.m_comboBoxGrid.SetSelection(gridIndex)
+ #aParameters.m_comboBoxGrid.Append('0.1mm (3.94mils)')
+ aParameters.m_radioBtnGO.SetValue(True)
+ aParameters.Show()
+
+ modal_result = aParameters.ShowModal()
+ if modal_result == wx.ID_OK:
+ grid = aParameters.m_comboBoxGrid.GetStringSelection()
+ gridSizeMM = float(grid.split('mm')[0])
+ if aParameters.m_radioBtnGO.GetValue():
+ use_grid_origin = True
+ else:
+ use_grid_origin = False
+ snap2grid(gridSizeMM,use_grid_origin)
+ else:
+ None # Cancel
+##
+
+def snap2grid(gridSizeMM,use_grid_origin):
+
+ pcb = pcbnew.GetBoard()
+ gridOrigin = pcb.GetGridOrigin()
+ auxOrigin = pcb.GetAuxOrigin()
+ content=''
+ locked_fp=''
+ #wxPoint(77470000, 135890000)
+ for module in pcb.GetModules():
+ if module.IsSelected():
+ if use_grid_origin:
+ mpx = module.GetPosition().x - gridOrigin.x
+ mpy = module.GetPosition().y - gridOrigin.y
+ #print(mpx,mpy)
+ mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.x
+ mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.y
+ #print(mpxOnG,mpyOnG)
+ locked=''
+ if not module.IsLocked():
+ module.SetPosition(wxPoint(mpxOnG,mpyOnG))
+ else:
+ locked='LOCKED'
+ X_POS=str(module.GetPosition().x) # - gridOrigin.x)
+ #X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - gridOrigin.x ))
+ X_POS="{0:<11}".format(X_POS)
+ Y_POS=str(module.GetPosition().y) # - gridOrigin.y)
+ Y_POS="{0:<11}".format(Y_POS)
+ ## mpOnGx = PutOnGridMM(module.GetPosition().x, gridSizeMM)
+ ## mpOnGy = PutOnGridMM(module.GetPosition().y, gridSizeMM)
+ ## module.SetPosition(wxPoint(mpOnGx,mpOnGy))
+ #module.SetPosition(wxPoint(mpOnGx+FromMM(100.0),mpOnGy+FromMM(2.0)))
+ #module.SetOrientation(10)
+ #Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - gridOrigin.y))
+ else: # AuxOrigin
+ mpx = module.GetPosition().x - auxOrigin.x
+ mpy = module.GetPosition().y - auxOrigin.y
+ #print(mpx,mpy)
+ mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ auxOrigin.x
+ mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ auxOrigin.y
+ #print(mpxOnG,mpyOnG)
+ locked=''
+ if not module.IsLocked():
+ module.SetPosition(wxPoint(mpxOnG,mpyOnG))
+ else:
+ locked='LOCKED'
+ X_POS=str(module.GetPosition().x) # - gridOrigin.x)
+ #X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - gridOrigin.x ))
+ X_POS="{0:<11}".format(X_POS)
+ Y_POS=str(module.GetPosition().y) # - gridOrigin.y)
+ Y_POS="{0:<11}".format(Y_POS)
+ ## mpOnGx = PutOnGridMM(module.GetPosition().x, gridSizeMM)
+ ## mpOnGy = PutOnGridMM(module.GetPosition().y, gridSizeMM)
+ ## module.SetPosition(wxPoint(mpOnGx,mpOnGy))
+ #module.SetPosition(wxPoint(mpOnGx+FromMM(100.0),mpOnGy+FromMM(2.0)))
+ #module.SetOrientation(10)
+ #Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - gridOrigin.y))
+ Reference="{0:<10}".format(str(module.GetReference()))
+ Value = str(module.GetValue())
+ Value=(Value[:17] + '..') if len(Value) > 19 else Value
+ Value="{0:<20}".format(Value)
+ Rotation='{0:.1f}'.format((module.GetOrientation()/10))
+ Rotation="{0:>6}".format(Rotation)+' '
+ if module.GetLayer() == 0:
+ Layer=" top"
+ else:
+ Layer=" bottom"
+ #Side="## Side :"+Layer+lsep
+ Layer="{0:<10}".format(Layer)
+ content+=Reference
+ if 'LOCKED' in locked:
+ locked_fp+=Reference + ' LOCKED'+'\n' #os.linesep
+ #content+=Value
+ content+=X_POS
+ content+=Y_POS
+ #content+=str(mpOnGx)
+ #content+=str(mpOnGy)
+ content+=str(mpxOnG)
+ content+=str(mpyOnG)
+ content+=Layer+'\n' #os.linesep
+ if len(content)>0:
+ content+=str(pcbnew.FromMM(gridSizeMM))+'\n'
+ info='Snapped to grid: '+str(gridSizeMM)+'mm\n'
+ if use_grid_origin:
+ content+="Using GridOrigin as Ref"+'\n'
+ info+="Using GridOrigin as Ref"+'\n'
+ else:
+ content+="Using AuxOrigin as Ref"+'\n'
+ info+="Using AuxOrigin as Ref"+'\n'
+ if debug:
+ wxLogDebug(content,debug)
+ #else:
+ wxLogDebug(info,True)
+ if len (locked_fp)>0:
+ locked_fp+='\n'+'NOT Moved (Locked fp)'
+ locked_fp+='\n'+info
+ wxLogDebug(locked_fp,True)
+ else:
+ wxLogDebug(info,True)
+ else:
+ wxLogDebug('No Modules Selected',True)
+ Refresh()
+ #return content
+
+ # wxLogDebug('showing Selected Tracks',debug)
+ # wx.LogMessage('Select Tracks to calculate the Length\nor One Pad to select connected Tracks')
+#
+
diff --git a/Snap2Grid/snap2grid.py.bak b/Snap2Grid/snap2grid.py.bak
new file mode 100644
index 0000000..15ecdfc
--- /dev/null
+++ b/Snap2Grid/snap2grid.py.bak
@@ -0,0 +1,200 @@
+# -*- coding: utf-8 -*-
+#
+# A script to Snap modules to selected Grid for kicad_pcb
+# requirements: KiCAD pcbnew >= 4.0
+# copyright Maurice easyw
+#
+#
+
+#import snaptogrid; import importlib; importlib.reload(snaptogrid)
+
+__version__ = '1.0.1'
+import sys, os
+import pcbnew
+import datetime
+import wx
+from pcbnew import *
+
+use_grid_origin = True
+
+gridReference = 2.54 #1.27 #mm pcbnew.FromMM(1.0) #0.1mm
+
+gridSizeMM = gridReference
+
+#from . import Send2GridDlg
+
+sys.path.append(os.path.dirname(__file__))
+
+debug = False
+def wxLogDebug(msg,dbg):
+ """printing messages only if show is omitted or True"""
+ if dbg == True:
+ wx.LogMessage(msg)
+#
+
+#class Snap2Grid_Dlg(Snap2GridDlg.Snap2GridDlg):
+# # from https://github.com/MitjaNemec/Kicad_action_plugins
+# # hack for new wxFormBuilder generating code incompatible with old wxPython
+# # noinspection PyMethodOverriding
+# def SetSizeHints(self, sz1, sz2):
+# if wx.__version__ < '4.0':
+# self.SetSizeHintsSz(sz1, sz2)
+# else:
+# super(RoundTrack_Dlg, self).SetSizeHints(sz1, sz2)
+#
+# # def onDeleteClick(self, event):
+# # return self.EndModal(wx.ID_DELETE)
+# #
+# # def onConnectClick(self, event):
+# # return self.EndModal(wx.ID_REVERT)
+#
+# def __init__(self, parent):
+# import wx
+# Send2GridDlg.Send2GridDlg.__init__(self, parent)
+# #self.GetSizer().Fit(self)
+# self.SetMinSize(self.GetSize())
+# #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
+# #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick)
+# #if wx.__version__ < '4.0':
+# # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+# # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+# #else:
+# # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
+# # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
+#
+# Python plugin stuff
+class snap_to_grid( pcbnew.ActionPlugin ):
+ """
+ A plugin to Snap modules to selected Grid for kicad_pcb
+ requirements: KiCAD pcbnew >= 4.0
+
+ """
+ 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 = "Snap Selected Module(s) to Grid\nversion "+__version__
+ self.category = "Modify PCB"
+ self.description = "Automaticaly Snap Selected Module(s) to Grid on an existing PCB"
+ #self.pcbnew_icon_support = hasattr(self, "show_toolbar_button")
+ self.show_toolbar_button = True
+ self.icon_file_name = os.path.join(os.path.dirname(__file__), './snap2grid.png')
+ #
+
+ def Run(self):
+ #self.pcb = GetBoard()
+ import sys,os
+ #mm_ius = 1000000.0
+
+ pcb = pcbnew.GetBoard()
+ gridOrigin = pcb.GetGridOrigin()
+ auxOrigin = pcb.GetAuxOrigin()
+ content=''
+ locked_fp=''
+ #wxPoint(77470000, 135890000)
+ for module in pcb.GetModules():
+ if module.IsSelected():
+ if use_grid_origin:
+ mpx = module.GetPosition().x - gridOrigin.x
+ mpy = module.GetPosition().y - gridOrigin.y
+ print(mpx,mpy)
+ mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.x
+ mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.y
+ print(mpxOnG,mpyOnG)
+ locked=''
+ if not module.IsLocked():
+ module.SetPosition(wxPoint(mpxOnG,mpyOnG))
+ else:
+ locked='LOCKED'
+ X_POS=str(module.GetPosition().x) # - gridOrigin.x)
+ #X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - gridOrigin.x ))
+ X_POS="{0:<11}".format(X_POS)
+ Y_POS=str(module.GetPosition().y) # - gridOrigin.y)
+ Y_POS="{0:<11}".format(Y_POS)
+ ## mpOnGx = PutOnGridMM(module.GetPosition().x, gridSizeMM)
+ ## mpOnGy = PutOnGridMM(module.GetPosition().y, gridSizeMM)
+ ## module.SetPosition(wxPoint(mpOnGx,mpOnGy))
+ #module.SetPosition(wxPoint(mpOnGx+FromMM(100.0),mpOnGy+FromMM(2.0)))
+ #module.SetOrientation(10)
+ #Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - gridOrigin.y))
+ # else:
+ # mpx = module.GetPosition().x - auxOrigin().x
+ # mpy = module.GetPosition().y - auxOrigin().y
+ # X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - auxOrigin().x ))
+ # X_POS="{0:<11}".format(X_POS)
+ # Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - auxOrigin().y))
+ # Y_POS="{0:<11}".format(Y_POS)
+ Reference="{0:<10}".format(str(module.GetReference()))
+ Value = str(module.GetValue())
+ Value=(Value[:17] + '..') if len(Value) > 19 else Value
+ Value="{0:<20}".format(Value)
+ Rotation='{0:.1f}'.format((module.GetOrientation()/10))
+ Rotation="{0:>6}".format(Rotation)+' '
+ if module.GetLayer() == 0:
+ Layer=" top"
+ else:
+ Layer=" bottom"
+ #Side="## Side :"+Layer+lsep
+ Layer="{0:<10}".format(Layer)
+ content+=Reference
+ if 'LOCKED' in locked:
+ locked_fp+=Reference + ' LOCKED'+'\n' #os.linesep
+ #content+=Value
+ content+=X_POS
+ content+=Y_POS
+ #content+=str(mpOnGx)
+ #content+=str(mpOnGy)
+ content+=str(mpxOnG)
+ content+=str(mpyOnG)
+ content+=Layer+'\n' #os.linesep
+ if len(content)>0:
+ content+=str(pcbnew.FromMM(gridReference))
+ wxLogDebug(content,debug)
+ if len (locked_fp)>0:
+ locked_fp+='\n'+'NOT Moved'
+ wxLogDebug(locked_fp,True)
+ else:
+ wxLogDebug('No Modules Selected',True)
+ Refresh()
+ #return content
+
+ #if 0:
+ # #from https://github.com/MitjaNemec/Kicad_action_plugins
+ # #hack wxFormBuilder py2/py3
+ # _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
+ # #aParameters = RoundTrackDlg(None)
+ # aParameters = RoundTrack_Dlg(_pcbnew_frame)
+ # #aParameters = RoundTrack_DlgEx(_pcbnew_frame)
+ # aParameters.Show()
+ # #end hack
+ # aParameters.m_distanceMM.SetValue("5")
+ # aParameters.m_segments.SetValue("16")
+ # aParameters.m_bitmap1.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "round_track_help.png") ) )
+ # modal_result = aParameters.ShowModal()
+ # segments = self.CheckSegmentsInput(
+ # aParameters.m_segments.GetValue(), "number of segments")
+ # distI = FromMM(self.CheckDistanceInput(aParameters.m_distanceMM.GetValue(), "distance from intersection"))
+ # if segments is not None and distI is not None:
+ # if modal_result == wx.ID_OK:
+ # Round_Selection(pcb, distI, segments)
+ # elif modal_result == wx.ID_DELETE:
+ # Delete_Segments(pcb)
+ # #wx.LogMessage('Round Segments on Track Net Deleted')
+ # elif modal_result == wx.ID_REVERT:
+ # wxLogDebug('Connecting Tracks',debug)
+ # Connect_Segments(pcb)
+ # else:
+ # None # Cancel
+ # else:
+ # None # Invalid input
+ # aParameters.Destroy()
+
+
+ # wxLogDebug('showing Selected Tracks',debug)
+ # wx.LogMessage('Select Tracks to calculate the Length\nor One Pad to select connected Tracks')
+#
+
diff --git a/Snap2Grid/snap2grid.svg b/Snap2Grid/snap2grid.svg
new file mode 100644
index 0000000..3875f66
--- /dev/null
+++ b/Snap2Grid/snap2grid.svg
@@ -0,0 +1,242 @@
+
+
diff --git a/Snap2Grid/snaptogrid_script.py b/Snap2Grid/snaptogrid_script.py
new file mode 100644
index 0000000..d78ceb8
--- /dev/null
+++ b/Snap2Grid/snaptogrid_script.py
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+#
+# A script to Snap modules to selected Grid for kicad_pcb
+# requirements: KiCAD pcbnew >= 4.0
+# copyright Maurice easyw
+#
+#
+
+#import snaptogrid; import importlib; importlib.reload(snaptogrid)
+import sys, os
+import pcbnew
+import datetime
+import wx
+from pcbnew import *
+
+use_grid_origin = True
+gridReference = 0.127 #1.27 #mm pcbnew.FromMM(1.0) #0.1mm
+
+
+# def PutOnGridMM(value, gridSizeMM):
+# thresh = FromMM(gridSizeMM)
+# return round(value/thresh)*thresh
+#
+# def PutOnGridMils(value, gridSizeMils):
+# thresh = FromMils(gridSizeMils)
+# return round(value/thresh)*thresh
+#def SetPosition(self, p):
+# """SetPosition(wxRect self, wxPoint p)"""
+# return _pcbnew.wxRect_SetPosition(self, p)
+
+
+def Snap2Grid(gridSizeMM,use_grid_origin):
+ import sys,os
+ #mm_ius = 1000000.0
+
+ pcb = pcbnew.GetBoard()
+ gridOrigin = pcb.GetGridOrigin()
+ auxOrigin = pcb.GetAuxOrigin()
+ content=''
+ #wxPoint(77470000, 135890000)
+ for module in pcb.GetModules():
+ if module.IsSelected():
+ if use_grid_origin:
+ mpx = module.GetPosition().x - gridOrigin.x
+ mpy = module.GetPosition().y - gridOrigin.y
+ print(mpx,mpy)
+ mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.x
+ mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.y
+ print(mpxOnG,mpyOnG)
+ module.SetPosition(wxPoint(mpxOnG,mpyOnG))
+ X_POS=str(module.GetPosition().x) # - gridOrigin.x)
+ #X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - gridOrigin.x ))
+ X_POS="{0:<11}".format(X_POS)
+ Y_POS=str(module.GetPosition().y) # - gridOrigin.y)
+ Y_POS="{0:<11}".format(Y_POS)
+ ## mpOnGx = PutOnGridMM(module.GetPosition().x, gridSizeMM)
+ ## mpOnGy = PutOnGridMM(module.GetPosition().y, gridSizeMM)
+ ## module.SetPosition(wxPoint(mpOnGx,mpOnGy))
+ #module.SetPosition(wxPoint(mpOnGx+FromMM(100.0),mpOnGy+FromMM(2.0)))
+ #module.SetOrientation(10)
+ #Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - gridOrigin.y))
+ # else:
+ # mpx = module.GetPosition().x - auxOrigin().x
+ # mpy = module.GetPosition().y - auxOrigin().y
+ # X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - auxOrigin().x ))
+ # X_POS="{0:<11}".format(X_POS)
+ # Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - auxOrigin().y))
+ # Y_POS="{0:<11}".format(Y_POS)
+ Reference="{0:<10}".format(str(module.GetReference()))
+ Value = str(module.GetValue())
+ Value=(Value[:17] + '..') if len(Value) > 19 else Value
+ Value="{0:<20}".format(Value)
+ Rotation='{0:.1f}'.format((module.GetOrientation()/10))
+ Rotation="{0:>6}".format(Rotation)+' '
+ if module.GetLayer() == 0:
+ Layer=" top"
+ else:
+ Layer=" bottom"
+ #Side="## Side :"+Layer+lsep
+ Layer="{0:<10}".format(Layer)
+ content+=Reference
+ #content+=Value
+ content+=X_POS
+ content+=Y_POS
+ #content+=str(mpOnGx)
+ #content+=str(mpOnGy)
+ content+=str(mpxOnG)
+ content+=str(mpyOnG)
+ content+=Layer+os.linesep
+ content+=str(pcbnew.FromMM(gridReference))
+ Refresh()
+ return content
+
+reply=Snap2Grid(gridReference,use_grid_origin)
+#LogMsg=reply
+wx.LogMessage(reply)
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..8a147a8
--- /dev/null
+++ b/__init__.py
@@ -0,0 +1,14 @@
+# pcbnew loads this folder as a package using import
+# thus __init__.py (this file) is executed
+# We import the plugin class here and register it to pcbnew
+
+from . import AnnularChecker
+
+from . import FabricationPositions
+
+from . import MoveToLayer
+
+from . import PcbToDxf
+
+from . import Snap2Grid
+
diff --git a/action_menu_annular_check.py b/action_menu_annular_check.py
deleted file mode 100644
index faaecbf..0000000
--- a/action_menu_annular_check.py
+++ /dev/null
@@ -1,604 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# A script to check for annular ring violations
-# both for TH pads and vias
-# requirements: KiCAD pcbnew >= 4.0
-# annular.py release "1.5.1"
-#
-# annular.py checking PCB for Annular Ring in Vias and TH Pads
-# (SMD, Connector and NPTH are skipped)
-# default Annular Ring >= 0.15 both for TH Pads and Vias
-# to change values modify:
-#
-# AR_SET = 0.150 #minimum annular accepted for pads
-# AR_SET_V = 0.150 #minimum annular accepted for vias
-
-# annular.py
-
-
-___version___="1.5.8x"
-
-global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V, found_violations, LogMsg
-#wx.LogMessage("My message")
-mm_ius = 1000000.0
-# (consider always drill +0.1)
-DRL_EXTRA=0.1
-DRL_EXTRA_ius=DRL_EXTRA * mm_ius
-
-AR_SET = 0.125 #minimum annular accepted for pads
-MIN_AR_SIZE = AR_SET * mm_ius
-
-AR_SET_V = 0.125 #minimum annular accepted for vias
-MIN_AR_SIZE_V = AR_SET_V * mm_ius
-
-import sys
-import wx
-import wx.richtext
-import subprocess
-import os
-import pcbnew
-from pcbnew import *
-import base64
-from wx.lib.embeddedimage import PyEmbeddedImage
-sys.path.append(os.path.dirname(__file__))
-
-
-class annular_check( pcbnew.ActionPlugin ):
- """
- A script to check for annular ring violations
- both for TH pads and vias
- requirements: KiCAD pcbnew >= 4.0
- annular.py release "1.5.1"
-
- annular.py checking PCB for Annular Ring in Vias and TH Pads
- (SMD, Connector and NPTH are skipped)
- default Annular Ring >= 0.15 both for TH Pads and Vias
- to change values modify:
-
- AR_SET = 0.150 #minimum annular accepted for pads
- AR_SET_V = 0.150 #minimum annular accepted for vias
- """
-
- 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 = "Annular check"
- self.category = "Checking PCB"
- self.description = "Automaticaly check annular on an existing PCB"
-
- def Run( self ):
-
- ###########################################################################
- ## Class AR_Prm
- ###########################################################################
-
- class AR_Prm ( wx.Dialog ):
-
- def __init__( self, parent ):
- wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = "AR parameters", pos = wx.DefaultPosition, size = wx.Size( 320,193 ), style = wx.DEFAULT_DIALOG_STYLE )
-
- self.SetSizeHints( 500,500 )
-
- self.SetIcon(PyEmbeddedImage(annular_ico_b64_data).GetIcon())
-
- bSizer1 = wx.BoxSizer( wx.VERTICAL )
-
- gSizer2 = wx.GridSizer( 0, 2, 0, 0 )
-
- self.m_staticText11 = wx.StaticText( self, wx.ID_ANY, u"PHD margin", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
- self.m_staticText11.Wrap( -1 )
-
- gSizer2.Add( self.m_staticText11, 0, wx.ALL, 5 )
-
- self.m_textPHD = wx.TextCtrl( self, wx.ID_ANY, str(DRL_EXTRA), wx.DefaultPosition, wx.DefaultSize, 0 )
- gSizer2.Add( self.m_textPHD, 0, wx.ALL, 5 )
-
- self.m_staticText1 = wx.StaticText( self, wx.ID_ANY, u"AR for pads", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
- self.m_staticText1.Wrap( -1 )
-
- gSizer2.Add( self.m_staticText1, 0, wx.ALL, 5 )
-
- self.m_textAR_SET = wx.TextCtrl( self, wx.ID_ANY, str(AR_SET), wx.DefaultPosition, wx.DefaultSize, 0 )
- gSizer2.Add( self.m_textAR_SET, 0, wx.ALL, 5 )
-
- self.m_staticText12 = wx.StaticText( self, wx.ID_ANY, u"AR for vias", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
- self.m_staticText12.Wrap( -1 )
-
- gSizer2.Add( self.m_staticText12, 0, wx.ALL, 5 )
-
- self.m_textAR_SET_V = wx.TextCtrl( self, wx.ID_ANY, str(AR_SET_V), wx.DefaultPosition, wx.DefaultSize, 0 )
- gSizer2.Add( self.m_textAR_SET_V, 0, wx.ALL, 5 )
-
-
- bSizer1.Add( gSizer2, 1, wx.EXPAND, 5 )
-
- gSizer1 = wx.GridSizer( 0, 2, 0, 0 )
-
- self.m_ok_btn = wx.Button( self, wx.ID_ANY, u"OK", wx.DefaultPosition, wx.DefaultSize, 0 )
- gSizer1.Add( self.m_ok_btn, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 )
-
- # self.m_cancel_btn = wx.Button( self, wx.ID_ANY, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 )
- # gSizer1.Add( self.m_cancel_btn, 0, wx.ALL, 5 )
-
-
- bSizer1.Add( gSizer1, 1, wx.EXPAND, 5 )
-
-
- self.SetSizer( bSizer1 )
- self.Layout()
-
- self.Centre( wx.BOTH )
-
- #### ----- connections
- # Connect Events
- self.Bind(wx.EVT_BUTTON, self.OnClickOK, self.m_ok_btn)
- # self.Bind(wx.EVT_BUTTON, self.OnClickCancel, self.m_cancel_btn)
- # Tooltips
- #self.m_cancel_btn.SetToolTip( wx.ToolTip(u"Cancel" ))
- self.m_ok_btn.SetToolTip( wx.ToolTip(u"Confirm" ))
- self.m_ok_btn.SetFocus()
- self.m_staticText1.SetToolTip( wx.ToolTip(u"Annular Ring for Pads (mm)" ))
- self.m_textAR_SET.SetToolTip( wx.ToolTip(u"Annular Ring for Pads (mm)" ))
- self.m_textAR_SET_V.SetToolTip( wx.ToolTip(u"Annular Ring for Vias (mm)" ))
- self.m_staticText12.SetToolTip( wx.ToolTip(u"Annular Ring for Vias (mm)" ))
- self.m_textPHD.SetToolTip( wx.ToolTip(u"Drill extra margin (mm)" ))
- self.m_staticText11.SetToolTip( wx.ToolTip(u"Drill extra margin (mm)" ))
-
- def __del__( self ):
- pass
-
- def OnClickOK(self, event):
- global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V
-
- self.m_ok_btn.SetLabel("Clicked")
- phd = float(self.m_textPHD.GetValue().replace(',','.'))
- ar = float(self.m_textAR_SET.GetValue().replace(',','.'))
- arv = float(self.m_textAR_SET_V.GetValue().replace(',','.'))
- DRL_EXTRA=phd
- DRL_EXTRA_ius=DRL_EXTRA * mm_ius
-
- AR_SET = ar #minimum annular accepted for pads
- MIN_AR_SIZE = AR_SET * mm_ius
-
- AR_SET_V = arv #minimum annular accepted for vias
- MIN_AR_SIZE_V = AR_SET_V * mm_ius
- self.Destroy()
-
- def OnClickCancel(self, event):
- self.m_cancel_btn.SetLabel("Clicked")
- self.Destroy()
-
- #wx.MessageDialog(self.frame,"ciao")
- #subprocess.check_call(["C:\pathToYourProgram\yourProgram.exe", "your", "arguments", "comma", "separated"])
- #http://stackoverflow.com/questions/1811691/running-an-outside-program-executable-in-python
-
- ## class displayDialog(wx.Dialog):
- ## """
- ## The default frame
- ## http://stackoverflow.com/questions/3566603/how-do-i-make-wx-textctrl-multi-line-text-update-smoothly
- ## """
- ## global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V, found_violations
- ## #----------------------------------------------------------------------
- ## #def __init__(self):
- ## # """Constructor"""
- ## # wx.Frame.__init__(self, None, title="Display Frame", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION)
- ## # panel = wx.Panel(self)
- ## def __init__(self, parent):
- ## wx.Dialog.__init__(self, parent, id=-1, title="Annular Checker")#
- ## #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION)
- ## #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION)
- ## #, pos=DefaultPosition, size=DefaultSize, style = wx.DEFAULT_FRAME_STYLE & (~wx.MAXIMIZE_BOX), name="fname")
- ## #, wx.ICON_INFORMATION) #, title="Annular Check", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION)
- ## #
- ##
- ## self.SetIcon(PyEmbeddedImage(annular_ico_b64_data).GetIcon())
- ## #wx.IconFromBitmap(wx.Bitmap("icon.ico", wx.BITMAP_TYPE_ANY)))
- ## self.panel = wx.Panel(self)
- ##
- ## if found_violations:
- ## self.title = wx.StaticText(self.panel, label="")
- ## #self.title.SetForegroundColour('#FF0000')
- ## #self.title.SetBackgroundColour('#FF0000')
- ## #font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD)
- ## #self.title.SetFont(font)
- ## else:
- ## self.title = wx.StaticText(self.panel, label="")
- ## #self.title.SetBackgroundColour('#00FF00')
- ## #font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD)
- ## #self.title.SetFont(font)
- ## #self.result = wx.StaticText(self.panel, label="")
- ## #self.result.SetForegroundColour('#FF0000')
- ## #self.button = wx.Button(self.panel, label="Save")
- ## #self.lblname = wx.StaticText(self.panel, label="Your name:")
- ## #self.editname = wx.TextCtrl(self.panel, size=(140, -1))
- ## ##self.editname = wx.TextCtrl(self.panel, size = (400, 400), style = wx.TE_MULTILINE|wx.TE_READONLY)
- ## self.m_richText1 = wx.richtext.RichTextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, size = (400, 400), style = 0|wx.VSCROLL|wx.HSCROLL|wx.WANTS_CHARS )# wx.TE_MULTILINE|wx.TE_READONLY) #0|wx.VSCROLL|wx.HSCROLL|wx.NO_BORDER|wx.WANTS_CHARS )
- ## #bSizer1.Add( self.m_richText1, 1, wx.EXPAND |wx.ALL, 5 )
- ##
- ##
- ## # Set sizer for the frame, so we can change frame size to match widgets
- ## self.windowSizer = wx.BoxSizer()
- ## self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
- ##
- ## # Set sizer for the panel content
- ## self.sizer = wx.GridBagSizer(5, 0)
- ## self.sizer.Add(self.title, (0, 0))
- ## #self.sizer.Add(self.result, (1, 0))
- ## #self.sizer.Add(self.lblname, (1, 0))
- ## ## self.sizer.Add(self.editname, (1, 0))
- ## self.sizer.Add(self.m_richText1, (1, 0))
- ## #self.ok_btn = wx.Button( self, wx.ID_ANY, u"Copy errors", wx.DefaultPosition, wx.DefaultSize, 0 )
- ## #self.sizer.Add( self.ok_btn, 0, wx.ALL | wx.EXPAND)
- ## #self.sizer.Add(self.ok_btn, (2, 0)) #, wx.ALL | flag=wx.EXPAND)
- ## #self.sizer.Add( self.ok_btn, 0, wx.ALL, 5 )
- ##
- ## #self.sizer.Add(self.ok_btn, (2, 0), (1, 2), flag=wx.EXPAND)
- ##
- ## # Set simple sizer for a nice border
- ## self.border = wx.BoxSizer()
- ## self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
- ##
- ## #self.ok_btn = wx.Button( self, wx.ID_ANY, u"Copy errors", wx.DefaultPosition, wx.DefaultSize, 0 )
- ## #self.windowSizer.Add(self.ok_btn, 0, wx.ALL)
- ## #self.sizer.Add( self.ok_btn, (2,0))
- ## #self.sizer.Add( self.ok_btn, 0, wx.ALL, 5 )
- ## # Use the sizers
- ## self.panel.SetSizerAndFit(self.border)
- ## self.SetSizerAndFit(self.windowSizer)
- ## #self.result.SetLabel(msg)
- ## # Set event handlers
- ## #self.button.Bind(wx.EVT_BUTTON, self.OnButton)
- ## #self.Show()
- ## #self.Bind(wx.EVT_CLOSE,self.OnClose)
- ##
- ## #def OnClose(self,e):
- ## # #wx.LogMessage("c")
- ## # e.Skip()
- ## #self.Close()
- ###########################################################################
- ## Class displayDialog
- ###########################################################################
-
- class displayDialog ( wx.Dialog ):
-
- global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V, found_violations, LogMsg
-
- def __init__( self, parent ):
- wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Annular Checker", pos = wx.DefaultPosition, size = wx.Size( 450,521 ), style = wx.DEFAULT_DIALOG_STYLE )
-
- self.SetSizeHints( 300,100 )
- self.SetIcon(PyEmbeddedImage(annular_ico_b64_data).GetIcon())
-
- bSizer1 = wx.BoxSizer( wx.VERTICAL )
-
- bSizer2 = wx.BoxSizer( wx.VERTICAL )
-
- self.m_staticTitle = wx.StaticText( self, wx.ID_ANY, u"", wx.DefaultPosition, wx.DefaultSize, 0 )
- self.m_staticTitle.Wrap( -1 )
-
- bSizer2.Add( self.m_staticTitle, 0, wx.ALL, 5 )
-
- self.m_richText1 = wx.richtext.RichTextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_READONLY|wx.VSCROLL|wx.HSCROLL|wx.NO_BORDER|wx.WANTS_CHARS )
- self.m_richText1.SetMinSize( wx.Size( 400,400 ) )
-
- bSizer2.Add( self.m_richText1, 1, wx.EXPAND |wx.ALL, 5 )
-
- gSizer3 = wx.GridSizer( 0, 2, 0, 0 )
-
- self.ok_btn = wx.Button( self, wx.ID_ANY, u"OK", wx.DefaultPosition, wx.DefaultSize, 0 )
- gSizer3.Add( self.ok_btn, 0, wx.ALL, 5 )
-
- self.copy_btn = wx.Button( self, wx.ID_ANY, u"Copy Text", wx.DefaultPosition, wx.DefaultSize, 0 )
- gSizer3.Add( self.copy_btn, 0, wx.ALL, 5 )
-
-
- bSizer2.Add( gSizer3, 1, wx.EXPAND, 5 )
-
-
- bSizer1.Add( bSizer2, 1, wx.EXPAND, 5 )
-
-
- self.SetSizer( bSizer1 )
- self.Layout()
-
- self.Centre( wx.BOTH )
-
- #### ----- connections
- # Connect Events
- self.Bind(wx.EVT_BUTTON, self.OnClickOK, self.ok_btn)
- self.Bind(wx.EVT_BUTTON, self.OnClickCopy, self.copy_btn)
- self.ok_btn.SetFocus()
- # Tooltips
- self.copy_btn.SetToolTip( wx.ToolTip(u"Copy Text to Clipboard" ))
- self.ok_btn.SetToolTip( wx.ToolTip(u"Exit" ))
-
- def __del__( self ):
- pass
-
- def OnClickOK(self, event):
- self.Destroy()
-
- def OnClickCopy(self, event):
- self.m_richText1.SelectAll()
- self.m_richText1.Copy()
- #global LogMsg
- #copy2clip(LogMsg)
- self.copy_btn.SetLabel("Text Copied")
-
- #def setMsg(self, t_msg):
- # pass
- #self.editname.SetValue(t_msg)
- #self.m_richText1.BeginBold()
- #self.m_richText1.WriteText(" You are in ")
- #self.m_richText1.BeginTextColour('red')
- #self.m_richText1.WriteText("danger ")
- #self.m_richText1.EndTextColour()
- #self.m_richText1.WriteText("at that spot!")
- #self.m_richText1.EndBold()
- #self.m_richText1.SetValue(t_msg)
- #self.m_htmlWin1.SetPage(t_msg)
-
-
- def annring_size(pad):
- # valid for oval pad/drills
- annrX=(pad.GetSize()[0] - (pad.GetDrillSize()[0]+DRL_EXTRA_ius))/2
- annrY=(pad.GetSize()[1] - (pad.GetDrillSize()[1]+DRL_EXTRA_ius))/2
- #annr=min(pad.GetSize()) - max(pad.GetDrillSize())
- #if annr < MIN_AR_SIZE:
- #print annrX
- #print annrY
- #print pad.GetSize()[0]/mm_ius
- #print pad.GetSize()[0]#/mm_ius
- #print pad.GetDrillSize()[0]#/mm_ius
- #print DRL_EXTRA_ius
- #print pad.GetDrillSize()[0]/mm_ius
- #print (pad.GetDrillSize()[0]+DRL_EXTRA_ius)/mm_ius
- #print annrX/mm_ius
- return min(annrX,annrY)
-
- def annringNP_size(pad):
- # valid for oval pad/drills
- annrX=(pad.GetSize()[0] - (pad.GetDrillSize()[0]))/2
- annrY=(pad.GetSize()[1] - (pad.GetDrillSize()[1]))/2
- #annr=min(pad.GetSize()) - max(pad.GetDrillSize())
- #if annr < MIN_AR_SIZE:
- #print annrX
- #print annrY
- #print pad.GetSize()[0]/mm_ius
- #print pad.GetSize()[0]#/mm_ius
- #print pad.GetDrillSize()[0]#/mm_ius
- #print DRL_EXTRA_ius
- #print pad.GetDrillSize()[0]/mm_ius
- #print (pad.GetDrillSize()[0]+DRL_EXTRA_ius)/mm_ius
- #print annrX/mm_ius
- #return min(annrX,annrY)
- return annrX,annrY
-
- def vias_annring_size(via):
- # calculating via annular
- annr=(via.GetWidth() - (via.GetDrillValue()+DRL_EXTRA_ius))/2
- #print via.GetWidth()
- #print via.GetDrillValue()
- return annr
-
- def f_mm(raw):
- return repr(raw/mm_ius)
-
- board = pcbnew.GetBoard()
- PassC=FailC=0
- PassCV=FailCV=0
-
- PassCN=FailCN=0
- PassCVN=FailCVN=0
-
- fileName = GetBoard().GetFileName()
- if len(fileName)==0:
- wx.LogMessage("a board needs to be saved/loaded!")
- else:
- found_violations=False
- frame1 = AR_Prm(None)
- #frame = wx.Frame(None)
- frame1.Center()
- #frame.setMsg(LogMsg)
- frame1.ShowModal()
- frame1.Destroy()
-
- frame = displayDialog(None)
- LogMsg=""
- writeTxt= frame.m_richText1.WriteText
- rt = frame.m_richText1
- rt.BeginItalic()
- writeTxt("'action_menu_annular_check.py'\n")
- #frame.m_richText1.WriteText("'action_menu_annular_check.py'\n")
- msg="'action_menu_annular_check.py'\n"
- msg+="version = "+___version___
- writeTxt("version = "+___version___)
- msg+="\nTesting PCB for Annular Rings\nTH Pads >= "+repr(AR_SET)+" Vias >= "+repr(AR_SET_V)+"\nPHD margin on PTH = "+ repr(DRL_EXTRA)
- writeTxt("\nTesting PCB for Annular Rings\nTH Pads >= "+repr(AR_SET)+" Vias >= "+repr(AR_SET_V)+"\nPHD margin on PTH = "+ repr(DRL_EXTRA))
- rt.EndItalic()
- writeTxt('\n\n')
- #print (msg)
- LogMsg+=msg+'\n\n'
-
- # print "LISTING VIAS:"
- for item in board.GetTracks():
- if type(item) is pcbnew.VIA:
- pos = item.GetPosition()
- drill = item.GetDrillValue()
- width = item.GetWidth()
- ARv = vias_annring_size(item)
- if ARv < MIN_AR_SIZE_V:
- # print("AR violation at %s." % (pad.GetPosition() / mm_ius )) Raw units, needs fixing
- XYpair = item.GetPosition()
- msg="AR Via violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])
- rt.BeginTextColour('red')
- writeTxt("AR Via violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])+'\n')
- rt.EndTextColour()
- #print (msg)
- LogMsg+=msg+'\n'
- FailCV = FailCV+1
- else:
- PassCV = PassCV+1
- #print type(item)
-
- msg="VIAS that Pass = "+repr(PassCV)+"; Fails = "+repr(FailCV)
- if FailCV >0:
- rt.BeginBold()
- writeTxt("VIAS that Pass = "+repr(PassCV)+"; ")
- if FailCV >0:
- rt.BeginTextColour('red')
- writeTxt("Fails = "+repr(FailCV)+'\n\n')
- if FailCV >0:
- rt.EndTextColour()
- rt.EndBold()
- print(msg)
- LogMsg+=msg+'\n'
-
- for module in board.GetModules():
- try:
- module_Pads=module.PadsList()
- except:
- module_Pads=module.Pads()
- for pad in module_Pads: #print(pad.GetAttribute())
- if pad.GetAttribute() == PAD_ATTRIB_STANDARD: #TH pad
- ARv = annring_size(pad)
- #print(f_mm(ARv))
- if ARv < MIN_AR_SIZE:
- # print("AR violation at %s." % (pad.GetPosition() / mm_ius )) Raw units, needs fixing
- XYpair = pad.GetPosition()
- msg="AR PTH violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])
- rt.BeginTextColour('red')
- writeTxt("AR PTH violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])+'\n')
- rt.EndTextColour()
- #print (msg)
- LogMsg+=msg+'\n'
- FailC = FailC+1
- else:
- PassC = PassC+1
- if pad.GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED:
- ARvX, ARvY = annringNP_size(pad)
- #print(f_mm(ARvX));print(f_mm(ARvY))
- if (ARvX) != 0 or ARvY != 0:
- ARv = min(ARvX, ARvY)
- if ARv < MIN_AR_SIZE:
- # print("AR violation at %s." % (pad.GetPosition() / mm_ius )) Raw units, needs fixing
- XYpair = pad.GetPosition()
- msg="AR NPTH warning of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])
- rt.BeginTextColour('red')
- writeTxt("AR NPTH warning of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])+'\n')
- rt.EndTextColour()
- #print (msg)
- LogMsg+=msg+'\n'
- FailCN = FailCN+1
- else:
- PassCN = PassCN+1
- else:
- PassCN = PassCN+1
-
- #if FailCV >0:
- #writeTxt('\n')
- msg = "TH PADS that Pass = "+repr(PassC)+"; Fails = "+repr(FailC)
- if FailC >0:
- rt.BeginBold()
- writeTxt("TH PADS that Pass = "+repr(PassC)+"; ")
- if FailC >0:
- rt.BeginTextColour('red')
- writeTxt("Fails = "+repr(FailC)+'\n')
- if FailC >0:
- rt.EndTextColour()
- rt.EndBold()
- print(msg)
- LogMsg+=msg+'\n'
-
- msg="NPTH PADS that Pass = "+repr(PassCN)+"; Fails = "+repr(FailCN)
- #writeTxt('\n')
- if FailCN >0:
- rt.BeginBold()
- writeTxt("NPTH PADS that Pass = "+repr(PassCN)+"; ")
- if FailCN >0:
- rt.BeginTextColour('red')
- writeTxt("Fails = "+repr(FailCN)+'\n')
- if FailC >0:
- rt.EndTextColour()
- rt.EndBold()
- print(msg)
- LogMsg+=msg+'\n'
-
- pcbName = (os.path.splitext(GetBoard().GetFileName())[0]) #filename no ext
- #wx.LogMessage(pcbName)#LogMsg)
- ##wx.LogMessage(LogMsg)
- FC=r"C:\FreeCAD\bin\freecad.exe"
- kSU=r"C:\Cad\Progetti_K\3D-FreeCad-tools\kicad-StepUp-tools.FCMacro"
- #subprocess.check_call([FC, kSU, pcbName])
- ##p = subprocess.Popen([FC, kSU, pcbName])
-
- #found_violations=False
- if (FailC+FailCN+FailCV)>0:
- found_violations=True
-
- if found_violations:
- #frame.m_staticTitle = wx.StaticText(frame, label=" Check result: (Violations found)")
- frame.m_staticTitle.SetLabel(" Check result: (Violations found)")
- #self.title.SetForegroundColour('#FF0000')
- frame.m_staticTitle.SetBackgroundColour('#FF0000')
- font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD)
- frame.m_staticTitle.SetFont(font)
- else:
- #frame.m_staticTitle = wx.StaticText(frame, label=" Annular Check result: OK")
- frame.m_staticTitle.SetLabel(" Annular Check result: OK")
- frame.m_staticTitle.SetBackgroundColour('#00FF00')
- font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD)
- frame.m_staticTitle.SetFont(font)
- ##frame = displayDialog(None)
- #frame = wx.Frame(None)
- frame.Center()
- #frame.setMsg(LogMsg)
- frame.ShowModal()
- frame.Destroy()
- #frame = wx.wxFrame(None, 10110, 'T-Make', size=wx.wxSize(100,100),
- # style=wx.wxSTAY_ON_TOP)
- #frame.show()
-
-# annular_check().register()
-if __name__ == "__main__":
- import argparse
-
- parser = argparse.ArgumentParser(
- description='KiCad PCB Annular Checker')
- parser.add_argument('file', type=str, help="KiCad PCB file")
- args = parser.parse_args()
- print("Loading %s" % args.file)
- main(pcbnew.LoadBoard(args.file))
-
-else:
- annular_check().register()
-
-
-# "b64_data" is a variable containing your base64 encoded jpeg
-annular_ico_b64_data =\
-"""
-iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAIQQAACEEB+v+u9gAAABl0RVh0U29mdHdhcmUAd3d
-3Lmlua3NjYXBlLm9yZ5vuPBoAAAJ5SURBVDiNdZRNSFRRFMd/976ZJjeBn2PUoiLaiMFkFkHIQ0NBdBUlJuIqiixmIYjQRgiJYKAMXRRSi6TCD5gaWiSFsy
-gixOyDpDAog8wn9SISapz33m0x82bmzcOzO/97/r973nn3XqGUojjCybIm4BhQD9Rl5XlgDnhi6ObTYo8oBIWTZeXAMNDlalW/FJYmMLd5fONA1NBN0wcKJ
-8sagftAZWRJcWHS5vCiouJ3pnClUvC8VnDtpOTTDgGwCpwydHM2Bwony8LAe6koH7hjc37aQXN8XwzAv5DgUo9krF0C/ABqDN1ck9n1G0D54C2H6OTmEICt
-KcXQTZvTCQegAhgFEFWzpW1A4uAHRaLfQhbPXgD+/8HfkKBhNMDXMACtEmgC6L/reCBWKGAzMmLxbQWWl2Fw0FJavqIkpYhO2m7aHADqNQcOLXq3DcSuKnp
-6Ajmhry8g1tfTxGJBVzryLuepl0Bk16qiJJUHKU0qOjryEDe6u4OF6e7vitCGAohIAFk0XCWEQkp8oWmeVAAiu78EFj5vF6S2iFyBtGxJPJ72gSYmPNpyOH
-McgAUJzFkazO/zetLRc4J43MayIJWCsTHLuTzkaellTa7rOVE1W9oOPDz6VjF90fI14QQ1RzhKCNsRhfpGEBqvB1jaKQDapKGbCeDBs/2C8Rb/XGTalsUQg
-Fin5kKmDN185DrPAD8HzmrcbpUony0flgZXujSGT+SuSC94L20LcA8obXiduSp1H8kdiz8l8KJWEOvUeLNXuJAuQzdnPKAsrBoYAY4DaA7sWck8I1+qKex0
-Cug1dHPNFcQmD1sL0AwcACJZeQF4BcwYuvm42PMfVgD11Y9MUIEAAAAASUVORK5CYII=
-"""
-
-
-# execfile("annular.py")
-# annular.py Testing PCB for Annular Ring >= 0.15
-# AR violation of 0.1 at XY 172.974,110.744
-# VIAS that Pass = 100 Fails = 1
-# AR violation of 0.1 at XY 172.212,110.744
-# AR violation of 0.0 at XY 154.813,96.52
-# PADS that Pass = 49 Fails = 2
-
diff --git a/action_menu_get3D_models.py b/action_menu_get3D_models.py
deleted file mode 100644
index 3dee3c0..0000000
--- a/action_menu_get3D_models.py
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-
-# licence GPL 2
-# copyright easyw
-
-## todo:
-# fix extra directory creation
-# add force override as option check
-# add OK-Cancel buttons
-# add popen to elevate process
-
-
-print "Work In Progress"
diff --git a/action_menu_move_to_layer.py b/action_menu_move_to_layer.py
deleted file mode 100644
index 75bd3b2..0000000
--- a/action_menu_move_to_layer.py
+++ /dev/null
@@ -1,239 +0,0 @@
-# move_to_edge_cuts.py
-#
-# Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
-#
-# This program 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.
-#
-# This program 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 this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-# MA 02110-1301, USA.
-#
-#
-
-import wx
-import pcbnew
-from pcbnew import *
-import base64
-from wx.lib.embeddedimage import PyEmbeddedImage
-___version___="1.1.3"
-
-
-class move_to_draw_layer( pcbnew.ActionPlugin ):
- """
- A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL)
- How to use:
- - move to GAL
- - select some draw objects
- - call the plugin
- - select the new layer
- - selected draw objects will be moved to new layer
- """
-
- 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 = "Move Selected drawings to chosen Layer"
- self.category = "Modify Drawing PCB"
- self.description = "Move Selected drawings to chosen Layer on an existing PCB"
-
- def Run( self ):
- found_selected=False
- #wx.MessageDialog(self.frame,"ciao")
- #subprocess.check_call(["C:\pathToYourProgram\yourProgram.exe", "your", "arguments", "comma", "separated"])
- #http://stackoverflow.com/questions/1811691/running-an-outside-program-executable-in-python
- def switch(x):
- return {
- 'Edge_Cuts': pcbnew.Edge_Cuts,
- 'Eco1_User': pcbnew.Eco1_User,
- 'Eco2_User': pcbnew.Eco2_User,
- 'Dwgs_User': pcbnew.Dwgs_User,
- 'Cmts_User': pcbnew.Cmts_User,
- 'Margin' : pcbnew.Margin,
- 'F_CrtYd' : pcbnew.F_CrtYd,
- 'B_CrtYd' : pcbnew.B_CrtYd,
- 'F_Fab' : pcbnew.F_Fab,
- 'B_Fab' : pcbnew.B_Fab,
- 'F_SilkS' : pcbnew.F_SilkS,
- 'B_SilkS' : pcbnew.B_SilkS,
- 'F_Mask' : pcbnew.F_Mask,
- 'B_Mask' : pcbnew.B_Mask,
- }[x]
-
- class displayDialog(wx.Dialog):
- """
- The default frame
- http://stackoverflow.com/questions/3566603/how-do-i-make-wx-textctrl-multi-line-text-update-smoothly
- """
-
- #----------------------------------------------------------------------
- #def __init__(self):
- # """Constructor"""
- # wx.Frame.__init__(self, None, title="Display Frame", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION)
- # panel = wx.Panel(self)
- def __init__(self, parent):
- wx.Dialog.__init__(self, parent, id=-1, title="Move to Layer")#
- #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION)
- #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION)
- #, pos=DefaultPosition, size=DefaultSize, style = wx.DEFAULT_FRAME_STYLE & (~wx.MAXIMIZE_BOX), name="fname")
- #, wx.ICON_INFORMATION) #, title="Annular Check", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION)
- #
-
- self.SetIcon(PyEmbeddedImage(move_to_layer_ico_b64_data).GetIcon())
- #wx.IconFromBitmap(wx.Bitmap("icon.ico", wx.BITMAP_TYPE_ANY)))
- self.panel = wx.Panel(self)
-
- self.ct = 0
- self.layerSelection = "Edge_Cuts"
- layerList = ["Edge_Cuts", "Eco1_User", "Eco2_User", "Dwgs_User", "Cmts_User",\
- "Margin", "F_CrtYd", "B_CrtYd", "F_Fab", "B_Fab", "F_SilkS", "B_SilkS", "F_Mask", "B_Mask"]
- self.combo = wx.ComboBox(self.panel, choices=layerList)
- self.combo.SetSelection(0)
-
- self.combo.Bind(wx.EVT_COMBOBOX, self.onCombo)
-
- self.title = wx.StaticText(self.panel, label="Move to Layer:")
- #self.result = wx.StaticText(self.panel, label="")
- #self.result.SetForegroundColour('#FF0000')
- #self.button = wx.Button(self.panel, label="Save")
- #self.lblname = wx.StaticText(self.panel, label="Your name:")
- #self.editname = wx.TextCtrl(self.panel, size=(140, -1))
- ##self.editname = wx.TextCtrl(self.panel, size = (300, 400), style = wx.TE_MULTILINE|wx.TE_READONLY)
-
-
- # Set sizer for the frame, so we can change frame size to match widgets
- self.windowSizer = wx.BoxSizer()
- self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
-
- # Set sizer for the panel content
- self.sizer = wx.GridBagSizer(5, 0)
- self.sizer.Add(self.title, (0, 0))
- self.button = wx.Button(self.panel, label="OK")
- self.sizer.Add(self.button, (2, 0), (1, 2), flag=wx.EXPAND)
- #self.sizer.Add(self.result, (1, 0))
- #self.sizer.Add(self.lblname, (1, 0))
- ##self.sizer.Add(self.editname, (1, 0))
- self.sizer.Add(self.combo, (1, 0))
- #self.sizer.Add(self.button, (2, 0), (1, 2), flag=wx.EXPAND)
-
- # Set simple sizer for a nice border
- self.border = wx.BoxSizer()
- self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
-
- # Use the sizers
- self.panel.SetSizerAndFit(self.border)
- self.SetSizerAndFit(self.windowSizer)
-
- #self.button = wx.Button(self.panel, label="Close")
- self.button.Bind(wx.EVT_BUTTON, self.OnClose)
- self.Bind(wx.EVT_CLOSE,self.OnClose)
-
- #----------------------------------------------------------------------
- def OnClose(self,e):
- #wx.LogMessage("c")
- e.Skip()
- self.Destroy() #Close()
- #self.result.SetLabel(msg)
- # Set event handlers
- #self.button.Bind(wx.EVT_BUTTON, self.OnButton)
- #self.Show()
- #self.Bind(wx.EVT_CLOSE,self.OnClose)
- def onCombo(self, event):
- """
- """
- self.layerSelection = self.combo.GetValue()
-
- #def OnClose(self,e):
- # #wx.LogMessage("c")
- # e.Skip()
- #self.Close()
-
- #def OnButton(self, e):
- # self.result.SetLabel(self.editname.GetValue())
- #def setMsg(self, t_msg):
- # self.editname.SetValue(t_msg)
-
- board = pcbnew.GetBoard()
- #wx.MessageDialog(None, 'This is a message box.', 'Test', wx.OK | wx.ICON_INFORMATION).ShowModal()
- fileName = GetBoard().GetFileName()
- if len(fileName)==0:
- wx.LogMessage("a board needs to be saved/loaded!")
- else:
- LogMsg=''
- msg="'move to layer tool'\n"
- msg+="version = "+___version___
- frame = displayDialog(None)
- #frame = wx.Frame(None)
- frame.Center()
- #frame.setMsg(LogMsg)
- frame.ShowModal()
- frame.Destroy()
-
- #dlg=wx.MessageBox( 'Changing Layer for Selected?', 'Confirm', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION )
- dlg=wx.MessageBox( 'Changing Layer for Selected '+frame.layerSelection+ '?', 'Confirm', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_WARNING )
- if dlg == wx.YES:
- #wx.LogMessage("YES")
- #wx.LogMessage(str(board.IsModified()))
- #board.SetModified()
- #wx.LogMessage(str(board.IsModified()))
- for drw in board.GetDrawings():
- if drw.IsSelected():
- drw.SetLayer(switch(frame.layerSelection))
- found_selected=True
-
- if found_selected!=True:
- LogMsg="select lines to be moved to new layer\n"
- LogMsg+="use GAL for selecting lines"
- wx.LogMessage(LogMsg)
- else:
- pcbnew.Refresh()
- LogMsg="selected drawings moved to "+frame.layerSelection+" layer"
- wx.LogMessage(LogMsg)
-
-
-
-move_to_draw_layer().register()
-
-
-# "b64_data" is a variable containing your base64 encoded jpeg
-move_to_layer_ico_b64_data =\
-"""
-iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAKYQAACmEB/MxKJQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAJrSURBVDiNnZRRSFNxFMa/s3vlLje3y0bpdKkwrcTCxbChQUIPUWBJ0IvQy3STCIkgoehFJIKCHkSCkLRBVNJT0EPQQ4W9bFmJDS0TSmwbc65ku7ZrY96dHsQ1yQfnB+flcPj9/985h0O+iz5nVtJGwGwjprEHg6N92IHErKSNTB9fcKmmDPa9qb3gdt9dmJg48hIQIswudaOwt7fXmhZXbzOhTdDgr7ZW3+rv78/lQWC2qaYMQIBSnjasrBqGAAawBqJ3ywDCACInzlod2dOT+xO1CtUFbVeFcHQawPM8iJjGGt7aPakK1Vg1Y02FYnu8AMkA7IVRJqfqv9YqlBNzWHIkTXLc0F4IImZGT09Pa06CU/udfeL3+5Nb9aD7Uvf1ZVv62pIjWbY3aP9jTgtHh4eHJzeBtqOBgQFdNB5t/x6xD4aCLksiUbGb2ZXNFzBzUQEEO4AgA8GOwrxuW9/ZJPEFgGUA5wuzRYPW7dBTAO1EH807Bq1LewRAD2jnCl4orkcbIUnj887me3M+n6+Vmbc/tUJ5PB45q9eHY01xo5zYlTT/0o8WZY1oSiYKnJybP/Q45lw0LDYmMNv2Q2biThHAlgtJBB3wvgHQWgBqAdAC4ACgo2+zdVl3JKSh4adYqkgAUUzsutx9R6lWPakK1Vg5VX7DaHx1P502HgbgBmAGCACiAAIAjwC6QDxeMmldEW5antV3gihWkhG8IhN3fjkWsYCA3JpgqXEsXPkcavwAwA9wABACzM3h/42e6gOQPzkiiGKlilSpmjIwL5UqVU1TZ2Y+dY0XOwCxJCN4D76u+XfYHg4VDQGAvyJXT3w3dEsJAAAAAElFTkSuQmCC"""
-
-# pcbnew.F_Cu
-# pcbnew.In1_Cu
-# pcbnew.In2_Cu
-#..
-# pcbnew.In30_Cu
-# pcbnew.B_Cu
-# pcbnew.B_Adhes
-# pcbnew.F_Adhes
-# pcbnew.B_Paste
-# pcbnew.F_Paste
-# pcbnew.B_SilkS
-# pcbnew.F_SilkS
-# pcbnew.B_Mask
-# pcbnew.F_Mask
-# pcbnew.Dwgs_User
-# pcbnew.Cmts_User
-# pcbnew.Eco1_User
-# pcbnew.Eco2_User
-# pcbnew.Edge_Cuts
-# pcbnew.Margin
-# pcbnew.B_CrtYd
-# pcbnew.F_CrtYd
-# pcbnew.B_Fab
-# pcbnew.F_Fab
diff --git a/action_menu_positions.py b/action_menu_positions.py
deleted file mode 100644
index 5ac3b15..0000000
--- a/action_menu_positions.py
+++ /dev/null
@@ -1,420 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# A script to generate POS file for kicad_pcb
-# requirements: KiCAD pcbnew >= 4.0
-# release "1.0.8"
-# copyright Maurice easyw
-#
-# main script from https://forum.kicad.info/t/pcba-wants-all-parts-in-the-pos-file-not-just-smd/10045/6
-#
-
-___version___="1.0.8"
-#wx.LogMessage("My message")
-#mm_ius = 1000000.0
-
-import sys, os
-import pcbnew
-import datetime
-import wx
-from pcbnew import *
-import base64
-from wx.lib.embeddedimage import PyEmbeddedImage
-
-"""
-execfile ("C:/kicad-wb-1602/msys64/home/userC/out3Dm/pack-x86_64/share/kicad/scripting/plugins/getpos.py")
-"""
-
-def generate_POS():
- import os
- mm_ius = 1000000.0
-
- my_board = pcbnew.GetBoard()
-
- fileName = pcbnew.GetBoard().GetFileName()
-
- 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]
-
- #lsep=os.linesep
- lsep='\n'
-
- LogMsg1=lsep+"reading from:" + lsep + dirpath + lsep + lsep
- out_filename_top_SMD=path+os.sep+name+"_POS_top_SMD.txt"
- out_filename_bot_SMD=path+os.sep+name+"_POS_bot_SMD.txt"
- out_filename_top_THD=path+os.sep+name+"_POS_top_THD.txt"
- out_filename_bot_THD=path+os.sep+name+"_POS_bot_THD.txt"
- out_filename_top_VIRTUAL=path+os.sep+name+"_POS_top_Virtual.txt"
- out_filename_bot_VIRTUAL=path+os.sep+name+"_POS_bot_Virtual.txt"
- out_filename_ALL=path+os.sep+name+"_POS_All.txt"
- #out_filename=path+os.sep+name+"_POS.txt"
- LogMsg1+="written to:" + lsep + out_filename_top_SMD + lsep
- LogMsg1+= out_filename_bot_SMD + lsep
- LogMsg1+= out_filename_top_THD + lsep
- LogMsg1+= out_filename_bot_THD + lsep
- LogMsg1+= out_filename_top_VIRTUAL + lsep
- LogMsg1+= out_filename_bot_VIRTUAL + lsep
- LogMsg1+= out_filename_ALL + lsep
- # print (LogMsg)
- #
- # print ("### Module positions - created on %s ###" % datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
- # print ("### Printed by get_pos v1")
- # print ("## Unit = mm, Angle = deg.")
- # print ("## Side : All")
- # print ("# Ref Val Package PosX PosY Rot Side Type")
-
- Header_1="### Module positions - created on " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M")+lsep
- Header_1+="### Printed by get_pos v1"+lsep
- Header_1+="## Unit = mm, Angle = deg."+lsep
- #LogMsg+="## Side : All"+lsep
- Header_2="## Board Aux Origin: " + str(my_board.GetAuxOrigin())+lsep
-
- Header_2+="{0:<10}".format("# Ref")+"{0:<20}".format("Val")+"{0:<20}".format("Package")+\
- "{0:<11}".format("PosX")+"{0:<11}".format("PosY")+"{0:<8}".format(" Rot")+\
- "{0:<10}".format(" Side")+" Type"+lsep
- content_top_SMD=''
- content_bot_SMD=''
- content_top_THD=''
- content_bot_THD=''
- content_top_VIRTUAL=''
- content_bot_VIRTUAL=''
- content_ALL=''
- SMD_pads = 0
- TH_pads = 0
- Virt_pads = 0
- TH_top_cnt = 0
- TH_bot_cnt = 0
- SMD_top_cnt = 0
- SMD_bot_cnt = 0
- Virt_top_cnt = 0
- Virt_bot_cnt = 0
-
- bb = my_board.GetBoardEdgesBoundingBox()
- pcb_height = bb.GetHeight() / mm_ius
- pcb_width = bb.GetWidth() / mm_ius
- #to add relative position to
- #print ("Board Aux Origin: " + str(my_board.GetAuxOrigin()))
-
- #'{0:<10} {1:<10} {2:<10}'.format(1.0, 2.2, 4.4))
-
- for module in my_board.GetModules():
- #print ("%s \"%s\" %s %1.3f %1.3f %1.3f %s" % ( module.GetReference(),
- #Nchars = 20
- # RefL = 10; ValL = 20
-
- md=""
- if module.GetAttributes() == 0: # PTH=0, SMD=1, Virtual = 2
- md = "THD"
- TH_pads+=module.GetPadCount()
- elif module.GetAttributes() == 1:
- md = "SMD"
- SMD_pads+=module.GetPadCount()
- else:
- md = "VIRTUAL"
- Virt_pads+=module.GetPadCount()
-
- #Reference=str(module.GetReference()).ljust(Nchars/2)
- #Value=str(module.GetValue()).ljust(Nchars)
- #Package=str(module.GetFPID().GetLibItemName()).ljust(Nchars)
- #X_POS=str(pcbnew.ToMM(module.GetPosition().x - my_board.GetAuxOrigin().x ))
- #Y_POS=str(-1*pcbnew.ToMM(module.GetPosition().y - my_board.GetAuxOrigin().y))
- #Rotation=str(module.GetOrientation()/10)
- #Layer="top".ljust(Nchars) if module.GetLayer() == 0 else "bottom".ljust(Nchars)
- #Type=md
- Reference="{0:<10}".format(str(module.GetReference()))
- Value = str(module.GetValue())
- Value=(Value[:17] + '..') if len(Value) > 19 else Value
- Value="{0:<20}".format(Value)
- Package = str(module.GetFPID().GetLibItemName())
- Package=(Package[:17] + '..') if len(Package) > 19 else Package
- Package="{0:<20}".format(Package)
- #Package="{0:<20}".format(str(module.GetFPID().GetLibItemName()))
- X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - my_board.GetAuxOrigin().x ))
- X_POS="{0:<11}".format(X_POS)
- Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - my_board.GetAuxOrigin().y))
- Y_POS="{0:<11}".format(Y_POS)
- Rotation='{0:.1f}'.format((module.GetOrientation()/10))
- Rotation="{0:>6}".format(Rotation)+' '
- if module.GetLayer() == 0:
- Layer=" top"
- else:
- Layer=" bottom"
- #Side="## Side :"+Layer+lsep
- Layer="{0:<10}".format(Layer)
- Type=' '+md
- content=Reference
- content+=Value
- content+=Package
- content+=X_POS
- content+=Y_POS
- content+=Rotation
- content+=Layer
- content+=Type+lsep
- if 'top' in Layer and 'SMD' in Type:
- content_top_SMD+=content
- SMD_top_cnt+=1
- elif 'bot' in Layer and 'SMD' in Type:
- content_bot_SMD+=content
- SMD_bot_cnt+=1
- elif 'top' in Layer and 'THD' in Type:
- content_top_THD+=content
- TH_top_cnt+=1
- elif 'bot' in Layer and 'THD' in Type:
- content_bot_THD+=content
- TH_bot_cnt+=1
- elif 'top' in Layer and 'VIRTUAL' in Type:
- content_top_VIRTUAL+=content
- Virt_top_cnt+=1
- elif 'bot' in Layer and 'VIRTUAL' in Type:
- content_bot_VIRTUAL+=content
- Virt_bot_cnt+=1
- content_ALL+=content
- #print ("%s %s %s %1.4f %1.4f %1.4f %s %s" % ( str(module.GetReference()).ljust(Nchars),
- # str(module.GetValue()).ljust(Nchars),
- # str(module.GetFPID().GetLibItemName()).ljust(Nchars),
- # pcbnew.ToMM(module.GetPosition().x - my_board.GetAuxOrigin().x ),
- # -1*pcbnew.ToMM(module.GetPosition().y - my_board.GetAuxOrigin().y),
- # module.GetOrientation()/10,
- # "top".ljust(Nchars) if module.GetLayer() == 0 else "bottom".ljust(Nchars),
- # md
- # ))
-
-#"top" if module.GetLayer() == 0 else "bottom"
-
- #LogMsg+="## End"+lsep
-
- Header=Header_1+"## Side : top"+lsep+Header_2
- content=Header+content_top_SMD+"## End"+lsep
- with open(out_filename_top_SMD,'w') as f_out:
- f_out.write(content)
- Header=Header_1+"## Side : bottom"+lsep+Header_2
- content=Header+content_bot_SMD+"## End"+lsep
- with open(out_filename_bot_SMD,'w') as f_out:
- f_out.write(content)
- Header=Header_1+"## Side : top"+lsep+Header_2
- content=Header+content_top_THD+"## End"+lsep
- with open(out_filename_top_THD,'w') as f_out:
- f_out.write(content)
- Header=Header_1+"## Side : bottom"+lsep+Header_2
- content=Header+content_bot_THD+"## End"+lsep
- with open(out_filename_bot_THD,'w') as f_out:
- f_out.write(content)
- Header=Header_1+"## Side : top"+lsep+Header_2
- content=Header+content_top_VIRTUAL+"## End"+lsep
- with open(out_filename_top_VIRTUAL,'w') as f_out:
- f_out.write(content)
- Header=Header_1+"## Side : bottom"+lsep+Header_2
- content=Header+content_bot_VIRTUAL+"## End"+lsep
- with open(out_filename_bot_VIRTUAL,'w') as f_out:
- f_out.write(content)
- Header=Header_1+"## Side : ALL"+lsep+Header_2
- content=Header+content_ALL+"## End"+lsep
- content = content + '## '+ str(SMD_pads) + ' SMD pads' +lsep
- content = content + '## '+ str(TH_pads) + ' TH pads' +lsep
- content = content + '## '+ str(Virt_pads) + ' Virtual pads' +lsep
- content = content + '## '+ str( TH_top_cnt) + ' Top TH modules' + lsep
- content = content + '## '+ str( TH_bot_cnt) + ' Bot TH modules' + lsep
- content = content + '## '+ str( SMD_top_cnt) + ' Top SMD modules' + lsep
- content = content + '## '+ str( SMD_bot_cnt) + ' Bot SMD modules' + lsep
- content = content + '## '+ str( Virt_top_cnt) + ' Top Virtual modules' + lsep
- content = content + '## '+ str( Virt_bot_cnt) + ' Bot Virtual modules' + lsep
-
- with open(out_filename_ALL,'w') as f_out:
- f_out.write(content)
-
- #with open(out_filename,'w') as f_out:
- # f_out.write(LogMsg)
- #LogMsg=""
- #f = open(out_filename,'w')
- #f.write(LogMsg)
- #f.close()
- LogMsg1+= lsep + str(SMD_pads) + ' SMD pads' +lsep
- LogMsg1+= str(TH_pads) + ' TH pads' +lsep
- LogMsg1+= str(Virt_pads) + ' Virtual pads' +lsep
- LogMsg1+= str( TH_top_cnt) + ' Top TH modules' + lsep
- LogMsg1+= str( TH_bot_cnt) + ' Bot TH modules' + lsep
- LogMsg1+= str( SMD_top_cnt) + ' Top SMD modules' + lsep
- LogMsg1+= str( SMD_bot_cnt) + ' Bot SMD modules' + lsep
- LogMsg1+= str( Virt_top_cnt) + ' Top Virtual modules' + lsep
- LogMsg1+= str( Virt_bot_cnt) + ' Bot Virtual modules' + lsep
- LogMsg1+= '{0:.3f}'.format( pcb_height ) + 'mm Pcb Height, ' + '{0:.3f}'.format( pcb_width ) + 'mm Pcb Width [based on Edge bounding box]' +lsep
-
- return LogMsg1
- #return LogMsg1+LogMsg
-
-
-
-
-class generatePOS( pcbnew.ActionPlugin ):
- """
- A script to generate POS file for kicad_pcb
- requirements: KiCAD pcbnew >= 4.0
- release "1.0.1"
-
- """
-
- 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 = "Generate POS output"
- self.category = "Fabrication Output"
- self.description = "Generate POS output for SMD, THD, Virtual"
-
- def Run( self ):
-
- #wx.MessageDialog(self.frame,"ciao")
- #subprocess.check_call(["C:\pathToYourProgram\yourProgram.exe", "your", "arguments", "comma", "separated"])
- #http://stackoverflow.com/questions/1811691/running-an-outside-program-executable-in-python
- class displayDialog(wx.Dialog):
- """
- The default frame
- http://stackoverflow.com/questions/3566603/how-do-i-make-wx-textctrl-multi-line-text-update-smoothly
- """
-
- #----------------------------------------------------------------------
- #def __init__(self):
- # """Constructor"""
- # wx.Frame.__init__(self, None, title="Display Frame", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION)
- # panel = wx.Panel(self)
- def __init__(self, parent):
- wx.Dialog.__init__(self, parent, id=-1, title="Generate POS output")#
- #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION)
- #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION)
- #, pos=DefaultPosition, size=DefaultSize, style = wx.DEFAULT_FRAME_STYLE & (~wx.MAXIMIZE_BOX), name="fname")
- #, wx.ICON_INFORMATION) #, title="Annular Check", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION)
- #
-
- self.SetIcon(PyEmbeddedImage(round_ico_b64_data).GetIcon())
- #wx.IconFromBitmap(wx.Bitmap("icon.ico", wx.BITMAP_TYPE_ANY)))
- self.panel = wx.Panel(self)
- self.title = wx.StaticText(self.panel, label="Generate POS debug:")
- #self.result = wx.StaticText(self.panel, label="")
- #self.result.SetForegroundColour('#FF0000')
- self.button = wx.Button(self.panel, label="Close")
- #self.lblname = wx.StaticText(self.panel, label="Your name:")
- #self.editname = wx.TextCtrl(self.panel, size=(140, -1))
- self.editname = wx.TextCtrl(self.panel, size = (600, 500), style = wx.TE_MULTILINE|wx.TE_READONLY)
-
-
- # Set sizer for the frame, so we can change frame size to match widgets
- self.windowSizer = wx.BoxSizer()
- self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
-
- # Set sizer for the panel content
- self.sizer = wx.GridBagSizer(5, 0)
- self.sizer.Add(self.title, (0, 0))
- #self.sizer.Add(self.result, (1, 0))
- #self.sizer.Add(self.lblname, (1, 0))
- self.sizer.Add(self.editname, (1, 0))
- self.sizer.Add(self.button, (2, 0), (1, 2), flag=wx.EXPAND)
-
- # Set simple sizer for a nice border
- self.border = wx.BoxSizer()
- self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
-
- # Use the sizers
- self.panel.SetSizerAndFit(self.border)
- self.SetSizerAndFit(self.windowSizer)
- #self.result.SetLabel(msg)
- # Set event handlers
- #self.Show()
- self.button.Bind(wx.EVT_BUTTON, self.OnClose)
- self.Bind(wx.EVT_CLOSE,self.OnClose)
-
- def OnClose(self,e):
- #wx.LogMessage("c")
- e.Skip()
- #self.Close()
- self.Destroy()
-
- #def OnButton(self, e):
- # self.result.SetLabel(self.editname.GetValue())
- def setMsg(self, t_msg):
- self.editname.SetValue(t_msg)
-
-
-
- def f_mm(raw):
- return repr(raw/mm_ius)
-
- board = pcbnew.GetBoard()
-
- #fileName = GetBoard().GetFileName()
- fileName = pcbnew.GetBoard().GetFileName()
- if len(fileName)==0:
- wx.LogMessage("a board needs to be saved/loaded!")
- else:
- LogMsg=''
- # msg="'get_pos.py'"+os.linesep
- msg="Generate POS output: version = "+___version___+os.linesep
- #msg+="Generate POS output"+os.linesep
- #print (msg)
- #LogMsg=msg+'\n\n'
-
- print(msg)
- LogMsg+=msg
- reply=generate_POS()
- LogMsg+=reply
-
- frame = displayDialog(None)
- #frame = wx.Frame(None)
- frame.Center()
- frame.setMsg(LogMsg)
- frame.ShowModal()
- frame.Destroy()
- #frame = wx.wxFrame(None, 10110, 'T-Make', size=wx.wxSize(100,100),
- # style=wx.wxSTAY_ON_TOP)
- #frame.show()
-
-generatePOS().register()
-
-# "b64_data" is a variable containing your base64 encoded jpeg
-round_ico_b64_data =\
-"""
-iVBORw0KGgoAAAANSUhEUgAAAEAAAAA/CAYAAABQHc7KAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAdDwAAHQ8Bjlx1kwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3Nj
-YXBlLm9yZ5vuPBoAAAw+SURBVGiB7Zt7cFTVHcc/d+9uSAIhklgIpiQ0tjxSkCKIQ1CpCO3wUKCW0cF0Bqf/VFTG6tROS/8QZuxYwZGHgqD4SjNToFFDjJjGB4LkyUPk
-FUhClETShCRssslu9u599I/Nvbm7e/eRENCZ8p3Zufec8zvn/H7f+zu/87h34QZu4Ab+nyGEyYsD7NdZl2sNGZAAzZxpZWQiMAu4FXBce72uC3xAPVAF9JgLrAiwA+lP
-PfXU4hUrVky9Dspdc+zdu/fkpk2bCrCw14oAAbBNmjTp5pkzZ97a5epGEPoL9IQQdA25D2k1qMxKVgisFakNHZs2bWLlypWMHj3awhQYNmwYJ0+ebAZsVk3aLGv1QVYU
-ZFnu+yl9aQVFUcjLyyM/Px9ZllEUf17Afd9VUVUUVUVVFFRVRQ2TNvKs8vWfXm6SO1Jdzdx77uHMmTP9ciZZTVUjmRiZAPCTLghCwBXg788/zz9eeCHAE0LuBQGhL23c
-h0kbeWHyjTLzr0/HxsZG5t17L18cOBBaNwoiEmAoa1xDGw2QsboPJiFc2pQXjQizDIDNZsPtdrNs2TLy8vJCZQdLQCjrFsxaPeUo95ZpU14AOWYiTOXBdXXXX716NX96
-9lk0TQvwkkERoFcODnghgW8gJERKR/IGKzJMOgJomn+K375tG7/LzaXX44lifpTFTllZGUePHQtkURDQNA2Px4NXknjzzTdDys3khc0PJxemXjjZhoYGw3Az9u3bx8KF
-CyksLIzYfEQCSkpKeOeddyzLuru7EQSBDRs2hFXuesDpdKJaRHpN06iurubJJ59kwYIFYetHJOCOWbPw9PZaPuFdb7yBzWbj4Yceiv40YygfMIF9bX5YVERtbW2IFwiC
-QE5ODjt37mTv3r1hm4lIwJIlS5g3b56/QZOiGrB7924cdjvr1q8PKAsxKJZ7q7TJyEjkfNPQQH19PYqimKoJLFy4kPz8fJKSkiKZGJmAkCCoK6pp/WVm5a+WBFNfQZkD
-8pBHHnmEHTt2YLfbo64Fou74QmYAQLOYBgdNAhZGRzA4mkFPPPEEL730UkyLIIhGgIXxugcEK3S1JMTsDRZQFMUIyGvWrImpjo7YPcCkpOEBkQwWBPaXfMTxmhNBDcK0
-n03lgcUPAHDoy0N8fuSLkH4zR2fwaO4qwD/VfVBaiKwFRvvh9gRUVcVut/P666+Tm5trlFlNjVYYdAwISAfJ6XmHK8v4IvEoTROvGG2m142is7yTpUuWAnDsq2Mc6Kyg
-7hethszNl5K4/VAWj+auQhAE6uvrKTtRQfn8OkPGIYnMLrwVURQpKChg0aJFgboPyRCwMp7AGBCJBAToSZFoHe8y5Ee2J8AVk6wg4B4ZKOPw2UOMUIcRIBPn8cs899xz
-TJo0KSZjrRDTsVfI+Da7l8Uw6Ffc+ikIxP6EoiE5Ofmq6kf3AAgxMpwHfPbZZ5w9e9You9zaCumhbbZ3tLNlyxYA6urqIDNUxuv1snnzZgBaWlqQZdlSv3fffZf4+Hhy
-cnKYNWtWqP5RiI56HhBxmgvKLy8vB2DOnDnMmTOHESNGWDaZmJhITk4OOTk5pKamWsrY7aIhk5WVhc1mrer06dNxOp0cPXo0qimW/UQsDWN82BggCKSnpzN79mwA3vvw
-fX5SO5oxnaMM+cTLdoYnDDdkyivL+XFtKjd9OtKQGeYUcTjiDBmXy0V8pYPZX04wZGyyYBBQW1s7KOMhllnAioQoMUDHY7//Ay0tLSHtms/vVj68ktkNs0NkUlJSjPs7
-77zTckkr/lIMaGswcWVIY0Dw3JuVlUVWVlbE9tPS0khLS4sok5ycbHjDUGPoZgH8Z3NNTU0kJSWxePHiIYv01xLRCQjakem7QUxpv5hARkYGY8aMoaioCFmWWbZs2VDq
-GkXN2A5BgxH9TLDvqndivpo715GamsqMGTM4ffr0gJW5FriqaTDY9TFfgzoQBAFJkqitreXgwYPGOcIPHbEFQQgbBP3Z/nRHRwc+n4+1a9cyefLkodU0Bpif9pBshkwt
-+y96MkynaWlpZGdnfy/GB2PINkNWcSBWdq8nNE2zPBeMhoENgQgNW+VVH6nmxNmvQ/LHpY3j1wt+BcCpU6c4fLwcgpRPSUphxfLfAtDW1kZxSTGKpgTIxIlxLH9guZHW
-D0bMOl31kVhfS0aDA8H+0o8pvXKISxM6jbyUS8O5rTzLIKCiooLdp9+n9vb+FePI9gR+/tEtBgHnzp2jqORDjt9zsb9xDW7/TwazZvg3QKqqGgQEzFaCQKTXo7EvhPT7
-viEQ7rX4qVOnyM/PB6C5uRlnhocLt102ymVRwdPgMWTOnz+Pe6QUcGjyo0YZrUwzZJqampBFNaAdnYCSkhIaGhrIzMzE4/EYBNhsNmw2G6IjLuIb4tgXQmGevjn/wQcf
-5MKFC0ZaFMWwdRITE/0K2MOoIEBCQgIADocj3NECmqYxY8YMJk6cSG9vbwgBDg1kNXzMijkG9GluGGCFKVOmMHVq/0clJ8+dspSLj483Vont7e183lQd2q8gcP/99+Pz
-+SgrK+PLM+WWbU2bNo2MjAyAAA/QMUzRkP3vDFSCvg+CQU6D1wterxdZlvH5fBaq98u43W4jrSgKPp8PSZKwO+LA5ux5b++ec8Bl/B9KBSC2Y/GArP5pMNKS2F9P4Obm
-EUyuGmvkJbckGC3q8qNaEpl+qP9YKL7LDhpIkoTP50OWZWwSTKxMM7XtR3d3Nx0dHciyTG9vLz6fj4SEBNLSxqKiKo89trqg/PDh94BKoJ+pWAiwcv+B4Df3L2dq7ZTA
-zHQYO7afkAULFpCZ6Tde0zQjmjvmOAwC0tPTmTf7XuZIXhRZ//RGwX6Hnbi4OGRZZtSoUaSmppCcfBM9PT18d+k75fHVj79TVVX1NvAV0M2ghkCM7m/lDdnZ2WRnZ4ct
-B8jMzGTcuHGG8ZIkBfz0YZCamsrSpUsRRRGHw2F4ob4AkmUfvb1eOjs7udh4UXn6j0+/VVVVtR2oATxWxsdGwDWGboDfCNkY8/pPkiR6enpwu93Ex8cbdfSrqqrIsg+P
-x4PT6eSbb79R/vqXtTurqqq2Ahew+DjSjAHNAkN1wGG1adE0zfjSLJgISZJCluC6vM/nw+12c+VKB3X1dfL6deu2VlRUvQpcxB/0Iq7bIxKQl5fHli1bjFfPuuKaptHW
-1oYgCMycOTOknsPh4OWXXyYnJyfEYDOCjTf/9E/uZFnG6/WGPH1ZlpEkL93dPbS1X+ZszVnpxRc3bDxSdWQb0IJFxB8wAbm5uRw4cCDsVyIAJ06cCMlbv369YXw06O5v
-/sZP6fsGUFEUJEnC7XaTkpISMFS83l66uly0Xm7h5Mmvezdv2bru+NHjbwFtgBKtXx2RZwFBYNu2bfT09FBQUBB1FygIAqtWrWLt2rWx9m/ATIB5OHi9XlwuF9nZ2X2k
-yLjdHjo7nTT/t5nyyrIru3a+9cyZM2c+AJxEcflgRI0Boijy9ttv09XVRWlpaVgSbDYb8+fPZ/v27TF3HhzJzd6g30uShMvlYvz48fh8Em63hytXOmhsaqSoqLAm/5//
-WtPa2lpBmGkuGmKaBRwOB7t372bRokVUVlaGfJQkiiJTpkxhz5494df2MSB4T6+qKh6Ph+TkZETRRleXi/b2Nuov1Klv7Nr10b4Piv4GnAd6GYTxMIBpMDExkX379nHf
-ffdx+vRpIzCKosjYsWMpLi4O+yosVpjX8fpY7+rqYsKECTidnbRebuHoseM9217ZuvX48RM7gO+IIdJHQkwEaPinw+TkZIqLi5k7dy4XL15E0zSGDx/O/v37o77ciITA
-r1H7SXC73Xg8Hm65ZSyNTRcpeP+D8zu3v/Z8V1dXCQMMduEwYH8dM2YMpaWl3HXXXbS3t1NYWDjo9/Pmud1mswUQoCgKLpeLn06YQH3DBWXjxo3FpSWlm4FjQCdX8dTN
-iDoLmE9X9PuMjAw++eQTampquPvuu43ywUAQBASbDVEUsdsdKKqKqCgomkB80k1aw7ffOv/8zNM72tvb/41/WetmiIwHawI0QK2pqWmrqKioj1Q5LS2NysrKq1ZC1TQ0
-DXyyik9V8PlkXG43Bz8tbXzt1VcKgI/xr+x8DKHxYL3HGc73/58hAX9wawaq8e/lr3q8h+vIKu+H8q8xBf9mJvLfPm7gBm7gBgaJ/wGnp66JbeWfegAAAABJRU5ErkJg
-gg==
-"""
-
-
-
-# execfile("round_tracks.py")
-