- 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
This commit is contained in:
Marius Stanciu
2022-04-07 14:58:16 +03:00
committed by Marius
parent 319283cdd0
commit b0b2c8e7f5
4 changed files with 154 additions and 151 deletions

View File

@@ -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

View File

@@ -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):

View File

@@ -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("<b>Dx</b>: %.*f&nbsp;&nbsp; <b>Dy</b>: "
"%.*f&nbsp;&nbsp;&nbsp;&nbsp;" %
(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(
"<b>Dx</b>: {}&nbsp;&nbsp; <b>Dy</b>: {}&nbsp;&nbsp;&nbsp;&nbsp;".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("<b>Dx</b>: %.*f&nbsp;&nbsp; <b>Dy</b>: "
"%.*f&nbsp;&nbsp;&nbsp;&nbsp;" %
(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(
# "<b>Dx</b>: {}&nbsp;&nbsp; <b>Dy</b>: {}&nbsp;&nbsp;&nbsp;&nbsp;".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:

View File

@@ -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: