- Isolation Tool - added ability to find the tool diameter that will guarantee total isolation of the currently selected Gerber object

This commit is contained in:
Marius Stanciu
2020-08-26 18:32:28 +03:00
parent d4c922cdf9
commit be01e00898
2 changed files with 103 additions and 3 deletions

View File

@@ -17,6 +17,7 @@ CHANGELOG for FlatCAM beta
- Drilling Tool - when replacing Tools if more than one tool for one diameter is found, the application exit the process and display an error in status bar; some minor fixes - Drilling Tool - when replacing Tools if more than one tool for one diameter is found, the application exit the process and display an error in status bar; some minor fixes
- Isolation Tool - remade the UI - Isolation Tool - remade the UI
- Isolation Tool - modified the add new tool method to search first in Tools Database for a suitable tool - Isolation Tool - modified the add new tool method to search first in Tools Database for a suitable tool
- Isolation Tool - added ability to find the tool diameter that will guarantee total isolation of the currently selected Gerber object
25.08.2020 25.08.2020

View File

@@ -11,15 +11,15 @@ from appTool import AppTool
from appGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog, FCButton, \ from appGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog, FCButton, \
FCComboBox, OptionalInputSection, FCSpinner, FCLabel FCComboBox, OptionalInputSection, FCSpinner, FCLabel
from appParsers.ParseGerber import Gerber from appParsers.ParseGerber import Gerber
from camlib import grace
from copy import deepcopy from copy import deepcopy
import numpy as np import numpy as np
import math
import simplejson as json import simplejson as json
import sys import sys
from shapely.ops import cascaded_union from shapely.ops import cascaded_union, nearest_points
from shapely.geometry import MultiPolygon, Polygon, MultiLineString, LineString, LinearRing, Point from shapely.geometry import MultiPolygon, Polygon, MultiLineString, LineString, LinearRing, Point
from matplotlib.backend_bases import KeyEvent as mpl_key_event from matplotlib.backend_bases import KeyEvent as mpl_key_event
@@ -38,6 +38,8 @@ log = logging.getLogger('base')
class ToolIsolation(AppTool, Gerber): class ToolIsolation(AppTool, Gerber):
optimal_found_sig = QtCore.pyqtSignal(float)
def __init__(self, app): def __init__(self, app):
self.app = app self.app = app
self.decimals = self.app.decimals self.decimals = self.app.decimals
@@ -193,6 +195,9 @@ class ToolIsolation(AppTool, Gerber):
self.t_ui.add_newtool_button.clicked.connect(self.on_tool_add) self.t_ui.add_newtool_button.clicked.connect(self.on_tool_add)
self.t_ui.deltool_btn.clicked.connect(self.on_tool_delete) self.t_ui.deltool_btn.clicked.connect(self.on_tool_delete)
self.t_ui.find_optimal_button.clicked.connect(self.on_find_optimal_tooldia)
self.optimal_found_sig.connect(lambda val: self.t_ui.new_tooldia_entry.set_value(float(val)))
self.t_ui.reference_combo_type.currentIndexChanged.connect(self.on_reference_combo_changed) self.t_ui.reference_combo_type.currentIndexChanged.connect(self.on_reference_combo_changed)
self.t_ui.select_combo.currentIndexChanged.connect(self.on_toggle_reference) self.t_ui.select_combo.currentIndexChanged.connect(self.on_toggle_reference)
@@ -889,7 +894,100 @@ class ToolIsolation(AppTool, Gerber):
}) })
def on_find_optimal_tooldia(self): def on_find_optimal_tooldia(self):
pass self.units = self.app.defaults['units'].upper()
obj_name = self.t_ui.object_combo.currentText()
# Get source object.
try:
fcobj = self.app.collection.get_by_name(obj_name)
except Exception:
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), str(obj_name)))
return
if fcobj is None:
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), str(obj_name)))
return
proc = self.app.proc_container.new(_("Working..."))
def job_thread(app_obj):
try:
old_disp_number = 0
pol_nr = 0
app_obj.proc_container.update_view_text(' %d%%' % 0)
total_geo = []
for ap in list(fcobj.apertures.keys()):
if 'geometry' in fcobj.apertures[ap]:
for geo_el in fcobj.apertures[ap]['geometry']:
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
if 'solid' in geo_el and geo_el['solid'] is not None and geo_el['solid'].is_valid:
total_geo.append(geo_el['solid'])
total_geo = MultiPolygon(total_geo)
total_geo = total_geo.buffer(0)
try:
__ = iter(total_geo)
geo_len = len(total_geo)
geo_len = (geo_len * (geo_len - 1)) / 2
except TypeError:
app_obj.inform.emit('[ERROR_NOTCL] %s' %
_("The Gerber object has one Polygon as geometry.\n"
"There are no distances between geometry elements to be found."))
return 'fail'
min_dict = {}
idx = 1
for geo in total_geo:
for s_geo in total_geo[idx:]:
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
# minimize the number of distances by not taking into considerations those that are too small
dist = geo.distance(s_geo)
dist = float('%.*f' % (self.decimals, dist))
loc_1, loc_2 = nearest_points(geo, s_geo)
proc_loc = (
(float('%.*f' % (self.decimals, loc_1.x)), float('%.*f' % (self.decimals, loc_1.y))),
(float('%.*f' % (self.decimals, loc_2.x)), float('%.*f' % (self.decimals, loc_2.y)))
)
if dist in min_dict:
min_dict[dist].append(proc_loc)
else:
min_dict[dist] = [proc_loc]
pol_nr += 1
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
if old_disp_number < disp_number <= 100:
app_obj.proc_container.update_view_text(' %d%%' % disp_number)
old_disp_number = disp_number
idx += 1
min_list = list(min_dict.keys())
min_dist = min(min_list)
min_dist_truncated = self.app.dec_format(float(min_dist), self.decimals)
self.optimal_found_sig.emit(min_dist_truncated)
app_obj.inform.emit('[success] %s: %s %s' %
(_("Optimal tool diameter found"), str(min_dist_truncated), self.units.lower()))
except Exception as ee:
proc.done()
log.debug(str(ee))
return
proc.done()
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
def on_tool_add(self): def on_tool_add(self):
self.blockSignals(True) self.blockSignals(True)
@@ -2972,6 +3070,7 @@ class IsoUI:
# Find Optimal Tooldia # Find Optimal Tooldia
self.find_optimal_button = FCButton(_('Find Optimal')) self.find_optimal_button = FCButton(_('Find Optimal'))
self.find_optimal_button.setIcon(QtGui.QIcon(self.app.resource_location + '/open_excellon32.png'))
self.find_optimal_button.setToolTip( self.find_optimal_button.setToolTip(
_("Find a tool diameter that is guaranteed\n" _("Find a tool diameter that is guaranteed\n"
"to do a complete isolation.") "to do a complete isolation.")