Files
kicad-action-tools/Snap2Grid/snap2grid.py

278 lines
12 KiB
Python

# -*- coding: utf-8 -*-
#
# A script to Snap modules to selected Grid for kicad_pcb
# requirements: KiCAD pcbnew >= 4.0
# copyright Maurice easyw
#
#
#import snaptogrid; import importlib; importlib.reload(snaptogrid)
### plugins errors
#import pcbnew;pcbnew.GetWizardsBackTrace()
__version__ = '1.2.2'
import datetime
import os
import sys
import pcbnew
import wx
from pcbnew import *
use_grid_origin = True
gridReference = 0.1 #1.27 #mm pcbnew.FromMM(1.0) #0.1mm
gridSizeMM = gridReference
from . import Snap2GridDlg
sys.path.append(os.path.dirname(__file__))
debug = False
def wxLogDebug(msg,dbg):
"""printing messages only if show is omitted or True"""
if dbg == True:
wx.LogMessage(msg)
#
def find_pcbnew_w():
windows = wx.GetTopLevelWindows()
pcbneww = [w for w in windows if "pcbnew" in w.GetTitle().lower()]
if len(pcbneww) != 1:
return None
return pcbneww[0]
#
class Snap2Grid_Dlg(Snap2GridDlg.Snap2GridDlg):
# from https://github.com/MitjaNemec/Kicad_action_plugins
# hack for new wxFormBuilder generating code incompatible with old wxPython
# noinspection PyMethodOverriding
def SetSizeHints(self, sz1, sz2):
if wx.__version__ < '4.0':
self.SetSizeHintsSz(sz1, sz2)
else:
super(Snap2Grid_Dlg, self).SetSizeHints(sz1, sz2)
# def onDeleteClick(self, event):
# return self.EndModal(wx.ID_DELETE)
#
# def onConnectClick(self, event):
# return self.EndModal(wx.ID_REVERT)
def __init__(self, parent):
import wx
Snap2GridDlg.Snap2GridDlg.__init__(self, parent)
#self.GetSizer().Fit(self)
self.SetMinSize(self.GetSize())
self.m_bitmapS2G.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./snap2grid-help.png")))
#self.SetIcon(wx.IconFromBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), "./snap2grid.png"))))
#self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
#self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick)
#if wx.__version__ < '4.0':
# self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
# self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
#else:
# self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
# self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
# Python plugin stuff
class snap_to_grid( pcbnew.ActionPlugin ):
"""
A plugin to Snap modules to selected Grid for kicad_pcb
requirements: KiCAD pcbnew >= 4.0
"""
def defaults( self ):
"""
Method defaults must be redefined
self.name should be the menu label to use
self.category should be the category (not yet used)
self.description should be a comprehensive description
of the plugin
"""
self.name = "Snap Selected Footprint(s) to Grid \nversion "+__version__
self.category = "Modify PCB"
self.description = "Automaticaly Snap Selected Footprint Module(s) to Grid on an existing PCB"
#self.pcbnew_icon_support = hasattr(self, "show_toolbar_button")
self.show_toolbar_button = True
self.icon_file_name = os.path.join(os.path.dirname(__file__), './snap2grid.png')
#
def Run(self):
#self.pcb = GetBoard()
import os
import sys
#mm_ius = 1000000.0
#_pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
pcbnew_window = find_pcbnew_w()
#aParameters = RoundTrackDlg(None)
aParameters = Snap2Grid_Dlg(pcbnew_window)
gridIndex = aParameters.m_comboBoxGrid.FindString('0.1mm (3.94mils)')
aParameters.m_comboBoxGrid.SetSelection(gridIndex)
#aParameters.m_comboBoxGrid.Append('0.1mm (3.94mils)')
aParameters.m_radioBtnGO.SetValue(True)
aParameters.Show()
modal_result = aParameters.ShowModal()
if modal_result == wx.ID_OK:
grid = aParameters.m_comboBoxGrid.GetStringSelection()
gridSizeMM = float(grid.split('mm')[0])
if aParameters.m_radioBtnGO.GetValue():
use_grid = 'gridorigin'
elif aParameters.m_radioBtnAO.GetValue():
use_grid = 'auxorigin'
else:
use_grid = 'topleft'
snap2grid(gridSizeMM,use_grid)
else:
None # Cancel
##
def snap2grid(gridSizeMM,use_grid):
pcb = pcbnew.GetBoard()
if hasattr(pcb, 'GetAuxOrigin'):
auxOrigin = pcb.GetAuxOrigin()
gridOrigin = pcb.GetGridOrigin()
else:
auxOrigin = pcb.GetDesignSettings().GetAuxOrigin()
gridOrigin = pcb.GetDesignSettings().GetGridOrigin()
if hasattr(pcb,'GetModules'):
footprints = pcb.GetModules()
else:
footprints = pcb.GetFootprints()
content=''
locked_fp=''
#wxPoint(77470000, 135890000)
for module in footprints:
if module.IsSelected():
if 'grid' in use_grid:
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():
if "6.99" in GetBuildVersion():
module.SetPosition(VECTOR2I(mpxOnG,mpyOnG))
else:
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))
elif 'aux' in use_grid: # 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():
if "6.99" in GetBuildVersion():
module.SetPosition(VECTOR2I(mpxOnG,mpyOnG))
else:
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
mpxOnG = int(mpx/FromMM(gridSizeMM))*FromMM(gridSizeMM) #+ auxOrigin.x
mpyOnG = int(mpy/FromMM(gridSizeMM))*FromMM(gridSizeMM) #+ auxOrigin.y
locked=''
if not module.IsLocked():
if "6.99" in GetBuildVersion():
module.SetPosition(VECTOR2I(mpxOnG,mpyOnG))
else:
module.SetPosition(wxPoint(mpxOnG,mpyOnG))
else:
locked='LOCKED'
X_POS=str(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)
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)
if "6.99" in GetBuildVersion():
Rotation='{0:.1f}'.format((module.GetOrientation().AsDegrees()/10))
else:
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 'grid' in use_grid:
content+="Using GridOrigin as Ref"+'\n'
info+="Using GridOrigin as Ref"+'\n'
elif 'aux' in use_grid:
content+="Using AuxOrigin as Ref"+'\n'
info+="Using AuxOrigin as Ref"+'\n'
else:
content+="Using Top Left Origin as Ref"+'\n'
info+="Using Top Left Origin 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')
#