diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index caeb61d7..f339a399 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -1026,7 +1026,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"painttooldia": 0.0625,
"paintoverlap": 0.15,
"paintmargin": 0.01,
- "paintmethod": "standard"
+ "paintmethod": "standard",
+ "multidepth": False,
+ "depthperpass": -0.002
})
# Attributes to be included in serialization
@@ -1055,7 +1057,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"painttooldia": self.ui.painttooldia_entry,
"paintoverlap": self.ui.paintoverlap_entry,
"paintmargin": self.ui.paintmargin_entry,
- "paintmethod": self.ui.paintmethod_combo
+ "paintmethod": self.ui.paintmethod_combo,
+ "multidepth": self.ui.mpass_cb,
+ "depthperpass": self.ui.maxdepth_entry
})
self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
@@ -1137,11 +1141,19 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.read_form()
self.generatecncjob()
- def generatecncjob(self, z_cut=None, z_move=None,
- feedrate=None, tooldia=None, outname=None,
- spindlespeed=None):
+ def generatecncjob(self,
+ z_cut=None,
+ z_move=None,
+ feedrate=None,
+ tooldia=None,
+ outname=None,
+ spindlespeed=None,
+ multidepth=None,
+ depthperpass=None):
"""
- Creates a CNCJob out of this Geometry object.
+ Creates a CNCJob out of this Geometry object. The actual
+ work is done by the target FlatCAMCNCjob object's
+ `generate_from_geometry_2()` method.
:param z_cut: Cut depth (negative)
:param z_move: Hight of the tool when travelling (not cutting)
@@ -1157,6 +1169,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
z_move = z_move if z_move is not None else self.options["travelz"]
feedrate = feedrate if feedrate is not None else self.options["feedrate"]
tooldia = tooldia if tooldia is not None else self.options["cnctooldia"]
+ multidepth = multidepth if multidepth is not None else self.options["multidepth"]
+ depthperpass = depthperpass if depthperpass is not None else self.options["depthperpass"]
# To allow default value to be "" (optional in gui) and translate to None
# if not isinstance(spindlespeed, int):
@@ -1186,7 +1200,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
job_obj.spindlespeed = spindlespeed
app_obj.progress.emit(40)
# TODO: The tolerance should not be hard coded. Just for testing.
- job_obj.generate_from_geometry_2(self, tolerance=0.0005)
+ job_obj.generate_from_geometry_2(self,
+ multidepth=multidepth,
+ depthpercut=depthperpass,
+ tolerance=0.0005)
app_obj.progress.emit(50)
job_obj.gcode_parse()
diff --git a/GUIElements.py b/GUIElements.py
index 79171a96..831379bc 100644
--- a/GUIElements.py
+++ b/GUIElements.py
@@ -246,9 +246,16 @@ class VerticalScrollArea(QtGui.QScrollArea):
return QtGui.QWidget.eventFilter(self, source, event)
-class OptionalInputSection():
+class OptionalInputSection:
def __init__(self, cb, optinputs):
+ """
+ Associates the a checkbox with a set of inputs.
+
+ :param cb: Checkbox that enables the optional inputs.
+ :param optinputs: List of widgets that are optional.
+ :return:
+ """
assert isinstance(cb, FCCheckBox), \
"Expected an FCCheckBox, got %s" % type(cb)
diff --git a/ObjectUI.py b/ObjectUI.py
index ebb4ea17..f7ce3d97 100644
--- a/ObjectUI.py
+++ b/ObjectUI.py
@@ -222,7 +222,9 @@ class GeometryObjectUI(ObjectUI):
)
self.custom_box.addWidget(self.plot_cb)
- ## Create CNC Job
+ #-----------------------------------
+ # Create CNC Job
+ #-----------------------------------
self.cncjob_label = QtGui.QLabel('Create CNC Job:')
self.cncjob_label.setToolTip(
"Create a CNC Job object\n"
@@ -283,15 +285,38 @@ class GeometryObjectUI(ObjectUI):
self.cncspindlespeed_entry = IntEntry(allow_empty=True)
grid1.addWidget(self.cncspindlespeed_entry, 4, 1)
+ # Multi-pass
+ mpasslabel = QtGui.QLabel('Multi-Depth:')
+ mpasslabel.setToolTip(
+ "Use multiple passes to limit\n"
+ "the cut depth in each pass. Will\n"
+ "cut multiple times until Cut Z is\n"
+ "reached."
+ )
+ grid1.addWidget(mpasslabel, 5, 0)
+ self.mpass_cb = FCCheckBox()
+ grid1.addWidget(self.mpass_cb, 5, 1)
+
+ maxdepthlabel = QtGui.QLabel('Depth/pass:')
+ maxdepthlabel.setToolTip(
+ "Depth of each pass."
+ )
+ grid1.addWidget(maxdepthlabel, 6, 0)
+ self.maxdepth_entry = LengthEntry()
+ grid1.addWidget(self.maxdepth_entry, 6, 1)
+
+ self.ois_mpass = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
+
+ # Button
self.generate_cnc_button = QtGui.QPushButton('Generate')
self.generate_cnc_button.setToolTip(
"Generate the CNC Job object."
)
self.custom_box.addWidget(self.generate_cnc_button)
- ################
- ## Paint area ##
- ################
+ #------------------------------
+ # Paint area
+ #------------------------------
self.paint_label = QtGui.QLabel('Paint Area:')
self.paint_label.setToolTip(
"Creates tool paths to cover the\n"
diff --git a/camlib.py b/camlib.py
index c677227f..5748635b 100644
--- a/camlib.py
+++ b/camlib.py
@@ -2715,8 +2715,13 @@ class CNCjob(Geometry):
self.gcode = gcode
- def generate_from_geometry_2(self, geometry, append=True, tooldia=None, tolerance=0,
- multipass=False, depthpercut=None):
+ def generate_from_geometry_2(self,
+ geometry,
+ append=True,
+ tooldia=None,
+ tolerance=0,
+ multidepth=False,
+ depthpercut=None):
"""
Second algorithm to generate from Geometry.
@@ -2732,6 +2737,7 @@ class CNCjob(Geometry):
"""
assert isinstance(geometry, Geometry), \
"Expected a Geometry, got %s" % type(geometry)
+
log.debug("generate_from_geometry_2()")
## Flatten the geometry
@@ -2768,7 +2774,7 @@ class CNCjob(Geometry):
self.gcode += self.feedminutecode + "\n"
self.gcode += "F%.2f\n" % self.feedrate
self.gcode += "G00 Z%.4f\n" % self.z_move # Move (up) to travel height
- if(self.spindlespeed != None):
+ if self.spindlespeed is not None:
self.gcode += "M03 S%d\n" % int(self.spindlespeed) # Spindle start with configured speed
else:
self.gcode += "M03\n" # Spindle start
@@ -2794,7 +2800,7 @@ class CNCjob(Geometry):
if pt != geo.coords[0] and pt == geo.coords[-1]:
geo.coords = list(geo.coords)[::-1]
- if not multipass:
+ if not multidepth:
# G-code
# Note: self.linear2gcode() and self.point2gcode() will
# lower and raise the tool every time.
@@ -2804,24 +2810,52 @@ class CNCjob(Geometry):
self.gcode += self.point2gcode(geo)
else:
log.warning("G-code generation not implemented for %s" % (str(type(geo))))
+
+ #--------- Multi-pass ---------
else:
if depthpercut is None:
depthpercut = self.z_cut
depth = 0
+ reverse = False
while depth > self.z_cut:
depth -= depthpercut
+ log.debug("DEPTH: %f" % depth)
# TODO: Working...
# G-code
# Note: self.linear2gcode() and self.point2gcode() will
# lower and raise the tool every time.
- # if type(geo) == LineString or type(geo) == LinearRing:
- # self.gcode += self.linear2gcode(geo, tolerance=tolerance)
- # elif type(geo) == Point:
- # self.gcode += self.point2gcode(geo)
- # else:
- # log.warning("G-code generation not implemented for %s" % (str(type(geo))))
+ # Cut at specific depth and do not leave the tool.
+ if type(geo) == LineString or type(geo) == LinearRing:
+ self.gcode += self.linear2gcode(geo, tolerance=tolerance,
+ zcut=depth,
+ up=False)
+
+ # Ignore multi-pass for points.
+ elif type(geo) == Point:
+ self.gcode += self.point2gcode(geo)
+ break # Ignoring ...
+
+ else:
+ log.warning("G-code generation not implemented for %s" % (str(type(geo))))
+
+ # Reverse coordinates if not a loop so we can continue
+ # cutting without returning to the beginhing.
+ if type(geo) == LineString:
+ geo.coords = list(geo.coords)[::-1]
+ reverse = True
+
+ # If geometry is reversed, revert.
+ if reverse:
+ if type(geo) == LineString:
+ geo.coords = list(geo.coords)[::-1]
+
+ # Lift the tool
+ self.gcode += "G00 Z%.4f\n" % self.z_move
+ # self.gcode += "( End of path. )\n"
+
+ # Did deletion at the beginning.
# Delete from index, update current location and continue.
#rti.delete(hits[0], geo.coords[0])
#rti.delete(hits[0], geo.coords[-1])