From 37e0a2a07fd4d134e8fd09984518ff484b528acd Mon Sep 17 00:00:00 2001 From: easyw Date: Sun, 3 Nov 2019 15:29:21 +0100 Subject: [PATCH 01/18] first step to renew the repo --- AnnularChecker/AR-params - Copy.fbp | 914 ++++++++++ AnnularChecker/AR-params.fbp | 1016 +++++++++++ AnnularChecker/__init__ (copy).py.txt | 2 + AnnularChecker/__init__.py | 2 + AnnularChecker/__init__.pyc | Bin 0 -> 265 bytes AnnularChecker/__init__HTML.py.txt | 2 + AnnularChecker/__init__OLD.py.txt | 56 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 209 bytes .../annular_checker.cpython-36.pyc | Bin 0 -> 11995 bytes .../annular_checker_html.cpython-36.pyc | Bin 0 -> 10294 bytes AnnularChecker/annular.png | Bin 0 -> 1092 bytes .../annular_checker-OLD.py.txt | 1213 ++++++------ AnnularChecker/annular_checker-html.py.txt | 455 +++++ AnnularChecker/annular_checker.py | 692 +++++++ AnnularChecker/annular_checker.pyc | Bin 0 -> 14910 bytes AnnularChecker/annular_checker_html.py.txt | 455 +++++ AnnularChecker/annular_ico.svg | 214 +++ AnnularChecker/dlg.py.txt | 85 + AnnularChecker/outDialog.fbp | 540 ++++++ AnnularChecker/tkinter-test.txt | 2 + FabricationPositions/__init__.py | 2 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 238 bytes .../fabrication_positions.cpython-36.pyc | Bin 0 -> 12389 bytes .../fabricationPositions-old.png | Bin 0 -> 1326 bytes .../fabricationPositions-old.svg | 308 ++++ FabricationPositions/fabricationPositions.png | Bin 0 -> 1332 bytes FabricationPositions/fabricationPositions.svg | 302 +++ .../fabrication_positions.py | 13 +- FabricationPositions/g888.png | Bin 0 -> 831 bytes MoveToLayer/Move2LayerDlg.py | 75 + MoveToLayer/__init__.py | 2 + .../__pycache__/Move2LayerDlg.cpython-36.pyc | Bin 0 -> 1928 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 228 bytes .../__pycache__/move_to_layer.cpython-36.pyc | Bin 0 -> 3209 bytes MoveToLayer/move2layer.png | Bin 0 -> 1501 bytes MoveToLayer/move2layer.svg | 200 ++ .../move_to_layer (copy).py | 79 +- MoveToLayer/move_to_layer.py | 288 +++ MoveToLayer/move_to_layer_dlg-t.fbp | 1623 +++++++++++++++++ MoveToLayer/move_to_layer_dlg.fbp | 536 ++++++ .../action_menu_pcb2dxf.py | 0 action_menu_get3D_models.py | 15 - 42 files changed, 8432 insertions(+), 659 deletions(-) create mode 100644 AnnularChecker/AR-params - Copy.fbp create mode 100644 AnnularChecker/AR-params.fbp create mode 100644 AnnularChecker/__init__ (copy).py.txt create mode 100644 AnnularChecker/__init__.py create mode 100644 AnnularChecker/__init__.pyc create mode 100644 AnnularChecker/__init__HTML.py.txt create mode 100644 AnnularChecker/__init__OLD.py.txt create mode 100644 AnnularChecker/__pycache__/__init__.cpython-36.pyc create mode 100644 AnnularChecker/__pycache__/annular_checker.cpython-36.pyc create mode 100644 AnnularChecker/__pycache__/annular_checker_html.cpython-36.pyc create mode 100644 AnnularChecker/annular.png rename action_menu_annular_check.py => AnnularChecker/annular_checker-OLD.py.txt (96%) create mode 100644 AnnularChecker/annular_checker-html.py.txt create mode 100644 AnnularChecker/annular_checker.py create mode 100644 AnnularChecker/annular_checker.pyc create mode 100644 AnnularChecker/annular_checker_html.py.txt create mode 100644 AnnularChecker/annular_ico.svg create mode 100644 AnnularChecker/dlg.py.txt create mode 100644 AnnularChecker/outDialog.fbp create mode 100644 AnnularChecker/tkinter-test.txt create mode 100644 FabricationPositions/__init__.py create mode 100644 FabricationPositions/__pycache__/__init__.cpython-36.pyc create mode 100644 FabricationPositions/__pycache__/fabrication_positions.cpython-36.pyc create mode 100644 FabricationPositions/fabricationPositions-old.png create mode 100644 FabricationPositions/fabricationPositions-old.svg create mode 100644 FabricationPositions/fabricationPositions.png create mode 100644 FabricationPositions/fabricationPositions.svg rename action_menu_positions.py => FabricationPositions/fabrication_positions.py (97%) create mode 100644 FabricationPositions/g888.png create mode 100644 MoveToLayer/Move2LayerDlg.py create mode 100644 MoveToLayer/__init__.py create mode 100644 MoveToLayer/__pycache__/Move2LayerDlg.cpython-36.pyc create mode 100644 MoveToLayer/__pycache__/__init__.cpython-36.pyc create mode 100644 MoveToLayer/__pycache__/move_to_layer.cpython-36.pyc create mode 100644 MoveToLayer/move2layer.png create mode 100644 MoveToLayer/move2layer.svg rename action_menu_move_to_layer.py => MoveToLayer/move_to_layer (copy).py (81%) create mode 100644 MoveToLayer/move_to_layer.py create mode 100644 MoveToLayer/move_to_layer_dlg-t.fbp create mode 100644 MoveToLayer/move_to_layer_dlg.fbp rename action_menu_pcb2dxf.py => PcbToDxf/action_menu_pcb2dxf.py (100%) delete mode 100644 action_menu_get3D_models.py 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 0000000000000000000000000000000000000000..1d8da1efc719defb257fd46d70c23bb9dd63888b GIT binary patch literal 265 zcmZ9H!3x4K42IL~B7*2Ec-zU{MZ_`Bf)g)NDWxm3ZtF_hfu244kUoPiV5)*(NWPGt zK>ozf(eU!P9|e3P!oI?CQ$&eLpaEzJ90(9e;0ADx0!bOcE{SnV5kwN;M+mNU-*C&s zNs4;&-tgmpUD^UA@B@UEm2zI%Bq%?)Espt|?wz!b_Q;%O#;m#LwCH%NbVX|=cuAeG q%J?vwrmvKCY4-7u2Mf}sj47==V>5GoUtF|Z**9_-JiGAmguDPdEkCpX literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b16f157ff1b62e9521e6ce40031722dff70cec48 GIT binary patch literal 209 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..16311f17fdd8aaba43b06433f322216f5547d3bd GIT binary patch literal 10294 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 aSMPv~5dF`jpGhYuAr5g+^~ng}-}_&9qKG&E literal 0 HcmV?d00001 diff --git a/AnnularChecker/annular.png b/AnnularChecker/annular.png new file mode 100644 index 0000000000000000000000000000000000000000..319fed8396ce00736c99669b3ccfc250b5fa68b8 GIT binary patch literal 1092 zcmV-K1iSl*P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGcKmY&;KmjPYOcDS902y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^DS16z6k00Xp1L_t(YOSP40Y*bYg$KQ0Oi^E&)o0&J0 z21==wsuhh8N?5|u1_&lvBnHyf7>SV@wYB8~(XdI_LLr0%3P}kX!qTV^gqALJo9Z`> zpBf`J=?6oMF(lQDZJoBW9RKINb~XgF2Mu)gB&dTLT<%M#< z>_UmiC^rU0y?;=jVo~W`ojy9OQPT$+ovziW?vO^y?ugk%;-2ejEA%Cp<^jA&Vu3Wd ze?ULY6JNNe)6F+kifA&CY$vA3^mV0bF3h>!>)KB!(gsW~0B(@QE}I->*v-jhU+MH) zak?~>--{GlbJIG7I4K9Acmq5OcmYR3?&cR>7^jP+C z=Xt1J2a7>&LLLZ;M&7}(IxS5Q&iBXusoE78f4e#oUX&k89Y3>2HFvL_kcXlA46Fy< zB)LAw3901>tuBjDD1^M37#pK-MR_zi=Z`{#0s}f3ZCV)Bz69O7U@5Xqw}jU*`syuV z6UT9JG%{jIljG4NjM+;!TYG1~aR<5sU^OyLw}gTC*2{MJM7|NTZ0Rwvq`-KN zFD2}?ANTK*C#EdpTuipK*e-Qi$W+{knm-Uxy!STfE`Xg#HQf@PQWLM-vBfTrsS1t0 zQ!`CnT}0j8G`8pcNK~`u^l!9Yi#VtJ3DsS24s1`zefN~-kuY8UrJ$%fH}U`AOW)RF zl_aks=SQe+gJYmPAxAij2l_=$`gC9VTYnNq>orrXH!F|fXa`rpC*YN2xn%5=WPi8# zfs;Q*g9`aG3z;!PrpEo2*mqk@IK7TuD82!wKqXjclOwX+weEc1x1ygXJ=dYrfxQ~_ zY*OgqOA7s3s!-o1l@2wiRMMVkS|L}VvmbN09Q;b&1IxgIR5`axmn2Juc2+*_>ky+X z$OOiwY~8yNUq<=&NdL_N5m7hP|Ndxx^u{d3;t z-0vMZ(kXbwJI>h z;HlqGPT;1W2l$wUpcL@#R)Xa-fAa@I2f2XrO)-Zl=b!n3r2hchUN?hsv~= 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 0000000000000000000000000000000000000000..55d33563c10b1c1abbb490d45b3b645ede05a70c GIT binary patch literal 14910 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 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 0000000000000000000000000000000000000000..d39deea7a07932796b881bbacc7c2d43be543bbc GIT binary patch literal 238 zcmXr!<>j*2xG&a&fq~&M5W@izkmUfx#Zo{bg&~D8has0Sijk2am9d#2i>aA`ks*aC zm_d{IB_mLQCgUyc^whl6qQsKa0RLb=P39=kw8W&M%;dz9%>2Cgg8br45Tm#VWbQ4F zqSW-v;*!*&l?+8JKmjoE%SS&WKQ~oBH?dS-FB_;cCB7i1G(9t~SRc&OO-u$Ep<9xl spHr;whA=$WI0|-M{il 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2aeec47cc2378cb450f92b27183796bf91574cd1 GIT binary patch literal 1332 zcmV-41JnIxpO}I&*&S$M zOQAo@&d>FsTPS6Lrln}&dHc@2bI-}#Z|+>+|A6xHas>d(7ZdX&y9~p4CwJVNOePOc z*FZL#eO^`7rGCGEQ#>9w#>e=?WX`#hh{8k^wrzXCbj8QvSzXs#D=RBK<4F+!N=ix! z1wmK<0GUjtfQTdjAfifHmX}UfnTSFFT#T`W!^6YBsH*y0DwWcJTwi2aULpuWG?&ka zs1yJgW0wJpOxFN_SwvJg=7)2Bf^%M{Y1*-yS}@aKjDd)<0MbD24fuS%0#Otn1OP!0 z3M|Xooy-3iK-*o=T?OC`#+V7<9DwDiRO$kdy90fFeS-kv01yg=iZYpu0RTjFM%VTD zbk$W=eH1_jz#oQTtjXyC$nzD<6c}Sad%fNl#)|`a=0HBwt*)!}X9J%Un1z`kamaaI zIKQQ3&yLUPYwA;S)^7p81*x}p`=0HKUR(A0UjJ49Lja(;&d$2(&Qx`FcK)bo+ULn+ z(wbO%QUG4u@mJ$v?)CMDxSpa10JC9OG=k@)Z>o z?F)y)v4)0*7pG*v>2xlyZ>X<4UYbDH0|#+bK8&?>Yv(pMH!q_S+Z7LVBOd66Tvl4p z+}ymZqN>8v6+DQp;6YsW4mg^cnyNQ%-n`7|bUu=={-jz^{a7{BpnB~b2m}BCZ*JKH z!x$ayPZvG`09gNaJ^K6m0RT_($1!{M?Az9!lmUmsflw%P6CVr)Z{oaOFT7sw4O}Xf zf@zxfP1(S7aNxiJBoYZQ#_W9Y8J`2`bQ+4HfO9_luNbJQsex&lFbqS^7oSuMbX`aL zt{<+Qm#nBp)x%YY?D!Ug{iB1eL@mb3+Lh@3=~tXQbP@o-M20o5uEyfUixG>(v?&=d z3`1ybZ8he6?~|%V7C@Jh*q_;NolTuJ6Z?-kR`=8~0Eo=rMbaE8+x1;cTJ!tM8~{23 zZP*vsmmM4&WJE+$GN5VNx@0o>(mL9(#cjFa6kRy-+tHTJL!B*^nR#EhEq4F_uB0#b zY}>YNQ?XgnsWzMgV=bZ71^8zvCTNf9pj6 zAkZNIu(;j&L2#=Z0BmNBn5H>!+u9R}+&*vu0Ep;aUDv;wjLE5j0YD%SD7J081wa`_ z+ftD;(90Mb!02AM@op?9w?tW4*?dJ&j*FtGbIvW!xy2akFD@=Vr6@{x#)QYi@AofK z6y=mCiUW+X0k7Blx1uOb_e6XQvMfI%%kl}2$Mct>DBoa)r=>8F7#bQn?eTbYNs=mD qE?4cPOP7p%58eyR_@DAWfqwuC2gyZ-AHQq>0000kB literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0db028e66a0d49d23f108eaea7007fd1c24ae71e GIT binary patch literal 831 zcmV-F1Hk-=P)HtaTOr`d64cTGv8!4;!f(|E|G z#~e1&D5Azg2`z*mxrkmYJxCD*Mev|=SXwQm^wbv9_SD)xB8irOfu_(HO2H1BwAtxo zoh04tZ+3R4hngVvBz=w#A1}P`rvQwa`K{-a#I@~9{xVtk+q~7;I^(%>TtxTUw*Q;ySw|v zh2IvGnkre2m&kwkx^ZayP|wWu>6j)3<@gHGYmLN_FFt#Detv$J5JEIZ$44o@R|cR* z?ZPxo+S}VvK34!p(?KqmL)UdiK0ZLbUI(B*^DfC`5+OuW09clVWm){2L?Xf9;2{5H zU|`@GSF6>8`i%Xb*tSijQb|5nP!vV@zK>~|YtI#=C<=u_0mpH63xK7iB^<}uKIrf7 z2Vik=aoeTSX$-?)Zf*`KB>=jvlh5br>gw`D7>4SFA1{)+W+8}i$GlDE>kOXf@yoGk zx;I|J7e2|+MGEg1IQQ*&-Yh+R!t}lwI*)Y{hM}tEa=E@o_dWA1_w5~NndL8WPfp$b z>Bj8r?8DxNec3nG2Gn>M=Tc?r?zQQwGp*(1o*}Ogdm*s6%H`E7H?RD>zP`So7K_C( z0_Emb1+A%7T-P1a=j}(i=F#!-N!Rkq~SW?g; zFXpxaL8H--zv|bkx7z+#m1-dBid+M5;`ignExQCzRjakF&?j~#7Ol)^-ogL?002ov JPDHLkV1mQ1i0l9W literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..34b0d7f221135865dda61ece8f49e1770fa6a8f0 GIT binary patch literal 1928 zcmZuyOK;mo5MDk-$(CiuuhdmtrAgBYMeI639|(#fl*CvAmOvh#vRalm9|5?d(!g6sIf9?Ck8!H;>(=9u$j(-M{|)@v{O#f1{-# zgZv06xeJUSA_U0JX2C|sh=@dbjfmu-zBrX^i3nX(m9M}SSuW%AA%gG-C@BN;kS!2o zi$oyeYXn{rkztmJ0^TYuei!}X-8Y>}FKz^9E^}o=1FU#R-}SAVFy0 zGLXWOnu;K)K)D*T(>Tx95Rre&321`)1<-FsPLQTbTdPk`@{U+R003JStWbie-rdK z{-+Ywi&-Tgy$`fpOBre@LoFp;#r^Du7ez-@hTOrzXM*2(}IW}Peh(K>fhy&QU4RL_>}1gf-AXhjrpCd zq)~-mOaE5^p{qaOB32bD`h+T}p9UV4hEYQ0#2JY zFOUi`AfYSH6p*OG1B}&r6rM)6Y(*aqgG;K`oq_8GSO3C@i(toDwMxa87gTNdP7s|@ z4P$@crx;VU)xf&-oR%8i3uhFhCsE?3el(zRm*tkL>nFWd+oJip+3p&+)_z8}8pdP& zsoBGgmTtC>akux}G-$D7bXzvF=roKDUF~`)LumSgG@&aqbdIUjq6;R(RQulO^jdY@ zq=jzkq`uqpE>b%mVmAsyZ;(>?hu9fXNhbuDX;RgAcA{GiT4=UAExT>?bkp7lak6mc zEuk83352mr9P2a!Iop~AGW~%^i)IVI0iwk@Pym}pbj1jV>18*K{lOUpoHs#^K0l({ zy4gCmaNV$aMh7qIP-~+!h3+ZP*7g&-5aLs=Xg`4xy>!+FnuqPWZq*IbUYna_=SEjD z;7;qf*`wO5i!oIp{b-cJ@j_o>kIJ=nuL)m3Iq`xQR2@1o>sRiSH}-+8&4eR+=UNBq z=aKJv$=vklcNBjKx8$GZ;dvB#hoLh%Jow3X9fF6!=*%A^hkSLh<*jKQmIgE)HVBCa7!v8LW z@%HsN+`@wQ3eRNVgdRMT0>)uPMgfyoG5&ev1lbO+HvanUP^_Ubix;yH8$b!mPZPB- nxTY${Yp|y3%Zr1H*o{lD;2TTnE-mUadS9#`0|UcjAcg}bAj<)Wi=}`>3PTEG4nrxyr<<5ul9`{UTaurjQ>^a` pv@9gw2V{$We0*kJW=VX!UP0w84x8Nkl+v73JCLi2LALQQ0s!F1KFt6C literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4c18bdda4eabdcc3b87b79fe8a70d4491472e995 GIT binary patch literal 3209 zcmai0OOG4J5$>KBhePhlSlfEoKrk?3OQS?w?b=9SLlGqHdL_f!jSwmbLcnMYr+dkv zhBNE#rl=*jCkpU6_xyqUiTsHmm%irYe-P-DsveU2h=L4J#p*|OS66>kU0-f&MDPCj z_a8pIPsqQ>h0g=|5s)f?al&aqdi6i;QD{2_eOb4io&#;SaK~QHqjjI(^SRdxxX**4 zF%EknB~J-&@bE3+p$JFe!tFJor^zGei3A-*(9`0yOOn>lup>E2sG)a(U3+o*?YJ*E z7yP?%IuJ8|r?cDH`I*8b7~VLnUW?u5>8X(W#UMk~)#ok+^-B;0L9=_#Pvn?#%AL1i z&*d)n-jbg86Y)sThpm0HdA=OO^;T=(|B6%x8k&q?omWKOoRg6=r*miFP*QGbS9^1^ za7O;Bj}utgIhwg&b?zsDai(ufi?P>2s=O*0Gn-wZyZKB!%S)}gGvlktiI6gYO-%dZ zSmGK_iQ>5Ds@V>*T{wS}v8+gyV(f3^-LvgsH5S|Bbh6!fm1ikuC&grtmulO#?xmTA zJ@4tND%3Wf^kro|w><`#>53KT$Ii*AY{Bkd04X$s(1>n2vrjMkrgPD@%)xo^t(>$6 zvbqBdoJ|UH=4d*i;3zVu=qPZS3*;@xf+A+Di=@3%Up7EZ`oK)cSYGBDycEH1hk1#P zGL5IT#}ZezaaM4WN>S=sZxfX*yN1#Sz;=O_2MO^YH?ACHwF%q~Y*?mafg3V5uK1)t zxy{&*leDNutZ(ePW@G96OcVuU^{%*eLgfZ-ZY@9$eufrcNQGXzZLcMTByX`|uCp1deK$t<`;TnNI6VOCj_~6vOv8R+-FCbgZiw4;ptxAu=s^ zybrVUa&Si_IF=17CCa!I)7XL_zLUOA^CImRBCg8fG|tQT>Eq`~Y*&3&O;Ks0#5cBm zFGd@%3+60)0GzNCS{7IR5p<~KaF!NDtcN15L3vpT`_UAOz)M45_{GKIX%5Tu zh25W{0hiS>1QCAdR79gi;v*0+>;Z|CyPDnr1Tu$1s4|!Pz`Z#g`J=${h7K2$2Ma(e zYw`y0h&$l;aQ1I&8G89p=wStxiQ{xqXcdnqN~2X$Kv!N0zMhF8+d=5WYFJGQjJ;DtUTEYu$aPtaN-TG+qf$F6(kpLjZ#Pf_fTf)%Zk;p(s@j zcXwgdT0M@dK04RkASi;FdDOzT?corR2JU>2-U+g`ZeSH~? z|4SLb7pG+`-sDQd;#T#8j!jX!%luRhUM4N$R0<>TJe4xzp`T5-a*}CXIHU1SQav=@ zsLD&z;JK{lGIpHXAm7Y0$j7!}M?Qq>nnF^nihe3tf1-6&CXUTG@)p49Jlt)Zn{b7N z?_p43Vj^J(nKOXjO*;GZzhkzu(pY0Q0;M%(XVBmj@M@C)WKei=7UT@jyMQMLq-9#r zF6PmF$fP{DMb3Qf&;12G3+BNnSP;my!KeYV8}kOt3|~32ubVp3E&E`>t9%yn@T@s+ z@}_RzAipJNO`DISql2|w7*m+hxiL4K)LVgbBOMKhpZDjaH$pqP5WWPf8Yh?G3;ZrZS zkwJlk^#*-&_1*(D&2=_pFs?oUMjVg6?-$b97w^HqA0}nzK~X_+R1Z7#Qfs$k3d2{! zy8SZ{29UOX_~eX2nj!!K3j_`qFCl&X#re^LBt_*8OoUn?gje!qt_xxOqMCwtBc)TR zaf@N%7^ibz;=_35IPand1q2>uiiiJzVTCpXWOn!enSQQjbA=(Zk8h(6<^~(KAXLTe zXtquczl)O%YpgZ(NtH@&T43}6#N!dfv3<|Y79OKIc`jay;!khfb`*U``hW4y|s;=syQK0|h1_MF!~H(}rrkga{f zrsss$B=#lkx>Q1-n4q63@td#AN7FZ*BJX#^ve?eC*p`@#>THL`%de4PWwtC&AKQZR jg)K7e((kjwgb(UU>LD7hwt&?q4`~}b;5lt?>lgn4-p)m^ literal 0 HcmV?d00001 diff --git a/MoveToLayer/move2layer.png b/MoveToLayer/move2layer.png new file mode 100644 index 0000000000000000000000000000000000000000..3e5b8855a650ff7c2023ea8d0abf0b21d899f4c7 GIT binary patch literal 1501 zcmV<31tR*1P)wC#_Lw$|Gu{Q3M$u zZDP8yP1=PRqtT?*MaA(twM}YFT{LM->VkAtA6+OQ(4f#v8Wl)PV}Z)l6e?kW8F^G@ zhM9ZsIo*_zaRy}U!j0eR=Kufmf8YJjIro0RYrJBRgwgDMshLG<`_r=Ch{*^38RN8Z z&xzVS~oQ)+G06^56s5Ny3G&KUs81!Z8^Q7-@7$>@6 zGU>sBBRF?-2SkBKBKZA&+`M@+q9{s-rfC-dsIxhaC%iy z=&ohM1OC3whYt(|E7$HMgyZ6xPY!ltf4L6pin8Kzlu~qcb;0BDz~OK}k|ZMlBLD;f z0W>!^2SrhAR}|&_=u6K&$g-Rz2trdzN{Zc>X*c|M-;A{U@>ufWK9oxX_@u@jM;;D` z(caz;LI}2P+Xkc27|nUTUbM8d%xIeS9i{ZREX#B@7o7mdabK&dx?y5s0uvLzB6Wg; zZ@_?z)$0KOPoF#n8@K_E%%Hx$Gfn^@1a`X}<>lqz=1i`)x0l|zb0iHp0nfj|I_jg1%?9nt#w`y!gAu^3WD9yi`-v;hge z11^{AUB=jTyWMUoEiDyyXcVED$fC);UN4$jo6se8;dah#p5-v(f26SeZqu?xvOLBD z4S&T6ICJLAdB)hM7K}h{~yCzEh(_6!-!@)Th_OC;Fms%d`b$ z?y{g55nBaS*x%655S+U%I#?AP_(x5C8!9{r-}v>8WGGD~I7-;U!=IVs`Tx zn85HT^AW;aR68=gnJDQj2@^`bY`Wg`RibtC9cfbYUd`u}(7NujZi7$q%~LiH7*Nz- zM2jC5YlXRm?P+Og-k9`4exSO#+6n`%hD@Q2cPs81g681!B@04O1eA7{A~%xD?fGC2 zXSG@@XLB#~1G{(cE>=19=P_way8q67gT`w~kz1xM*nDp@*5$9mfsYSBr+fA|z|d`qcVVH&`&3wBZmH5%zvN_B!^Wsu}UM_EmP2hH4oMR064@N=34FY>57R0*5S7L6tC2j)VSztWP?0r00000NkvXXu0mjf DlcLO* literal 0 HcmV?d00001 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" From f7a1ac44f83e520fafb2c37122912cc436111a15 Mon Sep 17 00:00:00 2001 From: easyw Date: Sun, 3 Nov 2019 23:27:45 +0100 Subject: [PATCH 02/18] move2layer ... initial dialog --- MoveToLayer/Move2LayerDlg.py | 6 +- .../__pycache__/Move2LayerDlg.cpython-36.pyc | Bin 1928 -> 0 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 228 -> 0 bytes .../__pycache__/move_to_layer.cpython-36.pyc | Bin 3209 -> 0 bytes MoveToLayer/move_to_layer (copy).py | 248 --- MoveToLayer/move_to_layer.py | 20 +- MoveToLayer/move_to_layer_dlg-t.fbp | 1623 ----------------- MoveToLayer/move_to_layer_dlg.fbp | 10 +- __init__.py | 11 + 9 files changed, 38 insertions(+), 1880 deletions(-) delete mode 100644 MoveToLayer/__pycache__/Move2LayerDlg.cpython-36.pyc delete mode 100644 MoveToLayer/__pycache__/__init__.cpython-36.pyc delete mode 100644 MoveToLayer/__pycache__/move_to_layer.cpython-36.pyc delete mode 100644 MoveToLayer/move_to_layer (copy).py delete mode 100644 MoveToLayer/move_to_layer_dlg-t.fbp create mode 100644 __init__.py diff --git a/MoveToLayer/Move2LayerDlg.py b/MoveToLayer/Move2LayerDlg.py index 08838fe..c380ba4 100644 --- a/MoveToLayer/Move2LayerDlg.py +++ b/MoveToLayer/Move2LayerDlg.py @@ -17,7 +17,7 @@ import wx.xrc 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 ) + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Move to Layer", pos = wx.DefaultPosition, size = wx.Size( 325,180 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) @@ -36,8 +36,8 @@ class Move2LayerDlg ( wx.Dialog ): 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 ) + self.m_comboBoxLayer = wx.ComboBox( self, wx.ID_ANY, u"Combo!", wx.DefaultPosition, wx.Size( 250,-1 ), m_comboBoxLayerChoices, 0 ) + bSizer31.Add( self.m_comboBoxLayer, 0, wx.ALL|wx.EXPAND, 5 ) bSizer3.Add( bSizer31, 0, 0, 5 ) diff --git a/MoveToLayer/__pycache__/Move2LayerDlg.cpython-36.pyc b/MoveToLayer/__pycache__/Move2LayerDlg.cpython-36.pyc deleted file mode 100644 index 34b0d7f221135865dda61ece8f49e1770fa6a8f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1928 zcmZuyOK;mo5MDk-$(CiuuhdmtrAgBYMeI639|(#fl*CvAmOvh#vRalm9|5?d(!g6sIf9?Ck8!H;>(=9u$j(-M{|)@v{O#f1{-# zgZv06xeJUSA_U0JX2C|sh=@dbjfmu-zBrX^i3nX(m9M}SSuW%AA%gG-C@BN;kS!2o zi$oyeYXn{rkztmJ0^TYuei!}X-8Y>}FKz^9E^}o=1FU#R-}SAVFy0 zGLXWOnu;K)K)D*T(>Tx95Rre&321`)1<-FsPLQTbTdPk`@{U+R003JStWbie-rdK z{-+Ywi&-Tgy$`fpOBre@LoFp;#r^Du7ez-@hTOrzXM*2(}IW}Peh(K>fhy&QU4RL_>}1gf-AXhjrpCd zq)~-mOaE5^p{qaOB32bD`h+T}p9UV4hEYQ0#2JY zFOUi`AfYSH6p*OG1B}&r6rM)6Y(*aqgG;K`oq_8GSO3C@i(toDwMxa87gTNdP7s|@ z4P$@crx;VU)xf&-oR%8i3uhFhCsE?3el(zRm*tkL>nFWd+oJip+3p&+)_z8}8pdP& zsoBGgmTtC>akux}G-$D7bXzvF=roKDUF~`)LumSgG@&aqbdIUjq6;R(RQulO^jdY@ zq=jzkq`uqpE>b%mVmAsyZ;(>?hu9fXNhbuDX;RgAcA{GiT4=UAExT>?bkp7lak6mc zEuk83352mr9P2a!Iop~AGW~%^i)IVI0iwk@Pym}pbj1jV>18*K{lOUpoHs#^K0l({ zy4gCmaNV$aMh7qIP-~+!h3+ZP*7g&-5aLs=Xg`4xy>!+FnuqPWZq*IbUYna_=SEjD z;7;qf*`wO5i!oIp{b-cJ@j_o>kIJ=nuL)m3Iq`xQR2@1o>sRiSH}-+8&4eR+=UNBq z=aKJv$=vklcNBjKx8$GZ;dvB#hoLh%Jow3X9fF6!=*%A^hkSLh<*jKQmIgE)HVBCa7!v8LW z@%HsN+`@wQ3eRNVgdRMT0>)uPMgfyoG5&ev1lbO+HvanUP^_Ubix;yH8$b!mPZPB- nxTY${Yp|y3%Zr1H*o{lD;2TTnE-mUadS9#`0|UcjAcg}bAj<)Wi=}`>3PTEG4nrxyr<<5ul9`{UTaurjQ>^a` pv@9gw2V{$We0*kJW=VX!UP0w84x8Nkl+v73JCLi2LALQQ0s!F1KFt6C diff --git a/MoveToLayer/__pycache__/move_to_layer.cpython-36.pyc b/MoveToLayer/__pycache__/move_to_layer.cpython-36.pyc deleted file mode 100644 index 4c18bdda4eabdcc3b87b79fe8a70d4491472e995..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3209 zcmai0OOG4J5$>KBhePhlSlfEoKrk?3OQS?w?b=9SLlGqHdL_f!jSwmbLcnMYr+dkv zhBNE#rl=*jCkpU6_xyqUiTsHmm%irYe-P-DsveU2h=L4J#p*|OS66>kU0-f&MDPCj z_a8pIPsqQ>h0g=|5s)f?al&aqdi6i;QD{2_eOb4io&#;SaK~QHqjjI(^SRdxxX**4 zF%EknB~J-&@bE3+p$JFe!tFJor^zGei3A-*(9`0yOOn>lup>E2sG)a(U3+o*?YJ*E z7yP?%IuJ8|r?cDH`I*8b7~VLnUW?u5>8X(W#UMk~)#ok+^-B;0L9=_#Pvn?#%AL1i z&*d)n-jbg86Y)sThpm0HdA=OO^;T=(|B6%x8k&q?omWKOoRg6=r*miFP*QGbS9^1^ za7O;Bj}utgIhwg&b?zsDai(ufi?P>2s=O*0Gn-wZyZKB!%S)}gGvlktiI6gYO-%dZ zSmGK_iQ>5Ds@V>*T{wS}v8+gyV(f3^-LvgsH5S|Bbh6!fm1ikuC&grtmulO#?xmTA zJ@4tND%3Wf^kro|w><`#>53KT$Ii*AY{Bkd04X$s(1>n2vrjMkrgPD@%)xo^t(>$6 zvbqBdoJ|UH=4d*i;3zVu=qPZS3*;@xf+A+Di=@3%Up7EZ`oK)cSYGBDycEH1hk1#P zGL5IT#}ZezaaM4WN>S=sZxfX*yN1#Sz;=O_2MO^YH?ACHwF%q~Y*?mafg3V5uK1)t zxy{&*leDNutZ(ePW@G96OcVuU^{%*eLgfZ-ZY@9$eufrcNQGXzZLcMTByX`|uCp1deK$t<`;TnNI6VOCj_~6vOv8R+-FCbgZiw4;ptxAu=s^ zybrVUa&Si_IF=17CCa!I)7XL_zLUOA^CImRBCg8fG|tQT>Eq`~Y*&3&O;Ks0#5cBm zFGd@%3+60)0GzNCS{7IR5p<~KaF!NDtcN15L3vpT`_UAOz)M45_{GKIX%5Tu zh25W{0hiS>1QCAdR79gi;v*0+>;Z|CyPDnr1Tu$1s4|!Pz`Z#g`J=${h7K2$2Ma(e zYw`y0h&$l;aQ1I&8G89p=wStxiQ{xqXcdnqN~2X$Kv!N0zMhF8+d=5WYFJGQjJ;DtUTEYu$aPtaN-TG+qf$F6(kpLjZ#Pf_fTf)%Zk;p(s@j zcXwgdT0M@dK04RkASi;FdDOzT?corR2JU>2-U+g`ZeSH~? z|4SLb7pG+`-sDQd;#T#8j!jX!%luRhUM4N$R0<>TJe4xzp`T5-a*}CXIHU1SQav=@ zsLD&z;JK{lGIpHXAm7Y0$j7!}M?Qq>nnF^nihe3tf1-6&CXUTG@)p49Jlt)Zn{b7N z?_p43Vj^J(nKOXjO*;GZzhkzu(pY0Q0;M%(XVBmj@M@C)WKei=7UT@jyMQMLq-9#r zF6PmF$fP{DMb3Qf&;12G3+BNnSP;my!KeYV8}kOt3|~32ubVp3E&E`>t9%yn@T@s+ z@}_RzAipJNO`DISql2|w7*m+hxiL4K)LVgbBOMKhpZDjaH$pqP5WWPf8Yh?G3;ZrZS zkwJlk^#*-&_1*(D&2=_pFs?oUMjVg6?-$b97w^HqA0}nzK~X_+R1Z7#Qfs$k3d2{! zy8SZ{29UOX_~eX2nj!!K3j_`qFCl&X#re^LBt_*8OoUn?gje!qt_xxOqMCwtBc)TR zaf@N%7^ibz;=_35IPand1q2>uiiiJzVTCpXWOn!enSQQjbA=(Zk8h(6<^~(KAXLTe zXtquczl)O%YpgZ(NtH@&T43}6#N!dfv3<|Y79OKIc`jay;!khfb`*U``hW4y|s;=syQK0|h1_MF!~H(}rrkga{f zrsss$B=#lkx>Q1-n4q63@td#AN7FZ*BJX#^ve?eC*p`@#>THL`%de4PWwtC&AKQZR jg)K7e((kjwgb(UU>LD7hwt&?q4`~}b;5lt?>lgn4-p)m^ diff --git a/MoveToLayer/move_to_layer (copy).py b/MoveToLayer/move_to_layer (copy).py deleted file mode 100644 index dc31ad2..0000000 --- a/MoveToLayer/move_to_layer (copy).py +++ /dev/null @@ -1,248 +0,0 @@ -# move_to_edge_cuts.py -# -# Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -# -# - -import wx -import pcbnew -from pcbnew import * -import base64 -from wx.lib.embeddedimage import PyEmbeddedImage -import os -___version___="1.2.0" - - -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 len(fileName)==0: - wx.LogMessage("a board needs to be saved/loaded!") - else: - LogMsg='' - msg="'move to layer tool'\n" - msg+="version = "+___version___ - frame = displayDialog(None) - #frame = wx.Frame(None) - frame.Center() - #frame.setMsg(LogMsg) - frame.ShowModal() - #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" - wx.LogMessage(LogMsg) - - - - -#move_to_draw_layer().register() - - -# "b64_data" is a variable containing your base64 encoded jpeg -move_to_layer_ico_b64_data =\ -""" -iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAKYQAACmEB/MxKJQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAJrSURBVDiNnZRRSFNxFMa/s3vlLje3y0bpdKkwrcTCxbChQUIPUWBJ0IvQy3STCIkgoehFJIKCHkSCkLRBVNJT0EPQQ4W9bFmJDS0TSmwbc65ku7ZrY96dHsQ1yQfnB+flcPj9/985h0O+iz5nVtJGwGwjprEHg6N92IHErKSNTB9fcKmmDPa9qb3gdt9dmJg48hIQIswudaOwt7fXmhZXbzOhTdDgr7ZW3+rv78/lQWC2qaYMQIBSnjasrBqGAAawBqJ3ywDCACInzlod2dOT+xO1CtUFbVeFcHQawPM8iJjGGt7aPakK1Vg1Y02FYnu8AMkA7IVRJqfqv9YqlBNzWHIkTXLc0F4IImZGT09Pa06CU/udfeL3+5Nb9aD7Uvf1ZVv62pIjWbY3aP9jTgtHh4eHJzeBtqOBgQFdNB5t/x6xD4aCLksiUbGb2ZXNFzBzUQEEO4AgA8GOwrxuW9/ZJPEFgGUA5wuzRYPW7dBTAO1EH807Bq1LewRAD2jnCl4orkcbIUnj887me3M+n6+Vmbc/tUJ5PB45q9eHY01xo5zYlTT/0o8WZY1oSiYKnJybP/Q45lw0LDYmMNv2Q2biThHAlgtJBB3wvgHQWgBqAdAC4ACgo2+zdVl3JKSh4adYqkgAUUzsutx9R6lWPakK1Vg5VX7DaHx1P502HgbgBmAGCACiAAIAjwC6QDxeMmldEW5antV3gihWkhG8IhN3fjkWsYCA3JpgqXEsXPkcavwAwA9wABACzM3h/42e6gOQPzkiiGKlilSpmjIwL5UqVU1TZ2Y+dY0XOwCxJCN4D76u+XfYHg4VDQGAvyJXT3w3dEsJAAAAAElFTkSuQmCC""" - -# pcbnew.F_Cu -# pcbnew.In1_Cu -# pcbnew.In2_Cu -#.. -# pcbnew.In30_Cu -# pcbnew.B_Cu -# pcbnew.B_Adhes -# pcbnew.F_Adhes -# pcbnew.B_Paste -# pcbnew.F_Paste -# pcbnew.B_SilkS -# pcbnew.F_SilkS -# pcbnew.B_Mask -# pcbnew.F_Mask -# pcbnew.Dwgs_User -# pcbnew.Cmts_User -# pcbnew.Eco1_User -# pcbnew.Eco2_User -# pcbnew.Edge_Cuts -# pcbnew.Margin -# pcbnew.B_CrtYd -# pcbnew.F_CrtYd -# pcbnew.B_Fab -# pcbnew.F_Fab diff --git a/MoveToLayer/move_to_layer.py b/MoveToLayer/move_to_layer.py index f36106f..50ecd01 100644 --- a/MoveToLayer/move_to_layer.py +++ b/MoveToLayer/move_to_layer.py @@ -203,6 +203,17 @@ class move_to_draw_layer( pcbnew.ActionPlugin ): board = pcbnew.GetBoard() #wx.MessageDialog(None, 'This is a message box.', 'Test', wx.OK | wx.ICON_INFORMATION).ShowModal() fileName = GetBoard().GetFileName() + # # dicts for converting layer name to id, used by _get_layer + # _std_layer_dict = {pcbnew.BOARD_GetStandardLayerName(n): n + # for n in range(pcbnew.PCB_LAYER_ID_COUNT)} + # #_std_layer_names = {s: n for n, s in _std_layer_dict.iteritems()} + # _std_layer_names = {s: n for n, s in _std_layer_dict.items()} + # _brd_layer_dict = {pcbnew.GetBoard().GetLayerName(n): n + # for n in range(pcbnew.PCB_LAYER_ID_COUNT)} + # #_std_layer_names = {s: n for n, s in _std_layer_dict.iteritems()} + # _brd_layer_names = {s: n for n, s in _brd_layer_dict.items()} + + if 0: #len(fileName) == 0: wx.LogMessage("A board needs to be saved/loaded\nto run the plugin!") else: @@ -211,9 +222,16 @@ class move_to_draw_layer( pcbnew.ActionPlugin ): _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] aParameters = Move2Layer_Dlg(_pcbnew_frame) aParameters.Show() + for l in range(pcbnew.PCB_LAYER_ID_COUNT): + aParameters.m_comboBoxLayer.Append(pcbnew.GetBoard().GetLayerName(l)) + aParameters.m_comboBoxLayer.Select(44) modal_result = aParameters.ShowModal() if modal_result == wx.ID_OK: - MoveToLayer(pcb, Layer) + LayerName = aParameters.m_comboBoxLayer.GetStringSelection() + idx = aParameters.m_comboBoxLayer.FindString(LayerName) + LayerStdName = pcbnew.BOARD_GetStandardLayerName(idx) + wx.LogMessage(LayerName+';'+str(idx)+';'+LayerStdName) + #MoveToLayer(pcb, Layer) else: None # Cancel diff --git a/MoveToLayer/move_to_layer_dlg-t.fbp b/MoveToLayer/move_to_layer_dlg-t.fbp deleted file mode 100644 index 824981f..0000000 --- a/MoveToLayer/move_to_layer_dlg-t.fbp +++ /dev/null @@ -1,1623 +0,0 @@ - - - - - - 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 index cd5db6e..5735e63 100644 --- a/MoveToLayer/move_to_layer_dlg.fbp +++ b/MoveToLayer/move_to_layer_dlg.fbp @@ -45,7 +45,7 @@ Move2LayerDlg - 390,180 + 325,180 wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER Move to Layer @@ -191,7 +191,7 @@ 5 - wxALL + wxALL|wxEXPAND 0 1 @@ -225,9 +225,9 @@ 0 - + -1,-1 0 - + -1,-1 1 m_comboBoxLayer 1 @@ -239,7 +239,7 @@ Resizable -1 1 - + 250,-1 ; ; forward_declare 0 diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..001b420 --- /dev/null +++ b/__init__.py @@ -0,0 +1,11 @@ +# pcbnew loads this folder as a package using import +# thus __init__.py (this file) is executed +# We import the plugin class here and register it to pcbnew + +from . import AnnularChecker + +from . import FabricationPositions + +from . import MoveToLayer + +from . import PcbToDxf From bca31caa1542e5c57f09a70299f9b6f58915ff19 Mon Sep 17 00:00:00 2001 From: easyw Date: Mon, 4 Nov 2019 12:45:36 +0100 Subject: [PATCH 03/18] improved position file plugin --- FabricationPositions/fabrication_positions.py | 70 ++++++++++++------ FabricationPositions/g888.png | Bin 831 -> 0 bytes 2 files changed, 46 insertions(+), 24 deletions(-) delete mode 100644 FabricationPositions/g888.png diff --git a/FabricationPositions/fabrication_positions.py b/FabricationPositions/fabrication_positions.py index bd9529b..eed38f3 100644 --- a/FabricationPositions/fabrication_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.9" +# release "1.1.1" # copyright Maurice easyw # # main script from https://forum.kicad.info/t/pcba-wants-all-parts-in-the-pos-file-not-just-smd/10045/6 # -___version___="1.2.0" +___version___="1.2.1" #wx.LogMessage("My message") #mm_ius = 1000000.0 @@ -40,7 +40,7 @@ def generate_POS(): #lsep=os.linesep lsep='\n' - LogMsg1=lsep+"reading from:" + lsep + dirpath + lsep + lsep + #LogMsg1=lsep+"reading from:" + lsep + dirpath + lsep + lsep out_filename_top_SMD=path+os.sep+name+"_POS_top_SMD.txt" out_filename_bot_SMD=path+os.sep+name+"_POS_bot_SMD.txt" out_filename_top_THD=path+os.sep+name+"_POS_top_THD.txt" @@ -49,13 +49,13 @@ def generate_POS(): out_filename_bot_VIRTUAL=path+os.sep+name+"_POS_bot_Virtual.txt" out_filename_ALL=path+os.sep+name+"_POS_All.txt" #out_filename=path+os.sep+name+"_POS.txt" - LogMsg1+="written to:" + lsep + out_filename_top_SMD + lsep - LogMsg1+= out_filename_bot_SMD + lsep - LogMsg1+= out_filename_top_THD + lsep - LogMsg1+= out_filename_bot_THD + lsep - LogMsg1+= out_filename_top_VIRTUAL + lsep - LogMsg1+= out_filename_bot_VIRTUAL + lsep - LogMsg1+= out_filename_ALL + lsep + #LogMsg1+="written to:" + lsep + out_filename_top_SMD + lsep + #LogMsg1+="written to:" + lsep + out_filename_bot_SMD + lsep + #LogMsg1+="written to:" + lsep + out_filename_top_THD + lsep + #LogMsg1+="written to:" + lsep + out_filename_bot_THD + lsep + #LogMsg1+="written to:" + lsep + out_filename_top_VIRTUAL + lsep + #LogMsg1+="written to:" + lsep + out_filename_bot_VIRTUAL + lsep + #LogMsg1+="written to:" + lsep + out_filename_ALL + lsep # print (LogMsg) # # print ("### Module positions - created on %s ###" % datetime.datetime.now().strftime("%Y-%m-%d %H:%M")) @@ -65,7 +65,7 @@ def generate_POS(): # print ("# Ref Val Package PosX PosY Rot Side Type") Header_1="### Module positions - created on " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M")+lsep - Header_1+="### Printed by get_pos v1"+lsep + Header_1+="### Printed by pcb_positions plugin"+lsep Header_1+="## Unit = mm, Angle = deg."+lsep #LogMsg+="## Side : All"+lsep Header_2="## Board Aux Origin: " + str(my_board.GetAuxOrigin())+lsep @@ -98,6 +98,13 @@ def generate_POS(): #'{0:<10} {1:<10} {2:<10}'.format(1.0, 2.2, 4.4)) + tracks = my_board.GetTracks() + vias = [] + for via in tracks: + if type(via) is pcbnew.VIA: + vias.append(via) + vias_cnt = len(vias) + for module in my_board.GetModules(): #print ("%s \"%s\" %s %1.3f %1.3f %1.3f %s" % ( module.GetReference(), #Nchars = 20 @@ -229,16 +236,31 @@ def generate_POS(): #f = open(out_filename,'w') #f.write(LogMsg) #f.close() - LogMsg1+= lsep + str(SMD_pads) + ' SMD pads' +lsep - LogMsg1+= str(TH_pads) + ' TH pads' +lsep - LogMsg1+= str(Virt_pads) + ' Virtual pads' +lsep - LogMsg1+= str( TH_top_cnt) + ' Top TH modules' + lsep - LogMsg1+= str( TH_bot_cnt) + ' Bot TH modules' + lsep - LogMsg1+= str( SMD_top_cnt) + ' Top SMD modules' + lsep - LogMsg1+= str( SMD_bot_cnt) + ' Bot SMD modules' + lsep - LogMsg1+= str( Virt_top_cnt) + ' Top Virtual modules' + lsep - LogMsg1+= str( Virt_bot_cnt) + ' Bot Virtual modules' + lsep - LogMsg1+= '{0:.3f}'.format( pcb_height ) + 'mm Pcb Height, ' + '{0:.3f}'.format( pcb_width ) + 'mm Pcb Width [based on Edge bounding box]' +lsep + LogMsg1="reading from:" + lsep + dirpath + lsep + LogMsg1+= lsep + 'Pads:' + lsep + LogMsg1+= 'SMD pads ' + str(SMD_pads) + lsep + LogMsg1+= 'TH pads ' + str(TH_pads) +lsep + LogMsg1+= 'Virtual pads ' + str(Virt_pads) + lsep + LogMsg1+= 'Vias ' + str( vias_cnt) + lsep + LogMsg1+= lsep + 'Modules:' + lsep + LogMsg1+= 'Top TH modules ' + str( TH_top_cnt) + lsep + LogMsg1+= 'Bot TH modules ' + str( TH_bot_cnt) + lsep + LogMsg1+= 'Top SMD modules ' + str( SMD_top_cnt) + lsep + LogMsg1+= 'Bot SMD modules ' + str( SMD_bot_cnt) + lsep + LogMsg1+= 'Top Virtual modules ' + str( Virt_top_cnt) + lsep + LogMsg1+= 'Bot Virtual modules ' + str( Virt_bot_cnt) + lsep + LogMsg1+= lsep + 'PCB Geometry:' + lsep + LogMsg1+= 'Pcb Height ' +'{0:.3f}'.format( pcb_height ) + 'mm, Pcb Width ' + '{0:.3f}'.format( pcb_width ) + 'mm' +lsep+'[based on Edge bounding box]' +lsep + LogMsg1+= lsep + #LogMsg1+=lsep+"reading from:" + lsep + dirpath + lsep + lsep + LogMsg1+="written to:" + lsep + out_filename_top_SMD + lsep + LogMsg1+=out_filename_bot_SMD + lsep + LogMsg1+=out_filename_top_THD + lsep + LogMsg1+=out_filename_bot_THD + lsep + LogMsg1+=out_filename_top_VIRTUAL + lsep + LogMsg1+=out_filename_bot_VIRTUAL + lsep + LogMsg1+=out_filename_ALL + lsep + return LogMsg1 #return LogMsg1+LogMsg @@ -264,11 +286,11 @@ class generatePOS( pcbnew.ActionPlugin ): """ self.name = "Generate Fabrication POS output\nversion "+___version___ self.category = "Fabrication Output" - self.description = "Generate POS output for SMD, THD, Virtual" + self.description = "Generate POS output for SMD, THD, Virtual\nand Board Statistics" #self.SetIcon(PyEmbeddedImage(getPos_ico_b64_data).GetIcon()) self.icon_file_name = os.path.join(os.path.dirname(__file__), "./fabricationPositions.png") self.show_toolbar_button = True - + def Run( self ): #wx.MessageDialog(self.frame,"ciao") @@ -375,7 +397,7 @@ class generatePOS( pcbnew.ActionPlugin ): # style=wx.wxSTAY_ON_TOP) #frame.show() -generatePOS().register() +#generatePOS().register() # "b64_data" is a variable containing your base64 encoded jpeg getPos_ico_b64_data =\ diff --git a/FabricationPositions/g888.png b/FabricationPositions/g888.png deleted file mode 100644 index 0db028e66a0d49d23f108eaea7007fd1c24ae71e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 831 zcmV-F1Hk-=P)HtaTOr`d64cTGv8!4;!f(|E|G z#~e1&D5Azg2`z*mxrkmYJxCD*Mev|=SXwQm^wbv9_SD)xB8irOfu_(HO2H1BwAtxo zoh04tZ+3R4hngVvBz=w#A1}P`rvQwa`K{-a#I@~9{xVtk+q~7;I^(%>TtxTUw*Q;ySw|v zh2IvGnkre2m&kwkx^ZayP|wWu>6j)3<@gHGYmLN_FFt#Detv$J5JEIZ$44o@R|cR* z?ZPxo+S}VvK34!p(?KqmL)UdiK0ZLbUI(B*^DfC`5+OuW09clVWm){2L?Xf9;2{5H zU|`@GSF6>8`i%Xb*tSijQb|5nP!vV@zK>~|YtI#=C<=u_0mpH63xK7iB^<}uKIrf7 z2Vik=aoeTSX$-?)Zf*`KB>=jvlh5br>gw`D7>4SFA1{)+W+8}i$GlDE>kOXf@yoGk zx;I|J7e2|+MGEg1IQQ*&-Yh+R!t}lwI*)Y{hM}tEa=E@o_dWA1_w5~NndL8WPfp$b z>Bj8r?8DxNec3nG2Gn>M=Tc?r?zQQwGp*(1o*}Ogdm*s6%H`E7H?RD>zP`So7K_C( z0_Emb1+A%7T-P1a=j}(i=F#!-N!Rkq~SW?g; zFXpxaL8H--zv|bkx7z+#m1-dBid+M5;`ignExQCzRjakF&?j~#7Ol)^-ogL?002ov JPDHLkV1mQ1i0l9W From 75d51c27e2e2cad4cd1ca7a2293d898b36ca8468 Mon Sep 17 00:00:00 2001 From: easyw Date: Mon, 4 Nov 2019 21:35:33 +0100 Subject: [PATCH 04/18] first new working version --- MoveToLayer/Move2LayerDlg.py | 4 +- MoveToLayer/move_to_layer.py | 207 ++++-------------------------- MoveToLayer/move_to_layer_dlg.fbp | 4 +- 3 files changed, 31 insertions(+), 184 deletions(-) diff --git a/MoveToLayer/Move2LayerDlg.py b/MoveToLayer/Move2LayerDlg.py index c380ba4..3f5f403 100644 --- a/MoveToLayer/Move2LayerDlg.py +++ b/MoveToLayer/Move2LayerDlg.py @@ -17,13 +17,13 @@ import wx.xrc class Move2LayerDlg ( wx.Dialog ): def __init__( self, parent ): - wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Move to Layer", pos = wx.DefaultPosition, size = wx.Size( 325,180 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Move to Layer", pos = wx.DefaultPosition, size = wx.Size( 325,190 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) bSizer3 = wx.BoxSizer( wx.VERTICAL ) - self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Select Objects to Move to Layer\n", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Selected Objects to Move to chosen Layer", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_comment.Wrap( -1 ) bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 ) diff --git a/MoveToLayer/move_to_layer.py b/MoveToLayer/move_to_layer.py index 50ecd01..bc6b7b1 100644 --- a/MoveToLayer/move_to_layer.py +++ b/MoveToLayer/move_to_layer.py @@ -25,10 +25,30 @@ from pcbnew import * import base64 from wx.lib.embeddedimage import PyEmbeddedImage import os -___version___="1.2.1" +___version___="1.2.2" from . import Move2LayerDlg + +def MoveToLayer(pcb,layerId): + for drw in pcb.GetDrawings(): + if drw.IsSelected(): + drw.SetLayer(layerId) + 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() + layerName = pcbnew.GetBoard().GetLayerName(layerId) + LogMsg="selected drawings moved to "+layerName+" layer" + wx.LogMessage(LogMsg) +# + + + # Python plugin stuff class Move2Layer_Dlg(Move2LayerDlg.Move2LayerDlg): @@ -81,127 +101,16 @@ class move_to_draw_layer( pcbnew.ActionPlugin ): of the plugin """ import os - self.name = "Move Selected drawings to chosen Layer\nversion "+___version___ + 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.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() # # dicts for converting layer name to id, used by _get_layer # _std_layer_dict = {pcbnew.BOARD_GetStandardLayerName(n): n @@ -228,79 +137,17 @@ class move_to_draw_layer( pcbnew.ActionPlugin ): modal_result = aParameters.ShowModal() if modal_result == wx.ID_OK: LayerName = aParameters.m_comboBoxLayer.GetStringSelection() - idx = aParameters.m_comboBoxLayer.FindString(LayerName) - LayerStdName = pcbnew.BOARD_GetStandardLayerName(idx) - wx.LogMessage(LayerName+';'+str(idx)+';'+LayerStdName) - #MoveToLayer(pcb, Layer) + LayerIndex = aParameters.m_comboBoxLayer.FindString(LayerName) + LayerStdName = pcbnew.BOARD_GetStandardLayerName(LayerIndex) + #wx.LogMessage(LayerName+';'+str(LayerIndex)+';'+LayerStdName) + MoveToLayer(board, LayerIndex) else: None # Cancel LogMsg='' msg="'move to layer tool'\n" msg+="version = "+___version___ - #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.fbp b/MoveToLayer/move_to_layer_dlg.fbp index 5735e63..43a4da8 100644 --- a/MoveToLayer/move_to_layer_dlg.fbp +++ b/MoveToLayer/move_to_layer_dlg.fbp @@ -45,7 +45,7 @@ Move2LayerDlg - 325,180 + 325,190 wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER Move to Layer @@ -90,7 +90,7 @@ 0 0 wxID_ANY - Select Objects to Move to Layer + Selected Objects will Move to chosen Layer 0 0 From 3adb80e746139084b32df068bbeb6f13cedf6dae Mon Sep 17 00:00:00 2001 From: easyw Date: Sun, 16 Feb 2020 08:17:45 +0100 Subject: [PATCH 05/18] first Snap2Grid release --- Snap2Grid/__init__.py | 2 + Snap2Grid/snap2grid.png | Bin 0 -> 1724 bytes Snap2Grid/snap2grid.py | 200 +++++++++++++++++++++++++++ Snap2Grid/snap2grid.svg | 242 +++++++++++++++++++++++++++++++++ Snap2Grid/snaptogrid_script.py | 96 +++++++++++++ __init__.py | 3 + 6 files changed, 543 insertions(+) create mode 100644 Snap2Grid/__init__.py create mode 100644 Snap2Grid/snap2grid.png create mode 100644 Snap2Grid/snap2grid.py create mode 100644 Snap2Grid/snap2grid.svg create mode 100644 Snap2Grid/snaptogrid_script.py diff --git a/Snap2Grid/__init__.py b/Snap2Grid/__init__.py new file mode 100644 index 0000000..07cb020 --- /dev/null +++ b/Snap2Grid/__init__.py @@ -0,0 +1,2 @@ +from .snap2grid import snap_to_grid +snap_to_grid().register() diff --git a/Snap2Grid/snap2grid.png b/Snap2Grid/snap2grid.png new file mode 100644 index 0000000000000000000000000000000000000000..d88097b00514408e5c6ecd1aec4211b3032ee57d GIT binary patch literal 1724 zcmV;t21EIYP)m8`F805A&;Oj~oWIZU^C9?zsI9FnQA(|h+e#_V zsZ*z}*3{H&l2Ycxc_GAmZEbCV9Xobx1JYx$;nLF5GmVXnW@=vjlM0y13LP18`L|4G zL{#Qjn#{XuZw6io*`vSeTQ`^k@Yv<0;oNKX7i(*4-@lh0YQ0i1q5~B6=7cX^ytoP& zT(kgC@@m;g+C;WN?oB((uGs~EsjJA9vJopl`nc7|y=Di%uto0mtsPzlkUMC76aF78WZa*hWT1eki5>w>=)u zd-DnqLL3F2h?#EzHFb4$r*vK4cIbqD$VPI7PBsjRGA z($LV5la*x4i(|h*pu^5K2IXgSs`e}gb>G=*=YBK5WjdJ z6;q(=dTWxMXmoaV9(B9jztnX-bm78<@kHN=wv%-CUjz*ZDK@Uz!1m{>sXx-dc>2uQ zBK;=c`r1B-dwF=0;8R?`7MCz>}#>NObL!92}0pNwx<#cyTklRhBImb+gO$ParRrr{~VV@L^z&Qfi+N;`6|FV@v;W-ws3~k(V@0+YL;PkB^_If@xqm zKnMIwKoc{6tR52%RlzL)0s+dS(e;|9?F4!|J3CJUr-35?E|=@i4u|6kkQt3en^`PA zfI}Cc>q97CbdnS-cpIjmPC&013!G)rIOaB*h#)r0SACS zrPSYmhD2X%`@9QW2VU##?VWujc64-%3L##P`F;= 4.0 +# copyright Maurice easyw +# +# + +#import snaptogrid; import importlib; importlib.reload(snaptogrid) + +__version__ = '1.0.1' +import sys, os +import pcbnew +import datetime +import wx +from pcbnew import * + +use_grid_origin = True + +gridReference = 2.54 #1.27 #mm pcbnew.FromMM(1.0) #0.1mm + +gridSizeMM = gridReference + +#from . import Send2GridDlg + +sys.path.append(os.path.dirname(__file__)) + +debug = False +def wxLogDebug(msg,dbg): + """printing messages only if show is omitted or True""" + if dbg == True: + wx.LogMessage(msg) +# + +#class Snap2Grid_Dlg(Snap2GridDlg.Snap2GridDlg): +# # from https://github.com/MitjaNemec/Kicad_action_plugins +# # hack for new wxFormBuilder generating code incompatible with old wxPython +# # noinspection PyMethodOverriding +# def SetSizeHints(self, sz1, sz2): +# if wx.__version__ < '4.0': +# self.SetSizeHintsSz(sz1, sz2) +# else: +# super(RoundTrack_Dlg, self).SetSizeHints(sz1, sz2) +# +# # def onDeleteClick(self, event): +# # return self.EndModal(wx.ID_DELETE) +# # +# # def onConnectClick(self, event): +# # return self.EndModal(wx.ID_REVERT) +# +# def __init__(self, parent): +# import wx +# Send2GridDlg.Send2GridDlg.__init__(self, parent) +# #self.GetSizer().Fit(self) +# self.SetMinSize(self.GetSize()) +# #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) +# #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) +# #if wx.__version__ < '4.0': +# # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) +# # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) +# #else: +# # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) +# # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) +# +# Python plugin stuff +class snap_to_grid( pcbnew.ActionPlugin ): + """ + A plugin to Snap modules to selected Grid for kicad_pcb + requirements: KiCAD pcbnew >= 4.0 + + """ + def defaults( self ): + """ + Method defaults must be redefined + self.name should be the menu label to use + self.category should be the category (not yet used) + self.description should be a comprehensive description + of the plugin + """ + self.name = "Snap Selected Module(s) to Grid\nversion "+__version__ + self.category = "Modify PCB" + self.description = "Automaticaly Snap Selected Module(s) to Grid on an existing PCB" + #self.pcbnew_icon_support = hasattr(self, "show_toolbar_button") + self.show_toolbar_button = True + self.icon_file_name = os.path.join(os.path.dirname(__file__), './snap2grid.png') + # + + def Run(self): + #self.pcb = GetBoard() + import sys,os + #mm_ius = 1000000.0 + + pcb = pcbnew.GetBoard() + gridOrigin = pcb.GetGridOrigin() + auxOrigin = pcb.GetAuxOrigin() + content='' + locked_fp='' + #wxPoint(77470000, 135890000) + for module in pcb.GetModules(): + if module.IsSelected(): + if use_grid_origin: + mpx = module.GetPosition().x - gridOrigin.x + mpy = module.GetPosition().y - gridOrigin.y + print(mpx,mpy) + mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.x + mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.y + print(mpxOnG,mpyOnG) + locked='' + if not module.IsLocked(): + module.SetPosition(wxPoint(mpxOnG,mpyOnG)) + else: + locked='LOCKED' + X_POS=str(module.GetPosition().x) # - gridOrigin.x) + #X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - gridOrigin.x )) + X_POS="{0:<11}".format(X_POS) + Y_POS=str(module.GetPosition().y) # - gridOrigin.y) + Y_POS="{0:<11}".format(Y_POS) + ## mpOnGx = PutOnGridMM(module.GetPosition().x, gridSizeMM) + ## mpOnGy = PutOnGridMM(module.GetPosition().y, gridSizeMM) + ## module.SetPosition(wxPoint(mpOnGx,mpOnGy)) + #module.SetPosition(wxPoint(mpOnGx+FromMM(100.0),mpOnGy+FromMM(2.0))) + #module.SetOrientation(10) + #Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - gridOrigin.y)) + # else: + # mpx = module.GetPosition().x - auxOrigin().x + # mpy = module.GetPosition().y - auxOrigin().y + # X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - auxOrigin().x )) + # X_POS="{0:<11}".format(X_POS) + # Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - auxOrigin().y)) + # Y_POS="{0:<11}".format(Y_POS) + Reference="{0:<10}".format(str(module.GetReference())) + Value = str(module.GetValue()) + Value=(Value[:17] + '..') if len(Value) > 19 else Value + Value="{0:<20}".format(Value) + Rotation='{0:.1f}'.format((module.GetOrientation()/10)) + Rotation="{0:>6}".format(Rotation)+' ' + if module.GetLayer() == 0: + Layer=" top" + else: + Layer=" bottom" + #Side="## Side :"+Layer+lsep + Layer="{0:<10}".format(Layer) + content+=Reference + if 'LOCKED' in locked: + locked_fp+=Reference + ' LOCKED'+'\n' #os.linesep + #content+=Value + content+=X_POS + content+=Y_POS + #content+=str(mpOnGx) + #content+=str(mpOnGy) + content+=str(mpxOnG) + content+=str(mpyOnG) + content+=Layer+'\n' #os.linesep + if len(content)>0: + content+=str(pcbnew.FromMM(gridReference)) + wxLogDebug(content,debug) + if len (locked_fp)>0: + locked_fp+='\n'+'NOT Moved' + wxLogDebug(locked_fp,True) + else: + wxLogDebug('No Modules Selected',True) + Refresh() + #return content + + #if 0: + # #from https://github.com/MitjaNemec/Kicad_action_plugins + # #hack wxFormBuilder py2/py3 + # _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] + # #aParameters = RoundTrackDlg(None) + # aParameters = RoundTrack_Dlg(_pcbnew_frame) + # #aParameters = RoundTrack_DlgEx(_pcbnew_frame) + # aParameters.Show() + # #end hack + # aParameters.m_distanceMM.SetValue("5") + # aParameters.m_segments.SetValue("16") + # aParameters.m_bitmap1.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "round_track_help.png") ) ) + # modal_result = aParameters.ShowModal() + # segments = self.CheckSegmentsInput( + # aParameters.m_segments.GetValue(), "number of segments") + # distI = FromMM(self.CheckDistanceInput(aParameters.m_distanceMM.GetValue(), "distance from intersection")) + # if segments is not None and distI is not None: + # if modal_result == wx.ID_OK: + # Round_Selection(pcb, distI, segments) + # elif modal_result == wx.ID_DELETE: + # Delete_Segments(pcb) + # #wx.LogMessage('Round Segments on Track Net Deleted') + # elif modal_result == wx.ID_REVERT: + # wxLogDebug('Connecting Tracks',debug) + # Connect_Segments(pcb) + # else: + # None # Cancel + # else: + # None # Invalid input + # aParameters.Destroy() + + + # wxLogDebug('showing Selected Tracks',debug) + # wx.LogMessage('Select Tracks to calculate the Length\nor One Pad to select connected Tracks') +# + diff --git a/Snap2Grid/snap2grid.svg b/Snap2Grid/snap2grid.svg new file mode 100644 index 0000000..0a08e02 --- /dev/null +++ b/Snap2Grid/snap2grid.svg @@ -0,0 +1,242 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Snap2Grid/snaptogrid_script.py b/Snap2Grid/snaptogrid_script.py new file mode 100644 index 0000000..d78ceb8 --- /dev/null +++ b/Snap2Grid/snaptogrid_script.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +# +# A script to Snap modules to selected Grid for kicad_pcb +# requirements: KiCAD pcbnew >= 4.0 +# copyright Maurice easyw +# +# + +#import snaptogrid; import importlib; importlib.reload(snaptogrid) +import sys, os +import pcbnew +import datetime +import wx +from pcbnew import * + +use_grid_origin = True +gridReference = 0.127 #1.27 #mm pcbnew.FromMM(1.0) #0.1mm + + +# def PutOnGridMM(value, gridSizeMM): +# thresh = FromMM(gridSizeMM) +# return round(value/thresh)*thresh +# +# def PutOnGridMils(value, gridSizeMils): +# thresh = FromMils(gridSizeMils) +# return round(value/thresh)*thresh +#def SetPosition(self, p): +# """SetPosition(wxRect self, wxPoint p)""" +# return _pcbnew.wxRect_SetPosition(self, p) + + +def Snap2Grid(gridSizeMM,use_grid_origin): + import sys,os + #mm_ius = 1000000.0 + + pcb = pcbnew.GetBoard() + gridOrigin = pcb.GetGridOrigin() + auxOrigin = pcb.GetAuxOrigin() + content='' + #wxPoint(77470000, 135890000) + for module in pcb.GetModules(): + if module.IsSelected(): + if use_grid_origin: + mpx = module.GetPosition().x - gridOrigin.x + mpy = module.GetPosition().y - gridOrigin.y + print(mpx,mpy) + mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.x + mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.y + print(mpxOnG,mpyOnG) + module.SetPosition(wxPoint(mpxOnG,mpyOnG)) + X_POS=str(module.GetPosition().x) # - gridOrigin.x) + #X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - gridOrigin.x )) + X_POS="{0:<11}".format(X_POS) + Y_POS=str(module.GetPosition().y) # - gridOrigin.y) + Y_POS="{0:<11}".format(Y_POS) + ## mpOnGx = PutOnGridMM(module.GetPosition().x, gridSizeMM) + ## mpOnGy = PutOnGridMM(module.GetPosition().y, gridSizeMM) + ## module.SetPosition(wxPoint(mpOnGx,mpOnGy)) + #module.SetPosition(wxPoint(mpOnGx+FromMM(100.0),mpOnGy+FromMM(2.0))) + #module.SetOrientation(10) + #Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - gridOrigin.y)) + # else: + # mpx = module.GetPosition().x - auxOrigin().x + # mpy = module.GetPosition().y - auxOrigin().y + # X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - auxOrigin().x )) + # X_POS="{0:<11}".format(X_POS) + # Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - auxOrigin().y)) + # Y_POS="{0:<11}".format(Y_POS) + Reference="{0:<10}".format(str(module.GetReference())) + Value = str(module.GetValue()) + Value=(Value[:17] + '..') if len(Value) > 19 else Value + Value="{0:<20}".format(Value) + Rotation='{0:.1f}'.format((module.GetOrientation()/10)) + Rotation="{0:>6}".format(Rotation)+' ' + if module.GetLayer() == 0: + Layer=" top" + else: + Layer=" bottom" + #Side="## Side :"+Layer+lsep + Layer="{0:<10}".format(Layer) + content+=Reference + #content+=Value + content+=X_POS + content+=Y_POS + #content+=str(mpOnGx) + #content+=str(mpOnGy) + content+=str(mpxOnG) + content+=str(mpyOnG) + content+=Layer+os.linesep + content+=str(pcbnew.FromMM(gridReference)) + Refresh() + return content + +reply=Snap2Grid(gridReference,use_grid_origin) +#LogMsg=reply +wx.LogMessage(reply) diff --git a/__init__.py b/__init__.py index 001b420..8a147a8 100644 --- a/__init__.py +++ b/__init__.py @@ -9,3 +9,6 @@ from . import FabricationPositions from . import MoveToLayer from . import PcbToDxf + +from . import Snap2Grid + From aa58deaf1a1f1d156bafee3f147f33b58869caab Mon Sep 17 00:00:00 2001 From: easyw Date: Sun, 16 Feb 2020 09:41:19 +0100 Subject: [PATCH 06/18] better icon --- Snap2Grid/snap2grid.png | Bin 1724 -> 1761 bytes Snap2Grid/snap2grid.svg | 54 ++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Snap2Grid/snap2grid.png b/Snap2Grid/snap2grid.png index d88097b00514408e5c6ecd1aec4211b3032ee57d..d812a83e589caedbc64ba37477b255cf427ed9cf 100644 GIT binary patch delta 1670 zcmV;126_3s4dD%tZhu}$L_t(oh3%GKP*m3)$3N%py^G84vLc|=Fcq9t8I*v#P%BQ2 zny9hO)JkL~&2%Ddt=80OZBm=DQ-s**4AVY1Xh1sTC$ke;5N*Wz-ZBz?qq@>|MF+LV3ALC%eIvhLa` zDJfZ0U0t1-X0nRrz!D8^5&iVeahOx^s?B(=@-s z;rJw8m)wFmFbv~-U0t1TWMpJM*9Bo-0`>LvCx3lD-}f(Fx->qY??RB!g2KYW^pup8 z?@1{q{CZ?Z@vlB(-^!f8q%U^bf@q?FG9I2?{V;Akim z`a?-c$@a3cvXnr8kWxD1IrP-O|!B7H@m2=``MtKEx3S@W7tNmJLs^ z=jq*4)mAfRnYmk(5rZFm>kxT)dHl5M6(Z4YD`S!qKYJCk+58|oJNxvf5&-acJP(p} zot>TZ-tXh7zr902=Om|I%%P_*m$tSx#(#|fP36r1l>B`q*RNk^baa$p`ZQ;s^8m2x zY%y1_US)iIT$@vo`AQZH27i6w!iCGD+W0r!idYR`2*Hi6o2`SN^uIfy1&#m?fayqR z>f*(VO{%K)1nv5d02@GXDmZcO+_^V^5nb2s#>by?53FCmKC8I6cyUZ_Y;3&H(0|ZS z&~A) zpYRqW5OBNQFDr^NXfl}wTrSt1E0FyG9RCNbfBr8mr91xWr>I@$yT9#c`xWoHX4qf) zaknkDUxcL1=kuNJ?d^3UjoIo-!+%&bJUrZ{D9WJQ?S3gfXTsT9zI^%Hz!GL!leTMM zV2yxd0!l5@q1<@iw16H;35EBq>b-B_UeWz!ALdvcgNq1`1T2PO4BAs{Tk|{_nzME3 zh{dmIf#C^@lu`iBfq{Wju{g=|fLBVnGAedRxG3No3jE1{d>}REYYk4m4}S~*(slXj z?l!0MV<0;kr~O{nzzN`hl=6@e;wj)K(XAiF=S(0F4u@YbnN0hEiLtS!0|HZ2f**AI1<@xGMSzOI$B#>&jM$GS^%fh`M$&9xCK}vkw`rY#RqV_ z1=_Aa@q&XSVcyp;36&CxBY*IIU%Rw5fPbA9i{&QpdTg(z zX|+7m!r0KfaIfA9gW$kD9RE3kN+k78}QR?aKefY Qu>b%707*qoM6N<$g3g;(v;Y7A delta 1633 zcmV-n2A=uh4ZIDIZhtvRL_t(oh3%GIOq=Hw$A8cBzBU1D92aP4%LYVlgGeX@(`F%R zzPcvu7LA1lDVwH-O=+@p(U!K$s!k)&Op~HbTBJ1>Y$=MuhNg|>BFVZ;-33dfji$o` z!aPDsz7_~cs4?cldGW{l>;fCvhKP=4(k}MDde8ry=bXRK@qhCn_=Kpftu0YXt&H1B zDbJ}>r>@r2)NGPc=EQj+#CvURZGjy-c5DOEW3l1V($X`Hjg4k%Uj35_n92$r8FKlz zOlL$?=2)7{yJ~L+UJ2Qwzv^2zm;>t zJs!_{^9m3`90i_;nQs9#b#-;8bY0)%Q-Q3+Seuqnw|{r<-W|6hcOQy#Qb<`?SooCH zY8@ElPI{czl=e_bNlA7v805x{8^;oAAX9$CMC!N2VsY-@zu&oH#S>cIbqD$VPI7PB zsjRGA($LV5la*KVD4n>C@n2@rlqC5 ztdyDz1Om+i0|V20_Uy43hOs$2JKOqci$$Z+48t&zc2kl7tJT_~l-dU1a5##9gW+)a zH`pnrP{U+b~+CGYkiuhjr8$@H%mg9=U-+v3M)%tN>Uf#+33IOnUJRhfWeSLil z-W}qP+q#KgMn!#vbaizxVNTIj(*Z!`Uw@W!>Cz>}#>NObL!92}0pNwx<#cyTklRn?Q#d#%|^!a@6c)i}HvuDpH-33Vk+-~>lQp($!rVUqARBZnc z@;-n=e}&bLj`*KWjQz}A|EdnyZ4F0kaZZGl&FAx-92^{Uq0HItD$`stIy%}VrM&HS zyI)JplRAP|VxpD+FGt}S0k2A^E`J#I+pAAJia?>1z%@Adh=AjT!+xsYUUerFRm+3| zf7ItRO>?_-RLj_MtQaAsUk^#khzeK}YW#Fw0YV6`Qfhh3>{ZY%;L8$zx1p=ActclT z#%#Nx9k{jgPaW#-4o7vf%k@tnFP5k0&cN_tV2@I2pAh2nz;|Oy|8d_AM1LZYmo!b= z4NQ)YkDsW5X<#`(2mDJw6ElCT9up2#!7Ts+0m`G%^_r&b1bRC=J5K|rfg=Dem+Q|C zhvN#68I4ApSu8$)Ll>ayLnvQ#k`yd>8>XO6L3tFu_@D&*2d`ofuus8rCLI5-2&ky2 zcv1*)7?_MiB5(Bc^bEy)E`OIRZC_T_Rv|=*5MnJeb52~lT?nxk@EV5krq}BY#eHRE zWsm8){$n5$s84)tr*_~S;3)u2(@fx{xWnOad;@qDKq<9x<;s;gUaxl&VBNZPcEd1! z4Wt2E)6>&013!P>00000NkvXXu0mjfCWkfJ diff --git a/Snap2Grid/snap2grid.svg b/Snap2Grid/snap2grid.svg index 0a08e02..3875f66 100644 --- a/Snap2Grid/snap2grid.svg +++ b/Snap2Grid/snap2grid.svg @@ -24,7 +24,7 @@ image/svg+xml - + @@ -46,7 +46,7 @@ inkscape:snap-grids="true" inkscape:snap-to-guides="true" inkscape:zoom="8.1181296" - inkscape:cx="-15.991654" + inkscape:cx="-43.153083" inkscape:cy="14.972949" inkscape:window-x="0" inkscape:window-y="0" @@ -109,11 +109,6 @@ inkscape:connector-curvature="0" id="path10-71" d="m 5.5,16 a 1.5,1.5022534 0 0 1 -3,0 1.5,1.5022534 0 1 1 3,0 z" /> - - - - - + + + + + From 84bba2a186c4ce755ae75746d4341db1b64c4bd1 Mon Sep 17 00:00:00 2001 From: easyw Date: Mon, 17 Feb 2020 15:39:00 +0100 Subject: [PATCH 07/18] improving Dialogs --- MoveToLayer/Move2LayerDlg.py | 9 +- MoveToLayer/Move2LayerDlg.py.bak | 75 +++ MoveToLayer/move_to_layer.py | 7 +- MoveToLayer/move_to_layer.py.bak | 153 ++++++ MoveToLayer/move_to_layer_dlg.fbp | 13 +- MoveToLayer/move_to_layer_dlg.fbp.bak | 536 ++++++++++++++++++++ PcbToDxf/__init__.py | 2 + Snap2Grid/Snap2GridDlg.fbp | 682 ++++++++++++++++++++++++++ Snap2Grid/Snap2GridDlg.py | 88 ++++ Snap2Grid/snap2grid.py | 292 ++++++----- Snap2Grid/snap2grid.py.bak | 200 ++++++++ 11 files changed, 1917 insertions(+), 140 deletions(-) create mode 100644 MoveToLayer/Move2LayerDlg.py.bak create mode 100644 MoveToLayer/move_to_layer.py.bak create mode 100644 MoveToLayer/move_to_layer_dlg.fbp.bak create mode 100644 PcbToDxf/__init__.py create mode 100644 Snap2Grid/Snap2GridDlg.fbp create mode 100644 Snap2Grid/Snap2GridDlg.py create mode 100644 Snap2Grid/snap2grid.py.bak diff --git a/MoveToLayer/Move2LayerDlg.py b/MoveToLayer/Move2LayerDlg.py index 3f5f403..66ed329 100644 --- a/MoveToLayer/Move2LayerDlg.py +++ b/MoveToLayer/Move2LayerDlg.py @@ -17,13 +17,13 @@ import wx.xrc class Move2LayerDlg ( wx.Dialog ): def __init__( self, parent ): - wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Move to Layer", pos = wx.DefaultPosition, size = wx.Size( 325,190 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Move to Layer", pos = wx.DefaultPosition, size = wx.Size( 568,263 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) bSizer3 = wx.BoxSizer( wx.VERTICAL ) - self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Selected Objects to Move to chosen Layer", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Selected Objects will Move to chosen Layer", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_comment.Wrap( -1 ) bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 ) @@ -63,6 +63,11 @@ class Move2LayerDlg ( wx.Dialog ): bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 ) + bSizer4 = wx.BoxSizer( wx.VERTICAL ) + + + bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 ) + self.SetSizer( bSizer3 ) self.Layout() diff --git a/MoveToLayer/Move2LayerDlg.py.bak b/MoveToLayer/Move2LayerDlg.py.bak new file mode 100644 index 0000000..3f5f403 --- /dev/null +++ b/MoveToLayer/Move2LayerDlg.py.bak @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version Oct 26 2018) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + +########################################################################### +## Class Move2LayerDlg +########################################################################### + +class Move2LayerDlg ( wx.Dialog ): + + def __init__( self, parent ): + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Move to Layer", pos = wx.DefaultPosition, size = wx.Size( 325,190 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) + + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) + + bSizer3 = wx.BoxSizer( wx.VERTICAL ) + + self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Selected Objects to Move to chosen Layer", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_comment.Wrap( -1 ) + + bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 ) + + bSizer31 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticTextLayer = wx.StaticText( self, wx.ID_ANY, u"Layer", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticTextLayer.Wrap( -1 ) + + bSizer31.Add( self.m_staticTextLayer, 1, wx.ALL|wx.EXPAND, 5 ) + + m_comboBoxLayerChoices = [] + self.m_comboBoxLayer = wx.ComboBox( self, wx.ID_ANY, u"Combo!", wx.DefaultPosition, wx.Size( 250,-1 ), m_comboBoxLayerChoices, 0 ) + bSizer31.Add( self.m_comboBoxLayer, 0, wx.ALL|wx.EXPAND, 5 ) + + + bSizer3.Add( bSizer31, 0, 0, 5 ) + + self.m_staticline1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + bSizer3.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 ) + + bSizer1 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText101 = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText101.Wrap( -1 ) + + bSizer1.Add( self.m_staticText101, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.m_buttonOK = wx.Button( self, wx.ID_OK, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 ) + + self.m_buttonOK.SetDefault() + bSizer1.Add( self.m_buttonOK, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer1.Add( self.m_buttonCancel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + + bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 ) + + + self.SetSizer( bSizer3 ) + self.Layout() + + self.Centre( wx.BOTH ) + + def __del__( self ): + pass + + diff --git a/MoveToLayer/move_to_layer.py b/MoveToLayer/move_to_layer.py index bc6b7b1..6a1a950 100644 --- a/MoveToLayer/move_to_layer.py +++ b/MoveToLayer/move_to_layer.py @@ -25,19 +25,20 @@ from pcbnew import * import base64 from wx.lib.embeddedimage import PyEmbeddedImage import os -___version___="1.2.2" +___version___="1.2.3" from . import Move2LayerDlg def MoveToLayer(pcb,layerId): + found_selected=False for drw in pcb.GetDrawings(): if drw.IsSelected(): drw.SetLayer(layerId) found_selected=True if found_selected!=True: - LogMsg="select lines to be moved to new layer\n" + LogMsg="select drawings to be moved to new layer\n" LogMsg+="use GAL for selecting lines" wx.LogMessage(LogMsg) else: @@ -101,7 +102,7 @@ class move_to_draw_layer( pcbnew.ActionPlugin ): of the plugin """ import os - self.name = "Move Selected Drawings to chosen Layer\nversion "+___version___ + 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") diff --git a/MoveToLayer/move_to_layer.py.bak b/MoveToLayer/move_to_layer.py.bak new file mode 100644 index 0000000..bc6b7b1 --- /dev/null +++ b/MoveToLayer/move_to_layer.py.bak @@ -0,0 +1,153 @@ +# 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.2" + +from . import Move2LayerDlg + + +def MoveToLayer(pcb,layerId): + for drw in pcb.GetDrawings(): + if drw.IsSelected(): + drw.SetLayer(layerId) + 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() + layerName = pcbnew.GetBoard().GetLayerName(layerId) + LogMsg="selected drawings moved to "+layerName+" layer" + wx.LogMessage(LogMsg) +# + + + +# Python plugin stuff + +class Move2Layer_Dlg(Move2LayerDlg.Move2LayerDlg): + # from https://github.com/MitjaNemec/Kicad_action_plugins + # hack for new wxFormBuilder generating code incompatible with old wxPython + # noinspection PyMethodOverriding + def SetSizeHints(self, sz1, sz2): + if wx.__version__ < '4.0': + self.SetSizeHintsSz(sz1, sz2) + else: + super(Move2Layer_Dlg, self).SetSizeHints(sz1, sz2) + + #def onApplyClick(self, event): + # return self.EndModal(wx.ID_OK) + # + #def onCancelClick(self, event): + # return self.EndModal(wx.ID_CANCEL) + + def __init__(self, parent): + import wx + Move2LayerDlg.Move2LayerDlg.__init__(self, parent) + #self.GetSizer().Fit(self) + self.SetMinSize(self.GetSize()) + # self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) + # self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) + # if wx.__version__ < '4.0': + # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + # else: + # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) +# +class move_to_draw_layer( pcbnew.ActionPlugin ): + """ + A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL) + How to use: + - move to GAL + - select some draw objects + - call the plugin + - select the new layer + - selected draw objects will be moved to new layer + """ + + def defaults( self ): + """ + Method defaults must be redefined + self.name should be the menu label to use + self.category should be the category (not yet used) + self.description should be a comprehensive description + of the plugin + """ + import os + self.name = "Move Selected Drawings to chosen Layer\nversion "+___version___ + self.category = "Modify PCB" + self.description = "Move Selected Drawings to chosen Layer on an existing PCB" + self.icon_file_name = os.path.join(os.path.dirname(__file__), "./move2layer.png") + self.show_toolbar_button = True + + def Run( self ): + found_selected=False + + board = pcbnew.GetBoard() + fileName = GetBoard().GetFileName() + # # dicts for converting layer name to id, used by _get_layer + # _std_layer_dict = {pcbnew.BOARD_GetStandardLayerName(n): n + # for n in range(pcbnew.PCB_LAYER_ID_COUNT)} + # #_std_layer_names = {s: n for n, s in _std_layer_dict.iteritems()} + # _std_layer_names = {s: n for n, s in _std_layer_dict.items()} + # _brd_layer_dict = {pcbnew.GetBoard().GetLayerName(n): n + # for n in range(pcbnew.PCB_LAYER_ID_COUNT)} + # #_std_layer_names = {s: n for n, s in _std_layer_dict.iteritems()} + # _brd_layer_names = {s: n for n, s in _brd_layer_dict.items()} + + + if 0: #len(fileName) == 0: + wx.LogMessage("A board needs to be saved/loaded\nto run the plugin!") + else: + #from https://github.com/MitjaNemec/Kicad_action_plugins + #hack wxFormBuilder py2/py3 + _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] + aParameters = Move2Layer_Dlg(_pcbnew_frame) + aParameters.Show() + for l in range(pcbnew.PCB_LAYER_ID_COUNT): + aParameters.m_comboBoxLayer.Append(pcbnew.GetBoard().GetLayerName(l)) + aParameters.m_comboBoxLayer.Select(44) + modal_result = aParameters.ShowModal() + if modal_result == wx.ID_OK: + LayerName = aParameters.m_comboBoxLayer.GetStringSelection() + LayerIndex = aParameters.m_comboBoxLayer.FindString(LayerName) + LayerStdName = pcbnew.BOARD_GetStandardLayerName(LayerIndex) + #wx.LogMessage(LayerName+';'+str(LayerIndex)+';'+LayerStdName) + MoveToLayer(board, LayerIndex) + else: + None # Cancel + + LogMsg='' + msg="'move to layer tool'\n" + msg+="version = "+___version___ + + +#move_to_draw_layer().register() + diff --git a/MoveToLayer/move_to_layer_dlg.fbp b/MoveToLayer/move_to_layer_dlg.fbp index 43a4da8..66f4aa8 100644 --- a/MoveToLayer/move_to_layer_dlg.fbp +++ b/MoveToLayer/move_to_layer_dlg.fbp @@ -45,7 +45,7 @@ Move2LayerDlg - 325,190 + 568,263 wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER Move to Layer @@ -530,6 +530,17 @@ + + 5 + wxEXPAND + 1 + + + bSizer4 + wxVERTICAL + none + + diff --git a/MoveToLayer/move_to_layer_dlg.fbp.bak b/MoveToLayer/move_to_layer_dlg.fbp.bak new file mode 100644 index 0000000..43a4da8 --- /dev/null +++ b/MoveToLayer/move_to_layer_dlg.fbp.bak @@ -0,0 +1,536 @@ + + + + + + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + Move2LayerDlg + 1000 + none + + 0 + Move2LayerDlg + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + Move2LayerDlg + + 325,190 + wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Move to Layer + + + + + + + bSizer3 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Selected Objects will Move to chosen Layer + 0 + + 0 + + + 0 + + 1 + m_comment + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + + 0 + + + bSizer31 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Layer + 0 + + 0 + + + 0 + + 1 + m_staticTextLayer + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + -1,-1 + 0 + -1,-1 + 1 + m_comboBoxLayer + 1 + + + protected + 1 + + Resizable + -1 + 1 + 250,-1 + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + Combo! + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + 5 + wxALIGN_RIGHT|wxEXPAND + 0 + + + bSizer1 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + + 0 + + 1 + m_staticText101 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 0 + + 1 + + 1 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + Apply + + 0 + + 0 + + + 0 + + 1 + m_buttonOK + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + 0 + + + 0 + + 1 + m_buttonCancel + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + diff --git a/PcbToDxf/__init__.py b/PcbToDxf/__init__.py new file mode 100644 index 0000000..68def39 --- /dev/null +++ b/PcbToDxf/__init__.py @@ -0,0 +1,2 @@ +from .action_menu_pcb2dxf import pcb2dxf +pcb2dxf().register() diff --git a/Snap2Grid/Snap2GridDlg.fbp b/Snap2Grid/Snap2GridDlg.fbp new file mode 100644 index 0000000..6becf11 --- /dev/null +++ b/Snap2Grid/Snap2GridDlg.fbp @@ -0,0 +1,682 @@ + + + + + + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + Snap2GridDlg + 1000 + none + + 0 + Snap2GridDlg + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + Snap2GridDlg + + 499,394 + wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Snap to Grid + + + + + + + bSizer3 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Selected Model(s) to Snap to the Grid + 0 + + 0 + + + 0 + + 1 + m_comment + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + + 0 + + + bSizer31 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Grid + 0 + + 0 + + + 0 + + 1 + m_staticTextGrid + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "1.0mm (39.37mils)" "0.5mm (19.69mils)" "0.25mm (9.84mils)" "0.1mm (3.94mils)" "2.54mm (100mils)" "1.27mm (50mils)" "0.635mm (25mils)" "0.508mm (20mils)" "0.254mm (10mils)" "0.127mm (5mils)" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + -1,-1 + 0 + -1,-1 + 1 + m_comboBoxGrid + 1 + + + protected + 1 + + Resizable + 0 + 1 + -1,-1 + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 1.0mm (39.37mils) + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + GridOrigin reference + + 0 + + + 0 + + 1 + m_radioBtnGO + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + AuxOrigin reference + + 0 + + + 0 + + 1 + m_radioBtnAO + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline2 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + 5 + wxALIGN_RIGHT|wxEXPAND + 0 + + + bSizer1 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 0 + + 1 + + 1 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + Apply + + 0 + + 0 + + + 0 + + 1 + m_buttonOK + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + 0 + + + 0 + + 1 + m_buttonCancel + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer4 + wxVERTICAL + none + + + + + + diff --git a/Snap2Grid/Snap2GridDlg.py b/Snap2Grid/Snap2GridDlg.py new file mode 100644 index 0000000..55c4f1d --- /dev/null +++ b/Snap2Grid/Snap2GridDlg.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version Oct 26 2018) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + +########################################################################### +## Class Snap2GridDlg +########################################################################### + +class Snap2GridDlg ( wx.Dialog ): + + def __init__( self, parent ): + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Snap to Grid", pos = wx.DefaultPosition, size = wx.Size( 499,394 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) + + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) + + bSizer3 = wx.BoxSizer( wx.VERTICAL ) + + self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Selected Model(s) to Snap\nto the Grid", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_comment.Wrap( -1 ) + + bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 ) + + bSizer31 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticTextGrid = wx.StaticText( self, wx.ID_ANY, u"Grid", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticTextGrid.Wrap( -1 ) + + bSizer31.Add( self.m_staticTextGrid, 1, wx.ALL|wx.EXPAND, 5 ) + + m_comboBoxGridChoices = [ u"1.0mm (39.37mils)", u"0.5mm (19.69mils)", u"0.25mm (9.84mils)", u"0.1mm (3.94mils)", u"2.54mm (100mils)", u"1.27mm (50mils)", u"0.635mm (25mils)", u"0.508mm (20mils)", u"0.254mm (10mils)", u"0.127mm (5mils)" ] + self.m_comboBoxGrid = wx.ComboBox( self, wx.ID_ANY, u"1.0mm (39.37mils)", wx.DefaultPosition, wx.Size( -1,-1 ), m_comboBoxGridChoices, 0 ) + self.m_comboBoxGrid.SetSelection( 0 ) + bSizer31.Add( self.m_comboBoxGrid, 0, wx.ALL|wx.EXPAND, 5 ) + + + bSizer3.Add( bSizer31, 0, 0, 5 ) + + self.m_staticline1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + bSizer3.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 ) + + self.m_radioBtnGO = wx.RadioButton( self, wx.ID_ANY, u"GridOrigin reference", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer3.Add( self.m_radioBtnGO, 0, wx.ALL, 5 ) + + self.m_radioBtnAO = wx.RadioButton( self, wx.ID_ANY, u"AuxOrigin reference", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer3.Add( self.m_radioBtnAO, 0, wx.ALL, 5 ) + + self.m_staticline2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + bSizer3.Add( self.m_staticline2, 0, wx.EXPAND |wx.ALL, 5 ) + + bSizer1 = wx.BoxSizer( wx.HORIZONTAL ) + + + bSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + + self.m_buttonOK = wx.Button( self, wx.ID_OK, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 ) + + self.m_buttonOK.SetDefault() + bSizer1.Add( self.m_buttonOK, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 ) + + self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer1.Add( self.m_buttonCancel, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 ) + + + bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 ) + + bSizer4 = wx.BoxSizer( wx.VERTICAL ) + + + bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 ) + + + self.SetSizer( bSizer3 ) + self.Layout() + + self.Centre( wx.BOTH ) + + def __del__( self ): + pass + + diff --git a/Snap2Grid/snap2grid.py b/Snap2Grid/snap2grid.py index 97edcbf..a8f98f4 100644 --- a/Snap2Grid/snap2grid.py +++ b/Snap2Grid/snap2grid.py @@ -8,6 +8,10 @@ #import snaptogrid; import importlib; importlib.reload(snaptogrid) +### plugins errors +#import pcbnew +#pcbnew.GetWizardsBackTrace() + __version__ = '1.0.1' import sys, os import pcbnew @@ -17,11 +21,11 @@ from pcbnew import * use_grid_origin = True -gridReference = 2.54 #1.27 #mm pcbnew.FromMM(1.0) #0.1mm +gridReference = 0.1 #1.27 #mm pcbnew.FromMM(1.0) #0.1mm gridSizeMM = gridReference -#from . import Send2GridDlg +from . import Snap2GridDlg sys.path.append(os.path.dirname(__file__)) @@ -32,36 +36,36 @@ def wxLogDebug(msg,dbg): wx.LogMessage(msg) # -#class Snap2Grid_Dlg(Snap2GridDlg.Snap2GridDlg): -# # from https://github.com/MitjaNemec/Kicad_action_plugins -# # hack for new wxFormBuilder generating code incompatible with old wxPython -# # noinspection PyMethodOverriding -# def SetSizeHints(self, sz1, sz2): -# if wx.__version__ < '4.0': -# self.SetSizeHintsSz(sz1, sz2) -# else: -# super(RoundTrack_Dlg, self).SetSizeHints(sz1, sz2) -# -# # def onDeleteClick(self, event): -# # return self.EndModal(wx.ID_DELETE) -# # -# # def onConnectClick(self, event): -# # return self.EndModal(wx.ID_REVERT) -# -# def __init__(self, parent): -# import wx -# Send2GridDlg.Send2GridDlg.__init__(self, parent) -# #self.GetSizer().Fit(self) -# self.SetMinSize(self.GetSize()) -# #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) -# #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) -# #if wx.__version__ < '4.0': -# # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) -# # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) -# #else: -# # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) -# # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) -# +class Snap2Grid_Dlg(Snap2GridDlg.Snap2GridDlg): + # from https://github.com/MitjaNemec/Kicad_action_plugins + # hack for new wxFormBuilder generating code incompatible with old wxPython + # noinspection PyMethodOverriding + def SetSizeHints(self, sz1, sz2): + if wx.__version__ < '4.0': + self.SetSizeHintsSz(sz1, sz2) + else: + super(Snap2Grid_Dlg, self).SetSizeHints(sz1, sz2) + + # def onDeleteClick(self, event): + # return self.EndModal(wx.ID_DELETE) + # + # def onConnectClick(self, event): + # return self.EndModal(wx.ID_REVERT) + + def __init__(self, parent): + import wx + Snap2GridDlg.Snap2GridDlg.__init__(self, parent) + #self.GetSizer().Fit(self) + self.SetMinSize(self.GetSize()) + #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) + #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) + #if wx.__version__ < '4.0': + # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + #else: + # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + # Python plugin stuff class snap_to_grid( pcbnew.ActionPlugin ): """ @@ -77,7 +81,7 @@ class snap_to_grid( pcbnew.ActionPlugin ): self.description should be a comprehensive description of the plugin """ - self.name = "Snap Selected Module(s) to Grid\nversion "+__version__ + self.name = "Snap Selected Modules to Grid \nversion "+__version__ self.category = "Modify PCB" self.description = "Automaticaly Snap Selected Module(s) to Grid on an existing PCB" #self.pcbnew_icon_support = hasattr(self, "show_toolbar_button") @@ -89,111 +93,131 @@ class snap_to_grid( pcbnew.ActionPlugin ): #self.pcb = GetBoard() import sys,os #mm_ius = 1000000.0 + _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] + #aParameters = RoundTrackDlg(None) + aParameters = Snap2Grid_Dlg(_pcbnew_frame) + gridIndex = aParameters.m_comboBoxGrid.FindString('0.1mm (3.94mils)') + aParameters.m_comboBoxGrid.SetSelection(gridIndex) + #aParameters.m_comboBoxGrid.Append('0.1mm (3.94mils)') + aParameters.m_radioBtnGO.SetValue(True) + aParameters.Show() - pcb = pcbnew.GetBoard() - gridOrigin = pcb.GetGridOrigin() - auxOrigin = pcb.GetAuxOrigin() - content='' - locked_fp='' - #wxPoint(77470000, 135890000) - for module in pcb.GetModules(): - if module.IsSelected(): - if use_grid_origin: - mpx = module.GetPosition().x - gridOrigin.x - mpy = module.GetPosition().y - gridOrigin.y - print(mpx,mpy) - mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.x - mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.y - print(mpxOnG,mpyOnG) - locked='' - if not module.IsLocked(): - module.SetPosition(wxPoint(mpxOnG,mpyOnG)) - else: - locked='LOCKED' - X_POS=str(module.GetPosition().x) # - gridOrigin.x) - #X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - gridOrigin.x )) - X_POS="{0:<11}".format(X_POS) - Y_POS=str(module.GetPosition().y) # - gridOrigin.y) - Y_POS="{0:<11}".format(Y_POS) - ## mpOnGx = PutOnGridMM(module.GetPosition().x, gridSizeMM) - ## mpOnGy = PutOnGridMM(module.GetPosition().y, gridSizeMM) - ## module.SetPosition(wxPoint(mpOnGx,mpOnGy)) - #module.SetPosition(wxPoint(mpOnGx+FromMM(100.0),mpOnGy+FromMM(2.0))) - #module.SetOrientation(10) - #Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - gridOrigin.y)) - # else: - # mpx = module.GetPosition().x - auxOrigin().x - # mpy = module.GetPosition().y - auxOrigin().y - # X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - auxOrigin().x )) - # X_POS="{0:<11}".format(X_POS) - # Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - auxOrigin().y)) - # Y_POS="{0:<11}".format(Y_POS) - Reference="{0:<10}".format(str(module.GetReference())) - Value = str(module.GetValue()) - Value=(Value[:17] + '..') if len(Value) > 19 else Value - Value="{0:<20}".format(Value) - Rotation='{0:.1f}'.format((module.GetOrientation()/10)) - Rotation="{0:>6}".format(Rotation)+' ' - if module.GetLayer() == 0: - Layer=" top" - else: - Layer=" bottom" - #Side="## Side :"+Layer+lsep - Layer="{0:<10}".format(Layer) - content+=Reference - if 'LOCKED' in locked: - locked_fp+=Reference + ' LOCKED'+'\n' #os.linesep - #content+=Value - content+=X_POS - content+=Y_POS - #content+=str(mpOnGx) - #content+=str(mpOnGy) - content+=str(mpxOnG) - content+=str(mpyOnG) - content+=Layer+'\n' #os.linesep - if len(content)>0: - content+=str(pcbnew.FromMM(gridReference)) - wxLogDebug(content,debug) - if len (locked_fp)>0: - locked_fp+='\n'+'NOT Moved' - wxLogDebug(locked_fp,True) + modal_result = aParameters.ShowModal() + if modal_result == wx.ID_OK: + grid = aParameters.m_comboBoxGrid.GetStringSelection() + gridSizeMM = float(grid.split('mm')[0]) + if aParameters.m_radioBtnGO.GetValue(): + use_grid_origin = True + else: + use_grid_origin = False + snap2grid(gridSizeMM,use_grid_origin) else: - wxLogDebug('No Modules Selected',True) - Refresh() - #return content + None # Cancel +## - #if 0: - # #from https://github.com/MitjaNemec/Kicad_action_plugins - # #hack wxFormBuilder py2/py3 - # _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] - # #aParameters = RoundTrackDlg(None) - # aParameters = RoundTrack_Dlg(_pcbnew_frame) - # #aParameters = RoundTrack_DlgEx(_pcbnew_frame) - # aParameters.Show() - # #end hack - # aParameters.m_distanceMM.SetValue("5") - # aParameters.m_segments.SetValue("16") - # aParameters.m_bitmap1.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "round_track_help.png") ) ) - # modal_result = aParameters.ShowModal() - # segments = self.CheckSegmentsInput( - # aParameters.m_segments.GetValue(), "number of segments") - # distI = FromMM(self.CheckDistanceInput(aParameters.m_distanceMM.GetValue(), "distance from intersection")) - # if segments is not None and distI is not None: - # if modal_result == wx.ID_OK: - # Round_Selection(pcb, distI, segments) - # elif modal_result == wx.ID_DELETE: - # Delete_Segments(pcb) - # #wx.LogMessage('Round Segments on Track Net Deleted') - # elif modal_result == wx.ID_REVERT: - # wxLogDebug('Connecting Tracks',debug) - # Connect_Segments(pcb) - # else: - # None # Cancel - # else: - # None # Invalid input - # aParameters.Destroy() - +def snap2grid(gridSizeMM,use_grid_origin): + pcb = pcbnew.GetBoard() + gridOrigin = pcb.GetGridOrigin() + auxOrigin = pcb.GetAuxOrigin() + content='' + locked_fp='' + #wxPoint(77470000, 135890000) + for module in pcb.GetModules(): + if module.IsSelected(): + if use_grid_origin: + mpx = module.GetPosition().x - gridOrigin.x + mpy = module.GetPosition().y - gridOrigin.y + #print(mpx,mpy) + mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.x + mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.y + #print(mpxOnG,mpyOnG) + locked='' + if not module.IsLocked(): + module.SetPosition(wxPoint(mpxOnG,mpyOnG)) + else: + locked='LOCKED' + X_POS=str(module.GetPosition().x) # - gridOrigin.x) + #X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - gridOrigin.x )) + X_POS="{0:<11}".format(X_POS) + Y_POS=str(module.GetPosition().y) # - gridOrigin.y) + Y_POS="{0:<11}".format(Y_POS) + ## mpOnGx = PutOnGridMM(module.GetPosition().x, gridSizeMM) + ## mpOnGy = PutOnGridMM(module.GetPosition().y, gridSizeMM) + ## module.SetPosition(wxPoint(mpOnGx,mpOnGy)) + #module.SetPosition(wxPoint(mpOnGx+FromMM(100.0),mpOnGy+FromMM(2.0))) + #module.SetOrientation(10) + #Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - gridOrigin.y)) + else: # AuxOrigin + mpx = module.GetPosition().x - auxOrigin.x + mpy = module.GetPosition().y - auxOrigin.y + #print(mpx,mpy) + mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ auxOrigin.x + mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ auxOrigin.y + #print(mpxOnG,mpyOnG) + locked='' + if not module.IsLocked(): + module.SetPosition(wxPoint(mpxOnG,mpyOnG)) + else: + locked='LOCKED' + X_POS=str(module.GetPosition().x) # - gridOrigin.x) + #X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - gridOrigin.x )) + X_POS="{0:<11}".format(X_POS) + Y_POS=str(module.GetPosition().y) # - gridOrigin.y) + Y_POS="{0:<11}".format(Y_POS) + ## mpOnGx = PutOnGridMM(module.GetPosition().x, gridSizeMM) + ## mpOnGy = PutOnGridMM(module.GetPosition().y, gridSizeMM) + ## module.SetPosition(wxPoint(mpOnGx,mpOnGy)) + #module.SetPosition(wxPoint(mpOnGx+FromMM(100.0),mpOnGy+FromMM(2.0))) + #module.SetOrientation(10) + #Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - gridOrigin.y)) + Reference="{0:<10}".format(str(module.GetReference())) + Value = str(module.GetValue()) + Value=(Value[:17] + '..') if len(Value) > 19 else Value + Value="{0:<20}".format(Value) + Rotation='{0:.1f}'.format((module.GetOrientation()/10)) + Rotation="{0:>6}".format(Rotation)+' ' + if module.GetLayer() == 0: + Layer=" top" + else: + Layer=" bottom" + #Side="## Side :"+Layer+lsep + Layer="{0:<10}".format(Layer) + content+=Reference + if 'LOCKED' in locked: + locked_fp+=Reference + ' LOCKED'+'\n' #os.linesep + #content+=Value + content+=X_POS + content+=Y_POS + #content+=str(mpOnGx) + #content+=str(mpOnGy) + content+=str(mpxOnG) + content+=str(mpyOnG) + content+=Layer+'\n' #os.linesep + if len(content)>0: + content+=str(pcbnew.FromMM(gridSizeMM))+'\n' + info='Snapped to grid: '+str(gridSizeMM)+'mm\n' + if use_grid_origin: + content+="Using GridOrigin as Ref"+'\n' + info+="Using GridOrigin as Ref"+'\n' + else: + content+="Using AuxOrigin as Ref"+'\n' + info+="Using AuxOrigin as Ref"+'\n' + if debug: + wxLogDebug(content,debug) + #else: + wxLogDebug(info,True) + if len (locked_fp)>0: + locked_fp+='\n'+'NOT Moved (Locked fp)' + locked_fp+='\n'+info + wxLogDebug(locked_fp,True) + else: + wxLogDebug(info,True) + else: + wxLogDebug('No Modules Selected',True) + Refresh() + #return content + # wxLogDebug('showing Selected Tracks',debug) # wx.LogMessage('Select Tracks to calculate the Length\nor One Pad to select connected Tracks') # diff --git a/Snap2Grid/snap2grid.py.bak b/Snap2Grid/snap2grid.py.bak new file mode 100644 index 0000000..15ecdfc --- /dev/null +++ b/Snap2Grid/snap2grid.py.bak @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +# +# A script to Snap modules to selected Grid for kicad_pcb +# requirements: KiCAD pcbnew >= 4.0 +# copyright Maurice easyw +# +# + +#import snaptogrid; import importlib; importlib.reload(snaptogrid) + +__version__ = '1.0.1' +import sys, os +import pcbnew +import datetime +import wx +from pcbnew import * + +use_grid_origin = True + +gridReference = 2.54 #1.27 #mm pcbnew.FromMM(1.0) #0.1mm + +gridSizeMM = gridReference + +#from . import Send2GridDlg + +sys.path.append(os.path.dirname(__file__)) + +debug = False +def wxLogDebug(msg,dbg): + """printing messages only if show is omitted or True""" + if dbg == True: + wx.LogMessage(msg) +# + +#class Snap2Grid_Dlg(Snap2GridDlg.Snap2GridDlg): +# # from https://github.com/MitjaNemec/Kicad_action_plugins +# # hack for new wxFormBuilder generating code incompatible with old wxPython +# # noinspection PyMethodOverriding +# def SetSizeHints(self, sz1, sz2): +# if wx.__version__ < '4.0': +# self.SetSizeHintsSz(sz1, sz2) +# else: +# super(RoundTrack_Dlg, self).SetSizeHints(sz1, sz2) +# +# # def onDeleteClick(self, event): +# # return self.EndModal(wx.ID_DELETE) +# # +# # def onConnectClick(self, event): +# # return self.EndModal(wx.ID_REVERT) +# +# def __init__(self, parent): +# import wx +# Send2GridDlg.Send2GridDlg.__init__(self, parent) +# #self.GetSizer().Fit(self) +# self.SetMinSize(self.GetSize()) +# #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) +# #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) +# #if wx.__version__ < '4.0': +# # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) +# # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) +# #else: +# # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) +# # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) +# +# Python plugin stuff +class snap_to_grid( pcbnew.ActionPlugin ): + """ + A plugin to Snap modules to selected Grid for kicad_pcb + requirements: KiCAD pcbnew >= 4.0 + + """ + def defaults( self ): + """ + Method defaults must be redefined + self.name should be the menu label to use + self.category should be the category (not yet used) + self.description should be a comprehensive description + of the plugin + """ + self.name = "Snap Selected Module(s) to Grid\nversion "+__version__ + self.category = "Modify PCB" + self.description = "Automaticaly Snap Selected Module(s) to Grid on an existing PCB" + #self.pcbnew_icon_support = hasattr(self, "show_toolbar_button") + self.show_toolbar_button = True + self.icon_file_name = os.path.join(os.path.dirname(__file__), './snap2grid.png') + # + + def Run(self): + #self.pcb = GetBoard() + import sys,os + #mm_ius = 1000000.0 + + pcb = pcbnew.GetBoard() + gridOrigin = pcb.GetGridOrigin() + auxOrigin = pcb.GetAuxOrigin() + content='' + locked_fp='' + #wxPoint(77470000, 135890000) + for module in pcb.GetModules(): + if module.IsSelected(): + if use_grid_origin: + mpx = module.GetPosition().x - gridOrigin.x + mpy = module.GetPosition().y - gridOrigin.y + print(mpx,mpy) + mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.x + mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM)+ gridOrigin.y + print(mpxOnG,mpyOnG) + locked='' + if not module.IsLocked(): + module.SetPosition(wxPoint(mpxOnG,mpyOnG)) + else: + locked='LOCKED' + X_POS=str(module.GetPosition().x) # - gridOrigin.x) + #X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - gridOrigin.x )) + X_POS="{0:<11}".format(X_POS) + Y_POS=str(module.GetPosition().y) # - gridOrigin.y) + Y_POS="{0:<11}".format(Y_POS) + ## mpOnGx = PutOnGridMM(module.GetPosition().x, gridSizeMM) + ## mpOnGy = PutOnGridMM(module.GetPosition().y, gridSizeMM) + ## module.SetPosition(wxPoint(mpOnGx,mpOnGy)) + #module.SetPosition(wxPoint(mpOnGx+FromMM(100.0),mpOnGy+FromMM(2.0))) + #module.SetOrientation(10) + #Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - gridOrigin.y)) + # else: + # mpx = module.GetPosition().x - auxOrigin().x + # mpy = module.GetPosition().y - auxOrigin().y + # X_POS='{0:.4f}'.format(pcbnew.ToMM(module.GetPosition().x - auxOrigin().x )) + # X_POS="{0:<11}".format(X_POS) + # Y_POS='{0:.4f}'.format(-1*pcbnew.ToMM(module.GetPosition().y - auxOrigin().y)) + # Y_POS="{0:<11}".format(Y_POS) + Reference="{0:<10}".format(str(module.GetReference())) + Value = str(module.GetValue()) + Value=(Value[:17] + '..') if len(Value) > 19 else Value + Value="{0:<20}".format(Value) + Rotation='{0:.1f}'.format((module.GetOrientation()/10)) + Rotation="{0:>6}".format(Rotation)+' ' + if module.GetLayer() == 0: + Layer=" top" + else: + Layer=" bottom" + #Side="## Side :"+Layer+lsep + Layer="{0:<10}".format(Layer) + content+=Reference + if 'LOCKED' in locked: + locked_fp+=Reference + ' LOCKED'+'\n' #os.linesep + #content+=Value + content+=X_POS + content+=Y_POS + #content+=str(mpOnGx) + #content+=str(mpOnGy) + content+=str(mpxOnG) + content+=str(mpyOnG) + content+=Layer+'\n' #os.linesep + if len(content)>0: + content+=str(pcbnew.FromMM(gridReference)) + wxLogDebug(content,debug) + if len (locked_fp)>0: + locked_fp+='\n'+'NOT Moved' + wxLogDebug(locked_fp,True) + else: + wxLogDebug('No Modules Selected',True) + Refresh() + #return content + + #if 0: + # #from https://github.com/MitjaNemec/Kicad_action_plugins + # #hack wxFormBuilder py2/py3 + # _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] + # #aParameters = RoundTrackDlg(None) + # aParameters = RoundTrack_Dlg(_pcbnew_frame) + # #aParameters = RoundTrack_DlgEx(_pcbnew_frame) + # aParameters.Show() + # #end hack + # aParameters.m_distanceMM.SetValue("5") + # aParameters.m_segments.SetValue("16") + # aParameters.m_bitmap1.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "round_track_help.png") ) ) + # modal_result = aParameters.ShowModal() + # segments = self.CheckSegmentsInput( + # aParameters.m_segments.GetValue(), "number of segments") + # distI = FromMM(self.CheckDistanceInput(aParameters.m_distanceMM.GetValue(), "distance from intersection")) + # if segments is not None and distI is not None: + # if modal_result == wx.ID_OK: + # Round_Selection(pcb, distI, segments) + # elif modal_result == wx.ID_DELETE: + # Delete_Segments(pcb) + # #wx.LogMessage('Round Segments on Track Net Deleted') + # elif modal_result == wx.ID_REVERT: + # wxLogDebug('Connecting Tracks',debug) + # Connect_Segments(pcb) + # else: + # None # Cancel + # else: + # None # Invalid input + # aParameters.Destroy() + + + # wxLogDebug('showing Selected Tracks',debug) + # wx.LogMessage('Select Tracks to calculate the Length\nor One Pad to select connected Tracks') +# + From d8f6e40f3a915d7f02c0e9eae3df04762b564f78 Mon Sep 17 00:00:00 2001 From: easyw Date: Mon, 17 Feb 2020 21:48:12 +0100 Subject: [PATCH 08/18] fabrication Pos improved --- .gitignore | 51 ++ FabricationPositions/PositionsDlg.fbp | 495 ++++++++++++++++++ FabricationPositions/PositionsDlg.py | 77 +++ FabricationPositions/fabrication_positions.py | 282 ++++++---- MoveToLayer/move_to_layer.py | 5 + MoveToLayer/move_to_layer.py.bak | 7 +- 6 files changed, 806 insertions(+), 111 deletions(-) create mode 100644 .gitignore create mode 100644 FabricationPositions/PositionsDlg.fbp create mode 100644 FabricationPositions/PositionsDlg.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..06703cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files, back +*.cab +*.msi +*.msm +*.msp +*.bak + +# Windows shortcuts +*.lnk + +# Python executable +*.pyc + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/FabricationPositions/PositionsDlg.fbp b/FabricationPositions/PositionsDlg.fbp new file mode 100644 index 0000000..ebc96d7 --- /dev/null +++ b/FabricationPositions/PositionsDlg.fbp @@ -0,0 +1,495 @@ + + + + + + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + PositionsDlg + 1000 + none + + 0 + PositionsDlg + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + PositionsDlg + + 499,296 + wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Generating Fab Positions + + + + + + + bSizer3 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Generating Modules Fab Positions + 0 + + 0 + + + 0 + + 1 + m_comment + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline2 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + 5 + + 0 + + + bSizer31 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Output DIR + 0 + + 0 + + + 0 + + 1 + m_staticText4 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_textCtrlDir + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + grb + + + + + + + + + 5 + wxALIGN_RIGHT|wxEXPAND + 0 + + + bSizer1 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 0 + + 1 + + 1 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + Apply + + 0 + + 0 + + + 0 + + 1 + m_buttonOK + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + 0 + + + 0 + + 1 + m_buttonCancel + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer4 + wxVERTICAL + none + + + + + + diff --git a/FabricationPositions/PositionsDlg.py b/FabricationPositions/PositionsDlg.py new file mode 100644 index 0000000..ea0ca4a --- /dev/null +++ b/FabricationPositions/PositionsDlg.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version Oct 26 2018) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + +########################################################################### +## Class PositionsDlg +########################################################################### + +class PositionsDlg ( wx.Dialog ): + + def __init__( self, parent ): + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Generating Fab Positions", pos = wx.DefaultPosition, size = wx.Size( 499,296 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) + + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) + + bSizer3 = wx.BoxSizer( wx.VERTICAL ) + + self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Generating Modules Fab Positions", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_comment.Wrap( -1 ) + + bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 ) + + self.m_staticline2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + bSizer3.Add( self.m_staticline2, 0, wx.EXPAND |wx.ALL, 5 ) + + bSizer31 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText4 = wx.StaticText( self, wx.ID_ANY, u"Output DIR", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText4.Wrap( -1 ) + + bSizer31.Add( self.m_staticText4, 0, wx.ALL, 5 ) + + self.m_textCtrlDir = wx.TextCtrl( self, wx.ID_ANY, u"grb", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer31.Add( self.m_textCtrlDir, 0, wx.ALL|wx.EXPAND, 5 ) + + + bSizer3.Add( bSizer31, 0, 0, 5 ) + + bSizer1 = wx.BoxSizer( wx.HORIZONTAL ) + + + bSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + + self.m_buttonOK = wx.Button( self, wx.ID_OK, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 ) + + self.m_buttonOK.SetDefault() + bSizer1.Add( self.m_buttonOK, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 ) + + self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer1.Add( self.m_buttonCancel, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 ) + + + bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 ) + + bSizer4 = wx.BoxSizer( wx.VERTICAL ) + + + bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 ) + + + self.SetSizer( bSizer3 ) + self.Layout() + + self.Centre( wx.BOTH ) + + def __del__( self ): + pass + + diff --git a/FabricationPositions/fabrication_positions.py b/FabricationPositions/fabrication_positions.py index eed38f3..64205d8 100644 --- a/FabricationPositions/fabrication_positions.py +++ b/FabricationPositions/fabrication_positions.py @@ -8,7 +8,12 @@ # main script from https://forum.kicad.info/t/pcba-wants-all-parts-in-the-pos-file-not-just-smd/10045/6 # -___version___="1.2.1" +### plugins errors +#import pcbnew +#pcbnew.GetWizardsBackTrace() + + +___version___="1.2.2" #wx.LogMessage("My message") #mm_ius = 1000000.0 @@ -24,7 +29,7 @@ from wx.lib.embeddedimage import PyEmbeddedImage execfile ("C:/kicad-wb-1602/msys64/home/userC/out3Dm/pack-x86_64/share/kicad/scripting/plugins/getpos.py") """ -def generate_POS(): +def generate_POS(dir): import os mm_ius = 1000000.0 @@ -36,18 +41,27 @@ def generate_POS(): path, fname = os.path.split(dirpath) ext = os.path.splitext(os.path.basename(fileName))[1] name = os.path.splitext(os.path.basename(fileName))[0] - + #wx.LogMessage(dir) #lsep=os.linesep lsep='\n' + if len(dir)>0: + dir = dir.rstrip('\\').rstrip('/') + if not os.path.exists(path+os.sep+dir): + #create dir + os.mkdir(path+os.sep+dir) + dir = dir+os.sep + #wx.LogMessage(dir) + else: + dir = dir+os.sep #LogMsg1=lsep+"reading from:" + lsep + dirpath + lsep + lsep - out_filename_top_SMD=path+os.sep+name+"_POS_top_SMD.txt" - out_filename_bot_SMD=path+os.sep+name+"_POS_bot_SMD.txt" - out_filename_top_THD=path+os.sep+name+"_POS_top_THD.txt" - out_filename_bot_THD=path+os.sep+name+"_POS_bot_THD.txt" - out_filename_top_VIRTUAL=path+os.sep+name+"_POS_top_Virtual.txt" - out_filename_bot_VIRTUAL=path+os.sep+name+"_POS_bot_Virtual.txt" - out_filename_ALL=path+os.sep+name+"_POS_All.txt" + out_filename_top_SMD=path+os.sep+dir+name+"_POS_top_SMD.txt" + out_filename_bot_SMD=path+os.sep+dir+name+"_POS_bot_SMD.txt" + out_filename_top_THD=path+os.sep+dir+name+"_POS_top_THD.txt" + out_filename_bot_THD=path+os.sep+dir+name+"_POS_bot_THD.txt" + out_filename_top_VIRTUAL=path+os.sep+dir+name+"_POS_top_Virtual.txt" + out_filename_bot_VIRTUAL=path+os.sep+dir+name+"_POS_bot_Virtual.txt" + out_filename_ALL=path+os.sep+dir+name+"_POS_All.txt" #out_filename=path+os.sep+name+"_POS.txt" #LogMsg1+="written to:" + lsep + out_filename_top_SMD + lsep #LogMsg1+="written to:" + lsep + out_filename_bot_SMD + lsep @@ -253,19 +267,54 @@ def generate_POS(): LogMsg1+= 'Pcb Height ' +'{0:.3f}'.format( pcb_height ) + 'mm, Pcb Width ' + '{0:.3f}'.format( pcb_width ) + 'mm' +lsep+'[based on Edge bounding box]' +lsep LogMsg1+= lsep #LogMsg1+=lsep+"reading from:" + lsep + dirpath + lsep + lsep - LogMsg1+="written to:" + lsep + out_filename_top_SMD + lsep - LogMsg1+=out_filename_bot_SMD + lsep - LogMsg1+=out_filename_top_THD + lsep - LogMsg1+=out_filename_bot_THD + lsep - LogMsg1+=out_filename_top_VIRTUAL + lsep - LogMsg1+=out_filename_bot_VIRTUAL + lsep - LogMsg1+=out_filename_ALL + lsep - + if 0: + LogMsg1+="written to:" + lsep + out_filename_top_SMD + lsep + LogMsg1+=out_filename_bot_SMD + lsep + LogMsg1+=out_filename_top_THD + lsep + LogMsg1+=out_filename_bot_THD + lsep + LogMsg1+=out_filename_top_VIRTUAL + lsep + LogMsg1+=out_filename_bot_VIRTUAL + lsep + LogMsg1+=out_filename_ALL + lsep + else: + LogMsg1+="written to:" + lsep + path+os.sep+dir + lsep return LogMsg1 #return LogMsg1+LogMsg +# Python plugin stuff +from . import PositionsDlg + +class Positions_Dlg(PositionsDlg.PositionsDlg): + # from https://github.com/MitjaNemec/Kicad_action_plugins + # hack for new wxFormBuilder generating code incompatible with old wxPython + # noinspection PyMethodOverriding + def SetSizeHints(self, sz1, sz2): + if wx.__version__ < '4.0': + self.SetSizeHintsSz(sz1, sz2) + else: + super(Positions_Dlg, self).SetSizeHints(sz1, sz2) + + #def onApplyClick(self, event): + # return self.EndModal(wx.ID_OK) + # + #def onCancelClick(self, event): + # return self.EndModal(wx.ID_CANCEL) + + def __init__(self, parent): + import wx + PositionsDlg.PositionsDlg.__init__(self, parent) + #self.GetSizer().Fit(self) + self.SetMinSize(self.GetSize()) + # self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) + # self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) + # if wx.__version__ < '4.0': + # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + # else: + # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) +# class generatePOS( pcbnew.ActionPlugin ): @@ -296,97 +345,114 @@ class generatePOS( pcbnew.ActionPlugin ): #wx.MessageDialog(self.frame,"ciao") #subprocess.check_call(["C:\pathToYourProgram\yourProgram.exe", "your", "arguments", "comma", "separated"]) #http://stackoverflow.com/questions/1811691/running-an-outside-program-executable-in-python - class displayDialog(wx.Dialog): - """ - The default frame - http://stackoverflow.com/questions/3566603/how-do-i-make-wx-textctrl-multi-line-text-update-smoothly - """ - - #---------------------------------------------------------------------- - #def __init__(self): - # """Constructor""" - # wx.Frame.__init__(self, None, title="Display Frame", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION) - # panel = wx.Panel(self) - def __init__(self, parent): - wx.Dialog.__init__(self, parent, id=-1, title="Generate POS output")# - #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION) - #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION) - #, pos=DefaultPosition, size=DefaultSize, style = wx.DEFAULT_FRAME_STYLE & (~wx.MAXIMIZE_BOX), name="fname") - #, wx.ICON_INFORMATION) #, title="Annular Check", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION) - # - - self.SetIcon(PyEmbeddedImage(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:") - #self.result = wx.StaticText(self.panel, label="") - #self.result.SetForegroundColour('#FF0000') - self.button = wx.Button(self.panel, label="Close") - #self.lblname = wx.StaticText(self.panel, label="Your name:") - #self.editname = wx.TextCtrl(self.panel, size=(140, -1)) - self.editname = wx.TextCtrl(self.panel, size = (600, 500), style = wx.TE_MULTILINE|wx.TE_READONLY) - - - # Set sizer for the frame, so we can change frame size to match widgets - self.windowSizer = wx.BoxSizer() - self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND) - - # Set sizer for the panel content - self.sizer = wx.GridBagSizer(5, 0) - self.sizer.Add(self.title, (0, 0)) - #self.sizer.Add(self.result, (1, 0)) - #self.sizer.Add(self.lblname, (1, 0)) - self.sizer.Add(self.editname, (1, 0)) - self.sizer.Add(self.button, (2, 0), (1, 2), flag=wx.EXPAND) - - # Set simple sizer for a nice border - self.border = wx.BoxSizer() - self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5) - - # Use the sizers - self.panel.SetSizerAndFit(self.border) - self.SetSizerAndFit(self.windowSizer) - #self.result.SetLabel(msg) - # Set event handlers - #self.Show() - self.button.Bind(wx.EVT_BUTTON, self.OnClose) - self.Bind(wx.EVT_CLOSE,self.OnClose) - - def OnClose(self,e): - #wx.LogMessage("c") - e.Skip() - #self.Close() - self.Destroy() - - #def OnButton(self, e): - # self.result.SetLabel(self.editname.GetValue()) - def setMsg(self, t_msg): - self.editname.SetValue(t_msg) - - - - def f_mm(raw): - return repr(raw/mm_ius) - - board = pcbnew.GetBoard() - - #fileName = GetBoard().GetFileName() - fileName = pcbnew.GetBoard().GetFileName() - if len(fileName)==0: - wx.LogMessage("a board needs to be saved/loaded!") + #from https://github.com/MitjaNemec/Kicad_action_plugins + #hack wxFormBuilder py2/py3 + _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] + aParameters = Positions_Dlg(_pcbnew_frame) + aParameters.Show() + modal_result = aParameters.ShowModal() + if modal_result == wx.ID_OK: + DirName = aParameters.m_textCtrlDir.GetValue() + #wx.LogMessage(DirName) + #wx.LogMessage(LayerName+';'+str(LayerIndex)+';'+LayerStdName) + GenPos(DirName) else: - LogMsg='' - # msg="'get_pos.py'"+os.linesep - msg="Generate POS output: version = "+___version___+os.linesep - #msg+="Generate POS output"+os.linesep - #print (msg) - #LogMsg=msg+'\n\n' - - print(msg) - LogMsg+=msg - reply=generate_POS() - LogMsg+=reply - + None # Cancel + +## +###class displayDialog(wx.Dialog): +### """ +### The default frame +### http://stackoverflow.com/questions/3566603/how-do-i-make-wx-textctrl-multi-line-text-update-smoothly +### """ +### +### #---------------------------------------------------------------------- +### #def __init__(self): +### # """Constructor""" +### # wx.Frame.__init__(self, None, title="Display Frame", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION) +### # panel = wx.Panel(self) +### def __init__(self, parent): +### wx.Dialog.__init__(self, parent, id=-1, title="Generate POS output")# +### #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION) +### #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION) +### #, pos=DefaultPosition, size=DefaultSize, style = wx.DEFAULT_FRAME_STYLE & (~wx.MAXIMIZE_BOX), name="fname") +### #, wx.ICON_INFORMATION) #, title="Annular Check", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION) +### # +### +### self.SetIcon(PyEmbeddedImage(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:") +### #self.result = wx.StaticText(self.panel, label="") +### #self.result.SetForegroundColour('#FF0000') +### self.button = wx.Button(self.panel, label="Close") +### #self.lblname = wx.StaticText(self.panel, label="Your name:") +### #self.editname = wx.TextCtrl(self.panel, size=(140, -1)) +### self.editname = wx.TextCtrl(self.panel, size = (600, 500), style = wx.TE_MULTILINE|wx.TE_READONLY) +### +### +### # Set sizer for the frame, so we can change frame size to match widgets +### self.windowSizer = wx.BoxSizer() +### self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND) +### +### # Set sizer for the panel content +### self.sizer = wx.GridBagSizer(5, 0) +### self.sizer.Add(self.title, (0, 0)) +### #self.sizer.Add(self.result, (1, 0)) +### #self.sizer.Add(self.lblname, (1, 0)) +### self.sizer.Add(self.editname, (1, 0)) +### self.sizer.Add(self.button, (2, 0), (1, 2), flag=wx.EXPAND) +### +### # Set simple sizer for a nice border +### self.border = wx.BoxSizer() +### self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5) +### +### # Use the sizers +### self.panel.SetSizerAndFit(self.border) +### self.SetSizerAndFit(self.windowSizer) +### #self.result.SetLabel(msg) +### # Set event handlers +### #self.Show() +### self.button.Bind(wx.EVT_BUTTON, self.OnClose) +### self.Bind(wx.EVT_CLOSE,self.OnClose) +### +### def OnClose(self,e): +### #wx.LogMessage("c") +### e.Skip() +### #self.Close() +### self.Destroy() +### +### #def OnButton(self, e): +### # self.result.SetLabel(self.editname.GetValue()) +### def setMsg(self, t_msg): +### self.editname.SetValue(t_msg) +### + +def GenPos(dir): + def f_mm(raw): + return repr(raw/mm_ius) + + board = pcbnew.GetBoard() + + #fileName = GetBoard().GetFileName() + fileName = pcbnew.GetBoard().GetFileName() + if len(fileName)==0: + wx.MessageBox("a board needs to be saved/loaded!") + else: + LogMsg='' + # msg="'get_pos.py'"+os.linesep + msg="Generate POS output: version = "+___version___+os.linesep + #msg+="Generate POS output"+os.linesep + #print (msg) + #LogMsg=msg+'\n\n' + + #print(msg) + LogMsg+=msg + reply=generate_POS(dir) + LogMsg+=reply + wx.LogMessage(LogMsg) + + if 0: frame = displayDialog(None) #frame = wx.Frame(None) frame.Center() diff --git a/MoveToLayer/move_to_layer.py b/MoveToLayer/move_to_layer.py index 6a1a950..8425071 100644 --- a/MoveToLayer/move_to_layer.py +++ b/MoveToLayer/move_to_layer.py @@ -19,6 +19,11 @@ # # +### plugins errors +#import pcbnew +#pcbnew.GetWizardsBackTrace() + + import wx import pcbnew from pcbnew import * diff --git a/MoveToLayer/move_to_layer.py.bak b/MoveToLayer/move_to_layer.py.bak index bc6b7b1..6a1a950 100644 --- a/MoveToLayer/move_to_layer.py.bak +++ b/MoveToLayer/move_to_layer.py.bak @@ -25,19 +25,20 @@ from pcbnew import * import base64 from wx.lib.embeddedimage import PyEmbeddedImage import os -___version___="1.2.2" +___version___="1.2.3" from . import Move2LayerDlg def MoveToLayer(pcb,layerId): + found_selected=False for drw in pcb.GetDrawings(): if drw.IsSelected(): drw.SetLayer(layerId) found_selected=True if found_selected!=True: - LogMsg="select lines to be moved to new layer\n" + LogMsg="select drawings to be moved to new layer\n" LogMsg+="use GAL for selecting lines" wx.LogMessage(LogMsg) else: @@ -101,7 +102,7 @@ class move_to_draw_layer( pcbnew.ActionPlugin ): of the plugin """ import os - self.name = "Move Selected Drawings to chosen Layer\nversion "+___version___ + 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") From 385d115b330ef7b886d63f486aedebe023039fe6 Mon Sep 17 00:00:00 2001 From: easyw Date: Mon, 17 Feb 2020 22:46:01 +0100 Subject: [PATCH 09/18] py3 fix for pcb2dxf --- PcbToDxf/action_menu_pcb2dxf.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/PcbToDxf/action_menu_pcb2dxf.py b/PcbToDxf/action_menu_pcb2dxf.py index 82e382c..e49b3af 100644 --- a/PcbToDxf/action_menu_pcb2dxf.py +++ b/PcbToDxf/action_menu_pcb2dxf.py @@ -24,13 +24,15 @@ # Created: 14.04.2016 # Copyright (C) 2016, Manfred Moitzi # License: MIT License + +#import pcbnew;pcbnew.GetWizardsBackTrace() from __future__ import unicode_literals dxf_parser="r12writer from ezdxf 0.7.6" __author__ = "mozman " script_name="kicadpcb2dxf" __author_script__="easyw Maurice" -___version___="3.8x" +___version___="3.8.1" from contextlib import contextmanager @@ -199,8 +201,12 @@ def dxf_tag(code, value): ################################################################### ##real python code easyw import sys -reload(sys) -sys.setdefaultencoding('utf8') #to accept utf8 chars +if sys.version_info[0] == 2: #if py2: + reload(sys) + sys.setdefaultencoding('utf8') #to accept utf8 chars +#else: +# import importlib +# importlib.reload(sys) import re, os from math import sqrt, atan2, degrees, sin, cos, radians From 98e916e899a23ca463c1cc11887ca57ad6f0228d Mon Sep 17 00:00:00 2001 From: easyw Date: Mon, 17 Feb 2020 23:19:37 +0100 Subject: [PATCH 10/18] adding pcb2dxf action icon --- PcbToDxf/action_menu_pcb2dxf.py | 2 ++ PcbToDxf/dxf_icon.png | Bin 0 -> 1172 bytes 2 files changed, 2 insertions(+) create mode 100644 PcbToDxf/dxf_icon.png diff --git a/PcbToDxf/action_menu_pcb2dxf.py b/PcbToDxf/action_menu_pcb2dxf.py index e49b3af..6f3ff9e 100644 --- a/PcbToDxf/action_menu_pcb2dxf.py +++ b/PcbToDxf/action_menu_pcb2dxf.py @@ -230,6 +230,8 @@ class pcb2dxf( pcbnew.ActionPlugin ): self.name = "export technical layers of pcb to DXF (saved board)" self.category = "export PCB" self.description = "export technical layers of pcb to DXF (saved board)" + self.show_toolbar_button = True + self.icon_file_name = os.path.join(os.path.dirname(__file__), './dxf_icon.png') def Run( self ): fileName = GetBoard().GetFileName() diff --git a/PcbToDxf/dxf_icon.png b/PcbToDxf/dxf_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..dad579726004fff03ad7386ff27d678d8b831f86 GIT binary patch literal 1172 zcmV;F1Z(?=P)990y@e`ofiCa~LPYpUIn2ch|B1EN+M`cR}Q zjf7COnnKaOh)@%u(p_39Hg%Hr!8GhX6fH@MZ;Ay?k%+}F45Cm>iy#`ZZc=*~{KnEblt4P>T{Nnhc9!gp;}C z1!SWrS_8sxBF%G!f;~rIw`zlpwBPd6EQ*uvI1w@yTmkwui{Ah&ji^}EAvC~J=U8ma zX))N5Qfv`-ma&}&)9w?-cz7z*%;z3yI@t36iDn*}@I zbRxw8giDTJan&%{f4r8_)d0JtBSkbITn6fFlM=;&qcwa~5WrhESRXVPb}CR@om$7^ z`UA|}Nph!%5lWb)&jn)4uTgoVk|}rGijOd8aGa&~jTt8U*P0w4R>5Cl@+^x-2e8R7 zIkr5`1EBjl0TG&ArnWn6dp-lP3jiYQ1^V&=5TBK|Qp>UqHa0dsTnqq!AG>eg7m7||19%b!Ppkq!1@dhmBKv@S z#RABr%gLn60Vv%xQw@WTuiz;Dx5d)|WlA<*kW#7_NEMqTQgwSrXv^di03!VI4*;~h zBUaP24|;ohi~0xwk}2MIjl8djtpeb|m%e{FxMA)STg_a*_|W#L8$Vf_Im)BOn(+AWgOTDlV$r!g zZUulNl}stct1OZU5O#&<`Fbs#=tvP=_7W;3v^W&aC2JuhV*>4^(_A?GD0#1|K0t7N zfWu003KtuuQo?C!PGRIz( z#xwCMP9;+OB*HsDxg8Y&4grT8V!VtY+cKtvmUtCC$rMi`d~E0V0oaiXDmaScHGJsT z*oxweU40=LSHkJ6Vr#sLo)IlE1xTJ=8K+&?BLDgY2hL@}ZiU*!8S m!N-JMIZAWAM0e%?Ab$g&CTIbxB0YHk0000 Date: Mon, 17 Feb 2020 23:22:48 +0100 Subject: [PATCH 11/18] adding version to menu pcb2dxf --- PcbToDxf/action_menu_pcb2dxf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PcbToDxf/action_menu_pcb2dxf.py b/PcbToDxf/action_menu_pcb2dxf.py index 6f3ff9e..16c7c94 100644 --- a/PcbToDxf/action_menu_pcb2dxf.py +++ b/PcbToDxf/action_menu_pcb2dxf.py @@ -227,7 +227,7 @@ class pcb2dxf( pcbnew.ActionPlugin ): self.description should be a comprehensive description of the plugin """ - self.name = "export technical layers of pcb to DXF (saved board)" + self.name = "export technical layers of pcb to DXF \nversion "+___version___ self.category = "export PCB" self.description = "export technical layers of pcb to DXF (saved board)" self.show_toolbar_button = True From 11e2ec6366cddf63fbfcb560cdfb2c417126cf70 Mon Sep 17 00:00:00 2001 From: easyw Date: Tue, 18 Feb 2020 09:56:51 +0100 Subject: [PATCH 12/18] better messaging for pcb2dxf --- PcbToDxf/action_menu_pcb2dxf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PcbToDxf/action_menu_pcb2dxf.py b/PcbToDxf/action_menu_pcb2dxf.py index 16c7c94..84caf88 100644 --- a/PcbToDxf/action_menu_pcb2dxf.py +++ b/PcbToDxf/action_menu_pcb2dxf.py @@ -257,7 +257,7 @@ class pcb2dxf( pcbnew.ActionPlugin ): #found_selected=False #board = pcbnew.GetBoard() - dlg=wx.MessageBox( 'Only SAVED board file will be exported to DXF file', 'Confirm', wx.OK | wx.CANCEL | wx.ICON_INFORMATION ) + dlg=wx.MessageBox( 'Exporting technical layers of pcb to DXF\nOnly SAVED board file will be exported to DXF file\n\nversion '+___version___, 'Confirm', wx.OK | wx.CANCEL | wx.ICON_INFORMATION ) if dlg == wx.OK: if os.path.isfile(out_filename): dlg=wx.MessageBox( 'Overwrite DXF file?', 'Confirm', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION ) From 9621ddd40acf3cc9a40ba8006588612f5d618303 Mon Sep 17 00:00:00 2001 From: easyw Date: Sat, 22 Feb 2020 23:30:04 +0100 Subject: [PATCH 13/18] first new dialogs release --- AnnularChecker/AR-params.fbp | 1016 ---------- .../{AR-params - Copy.fbp => AnnularDlg.fbp} | 1662 ++++++++--------- AnnularChecker/AnnularDlg.py | 93 + .../{outDialog.fbp => AnnularResultDlg.fbp} | 896 ++++----- AnnularChecker/AnnularResultDlg.py | 62 + AnnularChecker/__init__ (copy).py.txt | 2 - AnnularChecker/__init__.pyc | Bin 265 -> 0 bytes AnnularChecker/__init__HTML.py.txt | 2 - AnnularChecker/__init__OLD.py.txt | 56 - AnnularChecker/annular_checker-OLD.py.txt | 609 ------ AnnularChecker/annular_checker-html.py.txt | 455 ----- AnnularChecker/annular_checker.py | 924 ++++----- AnnularChecker/annular_checker_html.py.txt | 455 ----- AnnularChecker/dlg.py.txt | 85 - 14 files changed, 1616 insertions(+), 4701 deletions(-) delete mode 100644 AnnularChecker/AR-params.fbp rename AnnularChecker/{AR-params - Copy.fbp => AnnularDlg.fbp} (62%) create mode 100644 AnnularChecker/AnnularDlg.py rename AnnularChecker/{outDialog.fbp => AnnularResultDlg.fbp} (66%) create mode 100644 AnnularChecker/AnnularResultDlg.py delete mode 100644 AnnularChecker/__init__ (copy).py.txt delete mode 100644 AnnularChecker/__init__.pyc delete mode 100644 AnnularChecker/__init__HTML.py.txt delete mode 100644 AnnularChecker/__init__OLD.py.txt delete mode 100644 AnnularChecker/annular_checker-OLD.py.txt delete mode 100644 AnnularChecker/annular_checker-html.py.txt delete mode 100644 AnnularChecker/annular_checker_html.py.txt delete mode 100644 AnnularChecker/dlg.py.txt diff --git a/AnnularChecker/AR-params.fbp b/AnnularChecker/AR-params.fbp deleted file mode 100644 index 3a9e63a..0000000 --- a/AnnularChecker/AR-params.fbp +++ /dev/null @@ -1,1016 +0,0 @@ - - - - - - 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/AR-params - Copy.fbp b/AnnularChecker/AnnularDlg.fbp similarity index 62% rename from AnnularChecker/AR-params - Copy.fbp rename to AnnularChecker/AnnularDlg.fbp index 715b6c3..4a7af2a 100644 --- a/AnnularChecker/AR-params - Copy.fbp +++ b/AnnularChecker/AnnularDlg.fbp @@ -1,914 +1,748 @@ - - - - - - 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + AnnularDlg + 1000 + none + + 0 + AnnularDlg + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + AnnularDlg + + 380,317 + wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Annular Ring Checker + + + + + + + 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 + Check annular ring + 0 + + 0 + + + 0 + + 1 + m_LabelTitle + 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 + m_staticline8 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + 5 + wxALIGN_CENTER|wxALL + 1 + + 2 + 0 + + gSizer1 + none + 0 + 0 + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + PH Drill margin + 0 + + 0 + + + 0 + + 1 + m_staticTextPHD + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_textCtrlPHD + 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 Vias + 0 + + 0 + + + 0 + + 1 + m_staticTextARV + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_textCtrlARV + 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 Pads + 0 + + 0 + + + 0 + + 1 + m_staticTextARP + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_textCtrlARP + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + 5 + wxALIGN_RIGHT|wxEXPAND + 0 + + + bSizer1 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 0 + + 1 + + 1 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + Apply + + 0 + + 0 + + + 0 + + 1 + m_buttonOK + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + 0 + + + 0 + + 1 + m_buttonCancel + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer4 + wxVERTICAL + none + + + + + + diff --git a/AnnularChecker/AnnularDlg.py b/AnnularChecker/AnnularDlg.py new file mode 100644 index 0000000..966a320 --- /dev/null +++ b/AnnularChecker/AnnularDlg.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version Oct 26 2018) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + +########################################################################### +## Class AnnularDlg +########################################################################### + +class AnnularDlg ( wx.Dialog ): + + def __init__( self, parent ): + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Annular Ring Checker", pos = wx.DefaultPosition, size = wx.Size( 380,317 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) + + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) + + bSizer3 = wx.BoxSizer( wx.VERTICAL ) + + self.m_LabelTitle = wx.StaticText( self, wx.ID_ANY, u"Check annular ring", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_LabelTitle.Wrap( -1 ) + + bSizer3.Add( self.m_LabelTitle, 0, wx.ALL|wx.EXPAND, 5 ) + + self.m_staticline8 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + bSizer3.Add( self.m_staticline8, 0, wx.EXPAND |wx.ALL, 5 ) + + gSizer1 = wx.GridSizer( 0, 2, 0, 0 ) + + self.m_staticTextPHD = wx.StaticText( self, wx.ID_ANY, u"PH Drill margin", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticTextPHD.Wrap( -1 ) + + gSizer1.Add( self.m_staticTextPHD, 1, wx.ALL, 5 ) + + self.m_textCtrlPHD = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + gSizer1.Add( self.m_textCtrlPHD, 0, wx.ALIGN_RIGHT|wx.ALL, 5 ) + + self.m_staticTextARV = wx.StaticText( self, wx.ID_ANY, u"AR Vias", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticTextARV.Wrap( -1 ) + + gSizer1.Add( self.m_staticTextARV, 0, wx.ALL, 5 ) + + self.m_textCtrlARV = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + gSizer1.Add( self.m_textCtrlARV, 0, wx.ALIGN_RIGHT|wx.ALL, 5 ) + + self.m_staticTextARP = wx.StaticText( self, wx.ID_ANY, u"AR Pads", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticTextARP.Wrap( -1 ) + + gSizer1.Add( self.m_staticTextARP, 0, wx.ALL, 5 ) + + self.m_textCtrlARP = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + gSizer1.Add( self.m_textCtrlARP, 0, wx.ALIGN_RIGHT|wx.ALL, 5 ) + + + bSizer3.Add( gSizer1, 1, wx.ALIGN_CENTER|wx.ALL, 5 ) + + bSizer1 = wx.BoxSizer( wx.HORIZONTAL ) + + + bSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + + self.m_buttonOK = wx.Button( self, wx.ID_OK, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 ) + + self.m_buttonOK.SetDefault() + bSizer1.Add( self.m_buttonOK, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 ) + + self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer1.Add( self.m_buttonCancel, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 ) + + + bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 ) + + bSizer4 = wx.BoxSizer( wx.VERTICAL ) + + + bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 ) + + + self.SetSizer( bSizer3 ) + self.Layout() + + self.Centre( wx.BOTH ) + + def __del__( self ): + pass + + diff --git a/AnnularChecker/outDialog.fbp b/AnnularChecker/AnnularResultDlg.fbp similarity index 66% rename from AnnularChecker/outDialog.fbp rename to AnnularChecker/AnnularResultDlg.fbp index 87bc43d..5b31e95 100644 --- a/AnnularChecker/outDialog.fbp +++ b/AnnularChecker/AnnularResultDlg.fbp @@ -1,540 +1,356 @@ - - - - - - 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + AnnularResultDlg + 1000 + none + + 0 + AnnularResultDlg + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + AnnularResultDlg + + 383,521 + wxDEFAULT_DIALOG_STYLE + ; forward_declare + Annular Checker + + + + + + + bSizer1 + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bSizer2 + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + + 0 + + 1 + m_staticTitle + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND | wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + -1,400 + 1 + m_richTextResult + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_READONLY + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + wxVSCROLL|wxHSCROLL|wxNO_BORDER|wxWANTS_CHARS + + + + 5 + wxEXPAND + 1 + + 2 + 0 + + gSizer3 + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + OK + + 0 + + 0 + + + 0 + + 1 + ok_btn + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Copy Text + + 0 + + 0 + + + 0 + + 1 + copy_btn + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + diff --git a/AnnularChecker/AnnularResultDlg.py b/AnnularChecker/AnnularResultDlg.py new file mode 100644 index 0000000..71d10a4 --- /dev/null +++ b/AnnularChecker/AnnularResultDlg.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version Oct 26 2018) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc +import wx.richtext + +########################################################################### +## Class AnnularResultDlg +########################################################################### + +class AnnularResultDlg ( wx.Dialog ): + + def __init__( self, parent ): + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Annular Checker", pos = wx.DefaultPosition, size = wx.Size( 383,521 ), style = wx.DEFAULT_DIALOG_STYLE ) + + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) + + bSizer1 = wx.BoxSizer( wx.VERTICAL ) + + bSizer2 = wx.BoxSizer( wx.VERTICAL ) + + self.m_staticTitle = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticTitle.Wrap( -1 ) + + bSizer2.Add( self.m_staticTitle, 0, wx.ALL, 5 ) + + self.m_richTextResult = wx.richtext.RichTextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_READONLY|wx.VSCROLL|wx.HSCROLL|wx.NO_BORDER|wx.WANTS_CHARS ) + self.m_richTextResult.SetMinSize( wx.Size( -1,400 ) ) + + bSizer2.Add( self.m_richTextResult, 1, wx.EXPAND |wx.ALL, 5 ) + + gSizer3 = wx.GridSizer( 0, 2, 0, 0 ) + + self.ok_btn = wx.Button( self, wx.ID_ANY, u"OK", wx.DefaultPosition, wx.DefaultSize, 0 ) + gSizer3.Add( self.ok_btn, 0, wx.ALL, 5 ) + + self.copy_btn = wx.Button( self, wx.ID_ANY, u"Copy Text", wx.DefaultPosition, wx.DefaultSize, 0 ) + gSizer3.Add( self.copy_btn, 0, wx.ALL, 5 ) + + + bSizer2.Add( gSizer3, 1, wx.EXPAND, 5 ) + + + bSizer1.Add( bSizer2, 1, wx.EXPAND, 5 ) + + + self.SetSizer( bSizer1 ) + self.Layout() + + self.Centre( wx.BOTH ) + + def __del__( self ): + pass + + diff --git a/AnnularChecker/__init__ (copy).py.txt b/AnnularChecker/__init__ (copy).py.txt deleted file mode 100644 index 7caa4ab..0000000 --- a/AnnularChecker/__init__ (copy).py.txt +++ /dev/null @@ -1,2 +0,0 @@ -from .annular_checker import annular_check -annular_check().register() diff --git a/AnnularChecker/__init__.pyc b/AnnularChecker/__init__.pyc deleted file mode 100644 index 1d8da1efc719defb257fd46d70c23bb9dd63888b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmZ9H!3x4K42IL~B7*2Ec-zU{MZ_`Bf)g)NDWxm3ZtF_hfu244kUoPiV5)*(NWPGt zK>ozf(eU!P9|e3P!oI?CQ$&eLpaEzJ90(9e;0ADx0!bOcE{SnV5kwN;M+mNU-*C&s zNs4;&-tgmpUD^UA@B@UEm2zI%Bq%?)Espt|?wz!b_Q;%O#;m#LwCH%NbVX|=cuAeG q%J?vwrmvKCY4-7u2Mf}sj47==V>5GoUtF|Z**9_-JiGAmguDPdEkCpX diff --git a/AnnularChecker/__init__HTML.py.txt b/AnnularChecker/__init__HTML.py.txt deleted file mode 100644 index ba81907..0000000 --- a/AnnularChecker/__init__HTML.py.txt +++ /dev/null @@ -1,2 +0,0 @@ -from .annular_checker_html import annular_check -annular_check().register() diff --git a/AnnularChecker/__init__OLD.py.txt b/AnnularChecker/__init__OLD.py.txt deleted file mode 100644 index bae6b54..0000000 --- a/AnnularChecker/__init__OLD.py.txt +++ /dev/null @@ -1,56 +0,0 @@ -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/annular_checker-OLD.py.txt b/AnnularChecker/annular_checker-OLD.py.txt deleted file mode 100644 index 4375337..0000000 --- a/AnnularChecker/annular_checker-OLD.py.txt +++ /dev/null @@ -1,609 +0,0 @@ -# -*- coding: utf-8 -*- -# -# A script to check for annular ring violations -# both for TH pads and vias -# requirements: KiCAD pcbnew >= 4.0 -# annular.py release "1.5.1" -# -# annular.py checking PCB for Annular Ring in Vias and TH Pads -# (SMD, Connector and NPTH are skipped) -# default Annular Ring >= 0.15 both for TH Pads and Vias -# to change values modify: -# -# AR_SET = 0.150 #minimum annular accepted for pads -# AR_SET_V = 0.150 #minimum annular accepted for vias - -# annular.py - - -___version___="1.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 deleted file mode 100644 index d8fa608..0000000 --- a/AnnularChecker/annular_checker-html.py.txt +++ /dev/null @@ -1,455 +0,0 @@ -# -*- coding: utf-8 -*- -# -# A script to check for annular ring violations -# both for TH pads and vias -# requirements: KiCAD pcbnew >= 4.0 -# annular.py release "1.5.1" -# -# annular.py checking PCB for Annular Ring in Vias and TH Pads -# (SMD, Connector and NPTH are skipped) -# default Annular Ring >= 0.15 both for TH Pads and Vias -# to change values modify: -# -# AR_SET = 0.150 #minimum annular accepted for pads -# AR_SET_V = 0.150 #minimum annular accepted for vias - -# annular.py - - -___version___="1.5.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 index f123959..a5de1e7 100644 --- a/AnnularChecker/annular_checker.py +++ b/AnnularChecker/annular_checker.py @@ -16,9 +16,13 @@ # annular.py -___version___="AC version: 1.6.0" +#### plugins errors +#import pcbnew;pcbnew.GetWizardsBackTrace() + +global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V, found_violations, LogMsg, ___version___ + +___version___="1.6.1" -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) @@ -34,15 +38,112 @@ MIN_AR_SIZE_V = AR_SET_V * mm_ius import sys import wx import wx.richtext -import subprocess +#import subprocess import os import pcbnew from pcbnew import * -import base64 -from wx.lib.embeddedimage import PyEmbeddedImage +# import base64 +# from wx.lib.embeddedimage import PyEmbeddedImage + +from . import AnnularDlg +from . import AnnularResultDlg + sys.path.append(os.path.dirname(__file__)) +debug = False +def wxLogDebug(msg,dbg): + """printing messages only if show is omitted or True""" + if dbg == True: + wx.LogMessage(msg) +# + +class AnnularResult_Dlg(AnnularResultDlg.AnnularResultDlg): + # from https://github.com/MitjaNemec/Kicad_action_plugins + # hack for new wxFormBuilder generating code incompatible with old wxPython + # noinspection PyMethodOverriding + def SetSizeHints(self, sz1, sz2): + if wx.__version__ < '4.0': + self.SetSizeHintsSz(sz1, sz2) + else: + super(AnnularResult_Dlg, self).SetSizeHints(sz1, sz2) + def onOK(self, event): + return self.EndModal(wx.ID_OK) # if modal_result == wx.ID_OK: + + def OnClickCopy(self, event): + self.m_richTextResult.SelectAll() + self.m_richTextResult.Copy() + #global LogMsg + #copy2clip(LogMsg) + self.copy_btn.SetLabel("Text Copied") + + # def onDeleteClick(self, event): + # return self.EndModal(wx.ID_DELETE) + # + # def onConnectClick(self, event): + # return self.EndModal(wx.ID_REVERT) + + def __init__(self, parent): + import wx + AnnularResultDlg.AnnularResultDlg.__init__(self, parent) + #self.GetSizer().Fit(self) + self.SetMinSize(self.GetSize()) + #### ----- connections + # Connect Events + self.Bind(wx.EVT_BUTTON, self.onOK, self.ok_btn) + #self.ok_btn.Bind(wx.EVT_BUTTON, self.EndModal(wx.ID_OK)) + self.Bind(wx.EVT_BUTTON, self.OnClickCopy, self.copy_btn) + self.ok_btn.SetFocus() + # Tooltips + self.copy_btn.SetToolTip( wx.ToolTip(u"Copy Text to Clipboard" )) + self.ok_btn.SetToolTip( wx.ToolTip(u"Exit" )) + + #def onOK(self, event): + # return self.EndModal(wx.ID_OK) # if modal_result == wx.ID_OK: + + #def onConnectClick(self, event): + # return self.EndModal(wx.ID_REVERT) + + #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) + #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) + #if wx.__version__ < '4.0': + # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + #else: + # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + +class Annular_Dlg(AnnularDlg.AnnularDlg): + # from https://github.com/MitjaNemec/Kicad_action_plugins + # hack for new wxFormBuilder generating code incompatible with old wxPython + # noinspection PyMethodOverriding + def SetSizeHints(self, sz1, sz2): + if wx.__version__ < '4.0': + self.SetSizeHintsSz(sz1, sz2) + else: + super(Annular_Dlg, self).SetSizeHints(sz1, sz2) + + # def onDeleteClick(self, event): + # return self.EndModal(wx.ID_DELETE) + # + # def onConnectClick(self, event): + # return self.EndModal(wx.ID_REVERT) + + def __init__(self, parent): + import wx + AnnularDlg.AnnularDlg.__init__(self, parent) + #self.GetSizer().Fit(self) + self.SetMinSize(self.GetSize()) + #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) + #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) + #if wx.__version__ < '4.0': + # self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + # self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + #else: + # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + +# Python plugin stuff class annular_check( pcbnew.ActionPlugin ): """ A script to check for annular ring violations @@ -58,7 +159,7 @@ class annular_check( pcbnew.ActionPlugin ): AR_SET = 0.150 #minimum annular accepted for pads AR_SET_V = 0.150 #minimum annular accepted for vias """ - + global ___version___ def defaults( self ): """ Method defaults must be redefined @@ -67,7 +168,7 @@ class annular_check( pcbnew.ActionPlugin ): self.description should be a comprehensive description of the plugin """ - self.name = "Annular check" + self.name = "Annular check \nversion "+___version___ self.category = "Checking PCB" self.description = "Automaticaly check annular on an existing PCB" #self.pcbnew_icon_support = hasattr(self, "show_toolbar_button") @@ -75,582 +176,271 @@ class annular_check( pcbnew.ActionPlugin ): 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 ): + import sys,os + #mm_ius = 1000000.0 + _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] + #aParameters = RoundTrackDlg(None) + aParameters = Annular_Dlg(_pcbnew_frame) + aParameters.m_LabelTitle.SetLabel("Check annular ring: version: "+___version___) + aParameters.m_textCtrlARP.SetToolTip( wx.ToolTip(u"Annular Ring for Pads (mm)" )) + aParameters.m_staticTextPHD.SetToolTip( wx.ToolTip(u"Annular Ring for Pads (mm)" )) + aParameters.m_textCtrlARV.SetToolTip( wx.ToolTip(u"Annular Ring for Vias (mm)" )) + aParameters.m_staticTextARV.SetToolTip( wx.ToolTip(u"Annular Ring for Vias (mm)" )) + aParameters.m_textCtrlPHD.SetToolTip( wx.ToolTip(u"Drill extra margin (mm)" )) + aParameters.m_staticTextARP.SetToolTip( wx.ToolTip(u"Drill extra margin (mm)" )) + aParameters.m_textCtrlPHD.SetValue('0.1') + aParameters.m_textCtrlARP.SetValue('0.125') + aParameters.m_textCtrlARV.SetValue('0.125') + aParameters.Show() + modal_result = aParameters.ShowModal() + #import pcbnew;pcbnew.GetWizardsBackTrace() + if modal_result == wx.ID_OK: + global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V + phd = float(aParameters.m_textCtrlPHD.GetValue().replace(',','.')) + ar = float(aParameters.m_textCtrlARP.GetValue().replace(',','.')) + arv = float(aParameters.m_textCtrlARV.GetValue().replace(',','.')) + DRL_EXTRA=phd + DRL_EXTRA_ius=DRL_EXTRA * mm_ius - 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 ): + AR_SET = ar #minimum annular accepted for pads + MIN_AR_SIZE = AR_SET * mm_ius - 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!") + AR_SET_V = arv #minimum annular accepted for vias + MIN_AR_SIZE_V = AR_SET_V * mm_ius + #snap2grid(gridSizeMM,use_grid_origin) + calculate_AR() else: - 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: + None # Cancel + + +def annring_size(pad): + # valid for oval pad/drills + annrX=(pad.GetSize()[0] - (pad.GetDrillSize()[0]+DRL_EXTRA_ius))/2 + annrY=(pad.GetSize()[1] - (pad.GetDrillSize()[1]+DRL_EXTRA_ius))/2 + #annr=min(pad.GetSize()) - max(pad.GetDrillSize()) + #if annr < MIN_AR_SIZE: + #print annrX + #print annrY + #print pad.GetSize()[0]/mm_ius + #print pad.GetSize()[0]#/mm_ius + #print pad.GetDrillSize()[0]#/mm_ius + #print DRL_EXTRA_ius + #print pad.GetDrillSize()[0]/mm_ius + #print (pad.GetDrillSize()[0]+DRL_EXTRA_ius)/mm_ius + #print annrX/mm_ius + return min(annrX,annrY) + +def annringNP_size(pad): + # valid for oval pad/drills + annrX=(pad.GetSize()[0] - (pad.GetDrillSize()[0]))/2 + annrY=(pad.GetSize()[1] - (pad.GetDrillSize()[1]))/2 + #annr=min(pad.GetSize()) - max(pad.GetDrillSize()) + #if annr < MIN_AR_SIZE: + #print annrX + #print annrY + #print pad.GetSize()[0]/mm_ius + #print pad.GetSize()[0]#/mm_ius + #print pad.GetDrillSize()[0]#/mm_ius + #print DRL_EXTRA_ius + #print pad.GetDrillSize()[0]/mm_ius + #print (pad.GetDrillSize()[0]+DRL_EXTRA_ius)/mm_ius + #print annrX/mm_ius + #return min(annrX,annrY) + return annrX,annrY + +def vias_annring_size(via): + # calculating via annular + annr=(via.GetWidth() - (via.GetDrillValue()+DRL_EXTRA_ius))/2 + #print via.GetWidth() + #print via.GetDrillValue() + return annr + +def f_mm(raw): + return repr(raw/mm_ius) + + +def calculate_AR(): + global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V + board = pcbnew.GetBoard() + PassC=FailC=0 + PassCV=FailCV=0 + + PassCN=FailCN=0 + PassCVN=FailCVN=0 + + fileName = GetBoard().GetFileName() + if len(fileName)==0: + wx.LogMessage("a board needs to be saved/loaded!") + else: + found_violations=False + _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] + aResult = AnnularResult_Dlg(_pcbnew_frame) + #import pcbnew;pcbnew.GetWizardsBackTrace() + writeTxt= aResult.m_richTextResult.WriteText + rt = aResult.m_richTextResult + rt.BeginItalic() + writeTxt("'action_menu_annular_check.py'\n") + #frame.m_richText1.WriteText("'action_menu_annular_check.py'\n") + LogMsg="" + msg="'action_menu_annular_check.py'\n" + msg+="version = "+___version___ + writeTxt("version = "+___version___) + msg+="\nTesting PCB for Annular Rings\nTH Pads >= "+repr(AR_SET)+" Vias >= "+repr(AR_SET_V)+"\nPHD margin on PTH = "+ repr(DRL_EXTRA) + writeTxt("\nTesting PCB for Annular Rings\nTH Pads >= "+repr(AR_SET)+" Vias >= "+repr(AR_SET_V)+"\nPHD margin on PTH = "+ repr(DRL_EXTRA)) + rt.EndItalic() + writeTxt('\n\n') + #print (msg) + LogMsg+=msg+'\n\n' + + # print "LISTING VIAS:" + for item in board.GetTracks(): + if type(item) is pcbnew.VIA: + pos = item.GetPosition() + drill = item.GetDrillValue() + width = item.GetWidth() + ARv = vias_annring_size(item) + if ARv < MIN_AR_SIZE_V: # print("AR violation at %s." % (pad.GetPosition() / mm_ius )) Raw units, needs fixing - XYpair = item.GetPosition() - msg="AR Via violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1]) + 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 Via violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1])+'\n') + 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' - FailCV = FailCV+1 + FailC = FailC+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 + 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 PTH violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1]) + msg="AR NPTH warning 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') + 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' - 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 + FailCN = FailCN+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() + else: + PassCN = PassCN+1 + + #if FailCV >0: + #writeTxt('\n') + msg = "TH PADS that Pass = "+repr(PassC)+"; Fails = "+repr(FailC) + if FailC >0: + rt.BeginBold() + writeTxt("TH PADS that Pass = "+repr(PassC)+"; ") + if FailC >0: + rt.BeginTextColour('red') + writeTxt("Fails = "+repr(FailC)+'\n') + if FailC >0: + rt.EndTextColour() + rt.EndBold() + print(msg) + LogMsg+=msg+'\n' + + msg="NPTH PADS that Pass = "+repr(PassCN)+"; Fails = "+repr(FailCN) + #writeTxt('\n') + if FailCN >0: + rt.BeginBold() + writeTxt("NPTH PADS that Pass = "+repr(PassCN)+"; ") + if FailCN >0: + rt.BeginTextColour('red') + writeTxt("Fails = "+repr(FailCN)+'\n') + if FailC >0: + rt.EndTextColour() + rt.EndBold() + print(msg) + LogMsg+=msg+'\n' + + pcbName = (os.path.splitext(GetBoard().GetFileName())[0]) #filename no ext + #wx.LogMessage(pcbName)#LogMsg) + ##wx.LogMessage(LogMsg) + FC=r"C:\FreeCAD\bin\freecad.exe" + kSU=r"C:\Cad\Progetti_K\3D-FreeCad-tools\kicad-StepUp-tools.FCMacro" + #subprocess.check_call([FC, kSU, pcbName]) + ##p = subprocess.Popen([FC, kSU, pcbName]) + + #found_violations=False + if (FailC+FailCN+FailCV)>0: + found_violations=True + + if found_violations: + #frame.m_staticTitle = wx.StaticText(frame, label=" Check result: (Violations found)") + aResult.m_staticTitle.SetLabel(" Check result: (Violations found)") + #self.title.SetForegroundColour('#FF0000') + aResult.m_staticTitle.SetBackgroundColour('#FF0000') + font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD) + aResult.m_staticTitle.SetFont(font) + else: + #frame.m_staticTitle = wx.StaticText(frame, label=" Annular Check result: OK") + aResult.m_staticTitle.SetLabel(" Annular Check result: OK") + aResult.m_staticTitle.SetBackgroundColour('#00FF00') + font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD) + aResult.m_staticTitle.SetFont(font) + + + aResult.Show() + modal_result = aResult.ShowModal() + if modal_result == wx.ID_OK: + aResult.Destroy() + if modal_result == wx.ID_OK: + aResult.Destroy() + + # ##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__": diff --git a/AnnularChecker/annular_checker_html.py.txt b/AnnularChecker/annular_checker_html.py.txt deleted file mode 100644 index d8fa608..0000000 --- a/AnnularChecker/annular_checker_html.py.txt +++ /dev/null @@ -1,455 +0,0 @@ -# -*- coding: utf-8 -*- -# -# A script to check for annular ring violations -# both for TH pads and vias -# requirements: KiCAD pcbnew >= 4.0 -# annular.py release "1.5.1" -# -# annular.py checking PCB for Annular Ring in Vias and TH Pads -# (SMD, Connector and NPTH are skipped) -# default Annular Ring >= 0.15 both for TH Pads and Vias -# to change values modify: -# -# AR_SET = 0.150 #minimum annular accepted for pads -# AR_SET_V = 0.150 #minimum annular accepted for vias - -# annular.py - - -___version___="1.5.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/dlg.py.txt b/AnnularChecker/dlg.py.txt deleted file mode 100644 index 0711b2a..0000000 --- a/AnnularChecker/dlg.py.txt +++ /dev/null @@ -1,85 +0,0 @@ -# -*- 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 - - From 007862f3712bf86c15518560c77183788ef76a16 Mon Sep 17 00:00:00 2001 From: easyw Date: Sat, 22 Feb 2020 23:36:01 +0100 Subject: [PATCH 14/18] report list fixed --- AnnularChecker/annular_checker.py | 112 +++++++++++++++--------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/AnnularChecker/annular_checker.py b/AnnularChecker/annular_checker.py index a5de1e7..6c114e3 100644 --- a/AnnularChecker/annular_checker.py +++ b/AnnularChecker/annular_checker.py @@ -367,62 +367,62 @@ def calculate_AR(): else: PassCN = PassCN+1 - #if FailCV >0: - #writeTxt('\n') - msg = "TH PADS that Pass = "+repr(PassC)+"; Fails = "+repr(FailC) - if FailC >0: - rt.BeginBold() - writeTxt("TH PADS that Pass = "+repr(PassC)+"; ") - if FailC >0: - rt.BeginTextColour('red') - writeTxt("Fails = "+repr(FailC)+'\n') - if FailC >0: - rt.EndTextColour() - rt.EndBold() - print(msg) - LogMsg+=msg+'\n' - - msg="NPTH PADS that Pass = "+repr(PassCN)+"; Fails = "+repr(FailCN) - #writeTxt('\n') - if FailCN >0: - rt.BeginBold() - writeTxt("NPTH PADS that Pass = "+repr(PassCN)+"; ") - if FailCN >0: - rt.BeginTextColour('red') - writeTxt("Fails = "+repr(FailCN)+'\n') - if FailC >0: - rt.EndTextColour() - rt.EndBold() - print(msg) - LogMsg+=msg+'\n' - - pcbName = (os.path.splitext(GetBoard().GetFileName())[0]) #filename no ext - #wx.LogMessage(pcbName)#LogMsg) - ##wx.LogMessage(LogMsg) - FC=r"C:\FreeCAD\bin\freecad.exe" - kSU=r"C:\Cad\Progetti_K\3D-FreeCad-tools\kicad-StepUp-tools.FCMacro" - #subprocess.check_call([FC, kSU, pcbName]) - ##p = subprocess.Popen([FC, kSU, pcbName]) - - #found_violations=False - if (FailC+FailCN+FailCV)>0: - found_violations=True - - if found_violations: - #frame.m_staticTitle = wx.StaticText(frame, label=" Check result: (Violations found)") - aResult.m_staticTitle.SetLabel(" Check result: (Violations found)") - #self.title.SetForegroundColour('#FF0000') - aResult.m_staticTitle.SetBackgroundColour('#FF0000') - font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD) - aResult.m_staticTitle.SetFont(font) - else: - #frame.m_staticTitle = wx.StaticText(frame, label=" Annular Check result: OK") - aResult.m_staticTitle.SetLabel(" Annular Check result: OK") - aResult.m_staticTitle.SetBackgroundColour('#00FF00') - font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD) - aResult.m_staticTitle.SetFont(font) - - + #if FailCV >0: + #writeTxt('\n') + msg = "TH PADS that Pass = "+repr(PassC)+"; Fails = "+repr(FailC) + if FailC >0: + rt.BeginBold() + writeTxt("TH PADS that Pass = "+repr(PassC)+"; ") + if FailC >0: + rt.BeginTextColour('red') + writeTxt("Fails = "+repr(FailC)+'\n') + if FailC >0: + rt.EndTextColour() + rt.EndBold() + print(msg) + LogMsg+=msg+'\n' + + msg="NPTH PADS that Pass = "+repr(PassCN)+"; Fails = "+repr(FailCN) + #writeTxt('\n') + if FailCN >0: + rt.BeginBold() + writeTxt("NPTH PADS that Pass = "+repr(PassCN)+"; ") + if FailCN >0: + rt.BeginTextColour('red') + writeTxt("Fails = "+repr(FailCN)+'\n') + if FailC >0: + rt.EndTextColour() + rt.EndBold() + print(msg) + LogMsg+=msg+'\n' + + pcbName = (os.path.splitext(GetBoard().GetFileName())[0]) #filename no ext + #wx.LogMessage(pcbName)#LogMsg) + ##wx.LogMessage(LogMsg) + FC=r"C:\FreeCAD\bin\freecad.exe" + kSU=r"C:\Cad\Progetti_K\3D-FreeCad-tools\kicad-StepUp-tools.FCMacro" + #subprocess.check_call([FC, kSU, pcbName]) + ##p = subprocess.Popen([FC, kSU, pcbName]) + + #found_violations=False + if (FailC+FailCN+FailCV)>0: + found_violations=True + + if found_violations: + #frame.m_staticTitle = wx.StaticText(frame, label=" Check result: (Violations found)") + aResult.m_staticTitle.SetLabel(" Check result: (Violations found)") + #self.title.SetForegroundColour('#FF0000') + aResult.m_staticTitle.SetBackgroundColour('#FF0000') + font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD) + aResult.m_staticTitle.SetFont(font) + else: + #frame.m_staticTitle = wx.StaticText(frame, label=" Annular Check result: OK") + aResult.m_staticTitle.SetLabel(" Annular Check result: OK") + aResult.m_staticTitle.SetBackgroundColour('#00FF00') + font = wx.Font(wx.DEFAULT, wx.DECORATIVE, wx.ITALIC, wx.BOLD) + aResult.m_staticTitle.SetFont(font) + + aResult.Show() modal_result = aResult.ShowModal() if modal_result == wx.ID_OK: From 8d9b3b285ca97f0480c008c2b15ae49b0c79cdb7 Mon Sep 17 00:00:00 2001 From: easyw Date: Sat, 22 Feb 2020 23:47:14 +0100 Subject: [PATCH 15/18] Result Dialog not Modal --- AnnularChecker/annular_checker.py | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/AnnularChecker/annular_checker.py b/AnnularChecker/annular_checker.py index 6c114e3..fad8137 100644 --- a/AnnularChecker/annular_checker.py +++ b/AnnularChecker/annular_checker.py @@ -21,7 +21,7 @@ global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V, found_violations, LogMsg, ___version___ -___version___="1.6.1" +___version___="1.6.2" #wx.LogMessage("My message") mm_ius = 1000000.0 @@ -68,7 +68,8 @@ class AnnularResult_Dlg(AnnularResultDlg.AnnularResultDlg): super(AnnularResult_Dlg, self).SetSizeHints(sz1, sz2) def onOK(self, event): - return self.EndModal(wx.ID_OK) # if modal_result == wx.ID_OK: + self.Destroy() + #return self.EndModal(wx.ID_OK) # if modal_result == wx.ID_OK: def OnClickCopy(self, event): self.m_richTextResult.SelectAll() @@ -424,23 +425,12 @@ def calculate_AR(): aResult.Show() - modal_result = aResult.ShowModal() - if modal_result == wx.ID_OK: - aResult.Destroy() - if modal_result == wx.ID_OK: - aResult.Destroy() + #modal_result = aResult.ShowModal() + #if modal_result == wx.ID_OK: + # aResult.Destroy() + #if modal_result == wx.ID_OK: + # aResult.Destroy() - # ##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__": From 9ca2bea0b4acfb333f1f1eb8d803f8967862ad36 Mon Sep 17 00:00:00 2001 From: easyw Date: Sun, 23 Feb 2020 09:37:46 +0100 Subject: [PATCH 16/18] Annular checker, option to use drill size as finished hole size --- AnnularChecker/AnnularDlg.fbp | 318 +++++++++++++++++------------ AnnularChecker/AnnularDlg.py | 27 ++- AnnularChecker/annular_checker.py | 61 +++--- AnnularChecker/annular_checker.pyc | Bin 14910 -> 0 bytes README.md | 188 ++++++++--------- 5 files changed, 335 insertions(+), 259 deletions(-) delete mode 100644 AnnularChecker/annular_checker.pyc diff --git a/AnnularChecker/AnnularDlg.fbp b/AnnularChecker/AnnularDlg.fbp index 4a7af2a..7d576be 100644 --- a/AnnularChecker/AnnularDlg.fbp +++ b/AnnularChecker/AnnularDlg.fbp @@ -189,131 +189,6 @@ none 0 0 - - 5 - wxALL - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - PH Drill margin - 0 - - 0 - - - 0 - - 1 - m_staticTextPHD - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - - - -1 - - - - 5 - wxALIGN_RIGHT|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - - 0 - - 1 - m_textCtrlPHD - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - - 5 wxALL @@ -346,7 +221,7 @@ 0 0 wxID_ANY - AR Vias + AR Vias (mm) 0 0 @@ -471,7 +346,7 @@ 0 0 wxID_ANY - AR Pads + AR Pads (mm) 0 0 @@ -564,6 +439,195 @@ + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + PH Drill margin (mm) + 0 + + 0 + + + 0 + + 1 + m_staticTextPHD + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_textCtrlPHD + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + use drill size as finished hole size + + 0 + + + 0 + + 1 + m_checkBoxPHD + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + diff --git a/AnnularChecker/AnnularDlg.py b/AnnularChecker/AnnularDlg.py index 966a320..e147ed3 100644 --- a/AnnularChecker/AnnularDlg.py +++ b/AnnularChecker/AnnularDlg.py @@ -33,15 +33,7 @@ class AnnularDlg ( wx.Dialog ): gSizer1 = wx.GridSizer( 0, 2, 0, 0 ) - self.m_staticTextPHD = wx.StaticText( self, wx.ID_ANY, u"PH Drill margin", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_staticTextPHD.Wrap( -1 ) - - gSizer1.Add( self.m_staticTextPHD, 1, wx.ALL, 5 ) - - self.m_textCtrlPHD = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - gSizer1.Add( self.m_textCtrlPHD, 0, wx.ALIGN_RIGHT|wx.ALL, 5 ) - - self.m_staticTextARV = wx.StaticText( self, wx.ID_ANY, u"AR Vias", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticTextARV = wx.StaticText( self, wx.ID_ANY, u"AR Vias (mm)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticTextARV.Wrap( -1 ) gSizer1.Add( self.m_staticTextARV, 0, wx.ALL, 5 ) @@ -49,7 +41,7 @@ class AnnularDlg ( wx.Dialog ): self.m_textCtrlARV = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) gSizer1.Add( self.m_textCtrlARV, 0, wx.ALIGN_RIGHT|wx.ALL, 5 ) - self.m_staticTextARP = wx.StaticText( self, wx.ID_ANY, u"AR Pads", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticTextARP = wx.StaticText( self, wx.ID_ANY, u"AR Pads (mm)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticTextARP.Wrap( -1 ) gSizer1.Add( self.m_staticTextARP, 0, wx.ALL, 5 ) @@ -57,6 +49,21 @@ class AnnularDlg ( wx.Dialog ): self.m_textCtrlARP = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) gSizer1.Add( self.m_textCtrlARP, 0, wx.ALIGN_RIGHT|wx.ALL, 5 ) + self.m_staticTextPHD = wx.StaticText( self, wx.ID_ANY, u"PH Drill margin (mm)", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticTextPHD.Wrap( -1 ) + + self.m_staticTextPHD.Enable( False ) + + gSizer1.Add( self.m_staticTextPHD, 1, wx.ALL, 5 ) + + self.m_textCtrlPHD = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_textCtrlPHD.Enable( False ) + + gSizer1.Add( self.m_textCtrlPHD, 0, wx.ALIGN_RIGHT|wx.ALL, 5 ) + + self.m_checkBoxPHD = wx.CheckBox( self, wx.ID_ANY, u"use drill size as finished hole size", wx.DefaultPosition, wx.DefaultSize, 0 ) + gSizer1.Add( self.m_checkBoxPHD, 0, wx.ALL, 5 ) + bSizer3.Add( gSizer1, 1, wx.ALIGN_CENTER|wx.ALL, 5 ) diff --git a/AnnularChecker/annular_checker.py b/AnnularChecker/annular_checker.py index fad8137..eaf8bf6 100644 --- a/AnnularChecker/annular_checker.py +++ b/AnnularChecker/annular_checker.py @@ -8,20 +8,14 @@ # 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 - +# #### plugins errors #import pcbnew;pcbnew.GetWizardsBackTrace() global mm_ius, DRL_EXTRA, AR_SET, AR_SET_V, DRL_EXTRA_ius, MIN_AR_SIZE, MIN_AR_SIZE_V, found_violations, LogMsg, ___version___ -___version___="1.6.2" +___version___="1.6.3" #wx.LogMessage("My message") mm_ius = 1000000.0 @@ -124,17 +118,15 @@ class Annular_Dlg(AnnularDlg.AnnularDlg): else: super(Annular_Dlg, self).SetSizeHints(sz1, sz2) - # def onDeleteClick(self, event): - # return self.EndModal(wx.ID_DELETE) - # - # def onConnectClick(self, event): - # return self.EndModal(wx.ID_REVERT) - def __init__(self, parent): import wx AnnularDlg.AnnularDlg.__init__(self, parent) #self.GetSizer().Fit(self) self.SetMinSize(self.GetSize()) + #c1.Bind(wx.EVT_CHECKBOX, self.OntextMetric, c1) + #self.m_checkBoxPHD.Bind(wx.EVT_CHECKBOX, self.OnClickCheck, self.m_checkBoxPHD) + self.m_checkBoxPHD.Bind(wx.EVT_CHECKBOX, self.OnClickCheck) + #self.Bind(wx.EVT_CHECKBOX, self.OnClickCheck) #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) #if wx.__version__ < '4.0': @@ -143,6 +135,22 @@ class Annular_Dlg(AnnularDlg.AnnularDlg): #else: # self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) # self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + def OnClickCheck(self, event): + #self.Destroy() + if self.m_checkBoxPHD.IsChecked(): + #self.Destroy() + self.m_staticTextPHD.Enable() + self.m_textCtrlPHD.Enable() + else: + self.m_staticTextPHD.Disable() + self.m_textCtrlPHD.Disable() + + # def onDeleteClick(self, event): + # return self.EndModal(wx.ID_DELETE) + # + # def onConnectClick(self, event): + # return self.EndModal(wx.ID_REVERT) + # Python plugin stuff class annular_check( pcbnew.ActionPlugin ): @@ -150,15 +158,8 @@ 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 + AR_SET minimum annular accepted for pads + AR_SET_V minimum annular accepted for vias """ global ___version___ def defaults( self ): @@ -169,7 +170,7 @@ class annular_check( pcbnew.ActionPlugin ): self.description should be a comprehensive description of the plugin """ - self.name = "Annular check \nversion "+___version___ + self.name = "Annular checker \nversion "+___version___ self.category = "Checking PCB" self.description = "Automaticaly check annular on an existing PCB" #self.pcbnew_icon_support = hasattr(self, "show_toolbar_button") @@ -184,11 +185,12 @@ class annular_check( pcbnew.ActionPlugin ): aParameters = Annular_Dlg(_pcbnew_frame) aParameters.m_LabelTitle.SetLabel("Check annular ring: version: "+___version___) aParameters.m_textCtrlARP.SetToolTip( wx.ToolTip(u"Annular Ring for Pads (mm)" )) - aParameters.m_staticTextPHD.SetToolTip( wx.ToolTip(u"Annular Ring for Pads (mm)" )) + aParameters.m_staticTextPHD.SetToolTip( wx.ToolTip(u"Drill extra margin (mm)" )) aParameters.m_textCtrlARV.SetToolTip( wx.ToolTip(u"Annular Ring for Vias (mm)" )) aParameters.m_staticTextARV.SetToolTip( wx.ToolTip(u"Annular Ring for Vias (mm)" )) aParameters.m_textCtrlPHD.SetToolTip( wx.ToolTip(u"Drill extra margin (mm)" )) aParameters.m_staticTextARP.SetToolTip( wx.ToolTip(u"Drill extra margin (mm)" )) + aParameters.m_checkBoxPHD.SetToolTip( wx.ToolTip(u"use drill size as finished hole size\nadding an extra drill margin" )) aParameters.m_textCtrlPHD.SetValue('0.1') aParameters.m_textCtrlARP.SetValue('0.125') aParameters.m_textCtrlARV.SetValue('0.125') @@ -200,9 +202,12 @@ class annular_check( pcbnew.ActionPlugin ): phd = float(aParameters.m_textCtrlPHD.GetValue().replace(',','.')) ar = float(aParameters.m_textCtrlARP.GetValue().replace(',','.')) arv = float(aParameters.m_textCtrlARV.GetValue().replace(',','.')) - DRL_EXTRA=phd - DRL_EXTRA_ius=DRL_EXTRA * mm_ius - + if aParameters.m_checkBoxPHD.IsChecked(): + DRL_EXTRA=phd + DRL_EXTRA_ius=DRL_EXTRA * mm_ius + else: + DRL_EXTRA=0 + DRL_EXTRA_ius=DRL_EXTRA * mm_ius AR_SET = ar #minimum annular accepted for pads MIN_AR_SIZE = AR_SET * mm_ius diff --git a/AnnularChecker/annular_checker.pyc b/AnnularChecker/annular_checker.pyc deleted file mode 100644 index 55d33563c10b1c1abbb490d45b3b645ede05a70c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14910 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 action plugin tools - -- ### action_menu_annular_check.py -A script to check for annular ring violations -for PTH, NPTH pads and vias - -- ### action_menu_pcb2dxf -A script to export technical layers of kicad PCB to DXF -DXF generated file has single line draw as it should be for mechanical interchange (this option is missing in pcbnew plot) - -- ### action_menu_move_to_layer -A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL) - -- ### action_positions -A script to Generate Position Files for SMD, THD, Virtual, ALL - ---- -## action_menu_annular_check.py -A script to check for annular ring violations -for PTH, NPTH pads and vias - -requirements: KiCAD pcbnew > 4.0 built with KICAD_SCRIPTING_ACTION_MENU option activated -release "1.5.3" - -'action_menu_annular_check.py' checking PCB for Annular Ring in PTH, NPTH and Vias -(SMD, Connector and NPTH are skipped) -default Annular Ring >= 0.15 both for TH Pads and Vias -to change values modify: - - AR_SET = 0.150 #minimum annular accepted for pads - AR_SET_V = 0.150 #minimum annular accepted for vias - DRL_EXTRA = 0.100 #extra drill margin size for production - -Launch the Annular Check script in pcbnew from Tools menu: -![Annular Check](screenshots/annular-checker.gif) - -### todo (annular_check) -- [ ] add colors to output list - ---- -## action_menu_pcb2dxf -**kicadpcb2dxf** -_dxf exporter for mechanical layers of a kicad_pcb board_ -- "Dwgs", "Cmts", "Edge", "Eco1", "Eco2", "F.Fab", "B.Fab", "F.CrtYd", "B.CrtYd" -- the dxf generated has single line draw as it should be for mechanical interchange (this option is missing in pcbnew plot) - -creates DXF file of technical layers of the selected kicad pcb board - -![kicad pcb2dxf](screenshots/export-pcb2dxf.png) - -(this is a part of kicad StepUp tools; please refer to kicad StepUp tools for the full licence) - - kicadpcb2dxf: Copyright (c) 2015 Maurice easyw - dxf_parser="r12writer from ezdxf 0.7.6": Copyright (C) 2016, Manfred Moitzi with MIT License - -done: -- [x] added line, circle, arc primitives -- [x] added footprint support -- [x] fixed negative arc case -- [x] added text support (mirror & alignement not supported) -- [x] added multiline text -- [x] add quote support - -### todo (kicadpcb2dxf) -- [ ] tbd - ---- -## action_menu_move_to_layer -A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL) - -requirements: KiCAD pcbnew > 4.0 built with KICAD_SCRIPTING_ACTION_MENU option activated -release "1.1.0" - - A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL) - How to use: - - move to GAL - - select some draw objects - - call the plugin - - select the new layer - - selected draw objects will be moved to new layer - -Launch the 'Move Selected drawings to chosen Layer' script in pcbnew from Tools menu -![Move Selected drawings to chosen Layer](screenshots/move_to_layer.png) - -- ### action_positions -A script to Generate Position Files for SMD, THD, Virtual, ALL - -The script will generate Fabrication POS files for: - -- SMD -- THD -- VIRTUAL -- ALL +# kicad-action-tools +#### A suite of kicad action plugin tools + +- ### Annular Ring Checker +Check your kicad_pcb for annular ring violations: +PTH Plated Trough Hole, NPTH Non Plated Trough Hole Pads and Vias + +- ### action_menu_pcb2dxf +A script to export technical layers of kicad PCB to DXF +DXF generated file has single line draw as it should be for mechanical interchange (this option is missing in pcbnew plot) + +- ### action_menu_move_to_layer +A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL) + +- ### action_positions +A script to Generate Position Files for SMD, THD, Virtual, ALL + +--- +## action_menu_annular_check.py +A script to check for annular ring violations +for PTH, NPTH pads and vias + +requirements: KiCAD pcbnew > 4.0 built with KICAD_SCRIPTING_ACTION_MENU option activated +release "1.5.3" + +'action_menu_annular_check.py' checking PCB for Annular Ring in PTH, NPTH and Vias +(SMD, Connector and NPTH are skipped) +default Annular Ring >= 0.125 both for TH Pads and Vias +to change values modify: + + AR_SET = 0.150 #minimum annular accepted for pads + AR_SET_V = 0.150 #minimum annular accepted for vias + DRL_EXTRA = 0.100 #extra drill margin size for production + +Launch the Annular Check script in pcbnew from Tools menu: +![Annular Check](screenshots/annular-checker.gif) + +### todo (annular_check) +- [ ] add colors to output list + +--- +## action_menu_pcb2dxf +**kicadpcb2dxf** +_dxf exporter for mechanical layers of a kicad_pcb board_ +- "Dwgs", "Cmts", "Edge", "Eco1", "Eco2", "F.Fab", "B.Fab", "F.CrtYd", "B.CrtYd" +- the dxf generated has single line draw as it should be for mechanical interchange (this option is missing in pcbnew plot) + +creates DXF file of technical layers of the selected kicad pcb board + +![kicad pcb2dxf](screenshots/export-pcb2dxf.png) + +(this is a part of kicad StepUp tools; please refer to kicad StepUp tools for the full licence) + + kicadpcb2dxf: Copyright (c) 2015 Maurice easyw + dxf_parser="r12writer from ezdxf 0.7.6": Copyright (C) 2016, Manfred Moitzi with MIT License + +done: +- [x] added line, circle, arc primitives +- [x] added footprint support +- [x] fixed negative arc case +- [x] added text support (mirror & alignement not supported) +- [x] added multiline text +- [x] add quote support + +### todo (kicadpcb2dxf) +- [ ] tbd + +--- +## action_menu_move_to_layer +A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL) + +requirements: KiCAD pcbnew > 4.0 built with KICAD_SCRIPTING_ACTION_MENU option activated +release "1.1.0" + + A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL) + How to use: + - move to GAL + - select some draw objects + - call the plugin + - select the new layer + - selected draw objects will be moved to new layer + +Launch the 'Move Selected drawings to chosen Layer' script in pcbnew from Tools menu +![Move Selected drawings to chosen Layer](screenshots/move_to_layer.png) + +- ### action_positions +A script to Generate Position Files for SMD, THD, Virtual, ALL + +The script will generate Fabrication POS files for: + +- SMD +- THD +- VIRTUAL +- ALL From 4720c89b416d6c5991d67fcbb8178898b4c35d52 Mon Sep 17 00:00:00 2001 From: easyw Date: Sun, 23 Feb 2020 15:29:08 +0100 Subject: [PATCH 17/18] tiding up the repos --- AnnularChecker/.gitignore | 51 ++ AnnularChecker/AnnularDlg.fbp | 58 ++ AnnularChecker/AnnularDlg.py | 3 + .../__pycache__/__init__.cpython-36.pyc | Bin 209 -> 0 bytes .../annular_checker.cpython-36.pyc | Bin 11995 -> 0 bytes .../annular_checker_html.cpython-36.pyc | Bin 10294 -> 0 bytes AnnularChecker/annular_checker.py | 17 +- FabricationPositions/.gitignore | 51 ++ FabricationPositions/PositionsDlg.fbp | 58 ++ FabricationPositions/PositionsDlg.py | 3 + .../__pycache__/__init__.cpython-36.pyc | Bin 238 -> 0 bytes .../fabrication_positions.cpython-36.pyc | Bin 12389 -> 0 bytes FabricationPositions/fabrication.png | Bin 0 -> 1054 bytes FabricationPositions/fabrication.svg | 100 +++ FabricationPositions/fabrication_positions.py | 128 +--- MoveToLayer/.gitignore | 51 ++ MoveToLayer/Move2LayerDlg.fbp | 663 ++++++++++++++++++ MoveToLayer/Move2LayerDlg.py | 8 +- MoveToLayer/add_polygon.png | Bin 0 -> 919 bytes MoveToLayer/add_polygon.svg | 109 +++ MoveToLayer/move_to_layer.py | 3 + PcbToDxf/.gitignore | 51 ++ Snap2Grid/.gitignore | 51 ++ Snap2Grid/Snap2GridDlg.fbp | 58 ++ Snap2Grid/Snap2GridDlg.py | 3 + Snap2Grid/snap2grid.py | 4 +- 26 files changed, 1327 insertions(+), 143 deletions(-) create mode 100644 AnnularChecker/.gitignore delete mode 100644 AnnularChecker/__pycache__/__init__.cpython-36.pyc delete mode 100644 AnnularChecker/__pycache__/annular_checker.cpython-36.pyc delete mode 100644 AnnularChecker/__pycache__/annular_checker_html.cpython-36.pyc create mode 100644 FabricationPositions/.gitignore delete mode 100644 FabricationPositions/__pycache__/__init__.cpython-36.pyc delete mode 100644 FabricationPositions/__pycache__/fabrication_positions.cpython-36.pyc create mode 100644 FabricationPositions/fabrication.png create mode 100644 FabricationPositions/fabrication.svg create mode 100644 MoveToLayer/.gitignore create mode 100644 MoveToLayer/Move2LayerDlg.fbp create mode 100644 MoveToLayer/add_polygon.png create mode 100644 MoveToLayer/add_polygon.svg create mode 100644 PcbToDxf/.gitignore create mode 100644 Snap2Grid/.gitignore diff --git a/AnnularChecker/.gitignore b/AnnularChecker/.gitignore new file mode 100644 index 0000000..06703cd --- /dev/null +++ b/AnnularChecker/.gitignore @@ -0,0 +1,51 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files, back +*.cab +*.msi +*.msm +*.msp +*.bak + +# Windows shortcuts +*.lnk + +# Python executable +*.pyc + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/AnnularChecker/AnnularDlg.fbp b/AnnularChecker/AnnularDlg.fbp index 7d576be..0b33042 100644 --- a/AnnularChecker/AnnularDlg.fbp +++ b/AnnularChecker/AnnularDlg.fbp @@ -58,6 +58,64 @@ bSizer3 wxVERTICAL none + + 5 + wxALIGN_CENTER_HORIZONTAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_bitmapAR + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + + + 5 wxALL|wxEXPAND diff --git a/AnnularChecker/AnnularDlg.py b/AnnularChecker/AnnularDlg.py index e147ed3..98a071c 100644 --- a/AnnularChecker/AnnularDlg.py +++ b/AnnularChecker/AnnularDlg.py @@ -23,6 +23,9 @@ class AnnularDlg ( wx.Dialog ): bSizer3 = wx.BoxSizer( wx.VERTICAL ) + self.m_bitmapAR = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer3.Add( self.m_bitmapAR, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) + self.m_LabelTitle = wx.StaticText( self, wx.ID_ANY, u"Check annular ring", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_LabelTitle.Wrap( -1 ) diff --git a/AnnularChecker/__pycache__/__init__.cpython-36.pyc b/AnnularChecker/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index b16f157ff1b62e9521e6ce40031722dff70cec48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 209 zcmXr!<>jh)*c7%UcJAiCC{nT|SwFVMrtI<98r%ApEPHomr}-yQq9}=^{upnV7OO=y#XmKh z`eCTu1vG~oGKfzBcCpAImmt9&l1qTxf<5OH&-(q|m0x`IecPoV{HxIMa{~VYPt73;0uwR<6J?RvWSef& z#Q{OKGrR229UON8cj+#UyP1PIi=K>!r(KyYo_ejcJJZeIeHkB5{TV+}SJ9sq_tVfL+0o+N!bg`v=DzZP-BRus0)qmzsf?kmhxBgt zQT8f>mqOvur63CIcIIQ|ObO$CjoVTvaH426wNic^n4Vaen99?P{piaHDgTon)9-J- z$8!YXZ@>376(z<+L;Mt=cjG)#+E*A;Sga)Hl^m6}el{Rq;Hd=w6d@yGzHLm**qM#l zzZ5bK8W~b2bAb=H;g`$hdQsN0xkDv)B>xLm$Q!^<3e<9%TGa!3CBTaU2Nf+~5eGE2 zoDZC+m7=U;05x7?zoH*1Vt!)!Auqm3!#N{fHbOz(w`7hckfcnt9N4D* zi4ich0j78ZPg85*=YdeATvl>A9~BEEHb5b3N}zV6R;vmd=afu2kn2S~aIIOeJ2f#q zALtw~waxpX4tZ5RZ*n=W1Wx2)U8x016{a4XzvhJ;@M%tFQ;~GQY;g)Xk4kD;E!9iy zsg`p&rK&5850B>cM&0c8RqgjzrnTUeb68~lqtuQkgr_zKz{IAI6_^cBWOhIsa{$_P zN5NTeap=}Pmm+gs5>1yWM2-J#^R%YuhZPpE<_&|c*Yv=?g2hCZT2@$_vZfRdCdzUN zGk#d97a39Mhe`kfQV$g6eWggESFb78Yvg2I$yc=V8@1ZmPs&XFdh)PRQYK4seRARmjI*pc3DmCg+8nALH<5~9tL?E184u%bQk(Bg|P7bf4msh2b#l|B4+K*k>{F z7_W;Fq(eyWA{|D0ujwSZi_zw&K5`_ywP~MQlpnF7rmH#1xg8!7fPcjNBbYOAKVrS# zHQzDj!NOg3k8^bA!|SopA#P|<`yL+^jRtv`#errwyE`OYbeBC%FUP!Z#pCLZz&_G@ znqJPueVW5&H{sv_l5pez|0if|)S9C!+6PuoEvi4c#&Mw44$UPWMT_q5+Pn>tiy#X6 z{pL`6<}F^|if8|Uxqm=&|5n88-#_;?$!!oW9_$F^0TJ~e3-=3Sl(Q$4ZM&d5`&sh= zr~lK7Kr>Kycq!ErFRIc(9be2Db1kHM3#gD1bm6LcbYa%z9j!P6COi>DUVUw(rp-p)68 z`sWYfNq#>KkOkhd{*-FznN<%#bWD{w4o zpHE21?1om#k?T)C*iNAfPYO?M0{$IFEf(OfHAP@{MvyG1la2(JWL;g%@s%68Mku(E zXS=lVne(6o5_UlpUSbQ66SHT>dv}vsh1~`8u|C$%+wr5^1;4NdE%g+78ID+pOynr$AtRW(&aj@en_)+5=XNfg3eieR@IbV|Uo#wLb5lk2~no)U#%vcW$)s ztNR?Z`W(Dbqt$0O?{k=qTc7$7Xw%927`@g9wdm|@ z5nO%LwDH*x3ir7^6$%f~7BoDUuQA{cLG=jF=p_!(lomcl?ql+_EUMAMCsy6T!V~?e zj=gM^3|h4CjjWtuPJzAKem7f#$7JP<6rSnNEqs7ezi5{YSna{5A_~51M-z=+%h?TB z-mdxuj!IwuJ2up~)3B+`aO$dFR1ABS9PXOhPz+~HKQAg89jU&io!IbhEQbRnS;KkZ zYo1GCkVdzZY@g)XFLW|9+}mb2z_6{aX52WP9;jNWaks?@Khe?|oF6rxmP+IADC5Un zUN#ig)M60_3|*5gE&^2W_5b0g-3Kcl3dSc4+v%C%3afIlk~cirEKaC8P7Qi@K+%PQgkh9_7#qc_d) zY)6vmSV)Q+T}ztE%uH`er_)m!qcEHsIMC=ux78UDWO_^4D+)}v;n>mSs$rKH1Bk~B z4^<86TG8l^l&bo9N~g$$(N)UoC_s%&UuP3gq&STmKC{?-%M5&zBD-z$bkbzEGySD( zt<7v}C0&u-4Ji>eTtV}A<|$<>N7;S7YYsFs=G zjclj0!L4+9Jz;dMmqSH0ceK80cu_fxgI`*$8txWCEk-N3Iwlp^HpLtadre0N)~GyY z3f_qzPA6=`pUq~iC=@WGE1ZmHBfIIOH15)RAtQ#XikJwd-M!COWIE%{b7ZEKGt%A81F#0au^hD|&1` z$AF_x^xAHTeIg#453up+x7x&smaw*unY0t>;l|Mcgl~Bb`=5H`UHqf4f)4Ffu zI+`}wqkHr&1XR6EyWFjJbKKW-$bQ|=ak9(3q*?i(9SOtDMM`166rUU7#P}`kCD_uU z0EY9RSdn#YhH%ePOQPJGQZ33kMVlo;3K?n3MByrxvMOZH-x$ z9gr345gX6GeT~|is=Z3IzVz@_8V1t2O284_w&u^4(AH2sZqGnr*X5#F!gr(=CuV5&v$9j%aig@X%sbz3;O zx!5p(rkhLdS1yqUz*O8*~2L7LjHX`{XwDK&jZ|H`0#k(no}Qv8!lXn z=dq@P^Eq~d&lY_T>UNItp+*0&lb(+iVK(B!K)s z6lrz8B5TZWM9x&5J6Gcq+5@T?ATUPYA%RB(J|^&(z$XBP8zwo1z^sPjnqUmHwgzIg z+5LsNER%KFa6=1o8VZ$aPYHZVfKHQ!zwLjJW2(KNf(ZhX02z;_<_^i_$@r4MT3(Sh zO;x+ok!&&|h1V1DJ$Rw1P;wovlY7}hx)STz;CeC~NgCZdQX-wohL)vd%IGd-sa0xg zn!6-xYMJ{6^VID)fd%T@)pB`qm^!W?7pd$Of!74SL*TmvJ|jT7$>?q=IMmT3%KjdK zF90knp~Wa;g}^F6%MF>mq0IQaD_BH+zro!Qav$*Lj)v_u9Fe=Gt3mDtIUX&CLmYs^ z(I+;hTdToi{MXg-HAVGX@iw@E{$pa8tdJl!rhbj?uR9#n02(q)nGXo|me4j|A}$oa z%}nvd_;Cj_Gat;%w^&w^e_{ubeelRJZdrlB3o?BozNu}AMmNbA?(3>5u5_H*5vm$p zDO?Zcbg5W09JCR&5^}leeUH`E${_kF4ToYRg6I{!_Qu?=J0$83CRh6%>hTSM?-Lj! zaAjSos}5P@c9vUL|23JBi5qTY9iC|zS-W*tp+e|*Xo3y5I7}p}j=Pvna$V%gw!(u!dv$SvPd8E*Uht<~b^K8==Z+-BGjSI9W1 z)0<fsFQ|E~ zj|%7mhDMk9tpTBTIzm5m(Mz8eAlv5kHU<#>L6GL^+X=c@Zny)o9@yOrXbG^$oe#{7 z!VJ;dxV;^dQn-2s!G>I`Q9Iu61fsH9;1^(pEsP!TA2nz zT@DcMQus#GgPiW0`FBIF-$XS<2}$8M`)c{k0dU+6Pbg_nWcFr5tK=13SF@{c zX2UNywai}71$FHWze#?P(v|8~)y$fRhSubqR!KL;%pe;+5vbu)i`Rjt+wJd4Fy-|! z8*jKDMWa*rHAdQBV(`FRyUzM5Xr`u!YJB#}=|cE|e__IRN|1YJ-PkEn+=M6SYTaH` z%7!;y$*(E38os14gD{9jb)|5*zE)v!ky}X1W&Gi}nKo zVFGl*<%i--SES5L8U(cvveD$+5yFM~c@vc&-7z|$wC`Lb) zIxD5q$ygBaIfSaDWLVom_r~3hlI8VyB%4@IXE)+fIuh1&Vv-JGnwLmDIICe|5NT8> zk4F#s;m-y!+`L9B7~&%^9MKAelB~F(;SEPZ>q#jc+m0ZXn3m$P5JkV@VeSnR?f4V( z08QskZWpyP!p;d?5cm;*;p96%a;Z6>|`7u+vRXCfI>u+6ElIs?}j|{;u8z?GDl5>=PX}7y0wzu-Jnz5T!o2Q65|4_I2%!SxO+RdEIN{ zvAs$zo7MU-ciNv3xU%2Ru>OsO9Jy&$}4tMnrdEuc_tTv#GWJWsraZPriQ?I&>v)Ad=>QcTU;g?8l z9Y(hDz=AP)PlcpCdf91I=65M0xSR;3wl@(;&&Lj=!y}b4rQ&HST5JG`ZEi|ZC=v-i zJ9$=r#oH-PCASZ!wq{O3=lQr`#?6D#wn ztz>XJtR`3{nMg&G$>-*FAod3*_ZO>Zenrw zv>~0$hx1#NS4UcODl{ntkHd-S+|jG@^wLy#el9e#ys(}wMPeb{yPDhGOlMBgp-m+( z9p4rRAg?KiE9n-`LHEpG__<9~`X)4-;$Q-8CtsM@sq7LVQwFLcyKY zC8@Diil6Oo?(7t2qNh{Q75U^ic2wOvT%Reul$WLOabh#K9^XBl4d+tz)pFIlAQei7 z+WBIBT0cmiEv*E%8`^oij_B@G@MwDBSY27!T3+3nI$kem=aI0oP@h|mE+{WgR6VpL zRSsiP^k`}~v=iApsxDS`O3Jn*sr8qOk!WH5B)X8AQKRQUed%mvW98*cKDAfcNL0_) zm%VGbytK8_h#tvU$Oi5qlDWB+x!E=OJhrkEs->6X^>pJ%R*J>6{8C%rj!f^os;qB> z8w=Zo=&PxN*!0}y=5(@gxEe~-l7|P?rAYAjBsg7=S2x3Qb#-Y!q=bXD$(hh%a({An zDUBQQtfmC~3L<>J}Dp>Y$j z@4Z^vibZI{N~x{w_2lY&XfGD~%sc+rbTY_q=B@?z@J)AvthMQLklTPOpYs}bfHK{u zXA`ZkkKwJ=_p4eZ2S3NO+?Pb`+Q$dB3v-zPkQUYb3B~%XSf$U3c__-X@Gcpj#Fm*x zKE39rnm&np(Hs18NUjOFVl_Ot@5Gf+O)+{TEnlaveK+V8CXZ)phEHZJ3o2fwg{Uzv zFQQC%M+CJ$qK^K8${eI!jV@A)LGHkLG`L&S~ja?<9rnP`JrI`50Fb#+y?fDhzIrlKmYLioB#j- diff --git a/AnnularChecker/__pycache__/annular_checker_html.cpython-36.pyc b/AnnularChecker/__pycache__/annular_checker_html.cpython-36.pyc deleted file mode 100644 index 16311f17fdd8aaba43b06433f322216f5547d3bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10294 zcmbVSNpl-XcCNxs5TLk;n<%Lybc7B`6$)$Zx(!bXAw0TKW=Oiv(+$Rb!EHf9yL zz@WzwY=`Ybj};R>chQraF%jeMB|vbI-0m1KD(hwD z%X}|iX1@IL6<-B|{^3VI`N=OfCFwt<8$UPbFY%ZzS(2EPlbEc@%%M3fhb0e7nv*#- zm*o<)8??vr2-?eB%w6{7eB#}c>k)5%=iQs@75P9eAl|`T5N}U8n3Y7nFV}~+w|uYC zpX-+;-B%hY4e9};L;CQgd@0M)vc!C>=WB`e=)uzcOJ{CGA7%a{2mde8!&q)iA1jTs zUKaR9&Q0hOr3WmiPqIFC?;9t2oG3lKlyZ;s$E;s}R8mGH>QjG$zMfLPEu-q!M=qt( zvr9>q*g)x}6vUeStrfoiXQ4iI1BF%=}bl#^j&2a|J7=3vgRrJRdKgSVS`AlqvPwQ99d z)_A^fs27g3f5)u&75r4iEO4W4DOODpRmwq)D;;Kq8`Yw6V${l-Wz?#sXt7_j4h2(o zMX77d1TzDVW-6kZ>&Fd)>lM9fnV%_ZMp%s~^}>EtKUKc?k@9+aR&aF$OxMp9u9tPq z)Rm`Xow=u?`Yw;qjC9!uhlFgkJsKrVg+^7`Ci$cYl-ht&qJ!s|^~k46xK^#|1xt*I zDaj3RXk1s!Bcoo|*_7a9`hnIcTgt6&q3-PT+=6m*z|^;pLjpxpVK=Q>)Rhyh+|W&> zQe(!!`Ddb1B*M(;d?uPz+C9#qCSmWn+T6K$`S8JAX zu3OZyGfiYkA&u$nRf|P=qq(LOYLzpj8$9%rLDEdveNYyT~B6?`kx5?+s!q*t#p@2{;3IoOsNCLkjl@Hx2jbu%wcF>AaAar9YMquu7Qg zYdGajse{3>d@Wr#nV0$ScCjAj$JrObkG#eWVd9@a;$^_{c&Wed*jQoa~y4V1j(Qt|e6-aW#_-n$rN z{TD;6AvR$7N2NECpa-p9D{v`~N^EFU0v#0eu%OX*hi?$A?hAVG?5|ti(!EP5BK`Ci z7sFP63r7aVF>vI2Cv#70xHJeo@8dm$_Xys@c#pQ+#CI{)8nf;nN#Oi>hjW~bv^=db zA$4?A0zJ-x;}{7v8tdf8+j;0qdQ7zSX!Wx3QR$+$>TCH0<$ot1dv+xD!0K)JMf*t_ zMXQ(S+il;;XE}@l$4>;h{4{YfaUN(*lt!WHgB__lEW>`V;6!PRO7^6xV;6j9O6!5( zAGw%pO_s(lC2Qiy@y@}mma{e48QlYn&cVy5Cp(O@hri?Kdc>G|Fgl;0d>x6CkSO!t zv|J?dE62sdi$|@8SP#y34)bqXj|Ao9e(PcDVe8SQLs*=2a&oDw)1%)}r=ZXz2%Q3g z3S3jL{cm<)qvLUeKgJZ%jME$;3Q3BLW~ zSp7XFCbmVV7x$RWajq3F0fE9hj)6omip*DsgFBSAKz@# za=>Oz)&q%3*J3y4fUNbTGY3J?H?8-yH*eQDsdJ0^h;CXrpfKKny3zU9J=SPQYqEm9OTQd1x$>UB5&Y(`Khwqh) zcS;7jJcGAO811wNNq~tourUV&uyk%3Ujl%A`!Co6Q*PT~FxzbzR#~^5^_mGJU^I2x zZCdAL-S}@Xay-(vw1Jxbjg^Q}(Kvw0x1yA`Q?nPH6G$hJ*v$~=vmL3moELcaz~GhU zLGWCHv0iZ?QXoMT(G60RmwT^IwD!%Rg za;<3l@_E2rE1$PL@km}x?%DSuZOFY*GYz_1*scuOVK@?vsauI`J`z_GspWhoyO)UC zfsAfZ^@@Q@h3!QyUZ_<$ffjrC${87jT7G}=b)IRKW_y?0Jhm@XJENxD_H9Sg*?3q@ z7rfPp?SYTPWxx)!Ioi29lICq+yF9;bLkH@qoA*R_ zH`HXr_JkUi1TZ9Y9hXz%!i}NY&4x;Nu}etR5GhV&5i-N?MZ0owT5MT z!nmMu-FAgi*%hQlmD&F2b~Yc{%4SnZyC+o*myN`>(44^hrR za7@Y*oxM{&8hDrTeP}$ERsYa`VTK!u41<9!pLF#aG9oIOeF- zbEniPc)fQ@T`h;^vv6c0&f;%5wO)W^p7EXe$aJKuPT+=N6Qj}tMZPRVn_Hw;m)(W_qpq$T9LV&{dR4RF+VcNm& zhM+8;rn=tscrs6`Ii8F1St<$MD8YjFMs#eZ+WFNYbL%HqV>xI2kl7B6=bRcpxic~R zbM*69c*ONqat7oP@#n%~={$1t#s5E1-BsV6DwfTPBo79no3dup`vy|+rkcZB!@-2zekZt3q+Cwa`X1J?}Ll`R_i3< zJ@B}61BJ)+=ko|jG|EH=^7-S2R&Ljbt;kgf5!T}yL|v;TD4`oUEPy(M_#~5dz0cu` z`kcN2o<-&ssw9t0Kl39b*Qhe*6jw-!O!@9crkc;cV^)}9VtJjnPm$)Yy0>-20hBC4 z44wO|azIDzt=dD&s(&^!1Ls{hs-5T@tM_yo;enZB#Ark?Yv$F$;^N}$D_p)$U$WXu z<7GuV(qEpQy(Dj2fKPu}K}^VaSw^%&l)Y@!ak%I&%}Nb1u=4pWf!zf|Ht^yZB0JDw z4lvSzyevpC_ZvV=EF34IpKd@}PZ!d9TL8BJsJ=gucoVI9z$N0K-(c_O{mA)Cy#TR* zt*8|M81Ftj_we)s{F0CGmj>F9srm?|?LGjdZ}ovIjOc@)u#Zs>LwJS>h*; zlt!r*)EJ&|JQKL&_Xv17QhIRd2Hzw~5f26R2)vIC|+v7*z{77&<6W4@JkF1v{-0OdK7sMl|4S$Da)(IhntC zPwm7BI{_5zz#z(bA5|)%5CJU{)BKt8e7hUx1iWfg*%ab5ZV|s~dY{E&v-mZ~Zgtpg zn_2_Q>?|>T`wmkMIsGJOfRbTK=%5j}302!fQvzC)Qv#Y)76ns3;G;y7yJ_#z$3)S} z;tC~CkN~e}RdURAdU4uuVqEqR&g&4CeUZ~B!nJa(!EINpM#ppqUfKRgG@MGS+4y!8 zkPHwZ9wsP|hzN8=y!;cA5y(dK>%e32L_8U_dyz{=)krFt*t2~)Gc58XITwYYa{d*h zJHQdOQ$9h;JfLI}Np4_eC!YzYQ;9?fu0-9+rfh#j1h2q9$Da~U@2O}i&;x%?O{XZC zr@8YJxx_VrR-7FGq7nBVvHnQ1?L>qgfm|o9S+*N<&3D_cy}Jeu zP$fdYd0LnBxvL$31(a0+%^!ZpD!JM2!zTC=ihRff-!=SBor4B`@Zo_wcm*BvDiUm$ zI?>0Ja7wNbfSA3$j+V&{F~0lP3>h*zv(MBwmMO5;qa>N-A1;qwZVqDkprSq$Oqx#hWXnez&*3a}7 z?!`)u8D%|*bJTX0^{VYp)Qao6X~M6!FX=eqdNRPM>oum8#XZ6f=JWZ^w1DF0WEi?y ziQ82B0@j0$vm7V@5hm-rj?Q5%A?_;T!cVA0gOUUi+m9BIfs2A^`zTbDz!xpsMU-%l zs%3FwzhUY25NwiHv)Ob!ga8df5o$WZ*Qk$)8#ODbL^PjFW%C;eH5-la8Zo%*@RXMA zpuksM!&deI;2Q+Ec?tDXPuhn!T`a`Oz)hkoO3o4*Mn#?ByHcpmEqmu{*d#K>CGZMKN1(Ts_=V|XS*3i#BBE|IiH+U zO`qgEyL)xbKscp+waWE&u2^I(;ZSofu1~`i<>SDt$V;wp^^K_$4!2htaJfs8F2pnXtM? znVn{BVV4R*E6H$XdlON^V*EfoJTj5c@iPeS7RywpDF_J8oPG(~1 zbZni?ynVBnTP^9K>iou5%}8j*dh956v=ZN(O@>%#tGwEX9~;J5CB9eMOc#ySy)|`x zH=WKHi`j5wp{VT`nV5O*FB)g5^GH3S){0A~)wh{=Myoepy{gQfEzR#&nuSy|1yM8n z?VDHC>Z{%3<*iz&6h7aNS6+t>HzRM;<%QjHF;YD=7E}A#z1mVO6yM3_^j&p587XV! zotfC`US&PO77kKLbuJl7&Yl+5R{cwGUk8?&+exn$c2+VACt;)3SbbGTOmXWZytG}7 zSoKsk8!0ZIhU=&2Y-N2ubXu#PFC|oc@u;@)=CD+F^+wy=O)l-8Hr11bNO7z7_K3%3 z!!v5=IFg(z9KEg1Ezd?4UWeyb7E{?uG#yQ>RqOsmwNyFe=S#&o>mYl!yc*hW z^7BLkv9a0E(cI#(vAVjovbHsQoGS72XhdIZyiUay^*1Mm6<$_rhjBG_G`kz#iEbX% zmufo|eOpzH#+#*Rth8_vTg=QGvGb6%e73r=`eweE*{f_M>*uKz|9YXQZml+BM;a!w zsauJ3;q~h4SL@n&e03*mW>*r8Z1YIN(Vx}c@YHs6Zs%<+wGnA9ZkJ+jXAk0YuQxa6 z(#^xQaMDa49@Lkkq2rU#TuEEojA-?><^8Z837IqV;idHc%=qhA{!&KinwJ zv6YQvtgu;$%$bQ<^|YXdS9AJi>~*Mcy4N_Vyq@1!KiDot=H~X^u5ZPov|-iE)^;kr zwh-Qn$A9FX`j}tBM+jIZ4okjDS#f}pA8wzb;!Jd!=cYKnbKcXlX*%w0zuDNY^I8E% zH2*W=ZXvNf`}h~8#n-uEu$7JdX}$B0TL%5(R{P@qPVi~?rz3>gz0BZrcP5WVev4vr zs(@k};{Q^FI}|rA+lTKzh_aiy-KX+mgZ{BeM`r3k6*A{T4-kZ%kL5aQ!{5of*5xk5}I@YuHR^Y#Jv#Sl2m&yl!XuB*tZcwZet aSMPv~5dF`jpGhYuAr5g+^~ng}-}_&9qKG&E diff --git a/AnnularChecker/annular_checker.py b/AnnularChecker/annular_checker.py index eaf8bf6..25254e6 100644 --- a/AnnularChecker/annular_checker.py +++ b/AnnularChecker/annular_checker.py @@ -126,6 +126,8 @@ class Annular_Dlg(AnnularDlg.AnnularDlg): #c1.Bind(wx.EVT_CHECKBOX, self.OntextMetric, c1) #self.m_checkBoxPHD.Bind(wx.EVT_CHECKBOX, self.OnClickCheck, self.m_checkBoxPHD) self.m_checkBoxPHD.Bind(wx.EVT_CHECKBOX, self.OnClickCheck) + self.m_bitmapAR.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./annular.png"))) + #self.Bind(wx.EVT_CHECKBOX, self.OnClickCheck) #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) @@ -452,21 +454,6 @@ 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 diff --git a/FabricationPositions/.gitignore b/FabricationPositions/.gitignore new file mode 100644 index 0000000..06703cd --- /dev/null +++ b/FabricationPositions/.gitignore @@ -0,0 +1,51 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files, back +*.cab +*.msi +*.msm +*.msp +*.bak + +# Windows shortcuts +*.lnk + +# Python executable +*.pyc + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/FabricationPositions/PositionsDlg.fbp b/FabricationPositions/PositionsDlg.fbp index ebc96d7..6eeb1cf 100644 --- a/FabricationPositions/PositionsDlg.fbp +++ b/FabricationPositions/PositionsDlg.fbp @@ -119,6 +119,64 @@ -1 + + 5 + wxALIGN_CENTER_HORIZONTAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_bitmapFab + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + + + 5 wxEXPAND | wxALL diff --git a/FabricationPositions/PositionsDlg.py b/FabricationPositions/PositionsDlg.py index ea0ca4a..36cd0c3 100644 --- a/FabricationPositions/PositionsDlg.py +++ b/FabricationPositions/PositionsDlg.py @@ -28,6 +28,9 @@ class PositionsDlg ( wx.Dialog ): bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 ) + self.m_bitmapFab = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer3.Add( self.m_bitmapFab, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) + self.m_staticline2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer3.Add( self.m_staticline2, 0, wx.EXPAND |wx.ALL, 5 ) diff --git a/FabricationPositions/__pycache__/__init__.cpython-36.pyc b/FabricationPositions/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index d39deea7a07932796b881bbacc7c2d43be543bbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 238 zcmXr!<>j*2xG&a&fq~&M5W@izkmUfx#Zo{bg&~D8has0Sijk2am9d#2i>aA`ks*aC zm_d{IB_mLQCgUyc^whl6qQsKa0RLb=P39=kw8W&M%;dz9%>2Cgg8br45Tm#VWbQ4F zqSW-v;*!*&l?+8JKmjoE%SS&WKQ~oBH?dS-FB_;cCB7i1G(9t~SRc&OO-u$Ep<9xl spHr;whA=$WI0|-M{il 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 + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/FabricationPositions/fabrication_positions.py b/FabricationPositions/fabrication_positions.py index 64205d8..cc901f4 100644 --- a/FabricationPositions/fabrication_positions.py +++ b/FabricationPositions/fabrication_positions.py @@ -62,21 +62,6 @@ def generate_POS(dir): out_filename_top_VIRTUAL=path+os.sep+dir+name+"_POS_top_Virtual.txt" out_filename_bot_VIRTUAL=path+os.sep+dir+name+"_POS_bot_Virtual.txt" out_filename_ALL=path+os.sep+dir+name+"_POS_All.txt" - #out_filename=path+os.sep+name+"_POS.txt" - #LogMsg1+="written to:" + lsep + out_filename_top_SMD + lsep - #LogMsg1+="written to:" + lsep + out_filename_bot_SMD + lsep - #LogMsg1+="written to:" + lsep + out_filename_top_THD + lsep - #LogMsg1+="written to:" + lsep + out_filename_bot_THD + lsep - #LogMsg1+="written to:" + lsep + out_filename_top_VIRTUAL + lsep - #LogMsg1+="written to:" + lsep + out_filename_bot_VIRTUAL + lsep - #LogMsg1+="written to:" + lsep + out_filename_ALL + lsep - # print (LogMsg) - # - # print ("### Module positions - created on %s ###" % datetime.datetime.now().strftime("%Y-%m-%d %H:%M")) - # print ("### Printed by get_pos v1") - # print ("## Unit = mm, Angle = deg.") - # print ("## Side : All") - # print ("# Ref Val Package PosX PosY Rot Side Type") Header_1="### Module positions - created on " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M")+lsep Header_1+="### Printed by pcb_positions plugin"+lsep @@ -306,6 +291,7 @@ class Positions_Dlg(PositionsDlg.PositionsDlg): PositionsDlg.PositionsDlg.__init__(self, parent) #self.GetSizer().Fit(self) self.SetMinSize(self.GetSize()) + self.m_bitmapFab.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./fabrication.png"))) # self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) # self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) # if wx.__version__ < '4.0': @@ -333,7 +319,7 @@ class generatePOS( pcbnew.ActionPlugin ): self.description should be a comprehensive description of the plugin """ - self.name = "Generate Fabrication POS output\nversion "+___version___ + self.name = "Fabrication Position output \nversion "+___version___ self.category = "Fabrication Output" self.description = "Generate POS output for SMD, THD, Virtual\nand Board Statistics" #self.SetIcon(PyEmbeddedImage(getPos_ico_b64_data).GetIcon()) @@ -359,74 +345,6 @@ class generatePOS( pcbnew.ActionPlugin ): else: None # Cancel -## -###class displayDialog(wx.Dialog): -### """ -### The default frame -### http://stackoverflow.com/questions/3566603/how-do-i-make-wx-textctrl-multi-line-text-update-smoothly -### """ -### -### #---------------------------------------------------------------------- -### #def __init__(self): -### # """Constructor""" -### # wx.Frame.__init__(self, None, title="Display Frame", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION) -### # panel = wx.Panel(self) -### def __init__(self, parent): -### wx.Dialog.__init__(self, parent, id=-1, title="Generate POS output")# -### #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION) -### #, style=wx.DEFAULT_DIALOG_STYLE, wx.ICON_INFORMATION) -### #, pos=DefaultPosition, size=DefaultSize, style = wx.DEFAULT_FRAME_STYLE & (~wx.MAXIMIZE_BOX), name="fname") -### #, wx.ICON_INFORMATION) #, title="Annular Check", style=wx.DEFAULT_FRAME_STYLE, wx.ICON_INFORMATION) -### # -### -### self.SetIcon(PyEmbeddedImage(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:") -### #self.result = wx.StaticText(self.panel, label="") -### #self.result.SetForegroundColour('#FF0000') -### self.button = wx.Button(self.panel, label="Close") -### #self.lblname = wx.StaticText(self.panel, label="Your name:") -### #self.editname = wx.TextCtrl(self.panel, size=(140, -1)) -### self.editname = wx.TextCtrl(self.panel, size = (600, 500), style = wx.TE_MULTILINE|wx.TE_READONLY) -### -### -### # Set sizer for the frame, so we can change frame size to match widgets -### self.windowSizer = wx.BoxSizer() -### self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND) -### -### # Set sizer for the panel content -### self.sizer = wx.GridBagSizer(5, 0) -### self.sizer.Add(self.title, (0, 0)) -### #self.sizer.Add(self.result, (1, 0)) -### #self.sizer.Add(self.lblname, (1, 0)) -### self.sizer.Add(self.editname, (1, 0)) -### self.sizer.Add(self.button, (2, 0), (1, 2), flag=wx.EXPAND) -### -### # Set simple sizer for a nice border -### self.border = wx.BoxSizer() -### self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5) -### -### # Use the sizers -### self.panel.SetSizerAndFit(self.border) -### self.SetSizerAndFit(self.windowSizer) -### #self.result.SetLabel(msg) -### # Set event handlers -### #self.Show() -### self.button.Bind(wx.EVT_BUTTON, self.OnClose) -### self.Bind(wx.EVT_CLOSE,self.OnClose) -### -### def OnClose(self,e): -### #wx.LogMessage("c") -### e.Skip() -### #self.Close() -### self.Destroy() -### -### #def OnButton(self, e): -### # self.result.SetLabel(self.editname.GetValue()) -### def setMsg(self, t_msg): -### self.editname.SetValue(t_msg) -### def GenPos(dir): def f_mm(raw): @@ -465,47 +383,5 @@ def GenPos(dir): #generatePOS().register() -# "b64_data" is a variable containing your base64 encoded jpeg -getPos_ico_b64_data =\ -""" -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 -gg== -""" - - - # execfile("round_tracks.py") diff --git a/MoveToLayer/.gitignore b/MoveToLayer/.gitignore new file mode 100644 index 0000000..06703cd --- /dev/null +++ b/MoveToLayer/.gitignore @@ -0,0 +1,51 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files, back +*.cab +*.msi +*.msm +*.msp +*.bak + +# Windows shortcuts +*.lnk + +# Python executable +*.pyc + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/MoveToLayer/Move2LayerDlg.fbp b/MoveToLayer/Move2LayerDlg.fbp new file mode 100644 index 0000000..dafcfc7 --- /dev/null +++ b/MoveToLayer/Move2LayerDlg.fbp @@ -0,0 +1,663 @@ + + + + + + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + Move2LayerDlg + 1000 + none + + 0 + Move2LayerDlg + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + Move2LayerDlg + + 568,263 + wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Move to Layer + + + + + + + bSizer3 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Selected Objects will be Moved to chosen Layer + 0 + + 0 + + + 0 + + 1 + m_comment + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + + 0 + + + bSizer31 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Layer + 0 + + 0 + + + 0 + + 1 + m_staticTextLayer + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + -1,-1 + 0 + -1,-1 + 1 + m_comboBoxLayer + 1 + + + protected + 1 + + Resizable + -1 + 1 + 250,-1 + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + Combo! + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_bitmapLayers + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_bitmapDwgs + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + 5 + wxALIGN_RIGHT|wxEXPAND + 0 + + + bSizer1 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + + 0 + + 1 + m_staticText101 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 0 + + 1 + + 1 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + Apply + + 0 + + 0 + + + 0 + + 1 + m_buttonOK + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + 0 + + + 0 + + 1 + m_buttonCancel + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer4 + wxVERTICAL + none + + + + + + diff --git a/MoveToLayer/Move2LayerDlg.py b/MoveToLayer/Move2LayerDlg.py index 66ed329..ad184af 100644 --- a/MoveToLayer/Move2LayerDlg.py +++ b/MoveToLayer/Move2LayerDlg.py @@ -23,7 +23,7 @@ class Move2LayerDlg ( wx.Dialog ): bSizer3 = wx.BoxSizer( wx.VERTICAL ) - self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Selected Objects will Move to chosen Layer", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Selected Objects will be Moved to chosen Layer", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_comment.Wrap( -1 ) bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 ) @@ -39,6 +39,12 @@ class Move2LayerDlg ( wx.Dialog ): self.m_comboBoxLayer = wx.ComboBox( self, wx.ID_ANY, u"Combo!", wx.DefaultPosition, wx.Size( 250,-1 ), m_comboBoxLayerChoices, 0 ) bSizer31.Add( self.m_comboBoxLayer, 0, wx.ALL|wx.EXPAND, 5 ) + self.m_bitmapLayers = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer31.Add( self.m_bitmapLayers, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + + self.m_bitmapDwgs = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer31.Add( self.m_bitmapDwgs, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + bSizer3.Add( bSizer31, 0, 0, 5 ) diff --git a/MoveToLayer/add_polygon.png b/MoveToLayer/add_polygon.png new file mode 100644 index 0000000000000000000000000000000000000000..a2384a5ab8767f6db0fc48f48b6ea32907e0b53a GIT binary patch literal 919 zcmV;I18Dq-P)$c6sux=0oUF!eivP>7Nw?68 zsW(%0BZ#bJp=pPu;GN!j;f3@{ib%_}bAP}KkqyTNDu~$FfEBT_URaA-Q#(3V(=<)e zHaV{stqe=s6ZA)@%ldBkXsNo-d-DG1c0Nt3WP$Ty-KM~z~Ald?N=9N0Fl~)W73c*LKuKw7V%?}GZitd;!@0f?xMxI8`%Rg-hex|f%i4<9UhZk~Q>DYs~XvJ@+ZmQ7fe)nmti%Kgdw z1e=1tXWUlJf2)%vr2`)*8FhDEyl~q0CN*u-(9p0a5NP?+Lbk006&Cza;M%3K#+S{pXfp#D*)p{Vs=NDuK?qTvK)4S+E#B+a5U? zD@z*>s-p-}lFw8vPz3jj;dUUK(L#@^pBWS86q9C#KHs3JMCuk&F0upR3ec;7-9Qzj zwt{A4v%2j{2ISg^x=qOJ1a<*_;7efDtU6hsHyZV58#~87epvmiNTKkCJxLMOk<-BJ zjmX>i;r9dg)&(Fk4%te;IZHPR+yMy#cfoZFcEmP&o1Mv+>(pyg_21a>g$yWw`XlwR z?){IJzuJhLNe5dlZQ`dNz6HntJwO)_fovD}`xh!|hk5@2UC*S!+6Tqmux-3h7tUtx tjVSC%YPxk6d^g|b<*?93lq0+MhL<>kH7cH+BAEaH002ovPDHLkV1k$Krsx0w literal 0 HcmV?d00001 diff --git a/MoveToLayer/add_polygon.svg b/MoveToLayer/add_polygon.svg new file mode 100644 index 0000000..9ab7fbc --- /dev/null +++ b/MoveToLayer/add_polygon.svg @@ -0,0 +1,109 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/MoveToLayer/move_to_layer.py b/MoveToLayer/move_to_layer.py index 8425071..86b0299 100644 --- a/MoveToLayer/move_to_layer.py +++ b/MoveToLayer/move_to_layer.py @@ -78,6 +78,9 @@ class Move2Layer_Dlg(Move2LayerDlg.Move2LayerDlg): Move2LayerDlg.Move2LayerDlg.__init__(self, parent) #self.GetSizer().Fit(self) self.SetMinSize(self.GetSize()) + + self.m_bitmapLayers.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./add_polygon.png"))) + self.m_bitmapDwgs.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./move2layer.png"))) # self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) # self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) # if wx.__version__ < '4.0': diff --git a/PcbToDxf/.gitignore b/PcbToDxf/.gitignore new file mode 100644 index 0000000..06703cd --- /dev/null +++ b/PcbToDxf/.gitignore @@ -0,0 +1,51 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files, back +*.cab +*.msi +*.msm +*.msp +*.bak + +# Windows shortcuts +*.lnk + +# Python executable +*.pyc + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/Snap2Grid/.gitignore b/Snap2Grid/.gitignore new file mode 100644 index 0000000..06703cd --- /dev/null +++ b/Snap2Grid/.gitignore @@ -0,0 +1,51 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files, back +*.cab +*.msi +*.msm +*.msp +*.bak + +# Windows shortcuts +*.lnk + +# Python executable +*.pyc + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/Snap2Grid/Snap2GridDlg.fbp b/Snap2Grid/Snap2GridDlg.fbp index 6becf11..723beb8 100644 --- a/Snap2Grid/Snap2GridDlg.fbp +++ b/Snap2Grid/Snap2GridDlg.fbp @@ -254,6 +254,64 @@ + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_bitmapS2G + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + + + diff --git a/Snap2Grid/Snap2GridDlg.py b/Snap2Grid/Snap2GridDlg.py index 55c4f1d..a870395 100644 --- a/Snap2Grid/Snap2GridDlg.py +++ b/Snap2Grid/Snap2GridDlg.py @@ -40,6 +40,9 @@ class Snap2GridDlg ( wx.Dialog ): self.m_comboBoxGrid.SetSelection( 0 ) bSizer31.Add( self.m_comboBoxGrid, 0, wx.ALL|wx.EXPAND, 5 ) + self.m_bitmapS2G = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer31.Add( self.m_bitmapS2G, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + bSizer3.Add( bSizer31, 0, 0, 5 ) diff --git a/Snap2Grid/snap2grid.py b/Snap2Grid/snap2grid.py index a8f98f4..2de96bd 100644 --- a/Snap2Grid/snap2grid.py +++ b/Snap2Grid/snap2grid.py @@ -12,7 +12,7 @@ #import pcbnew #pcbnew.GetWizardsBackTrace() -__version__ = '1.0.1' +__version__ = '1.0.2' import sys, os import pcbnew import datetime @@ -57,6 +57,8 @@ class Snap2Grid_Dlg(Snap2GridDlg.Snap2GridDlg): Snap2GridDlg.Snap2GridDlg.__init__(self, parent) #self.GetSizer().Fit(self) self.SetMinSize(self.GetSize()) + self.m_bitmapS2G.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./snap2grid.png"))) + #self.SetIcon(wx.IconFromBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./snap2grid.png")))) #self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) #self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) #if wx.__version__ < '4.0': From 7e2a635ae12d8b8ae2f4682075be4afcecd2a0d2 Mon Sep 17 00:00:00 2001 From: easyw Date: Sun, 23 Feb 2020 18:39:09 +0100 Subject: [PATCH 18/18] better ReadMe file --- FabricationPositions/fabrication_positions.py | 2 +- PcbToDxf/action_menu_pcb2dxf.py | 2 +- README.md | 63 ++++++------------- Snap2Grid/snap2grid.py | 4 +- 4 files changed, 24 insertions(+), 47 deletions(-) diff --git a/FabricationPositions/fabrication_positions.py b/FabricationPositions/fabrication_positions.py index cc901f4..98c1eb3 100644 --- a/FabricationPositions/fabrication_positions.py +++ b/FabricationPositions/fabrication_positions.py @@ -319,7 +319,7 @@ class generatePOS( pcbnew.ActionPlugin ): self.description should be a comprehensive description of the plugin """ - self.name = "Fabrication Position output \nversion "+___version___ + self.name = "Fabrication Footprint Position \nversion "+___version___ self.category = "Fabrication Output" self.description = "Generate POS output for SMD, THD, Virtual\nand Board Statistics" #self.SetIcon(PyEmbeddedImage(getPos_ico_b64_data).GetIcon()) diff --git a/PcbToDxf/action_menu_pcb2dxf.py b/PcbToDxf/action_menu_pcb2dxf.py index 84caf88..035b260 100644 --- a/PcbToDxf/action_menu_pcb2dxf.py +++ b/PcbToDxf/action_menu_pcb2dxf.py @@ -227,7 +227,7 @@ class pcb2dxf( pcbnew.ActionPlugin ): self.description should be a comprehensive description of the plugin """ - self.name = "export technical layers of pcb to DXF \nversion "+___version___ + self.name = "Export pcb technical layers to DXF \nversion "+___version___ self.category = "export PCB" self.description = "export technical layers of pcb to DXF (saved board)" self.show_toolbar_button = True diff --git a/README.md b/README.md index 0047321..0c1181b 100644 --- a/README.md +++ b/README.md @@ -5,41 +5,31 @@ Check your kicad_pcb for annular ring violations: PTH Plated Trough Hole, NPTH Non Plated Trough Hole Pads and Vias -- ### action_menu_pcb2dxf -A script to export technical layers of kicad PCB to DXF -DXF generated file has single line draw as it should be for mechanical interchange (this option is missing in pcbnew plot) - -- ### action_menu_move_to_layer -A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL) +- ### Snap Selected Footprint(s) to Grid +Tool to move the selected footprint module(s) to the Grid. +The Modules can be easily aligned to GridOrigin or to Auxiliary Origin. -- ### action_positions -A script to Generate Position Files for SMD, THD, Virtual, ALL - +- ### Fabrication Footprint Position +Tool for the creation of the necessary files for the production of the printed circuit board. +Generate Position Files for SMD, THD, Virtual and ALL components, referred to Auxiliary Origin. + +- ### Move Selected Drawings to chosen Layer +Tool to Move Selected Drawing(s) to the chosen new Layer. + +- ### Export pcb technical layers to DXF +Tool to export technical layers of kicad PCB to DXF. +The DXF generated file has single line draw and different layers for each pcb technical layer. + --- -## action_menu_annular_check.py -A script to check for annular ring violations -for PTH, NPTH pads and vias - -requirements: KiCAD pcbnew > 4.0 built with KICAD_SCRIPTING_ACTION_MENU option activated -release "1.5.3" - -'action_menu_annular_check.py' checking PCB for Annular Ring in PTH, NPTH and Vias -(SMD, Connector and NPTH are skipped) -default Annular Ring >= 0.125 both for TH Pads and Vias -to change values modify: - - AR_SET = 0.150 #minimum annular accepted for pads - AR_SET_V = 0.150 #minimum annular accepted for vias - DRL_EXTRA = 0.100 #extra drill margin size for production +## Annular Ring Checker +Check your kicad_pcb for annular ring violations: +PTH Plated Trough Hole, NPTH Non Plated Trough Hole Pads and Vias Launch the Annular Check script in pcbnew from Tools menu: ![Annular Check](screenshots/annular-checker.gif) -### todo (annular_check) -- [ ] add colors to output list - --- -## action_menu_pcb2dxf +## Export pcb technical layers to DXF **kicadpcb2dxf** _dxf exporter for mechanical layers of a kicad_pcb board_ - "Dwgs", "Cmts", "Edge", "Eco1", "Eco2", "F.Fab", "B.Fab", "F.CrtYd", "B.CrtYd" @@ -61,13 +51,10 @@ done: - [x] added text support (mirror & alignement not supported) - [x] added multiline text - [x] add quote support - -### todo (kicadpcb2dxf) -- [ ] tbd --- -## action_menu_move_to_layer -A script to Move Selected Drawing(s) to chosen new Layer (available only in GAL) +## Move Selected Drawings to chosen Layer +Tool to Move Selected Drawing(s) to chosen new Layer requirements: KiCAD pcbnew > 4.0 built with KICAD_SCRIPTING_ACTION_MENU option activated release "1.1.0" @@ -82,13 +69,3 @@ release "1.1.0" Launch the 'Move Selected drawings to chosen Layer' script in pcbnew from Tools menu ![Move Selected drawings to chosen Layer](screenshots/move_to_layer.png) - -- ### action_positions -A script to Generate Position Files for SMD, THD, Virtual, ALL - -The script will generate Fabrication POS files for: - -- SMD -- THD -- VIRTUAL -- ALL diff --git a/Snap2Grid/snap2grid.py b/Snap2Grid/snap2grid.py index 2de96bd..9c68e7d 100644 --- a/Snap2Grid/snap2grid.py +++ b/Snap2Grid/snap2grid.py @@ -83,9 +83,9 @@ class snap_to_grid( pcbnew.ActionPlugin ): self.description should be a comprehensive description of the plugin """ - self.name = "Snap Selected Modules to Grid \nversion "+__version__ + self.name = "Snap Selected Footprint(s) to Grid \nversion "+__version__ self.category = "Modify PCB" - self.description = "Automaticaly Snap Selected Module(s) to Grid on an existing PCB" + self.description = "Automaticaly Snap Selected Footprint Module(s) to Grid on an existing PCB" #self.pcbnew_icon_support = hasattr(self, "show_toolbar_button") self.show_toolbar_button = True self.icon_file_name = os.path.join(os.path.dirname(__file__), './snap2grid.png')