diff --git a/FlatCAMApp.py b/FlatCAMApp.py index e58d3777..a8bc5e9a 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -2522,6 +2522,7 @@ class App(QtCore.QObject): self.pdf_tool = None self.image_tool = None self.pcb_wizard_tool = None + self.cal_exc_tool = None # always install tools only after the shell is initialized because the self.inform.emit() depends on shell self.install_tools() @@ -3054,6 +3055,10 @@ class App(QtCore.QObject): self.dblsidedtool = DblSidedTool(self) self.dblsidedtool.install(icon=QtGui.QIcon('share/doubleside16.png'), separator=True) + self.cal_exc_tool = ToolCalibrateExcellon(self) + self.cal_exc_tool.install(icon=QtGui.QIcon('share/drill16.png'), pos=self.ui.menutool, + before=self.dblsidedtool.menuAction, + separator=False) self.distance_tool = Distance(self) self.distance_tool.install(icon=QtGui.QIcon('share/distance16.png'), pos=self.ui.menuedit, before=self.ui.menueditorigin, diff --git a/README.md b/README.md index 85aeedf7..c82da55e 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ CAD program, and create G-Code for Isolation routing. - fixed a small bug in BETA status change - updated the About FlatCAM window - reverted change in tool dia being able to take only positive values in Gerber Object UI +- started to work to a new tool: Calibrate Excellon Tool 18.10.2019 diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py index bd90bf40..0e13913a 100644 --- a/flatcamGUI/FlatCAMGUI.py +++ b/flatcamGUI/FlatCAMGUI.py @@ -379,7 +379,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): # ######################################################################## # ########################## View # ###################################### # ######################################################################## - self.menuview = self.menu.addMenu(_('&View')) + self.menuview = self.menu.addMenu(_('View')) self.menuviewenable = self.menuview.addAction(QtGui.QIcon('share/replot16.png'), _('Enable all plots\tALT+1')) self.menuviewdisableall = self.menuview.addAction(QtGui.QIcon('share/clear_plot16.png'), _('Disable all plots\tALT+2')) @@ -430,7 +430,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): # ######################################################################## # ########################## Tool # ###################################### # ######################################################################## - self.menutool = QtWidgets.QMenu(_('&Tool')) + self.menutool = QtWidgets.QMenu(_('Tool')) self.menutoolaction = self.menu.addMenu(self.menutool) self.menutoolshell = self.menutool.addAction(QtGui.QIcon('share/shell16.png'), _('&Command Line\tS')) @@ -2469,9 +2469,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.app.dblsidedtool.run(toggle=True) return - # Transformation Tool + # Calibrate Excellon Tool if key == QtCore.Qt.Key_E: - self.app.transform_tool.run(toggle=True) + self.app.cal_exc_tool.run(toggle=True) return # Toggle Grid lines @@ -2519,9 +2519,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.app.on_view_source() return - # Cutout Tool - if key == QtCore.Qt.Key_U: - self.app.cutout_tool.run(toggle=True) + # Transformation Tool + if key == QtCore.Qt.Key_T: + self.app.transform_tool.run(toggle=True) return # Substract Tool @@ -2529,6 +2529,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.app.sub_tool.run(toggle=True) return + # Cutout Tool + if key == QtCore.Qt.Key_X: + self.app.cutout_tool.run(toggle=True) + return + # Panelize Tool if key == QtCore.Qt.Key_Z: self.app.panelize_tool.run(toggle=True) diff --git a/flatcamTools/ToolCalibrateExcellon.py b/flatcamTools/ToolCalibrateExcellon.py new file mode 100644 index 00000000..f0ea42a5 --- /dev/null +++ b/flatcamTools/ToolCalibrateExcellon.py @@ -0,0 +1,312 @@ +# ########################################################## +# FlatCAM: 2D Post-processing for Manufacturing # +# File Author: Marius Adrian Stanciu (c) # +# Date: 3/10/2019 # +# MIT Licence # +# ########################################################## + +from PyQt5 import QtWidgets, QtCore +from FlatCAMTool import FlatCAMTool +from flatcamGUI.GUIElements import FCDoubleSpinner, EvalEntry +import math +from shapely.geometry import Point +from shapely.geometry.base import * + +import gettext +import FlatCAMTranslation as fcTranslate +import builtins + +fcTranslate.apply_language('strings') +if '_' not in builtins.__dict__: + _ = gettext.gettext + + +class ToolCalibrateExcellon(FlatCAMTool): + + toolName = _("Calibrate Excellon") + + def __init__(self, app): + FlatCAMTool.__init__(self, app) + + self.app = app + self.canvas = self.app.plotcanvas + + self.decimals = 4 + + # ## Title + title_label = QtWidgets.QLabel("%s" % self.toolName) + title_label.setStyleSheet(""" + QLabel + { + font-size: 16px; + font-weight: bold; + } + """) + self.layout.addWidget(title_label) + + # ## Grid Layout + grid_lay = QtWidgets.QGridLayout() + self.layout.addLayout(grid_lay) + grid_lay.setColumnStretch(0, 0) + grid_lay.setColumnStretch(1, 1) + grid_lay.setColumnStretch(2, 1) + + self.exc_object_combo = QtWidgets.QComboBox() + self.exc_object_combo.setModel(self.app.collection) + self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex())) + self.exc_object_combo.setCurrentIndex(1) + + self.excobj_label = QtWidgets.QLabel("%s:" % _("EXCELLON")) + self.excobj_label.setToolTip( + _("Excellon Object to be mirrored.") + ) + + grid_lay.addWidget(self.excobj_label, 0, 0) + grid_lay.addWidget(self.exc_object_combo, 0, 1, 1, 2) + grid_lay.addWidget(QtWidgets.QLabel(''), 1, 0) + + self.points_table_label = QtWidgets.QLabel('%s' % _('Calibration Points')) + self.points_table_label.setToolTip( + _("Contain the expected calibration points and the\n" + "ones measured.") + ) + grid_lay.addWidget(self.points_table_label, 2, 0, 1, 2) + + # BOTTOM LEFT + self.bottom_left_lbl = QtWidgets.QLabel('%s' % _('Bottom Left')) + grid_lay.addWidget(self.bottom_left_lbl, 3, 0) + self.bottom_left_tgt_lbl = QtWidgets.QLabel('%s' % _('Target')) + grid_lay.addWidget(self.bottom_left_tgt_lbl, 3, 1) + self.bottom_left_found_lbl = QtWidgets.QLabel('%s' % _('Found')) + grid_lay.addWidget(self.bottom_left_found_lbl, 3, 2) + + self.bottom_left_coordx_lbl = QtWidgets.QLabel('%s' % _('X')) + grid_lay.addWidget(self.bottom_left_coordx_lbl, 4, 0) + self.bottom_left_coordx_tgt = EvalEntry() + self.bottom_left_coordx_tgt.setDisabled(True) + grid_lay.addWidget(self.bottom_left_coordx_tgt, 4, 1) + self.bottom_left_coordx_found = EvalEntry() + grid_lay.addWidget(self.bottom_left_coordx_found, 4, 2) + + self.bottom_left_coordy_lbl = QtWidgets.QLabel('%s' % _('Y')) + grid_lay.addWidget(self.bottom_left_coordy_lbl, 5, 0) + self.bottom_left_coordy_tgt = EvalEntry() + self.bottom_left_coordy_tgt.setDisabled(True) + grid_lay.addWidget(self.bottom_left_coordy_tgt, 5, 1) + self.bottom_left_coordy_found = EvalEntry() + grid_lay.addWidget(self.bottom_left_coordy_found, 5, 2) + + grid_lay.addWidget(QtWidgets.QLabel(''), 6, 0) + self.bottom_left_coordx_found.set_value(_('Set Origin')) + self.bottom_left_coordy_found.set_value(_('Set Origin')) + self.bottom_left_coordx_found.setDisabled(True) + self.bottom_left_coordy_found.setDisabled(True) + + # BOTTOM RIGHT + self.bottom_right_lbl = QtWidgets.QLabel('%s' % _('Bottom Right')) + grid_lay.addWidget(self.bottom_right_lbl, 7, 0) + self.bottom_right_tgt_lbl = QtWidgets.QLabel('%s' % _('Target')) + grid_lay.addWidget(self.bottom_right_tgt_lbl, 7, 1) + self.bottom_right_found_lbl = QtWidgets.QLabel('%s' % _('Found')) + grid_lay.addWidget(self.bottom_right_found_lbl, 7, 2) + + self.bottom_right_coordx_lbl = QtWidgets.QLabel('%s' % _('X')) + grid_lay.addWidget(self.bottom_right_coordx_lbl, 8, 0) + self.bottom_right_coordx_tgt = EvalEntry() + self.bottom_right_coordx_tgt.setDisabled(True) + grid_lay.addWidget(self.bottom_right_coordx_tgt, 8, 1) + self.bottom_right_coordx_found = EvalEntry() + grid_lay.addWidget(self.bottom_right_coordx_found, 8, 2) + + self.bottom_right_coordy_lbl = QtWidgets.QLabel('%s' % _('Y')) + grid_lay.addWidget(self.bottom_right_coordy_lbl, 9, 0) + self.bottom_right_coordy_tgt = EvalEntry() + self.bottom_right_coordy_tgt.setDisabled(True) + grid_lay.addWidget(self.bottom_right_coordy_tgt, 9, 1) + self.bottom_right_coordy_found = EvalEntry() + grid_lay.addWidget(self.bottom_right_coordy_found, 9, 2) + + grid_lay.addWidget(QtWidgets.QLabel(''), 10, 0) + + # TOP LEFT + self.top_left_lbl = QtWidgets.QLabel('%s' % _('Top Left')) + grid_lay.addWidget(self.top_left_lbl, 11, 0) + self.top_left_tgt_lbl = QtWidgets.QLabel('%s' % _('Target')) + grid_lay.addWidget(self.top_left_tgt_lbl, 11, 1) + self.top_left_found_lbl = QtWidgets.QLabel('%s' % _('Found')) + grid_lay.addWidget(self.top_left_found_lbl, 11, 2) + + self.top_left_coordx_lbl = QtWidgets.QLabel('%s' % _('X')) + grid_lay.addWidget(self.top_left_coordx_lbl, 12, 0) + self.top_left_coordx_tgt = EvalEntry() + self.top_left_coordx_tgt.setDisabled(True) + grid_lay.addWidget(self.top_left_coordx_tgt, 12, 1) + self.top_left_coordx_found = EvalEntry() + grid_lay.addWidget(self.top_left_coordx_found, 12, 2) + + self.top_left_coordy_lbl = QtWidgets.QLabel('%s' % _('Y')) + grid_lay.addWidget(self.top_left_coordy_lbl, 13, 0) + self.top_left_coordy_tgt = EvalEntry() + self.top_left_coordy_tgt.setDisabled(True) + grid_lay.addWidget(self.top_left_coordy_tgt, 13, 1) + self.top_left_coordy_found = EvalEntry() + grid_lay.addWidget(self.top_left_coordy_found, 13, 2) + + grid_lay.addWidget(QtWidgets.QLabel(''), 14, 0) + + # TOP RIGHT + self.top_right_lbl = QtWidgets.QLabel('%s' % _('Top Right')) + grid_lay.addWidget(self.top_right_lbl, 15, 0) + self.top_right_tgt_lbl = QtWidgets.QLabel('%s' % _('Target')) + grid_lay.addWidget(self.top_right_tgt_lbl, 15, 1) + self.top_right_found_lbl = QtWidgets.QLabel('%s' % _('Found')) + grid_lay.addWidget(self.top_right_found_lbl, 15, 2) + + self.top_right_coordx_lbl = QtWidgets.QLabel('%s' % _('X')) + grid_lay.addWidget(self.top_right_coordx_lbl, 16, 0) + self.top_right_coordx_tgt = EvalEntry() + self.top_right_coordx_tgt.setDisabled(True) + grid_lay.addWidget(self.top_right_coordx_tgt, 16, 1) + self.top_right_coordx_found = EvalEntry() + grid_lay.addWidget(self.top_right_coordx_found, 16, 2) + + self.top_right_coordy_lbl = QtWidgets.QLabel('%s' % _('Y')) + grid_lay.addWidget(self.top_right_coordy_lbl, 17, 0) + self.top_right_coordy_tgt = EvalEntry() + self.top_right_coordy_tgt.setDisabled(True) + grid_lay.addWidget(self.top_right_coordy_tgt, 17, 1) + self.top_right_coordy_found = EvalEntry() + grid_lay.addWidget(self.top_right_coordy_found, 17, 2) + + grid_lay.addWidget(QtWidgets.QLabel(''), 18, 0) + + # ## Buttons + self.start_button = QtWidgets.QPushButton(_("Start")) + self.start_button.setToolTip( + _("Start to collect four drill center coordinates,\n " + "to be used as references. ") + ) + + self.layout.addWidget(self.start_button) + + self.layout.addStretch() + + self.mr = None + self.units = '' + + # here store 4 points to be used for calibration + self.click_points = list() + + self.exc_obj = None + + # ## Signals + self.start_button.clicked.connect(self.on_start_collect_points) + + def run(self, toggle=True): + self.app.report_usage("ToolCalibrateExcellon()") + + if toggle: + # if the splitter is hidden, display it, else hide it but only if the current widget is the same + if self.app.ui.splitter.sizes()[0] == 0: + self.app.ui.splitter.setSizes([1, 1]) + else: + try: + if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName: + # if tab is populated with the tool but it does not have the focus, focus on it + if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab: + # focus on Tool Tab + self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab) + else: + self.app.ui.splitter.setSizes([0, 1]) + except AttributeError: + pass + else: + if self.app.ui.splitter.sizes()[0] == 0: + self.app.ui.splitter.setSizes([1, 1]) + + FlatCAMTool.run(self) + + self.set_tool_ui() + + self.app.ui.notebook.setTabText(2, _("Cal Exc Tool")) + + def install(self, icon=None, separator=None, **kwargs): + FlatCAMTool.install(self, icon, separator, shortcut='ALT+E', **kwargs) + + def set_tool_ui(self): + self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper() + + # ## Initialize form + # self.mm_entry.set_value('%.*f' % (self.decimals, 0)) + + def on_start_collect_points(self): + self.mr = self.canvas.graph_event_connect('mouse_release', self.on_mouse_click_release) + + if self.app.is_legacy is False: + self.canvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot) + else: + self.canvas.graph_event_disconnect(self.app.mr) + + selection_index = self.exc_object_combo.currentIndex() + model_index = self.app.collection.index(selection_index, 0, self.exc_object_combo.rootModelIndex()) + try: + self.exc_obj = model_index.internalPointer().obj + except Exception as e: + self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ...")) + return + + self.app.inform.emit(_("Click inside the First drill point. Bottom Left...")) + + def on_mouse_click_release(self, event): + if event.button == 1: + if self.app.is_legacy is False: + event_pos = event.pos + else: + event_pos = (event.xdata, event.ydata) + + pos_canvas = self.canvas.translate_coords(event_pos) + click_pt = Point([pos_canvas[0], pos_canvas[1]]) + + for tool, tool_dict in self.exc_obj.tools.items(): + for geo in tool_dict['solid_geometry']: + if click_pt.within(geo): + center_pt = geo.centroid + self.click_points.append( + ( + float('%.*f' % (self.decimals, center_pt.x)), + float('%.*f' % (self.decimals, center_pt.y)) + ) + ) + self.check_points() + + def check_points(self): + if len(self.click_points) == 1: + self.bottom_left_coordx_tgt.set_value(self.click_points[0][0]) + self.bottom_left_coordy_tgt.set_value(self.click_points[0][1]) + self.app.inform.emit(_("Click inside the Second drill point. Bottom Right...")) + elif len(self.click_points) == 2: + self.bottom_right_coordx_tgt.set_value(self.click_points[1][0]) + self.bottom_right_coordy_tgt.set_value(self.click_points[1][1]) + self.app.inform.emit(_("Click inside the Third drill point. Top Left...")) + elif len(self.click_points) == 3: + self.top_left_coordx_tgt.set_value(self.click_points[2][0]) + self.top_left_coordy_tgt.set_value(self.click_points[2][1]) + self.app.inform.emit(_("Click inside the Fourth drill point. Top Right...")) + elif len(self.click_points) == 4: + self.top_right_coordx_tgt.set_value(self.click_points[3][0]) + self.top_right_coordy_tgt.set_value(self.click_points[3][1]) + self.app.inform.emit('[success] %s' % _("Done. All four points have been acquired.")) + self.disconnect_cal_events() + + def disconnect_cal_events(self): + self.app.mr = self.canvas.graph_event_connect('mouse_release', self.app.on_mouse_click_release_over_plot) + + if self.app.is_legacy is False: + self.canvas.graph_event_disconnect('mouse_release', self.on_mouse_click_release) + else: + self.canvas.graph_event_disconnect(self.mr) + + def reset_fields(self): + self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex())) + +# end of file diff --git a/flatcamTools/ToolCutOut.py b/flatcamTools/ToolCutOut.py index cddd7b70..b60e67bf 100644 --- a/flatcamTools/ToolCutOut.py +++ b/flatcamTools/ToolCutOut.py @@ -373,7 +373,7 @@ class CutOut(FlatCAMTool): self.app.ui.notebook.setTabText(2, _("Cutout Tool")) def install(self, icon=None, separator=None, **kwargs): - FlatCAMTool.install(self, icon, separator, shortcut='ALT+U', **kwargs) + FlatCAMTool.install(self, icon, separator, shortcut='ALT+X', **kwargs) def set_tool_ui(self): self.reset_fields() diff --git a/flatcamTools/ToolTransform.py b/flatcamTools/ToolTransform.py index 9a7247a9..d56904ba 100644 --- a/flatcamTools/ToolTransform.py +++ b/flatcamTools/ToolTransform.py @@ -371,7 +371,7 @@ class ToolTransform(FlatCAMTool): self.app.ui.notebook.setTabText(2, _("Transform Tool")) def install(self, icon=None, separator=None, **kwargs): - FlatCAMTool.install(self, icon, separator, shortcut='ALT+E', **kwargs) + FlatCAMTool.install(self, icon, separator, shortcut='ALT+T', **kwargs) def set_tool_ui(self): # ## Initialize form diff --git a/flatcamTools/__init__.py b/flatcamTools/__init__.py index f12e59a2..f4b48149 100644 --- a/flatcamTools/__init__.py +++ b/flatcamTools/__init__.py @@ -2,6 +2,7 @@ import sys from flatcamTools.ToolCalculators import ToolCalculator +from flatcamTools.ToolCalibrateExcellon import ToolCalibrateExcellon from flatcamTools.ToolCutOut import CutOut from flatcamTools.ToolDblSided import DblSidedTool