diff --git a/FlatCAMObj.py b/FlatCAMObj.py index bb332ac1..e4eddb1d 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -267,7 +267,7 @@ class FlatCAMObj(QtCore.QObject): self.app.worker_task.emit({'fcn': worker_task, 'params': []}) def on_scale_button_click(self): - self.app.report_usage("obj_on_scale_button") + log.debug("FlatCAMObj.on_scale_button_click()") self.read_form() factor = self.ui.scale_entry.get_value() @@ -2338,11 +2338,13 @@ class FlatCAMExcellon(FlatCAMObj, Excellon): self.units = self.app.defaults['units'].upper() - try: - # if connected, disconnect the signal from the slot on item_changed as it creates issues - self.ui.tools_table.itemChanged.disconnect() - except (TypeError, AttributeError): - pass + for row in range(self.ui.tools_table.rowCount()): + try: + # if connected, disconnect the signal from the slot on item_changed as it creates issues + offset_spin_widget = self.ui.tools_table.cellWidget(row, 4) + offset_spin_widget.valueChanged.disconnect() + except (TypeError, AttributeError): + pass n = len(self.tools) # we have (n+2) rows because there are 'n' tools, each a row, plus the last 2 rows for totals. @@ -2378,45 +2380,42 @@ class FlatCAMExcellon(FlatCAMObj, Excellon): self.tot_slot_cnt += slot_cnt - exc_id = QtWidgets.QTableWidgetItem('%d' % int(tool_no)) - exc_id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.ui.tools_table.setItem(self.tool_row, 0, exc_id) # Tool name/id + exc_id_item = QtWidgets.QTableWidgetItem('%d' % int(tool_no)) + exc_id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - # Make sure that the drill diameter when in MM is with no more than 2 decimals - # There are no drill bits in MM with more than 3 decimals diameter - # For INCH the decimals should be no more than 3. There are no drills under 10mils + dia_item = QtWidgets.QTableWidgetItem('%.*f' % (self.decimals, self.tools[tool_no]['C'])) + dia_item.setFlags(QtCore.Qt.ItemIsEnabled) - dia = QtWidgets.QTableWidgetItem('%.*f' % (self.decimals, self.tools[tool_no]['C'])) - - dia.setFlags(QtCore.Qt.ItemIsEnabled) - - drill_count = QtWidgets.QTableWidgetItem('%d' % drill_cnt) - drill_count.setFlags(QtCore.Qt.ItemIsEnabled) + drill_count_item = QtWidgets.QTableWidgetItem('%d' % drill_cnt) + drill_count_item.setFlags(QtCore.Qt.ItemIsEnabled) # if the slot number is zero is better to not clutter the GUI with zero's so we print a space - if slot_cnt > 0: - slot_count = QtWidgets.QTableWidgetItem('%d' % slot_cnt) - else: - slot_count = QtWidgets.QTableWidgetItem('') - slot_count.setFlags(QtCore.Qt.ItemIsEnabled) + slot_count_str = '%d' % slot_cnt if slot_cnt > 0 else '' + slot_count_item = QtWidgets.QTableWidgetItem(slot_count_str) + slot_count_item.setFlags(QtCore.Qt.ItemIsEnabled) try: t_offset = self.tool_offset[float('%.*f' % (self.decimals, float(self.tools[tool_no]['C'])))] except KeyError: t_offset = self.app.defaults['excellon_offset'] - tool_offset_item = QtWidgets.QTableWidgetItem('%s' % str(t_offset)) - tool_offset_item.setFlags(QtCore.Qt.ItemIsEnabled) + tool_offset_item = FCDoubleSpinner() + tool_offset_item.set_precision(self.decimals) + tool_offset_item.set_range(-9999.9999, 9999.9999) + tool_offset_item.setWrapping(True) + tool_offset_item.setSingleStep(0.1) if self.units == 'MM' else tool_offset_item.setSingleStep(0.01) + tool_offset_item.set_value(t_offset) plot_item = FCCheckBox() plot_item.setLayoutDirection(QtCore.Qt.RightToLeft) if self.ui.plot_cb.isChecked(): plot_item.setChecked(True) - self.ui.tools_table.setItem(self.tool_row, 1, dia) # Diameter - self.ui.tools_table.setItem(self.tool_row, 2, drill_count) # Number of drills per tool - self.ui.tools_table.setItem(self.tool_row, 3, slot_count) # Number of drills per tool - self.ui.tools_table.setItem(self.tool_row, 4, tool_offset_item) # Tool offset + self.ui.tools_table.setItem(self.tool_row, 0, exc_id_item) # Tool name/id + self.ui.tools_table.setItem(self.tool_row, 1, dia_item) # Diameter + self.ui.tools_table.setItem(self.tool_row, 2, drill_count_item) # Number of drills per tool + self.ui.tools_table.setItem(self.tool_row, 3, slot_count_item) # Number of drills per tool + self.ui.tools_table.setCellWidget(self.tool_row, 4, tool_offset_item) # Tool offset empty_plot_item = QtWidgets.QTableWidgetItem('') empty_plot_item.setFlags(~QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.ui.tools_table.setItem(self.tool_row, 5, empty_plot_item) @@ -2538,7 +2537,12 @@ class FlatCAMExcellon(FlatCAMObj, Excellon): self.ui.generate_milling_slots_button.show() # we reactivate the signals after the after the tool adding as we don't need to see the tool been populated - self.ui.tools_table.itemChanged.connect(self.on_tool_offset_edit) + for row in range(self.ui.tools_table.rowCount()): + try: + offset_spin_widget = self.ui.tools_table.cellWidget(row, 4) + offset_spin_widget.valueChanged.connect(self.on_tool_offset_edit) + except (TypeError, AttributeError): + pass self.ui_connect() @@ -2647,36 +2651,29 @@ class FlatCAMExcellon(FlatCAMObj, Excellon): def on_tool_offset_edit(self): # if connected, disconnect the signal from the slot on item_changed as it creates issues - self.ui.tools_table.itemChanged.disconnect() - # self.tools_table_exc.selectionModel().currentChanged.disconnect() + for row in range(self.ui.tools_table.rowCount()): + try: + # if connected, disconnect the signal from the slot on item_changed as it creates issues + offset_spin_widget = self.ui.tools_table.cellWidget(row, 4) + offset_spin_widget.valueChanged.disconnect() + except (TypeError, AttributeError): + pass self.units = self.app.defaults['units'].upper() - self.is_modified = True row_of_item_changed = self.ui.tools_table.currentRow() dia = float('%.*f' % (self.decimals, float(self.ui.tools_table.item(row_of_item_changed, 1).text()))) - current_table_offset_edited = None - if self.ui.tools_table.currentItem() is not None: - try: - current_table_offset_edited = float(self.ui.tools_table.currentItem().text()) - except ValueError: - # try to convert comma to decimal point. if it's still not working error message and return - try: - current_table_offset_edited = float(self.ui.tools_table.currentItem().text().replace(',', '.')) - self.ui.tools_table.currentItem().setText( - self.ui.tools_table.currentItem().text().replace(',', '.')) - except ValueError: - self.app.inform.emit('[ERROR_NOTCL] %s' % - _("Wrong value format entered, use a number.")) - self.ui.tools_table.currentItem().setText(str(self.tool_offset[dia])) - return - - self.tool_offset[dia] = current_table_offset_edited + self.tool_offset[dia] = self.sender().get_value() # we reactivate the signals after the after the tool editing - self.ui.tools_table.itemChanged.connect(self.on_tool_offset_edit) + for row in range(self.ui.tools_table.rowCount()): + try: + offset_spin_widget = self.ui.tools_table.cellWidget(row, 4) + offset_spin_widget.valueChanged.connect(self.on_tool_offset_edit) + except (TypeError, AttributeError): + pass def get_selected_tools_list(self): """ diff --git a/README.md b/README.md index c95de6d0..d4fa69d1 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ CAD program, and create G-Code for Isolation routing. 6.12.2019 - fixed the toggle_units() method so now the grid values are accurate to the decimal +- cleaned up the Excellon parser and fixed some bugs (old and new); Excellon parser has it's own convert_units() method no longer inheriting from Geometry +- in Excellon UI fixed bug that did not allow editing of the Offset Z parameter from the Tool table 5.12.2019 diff --git a/flatcamParsers/ParseExcellon.py b/flatcamParsers/ParseExcellon.py index bdecfc8c..e93ae9bc 100644 --- a/flatcamParsers/ParseExcellon.py +++ b/flatcamParsers/ParseExcellon.py @@ -90,7 +90,6 @@ class Excellon(Geometry): self.tools = {} # list to store the drills, see above for description self.drills = [] - # self.slots (list) to store the slots; each is a dictionary self.slots = [] @@ -107,7 +106,7 @@ class Excellon(Geometry): self.index_per_tool = {} # Dictionary to store the indexed points for each tool # ## IN|MM -> Units are inherited from Geometry - # self.units = units + self.units = self.app.defaults['units'] # Trailing "T" or leading "L" (default) # self.zeros = "T" @@ -305,8 +304,7 @@ class Excellon(Geometry): # and we need to exit from here if self.detect_gcode_re.search(eline): log.warning("This is GCODE mark: %s" % eline) - self.app.inform.emit('[ERROR_NOTCL] %s: %s' % - (_('This is GCODE mark'), eline)) + self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_('This is GCODE mark'), eline)) return # Header Begin (M48) # @@ -341,11 +339,11 @@ class Excellon(Geometry): if line_units == 'MILS': spec = {"C": (float(match.group(2)) / 1000)} self.tools[str(name_tool)] = spec - log.debug(" Tool definition: %s %s" % (name_tool, spec)) + log.debug("Tool definition: %s %s" % (name_tool, spec)) else: spec = {"C": float(match.group(2))} self.tools[str(name_tool)] = spec - log.debug(" Tool definition: %s %s" % (name_tool, spec)) + log.debug("Tool definition: %s %s" % (name_tool, spec)) spec['solid_geometry'] = [] continue # search for Altium Excellon Format / Sprint Layout who is included as a comment @@ -387,17 +385,18 @@ class Excellon(Geometry): # object's units. match = self.meas_re.match(eline) if match: - # self.units = {"1": "MM", "2": "IN"}[match.group(1)] + self.units = {"1": "MM", "2": "IN"}[match.group(1)] # Modified for issue #80 - self.convert_units({"1": "MM", "2": "IN"}[match.group(1)]) - log.debug(" Units: %s" % self.units) + log.debug("ALternative M71/M72 units found, before conversion: %s" % self.units) + self.convert_units(self.units) + log.debug("ALternative M71/M72 units found, after conversion: %s" % self.units) if self.units == 'MM': - log.warning("Excellon format preset is: %s" % self.excellon_format_upper_mm + \ - ':' + str(self.excellon_format_lower_mm)) + log.warning("Excellon format preset is: %s:%s" % + (str(self.excellon_format_upper_mm), str(self.excellon_format_lower_mm))) else: - log.warning("Excellon format preset is: %s" % self.excellon_format_upper_in + \ - ':' + str(self.excellon_format_lower_in)) + log.warning("Excellon format preset is: %s:%s" % + (str(self.excellon_format_upper_in), str(self.excellon_format_lower_in))) continue # ### Body #### @@ -784,13 +783,13 @@ class Excellon(Geometry): # ## Units and number format # ## match = self.units_re.match(eline) if match: - self.units = match.group(1) + self.units = self.units = {"METRIC": "MM", "INCH": "IN"}[match.group(1)] self.zeros = match.group(2) # "T" or "L". Might be empty self.excellon_format = match.group(3) if self.excellon_format: upper = len(self.excellon_format.partition('.')[0]) lower = len(self.excellon_format.partition('.')[2]) - if self.units == 'METRIC': + if self.units == 'MM': self.excellon_format_upper_mm = upper self.excellon_format_lower_mm = lower else: @@ -798,57 +797,55 @@ class Excellon(Geometry): self.excellon_format_lower_in = lower # Modified for issue #80 - self.convert_units({"INCH": "IN", "METRIC": "MM"}[self.units]) - # log.warning(" Units/Format: %s %s" % (self.units, self.zeros)) - log.warning("Units: %s" % self.units) + log.warning("UNITS found inline before conversion: %s" % self.units) + self.convert_units(self.units) + log.warning("UNITS found inline after conversion: %s" % self.units) if self.units == 'MM': - log.warning("Excellon format preset is: %s" % str(self.excellon_format_upper_mm) + - ':' + str(self.excellon_format_lower_mm)) + log.warning("Excellon format preset is: %s:%s" % + (str(self.excellon_format_upper_mm), str(self.excellon_format_lower_mm))) else: - log.warning("Excellon format preset is: %s" % str(self.excellon_format_upper_in) + - ':' + str(self.excellon_format_lower_in)) - log.warning("Type of zeros found inline: %s" % self.zeros) + log.warning("Excellon format preset is: %s:%s" % + (str(self.excellon_format_upper_in), str(self.excellon_format_lower_in))) + log.warning("Type of ZEROS found inline, in header: %s" % self.zeros) continue # Search for units type again it might be alone on the line if "INCH" in eline: - line_units = "INCH" + line_units = "IN" # Modified for issue #80 - self.convert_units({"INCH": "IN", "METRIC": "MM"}[line_units]) - log.warning("Type of UNITS found inline: %s" % line_units) - log.warning("Excellon format preset is: %s" % str(self.excellon_format_upper_in) + - ':' + str(self.excellon_format_lower_in)) - # TODO: not working - # FlatCAMApp.App.inform.emit("Detected INLINE: %s" % str(eline)) + log.warning("Type of UNITS found inline, in header, before conversion: %s" % line_units) + self.convert_units(line_units) + log.warning("Type of UNITS found inline, in header, after conversion: %s" % self.units) + log.warning("Excellon format preset is: %s:%s" % + (str(self.excellon_format_upper_in), str(self.excellon_format_lower_in))) continue elif "METRIC" in eline: - line_units = "METRIC" + line_units = "MM" # Modified for issue #80 - self.convert_units({"INCH": "IN", "METRIC": "MM"}[line_units]) - log.warning("Type of UNITS found inline: %s" % line_units) - log.warning("Excellon format preset is: %s" % str(self.excellon_format_upper_mm) + - ':' + str(self.excellon_format_lower_mm)) - # TODO: not working - # FlatCAMApp.App.inform.emit("Detected INLINE: %s" % str(eline)) + log.warning("Type of UNITS found inline, in header, before conversion: %s" % line_units) + self.convert_units(line_units) + log.warning("Type of UNITS found inline, in header, after conversion: %s" % self.units) + log.warning("Excellon format preset is: %s:%s" % + (str(self.excellon_format_upper_mm), str(self.excellon_format_lower_mm))) continue # Search for zeros type again because it might be alone on the line match = re.search(r'[LT]Z', eline) if match: self.zeros = match.group() - log.warning("Type of zeros found: %s" % self.zeros) + log.warning("Type of ZEROS found: %s" % self.zeros) continue # ## Units and number format outside header# ## match = self.units_re.match(eline) if match: - self.units = match.group(1) + self.units = self.units = {"METRIC": "MM", "INCH": "IN"}[match.group(1)] self.zeros = match.group(2) # "T" or "L". Might be empty self.excellon_format = match.group(3) if self.excellon_format: upper = len(self.excellon_format.partition('.')[0]) lower = len(self.excellon_format.partition('.')[2]) - if self.units == 'METRIC': + if self.units == 'MM': self.excellon_format_upper_mm = upper self.excellon_format_lower_mm = lower else: @@ -856,18 +853,17 @@ class Excellon(Geometry): self.excellon_format_lower_in = lower # Modified for issue #80 - self.convert_units({"INCH": "IN", "METRIC": "MM"}[self.units]) - # log.warning(" Units/Format: %s %s" % (self.units, self.zeros)) - log.warning("Units: %s" % self.units) - if self.units == 'MM': - log.warning("Excellon format preset is: %s" % str(self.excellon_format_upper_mm) + - ':' + str(self.excellon_format_lower_mm)) - else: - log.warning("Excellon format preset is: %s" % str(self.excellon_format_upper_in) + - ':' + str(self.excellon_format_lower_in)) - log.warning("Type of zeros found outside header, inline: %s" % self.zeros) + log.warning("Type of UNITS found outside header, inline before conversion: %s" % self.units) + self.convert_units(self.units) + log.warning("Type of UNITS found outside header, inline after conversion: %s" % self.units) - log.warning("UNITS found outside header") + if self.units == 'MM': + log.warning("Excellon format preset is: %s:%s" % + (str(self.excellon_format_upper_mm), str(self.excellon_format_lower_mm))) + else: + log.warning("Excellon format preset is: %s:%s" % + (str(self.excellon_format_upper_in), str(self.excellon_format_lower_in))) + log.warning("Type of ZEROS found outside header, inline: %s" % self.zeros) continue log.warning("Line ignored: %s" % eline) @@ -875,6 +871,7 @@ class Excellon(Geometry): # make sure that since we are in headerless mode, we convert the tools only after the file parsing # is finished since the tools definitions are spread in the Excellon body. We use as units the value # from self.defaults['excellon_units'] + log.info("Zeros: %s, Units %s." % (self.zeros, self.units)) except Exception: log.error("Excellon PARSING FAILED. Line %d: %s" % (line_num, eline)) @@ -950,6 +947,8 @@ class Excellon(Geometry): :return: None """ + + log.debug("flatcamParsers.ParseExcellon.Excellon.create_geometry()") self.solid_geometry = [] try: # clear the solid_geometry in self.tools @@ -1084,16 +1083,29 @@ class Excellon(Geometry): :type str: IN or MM :return: """ - log.debug("camlib.Excellon.convert_units()") - factor = Geometry.convert_units(self, units) + # factor = Geometry.convert_units(self, units) + obj_units = units + if obj_units.upper() == self.units.upper(): + factor = 1.0 + elif obj_units.upper() == "MM": + factor = 25.4 + elif obj_units.upper() == "IN": + factor = 1 / 25.4 + else: + log.error("Unsupported units: %s" % str(obj_units)) + factor = 1.0 + log.debug("flatcamParsers.ParseExcellon.Excellon.convert_units() --> Factor: %s" % str(factor)) + + self.units = obj_units + self.scale(factor, factor) + self.file_units_factor = factor # Tools for tname in self.tools: self.tools[tname]["C"] *= factor self.create_geometry() - return factor def scale(self, xfactor, yfactor=None, point=None): @@ -1108,7 +1120,7 @@ class Excellon(Geometry): :return: None :rtype: NOne """ - log.debug("camlib.Excellon.scale()") + log.debug("flatcamParsers.ParseExcellon.Excellon..scale()") if yfactor is None: yfactor = xfactor