- added in Preferences a new Category: Gerber Advanced Options. For now it controls the display of Gerber Aperture Table and the "follow" attribute4

- fixed FlatCAMGerber.merge() to merge the self.apertures[ap]['solid_geometry'] too
- started to work on a new feature that allow adding a ToolChange GCode macro - GUI added both in CNCJob Selected tab and in CNCJob Preferences
- added a limited 'sort-of' Gerber Editor: it allows buffering and scaling of apertures
This commit is contained in:
Marius Stanciu
2019-02-26 00:33:31 +02:00
committed by Marius S
parent 11ef818f0d
commit 386c3408ca
6 changed files with 498 additions and 33 deletions

View File

@@ -330,11 +330,13 @@ class App(QtCore.QObject):
"global_workspace": self.ui.general_defaults_form.general_gui_group.workspace_cb, "global_workspace": self.ui.general_defaults_form.general_gui_group.workspace_cb,
"global_workspaceT": self.ui.general_defaults_form.general_gui_group.wk_cb, "global_workspaceT": self.ui.general_defaults_form.general_gui_group.wk_cb,
# Gerber General
"gerber_plot": self.ui.gerber_defaults_form.gerber_gen_group.plot_cb, "gerber_plot": self.ui.gerber_defaults_form.gerber_gen_group.plot_cb,
"gerber_solid": self.ui.gerber_defaults_form.gerber_gen_group.solid_cb, "gerber_solid": self.ui.gerber_defaults_form.gerber_gen_group.solid_cb,
"gerber_multicolored": self.ui.gerber_defaults_form.gerber_gen_group.multicolored_cb, "gerber_multicolored": self.ui.gerber_defaults_form.gerber_gen_group.multicolored_cb,
"gerber_circle_steps": self.ui.gerber_defaults_form.gerber_gen_group.circle_steps_entry, "gerber_circle_steps": self.ui.gerber_defaults_form.gerber_gen_group.circle_steps_entry,
# Gerber Options
"gerber_isotooldia": self.ui.gerber_defaults_form.gerber_opt_group.iso_tool_dia_entry, "gerber_isotooldia": self.ui.gerber_defaults_form.gerber_opt_group.iso_tool_dia_entry,
"gerber_isopasses": self.ui.gerber_defaults_form.gerber_opt_group.iso_width_entry, "gerber_isopasses": self.ui.gerber_defaults_form.gerber_opt_group.iso_width_entry,
"gerber_isooverlap": self.ui.gerber_defaults_form.gerber_opt_group.iso_overlap_entry, "gerber_isooverlap": self.ui.gerber_defaults_form.gerber_opt_group.iso_overlap_entry,
@@ -345,6 +347,12 @@ class App(QtCore.QObject):
"gerber_bboxmargin": self.ui.gerber_defaults_form.gerber_opt_group.bbmargin_entry, "gerber_bboxmargin": self.ui.gerber_defaults_form.gerber_opt_group.bbmargin_entry,
"gerber_bboxrounded": self.ui.gerber_defaults_form.gerber_opt_group.bbrounded_cb, "gerber_bboxrounded": self.ui.gerber_defaults_form.gerber_opt_group.bbrounded_cb,
# Gerber Advanced Options
"gerber_aperture_display": self.ui.gerber_defaults_form.gerber_adv_opt_group.aperture_table_visibility_cb,
"gerber_aperture_scale_factor": self.ui.gerber_defaults_form.gerber_adv_opt_group.scale_aperture_entry,
"gerber_aperture_buffer_factor": self.ui.gerber_defaults_form.gerber_adv_opt_group.buffer_aperture_entry,
"gerber_follow": self.ui.gerber_defaults_form.gerber_adv_opt_group.follow_cb,
# Excellon General # Excellon General
"excellon_plot": self.ui.excellon_defaults_form.excellon_gen_group.plot_cb, "excellon_plot": self.ui.excellon_defaults_form.excellon_gen_group.plot_cb,
"excellon_solid": self.ui.excellon_defaults_form.excellon_gen_group.solid_cb, "excellon_solid": self.ui.excellon_defaults_form.excellon_gen_group.solid_cb,
@@ -428,9 +436,14 @@ class App(QtCore.QObject):
"cncjob_fr_decimals": self.ui.cncjob_defaults_form.cncjob_gen_group.fr_dec_entry, "cncjob_fr_decimals": self.ui.cncjob_defaults_form.cncjob_gen_group.fr_dec_entry,
"cncjob_steps_per_circle": self.ui.cncjob_defaults_form.cncjob_gen_group.steps_per_circle_entry, "cncjob_steps_per_circle": self.ui.cncjob_defaults_form.cncjob_gen_group.steps_per_circle_entry,
# CNC Job Options
"cncjob_prepend": self.ui.cncjob_defaults_form.cncjob_opt_group.prepend_text, "cncjob_prepend": self.ui.cncjob_defaults_form.cncjob_opt_group.prepend_text,
"cncjob_append": self.ui.cncjob_defaults_form.cncjob_opt_group.append_text, "cncjob_append": self.ui.cncjob_defaults_form.cncjob_opt_group.append_text,
# CNC Job Advanced Options
"cncjob_toolchange_macro": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_text,
"cncjob_toolchange_macro_enable": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_cb,
# NCC Tool # NCC Tool
"tools_ncctools": self.ui.tools_defaults_form.tools_ncc_group.ncc_tool_dia_entry, "tools_ncctools": self.ui.tools_defaults_form.tools_ncc_group.ncc_tool_dia_entry,
"tools_nccoverlap": self.ui.tools_defaults_form.tools_ncc_group.ncc_overlap_entry, "tools_nccoverlap": self.ui.tools_defaults_form.tools_ncc_group.ncc_overlap_entry,
@@ -605,6 +618,7 @@ class App(QtCore.QObject):
"global_point_clipboard_format": "(%.4f, %.4f)", "global_point_clipboard_format": "(%.4f, %.4f)",
"global_zdownrate": None, "global_zdownrate": None,
# Gerber General
"gerber_plot": True, "gerber_plot": True,
"gerber_solid": True, "gerber_solid": True,
"gerber_multicolored": False, "gerber_multicolored": False,
@@ -612,6 +626,7 @@ class App(QtCore.QObject):
"gerber_isopasses": 1, "gerber_isopasses": 1,
"gerber_isooverlap": 0.15, "gerber_isooverlap": 0.15,
# Gerber Options
"gerber_combine_passes": False, "gerber_combine_passes": False,
"gerber_milling_type": "cl", "gerber_milling_type": "cl",
"gerber_noncoppermargin": 0.1, "gerber_noncoppermargin": 0.1,
@@ -621,6 +636,12 @@ class App(QtCore.QObject):
"gerber_circle_steps": 64, "gerber_circle_steps": 64,
"gerber_use_buffer_for_union": True, "gerber_use_buffer_for_union": True,
# Gerber Advanced Options
"gerber_aperture_display": False,
"gerber_aperture_scale_factor": 1.0,
"gerber_aperture_buffer_factor": 0.0,
"gerber_follow": False,
# Excellon General # Excellon General
"excellon_plot": True, "excellon_plot": True,
"excellon_solid": True, "excellon_solid": True,
@@ -696,14 +717,21 @@ class App(QtCore.QObject):
"geometry_segx": 0.0, "geometry_segx": 0.0,
"geometry_segy": 0.0, "geometry_segy": 0.0,
# CNC Job General
"cncjob_plot": True, "cncjob_plot": True,
"cncjob_plot_kind": 'all', "cncjob_plot_kind": 'all',
"cncjob_tooldia": 0.0393701, "cncjob_tooldia": 0.0393701,
"cncjob_coords_decimals": 4, "cncjob_coords_decimals": 4,
"cncjob_fr_decimals": 2, "cncjob_fr_decimals": 2,
"cncjob_steps_per_circle": 64,
# CNC Job Options
"cncjob_prepend": "", "cncjob_prepend": "",
"cncjob_append": "", "cncjob_append": "",
"cncjob_steps_per_circle": 64,
# CNC Job Advanced Options
"cncjob_toolchange_macro": "",
"cncjob_toolchange_macro_enable": False,
"tools_ncctools": "1.0, 0.5", "tools_ncctools": "1.0, 0.5",
"tools_nccoverlap": 0.4, "tools_nccoverlap": 0.4,

View File

@@ -2576,10 +2576,14 @@ class GerberPreferencesUI(QtWidgets.QWidget):
self.gerber_gen_group = GerberGenPrefGroupUI() self.gerber_gen_group = GerberGenPrefGroupUI()
self.gerber_gen_group.setFixedWidth(250) self.gerber_gen_group.setFixedWidth(250)
self.gerber_opt_group = GerberOptPrefGroupUI() self.gerber_opt_group = GerberOptPrefGroupUI()
self.gerber_opt_group.setFixedWidth(250) self.gerber_opt_group.setFixedWidth(200)
self.gerber_adv_opt_group = GerberAdvOptPrefGroupUI()
self.gerber_adv_opt_group.setFixedWidth(200)
self.layout.addWidget(self.gerber_gen_group) self.layout.addWidget(self.gerber_gen_group)
self.layout.addWidget(self.gerber_opt_group) self.layout.addWidget(self.gerber_opt_group)
self.layout.addWidget(self.gerber_adv_opt_group)
self.layout.addStretch() self.layout.addStretch()
@@ -2700,9 +2704,13 @@ class CNCJobPreferencesUI(QtWidgets.QWidget):
self.cncjob_gen_group.setFixedWidth(270) self.cncjob_gen_group.setFixedWidth(270)
self.cncjob_opt_group = CNCJobOptPrefGroupUI() self.cncjob_opt_group = CNCJobOptPrefGroupUI()
self.cncjob_opt_group.setFixedWidth(260) self.cncjob_opt_group.setFixedWidth(260)
self.cncjob_adv_opt_group = CNCJobAdvOptPrefGroupUI()
self.cncjob_adv_opt_group.setFixedWidth(260)
self.layout.addWidget(self.cncjob_gen_group) self.layout.addWidget(self.cncjob_gen_group)
self.layout.addWidget(self.cncjob_opt_group) self.layout.addWidget(self.cncjob_opt_group)
self.layout.addWidget(self.cncjob_adv_opt_group)
self.layout.addStretch() self.layout.addStretch()
@@ -3288,26 +3296,27 @@ class GerberGenPrefGroupUI(OptionsGroupUI):
grid0 = QtWidgets.QGridLayout() grid0 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0) self.layout.addLayout(grid0)
# Plot CB
self.plot_cb = FCCheckBox(label='Plot')
self.plot_options_label.setToolTip(
"Plot (show) this object."
)
grid0.addWidget(self.plot_cb, 0, 0)
# Solid CB # Solid CB
self.solid_cb = FCCheckBox(label='Solid') self.solid_cb = FCCheckBox(label='Solid')
self.solid_cb.setToolTip( self.solid_cb.setToolTip(
"Solid color polygons." "Solid color polygons."
) )
grid0.addWidget(self.solid_cb, 0, 1) grid0.addWidget(self.solid_cb, 0, 0)
# Multicolored CB # Multicolored CB
self.multicolored_cb = FCCheckBox(label='M-Color') self.multicolored_cb = FCCheckBox(label='M-Color')
self.multicolored_cb.setToolTip( self.multicolored_cb.setToolTip(
"Draw polygons in different colors." "Draw polygons in different colors."
) )
grid0.addWidget(self.multicolored_cb, 0, 2) grid0.addWidget(self.multicolored_cb, 0, 1)
# Plot CB
self.plot_cb = FCCheckBox(label='Plot')
self.plot_options_label.setToolTip(
"Plot (show) this object."
)
grid0.addWidget(self.plot_cb, 0, 2)
# Number of circle steps for circular aperture linear approximation # Number of circle steps for circular aperture linear approximation
self.circle_steps_label = QtWidgets.QLabel("Circle Steps:") self.circle_steps_label = QtWidgets.QLabel("Circle Steps:")
@@ -3447,6 +3456,73 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
self.layout.addStretch() self.layout.addStretch()
class GerberAdvOptPrefGroupUI(OptionsGroupUI):
def __init__(self, parent=None):
# OptionsGroupUI.__init__(self, "Gerber Adv. Options Preferences", parent=parent)
super(GerberAdvOptPrefGroupUI, self).__init__(self)
self.setTitle(str("Gerber Adv. Options"))
## Advanced Gerber Parameters
self.adv_param_label = QtWidgets.QLabel("<b>Advanced Param.:</b>")
self.adv_param_label.setToolTip(
"A list of Gerber advanced parameters.\n"
"Those parameters are available only for\n"
"Advanced App. Level."
)
self.layout.addWidget(self.adv_param_label)
grid0 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0)
# Follow Attribute
self.follow_cb = FCCheckBox(label='"Follow"')
self.follow_cb.setToolTip(
"Generate a 'Follow' geometry.\n"
"This means that it will cut through\n"
"the middle of the trace."
)
grid0.addWidget(self.follow_cb, 0, 0)
# Aperture Table Visibility CB
self.aperture_table_visibility_cb = FCCheckBox(label='Table Show/Hide')
self.aperture_table_visibility_cb.setToolTip(
"Toggle the display of the Gerber Apertures Table.\n"
"Also, on hide, it will delete all mark shapes\n"
"that are drawn on canvas."
)
grid0.addWidget(self.aperture_table_visibility_cb, 1, 0)
# Scale Aperture Factor
self.scale_aperture_label = QtWidgets.QLabel('Ap. Scale Factor:')
self.scale_aperture_label.setToolTip(
"Change the size of the selected apertures.\n"
"Factor by which to multiply\n"
"geometric features of this object."
)
grid0.addWidget(self.scale_aperture_label, 2, 0)
self.scale_aperture_entry = FloatEntry2()
grid0.addWidget(self.scale_aperture_entry, 2, 1)
# Buffer Aperture Factor
self.buffer_aperture_label = QtWidgets.QLabel('Ap. Buffer Factor:')
self.buffer_aperture_label.setToolTip(
"Change the size of the selected apertures.\n"
"Factor by which to expand/shrink\n"
"geometric features of this object."
)
grid0.addWidget(self.buffer_aperture_label, 3, 0)
self.buffer_aperture_entry = FloatEntry2()
grid0.addWidget(self.buffer_aperture_entry, 3, 1)
self.layout.addStretch()
class ExcellonGenPrefGroupUI(OptionsGroupUI): class ExcellonGenPrefGroupUI(OptionsGroupUI):
def __init__(self, parent=None): def __init__(self, parent=None):
@@ -4546,6 +4622,81 @@ class CNCJobOptPrefGroupUI(OptionsGroupUI):
self.layout.addStretch() self.layout.addStretch()
class CNCJobAdvOptPrefGroupUI(OptionsGroupUI):
def __init__(self, parent=None):
# OptionsGroupUI.__init__(self, "CNC Job Advanced Options Preferences", parent=None)
super(CNCJobAdvOptPrefGroupUI, self).__init__(self)
self.setTitle(str("CNC Job Adv. Options"))
## Export G-Code
self.export_gcode_label = QtWidgets.QLabel("<b>Export G-Code:</b>")
self.export_gcode_label.setToolTip(
"Export and save G-Code to\n"
"make this object to a file."
)
self.layout.addWidget(self.export_gcode_label)
# Prepend to G-Code
toolchangelabel = QtWidgets.QLabel('Toolchange G-Code:')
toolchangelabel.setToolTip(
"Type here any G-Code commands you would\n"
"like to be executed when Toolchange event is encountered.\n"
"This will constitute a Custom Toolchange GCode,\n"
"or a Toolchange Macro."
)
self.layout.addWidget(toolchangelabel)
self.toolchange_text = FCTextArea()
self.layout.addWidget(self.toolchange_text)
hlay = QtWidgets.QHBoxLayout()
self.layout.addLayout(hlay)
# Toolchange Replacement GCode
self.toolchange_cb = FCCheckBox(label='Use Toolchange Macro')
self.toolchange_cb.setToolTip(
"Check this box if you want to use\n"
"a Custom Toolchange GCode (macro)."
)
hlay.addWidget(self.toolchange_cb)
hlay.addStretch()
hlay1 = QtWidgets.QHBoxLayout()
self.layout.addLayout(hlay1)
# Variable list
self.tc_variable_combo = FCComboBox()
self.tc_variable_combo.setToolTip(
"A list of the FlatCAM variables that can be used\n"
"in the Toolchange event.\n"
"They have to be surrounded by the '%' symbol"
)
hlay1.addWidget(self.tc_variable_combo)
# Populate the Combo Box
variables = ['tool', 'toolC', 't_drills', 'toolchangex', 'toolchangey', 'toolchangez']
self.tc_variable_combo.addItems(variables)
self.tc_variable_combo.setItemData(0, "tool = tool number", Qt.ToolTipRole)
self.tc_variable_combo.setItemData(1, "toolC = tool diameter", Qt.ToolTipRole)
self.tc_variable_combo.setItemData(2, "t_drills = for Excellon, total number of drills", Qt.ToolTipRole)
self.tc_variable_combo.setItemData(3, "toolchangex = X coord for Toolchange", Qt.ToolTipRole)
self.tc_variable_combo.setItemData(4, "toolchangey = Y coord for Toolchange", Qt.ToolTipRole)
self.tc_variable_combo.setItemData(5, "toolchangez = Z coord for Toolchange", Qt.ToolTipRole)
hlay1.addStretch()
# Insert Variable into the Toolchange G-Code Text Box
self.tc_insert_buton = FCButton("Insert")
self.tc_insert_buton.setToolTip(
"Insert the variable in the GCode Box\n"
"surrounded by the '%' symbol."
)
hlay1.addWidget(self.tc_insert_buton)
self.layout.addStretch()
class ToolsNCCPrefGroupUI(OptionsGroupUI): class ToolsNCCPrefGroupUI(OptionsGroupUI):
def __init__(self, parent=None): def __init__(self, parent=None):
# OptionsGroupUI.__init__(self, "NCC Tool Options", parent=parent) # OptionsGroupUI.__init__(self, "NCC Tool Options", parent=parent)

View File

@@ -382,26 +382,39 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
grb_final.solid_geometry = [] grb_final.solid_geometry = []
grb_final.follow_geometry = [] grb_final.follow_geometry = []
if not grb_final.apertures:
grb_final.apertures = {}
if type(grb_final.solid_geometry) is not list: if type(grb_final.solid_geometry) is not list:
grb_final.solid_geometry = [grb_final.solid_geometry] grb_final.solid_geometry = [grb_final.solid_geometry]
grb_final.follow_geometry = [grb_final.follow_geometry] grb_final.follow_geometry = [grb_final.follow_geometry]
for grb in grb_list: for grb in grb_list:
for option in grb.options:
if option is not 'name':
try:
grb_final.options[option] = grb.options[option]
except:
log.warning("Failed to copy option.", option)
# Expand lists # Expand lists
if type(grb) is list: if type(grb) is list:
FlatCAMGerber.merge(grb, grb_final) FlatCAMGerber.merge(grb, grb_final)
else: # If not list, just append else: # If not list, just append
for option in grb.options:
if option is not 'name':
try:
grb_final.options[option] = grb.options[option]
except:
log.warning("Failed to copy option.", option)
for geos in grb.solid_geometry: for geos in grb.solid_geometry:
grb_final.solid_geometry.append(geos) grb_final.solid_geometry.append(geos)
grb_final.follow_geometry.append(geos) grb_final.follow_geometry.append(geos)
for ap in grb.apertures:
if ap not in grb_final.apertures:
grb_final.apertures[ap] = grb.apertures[ap]
else:
if 'solid_geometry' not in grb_final.apertures[ap]:
grb_final.apertures[ap]['solid_geometry'] = []
for geo in grb.apertures[ap]['solid_geometry']:
grb_final.apertures[ap]['solid_geometry'].append(geo)
grb_final.solid_geometry = MultiPolygon(grb_final.solid_geometry) grb_final.solid_geometry = MultiPolygon(grb_final.solid_geometry)
grb_final.follow_geometry = MultiPolygon(grb_final.follow_geometry) grb_final.follow_geometry = MultiPolygon(grb_final.follow_geometry)
@@ -425,7 +438,11 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
"noncoppermargin": 0.0, "noncoppermargin": 0.0,
"noncopperrounded": False, "noncopperrounded": False,
"bboxmargin": 0.0, "bboxmargin": 0.0,
"bboxrounded": False "bboxrounded": False,
"aperture_display": False,
"aperture_scale_factor": 1.0,
"aperture_buffer_factor": 0.0,
"follow": False
}) })
# type of isolation: 0 = exteriors, 1 = interiors, 2 = complete isolation (both interiors and exteriors) # type of isolation: 0 = exteriors, 1 = interiors, 2 = complete isolation (both interiors and exteriors)
@@ -479,7 +496,11 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
"noncoppermargin": self.ui.noncopper_margin_entry, "noncoppermargin": self.ui.noncopper_margin_entry,
"noncopperrounded": self.ui.noncopper_rounded_cb, "noncopperrounded": self.ui.noncopper_rounded_cb,
"bboxmargin": self.ui.bbmargin_entry, "bboxmargin": self.ui.bbmargin_entry,
"bboxrounded": self.ui.bbrounded_cb "bboxrounded": self.ui.bbrounded_cb,
"aperture_display": self.ui.aperture_table_visibility_cb,
"aperture_scale_factor": self.ui.scale_aperture_entry,
"aperture_buffer_factor": self.ui.buffer_aperture_entry,
"follow": self.ui.follow_cb
}) })
# Fill form fields only on object create # Fill form fields only on object create
@@ -498,6 +519,9 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
self.ui.generate_noncopper_button.clicked.connect(self.on_generatenoncopper_button_click) self.ui.generate_noncopper_button.clicked.connect(self.on_generatenoncopper_button_click)
self.ui.aperture_table_visibility_cb.stateChanged.connect(self.on_aperture_table_visibility_change) self.ui.aperture_table_visibility_cb.stateChanged.connect(self.on_aperture_table_visibility_change)
self.ui.follow_cb.stateChanged.connect(self.on_follow_cb_click) self.ui.follow_cb.stateChanged.connect(self.on_follow_cb_click)
self.ui.scale_aperture_button.clicked.connect(self.on_scale_aperture_click)
self.ui.buffer_aperture_button.clicked.connect(self.on_buffer_aperture_click)
self.ui.new_grb_button.clicked.connect(self.on_new_modified_gerber)
# Show/Hide Advanced Options # Show/Hide Advanced Options
if self.app.defaults["global_app_level"] == 'b': if self.app.defaults["global_app_level"] == 'b':
@@ -513,6 +537,9 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
else: else:
self.ui.level.setText('<span style="color:red;"><b>Advanced</b></span>') self.ui.level.setText('<span style="color:red;"><b>Advanced</b></span>')
# set initial state of the aperture table and associated widgets
self.on_aperture_table_visibility_change()
self.build_ui() self.build_ui()
def build_ui(self): def build_ui(self):
@@ -963,17 +990,151 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
self.ui.scale_aperture_label.setVisible(True) self.ui.scale_aperture_label.setVisible(True)
self.ui.scale_aperture_entry.setVisible(True) self.ui.scale_aperture_entry.setVisible(True)
self.ui.scale_aperture_button.setVisible(True) self.ui.scale_aperture_button.setVisible(True)
self.ui.buffer_aperture_label.setVisible(True)
self.ui.buffer_aperture_entry.setVisible(True)
self.ui.buffer_aperture_button.setVisible(True)
self.ui.new_grb_label.setVisible(True)
self.ui.new_grb_button.setVisible(True)
else: else:
self.ui.apertures_table.setVisible(False) self.ui.apertures_table.setVisible(False)
self.ui.scale_aperture_label.setVisible(False) self.ui.scale_aperture_label.setVisible(False)
self.ui.scale_aperture_entry.setVisible(False) self.ui.scale_aperture_entry.setVisible(False)
self.ui.scale_aperture_button.setVisible(False) self.ui.scale_aperture_button.setVisible(False)
self.ui.buffer_aperture_label.setVisible(False)
self.ui.buffer_aperture_entry.setVisible(False)
self.ui.buffer_aperture_button.setVisible(False)
self.ui.new_grb_label.setVisible(False)
self.ui.new_grb_button.setVisible(False)
# on hide disable all mark plots # on hide disable all mark plots
for row in range(self.ui.apertures_table.rowCount()): for row in range(self.ui.apertures_table.rowCount()):
self.ui.apertures_table.cellWidget(row, 5).set_value(False) self.ui.apertures_table.cellWidget(row, 5).set_value(False)
self.mark_shapes.clear(update=True) self.mark_shapes.clear(update=True)
def on_scale_aperture_click(self, signal):
try:
factor = self.ui.scale_aperture_entry.get_value()
except Exception as e:
log.debug("FlatCAMGerber.on_scale_aperture_click() --> %s" % str(e))
self.app.inform.emit("[ERROR_NOTCL] The aperture scale factor value is missing or wrong format.")
return
def scale_recursion(geom):
if type(geom) == list or type(geom) is MultiPolygon:
geoms=list()
for local_geom in geom:
geoms.append(scale_recursion(local_geom))
return geoms
else:
return affinity.scale(geom, factor, factor, origin='center')
if not self.ui.apertures_table.selectedItems():
self.app.inform.emit("[WARNING_NOTCL] No aperture to scale. Select at least one aperture and try again.")
return
for x in self.ui.apertures_table.selectedItems():
try:
apid = self.ui.apertures_table.item(x.row(), 1).text()
except Exception as e:
log.debug("FlatCAMGerber.on_scale_aperture_click() --> %s" % str(e))
self.apertures[apid]['solid_geometry'] = scale_recursion(self.apertures[apid]['solid_geometry'])
self.on_mark_cb_click_table()
def on_buffer_aperture_click(self, signal):
try:
buff_value = self.ui.buffer_aperture_entry.get_value()
except Exception as e:
log.debug("FlatCAMGerber.on_scale_aperture_click() --> %s" % str(e))
self.app.inform.emit("[ERROR_NOTCL] The aperture buffer value is missing or wrong format.")
return
def buffer_recursion(geom):
if type(geom) == list or type(geom) is MultiPolygon:
geoms=list()
for local_geom in geom:
geoms.append(buffer_recursion(local_geom))
return geoms
else:
return geom.buffer(buff_value, join_style=2)
if not self.ui.apertures_table.selectedItems():
self.app.inform.emit("[WARNING_NOTCL] No aperture to scale. Select at least one aperture and try again.")
return
for x in self.ui.apertures_table.selectedItems():
try:
apid = self.ui.apertures_table.item(x.row(), 1).text()
except Exception as e:
log.debug("FlatCAMGerber.on_scale_aperture_click() --> %s" % str(e))
self.apertures[apid]['solid_geometry'] = buffer_recursion(self.apertures[apid]['solid_geometry'])
self.on_mark_cb_click_table()
def on_new_modified_gerber(self, signal):
name = '%s_ap_mod' % str(self.options['name'])
apertures = deepcopy(self.apertures)
options = self.options
# geometry storage
poly_buff = []
# How the object should be initialized
def obj_init(gerber_obj, app_obj):
assert isinstance(gerber_obj, FlatCAMGerber), \
"Expected to initialize a FlatCAMGerber but got %s" % type(gerber_obj)
gerber_obj.source_file = ''
gerber_obj.multigeo = False
gerber_obj.follow = False
gerber_obj.apertures = apertures
for option in options:
# we don't want to overwrite the new name and we don't want to share the 'plot' state
# because the new object should ve visible even if the source is not visible
if option != 'name' and option != 'plot':
gerber_obj.options[option] = options[option]
# regenerate solid_geometry
app_obj.log.debug("Creating new Gerber object. Joining %s polygons.")
for ap in apertures:
for geo in apertures[ap]['solid_geometry']:
poly_buff.append(geo)
# buffering the poly_buff
new_geo = MultiPolygon(poly_buff)
new_geo = new_geo.buffer(0.0000001)
new_geo = new_geo.buffer(-0.0000001)
gerber_obj.solid_geometry = new_geo
app_obj.log.debug("Finished creation of a new Gerber object. Polygons joined.")
log.debug("on_new_modified_gerber()")
with self.app.proc_container.new("Generating Gerber") as proc:
self.app.progress.emit(10)
### Object creation ###
ret = self.app.new_object("gerber", name, obj_init, autoselected=False)
if ret == 'fail':
self.app.inform.emit('[ERROR_NOTCL] Cretion of Gerber failed.')
return
self.app.progress.emit(100)
# GUI feedback
self.app.inform.emit("[success] Created: " + name)
def convert_units(self, units): def convert_units(self, units):
""" """
Converts the units of the object by scaling dimensions in all geometry Converts the units of the object by scaling dimensions in all geometry
@@ -4698,7 +4859,9 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
"prepend": "", "prepend": "",
"dwell": False, "dwell": False,
"dwelltime": 1, "dwelltime": 1,
"type": 'Geometry' "type": 'Geometry',
"toolchange_macro": '',
"toolchange_macro_enable": False
}) })
''' '''
@@ -4900,6 +5063,8 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
# "tooldia": self.ui.tooldia_entry, # "tooldia": self.ui.tooldia_entry,
"append": self.ui.append_text, "append": self.ui.append_text,
"prepend": self.ui.prepend_text, "prepend": self.ui.prepend_text,
"toolchange_macro": self.ui.toolchange_text,
"toolchange_macro_enable": self.ui.toolchange_cb
}) })
# Fill form fields only on object create # Fill form fields only on object create
@@ -4924,8 +5089,10 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
if self.app.defaults["global_app_level"] == 'b': if self.app.defaults["global_app_level"] == 'b':
self.ui.level.setText('<span style="color:green;"><b>Basic</b></span>') self.ui.level.setText('<span style="color:green;"><b>Basic</b></span>')
self.ui.cnc_frame.hide()
else: else:
self.ui.level.setText('<span style="color:red;"><b>Advanced</b></span>') self.ui.level.setText('<span style="color:red;"><b>Advanced</b></span>')
self.ui.cnc_frame.show()
self.ui.updateplot_button.clicked.connect(self.on_updateplot_button_click) self.ui.updateplot_button.clicked.connect(self.on_updateplot_button_click)
self.ui.export_gcode_button.clicked.connect(self.on_exportgcode_button_click) self.ui.export_gcode_button.clicked.connect(self.on_exportgcode_button_click)

View File

@@ -1,7 +1,8 @@
import sys import sys
from PyQt5 import QtGui, QtCore, QtWidgets, QtWidgets from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt
from GUIElements import FCEntry, FloatEntry, EvalEntry, FCCheckBox, FCTable, \ from GUIElements import FCEntry, FloatEntry, EvalEntry, FCCheckBox, FCTable, \
LengthEntry, FCTextArea, IntEntry, RadioSet, OptionalInputSection, FCComboBox, FloatEntry2, EvalEntry2 LengthEntry, FCTextArea, IntEntry, RadioSet, OptionalInputSection, FCComboBox, FloatEntry2, EvalEntry2, FCButton
from camlib import Excellon from camlib import Excellon
@@ -180,6 +181,12 @@ class GerberObjectUI(ObjectUI):
# Aperture Table Visibility CB # Aperture Table Visibility CB
self.aperture_table_visibility_cb = FCCheckBox('Show/Hide') self.aperture_table_visibility_cb = FCCheckBox('Show/Hide')
self.aperture_table_visibility_cb.setToolTip(
"Toogle the display of the Gerber Apertures Table.\n"
"Also, on hide, it will delete all mark shapes\n"
"that are drawn on canvas."
)
self.aperture_table_visibility_cb.setLayoutDirection(QtCore.Qt.RightToLeft) self.aperture_table_visibility_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
hlay_plot.addWidget(self.aperture_table_visibility_cb) hlay_plot.addWidget(self.aperture_table_visibility_cb)
@@ -207,30 +214,69 @@ class GerberObjectUI(ObjectUI):
# self.apertures_table.setColumnHidden(5, True) # self.apertures_table.setColumnHidden(5, True)
#### Aperture Scale #### #### Aperture Scale ####
self.scale_aperture_grid = QtWidgets.QGridLayout() self.transform_aperture_grid = QtWidgets.QGridLayout()
self.custom_box.addLayout(self.scale_aperture_grid) self.custom_box.addLayout(self.transform_aperture_grid)
# Factor # Scale Aperture Factor
self.scale_aperture_label = QtWidgets.QLabel('<b>Factor:</b>') self.scale_aperture_label = QtWidgets.QLabel('Scale Factor:')
self.scale_aperture_label.setToolTip( self.scale_aperture_label.setToolTip(
"Change the size of the selected apertures.\n" "Change the size of the selected apertures.\n"
"Factor by which to multiply\n" "Factor by which to multiply\n"
"geometric features of this object." "geometric features of this object."
) )
self.scale_aperture_label.setFixedWidth(90) self.scale_aperture_label.setFixedWidth(90)
self.scale_aperture_grid.addWidget(self.scale_aperture_label, 0, 0) self.transform_aperture_grid.addWidget(self.scale_aperture_label, 0, 0)
self.scale_aperture_entry = FloatEntry2() self.scale_aperture_entry = FloatEntry2()
self.scale_aperture_entry.set_value(1.0) self.transform_aperture_grid.addWidget(self.scale_aperture_entry, 0, 1)
self.scale_aperture_grid.addWidget(self.scale_aperture_entry, 0, 1)
# Scale Button # Scale Button
self.scale_aperture_button = QtWidgets.QPushButton('Scale') self.scale_aperture_button = QtWidgets.QPushButton('Scale')
self.scale_aperture_button.setToolTip( self.scale_aperture_button.setToolTip(
"Perform scaling operation." "Perform scaling operation."
) )
self.scale_aperture_button.setFixedWidth(40) self.scale_aperture_button.setFixedWidth(50)
self.scale_aperture_grid.addWidget(self.scale_aperture_button, 0, 2) self.transform_aperture_grid.addWidget(self.scale_aperture_button, 0, 2)
# Buffer Aperture Factor
self.buffer_aperture_label = QtWidgets.QLabel('Buffer Factor:')
self.buffer_aperture_label.setToolTip(
"Change the size of the selected apertures.\n"
"Factor by which to expand/shrink\n"
"geometric features of this object."
)
self.buffer_aperture_label.setFixedWidth(90)
self.transform_aperture_grid.addWidget(self.buffer_aperture_label, 1, 0)
self.buffer_aperture_entry = FloatEntry2()
self.transform_aperture_grid.addWidget(self.buffer_aperture_entry, 1, 1)
# Buffer Button
self.buffer_aperture_button = QtWidgets.QPushButton('Buffer')
self.buffer_aperture_button.setToolTip(
"Perform scaling operation."
)
self.buffer_aperture_button.setFixedWidth(50)
self.transform_aperture_grid.addWidget(self.buffer_aperture_button, 1, 2)
new_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(new_hlay)
self.new_grb_label = QtWidgets.QLabel("<b>Generate new Gerber Object:</b>")
self.new_grb_label.setToolTip(
"Will generate a new Gerber object from the changed apertures.\n"
"This new object can then be isolated etc."
)
new_hlay.addWidget(self.new_grb_label)
new_hlay.addStretch()
self.new_grb_button = FCButton('Go')
self.new_grb_button.setToolTip(
"Will generate a new Gerber object from the changed apertures.\n"
"This new object can then be isolated etc.")
self.new_grb_button.setFixedWidth(50)
new_hlay.addWidget(self.new_grb_button)
# start with apertures table hidden # start with apertures table hidden
self.apertures_table.setVisible(False) self.apertures_table.setVisible(False)
@@ -238,6 +284,10 @@ class GerberObjectUI(ObjectUI):
self.scale_aperture_entry.setVisible(False) self.scale_aperture_entry.setVisible(False)
self.scale_aperture_button.setVisible(False) self.scale_aperture_button.setVisible(False)
self.buffer_aperture_label.setVisible(False)
self.buffer_aperture_entry.setVisible(False)
self.buffer_aperture_button.setVisible(False)
# Isolation Routing # Isolation Routing
self.isolation_routing_label = QtWidgets.QLabel("<b>Isolation Routing:</b>") self.isolation_routing_label = QtWidgets.QLabel("<b>Isolation Routing:</b>")
self.isolation_routing_label.setToolTip( self.isolation_routing_label.setToolTip(
@@ -1362,7 +1412,7 @@ class CNCObjectUI(ObjectUI):
) )
self.custom_box.addWidget(self.export_gcode_label) self.custom_box.addWidget(self.export_gcode_label)
# Prepend text to Gerber # Prepend text to GCode
prependlabel = QtWidgets.QLabel('Prepend to CNC Code:') prependlabel = QtWidgets.QLabel('Prepend to CNC Code:')
prependlabel.setToolTip( prependlabel.setToolTip(
"Type here any G-Code commands you would\n" "Type here any G-Code commands you would\n"
@@ -1373,7 +1423,7 @@ class CNCObjectUI(ObjectUI):
self.prepend_text = FCTextArea() self.prepend_text = FCTextArea()
self.custom_box.addWidget(self.prepend_text) self.custom_box.addWidget(self.prepend_text)
# Append text to Gerber # Append text to GCode
appendlabel = QtWidgets.QLabel('Append to CNC Code') appendlabel = QtWidgets.QLabel('Append to CNC Code')
appendlabel.setToolTip( appendlabel.setToolTip(
"Type here any G-Code commands you would\n" "Type here any G-Code commands you would\n"
@@ -1385,6 +1435,70 @@ class CNCObjectUI(ObjectUI):
self.append_text = FCTextArea() self.append_text = FCTextArea()
self.custom_box.addWidget(self.append_text) self.custom_box.addWidget(self.append_text)
self.cnc_frame = QtWidgets.QFrame()
self.cnc_frame.setContentsMargins(0, 0, 0, 0)
self.custom_box.addWidget(self.cnc_frame)
self.cnc_box = QtWidgets.QVBoxLayout()
self.cnc_box.setContentsMargins(0, 0, 0, 0)
self.cnc_frame.setLayout(self.cnc_box)
# Prepend to G-Code
toolchangelabel = QtWidgets.QLabel('Toolchange G-Code:')
toolchangelabel.setToolTip(
"Type here any G-Code commands you would\n"
"like to be executed when Toolchange event is encountered.\n"
"This will constitute a Custom Toolchange GCode,\n"
"or a Toolchange Macro."
)
self.cnc_box.addWidget(toolchangelabel)
self.toolchange_text = FCTextArea()
self.cnc_box.addWidget(self.toolchange_text)
cnclay = QtWidgets.QHBoxLayout()
self.cnc_box.addLayout(cnclay)
# Toolchange Replacement GCode
self.toolchange_cb = FCCheckBox(label='Use Toolchange Macro')
self.toolchange_cb.setToolTip(
"Check this box if you want to use\n"
"a Custom Toolchange GCode (macro)."
)
cnclay.addWidget(self.toolchange_cb)
cnclay.addStretch()
cnclay1 = QtWidgets.QHBoxLayout()
self.cnc_box.addLayout(cnclay1)
# Variable list
self.tc_variable_combo = FCComboBox()
self.tc_variable_combo.setToolTip(
"A list of the FlatCAM variables that can be used\n"
"in the Toolchange event.\n"
"They have to be surrounded by the '%' symbol"
)
cnclay1.addWidget(self.tc_variable_combo)
# Populate the Combo Box
variables = ['tool', 'toolC', 't_drills', 'toolchangex', 'toolchangey', 'toolchangez']
self.tc_variable_combo.addItems(variables)
self.tc_variable_combo.setItemData(0, "tool = tool number", Qt.ToolTipRole)
self.tc_variable_combo.setItemData(1, "toolC = tool diameter", Qt.ToolTipRole)
self.tc_variable_combo.setItemData(2, "t_drills = for Excellon, total number of drills", Qt.ToolTipRole)
self.tc_variable_combo.setItemData(3, "toolchangex = X coord for Toolchange", Qt.ToolTipRole)
self.tc_variable_combo.setItemData(4, "toolchangey = Y coord for Toolchange", Qt.ToolTipRole)
self.tc_variable_combo.setItemData(5, "toolchangez = Z coord for Toolchange", Qt.ToolTipRole)
cnclay1.addStretch()
# Insert Variable into the Toolchange G-Code Text Box
self.tc_insert_buton = FCButton("Insert")
self.tc_insert_buton.setToolTip(
"Insert the variable in the GCode Box\n"
"surrounded by the '%' symbol."
)
cnclay1.addWidget(self.tc_insert_buton)
h_lay = QtWidgets.QHBoxLayout() h_lay = QtWidgets.QHBoxLayout()
h_lay.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) h_lay.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.custom_box.addLayout(h_lay) self.custom_box.addLayout(h_lay)

View File

@@ -14,6 +14,10 @@ CAD program, and create G-Code for Isolation routing.
- fixed the Gerber object UI layout - fixed the Gerber object UI layout
- added ability to mark individual apertures in Gerber file using the Gerber Aperture Table - added ability to mark individual apertures in Gerber file using the Gerber Aperture Table
- more modifications for the Gerber UI layout; made 'follow' an advanced Gerber option - more modifications for the Gerber UI layout; made 'follow' an advanced Gerber option
- added in Preferences a new Category: Gerber Advanced Options. For now it controls the display of Gerber Aperture Table and the "follow" attribute4
- fixed FlatCAMGerber.merge() to merge the self.apertures[ap]['solid_geometry'] too
- started to work on a new feature that allow adding a ToolChange GCode macro - GUI added both in CNCJob Selected tab and in CNCJob Preferences
- added a limited 'sort-of' Gerber Editor: it allows buffering and scaling of apertures
24.02.2019 24.02.2019

View File

@@ -105,7 +105,8 @@ G00 X{toolchangex} Y{toolchangey}
T{tool} T{tool}
M6 M6
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills}) (MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex), M0
""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
toolchangey=self.coordinate_format % (p.coords_decimals, toolchangey), toolchangey=self.coordinate_format % (p.coords_decimals, toolchangey),
toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez), toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
tool=int(p.tool), tool=int(p.tool),