- fixed Find Optimal Plugin: there was an error triggered after finding the minimum distance

- upgraded the FInd Optimal Plugin UI
This commit is contained in:
Marius Stanciu
2021-10-02 23:40:02 +03:00
committed by Marius
parent fd8d473703
commit ff8ed49647
3 changed files with 149 additions and 67 deletions

View File

@@ -15,6 +15,8 @@ CHANGELOG for FlatCAM beta
- in Paint, NCC and Cutout Plugins when using a mode that require to be terminated (by mouse RMB or ESC key) the notebook UI element is disabled until this is done - in Paint, NCC and Cutout Plugins when using a mode that require to be terminated (by mouse RMB or ESC key) the notebook UI element is disabled until this is done
- for Transform and SolderPaste Plugins upgraded the UI - for Transform and SolderPaste Plugins upgraded the UI
- in SolderPaste Plugin now the paste is dispensed only on the pads/Gerber flashes - in SolderPaste Plugin now the paste is dispensed only on the pads/Gerber flashes
- fixed Find Optimal Plugin: there was an error triggered after finding the minimum distance
- upgraded the FInd Optimal Plugin UI
1.10.2021 1.10.2021

View File

@@ -850,7 +850,7 @@ class CornersUI:
self.tools_frame.setLayout(self.tools_box) self.tools_frame.setLayout(self.tools_box)
# ############################################################################################################# # #############################################################################################################
# Gerber Source Object Frame # Gerber Source Object
# ############################################################################################################# # #############################################################################################################
# Gerber object # # Gerber object #
@@ -881,9 +881,8 @@ class CornersUI:
par_frame = FCFrame() par_frame = FCFrame()
self.tools_box.addWidget(par_frame) self.tools_box.addWidget(par_frame)
# ## Grid Layout param_grid = FCGridLayout(v_spacing=5, h_spacing=3)
par_grid = FCGridLayout(v_spacing=5, h_spacing=3) par_frame.setLayout(param_grid)
par_frame.setLayout(par_grid)
# Type of Marker # Type of Marker
self.type_label = FCLabel('%s:' % _("Type")) self.type_label = FCLabel('%s:' % _("Type"))
@@ -896,8 +895,8 @@ class CornersUI:
{"label": _("Cross"), "value": "c"}, {"label": _("Cross"), "value": "c"},
]) ])
par_grid.addWidget(self.type_label, 2, 0) param_grid.addWidget(self.type_label, 2, 0)
par_grid.addWidget(self.type_radio, 2, 1) param_grid.addWidget(self.type_radio, 2, 1)
# Thickness # # Thickness #
self.thick_label = FCLabel('%s:' % _("Thickness")) self.thick_label = FCLabel('%s:' % _("Thickness"))
@@ -910,8 +909,8 @@ class CornersUI:
self.thick_entry.setWrapping(True) self.thick_entry.setWrapping(True)
self.thick_entry.setSingleStep(10 ** -self.decimals) self.thick_entry.setSingleStep(10 ** -self.decimals)
par_grid.addWidget(self.thick_label, 4, 0) param_grid.addWidget(self.thick_label, 4, 0)
par_grid.addWidget(self.thick_entry, 4, 1) param_grid.addWidget(self.thick_entry, 4, 1)
# Length # # Length #
self.l_label = FCLabel('%s:' % _("Length")) self.l_label = FCLabel('%s:' % _("Length"))
@@ -923,8 +922,8 @@ class CornersUI:
self.l_entry.set_precision(self.decimals) self.l_entry.set_precision(self.decimals)
self.l_entry.setSingleStep(10 ** -self.decimals) self.l_entry.setSingleStep(10 ** -self.decimals)
par_grid.addWidget(self.l_label, 6, 0) param_grid.addWidget(self.l_label, 6, 0)
par_grid.addWidget(self.l_entry, 6, 1) param_grid.addWidget(self.l_entry, 6, 1)
# Margin # # Margin #
self.margin_label = FCLabel('%s:' % _("Margin")) self.margin_label = FCLabel('%s:' % _("Margin"))
@@ -936,8 +935,8 @@ class CornersUI:
self.margin_entry.set_precision(self.decimals) self.margin_entry.set_precision(self.decimals)
self.margin_entry.setSingleStep(0.1) self.margin_entry.setSingleStep(0.1)
par_grid.addWidget(self.margin_label, 8, 0) param_grid.addWidget(self.margin_label, 8, 0)
par_grid.addWidget(self.margin_entry, 8, 1) param_grid.addWidget(self.margin_entry, 8, 1)
# ############################################################################################################# # #############################################################################################################
# Locations Frame # Locations Frame
@@ -1050,7 +1049,7 @@ class CornersUI:
grid_drill.addWidget(self.drill_dia_label, 0, 0) grid_drill.addWidget(self.drill_dia_label, 0, 0)
grid_drill.addWidget(self.drill_dia_entry, 0, 1) grid_drill.addWidget(self.drill_dia_entry, 0, 1)
FCGridLayout.set_common_column_size([grid_sel, par_grid, grid_loc, grid_drill], 0) FCGridLayout.set_common_column_size([grid_sel, param_grid, grid_loc, grid_drill], 0)
# ## Create an Excellon object # ## Create an Excellon object
self.drill_button = FCButton(_("Create Excellon Object")) self.drill_button = FCButton(_("Create Excellon Object"))

View File

@@ -9,7 +9,7 @@ from PyQt6 import QtWidgets, QtCore, QtGui
from appTool import AppTool from appTool import AppTool
from appGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox, FCComboBox, \ from appGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox, FCComboBox, \
FCLabel, FCButton, VerticalScrollArea, FCGridLayout FCLabel, FCButton, VerticalScrollArea, FCGridLayout, FCFrame
from camlib import grace from camlib import grace
from shapely.geometry import MultiPolygon from shapely.geometry import MultiPolygon
@@ -129,10 +129,57 @@ class ToolOptimal(AppTool):
self.ui.reset_button.clicked.connect(self.set_tool_ui) self.ui.reset_button.clicked.connect(self.set_tool_ui)
def disconnect_signals(self):
try:
self.update_text.disconnect(self.on_update_text)
except (TypeError, AttributeError):
pass
try:
self.update_sec_distances.disconnect(self.on_update_sec_distances_txt)
except (TypeError, AttributeError):
pass
try:
self.ui.calculate_button.clicked.disconnect(self.find_minimum_distance)
except (TypeError, AttributeError):
pass
try:
self.ui.locate_button.clicked.disconnect(self.on_locate_position)
except (TypeError, AttributeError):
pass
try:
self.ui.locations_textb.cursorPositionChanged.disconnect(self.on_textbox_clicked)
except (TypeError, AttributeError):
pass
try:
self.ui.locate_sec_button.clicked.disconnect(self.on_locate_sec_position)
except (TypeError, AttributeError):
pass
try:
self.ui.distances_textb.cursorPositionChanged.disconnect(self.on_distances_textb_clicked)
except (TypeError, AttributeError):
pass
try:
self.ui.locations_sec_textb.cursorPositionChanged.disconnect(self.on_locations_sec_clicked)
except (TypeError, AttributeError):
pass
try:
self.ui.reset_button.clicked.disconnect(self.set_tool_ui)
except (TypeError, AttributeError):
pass
def set_tool_ui(self): def set_tool_ui(self):
self.clear_ui(self.layout) self.clear_ui(self.layout)
self.ui = OptimalUI(layout=self.layout, app=self.app) self.ui = OptimalUI(layout=self.layout, app=self.app)
self.pluginName = self.ui.pluginName self.pluginName = self.ui.pluginName
self.disconnect_signals()
self.connect_signals_at_init() self.connect_signals_at_init()
self.ui.result_entry.set_value(0.0) self.ui.result_entry.set_value(0.0)
@@ -182,7 +229,7 @@ class ToolOptimal(AppTool):
proc = self.app.proc_container.new('%s...' % _("Working")) proc = self.app.proc_container.new('%s...' % _("Working"))
def job_thread(app_obj): def job_thread(app_obj, plugin_instance):
app_obj.inform.emit(_("Optimal Tool. Started to search for the minimum distance between copper features.")) app_obj.inform.emit(_("Optimal Tool. Started to search for the minimum distance between copper features."))
try: try:
old_disp_number = 0 old_disp_number = 0
@@ -221,28 +268,28 @@ class ToolOptimal(AppTool):
'%s: %s' % (_("Optimal Tool. Finding the distances between each two elements. Iterations"), '%s: %s' % (_("Optimal Tool. Finding the distances between each two elements. Iterations"),
str(geo_len))) str(geo_len)))
self.min_dict = {} plugin_instance.min_dict = {}
idx = 1 idx = 1
for geo in total_geo: for geo in total_geo.geoms:
for s_geo in total_geo[idx:]: for s_geo in total_geo.geoms[idx:]:
if self.app.abort_flag: if app_obj.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise grace raise grace
# minimize the number of distances by not taking into considerations those that are too small # minimize the number of distances by not taking into considerations those that are too small
dist = geo.distance(s_geo) dist = geo.distance(s_geo)
dist = float('%.*f' % (self.decimals, dist)) dist = app_obj.dec_format(dist, plugin_instance.decimals)
loc_1, loc_2 = nearest_points(geo, s_geo) loc_1, loc_2 = nearest_points(geo, s_geo)
proc_loc = ( proc_loc = (
(float('%.*f' % (self.decimals, loc_1.x)), float('%.*f' % (self.decimals, loc_1.y))), (app_obj.dec_format(loc_1.x, self.decimals), app_obj.dec_format(loc_1.y, self.decimals)),
(float('%.*f' % (self.decimals, loc_2.x)), float('%.*f' % (self.decimals, loc_2.y))) (app_obj.dec_format(loc_2.x, self.decimals), app_obj.dec_format(loc_2.y, self.decimals))
) )
if dist in self.min_dict: if dist in plugin_instance.min_dict:
self.min_dict[dist].append(proc_loc) plugin_instance.min_dict[dist].append(proc_loc)
else: else:
self.min_dict[dist] = [proc_loc] plugin_instance.min_dict[dist] = [proc_loc]
pol_nr += 1 pol_nr += 1
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100])) disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
@@ -254,29 +301,29 @@ class ToolOptimal(AppTool):
app_obj.inform.emit(_("Optimal Tool. Finding the minimum distance.")) app_obj.inform.emit(_("Optimal Tool. Finding the minimum distance."))
min_list = list(self.min_dict.keys()) min_list = list(plugin_instance.min_dict.keys())
min_dist = min(min_list) min_dist = min(min_list)
min_dist -= 10**-self.decimals # make sure that this will work for isolation case rep_min_dist = min_dist - 10**-self.decimals # make sure that this will work for isolation case
min_dist_string = '%.*f' % (self.decimals, float(min_dist)) min_dist_string = str(app_obj.dec_format(rep_min_dist, self.decimals))
self.ui.result_entry.set_value(min_dist_string) plugin_instance.ui.result_entry.set_value(min_dist_string)
freq = len(self.min_dict[min_dist]) freq = len(plugin_instance.min_dict[min_dist])
freq = '%d' % int(freq) freq = '%d' % int(freq)
self.ui.freq_entry.set_value(freq) plugin_instance.ui.freq_entry.set_value(freq)
min_locations = self.min_dict.pop(min_dist) min_locations = plugin_instance.min_dict.pop(min_dist)
self.update_text.emit(min_locations) self.update_text.emit(min_locations)
self.update_sec_distances.emit(self.min_dict) self.update_sec_distances.emit(plugin_instance.min_dict)
app_obj.inform.emit('[success] %s' % _("Optimal Tool. Finished successfully.")) app_obj.inform.emit('[success] %s' % _("Optimal Tool. Finished successfully."))
except Exception as ee: except Exception as ee:
proc.done() proc.done()
log.error(str(ee)) app_obj.log.error(str(ee))
return return
proc.done() proc.done()
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]}) self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app, self]})
def on_locate_position(self): def on_locate_position(self):
# cursor = self.locations_textb.textCursor() # cursor = self.locations_textb.textCursor()
@@ -443,11 +490,16 @@ class OptimalUI:
} }
""") """)
self.layout.addWidget(title_label) self.layout.addWidget(title_label)
self.layout.addWidget(FCLabel("")) # self.layout.addWidget(FCLabel(""))
# ## Grid Layout # #############################################################################################################
grid0 = FCGridLayout(v_spacing=5, h_spacing=3) # Gerber Source Object
self.layout.addLayout(grid0) # #############################################################################################################
self.obj_combo_label = FCLabel('<span style="color:darkorange;"><b>%s</b></span>' % _("Source Object"))
self.obj_combo_label.setToolTip(
"Gerber object for which to find the minimum distance between copper features."
)
self.layout.addWidget(self.obj_combo_label)
# ## Gerber Object to mirror # ## Gerber Object to mirror
self.gerber_object_combo = FCComboBox() self.gerber_object_combo = FCComboBox()
@@ -460,13 +512,25 @@ class OptimalUI:
self.gerber_object_label.setToolTip( self.gerber_object_label.setToolTip(
"Gerber object for which to find the minimum distance between copper features." "Gerber object for which to find the minimum distance between copper features."
) )
grid0.addWidget(self.gerber_object_label, 0, 0, 1, 2) self.layout.addWidget(self.gerber_object_combo)
grid0.addWidget(self.gerber_object_combo, 2, 0, 1, 2)
separator_line = QtWidgets.QFrame() # separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine) # separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) # separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
grid0.addWidget(separator_line, 4, 0, 1, 2) # grid0.addWidget(separator_line, 4, 0, 1, 2)
# #############################################################################################################
# Parameters Frame
# #############################################################################################################
self.param_label = FCLabel('<span style="color:blue;"><b>%s</b></span>' % _('Parameters'))
self.param_label.setToolTip(_("Parameters used for this tool."))
self.layout.addWidget(self.param_label)
par_frame = FCFrame()
self.layout.addWidget(par_frame)
param_grid = FCGridLayout(v_spacing=5, h_spacing=3)
par_frame.setLayout(param_grid)
# Precision = nr of decimals # Precision = nr of decimals
self.precision_label = FCLabel('%s:' % _("Precision")) self.precision_label = FCLabel('%s:' % _("Precision"))
@@ -475,13 +539,21 @@ class OptimalUI:
self.precision_spinner = FCSpinner(callback=self.confirmation_message_int) self.precision_spinner = FCSpinner(callback=self.confirmation_message_int)
self.precision_spinner.set_range(2, 10) self.precision_spinner.set_range(2, 10)
self.precision_spinner.setWrapping(True) self.precision_spinner.setWrapping(True)
grid0.addWidget(self.precision_label, 6, 0) param_grid.addWidget(self.precision_label, 0, 0)
grid0.addWidget(self.precision_spinner, 6, 1) param_grid.addWidget(self.precision_spinner, 0, 1)
# Results Title # #############################################################################################################
self.title_res_label = FCLabel('<b>%s:</b>' % _("Minimum distance")) # Results Frame
self.title_res_label.setToolTip(_("Display minimum distance between copper features.")) # #############################################################################################################
grid0.addWidget(self.title_res_label, 8, 0, 1, 2) res_label = FCLabel('<span style="color:green;"><b>%s</b></span>' % _("Minimum distance"))
res_label.setToolTip(_("Display minimum distance between copper features."))
self.layout.addWidget(res_label)
res_frame = FCFrame()
self.layout.addWidget(res_frame)
res_grid = FCGridLayout(v_spacing=5, h_spacing=3, c_stretch=[0, 1, 0])
res_frame.setLayout(res_grid)
# Result value # Result value
self.result_label = FCLabel('%s:' % _("Determined")) self.result_label = FCLabel('%s:' % _("Determined"))
@@ -491,25 +563,23 @@ class OptimalUI:
self.units_lbl = FCLabel(self.units.lower()) self.units_lbl = FCLabel(self.units.lower())
self.units_lbl.setDisabled(True) self.units_lbl.setDisabled(True)
hlay = QtWidgets.QHBoxLayout() res_grid.addWidget(self.result_label, 0, 0)
hlay.addWidget(self.result_entry) res_grid.addWidget(self.result_entry, 0, 1)
hlay.addWidget(self.units_lbl) res_grid.addWidget(self.units_lbl, 0, 2)
grid0.addWidget(self.units_lbl, 10, 0)
grid0.addLayout(hlay, 10, 1)
# Frequency of minimum encounter # Frequency of minimum encounter
self.freq_label = FCLabel('%s:' % _("Occurring")) self.freq_label = FCLabel('%s:' % _("Occurring"))
self.freq_label.setToolTip(_("How many times this minimum is found.")) self.freq_label.setToolTip(_("How many times this minimum is found."))
self.freq_entry = FCEntry() self.freq_entry = FCEntry()
self.freq_entry.setReadOnly(True) self.freq_entry.setReadOnly(True)
grid0.addWidget(self.freq_label, 12, 0)
grid0.addWidget(self.freq_entry, 12, 1) res_grid.addWidget(self.freq_label, 2, 0)
res_grid.addWidget(self.freq_entry, 2, 1, 1, 2)
# Control if to display the locations of where the minimum was found # Control if to display the locations of where the minimum was found
self.locations_cb = FCCheckBox(_("Minimum points coordinates")) self.locations_cb = FCCheckBox(_("Minimum points coordinates"))
self.locations_cb.setToolTip(_("Coordinates for points where minimum distance was found.")) self.locations_cb.setToolTip(_("Coordinates for points where minimum distance was found."))
grid0.addWidget(self.locations_cb, 14, 0, 1, 2) res_grid.addWidget(self.locations_cb, 4, 0, 1, 3)
# Locations where minimum was found # Locations where minimum was found
self.locations_textb = FCTextArea() self.locations_textb = FCTextArea()
@@ -524,7 +594,7 @@ class OptimalUI:
""" """
self.locations_textb.setStyleSheet(stylesheet) self.locations_textb.setStyleSheet(stylesheet)
grid0.addWidget(self.locations_textb, 16, 0, 1, 2) res_grid.addWidget(self.locations_textb, 6, 0, 1, 3)
# Jump button # Jump button
self.locate_button = FCButton(_("Jump to selected position")) self.locate_button = FCButton(_("Jump to selected position"))
@@ -534,24 +604,33 @@ class OptimalUI:
) )
self.locate_button.setMinimumWidth(60) self.locate_button.setMinimumWidth(60)
self.locate_button.setDisabled(True) self.locate_button.setDisabled(True)
grid0.addWidget(self.locate_button, 18, 0, 1, 2) res_grid.addWidget(self.locate_button, 8, 0, 1, 3)
# Other distances in Gerber # #############################################################################################################
self.title_second_res_label = FCLabel('<b>%s:</b>' % _("Other distances")) # Other Distances
# #############################################################################################################
self.title_second_res_label = FCLabel('<span style="color:magenta;"><b>%s</b></span>' % _("Other distances"))
self.title_second_res_label.setToolTip(_("Will display other distances in the Gerber file ordered from\n" self.title_second_res_label.setToolTip(_("Will display other distances in the Gerber file ordered from\n"
"the minimum to the maximum, not including the absolute minimum.")) "the minimum to the maximum, not including the absolute minimum."))
grid0.addWidget(self.title_second_res_label, 20, 0, 1, 2) self.layout.addWidget(self.title_second_res_label)
other_frame = FCFrame()
self.layout.addWidget(other_frame)
other_grid = FCGridLayout(v_spacing=5, h_spacing=3)
other_frame.setLayout(other_grid)
# Control if to display the locations of where the minimum was found # Control if to display the locations of where the minimum was found
self.sec_locations_cb = FCCheckBox(_("Other distances points coordinates")) self.sec_locations_cb = FCCheckBox(_("Other distances points coordinates"))
self.sec_locations_cb.setToolTip(_("Other distances and the coordinates for points\n" self.sec_locations_cb.setToolTip(_("Other distances and the coordinates for points\n"
"where the distance was found.")) "where the distance was found."))
grid0.addWidget(self.sec_locations_cb, 22, 0, 1, 2) other_grid.addWidget(self.sec_locations_cb, 0, 0, 1, 2)
# this way I can hide/show the frame # this way I can hide/show the frame
self.sec_locations_frame = QtWidgets.QFrame() self.sec_locations_frame = QtWidgets.QFrame()
self.sec_locations_frame.setContentsMargins(0, 0, 0, 0) self.sec_locations_frame.setContentsMargins(0, 0, 0, 0)
self.layout.addWidget(self.sec_locations_frame) other_grid.addWidget(self.sec_locations_frame, 2, 0, 1, 2)
self.distances_box = QtWidgets.QVBoxLayout() self.distances_box = QtWidgets.QVBoxLayout()
self.distances_box.setContentsMargins(0, 0, 0, 0) self.distances_box.setContentsMargins(0, 0, 0, 0)
self.sec_locations_frame.setLayout(self.distances_box) self.sec_locations_frame.setLayout(self.distances_box)
@@ -629,6 +708,8 @@ class OptimalUI:
self.calculate_button.setMinimumWidth(60) self.calculate_button.setMinimumWidth(60)
self.layout.addWidget(self.calculate_button) self.layout.addWidget(self.calculate_button)
FCGridLayout.set_common_column_size([param_grid, res_grid], 0)
self.layout.addStretch(1) self.layout.addStretch(1)
# ## Reset Tool # ## Reset Tool