From e53ef6914836a5ec8fdc84eefe1c8a3dbfc3199f Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Sat, 25 Jun 2022 22:28:40 +0200 Subject: [PATCH 1/7] Avoid the board edge by CopperEdgeCLearance amount --- ViaStitching/FillArea.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ViaStitching/FillArea.py b/ViaStitching/FillArea.py index 25bdb79..81d8514 100644 --- a/ViaStitching/FillArea.py +++ b/ViaStitching/FillArea.py @@ -429,6 +429,12 @@ STEP = '-' # KeepOuts are filtered because they have no name target_areas = filter(lambda x: (x.GetNetname() == self.netname), all_areas) + # Get the board outline and size with + board_edge = SHAPE_POLY_SET() + self.pcb.GetBoardPolygonOutlines(board_edge) + b_clearance = max(self.pcb.GetDesignSettings().m_CopperEdgeClearance, self.clearance) + self.size + board_edge.Deflate(int(b_clearance), int(12), SHAPE_POLY_SET.ROUND_ALL_CORNERS) + via_list = [] # Create a list of existing vias => faster than scanning through the whole rectangle max_target_area_clearance = 0 @@ -470,6 +476,8 @@ STEP = '-' # test_result only remains true if the via is inside an area and not on an edge test_result = (hit_test_area and not hit_test_edge) + test_result = (test_result and board_edge.Collide(VECTOR2I(point_to_test))) # check if inside board outline + if test_result: # Create a via object with information about the via and place it in the rectangle via_obj = ViaObject(x=x, y=y, pos_x=current_x, pos_y=current_y) From ba61bcd3bcb0ed7a1d93673ab1107c9ff056346d Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Sun, 26 Jun 2022 13:14:17 +0200 Subject: [PATCH 2/7] Only list nets with zones --- ViaStitching/FillAreaAction.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ViaStitching/FillAreaAction.py b/ViaStitching/FillAreaAction.py index aaabe6b..a5cc6d7 100644 --- a/ViaStitching/FillAreaAction.py +++ b/ViaStitching/FillAreaAction.py @@ -26,9 +26,9 @@ import os def PopulateNets(anet, dlg): - nets = pcbnew.GetBoard().GetNetsByName() - for netname, net in nets.items(): - netname = net.GetNetname() + zones = pcbnew.GetBoard().Zones() + for zone in zones: + netname = zone.GetNetname() if netname is not None and netname != "": dlg.m_cbNet.Append(netname) if anet is not None: From cddc38c8b271652e74110a8422785e75d6b110ac Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Sun, 26 Jun 2022 14:50:34 +0200 Subject: [PATCH 3/7] Implemented Concentric and Outline fill modes --- ViaStitching/FillArea.py | 121 +++++++++++++- ViaStitching/FillAreaAction.py | 12 +- ViaStitching/FillAreaDialog.py | 176 ++++++++++---------- ViaStitching/FillAreaTpl.fbp | 287 +++++++++++++++++---------------- 4 files changed, 357 insertions(+), 239 deletions(-) diff --git a/ViaStitching/FillArea.py b/ViaStitching/FillArea.py index 81d8514..0bad9da 100644 --- a/ViaStitching/FillArea.py +++ b/ViaStitching/FillArea.py @@ -105,6 +105,11 @@ class FillArea: REASON_DRAWING = 6 REASON_STEP = 7 + FILL_TYPE_RECTANGULAR = "Rectangular" + FILL_TYPE_STAR = "Star" + FILL_TYPE_CONCENTRIC = "Concentric" + FILL_TYPE_OUTLINE = "Outline" + def __init__(self, filename=None): self.filename = None self.clearance = 0 @@ -131,7 +136,7 @@ class FillArea: self.netname = None self.debug = False self.random = False - self.star = False + self.fill_type = self.FILL_TYPE_RECTANGULAR if self.netname is None: self.SetNetname("GND") @@ -155,8 +160,8 @@ class FillArea: self.random = r return self - def SetStar(self): - self.star = True + def SetType(self, type): + self.fill_type = type return self def SetPCB(self, pcb): @@ -252,6 +257,7 @@ STEP = '-' # wx.LogMessage('adding vias') self.pcb.Add(m) self.pcb_group.AddItem(m) + return m else: wxPrint("\nUnable to find a valid parent area (zone)") @@ -343,13 +349,111 @@ STEP = '-' ''' for x_pos in range(x-distance, x+distance+1): if (x_pos >= 0) and (x_pos < len(rectangle)): - distance_y = distance-abs(x-x_pos) if self.star else distance # Star or Standard shape + # Star or Standard shape + distance_y = distance-abs(x-x_pos) if self.fill_type==self.FILL_TYPE_STAR else distance for y_pos in range(y-distance_y, y+distance_y+1): if (y_pos >= 0) and (y_pos < len(rectangle[0])): if (x_pos == x) and (y_pos == y): continue rectangle[x_pos][y_pos] = self.REASON_STEP + + """ + Check if vias would not overlap and if in same outline then apply at minimum 60% of self.step + """ + def CheckViaDistance(self, p, via, outline): + p2 = VECTOR2I(via.GetPosition()) + + dist = 2*self.clearance + self.size/2 + via.GetWidth()/2 + + # If via in same outline, then apply bigger space + if outline.Collide(p2): + dist = max(dist, self.step*0.6) + + return (p-p2).EuclideanNorm() > dist + + """ + Add via along outline (SHAPE_LINE_CHAIN), starting at offset (fraction between 0.0 and 1.0) + Avoid placing vias to close to via present in all_vias + """ + def AddViasAlongOutline(self, outline, all_vias, offset=0): + via_placed = 0 + len = int(outline.Length()) + steps = len // self.step + steps = 1 if steps == 0 else steps + stepsize = int(len//steps) + for l in range (int(stepsize*offset), len, stepsize): + p = outline.PointAlong(l) + + if all( self.CheckViaDistance(p, via, outline) for via in all_vias): + via = self.AddVia(p.getWxPoint(), 0, 0) + all_vias.append(via) + via_placed+=1 + return via_placed + + def ConcentricFillVias(self): + wxPrint("Refill all zones") + self.RefillBoardAreas() + + wxPrint("Calculate placement areas") + + zones = [zone for zone in self.pcb.Zones() if zone.GetNetname() == self.netname] + self.parent_area = zones[0] + + # Create set of polygons where fill zones overlap on all layers + poly_set = None + for layer_id in self.pcb.GetEnabledLayers().CuStack(): + poly_set_layer = SHAPE_POLY_SET() + for zone in zones: + if zone.IsOnLayer(layer_id): + if poly_set is not None or not self.only_selected_area or zone.IsSelected(): + poly_set_layer.Append(zone.RawPolysList(layer_id)) + + if poly_set is None: + poly_set = poly_set_layer + else: + poly_set.BooleanIntersection(poly_set_layer,SHAPE_POLY_SET.PM_FAST) + poly_set.Simplify(SHAPE_POLY_SET.PM_FAST) + + if poly_set.OutlineCount()==0: + wxPrint("No areas to fill") + return + + + # Size the polygons so the vias fit inside + poly_set.Inflate(int(-(1*self.clearance + 0.5*self.size)),12,SHAPE_POLY_SET.CHAMFER_ALL_CORNERS) + + wxPrint("Generating concentric via placement") + # Get all vias from the selected net + all_vias = [track for track in self.pcb.GetTracks() if (track.GetClass()=="PCB_VIA" and track.GetNetname()==self.netname)] + + off = 0 + via_placed = 0 + # Place vias along all outlines and holes + while poly_set.OutlineCount() > 0: + for i in range(0, poly_set.OutlineCount()): + outline = poly_set.Outline(i) + via_placed += self.AddViasAlongOutline(outline, all_vias, off) + + for k in range(0, poly_set.HoleCount(i)): + hole = poly_set.Hole(i,k) + via_placed += self.AddViasAlongOutline(hole, all_vias, off) + + # Size the polygons to place the next ring + if self.fill_type == self.FILL_TYPE_CONCENTRIC: + poly_set.Inflate(int(-self.step),12,SHAPE_POLY_SET.CHAMFER_ALL_CORNERS) + off = 0.5 if off == 0 else 0 + else: + poly_set = SHAPE_POLY_SET() + + wxPrint("Refill all zones") + self.RefillBoardAreas() + + msg = "{:d} vias placed\n".format(via_placed) + wxPrint(msg+"Done!") + + return via_placed + def Run(self): VIA_GROUP_NAME = "ViaStitching {}".format(self.netname) @@ -377,6 +481,13 @@ STEP = '-' self.pcb_group.SetName(VIA_GROUP_NAME) self.pcb.Add(self.pcb_group) + if self.fill_type==self.FILL_TYPE_OUTLINE or self.fill_type==self.FILL_TYPE_CONCENTRIC: + self.ConcentricFillVias() + if self.filename: + self.pcb.Save(self.filename) + + return + if self.debug: print("%s: Line %u" % (time.time(), currentframe().f_lineno)) target_tracks = self.pcb.GetTracks() @@ -615,7 +726,7 @@ STEP = '-' self.PrintRect(rectangle) clear_distance = 0 - if self.step != 0.0 and self.star: + if self.step != 0.0 and self.fill_type == self.FILL_TYPE_STAR: # How much "via steps" should be removed around a via (round up) clear_distance = int((self.step+l_clearance) / l_clearance) diff --git a/ViaStitching/FillAreaAction.py b/ViaStitching/FillAreaAction.py index a5cc6d7..802d7de 100644 --- a/ViaStitching/FillAreaAction.py +++ b/ViaStitching/FillAreaAction.py @@ -26,11 +26,9 @@ import os def PopulateNets(anet, dlg): - zones = pcbnew.GetBoard().Zones() - for zone in zones: - netname = zone.GetNetname() - if netname is not None and netname != "": - dlg.m_cbNet.Append(netname) + netnames = list(set([zone.GetNetname() for zone in pcbnew.GetBoard().Zones()])) + netnames.sort() + dlg.m_cbNet.Set(netnames) if anet is not None: index = dlg.m_cbNet.FindString(anet) dlg.m_cbNet.Select(index) @@ -59,7 +57,6 @@ class FillAreaAction(pcbnew.ActionPlugin): # a.m_DrillMM.SetValue("0.3") # a.m_Netname.SetValue("GND") # a.m_ClearanceMM.SetValue("0.2") - # a.m_Star.SetValue(True) a.m_bitmapStitching.SetBitmap(wx.Bitmap(os.path.join(os.path.dirname(os.path.realpath(__file__)), "stitching-vias-help.png"))) self.board = pcbnew.GetBoard() self.boardDesignSettings = self.board.GetDesignSettings() @@ -84,8 +81,7 @@ class FillAreaAction(pcbnew.ActionPlugin): if a.m_Debug.IsChecked(): fill.SetDebug() fill.SetRandom(a.m_Random.IsChecked()) - if a.m_Star.IsChecked(): - fill.SetStar() + fill.SetType(a.m_cbFillType.GetStringSelection()) if a.m_only_selected.IsChecked(): fill.OnlyOnSelectedArea() fill.Run() diff --git a/ViaStitching/FillAreaDialog.py b/ViaStitching/FillAreaDialog.py index 64ca4b8..239f59c 100644 --- a/ViaStitching/FillAreaDialog.py +++ b/ViaStitching/FillAreaDialog.py @@ -1,147 +1,151 @@ # -*- coding: utf-8 -*- ########################################################################### -# Python code generated with wxFormBuilder (version 3.9.0 Jul 3 2021) -# http://www.wxformbuilder.org/ +## Python code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) +## http://www.wxformbuilder.org/ ## -# PLEASE DO *NOT* EDIT THIS FILE! +## PLEASE DO *NOT* EDIT THIS FILE! ########################################################################### import wx import wx.xrc ########################################################################### -# Class FillAreaDialog +## Class FillAreaDialog ########################################################################### +class FillAreaDialog ( wx.Dialog ): -class FillAreaDialog (wx.Dialog): + def __init__( self, parent ): + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Fill Area parameters", pos = wx.DefaultPosition, size = wx.Size( 402,580 ), style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) - def __init__(self, parent): - wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=u"Fill Area parameters", pos=wx.DefaultPosition, - size=wx.Size(402, 580), style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) - self.SetSizeHints(wx.DefaultSize, wx.DefaultSize) + bSizer3 = wx.BoxSizer( wx.VERTICAL ) - bSizer3 = wx.BoxSizer(wx.VERTICAL) + fgSizer1 = wx.FlexGridSizer( 0, 2, 0, 0 ) + fgSizer1.SetFlexibleDirection( wx.BOTH ) + fgSizer1.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) - fgSizer1 = wx.FlexGridSizer(0, 2, 0, 0) - fgSizer1.SetFlexibleDirection(wx.BOTH) - fgSizer1.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, u"Via copper size (mm)", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText3.Wrap( -1 ) - self.m_staticText3 = wx.StaticText(self, wx.ID_ANY, u"Via copper size (mm)", wx.DefaultPosition, wx.DefaultSize, 0) - self.m_staticText3.Wrap(-1) + fgSizer1.Add( self.m_staticText3, 1, wx.ALL|wx.EXPAND, 5 ) - fgSizer1.Add(self.m_staticText3, 1, wx.ALL | wx.EXPAND, 5) + self.m_SizeMM = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_SizeMM.SetMinSize( wx.Size( 1000,-1 ) ) - self.m_SizeMM = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0) - self.m_SizeMM.SetMinSize(wx.Size(1000, -1)) + fgSizer1.Add( self.m_SizeMM, 1, wx.ALL|wx.EXPAND, 5 ) - fgSizer1.Add(self.m_SizeMM, 1, wx.ALL | wx.EXPAND, 5) + self.m_staticText9 = wx.StaticText( self, wx.ID_ANY, u"Via drill size (mm)", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText9.Wrap( -1 ) - self.m_staticText9 = wx.StaticText(self, wx.ID_ANY, u"Via drill size (mm)", wx.DefaultPosition, wx.DefaultSize, 0) - self.m_staticText9.Wrap(-1) + fgSizer1.Add( self.m_staticText9, 1, wx.ALL|wx.EXPAND, 5 ) - fgSizer1.Add(self.m_staticText9, 1, wx.ALL | wx.EXPAND, 5) + self.m_DrillMM = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + fgSizer1.Add( self.m_DrillMM, 1, wx.ALL|wx.EXPAND, 5 ) - self.m_DrillMM = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0) - fgSizer1.Add(self.m_DrillMM, 1, wx.ALL | wx.EXPAND, 5) + self.m_staticText5 = wx.StaticText( self, wx.ID_ANY, u"Via clearance (mm)", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText5.Wrap( -1 ) - self.m_staticText5 = wx.StaticText(self, wx.ID_ANY, u"Via clearance (mm)", wx.DefaultPosition, wx.DefaultSize, 0) - self.m_staticText5.Wrap(-1) + fgSizer1.Add( self.m_staticText5, 1, wx.ALL|wx.EXPAND, 5 ) - fgSizer1.Add(self.m_staticText5, 1, wx.ALL | wx.EXPAND, 5) + self.m_ClearanceMM = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + fgSizer1.Add( self.m_ClearanceMM, 1, wx.ALL|wx.EXPAND, 5 ) - self.m_ClearanceMM = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0) - fgSizer1.Add(self.m_ClearanceMM, 1, wx.ALL | wx.EXPAND, 5) + self.m_staticText2 = wx.StaticText( self, wx.ID_ANY, u"Via grid (mm)", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText2.Wrap( -1 ) - self.m_staticText2 = wx.StaticText(self, wx.ID_ANY, u"Via grid (mm)", wx.DefaultPosition, wx.DefaultSize, 0) - self.m_staticText2.Wrap(-1) + fgSizer1.Add( self.m_staticText2, 0, wx.ALL, 5 ) - fgSizer1.Add(self.m_staticText2, 0, wx.ALL, 5) + self.m_StepMM = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + fgSizer1.Add( self.m_StepMM, 1, wx.ALL|wx.EXPAND, 5 ) - self.m_StepMM = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0) - fgSizer1.Add(self.m_StepMM, 1, wx.ALL | wx.EXPAND, 5) - fgSizer1.Add((0, 0), 1, wx.EXPAND, 5) + fgSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 ) - self.m_bitmapStitching = wx.StaticBitmap(self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0) - fgSizer1.Add(self.m_bitmapStitching, 0, wx.EXPAND, 5) + self.m_bitmapStitching = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 ) + fgSizer1.Add( self.m_bitmapStitching, 0, wx.EXPAND, 5 ) - self.m_staticText6 = wx.StaticText(self, wx.ID_ANY, u"Net name", wx.DefaultPosition, wx.DefaultSize, 0) - self.m_staticText6.Wrap(-1) + self.m_staticText6 = wx.StaticText( self, wx.ID_ANY, u"Net name", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText6.Wrap( -1 ) - fgSizer1.Add(self.m_staticText6, 1, wx.ALL | wx.EXPAND, 5) + fgSizer1.Add( self.m_staticText6, 1, wx.ALL|wx.EXPAND, 5 ) - m_cbNetChoices = [] - self.m_cbNet = wx.ComboBox(self, wx.ID_ANY, u"GND", wx.DefaultPosition, wx.DefaultSize, m_cbNetChoices, wx.CB_READONLY) - fgSizer1.Add(self.m_cbNet, 1, wx.ALL | wx.EXPAND, 5) + m_cbNetChoices = [] + self.m_cbNet = wx.ComboBox( self, wx.ID_ANY, u"GND", wx.DefaultPosition, wx.DefaultSize, m_cbNetChoices, wx.CB_READONLY ) + fgSizer1.Add( self.m_cbNet, 1, wx.ALL|wx.EXPAND, 5 ) - self.m_staticText7 = wx.StaticText(self, wx.ID_ANY, u"Debug mode", wx.DefaultPosition, wx.DefaultSize, 0) - self.m_staticText7.Wrap(-1) + self.m_staticText42 = wx.StaticText( self, wx.ID_ANY, u"Star Pattern", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText42.Wrap( -1 ) - fgSizer1.Add(self.m_staticText7, 1, wx.ALL | wx.EXPAND, 5) + fgSizer1.Add( self.m_staticText42, 0, wx.ALL, 5 ) - self.m_Debug = wx.CheckBox(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0) - fgSizer1.Add(self.m_Debug, 1, wx.ALL | wx.EXPAND, 5) + m_cbFillTypeChoices = [ u"Concentric", u"Outline", u"Rectangular", u"Star" ] + self.m_cbFillType = wx.ComboBox( self, wx.ID_ANY, u"Concentric", wx.DefaultPosition, wx.DefaultSize, m_cbFillTypeChoices, wx.CB_READONLY ) + fgSizer1.Add( self.m_cbFillType, 0, wx.ALL, 5 ) - self.m_staticText8 = wx.StaticText(self, wx.ID_ANY, u"Random it", wx.DefaultPosition, wx.DefaultSize, 0) - self.m_staticText8.Wrap(-1) + self.m_staticText8 = wx.StaticText( self, wx.ID_ANY, u"Random it", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText8.Wrap( -1 ) - fgSizer1.Add(self.m_staticText8, 0, wx.ALL, 5) + fgSizer1.Add( self.m_staticText8, 0, wx.ALL, 5 ) - self.m_Random = wx.CheckBox(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0) - fgSizer1.Add(self.m_Random, 0, wx.ALL, 5) + self.m_Random = wx.CheckBox( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + fgSizer1.Add( self.m_Random, 0, wx.ALL, 5 ) - self.m_staticText42 = wx.StaticText(self, wx.ID_ANY, u"Star Pattern", wx.DefaultPosition, wx.DefaultSize, 0) - self.m_staticText42.Wrap(-1) + self.m_staticText81 = wx.StaticText( self, wx.ID_ANY, u"Only under selected Zone", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText81.Wrap( -1 ) - fgSizer1.Add(self.m_staticText42, 0, wx.ALL, 5) + fgSizer1.Add( self.m_staticText81, 0, wx.ALL, 5 ) - self.m_Star = wx.CheckBox(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0) - fgSizer1.Add(self.m_Star, 0, wx.ALL, 5) + self.m_only_selected = wx.CheckBox( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + fgSizer1.Add( self.m_only_selected, 0, wx.ALL, 5 ) - self.m_staticText81 = wx.StaticText(self, wx.ID_ANY, u"Only under selected Zone", wx.DefaultPosition, wx.DefaultSize, 0) - self.m_staticText81.Wrap(-1) + self.m_staticText7 = wx.StaticText( self, wx.ID_ANY, u"Debug mode", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText7.Wrap( -1 ) - fgSizer1.Add(self.m_staticText81, 0, wx.ALL, 5) + fgSizer1.Add( self.m_staticText7, 1, wx.ALL|wx.EXPAND, 5 ) - self.m_only_selected = wx.CheckBox(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0) - fgSizer1.Add(self.m_only_selected, 0, wx.ALL, 5) + self.m_Debug = wx.CheckBox( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + fgSizer1.Add( self.m_Debug, 1, wx.ALL|wx.EXPAND, 5 ) - bSizer3.Add(fgSizer1, 1, wx.EXPAND, 5) - bSizer1 = wx.BoxSizer(wx.HORIZONTAL) + bSizer3.Add( fgSizer1, 1, wx.EXPAND, 5 ) - self.m_staticText101 = wx.StaticText(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0) - self.m_staticText101.Wrap(-1) + bSizer1 = wx.BoxSizer( wx.HORIZONTAL ) - bSizer1.Add(self.m_staticText101, 1, wx.ALL, 5) + self.m_staticText101 = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText101.Wrap( -1 ) - self.m_button1 = wx.Button(self, wx.ID_OK, u"Run", wx.DefaultPosition, wx.DefaultSize, 0) + bSizer1.Add( self.m_staticText101, 1, wx.ALL, 5 ) - self.m_button1.SetDefault() - bSizer1.Add(self.m_button1, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + self.m_button1 = wx.Button( self, wx.ID_OK, u"Run", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_button2 = wx.Button(self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0) - bSizer1.Add(self.m_button2, 0, wx.ALL, 5) + self.m_button1.SetDefault() + bSizer1.Add( self.m_button1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) - self.m_button3_delete = wx.Button(self, wx.ID_DELETE, u"Delete Vias", wx.DefaultPosition, wx.DefaultSize, 0) - bSizer1.Add(self.m_button3_delete, 0, wx.ALL, 5) + self.m_button2 = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer1.Add( self.m_button2, 0, wx.ALL, 5 ) - bSizer3.Add(bSizer1, 0, wx.EXPAND | wx.ALIGN_RIGHT, 5) + self.m_button3_delete = wx.Button( self, wx.ID_DELETE, u"Delete Vias", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer1.Add( self.m_button3_delete, 0, wx.ALL, 5 ) - self.SetSizer(bSizer3) - self.Layout() - self.Centre(wx.BOTH) + bSizer3.Add( bSizer1, 0, wx.EXPAND|wx.ALIGN_RIGHT, 5 ) - # Connect Events - self.m_button3_delete.Bind(wx.EVT_BUTTON, self.onDeleteClick) - def __del__(self): - pass + self.SetSizer( bSizer3 ) + self.Layout() - # Virtual event handlers, override them in your derived class - def onDeleteClick(self, event): - event.Skip() + self.Centre( wx.BOTH ) + + # Connect Events + self.m_button3_delete.Bind( wx.EVT_BUTTON, self.onDeleteClick ) + + def __del__( self ): + pass + + + # Virtual event handlers, override them in your derived class + def onDeleteClick( self, event ): + event.Skip() diff --git a/ViaStitching/FillAreaTpl.fbp b/ViaStitching/FillAreaTpl.fbp index fa064c4..ed1f33b 100644 --- a/ViaStitching/FillAreaTpl.fbp +++ b/ViaStitching/FillAreaTpl.fbp @@ -1,6 +1,6 @@ - + Python @@ -14,6 +14,7 @@ FillAreaDialog 1000 none + 0 FillAreaDialog @@ -25,6 +26,7 @@ 1 1 UI + 0 0 0 @@ -50,6 +52,7 @@ Fill Area parameters + 0 @@ -768,11 +771,11 @@ - + 5 - wxALL|wxEXPAND - 1 - + wxALL + 0 + 1 1 1 @@ -800,7 +803,7 @@ 0 0 wxID_ANY - Debug mode + Star Pattern 0 0 @@ -809,7 +812,7 @@ 0 1 - m_staticText7 + m_staticText42 1 @@ -829,11 +832,11 @@ -1 - + 5 - wxALL|wxEXPAND - 1 - + wxALL + 0 + 1 1 1 @@ -847,7 +850,7 @@ 1 0 - 0 + "Concentric" "Outline" "Rectangular" "Star" 1 1 @@ -862,7 +865,6 @@ 0 0 wxID_ANY - 0 @@ -870,7 +872,7 @@ 0 1 - m_Debug + m_cbFillType 1 @@ -878,9 +880,10 @@ 1 Resizable + -1 1 - + wxCB_READONLY 0 @@ -888,6 +891,7 @@ wxFILTER_NONE wxDefaultValidator + Concentric @@ -1018,131 +1022,6 @@ - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Star Pattern - 0 - - 0 - - - 0 - - 1 - m_staticText42 - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - - - -1 - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - - 0 - - - 0 - - 1 - m_Star - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - 5 wxALL @@ -1268,6 +1147,131 @@ + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Debug mode + 0 + + 0 + + + 0 + + 1 + m_staticText7 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_Debug + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + @@ -1353,6 +1357,7 @@ + 0 @@ -1425,6 +1430,7 @@ + 0 @@ -1497,6 +1503,7 @@ + 0 From b36fe79bbfeba9e1ba1f5c2a19bd9872fa11ca5e Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Sun, 26 Jun 2022 15:07:21 +0200 Subject: [PATCH 4/7] Corrected dialog height --- ViaStitching/FillAreaDialog.py | 2 +- ViaStitching/FillAreaTpl.fbp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ViaStitching/FillAreaDialog.py b/ViaStitching/FillAreaDialog.py index 239f59c..9d21b14 100644 --- a/ViaStitching/FillAreaDialog.py +++ b/ViaStitching/FillAreaDialog.py @@ -17,7 +17,7 @@ import wx.xrc class FillAreaDialog ( wx.Dialog ): def __init__( self, parent ): - wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Fill Area parameters", pos = wx.DefaultPosition, size = wx.Size( 402,580 ), style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Fill Area parameters", pos = wx.DefaultPosition, size = wx.Size( 402,590 ), style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) diff --git a/ViaStitching/FillAreaTpl.fbp b/ViaStitching/FillAreaTpl.fbp index ed1f33b..b68c33e 100644 --- a/ViaStitching/FillAreaTpl.fbp +++ b/ViaStitching/FillAreaTpl.fbp @@ -47,7 +47,7 @@ FillAreaDialog - 402,580 + 402,590 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER Fill Area parameters From 9c4e414ef357f745a3540ab858418e00b3cd4b73 Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Sun, 26 Jun 2022 15:37:30 +0200 Subject: [PATCH 5/7] Implemented via deletion --- ViaStitching/FillArea.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ViaStitching/FillArea.py b/ViaStitching/FillArea.py index 0bad9da..e08002f 100644 --- a/ViaStitching/FillArea.py +++ b/ViaStitching/FillArea.py @@ -454,6 +454,10 @@ STEP = '-' return via_placed + + """ + Main function which does the via placement or deletion + """ def Run(self): VIA_GROUP_NAME = "ViaStitching {}".format(self.netname) @@ -470,10 +474,13 @@ STEP = '-' Launch the process """ if self.delete_vias: - # timestmap again available - # target_tracks = filter(lambda x: (x.GetNetname().upper() == self.netname), self.pcb.GetTracks()) - wx.MessageBox( - "To delete vias:\n - select one of the generated via to select the group of vias named {}\n - hit delete key\n - That's all !".format(VIA_GROUP_NAME), "Information") + + if self.pcb_group is not None: + all_vias = [track for track in self.pcb.GetTracks() if (track.GetClass()=="PCB_VIA" and track.GetNetname()==self.netname)] + + for via in all_vias: + if via.GetParentGroup() is not None and via.GetParentGroup().GetName() == VIA_GROUP_NAME: + via.DeleteStructure() return # no need to run the rest of logic if self.pcb_group is None: From 89dca8193a8662752c18ab9f14aa3a3715b9668a Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Sun, 26 Jun 2022 15:45:12 +0200 Subject: [PATCH 6/7] Added FILL_TYPE_OUTLINE_NO_HOLES --- ViaStitching/FillArea.py | 10 ++++++---- ViaStitching/FillAreaDialog.py | 2 +- ViaStitching/FillAreaTpl.fbp | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ViaStitching/FillArea.py b/ViaStitching/FillArea.py index e08002f..36b83ef 100644 --- a/ViaStitching/FillArea.py +++ b/ViaStitching/FillArea.py @@ -109,6 +109,7 @@ class FillArea: FILL_TYPE_STAR = "Star" FILL_TYPE_CONCENTRIC = "Concentric" FILL_TYPE_OUTLINE = "Outline" + FILL_TYPE_OUTLINE_NO_HOLES = "Outline (No Holes)" def __init__(self, filename=None): self.filename = None @@ -435,9 +436,10 @@ STEP = '-' outline = poly_set.Outline(i) via_placed += self.AddViasAlongOutline(outline, all_vias, off) - for k in range(0, poly_set.HoleCount(i)): - hole = poly_set.Hole(i,k) - via_placed += self.AddViasAlongOutline(hole, all_vias, off) + if self.fill_type != self.FILL_TYPE_OUTLINE_NO_HOLES: + for k in range(0, poly_set.HoleCount(i)): + hole = poly_set.Hole(i,k) + via_placed += self.AddViasAlongOutline(hole, all_vias, off) # Size the polygons to place the next ring if self.fill_type == self.FILL_TYPE_CONCENTRIC: @@ -488,7 +490,7 @@ STEP = '-' self.pcb_group.SetName(VIA_GROUP_NAME) self.pcb.Add(self.pcb_group) - if self.fill_type==self.FILL_TYPE_OUTLINE or self.fill_type==self.FILL_TYPE_CONCENTRIC: + if self.fill_type==self.FILL_TYPE_CONCENTRIC or self.fill_type==self.FILL_TYPE_OUTLINE or self.fill_type==self.FILL_TYPE_OUTLINE_NO_HOLES: self.ConcentricFillVias() if self.filename: self.pcb.Save(self.filename) diff --git a/ViaStitching/FillAreaDialog.py b/ViaStitching/FillAreaDialog.py index 9d21b14..0220ae0 100644 --- a/ViaStitching/FillAreaDialog.py +++ b/ViaStitching/FillAreaDialog.py @@ -81,7 +81,7 @@ class FillAreaDialog ( wx.Dialog ): fgSizer1.Add( self.m_staticText42, 0, wx.ALL, 5 ) - m_cbFillTypeChoices = [ u"Concentric", u"Outline", u"Rectangular", u"Star" ] + m_cbFillTypeChoices = [ u"Concentric", u"Outline", u"Outline (No Holes)", u"Rectangular", u"Star" ] self.m_cbFillType = wx.ComboBox( self, wx.ID_ANY, u"Concentric", wx.DefaultPosition, wx.DefaultSize, m_cbFillTypeChoices, wx.CB_READONLY ) fgSizer1.Add( self.m_cbFillType, 0, wx.ALL, 5 ) diff --git a/ViaStitching/FillAreaTpl.fbp b/ViaStitching/FillAreaTpl.fbp index b68c33e..51bd564 100644 --- a/ViaStitching/FillAreaTpl.fbp +++ b/ViaStitching/FillAreaTpl.fbp @@ -850,7 +850,7 @@ 1 0 - "Concentric" "Outline" "Rectangular" "Star" + "Concentric" "Outline" "Outline (No Holes)" "Rectangular" "Star" 1 1 From acf74b7bc0ee7267760013616d07d887c590c058 Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Sun, 26 Jun 2022 16:20:53 +0200 Subject: [PATCH 7/7] Corrected distance to only 1 clearance Corrected same outline check for holes --- ViaStitching/FillArea.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ViaStitching/FillArea.py b/ViaStitching/FillArea.py index 36b83ef..4f2947a 100644 --- a/ViaStitching/FillArea.py +++ b/ViaStitching/FillArea.py @@ -365,28 +365,29 @@ STEP = '-' def CheckViaDistance(self, p, via, outline): p2 = VECTOR2I(via.GetPosition()) - dist = 2*self.clearance + self.size/2 + via.GetWidth()/2 + dist = self.clearance + self.size/2 + via.GetWidth()/2 # If via in same outline, then apply bigger space if outline.Collide(p2): - dist = max(dist, self.step*0.6) + dist = int(max(dist, self.step*0.6)) - return (p-p2).EuclideanNorm() > dist + return (p-p2).EuclideanNorm() >= dist """ Add via along outline (SHAPE_LINE_CHAIN), starting at offset (fraction between 0.0 and 1.0) Avoid placing vias to close to via present in all_vias """ - def AddViasAlongOutline(self, outline, all_vias, offset=0): + def AddViasAlongOutline(self, outline, outline_parent, all_vias, offset=0): via_placed = 0 + step = max(self.step, self.size+self.clearance) len = int(outline.Length()) - steps = len // self.step + steps = len // step steps = 1 if steps == 0 else steps stepsize = int(len//steps) for l in range (int(stepsize*offset), len, stepsize): p = outline.PointAlong(l) - if all( self.CheckViaDistance(p, via, outline) for via in all_vias): + if all(self.CheckViaDistance(p, via, outline_parent) for via in all_vias): via = self.AddVia(p.getWxPoint(), 0, 0) all_vias.append(via) via_placed+=1 @@ -434,16 +435,16 @@ STEP = '-' while poly_set.OutlineCount() > 0: for i in range(0, poly_set.OutlineCount()): outline = poly_set.Outline(i) - via_placed += self.AddViasAlongOutline(outline, all_vias, off) + via_placed += self.AddViasAlongOutline(outline, outline, all_vias, off) if self.fill_type != self.FILL_TYPE_OUTLINE_NO_HOLES: for k in range(0, poly_set.HoleCount(i)): hole = poly_set.Hole(i,k) - via_placed += self.AddViasAlongOutline(hole, all_vias, off) + via_placed += self.AddViasAlongOutline(hole, outline, all_vias, off) # Size the polygons to place the next ring if self.fill_type == self.FILL_TYPE_CONCENTRIC: - poly_set.Inflate(int(-self.step),12,SHAPE_POLY_SET.CHAMFER_ALL_CORNERS) + poly_set.Inflate(int(-max(self.step, self.size+self.clearance)),12,SHAPE_POLY_SET.CHAMFER_ALL_CORNERS) off = 0.5 if off == 0 else 0 else: poly_set = SHAPE_POLY_SET()