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 @@ + + + + + + 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 + + + AR_Prm + + 320,193 + wxDEFAULT_DIALOG_STYLE + ; forward_declare + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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_staticText11 + 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_staticText1 + 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_textPHD1 + 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_staticText12 + 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_textPHD11 + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/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 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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"