- upgraded the punch Gerber Tool

- updated the Turkish translation strings (by Mehmet Kaya)
This commit is contained in:
Marius Stanciu
2020-10-28 19:12:15 +02:00
committed by Marius
parent d1368425f1
commit 735a20242a
5 changed files with 413 additions and 299 deletions

View File

@@ -8,7 +8,7 @@
from PyQt5 import QtCore, QtWidgets, QtGui
from appTool import AppTool
from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCComboBox
from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCComboBox, FCTable
from copy import deepcopy
import logging
@@ -45,6 +45,8 @@ class ToolPunchGerber(AppTool):
self.ui.reset_button.clicked.connect(self.set_tool_ui)
self.ui.punch_object_button.clicked.connect(self.on_generate_object)
self.ui.gerber_object_combo.currentIndexChanged.connect(self.build_tool_ui)
self.ui.circular_cb.stateChanged.connect(
lambda state:
self.ui.circular_ring_entry.setDisabled(False) if state else
@@ -97,6 +99,7 @@ class ToolPunchGerber(AppTool):
AppTool.run(self)
self.set_tool_ui()
self.build_tool_ui()
self.app.ui.notebook.setTabText(2, _("Punch Tool"))
@@ -106,6 +109,7 @@ class ToolPunchGerber(AppTool):
def set_tool_ui(self):
self.reset_fields()
self.ui_disconnect()
self.ui_connect()
self.ui.method_punch.set_value(self.app.defaults["tools_punch_hole_type"])
self.ui.select_all_cb.set_value(False)
@@ -126,6 +130,69 @@ class ToolPunchGerber(AppTool):
self.ui.factor_entry.set_value(float(self.app.defaults["tools_punch_hole_prop_factor"]))
def build_tool_ui(self):
# 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())
obj = None
try:
obj = model_index.internalPointer().obj
sort = [int(k) for k in obj.apertures.keys()]
sorted_apertures = sorted(sort)
except Exception:
# no object loaded
sorted_apertures = []
n = len(sorted_apertures)
self.ui.apertures_table.setRowCount(n)
row = 0
for ap_code in sorted_apertures:
ap_code = str(ap_code)
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.setFlags(QtCore.Qt.ItemIsEnabled)
try:
if obj.apertures[ap_code]['size'] is not None:
size_val = self.app.dec_format(float(obj.apertures[ap_code]['size']), self.decimals)
ap_size_item = QtWidgets.QTableWidgetItem(str(size_val))
else:
ap_size_item = QtWidgets.QTableWidgetItem('')
except KeyError:
ap_size_item = QtWidgets.QTableWidgetItem('')
ap_size_item.setFlags(QtCore.Qt.ItemIsEnabled)
self.ui.apertures_table.setItem(row, 0, ap_code_item) # Aperture Code
self.ui.apertures_table.setItem(row, 1, ap_type_item) # Aperture Type
self.ui.apertures_table.setItem(row, 2, ap_size_item) # Aperture Dimensions
# increment row
row += 1
self.ui.apertures_table.resizeColumnsToContents()
self.ui.apertures_table.resizeRowsToContents()
vertical_header = self.ui.apertures_table.verticalHeader()
vertical_header.hide()
# self.ui.apertures_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
horizontal_header = self.ui.apertures_table.horizontalHeader()
horizontal_header.setMinimumSectionSize(10)
horizontal_header.setDefaultSectionSize(70)
horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
self.ui.apertures_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.ui.apertures_table.setSortingEnabled(False)
# self.ui.apertures_table.setMinimumHeight(self.ui.apertures_table.getHeight())
# self.ui.apertures_table.setMaximumHeight(self.ui.apertures_table.getHeight())
def on_select_all(self, state):
self.ui_disconnect()
if state:
@@ -143,29 +210,29 @@ class ToolPunchGerber(AppTool):
self.ui_connect()
def on_method(self, val):
self.ui.exc_label.setEnabled(False)
self.ui.exc_combo.setEnabled(False)
self.ui.fixed_label.setEnabled(False)
self.ui.dia_label.setEnabled(False)
self.ui.dia_entry.setEnabled(False)
self.ui.ring_frame.setEnabled(False)
self.ui.prop_label.setEnabled(False)
self.ui.factor_label.setEnabled(False)
self.ui.factor_entry.setEnabled(False)
self.ui.exc_label.hide()
self.ui.exc_combo.hide()
self.ui.fixed_label.hide()
self.ui.dia_label.hide()
self.ui.dia_entry.hide()
self.ui.ring_frame.hide()
self.ui.prop_label.hide()
self.ui.factor_label.hide()
self.ui.factor_entry.hide()
if val == 'exc':
self.ui.exc_label.setEnabled(True)
self.ui.exc_combo.setEnabled(True)
self.ui.exc_label.show()
self.ui.exc_combo.show()
elif val == 'fixed':
self.ui.fixed_label.setEnabled(True)
self.ui.dia_label.setEnabled(True)
self.ui.dia_entry.setEnabled(True)
self.ui.fixed_label.show()
self.ui.dia_label.show()
self.ui.dia_entry.show()
elif val == 'ring':
self.ui.ring_frame.setEnabled(True)
self.ui.ring_frame.show()
elif val == 'prop':
self.ui.prop_label.setEnabled(True)
self.ui.factor_label.setEnabled(True)
self.ui.factor_entry.setEnabled(True)
self.ui.prop_label.show()
self.ui.factor_label.show()
self.ui.factor_entry.show()
def ui_connect(self):
self.ui.select_all_cb.stateChanged.connect(self.on_select_all)
@@ -192,97 +259,114 @@ class ToolPunchGerber(AppTool):
outname = name + "_punched"
punch_method = self.ui.method_punch.get_value()
if punch_method == 'exc':
self.on_excellon_method(grb_obj, outname)
elif punch_method == 'fixed':
self.on_fixed_method(grb_obj, outname)
elif punch_method == 'ring':
self.on_ring_method(grb_obj, outname)
elif punch_method == 'prop':
self.on_proportional_method(grb_obj, outname)
def on_excellon_method(self, grb_obj, outname):
# get the Excellon file whose geometry will create the punch holes
selection_index = self.ui.exc_combo.currentIndex()
model_index = self.app.collection.index(selection_index, 0, self.ui.exc_combo.rootModelIndex())
try:
exc_obj = model_index.internalPointer().obj
except Exception:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ..."))
return
new_options = {}
for opt in grb_obj.options:
new_options[opt] = deepcopy(grb_obj.options[opt])
if punch_method == 'exc':
# 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
# get the Excellon file whose geometry will create the punch holes
selection_index = self.ui.exc_combo.currentIndex()
model_index = self.app.collection.index(selection_index, 0, self.ui.exc_combo.rootModelIndex())
# create the punched Gerber solid_geometry
punched_solid_geometry = grb_solid_geometry.difference(exc_solid_geometry)
try:
exc_obj = model_index.internalPointer().obj
except Exception:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ..."))
return
# update the gerber apertures to include the clear geometry so it can be exported successfully
new_apertures = deepcopy(grb_obj.apertures)
new_apertures_items = new_apertures.items()
# 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
# find maximum aperture id
new_apid = max([int(x) for x, __ in new_apertures_items])
# create the punched Gerber solid_geometry
punched_solid_geometry = grb_solid_geometry.difference(exc_solid_geometry)
# store here the clear geometry, the key is the drill size
holes_apertures = {}
# update the gerber apertures to include the clear geometry so it can be exported successfully
new_apertures = deepcopy(grb_obj.apertures)
new_apertures_items = new_apertures.items()
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']
# find maximum aperture id
new_apid = max([int(x) for x, __ in new_apertures_items])
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
# store here the clear geometry, the key is the drill size
holes_apertures = {}
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'] = []
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']
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
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
# 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
for hole_size, ap_val in holes_apertures.items():
new_apid += 1
new_apertures[str(new_apid)] = deepcopy(ap_val)
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'] = []
def init_func(new_obj, app_obj):
new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
new_obj.apertures = deepcopy(new_apertures)
# 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
for hole_size, ap_val in holes_apertures.items():
new_apid += 1
new_apertures[str(new_apid)] = deepcopy(ap_val)
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None,
local_use=new_obj, use_thread=False)
def init_func(new_obj, app_obj):
new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
self.app.app_obj.new_object('gerber', outname, init_func)
new_obj.apertures = deepcopy(new_apertures)
def on_fixed_method(self, grb_obj, outname):
punch_size = float(self.ui.dia_entry.get_value())
if punch_size == 0.0:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("The value of the fixed diameter is 0.0. Aborting."))
return 'fail'
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None,
local_use=new_obj, use_thread=False)
fail_msg = _("Could not generate punched hole Gerber because the punch hole size is bigger than"
" some of the apertures in the Gerber object.")
self.app.app_obj.new_object('gerber', outname, init_func)
elif punch_method == 'fixed':
punch_size = float(self.ui.dia_entry.get_value())
new_options = {}
for opt in grb_obj.options:
new_options[opt] = deepcopy(grb_obj.options[opt])
if punch_size == 0.0:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("The value of the fixed diameter is 0.0. Aborting."))
return 'fail'
# selected codes in thre apertures UI table
sel_apid = []
for it in self.ui.apertures_table.selectedItems():
sel_apid.append(it.text())
fail_msg = _("Could not generate punched hole Gerber because the punch hole size is bigger than"
" some of the apertures in the Gerber object.")
punching_geo = []
for apid in grb_obj.apertures:
punching_geo = []
for apid in grb_obj.apertures:
if apid in sel_apid:
if grb_obj.apertures[apid]['type'] == 'C' and self.ui.circular_cb.get_value():
for elem in grb_obj.apertures[apid]['geometry']:
if 'follow' in elem:
@@ -332,103 +416,112 @@ class ToolPunchGerber(AppTool):
return 'fail'
punching_geo.append(elem['follow'].buffer(punch_size / 2))
punching_geo = MultiPolygon(punching_geo)
if isinstance(grb_obj.solid_geometry, list):
temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
else:
temp_solid_geometry = grb_obj.solid_geometry
punched_solid_geometry = temp_solid_geometry.difference(punching_geo)
punching_geo = MultiPolygon(punching_geo)
if isinstance(grb_obj.solid_geometry, list):
temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
else:
temp_solid_geometry = grb_obj.solid_geometry
punched_solid_geometry = temp_solid_geometry.difference(punching_geo)
if punched_solid_geometry == temp_solid_geometry:
self.app.inform.emit('[WARNING_NOTCL] %s' %
_("Could not generate punched hole Gerber because the newly created object "
"geometry is the same as the one in the source object geometry..."))
return 'fail'
if punched_solid_geometry == temp_solid_geometry:
self.app.inform.emit('[WARNING_NOTCL] %s' %
_("Could not generate punched hole Gerber because the newly created object "
"geometry is the same as the one in the source object geometry..."))
return 'fail'
# update the gerber apertures to include the clear geometry so it can be exported successfully
new_apertures = deepcopy(grb_obj.apertures)
new_apertures_items = new_apertures.items()
# update the gerber apertures to include the clear geometry so it can be exported successfully
new_apertures = deepcopy(grb_obj.apertures)
new_apertures_items = new_apertures.items()
# find maximum aperture id
new_apid = max([int(x) for x, __ in new_apertures_items])
# find maximum aperture id
new_apid = max([int(x) for x, __ in new_apertures_items])
# store here the clear geometry, the key is the drill size
holes_apertures = {}
# store here the clear geometry, the key is the drill size
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 geo in punching_geo:
clear_apid_size = punch_size
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 geo in punching_geo:
clear_apid_size = punch_size
# since there may be drills that do not drill into a pad we test only for drills in a pad
if geo.within(elem['solid']):
geo_elem = {}
geo_elem['clear'] = geo.centroid
# since there may be drills that do not drill into a pad we test only for drills in a pad
if geo.within(elem['solid']):
geo_elem = {}
geo_elem['clear'] = geo.centroid
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
for hole_size, ap_val in holes_apertures.items():
new_apid += 1
new_apertures[str(new_apid)] = deepcopy(ap_val)
# 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
for hole_size, ap_val in holes_apertures.items():
new_apid += 1
new_apertures[str(new_apid)] = deepcopy(ap_val)
def init_func(new_obj, app_obj):
new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
def init_func(new_obj, app_obj):
new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
new_obj.apertures = deepcopy(new_apertures)
new_obj.apertures = deepcopy(new_apertures)
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None,
local_use=new_obj, use_thread=False)
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None,
local_use=new_obj, use_thread=False)
self.app.app_obj.new_object('gerber', outname, init_func)
elif punch_method == 'ring':
circ_r_val = self.ui.circular_ring_entry.get_value()
oblong_r_val = self.ui.oblong_ring_entry.get_value()
square_r_val = self.ui.square_ring_entry.get_value()
rect_r_val = self.ui.rectangular_ring_entry.get_value()
other_r_val = self.ui.other_ring_entry.get_value()
self.app.app_obj.new_object('gerber', outname, init_func)
dia = None
def on_ring_method(self, grb_obj, outname):
circ_r_val = self.ui.circular_ring_entry.get_value()
oblong_r_val = self.ui.oblong_ring_entry.get_value()
square_r_val = self.ui.square_ring_entry.get_value()
rect_r_val = self.ui.rectangular_ring_entry.get_value()
other_r_val = self.ui.other_ring_entry.get_value()
dia = None
if isinstance(grb_obj.solid_geometry, list):
temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
else:
temp_solid_geometry = grb_obj.solid_geometry
new_options = {}
for opt in grb_obj.options:
new_options[opt] = deepcopy(grb_obj.options[opt])
punched_solid_geometry = temp_solid_geometry
if isinstance(grb_obj.solid_geometry, list):
temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
else:
temp_solid_geometry = grb_obj.solid_geometry
new_apertures = deepcopy(grb_obj.apertures)
new_apertures_items = new_apertures.items()
punched_solid_geometry = temp_solid_geometry
# find maximum aperture id
new_apid = max([int(x) for x, __ in new_apertures_items])
new_apertures = deepcopy(grb_obj.apertures)
new_apertures_items = new_apertures.items()
# store here the clear geometry, the key is the new aperture size
holes_apertures = {}
# find maximum aperture id
new_apid = max([int(x) for x, __ in new_apertures_items])
for apid, apid_value in grb_obj.apertures.items():
ap_type = apid_value['type']
punching_geo = []
# selected codes in the apertures UI table
sel_apid = []
for it in self.ui.apertures_table.selectedItems():
sel_apid.append(it.text())
# store here the clear geometry, the key is the new aperture size
holes_apertures = {}
for apid, apid_value in grb_obj.apertures.items():
ap_type = apid_value['type']
punching_geo = []
if apid in sel_apid:
if ap_type == 'C' and self.ui.circular_cb.get_value():
dia = float(apid_value['size']) - (2 * circ_r_val)
for elem in apid_value['geometry']:
if 'follow' in elem and isinstance(elem['follow'], Point):
punching_geo.append(elem['follow'].buffer(dia / 2))
elif ap_type == 'O' and self.ui.oblong_cb.get_value():
width = float(apid_value['width'])
height = float(apid_value['height'])
@@ -442,7 +535,6 @@ class ToolPunchGerber(AppTool):
if 'follow' in elem:
if isinstance(elem['follow'], Point):
punching_geo.append(elem['follow'].buffer(dia / 2))
elif ap_type == 'R':
width = float(apid_value['width'])
height = float(apid_value['height'])
@@ -466,7 +558,6 @@ class ToolPunchGerber(AppTool):
if 'follow' in elem:
if isinstance(elem['follow'], Point):
punching_geo.append(elem['follow'].buffer(dia / 2))
elif self.ui.other_cb.get_value():
try:
dia = float(apid_value['size']) - (2 * other_r_val)
@@ -486,88 +577,95 @@ class ToolPunchGerber(AppTool):
if isinstance(elem['follow'], Point):
punching_geo.append(elem['follow'].buffer(dia / 2))
# if dia is None then none of the above applied so we skip the following
if dia is None:
continue
# if dia is None then none of the above applied so we skip the following
if dia is None:
continue
punching_geo = MultiPolygon(punching_geo)
punching_geo = MultiPolygon(punching_geo)
if punching_geo is None or punching_geo.is_empty:
continue
if punching_geo is None or punching_geo.is_empty:
continue
punched_solid_geometry = punched_solid_geometry.difference(punching_geo)
punched_solid_geometry = punched_solid_geometry.difference(punching_geo)
# update the gerber apertures to include the clear geometry so it can be exported successfully
for elem in apid_value['geometry']:
# make it work only for Gerber Flashes who are Points in 'follow'
if 'solid' in elem and isinstance(elem['follow'], Point):
clear_apid_size = dia
for geo in punching_geo:
# update the gerber apertures to include the clear geometry so it can be exported successfully
for elem in apid_value['geometry']:
# make it work only for Gerber Flashes who are Points in 'follow'
if 'solid' in elem and isinstance(elem['follow'], Point):
clear_apid_size = dia
for geo in punching_geo:
# since there may be drills that do not drill into a pad we test only for geos in a pad
if geo.within(elem['solid']):
geo_elem = {}
geo_elem['clear'] = geo.centroid
# since there may be drills that do not drill into a pad we test only for geos in a pad
if geo.within(elem['solid']):
geo_elem = {}
geo_elem['clear'] = geo.centroid
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
for hole_size, ap_val in holes_apertures.items():
new_apid += 1
new_apertures[str(new_apid)] = deepcopy(ap_val)
# 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
for hole_size, ap_val in holes_apertures.items():
new_apid += 1
new_apertures[str(new_apid)] = deepcopy(ap_val)
def init_func(new_obj, app_obj):
new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
def init_func(new_obj, app_obj):
new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
new_obj.apertures = deepcopy(new_apertures)
new_obj.apertures = deepcopy(new_apertures)
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None,
local_use=new_obj, use_thread=False)
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None,
local_use=new_obj, use_thread=False)
self.app.app_obj.new_object('gerber', outname, init_func)
self.app.app_obj.new_object('gerber', outname, init_func)
elif punch_method == 'prop':
prop_factor = self.ui.factor_entry.get_value() / 100.0
def on_proportional_method(self, grb_obj, outname):
prop_factor = self.ui.factor_entry.get_value() / 100.0
dia = None
new_options = {}
for opt in grb_obj.options:
new_options[opt] = deepcopy(grb_obj.options[opt])
dia = None
if isinstance(grb_obj.solid_geometry, list):
temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
else:
temp_solid_geometry = grb_obj.solid_geometry
if isinstance(grb_obj.solid_geometry, list):
temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
else:
temp_solid_geometry = grb_obj.solid_geometry
punched_solid_geometry = temp_solid_geometry
punched_solid_geometry = temp_solid_geometry
new_apertures = deepcopy(grb_obj.apertures)
new_apertures_items = new_apertures.items()
new_apertures = deepcopy(grb_obj.apertures)
new_apertures_items = new_apertures.items()
# find maximum aperture id
new_apid = max([int(x) for x, __ in new_apertures_items])
# find maximum aperture id
new_apid = max([int(x) for x, __ in new_apertures_items])
# selected codes in the apertures UI table
sel_apid = []
for it in self.ui.apertures_table.selectedItems():
sel_apid.append(it.text())
# store here the clear geometry, the key is the new aperture size
holes_apertures = {}
# store here the clear geometry, the key is the new aperture size
holes_apertures = {}
for apid, apid_value in grb_obj.apertures.items():
ap_type = apid_value['type']
punching_geo = []
for apid, apid_value in grb_obj.apertures.items():
ap_type = apid_value['type']
punching_geo = []
if apid in sel_apid:
if ap_type == 'C' and self.ui.circular_cb.get_value():
dia = float(apid_value['size']) * prop_factor
for elem in apid_value['geometry']:
if 'follow' in elem and isinstance(elem['follow'], Point):
punching_geo.append(elem['follow'].buffer(dia / 2))
elif ap_type == 'O' and self.ui.oblong_cb.get_value():
width = float(apid_value['width'])
height = float(apid_value['height'])
@@ -581,7 +679,6 @@ class ToolPunchGerber(AppTool):
if 'follow' in elem:
if isinstance(elem['follow'], Point):
punching_geo.append(elem['follow'].buffer(dia / 2))
elif ap_type == 'R':
width = float(apid_value['width'])
height = float(apid_value['height'])
@@ -605,7 +702,6 @@ class ToolPunchGerber(AppTool):
if 'follow' in elem:
if isinstance(elem['follow'], Point):
punching_geo.append(elem['follow'].buffer(dia / 2))
elif self.ui.other_cb.get_value():
try:
dia = float(apid_value['size']) * prop_factor
@@ -625,56 +721,56 @@ class ToolPunchGerber(AppTool):
if isinstance(elem['follow'], Point):
punching_geo.append(elem['follow'].buffer(dia / 2))
# if dia is None then none of the above applied so we skip the following
if dia is None:
continue
# if dia is None then none of the above applied so we skip the following
if dia is None:
continue
punching_geo = MultiPolygon(punching_geo)
punching_geo = MultiPolygon(punching_geo)
if punching_geo is None or punching_geo.is_empty:
continue
if punching_geo is None or punching_geo.is_empty:
continue
punched_solid_geometry = punched_solid_geometry.difference(punching_geo)
punched_solid_geometry = punched_solid_geometry.difference(punching_geo)
# update the gerber apertures to include the clear geometry so it can be exported successfully
for elem in apid_value['geometry']:
# make it work only for Gerber Flashes who are Points in 'follow'
if 'solid' in elem and isinstance(elem['follow'], Point):
clear_apid_size = dia
for geo in punching_geo:
# update the gerber apertures to include the clear geometry so it can be exported successfully
for elem in apid_value['geometry']:
# make it work only for Gerber Flashes who are Points in 'follow'
if 'solid' in elem and isinstance(elem['follow'], Point):
clear_apid_size = dia
for geo in punching_geo:
# since there may be drills that do not drill into a pad we test only for geos in a pad
if geo.within(elem['solid']):
geo_elem = {}
geo_elem['clear'] = geo.centroid
# since there may be drills that do not drill into a pad we test only for geos in a pad
if geo.within(elem['solid']):
geo_elem = {}
geo_elem['clear'] = geo.centroid
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
for hole_size, ap_val in holes_apertures.items():
new_apid += 1
new_apertures[str(new_apid)] = deepcopy(ap_val)
# 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
for hole_size, ap_val in holes_apertures.items():
new_apid += 1
new_apertures[str(new_apid)] = deepcopy(ap_val)
def init_func(new_obj, app_obj):
new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
def init_func(new_obj, app_obj):
new_obj.options.update(new_options)
new_obj.options['name'] = outname
new_obj.fill_color = deepcopy(grb_obj.fill_color)
new_obj.outline_color = deepcopy(grb_obj.outline_color)
new_obj.apertures = deepcopy(new_apertures)
new_obj.apertures = deepcopy(new_apertures)
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None,
local_use=new_obj, use_thread=False)
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
new_obj.source_file = self.app.f_handlers.export_gerber(obj_name=outname, filename=None,
local_use=new_obj, use_thread=False)
self.app.app_obj.new_object('gerber', outname, init_func)
self.app.app_obj.new_object('gerber', outname, init_func)
def reset_fields(self):
self.ui.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
@@ -738,9 +834,18 @@ class PunchUI:
grid_lay.addWidget(self.padt_label, 3, 0, 1, 2)
pad_all_grid = QtWidgets.QGridLayout()
pad_all_grid.setColumnStretch(0, 0)
pad_all_grid.setColumnStretch(1, 1)
grid_lay.addLayout(pad_all_grid, 5, 0, 1, 2)
pad_grid = QtWidgets.QGridLayout()
pad_grid.setColumnStretch(0, 0)
pad_all_grid.addLayout(pad_grid, 0, 0)
# Select all
self.select_all_cb = FCCheckBox('%s' % _("ALL"))
grid_lay.addWidget(self.select_all_cb)
pad_grid.addWidget(self.select_all_cb, 0, 0)
# Circular Aperture Selection
self.circular_cb = FCCheckBox('%s' % _("Circular"))
@@ -748,7 +853,7 @@ class PunchUI:
_("Process Circular Pads.")
)
grid_lay.addWidget(self.circular_cb, 5, 0, 1, 2)
pad_grid.addWidget(self.circular_cb, 1, 0)
# Oblong Aperture Selection
self.oblong_cb = FCCheckBox('%s' % _("Oblong"))
@@ -756,7 +861,7 @@ class PunchUI:
_("Process Oblong Pads.")
)
grid_lay.addWidget(self.oblong_cb, 6, 0, 1, 2)
pad_grid.addWidget(self.oblong_cb, 2, 0)
# Square Aperture Selection
self.square_cb = FCCheckBox('%s' % _("Square"))
@@ -764,7 +869,7 @@ class PunchUI:
_("Process Square Pads.")
)
grid_lay.addWidget(self.square_cb, 7, 0, 1, 2)
pad_grid.addWidget(self.square_cb, 3, 0)
# Rectangular Aperture Selection
self.rectangular_cb = FCCheckBox('%s' % _("Rectangular"))
@@ -772,7 +877,7 @@ class PunchUI:
_("Process Rectangular Pads.")
)
grid_lay.addWidget(self.rectangular_cb, 8, 0, 1, 2)
pad_grid.addWidget(self.rectangular_cb, 4, 0)
# Others type of Apertures Selection
self.other_cb = FCCheckBox('%s' % _("Others"))
@@ -780,7 +885,29 @@ class PunchUI:
_("Process pads not in the categories above.")
)
grid_lay.addWidget(self.other_cb, 9, 0, 1, 2)
pad_grid.addWidget(self.other_cb, 5, 0)
# Aperture Table
self.apertures_table = FCTable()
pad_all_grid.addWidget(self.apertures_table, 0, 1)
self.apertures_table.setColumnCount(3)
self.apertures_table.setHorizontalHeaderLabels([_('Code'), _('Type'), _('Size')])
self.apertures_table.setSortingEnabled(False)
self.apertures_table.setRowCount(0)
self.apertures_table.resizeColumnsToContents()
self.apertures_table.resizeRowsToContents()
self.apertures_table.horizontalHeaderItem(0).setToolTip(
_("Aperture Code"))
self.apertures_table.horizontalHeaderItem(1).setToolTip(
_("Type of aperture: circular, rectangle, macros etc"))
self.apertures_table.horizontalHeaderItem(2).setToolTip(
_("Aperture Size:"))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred)
self.apertures_table.setSizePolicy(sizePolicy)
self.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
@@ -832,11 +959,6 @@ class PunchUI:
grid0.addWidget(self.exc_label, 3, 0, 1, 2)
grid0.addWidget(self.exc_combo, 4, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 5, 0, 1, 2)
# Fixed Dia
self.fixed_label = QtWidgets.QLabel('<b>%s</b>' % _("Fixed Diameter"))
grid0.addWidget(self.fixed_label, 6, 0, 1, 2)
@@ -854,11 +976,9 @@ class PunchUI:
grid0.addWidget(self.dia_label, 8, 0)
grid0.addWidget(self.dia_entry, 8, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 9, 0, 1, 2)
# #############################################################################################################
# RING FRAME
# #############################################################################################################
self.ring_frame = QtWidgets.QFrame()
self.ring_frame.setContentsMargins(0, 0, 0, 0)
grid0.addWidget(self.ring_frame, 10, 0, 1, 2)
@@ -946,11 +1066,7 @@ class PunchUI:
self.grid1.addWidget(self.other_ring_label, 7, 0)
self.grid1.addWidget(self.other_ring_entry, 7, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 11, 0, 1, 2)
# #############################################################################################################
# Proportional value
self.prop_label = QtWidgets.QLabel('<b>%s</b>' % _("Proportional Diameter"))
@@ -1012,10 +1128,10 @@ class PunchUI:
self.rectangular_ring_entry.setEnabled(False)
self.other_ring_entry.setEnabled(False)
self.dia_entry.setDisabled(True)
self.dia_label.setDisabled(True)
self.factor_label.setDisabled(True)
self.factor_entry.setDisabled(True)
self.dia_entry.hide()
self.dia_label.hide()
self.factor_label.hide()
self.factor_entry.hide()
# #################################### FINSIHED GUI ###########################
# #############################################################################