- 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 - modified the add new tool method to search first in Tools Database  for a suitable tool
This commit is contained in:
Marius Stanciu
2020-08-26 17:21:00 +03:00
parent e22ae1ad6c
commit d4c922cdf9
3 changed files with 255 additions and 210 deletions

View File

@@ -14,6 +14,9 @@ CHANGELOG for FlatCAM beta
- Geometry object - now plotting color for an individual tool can be specified - Geometry object - now plotting color for an individual tool can be specified
- in CutOut Tool - when using 'thin gaps' option then the cut parts are colored differently than the rest of the geometry in the Geometry object - in CutOut Tool - when using 'thin gaps' option then the cut parts are colored differently than the rest of the geometry in the Geometry object
- solved some deprecation warnings (Shapely module) - solved some deprecation warnings (Shapely module)
- 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 - modified the add new tool method to search first in Tools Database for a suitable tool
25.08.2020 25.08.2020

View File

@@ -889,6 +889,10 @@ class ToolDrilling(AppTool, Excellon):
self.app.inform.emit('[ERROR] %s' % _("Failed to parse Tools DB file.")) self.app.inform.emit('[ERROR] %s' % _("Failed to parse Tools DB file."))
return return
if not self.tools_db_dict:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Tools DB empty."))
return
self.replace_tools() self.replace_tools()
def replace_tools(self): def replace_tools(self):
@@ -900,6 +904,8 @@ class ToolDrilling(AppTool, Excellon):
for orig_tool, orig_tool_val in self.excellon_tools.items(): for orig_tool, orig_tool_val in self.excellon_tools.items():
orig_tooldia = orig_tool_val['tooldia'] orig_tooldia = orig_tool_val['tooldia']
tool_found = 0
# look in database tools # look in database tools
for db_tool, db_tool_val in self.tools_db_dict.items(): for db_tool, db_tool_val in self.tools_db_dict.items():
db_tooldia = db_tool_val['tooldia'] db_tooldia = db_tool_val['tooldia']
@@ -908,6 +914,7 @@ class ToolDrilling(AppTool, Excellon):
# if we find a tool with the same diameter in the Tools DB just update it's data # if we find a tool with the same diameter in the Tools DB just update it's data
if orig_tooldia == db_tooldia: if orig_tooldia == db_tooldia:
tool_found += 1
for d in db_tool_val['data']: for d in db_tool_val['data']:
if d.find('tools_drill') == 0: if d.find('tools_drill') == 0:
new_tools_dict[orig_tool]['data'][d] = db_tool_val['data'][d] new_tools_dict[orig_tool]['data'][d] = db_tool_val['data'][d]
@@ -918,6 +925,7 @@ class ToolDrilling(AppTool, Excellon):
new_tools_dict[orig_tool]['data'][d] = db_tool_val['data'][d] new_tools_dict[orig_tool]['data'][d] = db_tool_val['data'][d]
# search for a tool that has a tolerance that the tool fits in # search for a tool that has a tolerance that the tool fits in
elif high_limit >= orig_tooldia >= low_limit: elif high_limit >= orig_tooldia >= low_limit:
tool_found += 1
new_tools_dict[orig_tool]['tooldia'] = db_tooldia new_tools_dict[orig_tool]['tooldia'] = db_tooldia
for d in db_tool_val['data']: for d in db_tool_val['data']:
if d.find('tools_drill') == 0: if d.find('tools_drill') == 0:
@@ -928,6 +936,13 @@ class ToolDrilling(AppTool, Excellon):
else: else:
new_tools_dict[orig_tool]['data'][d] = db_tool_val['data'][d] new_tools_dict[orig_tool]['data'][d] = db_tool_val['data'][d]
if tool_found > 1:
self.app.inform.emit(
'[WARNING_NOTCL] %s' % _("Cancelled.\n"
"Multiple tools for one tool diameter found in Tools Database."))
self.blockSignals(False)
return
self.excellon_tools = new_tools_dict self.excellon_tools = new_tools_dict
self.build_tool_ui() self.build_tool_ui()

View File

@@ -9,13 +9,15 @@ from PyQt5 import QtWidgets, QtCore, QtGui
from appTool import AppTool 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, OptionalHideInputSection FCComboBox, OptionalInputSection, FCSpinner, FCLabel
from appParsers.ParseGerber import Gerber from appParsers.ParseGerber import Gerber
from copy import deepcopy from copy import deepcopy
import numpy as np import numpy as np
import math import math
import simplejson as json
import sys
from shapely.ops import cascaded_union from shapely.ops import cascaded_union
from shapely.geometry import MultiPolygon, Polygon, MultiLineString, LineString, LinearRing, Point from shapely.geometry import MultiPolygon, Polygon, MultiLineString, LineString, LinearRing, Point
@@ -54,15 +56,18 @@ class ToolIsolation(AppTool, Gerber):
# ############################################################################# # #############################################################################
self.t_ui.tools_table.setupContextMenu() self.t_ui.tools_table.setupContextMenu()
self.t_ui.tools_table.addContextMenu( self.t_ui.tools_table.addContextMenu(
_("Add"), self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png") _("Search and Add"), self.on_add_tool_by_key,
icon=QtGui.QIcon(self.app.resource_location + "/plus16.png")
) )
self.t_ui.tools_table.addContextMenu( self.t_ui.tools_table.addContextMenu(
_("Add from DB"), self.on_add_tool_by_key, icon=QtGui.QIcon(self.app.resource_location + "/plus16.png") _("Pick from DB"),
self.on_add_tool_by_key,
icon=QtGui.QIcon(self.app.resource_location + "/search_db32.png")
) )
self.t_ui.tools_table.addContextMenu( self.t_ui.tools_table.addContextMenu(
_("Delete"), lambda: _("Delete"),
self.on_tool_delete(rows_to_delete=None, all_tools=None), lambda: self.on_tool_delete(rows_to_delete=None, all_tools=None),
icon=QtGui.QIcon(self.app.resource_location + "/delete32.png") icon=QtGui.QIcon(self.app.resource_location + "/trash16.png")
) )
# ############################################################################# # #############################################################################
@@ -139,8 +144,6 @@ class ToolIsolation(AppTool, Gerber):
"i_iso_type": "tools_iso_isotype" "i_iso_type": "tools_iso_isotype"
} }
self.old_tool_dia = None
self.connect_signals_at_init() self.connect_signals_at_init()
def install(self, icon=None, separator=None, **kwargs): def install(self, icon=None, separator=None, **kwargs):
@@ -187,14 +190,9 @@ class ToolIsolation(AppTool, Gerber):
# ############################################################################# # #############################################################################
# ############################ SIGNALS ######################################## # ############################ SIGNALS ########################################
# ############################################################################# # #############################################################################
self.t_ui.addtool_btn.clicked.connect(self.on_tool_add) self.t_ui.add_newtool_button.clicked.connect(self.on_tool_add)
self.t_ui.addtool_entry.returnPressed.connect(self.on_tooldia_updated)
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.tipdia_entry.returnPressed.connect(self.on_calculate_tooldia)
self.t_ui.tipangle_entry.returnPressed.connect(self.on_calculate_tooldia)
self.t_ui.cutz_entry.returnPressed.connect(self.on_calculate_tooldia)
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)
@@ -218,7 +216,6 @@ class ToolIsolation(AppTool, Gerber):
def set_tool_ui(self): def set_tool_ui(self):
self.units = self.app.defaults['units'].upper() self.units = self.app.defaults['units'].upper()
self.old_tool_dia = self.app.defaults["tools_iso_newdia"]
# try to select in the Gerber combobox the active object # try to select in the Gerber combobox the active object
try: try:
@@ -235,11 +232,6 @@ class ToolIsolation(AppTool, Gerber):
if app_mode == 'b': if app_mode == 'b':
self.t_ui.level.setText('<span style="color:green;"><b>%s</b></span>' % _('Basic')) self.t_ui.level.setText('<span style="color:green;"><b>%s</b></span>' % _('Basic'))
# override the Preferences Value; in Basic mode the Tool Type is always Circular ('C1')
self.t_ui.tool_type_radio.set_value('C1')
self.t_ui.tool_type_label.hide()
self.t_ui.tool_type_radio.hide()
self.t_ui.milling_type_label.hide() self.t_ui.milling_type_label.hide()
self.t_ui.milling_type_radio.hide() self.t_ui.milling_type_radio.hide()
@@ -267,10 +259,6 @@ class ToolIsolation(AppTool, Gerber):
else: else:
self.t_ui.level.setText('<span style="color:red;"><b>%s</b></span>' % _('Advanced')) self.t_ui.level.setText('<span style="color:red;"><b>%s</b></span>' % _('Advanced'))
self.t_ui.tool_type_radio.set_value(self.app.defaults["tools_iso_tool_type"])
self.t_ui.tool_type_label.show()
self.t_ui.tool_type_radio.show()
self.t_ui.milling_type_label.show() self.t_ui.milling_type_label.show()
self.t_ui.milling_type_radio.show() self.t_ui.milling_type_radio.show()
@@ -321,13 +309,7 @@ class ToolIsolation(AppTool, Gerber):
self.t_ui.poly_int_cb.set_value(self.app.defaults["tools_iso_poly_ints"]) self.t_ui.poly_int_cb.set_value(self.app.defaults["tools_iso_poly_ints"])
self.t_ui.forced_rest_iso_cb.set_value(self.app.defaults["tools_iso_force"]) self.t_ui.forced_rest_iso_cb.set_value(self.app.defaults["tools_iso_force"])
self.t_ui.cutz_entry.set_value(self.app.defaults["tools_iso_tool_cutz"]) self.t_ui.new_tooldia_entry.set_value(self.app.defaults["tools_iso_newdia"])
self.t_ui.tool_type_radio.set_value(self.app.defaults["tools_iso_tool_type"])
self.t_ui.tipdia_entry.set_value(self.app.defaults["tools_iso_tool_vtipdia"])
self.t_ui.tipangle_entry.set_value(self.app.defaults["tools_iso_tool_vtipangle"])
self.t_ui.addtool_entry.set_value(self.app.defaults["tools_iso_newdia"])
self.on_tool_type(val=self.t_ui.tool_type_radio.get_value())
loaded_obj = self.app.collection.get_by_name(self.t_ui.object_combo.get_value()) loaded_obj = self.app.collection.get_by_name(self.t_ui.object_combo.get_value())
if loaded_obj: if loaded_obj:
@@ -399,6 +381,7 @@ class ToolIsolation(AppTool, Gerber):
self.tooluid = 0 self.tooluid = 0
# adding tools from Preferences: FIXME should search in Tools Database
self.iso_tools.clear() self.iso_tools.clear()
for tool_dia in dias: for tool_dia in dias:
self.tooluid += 1 self.tooluid += 1
@@ -408,7 +391,7 @@ class ToolIsolation(AppTool, Gerber):
'offset': 'Path', 'offset': 'Path',
'offset_value': 0.0, 'offset_value': 0.0,
'type': 'Iso', 'type': 'Iso',
'tool_type': self.t_ui.tool_type_radio.get_value(), 'tool_type': 'V',
'data': deepcopy(self.default_data), 'data': deepcopy(self.default_data),
'solid_geometry': [] 'solid_geometry': []
} }
@@ -545,7 +528,6 @@ class ToolIsolation(AppTool, Gerber):
def ui_connect(self): def ui_connect(self):
self.t_ui.tools_table.itemChanged.connect(self.on_tool_edit) self.t_ui.tools_table.itemChanged.connect(self.on_tool_edit)
self.t_ui.tool_type_radio.activated_custom.connect(self.on_tool_type)
# rows selected # rows selected
self.t_ui.tools_table.clicked.connect(self.on_row_selection_change) self.t_ui.tools_table.clicked.connect(self.on_row_selection_change)
@@ -581,12 +563,6 @@ class ToolIsolation(AppTool, Gerber):
except (TypeError, AttributeError): except (TypeError, AttributeError):
pass pass
try:
# if connected, disconnect the signal from the slot on item_changed as it creates issues
self.t_ui.tool_type_radio.activated_custom.disconnect()
except (TypeError, AttributeError):
pass
# rows selected # rows selected
try: try:
self.t_ui.tools_table.clicked.disconnect() self.t_ui.tools_table.clicked.disconnect()
@@ -809,14 +785,10 @@ class ToolIsolation(AppTool, Gerber):
self.app.inform.emit('[WARNING_NOTCL] %s' % self.app.inform.emit('[WARNING_NOTCL] %s' %
_("Please enter a tool diameter with non-zero value, in Float format.")) _("Please enter a tool diameter with non-zero value, in Float format."))
return return
self.on_tool_add(dia=float(val)) self.on_tool_default_add(dia=float(val))
else: else:
self.app.inform.emit('[WARNING_NOTCL] %s...' % _("Adding Tool cancelled")) self.app.inform.emit('[WARNING_NOTCL] %s...' % _("Adding Tool cancelled"))
def on_tooldia_updated(self):
if self.t_ui.tool_type_radio.get_value() == 'C1':
self.old_tool_dia = self.t_ui.addtool_entry.get_value()
def on_reference_combo_changed(self): def on_reference_combo_changed(self):
obj_type = self.t_ui.reference_combo_type.currentIndex() obj_type = self.t_ui.reference_combo_type.currentIndex()
self.t_ui.reference_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex())) self.t_ui.reference_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
@@ -916,49 +888,155 @@ class ToolIsolation(AppTool, Gerber):
'tool_type': tt, 'tool_type': tt,
}) })
def on_tool_type(self, val): def on_find_optimal_tooldia(self):
if val == 'V': pass
self.t_ui.addtool_entry_lbl.setDisabled(True)
self.t_ui.addtool_entry.setDisabled(True)
self.t_ui.tipdialabel.show()
self.t_ui.tipdia_entry.show()
self.t_ui.tipanglelabel.show()
self.t_ui.tipangle_entry.show()
self.on_calculate_tooldia() def on_tool_add(self):
else: self.blockSignals(True)
self.t_ui.addtool_entry_lbl.setDisabled(False)
self.t_ui.addtool_entry.setDisabled(False)
self.t_ui.tipdialabel.hide()
self.t_ui.tipdia_entry.hide()
self.t_ui.tipanglelabel.hide()
self.t_ui.tipangle_entry.hide()
self.t_ui.addtool_entry.set_value(self.old_tool_dia) filename = self.app.data_path + '\\tools_db.FlatDB'
def on_calculate_tooldia(self): # construct a list of all 'tooluid' in the self.iso_tools
if self.t_ui.tool_type_radio.get_value() == 'V': tool_uid_list = [int(tooluid_key) for tooluid_key in self.iso_tools]
tip_dia = float(self.t_ui.tipdia_entry.get_value())
tip_angle = float(self.t_ui.tipangle_entry.get_value()) / 2.0
cut_z = float(self.t_ui.cutz_entry.get_value())
cut_z = -cut_z if cut_z < 0 else cut_z
# calculated tool diameter so the cut_z parameter is obeyed # find maximum from the temp_uid, add 1 and this is the new 'tooluid'
tool_dia = tip_dia + (2 * cut_z * math.tan(math.radians(tip_angle))) max_uid = 0 if not tool_uid_list else max(tool_uid_list)
tooluid = int(max_uid + 1)
# update the default_data so it is used in the iso_tools dict tool_dias = []
self.default_data.update({ for k, v in self.iso_tools.items():
"vtipdia": tip_dia, for tool_v in v.keys():
"vtipangle": (tip_angle * 2), if tool_v == 'tooldia':
}) tool_dias.append(self.app.dec_format(v[tool_v], self.decimals))
self.t_ui.addtool_entry.set_value(tool_dia) # determine the new tool diameter
tool_dia = self.t_ui.new_tooldia_entry.get_value()
if tool_dia is None or tool_dia == 0:
self.build_ui()
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Please enter a tool diameter with non-zero value, "
"in Float format."))
self.blockSignals(False)
return
truncated_tooldia = self.app.dec_format(tool_dia, self.decimals)
return tool_dia # if new tool diameter already in the Tool List then abort
else: if truncated_tooldia in tool_dias:
return float(self.t_ui.addtool_entry.get_value()) self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. Tool already in Tool Table."))
self.blockSignals(False)
return
def on_tool_add(self, dia=None, muted=None): # load the database tools from the file
try:
with open(filename) as f:
tools = f.read()
except IOError:
self.app.log.error("Could not load tools DB file.")
self.app.inform.emit('[ERROR] %s' % _("Could not load Tools DB file."))
self.blockSignals(False)
self.on_tool_default_add()
return
try:
# store here the tools from Tools Database when searching in Tools Database
tools_db_dict = json.loads(tools)
except Exception:
e = sys.exc_info()[0]
self.app.log.error(str(e))
self.app.inform.emit('[ERROR] %s' % _("Failed to parse Tools DB file."))
self.blockSignals(False)
self.on_tool_default_add()
return
if not tools_db_dict:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Tools DB empty."))
self.blockSignals(False)
return
new_tools_dict = deepcopy(self.default_data)
updated_tooldia = None
tool_found = 0
# look in database tools
for db_tool, db_tool_val in tools_db_dict.items():
db_tooldia = db_tool_val['tooldia']
low_limit = float(db_tool_val['data']['tol_min'])
high_limit = float(db_tool_val['data']['tol_max'])
# we need only tool marked for Isolation Tool
if db_tool_val['data']['tool_target'] != _('Isolation'):
continue
# if we find a tool with the same diameter in the Tools DB just update it's data
if truncated_tooldia == db_tooldia:
tool_found += 1
for d in db_tool_val['data']:
if d.find('tools_iso') == 0:
new_tools_dict[d] = db_tool_val['data'][d]
elif d.find('tools_') == 0:
# don't need data for other App Tools; this tests after 'tools_drill_'
continue
else:
new_tools_dict[d] = db_tool_val['data'][d]
# search for a tool that has a tolerance that the tool fits in
elif high_limit >= truncated_tooldia >= low_limit:
tool_found += 1
updated_tooldia = db_tooldia
for d in db_tool_val['data']:
if d.find('tools_iso') == 0:
new_tools_dict[d] = db_tool_val['data'][d]
elif d.find('tools_') == 0:
# don't need data for other App Tools; this tests after 'tools_drill_'
continue
else:
new_tools_dict[d] = db_tool_val['data'][d]
# test we found a suitable tool in Tools Database or if multiple ones
if tool_found == 0:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Tool not in Tools Database. Adding a default tool."))
self.on_tool_default_add()
self.blockSignals(False)
return
if tool_found > 1:
self.app.inform.emit(
'[WARNING_NOTCL] %s' % _("Cancelled.\n"
"Multiple tools for one tool diameter found in Tools Database."))
self.blockSignals(False)
return
# if new tool diameter found in Tools Database already in the Tool List then abort
if updated_tooldia is not None and updated_tooldia in tool_dias:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. Tool already in Tool Table."))
self.blockSignals(False)
return
self.iso_tools.update({
tooluid: {
'tooldia': updated_tooldia if updated_tooldia is not None else truncated_tooldia,
'offset': 'Path',
'offset_value': 0.0,
'type': ' Iso',
'tool_type': 'V',
'data': deepcopy(new_tools_dict),
'solid_geometry': []
}
})
self.blockSignals(False)
self.build_ui()
# select the tool just added
for row in range(self.t_ui.tools_table.rowCount()):
if int(self.t_ui.tools_table.item(row, 3).text()) == tooluid:
self.t_ui.tools_table.selectRow(row)
break
# update the UI form
self.update_ui()
self.app.inform.emit('[success] %s' % _("New tool added to Tool Table from Tools Database."))
def on_tool_default_add(self, dia=None, muted=None):
self.blockSignals(True) self.blockSignals(True)
self.units = self.app.defaults['units'].upper() self.units = self.app.defaults['units'].upper()
@@ -966,59 +1044,49 @@ class ToolIsolation(AppTool, Gerber):
if dia: if dia:
tool_dia = dia tool_dia = dia
else: else:
tool_dia = self.on_calculate_tooldia() tool_dia = self.t_ui.new_tooldia_entry.get_value()
if tool_dia is None:
self.build_ui()
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Please enter a tool diameter to add, in Float format."))
return
tool_dia = float('%.*f' % (self.decimals, tool_dia)) if tool_dia is None or tool_dia == 0:
self.build_ui()
if tool_dia == 0:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Please enter a tool diameter with non-zero value, " self.app.inform.emit('[WARNING_NOTCL] %s' % _("Please enter a tool diameter with non-zero value, "
"in Float format.")) "in Float format."))
self.blockSignals(False)
return return
# construct a list of all 'tooluid' in the self.tools tool_dia = self.app.dec_format(tool_dia, self.decimals)
tool_uid_list = []
for tooluid_key in self.iso_tools: # construct a list of all 'tooluid' in the self.iso_tools
tool_uid_item = int(tooluid_key) tool_uid_list = [int(tooluid_key) for tooluid_key in self.iso_tools]
tool_uid_list.append(tool_uid_item)
# find maximum from the temp_uid, add 1 and this is the new 'tooluid' # find maximum from the temp_uid, add 1 and this is the new 'tooluid'
if not tool_uid_list: max_uid = 0 if not tool_uid_list else max(tool_uid_list)
max_uid = 0
else:
max_uid = max(tool_uid_list)
self.tooluid = int(max_uid + 1) self.tooluid = int(max_uid + 1)
tool_dias = [] tool_dias = []
for k, v in self.iso_tools.items(): for k, v in self.iso_tools.items():
for tool_v in v.keys(): for tool_v in v.keys():
if tool_v == 'tooldia': if tool_v == 'tooldia':
tool_dias.append(float('%.*f' % (self.decimals, (v[tool_v])))) tool_dias.append(self.app.dec_format(v[tool_v], self.decimals))
if float('%.*f' % (self.decimals, tool_dia)) in tool_dias: truncated_tooldia = self.app.dec_format(tool_dia, self.decimals)
if truncated_tooldia in tool_dias:
if muted is None: if muted is None:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. Tool already in Tool Table.")) self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. Tool already in Tool Table."))
# self.t_ui.tools_table.itemChanged.connect(self.on_tool_edit) # self.t_ui.tools_table.itemChanged.connect(self.on_tool_edit)
self.blockSignals(False) self.blockSignals(False)
return return
else:
if muted is None: self.iso_tools.update({
self.app.inform.emit('[success] %s' % _("New tool added to Tool Table.")) int(self.tooluid): {
self.iso_tools.update({ 'tooldia': truncated_tooldia,
int(self.tooluid): { 'offset': 'Path',
'tooldia': float('%.*f' % (self.decimals, tool_dia)), 'offset_value': 0.0,
'offset': 'Path', 'type': ' Iso',
'offset_value': 0.0, 'tool_type': 'V',
'type': ' Iso', 'data': deepcopy(self.default_data),
'tool_type': self.t_ui.tool_type_radio.get_value(), 'solid_geometry': []
'data': deepcopy(self.default_data), }
'solid_geometry': [] })
}
})
self.blockSignals(False) self.blockSignals(False)
self.build_ui() self.build_ui()
@@ -1029,6 +1097,12 @@ class ToolIsolation(AppTool, Gerber):
self.t_ui.tools_table.selectRow(row) self.t_ui.tools_table.selectRow(row)
break break
# update the UI form
self.update_ui()
if muted is None:
self.app.inform.emit('[success] %s' % _("New tool added to Tool Table."))
def on_tool_edit(self, item): def on_tool_edit(self, item):
self.blockSignals(True) self.blockSignals(True)
@@ -2747,7 +2821,7 @@ class IsoUI:
self.tools_box.addLayout(self.title_box) self.tools_box.addLayout(self.title_box)
# ## Title # ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName) title_label = FCLabel("%s" % self.toolName)
title_label.setStyleSheet(""" title_label.setStyleSheet("""
QLabel QLabel
{ {
@@ -2763,7 +2837,7 @@ class IsoUI:
self.title_box.addWidget(title_label) self.title_box.addWidget(title_label)
# App Level label # App Level label
self.level = QtWidgets.QLabel("") self.level = FCLabel("")
self.level.setToolTip( self.level.setToolTip(
_( _(
"BASIC is suitable for a beginner. Many parameters\n" "BASIC is suitable for a beginner. Many parameters\n"
@@ -2777,7 +2851,7 @@ class IsoUI:
self.level.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self.level.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.title_box.addWidget(self.level) self.title_box.addWidget(self.level)
self.obj_combo_label = QtWidgets.QLabel('<b>%s</b>:' % _("GERBER")) self.obj_combo_label = FCLabel('<b>%s</b>:' % _("GERBER"))
self.obj_combo_label.setToolTip( self.obj_combo_label.setToolTip(
_("Gerber object for isolation routing.") _("Gerber object for isolation routing.")
) )
@@ -2801,7 +2875,7 @@ class IsoUI:
self.tools_box.addWidget(separator_line) self.tools_box.addWidget(separator_line)
# ### Tools ## ## # ### Tools ## ##
self.tools_table_label = QtWidgets.QLabel('<b>%s</b>' % _('Tools Table')) self.tools_table_label = FCLabel('<b>%s</b>' % _('Tools Table'))
self.tools_table_label.setToolTip( self.tools_table_label.setToolTip(
_("Tools pool from which the algorithm\n" _("Tools pool from which the algorithm\n"
"will pick the ones used for copper clearing.") "will pick the ones used for copper clearing.")
@@ -2849,7 +2923,7 @@ class IsoUI:
self.tools_box.addLayout(grid1) self.tools_box.addLayout(grid1)
# Tool order # Tool order
self.order_label = QtWidgets.QLabel('%s:' % _('Tool order')) self.order_label = FCLabel('%s:' % _('Tool order'))
self.order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n" self.order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n"
"'No' --> means that the used order is the one in the tool table\n" "'No' --> means that the used order is the one in the tool table\n"
"'Forward' --> means that the tools will be ordered from small to big\n" "'Forward' --> means that the tools will be ordered from small to big\n"
@@ -2878,101 +2952,53 @@ class IsoUI:
self.grid3.setColumnStretch(1, 1) self.grid3.setColumnStretch(1, 1)
self.tools_box.addLayout(self.grid3) self.tools_box.addLayout(self.grid3)
self.tool_sel_label = QtWidgets.QLabel('<b>%s</b>' % _("New Tool")) self.tool_sel_label = FCLabel('<b>%s</b>' % _('Add from DB'))
self.grid3.addWidget(self.tool_sel_label, 1, 0, 1, 2) self.grid3.addWidget(self.tool_sel_label, 0, 0, 1, 2)
# Tool Type Radio Button
self.tool_type_label = QtWidgets.QLabel('%s:' % _('Tool Type'))
self.tool_type_label.setToolTip(
_("Default tool type:\n"
"- 'V-shape'\n"
"- Circular")
)
self.tool_type_radio = RadioSet([{'label': _('V-shape'), 'value': 'V'},
{'label': _('Circular'), 'value': 'C1'}])
self.tool_type_radio.setToolTip(
_("Default tool type:\n"
"- 'V-shape'\n"
"- Circular")
)
self.tool_type_radio.setObjectName("i_tool_type")
self.grid3.addWidget(self.tool_type_label, 2, 0)
self.grid3.addWidget(self.tool_type_radio, 2, 1)
# Tip Dia
self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
self.tipdialabel.setToolTip(
_("The tip diameter for V-Shape Tool"))
self.tipdia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tipdia_entry.set_precision(self.decimals)
self.tipdia_entry.set_range(0.0000, 9999.9999)
self.tipdia_entry.setSingleStep(0.1)
self.tipdia_entry.setObjectName("i_vtipdia")
self.grid3.addWidget(self.tipdialabel, 3, 0)
self.grid3.addWidget(self.tipdia_entry, 3, 1)
# Tip Angle
self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle'))
self.tipanglelabel.setToolTip(
_("The tip angle for V-Shape Tool.\n"
"In degree."))
self.tipangle_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.tipangle_entry.set_precision(self.decimals)
self.tipangle_entry.set_range(0.0000, 180.0000)
self.tipangle_entry.setSingleStep(5)
self.tipangle_entry.setObjectName("i_vtipangle")
self.grid3.addWidget(self.tipanglelabel, 4, 0)
self.grid3.addWidget(self.tipangle_entry, 4, 1)
# Cut Z entry
cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
cutzlabel.setToolTip(
_("Depth of cut into material. Negative value.\n"
"In FlatCAM units.")
)
self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.cutz_entry.set_precision(self.decimals)
self.cutz_entry.set_range(-99999.9999, 0.0000)
self.cutz_entry.setObjectName("i_vcutz")
self.grid3.addWidget(cutzlabel, 5, 0)
self.grid3.addWidget(self.cutz_entry, 5, 1)
# ### Tool Diameter #### # ### Tool Diameter ####
self.addtool_entry_lbl = QtWidgets.QLabel('%s:' % _('Tool Dia')) self.new_tooldia_lbl = FCLabel('%s:' % _('Tool Dia'))
self.addtool_entry_lbl.setToolTip( self.new_tooldia_lbl.setToolTip(
_("Diameter for the new tool to add in the Tool Table.\n" _("Diameter for the new tool to add in the Tool Table.\n"
"If the tool is V-shape type then this value is automatically\n" "If the tool is V-shape type then this value is automatically\n"
"calculated from the other parameters.") "calculated from the other parameters.")
) )
self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message) self.new_tooldia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.addtool_entry.set_precision(self.decimals) self.new_tooldia_entry.set_precision(self.decimals)
self.addtool_entry.set_range(0.000, 9999.9999) self.new_tooldia_entry.set_range(0.000, 9999.9999)
self.addtool_entry.setObjectName("i_new_tooldia") self.new_tooldia_entry.setObjectName("i_new_tooldia")
self.grid3.addWidget(self.addtool_entry_lbl, 6, 0) self.grid3.addWidget(self.new_tooldia_lbl, 2, 0)
self.grid3.addWidget(self.addtool_entry, 6, 1) self.grid3.addWidget(self.new_tooldia_entry, 2, 1)
# Find Optimal Tooldia
self.find_optimal_button = FCButton(_('Find Optimal'))
self.find_optimal_button.setToolTip(
_("Find a tool diameter that is guaranteed\n"
"to do a complete isolation.")
)
self.grid3.addWidget(self.find_optimal_button, 4, 0, 1, 2)
bhlay = QtWidgets.QHBoxLayout() bhlay = QtWidgets.QHBoxLayout()
self.addtool_btn = QtWidgets.QPushButton(_('Add')) self.add_newtool_button = FCButton(_('Search and Add'))
self.addtool_btn.setToolTip( self.add_newtool_button.setIcon(QtGui.QIcon(self.app.resource_location + '/plus16.png'))
self.add_newtool_button.setToolTip(
_("Add a new tool to the Tool Table\n" _("Add a new tool to the Tool Table\n"
"with the diameter specified above.") "with the diameter specified above.\n"
"This is done by a background search\n"
"in the Tools Database. If nothing is found\n"
"in the Tools DB then a default tool is added.")
) )
bhlay.addWidget(self.add_newtool_button)
self.addtool_from_db_btn = QtWidgets.QPushButton(_('Add from DB')) self.addtool_from_db_btn = FCButton(_('Pick from DB'))
self.addtool_from_db_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/search_db32.png'))
self.addtool_from_db_btn.setToolTip( self.addtool_from_db_btn.setToolTip(
_("Add a new tool to the Tool Table\n" _("Add a new tool to the Tool Table\n"
"from the Tool Database.\n" "from the Tool Database.\n"
"Tool database administration in Menu: Options -> Tools Database") "Tool database administration in Menu: Options -> Tools Database")
) )
bhlay.addWidget(self.addtool_btn)
bhlay.addWidget(self.addtool_from_db_btn) bhlay.addWidget(self.addtool_from_db_btn)
self.grid3.addLayout(bhlay, 7, 0, 1, 2) self.grid3.addLayout(bhlay, 7, 0, 1, 2)
@@ -2982,21 +3008,22 @@ class IsoUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
self.grid3.addWidget(separator_line, 8, 0, 1, 2) self.grid3.addWidget(separator_line, 8, 0, 1, 2)
self.deltool_btn = QtWidgets.QPushButton(_('Delete')) self.deltool_btn = FCButton(_('Delete'))
self.deltool_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/trash16.png'))
self.deltool_btn.setToolTip( self.deltool_btn.setToolTip(
_("Delete a selection of tools in the Tool Table\n" _("Delete a selection of tools in the Tool Table\n"
"by first selecting a row(s) in the Tool Table.") "by first selecting a row(s) in the Tool Table.")
) )
self.grid3.addWidget(self.deltool_btn, 9, 0, 1, 2) self.grid3.addWidget(self.deltool_btn, 9, 0, 1, 2)
# self.grid3.addWidget(QtWidgets.QLabel(''), 10, 0, 1, 2) # self.grid3.addWidget(FCLabel(''), 10, 0, 1, 2)
separator_line = QtWidgets.QFrame() separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine) separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
self.grid3.addWidget(separator_line, 11, 0, 1, 2) self.grid3.addWidget(separator_line, 11, 0, 1, 2)
self.tool_data_label = QtWidgets.QLabel( self.tool_data_label = FCLabel(
"<b>%s: <font color='#0000FF'>%s %d</font></b>" % (_('Parameters for'), _("Tool"), int(1))) "<b>%s: <font color='#0000FF'>%s %d</font></b>" % (_('Parameters for'), _("Tool"), int(1)))
self.tool_data_label.setToolTip( self.tool_data_label.setToolTip(
_( _(
@@ -3007,7 +3034,7 @@ class IsoUI:
self.grid3.addWidget(self.tool_data_label, 12, 0, 1, 2) self.grid3.addWidget(self.tool_data_label, 12, 0, 1, 2)
# Passes # Passes
passlabel = QtWidgets.QLabel('%s:' % _('Passes')) passlabel = FCLabel('%s:' % _('Passes'))
passlabel.setToolTip( passlabel.setToolTip(
_("Width of the isolation gap in\n" _("Width of the isolation gap in\n"
"number (integer) of tool widths.") "number (integer) of tool widths.")
@@ -3020,7 +3047,7 @@ class IsoUI:
self.grid3.addWidget(self.passes_entry, 13, 1) self.grid3.addWidget(self.passes_entry, 13, 1)
# Overlap Entry # Overlap Entry
overlabel = QtWidgets.QLabel('%s:' % _('Overlap')) overlabel = FCLabel('%s:' % _('Overlap'))
overlabel.setToolTip( overlabel.setToolTip(
_("How much (percentage) of the tool width to overlap each tool pass.") _("How much (percentage) of the tool width to overlap each tool pass.")
) )
@@ -3035,7 +3062,7 @@ class IsoUI:
self.grid3.addWidget(self.iso_overlap_entry, 14, 1) self.grid3.addWidget(self.iso_overlap_entry, 14, 1)
# Milling Type Radio Button # Milling Type Radio Button
self.milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type')) self.milling_type_label = FCLabel('%s:' % _('Milling Type'))
self.milling_type_label.setToolTip( self.milling_type_label.setToolTip(
_("Milling type when the selected tool is of type: 'iso_op':\n" _("Milling type when the selected tool is of type: 'iso_op':\n"
"- climb / best for precision milling and to reduce tool usage\n" "- climb / best for precision milling and to reduce tool usage\n"
@@ -3055,7 +3082,7 @@ class IsoUI:
self.grid3.addWidget(self.milling_type_radio, 15, 1) self.grid3.addWidget(self.milling_type_radio, 15, 1)
# Follow # Follow
self.follow_label = QtWidgets.QLabel('%s:' % _('Follow')) self.follow_label = FCLabel('%s:' % _('Follow'))
self.follow_label.setToolTip( self.follow_label.setToolTip(
_("Generate a 'Follow' geometry.\n" _("Generate a 'Follow' geometry.\n"
"This means that it will cut through\n" "This means that it will cut through\n"
@@ -3072,7 +3099,7 @@ class IsoUI:
self.grid3.addWidget(self.follow_cb, 16, 1) self.grid3.addWidget(self.follow_cb, 16, 1)
# Isolation Type # Isolation Type
self.iso_type_label = QtWidgets.QLabel('%s:' % _('Isolation Type')) self.iso_type_label = FCLabel('%s:' % _('Isolation Type'))
self.iso_type_label.setToolTip( self.iso_type_label.setToolTip(
_("Choose how the isolation will be executed:\n" _("Choose how the isolation will be executed:\n"
"- 'Full' -> complete isolation of polygons\n" "- 'Full' -> complete isolation of polygons\n"
@@ -3110,7 +3137,7 @@ class IsoUI:
self.grid3.addWidget(separator_line, 23, 0, 1, 2) self.grid3.addWidget(separator_line, 23, 0, 1, 2)
# General Parameters # General Parameters
self.gen_param_label = QtWidgets.QLabel('<b>%s</b>' % _("Common Parameters")) self.gen_param_label = FCLabel('<b>%s</b>' % _("Common Parameters"))
self.gen_param_label.setToolTip( self.gen_param_label.setToolTip(
_("Parameters that are common for all tools.") _("Parameters that are common for all tools.")
) )
@@ -3189,7 +3216,7 @@ class IsoUI:
]) ])
# Isolation Scope # Isolation Scope
self.select_label = QtWidgets.QLabel('%s:' % _("Selection")) self.select_label = FCLabel('%s:' % _("Selection"))
self.select_label.setToolTip( self.select_label.setToolTip(
_("Isolation scope. Choose what to isolate:\n" _("Isolation scope. Choose what to isolate:\n"
"- 'All' -> Isolate all the polygons in the object\n" "- 'All' -> Isolate all the polygons in the object\n"
@@ -3206,7 +3233,7 @@ class IsoUI:
self.grid3.addWidget(self.select_label, 33, 0) self.grid3.addWidget(self.select_label, 33, 0)
self.grid3.addWidget(self.select_combo, 33, 1) self.grid3.addWidget(self.select_combo, 33, 1)
self.reference_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type")) self.reference_combo_type_label = FCLabel('%s:' % _("Ref. Type"))
self.reference_combo_type_label.setToolTip( self.reference_combo_type_label.setToolTip(
_("The type of FlatCAM object to be used as non copper clearing reference.\n" _("The type of FlatCAM object to be used as non copper clearing reference.\n"
"It can be Gerber, Excellon or Geometry.") "It can be Gerber, Excellon or Geometry.")
@@ -3217,7 +3244,7 @@ class IsoUI:
self.grid3.addWidget(self.reference_combo_type_label, 34, 0) self.grid3.addWidget(self.reference_combo_type_label, 34, 0)
self.grid3.addWidget(self.reference_combo_type, 34, 1) self.grid3.addWidget(self.reference_combo_type, 34, 1)
self.reference_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object")) self.reference_combo_label = FCLabel('%s:' % _("Ref. Object"))
self.reference_combo_label.setToolTip( self.reference_combo_label.setToolTip(
_("The FlatCAM object to be used as non copper clearing reference.") _("The FlatCAM object to be used as non copper clearing reference.")
) )
@@ -3246,7 +3273,7 @@ class IsoUI:
self.poly_int_cb.hide() self.poly_int_cb.hide()
# Area Selection shape # Area Selection shape
self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape")) self.area_shape_label = FCLabel('%s:' % _("Shape"))
self.area_shape_label.setToolTip( self.area_shape_label.setToolTip(
_("The kind of selection shape used for area selection.") _("The kind of selection shape used for area selection.")
) )
@@ -3265,7 +3292,7 @@ class IsoUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
self.grid3.addWidget(separator_line, 39, 0, 1, 2) self.grid3.addWidget(separator_line, 39, 0, 1, 2)
self.generate_iso_button = QtWidgets.QPushButton("%s" % _("Generate Geometry")) self.generate_iso_button = FCButton("%s" % _("Generate Geometry"))
self.generate_iso_button.setIcon(QtGui.QIcon(self.app.resource_location + '/geometry32.png')) self.generate_iso_button.setIcon(QtGui.QIcon(self.app.resource_location + '/geometry32.png'))
self.generate_iso_button.setStyleSheet(""" self.generate_iso_button.setStyleSheet("""
QPushButton QPushButton
@@ -3286,7 +3313,7 @@ class IsoUI:
) )
self.tools_box.addWidget(self.generate_iso_button) self.tools_box.addWidget(self.generate_iso_button)
self.create_buffer_button = QtWidgets.QPushButton(_('Buffer Solid Geometry')) self.create_buffer_button = FCButton(_('Buffer Solid Geometry'))
self.create_buffer_button.setToolTip( self.create_buffer_button.setToolTip(
_("This button is shown only when the Gerber file\n" _("This button is shown only when the Gerber file\n"
"is loaded without buffering.\n" "is loaded without buffering.\n"
@@ -3298,7 +3325,7 @@ class IsoUI:
self.tools_box.addStretch() self.tools_box.addStretch()
# ## Reset Tool # ## Reset Tool
self.reset_button = QtWidgets.QPushButton(_("Reset Tool")) self.reset_button = FCButton(_("Reset Tool"))
self.reset_button.setIcon(QtGui.QIcon(self.app.resource_location + '/reset32.png')) self.reset_button.setIcon(QtGui.QIcon(self.app.resource_location + '/reset32.png'))
self.reset_button.setToolTip( self.reset_button.setToolTip(
_("Will reset the tool parameters.") _("Will reset the tool parameters.")