diff --git a/src/Mod/Path/Path/Dressup/Boundary.py b/src/Mod/Path/Path/Dressup/Boundary.py index 9194b0d6d7..08a4293fd6 100644 --- a/src/Mod/Path/Path/Dressup/Boundary.py +++ b/src/Mod/Path/Path/Dressup/Boundary.py @@ -149,7 +149,8 @@ class PathBoundary: ): return None - if len(self.baseOp.Path.Commands) == 0: + path = PathUtils.getPathWithPlacement(self.baseOp) + if len(path.Commands) == 0: Path.Log.warning("No Path Commands for %s" % self.baseOp.Label) return [] @@ -164,13 +165,13 @@ class PathBoundary: ) self.strG0ZclearanceHeight = Path.Command("G0", {"Z": self.clearanceHeight}) - cmd = self.baseOp.Path.Commands[0] + cmd = path.Commands[0] pos = cmd.Placement.Base # bogus m/c position to create first edge bogusX = True bogusY = True commands = [cmd] lastExit = None - for cmd in self.baseOp.Path.Commands[1:]: + for cmd in path.Commands[1:]: if cmd.Name in Path.Geom.CmdMoveAll: if bogusX: bogusX = "X" not in cmd.Parameters diff --git a/src/Mod/Path/Path/Dressup/DogboneII.py b/src/Mod/Path/Path/Dressup/DogboneII.py index f4fa0243f6..2e4f74bd32 100644 --- a/src/Mod/Path/Path/Dressup/DogboneII.py +++ b/src/Mod/Path/Path/Dressup/DogboneII.py @@ -25,6 +25,7 @@ import FreeCAD import Path import Path.Base.Generator.dogboneII as dogboneII import Path.Base.Language as PathLanguage +import PathScripts.PathUtils as PathUtils import math if False: @@ -294,7 +295,7 @@ class Proxy(object): dressingUpDogbone = hasattr(obj.Base, "BoneBlacklist") if obj.Base and obj.Base.Path and obj.Base.Path.Commands: for i, instr in enumerate( - PathLanguage.Maneuver.FromPath(obj.Base.Path).instr + PathLanguage.Maneuver.FromPath(PathUtils.getPathWithPlacement(obj.Base)).instr ): # Path.Log.debug(f"instr: {instr}") if instr.isMove(): diff --git a/src/Mod/Path/Path/Dressup/Gui/AxisMap.py b/src/Mod/Path/Path/Dressup/Gui/AxisMap.py index 2cd1497a06..8a980d18c6 100644 --- a/src/Mod/Path/Path/Dressup/Gui/AxisMap.py +++ b/src/Mod/Path/Path/Dressup/Gui/AxisMap.py @@ -114,7 +114,7 @@ class ObjectDressup: if obj.Base.isDerivedFrom("Path::Feature"): if obj.Base.Path: if obj.Base.Path.Commands: - pp = obj.Base.Path.Commands + pp = PathUtils.getPathWithPlacement(obj.Base).Commands if len([i for i in pp if i.Name in Path.Geom.CmdMoveArc]) == 0: pathlist = pp else: diff --git a/src/Mod/Path/Path/Dressup/Gui/Dogbone.py b/src/Mod/Path/Path/Dressup/Gui/Dogbone.py index a1a59dcac2..73ce0ba498 100644 --- a/src/Mod/Path/Path/Dressup/Gui/Dogbone.py +++ b/src/Mod/Path/Path/Dressup/Gui/Dogbone.py @@ -910,7 +910,7 @@ class ObjectDressup(object): self.length = 0 # boneIserted = False - for (i, thisCommand) in enumerate(obj.Base.Path.Commands): + for (i, thisCommand) in enumerate(PathUtils.getPathWithPlacement(obj.Base).Commands): # if i > 14: # if lastCommand: # commands.append(lastCommand) diff --git a/src/Mod/Path/Path/Dressup/Gui/Dragknife.py b/src/Mod/Path/Path/Dressup/Gui/Dragknife.py index a807748e24..31545e8a85 100644 --- a/src/Mod/Path/Path/Dressup/Gui/Dragknife.py +++ b/src/Mod/Path/Path/Dressup/Gui/Dragknife.py @@ -388,7 +388,7 @@ class ObjectDressup: queue = [] - for curCommand in obj.Base.Path.Commands: + for curCommand in PathUtils.getPathWithPlacement(obj.Base).Commands: replace = None # don't worry about non-move commands, just add to output if curCommand.Name not in movecommands + rapidcommands: diff --git a/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py b/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py index db7e5e382f..9c394f792e 100644 --- a/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py +++ b/src/Mod/Path/Path/Dressup/Gui/LeadInOut.py @@ -188,7 +188,7 @@ class ObjectDressup: + "\n" ) obj.Length = 0.1 - self.wire, self.rapids = Path.Geom.wireForPath(obj.Base.Path) + self.wire, self.rapids = Path.Geom.wireForPath(PathUtils.getPathWithPlacement(obj.Base)) obj.Path = self.generateLeadInOutCurve(obj) def getDirectionOfPath(self, obj): @@ -556,7 +556,7 @@ class ObjectDressup: layers = [] # Read in all commands - for curCommand in obj.Base.Path.Commands: + for curCommand in PathUtils.getPathWithPlacement(obj.Base).Commands: Path.Log.debug("CurCMD: {}".format(curCommand)) if curCommand.Name not in movecommands + rapidcommands: # Don't worry about non-move commands, just add to output diff --git a/src/Mod/Path/Path/Dressup/Gui/RampEntry.py b/src/Mod/Path/Path/Dressup/Gui/RampEntry.py index 820f9516eb..697dd87501 100644 --- a/src/Mod/Path/Path/Dressup/Gui/RampEntry.py +++ b/src/Mod/Path/Path/Dressup/Gui/RampEntry.py @@ -222,7 +222,7 @@ class ObjectDressup: self.angle = obj.Angle self.method = obj.Method - self.wire, self.rapids = Path.Geom.wireForPath(obj.Base.Path) + self.wire, self.rapids = Path.Geom.wireForPath(PathUtils.getPathWithPlacement(obj.Base)) if self.method in ["RampMethod1", "RampMethod2", "RampMethod3"]: self.outedges = self.generateRamps() else: diff --git a/src/Mod/Path/Path/Dressup/Gui/ZCorrect.py b/src/Mod/Path/Path/Dressup/Gui/ZCorrect.py index c591a02867..baa9fc0ee8 100644 --- a/src/Mod/Path/Path/Dressup/Gui/ZCorrect.py +++ b/src/Mod/Path/Path/Dressup/Gui/ZCorrect.py @@ -155,7 +155,7 @@ class ObjectDressup: curveD = obj.ArcInterpolate.Value if obj.interpSurface.isNull(): # No valid probe data. return unchanged path - obj.Path = obj.Base.Path + obj.Path = PathUtils.getPathWithPlacement(obj.Base) return surface = obj.interpSurface.toNurbs().Faces[0].Surface @@ -163,8 +163,9 @@ class ObjectDressup: if obj.Base: if obj.Base.isDerivedFrom("Path::Feature"): if obj.Base.Path: - if obj.Base.Path.Commands: - pathlist = obj.Base.Path.Commands + path = PathUtils.getPathWithPlacement(obj.Base) + if path.Commands: + pathlist = path.Commands newcommandlist = [] currLocation = {"X": 0, "Y": 0, "Z": 0, "F": 0} diff --git a/src/Mod/Path/Path/Dressup/Tags.py b/src/Mod/Path/Path/Dressup/Tags.py index 72950e99c4..ecc84cd420 100644 --- a/src/Mod/Path/Path/Dressup/Tags.py +++ b/src/Mod/Path/Path/Dressup/Tags.py @@ -674,7 +674,8 @@ class PathData: def __init__(self, obj): Path.Log.track(obj.Base.Name) self.obj = obj - self.wire, rapid = Path.Geom.wireForPath(obj.Base.Path) + path = PathUtils.getPathWithPlacement(obj.Base) + self.wire, rapid = Path.Geom.wireForPath(path) self.rapid = _RapidEdges(rapid) if self.wire: self.edges = self.wire.Edges @@ -1255,7 +1256,7 @@ class ObjectTagDressup: if not self.tags: Path.Log.debug("execute - no tags") - obj.Path = obj.Base.Path + obj.Path = PathUtils.getPathWithPlacement(obj.Base) return try: @@ -1264,7 +1265,7 @@ class ObjectTagDressup: Path.Log.error( "processing tags failed clearing all tags ... '%s'" % (e.args[0]) ) - obj.Path = obj.Base.Path + obj.Path = PathUtils.getPathWithPlacement(obj.Base) # update disabled in case there are some additional ones disabled = copy.copy(self.obj.Disabled) diff --git a/src/Mod/Path/Path/Main/Gui/Inspect.py b/src/Mod/Path/Path/Main/Gui/Inspect.py index e24e537817..fe4967ba03 100644 --- a/src/Mod/Path/Path/Main/Gui/Inspect.py +++ b/src/Mod/Path/Path/Main/Gui/Inspect.py @@ -182,7 +182,7 @@ class GCodeEditorDialog(QtGui.QDialog): cursor.setPosition(ep) endrow = cursor.blockNumber() - commands = self.PathObj.Commands + commands = PathUtils.getPathWithPlacement(self.PathObj).Commands # Derive the starting position for the first selected command prevX = prevY = prevZ = None diff --git a/src/Mod/Path/Path/Main/Gui/Simulator.py b/src/Mod/Path/Path/Main/Gui/Simulator.py index 430f12b559..888fd0205e 100644 --- a/src/Mod/Path/Path/Main/Gui/Simulator.py +++ b/src/Mod/Path/Path/Main/Gui/Simulator.py @@ -24,6 +24,7 @@ import FreeCAD import Path import Path.Base.Util as PathUtil import Path.Dressup.Utils as PathDressup +import PathScripts.PathUtils as PathUtils import Path.Main.Job as PathJob import PathGui import PathSimulator @@ -202,7 +203,7 @@ class PathSimulation: self.icmd = 0 self.curpos = FreeCAD.Placement(self.initialPos, self.stdrot) self.cutTool.Placement = self.curpos - self.opCommands = self.operation.Path.Commands + self.opCommands = PathUtils.getPathWithPlacement(self.operation).Commands def SimulateMill(self): self.job = self.jobs[self.taskForm.form.comboJobs.currentIndex()] @@ -258,7 +259,7 @@ class PathSimulation: return self.busy = True - cmd = self.operation.Path.Commands[self.icmd] + cmd = self.opCommands[self.icmd] pathSolid = None if cmd.Name in ["G0"]: @@ -302,7 +303,7 @@ class PathSimulation: self.icmd += 1 self.iprogress += 1 self.UpdateProgress() - if self.icmd >= len(self.operation.Path.Commands): + if self.icmd >= len(self.opCommands): self.ioperation += 1 if self.ioperation >= len(self.activeOps): self.EndSimulation() diff --git a/src/Mod/Path/Path/Op/Gui/Array.py b/src/Mod/Path/Path/Op/Gui/Array.py index b7daea3400..0031a1adba 100644 --- a/src/Mod/Path/Path/Op/Gui/Array.py +++ b/src/Mod/Path/Path/Op/Gui/Array.py @@ -24,6 +24,7 @@ import FreeCAD import FreeCADGui import Path import PathScripts +import PathScripts.PathUtils as PathUtils from Path.Dressup.Utils import toolController from PySide import QtCore import math @@ -285,69 +286,6 @@ class PathArray: else: self.baseList = [baseList] - def rotatePath(self, path, angle, centre): - """ - Rotates Path around given centre vector - Only X and Y is considered - """ - CmdMoveRapid = ["G0", "G00"] - CmdMoveStraight = ["G1", "G01"] - CmdMoveCW = ["G2", "G02"] - CmdMoveCCW = ["G3", "G03"] - CmdDrill = ["G73", "G81", "G82", "G83"] - CmdMoveArc = CmdMoveCW + CmdMoveCCW - CmdMove = CmdMoveStraight + CmdMoveArc - - commands = [] - ang = angle / 180 * math.pi - currX = 0 - currY = 0 - for cmd in path.Commands: - if ( - (cmd.Name in CmdMoveRapid) - or (cmd.Name in CmdMove) - or (cmd.Name in CmdDrill) - ): - params = cmd.Parameters - x = params.get("X") - if x is None: - x = currX - currX = x - y = params.get("Y") - if y is None: - y = currY - currY = y - - # "move" the centre to origin - x = x - centre.x - y = y - centre.y - - # rotation around origin: - nx = x * math.cos(ang) - y * math.sin(ang) - ny = y * math.cos(ang) + x * math.sin(ang) - - # "move" the centre back and update - params.update({"X": nx + centre.x, "Y": ny + centre.y}) - - # Arcs need to have the I and J params rotated as well - if cmd.Name in CmdMoveArc: - i = params.get("I") - if i is None: - i = 0 - j = params.get("J") - if j is None: - j = 0 - - ni = i * math.cos(ang) - j * math.sin(ang) - nj = j * math.cos(ang) + i * math.sin(ang) - params.update({"I": ni, "J": nj}) - - cmd.Parameters = params - commands.append(cmd) - newPath = Path.Path(commands) - - return newPath - # Private method def _calculateJitter(self, pos): """_calculateJitter(pos) ... @@ -411,7 +349,7 @@ class PathArray: for b in base: pl = FreeCAD.Placement() pl.move(pos) - np = Path.Path([cm.transform(pl) for cm in b.Path.Commands]) + np = Path.Path([cm.transform(pl) for cm in PathUtils.getPathWithPlacement(b).Commands]) output += np.toGCode() elif self.arrayType == "Linear2D": @@ -438,7 +376,7 @@ class PathArray: if not (i == 0 and j == 0): pl.move(pos) np = Path.Path( - [cm.transform(pl) for cm in b.Path.Commands] + [cm.transform(pl) for cm in PathUtils.getPathWithPlacement(b).Commands] ) output += np.toGCode() else: @@ -464,7 +402,7 @@ class PathArray: if not (i == 0 and j == 0): pl.move(pos) np = Path.Path( - [cm.transform(pl) for cm in b.Path.Commands] + [cm.transform(pl) for cm in PathUtils.getPathWithPlacement(b).Commands] ) output += np.toGCode() # Eif @@ -474,7 +412,10 @@ class PathArray: ang = 360 if self.copies > 0: ang = self.angle / self.copies * (1 + i) - np = self.rotatePath(b.Path, ang, self.centre) + + pl = FreeCAD.Placement() + pl.rotate(self.centre, FreeCAD.Vector(0, 0, 1), ang) + np = PathUtils.applyPlacementToPath(pl, PathUtils.getPathWithPlacement(b)) output += np.toGCode() # return output diff --git a/src/Mod/Path/Path/Op/Gui/Copy.py b/src/Mod/Path/Path/Op/Gui/Copy.py index 939da3c488..001591ba5b 100644 --- a/src/Mod/Path/Path/Op/Gui/Copy.py +++ b/src/Mod/Path/Path/Op/Gui/Copy.py @@ -63,6 +63,8 @@ class ObjectPathCopy: obj.ToolController = obj.Base.ToolController if obj.Base.Path: obj.Path = obj.Base.Path.copy() + if obj.Base.Placement: + obj.Placement = obj.Base.Placement class ViewProviderPathCopy: diff --git a/src/Mod/Path/Path/Op/Gui/SimpleCopy.py b/src/Mod/Path/Path/Op/Gui/SimpleCopy.py index 64f2879108..9edf59a619 100644 --- a/src/Mod/Path/Path/Op/Gui/SimpleCopy.py +++ b/src/Mod/Path/Path/Op/Gui/SimpleCopy.py @@ -68,10 +68,13 @@ class CommandPathSimpleCopy: FreeCAD.ActiveDocument.openTransaction("Simple Copy") FreeCADGui.doCommand( - "srcpath = FreeCADGui.Selection.getSelectionEx()[0].Object.Path\n" + "srcobj = FreeCADGui.Selection.getSelectionEx()[0].Object\n" ) FreeCADGui.addModule("PathScripts.PathUtils") + FreeCADGui.doCommand( + "srcpath = PathScripts.PathUtils.getPathWithPlacement(srcobj)\n" + ) FreeCADGui.addModule("Path.Op.Custom") FreeCADGui.doCommand( 'obj = Path.Op.Custom.Create("' + selection[0].Name + '_SimpleCopy")' diff --git a/src/Mod/Path/Path/Post/UtilsParse.py b/src/Mod/Path/Path/Post/UtilsParse.py index 906118e2ab..7158cb483e 100644 --- a/src/Mod/Path/Path/Post/UtilsParse.py +++ b/src/Mod/Path/Path/Post/UtilsParse.py @@ -34,6 +34,7 @@ from FreeCAD import Units import Path import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils def create_comment(values, comment_string): """Create a comment from a string using the correct comment symbol.""" @@ -354,7 +355,7 @@ def parse_a_path(values, pathobj): f"Tool Controller Vertical Rapid Values are unset{nl}" ) - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: # List of elements in the command, code, and params. outstring = [] diff --git a/src/Mod/Path/Path/Post/scripts/KineticNCBeamicon2_post.py b/src/Mod/Path/Path/Post/scripts/KineticNCBeamicon2_post.py index bde97752fb..bdf308a5e0 100644 --- a/src/Mod/Path/Path/Post/scripts/KineticNCBeamicon2_post.py +++ b/src/Mod/Path/Path/Post/scripts/KineticNCBeamicon2_post.py @@ -39,6 +39,7 @@ import argparse import datetime import shlex from PathScripts import PathUtils +import PathScripts.PathUtils as PathUtils TOOLTIP = """ This is a postprocessor file for the Path workbench. It is used to @@ -344,7 +345,7 @@ def parse(pathobj): # if OUTPUT_COMMENTS: # out += linenumber() + "(" + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outstring = [] command = c.Name diff --git a/src/Mod/Path/Path/Post/scripts/centroid_post.py b/src/Mod/Path/Path/Post/scripts/centroid_post.py index 8c26792192..40116f3dd2 100644 --- a/src/Mod/Path/Path/Post/scripts/centroid_post.py +++ b/src/Mod/Path/Path/Post/scripts/centroid_post.py @@ -27,6 +27,7 @@ import os import FreeCAD from FreeCAD import Units import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils import datetime import Path @@ -276,7 +277,7 @@ def parse(pathobj): # if OUTPUT_COMMENTS: # out += linenumber() + "(" + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: commandlist = [] # list of elements in the command, code and params. command = c.Name # command M or G code or comment string diff --git a/src/Mod/Path/Path/Post/scripts/comparams_post.py b/src/Mod/Path/Path/Post/scripts/comparams_post.py index d4b1af4018..1b4dda0412 100644 --- a/src/Mod/Path/Path/Post/scripts/comparams_post.py +++ b/src/Mod/Path/Path/Post/scripts/comparams_post.py @@ -23,6 +23,7 @@ import FreeCAD import Path import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils TOOLTIP = """Example Post, using Path.Commands instead of Path.toGCode strings for Path gcode output.""" @@ -95,7 +96,7 @@ def export(obj, filename, argstring): gcode += firstcommand.Name if hasattr(fp, "Path"): - for c in fp.Path.Commands: + for c in PathUtils.getPathWithPlacement(fp).Commands: gcode += lineout(c, oldvals, modal) + "\n" oldvals = saveVals(c) gcode += "M2\n" diff --git a/src/Mod/Path/Path/Post/scripts/dumper_post.py b/src/Mod/Path/Path/Post/scripts/dumper_post.py index e9865aa9a1..e1d8919695 100644 --- a/src/Mod/Path/Path/Post/scripts/dumper_post.py +++ b/src/Mod/Path/Path/Post/scripts/dumper_post.py @@ -30,6 +30,7 @@ shows the dialog so you can see it. Useful for debugging, but not much else. """ import datetime import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils now = datetime.datetime.now() SHOW_EDITOR = True @@ -94,7 +95,7 @@ def parse(pathobj): out += "(Path: " + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: out += str(c) + "\n" return out diff --git a/src/Mod/Path/Path/Post/scripts/dxf_post.py b/src/Mod/Path/Path/Post/scripts/dxf_post.py index 6f228c55b7..487431a335 100644 --- a/src/Mod/Path/Path/Post/scripts/dxf_post.py +++ b/src/Mod/Path/Path/Post/scripts/dxf_post.py @@ -24,6 +24,7 @@ import FreeCAD import Part import Path +import PathScripts.PathUtils as PathUtils import datetime import importDXF @@ -100,7 +101,7 @@ def parse(pathobj): # Gotta start somewhere. Assume 0,0,0 curPoint = FreeCAD.Vector(0, 0, 0) - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: Path.Log.debug("{} -> {}".format(curPoint, c)) if "Z" in c.Parameters: newparams = c.Parameters diff --git a/src/Mod/Path/Path/Post/scripts/dynapath_4060_post.py b/src/Mod/Path/Path/Post/scripts/dynapath_4060_post.py index 3595a5453b..f270d4cb8e 100644 --- a/src/Mod/Path/Path/Post/scripts/dynapath_4060_post.py +++ b/src/Mod/Path/Path/Post/scripts/dynapath_4060_post.py @@ -32,6 +32,7 @@ import argparse import datetime import shlex import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils TOOLTIP = """ This is a post processor file for the FreeCAD Path workbench. It is used to @@ -420,7 +421,7 @@ def parse(pathobj): if not hasattr(pathobj, "Path"): return out - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outstring = [] command = c.Name # Convert G54-G59 Fixture offsets to E01-E06 for Dynapath Delta Control diff --git a/src/Mod/Path/Path/Post/scripts/dynapath_post.py b/src/Mod/Path/Path/Post/scripts/dynapath_post.py index 06ef144d4d..3037e6be1d 100644 --- a/src/Mod/Path/Path/Post/scripts/dynapath_post.py +++ b/src/Mod/Path/Path/Post/scripts/dynapath_post.py @@ -34,6 +34,7 @@ import FreeCAD from FreeCAD import Units import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils import argparse import datetime import shlex @@ -325,7 +326,7 @@ def parse(pathobj): if OUTPUT_COMMENTS: out += linenumber() + "(Path: " + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outstring = [] command = c.Name outstring.append(command) diff --git a/src/Mod/Path/Path/Post/scripts/fablin_post.py b/src/Mod/Path/Path/Post/scripts/fablin_post.py index 0c106f17f1..d2e08fabb6 100644 --- a/src/Mod/Path/Path/Post/scripts/fablin_post.py +++ b/src/Mod/Path/Path/Post/scripts/fablin_post.py @@ -26,6 +26,7 @@ import datetime import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils now = datetime.datetime.now() @@ -253,7 +254,7 @@ def parse(pathobj): if OUTPUT_COMMENTS: out += linenumber() + "(Path: " + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outstring = [] command = c.Name diff --git a/src/Mod/Path/Path/Post/scripts/fanuc_post.py b/src/Mod/Path/Path/Post/scripts/fanuc_post.py index 2199a83888..6e68e2426a 100644 --- a/src/Mod/Path/Path/Post/scripts/fanuc_post.py +++ b/src/Mod/Path/Path/Post/scripts/fanuc_post.py @@ -30,6 +30,7 @@ import datetime import shlex import os.path import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils TOOLTIP = """ This is a postprocessor file for the Path workbench. It is used to @@ -410,14 +411,15 @@ def parse(pathobj): "Tool Controller Vertical Rapid Values are unset" + "\n" ) - for index, c in enumerate(pathobj.Path.Commands): + commands = PathUtils.getPathWithPlacement(pathobj).Commands + for index, c in enumerate(commands): outstring = [] command = c.Name - if index + 1 == len(pathobj.Path.Commands): + if index + 1 == len(commands): nextcommand = "" else: - nextcommand = pathobj.Path.Commands[index + 1].Name + nextcommand = commands[index + 1].Name if adaptiveOp and c.Name in ["G0", "G00"]: if opHorizRapid and opVertRapid: diff --git a/src/Mod/Path/Path/Post/scripts/grbl_post.py b/src/Mod/Path/Path/Post/scripts/grbl_post.py index 90e9087971..0fd23e2003 100755 --- a/src/Mod/Path/Path/Post/scripts/grbl_post.py +++ b/src/Mod/Path/Path/Post/scripts/grbl_post.py @@ -29,6 +29,7 @@ from FreeCAD import Units import Path import Path.Base.Util as PathUtil import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils import argparse import datetime import shlex @@ -481,7 +482,7 @@ def parse(pathobj): if OUTPUT_COMMENTS: out += linenumber() + "(Path: " + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outstring = [] command = c.Name diff --git a/src/Mod/Path/Path/Post/scripts/heidenhain_post.py b/src/Mod/Path/Path/Post/scripts/heidenhain_post.py index 418db4ea64..66e3f55ffb 100644 --- a/src/Mod/Path/Path/Post/scripts/heidenhain_post.py +++ b/src/Mod/Path/Path/Post/scripts/heidenhain_post.py @@ -22,6 +22,7 @@ import argparse import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils import Path import PathScripts import shlex @@ -361,12 +362,14 @@ def export(objectslist, filename, argstring): elif isinstance(obj.Proxy, Path.Op.Helix.ObjectHelix): Object_Kind = "HELIX" + commands = PathUtils.getPathWithPlacement(obj).Commands + # If used compensated path, store, recompute and diff when asked if hasattr(obj, "UseComp") and SOLVE_COMPENSATION_ACTIVE: if obj.UseComp: if hasattr(obj.Path, "Commands") and Object_Kind == "PROFILE": # Take a copy of compensated path - STORED_COMPENSATED_OBJ = obj.Path.Commands + STORED_COMPENSATED_OBJ = commands # Find mill compensation if hasattr(obj, "Side") and hasattr(obj, "Direction"): if obj.Side == "Outside" and obj.Direction == "CW": @@ -380,14 +383,16 @@ def export(objectslist, filename, argstring): # set obj.UseComp to false and recompute() to get uncompensated path obj.UseComp = False obj.recompute() + commands = PathUtils.getPathWithPlacement(obj).Commands # small edges could be skipped and movements joints can add edges NameStr = "" if hasattr(obj, "Label"): NameStr = str(obj.Label) - if len(obj.Path.Commands) != len(STORED_COMPENSATED_OBJ): + if len(commands) != len(STORED_COMPENSATED_OBJ): # not same number of edges obj.UseComp = True obj.recompute() + commands = PathUtils.getPathWithPlacement(obj).Commands POSTGCODE.append("; MISSING EDGES UNABLE TO GET COMPENSATION") if not SKIP_WARNS: ( @@ -422,7 +427,7 @@ def export(objectslist, filename, argstring): POSTGCODE.append("; COMPENSATION ACTIVE") COMPENSATION_DIFF_STATUS[0] = True - for c in obj.Path.Commands: + for c in commands: Cmd_Count += 1 command = c.Name if command != "G0": @@ -458,7 +463,7 @@ def export(objectslist, filename, argstring): Spindle_Status += str(MACHINE_SPINDLE_DIRECTION) # Activate spindle Spindle_Active = True else: # At last rapid movement we turn off spindle - if Cmd_Count == len(obj.Path.Commands): + if Cmd_Count == len(commands): Spindle_Status += "5" # Deactivate spindle Spindle_Active = False else: diff --git a/src/Mod/Path/Path/Post/scripts/jtech_post.py b/src/Mod/Path/Path/Post/scripts/jtech_post.py index 4c95e8f50b..238bdb70e9 100644 --- a/src/Mod/Path/Path/Post/scripts/jtech_post.py +++ b/src/Mod/Path/Path/Post/scripts/jtech_post.py @@ -28,6 +28,7 @@ import argparse import datetime import shlex import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils TOOLTIP = """ This is a postprocessor file for the Path workbench. It is used to @@ -307,7 +308,7 @@ def parse(pathobj): if not hasattr(pathobj, "Path"): return out - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outstring = [] command = c.Name diff --git a/src/Mod/Path/Path/Post/scripts/linuxcnc_post.py b/src/Mod/Path/Path/Post/scripts/linuxcnc_post.py index 534a09b830..cd9865cbbc 100644 --- a/src/Mod/Path/Path/Post/scripts/linuxcnc_post.py +++ b/src/Mod/Path/Path/Post/scripts/linuxcnc_post.py @@ -28,6 +28,7 @@ import argparse import datetime import shlex import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils TOOLTIP = """ This is a postprocessor file for the Path workbench. It is used to @@ -355,7 +356,7 @@ def parse(pathobj): # if OUTPUT_COMMENTS: # out += linenumber() + "(" + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outstring = [] command = c.Name diff --git a/src/Mod/Path/Path/Post/scripts/mach3_mach4_post.py b/src/Mod/Path/Path/Post/scripts/mach3_mach4_post.py index cf0b32fa38..275ea3feb3 100644 --- a/src/Mod/Path/Path/Post/scripts/mach3_mach4_post.py +++ b/src/Mod/Path/Path/Post/scripts/mach3_mach4_post.py @@ -28,6 +28,7 @@ import argparse import datetime import shlex import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils TOOLTIP = """ This is a postprocessor file for the Path workbench. It is used to @@ -387,7 +388,7 @@ def parse(pathobj): "Tool Controller Vertical Rapid Values are unset" + "\n" ) - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outstring = [] command = c.Name diff --git a/src/Mod/Path/Path/Post/scripts/marlin_post.py b/src/Mod/Path/Path/Post/scripts/marlin_post.py index a948ac9df5..abebe51ae5 100644 --- a/src/Mod/Path/Path/Post/scripts/marlin_post.py +++ b/src/Mod/Path/Path/Post/scripts/marlin_post.py @@ -35,6 +35,7 @@ from FreeCAD import Units import Path import Path.Base.Util as PathUtil import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils Revised = "2020-11-03" # Revision date for this file. @@ -542,7 +543,7 @@ def parse(pathobj): if OUTPUT_COMMENTS and OUTPUT_PATH: out += linenumber() + "(Path: " + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outlist = [] command = c.Name outlist.append(command) diff --git a/src/Mod/Path/Path/Post/scripts/nccad_post.py b/src/Mod/Path/Path/Post/scripts/nccad_post.py index 7661c888e1..2b3791f88a 100644 --- a/src/Mod/Path/Path/Post/scripts/nccad_post.py +++ b/src/Mod/Path/Path/Post/scripts/nccad_post.py @@ -23,6 +23,7 @@ """Postprocessor to output real GCode for Max Computer GmbH nccad9.""" import FreeCAD import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils import datetime @@ -89,7 +90,7 @@ def export(objectslist, filename, argstring): gcode = HEADER for obj in objectslist: - for command in obj.Path.Commands: + for command in PathUtils.getPathWithPlacement(obj).Commands: # Manipulate tool change commands if "M6" == command.Name: gcode += TOOL_CHANGE.replace("TOOL", str(int(command.Parameters["T"]))) diff --git a/src/Mod/Path/Path/Post/scripts/opensbp_post.py b/src/Mod/Path/Path/Post/scripts/opensbp_post.py index caf2477dc2..8826a5a0e5 100644 --- a/src/Mod/Path/Path/Post/scripts/opensbp_post.py +++ b/src/Mod/Path/Path/Post/scripts/opensbp_post.py @@ -23,6 +23,7 @@ import datetime import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils TOOLTIP = """ @@ -351,7 +352,7 @@ def parse(pathobj): return output if OUTPUT_COMMENTS: output += linenumber() + "'(Path: " + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: command = c.Name if command in scommands: output += scommands[command](c) diff --git a/src/Mod/Path/Path/Post/scripts/philips_post.py b/src/Mod/Path/Path/Post/scripts/philips_post.py index d6e57cee6d..d52cb6eb59 100644 --- a/src/Mod/Path/Path/Post/scripts/philips_post.py +++ b/src/Mod/Path/Path/Post/scripts/philips_post.py @@ -28,6 +28,7 @@ import FreeCAD import argparse import time import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils import math TOOLTIP = """Post processor for Maho M 600E mill @@ -416,7 +417,7 @@ def export(objectslist, filename, argstring): for obj in objectslist: if hasattr(obj, "Comment"): gcode += linenumberify("(" + obj.Comment + ")") - for c in obj.Path.Commands: + for c in PathUtils.getPathWithPlacement(obj).Commands: outstring = [] command = c.Name if command != "G0": diff --git a/src/Mod/Path/Path/Post/scripts/refactored_centroid_post.py b/src/Mod/Path/Path/Post/scripts/refactored_centroid_post.py index ff4cf854d5..23c20c7c0f 100644 --- a/src/Mod/Path/Path/Post/scripts/refactored_centroid_post.py +++ b/src/Mod/Path/Path/Post/scripts/refactored_centroid_post.py @@ -28,6 +28,7 @@ import Path.Post.UtilsArguments as PostUtilsArguments import Path.Post.UtilsExport as PostUtilsExport + # # The following variables need to be global variables # to keep the PathPostProcessor.load method happy: diff --git a/src/Mod/Path/Path/Post/scripts/rrf_post.py b/src/Mod/Path/Path/Post/scripts/rrf_post.py index 4d09d7b9ba..5dd9c9f158 100644 --- a/src/Mod/Path/Path/Post/scripts/rrf_post.py +++ b/src/Mod/Path/Path/Post/scripts/rrf_post.py @@ -34,6 +34,7 @@ from FreeCAD import Units import Path import Path.Base.Util as PathUtil import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils Revised = "2021-10-21" # Revision date for this file. @@ -533,7 +534,7 @@ def parse(pathobj): if OUTPUT_COMMENTS and OUTPUT_PATH: out += linenumber() + "(Path: " + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outlist = [] command = c.Name outlist.append(command) diff --git a/src/Mod/Path/Path/Post/scripts/smoothie_post.py b/src/Mod/Path/Path/Post/scripts/smoothie_post.py index 00fd98cffa..b26f679f98 100644 --- a/src/Mod/Path/Path/Post/scripts/smoothie_post.py +++ b/src/Mod/Path/Path/Post/scripts/smoothie_post.py @@ -25,6 +25,7 @@ import argparse import datetime import Path.Post.Utils as PostUtils +import PathScripts.PathUtils as PathUtils import FreeCAD from FreeCAD import Units import shlex @@ -398,7 +399,7 @@ def parse(pathobj): # if OUTPUT_COMMENTS: # out += linenumber() + "(" + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: outstring = [] command = c.Name outstring.append(command) diff --git a/src/Mod/Path/Path/Post/scripts/uccnc_post.py b/src/Mod/Path/Path/Post/scripts/uccnc_post.py index 3cc2d93484..a8725aabb5 100644 --- a/src/Mod/Path/Path/Post/scripts/uccnc_post.py +++ b/src/Mod/Path/Path/Post/scripts/uccnc_post.py @@ -33,6 +33,7 @@ import FreeCAD from FreeCAD import Units import Path +import PathScripts.PathUtils as PathUtils import argparse import datetime @@ -602,7 +603,7 @@ def parse(pathobj): # if OUTPUT_COMMENTS: # out += linenumber() + "(" + pathobj.Label + ")\n" - for c in pathobj.Path.Commands: + for c in PathUtils.getPathWithPlacement(pathobj).Commands: commandlist = [] # list of elements in the command, code and params. command = c.Name.strip() # command M or G code or comment string commandlist.append(command) diff --git a/src/Mod/Path/PathScripts/PathUtils.py b/src/Mod/Path/PathScripts/PathUtils.py index fb16c65ae6..3a172fc8e7 100644 --- a/src/Mod/Path/PathScripts/PathUtils.py +++ b/src/Mod/Path/PathScripts/PathUtils.py @@ -838,3 +838,69 @@ def RtoIJ(startpoint, command): newcommand.Parameters = params return newcommand + +def getPathWithPlacement(pathobj): + """ + Applies the rotation, and then postition of the obj's Placement + to the obj's path + """ + + if not hasattr(pathobj, "Placement") or pathobj.Path is None: + return pathobj.Path + + return applyPlacementToPath(pathobj.Placement, pathobj.Path) + +def applyPlacementToPath(placement, path): + """ + Applies the rotation, and then postition of the placement to path + """ + + CmdMoveRapid = ["G0", "G00"] + CmdMoveStraight = ["G1", "G01"] + CmdMoveCW = ["G2", "G02"] + CmdMoveCCW = ["G3", "G03"] + CmdDrill = ["G73", "G81", "G82", "G83"] + CmdMoveArc = CmdMoveCW + CmdMoveCCW + CmdMove = CmdMoveStraight + CmdMoveArc + + commands = [] + currX = 0 + currY = 0 + currZ = 0 + for cmd in path.Commands: + if ( + (cmd.Name in CmdMoveRapid) + or (cmd.Name in CmdMove) + or (cmd.Name in CmdDrill) + ): + params = cmd.Parameters + currX = x = params.get("X", currX) + currY = y = params.get("Y", currY) + currZ = z = params.get("Z", currZ) + + x, y, z = placement.Rotation.multVec(FreeCAD.Vector(x, y ,z)) + + if x != currX: + params.update({"X": x}) + if y != currY: + params.update({"Y": y}) + if z != currZ: + params.update({"Z": z}) + + # Arcs need to have the I and J params rotated as well + if cmd.Name in CmdMoveArc: + currI = i = params.get("I", 0) + currJ = j = params.get("J", 0) + + i, j, k = placement.Rotation.multVec(FreeCAD.Vector(i, j, 0)) + + if currI != i: + params.update({"I": i}) + if currJ != j: + params.update({"J": j}) + + cmd.Parameters = params + commands.append(cmd.transform(placement)) + newPath = Path.Path(commands) + + return newPath