- 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:
12
CHANGELOG.md
12
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
|
||||
|
||||
16
appMain.py
16
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):
|
||||
|
||||
@@ -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 <b>Dy</b>: "
|
||||
"%.*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(
|
||||
"<b>Dx</b>: {} <b>Dy</b>: {} ".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 <b>Dy</b>: "
|
||||
"%.*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(
|
||||
# "<b>Dx</b>: {} <b>Dy</b>: {} ".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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user