- modified the GUI for Exclusion areas; now the shapes are displayed in a Table where they can be selected and deleted. Modification applied for Geometry Objects only (for now).

- fixed and error when converting units, error that acted when in those fields that accept lists of tools only one tool was added
This commit is contained in:
Marius Stanciu 2020-05-09 05:18:05 +03:00 committed by Marius
parent ee69744d6e
commit 0e07ea1541
6 changed files with 207 additions and 41 deletions

View File

@ -7,6 +7,11 @@ CHANGELOG for FlatCAM beta
================================================= =================================================
9.05.2020
- modified the GUI for Exclusion areas; now the shapes are displayed in a Table where they can be selected and deleted. Modification applied for Geometry Objects only (for now).
- fixed and error when converting units, error that acted when in those fields that accept lists of tools only one tool was added
8.05.2020 8.05.2020
- added a parameter to the FlatCAMDefaults class, whenever a value in the self.defaults dict change it will call a callback function and send to it the modified key - added a parameter to the FlatCAMDefaults class, whenever a value in the self.defaults dict change it will call a callback function and send to it the modified key

View File

@ -4328,12 +4328,14 @@ class App(QtCore.QObject):
]: ]:
if self.defaults[dim] is None or self.defaults[dim] == '': if self.defaults[dim] is None or self.defaults[dim] == '':
continue continue
try: try:
coordinates = self.defaults[dim].split(",") coordinates = self.defaults[dim].split(",")
coords_xy = [float(eval(a)) for a in coordinates if a != ''] coords_xy = [float(eval(a)) for a in coordinates if a != '']
coords_xy[0] *= sfactor coords_xy[0] *= sfactor
coords_xy[1] *= sfactor coords_xy[1] *= sfactor
self.defaults[dim] = "%.*f, %.*f" % (self.decimals, coords_xy[0], self.decimals, coords_xy[1]) self.defaults[dim] = "%.*f, %.*f" % (
self.decimals, coords_xy[0], self.decimals, coords_xy[1])
except Exception as e: except Exception as e:
log.debug("App.on_toggle_units.scale_defaults() --> 'string tuples': %s" % str(e)) log.debug("App.on_toggle_units.scale_defaults() --> 'string tuples': %s" % str(e))
@ -4343,9 +4345,10 @@ class App(QtCore.QObject):
if self.defaults[dim] is None or self.defaults[dim] == '': if self.defaults[dim] is None or self.defaults[dim] == '':
continue continue
if isinstance(self.defaults[dim], float): try:
self.defaults[dim] = float(self.defaults[dim])
tools_diameters = [self.defaults[dim]] tools_diameters = [self.defaults[dim]]
else: except ValueError:
try: try:
tools_string = self.defaults[dim].split(",") tools_string = self.defaults[dim].split(",")
tools_diameters = [eval(a) for a in tools_string if a != ''] tools_diameters = [eval(a) for a in tools_string if a != '']
@ -4354,9 +4357,14 @@ class App(QtCore.QObject):
continue continue
self.defaults[dim] = '' self.defaults[dim] = ''
for t in range(len(tools_diameters)): td_len = len(tools_diameters)
tools_diameters[t] *= sfactor if td_len > 1:
self.defaults[dim] += "%.*f," % (self.decimals, tools_diameters[t]) for t in range(td_len):
tools_diameters[t] *= sfactor
self.defaults[dim] += "%.*f," % (self.decimals, tools_diameters[t])
else:
tools_diameters[0] *= sfactor
self.defaults[dim] += "%.*f" % (self.decimals, tools_diameters[0])
elif dim in ['global_gridx', 'global_gridy']: elif dim in ['global_gridx', 'global_gridy']:
# format the number of decimals to the one specified in self.decimals # format the number of decimals to the one specified in self.decimals

View File

@ -10,6 +10,7 @@
# File Modified (major mod): Marius Adrian Stanciu # # File Modified (major mod): Marius Adrian Stanciu #
# Date: 11/4/2019 # # Date: 11/4/2019 #
# ########################################################## # ##########################################################
from PyQt5 import QtCore
from shapely.geometry import Polygon, MultiPolygon from shapely.geometry import Polygon, MultiPolygon
@ -17,7 +18,6 @@ from flatcamGUI.VisPyVisuals import ShapeCollection
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
import numpy as np import numpy as np
import re
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -129,9 +129,13 @@ def color_variant(hex_color, bright_factor=1):
return "#" + "".join([i for i in new_rgb]) return "#" + "".join([i for i in new_rgb])
class ExclusionAreas: class ExclusionAreas(QtCore.QObject):
e_shape_modified = QtCore.pyqtSignal()
def __init__(self, app): def __init__(self, app):
super().__init__()
self.app = app self.app = app
# Storage for shapes, storage that can be used by FlatCAm tools for utility geometry # Storage for shapes, storage that can be used by FlatCAm tools for utility geometry
@ -401,6 +405,7 @@ class ExclusionAreas:
'%s %s' % (_("Generate the CNC Job object."), _("With Exclusion areas.")) '%s %s' % (_("Generate the CNC Job object."), _("With Exclusion areas."))
) )
self.e_shape_modified.emit()
for k in self.exclusion_areas_storage: for k in self.exclusion_areas_storage:
print(k) print(k)
@ -514,3 +519,52 @@ class ExclusionAreas:
FlatCAMTool.delete_moving_selection_shape(self) FlatCAMTool.delete_moving_selection_shape(self)
self.app.delete_selection_shape() self.app.delete_selection_shape()
FlatCAMTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes) FlatCAMTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
self.app.inform.emit('[success] %s' % _("All exclusion zones deleted."))
def delete_sel_shapes(self, idxs):
"""
:param idxs: list of indexes in self.exclusion_areas_storage list to be deleted
:return:
"""
# delete all plotted shapes
FlatCAMTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
# delete shapes
for idx in sorted(idxs, reverse=True):
del self.exclusion_areas_storage[idx]
# re-add what's left after deletion in first step
if self.obj_type == 'excellon':
color = "#FF7400"
face_color = "#FF7400BF"
else:
color = "#098a8f"
face_color = "#FF7400BF"
face_alpha = 0.3
color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
for geo_el in self.exclusion_areas_storage:
if isinstance(geo_el['shape'], Polygon):
self.exclusion_shapes.add(
geo_el['shape'], color=color, face_color=color_t, update=True, layer=0, tolerance=None)
if self.app.is_legacy is True:
self.exclusion_shapes.redraw()
if self.exclusion_areas_storage:
self.app.inform.emit('[success] %s' % _("Selected exclusion zones deleted."))
else:
# restore the default StyleSheet
self.cnc_button.setStyleSheet("")
# update the StyleSheet
self.cnc_button.setStyleSheet("""
QPushButton
{
font-weight: bold;
}
""")
self.cnc_button.setToolTip('%s' % _("Generate the CNC Job object."))
self.app.inform.emit('[success] %s' % _("All exclusion zones deleted."))

View File

@ -2125,35 +2125,29 @@ class GeometryObjectUI(ObjectUI):
self.exclusion_box.setContentsMargins(0, 0, 0, 0) self.exclusion_box.setContentsMargins(0, 0, 0, 0)
self.exclusion_frame.setLayout(self.exclusion_box) self.exclusion_frame.setLayout(self.exclusion_box)
h_lay = QtWidgets.QHBoxLayout() self.exclusion_table = FCTable()
self.exclusion_box.addLayout(h_lay) self.exclusion_box.addWidget(self.exclusion_table)
self.exclusion_table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
# Button Add Area self.exclusion_table.setColumnCount(4)
self.add_area_button = QtWidgets.QPushButton(_('Add area')) self.exclusion_table.setColumnWidth(0, 20)
self.add_area_button.setToolTip(_("Add an Exclusion Area.")) self.exclusion_table.setHorizontalHeaderLabels(['#', _('Object'), _('Strategy'), _('Over Z')])
h_lay.addWidget(self.add_area_button)
# Button Delete Area self.exclusion_table.horizontalHeaderItem(0).setToolTip(_("This is the Area ID."))
self.delete_area_button = QtWidgets.QPushButton(_('Clear areas')) self.exclusion_table.horizontalHeaderItem(1).setToolTip(
self.delete_area_button.setToolTip(_("Delete all exclusion areas.")) _("Type of the object where the exclusion area was added."))
h_lay.addWidget(self.delete_area_button) self.exclusion_table.horizontalHeaderItem(2).setToolTip(
_("The strategy used for exclusion area. Go around the exclusion areas or over it."))
self.exclusion_table.horizontalHeaderItem(3).setToolTip(
_("If the strategy is to go over the area then this is the height at which the tool will go to avoid the "
"exclusion area."))
grid_l = QtWidgets.QGridLayout() self.exclusion_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
grid_l.setColumnStretch(0, 0)
grid_l.setColumnStretch(1, 1)
self.exclusion_box.addLayout(grid_l)
# Area Selection shape grid_a1 = QtWidgets.QGridLayout()
self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape")) grid_a1.setColumnStretch(0, 0)
self.area_shape_label.setToolTip( grid_a1.setColumnStretch(1, 1)
_("The kind of selection shape used for area selection.") self.exclusion_box.addLayout(grid_a1)
)
self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
{'label': _("Polygon"), 'value': 'polygon'}])
grid_l.addWidget(self.area_shape_label, 0, 0)
grid_l.addWidget(self.area_shape_radio, 0, 1)
# Chose Strategy # Chose Strategy
self.strategy_label = FCLabel('%s:' % _("Strategy")) self.strategy_label = FCLabel('%s:' % _("Strategy"))
@ -2164,8 +2158,8 @@ class GeometryObjectUI(ObjectUI):
self.strategy_radio = RadioSet([{'label': _('Over'), 'value': 'over'}, self.strategy_radio = RadioSet([{'label': _('Over'), 'value': 'over'},
{'label': _('Around'), 'value': 'around'}]) {'label': _('Around'), 'value': 'around'}])
grid_l.addWidget(self.strategy_label, 1, 0) grid_a1.addWidget(self.strategy_label, 1, 0)
grid_l.addWidget(self.strategy_radio, 1, 1) grid_a1.addWidget(self.strategy_radio, 1, 1)
# Over Z # Over Z
self.over_z_label = FCLabel('%s:' % _("Over Z")) self.over_z_label = FCLabel('%s:' % _("Over Z"))
@ -2175,8 +2169,36 @@ class GeometryObjectUI(ObjectUI):
self.over_z_entry.set_range(0.000, 9999.9999) self.over_z_entry.set_range(0.000, 9999.9999)
self.over_z_entry.set_precision(self.decimals) self.over_z_entry.set_precision(self.decimals)
grid_l.addWidget(self.over_z_label, 2, 0) grid_a1.addWidget(self.over_z_label, 2, 0)
grid_l.addWidget(self.over_z_entry, 2, 1) grid_a1.addWidget(self.over_z_entry, 2, 1)
# Button Add Area
self.add_area_button = QtWidgets.QPushButton(_('Add area'))
self.add_area_button.setToolTip(_("Add an Exclusion Area."))
# Area Selection shape
self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
{'label': _("Polygon"), 'value': 'polygon'}])
self.area_shape_radio.setToolTip(
_("The kind of selection shape used for area selection.")
)
grid_a1.addWidget(self.add_area_button, 4, 0)
grid_a1.addWidget(self.area_shape_radio, 4, 1)
h_lay_1 = QtWidgets.QHBoxLayout()
self.exclusion_box.addLayout(h_lay_1)
# Button Delete All Areas
self.delete_area_button = QtWidgets.QPushButton(_('Clear areas'))
self.delete_area_button.setToolTip(_("Delete all exclusion areas."))
# Button Delete Selected Areas
self.delete_sel_area_button = QtWidgets.QPushButton(_('Delete Selected'))
self.delete_sel_area_button.setToolTip(_("Delete all exclusion areas that are selected in the table."))
h_lay_1.addWidget(self.delete_area_button)
h_lay_1.addWidget(self.delete_sel_area_button)
# -------------------------- EXCLUSION AREAS END ------------------------------------------------------------- # -------------------------- EXCLUSION AREAS END -------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------ # ------------------------------------------------------------------------------------------------------------

View File

@ -159,6 +159,15 @@ class GeometryObject(FlatCAMObj, Geometry):
self.ui_disconnect() self.ui_disconnect()
FlatCAMObj.build_ui(self) FlatCAMObj.build_ui(self)
# Area Exception - exclusion shape added signal
# first disconnect it from any other object
try:
self.app.exc_areas.e_shape_modified.disconnect()
except (TypeError, AttributeError):
pass
# then connect it to the current build_ui() method
self.app.exc_areas.e_shape_modified.connect(self.build_ui)
self.units = self.app.defaults['units'] self.units = self.app.defaults['units']
tool_idx = 0 tool_idx = 0
@ -179,7 +188,6 @@ class GeometryObject(FlatCAMObj, Geometry):
# For INCH the decimals should be no more than 3. There are no tools under 10mils. # For INCH the decimals should be no more than 3. There are no tools under 10mils.
dia_item = QtWidgets.QTableWidgetItem('%.*f' % (self.decimals, float(tooluid_value['tooldia']))) dia_item = QtWidgets.QTableWidgetItem('%.*f' % (self.decimals, float(tooluid_value['tooldia'])))
dia_item.setFlags(QtCore.Qt.ItemIsEnabled) dia_item.setFlags(QtCore.Qt.ItemIsEnabled)
offset_item = FCComboBox() offset_item = FCComboBox()
@ -310,6 +318,58 @@ class GeometryObject(FlatCAMObj, Geometry):
"<b>%s: <font color='#0000FF'>%s</font></b>" % (_('Parameters for'), _("Multiple Tools")) "<b>%s: <font color='#0000FF'>%s</font></b>" % (_('Parameters for'), _("Multiple Tools"))
) )
# Build Exclusion Areas section
e_len = len(self.app.exc_areas.exclusion_areas_storage)
self.ui.exclusion_table.setRowCount(e_len)
area_id = 0
for area in range(e_len):
area_id += 1
area_dict = self.app.exc_areas.exclusion_areas_storage[area]
area_id_item = QtWidgets.QTableWidgetItem('%d' % int(area_id))
area_id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.ui.exclusion_table.setItem(area, 0, area_id_item) # Area id
object_item = QtWidgets.QTableWidgetItem('%s' % area_dict["obj_type"])
object_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.ui.exclusion_table.setItem(area, 1, object_item) # Origin Object
strategy_item = QtWidgets.QTableWidgetItem('%s' % area_dict["strategy"])
strategy_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.ui.exclusion_table.setItem(area, 2, strategy_item) # Strategy
overz_item = QtWidgets.QTableWidgetItem('%s' % area_dict["overz"])
overz_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.ui.exclusion_table.setItem(area, 3, overz_item) # Over Z
self.ui.exclusion_table.resizeColumnsToContents()
self.ui.exclusion_table.resizeRowsToContents()
area_vheader = self.ui.exclusion_table.verticalHeader()
area_vheader.hide()
self.ui.exclusion_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
area_hheader = self.ui.exclusion_table.horizontalHeader()
area_hheader.setMinimumSectionSize(10)
area_hheader.setDefaultSectionSize(70)
area_hheader.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
area_hheader.resizeSection(0, 20)
area_hheader.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
area_hheader.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
area_hheader.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)
# area_hheader.setStretchLastSection(True)
self.ui.exclusion_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.ui.exclusion_table.setColumnWidth(0, 20)
self.ui.exclusion_table.setMinimumHeight(self.ui.exclusion_table.getHeight())
self.ui.exclusion_table.setMaximumHeight(self.ui.exclusion_table.getHeight())
def set_ui(self, ui): def set_ui(self, ui):
FlatCAMObj.set_ui(self, ui) FlatCAMObj.set_ui(self, ui)
@ -534,8 +594,11 @@ class GeometryObject(FlatCAMObj, Geometry):
self.ui.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked) self.ui.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
self.ui.cutz_entry.returnPressed.connect(self.on_cut_z_changed) self.ui.cutz_entry.returnPressed.connect(self.on_cut_z_changed)
# Exclusion areas
self.ui.exclusion_table.horizontalHeader().sectionClicked.connect(self.ui.exclusion_table.selectAll)
self.ui.add_area_button.clicked.connect(self.on_add_area_click) self.ui.add_area_button.clicked.connect(self.on_add_area_click)
self.ui.delete_area_button.clicked.connect(self.on_clear_area_click) self.ui.delete_area_button.clicked.connect(self.on_clear_area_click)
self.ui.delete_sel_area_button.clicked.connect(self.on_delete_sel_areas)
def on_cut_z_changed(self): def on_cut_z_changed(self):
self.old_cutz = self.ui.cutz_entry.get_value() self.old_cutz = self.ui.cutz_entry.get_value()
@ -2463,6 +2526,20 @@ class GeometryObject(FlatCAMObj, Geometry):
def on_clear_area_click(self): def on_clear_area_click(self):
self.app.exc_areas.on_clear_area_click() self.app.exc_areas.on_clear_area_click()
self.app.exc_areas.e_shape_modified.emit()
def on_delete_sel_areas(self):
sel_model = self.ui.exclusion_table.selectionModel()
sel_indexes = sel_model.selectedIndexes()
# it will iterate over all indexes which means all items in all columns too but I'm interested only on rows
# so the duplicate rows will not be added
sel_rows = set()
for idx in sel_indexes:
sel_rows.add(idx.row())
self.app.exc_areas.delete_sel_shapes(idxs=list(sel_rows))
self.app.exc_areas.e_shape_modified.emit()
def plot_element(self, element, color=None, visible=None): def plot_element(self, element, color=None, visible=None):

View File

@ -308,8 +308,8 @@ class FlatCAMObj(QtCore.QObject):
for option in self.options: for option in self.options:
try: try:
self.set_form_item(option) self.set_form_item(option)
except Exception: except Exception as err:
self.app.log.warning("Unexpected error:", sys.exc_info()) self.app.log.warning("Unexpected error: %s" % str(sys.exc_info()), str(err))
def read_form(self): def read_form(self):
""" """
@ -323,7 +323,7 @@ class FlatCAMObj(QtCore.QObject):
try: try:
self.read_form_item(option) self.read_form_item(option)
except Exception: except Exception:
self.app.log.warning("Unexpected error:", sys.exc_info()) self.app.log.warning("Unexpected error: %s" % str(sys.exc_info()))
def set_form_item(self, option): def set_form_item(self, option):
""" """