- in Corner Marker Tool add new feature: ability to create an Excellon object with drill holes in the corner markes

- in Corner Marker Tool, will no longer update the current object with the marker geometry but create a new Gerber object
- in Join Excellon functionality made sure that the new Combo Exellon object will have copied the data from source objects and not just references, therefore will survive the delete of its parents
- updated Turkish translation (by Mehmet Kaya)
- updated all the languages except Turkish
This commit is contained in:
Marius Stanciu
2020-11-01 23:04:48 +02:00
committed by Marius
parent 55d5dece2c
commit fac4caf961
27 changed files with 2611 additions and 2147 deletions

View File

@@ -10,7 +10,8 @@ from PyQt5 import QtWidgets, QtCore, QtGui
from appTool import AppTool
from appGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCComboBox, FCButton, RadioSet, FCLabel
from shapely.geometry import MultiPolygon, LineString
from shapely.geometry import MultiPolygon, LineString, Point
from shapely.ops import unary_union
from copy import deepcopy
import logging
@@ -37,6 +38,9 @@ class ToolCorners(AppTool):
self.decimals = self.app.decimals
self.units = ''
# here we store the locations of the selected corners
self.points = {}
# #############################################################################
# ######################### Tool GUI ##########################################
# #############################################################################
@@ -57,6 +61,7 @@ class ToolCorners(AppTool):
# SIGNALS
self.ui.add_marker_button.clicked.connect(self.add_markers)
self.ui.toggle_all_cb.toggled.connect(self.on_toggle_all)
self.ui.drill_button.clicked.connect(self.on_create_drill_object)
def run(self, toggle=True):
self.app.defaults.report_usage("ToolCorners()")
@@ -96,6 +101,7 @@ class ToolCorners(AppTool):
self.ui.margin_entry.set_value(float(self.app.defaults["tools_corners_margin"]))
self.ui.toggle_all_cb.set_value(False)
self.ui.type_radio.set_value(self.app.defaults["tools_corners_type"])
self.ui.drill_dia_entry.set_value(self.app.defaults["tools_corners_drill_dia"])
def on_toggle_all(self, val):
self.ui.bl_cb.set_value(val)
@@ -123,26 +129,24 @@ class ToolCorners(AppTool):
return
xmin, ymin, xmax, ymax = self.grb_object.bounds()
points = {}
self.points = {}
if tl_state:
points['tl'] = (xmin, ymax)
self.points['tl'] = (xmin, ymax)
if tr_state:
points['tr'] = (xmax, ymax)
self.points['tr'] = (xmax, ymax)
if bl_state:
points['bl'] = (xmin, ymin)
self.points['bl'] = (xmin, ymin)
if br_state:
points['br'] = (xmax, ymin)
self.points['br'] = (xmax, ymin)
ret_val = self.add_corners_geo(points, g_obj=self.grb_object)
ret_val = self.add_corners_geo(self.points, g_obj=self.grb_object)
self.app.call_source = "app"
if ret_val == 'fail':
self.app.call_source = "app"
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
return
self.grb_object.source_file = self.app.f_handlers.export_gerber(obj_name=self.grb_object.options['name'],
filename=None,
local_use=self.grb_object,
use_thread=False)
self.on_exit()
self.on_exit(ret_val)
def add_corners_geo(self, points_storage, g_obj):
"""
@@ -155,8 +159,8 @@ class ToolCorners(AppTool):
marker_type = self.ui.type_radio.get_value()
line_thickness = self.ui.thick_entry.get_value()
line_length = self.ui.l_entry.get_value()
margin = self.ui.margin_entry.get_value()
line_length = self.ui.l_entry.get_value()
geo_list = []
@@ -169,7 +173,7 @@ class ToolCorners(AppTool):
pt = points_storage[key]
x = pt[0] - margin - line_thickness / 2.0
y = pt[1] + margin + line_thickness / 2.0
if type == 's':
if marker_type == 's':
line_geo_hor = LineString([
(x, y), (x + line_length, y)
])
@@ -189,7 +193,7 @@ class ToolCorners(AppTool):
pt = points_storage[key]
x = pt[0] + margin + line_thickness / 2.0
y = pt[1] + margin + line_thickness / 2.0
if type == 's':
if marker_type == 's':
line_geo_hor = LineString([
(x, y), (x - line_length, y)
])
@@ -209,7 +213,7 @@ class ToolCorners(AppTool):
pt = points_storage[key]
x = pt[0] - margin - line_thickness / 2.0
y = pt[1] - margin - line_thickness / 2.0
if type == 's':
if marker_type == 's':
line_geo_hor = LineString([
(x, y), (x + line_length, y)
])
@@ -229,7 +233,7 @@ class ToolCorners(AppTool):
pt = points_storage[key]
x = pt[0] + margin + line_thickness / 2.0
y = pt[1] - margin - line_thickness / 2.0
if type == 's':
if marker_type == 's':
line_geo_hor = LineString([
(x, y), (x - line_length, y)
])
@@ -246,8 +250,10 @@ class ToolCorners(AppTool):
geo_list.append(line_geo_hor)
geo_list.append(line_geo_vert)
new_apertures = deepcopy(g_obj.apertures)
aperture_found = None
for ap_id, ap_val in g_obj.apertures.items():
for ap_id, ap_val in new_apertures.items():
if ap_val['type'] == 'C' and ap_val['size'] == line_thickness:
aperture_found = ap_id
break
@@ -261,27 +267,25 @@ class ToolCorners(AppTool):
dict_el = {}
dict_el['follow'] = geo
dict_el['solid'] = geo_buff
g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
new_apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
else:
ap_keys = list(g_obj.apertures.keys())
ap_keys = list(new_apertures.keys())
if ap_keys:
new_apid = str(int(max(ap_keys)) + 1)
else:
new_apid = '10'
g_obj.apertures[new_apid] = {}
g_obj.apertures[new_apid]['type'] = 'C'
g_obj.apertures[new_apid]['size'] = line_thickness
g_obj.apertures[new_apid]['geometry'] = []
new_apertures[new_apid] = {}
new_apertures[new_apid]['type'] = 'C'
new_apertures[new_apid]['size'] = line_thickness
new_apertures[new_apid]['geometry'] = []
for geo in geo_list:
geo_buff = geo.buffer(line_thickness / 2.0, resolution=self.grb_steps_per_circle, join_style=3)
geo_buff_list.append(geo_buff)
dict_el = {}
dict_el['follow'] = geo
dict_el['solid'] = geo_buff
g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
dict_el = {'follow': geo, 'solid': geo_buff}
new_apertures[new_apid]['geometry'].append(deepcopy(dict_el))
s_list = []
if g_obj.solid_geometry:
@@ -299,22 +303,125 @@ class ToolCorners(AppTool):
except TypeError:
s_list.append(geo_buff_list)
g_obj.solid_geometry = MultiPolygon(s_list)
outname = '%s_%s' % (str(self.grb_object.options['name']), 'corners')
def initialize(grb_obj, app_obj):
grb_obj.multitool = False
grb_obj.multigeo = False
grb_obj.follow = False
grb_obj.apertures = new_apertures
grb_obj.solid_geometry = unary_union(s_list)
grb_obj.source_file = app_obj.f_handlers.export_gerber(obj_name=outname, filename=None, local_use=grb_obj,
use_thread=False)
ret = self.app.app_obj.new_object('gerber', outname, initialize, plot=True)
return ret
def on_create_drill_object(self):
self.app.call_source = "corners_tool"
tooldia = self.ui.drill_dia_entry.get_value()
if tooldia == 0:
self.app.inform.emit('[WARNING_NOTCL] %s %s' % (_("Cancelled."), _("The tool diameter is zero.")))
return
line_thickness = self.ui.thick_entry.get_value()
margin = self.ui.margin_entry.get_value()
tl_state = self.ui.tl_cb.get_value()
tr_state = self.ui.tr_cb.get_value()
bl_state = self.ui.bl_cb.get_value()
br_state = self.ui.br_cb.get_value()
if not tl_state and not tr_state and not bl_state and not br_state:
self.app.inform.emit("[ERROR_NOTCL] %s." % _("Please select at least a location"))
# get the Gerber object on which the corner marker will be inserted
selection_index = self.ui.object_combo.currentIndex()
model_index = self.app.collection.index(selection_index, 0, self.ui.object_combo.rootModelIndex())
try:
self.grb_object = model_index.internalPointer().obj
except Exception as e:
log.debug("ToolCorners.add_markers() --> %s" % str(e))
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
self.app.call_source = "app"
return
xmin, ymin, xmax, ymax = self.grb_object.bounds()
# list of (x,y) tuples. Store here the drill coordinates
drill_list = []
if tl_state:
x = xmin - margin - line_thickness / 2.0
y = ymax + margin + line_thickness / 2.0
drill_list.append(
Point((x, y))
)
if tr_state:
x = xmax + margin + line_thickness / 2.0
y = ymax + margin + line_thickness / 2.0
drill_list.append(
Point((x, y))
)
if bl_state:
x = xmin - margin - line_thickness / 2.0
y = ymin - margin - line_thickness / 2.0
drill_list.append(
Point((x, y))
)
if br_state:
x = xmax + margin + line_thickness / 2.0
y = ymin - margin - line_thickness / 2.0
drill_list.append(
Point((x, y))
)
tools = {1: {}}
tools[1]["tooldia"] = tooldia
tools[1]['drills'] = drill_list
tools[1]['solid_geometry'] = []
def obj_init(obj_inst, app_inst):
obj_inst.tools = deepcopy(tools)
obj_inst.create_geometry()
obj_inst.source_file = app_inst.f_handlers.export_excellon(obj_name=obj_inst.options['name'],
local_use=obj_inst,
filename=None,
use_thread=False)
outname = '%s_%s' % (str(self.grb_object.options['name']), 'corner_drills')
ret_val = self.app.app_obj.new_object("excellon", outname, obj_init)
self.app.call_source = "app"
if not ret_val == 'fail':
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
else:
self.app.inform.emit('[success] %s' % _("Excellon object with corner drills created."))
def replot(self, obj, run_thread=True):
def worker_task():
with self.app.proc_container.new('%s...' % _("Plotting")):
obj.plot()
self.app.app_obj.object_plotted.emit(obj)
if run_thread:
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
else:
worker_task()
def on_exit(self):
def on_exit(self, corner_gerber_obj):
# plot the object
try:
self.replot(obj=self.grb_object)
self.replot(obj=corner_gerber_obj)
except (AttributeError, TypeError):
return
@@ -328,11 +435,8 @@ class ToolCorners(AppTool):
except Exception as e:
log.debug("ToolCorners.on_exit() copper_obj bounds error --> %s" % str(e))
# reset the variables
self.grb_object = None
self.app.call_source = "app"
self.app.inform.emit('[success] %s' % _("Corners Tool exit."))
self.app.inform.emit('[success] %s' % _("A Gerber object with corner markers was created."))
class CornersUI:
@@ -381,21 +485,25 @@ class CornersUI:
)
self.layout.addWidget(self.points_label)
# BOTTOM LEFT
self.bl_cb = FCCheckBox(_("Bottom Left"))
self.layout.addWidget(self.bl_cb)
# BOTTOM RIGHT
self.br_cb = FCCheckBox(_("Bottom Right"))
self.layout.addWidget(self.br_cb)
# ## Grid Layout
grid_loc = QtWidgets.QGridLayout()
self.layout.addLayout(grid_loc)
# TOP LEFT
self.tl_cb = FCCheckBox(_("Top Left"))
self.layout.addWidget(self.tl_cb)
grid_loc.addWidget(self.tl_cb, 0, 0)
# TOP RIGHT
self.tr_cb = FCCheckBox(_("Top Right"))
self.layout.addWidget(self.tr_cb)
grid_loc.addWidget(self.tr_cb, 0, 1)
# BOTTOM LEFT
self.bl_cb = FCCheckBox(_("Bottom Left"))
grid_loc.addWidget(self.bl_cb, 1, 0)
# BOTTOM RIGHT
self.br_cb = FCCheckBox(_("Bottom Right"))
grid_loc.addWidget(self.br_cb, 1, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
@@ -443,7 +551,7 @@ class CornersUI:
_("The thickness of the line that makes the corner marker.")
)
self.thick_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.thick_entry.set_range(0.0000, 9.9999)
self.thick_entry.set_range(0.0000, 10.0000)
self.thick_entry.set_precision(self.decimals)
self.thick_entry.setWrapping(True)
self.thick_entry.setSingleStep(10 ** -self.decimals)
@@ -457,7 +565,7 @@ class CornersUI:
_("The length of the line that makes the corner marker.")
)
self.l_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.l_entry.set_range(-9999.9999, 9999.9999)
self.l_entry.set_range(-10000.0000, 10000.0000)
self.l_entry.set_precision(self.decimals)
self.l_entry.setSingleStep(10 ** -self.decimals)
@@ -470,17 +578,17 @@ class CornersUI:
_("Bounding box margin.")
)
self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.margin_entry.set_range(-9999.9999, 9999.9999)
self.margin_entry.set_range(-10000.0000, 10000.0000)
self.margin_entry.set_precision(self.decimals)
self.margin_entry.setSingleStep(0.1)
grid_lay.addWidget(self.margin_label, 8, 0)
grid_lay.addWidget(self.margin_entry, 8, 1)
separator_line_2 = QtWidgets.QFrame()
separator_line_2.setFrameShape(QtWidgets.QFrame.HLine)
separator_line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
grid_lay.addWidget(separator_line_2, 10, 0, 1, 2)
# separator_line_2 = QtWidgets.QFrame()
# separator_line_2.setFrameShape(QtWidgets.QFrame.HLine)
# separator_line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
# grid_lay.addWidget(separator_line_2, 10, 0, 1, 2)
# ## Insert Corner Marker
self.add_marker_button = FCButton(_("Add Marker"))
@@ -496,6 +604,42 @@ class CornersUI:
""")
grid_lay.addWidget(self.add_marker_button, 12, 0, 1, 2)
separator_line_2 = QtWidgets.QFrame()
separator_line_2.setFrameShape(QtWidgets.QFrame.HLine)
separator_line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
grid_lay.addWidget(separator_line_2, 14, 0, 1, 2)
# Drill is corners
self.drills_label = FCLabel('<b>%s:</b>' % _('Drills in Corners'))
grid_lay.addWidget(self.drills_label, 16, 0, 1, 2)
# Drill Tooldia #
self.drill_dia_label = FCLabel('%s:' % _("Tool Dia"))
self.drill_dia_label.setToolTip(
'%s.' % _("Drill Diameter")
)
self.drill_dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
self.drill_dia_entry.set_range(0.0000, 100.0000)
self.drill_dia_entry.set_precision(self.decimals)
self.drill_dia_entry.setWrapping(True)
grid_lay.addWidget(self.drill_dia_label, 18, 0)
grid_lay.addWidget(self.drill_dia_entry, 18, 1)
# ## Create an Excellon object
self.drill_button = FCButton(_("Create Excellon Object"))
self.drill_button.setIcon(QtGui.QIcon(self.app.resource_location + '/drill32.png'))
self.drill_button.setToolTip(
_("Will add drill holes in the center of the markers.")
)
self.drill_button.setStyleSheet("""
QPushButton
{
font-weight: bold;
}
""")
grid_lay.addWidget(self.drill_button, 20, 0, 1, 2)
self.layout.addStretch()
# ## Reset Tool