summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2023-10-23 14:51:15 +0200
committerjaseg <git@jaseg.de>2023-10-23 14:51:15 +0200
commitc4f176d3f43a020abeaa9d2500237d8ff77e5e3f (patch)
tree381547ad5638057527b36f3becc2d247e224df4c
parentcac262ce37357f224ea0253018be74cb61ef7ef8 (diff)
downloadkimesh-c4f176d3f43a020abeaa9d2500237d8ff77e5e3f.tar.gz
kimesh-c4f176d3f43a020abeaa9d2500237d8ff77e5e3f.tar.bz2
kimesh-c4f176d3f43a020abeaa9d2500237d8ff77e5e3f.zip
Improve error handling, add runtime options
-rw-r--r--main_dialog.fbp416
-rw-r--r--mesh_dialog.py142
-rw-r--r--mesh_plugin_dialog.py39
3 files changed, 556 insertions, 41 deletions
diff --git a/main_dialog.fbp b/main_dialog.fbp
index 9852735..d97f4c0 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,458</property>
+ <property name="size">632,580</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>
@@ -64,6 +64,68 @@
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
+ <property name="flag">wxALL|wxEXPAND</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">&lt;font color=&quot;red&quot;&gt;&lt;b&gt;Warning: Board outline not found&lt;/b&gt;&lt;/font&gt;</property>
+ <property name="markup">1</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_warningLabel</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">wxALIGN_CENTER_HORIZONTAL</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">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxFlexGridSizer" expanded="true">
@@ -1333,6 +1395,358 @@
</object>
</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>
+ <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 zone keepouts</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_useKeepoutCheckbox</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">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>
+ <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 board outline</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_useOutlineCheckbox</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">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>
+ <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">Save layout visualizations</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_vizCheckbox</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">Visualization output directory</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_staticText14</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|wxEXPAND</property>
+ <property name="proportion">0</property>
+ <object class="wxTextCtrl" 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="max_size"></property>
+ <property name="maximize_button">0</property>
+ <property name="maximum_size"></property>
+ <property name="maxlength"></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_vizTextfield</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="value"></property>
+ <property name="window_extra_style"></property>
+ <property name="window_name"></property>
+ <property name="window_style"></property>
+ </object>
+ </object>
</object>
</object>
<object class="sizeritem" expanded="true">
diff --git a/mesh_dialog.py b/mesh_dialog.py
index 9812bba..17dcf6a 100644
--- a/mesh_dialog.py
+++ b/mesh_dialog.py
@@ -8,6 +8,7 @@ from itertools import count, islice
import json
import re
from os import path
+import os
import wx
@@ -30,16 +31,20 @@ class AbortError(SystemError):
@dataclasses.dataclass
class GeneratorSettings:
- edge_clearance: float = 1.5 # mm
- anchor: str = None # Footprint designator
- chamfer: float = 0.0 # unit fraction
- mask_layer_id: int = 0 # kicad layer id, populated later
- random_seed: str = None
- randomness: float = 1.0
+ edge_clearance: float = 1.5 # mm
+ anchor: str = None # Footprint designator
+ chamfer: float = 0.0 # unit fraction
+ mask_layer_id: int = 0 # kicad layer id, populated later
+ random_seed: str = None
+ randomness: float = 1.0
+ use_keepouts: bool = True
+ use_outline: bool = True
+ save_visualization: bool = True
+ visualization_path: str = 'mesh_visualizations'
def serialize(self):
d = dataclasses.asdict(self)
- d['kimesh_settings_version'] = '2.0.0'
+ d['kimesh_settings_version'] = '2.1.0'
return json.dumps(d).encode()
@classmethod
@@ -47,7 +52,7 @@ class GeneratorSettings:
d = json.loads(data.decode())
version = d.pop('kimesh_settings_version')
vtup = tuple(map(int, version.split('.')))
- if vtup > (2, 0, 0):
+ if vtup > (2, 1, 0):
raise cls.VersionError("Project kimesh settings file is too new for this plugin's version.")
return cls(**d)
@@ -69,6 +74,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
self.nets = { str(wxs) for wxs, netinfo in board.GetNetsByName().items() }
self.update_net_label(None)
+ self.update_outline_warning()
self.Fit()
@@ -104,9 +110,64 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
self.m_seedInput.Value = settings.random_seed or ''
self.m_randomnessSpin.Value = settings.randomness*100.0
self.m_edgeClearanceSpin.Value = settings.edge_clearance
+ self.m_useOutlineCheckbox.Value = settings.use_outline
+ self.m_useKeepoutCheckbox.Value = settings.use_keepouts
+ self.m_vizTextfield.Value = settings.visualization_path
+ self.m_vizCheckbox.Value = settings.save_visualization
self.SetMinSize(self.GetSize())
+ @contextmanager
+ def viz(self, filename):
+ if self.m_vizCheckbox.Value:
+ val = self.m_vizTextfield.Value
+ project_dir = path.dirname(self.board.GetFileName())
+ if val:
+ val = path.join(project_dir, val)
+ if not os.path.isdir(val):
+ os.mkdir(val)
+ filename = path.join(val, filename)
+
+ filename = path.join(project_dir, filename)
+ with open(filename, 'w') as f:
+ wrapper = DebugOutputWrapper(f)
+ yield wrapper
+ wrapper.save()
+
+ else:
+ wrapper = DebugOutputWrapper(None)
+ yield wrapper
+
+ def board_has_outline(self):
+ # KiCad's API is absolutely insane. As long as the board has an outline, the board outline function works
+ # alright. Now imagine the Edge.Cuts layer is empty. What would be a sane thing to do? I guess raising an error
+ # would be the best, with the second best being to return something like the hull of all objects on the other
+ # layers. Alas, KiCad doesn't do either. Instead, KiCad returns the union of the shapes of all objects on the
+ # **VISIBLE** layers, so the result of that outline function changes with which layers the user has set to
+ # visible. Whyyyyy :(
+ #
+ # We have to work around this to avoid presenting the user with a foot-gun in case they hide their mesh
+ # definition layer.
+ #
+ edge_cuts = self.board.GetLayerID('Edge.Cuts')
+ outline_objs = []
+ for drawing in self.board.GetDrawings():
+ if drawing.GetLayer() == edge_cuts:
+ return True
+ else:
+ return False
+
+ def update_outline_warning(self):
+ outlines = pcbnew.SHAPE_POLY_SET()
+ self.board.GetBoardPolygonOutlines(outlines)
+ board_outlines = list(self.poly_set_to_shapely(outlines))
+ board_mask = shapely.ops.unary_union(board_outlines)
+
+ if not self.board_has_outline() or board_mask.is_empty:
+ self.m_warningLabel.SetLabelMarkup('<b>Warning: Board outline not found</b>')
+ else:
+ self.m_warningLabel.SetLabelMarkup('')
+
def get_matching_nets(self):
prefix = self.m_net_prefix.Value
return { net for net in self.nets if net.startswith(prefix) }
@@ -170,7 +231,11 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
chamfer = float(self.m_chamferSpin.Value)/100.0,
mask_layer_id = self.m_maskLayerChoice.GetSelection(),
random_seed = str(self.m_seedInput.Value) or None,
- randomness = float(self.m_randomnessSpin.Value)/100.0)
+ randomness = float(self.m_randomnessSpin.Value)/100.0,
+ use_outline = self.m_useOutlineCheckbox.Value,
+ use_keepouts = self.m_useKeepoutCheckbox.Value,
+ visualization_path = self.m_vizTextfield.Value,
+ save_visualization = self.m_vizCheckbox.Value)
except ValueError as e:
return wx.MessageDialog(self, "Invalid input value: {}.".format(e), "Invalid input").ShowModal()
@@ -198,29 +263,37 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
keepouts.append(zone.Outline())
print(f'Found {len(keepouts)} keepout areas.')
- outlines = pcbnew.SHAPE_POLY_SET()
- 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)
- print('board outline bounds:', board_mask.bounds)
- if board_mask.is_empty:
- return wx.MessageDialog(self, "Error: Could not find the board outline, or board edge clearance is set too high.").ShowModal()
+ 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()
+ self.board.GetBoardPolygonOutlines(outlines)
+ 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)
+ 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:
+ mask = None
zone_outlines = [ outline for zone in mesh_zones for outline in self.poly_set_to_shapely(zone) ]
zone_mask = shapely.ops.unary_union(zone_outlines)
if zone_mask.is_empty:
- mask = board_mask
+ return wx.MessageDialog(self, "Error: Empty mesh outline on mesh outline layer. Make sure the mesh outline is defined with polygon objects only. Other shapes are not supported yet.").ShowModal()
+ elif mask is None:
+ mask = zone_mask
else:
- mask = zone_mask.intersection(board_mask)
+ mask = zone_mask.intersection(mask)
print('Mesh mask bounds:', zone_mask.bounds)
- 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)
+ 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)
+ 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.")
try:
def warn(msg):
@@ -307,7 +380,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
grid.append(row)
num_valid = 0
- with DebugOutput('dbg_grid.svg') as dbg:
+ with self.viz('mesh_grid.svg') as dbg:
dbg.add(mask, color='#00000020')
for y, row in enumerate(grid, start=grid_y0):
@@ -389,10 +462,10 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
not_visited = { (x, y) for x in range(grid_x0, grid_x0+grid_cols) for y in range(grid_y0, grid_y0+grid_rows) if is_valid(grid[y-grid_y0][x-grid_x0]) }
num_to_visit = len(not_visited)
track_count = 0
- with DebugOutput('dbg_cells.svg') as dbg_cells,\
- DebugOutput('dbg_composite.svg') as dbg_composite,\
- DebugOutput('dbg_tiles.svg') as dbg_tiles,\
- DebugOutput('dbg_traces.svg') as dbg_traces:
+ with self.viz('mesh_cells.svg') as dbg_cells,\
+ self.viz('mesh_composite.svg') as dbg_composite,\
+ self.viz('mesh_tiles.svg') as dbg_tiles,\
+ self.viz('mesh_traces.svg') as dbg_traces:
dbg_cells.add(mask, color='#00000020')
dbg_composite.add(mask, color='#00000020')
dbg_traces.add(mask, color='#00000020')
@@ -425,7 +498,7 @@ class MeshPluginMainDialog(mesh_plugin_dialog.MainDialog):
i = 0
past_tiles = {}
def dump_output(i):
- with DebugOutput(f'per-tile/step{i}.svg') as dbg_per_tile:
+ with self.viz(f'per-tile/step{i}.svg') as dbg_per_tile:
dbg_per_tile.add(mask, color='#00000020')
for foo in anchor_outlines:
dbg_per_tile.add(foo, color='#00000080', stroke_width=0.05, stroke_color='#00000000')
@@ -607,13 +680,6 @@ def virihex(val, max=1.0, alpha=1.0):
r, g, b, a = [ int(round(0xff*c)) for c in [r, g, b, alpha] ]
return f'#{r:02x}{g:02x}{b:02x}{a:02x}'
-@contextmanager
-def DebugOutput(filename):
- with open(filename, 'w') as f:
- wrapper = DebugOutputWrapper(f)
- yield wrapper
- wrapper.save()
-
class DebugOutputWrapper:
def __init__(self, f):
self.f = f
diff --git a/mesh_plugin_dialog.py b/mesh_plugin_dialog.py
index 6223481..790caa8 100644
--- a/mesh_plugin_dialog.py
+++ b/mesh_plugin_dialog.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
###########################################################################
-## Python code generated with wxFormBuilder (version 3.10.1-367-gf0e67a69)
+## Python code generated with wxFormBuilder (version 3.10.1-380-gf48f2659)
## http://www.wxformbuilder.org/
##
## PLEASE DO *NOT* EDIT THIS FILE!
@@ -17,12 +17,18 @@ 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,458 ), 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,580 ), style = wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.MINIMIZE_BOX|wx.RESIZE_BORDER|wx.STAY_ON_TOP )
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
+ self.m_warningLabel = wx.StaticText( self, wx.ID_ANY, u"<font color=\"red\"><b>Warning: Board outline not found</b></font>", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTER_HORIZONTAL )
+ self.m_warningLabel.SetLabelMarkup( u"<font color=\"red\"><b>Warning: Board outline not found</b></font>" )
+ self.m_warningLabel.Wrap( -1 )
+
+ bSizer1.Add( self.m_warningLabel, 0, wx.ALL|wx.EXPAND, 5 )
+
fgSizer1 = wx.FlexGridSizer( 0, 2, 0, 0 )
fgSizer1.AddGrowableCol( 1 )
fgSizer1.SetFlexibleDirection( wx.BOTH )
@@ -138,6 +144,35 @@ class MainDialog ( wx.Dialog ):
fgSizer1.Add( bSizer12, 1, wx.EXPAND, 5 )
+ fgSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 )
+
+ self.m_useKeepoutCheckbox = wx.CheckBox( self, wx.ID_ANY, u"Respect zone keepouts", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_useKeepoutCheckbox.SetValue(True)
+ fgSizer1.Add( self.m_useKeepoutCheckbox, 0, wx.ALL, 5 )
+
+
+ fgSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 )
+
+ self.m_useOutlineCheckbox = wx.CheckBox( self, wx.ID_ANY, u"Respect board outline", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_useOutlineCheckbox.SetValue(True)
+ fgSizer1.Add( self.m_useOutlineCheckbox, 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 )
+
+ self.m_staticText14 = wx.StaticText( self, wx.ID_ANY, u"Visualization output directory", wx.DefaultPosition, wx.DefaultSize, 0 )
+ self.m_staticText14.Wrap( -1 )
+
+ fgSizer1.Add( self.m_staticText14, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+ self.m_vizTextfield = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+ fgSizer1.Add( self.m_vizTextfield, 0, wx.ALL|wx.EXPAND, 5 )
+
+
bSizer1.Add( fgSizer1, 1, wx.EXPAND, 5 )
bSizer99 = wx.BoxSizer( wx.HORIZONTAL )