#!/usr/bin/env python # Implementation of the action plugin derived from pcbnew.ActionPlugin import pcbnew import os import sys import re import time import json import math import wx import uuid from collections import OrderedDict from .viafence import * from .viafence_dialogs import * debug = False temporary_fix = True def wxLogDebug(msg,show): """printing messages only if show is omitted or True""" if show: wx.LogMessage(msg) # def getTrackAngleRadians(track): #return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x))) return (math.atan2((track.GetEnd().y - track.GetStart().y), (track.GetEnd().x - track.GetStart().x))) # def distance (p1,p2): return math.hypot(p1.y-p2.y,p1.x-p2.x) class ViaFenceAction(pcbnew.ActionPlugin): # ActionPlugin descriptive information def defaults(self): self.name = "Via Fence Generator\nversion 2.8" self.category = "Modify PCB" self.description = "Add a via fence to nets or tracks on the board" self.icon_file_name = os.path.join(os.path.dirname(__file__), "resources/fencing-vias.png") self.show_toolbar_button = True def dumpJSON(self, file): dict = { 'pathList': self.pathList, 'viaOffset': self.viaOffset, 'viaPitch': self.viaPitch, 'viaPoints': self.viaPoints if hasattr(self, 'viaPoints') else [] } with open(file, 'w') as file: json.dump(dict, file, indent=4, sort_keys=True) # Return an ordered {layerId: layerName} dict of enabled layers def getLayerMap(self): layerMap = [] for i in list(range(pcbnew.PCB_LAYER_ID_COUNT)): if self.boardObj.IsLayerEnabled(i): layerMap += [[i, self.boardObj.GetLayerName(i)]] return OrderedDict(layerMap) # Return an ordered {netCode: netName} dict of nets in the board def getNetMap(self): netMap = OrderedDict(self.boardObj.GetNetsByNetcode()) netMap.pop(0) # TODO: What is Net 0? return netMap # Generates a list of net filter phrases using the local netMap # Currently all nets are included as filter phrases # Additionally, differential Nets get a special filter phrase def createNetFilterSuggestions(self): netFilterList = ['*'] netList = [self.netMap[item].GetNetname() for item in self.netMap] diffMap = {'+': '-', 'P': 'N', '-': '+', 'N': 'P'} regexMap = {'+': '[+-]', '-': '[+-]', 'P': '[PN]', 'N': '[PN]'} invertDiffNet = lambda netName : netName[0:-1] + diffMap[netName[-1]] isDiffNet = lambda netName : True if netName[-1] in diffMap.keys() else False # Translate board nets into a filter list for netName in netList: if isDiffNet(netName) and invertDiffNet(netName) in netList: # If we have a +/- or P/N pair, we insert a regex entry once into the filter list filterText = netName[0:-1] + regexMap[netName[-1]] if (filterText not in netFilterList): netFilterList += [filterText] # Append every net to the filter list netFilterList += [netName] return netFilterList # Generates a RegEx string from a SimpleEx (which is a proprietary invention ;-)) # The SimpleEx only supports [...] with single chars and * used as a wildcard def regExFromSimpleEx(self, simpleEx): # Escape the entire filter string. Unescape and remap specific characters that we want to allow subsTable = {r'\[':'[', r'\]':']', r'\*':'.*'} regEx = re.escape(simpleEx) for subsFrom, subsTo in subsTable.items(): regEx = regEx.replace(subsFrom, subsTo) return regEx def createVias(self, viaPoints, viaDrill, viaSize, netCode): newVias = [] for viaPoint in viaPoints: if not(hasattr(pcbnew,'DRAWSEGMENT')): newVia = pcbnew.PCB_VIA(self.boardObj) else: newVia = pcbnew.VIA(self.boardObj) if hasattr(newVia, 'SetTimeStamp'): ts = 55 newVia.SetTimeStamp(ts) # adding a unique number as timestamp to mark this via as generated by this script self.boardObj.Add(newVia) newVia.SetPosition(pcbnew.wxPoint(viaPoint[0], viaPoint[1])) newVia.SetWidth(viaSize) newVia.SetDrill(viaDrill) if hasattr(pcbnew, 'VIA_THROUGH'): newVia.SetViaType(pcbnew.VIA_THROUGH) else: newVia.SetViaType(pcbnew.VIATYPE_THROUGH) newVia.SetNetCode(netCode) newVias += [newVia] return newVias def onDeleteClick(self, event): return self.mainDlg.EndModal(wx.ID_DELETE) def checkPads(self): ##Check vias collisions with all pads => all pads on all layers #wxPrint("Processing all pads...") if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: self.clearance = 0 #TBF else: self.clearance = self.boardObj.GetDesignSettings().GetDefault().GetClearance() #lboard = self.boardObj.ComputeBoundingBox(False) #origin = lboard.GetPosition() # Create an initial rectangle: all is set to "REASON_NO_SIGNAL" # get a margin to avoid out of range l_clearance = self.clearance + self.viaSize #+ self.size #x_limit = int((lboard.GetWidth() + l_clearance) / l_clearance) + 1 #y_limit = int((lboard.GetHeight() + l_clearance) / l_clearance) + 1 viasToRemove = [] removed = False expansion = 1.6 # extra expansion to fix HitTest for pad in self.boardObj.GetPads(): #wx.LogMessage(str(self.viaPointsSafe)) #wx.LogMessage(str(pad.GetPosition())) #local_offset = max(pad.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2) if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: pad_clr = 0 # FIXME local_offset = max(pad_clr, self.clearance) + (self.viaSize / 2) else: local_offset = max(pad.GetClearance(), self.clearance) + (self.viaSize / 2) max_size = max(pad.GetSize().x, pad.GetSize().y) #start_x = int(floor(((pad.GetPosition().x - (max_size / 2.0 + local_offset)) - origin.x) / l_clearance)) #stop_x = int(ceil(((pad.GetPosition().x + (max_size / 2.0 + local_offset)) - origin.x) / l_clearance)) #start_y = int(floor(((pad.GetPosition().y - (max_size / 2.0 + local_offset)) - origin.y) / l_clearance)) #stop_y = int(ceil(((pad.GetPosition().y + (max_size / 2.0 + local_offset)) - origin.y) / l_clearance)) #for x in range(start_x, stop_x + 1): # for y in range(start_y, stop_y + 1): for viaPos in self.viaPointsSafe: if 1: #try: #if isinstance(rectangle[x][y], ViaObject): #start_rect = wxPoint(origin.x + (l_clearance * x) - local_offset, # origin.y + (l_clearance * y) - local_offset) #start_rect = pcbnew.wxPoint(viaPos[0] + (l_clearance * viaPos[0]) - local_offset, # viaPos[1] + (l_clearance * viaPos[1]) - local_offset) start_rect = pcbnew.wxPoint(viaPos[0] - local_offset*expansion, viaPos[1] - local_offset*expansion) size_rect = pcbnew.wxSize(2 * expansion * local_offset, 2 * expansion * local_offset) wxLogDebug(str(pcbnew.ToMM(start_rect))+'::'+str(pcbnew.ToMM(size_rect)),debug) if pad.HitTest(pcbnew.EDA_RECT(start_rect, size_rect), False): #rectangle[x][y] = self.REASON_PAD wxLogDebug('Hit on Pad: viaPos:'+str(viaPos),debug) #self.viaPointsSafe.pop(i) #self.viaPointsSafe.remove(viaPos) viasToRemove.append(viaPos) removed = True #else: # viaPSafe.append(viaPos) else: #except: wx.LogMessage("exception on Processing all pads...") #i+=1 #self.viaPointSafe = viaPSafe #wx.LogMessage(str(viasToRemove)) newPoints = [p for p in self.viaPointsSafe if p not in viasToRemove] #wx.LogMessage(str(newPoints)) #wx.LogMessage(str(len(newPoints))) self.viaPointsSafe = newPoints return removed def checkTracks(self): ##Check vias collisions with all tracks if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: self.clearance = 0 #TBF else: self.clearance = self.boardObj.GetDesignSettings().GetDefault().GetClearance() #lboard = self.boardObj.ComputeBoundingBox(False) #origin = lboard.GetPosition() # Create an initial rectangle: all is set to "REASON_NO_SIGNAL" # get a margin to avoid out of range l_clearance = self.clearance + self.viaSize #+ self.size #wxLogDebug(str(l_clearance),True) #x_limit = int((lboard.GetWidth() + l_clearance) / l_clearance) + 1 #y_limit = int((lboard.GetHeight() + l_clearance) / l_clearance) + 1 viasToRemove = [] removed = False expansion = 2 # extra expansion to fix HitTest for track in self.boardObj.GetTracks(): #wx.LogMessage(str(self.viaPointsSafe)) #wx.LogMessage(str(pad.GetPosition())) #local_offset = max(pad.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2) if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: trk_clr = 0 # FIXME #trk_clr = track.GetClearance() local_offset = max(trk_clr, self.clearance) + (self.viaSize / 2) else: local_offset = max(track.GetClearance(), self.clearance) + (self.viaSize / 2) #wxLogDebug(str(max_size),True) #max_size = max(pad.GetSize().x, pad.GetSize().y) #start_x = int(floor(((pad.GetPosition().x - (max_size / 2.0 + local_offset)) - origin.x) / l_clearance)) #stop_x = int(ceil(((pad.GetPosition().x + (max_size / 2.0 + local_offset)) - origin.x) / l_clearance)) #start_y = int(floor(((pad.GetPosition().y - (max_size / 2.0 + local_offset)) - origin.y) / l_clearance)) #stop_y = int(ceil(((pad.GetPosition().y + (max_size / 2.0 + local_offset)) - origin.y) / l_clearance)) #for x in range(start_x, stop_x + 1): # for y in range(start_y, stop_y + 1): #wx.LogMessage(str(getTrackAngleRadians(track))) angle = abs(math.degrees(getTrackAngleRadians(track))) if (angle > 15 and angle <75) or (angle > 105 and angle <165) or (angle > 195 and angle <255) or (angle > 285 and angle <345): expansion = 1.4 # extra expansion to fix HitTest #wx.LogMessage(str(angle)+'::'+str(expansion)) else: expansion = 2.0 # extra expansion to fix HitTest #wx.LogMessage(str(angle)+'::'+str(expansion)) for viaPos in self.viaPointsSafe: if 1: #try: #if isinstance(rectangle[x][y], ViaObject): #start_rect = wxPoint(origin.x + (l_clearance * x) - local_offset, # origin.y + (l_clearance * y) - local_offset) #start_rect = pcbnew.wxPoint(viaPos[0] + (l_clearance * viaPos[0]) - local_offset, # viaPos[1] + (l_clearance * viaPos[1]) - local_offset) start_rect = pcbnew.wxPoint(viaPos[0] - local_offset*expansion, viaPos[1] - local_offset*expansion) size_rect = pcbnew.wxSize(2 * expansion * local_offset, 2 * expansion * local_offset) wxLogDebug(str(pcbnew.ToMM(start_rect))+'::'+str(pcbnew.ToMM(size_rect)),debug) #wxLogDebug(str(track.GetNetCode()),True) #wxLogDebug(str(self.viaNetId),True) #wxLogDebug(str(type(track)),True) if (hasattr(pcbnew,'DRAWSEGMENT')): trk_type = pcbnew.TRACK else: trk_type = pcbnew.PCB_TRACK if track.GetNetCode() != self.viaNetId or type(track) != trk_type: #PCB_VIA_T: #wxLogDebug('here',True) #if track.HitTest(pcbnew.EDA_RECT(start_rect, size_rect), False): aContained=False;aAccuracy=0 if track.HitTest(pcbnew.EDA_RECT(start_rect, size_rect), aContained, aAccuracy): #rectangle[x][y] = self.REASON_PAD wxLogDebug('Hit on Track: viaPos:'+str(viaPos),debug) #self.viaPointsSafe.pop(i) #self.viaPointsSafe.remove(viaPos) viasToRemove.append(viaPos) removed = True #else: # viaPSafe.append(viaPos) else: #except: wx.LogMessage("exception on Processing all tracks...") #i+=1 #self.viaPointSafe = viaPSafe #wx.LogMessage(str(viasToRemove)) newPoints = [p for p in self.viaPointsSafe if p not in viasToRemove] #wx.LogMessage(str(newPoints)) #wx.LogMessage(str(len(newPoints))) self.viaPointsSafe = newPoints return removed # ------------------------------------------------------------------------------------ def DoKeyPress(self, event): if event.GetKeyCode() == wx.WXK_RETURN: self.mainDlg.EndModal(wx.ID_OK) else: event.Skip() def selfToMainDialog(self): self.mainDlg.lstLayer.SetItems(list(self.layerMap.values())) #maui self.mainDlg.lstLayer.SetSelection(self.layerId) self.mainDlg.txtNetFilter.SetItems(self.netFilterList) self.mainDlg.txtNetFilter.SetSelection(self.netFilterList.index(self.netFilter)) self.mainDlg.txtViaOffset.SetValue(str(pcbnew.ToMM(self.viaOffset))) self.mainDlg.txtViaPitch.SetValue(str(pcbnew.ToMM(self.viaPitch))) self.mainDlg.txtViaDrill.SetValue(str(pcbnew.ToMM(self.viaDrill))) self.mainDlg.txtViaSize.SetValue(str(pcbnew.ToMM(self.viaSize))) self.mainDlg.txtViaOffset.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress) #self.mainDlg.txtViaOffset.Bind(wx.EVT_TEXT_ENTER, self.mainDlg.EndModal(wx.ID_OK)) self.mainDlg.txtViaPitch.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress) self.mainDlg.txtViaDrill.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress) self.mainDlg.txtViaSize.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress) self.mainDlg.lstViaNet.SetItems([item.GetNetname() for item in self.netMap.values()]) for i, item in enumerate (self.netMap.values()): if self.mainDlg.lstViaNet.GetString(i) in ["GND", "/GND"]: self.mainDlg.lstViaNet.SetSelection(i) break if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: #temporary_fix!!! self.mainDlg.chkNetFilter.Enable (False) self.mainDlg.chkNetFilter.SetValue(self.isNetFilterChecked) self.mainDlg.txtNetFilter.Enable(self.isNetFilterChecked) self.mainDlg.chkLayer.SetValue(self.isLayerChecked) self.mainDlg.lstLayer.Enable(self.isLayerChecked) self.mainDlg.chkIncludeDrawing.SetValue(self.isIncludeDrawingChecked) self.mainDlg.chkIncludeSelection.SetValue(self.isIncludeSelectionChecked) self.mainDlg.chkDebugDump.SetValue(self.isDebugDumpChecked) self.mainDlg.chkRemoveViasWithClearanceViolation.SetValue(self.isRemoveViasWithClearanceViolationChecked) self.mainDlg.chkSameNetZoneViasOnly.SetValue(self.isSameNetZoneViasOnlyChecked) self.mainDlg.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) # hiding unimplemented controls #self.mainDlg.chkRemoveViasWithClearanceViolation.Hide() self.mainDlg.chkSameNetZoneViasOnly.Hide() def mainDialogToSelf(self): self.netFilter = self.mainDlg.txtNetFilter.GetValue() if len(list(self.layerMap.keys())) > 0: self.layerId = list(self.layerMap.keys())[self.mainDlg.lstLayer.GetSelection()] #maui self.viaOffset = pcbnew.FromMM(float(self.mainDlg.txtViaOffset.GetValue().replace(',','.'))) self.viaPitch = pcbnew.FromMM(float(self.mainDlg.txtViaPitch.GetValue().replace(',','.'))) self.viaDrill = pcbnew.FromMM(float(self.mainDlg.txtViaDrill.GetValue().replace(',','.'))) self.viaSize = pcbnew.FromMM(float(self.mainDlg.txtViaSize.GetValue().replace(',','.'))) if len(list(self.netMap.keys())) > 0: self.viaNetId = list(self.netMap.keys())[self.mainDlg.lstViaNet.GetSelection()] #maui self.isNetFilterChecked = self.mainDlg.chkNetFilter.GetValue() self.isLayerChecked = self.mainDlg.chkLayer.GetValue() self.isIncludeDrawingChecked = self.mainDlg.chkIncludeDrawing.GetValue() self.isIncludeSelectionChecked = self.mainDlg.chkIncludeSelection.GetValue() self.isDebugDumpChecked = self.mainDlg.chkDebugDump.GetValue() self.isSameNetZoneViasOnlyChecked = self.mainDlg.chkSameNetZoneViasOnly.GetValue() self.isRemoveViasWithClearanceViolationChecked = self.mainDlg.chkRemoveViasWithClearanceViolation.GetValue() def Run(self): #check for pyclipper lib pyclip = False try: import pyclipper pyclip = True # import pyclipper; pyclipper.__file__ except: #error exception if pyclipper lib is missing import sys, os from sys import platform as _platform if sys.version_info.major == 2 and sys.version_info.minor == 7: if _platform == "linux" or _platform == "linux2": # linux sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'python-pyclipper','py2-7-linux-64')) elif _platform == "darwin": #osx sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'python-pyclipper','py2-7-mac-64')) else: #win sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'python-pyclipper','py2-7-win-64')) try: import pyclipper pyclip = True except: msg = u"\u2718 ERROR Missing KiCAD \'pyclipper\' python module:\nplease install it using pip\nin your KiCAD python environment.\n[You may need administrative rights]" wdlg = wx.MessageDialog(None, msg,'ERROR message',wx.OK | wx.ICON_WARNING)# wx.ICON_ERROR) result = wdlg.ShowModal() if pyclip: #import pyclipper import os #self.mainDlg = MainDialog(None) #self.selfToMainDialog() self.boardObj = pcbnew.GetBoard() self.boardDesignSettingsObj = self.boardObj.GetDesignSettings() self.boardPath = os.path.dirname(os.path.realpath(self.boardObj.GetFileName())) self.layerMap = self.getLayerMap() if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: self.highlightedNetId = -1 # Nasty work around... GetHighLightNetCodes returns a swig object >_< # hl_nets = filter(lambda x: x.IsSelected(), self.boardObj.GetTracks()) # hl_net_codes = set(net.GetNetCode() for net in hl_nets) # if len(hl_net_codes) == 1: # self.highlightedNetId = hl_net_codes.pop() # else: # wdlg = wx.MessageDialog(None, u"\u2718 ERROR Please only select one net",'ERROR message',wx.OK | wx.ICON_WARNING)# wx.ICON_ERROR) # result = wdlg.ShowModal() # return else: self.highlightedNetId = self.boardObj.GetHighLightNetCode() self.netMap = self.getNetMap() self.netFilterList = self.createNetFilterSuggestions() self.netFilter = self.netMap[self.highlightedNetId].GetNetname() if self.highlightedNetId != -1 else self.netFilterList[0] self.viaSize = self.boardDesignSettingsObj.GetCurrentViaSize() self.layerId = 0 #TODO: How to get currently selected layer? self.viaDrill = self.boardDesignSettingsObj.GetCurrentViaDrill() self.viaPitch = pcbnew.FromMM(1.3) self.viaOffset = pcbnew.FromMM(1.3) self.viaNetId = 0 #TODO: Maybe a better init value here. Try to find "GND" maybe? self.isNetFilterChecked = 1 if self.highlightedNetId != -1 else 0 #if len(list(self.netMap.keys())) > 0: # self.viaNetId = list(self.netMap.keys())[self.mainDlg.lstViaNet.GetSelection()] #maui self.isLayerChecked = 0 self.isIncludeDrawingChecked = 0 self.isIncludeSelectionChecked = 1 self.isDebugDumpChecked = 0 self.isRemoveViasWithClearanceViolationChecked = 1 self.isSameNetZoneViasOnlyChecked = 0 self.mainDlg = MainDialog(None) self.selfToMainDialog() if hasattr(self.boardObj, 'm_Uuid'): self.mainDlg.m_buttonDelete.Disable() self.mainDlg.m_buttonDelete.SetToolTip( u"fencing vias are placed in a group,\nto delete fencing vias, just delete the group" ) reply = self.mainDlg.ShowModal() if (reply == wx.ID_OK): # User pressed OK. # Assemble a list of pcbnew.BOARD_ITEMs derived objects that support GetStart/GetEnd and IsOnLayer self.mainDialogToSelf() lineObjects = [] arcObjects = [] # creating a unique group for vias if not(hasattr(pcbnew,'DRAWSEGMENT')): #creating a group of fencing vias groupName = uuid.uuid4() #randomword(5) pcb_group = pcbnew.PCB_GROUP(None) pcb_group.SetName(groupName) self.boardObj.Add(pcb_group) # Do we want to include net tracks? if (self.isNetFilterChecked): # Find nets that match the generated regular expression and add their tracks to the list netRegex = self.regExFromSimpleEx(self.netFilter) for netId in self.netMap: if re.match(netRegex, self.netMap[netId].GetNetname()): for trackObject in self.boardObj.TracksInNet(netId): #wx.LogMessage('type '+str(trackObject.GetStart())) #wx.LogMessage('type '+str(trackObject.GetMid())) if (hasattr(pcbnew,'DRAWSEGMENT')): trk_type = pcbnew.TRACK else: trk_type = pcbnew.PCB_TRACK trk_arc = pcbnew.PCB_ARC if hasattr(trackObject,'GetMid()'): arcObjects += [trackObject] elif type(trackObject) is trk_type: lineObjects += [trackObject] # wx.LogMessage('net selected '+str(lineObjects)) # wx.LogMessage('net selected '+str(arcObjects)) # Do we want to include drawing segments? if (self.isIncludeDrawingChecked): boardItem = self.boardObj.GetDrawings().GetFirst() while boardItem is not None: if pcbnew.DRAWSEGMENT.ClassOf(boardItem): # A drawing segment (not a text or something else) drawingObject = boardItem.Cast() if drawingObject.GetShape() == pcbnew.S_SEGMENT: # A straight line lineObjects += [drawingObject] boardItem = boardItem.Next() # Do we want to include track segments? if (self.isIncludeSelectionChecked): if (hasattr(pcbnew,'DRAWSEGMENT')): trk_type = pcbnew.TRACK else: trk_type = pcbnew.PCB_TRACK trk_arc = pcbnew.PCB_ARC for item in self.boardObj.GetTracks(): #wx.LogMessage('type track: %s' % str(type(item))) if not (hasattr(pcbnew,'DRAWSEGMENT')): if type(item) is trk_arc and item.IsSelected(): wx.LogMessage('type track: %s' % str(type(item))) arcObjects += [item] if type(item) is trk_type and item.IsSelected(): lineObjects += [item] # Do we want to filter the generated lines by layer? if (self.isLayerChecked): # Filter by layer # TODO: Make layer selection also a regex lineObjects = [lineObject for lineObject in lineObjects if lineObject.IsOnLayer(self.layerId)] arcObjects = [arcObject for arcObject in arcObjects if arcObject.IsOnLayer(self.layerId)] #wx.LogMessage('arcs: %s' % str(arcObjects)) for arc in arcObjects: segNBR = 16 start = arc.GetStart() end = arc.GetEnd() md = arc.GetMid() width = arc.GetWidth() layer = arc.GetLayerSet() netName = None cnt, rad = getCircleCenterRadius(start,end,md) pts = create_round_pts(start,end,cnt,rad,layer,width,netName,segNBR) self.pathListArcs = [[ [p.x, p.y], [pts[i+1].x, pts[i+1].y] ] for i,p in enumerate(pts[:-1])] # Generate via fence try: viaPointsArcs = [] if len (arcObjects) > 0: viaPointsArcs = generateViaFence(self.pathListArcs, self.viaOffset, self.viaPitch) viaObjListArcs = self.createVias(viaPointsArcs, self.viaDrill, self.viaSize, self.viaNetId) for v in viaObjListArcs: pcb_group.AddItem(v) except Exception as exc: wx.LogMessage('exception on via fence generation: %s' % str(exc)) import traceback wx.LogMessage(traceback.format_exc()) viaPoints = [] #wx.LogMessage('pL: %s' % str(self.pathListArcs)) #wx.LogMessage('pts: %s' % str(pts)) # Generate a path list from the pcbnew.BOARD_ITEM objects self.pathList = [[ [lineObject.GetStart()[0], lineObject.GetStart()[1]], [lineObject.GetEnd()[0], lineObject.GetEnd()[1]] ] for lineObject in lineObjects] #wx.LogMessage('pL: %s' % str(self.pathList)) # Generate via fence try: viaPointsArcs = [] viaPoints = generateViaFence(self.pathList, self.viaOffset, self.viaPitch) #if len (arcObjects) > 0: # viaPointsArcs = generateViaFence(self.pathListArcs, self.viaOffset, self.viaPitch) except Exception as exc: wx.LogMessage('exception on via fence generation: %s' % str(exc)) import traceback wx.LogMessage(traceback.format_exc()) viaPoints = [] if (self.isDebugDumpChecked): self.viaPoints = viaPoints self.dumpJSON(os.path.join(self.boardPath, time.strftime("viafence-%Y%m%d-%H%M%S.json"))) removed = False if (self.isRemoveViasWithClearanceViolationChecked): #if self.mainDlg.chkRemoveViasWithClearanceViolation.GetValue(): # Remove Vias that violate clearance to other things # Check against other tracks #wx.LogMessage('hereIam') # removing generated & colliding vias viaPointsSafe = [] for i,v in enumerate(viaPoints): #clearance = v.GetClearance() collision_found = False tolerance = 1 + 0.2 # This should be handled with Net Clearance for j, vn in enumerate(viaPoints[i+1:]): if distance (pcbnew.wxPoint(v[0], v[1]),pcbnew.wxPoint(vn[0], vn[1])) < int(self.viaSize*tolerance): # +clearance viasize+20%: collision_found = True if not collision_found: viaPointsSafe.append(v) self.viaPointsSafe = viaPointsSafe #wx.LogMessage(str(len(self.viaPointsSafe))) removed = self.checkPads() remvd = self.checkTracks() removed = removed or remvd else: self.viaPointsSafe = viaPoints #wx.LogMessage(str(len(self.viaPointsSafe))) #self.checkPads() #wx.LogMessage(str(len(self.viaPointsSafe))) viaObjList = self.createVias(self.viaPointsSafe, self.viaDrill, self.viaSize, self.viaNetId) # viaObjListArcs = [] # if len (arcObjects) > 0: # viaObjListArcs = self.createVias(viaPointsArcs, self.viaDrill, self.viaSize, self.viaNetId) if not(hasattr(pcbnew,'DRAWSEGMENT')): #creating a group of fencing vias # groupName = uuid.uuid4() #randomword(5) # pcb_group = pcbnew.PCB_GROUP(None) # pcb_group.SetName(groupName) # self.boardObj.Add(pcb_group) for v in viaObjList: pcb_group.AddItem(v) #for v in viaObjListArcs: # pcb_group.AddItem(v) via_nbr = len(self.viaPointsSafe) via_nbr += len(viaPointsArcs) msg = u'Placed {0:} Fencing Vias.\n\u26A0 Please run a DRC check on your board.'.format(str(via_nbr)) if removed: msg += u'\n\u281B Removed DRC colliding vias.' wx.LogMessage(msg) #viaObjList = self.createVias(viaPoints, self.viaDrill, self.viaSize, self.viaNetId) #via_nbr = len(viaPoints) elif (reply == wx.ID_DELETE): #user clicked ('Delete Fence Vias') target_tracks = filter(lambda x: ((x.Type() == pcbnew.PCB_VIA_T)and (x.GetTimeStamp() == 55)), self.boardObj.GetTracks()) #wx.LogMessage(str(len(target_tracks))) target_tracks_cp = list(target_tracks) l = len (target_tracks_cp) for i in range(l): #if type(target_tracks_cp[i]) is PCB_TRACK and target_tracks_cp[i].IsSelected(): #item.GetNetname() == net_name: self.boardObj.RemoveNative(target_tracks_cp[i]) #removing via #for via in target_tracks: # #if via.GetTimeStamp() == 55: # self.boardObj.RemoveNative(via) # #wx.LogMessage('removing via') #pcbnew.Refresh() self.mainDlg.Destroy() #the Dlg needs to be destroyed to release pcbnew # TODO: Implement # if (self.isRemoveViasWithClearanceViolationChecked): # # Remove Vias that violate clearance to other things # # Check against other tracks # for viaObj in viaObjList: # for track in self.boardObj.GetTracks(): # clearance = track.GetClearance(viaObj) # if track.HitTest(False, clearance): # self.boardObj.RemoveNative(viaObj) # TODO: Implement # if (self.isSameNetZoneViasOnlyChecked): # # Keep via only if it is in a filled zone with the same net # import numpy as np # import matplotlib.pyplot as plt # for path in self.pathList: # plt.plot(np.array(path).T[0], np.array(path).T[1], linewidth=2) # for via in viaPoints: # plt.plot(via[0], via[1], 'o', markersize=10) # plt.ylim(plt.ylim()[::-1]) # plt.axes().set_aspect('equal','box') # plt.show()