diff --git a/AnnularChecker/AR-params - Copy.fbp b/AnnularChecker/AR-params - Copy.fbp
new file mode 100644
index 0000000..715b6c3
--- /dev/null
+++ b/AnnularChecker/AR-params - Copy.fbp
@@ -0,0 +1,914 @@
+
+
+
+
+
diff --git a/AnnularChecker/AR-params.fbp b/AnnularChecker/AR-params.fbp
new file mode 100644
index 0000000..3a9e63a
--- /dev/null
+++ b/AnnularChecker/AR-params.fbp
@@ -0,0 +1,1016 @@
+
+
+
+
+
+ Python
+ 1
+ source_name
+ 0
+ 0
+ res
+ UTF-8
+ connect
+
+ 1000
+ none
+
+ 0
+ parametersDlg
+
+ .
+
+ 1
+ 1
+ 1
+ 1
+ UI
+ 0
+ 0
+
+ 0
+ wxAUI_MGR_DEFAULT
+
+ wxBOTH
+
+ 1
+ 1
+ impl_virtual
+
+
+
+ 0
+ wxID_ANY
+
+
+ AR_Prm
+
+ 320,229
+ wxDEFAULT_DIALOG_STYLE
+ ; forward_declare
+ Annular Checker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ bSizer1
+ wxVERTICAL
+ none
+
+ 5
+ wxEXPAND
+ 1
+
+ 2
+ 0
+
+ gSizer2
+ none
+ 0
+ 0
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ PHD margin
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_StaticTextPHD
+ 1
+
+
+ protected
+ 1
+ -1,-1
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+
+ 0
+
+ 1
+ m_textPHD
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ AR for pads
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_StaticTextAR_SET
+ 1
+
+
+ protected
+ 1
+ -1,-1
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+
+ 0
+
+ 1
+ m_textAR_SET
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ AR for vias
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_StaticTextAR_SET_V
+ 1
+
+
+ protected
+ 1
+ -1,-1
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+
+ 0
+
+ 1
+ m_textAR_SET_V
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+ Version
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticTextVersion
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND
+ 1
+
+ 2
+ 0
+
+ gSizer1
+ 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
+ m_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
+ Cancel
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_cancel_btn
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+ ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AnnularChecker/__init__ (copy).py.txt b/AnnularChecker/__init__ (copy).py.txt
new file mode 100644
index 0000000..7caa4ab
--- /dev/null
+++ b/AnnularChecker/__init__ (copy).py.txt
@@ -0,0 +1,2 @@
+from .annular_checker import annular_check
+annular_check().register()
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/__init__.pyc b/AnnularChecker/__init__.pyc
new file mode 100644
index 0000000..1d8da1e
Binary files /dev/null and b/AnnularChecker/__init__.pyc differ
diff --git a/AnnularChecker/__init__HTML.py.txt b/AnnularChecker/__init__HTML.py.txt
new file mode 100644
index 0000000..ba81907
--- /dev/null
+++ b/AnnularChecker/__init__HTML.py.txt
@@ -0,0 +1,2 @@
+from .annular_checker_html import annular_check
+annular_check().register()
diff --git a/AnnularChecker/__init__OLD.py.txt b/AnnularChecker/__init__OLD.py.txt
new file mode 100644
index 0000000..bae6b54
--- /dev/null
+++ b/AnnularChecker/__init__OLD.py.txt
@@ -0,0 +1,56 @@
+from annular_checker import annular_check
+import pcbnew
+import wx
+import wx.aui
+import threading
+import time
+import sys
+import subprocess
+import os
+# import pcbnew
+from pcbnew import *
+# import base64
+from wx.lib.embeddedimage import PyEmbeddedImage
+
+plugin = annular_check()
+plugin.register()
+
+
+def check_for_annular_button():
+ # From Miles McCoo's blog
+ # https://kicad.mmccoo.com/2017/03/05/adding-your-own-command-buttons-to-the-pcbnew-gui/
+ def find_pcbnew_window():
+ windows = wx.GetTopLevelWindows()
+ pcbnewwn = [w for w in windows if "Pcbnew" in w.GetTitle()]
+ if len(pcbnewwn) != 1:
+ return None
+ return pcbnewwn[0]
+
+ def callback(_):
+ plugin.Run()
+
+ import os
+ path = os.path.dirname(__file__)
+ bm = wx.Bitmap(path + '/annular.png', wx.BITMAP_TYPE_PNG)
+ button_wx_item_id = 1
+ while True:
+ time.sleep(1.5)
+ pcbwin = find_pcbnew_window()
+ if not pcbwin:
+ continue
+
+ top_tb = pcbwin.FindWindowById(pcbnew.ID_H_TOOLBAR)
+ if button_wx_item_id == 1 or not top_tb.FindTool(button_wx_item_id):
+ #top_tb.AddSeparator()
+ button_wx_item_id = wx.NewId()
+ top_tb.AddTool(button_wx_item_id, "aChecker", bm,
+ "PCB Annular Checker", wx.ITEM_NORMAL)
+
+ top_tb.Bind(wx.EVT_TOOL, callback, id=button_wx_item_id)
+ top_tb.Realize()
+
+
+if 0:
+ t = threading.Thread(target=check_for_annular_button)
+ t.daemon = True
+ t.start()
diff --git a/AnnularChecker/__pycache__/__init__.cpython-36.pyc b/AnnularChecker/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000..b16f157
Binary files /dev/null and b/AnnularChecker/__pycache__/__init__.cpython-36.pyc differ
diff --git a/AnnularChecker/__pycache__/annular_checker.cpython-36.pyc b/AnnularChecker/__pycache__/annular_checker.cpython-36.pyc
new file mode 100644
index 0000000..5338f5a
Binary files /dev/null and b/AnnularChecker/__pycache__/annular_checker.cpython-36.pyc differ
diff --git a/AnnularChecker/__pycache__/annular_checker_html.cpython-36.pyc b/AnnularChecker/__pycache__/annular_checker_html.cpython-36.pyc
new file mode 100644
index 0000000..16311f1
Binary files /dev/null and b/AnnularChecker/__pycache__/annular_checker_html.cpython-36.pyc differ
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/action_menu_annular_check.py b/AnnularChecker/annular_checker-OLD.py.txt
similarity index 96%
rename from action_menu_annular_check.py
rename to AnnularChecker/annular_checker-OLD.py.txt
index faaecbf..4375337 100644
--- a/action_menu_annular_check.py
+++ b/AnnularChecker/annular_checker-OLD.py.txt
@@ -1,604 +1,609 @@
-# -*- 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
-
+# -*- 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.6.0"
+
+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"
+ #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 ):
+
+ ###########################################################################
+ ## 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.Show(True)
+ frame.ShowModal()
+ #frame.show()
+ 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/AnnularChecker/annular_checker-html.py.txt b/AnnularChecker/annular_checker-html.py.txt
new file mode 100644
index 0000000..d8fa608
--- /dev/null
+++ b/AnnularChecker/annular_checker-html.py.txt
@@ -0,0 +1,455 @@
+# -*- 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.7"
+
+global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V, found_violations
+#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.html
+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_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="Check result: (Violations found)")
+ #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="Annular Check result: OK")
+ self.title.SetBackgroundColour('#00FF00')
+ #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_htmlWin1 = wx.html.HtmlWindow( self.panel, wx.ID_ANY, wx.DefaultPosition, wx.Size( 400,400 ), wx.html.HW_SCROLLBAR_AUTO )
+ #bSizer1.Add( self.m_htmlWin1, 0, 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.m_htmlWin1, 1, wx.ALL | wx.EXPAND)
+ 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.m_htmlWin1, (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.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()
+
+ #def OnButton(self, e):
+ # self.result.SetLabel(self.editname.GetValue())
+ def setMsg(self, t_msg):
+ self.editname.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:
+
+ frame = AR_Prm(None)
+ #frame = wx.Frame(None)
+ frame.Center()
+ #frame.setMsg(LogMsg)
+ frame.ShowModal()
+ frame.Destroy()
+
+ LogMsg="
Hello, world!
"
+ msg="action_menu_annular_check.py
"
+ msg+="version = "+___version___
+ msg+="
Testing PCB for Annular Rings
TH Pads = "+repr(AR_SET)+" Vias = "+repr(AR_SET_V)+"
PHD margin on PTH = "+ repr(DRL_EXTRA)
+ #print (msg)
+ LogMsg+=msg+"
"
+
+ # 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])
+ #print (msg)
+ LogMsg+=msg+"
"
+ FailCV = FailCV+1
+ else:
+ PassCV = PassCV+1
+ #print type(item)
+
+ msg="VIAS that Pass = "+repr(PassCV)+"; Fails = "+repr(FailCV)
+ # print(msg)
+ LogMsg+=msg+"
"
+
+ 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])
+ #print (msg)
+ LogMsg+=msg+"
"
+ 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])
+ #print (msg)
+ LogMsg+=msg+"
"
+ FailCN = FailCN+1
+ else:
+ PassCN = PassCN+1
+ else:
+ PassCN = PassCN+1
+
+ msg = "TH PADS that Pass = "+repr(PassC)+"; Fails = "+repr(FailC)
+ print(msg)
+ LogMsg+=msg+"
"
+
+ msg="NPTH PADS that Pass = "+repr(PassCN)+"; Fails = "+repr(FailCN)
+ print(msg)
+ LogMsg+=msg+""
+
+ 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
+
+ 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/AnnularChecker/annular_checker.py b/AnnularChecker/annular_checker.py
new file mode 100644
index 0000000..f123959
--- /dev/null
+++ b/AnnularChecker/annular_checker.py
@@ -0,0 +1,692 @@
+# -*- 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___="AC version: 1.6.0"
+
+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"
+ #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 ):
+
+ ###########################################################################
+ ## 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)" ))
+ class AR_Prm ( 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( 320,229 ), style = wx.DEFAULT_DIALOG_STYLE )
+
+ self.SetSizeHints( 320, 320 )
+
+ bSizer1 = wx.BoxSizer( wx.VERTICAL )
+
+ gSizer2 = wx.GridSizer( 0, 2, 0, 0 )
+
+ self.m_StaticTextPHD = wx.StaticText( self, wx.ID_ANY, u"PHD margin", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
+ self.m_StaticTextPHD.Wrap( -1 )
+
+ gSizer2.Add( self.m_StaticTextPHD, 0, wx.ALL, 5 )
+
+ self.m_textPHD = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer2.Add( self.m_textPHD, 0, wx.ALL, 5 )
+
+ self.m_StaticTextAR_SET = wx.StaticText( self, wx.ID_ANY, u"AR for pads", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
+ self.m_StaticTextAR_SET.Wrap( -1 )
+
+ gSizer2.Add( self.m_StaticTextAR_SET, 0, wx.ALL, 5 )
+
+ self.m_textAR_SET = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer2.Add( self.m_textAR_SET, 0, wx.ALL, 5 )
+
+ self.m_StaticTextAR_SET_V = wx.StaticText( self, wx.ID_ANY, u"AR for vias", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
+ self.m_StaticTextAR_SET_V.Wrap( -1 )
+
+ gSizer2.Add( self.m_StaticTextAR_SET_V, 0, wx.ALL, 5 )
+
+ self.m_textAR_SET_V = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer2.Add( self.m_textAR_SET_V, 0, wx.ALL, 5 )
+
+ bSizer2 = wx.BoxSizer( wx.VERTICAL )
+
+ self.m_staticTextVersion = wx.StaticText( self, wx.ID_ANY, u"Version", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticTextVersion.Wrap( -1 )
+
+ bSizer2.Add( self.m_staticTextVersion, 0, wx.ALL, 5 )
+
+
+ gSizer2.Add( bSizer2, 1, wx.EXPAND, 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, 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.SetValue(str(AR_SET))
+ self.m_textAR_SET.SetToolTip( wx.ToolTip(u"Annular Ring for Pads (mm)" ))
+ self.m_textAR_SET_V.SetValue(str(AR_SET_V))
+ 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_staticTextVersion.SetLabel(___version___)
+ self.m_textPHD.SetValue(str(DRL_EXTRA))
+ 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.Show(True)
+ frame.ShowModal()
+ #frame.show()
+ 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/AnnularChecker/annular_checker.pyc b/AnnularChecker/annular_checker.pyc
new file mode 100644
index 0000000..55d3356
Binary files /dev/null and b/AnnularChecker/annular_checker.pyc differ
diff --git a/AnnularChecker/annular_checker_html.py.txt b/AnnularChecker/annular_checker_html.py.txt
new file mode 100644
index 0000000..d8fa608
--- /dev/null
+++ b/AnnularChecker/annular_checker_html.py.txt
@@ -0,0 +1,455 @@
+# -*- 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.7"
+
+global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V, found_violations
+#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.html
+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_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="Check result: (Violations found)")
+ #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="Annular Check result: OK")
+ self.title.SetBackgroundColour('#00FF00')
+ #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_htmlWin1 = wx.html.HtmlWindow( self.panel, wx.ID_ANY, wx.DefaultPosition, wx.Size( 400,400 ), wx.html.HW_SCROLLBAR_AUTO )
+ #bSizer1.Add( self.m_htmlWin1, 0, 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.m_htmlWin1, 1, wx.ALL | wx.EXPAND)
+ 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.m_htmlWin1, (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.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()
+
+ #def OnButton(self, e):
+ # self.result.SetLabel(self.editname.GetValue())
+ def setMsg(self, t_msg):
+ self.editname.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:
+
+ frame = AR_Prm(None)
+ #frame = wx.Frame(None)
+ frame.Center()
+ #frame.setMsg(LogMsg)
+ frame.ShowModal()
+ frame.Destroy()
+
+ LogMsg="Hello, world!
"
+ msg="action_menu_annular_check.py
"
+ msg+="version = "+___version___
+ msg+="
Testing PCB for Annular Rings
TH Pads = "+repr(AR_SET)+" Vias = "+repr(AR_SET_V)+"
PHD margin on PTH = "+ repr(DRL_EXTRA)
+ #print (msg)
+ LogMsg+=msg+"
"
+
+ # 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])
+ #print (msg)
+ LogMsg+=msg+"
"
+ FailCV = FailCV+1
+ else:
+ PassCV = PassCV+1
+ #print type(item)
+
+ msg="VIAS that Pass = "+repr(PassCV)+"; Fails = "+repr(FailCV)
+ # print(msg)
+ LogMsg+=msg+"
"
+
+ 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])
+ #print (msg)
+ LogMsg+=msg+"
"
+ 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])
+ #print (msg)
+ LogMsg+=msg+"
"
+ FailCN = FailCN+1
+ else:
+ PassCN = PassCN+1
+ else:
+ PassCN = PassCN+1
+
+ msg = "TH PADS that Pass = "+repr(PassC)+"; Fails = "+repr(FailC)
+ print(msg)
+ LogMsg+=msg+"
"
+
+ msg="NPTH PADS that Pass = "+repr(PassCN)+"; Fails = "+repr(FailCN)
+ print(msg)
+ LogMsg+=msg+""
+
+ 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
+
+ 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/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/dlg.py.txt b/AnnularChecker/dlg.py.txt
new file mode 100644
index 0000000..0711b2a
--- /dev/null
+++ b/AnnularChecker/dlg.py.txt
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Jul 11 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+
+###########################################################################
+## Class AR_Prm
+###########################################################################
+
+class AR_Prm ( 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( 320,229 ), style = wx.DEFAULT_DIALOG_STYLE )
+
+ self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+
+ bSizer1 = wx.BoxSizer( wx.VERTICAL )
+
+ gSizer2 = wx.GridSizer( 0, 2, 0, 0 )
+
+ self.m_StaticTextPHD = wx.StaticText( self, wx.ID_ANY, u"PHD margin", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
+ self.m_StaticTextPHD.Wrap( -1 )
+
+ gSizer2.Add( self.m_StaticTextPHD, 0, wx.ALL, 5 )
+
+ self.m_textPHD = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer2.Add( self.m_textPHD, 0, wx.ALL, 5 )
+
+ self.m_StaticTextAR_SET = wx.StaticText( self, wx.ID_ANY, u"AR for pads", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
+ self.m_StaticTextAR_SET.Wrap( -1 )
+
+ gSizer2.Add( self.m_StaticTextAR_SET, 0, wx.ALL, 5 )
+
+ self.m_textAR_SET = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer2.Add( self.m_textAR_SET, 0, wx.ALL, 5 )
+
+ self.m_StaticTextAR_SET_V = wx.StaticText( self, wx.ID_ANY, u"AR for vias", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
+ self.m_StaticTextAR_SET_V.Wrap( -1 )
+
+ gSizer2.Add( self.m_StaticTextAR_SET_V, 0, wx.ALL, 5 )
+
+ self.m_textAR_SET_V = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ gSizer2.Add( self.m_textAR_SET_V, 0, wx.ALL, 5 )
+
+ bSizer2 = wx.BoxSizer( wx.VERTICAL )
+
+ self.m_staticTextVersion = wx.StaticText( self, wx.ID_ANY, u"Version", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticTextVersion.Wrap( -1 )
+
+ bSizer2.Add( self.m_staticTextVersion, 0, wx.ALL, 5 )
+
+
+ gSizer2.Add( bSizer2, 1, wx.EXPAND, 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, 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 )
+
+ def __del__( self ):
+ pass
+
+
diff --git a/AnnularChecker/outDialog.fbp b/AnnularChecker/outDialog.fbp
new file mode 100644
index 0000000..87bc43d
--- /dev/null
+++ b/AnnularChecker/outDialog.fbp
@@ -0,0 +1,540 @@
+
+
+
+
+
+ C++
+ 1
+ source_name
+ 0
+ 0
+ res
+ UTF-8
+ connect
+
+ 1000
+ none
+
+ 0
+ parametersDlg
+
+ .
+
+ 1
+ 1
+ 1
+ 1
+ UI
+ 0
+ 0
+
+ 0
+ wxAUI_MGR_DEFAULT
+
+ wxBOTH
+
+ 1
+ 1
+ impl_virtual
+
+
+
+ 0
+ wxID_ANY
+
+
+ displayDialog
+
+ 320,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_richText1
+ 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/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/__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/__pycache__/__init__.cpython-36.pyc b/FabricationPositions/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000..d39deea
Binary files /dev/null and b/FabricationPositions/__pycache__/__init__.cpython-36.pyc differ
diff --git a/FabricationPositions/__pycache__/fabrication_positions.cpython-36.pyc b/FabricationPositions/__pycache__/fabrication_positions.cpython-36.pyc
new file mode 100644
index 0000000..f1d7b0c
Binary files /dev/null and b/FabricationPositions/__pycache__/fabrication_positions.cpython-36.pyc differ
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/action_menu_positions.py b/FabricationPositions/fabrication_positions.py
similarity index 97%
rename from action_menu_positions.py
rename to FabricationPositions/fabrication_positions.py
index 5ac3b15..bd9529b 100644
--- a/action_menu_positions.py
+++ b/FabricationPositions/fabrication_positions.py
@@ -2,13 +2,13 @@
#
# A script to generate POS file for kicad_pcb
# requirements: KiCAD pcbnew >= 4.0
-# release "1.0.8"
+# release "1.0.9"
# 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"
+___version___="1.2.0"
#wx.LogMessage("My message")
#mm_ius = 1000000.0
@@ -262,9 +262,12 @@ class generatePOS( pcbnew.ActionPlugin ):
self.description should be a comprehensive description
of the plugin
"""
- self.name = "Generate POS output"
+ self.name = "Generate Fabrication POS output\nversion "+___version___
self.category = "Fabrication Output"
self.description = "Generate POS output for SMD, THD, Virtual"
+ #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 ):
@@ -290,7 +293,7 @@ class generatePOS( pcbnew.ActionPlugin ):
#, wx.ICON_INFORMATION) #, title="Annular Check", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION)
#
- self.SetIcon(PyEmbeddedImage(round_ico_b64_data).GetIcon())
+ self.SetIcon(PyEmbeddedImage(getPos_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:")
@@ -375,7 +378,7 @@ class generatePOS( pcbnew.ActionPlugin ):
generatePOS().register()
# "b64_data" is a variable containing your base64 encoded jpeg
-round_ico_b64_data =\
+getPos_ico_b64_data =\
"""
iVBORw0KGgoAAAANSUhEUgAAAEAAAAA/CAYAAABQHc7KAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAdDwAAHQ8Bjlx1kwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3Nj
YXBlLm9yZ5vuPBoAAAw+SURBVGiB7Zt7cFTVHcc/d+9uSAIhklgIpiQ0tjxSkCKIQ1CpCO3wUKCW0cF0Bqf/VFTG6tROS/8QZuxYwZGHgqD4SjNToFFDjJjGB4LkyUPk
diff --git a/FabricationPositions/g888.png b/FabricationPositions/g888.png
new file mode 100644
index 0000000..0db028e
Binary files /dev/null and b/FabricationPositions/g888.png differ
diff --git a/MoveToLayer/Move2LayerDlg.py b/MoveToLayer/Move2LayerDlg.py
new file mode 100644
index 0000000..08838fe
--- /dev/null
+++ b/MoveToLayer/Move2LayerDlg.py
@@ -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( 390,180 ), 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"Select Objects to Move to Layer\n", 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.DefaultSize, m_comboBoxLayerChoices, 0 )
+ bSizer31.Add( self.m_comboBoxLayer, 0, 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 )
+
+
+ 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/__pycache__/Move2LayerDlg.cpython-36.pyc b/MoveToLayer/__pycache__/Move2LayerDlg.cpython-36.pyc
new file mode 100644
index 0000000..34b0d7f
Binary files /dev/null and b/MoveToLayer/__pycache__/Move2LayerDlg.cpython-36.pyc differ
diff --git a/MoveToLayer/__pycache__/__init__.cpython-36.pyc b/MoveToLayer/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000..e61b682
Binary files /dev/null and b/MoveToLayer/__pycache__/__init__.cpython-36.pyc differ
diff --git a/MoveToLayer/__pycache__/move_to_layer.cpython-36.pyc b/MoveToLayer/__pycache__/move_to_layer.cpython-36.pyc
new file mode 100644
index 0000000..4c18bdd
Binary files /dev/null and b/MoveToLayer/__pycache__/move_to_layer.cpython-36.pyc differ
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/action_menu_move_to_layer.py b/MoveToLayer/move_to_layer (copy).py
similarity index 81%
rename from action_menu_move_to_layer.py
rename to MoveToLayer/move_to_layer (copy).py
index 75bd3b2..dc31ad2 100644
--- a/action_menu_move_to_layer.py
+++ b/MoveToLayer/move_to_layer (copy).py
@@ -24,7 +24,8 @@ import pcbnew
from pcbnew import *
import base64
from wx.lib.embeddedimage import PyEmbeddedImage
-___version___="1.1.3"
+import os
+___version___="1.2.0"
class move_to_draw_layer( pcbnew.ActionPlugin ):
@@ -46,9 +47,12 @@ class move_to_draw_layer( pcbnew.ActionPlugin ):
self.description should be a comprehensive description
of the plugin
"""
- self.name = "Move Selected drawings to chosen Layer"
- self.category = "Modify Drawing PCB"
+ 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
@@ -69,8 +73,6 @@ class move_to_draw_layer( pcbnew.ActionPlugin ):
'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):
@@ -98,8 +100,7 @@ class move_to_draw_layer( pcbnew.ActionPlugin ):
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"]
+ layerList = ["Edge_Cuts", "Eco1_User", "Eco2_User", "Dwgs_User", "Cmts_User", "Margin", "F_CrtYd", "B_CrtYd", "F_Fab", "B_Fab", "F_SilkS", "B_SilkS"]
self.combo = wx.ComboBox(self.panel, choices=layerList)
self.combo.SetSelection(0)
@@ -145,7 +146,7 @@ class move_to_draw_layer( pcbnew.ActionPlugin ):
def OnClose(self,e):
#wx.LogMessage("c")
e.Skip()
- self.Destroy() #Close()
+ self.Close()
#self.result.SetLabel(msg)
# Set event handlers
#self.button.Bind(wx.EVT_BUTTON, self.OnButton)
@@ -175,37 +176,45 @@ class move_to_draw_layer( pcbnew.ActionPlugin ):
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()
+ frame = displayDialog(None)
+ #frame = wx.Frame(None)
+ frame.Center()
+ #frame.setMsg(LogMsg)
+ frame.ShowModal()
+ #dlg.Destroy()
+ 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)
+ #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()))
+ #try:
+ # board_drawings=board.GetDrawings()
+ #except:
+ # board_drawings=board.DrawingsList()
+ #
+ #for drw in board_drawings:
+ 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()
+#move_to_draw_layer().register()
# "b64_data" is a variable containing your base64 encoded jpeg
diff --git a/MoveToLayer/move_to_layer.py b/MoveToLayer/move_to_layer.py
new file mode 100644
index 0000000..f36106f
--- /dev/null
+++ b/MoveToLayer/move_to_layer.py
@@ -0,0 +1,288 @@
+# 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.1"
+
+from . import Move2LayerDlg
+
+# 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
+ #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,
+ }[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"]
+ # 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.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 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()
+ modal_result = aParameters.ShowModal()
+ if modal_result == wx.ID_OK:
+ MoveToLayer(pcb, Layer)
+ else:
+ None # Cancel
+
+ LogMsg=''
+ msg="'move to layer tool'\n"
+ msg+="version = "+___version___
+ #wx.LogMessage(LogMsg)
+
+ # frame = displayDialog(None)
+ # #frame = wx.Frame(None)
+ # frame.Center()
+ # #frame.setMsg(LogMsg)
+ # frame.ShowModal()
+ # #dlg.Destroy()
+ # 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()))
+ # #try:
+ # # board_drawings=board.GetDrawings()
+ # #except:
+ # # board_drawings=board.DrawingsList()
+ # #
+ # #for drw in board_drawings:
+ # 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"
+
+
+
+
+
+#move_to_draw_layer().register()
+
+# 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/MoveToLayer/move_to_layer_dlg-t.fbp b/MoveToLayer/move_to_layer_dlg-t.fbp
new file mode 100644
index 0000000..824981f
--- /dev/null
+++ b/MoveToLayer/move_to_layer_dlg-t.fbp
@@ -0,0 +1,1623 @@
+
+
+
+
+
+ Python
+ 1
+ source_name
+ 0
+ 0
+ res
+ UTF-8
+ connect
+ viafence_basedialogs
+ 1000
+ none
+
+ 0
+ viafence_basedialogs
+
+ ..
+
+ 1
+ 1
+ 1
+ 1
+ UI
+ 0
+ 0
+
+ 0
+ wxAUI_MGR_DEFAULT
+
+ wxBOTH
+
+ 1
+ 1
+ impl_virtual
+
+
+
+ 0
+ wxID_ANY
+ -1,-1
+ -1,-1
+ MainDialogBase
+
+ 503,567
+ wxCAPTION|wxCLOSE_BOX|wxRESIZE_BORDER
+
+ Via Fence Generator
+
+
+
+
+ OnInitDialog
+
+
+ mainSizer
+ wxVERTICAL
+ none
+
+ 5
+ wxEXPAND
+ 1
+
+
+ wxBOTH
+ 0
+
+ 0
+
+ gbSizer4
+ wxFLEX_GROWMODE_SPECIFIED
+ none
+ 0
+
+ 5
+ 1
+ 0
+ wxEXPAND
+ 0
+ 1
+
+
+ bSizer23
+ wxVERTICAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 1
+
+ wxID_ANY
+ Via Settings
+
+ sbSizer2
+ wxVERTICAL
+ 1
+ none
+
+ 5
+ wxEXPAND
+ 1
+
+ 2
+ wxBOTH
+ 1
+
+ 0
+
+ fgSizer4
+ wxFLEX_GROWMODE_SPECIFIED
+ none
+ 8
+ 0
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Offset (mm):
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticText11
+ 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
+
+
+
+ 0
+ -1,-1
+ 1
+ txtViaOffset
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxTE_PROCESS_ENTER|wxTE_RIGHT
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Pitch (mm):
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticText21
+ 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
+
+
+
+ 0
+
+ 1
+ txtViaPitch
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxTE_PROCESS_ENTER|wxTE_RIGHT
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Via Drill (mm):
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticText13
+ 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
+
+
+
+ 0
+
+ 1
+ txtViaDrill
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxTE_PROCESS_ENTER|wxTE_RIGHT
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Via Size (mm):
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticText14
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+
+
+ -1
+
+
+
+ 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
+ txtViaSize
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+ wxTE_PROCESS_ENTER|wxTE_RIGHT
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Via Net:
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_staticText23
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 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
+ lstViaNet
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 0
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+ 1
+ 1
+ wxEXPAND|wxALL
+ 0
+ 1
+
+
+ bSizer21
+ wxVERTICAL
+ none
+
+ 5
+
+ 0
+
+ 9
+ protected
+ 0
+
+
+
+ 5
+ wxEXPAND
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ bmpViafence
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+ 0
+
+
+
+
+
+
+
+
+
+ 5
+ 1
+ 0
+ wxALL|wxEXPAND
+ 1
+ 1
+
+ wxID_ANY
+ Input Tracks
+
+ sbSizer411
+ wxVERTICAL
+ 1
+ none
+
+ 5
+ wxEXPAND
+ 0
+
+ 1
+ 0
+
+ gSizer4
+ none
+ 3
+ 0
+
+ 5
+ wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Include Selected
+
+ 0
+
+
+ 0
+
+ 1
+ chkIncludeSelection
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Include Drawing Lines
+
+ 0
+
+
+ 0
+
+ 1
+ chkIncludeDrawing
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxEXPAND|wxALIGN_CENTER_VERTICAL
+ 1
+
+ 2
+ wxHORIZONTAL
+ 1
+
+ 10
+
+ fgSizer311
+ wxFLEX_GROWMODE_SPECIFIED
+ none
+ 1
+ 0
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Net(s):
+
+ 0
+
+
+ 0
+
+ 1
+ chkNetFilter
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+ OnNetFilterCheckBox
+
+
+
+ 5
+ wxALL|wxEXPAND
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 0
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+ -1,-1
+
+ 0
+
+ 1
+ txtNetFilter
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ -1
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+ Combo!
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND|wxALIGN_CENTER_VERTICAL
+ 1
+
+ 2
+ wxHORIZONTAL
+ 1
+
+ 10
+
+ fgSizer31
+ wxFLEX_GROWMODE_SPECIFIED
+ none
+ 1
+ 0
+
+ 5
+ wxALL|wxEXPAND
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Layer:
+
+ 0
+
+
+ 0
+
+ 1
+ chkLayer
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+ OnLayerCheckBox
+
+
+
+ 5
+ wxALL|wxEXPAND
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 0
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ lstLayer
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 0
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+ 1
+ 1
+ wxEXPAND|wxALL
+ 1
+ 1
+
+ wxID_ANY
+ Output VIAs
+
+ sbSizer4
+ wxVERTICAL
+ 1
+ none
+
+ 5
+ wxEXPAND
+ 1
+
+ 1
+ 0
+
+ gSizer2
+ none
+ 3
+ 0
+
+ 5
+ wxEXPAND|wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Keep VIAs in
Via Net zones only
+
+ 0
+
+
+ 0
+
+ 1
+ chkSameNetZoneViasOnly
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT
+ 1
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Remove VIAs violating
clearance rules
+
+ 0
+
+
+ 0
+
+ 1
+ chkRemoveViasWithClearanceViolation
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxALIGN_CENTER|wxALL
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+
+ 0
+ 0
+
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+
+ 0
+ 0
+ wxID_ANY
+ Delete Vias
+
+ 0
+
+ 0
+
+
+ 0
+
+ 1
+ m_buttonDelete
+ 1
+
+
+ protected
+ 1
+
+
+
+ Resizable
+ 1
+
+
+ ; ; forward_declare
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+ wxEXPAND
+ 0
+
+
+ bSizer5
+ wxHORIZONTAL
+ none
+
+ 5
+ wxALL|wxEXPAND
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+ 0
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+ Debug Dump
+
+ 0
+
+
+ 0
+
+ 1
+ chkDebugDump
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ 1
+
+
+
+ 0
+
+
+ wxFILTER_NONE
+ wxDefaultValidator
+
+
+
+
+
+
+
+ 5
+ wxEXPAND
+ 1
+
+ 0
+ protected
+ 0
+
+
+
+ 5
+ wxEXPAND|wxALL
+ 0
+
+ 0
+ 1
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+
+ m_sdbSizer1
+ protected
+
+
+
+
+
+
+
+
diff --git a/MoveToLayer/move_to_layer_dlg.fbp b/MoveToLayer/move_to_layer_dlg.fbp
new file mode 100644
index 0000000..cd5db6e
--- /dev/null
+++ b/MoveToLayer/move_to_layer_dlg.fbp
@@ -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
+
+ 390,180
+ 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
+ Select Objects to Move to 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
+ 0
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+ 0
+
+ 1
+
+ 1
+ 0
+ Dock
+ 0
+ Left
+ 1
+
+ 1
+
+ 0
+ 0
+ wxID_ANY
+
+ 0
+
+
+ 0
+
+ 1
+ m_comboBoxLayer
+ 1
+
+
+ protected
+ 1
+
+ Resizable
+ -1
+ 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/action_menu_pcb2dxf.py b/PcbToDxf/action_menu_pcb2dxf.py
similarity index 100%
rename from action_menu_pcb2dxf.py
rename to PcbToDxf/action_menu_pcb2dxf.py
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"