- made confirmation messages for the values that are modified not to be printed in the Shell
- Isolation Tool: working on the Rest machining: almost there, perhaps I will use multiprocessing
This commit is contained in:
parent
14e6d5f63a
commit
15d94404a7
|
@ -153,17 +153,20 @@ class ObjectUI(QtWidgets.QWidget):
|
||||||
|
|
||||||
def confirmation_message(self, accepted, minval, maxval):
|
def confirmation_message(self, accepted, minval, maxval):
|
||||||
if accepted is False:
|
if accepted is False:
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
|
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' % (_("Edited value is out of range"),
|
||||||
(_("Edited value is out of range"), self.decimals, minval, self.decimals, maxval))
|
self.decimals,
|
||||||
|
minval,
|
||||||
|
self.decimals,
|
||||||
|
maxval), False)
|
||||||
else:
|
else:
|
||||||
self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
|
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
||||||
|
|
||||||
def confirmation_message_int(self, accepted, minval, maxval):
|
def confirmation_message_int(self, accepted, minval, maxval):
|
||||||
if accepted is False:
|
if accepted is False:
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s: [%d, %d]' %
|
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%d, %d]' %
|
||||||
(_("Edited value is out of range"), minval, maxval))
|
(_("Edited value is out of range"), minval, maxval), False)
|
||||||
else:
|
else:
|
||||||
self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
|
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
||||||
|
|
||||||
|
|
||||||
class GerberObjectUI(ObjectUI):
|
class GerberObjectUI(ObjectUI):
|
||||||
|
|
14
AppTool.py
14
AppTool.py
|
@ -277,16 +277,20 @@ class AppTool(QtWidgets.QWidget):
|
||||||
|
|
||||||
def confirmation_message(self, accepted, minval, maxval):
|
def confirmation_message(self, accepted, minval, maxval):
|
||||||
if accepted is False:
|
if accepted is False:
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
|
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' % (_("Edited value is out of range"),
|
||||||
(_("Edited value is out of range"), self.decimals, minval, self.decimals, maxval))
|
self.decimals,
|
||||||
|
minval,
|
||||||
|
self.decimals,
|
||||||
|
maxval), False)
|
||||||
else:
|
else:
|
||||||
self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
|
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
||||||
|
|
||||||
def confirmation_message_int(self, accepted, minval, maxval):
|
def confirmation_message_int(self, accepted, minval, maxval):
|
||||||
if accepted is False:
|
if accepted is False:
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s: [%d, %d]' % (_("Edited value is out of range"), minval, maxval))
|
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%d, %d]' %
|
||||||
|
(_("Edited value is out of range"), minval, maxval), False)
|
||||||
else:
|
else:
|
||||||
self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
|
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
||||||
|
|
||||||
def sizeHint(self):
|
def sizeHint(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -136,7 +136,7 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
_("This is the Tool Number.\n"
|
_("This is the Tool Number.\n"
|
||||||
"Non copper clearing will start with the tool with the biggest \n"
|
"Non copper clearing will start with the tool with the biggest \n"
|
||||||
"diameter, continuing until there are no more tools.\n"
|
"diameter, continuing until there are no more tools.\n"
|
||||||
"Only tools that create NCC clearing geometry will still be present\n"
|
"Only tools that create Isolation geometry will still be present\n"
|
||||||
"in the resulting geometry. This is because with some tools\n"
|
"in the resulting geometry. This is because with some tools\n"
|
||||||
"this function will not be able to create painting geometry.")
|
"this function will not be able to create painting geometry.")
|
||||||
)
|
)
|
||||||
|
@ -163,19 +163,19 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
self.tools_box.addLayout(grid1)
|
self.tools_box.addLayout(grid1)
|
||||||
|
|
||||||
# Tool order
|
# Tool order
|
||||||
self.ncc_order_label = QtWidgets.QLabel('%s:' % _('Tool order'))
|
self.order_label = QtWidgets.QLabel('%s:' % _('Tool order'))
|
||||||
self.ncc_order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n"
|
self.order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n"
|
||||||
"'No' --> means that the used order is the one in the tool table\n"
|
"'No' --> means that the used order is the one in the tool table\n"
|
||||||
"'Forward' --> means that the tools will be ordered from small to big\n"
|
"'Forward' --> means that the tools will be ordered from small to big\n"
|
||||||
"'Reverse' --> means that the tools will ordered from big to small\n\n"
|
"'Reverse' --> means that the tools will ordered from big to small\n\n"
|
||||||
"WARNING: using rest machining will automatically set the order\n"
|
"WARNING: using rest machining will automatically set the order\n"
|
||||||
"in reverse and disable this control."))
|
"in reverse and disable this control."))
|
||||||
|
|
||||||
self.order_radio = RadioSet([{'label': _('No'), 'value': 'no'},
|
self.order_radio = RadioSet([{'label': _('No'), 'value': 'no'},
|
||||||
{'label': _('Forward'), 'value': 'fwd'},
|
{'label': _('Forward'), 'value': 'fwd'},
|
||||||
{'label': _('Reverse'), 'value': 'rev'}])
|
{'label': _('Reverse'), 'value': 'rev'}])
|
||||||
|
|
||||||
grid1.addWidget(self.ncc_order_label, 1, 0)
|
grid1.addWidget(self.order_label, 1, 0)
|
||||||
grid1.addWidget(self.order_radio, 1, 1)
|
grid1.addWidget(self.order_radio, 1, 1)
|
||||||
|
|
||||||
separator_line = QtWidgets.QFrame()
|
separator_line = QtWidgets.QFrame()
|
||||||
|
@ -1082,10 +1082,7 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
|
|
||||||
sorted_tools = []
|
sorted_tools = []
|
||||||
for k, v in self.iso_tools.items():
|
for k, v in self.iso_tools.items():
|
||||||
if self.units == "IN":
|
sorted_tools.append(float('%.*f' % (self.decimals, float(v['tooldia']))))
|
||||||
sorted_tools.append(float('%.*f' % (self.decimals, float(v['tooldia']))))
|
|
||||||
else:
|
|
||||||
sorted_tools.append(float('%.*f' % (self.decimals, float(v['tooldia']))))
|
|
||||||
|
|
||||||
order = self.order_radio.get_value()
|
order = self.order_radio.get_value()
|
||||||
if order == 'fwd':
|
if order == 'fwd':
|
||||||
|
@ -1323,14 +1320,14 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
def on_rest_machining_check(self, state):
|
def on_rest_machining_check(self, state):
|
||||||
if state:
|
if state:
|
||||||
self.order_radio.set_value('rev')
|
self.order_radio.set_value('rev')
|
||||||
self.ncc_order_label.setDisabled(True)
|
self.order_label.setDisabled(True)
|
||||||
self.order_radio.setDisabled(True)
|
self.order_radio.setDisabled(True)
|
||||||
|
|
||||||
self.old_combine_state = self.combine_passes_cb.get_value()
|
self.old_combine_state = self.combine_passes_cb.get_value()
|
||||||
self.combine_passes_cb.set_value(True)
|
self.combine_passes_cb.set_value(True)
|
||||||
self.combine_passes_cb.setDisabled(True)
|
self.combine_passes_cb.setDisabled(True)
|
||||||
else:
|
else:
|
||||||
self.ncc_order_label.setDisabled(False)
|
self.order_label.setDisabled(False)
|
||||||
self.order_radio.setDisabled(False)
|
self.order_radio.setDisabled(False)
|
||||||
|
|
||||||
self.combine_passes_cb.set_value(self.old_combine_state)
|
self.combine_passes_cb.set_value(self.old_combine_state)
|
||||||
|
@ -1883,101 +1880,102 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
total_solid_geometry = []
|
total_solid_geometry = []
|
||||||
|
|
||||||
iso_name = iso_obj.options["name"]
|
iso_name = iso_obj.options["name"]
|
||||||
geometry = iso2geo
|
work_geo = iso_obj.solid_geometry if iso2geo is None else iso2geo
|
||||||
|
|
||||||
for tool in tools_storage:
|
sorted_tools = []
|
||||||
tool_dia = tools_storage[tool]['tooldia']
|
for k, v in self.iso_tools.items():
|
||||||
tool_type = tools_storage[tool]['tool_type']
|
sorted_tools.append(float('%.*f' % (self.decimals, float(v['tooldia']))))
|
||||||
tool_data = tools_storage[tool]['data']
|
|
||||||
|
|
||||||
to_follow = tool_data['tools_iso_follow']
|
order = self.order_radio.get_value()
|
||||||
|
if order == 'fwd':
|
||||||
|
sorted_tools.sort(reverse=False)
|
||||||
|
elif order == 'rev':
|
||||||
|
sorted_tools.sort(reverse=True)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
work_geo = geometry
|
for sorted_tool in sorted_tools:
|
||||||
if work_geo is None:
|
for tool in tools_storage:
|
||||||
work_geo = iso_obj.follow_geometry if to_follow else iso_obj.solid_geometry
|
if float('%.*f' % (self.decimals, tools_storage[tool]['tooldia'])) == sorted_tool:
|
||||||
|
|
||||||
iso_t = {
|
tool_dia = tools_storage[tool]['tooldia']
|
||||||
'ext': 0,
|
tool_type = tools_storage[tool]['tool_type']
|
||||||
'int': 1,
|
tool_data = tools_storage[tool]['data']
|
||||||
'full': 2
|
|
||||||
}[tool_data['tools_iso_isotype']]
|
|
||||||
|
|
||||||
passes = tool_data['tools_iso_passes']
|
iso_t = {
|
||||||
overlap = tool_data['tools_iso_overlap']
|
'ext': 0,
|
||||||
overlap /= 100.0
|
'int': 1,
|
||||||
|
'full': 2
|
||||||
|
}[tool_data['tools_iso_isotype']]
|
||||||
|
|
||||||
milling_type = tool_data['tools_iso_milling_type']
|
passes = tool_data['tools_iso_passes']
|
||||||
|
overlap = tool_data['tools_iso_overlap']
|
||||||
|
overlap /= 100.0
|
||||||
|
|
||||||
iso_except = tool_data['tools_iso_isoexcept']
|
milling_type = tool_data['tools_iso_milling_type']
|
||||||
|
# if milling type is climb then the move is counter-clockwise around features
|
||||||
|
mill_dir = True if milling_type == 'cl' else False
|
||||||
|
|
||||||
outname = "%s_%.*f" % (iso_obj.options["name"], self.decimals, float(tool_dia))
|
iso_except = tool_data['tools_iso_isoexcept']
|
||||||
|
|
||||||
iso_name = outname + "_iso"
|
outname = "%s_%.*f" % (iso_obj.options["name"], self.decimals, float(tool_dia))
|
||||||
if iso_t == 0:
|
|
||||||
iso_name = outname + "_ext_iso"
|
|
||||||
elif iso_t == 1:
|
|
||||||
iso_name = outname + "_int_iso"
|
|
||||||
|
|
||||||
# transfer the Cut Z and Vtip and VAngle values in case that we use the V-Shape tool in Gerber UI
|
iso_name = outname + "_iso"
|
||||||
if tool_type.lower() == 'v':
|
if iso_t == 0:
|
||||||
new_cutz = self.ui.cutz_spinner.get_value()
|
iso_name = outname + "_ext_iso"
|
||||||
new_vtipdia = self.ui.tipdia_spinner.get_value()
|
elif iso_t == 1:
|
||||||
new_vtipangle = self.ui.tipangle_spinner.get_value()
|
iso_name = outname + "_int_iso"
|
||||||
tool_type = 'V'
|
|
||||||
tool_data.update({
|
|
||||||
"name": iso_name,
|
|
||||||
"cutz": new_cutz,
|
|
||||||
"vtipdia": new_vtipdia,
|
|
||||||
"vtipangle": new_vtipangle,
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
tool_data.update({
|
|
||||||
"name": iso_name,
|
|
||||||
})
|
|
||||||
tool_type = 'C1'
|
|
||||||
|
|
||||||
solid_geo = []
|
# transfer the Cut Z and Vtip and VAngle values in case that we use the V-Shape tool in Gerber UI
|
||||||
for nr_pass in range(passes):
|
if tool_type.lower() == 'v':
|
||||||
iso_offset = tool_dia * ((2 * nr_pass + 1) / 2.0000001) - (nr_pass * overlap * tool_dia)
|
new_cutz = self.ui.cutz_spinner.get_value()
|
||||||
|
new_vtipdia = self.ui.tipdia_spinner.get_value()
|
||||||
|
new_vtipangle = self.ui.tipangle_spinner.get_value()
|
||||||
|
tool_type = 'V'
|
||||||
|
tool_data.update({
|
||||||
|
"name": iso_name,
|
||||||
|
"cutz": new_cutz,
|
||||||
|
"vtipdia": new_vtipdia,
|
||||||
|
"vtipangle": new_vtipangle,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
tool_data.update({
|
||||||
|
"name": iso_name,
|
||||||
|
})
|
||||||
|
tool_type = 'C1'
|
||||||
|
|
||||||
# if milling type is climb then the move is counter-clockwise around features
|
solid_geo, work_geo = self.generate_rest_geometry(geometry=work_geo, tooldia=tool_dia,
|
||||||
mill_dir = 1 if milling_type == 'cl' else 0
|
passes=passes, overlap=overlap, invert=mill_dir,
|
||||||
|
env_iso_type=iso_t)
|
||||||
|
|
||||||
iso_geo = self.generate_envelope(iso_offset, mill_dir, geometry=work_geo, env_iso_type=iso_t,
|
# ############################################################
|
||||||
follow=to_follow, nr_passes=nr_pass)
|
# ########## AREA SUBTRACTION ################################
|
||||||
if iso_geo == 'fail':
|
# ############################################################
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
|
if iso_except:
|
||||||
continue
|
self.app.proc_container.update_view_text(' %s' % _("Subtracting Geo"))
|
||||||
try:
|
solid_geo = self.area_subtraction(solid_geo)
|
||||||
for geo in iso_geo:
|
|
||||||
solid_geo.append(geo)
|
|
||||||
except TypeError:
|
|
||||||
solid_geo.append(iso_geo)
|
|
||||||
|
|
||||||
# ############################################################
|
if lim_area:
|
||||||
# ########## AREA SUBTRACTION ################################
|
self.app.proc_container.update_view_text(' %s' % _("Intersecting Geo"))
|
||||||
# ############################################################
|
solid_geo = self.area_intersection(solid_geo, intersection_geo=lim_area)
|
||||||
if iso_except:
|
|
||||||
self.app.proc_container.update_view_text(' %s' % _("Subtracting Geo"))
|
|
||||||
solid_geo = self.area_subtraction(solid_geo)
|
|
||||||
|
|
||||||
if lim_area:
|
tools_storage.update({
|
||||||
self.app.proc_container.update_view_text(' %s' % _("Intersecting Geo"))
|
tool: {
|
||||||
solid_geo = self.area_intersection(solid_geo, intersection_geo=lim_area)
|
'tooldia': float(tool_dia),
|
||||||
|
'offset': 'Path',
|
||||||
|
'offset_value': 0.0,
|
||||||
|
'type': _('Rough'),
|
||||||
|
'tool_type': tool_type,
|
||||||
|
'data': tool_data,
|
||||||
|
'solid_geometry': deepcopy(solid_geo)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
tools_storage.update({
|
total_solid_geometry += solid_geo
|
||||||
tool: {
|
|
||||||
'tooldia': float(tool_dia),
|
|
||||||
'offset': 'Path',
|
|
||||||
'offset_value': 0.0,
|
|
||||||
'type': _('Rough'),
|
|
||||||
'tool_type': tool_type,
|
|
||||||
'data': tool_data,
|
|
||||||
'solid_geometry': deepcopy(solid_geo)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
total_solid_geometry += solid_geo
|
# if the geometry is all isolated
|
||||||
|
if not work_geo:
|
||||||
|
break
|
||||||
|
|
||||||
def iso_init(geo_obj, app_obj):
|
def iso_init(geo_obj, app_obj):
|
||||||
geo_obj.options["cnctooldia"] = str(tool_dia)
|
geo_obj.options["cnctooldia"] = str(tool_dia)
|
||||||
|
@ -1989,11 +1987,12 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
if len(tools_storage) > 1:
|
if len(tools_storage) > 1:
|
||||||
geo_obj.multigeo = True
|
geo_obj.multigeo = True
|
||||||
else:
|
else:
|
||||||
if to_follow:
|
try:
|
||||||
passes_no = 1
|
|
||||||
else:
|
|
||||||
passes_no = float(tools_storage[0]['data']['tools_iso_passes'])
|
passes_no = float(tools_storage[0]['data']['tools_iso_passes'])
|
||||||
geo_obj.multigeo = True if passes_no > 1 else False
|
geo_obj.multigeo = True if passes_no > 1 else False
|
||||||
|
except KeyError as e:
|
||||||
|
log.debug("ToolIsolation.combined_rest.iso_init() --> KeyError: %s" % str(e))
|
||||||
|
geo_obj.multogeo = False
|
||||||
|
|
||||||
# detect if solid_geometry is empty and this require list flattening which is "heavy"
|
# detect if solid_geometry is empty and this require list flattening which is "heavy"
|
||||||
# or just looking in the lists (they are one level depth) and if any is not empty
|
# or just looking in the lists (they are one level depth) and if any is not empty
|
||||||
|
@ -2018,6 +2017,20 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
|
|
||||||
self.app.app_obj.new_object("geometry", iso_name, iso_init, plot=plot)
|
self.app.app_obj.new_object("geometry", iso_name, iso_init, plot=plot)
|
||||||
|
|
||||||
|
# the tools are finished but the isolation is not finished therefore it failed
|
||||||
|
if work_geo:
|
||||||
|
self.app.inform.emit("[WARNING] %s" % _("Partial failure. The geometry was processed with all tools.\n"
|
||||||
|
"But there are still un-isolated geometry elements. "
|
||||||
|
"Try to include a tool with smaller diameter."))
|
||||||
|
self.app.shell_message(msg=_("The following are coordinates for the copper features "
|
||||||
|
"that could not be isolated:"))
|
||||||
|
msg = ''
|
||||||
|
for geo in work_geo:
|
||||||
|
pt = geo.representative_point()
|
||||||
|
coords = '(%s, %s), ' % (str(pt.x), str(pt.y))
|
||||||
|
msg += coords
|
||||||
|
self.app.shell_message(msg=msg)
|
||||||
|
|
||||||
def combined_normal(self, iso_obj, iso2geo, tools_storage, lim_area, plot=True):
|
def combined_normal(self, iso_obj, iso2geo, tools_storage, lim_area, plot=True):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -2112,16 +2125,16 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
solid_geo.append(iso_geo)
|
solid_geo.append(iso_geo)
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
# ########## AREA SUBTRACTION ################################
|
# ########## AREA SUBTRACTION ################################
|
||||||
# ############################################################
|
# ############################################################
|
||||||
if iso_except:
|
if iso_except:
|
||||||
self.app.proc_container.update_view_text(' %s' % _("Subtracting Geo"))
|
self.app.proc_container.update_view_text(' %s' % _("Subtracting Geo"))
|
||||||
solid_geo = self.area_subtraction(solid_geo)
|
solid_geo = self.area_subtraction(solid_geo)
|
||||||
|
|
||||||
if lim_area:
|
if lim_area:
|
||||||
self.app.proc_container.update_view_text(' %s' % _("Intersecting Geo"))
|
self.app.proc_container.update_view_text(' %s' % _("Intersecting Geo"))
|
||||||
solid_geo = self.area_intersection(solid_geo, intersection_geo=lim_area)
|
solid_geo = self.area_intersection(solid_geo, intersection_geo=lim_area)
|
||||||
|
|
||||||
tools_storage.update({
|
tools_storage.update({
|
||||||
tool: {
|
tool: {
|
||||||
|
@ -2675,6 +2688,14 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
def poly2rings(poly):
|
def poly2rings(poly):
|
||||||
return [poly.exterior] + [interior for interior in poly.interiors]
|
return [poly.exterior] + [interior for interior in poly.interiors]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def poly2ext(poly):
|
||||||
|
return [poly.exterior]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def poly2ints(poly):
|
||||||
|
return [interior for interior in poly.interiors]
|
||||||
|
|
||||||
def generate_envelope(self, offset, invert, geometry=None, env_iso_type=2, follow=None, nr_passes=0):
|
def generate_envelope(self, offset, invert, geometry=None, env_iso_type=2, follow=None, nr_passes=0):
|
||||||
"""
|
"""
|
||||||
Isolation_geometry produces an envelope that is going on the left of the geometry
|
Isolation_geometry produces an envelope that is going on the left of the geometry
|
||||||
|
@ -2734,6 +2755,98 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
return 'fail'
|
return 'fail'
|
||||||
return geom
|
return geom
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_rest_geometry(geometry, tooldia, passes, overlap, invert, env_iso_type=2):
|
||||||
|
"""
|
||||||
|
Will try to isolate the geometry and return a tuple made of list of paths made through isolation
|
||||||
|
and a list of Shapely Polygons that could not be isolated
|
||||||
|
|
||||||
|
:param geometry: A list of Shapely Polygons to be isolated
|
||||||
|
:type geometry: list
|
||||||
|
:param tooldia: The tool diameter used to do the isolation
|
||||||
|
:type tooldia: float
|
||||||
|
:param passes: Number of passes that will made the isolation
|
||||||
|
:type passes: int
|
||||||
|
:param overlap: How much to overlap the previous pass; in percentage [0.00, 99.99]%
|
||||||
|
:type overlap: float
|
||||||
|
:param invert: If to invert the direction of the resulting isolated geometries
|
||||||
|
:type invert: bool
|
||||||
|
:param env_iso_type: can be either 0 = keep exteriors or 1 = keep interiors or 2 = keep all paths
|
||||||
|
:type env_iso_type: int
|
||||||
|
:return: Tuple made from list of isolating paths and list of not isolated Polygons
|
||||||
|
:rtype: tuple
|
||||||
|
"""
|
||||||
|
|
||||||
|
isolated_geo = []
|
||||||
|
not_isolated_geo = []
|
||||||
|
|
||||||
|
work_geo = []
|
||||||
|
|
||||||
|
for idx, geo in enumerate(geometry):
|
||||||
|
good_pass_iso = []
|
||||||
|
start_idx = idx + 1
|
||||||
|
|
||||||
|
for nr_pass in range(passes):
|
||||||
|
iso_offset = tooldia * ((2 * nr_pass + 1) / 2.0) - (nr_pass * overlap * tooldia)
|
||||||
|
buf_chek = iso_offset * 2
|
||||||
|
check_geo = geo.buffer(buf_chek)
|
||||||
|
|
||||||
|
intersect_flag = False
|
||||||
|
# find if current pass for current geo is valid (no intersection with other geos))
|
||||||
|
for geo_search_idx in range(idx):
|
||||||
|
if check_geo.intersects(geometry[geo_search_idx]):
|
||||||
|
intersect_flag = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if intersect_flag == False:
|
||||||
|
for geo_search_idx in range(start_idx, len(geometry)):
|
||||||
|
if check_geo.intersects(geometry[geo_search_idx]):
|
||||||
|
intersect_flag = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# if we had an intersection do nothing, else add the geo to the good pass isolations
|
||||||
|
if intersect_flag is False:
|
||||||
|
good_pass_iso.append(geo.buffer(iso_offset))
|
||||||
|
|
||||||
|
if good_pass_iso:
|
||||||
|
work_geo += good_pass_iso
|
||||||
|
else:
|
||||||
|
not_isolated_geo.append(geo)
|
||||||
|
|
||||||
|
if invert:
|
||||||
|
try:
|
||||||
|
pl = []
|
||||||
|
for p in work_geo:
|
||||||
|
if p is not None:
|
||||||
|
if isinstance(p, Polygon):
|
||||||
|
pl.append(Polygon(p.exterior.coords[::-1], p.interiors))
|
||||||
|
elif isinstance(p, LinearRing):
|
||||||
|
pl.append(Polygon(p.coords[::-1]))
|
||||||
|
work_geo = MultiPolygon(pl)
|
||||||
|
except TypeError:
|
||||||
|
if isinstance(work_geo, Polygon) and work_geo is not None:
|
||||||
|
work_geo = [Polygon(work_geo.exterior.coords[::-1], work_geo.interiors)]
|
||||||
|
elif isinstance(work_geo, LinearRing) and work_geo is not None:
|
||||||
|
work_geo = [Polygon(work_geo.coords[::-1])]
|
||||||
|
else:
|
||||||
|
log.debug("ToolIsolation.generate_rest_geometry() Error --> Unexpected Geometry %s" %
|
||||||
|
type(work_geo))
|
||||||
|
except Exception as e:
|
||||||
|
log.debug("ToolIsolation.generate_rest_geometry() Error --> %s" % str(e))
|
||||||
|
return 'fail', 'fail'
|
||||||
|
|
||||||
|
if env_iso_type == 0: # exterior
|
||||||
|
for geo in work_geo:
|
||||||
|
isolated_geo.append(geo.exterior)
|
||||||
|
elif env_iso_type == 1: # interiors
|
||||||
|
for geo in work_geo:
|
||||||
|
isolated_geo += [interior for interior in geo.interiors]
|
||||||
|
else: # exterior + interiors
|
||||||
|
for geo in work_geo:
|
||||||
|
isolated_geo += [geo.exterior] + [interior for interior in geo.interiors]
|
||||||
|
|
||||||
|
return isolated_geo, not_isolated_geo
|
||||||
|
|
||||||
def on_iso_tool_add_from_db_executed(self, tool):
|
def on_iso_tool_add_from_db_executed(self, tool):
|
||||||
"""
|
"""
|
||||||
Here add the tool from DB in the selected geometry object
|
Here add the tool from DB in the selected geometry object
|
||||||
|
@ -2809,7 +2922,7 @@ class ToolIsolation(AppTool, Gerber):
|
||||||
'solid_geometry': []
|
'solid_geometry': []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.iso_tools[tooluid]['data']['name'] = '_ncc'
|
self.iso_tools[tooluid]['data']['name'] = '_iso'
|
||||||
|
|
||||||
self.app.inform.emit('[success] %s' % _("New tool added to Tool Table."))
|
self.app.inform.emit('[success] %s' % _("New tool added to Tool Table."))
|
||||||
|
|
||||||
|
|
12
App_Main.py
12
App_Main.py
|
@ -9845,12 +9845,12 @@ class App(QtCore.QObject):
|
||||||
"""
|
"""
|
||||||
Shows a message on the FlatCAM Shell
|
Shows a message on the FlatCAM Shell
|
||||||
|
|
||||||
:param msg: Message to display.
|
:param msg: Message to display.
|
||||||
:param show: Opens the shell.
|
:param show: Opens the shell.
|
||||||
:param error: Shows the message as an error.
|
:param error: Shows the message as an error.
|
||||||
:param warning: Shows the message as an warning.
|
:param warning: Shows the message as an warning.
|
||||||
:param success: Shows the message as an success.
|
:param success: Shows the message as an success.
|
||||||
:param selected: Indicate that something was selected on canvas
|
:param selected: Indicate that something was selected on canvas
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
if show:
|
if show:
|
||||||
|
|
|
@ -7,6 +7,11 @@ CHANGELOG for FlatCAM beta
|
||||||
|
|
||||||
=================================================
|
=================================================
|
||||||
|
|
||||||
|
30.05.2020
|
||||||
|
|
||||||
|
- made confirmation messages for the values that are modified not to be printed in the Shell
|
||||||
|
- Isolation Tool: working on the Rest machining: almost there, perhaps I will use multiprocessing
|
||||||
|
|
||||||
29.05.2020
|
29.05.2020
|
||||||
|
|
||||||
- fixed the Tool Isolation when using the 'follow' parameter
|
- fixed the Tool Isolation when using the 'follow' parameter
|
||||||
|
|
Loading…
Reference in New Issue