From 22d05935e881c67401e3ec8afbd39a89bfb12449 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Mon, 13 Jul 2020 03:04:44 +0300 Subject: [PATCH] - fixed a bug in Tools Database: due of not disconnecting the signals it created a race that was concluded into a RuntimeError exception (an dict changed size during iteration) - Drilling Tool - working in adding tools auto-load from Tools DB - some updates to the Excellon Object options - Drilling Tool - manual add from Tools DB is working --- CHANGELOG.md | 7 + appDatabase.py | 86 ++++++- .../general/GeneralAppSettingsGroupUI.py | 18 +- appObjects/FlatCAMExcellon.py | 238 ++++++++---------- appTools/ToolDrilling.py | 140 ++++++++--- app_Main.py | 10 +- 6 files changed, 325 insertions(+), 174 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13b6bd77..1caabf9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ CHANGELOG for FlatCAM beta ================================================= +13.07.2020 + +- fixed a bug in Tools Database: due of not disconnecting the signals it created a race that was concluded into a RuntimeError exception (an dict changed size during iteration) +- Drilling Tool - working in adding tools auto-load from Tools DB +- some updates to the Excellon Object options +- Drilling Tool - manual add from Tools DB is working + 12.07.2020 - when creating a new FlatCAM object, the options will be updated with FlatCAM tools properties that relate to them diff --git a/appDatabase.py b/appDatabase.py index a809eff1..b425b883 100644 --- a/appDatabase.py +++ b/appDatabase.py @@ -1146,6 +1146,43 @@ class ToolsDB2UI: self.grid_tool.addWidget(self.tool_object_label, 2, 0) self.grid_tool.addWidget(self.object_type_combo, 2, 1) + # Tool Tolerance + self.tol_label = QtWidgets.QLabel("%s:" % _("Tolerance")) + self.tol_label.setToolTip( + _("Tool tolerance. If there is a tool in the Excellon object with\n" + "the value within the limits then this tool from DB will be used.\n" + "This behavior is enabled in the Drilling Tool.") + ) + self.grid_tool.addWidget(self.tol_label, 4, 0, 1, 2) + + # Tolerance Min Limit + self.min_limit_label = QtWidgets.QLabel('%s:' % _("Min")) + self.min_limit_label.setToolTip( + _("Set the tool tolerance minimum.") + ) + self.tol_min_entry = FCDoubleSpinner(callback=self.confirmation_message) + self.tol_min_entry.set_precision(self.decimals) + self.tol_min_entry.set_range(0, 9999.9999) + self.tol_min_entry.setSingleStep(0.1) + self.tol_min_entry.setObjectName("gdb_tol_min") + + self.grid_tool.addWidget(self.min_limit_label, 6, 0) + self.grid_tool.addWidget(self.tol_min_entry, 6, 1) + + # Tolerance Min Limit + self.max_limit_label = QtWidgets.QLabel('%s:' % _("Max")) + self.max_limit_label.setToolTip( + _("Set the tool tolerance maximum.") + ) + self.tol_max_entry = FCDoubleSpinner(callback=self.confirmation_message) + self.tol_max_entry.set_precision(self.decimals) + self.tol_max_entry.set_range(0, 9999.9999) + self.tol_max_entry.setSingleStep(0.1) + self.tol_max_entry.setObjectName("gdb_tol_max") + + self.grid_tool.addWidget(self.max_limit_label, 7, 0) + self.grid_tool.addWidget(self.tol_max_entry, 7, 1) + # ########################################################################### # ############### BASIC GEOMETRY UI form #################################### # ########################################################################### @@ -1872,10 +1909,6 @@ class ToolsDB2UI: self.grid5.addWidget(self.feedrate_rapid_label, 16, 0) self.grid5.addWidget(self.feedrate_rapid_entry, 16, 1) - # default values is to hide - self.feedrate_rapid_label.hide() - self.feedrate_rapid_entry.hide() - # Spindlespeed self.spindle_label = QtWidgets.QLabel('%s:' % _('Spindle speed')) self.spindle_label.setToolTip( @@ -2117,6 +2150,8 @@ class ToolsDB2(QtWidgets.QWidget): self.form_fields = { "object_type": self.ui.object_type_combo, + "tol_min": self.ui.tol_min_entry, + "tol_max": self.ui.tol_max_entry, # Basic "name": self.ui.name_entry, "tooldia": self.ui.dia_entry, @@ -2187,6 +2222,8 @@ class ToolsDB2(QtWidgets.QWidget): self.name2option = { "gdb_object_type": "object_type", + "gdb_tol_min": "tol_min", + "gdb_tol_max": "tol_max", # Basic "gdb_name": "name", @@ -2319,8 +2356,10 @@ class ToolsDB2(QtWidgets.QWidget): self.on_tool_requested_from_app() def on_list_selection_change(self, current, previous): + self.ui_disconnect() self.current_toolid = int(current.text(0)) self.storage_to_form(self.db_tool_dict[current.text(0)]) + self.ui_connect() def on_list_item_edited(self, item, column): if column == 0: @@ -2504,6 +2543,8 @@ class ToolsDB2(QtWidgets.QWidget): "endz": float(self.app.defaults["geometry_endz"]), "object_type": _("General"), + "tol_min": 0.0, + "tol_max": 0.0, # NCC "tools_nccoperation": self.app.defaults["tools_nccoperation"], @@ -2750,7 +2791,7 @@ class ToolsDB2(QtWidgets.QWidget): for idx in range(self.app_ui.plot_tab_area.count()): if self.app_ui.plot_tab_area.tabText(idx) == _("Tools Database"): self.app_ui.plot_tab_area.tabBar.setTabTextColor(idx, QtGui.QColor('black')) - self.save_db_btn.setStyleSheet("") + self.ui.save_db_btn.setStyleSheet("") # Save Tools DB in a file try: @@ -2927,6 +2968,11 @@ class ToolsDB2(QtWidgets.QWidget): else: if wdg_name == "gdb_object_type": self.db_tool_dict[tool_id]['data']['object_type'] = val + elif wdg_name == "gdb_tol_min": + self.db_tool_dict[tool_id]['data']['tol_min'] = val + elif wdg_name == "gdb_tol_max": + self.db_tool_dict[tool_id]['data']['tol_max'] = val + elif wdg_name == "gdb_cutz": self.db_tool_dict[tool_id]['data']['cutz'] = val elif wdg_name == "gdb_multidepth": @@ -3002,6 +3048,36 @@ class ToolsDB2(QtWidgets.QWidget): elif wdg_name == "gdb_i_iso_type": self.db_tool_dict[tool_id]['data']['tools_iso_isotype'] = val + # Drilling Tool + elif wdg_name == "gdb_e_cutz": + self.db_tool_dict[tool_id]['data']['tools_drill_cutz'] = val + elif wdg_name == "gdb_e_multidepth": + self.db_tool_dict[tool_id]['data']['tools_drill_multidepth'] = val + elif wdg_name == "gdb_e_depthperpass": + self.db_tool_dict[tool_id]['data']['tools_drill_depthperpass'] = val + elif wdg_name == "gdb_e_travelz": + self.db_tool_dict[tool_id]['data']['tools_drill_travelz'] = val + + elif wdg_name == "gdb_e_feedratez": + self.db_tool_dict[tool_id]['data']['tools_drill_feedrate_z'] = val + elif wdg_name == "gdb_e_fr_rapid": + self.db_tool_dict[tool_id]['data']['tools_drill_feedrate_rapid'] = val + elif wdg_name == "gdb_e_spindlespeed": + self.db_tool_dict[tool_id]['data']['tools_drill_spindlespeed'] = val + elif wdg_name == "gdb_e_dwell": + self.db_tool_dict[tool_id]['data']['tools_drill_dwell'] = val + elif wdg_name == "gdb_e_dwelltime": + self.db_tool_dict[tool_id]['data']['tools_drill_dwelltime'] = val + + elif wdg_name == "gdb_e_offset": + self.db_tool_dict[tool_id]['data']['tools_drill_offset'] = val + elif wdg_name == "gdb_e_drill_slots": + self.db_tool_dict[tool_id]['data']['tools_drill_drill_slots'] = val + elif wdg_name == "gdb_e_drill_slots_over": + self.db_tool_dict[tool_id]['data']['tools_drill_drill_overlap'] = val + elif wdg_name == "gdb_e_drill_last_drill": + self.db_tool_dict[tool_id]['data']['tools_drill_last_drill'] = val + self.callback_app() def on_tool_requested_from_app(self): diff --git a/appGUI/preferences/general/GeneralAppSettingsGroupUI.py b/appGUI/preferences/general/GeneralAppSettingsGroupUI.py index 2cf301d1..c2e4aab4 100644 --- a/appGUI/preferences/general/GeneralAppSettingsGroupUI.py +++ b/appGUI/preferences/general/GeneralAppSettingsGroupUI.py @@ -98,12 +98,26 @@ class GeneralAppSettingsGroupUI(OptionsGroupUI2): self.workspace_type_label = self.option_dict()["global_workspaceT"].label_widget self.workspace_orientation_field = self.option_dict()["global_workspace_orientation"].get_field() self.workspace_orientation_label = self.option_dict()["global_workspace_orientation"].label_widget - self.wks = OptionalInputSection(self.workspace_enabled_field, [self.workspace_type_label, self.workspace_type_field, self.workspace_orientation_label, self.workspace_orientation_field]) + self.wks = OptionalInputSection( + self.workspace_enabled_field, + [ + self.workspace_type_label, + self.workspace_type_field, + self.workspace_orientation_label, + self.workspace_orientation_field + ] + ) self.mouse_cursor_color_enabled_field = self.option_dict()["global_cursor_color_enabled"].get_field() self.mouse_cursor_color_field = self.option_dict()["global_cursor_color"].get_field() self.mouse_cursor_color_label = self.option_dict()["global_cursor_color"].label_widget - self.mois = OptionalInputSection(self.mouse_cursor_color_enabled_field, [self.mouse_cursor_color_label, self.mouse_cursor_color_field]) + self.mois = OptionalInputSection( + self.mouse_cursor_color_enabled_field, + [ + self.mouse_cursor_color_label, + self.mouse_cursor_color_field + ] + ) self.mouse_cursor_color_enabled_field.stateChanged.connect(self.on_mouse_cursor_color_enable) self.mouse_cursor_color_field.entry.editingFinished.connect(self.on_mouse_cursor_entry) diff --git a/appObjects/FlatCAMExcellon.py b/appObjects/FlatCAMExcellon.py index c23effe4..a567260a 100644 --- a/appObjects/FlatCAMExcellon.py +++ b/appObjects/FlatCAMExcellon.py @@ -53,39 +53,22 @@ class ExcellonObject(FlatCAMObj, Excellon): "plot": True, "solid": False, "multicolored": False, + "merge_fuse_tools": True, - "operation": "drill", - "milling_type": "drills", - - "milling_dia": 0.04, - - "cutz": -0.1, - "multidepth": False, - "depthperpass": 0.7, - "travelz": 0.1, - "feedrate": self.app.defaults["geometry_feedrate"], - "feedrate_z": 5.0, - "feedrate_rapid": 5.0, "tooldia": 0.1, + "milling_dia": 0.04, "slot_tooldia": 0.1, - "toolchange": False, - "toolchangez": 1.0, - "toolchangexy": "0.0, 0.0", - "extracut": self.app.defaults["geometry_extracut"], - "extracut_length": self.app.defaults["geometry_extracut_length"], - "endz": 2.0, - "endxy": '', - "startz": None, - "offset": 0.0, - "spindlespeed": 0, - "dwell": True, - "dwelltime": 1000, - "ppname_e": 'default', - "ppname_g": self.app.defaults["geometry_ppname_g"], - "z_pdepth": -0.02, - "feedrate_probe": 3.0, + "format_upper_in": 2, + "format_lower_in": 4, + "format_upper_mm": 3, + "lower_mm": 3, + "zeros": "T", + "units": "INCH", + "update": True, + "optimization_type": "B", + "search_time": 3 }) # TODO: Document this. @@ -99,14 +82,6 @@ class ExcellonObject(FlatCAMObj, Excellon): # default set of data to be added to each tool in self.tools as self.tools[tool]['data'] = self.default_data self.default_data = {} - # fill in self.default_data values from self.options - for opt_key, opt_val in self.app.options.items(): - if opt_key.find('excellon_') == 0: - self.default_data[opt_key] = deepcopy(opt_val) - for opt_key, opt_val in self.app.options.items(): - if opt_key.find('geometry_') == 0: - self.default_data[opt_key] = deepcopy(opt_val) - # variable to store the total amount of drills per job self.tot_drill_cnt = 0 self.tool_row = 0 @@ -133,99 +108,6 @@ class ExcellonObject(FlatCAMObj, Excellon): # from predecessors. self.ser_attrs += ['options', 'kind', 'fill_color', 'outline_color', 'alpha_level'] - @staticmethod - def merge(exc_list, exc_final, decimals=None, fuse_tools=True): - """ - Merge Excellon objects found in exc_list parameter into exc_final object. - Options are always copied from source . - - Tools are disregarded, what is taken in consideration is the unique drill diameters found as values in the - exc_list tools dict's. In the reconstruction section for each unique tool diameter it will be created a - tool_name to be used in the final Excellon object, exc_final. - - If only one object is in exc_list parameter then this function will copy that object in the exc_final - - :param exc_list: List or one object of ExcellonObject Objects to join. - :type exc_list: list - :param exc_final: Destination ExcellonObject object. - :type exc_final: class - :param decimals: The number of decimals to be used for diameters - :type decimals: int - :param fuse_tools: If True will try to fuse tools of the same diameter for the Excellon objects - :type fuse_tools: bool - :return: None - """ - - if exc_final.tools is None: - exc_final.tools = {} - - if decimals is None: - decimals = 4 - decimals_exc = decimals - - try: - flattened_list = list(itertools.chain(*exc_list)) - except TypeError: - flattened_list = exc_list - - new_tools = {} - total_geo = [] - toolid = 0 - for exc in flattened_list: - # copy options of the current excellon obj to the final excellon obj - # only the last object options will survive - for option in exc.options: - if option != 'name': - try: - exc_final.options[option] = exc.options[option] - except Exception: - exc.app.log.warning("Failed to copy option.", option) - - for tool in exc.tools: - toolid += 1 - new_tools[toolid] = exc.tools[tool] - - exc_final.tools = deepcopy(new_tools) - # add the zeros and units to the exc_final object - exc_final.zeros = exc.zeros - exc_final.units = exc.units - total_geo += exc.solid_geometry - - exc_final.solid_geometry = total_geo - - fused_tools_dict = {} - if exc_final.tools and fuse_tools: - toolid = 0 - for tool, tool_dict in exc_final.tools.items(): - current_tooldia = float('%.*f' % (decimals_exc, tool_dict['tooldia'])) - toolid += 1 - - # calculate all diameters in fused_tools_dict - all_dia = [] - if fused_tools_dict: - for f_tool in fused_tools_dict: - all_dia.append(float('%.*f' % (decimals_exc, fused_tools_dict[f_tool]['tooldia']))) - - if current_tooldia in all_dia: - # find tool for current_tooldia in fuse_tools - t = None - for f_tool in fused_tools_dict: - if fused_tools_dict[f_tool]['tooldia'] == current_tooldia: - t = f_tool - break - if t: - fused_tools_dict[t]['drills'] += tool_dict['drills'] - fused_tools_dict[t]['slots'] += tool_dict['slots'] - fused_tools_dict[t]['solid_geometry'] += tool_dict['solid_geometry'] - else: - fused_tools_dict[toolid] = tool_dict - fused_tools_dict[toolid]['tooldia'] = current_tooldia - - exc_final.tools = fused_tools_dict - - # create the geometry for the exc_final object - exc_final.create_geometry() - def set_ui(self, ui): """ Configures the user interface for this object. @@ -246,6 +128,11 @@ class ExcellonObject(FlatCAMObj, Excellon): if opt_key.find('tools_drill_') == 0: self.options[opt_key] = deepcopy(opt_val) + # fill in self.default_data values from self.options + for opt_key, opt_val in self.app.options.items(): + if opt_key.find('excellon_') == 0 or opt_key.find('tools_drill_') == 0: + self.default_data[opt_key] = deepcopy(opt_val) + self.form_fields.update({ "plot": self.ui.plot_cb, "solid": self.ui.solid_cb, @@ -1310,3 +1197,96 @@ class ExcellonObject(FlatCAMObj, Excellon): self.shapes.redraw() except (ObjectDeleted, AttributeError): self.shapes.clear(update=True) + + @staticmethod + def merge(exc_list, exc_final, decimals=None, fuse_tools=True): + """ + Merge Excellon objects found in exc_list parameter into exc_final object. + Options are always copied from source . + + Tools are disregarded, what is taken in consideration is the unique drill diameters found as values in the + exc_list tools dict's. In the reconstruction section for each unique tool diameter it will be created a + tool_name to be used in the final Excellon object, exc_final. + + If only one object is in exc_list parameter then this function will copy that object in the exc_final + + :param exc_list: List or one object of ExcellonObject Objects to join. + :type exc_list: list + :param exc_final: Destination ExcellonObject object. + :type exc_final: class + :param decimals: The number of decimals to be used for diameters + :type decimals: int + :param fuse_tools: If True will try to fuse tools of the same diameter for the Excellon objects + :type fuse_tools: bool + :return: None + """ + + if exc_final.tools is None: + exc_final.tools = {} + + if decimals is None: + decimals = 4 + decimals_exc = decimals + + try: + flattened_list = list(itertools.chain(*exc_list)) + except TypeError: + flattened_list = exc_list + + new_tools = {} + total_geo = [] + toolid = 0 + for exc in flattened_list: + # copy options of the current excellon obj to the final excellon obj + # only the last object options will survive + for option in exc.options: + if option != 'name': + try: + exc_final.options[option] = exc.options[option] + except Exception: + exc.app.log.warning("Failed to copy option.", option) + + for tool in exc.tools: + toolid += 1 + new_tools[toolid] = exc.tools[tool] + + exc_final.tools = deepcopy(new_tools) + # add the zeros and units to the exc_final object + exc_final.zeros = exc.zeros + exc_final.units = exc.units + total_geo += exc.solid_geometry + + exc_final.solid_geometry = total_geo + + fused_tools_dict = {} + if exc_final.tools and fuse_tools: + toolid = 0 + for tool, tool_dict in exc_final.tools.items(): + current_tooldia = float('%.*f' % (decimals_exc, tool_dict['tooldia'])) + toolid += 1 + + # calculate all diameters in fused_tools_dict + all_dia = [] + if fused_tools_dict: + for f_tool in fused_tools_dict: + all_dia.append(float('%.*f' % (decimals_exc, fused_tools_dict[f_tool]['tooldia']))) + + if current_tooldia in all_dia: + # find tool for current_tooldia in fuse_tools + t = None + for f_tool in fused_tools_dict: + if fused_tools_dict[f_tool]['tooldia'] == current_tooldia: + t = f_tool + break + if t: + fused_tools_dict[t]['drills'] += tool_dict['drills'] + fused_tools_dict[t]['slots'] += tool_dict['slots'] + fused_tools_dict[t]['solid_geometry'] += tool_dict['solid_geometry'] + else: + fused_tools_dict[toolid] = tool_dict + fused_tools_dict[toolid]['tooldia'] = current_tooldia + + exc_final.tools = fused_tools_dict + + # create the geometry for the exc_final object + exc_final.create_geometry() diff --git a/appTools/ToolDrilling.py b/appTools/ToolDrilling.py index 2ab250b1..acce7fe1 100644 --- a/appTools/ToolDrilling.py +++ b/appTools/ToolDrilling.py @@ -16,7 +16,10 @@ from copy import deepcopy import numpy as np -from shapely.geometry import Point, LineString +from shapely.geometry import LineString + +import json +import sys from matplotlib.backend_bases import KeyEvent as mpl_key_event @@ -122,42 +125,45 @@ class ToolDrilling(AppTool, Excellon): self.area_sel_disconnect_flag = False self.poly_sel_disconnect_flag = False + # Tools Database + self.tools_db_dict = None + self.form_fields = { - "cutz": self.t_ui.cutz_entry, - "multidepth": self.t_ui.mpass_cb, - "depthperpass": self.t_ui.maxdepth_entry, - "travelz": self.t_ui.travelz_entry, - "feedrate_z": self.t_ui.feedrate_z_entry, - "feedrate_rapid": self.t_ui.feedrate_rapid_entry, + "tools_drill_cutz": self.t_ui.cutz_entry, + "tools_drill_multidepth": self.t_ui.mpass_cb, + "tools_drill_depthperpass": self.t_ui.maxdepth_entry, + "tools_drill_travelz": self.t_ui.travelz_entry, + "tools_drill_feedrate_z": self.t_ui.feedrate_z_entry, + "tools_drill_feedrate_rapid": self.t_ui.feedrate_rapid_entry, - "spindlespeed": self.t_ui.spindlespeed_entry, - "dwell": self.t_ui.dwell_cb, - "dwelltime": self.t_ui.dwelltime_entry, + "tools_drill_spindlespeed": self.t_ui.spindlespeed_entry, + "tools_drill_dwell": self.t_ui.dwell_cb, + "tools_drill_dwelltime": self.t_ui.dwelltime_entry, - "offset": self.t_ui.offset_entry, + "tools_drill_offset": self.t_ui.offset_entry, - "drill_slots": self.t_ui.drill_slots_cb, - "drill_overlap": self.t_ui.drill_overlap_entry, - "last_drill": self.t_ui.last_drill_cb + "tools_drill_drill_slots": self.t_ui.drill_slots_cb, + "tools_drill_drill_overlap": self.t_ui.drill_overlap_entry, + "tools_drill_last_drill": self.t_ui.last_drill_cb } self.name2option = { - "e_cutz": "cutz", - "e_multidepth": "multidepth", - "e_depthperpass": "depthperpass", - "e_travelz": "travelz", - "e_feedratez": "feedrate_z", - "e_fr_rapid": "feedrate_rapid", + "e_cutz": "tools_drill_cutz", + "e_multidepth": "tools_drill_multidepth", + "e_depthperpass": "tools_drill_depthperpass", + "e_travelz": "tools_drill_travelz", + "e_feedratez": "tools_drill_feedrate_z", + "e_fr_rapid": "tools_drill_feedrate_rapid", - "e_spindlespeed": "spindlespeed", - "e_dwell": "dwell", - "e_dwelltime": "dwelltime", + "e_spindlespeed": "tools_drill_spindlespeed", + "e_dwell": "tools_drill_dwell", + "e_dwelltime": "tools_drill_dwelltime", - "e_offset": "offset", + "e_offset": "tools_drill_offset", - "e_drill_slots": "drill_slots", - "e_drill_slots_overlap": "drill_overlap", - "e_drill_last_drill": "last_drill", + "e_drill_slots": "tools_drill_drill_slots", + "e_drill_slots_overlap": "tools_drill_drill_overlap", + "e_drill_last_drill": "tools_drill_last_drill", } self.poly_drawn = False @@ -205,6 +211,8 @@ class ToolDrilling(AppTool, Excellon): # ############################ SIGNALS ######################################## # ############################################################################# + self.t_ui.manual_load_db_btn.clicked.connect(self.on_tool_db_load) + self.t_ui.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked) self.t_ui.generate_cnc_button.clicked.connect(self.on_cnc_button_click) self.t_ui.tools_table.drag_drop_sig.connect(self.rebuild_ui) @@ -344,7 +352,7 @@ class ToolDrilling(AppTool, Excellon): # fill in self.default_data values from self.options for opt_key, opt_val in self.app.options.items(): - if opt_key.find('excellon_') == 0: + if opt_key.find('excellon_') == 0 or opt_key.find('tools_drill_') == 0: self.default_data[opt_key] = deepcopy(opt_val) self.first_click = False @@ -403,6 +411,7 @@ class ToolDrilling(AppTool, Excellon): self.t_ui.drill_overlap_label.hide() self.t_ui.drill_overlap_entry.hide() self.t_ui.last_drill_cb.hide() + # if the app mode is Basic then disable this feature if app_mode == 'b': self.t_ui.drill_slots_cb.set_value(False) @@ -697,12 +706,16 @@ class ToolDrilling(AppTool, Excellon): self.t_ui.exc_param_frame.setDisabled(True) self.set_tool_ui() else: - self.excellon_tools = self.excellon_obj.tools self.app.collection.set_active(self.obj_name) self.t_ui.exc_param_frame.setDisabled(False) - self.excellon_tools = self.excellon_obj.tools - self.build_tool_ui() + if self.t_ui.autoload_db_cb.get_value(): + self.excellon_tools = self.excellon_obj.tools + self.on_tool_db_load() + else: + # self.on_tool_db_load() already build once the tool UI, no need to do it twice + self.excellon_tools = self.excellon_obj.tools + self.build_tool_ui() sel_rows = set() table_items = self.t_ui.tools_table.selectedItems() @@ -795,6 +808,71 @@ class ToolDrilling(AppTool, Excellon): except (TypeError, ValueError): pass + def on_tool_db_load(self): + + filename = self.app.data_path + '\\geo_tools_db.FlatDB' + + # 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.")) + return + + try: + self.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.")) + return + + self.replace_tools() + + def replace_tools(self): + log.debug("ToolDrilling.replace_tools()") + + if self.excellon_obj: + new_tools_dict = deepcopy(self.excellon_tools) + + for orig_tool, orig_tool_val in self.excellon_tools.items(): + orig_tooldia = orig_tool_val['tooldia'] + + # look in database tools + for db_tool, db_tool_val in self.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']) + + # if we find a tool with the same diameter in the Tools DB just update it's data + if orig_tooldia == db_tooldia: + for d in db_tool_val['data']: + if d.find('tools_drill') == 0: + new_tools_dict[orig_tool]['data'][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[orig_tool]['data'][d] = db_tool_val['data'][d] + # search for a tool that has a tolerance that the tool fits in + elif high_limit >= orig_tooldia >= low_limit: + new_tools_dict[orig_tool]['tooldia'] = db_tooldia + for d in db_tool_val['data']: + if d.find('tools_drill') == 0: + new_tools_dict[orig_tool]['data'][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[orig_tool]['data'][d] = db_tool_val['data'][d] + + self.excellon_tools = new_tools_dict + for td in self.excellon_tools: + print(td, self.excellon_tools[td]) + self.build_tool_ui() + def on_toggle_all_rows(self): """ will toggle the selection of all rows in Tools table diff --git a/app_Main.py b/app_Main.py index 8b4d1333..2401f182 100644 --- a/app_Main.py +++ b/app_Main.py @@ -8935,22 +8935,18 @@ class App(QtCore.QObject): # How the object should be initialized def obj_init(excellon_obj, app_obj): - try: ret = excellon_obj.parse_file(filename=filename) if ret == "fail": log.debug("Excellon parsing failed.") - self.inform.emit('[ERROR_NOTCL] %s' % - _("This is not Excellon file.")) + self.inform.emit('[ERROR_NOTCL] %s' % _("This is not Excellon file.")) return "fail" except IOError: - app_obj.inform.emit('[ERROR_NOTCL] %s: %s' % - (_("Cannot open file"), filename)) + app_obj.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Cannot open file"), filename)) log.debug("Could not open Excellon object.") return "fail" except Exception: - msg = '[ERROR_NOTCL] %s' % \ - _("An internal error has occurred. See shell.\n") + msg = '[ERROR_NOTCL] %s' % _("An internal error has occurred. See shell.\n") msg += traceback.format_exc() app_obj.inform.emit(msg) return "fail"