- 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:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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.")
|
||||||
|
|||||||
Reference in New Issue
Block a user