From 7424bb917ca2f42f0b2d6c0b7b50bd34ccbbb332 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Thu, 6 Feb 2020 01:39:19 +0200 Subject: [PATCH] - Modified the Distance Tool such that the Measure button can't be clicked while measuring is in progress - optimized selection of drills in the Excellon Editor - fixed bugs in multiple selection in Excellon Editor - fixed selection problems in Gerber Editor - in Distance Tool, when run in the Excellon or Gerber Editor, added a new option to snap to center of the geometry (drill for Excellon, pad for Gerber) --- FlatCAMApp.py | 3 + README.md | 8 + flatcamEditors/FlatCAMExcEditor.py | 62 +++--- flatcamEditors/FlatCAMGrbEditor.py | 53 ++--- flatcamTools/ToolDistance.py | 300 +++++++++++++++++++++-------- 5 files changed, 298 insertions(+), 128 deletions(-) diff --git a/FlatCAMApp.py b/FlatCAMApp.py index b6a695ae..3f0d9086 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -890,6 +890,9 @@ class App(QtCore.QObject): # Subtract Tool "tools_sub_close_paths": True, + # Distance Tool + "tools_dist_snap_center": False, + # ################################################################################### # ################################ TOOLS 2 ########################################## # ################################################################################### diff --git a/README.md b/README.md index e50d47be..2728cc8b 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,14 @@ CAD program, and create G-Code for Isolation routing. ================================================= +5.02.2020 + +- Modified the Distance Tool such that the Measure button can't be clicked while measuring is in progress +- optimized selection of drills in the Excellon Editor +- fixed bugs in multiple selection in Excellon Editor +- fixed selection problems in Gerber Editor +- in Distance Tool, when run in the Excellon or Gerber Editor, added a new option to snap to center of the geometry (drill for Excellon, pad for Gerber) + 3.02.2020 - modified Spinbox and DoubleSpinbox Custom UI elements such that they issue a warning status message when the typed value is out of range diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py index e2dc8bdb..a4136d3c 100644 --- a/flatcamEditors/FlatCAMExcEditor.py +++ b/flatcamEditors/FlatCAMExcEditor.py @@ -1334,8 +1334,8 @@ class FCDrillCopy(FCDrillMove): class FCDrillSelect(DrawTool): - def __init__(self, exc_editor_app): - DrawTool.__init__(self, exc_editor_app) + def __init__(self, draw_app): + DrawTool.__init__(self, draw_app) self.name = 'drill_select' try: @@ -1343,7 +1343,7 @@ class FCDrillSelect(DrawTool): except Exception as e: pass - self.exc_editor_app = exc_editor_app + self.exc_editor_app = draw_app self.storage = self.exc_editor_app.storage_dict # self.selected = self.exc_editor_app.selected @@ -1368,10 +1368,10 @@ class FCDrillSelect(DrawTool): else: mod_key = None - if mod_key == self.draw_app.app.defaults["global_mselect_key"]: + if mod_key == self.exc_editor_app.app.defaults["global_mselect_key"]: pass else: - self.exc_editor_app.selected = [] + self.exc_editor_app.selected = list() def click_release(self, pos): self.exc_editor_app.tools_table_exc.clearSelection() @@ -1379,8 +1379,10 @@ class FCDrillSelect(DrawTool): try: for storage in self.exc_editor_app.storage_dict: - for sh in self.exc_editor_app.storage_dict[storage].get_objects(): - self.sel_storage.insert(sh) + # for sh in self.exc_editor_app.storage_dict[storage].get_objects(): + # self.sel_storage.insert(sh) + _, st_closest_shape = self.exc_editor_app.storage_dict[storage].nearest(pos) + self.sel_storage.insert(st_closest_shape) _, closest_shape = self.sel_storage.nearest(pos) @@ -1417,37 +1419,41 @@ class FCDrillSelect(DrawTool): else: mod_key = None - if mod_key == self.draw_app.app.defaults["global_mselect_key"]: + if mod_key == self.exc_editor_app.app.defaults["global_mselect_key"]: if closest_shape in self.exc_editor_app.selected: self.exc_editor_app.selected.remove(closest_shape) else: self.exc_editor_app.selected.append(closest_shape) else: - self.draw_app.selected = [] - self.draw_app.selected.append(closest_shape) + self.exc_editor_app.selected = list() + self.exc_editor_app.selected.append(closest_shape) # select the diameter of the selected shape in the tool table try: - self.draw_app.tools_table_exc.cellPressed.disconnect() + self.exc_editor_app.tools_table_exc.cellPressed.disconnect() except (TypeError, AttributeError): pass - self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) + # if mod_key == self.exc_editor_app.app.defaults["global_mselect_key"]: + # self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) + self.sel_tools.clear() + for shape_s in self.exc_editor_app.selected: for storage in self.exc_editor_app.storage_dict: if shape_s in self.exc_editor_app.storage_dict[storage].get_objects(): self.sel_tools.add(storage) + self.exc_editor_app.tools_table_exc.clearSelection() for storage in self.sel_tools: - for k, v in self.draw_app.tool2tooldia.items(): + for k, v in self.exc_editor_app.tool2tooldia.items(): if v == storage: self.exc_editor_app.tools_table_exc.selectRow(int(k) - 1) - self.draw_app.last_tool_selected = int(k) + self.exc_editor_app.last_tool_selected = int(k) break - self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + # self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) - self.draw_app.tools_table_exc.cellPressed.connect(self.draw_app.on_row_selected) + self.exc_editor_app.tools_table_exc.cellPressed.connect(self.exc_editor_app.on_row_selected) # delete whatever is in selection storage, there is no longer need for those shapes self.sel_storage = FlatCAMExcEditor.make_storage() @@ -2054,32 +2060,32 @@ class FlatCAMExcEditor(QtCore.QObject): self.in_action = False - self.storage_dict = {} + self.storage_dict = dict() - self.current_storage = [] + self.current_storage = list() # build the data from the Excellon point into a dictionary # {tool_dia: [geometry_in_points]} - self.points_edit = {} - self.slot_points_edit = {} + self.points_edit = dict() + self.slot_points_edit = dict() - self.sorted_diameters = [] + self.sorted_diameters = list() - self.new_drills = [] - self.new_tools = {} - self.new_slots = [] - self.new_tool_offset = {} + self.new_drills = list() + self.new_tools = dict() + self.new_slots = list() + self.new_tool_offset = dict() # dictionary to store the tool_row and diameters in Tool_table # it will be updated everytime self.build_ui() is called - self.olddia_newdia = {} + self.olddia_newdia = dict() - self.tool2tooldia = {} + self.tool2tooldia = dict() # this will store the value for the last selected tool, for use after clicking on canvas when the selection # is cleared but as a side effect also the selected tool is cleared self.last_tool_selected = None - self.utility = [] + self.utility = list() # this will flag if the Editor "tools" are launched from key shortcuts (True) or from menu toolbar (False) self.launched_from_shortcuts = False diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py index 2bd6a8bb..e1006725 100644 --- a/flatcamEditors/FlatCAMGrbEditor.py +++ b/flatcamEditors/FlatCAMGrbEditor.py @@ -2300,10 +2300,10 @@ class FCApertureSelect(DrawTool): # since FCApertureSelect tool is activated whenever a tool is exited I place here the reinitialization of the # bending modes using in FCRegion and FCTrack - self.draw_app.bend_mode = 1 + self.grb_editor_app.bend_mode = 1 # here store the selected apertures - self.sel_aperture = set() + self.sel_aperture = list() try: self.grb_editor_app.apertures_table.clearSelection() @@ -2332,7 +2332,7 @@ class FCApertureSelect(DrawTool): else: mod_key = None - if mod_key == self.draw_app.app.defaults["global_mselect_key"]: + if mod_key == self.grb_editor_app.app.defaults["global_mselect_key"]: pass else: self.grb_editor_app.selected = [] @@ -2348,46 +2348,53 @@ class FCApertureSelect(DrawTool): else: mod_key = None + if mod_key != self.grb_editor_app.app.defaults["global_mselect_key"]: + self.grb_editor_app.selected.clear() + self.sel_aperture.clear() + for storage in self.grb_editor_app.storage_dict: try: - for geo_el in self.grb_editor_app.storage_dict[storage]['geometry']: - if 'solid' in geo_el.geo: - geometric_data = geo_el.geo['solid'] + for shape_stored in self.grb_editor_app.storage_dict[storage]['geometry']: + if 'solid' in shape_stored.geo: + geometric_data = shape_stored.geo['solid'] if Point(point).within(geometric_data): - if mod_key == self.grb_editor_app.app.defaults["global_mselect_key"]: - if geo_el in self.draw_app.selected: - self.draw_app.selected.remove(geo_el) - self.sel_aperture.remove(storage) - else: - # add the object to the selected shapes - self.draw_app.selected.append(geo_el) - self.sel_aperture.add(storage) + if shape_stored in self.grb_editor_app.selected: + self.grb_editor_app.selected.remove(shape_stored) else: - self.draw_app.selected.append(geo_el) - self.sel_aperture.add(storage) + # add the object to the selected shapes + self.grb_editor_app.selected.append(shape_stored) except KeyError: pass # select the aperture in the Apertures Table that is associated with the selected shape + self.sel_aperture.clear() + + self.grb_editor_app.apertures_table.clearSelection() try: - self.draw_app.apertures_table.cellPressed.disconnect() + self.grb_editor_app.apertures_table.cellPressed.disconnect() except Exception as e: log.debug("FlatCAMGrbEditor.FCApertureSelect.click_release() --> %s" % str(e)) - self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) + for shape_s in self.grb_editor_app.selected: + for storage in self.grb_editor_app.storage_dict: + if shape_s in self.grb_editor_app.storage_dict[storage]['geometry']: + self.sel_aperture.append(storage) + + # self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) for aper in self.sel_aperture: for row in range(self.grb_editor_app.apertures_table.rowCount()): if str(aper) == self.grb_editor_app.apertures_table.item(row, 1).text(): - self.grb_editor_app.apertures_table.selectRow(row) - self.draw_app.last_aperture_selected = aper - self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + if not self.grb_editor_app.apertures_table.item(row, 0).isSelected(): + self.grb_editor_app.apertures_table.selectRow(row) + self.grb_editor_app.last_aperture_selected = aper + # self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) - self.draw_app.apertures_table.cellPressed.connect(self.draw_app.on_row_selected) + self.grb_editor_app.apertures_table.cellPressed.connect(self.grb_editor_app.on_row_selected) return "" def clean_up(self): - self.draw_app.plot_all() + self.grb_editor_app.plot_all() class FCTransform(FCShapeTool): diff --git a/flatcamTools/ToolDistance.py b/flatcamTools/ToolDistance.py index 1a5bc568..84a6c547 100644 --- a/flatcamTools/ToolDistance.py +++ b/flatcamTools/ToolDistance.py @@ -9,13 +9,18 @@ from PyQt5 import QtWidgets, QtCore from FlatCAMTool import FlatCAMTool from flatcamGUI.VisPyVisuals import * -from flatcamGUI.GUIElements import FCEntry +from flatcamGUI.GUIElements import FCEntry, FCButton, FCCheckBox + +from shapely.geometry import Point, MultiLineString, Polygon + +import FlatCAMTranslation as fcTranslate +from camlib import FlatCAMRTreeStorage +from flatcamEditors.FlatCAMGeoEditor import DrawToolShape from copy import copy import math import logging import gettext -import FlatCAMTranslation as fcTranslate import builtins fcTranslate.apply_language('strings') @@ -43,82 +48,101 @@ class Distance(FlatCAMTool): self.layout.addWidget(title_label) # ## Form Layout - form_layout = QtWidgets.QFormLayout() - self.layout.addLayout(form_layout) + grid0 = QtWidgets.QGridLayout() + grid0.setColumnStretch(0, 0) + grid0.setColumnStretch(1, 1) + self.layout.addLayout(grid0) self.units_label = QtWidgets.QLabel('%s:' % _("Units")) self.units_label.setToolTip(_("Those are the units in which the distance is measured.")) self.units_value = QtWidgets.QLabel("%s" % str({'mm': _("METRIC (mm)"), 'in': _("INCH (in)")}[self.units])) self.units_value.setDisabled(True) + grid0.addWidget(self.units_label, 0, 0) + grid0.addWidget(self.units_value, 0, 1) + + self.snap_center_cb = FCCheckBox(_("Snap to center")) + self.snap_center_cb.setToolTip( + _("Mouse cursor will snap to the center of the pad/drill\n" + "when it is hovering over the geometry of the pad/drill.") + ) + grid0.addWidget(self.snap_center_cb, 1, 0, 1, 2) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 2, 0, 1, 2) + self.start_label = QtWidgets.QLabel("%s:" % _('Start Coords')) self.start_label.setToolTip(_("This is measuring Start point coordinates.")) - self.stop_label = QtWidgets.QLabel("%s:" % _('Stop Coords')) - self.stop_label.setToolTip(_("This is the measuring Stop point coordinates.")) - - self.distance_x_label = QtWidgets.QLabel('%s:' % _("Dx")) - self.distance_x_label.setToolTip(_("This is the distance measured over the X axis.")) - - self.distance_y_label = QtWidgets.QLabel('%s:' % _("Dy")) - self.distance_y_label.setToolTip(_("This is the distance measured over the Y axis.")) - - self.angle_label = QtWidgets.QLabel('%s:' % _("Angle")) - self.angle_label.setToolTip(_("This is orientation angle of the measuring line.")) - - self.total_distance_label = QtWidgets.QLabel("%s:" % _('DISTANCE')) - self.total_distance_label.setToolTip(_("This is the point to point Euclidian distance.")) - self.start_entry = FCEntry() self.start_entry.setReadOnly(True) self.start_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self.start_entry.setToolTip(_("This is measuring Start point coordinates.")) + grid0.addWidget(self.start_label, 3, 0) + grid0.addWidget(self.start_entry, 3, 1) + + self.stop_label = QtWidgets.QLabel("%s:" % _('Stop Coords')) + self.stop_label.setToolTip(_("This is the measuring Stop point coordinates.")) + self.stop_entry = FCEntry() self.stop_entry.setReadOnly(True) self.stop_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self.stop_entry.setToolTip(_("This is the measuring Stop point coordinates.")) + grid0.addWidget(self.stop_label, 4, 0) + grid0.addWidget(self.stop_entry, 4, 1) + + self.distance_x_label = QtWidgets.QLabel('%s:' % _("Dx")) + self.distance_x_label.setToolTip(_("This is the distance measured over the X axis.")) + self.distance_x_entry = FCEntry() self.distance_x_entry.setReadOnly(True) self.distance_x_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self.distance_x_entry.setToolTip(_("This is the distance measured over the X axis.")) + grid0.addWidget(self.distance_x_label, 5, 0) + grid0.addWidget(self.distance_x_entry, 5, 1) + + self.distance_y_label = QtWidgets.QLabel('%s:' % _("Dy")) + self.distance_y_label.setToolTip(_("This is the distance measured over the Y axis.")) + self.distance_y_entry = FCEntry() self.distance_y_entry.setReadOnly(True) self.distance_y_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self.distance_y_entry.setToolTip(_("This is the distance measured over the Y axis.")) + grid0.addWidget(self.distance_y_label, 6, 0) + grid0.addWidget(self.distance_y_entry, 6, 1) + + self.angle_label = QtWidgets.QLabel('%s:' % _("Angle")) + self.angle_label.setToolTip(_("This is orientation angle of the measuring line.")) + self.angle_entry = FCEntry() self.angle_entry.setReadOnly(True) self.angle_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self.angle_entry.setToolTip(_("This is orientation angle of the measuring line.")) + grid0.addWidget(self.angle_label, 7, 0) + grid0.addWidget(self.angle_entry, 7, 1) + + self.total_distance_label = QtWidgets.QLabel("%s:" % _('DISTANCE')) + self.total_distance_label.setToolTip(_("This is the point to point Euclidian distance.")) + self.total_distance_entry = FCEntry() self.total_distance_entry.setReadOnly(True) self.total_distance_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self.total_distance_entry.setToolTip(_("This is the point to point Euclidian distance.")) - self.measure_btn = QtWidgets.QPushButton(_("Measure")) + grid0.addWidget(self.total_distance_label, 8, 0) + grid0.addWidget(self.total_distance_entry, 8, 1) + + self.measure_btn = FCButton(_("Measure")) # self.measure_btn.setFixedWidth(70) self.layout.addWidget(self.measure_btn) - form_layout.addRow(self.units_label, self.units_value) - form_layout.addRow(self.start_label, self.start_entry) - form_layout.addRow(self.stop_label, self.stop_entry) - form_layout.addRow(self.distance_x_label, self.distance_x_entry) - form_layout.addRow(self.distance_y_label, self.distance_y_entry) - form_layout.addRow(self.angle_label, self.angle_entry) - form_layout.addRow(self.total_distance_label, self.total_distance_entry) - - # initial view of the layout - self.start_entry.set_value('(0, 0)') - self.stop_entry.set_value('(0, 0)') - self.distance_x_entry.set_value('0.0') - self.distance_y_entry.set_value('0.0') - self.angle_entry.set_value('0.0') - self.total_distance_entry.set_value('0.0') - self.layout.addStretch() # store here the first click and second click of the measurement process @@ -137,6 +161,15 @@ class Distance(FlatCAMTool): self.mm = None self.mr = None + # monitor if the tool was used + self.tool_done = False + + # store the grid status here + self.grid_status_memory = False + + # store here if the snap button was clicked + self.snap_toggled = None + # VisPy visuals if self.app.is_legacy is False: self.sel_shapes = ShapeCollection(parent=self.app.plotcanvas.view.scene, layers=1) @@ -145,6 +178,7 @@ class Distance(FlatCAMTool): self.sel_shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='measurement') self.measure_btn.clicked.connect(self.activate_measure_tool) + self.snap_center_cb.toggled.connect(self.on_snap_toggled) def run(self, toggle=False): self.app.report_usage("ToolDistance()") @@ -154,6 +188,8 @@ class Distance(FlatCAMTool): self.rel_point1 = None self.rel_point2 = None + self.tool_done = False + if self.app.tool_tab_locked is True: return @@ -177,7 +213,7 @@ class Distance(FlatCAMTool): # Remove anything else in the GUI self.app.ui.tool_scroll_area.takeWidget() - # Put ourself in the GUI + # Put ourselves in the GUI self.app.ui.tool_scroll_area.setWidget(self) # Switch notebook to tool page @@ -195,20 +231,45 @@ class Distance(FlatCAMTool): self.angle_entry.set_value('0.0') self.total_distance_entry.set_value('0.0') + self.snap_center_cb.set_value(self.app.defaults['tools_dist_snap_center']) + + # snap center works only for Gerber and Execellon Editor's + if self.original_call_source == 'exc_editor' or self.original_call_source == 'grb_editor': + self.snap_center_cb.show() + else: + self.snap_center_cb.hide() + # this is a hack; seems that triggering the grid will make the visuals better # trigger it twice to return to the original state self.app.ui.grid_snap_btn.trigger() self.app.ui.grid_snap_btn.trigger() + if self.app.ui.grid_snap_btn.isChecked(): + self.grid_status_memory = True + log.debug("Distance Tool --> tool initialized") + def on_snap_toggled(self, state): + self.app.defaults['tools_dist_snap_center'] = state + if state: + # disengage the grid snapping since it will be hard to find the drills or pads on grid + if self.app.ui.grid_snap_btn.isChecked(): + self.app.ui.grid_snap_btn.trigger() + def activate_measure_tool(self): # ENABLE the Measuring TOOL self.active = True + # disable the measuring button + self.measure_btn.setDisabled(True) + self.measure_btn.setText('%s...' % _("Working")) + self.clicked_meas = 0 self.original_call_source = copy(self.app.call_source) + snap_center = self.app.defaults['tools_dist_snap_center'] + self.on_snap_toggled(snap_center) + self.app.inform.emit(_("MEASURING: Click on the Start point ...")) self.units = self.app.defaults['units'].lower() @@ -267,6 +328,10 @@ class Distance(FlatCAMTool): self.active = False self.points = [] + # disable the measuring button + self.measure_btn.setDisabled(False) + self.measure_btn.setText(_("Measure")) + self.app.call_source = copy(self.original_call_source) if self.original_call_source == 'app': self.app.mm = self.canvas.graph_event_connect('mouse_move', self.app.on_mouse_move_over_plot) @@ -307,8 +372,16 @@ class Distance(FlatCAMTool): # delete the measuring line self.delete_shape() + # restore the grid status + if (self.app.ui.grid_snap_btn.isChecked() and self.grid_status_memory is False) or \ + (not self.app.ui.grid_snap_btn.isChecked() and self.grid_status_memory is True): + self.app.ui.grid_snap_btn.trigger() + log.debug("Distance Tool --> exit tool") + if self.tool_done is False: + self.app.inform.emit('%s' % _("Distance Tool finished.")) + def on_mouse_click_release(self, event): # mouse click releases will be accepted only if the left button is clicked # this is necessary because right mouse click or middle mouse click @@ -323,11 +396,71 @@ class Distance(FlatCAMTool): pos_canvas = self.canvas.translate_coords(event_pos) - # if GRID is active we need to get the snapped positions - if self.app.grid_status() == True: - pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1]) + if self.snap_center_cb.get_value() is False: + # if GRID is active we need to get the snapped positions + if self.app.grid_status(): + pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1]) + else: + pos = pos_canvas[0], pos_canvas[1] else: - pos = pos_canvas[0], pos_canvas[1] + pos = (pos_canvas[0], pos_canvas[1]) + current_pt = Point(pos) + shapes_storage = self.make_storage() + + if self.original_call_source == 'exc_editor': + for storage in self.app.exc_editor.storage_dict: + __, st_closest_shape = self.app.exc_editor.storage_dict[storage].nearest(pos) + shapes_storage.insert(st_closest_shape) + + __, closest_shape = shapes_storage.nearest(pos) + + # if it's a drill + if isinstance(closest_shape.geo, MultiLineString): + radius = closest_shape.geo[0].length / 2.0 + center_pt = closest_shape.geo.centroid + + geo_buffered = center_pt.buffer(radius) + + if current_pt.within(geo_buffered): + pos = (center_pt.x, center_pt.y) + + # if it's a slot + elif isinstance(closest_shape.geo, Polygon): + geo_buffered = closest_shape.geo.buffer(0) + center_pt = geo_buffered.centroid + + if current_pt.within(geo_buffered): + pos = (center_pt.x, center_pt.y) + + elif self.original_call_source == 'grb_editor': + clicked_pads = list() + for storage in self.app.grb_editor.storage_dict: + try: + for shape_stored in self.app.grb_editor.storage_dict[storage]['geometry']: + if 'solid' in shape_stored.geo: + geometric_data = shape_stored.geo['solid'] + if Point(current_pt).within(geometric_data): + if isinstance(shape_stored.geo['follow'], Point): + clicked_pads.append(shape_stored.geo['follow']) + except KeyError: + pass + + if len(clicked_pads) > 1: + self.tool_done = True + self.deactivate_measure_tool() + self.app.inform.emit('[WARNING_NOTCL] %s' % _("Pads overlapped. Aborting.")) + return + + pos = (clicked_pads[0].x, clicked_pads[0].y) + + self.app.on_jump_to(custom_location=pos, fit_center=False) + # Update cursor + self.app.app_cursor.enabled = True + self.app.app_cursor.set_data(np.asarray([(pos[0], pos[1])]), + symbol='++', edge_color='#000000', + edge_width=self.app.defaults["global_cursor_width"], + size=self.app.defaults["global_cursor_size"]) + self.points.append(pos) # Reset here the relative coordinates so there is a new reference on the click position @@ -340,41 +473,46 @@ class Distance(FlatCAMTool): self.rel_point2 = copy(self.rel_point1) self.rel_point1 = pos - if len(self.points) == 1: - self.start_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1])) - self.app.inform.emit(_("MEASURING: Click on the Destination point ...")) - elif len(self.points) == 2: - dx = self.points[1][0] - self.points[0][0] - dy = self.points[1][1] - self.points[0][1] - d = math.sqrt(dx ** 2 + dy ** 2) - self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1])) + self.calculate_distance(pos=pos) - self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | {tx3} = {d_z}".format( - tx1=_("MEASURING"), - tx2=_("Result"), - tx3=_("Distance"), - d_x='%*f' % (self.decimals, abs(dx)), - d_y='%*f' % (self.decimals, abs(dy)), - d_z='%*f' % (self.decimals, abs(d))) + def calculate_distance(self, pos): + if len(self.points) == 1: + self.start_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1])) + self.app.inform.emit(_("MEASURING: Click on the Destination point ...")) + elif len(self.points) == 2: + self.app.app_cursor.enabled = False + dx = self.points[1][0] - self.points[0][0] + dy = self.points[1][1] - self.points[0][1] + d = math.sqrt(dx ** 2 + dy ** 2) + self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1])) + + self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | {tx3} = {d_z}".format( + tx1=_("MEASURING"), + tx2=_("Result"), + tx3=_("Distance"), + d_x='%*f' % (self.decimals, abs(dx)), + d_y='%*f' % (self.decimals, abs(dy)), + d_z='%*f' % (self.decimals, abs(d))) + ) + + self.distance_x_entry.set_value('%.*f' % (self.decimals, abs(dx))) + self.distance_y_entry.set_value('%.*f' % (self.decimals, abs(dy))) + + if dx != 0.0: + try: + angle = math.degrees(math.atan(dy / dx)) + self.angle_entry.set_value('%.*f' % (self.decimals, angle)) + except Exception: + pass + + self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d))) + self.app.ui.rel_position_label.setText( + "Dx: {}   Dy: {}    ".format( + '%.*f' % (self.decimals, pos[0]), '%.*f' % (self.decimals, pos[1]) ) - - self.distance_x_entry.set_value('%.*f' % (self.decimals, abs(dx))) - self.distance_y_entry.set_value('%.*f' % (self.decimals, abs(dy))) - - if dx != 0.0: - try: - angle = math.degrees(math.atan(dy / dx)) - self.angle_entry.set_value('%.*f' % (self.decimals, angle)) - except Exception as e: - pass - - self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d))) - self.app.ui.rel_position_label.setText( - "Dx: {}   Dy: {}    ".format( - '%.*f' % (self.decimals, pos[0]), '%.*f' % (self.decimals, pos[1]) - ) - ) - self.deactivate_measure_tool() + ) + self.tool_done = True + self.deactivate_measure_tool() def on_mouse_move_meas(self, event): try: # May fail in case mouse not within axes @@ -391,7 +529,7 @@ class Distance(FlatCAMTool): pos_canvas = self.app.plotcanvas.translate_coords((x, y)) - if self.app.grid_status() == True: + if self.app.grid_status(): pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1]) # Update cursor @@ -465,7 +603,15 @@ class Distance(FlatCAMTool): self.sel_shapes.clear() self.sel_shapes.redraw() - def set_meas_units(self, units): - self.meas.units_label.setText("[" + self.app.options["units"].lower() + "]") + @staticmethod + def make_storage(): + # ## Shape storage. + storage = FlatCAMRTreeStorage() + storage.get_points = DrawToolShape.get_pts + + return storage + + # def set_meas_units(self, units): + # self.meas.units_label.setText("[" + self.app.options["units"].lower() + "]") # end of file