diff --git a/CHANGELOG.md b/CHANGELOG.md index 68cd13c2..fb2cd107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ CHANGELOG for FlatCAM beta ================================================= +10.07.2020 + +- Tool Drilling - moved some of the Excellon Preferences related to drilling operation to it's own group Drilling Tool Options +- optimized the CNCJob UI to look like other parts of the app + 9.07.2020 - Tool Drilling - remade the methods used to generate GCode from Excellon, to parse the GCode. Now the GCode and GCode_parsed are stored individually for each tool and also they are plotted individually diff --git a/appGUI/ObjectUI.py b/appGUI/ObjectUI.py index d59af045..a3e25c92 100644 --- a/appGUI/ObjectUI.py +++ b/appGUI/ObjectUI.py @@ -1555,11 +1555,13 @@ class CNCObjectUI(ObjectUI): for i in range(0, self.common_grid.count()): self.common_grid.itemAt(i).widget().hide() - # ## Plot options - self.plot_options_label = QtWidgets.QLabel("%s:" % _("Plot Options")) - self.custom_box.addWidget(self.plot_options_label) + f_lay = QtWidgets.QGridLayout() + f_lay.setColumnStretch(0, 0) + f_lay.setColumnStretch(1, 1) + self.custom_box.addLayout(f_lay) - self.cncplot_method_label = QtWidgets.QLabel("%s:" % _("Plot kind")) + # Plot Options + self.cncplot_method_label = QtWidgets.QLabel("%s:" % _("Plot Options")) self.cncplot_method_label.setToolTip( _( "This selects the kind of geometries on the canvas to plot.\n" @@ -1575,72 +1577,69 @@ class CNCObjectUI(ObjectUI): {"label": _("Cut"), "value": "cut"} ], stretch=False) - self.annotation_label = QtWidgets.QLabel("%s:" % _("Display Annotation")) - self.annotation_label.setToolTip( + f_lay.addWidget(self.cncplot_method_label, 0, 0) + f_lay.addWidget(self.cncplot_method_combo, 0, 1, 1, 2) + + self.name_hlay = QtWidgets.QHBoxLayout() + f_lay.addLayout(self.name_hlay, 1, 0, 1, 3) + + # ## Object name + name_label = QtWidgets.QLabel("%s:" % _("Name")) + self.name_entry = FCEntry() + self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus) + + self.name_hlay.addWidget(name_label) + self.name_hlay.addWidget(self.name_entry) + + # Annotation + self.annotation_cb = FCCheckBox(_("Display Annotation")) + self.annotation_cb.setToolTip( _("This selects if to display text annotation on the plot.\n" "When checked it will display numbers in order for each end\n" "of a travel line.") ) - self.annotation_cb = FCCheckBox() + f_lay.addWidget(self.annotation_cb, 2, 0, 1, 3) - # ## Object name - self.name_hlay = QtWidgets.QHBoxLayout() - self.custom_box.addLayout(self.name_hlay) - name_label = QtWidgets.QLabel("%s:" % _("Name")) - self.name_entry = FCEntry() - self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus) - self.name_hlay.addWidget(name_label) - self.name_hlay.addWidget(self.name_entry) + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + f_lay.addWidget(separator_line, 3, 0, 1, 3) - self.t_distance_label = QtWidgets.QLabel("%s:" % _("Travelled dist.")) + # Travelled Distance + self.t_distance_label = QtWidgets.QLabel("%s:" % _("Travelled distance")) self.t_distance_label.setToolTip( _("This is the total travelled distance on X-Y plane.\n" "In current units.") ) self.t_distance_entry = FCEntry() - self.t_distance_entry.setToolTip( - _("This is the total travelled distance on X-Y plane.\n" - "In current units.") - ) self.units_label = QtWidgets.QLabel() + f_lay.addWidget(self.t_distance_label, 5, 0) + f_lay.addWidget(self.t_distance_entry, 5, 1) + f_lay.addWidget(self.units_label, 5, 2) + + # Estimated Time self.t_time_label = QtWidgets.QLabel("%s:" % _("Estimated time")) self.t_time_label.setToolTip( _("This is the estimated time to do the routing/drilling,\n" "without the time spent in ToolChange events.") ) self.t_time_entry = FCEntry() - self.t_time_entry.setToolTip( - _("This is the estimated time to do the routing/drilling,\n" - "without the time spent in ToolChange events.") - ) self.units_time_label = QtWidgets.QLabel() - f_lay = QtWidgets.QGridLayout() - f_lay.setColumnStretch(1, 1) - f_lay.setColumnStretch(2, 1) - - self.custom_box.addLayout(f_lay) - f_lay.addWidget(self.cncplot_method_label, 0, 0) - f_lay.addWidget(self.cncplot_method_combo, 0, 1) - f_lay.addWidget(QtWidgets.QLabel(''), 0, 2) - f_lay.addWidget(self.annotation_label, 1, 0) - f_lay.addWidget(self.annotation_cb, 1, 1) - f_lay.addWidget(QtWidgets.QLabel(''), 1, 2) - f_lay.addWidget(self.t_distance_label, 2, 0) - f_lay.addWidget(self.t_distance_entry, 2, 1) - f_lay.addWidget(self.units_label, 2, 2) - f_lay.addWidget(self.t_time_label, 3, 0) - f_lay.addWidget(self.t_time_entry, 3, 1) - f_lay.addWidget(self.units_time_label, 3, 2) + f_lay.addWidget(self.t_time_label, 7, 0) + f_lay.addWidget(self.t_time_entry, 7, 1) + f_lay.addWidget(self.units_time_label, 7, 2) self.t_distance_label.hide() self.t_distance_entry.setVisible(False) self.t_time_label.hide() self.t_time_entry.setVisible(False) - e1_lbl = QtWidgets.QLabel('') - self.custom_box.addWidget(e1_lbl) + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + f_lay.addWidget(separator_line, 9, 0, 1, 3) hlay = QtWidgets.QHBoxLayout() self.custom_box.addLayout(hlay) diff --git a/appGUI/preferences/PreferencesUIManager.py b/appGUI/preferences/PreferencesUIManager.py index 440add86..a57b69d3 100644 --- a/appGUI/preferences/PreferencesUIManager.py +++ b/appGUI/preferences/PreferencesUIManager.py @@ -194,23 +194,8 @@ class PreferencesUIManager: "excellon_milling_dia": self.ui.excellon_defaults_form.excellon_opt_group.mill_dia_entry, - "excellon_cutz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry, - "excellon_multidepth": self.ui.excellon_defaults_form.excellon_opt_group.mpass_cb, - "excellon_depthperpass": self.ui.excellon_defaults_form.excellon_opt_group.maxdepth_entry, - "excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry, - "excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.endz_entry, - "excellon_endxy": self.ui.excellon_defaults_form.excellon_opt_group.endxy_entry, - - "excellon_feedrate_z": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry, - "excellon_spindlespeed": self.ui.excellon_defaults_form.excellon_opt_group.spindlespeed_entry, - "excellon_dwell": self.ui.excellon_defaults_form.excellon_opt_group.dwell_cb, - "excellon_dwelltime": self.ui.excellon_defaults_form.excellon_opt_group.dwelltime_entry, - "excellon_toolchange": self.ui.excellon_defaults_form.excellon_opt_group.toolchange_cb, - "excellon_toolchangez": self.ui.excellon_defaults_form.excellon_opt_group.toolchangez_entry, - "excellon_ppname_e": self.ui.excellon_defaults_form.excellon_opt_group.pp_excellon_name_cb, "excellon_tooldia": self.ui.excellon_defaults_form.excellon_opt_group.tooldia_entry, "excellon_slot_tooldia": self.ui.excellon_defaults_form.excellon_opt_group.slot_tooldia_entry, - "excellon_gcode_type": self.ui.excellon_defaults_form.excellon_opt_group.excellon_gcode_type_radio, # Excellon Advanced Options "excellon_offset": self.ui.excellon_defaults_form.excellon_adv_opt_group.offset_entry, @@ -222,9 +207,6 @@ class PreferencesUIManager: "excellon_spindledir": self.ui.excellon_defaults_form.excellon_adv_opt_group.spindledir_radio, "excellon_f_plunge": self.ui.excellon_defaults_form.excellon_adv_opt_group.fplunge_cb, "excellon_f_retract": self.ui.excellon_defaults_form.excellon_adv_opt_group.fretract_cb, - "excellon_drill_slots": self.ui.excellon_defaults_form.excellon_adv_opt_group.drill_slots_cb, - "excellon_drill_overlap": self.ui.excellon_defaults_form.excellon_adv_opt_group.drill_overlap_entry, - "excellon_last_drill": self.ui.excellon_defaults_form.excellon_adv_opt_group.last_drill_cb, # Excellon Export "excellon_exp_units": self.ui.excellon_defaults_form.excellon_exp_group.excellon_units_radio, @@ -355,10 +337,31 @@ class PreferencesUIManager: "tools_iso_isoexcept": self.ui.tools_defaults_form.tools_iso_group.except_cb, "tools_iso_selection": self.ui.tools_defaults_form.tools_iso_group.select_combo, "tools_iso_poly_ints": self.ui.tools_defaults_form.tools_iso_group.poly_int_cb, - "tools_iso_force": self.ui.tools_defaults_form.tools_iso_group.force_iso_cb, + "tools_iso_force": self.ui.tools_defaults_form.tools_iso_group.force_iso_cb, "tools_iso_area_shape": self.ui.tools_defaults_form.tools_iso_group.area_shape_radio, "tools_iso_plotting": self.ui.tools_defaults_form.tools_iso_group.plotting_radio, + # Drilling Tool + "tools_drill_tool_order": self.ui.tools_defaults_form.tools_drill_group.order_radio, + "tools_drill_cutz": self.ui.tools_defaults_form.tools_drill_group.cutz_entry, + "tools_drill_multidepth": self.ui.tools_defaults_form.tools_drill_group.mpass_cb, + "tools_drill_depthperpass": self.ui.tools_defaults_form.tools_drill_group.maxdepth_entry, + "tools_drill_travelz": self.ui.tools_defaults_form.tools_drill_group.travelz_entry, + "tools_drill_endz": self.ui.tools_defaults_form.tools_drill_group.endz_entry, + "tools_drill_endxy": self.ui.tools_defaults_form.tools_drill_group.endxy_entry, + + "tools_drill_feedrate_z": self.ui.tools_defaults_form.tools_drill_group.feedrate_z_entry, + "tools_drill_spindlespeed": self.ui.tools_defaults_form.tools_drill_group.spindlespeed_entry, + "tools_drill_dwell": self.ui.tools_defaults_form.tools_drill_group.dwell_cb, + "tools_drill_dwelltime": self.ui.tools_defaults_form.tools_drill_group.dwelltime_entry, + "tools_drill_toolchange": self.ui.tools_defaults_form.tools_drill_group.toolchange_cb, + "tools_drill_toolchangez": self.ui.tools_defaults_form.tools_drill_group.toolchangez_entry, + "tools_drill_ppname_e": self.ui.tools_defaults_form.tools_drill_group.pp_excellon_name_cb, + + "tools_drill_drill_slots": self.ui.tools_defaults_form.tools_drill_group.drill_slots_cb, + "tools_drill_drill_overlap": self.ui.tools_defaults_form.tools_drill_group.drill_overlap_entry, + "tools_drill_last_drill": self.ui.tools_defaults_form.tools_drill_group.last_drill_cb, + # NCC Tool "tools_ncctools": self.ui.tools_defaults_form.tools_ncc_group.ncc_tool_dia_entry, "tools_nccorder": self.ui.tools_defaults_form.tools_ncc_group.ncc_order_radio, diff --git a/appGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py b/appGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py index 571475a4..94d9986b 100644 --- a/appGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py +++ b/appGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py @@ -152,42 +152,4 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI): grid1.addWidget(self.fretract_cb, 8, 0, 1, 2) - separator_line = QtWidgets.QFrame() - separator_line.setFrameShape(QtWidgets.QFrame.HLine) - separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) - grid1.addWidget(separator_line, 9, 0, 1, 2) - - # DRILL SLOTS LABEL - self.dslots_label = QtWidgets.QLabel('%s:' % _('Drilling Slots')) - grid1.addWidget(self.dslots_label, 10, 0, 1, 2) - - # Drill slots - self.drill_slots_cb = FCCheckBox('%s' % _('Drill slots')) - self.drill_slots_cb.setToolTip( - _("If the selected tool has slots then they will be drilled.") - ) - grid1.addWidget(self.drill_slots_cb, 11, 0, 1, 2) - - # Drill Overlap - self.drill_overlap_label = QtWidgets.QLabel('%s:' % _('Overlap')) - self.drill_overlap_label.setToolTip( - _("How much (percentage) of the tool diameter to overlap previous drill hole.") - ) - - self.drill_overlap_entry = FCDoubleSpinner() - self.drill_overlap_entry.set_precision(self.decimals) - self.drill_overlap_entry.set_range(0.0, 9999.9999) - self.drill_overlap_entry.setSingleStep(0.1) - - grid1.addWidget(self.drill_overlap_label, 12, 0) - grid1.addWidget(self.drill_overlap_entry, 12, 1) - - # Last drill in slot - self.last_drill_cb = FCCheckBox('%s' % _('Last drill')) - self.last_drill_cb.setToolTip( - _("If the slot length is not completely covered by drill holes,\n" - "add a drill hole on the slot end point.") - ) - grid1.addWidget(self.last_drill_cb, 14, 0, 1, 2) - self.layout.addStretch() diff --git a/appGUI/preferences/excellon/ExcellonOptPrefGroupUI.py b/appGUI/preferences/excellon/ExcellonOptPrefGroupUI.py index 4d75b3bf..de1c14c3 100644 --- a/appGUI/preferences/excellon/ExcellonOptPrefGroupUI.py +++ b/appGUI/preferences/excellon/ExcellonOptPrefGroupUI.py @@ -89,201 +89,6 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI): grid2.addWidget(self.mill_dia_label, 2, 0) grid2.addWidget(self.mill_dia_entry, 2, 1) - # Cut Z - cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z')) - cutzlabel.setToolTip( - _("Drill depth (negative)\n" - "below the copper surface.") - ) - - self.cutz_entry = FCDoubleSpinner() - - if machinist_setting == 0: - self.cutz_entry.set_range(-9999.9999, 0.0000) - else: - self.cutz_entry.set_range(-9999.9999, 9999.9999) - - self.cutz_entry.setSingleStep(0.1) - self.cutz_entry.set_precision(self.decimals) - - grid2.addWidget(cutzlabel, 3, 0) - grid2.addWidget(self.cutz_entry, 3, 1) - - # Multi-Depth - self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth")) - self.mpass_cb.setToolTip( - _( - "Use multiple passes to limit\n" - "the cut depth in each pass. Will\n" - "cut multiple times until Cut Z is\n" - "reached." - ) - ) - - self.maxdepth_entry = FCDoubleSpinner() - self.maxdepth_entry.set_precision(self.decimals) - self.maxdepth_entry.set_range(0, 9999.9999) - self.maxdepth_entry.setSingleStep(0.1) - - self.maxdepth_entry.setToolTip(_("Depth of each pass (positive).")) - - grid2.addWidget(self.mpass_cb, 4, 0) - grid2.addWidget(self.maxdepth_entry, 4, 1) - - # Travel Z - travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z')) - travelzlabel.setToolTip( - _("Tool height when travelling\n" - "across the XY plane.") - ) - - self.travelz_entry = FCDoubleSpinner() - self.travelz_entry.set_precision(self.decimals) - - if machinist_setting == 0: - self.travelz_entry.set_range(0.0001, 9999.9999) - else: - self.travelz_entry.set_range(-9999.9999, 9999.9999) - - grid2.addWidget(travelzlabel, 5, 0) - grid2.addWidget(self.travelz_entry, 5, 1) - - # Tool change: - self.toolchange_cb = FCCheckBox('%s' % _("Tool change")) - self.toolchange_cb.setToolTip( - _("Include tool-change sequence\n" - "in G-Code (Pause for tool change).") - ) - grid2.addWidget(self.toolchange_cb, 6, 0, 1, 2) - - # Tool Change Z - toolchangezlabel = QtWidgets.QLabel('%s:' % _('Toolchange Z')) - toolchangezlabel.setToolTip( - _("Z-axis position (height) for\n" - "tool change.") - ) - - self.toolchangez_entry = FCDoubleSpinner() - self.toolchangez_entry.set_precision(self.decimals) - - if machinist_setting == 0: - self.toolchangez_entry.set_range(0.0001, 9999.9999) - else: - self.toolchangez_entry.set_range(-9999.9999, 9999.9999) - - grid2.addWidget(toolchangezlabel, 7, 0) - grid2.addWidget(self.toolchangez_entry, 7, 1) - - # End Move Z - endz_label = QtWidgets.QLabel('%s:' % _('End move Z')) - endz_label.setToolTip( - _("Height of the tool after\n" - "the last move at the end of the job.") - ) - self.endz_entry = FCDoubleSpinner() - self.endz_entry.set_precision(self.decimals) - - if machinist_setting == 0: - self.endz_entry.set_range(0.0000, 9999.9999) - else: - self.endz_entry.set_range(-9999.9999, 9999.9999) - - grid2.addWidget(endz_label, 8, 0) - grid2.addWidget(self.endz_entry, 8, 1) - - # End Move X,Y - endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y')) - endmove_xy_label.setToolTip( - _("End move X,Y position. In format (x,y).\n" - "If no value is entered then there is no move\n" - "on X,Y plane at the end of the job.") - ) - self.endxy_entry = NumericalEvalTupleEntry(border_color='#0069A9') - - grid2.addWidget(endmove_xy_label, 9, 0) - grid2.addWidget(self.endxy_entry, 9, 1) - - # Feedrate Z - frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z')) - frlabel.setToolTip( - _("Tool speed while drilling\n" - "(in units per minute).\n" - "So called 'Plunge' feedrate.\n" - "This is for linear move G01.") - ) - self.feedrate_z_entry = FCDoubleSpinner() - self.feedrate_z_entry.set_precision(self.decimals) - self.feedrate_z_entry.set_range(0, 99999.9999) - - grid2.addWidget(frlabel, 10, 0) - grid2.addWidget(self.feedrate_z_entry, 10, 1) - - # Spindle speed - spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed')) - spdlabel.setToolTip( - _("Speed of the spindle\n" - "in RPM (optional)") - ) - - self.spindlespeed_entry = FCSpinner() - self.spindlespeed_entry.set_range(0, 1000000) - self.spindlespeed_entry.set_step(100) - - grid2.addWidget(spdlabel, 11, 0) - grid2.addWidget(self.spindlespeed_entry, 11, 1) - - # Dwell - self.dwell_cb = FCCheckBox('%s' % _('Enable Dwell')) - self.dwell_cb .setToolTip( - _("Pause to allow the spindle to reach its\n" - "speed before cutting.") - ) - - grid2.addWidget(self.dwell_cb, 12, 0, 1, 2) - - # Dwell Time - dwelltime = QtWidgets.QLabel('%s:' % _('Duration')) - dwelltime.setToolTip(_("Number of time units for spindle to dwell.")) - self.dwelltime_entry = FCDoubleSpinner() - self.dwelltime_entry.set_precision(self.decimals) - self.dwelltime_entry.set_range(0, 99999.9999) - - grid2.addWidget(dwelltime, 13, 0) - grid2.addWidget(self.dwelltime_entry, 13, 1) - - self.ois_dwell_exc = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry]) - - # preprocessor selection - pp_excellon_label = QtWidgets.QLabel('%s:' % _("Preprocessor")) - pp_excellon_label.setToolTip( - _("The preprocessor JSON file that dictates\n" - "Gcode output.") - ) - - self.pp_excellon_name_cb = FCComboBox() - self.pp_excellon_name_cb.setFocusPolicy(Qt.StrongFocus) - - grid2.addWidget(pp_excellon_label, 14, 0) - grid2.addWidget(self.pp_excellon_name_cb, 14, 1) - - # ### Choose what to use for Gcode creation: Drills, Slots or Both - excellon_gcode_type_label = QtWidgets.QLabel('%s' % _('Gcode')) - excellon_gcode_type_label.setToolTip( - _("Choose what to use for GCode generation:\n" - "'Drills', 'Slots' or 'Both'.\n" - "When choosing 'Slots' or 'Both', slots will be\n" - "converted to drills.") - ) - self.excellon_gcode_type_radio = RadioSet([{'label': 'Drills', 'value': 'drills'}, - {'label': 'Slots', 'value': 'slots'}, - {'label': 'Both', 'value': 'both'}]) - grid2.addWidget(excellon_gcode_type_label, 15, 0) - grid2.addWidget(self.excellon_gcode_type_radio, 15, 1) - - # until I decide to implement this feature those remain disabled - excellon_gcode_type_label.hide() - self.excellon_gcode_type_radio.setVisible(False) - # ### Milling Holes ## ## self.mill_hole_label = QtWidgets.QLabel('%s' % _('Mill Holes')) self.mill_hole_label.setToolTip( diff --git a/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py b/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py index 23b94587..a0ca21bb 100644 --- a/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py +++ b/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py @@ -71,8 +71,11 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI): _("Mirror vertically (X) or horizontally (Y).") ) - self.empty_lb1 = QtWidgets.QLabel("") - grid0.addWidget(self.empty_lb1, 2, 0) + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 2, 0, 1, 2) + grid0.addWidget(self.mirax_label, 3, 0) grid0.addWidget(self.mirror_axis_radio, 3, 1) diff --git a/appGUI/preferences/tools/ToolsCutoutPrefGroupUI.py b/appGUI/preferences/tools/ToolsCutoutPrefGroupUI.py index 1f73f6fe..0bc6b4fe 100644 --- a/appGUI/preferences/tools/ToolsCutoutPrefGroupUI.py +++ b/appGUI/preferences/tools/ToolsCutoutPrefGroupUI.py @@ -164,7 +164,7 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI): gaps_items = ['None', 'LR', 'TB', '4', '2LR', '2TB', '8'] for it in gaps_items: self.gaps_combo.addItem(it) - self.gaps_combo.setStyleSheet('background-color: rgb(255,255,255)') + # self.gaps_combo.setStyleSheet('background-color: rgb(255,255,255)') # Surrounding convex box shape self.convex_box = FCCheckBox('%s' % _("Convex Shape")) diff --git a/appGUI/preferences/tools/ToolsDrillPrefGroupUI.py b/appGUI/preferences/tools/ToolsDrillPrefGroupUI.py new file mode 100644 index 00000000..9173c43b --- /dev/null +++ b/appGUI/preferences/tools/ToolsDrillPrefGroupUI.py @@ -0,0 +1,271 @@ +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings, Qt + +from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCComboBox, FCCheckBox, FCSpinner, NumericalEvalTupleEntry, \ + OptionalInputSection +from appGUI.preferences.OptionsGroupUI import OptionsGroupUI + +import gettext +import appTranslation as fcTranslate +import builtins + +fcTranslate.apply_language('strings') +if '_' not in builtins.__dict__: + _ = gettext.gettext + +settings = QSettings("Open Source", "FlatCAM") +if settings.contains("machinist"): + machinist_setting = settings.value('machinist', type=int) +else: + machinist_setting = 0 + + +class ToolsDrillPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + super(ToolsDrillPrefGroupUI, self).__init__(self, parent=parent) + + self.setTitle(str(_("Drilling Tool Options"))) + self.decimals = decimals + + # ## Clear non-copper regions + self.drill_label = QtWidgets.QLabel("%s:" % _("Parameters")) + self.drill_label.setToolTip( + _("Create CNCJob with toolpaths for drilling or milling holes.") + ) + self.layout.addWidget(self.drill_label) + + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) + + # Tool order Radio Button + self.order_label = QtWidgets.QLabel('%s:' % _('Tool order')) + 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" + "'Forward' --> means that the tools will be ordered from small to big\n" + "'Reverse' --> means that the tools will ordered from big to small\n\n" + "WARNING: using rest machining will automatically set the order\n" + "in reverse and disable this control.")) + + self.order_radio = RadioSet([{'label': _('No'), 'value': 'no'}, + {'label': _('Forward'), 'value': 'fwd'}, + {'label': _('Reverse'), 'value': 'rev'}]) + + grid0.addWidget(self.order_label, 1, 0) + grid0.addWidget(self.order_radio, 1, 1, 1, 2) + + # Cut Z + cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z')) + cutzlabel.setToolTip( + _("Drill depth (negative)\n" + "below the copper surface.") + ) + + self.cutz_entry = FCDoubleSpinner() + + if machinist_setting == 0: + self.cutz_entry.set_range(-9999.9999, 0.0000) + else: + self.cutz_entry.set_range(-9999.9999, 9999.9999) + + self.cutz_entry.setSingleStep(0.1) + self.cutz_entry.set_precision(self.decimals) + + grid0.addWidget(cutzlabel, 3, 0) + grid0.addWidget(self.cutz_entry, 3, 1, 1, 2) + + # Multi-Depth + self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth")) + self.mpass_cb.setToolTip( + _( + "Use multiple passes to limit\n" + "the cut depth in each pass. Will\n" + "cut multiple times until Cut Z is\n" + "reached." + ) + ) + + self.maxdepth_entry = FCDoubleSpinner() + self.maxdepth_entry.set_precision(self.decimals) + self.maxdepth_entry.set_range(0, 9999.9999) + self.maxdepth_entry.setSingleStep(0.1) + + self.maxdepth_entry.setToolTip(_("Depth of each pass (positive).")) + + grid0.addWidget(self.mpass_cb, 4, 0) + grid0.addWidget(self.maxdepth_entry, 4, 1, 1, 2) + + # Travel Z + travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z')) + travelzlabel.setToolTip( + _("Tool height when travelling\n" + "across the XY plane.") + ) + + self.travelz_entry = FCDoubleSpinner() + self.travelz_entry.set_precision(self.decimals) + + if machinist_setting == 0: + self.travelz_entry.set_range(0.0001, 9999.9999) + else: + self.travelz_entry.set_range(-9999.9999, 9999.9999) + + grid0.addWidget(travelzlabel, 5, 0) + grid0.addWidget(self.travelz_entry, 5, 1, 1, 2) + + # Tool change: + self.toolchange_cb = FCCheckBox('%s' % _("Tool change")) + self.toolchange_cb.setToolTip( + _("Include tool-change sequence\n" + "in G-Code (Pause for tool change).") + ) + grid0.addWidget(self.toolchange_cb, 6, 0, 1, 3) + + # Tool Change Z + toolchangezlabel = QtWidgets.QLabel('%s:' % _('Toolchange Z')) + toolchangezlabel.setToolTip( + _("Z-axis position (height) for\n" + "tool change.") + ) + + self.toolchangez_entry = FCDoubleSpinner() + self.toolchangez_entry.set_precision(self.decimals) + + if machinist_setting == 0: + self.toolchangez_entry.set_range(0.0001, 9999.9999) + else: + self.toolchangez_entry.set_range(-9999.9999, 9999.9999) + + grid0.addWidget(toolchangezlabel, 7, 0) + grid0.addWidget(self.toolchangez_entry, 7, 1, 1, 2) + + # End Move Z + endz_label = QtWidgets.QLabel('%s:' % _('End move Z')) + endz_label.setToolTip( + _("Height of the tool after\n" + "the last move at the end of the job.") + ) + self.endz_entry = FCDoubleSpinner() + self.endz_entry.set_precision(self.decimals) + + if machinist_setting == 0: + self.endz_entry.set_range(0.0000, 9999.9999) + else: + self.endz_entry.set_range(-9999.9999, 9999.9999) + + grid0.addWidget(endz_label, 8, 0) + grid0.addWidget(self.endz_entry, 8, 1, 1, 2) + + # End Move X,Y + endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y')) + endmove_xy_label.setToolTip( + _("End move X,Y position. In format (x,y).\n" + "If no value is entered then there is no move\n" + "on X,Y plane at the end of the job.") + ) + self.endxy_entry = NumericalEvalTupleEntry(border_color='#0069A9') + + grid0.addWidget(endmove_xy_label, 9, 0) + grid0.addWidget(self.endxy_entry, 9, 1, 1, 2) + + # Feedrate Z + frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z')) + frlabel.setToolTip( + _("Tool speed while drilling\n" + "(in units per minute).\n" + "So called 'Plunge' feedrate.\n" + "This is for linear move G01.") + ) + self.feedrate_z_entry = FCDoubleSpinner() + self.feedrate_z_entry.set_precision(self.decimals) + self.feedrate_z_entry.set_range(0, 99999.9999) + + grid0.addWidget(frlabel, 10, 0) + grid0.addWidget(self.feedrate_z_entry, 10, 1, 1, 2) + + # Spindle speed + spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed')) + spdlabel.setToolTip( + _("Speed of the spindle\n" + "in RPM (optional)") + ) + + self.spindlespeed_entry = FCSpinner() + self.spindlespeed_entry.set_range(0, 1000000) + self.spindlespeed_entry.set_step(100) + + grid0.addWidget(spdlabel, 11, 0) + grid0.addWidget(self.spindlespeed_entry, 11, 1, 1, 2) + + # Dwell + self.dwell_cb = FCCheckBox('%s' % _('Enable Dwell')) + self.dwell_cb.setToolTip( + _("Pause to allow the spindle to reach its\n" + "speed before cutting.") + ) + + grid0.addWidget(self.dwell_cb, 12, 0, 1, 3) + + # Dwell Time + dwelltime = QtWidgets.QLabel('%s:' % _('Duration')) + dwelltime.setToolTip(_("Number of time units for spindle to dwell.")) + self.dwelltime_entry = FCDoubleSpinner() + self.dwelltime_entry.set_precision(self.decimals) + self.dwelltime_entry.set_range(0, 99999.9999) + + grid0.addWidget(dwelltime, 13, 0) + grid0.addWidget(self.dwelltime_entry, 13, 1, 1, 2) + + self.ois_dwell_exc = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry]) + + # preprocessor selection + pp_excellon_label = QtWidgets.QLabel('%s:' % _("Preprocessor")) + pp_excellon_label.setToolTip( + _("The preprocessor JSON file that dictates\n" + "Gcode output.") + ) + + self.pp_excellon_name_cb = FCComboBox() + self.pp_excellon_name_cb.setFocusPolicy(Qt.StrongFocus) + + grid0.addWidget(pp_excellon_label, 14, 0) + grid0.addWidget(self.pp_excellon_name_cb, 14, 1, 1, 2) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 16, 0, 1, 3) + + # DRILL SLOTS LABEL + self.dslots_label = QtWidgets.QLabel('%s:' % _('Drilling Slots')) + grid0.addWidget(self.dslots_label, 18, 0, 1, 3) + + # Drill slots + self.drill_slots_cb = FCCheckBox('%s' % _('Drill slots')) + self.drill_slots_cb.setToolTip( + _("If the selected tool has slots then they will be drilled.") + ) + grid0.addWidget(self.drill_slots_cb, 20, 0, 1, 3) + + # Drill Overlap + self.drill_overlap_label = QtWidgets.QLabel('%s:' % _('Overlap')) + self.drill_overlap_label.setToolTip( + _("How much (percentage) of the tool diameter to overlap previous drill hole.") + ) + + self.drill_overlap_entry = FCDoubleSpinner() + self.drill_overlap_entry.set_precision(self.decimals) + self.drill_overlap_entry.set_range(0.0, 9999.9999) + self.drill_overlap_entry.setSingleStep(0.1) + + grid0.addWidget(self.drill_overlap_label, 22, 0) + grid0.addWidget(self.drill_overlap_entry, 22, 1, 1, 2) + + # Last drill in slot + self.last_drill_cb = FCCheckBox('%s' % _('Last drill')) + self.last_drill_cb.setToolTip( + _("If the slot length is not completely covered by drill holes,\n" + "add a drill hole on the slot end point.") + ) + grid0.addWidget(self.last_drill_cb, 24, 0, 1, 3) + + self.layout.addStretch() diff --git a/appGUI/preferences/tools/ToolsPreferencesUI.py b/appGUI/preferences/tools/ToolsPreferencesUI.py index a3133fe4..cd9cf1ab 100644 --- a/appGUI/preferences/tools/ToolsPreferencesUI.py +++ b/appGUI/preferences/tools/ToolsPreferencesUI.py @@ -14,6 +14,7 @@ from appGUI.preferences.tools.ToolsCutoutPrefGroupUI import ToolsCutoutPrefGroup from appGUI.preferences.tools.ToolsNCCPrefGroupUI import ToolsNCCPrefGroupUI from appGUI.preferences.tools.ToolsPaintPrefGroupUI import ToolsPaintPrefGroupUI from appGUI.preferences.tools.ToolsISOPrefGroupUI import ToolsISOPrefGroupUI +from appGUI.preferences.tools.ToolsDrillPrefGroupUI import ToolsDrillPrefGroupUI import gettext import appTranslation as fcTranslate @@ -41,6 +42,9 @@ class ToolsPreferencesUI(QtWidgets.QWidget): self.tools_iso_group = ToolsISOPrefGroupUI(decimals=self.decimals) self.tools_iso_group.setMinimumWidth(220) + self.tools_drill_group = ToolsDrillPrefGroupUI(decimals=self.decimals) + self.tools_drill_group.setMinimumWidth(220) + self.tools_ncc_group = ToolsNCCPrefGroupUI(decimals=self.decimals) self.tools_ncc_group.setMinimumWidth(220) @@ -75,17 +79,19 @@ class ToolsPreferencesUI(QtWidgets.QWidget): self.tools_sub_group.setMinimumWidth(200) self.vlay = QtWidgets.QVBoxLayout() - self.vlay.addWidget(self.tools_ncc_group) - self.vlay.addWidget(self.tools_cutout_group) + + self.vlay.addWidget(self.tools_iso_group) + self.vlay.addWidget(self.tools_drill_group) self.vlay1 = QtWidgets.QVBoxLayout() - self.vlay1.addWidget(self.tools_paint_group) - self.vlay1.addWidget(self.tools_iso_group) + self.vlay1.addWidget(self.tools_ncc_group) + self.vlay1.addWidget(self.tools_2sided_group) + self.vlay1.addWidget(self.tools_cutout_group) + self.vlay1.addWidget(self.tools_sub_group) self.vlay2 = QtWidgets.QVBoxLayout() + self.vlay2.addWidget(self.tools_paint_group) self.vlay2.addWidget(self.tools_transform_group) - self.vlay2.addWidget(self.tools_2sided_group) - self.vlay2.addWidget(self.tools_sub_group) self.vlay3 = QtWidgets.QVBoxLayout() self.vlay3.addWidget(self.tools_film_group) diff --git a/appObjects/FlatCAMExcellon.py b/appObjects/FlatCAMExcellon.py index 4a6555bd..09d9b27e 100644 --- a/appObjects/FlatCAMExcellon.py +++ b/appObjects/FlatCAMExcellon.py @@ -131,7 +131,7 @@ class ExcellonObject(FlatCAMObj, Excellon): # Attributes to be included in serialization # Always append to it because it carries contents # from predecessors. - self.ser_attrs += ['options', 'kind'] + self.ser_attrs += ['options', 'kind', 'fill_color', 'outline_color', 'alpha_level'] @staticmethod def merge(exc_list, exc_final, decimals=None, fuse_tools=True): @@ -226,6 +226,58 @@ class ExcellonObject(FlatCAMObj, Excellon): # create the geometry for the exc_final object exc_final.create_geometry() + def set_ui(self, ui): + """ + Configures the user interface for this object. + Connects options to form fields. + + :param ui: User interface object. + :type ui: ExcellonObjectUI + :return: None + """ + FlatCAMObj.set_ui(self, ui) + + log.debug("ExcellonObject.set_ui()") + + self.units = self.app.defaults['units'].upper() + + self.form_fields.update({ + "plot": self.ui.plot_cb, + "solid": self.ui.solid_cb, + "multicolored": self.ui.multicolored_cb, + + "tooldia": self.ui.tooldia_entry, + "slot_tooldia": self.ui.slot_tooldia_entry, + }) + + self.to_form() + + # Show/Hide Advanced Options + if self.app.defaults["global_app_level"] == 'b': + self.ui.level.setText('%s' % _('Basic')) + + self.ui.tools_table.setColumnHidden(4, True) + self.ui.tools_table.setColumnHidden(5, True) + else: + self.ui.level.setText('%s' % _('Advanced')) + + assert isinstance(self.ui, ExcellonObjectUI), \ + "Expected a ExcellonObjectUI, got %s" % type(self.ui) + + self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click) + self.ui.solid_cb.stateChanged.connect(self.on_solid_cb_click) + self.ui.multicolored_cb.stateChanged.connect(self.on_multicolored_cb_click) + + self.ui.drill_button.clicked.connect(lambda: self.app.drilling_tool.run(toggle=True)) + # self.ui.milling_button.clicked.connect(lambda: self.app.milling_tool.run(toggle=True)) + + self.ui.generate_milling_button.clicked.connect(self.on_generate_milling_button_click) + self.ui.generate_milling_slots_button.clicked.connect(self.on_generate_milling_slots_button_click) + + self.ui.tools_table.horizontalHeader().sectionClicked.connect(self.on_toggle_rows) + + self.units_found = self.app.defaults['units'] + def build_ui(self): """ Will (re)build the Excellon UI updating it (the tool table) @@ -455,58 +507,6 @@ class ExcellonObject(FlatCAMObj, Excellon): self.ui_connect() - def set_ui(self, ui): - """ - Configures the user interface for this object. - Connects options to form fields. - - :param ui: User interface object. - :type ui: ExcellonObjectUI - :return: None - """ - FlatCAMObj.set_ui(self, ui) - - log.debug("ExcellonObject.set_ui()") - - self.units = self.app.defaults['units'].upper() - - self.form_fields.update({ - "plot": self.ui.plot_cb, - "solid": self.ui.solid_cb, - "multicolored": self.ui.multicolored_cb, - - "tooldia": self.ui.tooldia_entry, - "slot_tooldia": self.ui.slot_tooldia_entry, - }) - - self.to_form() - - # Show/Hide Advanced Options - if self.app.defaults["global_app_level"] == 'b': - self.ui.level.setText('%s' % _('Basic')) - - self.ui.tools_table.setColumnHidden(4, True) - self.ui.tools_table.setColumnHidden(5, True) - else: - self.ui.level.setText('%s' % _('Advanced')) - - assert isinstance(self.ui, ExcellonObjectUI), \ - "Expected a ExcellonObjectUI, got %s" % type(self.ui) - - self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click) - self.ui.solid_cb.stateChanged.connect(self.on_solid_cb_click) - self.ui.multicolored_cb.stateChanged.connect(self.on_multicolored_cb_click) - - self.ui.drill_button.clicked.connect(lambda: self.app.drilling_tool.run(toggle=True)) - # self.ui.milling_button.clicked.connect(lambda: self.app.milling_tool.run(toggle=True)) - - self.ui.generate_milling_button.clicked.connect(self.on_generate_milling_button_click) - self.ui.generate_milling_slots_button.clicked.connect(self.on_generate_milling_slots_button_click) - - self.ui.tools_table.horizontalHeader().sectionClicked.connect(self.on_toggle_rows) - - self.units_found = self.app.defaults['units'] - def ui_connect(self): """ Will connect all signals in the Excellon UI that needs to be connected @@ -548,7 +548,6 @@ class ExcellonObject(FlatCAMObj, Excellon): except (TypeError, AttributeError): pass - def on_row_selection_change(self): """ Called when the user clicks on a row in Tools Table @@ -950,9 +949,9 @@ class ExcellonObject(FlatCAMObj, Excellon): # in case that the tool used has the same diameter with the hole, and since the maximum resolution # for FlatCAM is 6 decimals, # we add a tenth of the minimum value, meaning 0.0000001, which from our point of view is "almost zero" - for tool in tools: - for drill in self.tools[tool]['drills']: - buffer_value = self.tools[tool]['tooldia'] / 2 - tooldia / 2 + for etool in tools: + for drill in self.tools[etool]['drills']: + buffer_value = self.tools[etool]['tooldia'] / 2 - tooldia / 2 if buffer_value == 0: geo_obj.solid_geometry.append(drill.buffer(0.0000001).exterior) else: diff --git a/appObjects/FlatCAMGerber.py b/appObjects/FlatCAMGerber.py index 61487419..25d759d3 100644 --- a/appObjects/FlatCAMGerber.py +++ b/appObjects/FlatCAMGerber.py @@ -200,7 +200,8 @@ class GerberObject(FlatCAMObj, Gerber): # Fill form fields only on object create self.to_form() - assert isinstance(self.ui, GerberObjectUI) + assert isinstance(self.ui, GerberObjectUI), \ + "Expected a GerberObjectUI, got %s" % type(self.ui) self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click) self.ui.solid_cb.stateChanged.connect(self.on_solid_cb_click) diff --git a/appTools/ToolDrilling.py b/appTools/ToolDrilling.py index 84195749..69093a09 100644 --- a/appTools/ToolDrilling.py +++ b/appTools/ToolDrilling.py @@ -15,9 +15,7 @@ from appParsers.ParseExcellon import Excellon from copy import deepcopy import numpy as np -import math -from shapely.ops import unary_union from shapely.geometry import Point, LineString from matplotlib.backend_bases import KeyEvent as mpl_key_event @@ -27,8 +25,6 @@ import gettext import appTranslation as fcTranslate import builtins import platform -import re -import traceback from Common import GracefulException as grace @@ -36,10 +32,6 @@ fcTranslate.apply_language('strings') if '_' not in builtins.__dict__: _ = gettext.gettext -if platform.architecture()[0] == '64bit': - from ortools.constraint_solver import pywrapcp - from ortools.constraint_solver import routing_enums_pb2 - log = logging.getLogger('base') settings = QtCore.QSettings("Open Source", "FlatCAM") @@ -170,7 +162,6 @@ class ToolDrilling(AppTool, Excellon): "e_drill_last_drill": "last_drill", } - self.old_tool_dia = None self.poly_drawn = False self.connect_signals_at_init() @@ -237,7 +228,6 @@ class ToolDrilling(AppTool, Excellon): def set_tool_ui(self): self.units = self.app.defaults['units'].upper() - self.old_tool_dia = self.app.defaults["tools_iso_newdia"] # try to select in the Excellon combobox the active object try: @@ -292,7 +282,7 @@ class ToolDrilling(AppTool, Excellon): self.t_ui.tools_frame.show() - self.t_ui.order_radio.set_value(self.app.defaults["excellon_tool_order"]) + self.t_ui.order_radio.set_value(self.app.defaults["tools_drill_tool_order"]) loaded_obj = self.app.collection.get_by_name(self.t_ui.object_combo.get_value()) if loaded_obj: @@ -324,56 +314,49 @@ class ToolDrilling(AppTool, Excellon): "excellon_plot_line": self.app.defaults["excellon_plot_line"], # Excellon Options - "excellon_tool_order": self.app.defaults["excellon_tool_order"], + "tooldia": self.app.defaults["excellon_tooldia"], + "slot_tooldia": self.app.defaults["excellon_slot_tooldia"], - "cutz": self.app.defaults["excellon_cutz"], - "multidepth": self.app.defaults["excellon_multidepth"], - "depthperpass": self.app.defaults["excellon_depthperpass"], - - "travelz": self.app.defaults["excellon_travelz"], - "endz": self.app.defaults["excellon_endz"], - "endxy": self.app.defaults["excellon_endxy"], - - "feedrate_z": self.app.defaults["excellon_feedrate_z"], - - "spindlespeed": self.app.defaults["excellon_spindlespeed"], - "dwell": self.app.defaults["excellon_dwell"], - "dwelltime": self.app.defaults["excellon_dwelltime"], - - "toolchange": self.app.defaults["excellon_toolchange"], - "toolchangez": self.app.defaults["excellon_toolchangez"], - - "ppname_e": self.app.defaults["excellon_ppname_e"], - - "tooldia": self.app.defaults["excellon_tooldia"], - "slot_tooldia": self.app.defaults["excellon_slot_tooldia"], - - "gcode_type": self.app.defaults["excellon_gcode_type"], + # Excellon Advanced Options + "offset": self.app.defaults["excellon_offset"], + "toolchangexy": self.app.defaults["excellon_toolchangexy"], + "startz": self.app.defaults["excellon_startz"], + "feedrate_rapid": self.app.defaults["excellon_feedrate_rapid"], + "z_pdepth": self.app.defaults["excellon_z_pdepth"], + "feedrate_probe": self.app.defaults["excellon_feedrate_probe"], + "spindledir": self.app.defaults["excellon_spindledir"], + "f_plunge": self.app.defaults["excellon_f_plunge"], + "f_retract": self.app.defaults["excellon_f_retract"], "excellon_area_exclusion": self.app.defaults["excellon_area_exclusion"], "excellon_area_shape": self.app.defaults["excellon_area_shape"], "excellon_area_strategy": self.app.defaults["excellon_area_strategy"], "excellon_area_overz": self.app.defaults["excellon_area_overz"], - # Excellon Advanced Options - "offset": self.app.defaults["excellon_offset"], - "toolchangexy": self.app.defaults["excellon_toolchangexy"], - "startz": self.app.defaults["excellon_startz"], - "feedrate_rapid": self.app.defaults["excellon_feedrate_rapid"], - "z_pdepth": self.app.defaults["excellon_z_pdepth"], - "feedrate_probe": self.app.defaults["excellon_feedrate_probe"], - "spindledir": self.app.defaults["excellon_spindledir"], - "f_plunge": self.app.defaults["excellon_f_plunge"], - "f_retract": self.app.defaults["excellon_f_retract"], + + "tools_drill_tool_order": self.app.defaults["tools_drill_tool_order"], + "tools_drill_cutz": self.app.defaults["tools_drill_cutz"], + "tools_drill_multidepth": self.app.defaults["tools_drill_multidepth"], + "tools_drill_depthperpass": self.app.defaults["tools_drill_depthperpass"], + + "tools_drill_travelz": self.app.defaults["tools_drill_travelz"], + "tools_drill_endz": self.app.defaults["tools_drill_endz"], + "tools_drill_endxy": self.app.defaults["tools_drill_endxy"], + "tools_drill_feedrate_z": self.app.defaults["tools_drill_feedrate_z"], + + "tools_drill_spindlespeed": self.app.defaults["tools_drill_spindlespeed"], + "tools_drill_dwell": self.app.defaults["tools_drill_dwell"], + "tools_drill_dwelltime": self.app.defaults["tools_drill_dwelltime"], + + "tools_drill_toolchange": self.app.defaults["tools_drill_toolchange"], + "tools_drill_toolchangez": self.app.defaults["tools_drill_toolchangez"], + "tools_drill_ppname_e": self.app.defaults["tools_drill_ppname_e"], # Drill Slots - "drill_slots": self.app.defaults["excellon_drill_slots"], - "drill_overlap": self.app.defaults["excellon_drill_overlap"], - "last_drill": self.app.defaults["excellon_last_drill"], + "tools_drill_drill_slots": self.app.defaults["tools_drill_drill_slots"], + "tools_drill_drill_overlap": self.app.defaults["tools_drill_drill_overlap"], + "tools_drill_last_drill": self.app.defaults["tools_drill_last_drill"], - "gcode": '', - "gcode_parsed": '', - "geometry": [], } # fill in self.default_data values from self.options @@ -408,21 +391,21 @@ class ToolDrilling(AppTool, Excellon): # ####### Fill in the parameters ######### # ######################################## # ######################################## - self.t_ui.cutz_entry.set_value(self.app.defaults["excellon_cutz"]) - self.t_ui.mpass_cb.set_value(self.app.defaults["excellon_multidepth"]) - self.t_ui.maxdepth_entry.set_value(self.app.defaults["excellon_depthperpass"]) - self.t_ui.travelz_entry.set_value(self.app.defaults["excellon_travelz"]) - self.t_ui.feedrate_z_entry.set_value(self.app.defaults["excellon_feedrate_z"]) + self.t_ui.cutz_entry.set_value(self.app.defaults["tools_drill_cutz"]) + self.t_ui.mpass_cb.set_value(self.app.defaults["tools_drill_multidepth"]) + self.t_ui.maxdepth_entry.set_value(self.app.defaults["tools_drill_depthperpass"]) + self.t_ui.travelz_entry.set_value(self.app.defaults["tools_drill_travelz"]) + self.t_ui.feedrate_z_entry.set_value(self.app.defaults["tools_drill_feedrate_z"]) self.t_ui.feedrate_rapid_entry.set_value(self.app.defaults["excellon_feedrate_rapid"]) - self.t_ui.spindlespeed_entry.set_value(self.app.defaults["excellon_spindlespeed"]) - self.t_ui.dwell_cb.set_value(self.app.defaults["excellon_dwell"]) - self.t_ui.dwelltime_entry.set_value(self.app.defaults["excellon_dwelltime"]) + self.t_ui.spindlespeed_entry.set_value(self.app.defaults["tools_drill_spindlespeed"]) + self.t_ui.dwell_cb.set_value(self.app.defaults["tools_drill_dwell"]) + self.t_ui.dwelltime_entry.set_value(self.app.defaults["tools_drill_dwelltime"]) self.t_ui.offset_entry.set_value(self.app.defaults["excellon_offset"]) - self.t_ui.toolchange_cb.set_value(self.app.defaults["excellon_toolchange"]) - self.t_ui.toolchangez_entry.set_value(self.app.defaults["excellon_toolchangez"]) + self.t_ui.toolchange_cb.set_value(self.app.defaults["tools_drill_toolchange"]) + self.t_ui.toolchangez_entry.set_value(self.app.defaults["tools_drill_toolchangez"]) self.t_ui.estartz_entry.set_value(self.app.defaults["excellon_startz"]) - self.t_ui.endz_entry.set_value(self.app.defaults["excellon_endz"]) - self.t_ui.endxy_entry.set_value(self.app.defaults["excellon_endxy"]) + self.t_ui.endz_entry.set_value(self.app.defaults["tools_drill_endz"]) + self.t_ui.endxy_entry.set_value(self.app.defaults["tools_drill_endxy"]) self.t_ui.pdepth_entry.set_value(self.app.defaults["excellon_z_pdepth"]) self.t_ui.feedrate_probe_entry.set_value(self.app.defaults["excellon_feedrate_probe"]) self.t_ui.exclusion_cb.set_value(self.app.defaults["excellon_area_exclusion"]) @@ -431,9 +414,9 @@ class ToolDrilling(AppTool, Excellon): self.t_ui.area_shape_radio.set_value(self.app.defaults["excellon_area_shape"]) # Drill slots - part of the Advanced Excellon params - self.t_ui.drill_slots_cb.set_value(self.app.defaults["excellon_drill_slots"]) - self.t_ui.drill_overlap_entry.set_value(self.app.defaults["excellon_drill_overlap"]) - self.t_ui.last_drill_cb.set_value(self.app.defaults["excellon_last_drill"]) + self.t_ui.drill_slots_cb.set_value(self.app.defaults["tools_drill_drill_slots"]) + self.t_ui.drill_overlap_entry.set_value(self.app.defaults["tools_drill_drill_overlap"]) + self.t_ui.last_drill_cb.set_value(self.app.defaults["tools_drill_last_drill"]) # if the app mode is Basic then disable this feature if app_mode == 'b': self.t_ui.drill_slots_cb.set_value(False) @@ -917,7 +900,7 @@ class ToolDrilling(AppTool, Excellon): for form_key in self.form_fields: for storage_key in dict_storage: if form_key == storage_key and form_key not in \ - ["toolchange", "toolchangez", "startz", "endz", "ppname_e", "ppname_g"]: + ["tools_drill_toolchange", "tools_drill_toolchangez", "startz", "endz", "tools_drill_ppname_e"]: try: self.form_fields[form_key].set_value(dict_storage[form_key]) except Exception as e: @@ -1060,239 +1043,6 @@ class ToolDrilling(AppTool, Excellon): 'tool_type': tt, }) - def generate_milling_drills(self, tools=None, outname=None, tooldia=None, plot=False, use_thread=False): - """ - Will generate an Geometry Object allowing to cut a drill hole instead of drilling it. - - Note: This method is a good template for generic operations as - it takes it's options from parameters or otherwise from the - object's options and returns a (success, msg) tuple as feedback - for shell operations. - - :param tools: A list of tools where the drills are to be milled or a string: "all" - :type tools: - :param outname: the name of the resulting Geometry object - :type outname: str - :param tooldia: the tool diameter to be used in creation of the milling path (Geometry Object) - :type tooldia: float - :param plot: if to plot the resulting object - :type plot: bool - :param use_thread: if to use threading for creation of the Geometry object - :type use_thread: bool - :return: Success/failure condition tuple (bool, str). - :rtype: tuple - """ - - # Get the tools from the list. These are keys - # to self.tools - if tools is None: - tools = self.get_selected_tools_list() - - if outname is None: - outname = self.options["name"] + "_mill" - - if tooldia is None: - tooldia = float(self.options["tooldia"]) - - # Sort tools by diameter. items() -> [('name', diameter), ...] - # sorted_tools = sorted(list(self.tools.items()), key=lambda tl: tl[1]) # no longer works in Python3 - - sort = [] - for k, v in self.tools.items(): - sort.append((k, v.get('tooldia'))) - sorted_tools = sorted(sort, key=lambda t1: t1[1]) - - if tools == "all": - tools = [i[0] for i in sorted_tools] # List if ordered tool names. - log.debug("Tools 'all' and sorted are: %s" % str(tools)) - - if len(tools) == 0: - self.app.inform.emit('[ERROR_NOTCL] %s' % - _("Please select one or more tools from the list and try again.")) - return False, "Error: No tools." - - for tool in tools: - if tooldia > self.tools[tool]["C"]: - self.app.inform.emit( - '[ERROR_NOTCL] %s %s: %s' % ( - _("Milling tool for DRILLS is larger than hole size. Cancelled."), - _("Tool"), - str(tool) - ) - ) - return False, "Error: Milling tool is larger than hole." - - def geo_init(geo_obj, app_obj): - """ - - :param geo_obj: New object - :type geo_obj: GeometryObject - :param app_obj: App - :type app_obj: FlatCAMApp.App - :return: - :rtype: - """ - assert geo_obj.kind == 'geometry', "Initializer expected a GeometryObject, got %s" % type(geo_obj) - - app_obj.inform.emit(_("Generating drills milling geometry...")) - - # ## Add properties to the object - - # get the tool_table items in a list of row items - tool_table_items = self.get_selected_tools_table_items() - # insert an information only element in the front - tool_table_items.insert(0, [_("Tool_nr"), _("Diameter"), _("Drills_Nr"), _("Slots_Nr")]) - - geo_obj.options['Tools_in_use'] = tool_table_items - geo_obj.options['type'] = 'Excellon Geometry' - geo_obj.options["cnctooldia"] = str(tooldia) - geo_obj.options["multidepth"] = self.options["multidepth"] - geo_obj.solid_geometry = [] - - # in case that the tool used has the same diameter with the hole, and since the maximum resolution - # for FlatCAM is 6 decimals, - # we add a tenth of the minimum value, meaning 0.0000001, which from our point of view is "almost zero" - for hole in self.drills: - if hole['tool'] in tools: - buffer_value = self.tools[hole['tool']]["C"] / 2 - tooldia / 2 - if buffer_value == 0: - geo_obj.solid_geometry.append( - Point(hole['point']).buffer(0.0000001).exterior) - else: - geo_obj.solid_geometry.append( - Point(hole['point']).buffer(buffer_value).exterior) - - if use_thread: - def geo_thread(a_obj): - a_obj.app_obj.new_object("geometry", outname, geo_init, plot=plot) - - # Create a promise with the new name - self.app.collection.promise(outname) - - # Send to worker - self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]}) - else: - self.app.app_obj.new_object("geometry", outname, geo_init, plot=plot) - - return True, "" - - def generate_milling_slots(self, tools=None, outname=None, tooldia=None, plot=False, use_thread=False): - """ - Will generate an Geometry Object allowing to cut/mill a slot hole. - - Note: This method is a good template for generic operations as - it takes it's options from parameters or otherwise from the - object's options and returns a (success, msg) tuple as feedback - for shell operations. - - :param tools: A list of tools where the drills are to be milled or a string: "all" - :type tools: - :param outname: the name of the resulting Geometry object - :type outname: str - :param tooldia: the tool diameter to be used in creation of the milling path (Geometry Object) - :type tooldia: float - :param plot: if to plot the resulting object - :type plot: bool - :param use_thread: if to use threading for creation of the Geometry object - :type use_thread: bool - :return: Success/failure condition tuple (bool, str). - :rtype: tuple - """ - - # Get the tools from the list. These are keys - # to self.tools - if tools is None: - tools = self.get_selected_tools_list() - - if outname is None: - outname = self.options["name"] + "_mill" - - if tooldia is None: - tooldia = float(self.options["slot_tooldia"]) - - # Sort tools by diameter. items() -> [('name', diameter), ...] - # sorted_tools = sorted(list(self.tools.items()), key=lambda tl: tl[1]) # no longer works in Python3 - - sort = [] - for k, v in self.tools.items(): - sort.append((k, v.get('tooldia'))) - sorted_tools = sorted(sort, key=lambda t1: t1[1]) - - if tools == "all": - tools = [i[0] for i in sorted_tools] # List if ordered tool names. - log.debug("Tools 'all' and sorted are: %s" % str(tools)) - - if len(tools) == 0: - self.app.inform.emit('[ERROR_NOTCL] %s' % - _("Please select one or more tools from the list and try again.")) - return False, "Error: No tools." - - for tool in tools: - # I add the 0.0001 value to account for the rounding error in converting from IN to MM and reverse - adj_toolstable_tooldia = float('%.*f' % (self.decimals, float(tooldia))) - adj_file_tooldia = float('%.*f' % (self.decimals, float(self.tools[tool]["C"]))) - if adj_toolstable_tooldia > adj_file_tooldia + 0.0001: - self.app.inform.emit('[ERROR_NOTCL] %s' % - _("Milling tool for SLOTS is larger than hole size. Cancelled.")) - return False, "Error: Milling tool is larger than hole." - - def geo_init(geo_obj, app_obj): - assert geo_obj.kind == 'geometry', "Initializer expected a GeometryObject, got %s" % type(geo_obj) - - app_obj.inform.emit(_("Generating slot milling geometry...")) - - # ## Add properties to the object - # get the tool_table items in a list of row items - tool_table_items = self.get_selected_tools_table_items() - # insert an information only element in the front - tool_table_items.insert(0, [_("Tool_nr"), _("Diameter"), _("Drills_Nr"), _("Slots_Nr")]) - - geo_obj.options['Tools_in_use'] = tool_table_items - geo_obj.options['type'] = 'Excellon Geometry' - geo_obj.options["cnctooldia"] = str(tooldia) - geo_obj.options["multidepth"] = self.options["multidepth"] - geo_obj.solid_geometry = [] - - # in case that the tool used has the same diameter with the hole, and since the maximum resolution - # for FlatCAM is 6 decimals, - # we add a tenth of the minimum value, meaning 0.0000001, which from our point of view is "almost zero" - for slot in self.slots: - if slot['tool'] in tools: - toolstable_tool = float('%.*f' % (self.decimals, float(tooldia))) - file_tool = float('%.*f' % (self.decimals, float(self.tools[tool]["C"]))) - - # I add the 0.0001 value to account for the rounding error in converting from IN to MM and reverse - # for the file_tool (tooldia actually) - buffer_value = float(file_tool / 2) - float(toolstable_tool / 2) + 0.0001 - if buffer_value == 0: - start = slot['start'] - stop = slot['stop'] - - lines_string = LineString([start, stop]) - poly = lines_string.buffer(0.0000001, int(self.geo_steps_per_circle)).exterior - geo_obj.solid_geometry.append(poly) - else: - start = slot['start'] - stop = slot['stop'] - - lines_string = LineString([start, stop]) - poly = lines_string.buffer(buffer_value, int(self.geo_steps_per_circle)).exterior - geo_obj.solid_geometry.append(poly) - - if use_thread: - def geo_thread(a_obj): - a_obj.app_obj.new_object("geometry", outname + '_slot', geo_init, plot=plot) - - # Create a promise with the new name - self.app.collection.promise(outname) - - # Send to worker - self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]}) - else: - self.app.app_obj.new_object("geometry", outname + '_slot', geo_init, plot=plot) - - return True, "" - def on_pp_changed(self): current_pp = self.t_ui.pp_excellon_name_cb.get_value() @@ -1533,7 +1283,8 @@ class ToolDrilling(AppTool, Excellon): self.t_ui.exclusion_table.selectAll() self.draw_sel_shape() - def process_slot_as_drills(self, slot, overlap, add_last_pt=False): + @staticmethod + def process_slot_as_drills(slot, overlap, add_last_pt=False): drills_list = [] start_pt = slot[0] @@ -1756,9 +1507,9 @@ class ToolDrilling(AppTool, Excellon): slot_no = 0 if 'slots' in self.excellon_tools[to_ol]: slot_no = len(self.excellon_tools[to_ol]['slots']) - for slot in self.excellon_tools[to_ol]['slots']: - start = (slot[0].x, slot[0].y) - stop = (slot[1].x, slot[1].y) + for eslot in self.excellon_tools[to_ol]['slots']: + start = (eslot[0].x, eslot[0].y) + stop = (eslot[1].x, eslot[1].y) sol_geo.append( LineString([start, stop]).buffer((it[1] / 2.0), resolution=job_obj.geo_steps_per_circle) @@ -1796,7 +1547,7 @@ class ToolDrilling(AppTool, Excellon): # ######################################################################################################### # ######################################################################################################### # Prepprocessor - job_obj.pp_excellon_name = self.default_data["excellon_ppname_e"] + job_obj.pp_excellon_name = self.default_data["tools_drill_ppname_e"] job_obj.pp_excellon = self.app.preprocessors[job_obj.pp_excellon_name] p = job_obj.pp_excellon diff --git a/app_Main.py b/app_Main.py index 66922dbe..4f6ee7e3 100644 --- a/app_Main.py +++ b/app_Main.py @@ -573,7 +573,7 @@ class App(QtCore.QObject): if name == 'hpgl': continue - self.ui.excellon_defaults_form.excellon_opt_group.pp_excellon_name_cb.addItem(name) + self.ui.tools_defaults_form.tools_drill_group.pp_excellon_name_cb.addItem(name) # add ToolTips for the Preprocessor ComboBoxes in Preferences for it in range(self.ui.tools_defaults_form.tools_solderpaste_group.pp_combo.count()): @@ -583,9 +583,9 @@ class App(QtCore.QObject): self.ui.geometry_defaults_form.geometry_opt_group.pp_geometry_name_cb.setItemData( it, self.ui.geometry_defaults_form.geometry_opt_group.pp_geometry_name_cb.itemText(it), QtCore.Qt.ToolTipRole) - for it in range(self.ui.excellon_defaults_form.excellon_opt_group.pp_excellon_name_cb.count()): - self.ui.excellon_defaults_form.excellon_opt_group.pp_excellon_name_cb.setItemData( - it, self.ui.excellon_defaults_form.excellon_opt_group.pp_excellon_name_cb.itemText(it), + for it in range(self.ui.tools_defaults_form.tools_drill_group.pp_excellon_name_cb.count()): + self.ui.tools_defaults_form.tools_drill_group.pp_excellon_name_cb.setItemData( + it, self.ui.tools_defaults_form.tools_drill_group.pp_excellon_name_cb.itemText(it), QtCore.Qt.ToolTipRole) # ########################################################################################################### diff --git a/defaults.py b/defaults.py index 83053262..f8868db7 100644 --- a/defaults.py +++ b/defaults.py @@ -251,31 +251,12 @@ class FlatCAMDefaults: # Excellon Options "excellon_operation": "drill", - "excellon_tool_order": 'no', "excellon_milling_type": "drills", "excellon_milling_dia": 0.8, - "excellon_cutz": -1.7, - "excellon_multidepth": False, - "excellon_depthperpass": 0.7, - "excellon_travelz": 2, - "excellon_endz": 0.5, - "excellon_endxy": None, - "excellon_feedrate_z": 300, - "excellon_spindlespeed": 0, - "excellon_dwell": False, - "excellon_dwelltime": 1, - "excellon_toolchange": False, - "excellon_toolchangez": 15, - "excellon_ppname_e": 'default', "excellon_tooldia": 0.8, "excellon_slot_tooldia": 1.8, - "excellon_gcode_type": "drills", - "excellon_area_exclusion": False, - "excellon_area_shape": "polygon", - "excellon_area_strategy": "over", - "excellon_area_overz": 1.0, # Excellon Advanced Options "excellon_offset": 0.0, @@ -287,9 +268,11 @@ class FlatCAMDefaults: "excellon_spindledir": 'CW', "excellon_f_plunge": False, "excellon_f_retract": False, - "excellon_drill_slots": False, - "excellon_drill_overlap": 0.0, - "excellon_last_drill": True, + + "excellon_area_exclusion": False, + "excellon_area_shape": "polygon", + "excellon_area_strategy": "over", + "excellon_area_overz": 1.0, # Excellon Export "excellon_exp_units": 'INCH', @@ -428,6 +411,27 @@ class FlatCAMDefaults: "tools_iso_area_shape": "square", "tools_iso_plotting": 'normal', + # Drilling Tool + "tools_drill_tool_order": 'no', + "tools_drill_cutz": -1.7, + "tools_drill_multidepth": False, + "tools_drill_depthperpass": 0.7, + "tools_drill_travelz": 2, + "tools_drill_endz": 0.5, + "tools_drill_endxy": None, + + "tools_drill_feedrate_z": 300, + "tools_drill_spindlespeed": 0, + "tools_drill_dwell": False, + "tools_drill_dwelltime": 1, + "tools_drill_toolchange": False, + "tools_drill_toolchangez": 15, + "tools_drill_ppname_e": 'default', + + "tools_drill_drill_slots": False, + "tools_drill_drill_overlap": 0.0, + "tools_drill_last_drill": True, + # NCC Tool "tools_ncctools": "1.0, 0.5", "tools_nccorder": 'rev',