summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2023-10-30 15:26:45 +0100
committerjaseg <git@jaseg.de>2023-10-30 15:26:45 +0100
commit7e33137f104c168b782bc9761571a98e3752d8c8 (patch)
tree4586a1ec77bf69f9f2c403df07662b615dcc5880
parentd50efe4695afe21a0a6e18d3d721411e196941b7 (diff)
downloadkimesh-7e33137f104c168b782bc9761571a98e3752d8c8.tar.gz
kimesh-7e33137f104c168b782bc9761571a98e3752d8c8.tar.bz2
kimesh-7e33137f104c168b782bc9761571a98e3752d8c8.zip
Add track/via avoidance and also generate 1-pin heater mesh anchors
-rw-r--r--de.jaseg.kimesh.footprints/metadata.json27
-rw-r--r--de.jaseg.kimesh.plugin/metadata.json27
-rw-r--r--de.jaseg.kimesh.plugin/plugins/mesh_dialog.py83
-rw-r--r--de.jaseg.kimesh.plugin/plugins/mesh_plugin_dialog.py17
-rw-r--r--main_dialog.fbp204
-rw-r--r--package.py2
6 files changed, 286 insertions, 74 deletions
diff --git a/de.jaseg.kimesh.footprints/metadata.json b/de.jaseg.kimesh.footprints/metadata.json
deleted file mode 100644
index 5f0225f..0000000
--- a/de.jaseg.kimesh.footprints/metadata.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "$schema": "https://go.kicad.org/pcm/schemas/v1",
- "name": "KiMesh",
- "description": "A security mesh generator for KiCad",
- "description_full": "This is the footprint package for the KiMesh security mesh generator.",
- "identifier": "de.jaseg.kimesh.footprints",
- "type": "library",
- "author": {
- "name": "jaseg",
- "contact": {
- "web": "https://jaseg.de/"
- }
- },
- "license": "CERN-OHL",
- "resources": {
- "homepage": "https://jaseg.de/projects/kimesh",
- "git": "https://git.jaseg.de/kimesh.git",
- "issues": "https://github.com/jaseg/kimesh/issues"
- },
- "versions": [
- {
- "version": "1.0.1",
- "status": "stable",
- "kicad_version": "7.99"
- }
- ]
-} \ No newline at end of file
diff --git a/de.jaseg.kimesh.plugin/metadata.json b/de.jaseg.kimesh.plugin/metadata.json
deleted file mode 100644
index 5256ccb..0000000
--- a/de.jaseg.kimesh.plugin/metadata.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "$schema": "https://go.kicad.org/pcm/schemas/v1",
- "name": "KiMesh",
- "description": "A security mesh generator for KiCad",
- "description_full": "KiMesh automatically generates security meshes for you. A security mesh is a set of PCB traces that cover an area to detect physical tampering. KiMesh can cover arbitrary areas with two or more traces. Note: The KiMesh footprints Add-On must be installed alongside KiMesh. For detailed usage instructions, please have a look at the KiMesh website linked in the add-on information.",
- "identifier": "de.jaseg.kimesh.plugin",
- "type": "plugin",
- "author": {
- "name": "jaseg",
- "contact": {
- "web": "https://jaseg.de/"
- }
- },
- "license": "GPL-3.0",
- "resources": {
- "homepage": "https://jaseg.de/projects/kimesh",
- "git": "https://git.jaseg.de/kimesh.git",
- "issues": "https://github.com/jaseg/kimesh/issues"
- },
- "versions": [
- {
- "version": "1.0.1",
- "status": "stable",
- "kicad_version": "7.99"
- }
- ]
-} \ No newline at end of file
diff --git a/de.jaseg.kimesh.plugin/plugins/mesh_dialog.py b/de.jaseg.kimesh.plugin/plugins/mesh_dialog.py
index 4bcbc38..3b574de 100644
--- a/de.jaseg.kimesh.plugin/plugins/mesh_dialog.py
+++ b/de.jaseg.kimesh.plugin/plugins/mesh_dialog.py
@@ -39,6 +39,8 @@ class GeneratorSettings:
randomness: float = 1.0
use_keepouts: bool = True
use_outline: bool = True
+ use_tracks: bool = False
+ track_clearance: float = 0.2 # mm
save_visualization: bool = True
visualization_path: str = 'mesh_visualizations'
@@ -115,6 +117,8 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
self.m_useKeepoutCheckbox.Value = settings.use_keepouts
self.m_vizTextfield.Value = settings.visualization_path
self.m_vizCheckbox.Value = settings.save_visualization
+ self.m_trackClearanceCheckbox.Value = settings.use_tracks
+ self.m_trackClearanceSpin.Value = settings.track_clearance
self.SetMinSize(self.GetSize())
@@ -204,7 +208,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
count += 1
self.board.Remove(track)
- print(f'Tore up {count} trace segments.')
+ print(f'KiMesh: Tore up {count} trace segments.')
def settings_fn(self):
return path.join(path.dirname(self.board.GetFileName()), 'last_kimesh_settings.json')
@@ -236,14 +240,16 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
use_outline = self.m_useOutlineCheckbox.Value,
use_keepouts = self.m_useKeepoutCheckbox.Value,
visualization_path = self.m_vizTextfield.Value,
- save_visualization = self.m_vizCheckbox.Value)
+ save_visualization = self.m_vizCheckbox.Value,
+ use_tracks = self.m_trackClearanceCheckbox.Value,
+ track_clearance = self.m_trackClearanceSpin.Value)
except ValueError as e:
return wx.MessageDialog(self, "Invalid input value: {}.".format(e), "Invalid input").ShowModal()
try:
with open(self.settings_fn(), 'wb') as f:
f.write(settings.serialize())
- print('Saved settings to', f.name)
+ print('KiMesh: Saved settings to', f.name)
except:
wx.MessageDialog(self, "Cannot save settings: {}.".format(e), "File I/O error").ShowModal()
@@ -262,7 +268,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
for zone in self.board.Zones():
if zone.GetDoNotAllowCopperPour() and zone.GetLayerSet().Contains(target_layer_id):
keepouts.append(zone.Outline())
- print(f'Found {len(keepouts)} keepout areas.')
+ print(f'KiMesh: Found {len(keepouts)} keepout areas.')
if self.board_has_outline() and self.m_useOutlineCheckbox.Value: # Avoid foot-gun due to insane API. See note in the function.
outlines = pcbnew.SHAPE_POLY_SET()
@@ -270,7 +276,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
board_outlines = list(self.poly_set_to_shapely(outlines))
board_mask = shapely.ops.unary_union(board_outlines)
mask = board_mask.buffer(-settings.edge_clearance)
- print('board outline bounds:', mask.bounds)
+ print('KiMesh: Board outline bounds:', mask.bounds)
if mask.is_empty:
return wx.MessageDialog(self, "Error: Board edge clearance is set too high. There is nothing left for the mesh after applying clearance.").ShowModal()
else:
@@ -284,15 +290,15 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
mask = zone_mask
else:
mask = zone_mask.intersection(mask)
- print('Mesh mask bounds:', zone_mask.bounds)
+ print('KiMesh: Mesh mask bounds:', zone_mask.bounds)
if self.m_useKeepoutCheckbox.Value:
keepout_outlines = [ outline for zone in keepouts for outline in self.poly_set_to_shapely(zone) ]
keepout_mask = shapely.ops.unary_union(keepout_outlines)
if not keepout_mask.is_empty:
mask = shapely.difference(mask, keepout_mask)
- print('keepout mask bounds:', keepout_mask.bounds)
- print('resulting mask bounds:', mask.bounds)
+ print('KiMesh: Keepout mask bounds:', keepout_mask.bounds)
+ print('KiMesh: Total mask bounds:', mask.bounds)
if mask.is_empty:
return wx.MessageDialog(self, "Error: After applying all keepouts, and intersecting with the board's outline, the mesh outline is empty.")
@@ -345,7 +351,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
width_per_trace = trace_width + space_width
grid_cell_width = width_per_trace * num_traces * 2
- print(f'mesh cell size is {grid_cell_width}')
+ print(f'KiMesh: mesh cell size is {grid_cell_width} mm')
x0, y0 = anchor_pads[len(anchor_pads)//2].GetPosition()
x0, y0 = pcbnew.ToMM(x0), pcbnew.ToMM(y0)
@@ -353,7 +359,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
xl, yl = pcbnew.ToMM(xl), pcbnew.ToMM(yl)
mesh_angle = math.atan2(xl-x0, yl-y0)
- print('mesh angle is', math.degrees(mesh_angle))
+ print('KiMesh Mesh angle is', math.degrees(mesh_angle), 'degrees')
len_along = - width_per_trace/2
x0 += len_along * math.sin(mesh_angle)
y0 += len_along * math.cos(mesh_angle)
@@ -366,7 +372,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
grid_origin = grid_x0*grid_cell_width, grid_y0*grid_cell_width
grid_rows = int(math.ceil((bbox[3] - grid_origin[1]) / grid_cell_width))
grid_cols = int(math.ceil((bbox[2] - grid_origin[0]) / grid_cell_width))
- print(f'generating grid of size {grid_rows} * {grid_cols} with origin {grid_x0}, {grid_y0}')
+ print(f'KiMesh: Generating grid of size {grid_rows} * {grid_cols} with origin {grid_x0}, {grid_y0}')
grid = []
for y in range(grid_y0, grid_y0+grid_rows):
@@ -380,6 +386,17 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
row.append(cell)
grid.append(row)
+ def check_track_collision(cell, clearance=0.2):
+ cell_lc = pcbnew.SHAPE_LINE_CHAIN([pcbnew.VECTOR2I(pcbnew.FromMM(pt_x), pcbnew.FromMM(pt_y))
+ for pt_x, pt_y in cell.exterior.coords], True)
+ for track_or_via in self.board.GetTracks():
+ if not track_or_via.GetLayerSet().Contains(target_layer_id):
+ continue
+
+ if pcbnew.ToMM(track_or_via.GetEffectiveShape().GetClearance(cell_lc)) < clearance:
+ return True
+ return False
+
num_valid = 0
with self.viz('mesh_grid.svg') as dbg:
dbg.add(mask, color='#00000020')
@@ -389,11 +406,17 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
if mask.contains(cell):
if x == -1 and y == 0: # exit cell
color = '#ff00ff80'
+
+ elif check_track_collision(cell):
+ color = '#ffff0080'
+
else:
num_valid += 1
color = '#00ff0080'
+
elif mask.overlaps(cell):
- color = '#ffff0080'
+ color = '#ff800080'
+
else:
color = '#ff000080'
dbg.add(cell, color=color)
@@ -401,11 +424,32 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
for foo in anchor_outlines:
dbg.add(foo, color='#0000ff00', stroke_width=0.05, stroke_color='#000000ff')
+ for track in self.board.GetTracks():
+ if not track.GetLayerSet().Contains(target_layer_id):
+ continue
+
+ shape = track.GetEffectiveShape().Cast()
+ if isinstance(shape, pcbnew.SHAPE_SEGMENT):
+ seg = shape.GetSeg()
+ dbg.add([[(pcbnew.ToMM(seg.A.x), pcbnew.ToMM(seg.A.y)),
+ (pcbnew.ToMM(seg.B.x), pcbnew.ToMM(seg.B.y))]],
+ color='none', stroke_width=pcbnew.ToMM(shape.GetWidth()), stroke_color='#ff0000ff')
+
+ elif isinstance(shape, pcbnew.SHAPE_CIRCLE):
+ center = shape.GetCenter()
+ c_cx, c_cy = pcbnew.ToMM(center.y), pcbnew.ToMM(center.y)
+ c_r = pcbnew.ToMM(shape.GetRadius())
+ dbg.add([[(c_cx, c_cy-c_r), (c_cx, c_cy+c_r)], [(c_cx-c_r, c_cy), (c_cx+c_r, c_cy)]], color='none', stroke_width=0.05, stroke_color='#ff0000ff')
+
dbg.add([[(x0-2, y0), (x0+2, y0)], [(x0, y0-2), (x0, y0+2)]], color='none', stroke_width=0.05, stroke_color='#ff0000ff')
def is_valid(cell):
if not mask.contains(cell):
return False
+
+ if self.m_trackClearanceCheckbox.Value and check_track_collision(cell, self.m_trackClearanceSpin.Value):
+ return False
+
return True
def iter_neighbors(x, y):
@@ -439,8 +483,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
rnd_state.shuffle(l)
yield from l
- def add_track(segment:geometry.LineString, net=None):
- coords = list(segment.coords)
+ def add_track(coords, net=None):
for (x1, y1), (x2, y2) in zip(coords, coords[1:]):
if (x1, y1) == (x2, y2): # zero-length track due to zero chamfer
continue
@@ -530,6 +573,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
segment = affinity.translate(segment, x0, y0)
dbg_per_tile.add(segment, stroke_width=trace_width, color='#ff000000', stroke_color=stroke_color)
+ tracks_to_add = []
armed = False
while not_visited or stack:
for n_x, n_y, bmask in skewed_random_iter(iter_neighbors(x, y), entry_dir, settings.randomness):
@@ -565,16 +609,21 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
dbg_composite.add(segment, stroke_width=trace_width, color='#ff000000', stroke_color='#ffffff60')
dbg_traces.add(segment, stroke_width=trace_width, color='#ff000000', stroke_color='#000000ff')
dbg_tiles.add(segment, stroke_width=trace_width, color='#ff000000', stroke_color=stroke_color)
- add_track(segment, netinfos[net]) # FIXME (works, disabled for debug)
+ tracks_to_add.append((list(segment.coords), netinfos[net]))
track_count += 1
+
if not stack:
break
+
if armed:
i += 1
#dump_output(i)
armed = False
*stack, (x, y, key, entry_dir, depth) = stack
+ for coords, net in tracks_to_add:
+ add_track(coords, net)
+
dbg_cells.scale_colors('visit_depth', max_depth)
dbg_composite.scale_colors('visit_depth', max_depth)
@@ -585,7 +634,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
dbg_tiles.add(foo, color='#00000080', stroke_width=0.05, stroke_color='#00000000')
- print(f'Added {track_count} trace segments.')
+ print(f'KiMesh: Added {track_count} trace segments.')
#pcbnew.Refresh()
#self.tearup_mesh()
@@ -732,7 +781,7 @@ class DebugOutputWrapper:
raise ValueError(f'Unhandled shapely object type {type(obj)}')
return (f'<path fill-rule="evenodd" fill="{fill_color}" opacity="{opacity}" stroke="{stroke_color}" '
- f'stroke-width="{stroke_width}" d="{path}" />')
+ f'stroke-width="{stroke_width}" stroke-linecap="round" stroke-linejoin="round" d="{path}" />')
def save(self, margin:'unit'=5, scale:'px/unit'=10):
#specify margin in coordinate units
diff --git a/de.jaseg.kimesh.plugin/plugins/mesh_plugin_dialog.py b/de.jaseg.kimesh.plugin/plugins/mesh_plugin_dialog.py
index 790caa8..062e63c 100644
--- a/de.jaseg.kimesh.plugin/plugins/mesh_plugin_dialog.py
+++ b/de.jaseg.kimesh.plugin/plugins/mesh_plugin_dialog.py
@@ -17,7 +17,7 @@ import wx.xrc
class MainDialog ( wx.Dialog ):
def __init__( self, parent ):
- wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Security Mesh Generator Plugin", pos = wx.DefaultPosition, size = wx.Size( 632,580 ), style = wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.MINIMIZE_BOX|wx.RESIZE_BORDER|wx.STAY_ON_TOP )
+ wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Security Mesh Generator Plugin", pos = wx.DefaultPosition, size = wx.Size( 632,650 ), style = wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.MINIMIZE_BOX|wx.RESIZE_BORDER|wx.STAY_ON_TOP )
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
@@ -160,6 +160,21 @@ class MainDialog ( wx.Dialog ):
fgSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 )
+ self.m_trackClearanceCheckbox = wx.CheckBox( self, wx.ID_ANY, u"Respect Tracks and Vias", wx.DefaultPosition, wx.DefaultSize, 0 )
+ fgSizer1.Add( self.m_trackClearanceCheckbox, 0, wx.ALL, 5 )
+
+ self.m_staticText15 = wx.StaticText( self, wx.ID_ANY, u"Track/Via clearance", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticText15.Wrap( -1 )
+
+ fgSizer1.Add( self.m_staticText15, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+ self.m_trackClearanceSpin = wx.SpinCtrlDouble( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.SP_ARROW_KEYS, 0, 1000, 0.2, 0.1 )
+ self.m_trackClearanceSpin.SetDigits( 3 )
+ fgSizer1.Add( self.m_trackClearanceSpin, 0, wx.ALL, 5 )
+
+
+ fgSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 )
+
self.m_vizCheckbox = wx.CheckBox( self, wx.ID_ANY, u"Save layout visualizations", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_vizCheckbox.SetValue(True)
fgSizer1.Add( self.m_vizCheckbox, 0, wx.ALL, 5 )
diff --git a/main_dialog.fbp b/main_dialog.fbp
index d97f4c0..0740008 100644
--- a/main_dialog.fbp
+++ b/main_dialog.fbp
@@ -48,7 +48,7 @@
<property name="minimum_size"></property>
<property name="name">MainDialog</property>
<property name="pos"></property>
- <property name="size">632,580</property>
+ <property name="size">632,650</property>
<property name="style">wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSTAY_ON_TOP</property>
<property name="subclass">; ; forward_declare</property>
<property name="title">Security Mesh Generator Plugin</property>
@@ -1573,6 +1573,208 @@
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
+ <property name="checked">0</property>
+ <property name="close_button">1</property>
+ <property name="context_help"></property>
+ <property name="context_menu">1</property>
+ <property name="default_pane">0</property>
+ <property name="dock">Dock</property>
+ <property name="dock_fixed">0</property>
+ <property name="docking">Left</property>
+ <property name="drag_accept_files">0</property>
+ <property name="enabled">1</property>
+ <property name="fg"></property>
+ <property name="floatable">1</property>
+ <property name="font"></property>
+ <property name="gripper">0</property>
+ <property name="hidden">0</property>
+ <property name="id">wxID_ANY</property>
+ <property name="label">Respect Tracks and Vias</property>
+ <property name="max_size"></property>
+ <property name="maximize_button">0</property>
+ <property name="maximum_size"></property>
+ <property name="min_size"></property>
+ <property name="minimize_button">0</property>
+ <property name="minimum_size"></property>
+ <property name="moveable">1</property>
+ <property name="name">m_trackClearanceCheckbox</property>
+ <property name="pane_border">1</property>
+ <property name="pane_position"></property>
+ <property name="pane_size"></property>
+ <property name="permission">protected</property>
+ <property name="pin_button">1</property>
+ <property name="pos"></property>
+ <property name="resize">Resizable</property>
+ <property name="show">1</property>
+ <property name="size"></property>
+ <property name="style"></property>
+ <property name="subclass">; ; forward_declare</property>
+ <property name="toolbar_pane">0</property>
+ <property name="tooltip"></property>
+ <property name="validator_data_type"></property>
+ <property name="validator_style">wxFILTER_NONE</property>
+ <property name="validator_type">wxDefaultValidator</property>
+ <property name="validator_variable"></property>
+ <property name="window_extra_style"></property>
+ <property name="window_name"></property>
+ <property name="window_style"></property>
+ </object>
+ </object>
+ <object class="sizeritem" expanded="true">
+ <property name="border">5</property>
+ <property name="flag">wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</property>
+ <property name="proportion">0</property>
+ <object class="wxStaticText" expanded="true">
+ <property name="BottomDockable">1</property>
+ <property name="LeftDockable">1</property>
+ <property name="RightDockable">1</property>
+ <property name="TopDockable">1</property>
+ <property name="aui_layer"></property>
+ <property name="aui_name"></property>
+ <property name="aui_position"></property>
+ <property name="aui_row"></property>
+ <property name="best_size"></property>
+ <property name="bg"></property>
+ <property name="caption"></property>
+ <property name="caption_visible">1</property>
+ <property name="center_pane">0</property>
+ <property name="close_button">1</property>
+ <property name="context_help"></property>
+ <property name="context_menu">1</property>
+ <property name="default_pane">0</property>
+ <property name="dock">Dock</property>
+ <property name="dock_fixed">0</property>
+ <property name="docking">Left</property>
+ <property name="drag_accept_files">0</property>
+ <property name="enabled">1</property>
+ <property name="fg"></property>
+ <property name="floatable">1</property>
+ <property name="font"></property>
+ <property name="gripper">0</property>
+ <property name="hidden">0</property>
+ <property name="id">wxID_ANY</property>
+ <property name="label">Track/Via clearance</property>
+ <property name="markup">0</property>
+ <property name="max_size"></property>
+ <property name="maximize_button">0</property>
+ <property name="maximum_size"></property>
+ <property name="min_size"></property>
+ <property name="minimize_button">0</property>
+ <property name="minimum_size"></property>
+ <property name="moveable">1</property>
+ <property name="name">m_staticText15</property>
+ <property name="pane_border">1</property>
+ <property name="pane_position"></property>
+ <property name="pane_size"></property>
+ <property name="permission">protected</property>
+ <property name="pin_button">1</property>
+ <property name="pos"></property>
+ <property name="resize">Resizable</property>
+ <property name="show">1</property>
+ <property name="size"></property>
+ <property name="style"></property>
+ <property name="subclass">; ; forward_declare</property>
+ <property name="toolbar_pane">0</property>
+ <property name="tooltip"></property>
+ <property name="window_extra_style"></property>
+ <property name="window_name"></property>
+ <property name="window_style"></property>
+ <property name="wrap">-1</property>
+ </object>
+ </object>
+ <object class="sizeritem" expanded="true">
+ <property name="border">5</property>
+ <property name="flag">wxALL</property>
+ <property name="proportion">0</property>
+ <object class="wxSpinCtrlDouble" expanded="true">
+ <property name="BottomDockable">1</property>
+ <property name="LeftDockable">1</property>
+ <property name="RightDockable">1</property>
+ <property name="TopDockable">1</property>
+ <property name="aui_layer"></property>
+ <property name="aui_name"></property>
+ <property name="aui_position"></property>
+ <property name="aui_row"></property>
+ <property name="best_size"></property>
+ <property name="bg"></property>
+ <property name="caption"></property>
+ <property name="caption_visible">1</property>
+ <property name="center_pane">0</property>
+ <property name="close_button">1</property>
+ <property name="context_help"></property>
+ <property name="context_menu">1</property>
+ <property name="default_pane">0</property>
+ <property name="digits">3</property>
+ <property name="dock">Dock</property>
+ <property name="dock_fixed">0</property>
+ <property name="docking">Left</property>
+ <property name="drag_accept_files">0</property>
+ <property name="enabled">1</property>
+ <property name="fg"></property>
+ <property name="floatable">1</property>
+ <property name="font"></property>
+ <property name="gripper">0</property>
+ <property name="hidden">0</property>
+ <property name="id">wxID_ANY</property>
+ <property name="inc">0.1</property>
+ <property name="initial">0.2</property>
+ <property name="max">1000</property>
+ <property name="max_size"></property>
+ <property name="maximize_button">0</property>
+ <property name="maximum_size"></property>
+ <property name="min">0</property>
+ <property name="min_size"></property>
+ <property name="minimize_button">0</property>
+ <property name="minimum_size"></property>
+ <property name="moveable">1</property>
+ <property name="name">m_trackClearanceSpin</property>
+ <property name="pane_border">1</property>
+ <property name="pane_position"></property>
+ <property name="pane_size"></property>
+ <property name="permission">protected</property>
+ <property name="pin_button">1</property>
+ <property name="pos"></property>
+ <property name="resize">Resizable</property>
+ <property name="show">1</property>
+ <property name="size"></property>
+ <property name="style">wxSP_ARROW_KEYS</property>
+ <property name="subclass">; ; forward_declare</property>
+ <property name="toolbar_pane">0</property>
+ <property name="tooltip"></property>
+ <property name="value"></property>
+ <property name="window_extra_style"></property>
+ <property name="window_name"></property>
+ <property name="window_style"></property>
+ </object>
+ </object>
+ <object class="sizeritem" expanded="true">
+ <property name="border">5</property>
+ <property name="flag">wxEXPAND</property>
+ <property name="proportion">1</property>
+ <object class="spacer" expanded="true">
+ <property name="height">0</property>
+ <property name="permission">protected</property>
+ <property name="width">0</property>
+ </object>
+ </object>
+ <object class="sizeritem" expanded="true">
+ <property name="border">5</property>
+ <property name="flag">wxALL</property>
+ <property name="proportion">0</property>
+ <object class="wxCheckBox" expanded="true">
+ <property name="BottomDockable">1</property>
+ <property name="LeftDockable">1</property>
+ <property name="RightDockable">1</property>
+ <property name="TopDockable">1</property>
+ <property name="aui_layer"></property>
+ <property name="aui_name"></property>
+ <property name="aui_position"></property>
+ <property name="aui_row"></property>
+ <property name="best_size"></property>
+ <property name="bg"></property>
+ <property name="caption"></property>
+ <property name="caption_visible">1</property>
+ <property name="center_pane">0</property>
<property name="checked">1</property>
<property name="close_button">1</property>
<property name="context_help"></property>
diff --git a/package.py b/package.py
index 942d367..a07ed60 100644
--- a/package.py
+++ b/package.py
@@ -41,7 +41,7 @@ def do_release(version, increment):
footprint_dir.mkdir()
print('Re-generating footprints')
- for n in range(2, 9):
+ for n in range(1, 9):
subprocess.run(['python', '-m', 'footprint_generator',
'-w', '0.100,0.120,0.150,0.200,0.250,0.300,0.350,0.400,0.500,0.600,0.700,0.800,1.000,1.200,1.500,1.800',
'-c', '0.100,0.120,0.150,0.200,0.300,0.400,0.500',