From af2d178e570a9238e30c0d39094c9df61c4be470 Mon Sep 17 00:00:00 2001 From: sliptonic Date: Fri, 9 Jan 2026 12:11:00 -0600 Subject: [PATCH] CAM: Adding retract annotation to drilling commands (#26584) * Adding retract annotation to drilling commands checkpoint * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/Mod/CAM/Path/Op/Drilling.py | 154 ++++++++++++++------------------ 1 file changed, 67 insertions(+), 87 deletions(-) diff --git a/src/Mod/CAM/Path/Op/Drilling.py b/src/Mod/CAM/Path/Op/Drilling.py index a2ac1e1b7a..da9ec0c60b 100644 --- a/src/Mod/CAM/Path/Op/Drilling.py +++ b/src/Mod/CAM/Path/Op/Drilling.py @@ -28,6 +28,7 @@ import Part import Path import Path.Base.FeedRate as PathFeedRate import Path.Base.Generator.drill as drill +import Path.Base.Generator.linking as linking import Path.Base.MachineState as PathMachineState import Path.Op.Base as PathOp import Path.Op.CircularHoleBase as PathCircularHoleBase @@ -65,10 +66,6 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): # Enumeration lists for App::PropertyEnumeration properties enums = { - "RetractMode": [ - (translate("CAM_Drilling", "G98"), "G98"), - (translate("CAM_Drilling", "G99"), "G99"), - ], # How high to retract after a drilling move "ExtraOffset": [ (translate("CAM_Drilling", "None"), "None"), (translate("CAM_Drilling", "Drill Tip"), "Drill Tip"), @@ -110,6 +107,19 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): "Drill", QT_TRANSLATE_NOOP("App::Property", "Use G85 boring cycle with feed out"), ) + if hasattr(obj, "RetractMode"): + obj.removeProperty("RetractMode") + + if not hasattr(obj, "KeepToolDown"): + obj.addProperty( + "App::PropertyBool", + "KeepToolDown", + "Drill", + QT_TRANSLATE_NOOP( + "App::Property", + "Apply G99 retraction: only retract to RetractHeight between holes in this operation", + ), + ) def initCircularHoleOperation(self, obj): """initCircularHoleOperation(obj) ... add drilling specific properties to obj.""" @@ -155,15 +165,6 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): "Calculate the tip length and subtract from final depth", ), ) - obj.addProperty( - "App::PropertyEnumeration", - "RetractMode", - "Drill", - QT_TRANSLATE_NOOP( - "App::Property", - "Controls tool retract height between holes in same op, Default=G98: safety height\nUse property KeepToolDown to change this", - ), - ) obj.addProperty( "App::PropertyDistance", "RetractHeight", @@ -195,23 +196,12 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): QT_TRANSLATE_NOOP("App::Property", "Use G85 boring cycle with feed out"), ) - obj.setEditorMode("RetractMode", 1) # Set property read-only - - for n in self.propertyEnumerations(): - setattr(obj, n[0], n[1]) - def circularHoleExecute(self, obj, holes): """circularHoleExecute(obj, holes) ... generate drill operation for each hole in holes.""" Path.Log.track() - machine = PathMachineState.MachineState() + machinestate = PathMachineState.MachineState() - self.commandlist.append(Path.Command("(Begin Drilling)")) - self.commandlist.append(Path.Command("G90")) # Set absolute distance mode before any moves - - # rapid to clearance height - command = Path.Command("G0", {"Z": obj.ClearanceHeight.Value}) - machine.addCommand(command) - self.commandlist.append(command) + mode = "G99" if obj.KeepToolDown else "G98" # Calculate offsets to add to target edge endoffset = 0.0 @@ -220,76 +210,66 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): elif obj.ExtraOffset == "2x Drill Tip": endoffset = PathUtils.drillTipLength(self.tool) * 2 - if not hasattr(obj, "KeepToolDown"): - obj.addProperty( - "App::PropertyBool", - "KeepToolDown", - "Drill", - QT_TRANSLATE_NOOP( - "App::Property", - "Apply G99 retraction: only retract to RetractHeight between holes in this operation", - ), - ) - - if not hasattr(obj, "RetractMode"): - obj.addProperty( - "App::PropertyEnumeration", - "RetractMode", - "Drill", - QT_TRANSLATE_NOOP( - "App::Property", - "Controls tool retract height between holes in same op, Default=G98: safety height\nUse property KeepToolDown to change this", - ), - ) - obj.setEditorMode("RetractMode", 1) # Set property read-only - # ensure new enums exist in old class - for n in self.propertyEnumerations(): - setattr(obj, n[0], n[1]) - - # http://linuxcnc.org/docs/html/gcode/g-code.html#gcode:g98-g99 - if obj.KeepToolDown: - obj.RetractMode = "G99" - else: - obj.RetractMode = "G98" - self.commandlist.append(Path.Command(obj.RetractMode)) - - # This section is technical debt. The computation of the - # target shapes should be factored out for reuse. - # This will likely mean refactoring upstream CircularHoleBase to pass - # spotshapes instead of holes. - + # compute the drilling targets edgelist = [] for hole in holes: v1 = FreeCAD.Vector(hole["x"], hole["y"], obj.StartDepth.Value) v2 = FreeCAD.Vector(hole["x"], hole["y"], obj.FinalDepth.Value - endoffset) edgelist.append(Part.makeLine(v1, v2)) - # iterate the edgelist and generate gcode - safeHeight = True - for edge in edgelist: + # build list of solids for collision detection. + # Include base objects from job + solids = [] + for base in job.BaseObjects: + solids.append(base.Shape) + # http://linuxcnc.org/docs/html/gcode/g-code.html#gcode:g98-g99 + + # This section is technical debt. The computation of the + # target shapes should be factored out for reuse. + # This will likely mean refactoring upstream CircularHoleBase to pass + # spotshapes instead of holes. + + # Start computing the Path + self.commandlist.append(Path.Command("(Begin Drilling)")) + + # Make sure tool is at a clearance height + command = Path.Command("G0", {"Z": obj.ClearanceHeight.Value}) + # machine.addCommand(command) + self.commandlist.append(command) + + # iterate the edgelist and generate gcode + firstMove = True + for edge in edgelist: Path.Log.debug(edge) - # move to hole location - + # Get the target start point startPoint = edge.Vertexes[0].Point - # G81,83 will do this move anyway but FreeCAD sets feedrate according to _isVertical, - # so do this explicitly before drilling. - command = Path.Command("G0", {"X": startPoint.x, "Y": startPoint.y}) - self.commandlist.append(command) - machine.addCommand(command) - - # rapid to safe height for first edge only //Dimitrios - if safeHeight is True: + # Get linking moves from current to start of target + if firstMove: # Build manually + command = Path.Command("G0", {"X": startPoint.x, "Y": startPoint.y}) + self.commandlist.append(command) + machinestate.addCommand(command) command = Path.Command("G0", {"Z": obj.SafeHeight.Value}) self.commandlist.append(command) - machine.addCommand(command) - safeHeight = False + machinestate.addCommand(command) + firstMove = False - # Technical Debt: We are assuming the edges are aligned. - # This assumption should be corrected and the necessary rotations - # performed to align the edge with the Z axis for drilling + else: # Use get_linking_moves generator + linking_moves = linking.get_linking_moves( + machinestate.getPosition(), + startPoint, + obj.ClearanceHeight.Value, + obj.SafeHeight.Value, + self.tool, + solids, + obj.RetractHeight.Value, + ) + if len(linking_moves) == 1: # straight move possible. Do nothing. + pass + else: + self.commandlist.extend(linking_moves) # Perform drilling dwelltime = obj.DwellTime if obj.DwellEnabled else 0.0 @@ -312,12 +292,13 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): Path.Log.info(e) continue + # Set RetractMode annotation for each command for command in drillcommands: + annotations = command.Annotations + annotations["RetractMode"] = mode + command.Annotations = annotations self.commandlist.append(command) - machine.addCommand(command) - - # Cancel canned drilling cycle - self.commandlist.append(Path.Command("G80")) + # machine.addCommand(command) # Apply feedrates to commands PathFeedRate.setFeedRate(self.commandlist, obj.ToolController) @@ -353,7 +334,6 @@ def SetupProperties(): setup.append("DwellTime") setup.append("DwellEnabled") setup.append("AddTipLength") - setup.append("RetractMode") setup.append("ExtraOffset") setup.append("RetractHeight") setup.append("KeepToolDown")