- major refactoring: started to move the methods connected to the Edit menu to their own class to clean up the App mega class

This commit is contained in:
Marius Stanciu
2024-03-28 14:49:05 +02:00
parent d583bb8cf2
commit e7cd73fde1
17 changed files with 766 additions and 726 deletions

View File

@@ -35,7 +35,7 @@ import platform
import re
import subprocess
from shapely import Point, MultiPolygon, MultiLineString, Polygon, LinearRing, LineString
from shapely import Point, MultiPolygon, MultiLineString, Polygon
from shapely.ops import unary_union
from io import StringIO
@@ -74,7 +74,8 @@ from appCommon.Common import ExclusionAreas
from appCommon.Common import AppLogging
from appCommon.RegisterFileKeywords import RegisterFK, Extensions, KeyWords
from appHandlers.AppIO import AppIO
from appHandlers.appIO import appIO
from appHandlers.appEdit import appEditor
from Bookmark import BookmarkManager
from appDatabase import ToolsDB2
@@ -100,10 +101,10 @@ from camlib import to_dict, Geometry, CNCjob
from appPreProcessor import load_preprocessors
# App appEditors
from appEditors.AppGeoEditor import AppGeoEditor
from appEditors.AppExcEditor import AppExcEditor
from appEditors.AppGerberEditor import AppGerberEditor
from appEditors.AppTextEditor import AppTextEditor
from appEditors.appGeoEditor import AppGeoEditor
from appEditors.appExcEditor import AppExcEditor
from appEditors.appGerberEditor import AppGerberEditor
from appEditors.appTextEditor import AppTextEditor
from appEditors.appGCodeEditor import AppGCodeEditor
# App Workers
@@ -386,7 +387,7 @@ class App(QtCore.QObject):
# store here the mouse cursor
self.cursor = None
# while True no canvas context menu will be showen
# while True no canvas context menu will be shown
self.inhibit_context_menu = False
# Variable to store the GCODE that was edited
@@ -986,8 +987,6 @@ class App(QtCore.QObject):
# ###########################################################################################################
# ############################################# Activity Monitor ############################################
# ###########################################################################################################
# self.activity_view = FlatCAMActivityView(app=self)
# self.ui.infobar.addWidget(self.activity_view)
self.proc_container = FCVisibleProcessContainer(self.ui.activity_view)
# ###########################################################################################################
@@ -1080,7 +1079,7 @@ class App(QtCore.QObject):
# Separate thread (Not worker)
# Check for updates on startup but only if the user consent and the app is not in Beta version
if (self.beta is False or self.beta is None) and self.options["global_version_check"] is True:
self.log.info("Checking for updates in backgroud (this is version %s)." % str(self.version))
self.log.info("Checking for updates in background (this is version %s)." % str(self.version))
# self.thr2 = QtCore.QThread()
self.worker_task.emit({'fcn': self.version_check, 'params': []})
@@ -1126,7 +1125,8 @@ class App(QtCore.QObject):
# ###################################### INSTANTIATE CLASSES THAT HOLD THE MENU HANDLERS ####################
# ###########################################################################################################
# ###########################################################################################################
self.f_handlers = AppIO(app=self)
self.f_handlers = appIO(app=self)
self.edit_class = appEditor(app=self)
# this is calculated in the class above (somehow?)
self.options["root_folder_path"] = self.app_home
@@ -1905,25 +1905,25 @@ class App(QtCore.QObject):
self.ui.menueditedit.triggered.connect(lambda: self.on_editing_start())
self.ui.menueditok.triggered.connect(lambda: self.on_editing_finished())
self.ui.menuedit_join2geo.triggered.connect(self.on_edit_join)
self.ui.menuedit_join_exc2exc.triggered.connect(self.on_edit_join_exc)
self.ui.menuedit_join_grb2grb.triggered.connect(self.on_edit_join_grb)
self.ui.menuedit_join2geo.triggered.connect(self.edit_class.on_edit_join)
self.ui.menuedit_join_exc2exc.triggered.connect(self.edit_class.on_edit_join_exc)
self.ui.menuedit_join_grb2grb.triggered.connect(self.edit_class.on_edit_join_grb)
self.ui.menuedit_convert_sg2mg.triggered.connect(self.on_convert_singlegeo_to_multigeo)
self.ui.menuedit_convert_mg2sg.triggered.connect(self.on_convert_multigeo_to_singlegeo)
self.ui.menuedit_convert_sg2mg.triggered.connect(self.edit_class.on_convert_singlegeo_to_multigeo)
self.ui.menuedit_convert_mg2sg.triggered.connect(self.edit_class.on_convert_multigeo_to_singlegeo)
self.ui.menueditdelete.triggered.connect(self.on_delete)
self.ui.menueditcopyobject.triggered.connect(self.on_copy_command)
self.ui.menueditconvert_any2geo.triggered.connect(lambda: self.convert_any2geo())
self.ui.menueditconvert_any2gerber.triggered.connect(lambda: self.convert_any2gerber())
self.ui.menueditconvert_any2excellon.triggered.connect(lambda: self.convert_any2excellon())
self.ui.menueditconvert_any2geo.triggered.connect(lambda: self.edit_class.convert_any2geo())
self.ui.menueditconvert_any2gerber.triggered.connect(lambda: self.edit_class.convert_any2gerber())
self.ui.menueditconvert_any2excellon.triggered.connect(lambda: self.edit_class.convert_any2excellon())
self.ui.menuedit_numeric_move.triggered.connect(lambda: self.on_numeric_move())
self.ui.menueditorigin.triggered.connect(self.on_set_origin)
self.ui.menuedit_move2origin.triggered.connect(self.on_move2origin)
self.ui.menuedit_center_in_origin.triggered.connect(self.on_custom_origin)
self.ui.menuedit_center_in_origin.triggered.connect(self.edit_class.on_custom_origin)
self.ui.menueditjump.triggered.connect(self.on_jump_to)
self.ui.menueditlocate.triggered.connect(lambda: self.on_locate(obj=self.collection.get_active()))
@@ -4029,208 +4029,12 @@ class App(QtCore.QObject):
with open(config_file, 'w') as f:
f.writelines(data)
def on_edit_join(self, name=None):
"""
Callback for Edit->Join. Joins the selected geometry objects into
a new one.
:return: None
"""
self.defaults.report_usage("on_edit_join()")
obj_name_single = str(name) if name else "Combo_SingleGeo"
obj_name_multi = str(name) if name else "Combo_MultiGeo"
geo_type_set = set()
objs = self.collection.get_selected()
if len(objs) < 2:
self.inform.emit('[ERROR_NOTCL] %s: %d' %
(_("At least two objects are required for join. Objects currently selected"), len(objs)))
return 'fail'
for obj in objs:
geo_type_set.add(obj.multigeo)
# if len(geo_type_list) == 1 means that all list elements are the same
if len(geo_type_set) != 1:
self.inform.emit('[ERROR] %s' %
_("Failed join. The Geometry objects are of different types.\n"
"At least one is MultiGeo type and the other is SingleGeo type. A possibility is to "
"convert from one to another and retry joining \n"
"but in the case of converting from MultiGeo to SingleGeo, informations may be lost and "
"the result may not be what was expected. \n"
"Check the generated GCODE."))
return
fuse_tools = self.options["geometry_merge_fuse_tools"]
# if at least one True object is in the list then due of the previous check, all list elements are True objects
if True in geo_type_set:
def initialize(geo_obj, app):
GeometryObject.merge(geo_list=objs, geo_final=geo_obj, multi_geo=True, fuse_tools=fuse_tools,
log=app.log)
app.inform.emit('[success] %s.' % _("Geometry merging finished"))
# rename all the ['name] key in obj.tools[tooluid]['data'] to the obj_name_multi
for v in geo_obj.tools.values():
v['data']['name'] = obj_name_multi
self.app_obj.new_object("geometry", obj_name_multi, initialize)
else:
def initialize(geo_obj, app):
GeometryObject.merge(geo_list=objs, geo_final=geo_obj, multi_geo=False, fuse_tools=fuse_tools,
log=app.log)
app.inform.emit('[success] %s.' % _("Geometry merging finished"))
# rename all the ['name] key in obj.tools[tooluid]['data'] to the obj_name_multi
for v in geo_obj.tools.values():
v['data']['name'] = obj_name_single
self.app_obj.new_object("geometry", obj_name_single, initialize)
self.should_we_save = True
def on_edit_join_exc(self):
"""
Callback for Edit->Join Excellon. Joins the selected Excellon objects into
a new Excellon.
:return: None
"""
self.defaults.report_usage("on_edit_join_exc()")
objs = self.collection.get_selected()
for obj in objs:
if not isinstance(obj, ExcellonObject):
self.inform.emit('[ERROR_NOTCL] %s' % _("Failed. Excellon joining works only on Excellon objects."))
return
if len(objs) < 2:
self.inform.emit('[ERROR_NOTCL] %s: %d' %
(_("At least two objects are required for join. Objects currently selected"), len(objs)))
return 'fail'
fuse_tools = self.options["excellon_merge_fuse_tools"]
def initialize(exc_obj, app):
ExcellonObject.merge(exc_list=objs, exc_final=exc_obj, decimals=self.decimals, fuse_tools=fuse_tools,
log=app.log)
app.inform.emit('[success] %s.' % _("Excellon merging finished"))
self.app_obj.new_object("excellon", 'Combo_Excellon', initialize)
self.should_we_save = True
def on_edit_join_grb(self):
"""
Callback for Edit->Join Gerber. Joins the selected Gerber objects into
a new Gerber object.
:return: None
"""
self.defaults.report_usage("on_edit_join_grb()")
objs = self.collection.get_selected()
for obj in objs:
if not isinstance(obj, GerberObject):
self.inform.emit('[ERROR_NOTCL] %s' % _("Failed. Gerber joining works only on Gerber objects."))
return
if len(objs) < 2:
self.inform.emit('[ERROR_NOTCL] %s: %d' %
(_("At least two objects are required for join. Objects currently selected"), len(objs)))
return 'fail'
def initialize(grb_obj, app):
GerberObject.merge(grb_list=objs, grb_final=grb_obj, app=self)
app.inform.emit('[success] %s.' % _("Gerber merging finished"))
self.app_obj.new_object("gerber", 'Combo_Gerber', initialize)
self.should_we_save = True
def on_convert_singlegeo_to_multigeo(self):
"""
Called for converting a Geometry object from single-geo to multi-geo.
Single-geo Geometry objects store their geometry data into self.solid_geometry.
Multi-geo Geometry objects store their geometry data into the `self.tools` dictionary, each key
(a tool actually) having as a value another dictionary. This value dictionary has
one of its keys 'solid_geometry' which holds the solid-geometry of that tool.
:return: None
"""
self.defaults.report_usage("on_convert_singlegeo_to_multigeo()")
obj = self.collection.get_active()
if obj is None:
self.inform.emit('[ERROR_NOTCL] %s' % _("Failed. Select a Geometry Object and try again."))
return
if not isinstance(obj, GeometryObject):
self.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Expected a GeometryObject, got"), type(obj)))
return
obj.multigeo = True
for tooluid, dict_value in obj.tools.items():
dict_value['solid_geometry'] = deepcopy(obj.solid_geometry)
if not isinstance(obj.solid_geometry, list):
obj.solid_geometry = [obj.solid_geometry]
# obj.solid_geometry[:] = []
obj.plot()
self.should_we_save = True
self.inform.emit('[success] %s' % _("A Geometry object was converted to MultiGeo type."))
def on_convert_multigeo_to_singlegeo(self):
"""
Called for converting a Geometry object from multi-geo to single-geo.
Single-geo Geometry objects store their geometry data into self.solid_geometry.
Multi-geo Geometry objects store their geometry data into the self.tools dictionary, each key (a tool actually)
having as a value another dictionary. This value dictionary has one of its keys 'solid_geometry' which holds
the solid-geometry of that tool.
:return: None
"""
self.defaults.report_usage("on_convert_multigeo_to_singlegeo()")
obj = self.collection.get_active()
if obj is None:
self.inform.emit('[ERROR_NOTCL] %s' % _("Failed. Select a Geometry Object and try again."))
return
if not isinstance(obj, GeometryObject):
self.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Expected a GeometryObject, got"), type(obj)))
return
obj.multigeo = False
total_solid_geometry = []
for tooluid, dict_value in obj.tools.items():
total_solid_geometry += deepcopy(dict_value['solid_geometry'])
# clear the original geometry
if isinstance(dict_value['solid_geometry'], list):
dict_value['solid_geometry'][:] = []
else:
dict_value['solid_geometry'] = []
obj.solid_geometry = deepcopy(total_solid_geometry)
obj.plot()
self.should_we_save = True
self.inform.emit('[success] %s' % _("A Geometry object was converted to SingleGeo type."))
def on_defaults_dict_change(self, field):
"""
Called whenever a key changed in the self.options dictionary. It will set the required GUI element in the
Called whenever a key changed in the "self.options" dictionary. It will set the required GUI element in the
Edit -> Preferences tab window.
:param field: the key of the self.options dictionary that was changed.
:param field: the key of the "self.options" dictionary that was changed.
:return: None
"""
self.preferencesUiManager.defaults_write_form_field(field=field)
@@ -4715,118 +4519,6 @@ class App(QtCore.QObject):
worker_task()
self.should_we_save = True
def on_custom_origin(self, use_thread=True):
"""
Move selected objects to be centered in certain standard locations of the object (corners and center).
:param use_thread: Control if to use threaded operation. Boolean.
:return:
"""
obj_list = self.collection.get_selected()
if not obj_list:
self.inform.emit('[ERROR_NOTCL] %s' % _("Failed. No object(s) selected..."))
return
choices = [
{"label": _("Quadrant 2"), "value": "tl"},
{"label": _("Quadrant 1"), "value": "tr"},
{"label": _("Quadrant 3"), "value": "bl"},
{"label": _("Quadrant 4"), "value": "br"},
{"label": _("Center"), "value": "c"}
]
dia_box = DialogBoxChoice(title='%s:' % _("Custom Origin"),
icon=QtGui.QIcon(self.resource_location + '/origin3_32.png'),
choices=choices,
default_choice='c',
parent=self.ui)
if dia_box.ok is True:
try:
location_point = dia_box.location_point
except Exception:
return
else:
return
def worker_task():
with self.proc_container.new('%s ...' % _("Custom Origin")):
xminlist = []
yminlist = []
xmaxlist = []
ymaxlist = []
# first get a bounding box to fit all
for obj in obj_list:
xmin, ymin, xmax, ymax = obj.bounds()
xminlist.append(xmin)
yminlist.append(ymin)
xmaxlist.append(xmax)
ymaxlist.append(ymax)
# get the minimum x,y for all objects selected
x0 = min(xminlist)
y0 = min(yminlist)
x1 = max(xmaxlist)
y1 = max(ymaxlist)
if location_point == 'bl':
location = (x0, y0)
elif location_point == 'tl':
location = (x0, y1)
elif location_point == 'br':
location = (x1, y0)
elif location_point == 'tr':
location = (x1, y1)
else:
# center
cx = x0 + abs((x1 - x0) / 2)
cy = y0 + abs((y1 - y0) / 2)
location = (cx, cy)
for obj in obj_list:
obj.offset((-location[0], -location[1]))
self.app_obj.object_changed.emit(obj)
# Update the object bounding box options
a, b, c, d = obj.bounds()
obj.obj_options['xmin'] = a
obj.obj_options['ymin'] = b
obj.obj_options['xmax'] = c
obj.obj_options['ymax'] = d
# make sure to update the Offset field in Properties Tab
try:
obj.set_offset_values()
except AttributeError:
# not all objects have this attribute
pass
for obj in obj_list:
obj.plot()
self.plotcanvas.fit_view()
for obj in obj_list:
out_name = obj.obj_options["name"]
if obj.kind == 'gerber':
obj.source_file = self.f_handlers.export_gerber(
obj_name=out_name, filename=None, local_use=obj, use_thread=False)
elif obj.kind == 'excellon':
obj.source_file = self.f_handlers.export_excellon(
obj_name=out_name, filename=None, local_use=obj, use_thread=False)
elif obj.kind == 'geometry':
obj.source_file = self.f_handlers.export_dxf(
obj_name=out_name, filename=None, local_use=obj, use_thread=False)
self.inform.emit('[success] %s...' % _('Origin set'))
if use_thread is True:
self.worker_task.emit({'fcn': worker_task, 'params': []})
else:
worker_task()
self.should_we_save = True
def on_jump_to(self, custom_location=None, fit_center=True):
"""
Jump to a location by setting the mouse cursor location.
@@ -5292,379 +4984,6 @@ class App(QtCore.QObject):
self.log.error(
"App.on_rename_object() --> Could not rename the object in the list. --> %s" % str(e))
def convert_any2geo(self):
"""
Will convert any object out of Gerber, Excellon, Geometry to Geometry object.
:return:
"""
self.defaults.report_usage("convert_any2geo()")
# store here the default data for Geometry Data
default_data = {}
for opt_key, opt_val in self.options.items():
if opt_key.find('geometry' + "_") == 0:
oname = opt_key[len('geometry') + 1:]
default_data[oname] = self.options[opt_key]
else:
default_data[opt_key] = self.options[opt_key]
if isinstance(self.options["tools_mill_tooldia"], float):
tools_diameters = [self.options["tools_mill_tooldia"]]
else:
try:
dias = str(self.options["tools_mill_tooldia"]).strip('[').strip(']')
tools_string = dias.split(",")
tools_diameters = [eval(a) for a in tools_string if a != '']
except Exception as e:
self.log.error("App.convert_any2geo() --> %s" % str(e))
return 'fail'
tools = {}
t_id = 0
for tooldia in tools_diameters:
t_id += 1
new_tool = {
'tooldia': tooldia,
'offset': 'Path',
'offset_value': 0.0,
'type': 'Rough',
'tool_type': 'C1',
'data': deepcopy(default_data),
'solid_geometry': []
}
tools[t_id] = deepcopy(new_tool)
def initialize_from_gerber(new_obj, app_obj):
app_obj.log.debug("Gerber converted to Geometry: %s" % str(obj.obj_options["name"]))
new_obj.solid_geometry = deepcopy(obj.solid_geometry)
try:
new_obj.follow_geometry = obj.follow_geometry
except AttributeError:
pass
new_obj.obj_options.update(deepcopy(default_data))
new_obj.obj_options["tools_mill_tooldia"] = tools_diameters[0] if tools_diameters else 0.0
new_obj.tools = deepcopy(tools)
for k in new_obj.tools:
new_obj.tools[k]['solid_geometry'] = deepcopy(obj.solid_geometry)
def initialize_from_excellon(new_obj, app_obj):
app_obj.log.debug("Excellon converted to Geometry: %s" % str(obj.obj_options["name"]))
solid_geo = []
for tool in obj.tools:
for geo in obj.tools[tool]['solid_geometry']:
solid_geo.append(geo)
new_obj.solid_geometry = deepcopy(solid_geo)
if not new_obj.solid_geometry:
app_obj.log("convert_any2geo() failed")
return 'fail'
new_obj.obj_options.update(deepcopy(default_data))
new_obj.obj_options["tools_mill_tooldia"] = tools_diameters[0] if tools_diameters else 0.0
new_obj.tools = deepcopy(tools)
for k in new_obj.tools:
new_obj.tools[k]['solid_geometry'] = deepcopy(obj.solid_geometry)
if not self.collection.get_selected():
self.log.warning("App.convert_any2geo --> No object selected")
self.inform.emit('[WARNING_NOTCL] %s' % _("No object is selected."))
return
for obj in self.collection.get_selected():
outname = '%s_conv' % obj.obj_options["name"]
try:
if obj.kind == 'excellon':
self.app_obj.new_object("geometry", outname, initialize_from_excellon)
if obj.kind == 'gerber':
self.app_obj.new_object("geometry", outname, initialize_from_gerber)
except Exception as e:
self.log.error("Convert any2geo operation failed: %s" % str(e))
def convert_any2gerber(self):
"""
Will convert any object out of Gerber, Excellon, Geometry to Gerber object.
:return:
"""
def initialize_from_geometry(obj_init, app_obj):
apertures = {
0: {
'size': 0.0,
'type': 'REG',
'geometry': []
}
}
for obj_orig in obj.solid_geometry:
new_elem = {'solid': obj_orig}
try:
new_elem['follow'] = obj_orig.exterior
except AttributeError:
pass
apertures[0]['geometry'].append(deepcopy(new_elem))
obj_init.solid_geometry = deepcopy(obj.solid_geometry)
obj_init.tools = deepcopy(apertures)
if not obj_init.tools:
app_obj.log("convert_any2gerber() failed")
return 'fail'
def initialize_from_excellon(obj_init, app_obj):
apertures = {}
apid = 10
for tool in obj.tools:
apertures[apid] = {
'size': float(obj.tools[tool]['tooldia']),
'type': 'C',
'geometry': []
}
for geo in obj.tools[tool]['solid_geometry']:
new_el = {
'solid': geo,
'follow': geo.exterior
}
apertures[apid]['geometry'].append(deepcopy(new_el))
apid += 1
# create solid_geometry
solid_geometry = []
for apid_val in apertures.values():
for geo_el in apid_val['geometry']:
solid_geometry.append(geo_el['solid']) # noqa
solid_geometry = MultiPolygon(solid_geometry)
solid_geometry = solid_geometry.buffer(0.0000001)
obj_init.solid_geometry = deepcopy(solid_geometry)
obj_init.tools = deepcopy(apertures)
if not obj_init.tools:
app_obj.log("convert_any2gerber() failed")
return 'fail'
if not self.collection.get_selected():
self.log.warning("App.convert_any2gerber --> No object selected")
self.inform.emit('[WARNING_NOTCL] %s' % _("No object is selected."))
return
for obj in self.collection.get_selected():
outname = '%s_conv' % obj.obj_options["name"]
try:
if obj.kind == 'excellon':
self.app_obj.new_object("gerber", outname, initialize_from_excellon)
elif obj.kind == 'geometry':
self.app_obj.new_object("gerber", outname, initialize_from_geometry)
else:
self.log.warning("App.convert_any2gerber --> This is no valid object for conversion.")
except Exception as e:
return "Operation failed: %s" % str(e)
def convert_any2excellon(self, conv_obj_name=None):
"""
Will convert any object out of Gerber, Excellon, Geometry to an Excellon object.
:param conv_obj_name: a FlatCAM object
:return:
"""
self.log.debug("Running conversion to Excellon object...")
def initialize_from_geometry(obj_init, app_obj):
tools = {}
tooluid = 1
obj_init.solid_geometry = []
for tool in obj.tools:
print(obj.tools[tool])
for geo in obj.solid_geometry:
if not isinstance(geo, (Polygon, MultiPolygon, LinearRing)):
continue
minx, miny, maxx, maxy = geo.bounds
new_dia = min([maxx - minx, maxy - miny])
new_drill = geo.centroid
new_drill_geo = new_drill.buffer(new_dia / 2.0)
current_tooldias = []
if tools:
for tool in tools:
if tools[tool] and 'tooldia' in tools[tool]:
current_tooldias.append(tools[tool]['tooldia'])
if new_dia in current_tooldias:
digits = app_obj.decimals
for tool in tools:
if app_obj.dec_format(tools[tool]["tooldia"], digits) == app_obj.dec_format(new_dia, digits):
tools[tool]['drills'].append(new_drill)
tools[tool]['solid_geometry'].append(deepcopy(new_drill_geo))
else:
tools[tooluid] = {}
tools[tooluid]['tooldia'] = new_dia
tools[tooluid]['drills'] = [new_drill]
tools[tooluid]['slots'] = []
tools[tooluid]['solid_geometry'] = [new_drill_geo]
tooluid += 1
try:
obj_init.solid_geometry.append(new_drill_geo)
except (TypeError, AttributeError):
obj_init.solid_geometry = [new_drill_geo]
obj_init.tools = deepcopy(tools)
obj_init.solid_geometry = unary_union(obj_init.solid_geometry)
if not obj_init.solid_geometry:
return 'fail'
def initialize_from_gerber(obj_init, app_obj):
tools = {}
tooluid = 1
digits = app_obj.decimals
obj_init.solid_geometry = []
for apid in obj.tools:
if 'geometry' in obj.tools[apid]:
for geo_dict in obj.tools[apid]['geometry']:
if 'follow' in geo_dict:
if isinstance(geo_dict['follow'], Point):
geo = geo_dict['solid']
minx, miny, maxx, maxy = geo.bounds
new_dia = min([maxx - minx, maxy - miny])
new_drill = geo.centroid
new_drill_geo = new_drill.buffer(new_dia / 2.0)
current_tooldias = []
if tools:
for tool in tools:
if tools[tool] and 'tooldia' in tools[tool]:
current_tooldias.append(
app_obj.dec_format(tools[tool]['tooldia'], digits)
)
formatted_new_dia = app_obj.dec_format(new_dia, digits)
if formatted_new_dia in current_tooldias:
for tool in tools:
if app_obj.dec_format(tools[tool]["tooldia"], digits) == formatted_new_dia:
if new_drill not in tools[tool]['drills']:
tools[tool]['drills'].append(new_drill)
tools[tool]['solid_geometry'].append(deepcopy(new_drill_geo))
else:
tools[tooluid] = {
'tooldia': new_dia,
'drills': [new_drill],
'slots': [],
'solid_geometry': [new_drill_geo]
}
tooluid += 1
try:
obj_init.solid_geometry.append(new_drill_geo)
except (TypeError, AttributeError):
obj_init.solid_geometry = [new_drill_geo]
elif isinstance(geo_dict['follow'], LineString):
geo_coords = list(geo_dict['follow'].coords)
# slots can have only a start and stop point and no intermediate points
if len(geo_coords) != 2:
continue
geo = geo_dict['solid']
try:
new_dia = obj.tools[apid]['size']
except Exception:
continue
new_slot = (Point(geo_coords[0]), Point(geo_coords[1]))
new_slot_geo = geo
current_tooldias = []
if tools:
for tool in tools:
if tools[tool] and 'tooldia' in tools[tool]:
current_tooldias.append(
float('%.*f' % (self.decimals, tools[tool]['tooldia']))
)
if float('%.*f' % (self.decimals, new_dia)) in current_tooldias:
for tool in tools:
if float('%.*f' % (self.decimals, tools[tool]["tooldia"])) == float(
'%.*f' % (self.decimals, new_dia)):
if new_slot not in tools[tool]['slots']:
tools[tool]['slots'].append(new_slot)
tools[tool]['solid_geometry'].append(deepcopy(new_slot_geo))
else:
tools[tooluid] = {}
tools[tooluid]['tooldia'] = new_dia
tools[tooluid]['drills'] = []
tools[tooluid]['slots'] = [new_slot]
tools[tooluid]['solid_geometry'] = [new_slot_geo]
tooluid += 1
try:
obj_init.solid_geometry.append(new_slot_geo)
except (TypeError, AttributeError):
obj_init.solid_geometry = [new_slot_geo]
obj_init.tools = deepcopy(tools)
obj_init.solid_geometry = unary_union(obj_init.solid_geometry)
if not obj_init.solid_geometry:
return 'fail'
obj_init.source_file = app_obj.f_handlers.export_excellon(obj_name=outname, local_use=obj_init,
filename=None, use_thread=False)
if conv_obj_name is None:
if not self.collection.get_selected():
self.log.warning("App.convert_any2excellon--> No object selected")
self.inform.emit('[WARNING_NOTCL] %s' % _("No object is selected."))
return
for obj in self.collection.get_selected():
obj_name = obj.obj_options["name"]
outname = "%s_conv" % str(obj_name)
try:
if obj.kind == 'gerber':
self.app_obj.new_object("excellon", outname, initialize_from_gerber)
elif obj.kind == 'geometry':
self.app_obj.new_object("excellon", outname, initialize_from_geometry)
else:
self.log.warning("App.convert_any2excellon --> This is no valid object for conversion.")
except Exception as e:
return "Operation failed: %s" % str(e)
else:
outname = conv_obj_name
obj = self.collection.get_by_name(outname)
try:
if obj.kind == 'gerber':
self.app_obj.new_object("excellon", outname, initialize_from_gerber)
elif obj.kind == 'geometry':
self.app_obj.new_object("excellon", outname, initialize_from_geometry)
else:
self.log.warning("App.convert_any2excellon --> This is no valid object for conversion.")
except Exception as e:
self.log.error("App.convert_any2excellon() --> %s" % str(e))
return "Operation failed: %s" % str(e)
def abort_all_tasks(self):
"""
Executed when a certain key combo is pressed (Ctrl+Alt+X). Will abort current task
@@ -6044,7 +5363,7 @@ class App(QtCore.QObject):
self.ui.toggle_coords(checked=self.options["global_coords_bar_show"])
self.ui.toggle_delta_coords(checked=self.options["global_delta_coords_bar_show"])
def on_plot_area_tab_double_clicked(self, index: int):
def on_plot_area_tab_double_clicked(self):
# tab_obj_name = self.ui.plot_tab_area.widget(index).objectName()
# print(tab_obj_name)
self.ui.on_toggle_notebook()