diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt index b30ca0e472..098bb114dd 100644 --- a/src/Mod/Path/CMakeLists.txt +++ b/src/Mod/Path/CMakeLists.txt @@ -128,6 +128,7 @@ SET(PathScripts_post_SRCS PathScripts/post/comparams_post.py PathScripts/post/dynapath_post.py PathScripts/post/example_pre.py + PathScripts/post/gcode_pre.py PathScripts/post/grbl_post.py PathScripts/post/jtech_post.py PathScripts/post/linuxcnc_post.py diff --git a/src/Mod/Path/PathScripts/PathCustom.py b/src/Mod/Path/PathScripts/PathCustom.py index 74cb93ba1a..a06b8b51ef 100644 --- a/src/Mod/Path/PathScripts/PathCustom.py +++ b/src/Mod/Path/PathScripts/PathCustom.py @@ -25,9 +25,12 @@ import FreeCAD import FreeCADGui import Path from PySide import QtCore +from copy import copy + __doc__ = """Path Custom object and FreeCAD command""" +movecommands = ['G0', 'G00', 'G1', 'G01', 'G2', 'G02', 'G3', 'G03'] # Qt translation handling def translate(context, text, disambig=None): @@ -35,10 +38,14 @@ def translate(context, text, disambig=None): class ObjectCustom: + def __init__(self, obj): + obj.addProperty("App::PropertyStringList", "Gcode", "Path", + QtCore.QT_TRANSLATE_NOOP("PathCustom", "The gcode to be inserted")) + obj.addProperty("App::PropertyLink", "ToolController", "Path", + QtCore.QT_TRANSLATE_NOOP("PathCustom", "The tool controller that will be used to calculate the path")) + obj.addProperty("App::PropertyPlacement", "Offset", "Path", + "Placement Offset") - def __init__(self,obj): - obj.addProperty("App::PropertyStringList", "Gcode", "Path", QtCore.QT_TRANSLATE_NOOP("PathCustom", "The gcode to be inserted")) - obj.addProperty("App::PropertyLink", "ToolController", "Path", QtCore.QT_TRANSLATE_NOOP("PathCustom", "The tool controller that will be used to calculate the path")) obj.Proxy = self def __getstate__(self): @@ -48,13 +55,22 @@ class ObjectCustom: return None def execute(self, obj): + newpath = Path.Path() if obj.Gcode: - s = "" for l in obj.Gcode: - s += str(l) - if s: - path = Path.Path(s) - obj.Path = path + newcommand = Path.Command(str(l)) + if newcommand.Name in movecommands: + if 'X' in newcommand.Parameters: + newcommand.x += obj.Offset.Base.x + if 'Y' in newcommand.Parameters: + newcommand.y += obj.Offset.Base.y + if 'Z' in newcommand.Parameters: + newcommand.z += obj.Offset.Base.z + + newpath.insertCommand(newcommand) + + obj.Path=newpath + class CommandPathCustom: @@ -75,7 +91,7 @@ class CommandPathCustom: FreeCAD.ActiveDocument.openTransaction("Create Custom Path") FreeCADGui.addModule("PathScripts.PathCustom") FreeCADGui.addModule("PathScripts.PathUtils") - FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Custom")') + FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "Custom")') FreeCADGui.doCommand('PathScripts.PathCustom.ObjectCustom(obj)') FreeCADGui.doCommand('obj.ViewObject.Proxy = 0') FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)') @@ -86,4 +102,4 @@ class CommandPathCustom: if FreeCAD.GuiUp: # register the FreeCAD command - FreeCADGui.addCommand('Path_Custom', CommandPathCustom()) + FreeCADGui.addCommand('Path_Custom', CommandPathCustom()) \ No newline at end of file diff --git a/src/Mod/Path/PathScripts/post/example_pre.py b/src/Mod/Path/PathScripts/post/example_pre.py index 5928c30301..48ceb433bf 100644 --- a/src/Mod/Path/PathScripts/post/example_pre.py +++ b/src/Mod/Path/PathScripts/post/example_pre.py @@ -73,13 +73,11 @@ def insert(filename, docname): def parse(inputstring): "parse(inputstring): returns a parsed output string" print("preprocessing...") - print(inputstring) PathLog.track(inputstring) # split the input by line lines = inputstring.split("\n") - output = "" - lastcommand = None - print(lines) + output = [] #"" + lastcommand = None for lin in lines: # remove any leftover trailing and preceding spaces @@ -91,7 +89,7 @@ def parse(inputstring): # remove line numbers lin = lin.split(" ", 1) if len(lin) >= 1: - lin = lin[1] + lin = lin[1].strip() else: continue @@ -100,7 +98,8 @@ def parse(inputstring): continue if lin[0].upper() in ["G", "M"]: # found a G or M command: we store it - output += lin + "\n" + #output += lin + "\n" + output.append(Path.Command(str(lin))) # + "\n" last = lin[0].upper() for c in lin[1:]: if not c.isdigit(): @@ -110,7 +109,7 @@ def parse(inputstring): lastcommand = last elif lastcommand: # no G or M command: we repeat the last one - output += lastcommand + " " + lin + "\n" + output.append(Path.Command(str(lastcommand + " " + lin))) # + "\n" print("done preprocessing.") return output diff --git a/src/Mod/Path/PathScripts/post/gcode_pre.py b/src/Mod/Path/PathScripts/post/gcode_pre.py new file mode 100644 index 0000000000..053c39c229 --- /dev/null +++ b/src/Mod/Path/PathScripts/post/gcode_pre.py @@ -0,0 +1,129 @@ +# *************************************************************************** +# * (c) Yorik van Havre (yorik@uncreated.net) 2014 * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Lesser General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# ***************************************************************************/ + + +''' +This is an example preprocessor file for the Path workbench. Its aim is to +open a gcode file, parse its contents, and create the appropriate objects +in FreeCAD. + +Read the Path Workbench documentation to know how to create Path objects +from GCode. +''' + +import os +import Path +import FreeCAD +import PathScripts.PathUtils +import PathScripts.PathLog as PathLog +import re + +# LEVEL = PathLog.Level.DEBUG +LEVEL = PathLog.Level.INFO +PathLog.setLevel(LEVEL, PathLog.thisModule()) + +if LEVEL == PathLog.Level.DEBUG: + PathLog.trackModule(PathLog.thisModule()) + + +# to distinguish python built-in open function from the one declared below +if open.__module__ in ['__builtin__', 'io']: + pythonopen = open + + +def open(filename): + "called when freecad opens a file." + PathLog.track(filename) + docname = os.path.splitext(os.path.basename(filename))[0] + doc = FreeCAD.newDocument(docname) + insert(filename, doc.Name) + + +def insert(filename, docname): + "called when freecad imports a file" + PathLog.track(filename) + gfile = pythonopen(filename) + gcode = gfile.read() + gfile.close() + # split on tool changes + paths = re.split('(?=[mM]+\s?0?6)', gcode) + # if there are any tool changes combine the preamble with the default tool + if len(paths) > 1: + paths = ["\n".join(paths[0:2])] + paths[2:] + for path in paths: + gcode = parse(path) + doc = FreeCAD.getDocument(docname) + obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "Custom") + PathScripts.PathCustom.ObjectCustom(obj) + obj.ViewObject.Proxy = 0 + obj.Gcode = gcode + PathScripts.PathUtils.addToJob(obj) + obj.ToolController = PathScripts.PathUtils.findToolController(obj) + FreeCAD.ActiveDocument.recompute() + + +def parse(inputstring): + "parse(inputstring): returns a parsed output string" + print("preprocessing...") + PathLog.track(inputstring) + # split the input by line + lines = inputstring.split("\n") + output = [] #"" + lastcommand = None + + for lin in lines: + # remove any leftover trailing and preceding spaces + lin = lin.strip() + if not lin: + # discard empty lines + continue + if lin[0].upper() in ["N"]: + # remove line numbers + lin = lin.split(" ", 1) + if len(lin) >= 1: + lin = lin[1].strip() + else: + continue + + if lin[0] in ["(", "%", "#", ";"]: + # discard comment and other non strictly gcode lines + continue + if lin[0].upper() in ["G", "M"]: + # found a G or M command: we store it + #output += lin + "\n" + output.append(lin) # + "\n" + last = lin[0].upper() + for c in lin[1:]: + if not c.isdigit(): + break + else: + last += c + lastcommand = last + elif lastcommand: + # no G or M command: we repeat the last one + output.append(lastcommand + " " + lin) # + "\n" + + print("done preprocessing.") + return output + +print(__name__ + " gcode preprocessor loaded.")