Merged marius_stanciu/flatcam_beta/Beta_8.994 into Beta

Punch Gerber Tool improvements
This commit is contained in:
Marius Stanciu 2020-10-29 03:31:54 +02:00
commit db7930d359
20 changed files with 148 additions and 44 deletions

View File

@ -7,6 +7,12 @@ CHANGELOG for FlatCAM beta
=================================================
29.10.2020
- added icons in most application Tools
- updated Punch Gerber Tool such that the aperture table is updated upon clicking of the checboxes in Processed Pads Type
- updated Punch Gerber Tool: the Excellon method now takes into consideration the pads choice
28.10.2020
- a series of PEP8 corrections in the FlatCAMGeometry.py

View File

@ -1420,6 +1420,7 @@ class ThievingUI:
# ## Insert Copper Thieving
self.fill_button = QtWidgets.QPushButton(_("Insert Copper thieving"))
self.fill_button.setIcon(QtGui.QIcon(self.app.resource_location + '/copperfill32.png'))
self.fill_button.setToolTip(
_("Will add a polygon (may be split in multiple parts)\n"
"that will surround the actual Gerber traces at a certain distance.")
@ -1481,6 +1482,7 @@ class ThievingUI:
# ## Insert Robber Bar
self.rb_button = QtWidgets.QPushButton(_("Insert Robber Bar"))
self.rb_button.setIcon(QtGui.QIcon(self.app.resource_location + '/robber32.png'))
self.rb_button.setToolTip(
_("Will add a polygon with a defined thickness\n"
"that will surround the actual Gerber object\n"
@ -1560,6 +1562,7 @@ class ThievingUI:
# ## Pattern Plating Mask
self.ppm_button = QtWidgets.QPushButton(_("Generate pattern plating mask"))
self.ppm_button.setIcon(QtGui.QIcon(self.app.resource_location + '/pattern32.png'))
self.ppm_button.setToolTip(
_("Will add to the soldermask gerber geometry\n"
"the geometries of the copper thieving and/or\n"

View File

@ -428,6 +428,7 @@ class CornersUI:
# ## Insert Corner Marker
self.add_marker_button = FCButton(_("Add Marker"))
self.add_marker_button.setIcon(QtGui.QIcon(self.app.resource_location + '/corners_32.png'))
self.add_marker_button.setToolTip(
_("Will add corner markers to the selected Gerber file.")
)

View File

@ -785,6 +785,7 @@ class DsidedUI:
grid_lay3.addWidget(self.box_combo, 3, 0, 1, 2)
self.mirror_button = QtWidgets.QPushButton(_("Mirror"))
self.mirror_button.setIcon(QtGui.QIcon(self.app.resource_location + '/doubleside16.png'))
self.mirror_button.setToolTip(
_("Mirrors (flips) the specified object around \n"
"the specified axis. Does not create a new \n"
@ -921,6 +922,7 @@ class DsidedUI:
# ## Buttons
self.create_alignment_hole_button = QtWidgets.QPushButton(_("Create Excellon Object"))
self.create_alignment_hole_button.setIcon(QtGui.QIcon(self.app.resource_location + '/drill32.png'))
self.create_alignment_hole_button.setToolTip(
_("Creates an Excellon Object containing the\n"
"specified alignment holes and their mirror\n"

View File

@ -441,6 +441,7 @@ class EtchUI:
grid0.addWidget(separator_line, 22, 0, 1, 2)
self.compensate_btn = FCButton(_('Compensate'))
self.compensate_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/etch_32.png'))
self.compensate_btn.setToolTip(
_("Will increase the copper features thickness to compensate the lateral etch.")
)

View File

@ -686,6 +686,7 @@ class ExtractDrillsUI:
# Extract drills from Gerber apertures flashes (pads)
self.e_drills_button = QtWidgets.QPushButton(_("Extract Drills"))
self.e_drills_button.setIcon(QtGui.QIcon(self.app.resource_location + '/drill16.png'))
self.e_drills_button.setToolTip(
_("Extract drills from a given Gerber file.")
)

View File

@ -882,6 +882,7 @@ class FidoUI:
# ## Insert Copper Fiducial
self.add_cfid_button = QtWidgets.QPushButton(_("Add Fiducial"))
self.add_cfid_button.setIcon(QtGui.QIcon(self.app.resource_location + '/fiducials_32.png'))
self.add_cfid_button.setToolTip(
_("Will add a polygon on the copper layer to serve as fiducial.")
)

View File

@ -267,6 +267,7 @@ class InvertUI:
grid0.addWidget(separator_line, 9, 0, 1, 2)
self.invert_btn = FCButton(_('Invert Gerber'))
self.invert_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/invert32.png'))
self.invert_btn.setToolTip(
_("Will invert the Gerber object: areas that have copper\n"
"will be empty of copper and previous empty area will be\n"

View File

@ -573,6 +573,7 @@ class OptimalUI:
# GO button
self.calculate_button = FCButton(_("Find Minimum"))
self.calculate_button.setIcon(QtGui.QIcon(self.app.resource_location + '/open_excellon32.png'))
self.calculate_button.setToolTip(
_("Calculate the minimum distance between copper features,\n"
"this will allow the determination of the right tool to\n"

View File

@ -8,7 +8,8 @@
from PyQt5 import QtWidgets, QtGui, QtCore
from appTool import AppTool
from appGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection, FCComboBox
from appGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection, FCComboBox, \
FCButton, FCLabel
from camlib import grace
from copy import deepcopy
@ -639,7 +640,7 @@ class PanelizeUI:
self.layout = layout
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label = FCLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
{
@ -649,7 +650,7 @@ class PanelizeUI:
""")
self.layout.addWidget(title_label)
self.object_label = QtWidgets.QLabel('<b>%s:</b>' % _("Source Object"))
self.object_label = FCLabel('<b>%s:</b>' % _("Source Object"))
self.object_label.setToolTip(
_("Specify the type of object to be panelized\n"
"It can be of type: Gerber, Excellon or Geometry.\n"
@ -673,7 +674,7 @@ class PanelizeUI:
self.type_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
self.type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
self.type_object_label = QtWidgets.QLabel('%s:' % _("Object Type"))
self.type_object_label = FCLabel('%s:' % _("Object Type"))
form_layout_0.addRow(self.type_object_label, self.type_obj_combo)
@ -696,7 +697,7 @@ class PanelizeUI:
# Type of box Panel object
self.reference_radio = RadioSet([{'label': _('Object'), 'value': 'object'},
{'label': _('Bounding Box'), 'value': 'bbox'}])
self.box_label = QtWidgets.QLabel("<b>%s:</b>" % _("Penelization Reference"))
self.box_label = FCLabel("<b>%s:</b>" % _("Penelization Reference"))
self.box_label.setToolTip(
_("Choose the reference for panelization:\n"
"- Object = the bounding box of a different object\n"
@ -719,7 +720,7 @@ class PanelizeUI:
self.type_box_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
self.type_box_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
self.type_box_combo_label = QtWidgets.QLabel('%s:' % _("Box Type"))
self.type_box_combo_label = FCLabel('%s:' % _("Box Type"))
self.type_box_combo_label.setToolTip(
_("Specify the type of object to be used as an container for\n"
"panelization. It can be: Gerber or Geometry type.\n"
@ -745,7 +746,7 @@ class PanelizeUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
form_layout.addRow(separator_line)
panel_data_label = QtWidgets.QLabel("<b>%s:</b>" % _("Panel Data"))
panel_data_label = FCLabel("<b>%s:</b>" % _("Panel Data"))
panel_data_label.setToolTip(
_("This informations will shape the resulting panel.\n"
"The number of rows and columns will set how many\n"
@ -761,7 +762,7 @@ class PanelizeUI:
self.spacing_columns.set_range(0, 9999)
self.spacing_columns.set_precision(4)
self.spacing_columns_label = QtWidgets.QLabel('%s:' % _("Spacing cols"))
self.spacing_columns_label = FCLabel('%s:' % _("Spacing cols"))
self.spacing_columns_label.setToolTip(
_("Spacing between columns of the desired panel.\n"
"In current units.")
@ -773,7 +774,7 @@ class PanelizeUI:
self.spacing_rows.set_range(0, 9999)
self.spacing_rows.set_precision(4)
self.spacing_rows_label = QtWidgets.QLabel('%s:' % _("Spacing rows"))
self.spacing_rows_label = FCLabel('%s:' % _("Spacing rows"))
self.spacing_rows_label.setToolTip(
_("Spacing between rows of the desired panel.\n"
"In current units.")
@ -784,7 +785,7 @@ class PanelizeUI:
self.columns = FCSpinner(callback=self.confirmation_message_int)
self.columns.set_range(0, 9999)
self.columns_label = QtWidgets.QLabel('%s:' % _("Columns"))
self.columns_label = FCLabel('%s:' % _("Columns"))
self.columns_label.setToolTip(
_("Number of columns of the desired panel")
)
@ -794,7 +795,7 @@ class PanelizeUI:
self.rows = FCSpinner(callback=self.confirmation_message_int)
self.rows.set_range(0, 9999)
self.rows_label = QtWidgets.QLabel('%s:' % _("Rows"))
self.rows_label = FCLabel('%s:' % _("Rows"))
self.rows_label.setToolTip(
_("Number of rows of the desired panel")
)
@ -808,7 +809,7 @@ class PanelizeUI:
# Type of resulting Panel object
self.panel_type_radio = RadioSet([{'label': _('Gerber'), 'value': 'gerber'},
{'label': _('Geo'), 'value': 'geometry'}])
self.panel_type_label = QtWidgets.QLabel("<b>%s:</b>" % _("Panel Type"))
self.panel_type_label = FCLabel("<b>%s:</b>" % _("Panel Type"))
self.panel_type_label.setToolTip(
_("Choose the type of object for the panel object:\n"
"- Geometry\n"
@ -842,7 +843,7 @@ class PanelizeUI:
self.x_width_entry.set_precision(4)
self.x_width_entry.set_range(0, 9999)
self.x_width_lbl = QtWidgets.QLabel('%s:' % _("Width (DX)"))
self.x_width_lbl = FCLabel('%s:' % _("Width (DX)"))
self.x_width_lbl.setToolTip(
_("The width (DX) within which the panel must fit.\n"
"In current units.")
@ -853,7 +854,7 @@ class PanelizeUI:
self.y_height_entry.set_range(0, 9999)
self.y_height_entry.set_precision(4)
self.y_height_lbl = QtWidgets.QLabel('%s:' % _("Height (DY)"))
self.y_height_lbl = FCLabel('%s:' % _("Height (DY)"))
self.y_height_lbl.setToolTip(
_("The height (DY)within which the panel must fit.\n"
"In current units.")
@ -869,7 +870,8 @@ class PanelizeUI:
form_layout.addRow(separator_line)
# Buttons
self.panelize_object_button = QtWidgets.QPushButton(_("Panelize Object"))
self.panelize_object_button = FCButton(_("Panelize Object"))
self.panelize_object_button.setIcon(QtGui.QIcon(self.app.resource_location + '/panelize16.png'))
self.panelize_object_button.setToolTip(
_("Panelize the specified object around the specified box.\n"
"In other words it creates multiple copies of the source object,\n"
@ -886,7 +888,7 @@ class PanelizeUI:
self.layout.addStretch()
# ## Reset Tool
self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
self.reset_button = FCButton(_("Reset Tool"))
self.reset_button.setIcon(QtGui.QIcon(self.app.resource_location + '/reset32.png'))
self.reset_button.setToolTip(
_("Will reset the tool parameters.")

View File

@ -13,6 +13,7 @@ from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCComboBox
from copy import deepcopy
import logging
from shapely.geometry import MultiPolygon, Point
from shapely.ops import unary_union
import gettext
import appTranslation as fcTranslate
@ -74,6 +75,12 @@ class ToolPunchGerber(AppTool):
self.ui.other_ring_entry.setDisabled(False) if state else self.ui.other_ring_entry.setDisabled(True)
)
self.ui.circular_cb.stateChanged.connect(self.build_tool_ui)
self.ui.oblong_cb.stateChanged.connect(self.build_tool_ui)
self.ui.square_cb.stateChanged.connect(self.build_tool_ui)
self.ui.rectangular_cb.stateChanged.connect(self.build_tool_ui)
self.ui.other_cb.stateChanged.connect(self.build_tool_ui)
def run(self, toggle=True):
self.app.defaults.report_usage("ToolPunchGerber()")
@ -131,6 +138,10 @@ class ToolPunchGerber(AppTool):
self.ui.factor_entry.set_value(float(self.app.defaults["tools_punch_hole_prop_factor"]))
def build_tool_ui(self):
# reset table
self.ui.apertures_table.clear()
self.ui.apertures_table.setRowCount(0)
# get the Gerber file who is the source of the punched Gerber
selection_index = self.ui.gerber_object_combo.currentIndex()
model_index = self.app.collection.index(selection_index, 0, self.ui.gerber_object_combo.rootModelIndex())
@ -144,17 +155,54 @@ class ToolPunchGerber(AppTool):
# no object loaded
sorted_apertures = []
n = len(sorted_apertures)
# n = len(sorted_apertures)
# calculate how many rows to add
n = 0
for ap_code in sorted_apertures:
ap_code = str(ap_code)
ap_type = obj.apertures[ap_code]['type']
if ap_type == 'C' and self.ui.circular_cb.get_value() is True:
n += 1
if ap_type == 'R':
if self.ui.square_cb.get_value() is True:
n += 1
elif self.ui.rectangular_cb.get_value() is True:
n += 1
if ap_type == 'O' and self.ui.oblong_cb.get_value() is True:
n += 1
if ap_type not in ['C', 'R', 'O'] and self.ui.other_cb.get_value() is True:
n += 1
self.ui.apertures_table.setRowCount(n)
row = 0
for ap_code in sorted_apertures:
ap_code = str(ap_code)
ap_type = obj.apertures[ap_code]['type']
if ap_type == 'C':
if self.ui.circular_cb.get_value() is False:
continue
elif ap_type == 'R':
if self.ui.square_cb.get_value() is True:
pass
elif self.ui.rectangular_cb.get_value() is True:
pass
else:
continue
elif ap_type == 'O':
if self.ui.oblong_cb.get_value() is False:
continue
elif self.ui.other_cb.get_value() is True:
pass
else:
continue
ap_code_item = QtWidgets.QTableWidgetItem(ap_code)
ap_code_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
ap_type_item = QtWidgets.QTableWidgetItem(str(obj.apertures[ap_code]['type']))
ap_type_item = QtWidgets.QTableWidgetItem(str(ap_type))
ap_type_item.setFlags(QtCore.Qt.ItemIsEnabled)
try:
@ -174,6 +222,7 @@ class ToolPunchGerber(AppTool):
# increment row
row += 1
self.ui.apertures_table.selectColumn(0)
self.ui.apertures_table.resizeColumnsToContents()
self.ui.apertures_table.resizeRowsToContents()
@ -283,15 +332,45 @@ class ToolPunchGerber(AppTool):
for opt in grb_obj.options:
new_options[opt] = deepcopy(grb_obj.options[opt])
# selected codes in thre apertures UI table
sel_apid = []
for it in self.ui.apertures_table.selectedItems():
sel_apid.append(it.text())
# this is the punching geometry
exc_solid_geometry = MultiPolygon(exc_obj.solid_geometry)
if isinstance(grb_obj.solid_geometry, list):
grb_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
else:
grb_solid_geometry = grb_obj.solid_geometry
# create the punched Gerber solid_geometry
punched_solid_geometry = grb_solid_geometry.difference(exc_solid_geometry)
# this is the target geometry
# if isinstance(grb_obj.solid_geometry, list):
# grb_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
# else:
# grb_solid_geometry = grb_obj.solid_geometry
grb_solid_geometry = []
target_geometry = []
for apid in grb_obj.apertures:
if 'geometry' in grb_obj.apertures[apid]:
for el_geo in grb_obj.apertures[apid]['geometry']:
if 'solid' in el_geo:
if apid in sel_apid:
target_geometry.append(el_geo['solid'])
else:
grb_solid_geometry.append(el_geo['solid'])
target_geometry = MultiPolygon(target_geometry)
# create the punched Gerber solid_geometry
punched_target_geometry = target_geometry.difference(exc_solid_geometry)
# add together the punched geometry and the not affected geometry
punched_solid_geometry = []
try:
for geo in punched_target_geometry.geoms:
punched_solid_geometry.append(geo)
except AttributeError:
punched_solid_geometry.append(punched_target_geometry)
for geo in grb_solid_geometry:
punched_solid_geometry.append(geo)
punched_solid_geometry = unary_union(punched_solid_geometry)
# update the gerber apertures to include the clear geometry so it can be exported successfully
new_apertures = deepcopy(grb_obj.apertures)
@ -304,27 +383,28 @@ class ToolPunchGerber(AppTool):
holes_apertures = {}
for apid, val in new_apertures_items:
for elem in val['geometry']:
# make it work only for Gerber Flashes who are Points in 'follow'
if 'solid' in elem and isinstance(elem['follow'], Point):
for tool in exc_obj.tools:
clear_apid_size = exc_obj.tools[tool]['tooldia']
if apid in sel_apid:
for elem in val['geometry']:
# make it work only for Gerber Flashes who are Points in 'follow'
if 'solid' in elem and isinstance(elem['follow'], Point):
for tool in exc_obj.tools:
clear_apid_size = exc_obj.tools[tool]['tooldia']
if 'drills' in exc_obj.tools[tool]['drills']:
for drill_pt in exc_obj.tools[tool]['drills']:
# since there may be drills that do not drill into a pad we test only for
# drills in a pad
if drill_pt.within(elem['solid']):
geo_elem = {}
geo_elem['clear'] = drill_pt
if 'drills' in exc_obj.tools[tool]:
for drill_pt in exc_obj.tools[tool]['drills']:
# since there may be drills that do not drill into a pad we test only for
# drills in a pad
if drill_pt.within(elem['solid']):
geo_elem = {}
geo_elem['clear'] = drill_pt
if clear_apid_size not in holes_apertures:
holes_apertures[clear_apid_size] = {}
holes_apertures[clear_apid_size]['type'] = 'C'
holes_apertures[clear_apid_size]['size'] = clear_apid_size
holes_apertures[clear_apid_size]['geometry'] = []
if clear_apid_size not in holes_apertures:
holes_apertures[clear_apid_size] = {}
holes_apertures[clear_apid_size]['type'] = 'C'
holes_apertures[clear_apid_size]['size'] = clear_apid_size
holes_apertures[clear_apid_size]['geometry'] = []
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
# add the clear geometry to new apertures; it's easier than to test if there are apertures with the same
# size and add there the clear geometry
@ -932,8 +1012,8 @@ class PunchUI:
[
{'label': _('Excellon'), 'value': 'exc'},
{'label': _("Fixed Diameter"), 'value': 'fixed'},
{'label': _("Fixed Annular Ring"), 'value': 'ring'},
{'label': _("Proportional"), 'value': 'prop'}
{'label': _("Proportional"), 'value': 'prop'},
{'label': _("Fixed Annular Ring"), 'value': 'ring'}
],
orientation='vertical',
stretch=False)
@ -1094,6 +1174,7 @@ class PunchUI:
# Buttons
self.punch_object_button = QtWidgets.QPushButton(_("Punch Gerber"))
self.punch_object_button.setIcon(QtGui.QIcon(self.app.resource_location + '/punch32.png'))
self.punch_object_button.setToolTip(
_("Create a Gerber object from the selected object, within\n"
"the specified box.")

View File

@ -892,6 +892,7 @@ class QRcodeUI:
# ## Insert QRCode
self.qrcode_button = QtWidgets.QPushButton(_("Insert QRCode"))
self.qrcode_button.setIcon(QtGui.QIcon(self.app.resource_location + '/qrcode32.png'))
self.qrcode_button.setToolTip(
_("Create the QRCode object.")
)

View File

@ -1601,6 +1601,7 @@ class RulesUI:
# hlay_2.addStretch()
self.run_button = FCButton(_("Run Rules Check"))
self.run_button.setIcon(QtGui.QIcon(self.app.resource_location + '/rules32.png'))
self.run_button.setToolTip(
_("Panelize the specified object around the specified box.\n"
"In other words it creates multiple copies of the source object,\n"

View File

@ -704,6 +704,7 @@ class SubUI:
grid0.addWidget(self.sub_gerber_combo, 4, 1)
self.intersect_btn = FCButton(_('Subtract Gerber'))
self.intersect_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/subtract_btn32.png'))
self.intersect_btn.setToolTip(
_("Will remove the area occupied by the subtractor\n"
"Gerber from the Target Gerber.\n"
@ -761,6 +762,7 @@ class SubUI:
grid0.addWidget(self.close_paths_cb, 16, 0, 1, 2)
self.intersect_geo_btn = FCButton(_('Subtract Geometry'))
self.intersect_geo_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/subtract_btn32.png'))
self.intersect_geo_btn.setToolTip(
_("Will remove the area occupied by the subtractor\n"
"Geometry from the Target Geometry.")

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 986 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B