diff --git a/README.md b/README.md index e9e78059..0ee30bf7 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ CAD program, and create G-Code for Isolation routing. - fixed bug in Geometry Editor in buffer_int() function that created an Circular Reference Error when applying buffer interior on a geometry. - fixed issue with not possible to close the app after a project save. +- preliminary Gerber Editor.on_aperture_delete() +- fixed 'circular reference' error when creating the new Gerber file in Gerber Editor +- preliminary Gerber Editor.on_aperture_add() 5.04.2019 diff --git a/camlib.py b/camlib.py index 26839a8f..cdddcff1 100644 --- a/camlib.py +++ b/camlib.py @@ -3186,7 +3186,7 @@ class Gerber (Geometry): :rtype : None :return: None """ - + pass # self.buffer_paths() # # self.fix_regions() diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py index 343716fe..5e339a7a 100644 --- a/flatcamEditors/FlatCAMGrbEditor.py +++ b/flatcamEditors/FlatCAMGrbEditor.py @@ -13,6 +13,7 @@ import copy from camlib import * from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, SpinBoxDelegate from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor +from FlatCAMObj import FlatCAMGerber import gettext import FlatCAMTranslation as fcTranslate @@ -109,7 +110,7 @@ class FCApertureResize(FCShapeTool): # if following the resize of the drills there will be no more drills for the selected tool then # delete that tool if not self.draw_app.points_edit[sel_dia]: - self.draw_app.on_tool_delete(sel_dia) + self.draw_app.on_aperture_delete(sel_dia) for shp in sel_shapes_to_be_deleted: self.draw_app.selected.remove(shp) @@ -661,6 +662,9 @@ class FlatCAMGrbEditor(QtCore.QObject): self.new_apertures = {} self.new_aperture_macros = {} + # store here the plot promises, if empty the delayed plot will be activated + self.grb_plot_promises = [] + # dictionary to store the tool_row and diameters in Tool_table # it will be updated everytime self.build_ui() is called self.olddia_newdia = {} @@ -680,9 +684,9 @@ class FlatCAMGrbEditor(QtCore.QObject): self.app.ui.delete_drill_btn.triggered.connect(self.on_delete_btn) self.name_entry.returnPressed.connect(self.on_name_activate) - self.addaperture_btn.clicked.connect(self.on_tool_add) + self.addaperture_btn.clicked.connect(self.on_aperture_add) # self.addtool_entry.editingFinished.connect(self.on_tool_add) - self.delaperture_btn.clicked.connect(self.on_tool_delete) + self.delaperture_btn.clicked.connect(self.on_aperture_delete) self.apertures_table.selectionModel().currentChanged.connect(self.on_row_selected) self.array_type_combo.currentIndexChanged.connect(self.on_array_type_combo) @@ -703,6 +707,7 @@ class FlatCAMGrbEditor(QtCore.QObject): self.drill_direction_radio.set_value('CW') self.drill_axis_radio.set_value('X') self.gerber_obj = None + self.gerber_obj_options = {} # VisPy Visuals self.shapes = self.app.plotcanvas.new_shape_collection(layers=1) @@ -784,7 +789,7 @@ class FlatCAMGrbEditor(QtCore.QObject): sort_temp = [] for aperture in self.olddia_newdia: - sort_temp.append(float(aperture)) + sort_temp.append(int(aperture)) self.sorted_apid = sorted(sort_temp) # populate self.intial_table_rows dict with the tool number as keys and tool diameters as values @@ -814,9 +819,11 @@ class FlatCAMGrbEditor(QtCore.QObject): self.apertures_row = 0 aper_no = self.apertures_row + 1 + sort = [] - for k, v in list(self.gerber_obj.apertures.items()): + for k, v in list(self.storage_dict.items()): sort.append(int(k)) + sorted_apertures = sorted(sort) sort = [] @@ -837,20 +844,20 @@ class FlatCAMGrbEditor(QtCore.QObject): ap_code_item = QtWidgets.QTableWidgetItem(ap_code) ap_code_item.setFlags(QtCore.Qt.ItemIsEnabled) - ap_type_item = QtWidgets.QTableWidgetItem(str(self.gerber_obj.apertures[ap_code]['type'])) + ap_type_item = QtWidgets.QTableWidgetItem(str(self.storage_dict[ap_code]['type'])) ap_type_item.setFlags(QtCore.Qt.ItemIsEnabled) - if str(self.gerber_obj.apertures[ap_code]['type']) == 'R' or str(self.gerber_obj.apertures[ap_code]['type']) == 'O': + if str(self.storage_dict[ap_code]['type']) == 'R' or str(self.storage_dict[ap_code]['type']) == 'O': ap_dim_item = QtWidgets.QTableWidgetItem( - '%.4f, %.4f' % (self.gerber_obj.apertures[ap_code]['width'] * self.gerber_obj.file_units_factor, - self.gerber_obj.apertures[ap_code]['height'] * self.gerber_obj.file_units_factor + '%.4f, %.4f' % (self.storage_dict[ap_code]['width'] * self.gerber_obj.file_units_factor, + self.storage_dict[ap_code]['height'] * self.gerber_obj.file_units_factor ) ) ap_dim_item.setFlags(QtCore.Qt.ItemIsEnabled) - elif str(self.gerber_obj.apertures[ap_code]['type']) == 'P': + elif str(self.storage_dict[ap_code]['type']) == 'P': ap_dim_item = QtWidgets.QTableWidgetItem( - '%.4f, %.4f' % (self.gerber_obj.apertures[ap_code]['diam'] * self.gerber_obj.file_units_factor, - self.gerber_obj.apertures[ap_code]['nVertices'] * self.gerber_obj.file_units_factor) + '%.4f, %.4f' % (self.storage_dict[ap_code]['diam'] * self.gerber_obj.file_units_factor, + self.storage_dict[ap_code]['nVertices'] * self.gerber_obj.file_units_factor) ) ap_dim_item.setFlags(QtCore.Qt.ItemIsEnabled) else: @@ -858,9 +865,9 @@ class FlatCAMGrbEditor(QtCore.QObject): ap_dim_item.setFlags(QtCore.Qt.ItemIsEnabled) try: - if self.gerber_obj.apertures[ap_code]['size'] is not None: + if self.storage_dict[ap_code]['size'] is not None: ap_size_item = QtWidgets.QTableWidgetItem('%.4f' % - float(self.gerber_obj.apertures[ap_code]['size'] * + float(self.storage_dict[ap_code]['size'] * self.gerber_obj.file_units_factor)) else: ap_size_item = QtWidgets.QTableWidgetItem('') @@ -929,30 +936,26 @@ class FlatCAMGrbEditor(QtCore.QObject): # we reactivate the signals after the after the tool adding as we don't need to see the tool been populated self.apertures_table.itemChanged.connect(self.on_tool_edit) - def on_tool_add(self, tooldia=None): + def on_aperture_add(self, apid=None): self.is_modified = True - if tooldia: - tool_dia = tooldia + if apid: + ap_id = apid else: try: - tool_dia = float(self.addtool_entry.get_value()) + ap_id = str(self.addtool_entry.get_value()) except ValueError: - # try to convert comma to decimal point. if it's still not working error message and return - try: - tool_dia = float(self.addtool_entry.get_value().replace(',', '.')) - except ValueError: - self.app.inform.emit(_("[ERROR_NOTCL] Wrong value format entered, " - "use a number.") - ) - return + return - if tool_dia not in self.olddia_newdia: - storage_elem = FlatCAMGeoEditor.make_storage() - self.storage_dict[tool_dia] = storage_elem + if ap_id not in self.olddia_newdia: + self.storage_dict[ap_id] = {} + self.storage_dict[ap_id]['type'] = 'C' + self.storage_dict[ap_id]['size'] = 1 + self.storage_dict[ap_id]['solid_geometry'] = [] + self.storage_dict[ap_id]['follow_geometry'] = [] # self.olddia_newdia dict keeps the evidence on current tools diameters as keys and gets updated on values # each time a tool diameter is edited or added - self.olddia_newdia[tool_dia] = tool_dia + self.olddia_newdia[ap_id] = ap_id else: self.app.inform.emit(_("[WARNING_NOTCL] Tool already in the original or actual tool list.\n" "Save and reedit Excellon if you need to add this tool. ") @@ -961,56 +964,49 @@ class FlatCAMGrbEditor(QtCore.QObject): # since we add a new tool, we update also the initial state of the tool_table through it's dictionary # we add a new entry in the tool2tooldia dict - self.tool2tooldia[len(self.olddia_newdia)] = tool_dia + self.tool2tooldia[len(self.olddia_newdia)] = ap_id - self.app.inform.emit(_("[success] Added new tool with dia: {dia} {units}").format(dia=str(tool_dia), units=str(self.units))) + self.app.inform.emit(_("[success] Added new tool with dia: {apid}").format(apid=str(ap_id))) self.build_ui() # make a quick sort through the tool2tooldia dict so we find which row to select row_to_be_selected = None for key in sorted(self.tool2tooldia): - if self.tool2tooldia[key] == tool_dia: + if self.tool2tooldia[key] == ap_id: row_to_be_selected = int(key) - 1 break self.apertures_table.selectRow(row_to_be_selected) - def on_tool_delete(self, dia=None): + def on_aperture_delete(self, apid=None): self.is_modified = True deleted_tool_dia_list = [] deleted_tool_offset_list = [] try: - if dia is None or dia is False: + if apid is None or apid is False: # deleted_tool_dia = float(self.apertures_table.item(self.apertures_table.currentRow(), 1).text()) for index in self.apertures_table.selectionModel().selectedRows(): row = index.row() - deleted_tool_dia_list.append(float(self.apertures_table.item(row, 1).text())) + deleted_tool_dia_list.append(self.apertures_table.item(row, 1).text()) else: - if isinstance(dia, list): - for dd in dia: - deleted_tool_dia_list.append(float('%.4f' % dd)) + if isinstance(apid, list): + for dd in apid: + deleted_tool_dia_list.append(dd) else: - deleted_tool_dia_list.append(float('%.4f' % dia)) + deleted_tool_dia_list.append(apid) except: self.app.inform.emit(_("[WARNING_NOTCL] Select a tool in Tool Table")) return for deleted_tool_dia in deleted_tool_dia_list: - - # delete de tool offset - self.gerber_obj.tool_offset.pop(float(deleted_tool_dia), None) - # delete the storage used for that tool - storage_elem = FlatCAMGeoEditor.make_storage() - self.storage_dict[deleted_tool_dia] = storage_elem self.storage_dict.pop(deleted_tool_dia, None) # I've added this flag_del variable because dictionary don't like # having keys deleted while iterating through them flag_del = [] - # self.points_edit.pop(deleted_tool_dia, None) for deleted_tool in self.tool2tooldia: if self.tool2tooldia[deleted_tool] == deleted_tool_dia: flag_del.append(deleted_tool) @@ -1019,19 +1015,13 @@ class FlatCAMGrbEditor(QtCore.QObject): for tool_to_be_deleted in flag_del: # delete the tool self.tool2tooldia.pop(tool_to_be_deleted, None) - - # delete also the drills from points_edit dict just in case we add the tool again, we don't want to show the - # number of drills from before was deleter - self.points_edit[deleted_tool_dia] = [] flag_del = [] self.olddia_newdia.pop(deleted_tool_dia, None) - self.app.inform.emit(_("[success] Deleted tool with dia: {del_dia} {units}").format(del_dia=str(deleted_tool_dia), units=str(self.units))) + self.app.inform.emit(_("[success] Deleted aperture with code: {del_dia}").format(del_dia=str(deleted_tool_dia))) self.plot_all() - # self.app.inform.emit("Could not delete selected tool") - self.build_ui() def on_tool_edit(self, item_changed): @@ -1081,7 +1071,7 @@ class FlatCAMGrbEditor(QtCore.QObject): self.points_edit[current_table_dia_edited].append((0, 0)) self.add_gerber_shape(geometry, self.storage_dict[current_table_dia_edited]) - self.on_tool_delete(dia=dia_changed) + self.on_aperture_delete(apid=dia_changed) # delete the tool offset self.gerber_obj.tool_offset.pop(dia_changed, None) @@ -1220,7 +1210,7 @@ class FlatCAMGrbEditor(QtCore.QObject): # self.storage = FlatCAMExcEditor.make_storage() self.plot_all() - def edit_fcgerber(self, exc_obj): + def edit_fcgerber(self, orig_grb_obj): """ Imports the geometry found in self.apertures from the given FlatCAM Gerber object into the editor. @@ -1229,33 +1219,29 @@ class FlatCAMGrbEditor(QtCore.QObject): :return: None """ - assert isinstance(exc_obj, Gerber), \ - "Expected an Excellon Object, got %s" % type(exc_obj) - self.deactivate() self.activate() + # create a reference to the source object + self.gerber_obj = orig_grb_obj + + self.gerber_obj_options = orig_grb_obj.options + # Hide original geometry - self.gerber_obj = exc_obj - exc_obj.visible = False + orig_grb_obj.visible = False # Set selection tolerance # DrawToolShape.tolerance = fc_excellon.drawing_tolerance * 10 self.select_tool("select") - self.set_ui() - - # now that we hava data, create the GUI interface and add it to the Tool Tab - self.build_ui() - # we activate this after the initial build as we don't need to see the tool been populated self.apertures_table.itemChanged.connect(self.on_tool_edit) # build the geometry for each tool-diameter, each drill will be represented by a '+' symbol # and then add it to the storage elements (each storage elements is a member of a list - def job_thread(apid): + def job_thread(self, apid): with self.app.proc_container.new(_("Adding aperture: %s geo ...") % str(apid)): solid_storage_elem = [] follow_storage_elem = [] @@ -1275,18 +1261,19 @@ class FlatCAMGrbEditor(QtCore.QObject): else: self.storage_dict[apid][k] = v - apid_promise = apid - # Check promises and clear if exists - self.app.collection.plot_remove_promise(apid_promise) - # if apid_promise in self.app.collection.plot_promises: - # self.app.collection.plot_promises.remove(apid_promise) + while True: + try: + self.grb_plot_promises.remove(apid) + time.sleep(0.5) + except ValueError: + break for apid in self.gerber_obj.apertures: - self.app.worker_task.emit({'fcn': job_thread, 'params': [apid]}) - self.app.collection.plot_promise(apid) + self.grb_plot_promises.append(apid) + self.app.worker_task.emit({'fcn': job_thread, 'params': [self, apid]}) - self.start_delayed_plot(check_period=500) + self.start_delayed_plot(check_period=1000) def update_fcgerber(self, grb_obj): """ @@ -1296,6 +1283,8 @@ class FlatCAMGrbEditor(QtCore.QObject): :return: None """ + new_grb_name = self.edited_obj_name + # if the 'delayed plot' malfunctioned stop the QTimer try: self.plot_thread.stop() @@ -1305,14 +1294,14 @@ class FlatCAMGrbEditor(QtCore.QObject): if "_edit" in self.edited_obj_name: try: id = int(self.edited_obj_name[-1]) + 1 - self.edited_obj_name = self.edited_obj_name[:-1] + str(id) + new_grb_name= self.edited_obj_name[:-1] + str(id) except ValueError: - self.edited_obj_name += "_1" + new_grb_name += "_1" else: - self.edited_obj_name += "_edit" + new_grb_name = self.edited_obj_name + "_edit" self.app.worker_task.emit({'fcn': self.new_edited_gerber, - 'params': [self.edited_obj_name]}) + 'params': [new_grb_name]}) # reset the tool table self.apertures_table.clear() @@ -1349,29 +1338,36 @@ class FlatCAMGrbEditor(QtCore.QObject): :return: None """ - self.app.log.debug("Update the Gerber object with edited content. Source is %s" % - self.gerber_obj.options['name']) + self.app.log.debug("Update the Gerber object with edited content. Source is: %s" % + self.gerber_obj.options['name'].upper()) + + out_name = outname # How the object should be initialized def obj_init(grb_obj, app_obj): poly_buffer = [] follow_buffer = [] + new_geo = [] for storage_apid, storage_val in self.storage_dict.items(): grb_obj.apertures[storage_apid] = {} + for k, v in storage_val.items(): if k == 'solid_geometry': grb_obj.apertures[storage_apid][k] = [] for geo in v: - grb_obj.apertures[storage_apid][k].append(deepcopy(geo.geo)) - poly_buffer.append(deepcopy(geo.geo)) - if k == 'follow_geometry': + new_geo = deepcopy(geo.geo) + grb_obj.apertures[storage_apid][k].append(new_geo) + poly_buffer.append(new_geo) + + elif k == 'follow_geometry': grb_obj.apertures[storage_apid][k] = [] for geo in v: - grb_obj.apertures[storage_apid][k].append(deepcopy(geo.geo)) - follow_buffer.append(deepcopy(geo.geo)) + new_geo = deepcopy(geo.geo) + grb_obj.apertures[storage_apid][k].append(new_geo) + follow_buffer.append(new_geo) else: - grb_obj.apertures[storage_apid][k] = v + grb_obj.apertures[storage_apid][k] = deepcopy(v) grb_obj.aperture_macros = deepcopy(self.gerber_obj.aperture_macros) @@ -1382,9 +1378,11 @@ class FlatCAMGrbEditor(QtCore.QObject): grb_obj.follow_geometry = deepcopy(follow_buffer) - grb_obj.options = self.gerber_obj.options.copy() - grb_obj.options['name'] = outname - + for k, v in self.gerber_obj_options.items(): + if k == 'name': + grb_obj.options[k] = out_name + else: + grb_obj.options[k] = deepcopy(v) try: grb_obj.create_geometry() @@ -1832,11 +1830,15 @@ class FlatCAMGrbEditor(QtCore.QObject): self.plot_thread.start() def check_plot_finished(self): - print(self.app.collection.plot_promises) + # print(self.grb_plot_promises) try: - has_promise = self.app.collection.has_plot_promises() - if has_promise == False: + if not self.grb_plot_promises: self.plot_thread.stop() + + self.set_ui() + # now that we hava data, create the GUI interface and add it to the Tool Tab + self.build_ui() + self.plot_all() log.debug("FlatCAMGrbEditor --> delayed_plot finished") except Exception: