- modified the Cutout Tool to generate multi-geo objects therefore the set geometry parameters will populate the Geometry Object UI

- modified the Panelize Tool to optimize the output from Cutout Tool such that there are no longer overlapping cuts
- some string corrections
This commit is contained in:
Marius Stanciu
2020-05-02 15:56:30 +03:00
committed by Marius
parent 48b3f8d65a
commit ada271cbd6
23 changed files with 238 additions and 137 deletions

View File

@@ -293,12 +293,12 @@ class CutOut(FlatCAMTool):
font-weight: bold;
}
""")
self.layout.addWidget(self.rect_cutout_object_btn)
grid0.addWidget(self.rect_cutout_object_btn, 21, 0, 1, 2)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
grid0.addWidget(separator_line, 21, 0, 1, 2)
grid0.addWidget(separator_line, 22, 0, 1, 2)
# Title5
title_manual_label = QtWidgets.QLabel("<font size=4><b>%s</b></font>" % _('B. Manual Bridge Gaps'))
@@ -307,7 +307,7 @@ class CutOut(FlatCAMTool):
"This is done by mouse clicking on the perimeter of the\n"
"Geometry object that is used as a cutout object. ")
)
grid0.addWidget(title_manual_label, 22, 0, 1, 2)
grid0.addWidget(title_manual_label, 23, 0, 1, 2)
# Manual Geo Object
self.man_object_combo = FCComboBox()
@@ -322,8 +322,8 @@ class CutOut(FlatCAMTool):
)
# self.man_object_label.setMinimumWidth(60)
grid0.addWidget(self.man_object_label, 23, 0, 1, 2)
grid0.addWidget(self.man_object_combo, 24, 0, 1, 2)
grid0.addWidget(self.man_object_label, 25, 0, 1, 2)
grid0.addWidget(self.man_object_combo, 26, 0, 1, 2)
self.man_geo_creation_btn = FCButton(_("Generate Manual Geometry"))
self.man_geo_creation_btn.setToolTip(
@@ -338,7 +338,7 @@ class CutOut(FlatCAMTool):
font-weight: bold;
}
""")
grid0.addWidget(self.man_geo_creation_btn, 25, 0, 1, 2)
grid0.addWidget(self.man_geo_creation_btn, 28, 0, 1, 2)
self.man_gaps_creation_btn = FCButton(_("Manual Add Bridge Gaps"))
self.man_gaps_creation_btn.setToolTip(
@@ -354,7 +354,7 @@ class CutOut(FlatCAMTool):
font-weight: bold;
}
""")
grid0.addWidget(self.man_gaps_creation_btn, 27, 0, 1, 2)
grid0.addWidget(self.man_gaps_creation_btn, 30, 0, 1, 2)
self.layout.addStretch()
@@ -394,6 +394,9 @@ class CutOut(FlatCAMTool):
self.x_pos = None
self.y_pos = None
# store the default data for the resulting Geometry Object
self.default_data = {}
# Signals
self.ff_cutout_object_btn.clicked.connect(self.on_freeform_cutout)
self.rect_cutout_object_btn.clicked.connect(self.on_rectangular_cutout)
@@ -454,6 +457,48 @@ class CutOut(FlatCAMTool):
self.convex_box.set_value(self.app.defaults['tools_cutout_convexshape'])
self.type_obj_radio.set_value('grb')
self.default_data.update({
"plot": True,
"cutz": float(self.app.defaults["geometry_cutz"]),
"multidepth": self.app.defaults["geometry_multidepth"],
"depthperpass": float(self.app.defaults["geometry_depthperpass"]),
"vtipdia": float(self.app.defaults["geometry_vtipdia"]),
"vtipangle": float(self.app.defaults["geometry_vtipangle"]),
"travelz": float(self.app.defaults["geometry_travelz"]),
"feedrate": float(self.app.defaults["geometry_feedrate"]),
"feedrate_z": float(self.app.defaults["geometry_feedrate_z"]),
"feedrate_rapid": float(self.app.defaults["geometry_feedrate_rapid"]),
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
"dwell": self.app.defaults["geometry_dwell"],
"dwelltime": float(self.app.defaults["geometry_dwelltime"]),
"ppname_g": self.app.defaults["geometry_ppname_g"],
"extracut": self.app.defaults["geometry_extracut"],
"extracut_length": float(self.app.defaults["geometry_extracut_length"]),
"toolchange": self.app.defaults["geometry_toolchange"],
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
"toolchangez": float(self.app.defaults["geometry_toolchangez"]),
"startz": self.app.defaults["geometry_startz"],
"endz": float(self.app.defaults["geometry_endz"]),
# NCC
"tools_nccoperation": self.app.defaults["tools_nccoperation"],
"tools_nccmilling_type": self.app.defaults["tools_nccmilling_type"],
"tools_nccoverlap": float(self.app.defaults["tools_nccoverlap"]),
"tools_nccmargin": float(self.app.defaults["tools_nccmargin"]),
"tools_nccmethod": self.app.defaults["tools_nccmethod"],
"tools_nccconnect": self.app.defaults["tools_nccconnect"],
"tools_ncccontour": self.app.defaults["tools_ncccontour"],
"tools_ncc_offset_choice": self.app.defaults["tools_ncc_offset_choice"],
"tools_ncc_offset_value": float(self.app.defaults["tools_ncc_offset_value"]),
# Paint
"tools_paintoverlap": float(self.app.defaults["tools_paintoverlap"]),
"tools_paintmargin": float(self.app.defaults["tools_paintmargin"]),
"tools_paintmethod": self.app.defaults["tools_paintmethod"],
"tools_pathconnect": self.app.defaults["tools_pathconnect"],
"tools_paintcontour": self.app.defaults["tools_paintcontour"],
})
def on_freeform_cutout(self):
log.debug("Cutout.on_freeform_cutout() was launched ...")
@@ -622,8 +667,8 @@ class CutOut(FlatCAMTool):
solid_geo += cutout_handler(geom=geom_struct)
geo_obj.solid_geometry = deepcopy(solid_geo)
xmin, ymin, xmax, ymax = recursive_bounds(geo_obj.solid_geometry)
geo_obj.solid_geometry = deepcopy(solid_geo)
geo_obj.options['xmin'] = xmin
geo_obj.options['ymin'] = ymin
geo_obj.options['xmax'] = xmax
@@ -633,6 +678,23 @@ class CutOut(FlatCAMTool):
geo_obj.options['multidepth'] = self.mpass_cb.get_value()
geo_obj.options['depthperpass'] = self.maxdepth_entry.get_value()
geo_obj.tools.update({
1: {
'tooldia': str(dia),
'offset': 'Path',
'offset_value': 0.0,
'type': _('Rough'),
'tool_type': 'C1',
'data': self.default_data,
'solid_geometry': geo_obj.solid_geometry
}
})
geo_obj.multigeo = True
geo_obj.tools[1]['data']['name'] = outname
geo_obj.tools[1]['data']['cutz'] = self.cutz_entry.get_value()
geo_obj.tools[1]['data']['multidepth'] = self.mpass_cb.get_value()
geo_obj.tools[1]['data']['depthperpass'] = self.maxdepth_entry.get_value()
outname = cutout_obj.options["name"] + "_cutout"
self.app.new_object('geometry', outname, geo_init)
@@ -759,6 +821,7 @@ class CutOut(FlatCAMTool):
return proc_geometry
if kind == 'single':
# fuse the lines
object_geo = unary_union(object_geo)
xmin, ymin, xmax, ymax = object_geo.bounds
@@ -805,11 +868,28 @@ class CutOut(FlatCAMTool):
_("Rectangular cutout with negative margin is not possible."))
return "fail"
geo_obj.solid_geometry = deepcopy(solid_geo)
geo_obj.options['cnctooldia'] = str(dia)
geo_obj.options['cutz'] = self.cutz_entry.get_value()
geo_obj.options['multidepth'] = self.mpass_cb.get_value()
geo_obj.options['depthperpass'] = self.maxdepth_entry.get_value()
geo_obj.solid_geometry = deepcopy(solid_geo)
geo_obj.tools.update({
1: {
'tooldia': str(dia),
'offset': 'Path',
'offset_value': 0.0,
'type': _('Rough'),
'tool_type': 'C1',
'data': self.default_data,
'solid_geometry': geo_obj.solid_geometry
}
})
geo_obj.multigeo = True
geo_obj.tools[1]['data']['name'] = outname
geo_obj.tools[1]['data']['cutz'] = self.cutz_entry.get_value()
geo_obj.tools[1]['data']['multidepth'] = self.mpass_cb.get_value()
geo_obj.tools[1]['data']['depthperpass'] = self.maxdepth_entry.get_value()
outname = cutout_obj.options["name"] + "_cutout"
ret = self.app.new_object('geometry', outname, geo_init)
@@ -954,6 +1034,23 @@ class CutOut(FlatCAMTool):
geo_obj.options['multidepth'] = self.mpass_cb.get_value()
geo_obj.options['depthperpass'] = self.maxdepth_entry.get_value()
geo_obj.tools.update({
1: {
'tooldia': str(dia),
'offset': 'Path',
'offset_value': 0.0,
'type': _('Rough'),
'tool_type': 'C1',
'data': self.default_data,
'solid_geometry': geo_obj.solid_geometry
}
})
geo_obj.multigeo = True
geo_obj.tools[1]['data']['name'] = outname
geo_obj.tools[1]['data']['cutz'] = self.cutz_entry.get_value()
geo_obj.tools[1]['data']['multidepth'] = self.mpass_cb.get_value()
geo_obj.tools[1]['data']['depthperpass'] = self.maxdepth_entry.get_value()
outname = cutout_obj.options["name"] + "_cutout"
self.app.new_object('geometry', outname, geo_init)

View File

@@ -14,6 +14,8 @@ from copy import deepcopy
import numpy as np
import shapely.affinity as affinity
from shapely.ops import unary_union
from shapely.geometry import LineString
import gettext
import FlatCAMTranslation as fcTranslate
@@ -402,19 +404,18 @@ class Panelize(FlatCAMTool):
def on_panelize(self):
name = self.object_combo.currentText()
# Get source object.
# Get source object to be panelized.
try:
panel_obj = self.app.collection.get_by_name(str(name))
panel_source_obj = self.app.collection.get_by_name(str(name))
except Exception as e:
log.debug("Panelize.on_panelize() --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
(_("Could not retrieve object"), name))
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), name))
return "Could not retrieve object: %s" % name
if panel_obj is None:
if panel_source_obj is None:
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
(_("Object not found"), panel_obj))
return "Object not found: %s" % panel_obj
(_("Object not found"), panel_source_obj))
return "Object not found: %s" % panel_source_obj
boxname = self.box_combo.currentText()
@@ -422,17 +423,15 @@ class Panelize(FlatCAMTool):
box = self.app.collection.get_by_name(boxname)
except Exception as e:
log.debug("Panelize.on_panelize() --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
(_("Could not retrieve object"), boxname))
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), boxname))
return "Could not retrieve object: %s" % boxname
if box is None:
self.app.inform.emit('[WARNING_NOTCL]%s: %s' %
(_("No object Box. Using instead"), panel_obj))
self.app.inform.emit('[WARNING_NOTCL]%s: %s' % (_("No object Box. Using instead"), panel_source_obj))
self.reference_radio.set_value('bbox')
if self.reference_radio.get_value() == 'bbox':
box = panel_obj
box = panel_source_obj
self.outname = name + '_panelized'
@@ -478,20 +477,20 @@ class Panelize(FlatCAMTool):
rows -= 1
panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1))
if panel_obj.kind == 'excellon' or panel_obj.kind == 'geometry':
if panel_source_obj.kind == 'excellon' or panel_source_obj.kind == 'geometry':
# make a copy of the panelized Excellon or Geometry tools
copied_tools = {}
for tt, tt_val in list(panel_obj.tools.items()):
for tt, tt_val in list(panel_source_obj.tools.items()):
copied_tools[tt] = deepcopy(tt_val)
if panel_obj.kind == 'gerber':
if panel_source_obj.kind == 'gerber':
# make a copy of the panelized Gerber apertures
copied_apertures = {}
for tt, tt_val in list(panel_obj.apertures.items()):
for tt, tt_val in list(panel_source_obj.apertures.items()):
copied_apertures[tt] = deepcopy(tt_val)
def panelize_2():
if panel_obj is not None:
def panelize_worker():
if panel_source_obj is not None:
self.app.inform.emit(_("Generating panel ... "))
def job_init_excellon(obj_fin, app_obj):
@@ -501,15 +500,15 @@ class Panelize(FlatCAMTool):
obj_fin.slots = []
obj_fin.solid_geometry = []
for option in panel_obj.options:
for option in panel_source_obj.options:
if option != 'name':
try:
obj_fin.options[option] = panel_obj.options[option]
obj_fin.options[option] = panel_source_obj.options[option]
except KeyError:
log.warning("Failed to copy option. %s" % str(option))
geo_len_drills = len(panel_obj.drills) if panel_obj.drills else 0
geo_len_slots = len(panel_obj.slots) if panel_obj.slots else 0
geo_len_drills = len(panel_source_obj.drills) if panel_source_obj.drills else 0
geo_len_slots = len(panel_source_obj.slots) if panel_source_obj.slots else 0
element = 0
for row in range(rows):
@@ -518,9 +517,9 @@ class Panelize(FlatCAMTool):
element += 1
old_disp_number = 0
if panel_obj.drills:
if panel_source_obj.drills:
drill_nr = 0
for tool_dict in panel_obj.drills:
for tool_dict in panel_source_obj.drills:
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
@@ -543,9 +542,9 @@ class Panelize(FlatCAMTool):
disp_number))
old_disp_number = disp_number
if panel_obj.slots:
if panel_source_obj.slots:
slot_nr = 0
for tool_dict in panel_obj.slots:
for tool_dict in panel_source_obj.slots:
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
@@ -574,8 +573,8 @@ class Panelize(FlatCAMTool):
currenty += lenghty
obj_fin.create_geometry()
obj_fin.zeros = panel_obj.zeros
obj_fin.units = panel_obj.units
obj_fin.zeros = panel_source_obj.zeros
obj_fin.units = panel_source_obj.units
self.app.proc_container.update_view_text('')
def job_init_geometry(obj_fin, app_obj):
@@ -598,36 +597,36 @@ class Panelize(FlatCAMTool):
obj_fin.solid_geometry = []
# create the initial structure on which to create the panel
if panel_obj.kind == 'geometry':
obj_fin.multigeo = panel_obj.multigeo
if panel_source_obj.kind == 'geometry':
obj_fin.multigeo = panel_source_obj.multigeo
obj_fin.tools = copied_tools
if panel_obj.multigeo is True:
for tool in panel_obj.tools:
if panel_source_obj.multigeo is True:
for tool in panel_source_obj.tools:
obj_fin.tools[tool]['solid_geometry'][:] = []
elif panel_obj.kind == 'gerber':
elif panel_source_obj.kind == 'gerber':
obj_fin.apertures = copied_apertures
for ap in obj_fin.apertures:
obj_fin.apertures[ap]['geometry'] = []
# find the number of polygons in the source solid_geometry
geo_len = 0
if panel_obj.kind == 'geometry':
if panel_obj.multigeo is True:
for tool in panel_obj.tools:
if panel_source_obj.kind == 'geometry':
if panel_source_obj.multigeo is True:
for tool in panel_source_obj.tools:
try:
geo_len += len(panel_obj.tools[tool]['solid_geometry'])
geo_len += len(panel_source_obj.tools[tool]['solid_geometry'])
except TypeError:
geo_len += 1
else:
try:
geo_len = len(panel_obj.solid_geometry)
geo_len = len(panel_source_obj.solid_geometry)
except TypeError:
geo_len = 1
elif panel_obj.kind == 'gerber':
for ap in panel_obj.apertures:
if 'geometry' in panel_obj.apertures[ap]:
elif panel_source_obj.kind == 'gerber':
for ap in panel_source_obj.apertures:
if 'geometry' in panel_source_obj.apertures[ap]:
try:
geo_len += len(panel_obj.apertures[ap]['geometry'])
geo_len += len(panel_source_obj.apertures[ap]['geometry'])
except TypeError:
geo_len += 1
@@ -639,29 +638,23 @@ class Panelize(FlatCAMTool):
element += 1
old_disp_number = 0
if panel_obj.kind == 'geometry':
if panel_obj.multigeo is True:
for tool in panel_obj.tools:
# Will panelize a Geometry Object
if panel_source_obj.kind == 'geometry':
if panel_source_obj.multigeo is True:
for tool in panel_source_obj.tools:
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
# geo = translate_recursion(panel_obj.tools[tool]['solid_geometry'])
# if isinstance(geo, list):
# obj_fin.tools[tool]['solid_geometry'] += geo
# else:
# obj_fin.tools[tool]['solid_geometry'].append(geo)
# calculate the number of polygons
geo_len = len(panel_obj.tools[tool]['solid_geometry'])
geo_len = len(panel_source_obj.tools[tool]['solid_geometry'])
pol_nr = 0
for geo_el in panel_obj.tools[tool]['solid_geometry']:
for geo_el in panel_source_obj.tools[tool]['solid_geometry']:
trans_geo = translate_recursion(geo_el)
obj_fin.tools[tool]['solid_geometry'].append(trans_geo)
pol_nr += 1
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
if old_disp_number < disp_number <= 100:
self.app.proc_container.update_view_text(' %s: %d %d%%' %
(_("Copy"),
@@ -669,23 +662,18 @@ class Panelize(FlatCAMTool):
disp_number))
old_disp_number = disp_number
else:
# geo = translate_recursion(panel_obj.solid_geometry)
# if isinstance(geo, list):
# obj_fin.solid_geometry += geo
# else:
# obj_fin.solid_geometry.append(geo)
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
try:
# calculate the number of polygons
geo_len = len(panel_obj.solid_geometry)
geo_len = len(panel_source_obj.solid_geometry)
except TypeError:
geo_len = 1
pol_nr = 0
try:
for geo_el in panel_obj.solid_geometry:
for geo_el in panel_source_obj.solid_geometry:
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
@@ -702,21 +690,18 @@ class Panelize(FlatCAMTool):
int(element),
disp_number))
old_disp_number = disp_number
except TypeError:
trans_geo = translate_recursion(panel_obj.solid_geometry)
trans_geo = translate_recursion(panel_source_obj.solid_geometry)
obj_fin.solid_geometry.append(trans_geo)
# Will panelize a Gerber Object
else:
# geo = translate_recursion(panel_obj.solid_geometry)
# if isinstance(geo, list):
# obj_fin.solid_geometry += geo
# else:
# obj_fin.solid_geometry.append(geo)
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
try:
for geo_el in panel_obj.solid_geometry:
for geo_el in panel_source_obj.solid_geometry:
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
@@ -724,21 +709,21 @@ class Panelize(FlatCAMTool):
trans_geo = translate_recursion(geo_el)
obj_fin.solid_geometry.append(trans_geo)
except TypeError:
trans_geo = translate_recursion(panel_obj.solid_geometry)
trans_geo = translate_recursion(panel_source_obj.solid_geometry)
obj_fin.solid_geometry.append(trans_geo)
for apid in panel_obj.apertures:
for apid in panel_source_obj.apertures:
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
if 'geometry' in panel_obj.apertures[apid]:
if 'geometry' in panel_source_obj.apertures[apid]:
try:
# calculate the number of polygons
geo_len = len(panel_obj.apertures[apid]['geometry'])
geo_len = len(panel_source_obj.apertures[apid]['geometry'])
except TypeError:
geo_len = 1
pol_nr = 0
for el in panel_obj.apertures[apid]['geometry']:
for el in panel_source_obj.apertures[apid]['geometry']:
if self.app.abort_flag:
# graceful abort requested by the user
raise grace
@@ -771,20 +756,34 @@ class Panelize(FlatCAMTool):
currentx += lenghtx
currenty += lenghty
print("before", obj_fin.tools)
if panel_source_obj.kind == 'geometry' and panel_source_obj.multigeo is True:
# I'm going to do this only here as a fix for panelizing cutouts
# I'm going to separate linestrings out of the solid geometry from other
# possible type of elements and apply unary_union on them to fuse them
for tool in obj_fin.tools:
lines = []
other_geo = []
for geo in obj_fin.tools[tool]['solid_geometry']:
if isinstance(geo, LineString):
lines.append(geo)
else:
other_geo.append(geo)
fused_lines = list(unary_union(lines))
obj_fin.tools[tool]['solid_geometry'] = fused_lines + other_geo
print("after", obj_fin.tools)
if panel_type == 'gerber':
self.app.inform.emit('%s' % _("Generating panel ... Adding the Gerber code."))
obj_fin.source_file = self.app.export_gerber(obj_name=self.outname, filename=None,
local_use=obj_fin, use_thread=False)
# app_obj.log.debug("Found %s geometries. Creating a panel geometry cascaded union ..." %
# len(obj_fin.solid_geometry))
# obj_fin.solid_geometry = cascaded_union(obj_fin.solid_geometry)
# app_obj.log.debug("Finished creating a cascaded union for the panel.")
self.app.proc_container.update_view_text('')
self.app.inform.emit('%s: %d' % (_("Generating panel... Spawning copies"), (int(rows * columns))))
if panel_obj.kind == 'excellon':
if panel_source_obj.kind == 'excellon':
self.app.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True)
else:
self.app.new_object(panel_type, self.outname, job_init_geometry, plot=True, autoselected=True)
@@ -801,7 +800,7 @@ class Panelize(FlatCAMTool):
def job_thread(app_obj):
try:
panelize_2()
panelize_worker()
self.app.inform.emit('[success] %s' % _("Panel created successfully."))
except Exception as ee:
proc.done()

View File

@@ -155,7 +155,7 @@ class SolderPaste(FlatCAMTool):
step1_lbl = QtWidgets.QLabel("<b>%s:</b>" % _('STEP 1'))
step1_lbl.setToolTip(
_("First step is to select a number of nozzle tools for usage\n"
"and then optionally modify the GCode parameters bellow.")
"and then optionally modify the GCode parameters below.")
)
step1_description_lbl = QtWidgets.QLabel(_("Select tools.\n"
"Modify parameters."))

View File

@@ -97,7 +97,7 @@ class ToolSub(FlatCAMTool):
form_layout.addRow(self.sub_gerber_label, self.sub_gerber_combo)
self.intersect_btn = FCButton(_('Substract Gerber'))
self.intersect_btn = FCButton(_('Subtract Gerber'))
self.intersect_btn.setToolTip(
_("Will remove the area occupied by the subtractor\n"
"Gerber from the Target Gerber.\n"