diff --git a/CHANGELOG.md b/CHANGELOG.md index da764cc0..4b4cbae8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ CHANGELOG for FlatCAM Evo beta ================================================= +20.04.2022 + +- in Solderpast Plugin fixed the GCode generation; make sure that if no object is selected then the first Gerber object is autoselected +- in Solderpaste Plugin fixed the CNCJob plotting +- in Solderpaste Plugin added a new parameter 'Margin' which allows reducing how much solderpaste is added and therefore adding a space between the solderpaste and the pad boundary +- all CNCJob objects generated by the Solderpaste plugin now have the GCode saved as source_code which can be saved also from the CNCJob object context menu, and edited + 19.04.2022 - fixed and prettified the 'Light' theme diff --git a/appGUI/preferences/PreferencesUIManager.py b/appGUI/preferences/PreferencesUIManager.py index 35a4a37d..cd3bcb53 100644 --- a/appGUI/preferences/PreferencesUIManager.py +++ b/appGUI/preferences/PreferencesUIManager.py @@ -575,6 +575,7 @@ class PreferencesUIManager(QtCore.QObject): # SolderPaste Dispensing Tool "tools_solderpaste_tools": self.ui.plugin_pref_form.tools_solderpaste_group.nozzle_tool_dia_entry, "tools_solderpaste_new": self.ui.plugin_pref_form.tools_solderpaste_group.addtool_entry, + "tools_solderpaste_margin": self.ui.plugin_pref_form.tools_solderpaste_group.margin_entry, "tools_solderpaste_z_start": self.ui.plugin_pref_form.tools_solderpaste_group.z_start_entry, "tools_solderpaste_z_dispense": self.ui.plugin_pref_form.tools_solderpaste_group.z_dispense_entry, "tools_solderpaste_z_stop": self.ui.plugin_pref_form.tools_solderpaste_group.z_stop_entry, diff --git a/appGUI/preferences/tools/ToolsSolderpastePrefGroupUI.py b/appGUI/preferences/tools/ToolsSolderpastePrefGroupUI.py index d4a83813..218c71d9 100644 --- a/appGUI/preferences/tools/ToolsSolderpastePrefGroupUI.py +++ b/appGUI/preferences/tools/ToolsSolderpastePrefGroupUI.py @@ -60,8 +60,23 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): self.addtool_entry.set_range(0.0000001, 10000.0000) self.addtool_entry.setSingleStep(0.1) - param_grid.addWidget(self.addtool_entry_lbl, 1, 0) - param_grid.addWidget(self.addtool_entry, 1, 1) + param_grid.addWidget(self.addtool_entry_lbl, 2, 0) + param_grid.addWidget(self.addtool_entry, 2, 1) + + # Margin + self.margin_label = FCLabel('%s:' % _("Margin")) + self.margin_label.setToolTip('%s %s' % ( + _("Offset from the boundary."), + _("Fraction of tool diameter.") + ) + ) + self.margin_entry = FCDoubleSpinner(suffix='%') + self.margin_entry.set_range(-100.0000, 100.0000) + self.margin_entry.set_precision(self.decimals) + self.margin_entry.setSingleStep(0.1) + + param_grid.addWidget(self.margin_label, 4, 0) + param_grid.addWidget(self.margin_entry, 4, 1) # Z dispense start self.z_start_entry = FCDoubleSpinner() @@ -73,8 +88,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): self.z_start_label.setToolTip( _("The height (Z) when solder paste dispensing starts.") ) - param_grid.addWidget(self.z_start_label, 2, 0) - param_grid.addWidget(self.z_start_entry, 2, 1) + param_grid.addWidget(self.z_start_label, 6, 0) + param_grid.addWidget(self.z_start_entry, 6, 1) # Z dispense self.z_dispense_entry = FCDoubleSpinner() @@ -86,8 +101,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): self.z_dispense_label.setToolTip( _("The height (Z) when doing solder paste dispensing.") ) - param_grid.addWidget(self.z_dispense_label, 3, 0) - param_grid.addWidget(self.z_dispense_entry, 3, 1) + param_grid.addWidget(self.z_dispense_label, 8, 0) + param_grid.addWidget(self.z_dispense_entry, 8, 1) # Z dispense stop self.z_stop_entry = FCDoubleSpinner() @@ -99,8 +114,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): self.z_stop_label.setToolTip( _("The height (Z) when solder paste dispensing stops.") ) - param_grid.addWidget(self.z_stop_label, 4, 0) - param_grid.addWidget(self.z_stop_entry, 4, 1) + param_grid.addWidget(self.z_stop_label, 10, 0) + param_grid.addWidget(self.z_stop_entry, 101, 1) # Z travel self.z_travel_entry = FCDoubleSpinner() @@ -113,8 +128,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): _("The height (Z) for travel between pads\n" "(without dispensing solder paste).") ) - param_grid.addWidget(self.z_travel_label, 5, 0) - param_grid.addWidget(self.z_travel_entry, 5, 1) + param_grid.addWidget(self.z_travel_label, 12, 0) + param_grid.addWidget(self.z_travel_entry, 12, 1) # Z toolchange location self.z_toolchange_entry = FCDoubleSpinner() @@ -126,8 +141,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): self.z_toolchange_label.setToolTip( _("The height (Z) for tool (nozzle) change.") ) - param_grid.addWidget(self.z_toolchange_label, 6, 0) - param_grid.addWidget(self.z_toolchange_entry, 6, 1) + param_grid.addWidget(self.z_toolchange_label, 14, 0) + param_grid.addWidget(self.z_toolchange_entry, 14, 1) # X,Y Toolchange location self.xy_toolchange_entry = NumericalEvalTupleEntry(border_color='#0069A9') @@ -136,8 +151,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): _("The X,Y location for tool (nozzle) change.\n" "The format is (x, y) where x and y are real numbers.") ) - param_grid.addWidget(self.xy_toolchange_label, 7, 0) - param_grid.addWidget(self.xy_toolchange_entry, 7, 1) + param_grid.addWidget(self.xy_toolchange_label, 16, 0) + param_grid.addWidget(self.xy_toolchange_entry, 16, 1) # Feedrate X-Y self.frxy_entry = FCDoubleSpinner() @@ -149,8 +164,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): self.frxy_label.setToolTip( _("Feedrate (speed) while moving on the X-Y plane.") ) - param_grid.addWidget(self.frxy_label, 8, 0) - param_grid.addWidget(self.frxy_entry, 8, 1) + param_grid.addWidget(self.frxy_label, 18, 0) + param_grid.addWidget(self.frxy_entry, 18, 1) # Feedrate Z self.frz_entry = FCDoubleSpinner() @@ -163,8 +178,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): _("Feedrate (speed) while moving vertically\n" "(on Z plane).") ) - param_grid.addWidget(self.frz_label, 9, 0) - param_grid.addWidget(self.frz_entry, 9, 1) + param_grid.addWidget(self.frz_label, 20, 0) + param_grid.addWidget(self.frz_entry, 20, 1) # Feedrate Z Dispense self.frz_dispense_entry = FCDoubleSpinner() @@ -177,8 +192,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): _("Feedrate (speed) while moving up vertically\n" "to Dispense position (on Z plane).") ) - param_grid.addWidget(self.frz_dispense_label, 10, 0) - param_grid.addWidget(self.frz_dispense_entry, 10, 1) + param_grid.addWidget(self.frz_dispense_label, 22, 0) + param_grid.addWidget(self.frz_dispense_entry, 22, 1) # Spindle Speed Forward self.speedfwd_entry = FCSpinner() @@ -190,25 +205,25 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): _("The dispenser speed while pushing solder paste\n" "through the dispenser nozzle.") ) - param_grid.addWidget(self.speedfwd_label, 11, 0) - param_grid.addWidget(self.speedfwd_entry, 11, 1) + param_grid.addWidget(self.speedfwd_label, 24, 0) + param_grid.addWidget(self.speedfwd_entry, 24, 1) # Dwell Forward self.dwellfwd_entry = FCDoubleSpinner() self.dwellfwd_entry.set_precision(self.decimals) - self.dwellfwd_entry.set_range(0.0000001, 10000.0000) + self.dwellfwd_entry.set_range(0.0000, 10000.0000) self.dwellfwd_entry.setSingleStep(0.1) self.dwellfwd_label = FCLabel('%s:' % _("Dwell FWD")) self.dwellfwd_label.setToolTip( _("Pause after solder dispensing.") ) - param_grid.addWidget(self.dwellfwd_label, 12, 0) - param_grid.addWidget(self.dwellfwd_entry, 12, 1) + param_grid.addWidget(self.dwellfwd_label, 26, 0) + param_grid.addWidget(self.dwellfwd_entry, 26, 1) # Spindle Speed Reverse self.speedrev_entry = FCSpinner() - self.speedrev_entry.set_range(0, 999999) + self.speedrev_entry.set_range(0, 1000000) self.speedrev_entry.set_step(1000) self.speedrev_label = FCLabel('%s:' % _("Spindle Speed REV")) @@ -216,13 +231,13 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): _("The dispenser speed while retracting solder paste\n" "through the dispenser nozzle.") ) - param_grid.addWidget(self.speedrev_label, 13, 0) - param_grid.addWidget(self.speedrev_entry, 13, 1) + param_grid.addWidget(self.speedrev_label, 28, 0) + param_grid.addWidget(self.speedrev_entry, 28, 1) # Dwell Reverse self.dwellrev_entry = FCDoubleSpinner() self.dwellrev_entry.set_precision(self.decimals) - self.dwellrev_entry.set_range(0.0000001, 10000.0000) + self.dwellrev_entry.set_range(0.0000, 10000.0000) self.dwellrev_entry.setSingleStep(0.1) self.dwellrev_label = FCLabel('%s:' % _("Dwell REV")) @@ -230,8 +245,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): _("Pause after solder paste dispenser retracted,\n" "to allow pressure equilibrium.") ) - param_grid.addWidget(self.dwellrev_label, 14, 0) - param_grid.addWidget(self.dwellrev_entry, 14, 1) + param_grid.addWidget(self.dwellrev_label, 30, 0) + param_grid.addWidget(self.dwellrev_entry, 30, 1) # Preprocessors pp_label = FCLabel('%s:' % _('Preprocessor')) @@ -246,7 +261,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI): for it in range(self.pp_combo.count()): self.pp_combo.setItemData(it, self.pp_combo.itemText(it), QtCore.Qt.ItemDataRole.ToolTipRole) - param_grid.addWidget(pp_label, 15, 0) - param_grid.addWidget(self.pp_combo, 15, 1) + param_grid.addWidget(pp_label, 32, 0) + param_grid.addWidget(self.pp_combo, 32, 1) self.layout.addStretch() diff --git a/appObjects/CNCJobObject.py b/appObjects/CNCJobObject.py index 8cf9abb8..e795c3ef 100644 --- a/appObjects/CNCJobObject.py +++ b/appObjects/CNCJobObject.py @@ -1001,15 +1001,15 @@ class CNCJobObject(FlatCAMObj, CNCjob): if postamble == '': postamble = self.app.options["cncjob_append"] - try: - if self.special_group: - self.app.inform.emit('[WARNING_NOTCL] %s %s %s.' % - (_("This CNCJob object can't be processed because it is a"), - str(self.special_group), - _("CNCJob object"))) - return 'fail' - except AttributeError: - pass + # try: + # if self.special_group: + # self.app.inform.emit('[WARNING_NOTCL] %s %s %s.' % + # (_("This CNCJob object can't be processed because it is a"), + # str(self.special_group), + # _("CNCJob object"))) + # return 'fail' + # except AttributeError: + # pass # if this dict is not empty then the object is a Geometry object if self.obj_options['type'].lower() == 'geometry': @@ -1357,7 +1357,8 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.plot2(tooldia=dia_plot, obj=self, visible=visible, gcode_parsed=gcode_parsed, kind=kind) self.shapes.redraw() - except (ObjectDeleted, AttributeError): + except (ObjectDeleted, AttributeError) as err: + self.app.log.debug("CNCJobObject.plot() --> %s" % str(err)) self.shapes.clear(update=True) if self.app.use_3d_engine: self.annotation.clear(update=True) diff --git a/appPlugins/ToolSolderPaste.py b/appPlugins/ToolSolderPaste.py index 58586eed..1a7efd3e 100644 --- a/appPlugins/ToolSolderPaste.py +++ b/appPlugins/ToolSolderPaste.py @@ -154,6 +154,7 @@ class SolderPaste(AppTool): "tools_solderpaste_z_dispense": self.ui.z_dispense_entry, "tools_solderpaste_z_stop": self.ui.z_stop_entry, "tools_solderpaste_z_travel": self.ui.z_travel_entry, + "tools_solderpaste_margin": self.ui.margin_entry, "tools_solderpaste_z_toolchange": self.ui.z_toolchange_entry, "tools_solderpaste_xy_toolchange": self.ui.xy_toolchange_entry, "tools_solderpaste_frxy": self.ui.frxy_entry, @@ -217,6 +218,12 @@ class SolderPaste(AppTool): if obj and obj.kind == 'gerber': obj_name = obj.obj_options['name'] self.ui.obj_combo.set_value(obj_name) + else: + # select first Gerber object found + for o in self.app.collection.get_list(): + if o.kind == 'gerber': + obj_name = o.obj_options['name'] + self.ui.obj_combo.set_value(obj_name) def build_ui(self): """ @@ -451,6 +458,8 @@ class SolderPaste(AppTool): current_row = self.ui.tools_table.currentRow() uid = tooluid if tooluid else int(self.ui.tools_table.item(current_row, 2).text()) + if uid < 0: + return for key in self.form_fields: self.tooltable_tools[uid]['data'].update({ key: self.form_fields[key].get_value() @@ -718,6 +727,10 @@ class SolderPaste(AppTool): :param use_thread: use thread, True or False :return: a Geometry type object """ + + # this is a percentage of the tool diameter + tool_margin = self.ui.margin_entry.get_value() + proc = self.app.proc_container.new('%s...' % _("Working")) obj = work_object @@ -795,7 +808,7 @@ class SolderPaste(AppTool): tooluid = 1 for tool in sorted_tools: - offset = tool / 2 + offset = ((tool_margin * tool) * 0.01) + (tool / 2) for uid, vl in self.tooltable_tools.items(): if float('%.*f' % (self.decimals, float(vl['tooldia']))) == tool: tooluid = int(uid) @@ -817,7 +830,7 @@ class SolderPaste(AppTool): # so we do a hack: get first the exterior in a form of LinearRings and then convert back to Polygon # because intersection does not work on LinearRings for g in work_geo: - # for whatever reason intersection on LinearRings does not work so we convert back to Polygons + # for whatever reason intersection on LinearRings does not work, so we convert back to Polygons poly = Polygon(g) x_min, y_min, x_max, y_max = poly.bounds @@ -1002,13 +1015,13 @@ class SolderPaste(AppTool): app_obj.log.debug("GeometryObject.mtool_gen_cncjob() --> generate_from_geometry2() failed") return 'fail' else: - tool_cnc_dict['gcode'] = StringIO(res) + tool_cnc_dict['gcode'] = res total_gcode += res # ## PARSE GCODE # ## tool_cnc_dict['gcode_parsed'] = new_obj.gcode_parse(tool_data=tool_cnc_dict['data']) - # TODO this serve for bounding box creation only; should be optimized + # TODO this serve for bounding box creation only; should be optimized. Using recursive bounds()? tool_cnc_dict['solid_geometry'] = unary_union([geo['geom'] for geo in tool_cnc_dict['gcode_parsed']]) # tell gcode_parse from which point to start drawing the lines depending on what kind of @@ -1019,6 +1032,9 @@ class SolderPaste(AppTool): }) tool_cnc_dict.clear() + used_tools = list(obj.tools.keys()) + new_obj.used_tools = used_tools + new_obj.source_file = StringIO(total_gcode) if use_thread: @@ -1330,6 +1346,21 @@ class SolderUI: param_grid.addWidget(self.z_travel_label, 0, 0) param_grid.addWidget(self.z_travel_entry, 0, 1) + # MARGIN + self.margin_label = FCLabel('%s:' % _("Margin")) + self.margin_label.setToolTip('%s %s' % ( + _("Offset from the boundary."), + _("Fraction of tool diameter.") + ) + ) + self.margin_entry = FCDoubleSpinner(suffix='%') + self.margin_entry.set_range(-100.0000, 100.0000) + self.margin_entry.set_precision(self.decimals) + self.margin_entry.setSingleStep(0.1) + + param_grid.addWidget(self.margin_label, 2, 0) + param_grid.addWidget(self.margin_entry, 2, 1) + # ############################################################################################################# # Dispense Frame # ############################################################################################################# diff --git a/defaults.py b/defaults.py index 2cd38352..8dc78ab6 100644 --- a/defaults.py +++ b/defaults.py @@ -650,6 +650,7 @@ class AppDefaults: # SolderPaste Tool "tools_solderpaste_tools": "1.0, 0.3", "tools_solderpaste_new": 0.3, + "tools_solderpaste_margin": 0.0, "tools_solderpaste_z_start": 0.05, "tools_solderpaste_z_dispense": 0.1, "tools_solderpaste_z_stop": 0.05,