diff --git a/CHANGELOG.md b/CHANGELOG.md index 974a2c6e..d32cc5e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ CHANGELOG for FlatCAM beta 9.06.2020 - fixed a possible problem in generating bounds value for a solid_geometry that have empty geo elements +- added ability to merge tools when merging Geometry objects if they share the same attributes like: diameter, tool_type or type +- added a control in Edit -> Preferences -> Geometry to control if to merge/fuse tools during Geometry merging 8.06.2020 diff --git a/appGUI/preferences/PreferencesUIManager.py b/appGUI/preferences/PreferencesUIManager.py index d935cf19..1ebae577 100644 --- a/appGUI/preferences/PreferencesUIManager.py +++ b/appGUI/preferences/PreferencesUIManager.py @@ -261,11 +261,12 @@ class PreferencesUIManager: self.ui.excellon_defaults_form.excellon_editor_group.slot_array_circular_angle_entry, # Geometry General - "geometry_plot": self.ui.geometry_defaults_form.geometry_gen_group.plot_cb, - "geometry_multicolored": self.ui.geometry_defaults_form.geometry_gen_group.multicolored_cb, - "geometry_circle_steps": self.ui.geometry_defaults_form.geometry_gen_group.circle_steps_entry, - "geometry_cnctooldia": self.ui.geometry_defaults_form.geometry_gen_group.cnctooldia_entry, - "geometry_plot_line": self.ui.geometry_defaults_form.geometry_gen_group.line_color_entry, + "geometry_plot": self.ui.geometry_defaults_form.geometry_gen_group.plot_cb, + "geometry_multicolored": self.ui.geometry_defaults_form.geometry_gen_group.multicolored_cb, + "geometry_circle_steps": self.ui.geometry_defaults_form.geometry_gen_group.circle_steps_entry, + "geometry_cnctooldia": self.ui.geometry_defaults_form.geometry_gen_group.cnctooldia_entry, + "geometry_merge_fuse_tools": self.ui.geometry_defaults_form.geometry_gen_group.fuse_tools_cb, + "geometry_plot_line": self.ui.geometry_defaults_form.geometry_gen_group.line_color_entry, # Geometry Options "geometry_cutz": self.ui.geometry_defaults_form.geometry_opt_group.cutz_entry, diff --git a/appGUI/preferences/geometry/GeometryGenPrefGroupUI.py b/appGUI/preferences/geometry/GeometryGenPrefGroupUI.py index 7040a877..34658d0b 100644 --- a/appGUI/preferences/geometry/GeometryGenPrefGroupUI.py +++ b/appGUI/preferences/geometry/GeometryGenPrefGroupUI.py @@ -86,9 +86,26 @@ class GeometryGenPrefGroupUI(OptionsGroupUI): separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) grid0.addWidget(separator_line, 9, 0, 1, 2) + # Fuse Tools + self.join_geo_label = QtWidgets.QLabel('%s:' % _('Join Geometry')) + grid0.addWidget(self.join_geo_label, 10, 0, 1, 2) + + self.fuse_tools_cb = FCCheckBox(_("Fuse Tools")) + self.fuse_tools_cb.setToolTip( + _("When checked the joined (merged) geometry object tools\n" + "will be merged also but only if they share the same attributes,\n" + "like diameter, tool_type or type.") + ) + grid0.addWidget(self.fuse_tools_cb, 11, 0, 1, 2) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 12, 0, 1, 2) + # Geometry Object Color - self.gerber_color_label = QtWidgets.QLabel('%s' % _('Object Color')) - grid0.addWidget(self.gerber_color_label, 10, 0, 1, 2) + self.gerber_color_label = QtWidgets.QLabel('%s:' % _('Object Color')) + grid0.addWidget(self.gerber_color_label, 13, 0, 1, 2) # Plot Line Color self.line_color_label = QtWidgets.QLabel('%s:' % _('Outline')) @@ -97,8 +114,8 @@ class GeometryGenPrefGroupUI(OptionsGroupUI): ) self.line_color_entry = FCColorEntry() - grid0.addWidget(self.line_color_label, 11, 0) - grid0.addWidget(self.line_color_entry, 11, 1) + grid0.addWidget(self.line_color_label, 14, 0) + grid0.addWidget(self.line_color_entry, 14, 1) self.layout.addStretch() diff --git a/appObjects/FlatCAMGeometry.py b/appObjects/FlatCAMGeometry.py index b0f84ee2..a82383d8 100644 --- a/appObjects/FlatCAMGeometry.py +++ b/appObjects/FlatCAMGeometry.py @@ -22,6 +22,8 @@ import math import numpy as np from copy import deepcopy import traceback +from collections import defaultdict +from functools import reduce import gettext import appTranslation as fcTranslate @@ -2773,13 +2775,14 @@ class GeometryObject(FlatCAMObj, Geometry): self.plot() @staticmethod - def merge(geo_list, geo_final, multigeo=None): + def merge(geo_list, geo_final, multigeo=None, fuse_tools=None): """ Merges the geometry of objects in grb_list into the geometry of geo_final. - :param geo_list: List of GerberObject Objects to join. - :param geo_final: Destination GerberObject object. - :param multigeo: if the merged geometry objects are of type MultiGeo + :param geo_list: List of GerberObject Objects to join. + :param geo_final: Destination GerberObject object. + :param multigeo: if the merged geometry objects are of type MultiGeo + :param fuse_tools: If True will try to fuse tools of the same type for the Geometry objects :return: None """ @@ -2834,38 +2837,52 @@ class GeometryObject(FlatCAMObj, Geometry): geo_final.options.update(new_options) geo_final.solid_geometry = new_solid_geometry - # merge the geometries of the tools that share the same tool diameter and the same tool_type and the same type - final_tools = {} - same_dia = {} - same_type = {} - same_tool_type = {} + if new_tools and fuse_tools is True: + # merge the geometries of the tools that share the same tool diameter and the same tool_type + # and the same type + final_tools = {} + same_dia = defaultdict(list) + same_type = defaultdict(list) + same_tool_type = defaultdict(list) - # find tools that have the same diameter and group them by diameter - for k, v in new_tools.items(): - if v['tooldia'] not in same_dia: - same_dia[v['tooldia']] = [k] - else: + # find tools that have the same diameter and group them by diameter + for k, v in new_tools.items(): same_dia[v['tooldia']].append(k) - # find tools that have the same type and group them by type - for k, v in new_tools.items(): - if v['type'] not in same_type: - same_type[v['type']] = [k] - else: + # find tools that have the same type and group them by type + for k, v in new_tools.items(): same_type[v['type']].append(k) - # find tools that have the same tool_type and group them by tool_type - for k, v in new_tools.items(): - if v['tool_type'] not in same_tool_type: - same_tool_type[v['tool_type']] = [k] - else: + # find tools that have the same tool_type and group them by tool_type + for k, v in new_tools.items(): same_tool_type[v['tool_type']].append(k) - print(same_dia) - print(same_type) - print(same_tool_type) + # find the intersections in the above groups + intersect_list = [] + for dia, dia_list in same_dia.items(): + for ty, type_list in same_type.items(): + for t_ty, tool_type_list in same_tool_type.items(): + intersection = reduce(np.intersect1d, (dia_list, type_list, tool_type_list)).tolist() + if intersection: + intersect_list.append(intersection) - geo_final.tools = new_tools + new_tool_nr = 1 + for i_lst in intersect_list: + new_solid_geo = [] + for old_tool in i_lst: + new_solid_geo += new_tools[old_tool]['solid_geometry'] + + if new_solid_geo: + final_tools[new_tool_nr] = \ + { + k: deepcopy(new_tools[old_tool][k]) for k in new_tools[old_tool] if k != 'solid_geometry' + } + final_tools[new_tool_nr]['solid_geometry'] = deepcopy(new_solid_geo) + new_tool_nr += 1 + else: + final_tools = new_tools + + geo_final.tools = final_tools @staticmethod def get_pts(o): diff --git a/app_Main.py b/app_Main.py index b800d6d7..fdb54823 100644 --- a/app_Main.py +++ b/app_Main.py @@ -3816,10 +3816,12 @@ class App(QtCore.QObject): "Check the generated GCODE.")) return + fuse_tools = self.defaults["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, multigeo=True) + GeometryObject.merge(geo_list=objs, geo_final=geo_obj, multigeo=True, fuse_tools=fuse_tools) app.inform.emit('[success] %s.' % _("Geometry merging finished")) # rename all the ['name] key in obj.tools[tooluid]['data'] to the obj_name_multi @@ -3829,7 +3831,7 @@ class App(QtCore.QObject): 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, multigeo=False) + GeometryObject.merge(geo_list=objs, geo_final=geo_obj, multigeo=False, fuse_tools=fuse_tools) app.inform.emit('[success] %s.' % _("Geometry merging finished")) # rename all the ['name] key in obj.tools[tooluid]['data'] to the obj_name_multi diff --git a/defaults.py b/defaults.py index 2de09902..747d1b7f 100644 --- a/defaults.py +++ b/defaults.py @@ -314,6 +314,7 @@ class FlatCAMDefaults: "geometry_multicolored": False, "geometry_circle_steps": 64, "geometry_cnctooldia": "2.4", + "geometry_merge_fuse_tools": True, "geometry_plot_line": "#FF0000", # Geometry Options