- more work in the new Laser Mode in the Paint Tool

This commit is contained in:
Marius Stanciu
2020-02-15 21:11:06 +02:00
committed by Marius
parent d24290a2b6
commit 25c9a31179
3 changed files with 930 additions and 166 deletions

View File

@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
- in Paint Tool added a new method of painting named Combo who will pass through all the methods until the polygon is cleared - in Paint Tool added a new method of painting named Combo who will pass through all the methods until the polygon is cleared
- in Paint Tool attempting to add a new mode suitable for Laser usage - in Paint Tool attempting to add a new mode suitable for Laser usage
- more work in the new Laser Mode in the Paint Tool
14.02.2020 14.02.2020

View File

@@ -1582,7 +1582,7 @@ class Geometry(object):
""" """
# log.debug("camlib.fill_with_lines()") # log.debug("camlib.fill_with_lines()")
if not isinstance(line, LineString) or not isinstance(line, MultiLineString): if not isinstance(line, LineString) and not isinstance(line, MultiLineString):
log.debug("camlib.Geometry.fill_with_lines() --> Not a LineString/MultiLineString but %s" % str(type(line))) log.debug("camlib.Geometry.fill_with_lines() --> Not a LineString/MultiLineString but %s" % str(type(line)))
return None return None
@@ -1596,10 +1596,10 @@ class Geometry(object):
lines_trimmed = [] lines_trimmed = []
polygon = line.buffer(aperture_size / 1.99999999999999999, int(steps_per_circle)) polygon = line.buffer(aperture_size / 2.0, int(steps_per_circle))
try: try:
margin_poly = polygon.buffer(-tooldia / 1.99999999, int(steps_per_circle)) margin_poly = polygon.buffer(-tooldia / 2.0, int(steps_per_circle))
except Exception: except Exception:
log.debug("camlib.Geometry.fill_with_lines() --> Could not buffer the Polygon, tool diameter too high") log.debug("camlib.Geometry.fill_with_lines() --> Could not buffer the Polygon, tool diameter too high")
return None return None
@@ -1615,41 +1615,51 @@ class Geometry(object):
# provide the app with a way to process the GUI events when in a blocking loop # provide the app with a way to process the GUI events when in a blocking loop
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle)) new_line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
line = line.intersection(margin_poly) new_line = new_line.intersection(margin_poly)
lines_trimmed.append(line) lines_trimmed.append(new_line)
line = line.parallel_offset(distance=delta, side='right', resolution=int(steps_per_circle)) new_line = line.parallel_offset(distance=delta, side='right', resolution=int(steps_per_circle))
line = line.intersection(margin_poly) new_line = new_line.intersection(margin_poly)
lines_trimmed.append(line) lines_trimmed.append(new_line)
delta += tooldia * (1 - overlap) delta += tooldia * (1 - overlap)
if prog_plot: if prog_plot:
self.plot_temp_shapes(line) self.plot_temp_shapes(new_line)
self.temp_shapes.redraw() self.temp_shapes.redraw()
# Last line # Last line
delta = aperture_size / 2 delta = (aperture_size / 2) - (tooldia / 2.00000001)
line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle)) new_line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
line = line.intersection(margin_poly) new_line = new_line.intersection(margin_poly)
for ll in line:
lines_trimmed.append(ll)
if prog_plot:
self.plot_temp_shapes(line)
line = line.parallel_offset(distance=delta, side='left', resolution=int(steps_per_circle))
line = line.intersection(margin_poly)
for ll in line:
lines_trimmed.append(ll)
if prog_plot:
self.plot_temp_shapes(line)
except Exception as e: except Exception as e:
log.debug('camlib.Geometry.fill_with_lines() Processing poly --> %s' % str(e)) log.debug('camlib.Geometry.fill_with_lines() Processing poly --> %s' % str(e))
return None return None
try:
for ll in new_line:
lines_trimmed.append(ll)
if prog_plot:
self.plot_temp_shapes(ll)
except TypeError:
lines_trimmed.append(new_line)
if prog_plot:
self.plot_temp_shapes(new_line)
new_line = line.parallel_offset(distance=delta, side='right', resolution=int(steps_per_circle))
new_line = new_line.intersection(margin_poly)
try:
for ll in new_line:
lines_trimmed.append(ll)
if prog_plot:
self.plot_temp_shapes(ll)
except TypeError:
lines_trimmed.append(new_line)
if prog_plot:
self.plot_temp_shapes(new_line)
if prog_plot: if prog_plot:
self.temp_shapes.redraw() self.temp_shapes.redraw()
@@ -3434,10 +3444,13 @@ class CNCjob(Geometry):
self.f_plunge = self.app.defaults["geometry_f_plunge"] self.f_plunge = self.app.defaults["geometry_f_plunge"]
if self.z_cut is None: if self.z_cut is None:
if 'laser' not in self.pp_geometry_name:
self.app.inform.emit('[ERROR_NOTCL] %s' % self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Cut_Z parameter is None or zero. Most likely a bad combinations of " _("Cut_Z parameter is None or zero. Most likely a bad combinations of "
"other parameters.")) "other parameters."))
return 'fail' return 'fail'
else:
self.z_cut = 0
if self.machinist_setting == 0: if self.machinist_setting == 0:
if self.z_cut > 0: if self.z_cut > 0:
@@ -3448,7 +3461,7 @@ class CNCjob(Geometry):
"therefore the app will convert the value to negative." "therefore the app will convert the value to negative."
"Check the resulting CNC code (Gcode etc).")) "Check the resulting CNC code (Gcode etc)."))
self.z_cut = -self.z_cut self.z_cut = -self.z_cut
elif self.z_cut == 0: elif self.z_cut == 0 and 'laser' not in self.pp_geometry_name:
self.app.inform.emit('[WARNING] %s: %s' % self.app.inform.emit('[WARNING] %s: %s' %
(_("The Cut Z parameter is zero. There will be no cut, skipping file"), (_("The Cut Z parameter is zero. There will be no cut, skipping file"),
self.options['name'])) self.options['name']))
@@ -3793,11 +3806,14 @@ class CNCjob(Geometry):
if self.machinist_setting == 0: if self.machinist_setting == 0:
if self.z_cut is None: if self.z_cut is None:
if 'laser' not in self.pp_geometry_name:
self.app.inform.emit( self.app.inform.emit(
'[ERROR_NOTCL] %s' % _("Cut_Z parameter is None or zero. Most likely a bad combinations of " '[ERROR_NOTCL] %s' % _("Cut_Z parameter is None or zero. Most likely a bad combinations of "
"other parameters.") "other parameters.")
) )
return 'fail' return 'fail'
else:
self.z_cut = 0.0
if self.z_cut > 0: if self.z_cut > 0:
self.app.inform.emit('[WARNING] %s' % self.app.inform.emit('[WARNING] %s' %
@@ -3807,7 +3823,7 @@ class CNCjob(Geometry):
"therefore the app will convert the value to negative." "therefore the app will convert the value to negative."
"Check the resulting CNC code (Gcode etc).")) "Check the resulting CNC code (Gcode etc)."))
self.z_cut = -self.z_cut self.z_cut = -self.z_cut
elif self.z_cut == 0: elif self.z_cut == 0 and 'laser' not in self.pp_geometry_name:
self.app.inform.emit( self.app.inform.emit(
'[WARNING] %s: %s' % (_("The Cut Z parameter is zero. There will be no cut, skipping file"), '[WARNING] %s: %s' % (_("The Cut Z parameter is zero. There will be no cut, skipping file"),
geometry.options['name']) geometry.options['name'])

View File

@@ -13,12 +13,12 @@ from copy import deepcopy
# from ObjectCollection import * # from ObjectCollection import *
from flatcamParsers.ParseGerber import Gerber from flatcamParsers.ParseGerber import Gerber
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry
from camlib import Geometry from camlib import Geometry, FlatCAMRTreeStorage
from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet, FCButton from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet, FCButton
import FlatCAMApp import FlatCAMApp
from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point, MultiLineString
from shapely.ops import cascaded_union from shapely.ops import cascaded_union, unary_union, linemerge
import numpy as np import numpy as np
import math import math
@@ -447,7 +447,6 @@ class ToolPaint(FlatCAMTool, Gerber):
) )
grid4.addWidget(self.rest_cb, 16, 0, 1, 2) grid4.addWidget(self.rest_cb, 16, 0, 1, 2)
# Laser Mode # Laser Mode
self.laser_cb = FCCheckBox(_("Laser Mode")) self.laser_cb = FCCheckBox(_("Laser Mode"))
self.laser_cb.setToolTip( self.laser_cb.setToolTip(
@@ -681,6 +680,7 @@ class ToolPaint(FlatCAMTool, Gerber):
def run(self, toggle=True): def run(self, toggle=True):
self.app.report_usage("ToolPaint()") self.app.report_usage("ToolPaint()")
log.debug("ToolPaint().run() was launched ...")
if toggle: if toggle:
# if the splitter is hidden, display it, else hide it but only if the current widget is the same # if the splitter is hidden, display it, else hide it but only if the current widget is the same
@@ -795,9 +795,9 @@ class ToolPaint(FlatCAMTool, Gerber):
self.blockSignals(True) self.blockSignals(True)
row = self.tools_table.currentRow() # row = self.tools_table.currentRow()
if row < 0: # if row < 0:
row = 0 # row = 0
# this new dict will hold the actual useful data, another dict that is the value of key 'data' # this new dict will hold the actual useful data, another dict that is the value of key 'data'
temp_tools = {} temp_tools = {}
@@ -952,32 +952,8 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tools_frame.show() self.tools_frame.show()
self.reset_fields() self.reset_fields()
# ## Init the GUI interface
self.order_radio.set_value(self.app.defaults["tools_paintorder"])
self.paintmargin_entry.set_value(self.app.defaults["tools_paintmargin"])
self.paintmethod_combo.set_value(self.app.defaults["tools_paintmethod"])
self.selectmethod_combo.set_value(self.app.defaults["tools_selectmethod"])
self.pathconnect_cb.set_value(self.app.defaults["tools_pathconnect"])
self.paintcontour_cb.set_value(self.app.defaults["tools_paintcontour"])
self.paintoverlap_entry.set_value(self.app.defaults["tools_paintoverlap"])
self.cutz_entry.set_value(self.app.defaults["tools_paintcutz"])
self.tool_type_radio.set_value(self.app.defaults["tools_painttool_type"])
self.tipdia_entry.set_value(self.app.defaults["tools_painttipdia"])
self.tipangle_entry.set_value(self.app.defaults["tools_painttipangle"])
self.addtool_entry.set_value(self.app.defaults["tools_paintnewdia"])
self.rest_cb.set_value(self.app.defaults["tools_paintrest"])
self.old_tool_dia = self.app.defaults["tools_paintnewdia"] self.old_tool_dia = self.app.defaults["tools_paintnewdia"]
self.on_tool_type(val=self.tool_type_radio.get_value())
# make the default object type, "Geometry"
self.type_obj_combo.setCurrentIndex(2)
# make the Laser Mode disabled because the Geometry object is default
self.laser_cb.setEnabled(False)
# updated units # updated units
self.units = self.app.defaults['units'].upper() self.units = self.app.defaults['units'].upper()
@@ -1020,6 +996,30 @@ class ToolPaint(FlatCAMTool, Gerber):
"paintrest": self.app.defaults["tools_paintrest"], "paintrest": self.app.defaults["tools_paintrest"],
}) })
# ## Init the GUI interface
self.order_radio.set_value(self.app.defaults["tools_paintorder"])
self.paintmargin_entry.set_value(self.app.defaults["tools_paintmargin"])
self.paintmethod_combo.set_value(self.app.defaults["tools_paintmethod"])
self.selectmethod_combo.set_value(self.app.defaults["tools_selectmethod"])
self.pathconnect_cb.set_value(self.app.defaults["tools_pathconnect"])
self.paintcontour_cb.set_value(self.app.defaults["tools_paintcontour"])
self.paintoverlap_entry.set_value(self.app.defaults["tools_paintoverlap"])
self.cutz_entry.set_value(self.app.defaults["tools_paintcutz"])
self.tool_type_radio.set_value(self.app.defaults["tools_painttool_type"])
self.tipdia_entry.set_value(self.app.defaults["tools_painttipdia"])
self.tipangle_entry.set_value(self.app.defaults["tools_painttipangle"])
self.addtool_entry.set_value(self.app.defaults["tools_paintnewdia"])
self.rest_cb.set_value(self.app.defaults["tools_paintrest"])
self.on_tool_type(val=self.tool_type_radio.get_value())
# make the default object type, "Geometry"
self.type_obj_combo.setCurrentIndex(2)
# make the Laser Mode disabled because the Geometry object is default
self.laser_cb.setEnabled(False)
try: try:
diameters = [float(self.app.defaults["tools_painttooldia"])] diameters = [float(self.app.defaults["tools_painttooldia"])]
except (ValueError, TypeError): except (ValueError, TypeError):
@@ -1718,7 +1718,7 @@ class ToolPaint(FlatCAMTool, Gerber):
polygon_list = None polygon_list = None
if inside_pt and poly_list is None: if inside_pt and poly_list is None:
polygon_list = [self.find_polygon(point=inside_pt, geoset=obj.solid_geometry)] polygon_list = [self.find_polygon(point=inside_pt, geoset=obj.solid_geometry)]
elif inside_pt is None and poly_list: elif (inside_pt is None and poly_list) or (inside_pt and poly_list):
polygon_list = poly_list polygon_list = poly_list
# No polygon? # No polygon?
@@ -1797,34 +1797,152 @@ class ToolPaint(FlatCAMTool, Gerber):
connect=conn, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
elif paint_method == "laser_lines": elif paint_method == "laser_lines":
line = None # line = None
aperture_size = None # aperture_size = None
# determine the Gerber follow line # the key is the aperture type and the val is a list of geo elements
flash_el_dict = dict()
# the key is the aperture size, the val is a list of geo elements
traces_el_dict = dict()
# find the flashes and the lines that are in the selected polygon and store them separately
for apid, apval in obj.apertures.items(): for apid, apval in obj.apertures.items():
for geo_el in apval['geometry']: for geo_el in apval['geometry']:
if 'solid' in geo_el: if apval["size"] == 0.0:
if Point(inside_pt).within(geo_el['solid']): if apval["size"] in traces_el_dict:
if not isinstance(geo_el['follow'], Point): traces_el_dict[apval["size"]].append(geo_el)
line = geo_el['follow'] else:
traces_el_dict[apval["size"]] = [geo_el]
if apval['type'] == 'C': if 'follow' in geo_el and geo_el['follow'].within(polyg):
if isinstance(geo_el['follow'], Point):
if apval["type"] == 'C':
if 'C' in flash_el_dict:
flash_el_dict['C'].append(geo_el)
else:
flash_el_dict['C'] = [geo_el]
elif apval["type"] == 'O':
if 'O' in flash_el_dict:
flash_el_dict['O'].append(geo_el)
else:
flash_el_dict['O'] = [geo_el]
elif apval["type"] == 'R':
if 'R' in flash_el_dict:
flash_el_dict['R'].append(geo_el)
else:
flash_el_dict['R'] = [geo_el]
else:
aperture_size = apval['size'] aperture_size = apval['size']
if aperture_size in traces_el_dict:
traces_el_dict[aperture_size].append(geo_el)
else: else:
if apval['width'] > apval['height']: traces_el_dict[aperture_size] = [geo_el]
aperture_size = apval['height']
else: cpoly = FlatCAMRTreeStorage()
aperture_size = apval['width'] pads_lines_list = list()
print(line, aperture_size)
if line: # process the flashes found in the selected polygon with the 'lines' method for rectangular
cpoly = self.fill_with_lines(line, aperture_size, # flashes and with 'seed' for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings with always True
for ap_type in flash_el_dict:
for elem in flash_el_dict[ap_type]:
if 'solid' in elem:
if ap_type == 'C':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tooldiameter, tooldia=tooldiameter,
steps_per_circle=self.app.defaults["geometry_circle_steps"], steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'O':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tooldiameter,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'R':
f_o = self.clear_polygon3(elem['solid'],
tooldia=tooldiameter,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
# add the lines from pads to the storage
try:
for lin in pads_lines_list:
if lin:
cpoly.insert(lin)
except TypeError:
cpoly.insert(pads_lines_list)
copper_lines_list = list()
# process the traces found in the selected polygon using the 'laser_lines' method,
# method which will follow the 'follow' line therefore use the longer path possible for the
# laser, therefore the acceleration will play a smaller factor
for aperture_size in traces_el_dict:
for elem in traces_el_dict[aperture_size]:
line = elem['follow']
if line:
t_o = self.fill_with_lines(line, aperture_size,
tooldia=tooldiameter,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over, overlap=over,
contour=cont, contour=cont,
connect=conn, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
copper_lines_list += [p for p in t_o.get_objects() if p]
# add the lines from copper features to storage but first try to make as few lines as possible
# by trying to fuse them
lines_union = linemerge(unary_union(copper_lines_list))
try:
for lin in lines_union:
if lin:
cpoly.insert(lin)
except TypeError:
cpoly.insert(lines_union)
# # determine the Gerber follow line
# for apid, apval in obj.apertures.items():
# for geo_el in apval['geometry']:
# if 'solid' in geo_el:
# if Point(inside_pt).within(geo_el['solid']):
# if not isinstance(geo_el['follow'], Point):
# line = geo_el['follow']
#
# if apval['type'] == 'C':
# aperture_size = apval['size']
# else:
# if apval['width'] > apval['height']:
# aperture_size = apval['height']
# else:
# aperture_size = apval['width']
#
# if line:
# cpoly = self.fill_with_lines(line, aperture_size,
# tooldia=tooldiameter,
# steps_per_circle=self.app.defaults["geometry_circle_steps"],
# overlap=over,
# contour=cont,
# connect=conn,
# prog_plot=prog_plot)
elif paint_method == "combo": elif paint_method == "combo":
self.app.inform.emit(_("Painting polygon with method: lines.")) self.app.inform.emit(_("Painting polygon with method: lines."))
cpoly = self.clear_polygon3(polyg, cpoly = self.clear_polygon3(polyg,
@@ -2225,6 +2343,132 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont, contour=cont,
connect=conn, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
elif paint_method == "laser_lines":
# line = None
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
flash_el_dict = dict()
# the key is the aperture size, the val is a list of geo elements
traces_el_dict = dict()
# find the flashes and the lines that are in the selected polygon and store
# them separately
for apid, apval in obj.apertures.items():
for geo_el in apval['geometry']:
if apval["size"] == 0.0:
if apval["size"] in traces_el_dict:
traces_el_dict[apval["size"]].append(geo_el)
else:
traces_el_dict[apval["size"]] = [geo_el]
if 'follow' in geo_el and geo_el['follow'].within(pol):
if isinstance(geo_el['follow'], Point):
if apval["type"] == 'C':
if 'C' in flash_el_dict:
flash_el_dict['C'].append(geo_el)
else:
flash_el_dict['C'] = [geo_el]
elif apval["type"] == 'O':
if 'O' in flash_el_dict:
flash_el_dict['O'].append(geo_el)
else:
flash_el_dict['O'] = [geo_el]
elif apval["type"] == 'R':
if 'R' in flash_el_dict:
flash_el_dict['R'].append(geo_el)
else:
flash_el_dict['R'] = [geo_el]
else:
aperture_size = apval['size']
if aperture_size in traces_el_dict:
traces_el_dict[aperture_size].append(geo_el)
else:
traces_el_dict[aperture_size] = [geo_el]
cp = FlatCAMRTreeStorage()
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method
# for rectangular flashes and with 'seed' for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings
# with always True
for ap_type in flash_el_dict:
for elem in flash_el_dict[ap_type]:
if 'solid' in elem:
if ap_type == 'C':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'O':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'R':
f_o = self.clear_polygon3(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
# add the lines from pads to the storage
try:
for lin in pads_lines_list:
if lin:
cp.insert(lin)
except TypeError:
cp.insert(pads_lines_list)
copper_lines_list = list()
# process the traces found in the selected polygon using the 'laser_lines'
# method, method which will follow the 'follow' line therefore use the longer
# path possible for the laser, therefore the acceleration will play
# a smaller factor
for aperture_size in traces_el_dict:
for elem in traces_el_dict[aperture_size]:
line = elem['follow']
if line:
t_o = self.fill_with_lines(line, aperture_size,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
copper_lines_list += [p for p in t_o.get_objects() if p]
# add the lines from copper features to storage but first try to make as few
# lines as possible
# by trying to fuse them
lines_union = linemerge(unary_union(copper_lines_list))
try:
for lin in lines_union:
if lin:
cp.insert(lin)
except TypeError:
cp.insert(lines_union)
elif paint_method == "combo": elif paint_method == "combo":
self.app.inform.emit(_("Painting polygons with method: lines.")) self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(pol, cp = self.clear_polygon3(pol,
@@ -2301,6 +2545,132 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont, contour=cont,
connect=conn, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
elif paint_method == "laser_lines":
# line = None
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
flash_el_dict = dict()
# the key is the aperture size, the val is a list of geo elements
traces_el_dict = dict()
# find the flashes and the lines that are in the selected polygon and store
# them separately
for apid, apval in obj.apertures.items():
for geo_el in apval['geometry']:
if apval["size"] == 0.0:
if apval["size"] in traces_el_dict:
traces_el_dict[apval["size"]].append(geo_el)
else:
traces_el_dict[apval["size"]] = [geo_el]
if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
if isinstance(geo_el['follow'], Point):
if apval["type"] == 'C':
if 'C' in flash_el_dict:
flash_el_dict['C'].append(geo_el)
else:
flash_el_dict['C'] = [geo_el]
elif apval["type"] == 'O':
if 'O' in flash_el_dict:
flash_el_dict['O'].append(geo_el)
else:
flash_el_dict['O'] = [geo_el]
elif apval["type"] == 'R':
if 'R' in flash_el_dict:
flash_el_dict['R'].append(geo_el)
else:
flash_el_dict['R'] = [geo_el]
else:
aperture_size = apval['size']
if aperture_size in traces_el_dict:
traces_el_dict[aperture_size].append(geo_el)
else:
traces_el_dict[aperture_size] = [geo_el]
cp = FlatCAMRTreeStorage()
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method
# for rectangular flashes and with 'seed' for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings
# with always True
for ap_type in flash_el_dict:
for elem in flash_el_dict[ap_type]:
if 'solid' in elem:
if ap_type == 'C':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'O':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'R':
f_o = self.clear_polygon3(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
# add the lines from pads to the storage
try:
for lin in pads_lines_list:
if lin:
cp.insert(lin)
except TypeError:
cp.insert(pads_lines_list)
copper_lines_list = list()
# process the traces found in the selected polygon using the 'laser_lines'
# method, method which will follow the 'follow' line therefore use the longer
# path possible for the laser, therefore the acceleration will play
# a smaller factor
for aperture_size in traces_el_dict:
for elem in traces_el_dict[aperture_size]:
line = elem['follow']
if line:
t_o = self.fill_with_lines(line, aperture_size,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
copper_lines_list += [p for p in t_o.get_objects() if p]
# add the lines from copper features to storage but first try to make as few
# lines as possible
# by trying to fuse them
lines_union = linemerge(unary_union(copper_lines_list))
try:
for lin in lines_union:
if lin:
cp.insert(lin)
except TypeError:
cp.insert(lines_union)
elif paint_method == "combo": elif paint_method == "combo":
self.app.inform.emit(_("Painting polygons with method: lines.")) self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf, cp = self.clear_polygon3(poly_buf,
@@ -2553,6 +2923,132 @@ class ToolPaint(FlatCAMTool, Gerber):
steps_per_circle=self.app.defaults["geometry_circle_steps"], steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn, overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
elif paint_method == "laser_lines":
# line = None
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
flash_el_dict = dict()
# the key is the aperture size, the val is a list of geo elements
traces_el_dict = dict()
# find the flashes and the lines that are in the selected polygon and store
# them separately
for apid, apval in obj.apertures.items():
for geo_el in apval['geometry']:
if apval["size"] == 0.0:
if apval["size"] in traces_el_dict:
traces_el_dict[apval["size"]].append(geo_el)
else:
traces_el_dict[apval["size"]] = [geo_el]
if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
if isinstance(geo_el['follow'], Point):
if apval["type"] == 'C':
if 'C' in flash_el_dict:
flash_el_dict['C'].append(geo_el)
else:
flash_el_dict['C'] = [geo_el]
elif apval["type"] == 'O':
if 'O' in flash_el_dict:
flash_el_dict['O'].append(geo_el)
else:
flash_el_dict['O'] = [geo_el]
elif apval["type"] == 'R':
if 'R' in flash_el_dict:
flash_el_dict['R'].append(geo_el)
else:
flash_el_dict['R'] = [geo_el]
else:
aperture_size = apval['size']
if aperture_size in traces_el_dict:
traces_el_dict[aperture_size].append(geo_el)
else:
traces_el_dict[aperture_size] = [geo_el]
cp = FlatCAMRTreeStorage()
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method
# for rectangular flashes and with 'seed' for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings
# with always True
for ap_type in flash_el_dict:
for elem in flash_el_dict[ap_type]:
if 'solid' in elem:
if ap_type == 'C':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'O':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'R':
f_o = self.clear_polygon3(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
# add the lines from pads to the storage
try:
for lin in pads_lines_list:
if lin:
cp.insert(lin)
except TypeError:
cp.insert(pads_lines_list)
copper_lines_list = list()
# process the traces found in the selected polygon using the 'laser_lines'
# method, method which will follow the 'follow' line therefore use the longer
# path possible for the laser, therefore the acceleration will play
# a smaller factor
for aperture_size in traces_el_dict:
for elem in traces_el_dict[aperture_size]:
line = elem['follow']
if line:
t_o = self.fill_with_lines(line, aperture_size,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
copper_lines_list += [p for p in t_o.get_objects() if p]
# add the lines from copper features to storage but first try to make as few
# lines as possible
# by trying to fuse them
lines_union = linemerge(unary_union(copper_lines_list))
try:
for lin in lines_union:
if lin:
cp.insert(lin)
except TypeError:
cp.insert(lines_union)
elif paint_method == "combo": elif paint_method == "combo":
self.app.inform.emit(_("Painting polygons with method: lines.")) self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf, cp = self.clear_polygon3(poly_buf,
@@ -2907,6 +3403,132 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont, contour=cont,
connect=conn, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
elif paint_method == "laser_lines":
# line = None
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
flash_el_dict = dict()
# the key is the aperture size, the val is a list of geo elements
traces_el_dict = dict()
# find the flashes and the lines that are in the selected polygon and store
# them separately
for apid, apval in obj.apertures.items():
for geo_el in apval['geometry']:
if apval["size"] == 0.0:
if apval["size"] in traces_el_dict:
traces_el_dict[apval["size"]].append(geo_el)
else:
traces_el_dict[apval["size"]] = [geo_el]
if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
if isinstance(geo_el['follow'], Point):
if apval["type"] == 'C':
if 'C' in flash_el_dict:
flash_el_dict['C'].append(geo_el)
else:
flash_el_dict['C'] = [geo_el]
elif apval["type"] == 'O':
if 'O' in flash_el_dict:
flash_el_dict['O'].append(geo_el)
else:
flash_el_dict['O'] = [geo_el]
elif apval["type"] == 'R':
if 'R' in flash_el_dict:
flash_el_dict['R'].append(geo_el)
else:
flash_el_dict['R'] = [geo_el]
else:
aperture_size = apval['size']
if aperture_size in traces_el_dict:
traces_el_dict[aperture_size].append(geo_el)
else:
traces_el_dict[aperture_size] = [geo_el]
cp = FlatCAMRTreeStorage()
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method
# for rectangular flashes and with 'seed' for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings
# with always True
for ap_type in flash_el_dict:
for elem in flash_el_dict[ap_type]:
if 'solid' in elem:
if ap_type == 'C':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'O':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'R':
f_o = self.clear_polygon3(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
# add the lines from pads to the storage
try:
for lin in pads_lines_list:
if lin:
cp.insert(lin)
except TypeError:
cp.insert(pads_lines_list)
copper_lines_list = list()
# process the traces found in the selected polygon using the 'laser_lines'
# method, method which will follow the 'follow' line therefore use the longer
# path possible for the laser, therefore the acceleration will play
# a smaller factor
for aperture_size in traces_el_dict:
for elem in traces_el_dict[aperture_size]:
line = elem['follow']
if line:
t_o = self.fill_with_lines(line, aperture_size,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
copper_lines_list += [p for p in t_o.get_objects() if p]
# add the lines from copper features to storage but first try to make as few
# lines as possible
# by trying to fuse them
lines_union = linemerge(unary_union(copper_lines_list))
try:
for lin in lines_union:
if lin:
cp.insert(lin)
except TypeError:
cp.insert(lines_union)
elif paint_method == "combo": elif paint_method == "combo":
self.app.inform.emit(_("Painting polygons with method: lines.")) self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf, cp = self.clear_polygon3(poly_buf,
@@ -3101,12 +3723,137 @@ class ToolPaint(FlatCAMTool, Gerber):
steps_per_circle=self.app.defaults["geometry_circle_steps"], steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over, contour=cont, connect=conn, overlap=over, contour=cont, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
elif paint_method == "laser_lines":
# line = None
# aperture_size = None
# the key is the aperture type and the val is a list of geo elements
flash_el_dict = dict()
# the key is the aperture size, the val is a list of geo elements
copper_el_dict = dict()
# find the flashes and the lines that are in the selected polygon and store
# them separately
for apid, apval in obj.apertures.items():
for geo_el in apval['geometry']:
if apval["size"] == 0.0:
if apval["size"] in copper_el_dict:
copper_el_dict[apval["size"]].append(geo_el)
else:
copper_el_dict[apval["size"]] = [geo_el]
if 'follow' in geo_el and geo_el['follow'].within(poly_buf):
if isinstance(geo_el['follow'], Point):
if apval["type"] == 'C':
if 'C' in flash_el_dict:
flash_el_dict['C'].append(geo_el)
else:
flash_el_dict['C'] = [geo_el]
elif apval["type"] == 'O':
if 'O' in flash_el_dict:
flash_el_dict['O'].append(geo_el)
else:
flash_el_dict['O'] = [geo_el]
elif apval["type"] == 'R':
if 'R' in flash_el_dict:
flash_el_dict['R'].append(geo_el)
else:
flash_el_dict['R'] = [geo_el]
else:
aperture_size = apval['size']
if aperture_size in copper_el_dict:
copper_el_dict[aperture_size].append(geo_el)
else:
copper_el_dict[aperture_size] = [geo_el]
cp = FlatCAMRTreeStorage()
pads_lines_list = list()
# process the flashes found in the selected polygon with the 'lines' method
# for rectangular flashes and with 'seed' for oblong and circular flashes
# and pads (flahes) need the contour therefore I override the GUI settings
# with always True
for ap_type in flash_el_dict:
for elem in flash_el_dict[ap_type]:
if 'solid' in elem:
if ap_type == 'C':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'O':
f_o = self.clear_polygon2(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
elif ap_type == 'R':
f_o = self.clear_polygon3(elem['solid'],
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=True,
connect=conn,
prog_plot=prog_plot)
pads_lines_list += [p for p in f_o.get_objects() if p]
# add the lines from pads to the storage
try:
for lin in pads_lines_list:
if lin:
cp.insert(lin)
except TypeError:
cp.insert(pads_lines_list)
copper_lines_list = list()
# process the traces found in the selected polygon using the 'laser_lines'
# method, method which will follow the 'follow' line therefore use the longer
# path possible for the laser, therefore the acceleration will play
# a smaller factor
for aperture_size in copper_el_dict:
for elem in copper_el_dict[aperture_size]:
line = elem['follow']
if line:
t_o = self.fill_with_lines(line, aperture_size,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
copper_lines_list += [p for p in t_o.get_objects() if p]
# add the lines from copper features to storage but first try to make as few
# lines as possible
# by trying to fuse them
lines_union = linemerge(unary_union(copper_lines_list))
try:
for lin in lines_union:
if lin:
cp.insert(lin)
except TypeError:
cp.insert(lines_union)
elif paint_method == "combo": elif paint_method == "combo":
self.app.inform.emit(_("Painting polygons with method: lines.")) self.app.inform.emit(_("Painting polygons with method: lines."))
cp = self.clear_polygon3(poly_buf, cp = self.clear_polygon3(poly_buf,
tooldia=tool_dia, tooldia=tool_dia,
steps_per_circle=self.app.defaults[ steps_per_circle=self.app.defaults["geometry_circle_steps"],
"geometry_circle_steps"],
overlap=over, overlap=over,
contour=cont, contour=cont,
connect=conn, connect=conn,