From d1733f1e1d58892c8efe8fde65143f28a515ecf4 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Tue, 18 Aug 2020 15:30:33 +0300 Subject: [PATCH] - in Doublesided Tool added some UI for Excellon hole snapping --- CHANGELOG.md | 4 + .../tools/Tools2sidedPrefGroupUI.py | 18 ++- appObjects/FlatCAMCNCJob.py | 7 +- appTools/ToolDblSided.py | 125 +++++++++++++----- 4 files changed, 110 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a2467c9..77778e02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ CHANGELOG for FlatCAM beta ================================================= +18.08.2020 + +- in Doublesided Tool added some UI for Excellon hole snapping + 17.08.2020 - in CNCJob UI Autolevelling - GRBL GUI controls are now organized in a tab widget diff --git a/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py b/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py index a0ca21bb..e45602ef 100644 --- a/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py +++ b/appGUI/preferences/tools/Tools2sidedPrefGroupUI.py @@ -80,13 +80,21 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.mirror_axis_radio, 3, 1) # ## Axis Location - self.axis_location_radio = RadioSet([{'label': _('Point'), 'value': 'point'}, - {'label': _('Box'), 'value': 'box'}]) + self.axis_location_radio = RadioSet( + [ + {'label': _('Point'), 'value': 'point'}, + {'label': _('Box'), 'value': 'box'}, + {'label': _('Hole Snap'), 'value': 'hole'}, + ] + ) self.axloc_label = QtWidgets.QLabel('%s:' % _("Axis Ref")) self.axloc_label.setToolTip( - _("The axis should pass through a point or cut\n " - "a specified box (in a FlatCAM object) through \n" - "the center.") + _("The coordinates used as reference for the mirror operation.\n" + "Can be:\n" + "- Point -> a set of coordinates (x,y) around which the object is mirrored\n" + "- Box -> a set of coordinates (x, y) obtained from the center of the\n" + "bounding box of another object selected below\n" + "- Hole Snap-> a point defined by the center of a drill hone in a Excellon object") ) grid0.addWidget(self.axloc_label, 4, 0) diff --git a/appObjects/FlatCAMCNCJob.py b/appObjects/FlatCAMCNCJob.py index 29ddcfea..341c7436 100644 --- a/appObjects/FlatCAMCNCJob.py +++ b/appObjects/FlatCAMCNCJob.py @@ -691,12 +691,13 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.mouse_events_connected = True - # self.calculate_voronoi_diagram() + self.calculate_voronoi_diagram() self.build_al_table_sig.emit() - # def calculate_voronoi_diagram(self): - # return voronoi_diagram() + def calculate_voronoi_diagram(self): + pass + # return voronoi_diagram() # To be called after clicking on the plot. def on_mouse_click_release(self, event): diff --git a/appTools/ToolDblSided.py b/appTools/ToolDblSided.py index 1e68cefa..8f1fe0f4 100644 --- a/appTools/ToolDblSided.py +++ b/appTools/ToolDblSided.py @@ -2,7 +2,7 @@ from PyQt5 import QtWidgets, QtCore, QtGui from appTool import AppTool -from appGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry, FCButton, FCComboBox +from appGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry, FCButton, FCComboBox, FCCheckBox from numpy import Inf @@ -335,15 +335,20 @@ class DblSidedTool(AppTool): self.ui.alignment_holes.set_value(self.drill_values) def on_toggle_pointbox(self): - if self.ui.axis_location.get_value() == "point": + val = self.ui.axis_location.get_value() + if val == "point": self.ui.point_entry.show() self.ui.add_point_button.show() self.ui.box_type_label.hide() self.ui.box_type_radio.hide() self.ui.box_combo.hide() + self.ui.exc_hole_lbl.hide() + self.ui.exc_combo.hide() + self.ui.pick_hole_button.hide() + self.ui.align_ref_label_val.set_value(self.ui.point_entry.get_value()) - else: + elif val == 'box': self.ui.point_entry.hide() self.ui.add_point_button.hide() @@ -351,7 +356,22 @@ class DblSidedTool(AppTool): self.ui.box_type_radio.show() self.ui.box_combo.show() + self.ui.exc_hole_lbl.hide() + self.ui.exc_combo.hide() + self.ui.pick_hole_button.hide() + self.ui.align_ref_label_val.set_value("Box centroid") + elif val == 'hole': + self.ui.point_entry.show() + self.ui.add_point_button.hide() + + self.ui.box_type_label.hide() + self.ui.box_type_radio.hide() + self.ui.box_combo.hide() + + self.ui.exc_hole_lbl.show() + self.ui.exc_combo.show() + self.ui.pick_hole_button.show() def on_bbox_coordinates(self): @@ -605,10 +625,16 @@ class DsidedUI: "Can be:\n" "- Point -> a set of coordinates (x,y) around which the object is mirrored\n" "- Box -> a set of coordinates (x, y) obtained from the center of the\n" - "bounding box of another object selected below") + "bounding box of another object selected below\n" + "- Hole Snap -> a point defined by the center of a drill hone in a Excellon object") + ) + self.axis_location = RadioSet( + [ + {'label': _('Point'), 'value': 'point'}, + {'label': _('Box'), 'value': 'box'}, + {'label': _('Hole Snap'), 'value': 'hole'}, + ] ) - self.axis_location = RadioSet([{'label': _('Point'), 'value': 'point'}, - {'label': _('Box'), 'value': 'box'}]) grid_lay1.addWidget(self.axloc_label, 4, 0) grid_lay1.addWidget(self.axis_location, 4, 1, 1, 2) @@ -636,11 +662,38 @@ class DsidedUI: grid_lay1.addWidget(self.point_entry, 7, 0, 1, 2) grid_lay1.addWidget(self.add_point_button, 7, 2) + self.exc_hole_lbl = QtWidgets.QLabel('%s:' % _("Excellon")) + self.exc_hole_lbl.setToolTip( + _("Object that holds holes that can be picked as reference for mirroing.") + ) + + # Excellon Object that holds the holes + self.exc_combo = FCComboBox() + self.exc_combo.setModel(self.app.collection) + self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex())) + self.exc_combo.is_last = True + + self.exc_hole_lbl.hide() + self.exc_combo.hide() + + grid_lay1.addWidget(self.exc_hole_lbl, 10, 0) + grid_lay1.addWidget(self.exc_combo, 10, 1, 1, 2) + + self.pick_hole_button = FCButton(_("Pick hole")) + self.pick_hole_button.setToolTip( + _("Click inside a drill hole that belong to the selected Excellon object,\n" + "and the hole center coordinates will be copied to the Point field.") + ) + + self.pick_hole_button.hide() + + grid_lay1.addWidget(self.pick_hole_button, 12, 0, 1, 3) + # ## Grid Layout - grid_lay2 = QtWidgets.QGridLayout() - grid_lay2.setColumnStretch(0, 0) - grid_lay2.setColumnStretch(1, 1) - self.layout.addLayout(grid_lay2) + grid_lay3 = QtWidgets.QGridLayout() + grid_lay3.setColumnStretch(0, 0) + grid_lay3.setColumnStretch(1, 1) + self.layout.addLayout(grid_lay3) self.box_type_label = QtWidgets.QLabel('%s:' % _("Reference Object")) self.box_type_label.setToolTip( @@ -657,8 +710,8 @@ class DsidedUI: self.box_type_label.hide() self.box_type_radio.hide() - grid_lay2.addWidget(self.box_type_label, 0, 0, 1, 2) - grid_lay2.addWidget(self.box_type_radio, 1, 0, 1, 2) + grid_lay3.addWidget(self.box_type_label, 0, 0, 1, 2) + grid_lay3.addWidget(self.box_type_radio, 1, 0, 1, 2) # Object used as BOX reference self.box_combo = FCComboBox() @@ -668,14 +721,14 @@ class DsidedUI: self.box_combo.hide() - grid_lay2.addWidget(self.box_combo, 3, 0, 1, 2) + grid_lay3.addWidget(self.box_combo, 3, 0, 1, 2) separator_line = QtWidgets.QFrame() separator_line.setFrameShape(QtWidgets.QFrame.HLine) separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) - grid_lay2.addWidget(separator_line, 4, 0, 1, 2) + grid_lay3.addWidget(separator_line, 4, 0, 1, 2) - grid_lay2.addWidget(QtWidgets.QLabel(""), 5, 0, 1, 2) + grid_lay3.addWidget(QtWidgets.QLabel(""), 5, 0, 1, 2) # ## Title Bounds Values self.bv_label = QtWidgets.QLabel("%s:" % _('Bounds Values')) @@ -683,7 +736,7 @@ class DsidedUI: _("Select on canvas the object(s)\n" "for which to calculate bounds values.") ) - grid_lay2.addWidget(self.bv_label, 6, 0, 1, 2) + grid_lay3.addWidget(self.bv_label, 6, 0, 1, 2) # Xmin value self.xmin_entry = FCDoubleSpinner(callback=self.confirmation_message) @@ -696,8 +749,8 @@ class DsidedUI: ) self.xmin_entry.setReadOnly(True) - grid_lay2.addWidget(self.xmin_btn, 7, 0) - grid_lay2.addWidget(self.xmin_entry, 7, 1) + grid_lay3.addWidget(self.xmin_btn, 7, 0) + grid_lay3.addWidget(self.xmin_entry, 7, 1) # Ymin value self.ymin_entry = FCDoubleSpinner(callback=self.confirmation_message) @@ -710,8 +763,8 @@ class DsidedUI: ) self.ymin_entry.setReadOnly(True) - grid_lay2.addWidget(self.ymin_btn, 8, 0) - grid_lay2.addWidget(self.ymin_entry, 8, 1) + grid_lay3.addWidget(self.ymin_btn, 8, 0) + grid_lay3.addWidget(self.ymin_entry, 8, 1) # Xmax value self.xmax_entry = FCDoubleSpinner(callback=self.confirmation_message) @@ -724,8 +777,8 @@ class DsidedUI: ) self.xmax_entry.setReadOnly(True) - grid_lay2.addWidget(self.xmax_btn, 9, 0) - grid_lay2.addWidget(self.xmax_entry, 9, 1) + grid_lay3.addWidget(self.xmax_btn, 9, 0) + grid_lay3.addWidget(self.xmax_entry, 9, 1) # Ymax value self.ymax_entry = FCDoubleSpinner(callback=self.confirmation_message) @@ -738,8 +791,8 @@ class DsidedUI: ) self.ymax_entry.setReadOnly(True) - grid_lay2.addWidget(self.ymax_btn, 10, 0) - grid_lay2.addWidget(self.ymax_entry, 10, 1) + grid_lay3.addWidget(self.ymax_btn, 10, 0) + grid_lay3.addWidget(self.ymax_entry, 10, 1) # Center point value self.center_entry = FCEntry() @@ -752,8 +805,8 @@ class DsidedUI: ) self.center_entry.setReadOnly(True) - grid_lay2.addWidget(self.center_btn, 12, 0) - grid_lay2.addWidget(self.center_entry, 12, 1) + grid_lay3.addWidget(self.center_btn, 12, 0) + grid_lay3.addWidget(self.center_entry, 12, 1) # Calculate Bounding box self.calculate_bb_button = QtWidgets.QPushButton(_("Calculate Bounds Values")) @@ -768,14 +821,14 @@ class DsidedUI: font-weight: bold; } """) - grid_lay2.addWidget(self.calculate_bb_button, 13, 0, 1, 2) + grid_lay3.addWidget(self.calculate_bb_button, 13, 0, 1, 2) separator_line = QtWidgets.QFrame() separator_line.setFrameShape(QtWidgets.QFrame.HLine) separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) - grid_lay2.addWidget(separator_line, 14, 0, 1, 2) + grid_lay3.addWidget(separator_line, 14, 0, 1, 2) - grid_lay2.addWidget(QtWidgets.QLabel(""), 15, 0, 1, 2) + grid_lay3.addWidget(QtWidgets.QLabel(""), 15, 0, 1, 2) # ## Alignment holes self.alignment_label = QtWidgets.QLabel("%s:" % _('PCB Alignment')) @@ -784,7 +837,7 @@ class DsidedUI: "specified alignment holes and their mirror\n" "images.") ) - grid_lay2.addWidget(self.alignment_label, 25, 0, 1, 2) + grid_lay3.addWidget(self.alignment_label, 25, 0, 1, 2) # ## Drill diameter for alignment holes self.dt_label = QtWidgets.QLabel("%s:" % _('Drill Diameter')) @@ -799,8 +852,8 @@ class DsidedUI: self.drill_dia.set_precision(self.decimals) self.drill_dia.set_range(0.0000, 9999.9999) - grid_lay2.addWidget(self.dt_label, 26, 0) - grid_lay2.addWidget(self.drill_dia, 26, 1) + grid_lay3.addWidget(self.dt_label, 26, 0) + grid_lay3.addWidget(self.drill_dia, 26, 1) # ## Alignment Axis self.align_ax_label = QtWidgets.QLabel('%s:' % _("Align Axis")) @@ -810,8 +863,8 @@ class DsidedUI: self.align_axis_radio = RadioSet([{'label': 'X', 'value': 'X'}, {'label': 'Y', 'value': 'Y'}]) - grid_lay2.addWidget(self.align_ax_label, 27, 0) - grid_lay2.addWidget(self.align_axis_radio, 27, 1) + grid_lay3.addWidget(self.align_ax_label, 27, 0) + grid_lay3.addWidget(self.align_axis_radio, 27, 1) # ## Alignment Reference Point self.align_ref_label = QtWidgets.QLabel('%s:' % _("Reference")) @@ -829,8 +882,8 @@ class DsidedUI: ) self.align_ref_label_val.setDisabled(True) - grid_lay2.addWidget(self.align_ref_label, 28, 0) - grid_lay2.addWidget(self.align_ref_label_val, 28, 1) + grid_lay3.addWidget(self.align_ref_label, 28, 0) + grid_lay3.addWidget(self.align_ref_label_val, 28, 1) grid_lay4 = QtWidgets.QGridLayout() self.layout.addLayout(grid_lay4)