- NCC Plugin: modified the previous change and now the simplification action is much bigger reducing the number of coordinates by a factor of 20 (20 times less)
- Paint Plugin: same as above - Ncc Plugin: added some more tooltips - Isolation Plugin: fixed some issues when using the Rest Machining option
This commit is contained in:
@@ -2074,13 +2074,13 @@ class ToolIsolation(AppTool, Gerber):
|
||||
solid_geo = self.area_intersection(solid_geo, intersection_geo=lim_area)
|
||||
|
||||
# make sure that no empty geometry element is in the solid_geometry
|
||||
new_solid_geo = [geo for geo in solid_geo if not geo.is_empty]
|
||||
new_solid_geo = flatten_shapely_geometry(solid_geo)
|
||||
|
||||
tools_storage.update({
|
||||
tool: {
|
||||
'tooldia': float(tool_dia),
|
||||
'data': tool_data,
|
||||
'solid_geometry': deepcopy(new_solid_geo)
|
||||
'solid_geometry': new_solid_geo
|
||||
}
|
||||
})
|
||||
tools_storage[tool]['data']['tools_mill_tooldia'] = float(tool_dia)
|
||||
@@ -2090,11 +2090,10 @@ class ToolIsolation(AppTool, Gerber):
|
||||
if not work_geo:
|
||||
break
|
||||
|
||||
total_solid_geometry = self.flatten_list(total_solid_geometry)
|
||||
total_solid_geometry = [g for g in total_solid_geometry if not g.is_empty]
|
||||
if simp_en:
|
||||
total_solid_geometry = [
|
||||
g.simplify(tolerance=simp_tol) for g in total_solid_geometry if not g.is_empty]
|
||||
total_solid_geometry = flatten_shapely_geometry(total_solid_geometry, simplify_tolerance=simp_tol)
|
||||
else:
|
||||
total_solid_geometry = flatten_shapely_geometry(total_solid_geometry)
|
||||
|
||||
# clean the progressive plotted shapes if it was used
|
||||
if plot and self.app.options["tools_iso_plotting"] == 'progressive':
|
||||
@@ -2169,7 +2168,7 @@ class ToolIsolation(AppTool, Gerber):
|
||||
pt = geo.representative_point()
|
||||
coords = '(%s, %s), ' % (str(pt.x), str(pt.y))
|
||||
msg += coords
|
||||
self.app.inform_shell.emit(msg=msg)
|
||||
self.app.inform_shell.emit(msg)
|
||||
|
||||
def combined_normal(self, iso_obj, iso2geo, tools_storage, lim_area, sel_tools, iso_except, extra_passes=None,
|
||||
negative_dia=None, simp_en=False, simp_tol=0.001, plot=True, prog_plot=None):
|
||||
@@ -3266,30 +3265,21 @@ class ToolIsolation(AppTool, Gerber):
|
||||
else:
|
||||
not_isolated_geo.append(geo)
|
||||
|
||||
work_geo_shp = work_geo.geoms if isinstance(work_geo, MultiPolygon) else work_geo
|
||||
work_geo_shp = flatten_shapely_geometry(work_geo)
|
||||
if invert:
|
||||
try:
|
||||
pl = []
|
||||
for p in work_geo_shp:
|
||||
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]))
|
||||
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_shp = MultiPolygon(pl)
|
||||
except TypeError:
|
||||
if isinstance(work_geo_shp, Polygon) and work_geo_shp is not None:
|
||||
work_geo_shp = [Polygon(work_geo_shp.exterior.coords[::-1], work_geo_shp.interiors)]
|
||||
elif isinstance(work_geo_shp, LinearRing) and work_geo_shp is not None:
|
||||
work_geo_shp = [Polygon(work_geo_shp.coords[::-1])]
|
||||
else:
|
||||
self.app.log.debug(
|
||||
"ToolIsolation.generate_rest_geometry() Error --> Unexpected Geometry %s" % type(work_geo))
|
||||
except Exception as e:
|
||||
self.app.log.error("ToolIsolation.generate_rest_geometry() Error --> %s" % str(e))
|
||||
return 'fail', 'fail'
|
||||
|
||||
actual_geo = work_geo_shp.geoms if isinstance(work_geo, MultiPolygon) else work_geo_shp
|
||||
actual_geo = flatten_shapely_geometry(work_geo_shp)
|
||||
if env_iso_type == 0: # exterior
|
||||
for geo in actual_geo:
|
||||
isolated_geo.append(geo.exterior)
|
||||
|
||||
@@ -2187,7 +2187,6 @@ class NonCopperClear(AppTool, Gerber):
|
||||
steps_per_circle=self.circle_steps,
|
||||
overlap=ncc_overlap, contour=ncc_contour,
|
||||
connect=ncc_connect,
|
||||
simplify_tol=simplify_tol,
|
||||
prog_plot=prog_plot)
|
||||
except grace:
|
||||
return "fail"
|
||||
@@ -2248,8 +2247,10 @@ class NonCopperClear(AppTool, Gerber):
|
||||
self.app.log.error("NonCopperClear.clear_polygon_worker() Combo --> %s" % str(ee))
|
||||
|
||||
if cp and cp.objects:
|
||||
ret_val = list(cp.get_objects())
|
||||
return ret_val
|
||||
if simplify_tol > 0.0:
|
||||
return [x.simplify(simplify_tol) for x in cp.get_objects()]
|
||||
else:
|
||||
return [x for x in cp.get_objects()]
|
||||
else:
|
||||
pt = pol.representative_point()
|
||||
coords = (pt.x, pt.y)
|
||||
@@ -2285,9 +2286,9 @@ class NonCopperClear(AppTool, Gerber):
|
||||
self.app.log.debug("Executing the clear_copper handler ...")
|
||||
|
||||
if run_threaded:
|
||||
proc = self.app.proc_container.new('%s...' % _("Non-Copper Clearing"))
|
||||
proc = self.app.proc_container.new('%s...' % _("Working"))
|
||||
else:
|
||||
self.app.proc_container.view.set_busy('%s...' % _("Non-Copper Clearing"))
|
||||
self.app.proc_container.view.set_busy('%s...' % _("Working"))
|
||||
QtWidgets.QApplication.processEvents()
|
||||
|
||||
# ######################################################################################################
|
||||
@@ -2300,7 +2301,7 @@ class NonCopperClear(AppTool, Gerber):
|
||||
rest_machining_choice = self.ui.ncc_rest_cb.get_value()
|
||||
|
||||
# TODO this should be in preferences and in the UI
|
||||
simplification_value = 0.02
|
||||
simplification_value = 0.01
|
||||
|
||||
# determine if to use the progressive plotting
|
||||
prog_plot = True if self.app.options["tools_ncc_plotting"] == 'progressive' else False
|
||||
@@ -2360,7 +2361,9 @@ class NonCopperClear(AppTool, Gerber):
|
||||
bbox = self.apply_margin_to_bounding_box(bbox=bbox_geo, box_kind=bbox_kind,
|
||||
ncc_select=ncc_select, ncc_margin=ncc_margin)
|
||||
|
||||
# ----------------------------------------------------
|
||||
# COPPER CLEARING with tools marked for CLEAR#
|
||||
# ----------------------------------------------------
|
||||
for tool in sorted_clear_tools:
|
||||
self.app.log.debug("Starting geometry processing for tool: %s" % str(tool))
|
||||
if self.app.abort_flag:
|
||||
@@ -2376,16 +2379,23 @@ class NonCopperClear(AppTool, Gerber):
|
||||
)
|
||||
app_obj.proc_container.update_view_text(' %d%%' % 0)
|
||||
|
||||
# ----------------------------------------------------
|
||||
# store here the geometry generated by clear operation
|
||||
# ----------------------------------------------------
|
||||
cleared_geo = []
|
||||
|
||||
tool_uid = 0 # find the current tool_uid
|
||||
# ----------------------------------------------------
|
||||
# find the current tool_uid
|
||||
# ----------------------------------------------------
|
||||
tool_uid = 0
|
||||
for k, v in self.ncc_tools.items():
|
||||
if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool)):
|
||||
tool_uid = int(k)
|
||||
break
|
||||
|
||||
# ----------------------------------------------------
|
||||
# parameters that are particular to the current tool
|
||||
# ----------------------------------------------------
|
||||
ncc_overlap = float(self.ncc_tools[tool_uid]["data"]["tools_ncc_overlap"]) / 100.0
|
||||
ncc_method = self.ncc_tools[tool_uid]["data"]["tools_ncc_method"]
|
||||
ncc_connect = self.ncc_tools[tool_uid]["data"]["tools_ncc_connect"]
|
||||
@@ -2393,107 +2403,119 @@ class NonCopperClear(AppTool, Gerber):
|
||||
has_offset = self.ncc_tools[tool_uid]["data"]["tools_ncc_offset_choice"]
|
||||
ncc_offset = float(self.ncc_tools[tool_uid]["data"]["tools_ncc_offset_value"])
|
||||
|
||||
# ----------------------------------------------------
|
||||
# Area to clear
|
||||
# ----------------------------------------------------
|
||||
result = self.get_tool_empty_area(name=name, ncc_obj=ncc_obj, geo_obj=geo_obj, isotooldia=isotd_list,
|
||||
ncc_margin=ncc_margin, has_offset=has_offset, ncc_offset=ncc_offset,
|
||||
tools_storage=tools_storage, bounding_box=bbox)
|
||||
|
||||
area, warning_flag = result
|
||||
|
||||
if area == "fail":
|
||||
self.app.log.debug("Failed to create empty area for this tool.")
|
||||
continue
|
||||
|
||||
# Transform area to MultiPolygon
|
||||
if isinstance(area, Polygon):
|
||||
area = MultiPolygon([area])
|
||||
tool_empty_area = flatten_shapely_geometry(area)
|
||||
if not tool_empty_area:
|
||||
continue
|
||||
|
||||
# variables to display the percentage of work done
|
||||
geo_len = len(area.geoms)
|
||||
|
||||
old_disp_number = 0
|
||||
geo_len = len(tool_empty_area)
|
||||
self.app.log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
|
||||
|
||||
tool_empty_area = flatten_shapely_geometry(area.geoms)
|
||||
# ----------------------------------------------------
|
||||
# Copper-clear the Polygons in the non-copper-area
|
||||
# Iterate over them
|
||||
# ----------------------------------------------------
|
||||
pol_nr = 0
|
||||
for p in tool_empty_area:
|
||||
# provide the app with a way to process the GUI events when in a blocking loop
|
||||
if not run_threaded:
|
||||
QtWidgets.QApplication.processEvents()
|
||||
|
||||
if tool_empty_area:
|
||||
pol_nr = 0
|
||||
for p in tool_empty_area:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise grace
|
||||
|
||||
# ----------------------------------------------------
|
||||
# attempt to fix possible problems with the polygon
|
||||
# ----------------------------------------------------
|
||||
p = p.buffer(0.0000001)
|
||||
p = flatten_shapely_geometry(p, simplify_tolerance=simplification_value)
|
||||
|
||||
poly_failed = 0
|
||||
for pol in p:
|
||||
# provide the app with a way to process the GUI events when in a blocking loop
|
||||
if not run_threaded:
|
||||
QtWidgets.QApplication.processEvents()
|
||||
QtWidgets.QApplication.processEvents()
|
||||
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise grace
|
||||
|
||||
# clean the polygon
|
||||
p = p.buffer(0.0000001)
|
||||
p = flatten_shapely_geometry(p, simplify_tolerance=simplification_value)
|
||||
|
||||
poly_failed = 0
|
||||
for pol in p:
|
||||
# provide the app with a way to process the GUI events when in a blocking loop
|
||||
QtWidgets.QApplication.processEvents()
|
||||
|
||||
if pol is not None and pol.is_valid and isinstance(pol, Polygon):
|
||||
res = self.clear_polygon_worker(pol=pol, tooldia=tool,
|
||||
ncc_method=ncc_method,
|
||||
ncc_overlap=ncc_overlap,
|
||||
ncc_connect=ncc_connect,
|
||||
ncc_contour=ncc_contour,
|
||||
simplify_tol=simplification_value,
|
||||
prog_plot=prog_plot)
|
||||
if res is not None:
|
||||
cleared_geo += res
|
||||
else:
|
||||
poly_failed += 1
|
||||
if pol is not None and pol.is_valid and isinstance(pol, Polygon):
|
||||
# ----------------------------------------------------
|
||||
# This is where copper clearing is happening
|
||||
# ----------------------------------------------------
|
||||
res = self.clear_polygon_worker(pol=pol, tooldia=tool,
|
||||
ncc_method=ncc_method,
|
||||
ncc_overlap=ncc_overlap,
|
||||
ncc_connect=ncc_connect,
|
||||
ncc_contour=ncc_contour,
|
||||
simplify_tol=simplification_value,
|
||||
prog_plot=prog_plot)
|
||||
if res is not None:
|
||||
cleared_geo += res
|
||||
else:
|
||||
self.app.log.warning(
|
||||
"Expected geo is a Polygon. Instead got a %s" % str(type(pol)))
|
||||
poly_failed += 1
|
||||
else:
|
||||
self.app.log.warning(
|
||||
"Expected geo is a Polygon. Instead got a %s" % str(type(pol)))
|
||||
|
||||
pol_nr += 1
|
||||
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
||||
# log.debug("Polygons cleared: %d" % pol_nr)
|
||||
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(' %d%%' % disp_number)
|
||||
old_disp_number = disp_number
|
||||
|
||||
if old_disp_number < disp_number <= 100:
|
||||
self.app.proc_container.update_view_text(' %d%%' % disp_number)
|
||||
old_disp_number = disp_number
|
||||
# log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
|
||||
if poly_failed > 0:
|
||||
app_obj.poly_not_cleared = True
|
||||
|
||||
if poly_failed > 0:
|
||||
app_obj.poly_not_cleared = True
|
||||
# ---------------------------------------------------------
|
||||
# Debug message regarding how many points are in the result
|
||||
# ---------------------------------------------------------
|
||||
l_coords = 0
|
||||
for i in range(len(cleared_geo)):
|
||||
l_coords += len(cleared_geo[i].coords)
|
||||
self.app.log.debug(
|
||||
"NCC Tool.clear_copper.gen_clear_area() -> Number of cleared geo coords: %s" % str(l_coords))
|
||||
|
||||
l_coords = 0
|
||||
for i in range(len(cleared_geo)):
|
||||
l_coords += len(cleared_geo[i].coords)
|
||||
self.app.log.debug(
|
||||
"NCC Tool.clear_copper.gen_clear_area() -> Number of cleared geo coords: %s" % str(l_coords))
|
||||
# -----------------------------------------------------------
|
||||
# check if there is a geometry at all in the cleared geometry
|
||||
# -----------------------------------------------------------
|
||||
if cleared_geo:
|
||||
formatted_tool = self.app.dec_format(tool, self.decimals)
|
||||
# find the tooluid associated with the current tool_dia so we know where to add the tool
|
||||
# solid_geometry
|
||||
for k, v in tools_storage.items():
|
||||
if self.app.dec_format(v['tooldia'], self.decimals) == formatted_tool:
|
||||
current_uid = int(k)
|
||||
|
||||
# check if there is a geometry at all in the cleared geometry
|
||||
if cleared_geo:
|
||||
formatted_tool = self.app.dec_format(tool, self.decimals)
|
||||
# find the tooluid associated with the current tool_dia so we know where to add the tool
|
||||
# solid_geometry
|
||||
for k, v in tools_storage.items():
|
||||
if self.app.dec_format(v['tooldia'], self.decimals) == formatted_tool:
|
||||
current_uid = int(k)
|
||||
|
||||
# add the solid_geometry to the current too in self.paint_tools dictionary
|
||||
# and then reset the temporary list that stored that solid_geometry
|
||||
v['solid_geometry'] = deepcopy(cleared_geo)
|
||||
v['data']['name'] = name
|
||||
geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
|
||||
break
|
||||
else:
|
||||
self.app.log.debug("There are no geometries in the cleared polygon.")
|
||||
# add the solid_geometry to the current too in self.paint_tools dictionary
|
||||
# and then reset the temporary list that stored that solid_geometry
|
||||
v['solid_geometry'] = deepcopy(cleared_geo)
|
||||
v['data']['name'] = name
|
||||
geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
|
||||
break
|
||||
else:
|
||||
self.app.log.debug("There are no geometries in the cleared polygon.")
|
||||
|
||||
# ----------------------------------------------------
|
||||
# clean the progressive plotted shapes if it was used
|
||||
# ----------------------------------------------------
|
||||
if self.app.options["tools_ncc_plotting"] == 'progressive':
|
||||
self.temp_shapes.clear(update=True)
|
||||
|
||||
# ----------------------------------------------------
|
||||
# delete tools with empty geometry
|
||||
# look for keys in the tools_storage dict that have 'solid_geometry' values empty
|
||||
# ----------------------------------------------------
|
||||
for uid, uid_val in list(tools_storage.items()):
|
||||
try:
|
||||
# if the solid_geometry (type=list) is empty
|
||||
@@ -2516,7 +2538,9 @@ class NonCopperClear(AppTool, Gerber):
|
||||
geo_obj.multigeo = True
|
||||
geo_obj.tools = dict(tools_storage)
|
||||
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
# test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
has_solid_geo = 0
|
||||
for tid in geo_obj.tools:
|
||||
if geo_obj.tools[tid]['solid_geometry']:
|
||||
@@ -2528,8 +2552,10 @@ class NonCopperClear(AppTool, Gerber):
|
||||
app_obj.inform.emit(msg)
|
||||
return 'fail'
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# check to see if geo_obj.tools is empty
|
||||
# it will be updated only if there is a solid_geometry for tools
|
||||
# ----------------------------------------------------------------
|
||||
if geo_obj.tools:
|
||||
if warning_flag == 0:
|
||||
self.app.inform.emit('[success] %s' % _("NCC Tool clear all done."))
|
||||
@@ -2889,9 +2915,9 @@ class NonCopperClear(AppTool, Gerber):
|
||||
:return:
|
||||
"""
|
||||
if run_threaded:
|
||||
proc = self.app.proc_container.new('%s...' % _("Non-Copper Clearing"))
|
||||
proc = self.app.proc_container.new('%s...' % _("Working"))
|
||||
else:
|
||||
self.app.proc_container.view.set_busy('%s...' % _("Non-Copper Clearing"))
|
||||
self.app.proc_container.view.set_busy('%s...' % _("Working"))
|
||||
QtWidgets.QApplication.processEvents()
|
||||
|
||||
# #####################################################################
|
||||
|
||||
@@ -1871,6 +1871,9 @@ class ToolPaint(AppTool, Gerber):
|
||||
tools_storage = self.paint_tools if tools_storage is None else tools_storage
|
||||
use_rest_strategy = rest if rest is not None else self.ui.rest_cb.get_value()
|
||||
|
||||
# TODO this should be in preferences and in the UI
|
||||
simplification_value = 0.01
|
||||
|
||||
sorted_tools = []
|
||||
if tooldia is not None:
|
||||
try:
|
||||
@@ -1959,7 +1962,7 @@ class ToolPaint(AppTool, Gerber):
|
||||
# effective polygon clearing job
|
||||
# -----------------------------
|
||||
try:
|
||||
cp = []
|
||||
cp_list = []
|
||||
for pp in poly_buf:
|
||||
# provide the app with a way to process the GUI events when in a blocking loop
|
||||
QtWidgets.QApplication.processEvents()
|
||||
@@ -1970,7 +1973,7 @@ class ToolPaint(AppTool, Gerber):
|
||||
cont=cont, paint_method=paint_method, obj=obj,
|
||||
prog_plot=prog_plot)
|
||||
if geo_res:
|
||||
cp.append(geo_res)
|
||||
cp_list.append(geo_res)
|
||||
pol_nr += 1
|
||||
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
||||
# log.debug("Polygons cleared: %d" % pol_nr)
|
||||
@@ -1980,9 +1983,12 @@ class ToolPaint(AppTool, Gerber):
|
||||
old_disp_number = disp_number
|
||||
|
||||
total_geometry = []
|
||||
if cp:
|
||||
for x in cp:
|
||||
total_geometry += list(x.get_objects())
|
||||
if cp_list:
|
||||
for cp in cp_list:
|
||||
if simplification_value > 0.0:
|
||||
total_geometry += [x.simplify(simplification_value) for x in cp.get_objects()]
|
||||
else:
|
||||
total_geometry += [x for x in cp.get_objects()]
|
||||
|
||||
# clean the geometry
|
||||
total_geometry = [g for g in total_geometry if g and not g.is_empty]
|
||||
@@ -2141,7 +2147,12 @@ class ToolPaint(AppTool, Gerber):
|
||||
geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn,
|
||||
cont=cont, paint_method=paint_method, obj=obj,
|
||||
prog_plot=prog_plot)
|
||||
geo_elems = list(geo_res.get_objects())
|
||||
|
||||
if simplification_value > 0.0:
|
||||
geo_elems = [x.simplify(simplification_value) for x in geo_res.get_objects()]
|
||||
else:
|
||||
geo_elems = [x for x in geo_res.get_objects()]
|
||||
|
||||
# See if the polygon was completely cleared
|
||||
pp_cleared = unary_union(geo_elems).buffer(tool_dia / 2.0)
|
||||
rest_geo = pp.difference(pp_cleared)
|
||||
@@ -2153,6 +2164,7 @@ class ToolPaint(AppTool, Gerber):
|
||||
|
||||
if geo_res:
|
||||
cleared_geo += geo_elems
|
||||
|
||||
pol_nr += 1
|
||||
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
|
||||
# log.debug("Polygons cleared: %d" % pol_nr)
|
||||
|
||||
Reference in New Issue
Block a user