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