summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjaseg <git@jaseg.net>2020-12-29 12:03:52 +0100
committerjaseg <git@jaseg.net>2020-12-29 12:14:42 +0100
commit8913c91e83c92cb35a72b1a1cafb90117eec38a7 (patch)
tree5f7e3631e794bf39b7f540593aef4126edb4544d
parentecde8f1c8fd48b52b834a85fc234715c0cad12a4 (diff)
downloadkimesh-8913c91e83c92cb35a72b1a1cafb90117eec38a7.tar.gz
kimesh-8913c91e83c92cb35a72b1a1cafb90117eec38a7.tar.bz2
kimesh-8913c91e83c92cb35a72b1a1cafb90117eec38a7.zip
Persist settings
-rw-r--r--plugin/main_dialog.fbp197
-rw-r--r--plugin/mesh_dialog.py67
-rw-r--r--plugin/mesh_plugin_dialog.py19
3 files changed, 278 insertions, 5 deletions
diff --git a/plugin/main_dialog.fbp b/plugin/main_dialog.fbp
index 65bd700..2d08714 100644
--- a/plugin/main_dialog.fbp
+++ b/plugin/main_dialog.fbp
@@ -895,6 +895,203 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
+ <property name="label">Board edge 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_staticText261</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="1">
+ <property name="border">5</property>
+ <property name="flag">wxEXPAND</property>
+ <property name="proportion">1</property>
+ <object class="wxBoxSizer" expanded="1">
+ <property name="minimum_size"></property>
+ <property name="name">bSizer51</property>
+ <property name="orient">wxHORIZONTAL</property>
+ <property name="permission">none</property>
+ <object class="sizeritem" expanded="1">
+ <property name="border">5</property>
+ <property name="flag">wxALL</property>
+ <property name="proportion">0</property>
+ <object class="wxSpinCtrlDouble" expanded="1">
+ <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="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">1.500000</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_edgeClearanceSpin</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="1">
+ <property name="border">5</property>
+ <property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
+ <property name="proportion">0</property>
+ <object class="wxStaticText" expanded="1">
+ <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="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">mm</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_staticText61</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>
+ </object>
+ <object class="sizeritem" expanded="1">
+ <property name="border">5</property>
+ <property name="flag">wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</property>
+ <property name="proportion">0</property>
+ <object class="wxStaticText" expanded="1">
+ <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="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">Anchor exit direction</property>
<property name="markup">0</property>
<property name="max_size"></property>
diff --git a/plugin/mesh_dialog.py b/plugin/mesh_dialog.py
index b9911b6..fbdbd7a 100644
--- a/plugin/mesh_dialog.py
+++ b/plugin/mesh_dialog.py
@@ -1,10 +1,12 @@
from collections import defaultdict
-from dataclasses import dataclass
+import dataclasses
from contextlib import contextmanager
import textwrap
import random
import math
from itertools import count, islice
+import json
+from os import path
import wx
@@ -25,12 +27,14 @@ class GeneratorError(ValueError):
class AbortError(SystemError):
pass
-@dataclass
+@dataclasses.dataclass
class GeneratorSettings:
mesh_angle: float = 0.0 # deg
trace_width: float = 0.127 # mm
space_width: float = 0.127 # mm
+ edge_clearance: float = 1.5 # mm
anchor_exit: float = 0.0 # deg
+ anchor: str = None # Footprint designator
num_traces: int = 2
offset_x: float = 0.0 # mm
offset_y: float = 0.0 # mm
@@ -40,6 +44,24 @@ class GeneratorSettings:
random_seed: str = None
randomness: float = 1.0
+ def serialize(self):
+ d = dataclasses.asdict(self)
+ d['kimesh_settings_version'] = '1.0.0'
+ return json.dumps(d).encode()
+
+ @classmethod
+ def deserialize(cls, data):
+ d = json.loads(data.decode())
+ version = d.pop('kimesh_settings_version')
+ vtup = tuple(map(int, version.split('.')))
+ if vtup > (2, 0, 0):
+ raise cls.VersionError("Project kimesh settings file is too new for this plugin's version.")
+ return cls(**d)
+
+ class VersionError(ValueError):
+ pass
+
+
class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
def __init__(self, board):
mesh_plugin_dialog.MainDialog.__init__(self, None)
@@ -67,9 +89,32 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
self.m_maskLayerChoice.Append(name)
if name == 'User.Eco1':
self.m_maskLayerChoice.SetSelection(i)
- elif name == 'F.Cu':
+ elif name == 'B.Cu':
self.m_layerChoice.SetSelection(i)
+ if path.isfile(self.settings_fn()):
+ with open(self.settings_fn(), 'rb') as f:
+ try:
+ settings = GeneratorSettings.deserialize(f.read())
+
+ self.m_angleSpin.Value = settings.mesh_angle
+ self.m_traceSpin.Value = settings.trace_width
+ self.m_spaceSpin.Value = settings.space_width
+ self.m_exitSpin.Value = settings.anchor_exit
+ self.m_anchorInput.Value = settings.anchor
+ self.m_traceCountSpin.Value = settings.num_traces
+ self.m_offsetXSpin.Value = settings.offset_x
+ self.m_offsetYSpin.Value = settings.offset_y
+ self.m_chamferSpin.Value = settings.chamfer*100.0
+ self.m_layerChoice.SetSelection(settings.target_layer_id)
+ self.m_maskLayerChoice.SetSelection(settings.mask_layer_id)
+ self.m_seedInput.Value = settings.random_seed or ''
+ self.m_randomnessSpin.Value = settings.randomness*100.0
+ self.m_edgeClearanceSpin.Value = settings.edge_clearance
+
+ except GeneratorSettings.VersionError as e:
+ wx.MessageDialog(self, "Cannot load settings: {}.".format(e), "File I/O error").ShowModal()
+
self.SetMinSize(self.GetSize())
def get_matching_nets(self):
@@ -120,13 +165,18 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
self.board.Remove(track)
print(f'Tore up {count} trace segments.')
+ def settings_fn(self):
+ return path.join(path.dirname(self.board.GetFileName()), 'last_kimesh_settings.json')
+
def generate_mesh(self, evt):
try:
settings = GeneratorSettings(
mesh_angle = float(self.m_angleSpin.Value),
trace_width = float(self.m_traceSpin.Value),
space_width = float(self.m_spaceSpin.Value),
+ edge_clearance = float(self.m_edgeClearanceSpin.Value),
anchor_exit = float(self.m_exitSpin.Value),
+ anchor = str(self.m_anchorInput.Value),
num_traces = int(self.m_traceCountSpin.Value),
offset_x = float(self.m_offsetXSpin.Value),
offset_y = float(self.m_offsetYSpin.Value),
@@ -138,6 +188,13 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
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)
+ except:
+ wx.MessageDialog(self, "Cannot save settings: {}.".format(e), "File I/O error").ShowModal()
+
mesh_zones = []
for drawing in self.board.GetDrawings():
if drawing.GetLayer() == settings.mask_layer_id:
@@ -151,13 +208,14 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
self.board.GetBoardPolygonOutlines(outlines, "")
board_outlines = list(self.poly_set_to_shapely(outlines))
board_mask = shapely.ops.unary_union(board_outlines)
+ board_mask = board_mask.buffer(-settings.edge_clearance)
zone_outlines = [ outline for zone in mesh_zones for outline in self.poly_set_to_shapely(zone.GetPolyShape()) ]
zone_mask = shapely.ops.unary_union(zone_outlines)
mask = zone_mask.intersection(board_mask)
- anchor = [ mod for mod in self.board.GetModules() if mod.GetReference() == self.m_anchorInput.Value ]
+ anchor = [ mod for mod in self.board.GetModules() if mod.GetReference() == settings.anchor ]
if len(anchor) == 0:
return wx.MessageDialog(self, f'Error: Could not find anchor footprint "{self.m_anchorInput.Value}".').ShowModal()
if len(anchor) > 1:
@@ -546,7 +604,6 @@ def virihex(val, max=1.0, alpha=1.0):
@contextmanager
def DebugOutput(filename):
- from os import path
filename = path.join('/tmp', filename)
with open(filename, 'w') as f:
wrapper = DebugOutputWrapper(f)
diff --git a/plugin/mesh_plugin_dialog.py b/plugin/mesh_plugin_dialog.py
index c1bdaa9..746030a 100644
--- a/plugin/mesh_plugin_dialog.py
+++ b/plugin/mesh_plugin_dialog.py
@@ -101,6 +101,25 @@ class MainDialog ( wx.Dialog ):
fgSizer1.Add( bSizer6, 1, wx.EXPAND, 5 )
+ self.m_staticText261 = wx.StaticText( self, wx.ID_ANY, u"Board edge clearance", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticText261.Wrap( -1 )
+
+ fgSizer1.Add( self.m_staticText261, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+ bSizer51 = wx.BoxSizer( wx.HORIZONTAL )
+
+ self.m_edgeClearanceSpin = wx.SpinCtrlDouble( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.SP_ARROW_KEYS, 0, 1000, 1.500000, 0.1 )
+ self.m_edgeClearanceSpin.SetDigits( 3 )
+ bSizer51.Add( self.m_edgeClearanceSpin, 0, wx.ALL, 5 )
+
+ self.m_staticText61 = wx.StaticText( self, wx.ID_ANY, u"mm", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticText61.Wrap( -1 )
+
+ bSizer51.Add( self.m_staticText61, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+
+ fgSizer1.Add( bSizer51, 1, wx.EXPAND, 5 )
+
self.m_staticText11 = wx.StaticText( self, wx.ID_ANY, u"Anchor exit direction", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText11.Wrap( -1 )