From b0b2c8e7f5940d19e39f62cc97575ea542c39bf3 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Thu, 7 Apr 2022 14:58:16 +0300 Subject: [PATCH] - some fixes to the Tcl commands contribution from Ali Khalil - refactoring code in Distance Plugin and making sure that the measurements are done correctly - work in progress --- CHANGELOG.md | 12 ++ appMain.py | 16 ++- appPlugins/ToolDistance.py | 241 +++++++++++++++----------------- tclCommands/TclCommandCutout.py | 36 ++--- 4 files changed, 154 insertions(+), 151 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d168fd6..d04dd1a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ CHANGELOG for FlatCAM Evo beta ================================================= +7.04.2022 + +- refactoring code in Distance Plugin and making sure that the measurements are done correctly - work in progress + +6.04.2022 + +- some fixes to the Tcl commands contribution from Ali Khalil + +5.04.2022 + +- fixed Distance plugin grid snap restore + 3.04.2022 - in Cutout Plugin exposed the any_cutout_handler() method and made sure that the `gaps` parameter case does not matter diff --git a/appMain.py b/appMain.py index e28de4c9..2e65be08 100644 --- a/appMain.py +++ b/appMain.py @@ -3563,6 +3563,16 @@ class App(QtCore.QObject): 'description': '', 'email': '' }, + { + 'name': "Maftei Albert-Alexandru", + 'description': '', + 'email': '' + }, + { + 'name': "Emily Ellis", + 'description': '', + 'email': '' + }, ] self.prog_grid_lay = GLay(v_spacing=5, h_spacing=3, c_stretch=[0, 0, 1]) @@ -8350,10 +8360,14 @@ class App(QtCore.QObject): :return: None """ self.log.debug("Plot_all()") + obj_collection = self.collection.get_list() + if not obj_collection: + return + if muted is not True: self.inform[str, bool].emit('%s...' % _("Redrawing all objects"), False) - for plot_obj in self.collection.get_list(): + for plot_obj in obj_collection: if plot_obj.obj_options['plot'] is False: continue def worker_task(obj): diff --git a/appPlugins/ToolDistance.py b/appPlugins/ToolDistance.py index 8583360d..ffd7a6c5 100644 --- a/appPlugins/ToolDistance.py +++ b/appPlugins/ToolDistance.py @@ -37,9 +37,6 @@ class Distance(AppTool): # store here the first click and second click of the measurement process self.points = [] - self.rel_point1 = None - self.rel_point2 = None - self.active = False self.clicked_meas = None self.meas_line = None @@ -88,8 +85,6 @@ class Distance(AppTool): if self.app.plugin_tab_locked is True: return - self.init_plugin() - if toggle: # if the splitter is hidden, display it if self.app.ui.splitter.sizes()[0] == 0: @@ -149,12 +144,14 @@ class Distance(AppTool): def init_plugin(self): self.points[:] = [] - self.rel_point1 = None - self.rel_point2 = None self.tool_done = False self.last_shape = None self.total_distance = 0.0 + self.clicked_meas = 0 + self.original_call_source = copy(self.app.call_source) + self.units = self.app.app_units.lower() + def install(self, icon=None, separator=None, **kwargs): AppTool.install(self, icon, separator, shortcut='Ctrl+M', **kwargs) @@ -194,27 +191,19 @@ class Distance(AppTool): self.units = self.app.app_units.lower() self.app.command_active = "Distance" + self.tool_done = False + self.grid_status_memory = True if self.app.ui.grid_snap_btn.isChecked() else False self.ui.snap_center_cb.set_value(self.app.options['tools_dist_snap_center']) self.ui.big_cursor_cb.set_value(self.app.options['tools_dist_big_cursor']) - # # 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.ui.snap_center_cb.show() - # snap_center = self.app.options['tools_dist_snap_center'] - # self.on_snap_toggled(snap_center) - # - # self.ui.snap_center_cb.toggled.connect(self.on_snap_toggled) - # else: - # self.ui.snap_center_cb.hide() - # try: - # self.ui.snap_center_cb.toggled.disconnect(self.on_snap_toggled) - # except (TypeError, AttributeError): - # pass - self.ui.snap_center_cb.show() snap_center = self.app.options['tools_dist_snap_center'] self.on_snap_toggled(snap_center) + try: + self.ui.snap_center_cb.toggled.disconnect() + except (AttributeError, TypeError): + pass self.ui.snap_center_cb.toggled.connect(self.on_snap_toggled) # this is a hack; seems that triggering the grid will make the visuals better @@ -222,8 +211,6 @@ class Distance(AppTool): self.app.ui.grid_snap_btn.trigger() self.app.ui.grid_snap_btn.trigger() - self.grid_status_memory = True if self.app.ui.grid_snap_btn.isChecked() else False - # initial view of the layout self.initial_view() @@ -262,10 +249,7 @@ class Distance(AppTool): self.ui.measure_btn.setDisabled(True) self.ui.measure_btn.setText('%s...' % _("Working")) - self.clicked_meas = 0 - self.original_call_source = copy(self.app.call_source) - self.units = self.app.app_units.lower() - + self.init_plugin() self.ui_connect() self.set_tool_ui() @@ -379,62 +363,9 @@ class Distance(AppTool): self.app.ui.grid_snap_btn.trigger() if self.tool_done is False: + self.tool_done = True self.app.inform.emit('%s' % _("Done.")) - 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 - # are used for panning on the canvas - # log.debug("Distance Tool --> mouse click release") - - snap_enabled = self.ui.snap_center_cb.get_value() - multipoint = self.ui.multipoint_cb.get_value() - - if self.app.use_3d_engine: - event_pos = event.pos - right_button = 2 - event_is_dragging = self.mouse_is_dragging - else: - event_pos = (event.xdata, event.ydata) - right_button = 3 - event_is_dragging = self.app.plotcanvas.is_dragging - - if event.button == 1: - pos_canvas = self.canvas.translate_coords(event_pos) - - if snap_enabled 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 = self.snap_handler(pos) - - self.points.append(pos) - - # Reset here the relative coordinates so there is a new reference on the click position - if self.rel_point1 is None: - self.app.ui.rel_position_label.setText("Dx: %.*f   Dy: " - "%.*f    " % - (self.decimals, 0.0, self.decimals, 0.0)) - self.rel_point1 = pos - else: - self.rel_point2 = copy(self.rel_point1) - self.rel_point1 = pos - - self.calculate_distance(pos=pos) - elif event.button == right_button and event_is_dragging is False: - if multipoint is False: - self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled.")) - else: - # update end point - end_val = self.update_end_point(self.points[-1]) - self.display_end(end_val) - self.app.inform.emit("[success] %s" % _("Done.")) - self.on_exit() - def calculate_distance(self, pos): multipoint = self.ui.multipoint_cb.get_value() @@ -452,15 +383,6 @@ class Distance(AppTool): d = math.sqrt(dx ** 2 + dy ** 2) self.ui.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d))) - # 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.app.ui.rel_position_label.setText( "Dx: {}   Dy: {}    ".format( '%.*f' % (self.decimals, pos[0]), '%.*f' % (self.decimals, pos[1]) @@ -618,6 +540,85 @@ class Distance(AppTool): self.app.options['tools_dist_big_cursor'] = False self.app.on_cursor_type(val="small", control_cursor=True) + def update_position_info(self, pos_canvas): + big_cursor_state = self.ui.big_cursor_cb.get_value() + grid_snap_state = self.app.grid_status() + + if big_cursor_state is False: + if grid_snap_state: + pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1]) + # Update cursor + self.app.app_cursor.set_data(np.asarray([(pos[0], pos[1])]), + symbol='++', edge_color=self.app.plotcanvas.cursor_color, + edge_width=self.app.options["global_cursor_width"], + size=self.app.options["global_cursor_size"]) + else: + pos = (pos_canvas[0], pos_canvas[1]) + else: + if grid_snap_state: + pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1]) + else: + if self.app.app_cursor.enabled is False: + self.app.app_cursor.enabled = True + pos = (pos_canvas[0], pos_canvas[1]) + # Update cursor + self.app.app_cursor.set_data(np.asarray([(pos[0], pos[1])]), + symbol='++', edge_color=self.app.plotcanvas.cursor_color, + edge_width=self.app.options["global_cursor_width"], + size=self.app.options["global_cursor_size"]) + + return pos + + 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 + # are used for panning on the canvas + # log.debug("Distance Tool --> mouse click release") + + snap_enabled = self.ui.snap_center_cb.get_value() + multipoint = self.ui.multipoint_cb.get_value() + + if self.app.use_3d_engine: + event_pos = event.pos + right_button = 2 + event_is_dragging = self.mouse_is_dragging + else: + event_pos = (event.xdata, event.ydata) + right_button = 3 + event_is_dragging = self.app.plotcanvas.is_dragging + + if event.button == 1: + pos_canvas = self.canvas.translate_coords(event_pos) + + if snap_enabled 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 = self.snap_handler(pos) + + self.points.append(pos) + + # Reset here the relative coordinates so there is a new reference on the click position + if len(self.points) == 1: + self.app.ui.rel_position_label.setText("Dx: %.*f   Dy: " + "%.*f    " % + (self.decimals, 0.0, self.decimals, 0.0)) + + self.calculate_distance(pos=pos) + elif event.button == right_button and event_is_dragging is False: + if multipoint is False: + self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled.")) + else: + # update end point + end_val = self.update_end_point(self.points[-1]) + self.display_end(end_val) + self.app.inform.emit("[success] %s" % _("Done.")) + self.on_exit() + def on_mouse_move(self, event): multipoint = self.ui.multipoint_cb.get_value() @@ -633,55 +634,31 @@ class Distance(AppTool): y = float(event_pos[1]) except TypeError: return - pos_canvas = self.app.plotcanvas.translate_coords((x, y)) - big_cursor_state = self.ui.big_cursor_cb.get_value() - grid_snap_state = self.app.grid_status() - if big_cursor_state is False: - if grid_snap_state: - pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1]) - # Update cursor - self.app.app_cursor.set_data(np.asarray([(pos[0], pos[1])]), - symbol='++', edge_color=self.app.plotcanvas.cursor_color, - edge_width=self.app.options["global_cursor_width"], - size=self.app.options["global_cursor_size"]) - else: - pos = (pos_canvas[0], pos_canvas[1]) - else: - if grid_snap_state: - pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1]) - else: - if self.app.app_cursor.enabled is False: - self.app.app_cursor.enabled = True - pos = (pos_canvas[0], pos_canvas[1]) - # Update cursor - self.app.app_cursor.set_data(np.asarray([(pos[0], pos[1])]), - symbol='++', edge_color=self.app.plotcanvas.cursor_color, - edge_width=self.app.options["global_cursor_width"], - size=self.app.options["global_cursor_size"]) + # update position info + pos = self.update_position_info(pos_canvas) - self.app.ui.update_location_labels(dx=None, dy=None, x=pos[0], y=pos[1]) - self.app.plotcanvas.on_update_text_hud('0.0', '0.0', pos[0], pos[1]) - - if self.rel_point1 is not None: - dx = pos[0] - float(self.rel_point1[0]) - dy = pos[1] - float(self.rel_point1[1]) - else: - dx = pos[0] - dy = pos[1] - - # self.app.ui.rel_position_label.setText( - # "Dx: {}   Dy: {}    ".format( - # '%.*f' % (self.decimals, dx), '%.*f' % (self.decimals, dy) - # ) - # ) + # ------------------------------------------------------------ + # Update Status Bar location labels + # ------------------------------------------------------------ + dx = pos[0] + dy = pos[1] + if len(self.points) == 1: + dx = pos[0] - float(self.points[0][0]) + dy = pos[1] - float(self.points[0][1]) + elif len(self.points) == 2: + dx = float(self.points[1][0]) - float(self.points[0][0]) + dy = float(self.points[1][1]) - float(self.points[0][1]) self.app.ui.update_location_labels(dx=dx, dy=dy, x=pos[0], y=pos[1]) + # self.app.ui.update_location_labels(dx=None, dy=None, x=pos[0], y=pos[1]) + self.app.plotcanvas.on_update_text_hud(dx, dy, pos[0], pos[1]) + except Exception as e: self.app.log.error("Distance.on_mouse_move() position --> %s" % str(e)) - self.app.ui.position_label.setText("") - self.app.ui.rel_position_label.setText("") + self.app.ui.update_location_labels(dx=None, dy=None, x=None, y=None) + self.app.plotcanvas.on_update_text_hud('0.0', '0.0', '0.0', '0.0') return try: diff --git a/tclCommands/TclCommandCutout.py b/tclCommands/TclCommandCutout.py index 8ff40956..c7513113 100644 --- a/tclCommands/TclCommandCutout.py +++ b/tclCommands/TclCommandCutout.py @@ -1,17 +1,14 @@ + # from matplotlib.colors import LinearSegmentedColormap from tclCommands.TclCommand import TclCommand import collections -import logging from copy import deepcopy -import gettext -from shapely.geometry import LineString, box +from shapely.geometry import box from shapely.ops import linemerge from camlib import flatten_shapely_geometry -log = logging.getLogger('base') - class TclCommandCutout(TclCommand): """ @@ -22,11 +19,11 @@ class TclCommandCutout(TclCommand): """ - # List of all command aliases, to be able use old + # List of all command aliases, to be able to use old # names for backward compatibility (add_poly, add_polygon) aliases = ['cutout', 'geocutout'] - description = '%s %s' % ("--", "Creates board cutout from an object (Gerber or Geometry).") + description = '%s %s' % ("--", "Creates board cutout from an outline object (Gerber or Geometry).") # Dictionary of types from Tcl command, needs to be ordered arg_names = collections.OrderedDict([ @@ -90,8 +87,9 @@ class TclCommandCutout(TclCommand): if 'gaps' in args: if str(args['gaps']).lower() not in ["none", "tb", "lr", "2tb", "2lr", "4", "8"]: - self.raise_tcl_error( - "Incorrect -gaps values. Can be only a string from: 'none', 'tb', 'lr', '2tb', '2lr', '4', and '8'.") + error_msg = "Incorrect -gaps values. " \ + "Can be only a string from: 'none', 'tb', 'lr', '2tb', '2lr', '4', and '8'." + self.raise_tcl_error(error_msg) return "fail" gaps_par = str(args['gaps']) else: @@ -109,11 +107,11 @@ class TclCommandCutout(TclCommand): if 'type' in args: if args['type'] not in ['rect', 'any']: - self.raise_tcl_error(_("Incorrect -type value. Can only an be: 'rect', 'any'. default: any")) + self.raise_tcl_error("Incorrect -type value. Can only an be: 'rect', 'any'. default: any") return 'fail' type_par = args['type'] else: - self.app.log.info(_("No type value specified. Using default: any.")) + self.app.log.info("No type value specified. Using default: any.") type_par = 'any' try: @@ -129,8 +127,8 @@ class TclCommandCutout(TclCommand): gapsize = gapsize_par + dia_par + xmin, ymin, xmax, ymax = cutout_obj.bounds() if type_par == 'rect': - xmin, ymin, xmax, ymax = cutout_obj.bounds() cutout_geom = flatten_shapely_geometry(box(xmin, ymin, xmax, ymax)) else: cutout_geom = flatten_shapely_geometry(cutout_obj.solid_geometry) @@ -143,14 +141,16 @@ class TclCommandCutout(TclCommand): geom_struct_buff = geom_struct.buffer(-margin_par + abs(dia_par / 2)) geom_struct = geom_struct_buff.interiors - if type_par == 'rect': - solid_geo = self.app.cutout_tool.rect_cutout_handler(geom_struct, dia_par, gaps_par, gapsize, margin_par, xmin, ymin, xmax, ymax) - else: - solid_geo, r_geo = self.app.cutout_tool.any_cutout_handler(geom_struct, dia_par, gaps_par, gapsize, margin_par) + if type_par == 'rect': + solid_geo = self.app.cutout_tool.rect_cutout_handler( + geom_struct, dia_par, gaps_par, gapsize, margin_par, xmin, ymin, xmax, ymax) + else: + solid_geo, r_geo = self.app.cutout_tool.any_cutout_handler( + geom_struct, dia_par, gaps_par, gapsize, margin_par) if not solid_geo: self.app.log.debug("TclCommandCutout.geo_init_me() -> Empty solid geometry.") - self.app.log.error('[ERROR] %s' % _("Failed.")) + self.app.log.error('[ERROR] %s' % "Failed.") return "fail" try: @@ -182,7 +182,7 @@ class TclCommandCutout(TclCommand): try: ret = self.app.app_obj.new_object("geometry", outname, geo_init_me, plot=False) if ret == 'fail': - self.app.log.error("Could not create a cutout Geometry object." ) + self.app.log.error("Could not create a cutout Geometry object.") return "fail" self.app.log.info("[success] Cutout operation finished.") except Exception as e: