From d1b927767a5193a72765ab7c280cf5dcb5947560 Mon Sep 17 00:00:00 2001 From: sliptonic Date: Sun, 3 Jul 2016 10:27:12 -0500 Subject: [PATCH] Fix for bug #2528 Improved handling of comments --- src/Mod/Path/PathScripts/PathLoadTool.py | 8 +-- src/Mod/Path/PathScripts/PathMachine.py | 3 +- src/Mod/Path/PathScripts/PathPocket.py | 2 + src/Mod/Path/PathScripts/PathProfile.py | 6 ++ src/Mod/Path/PathScripts/PathSurface.py | 33 ++++------ src/Mod/Path/PathScripts/dumper_post.py | 74 +++++++++++------------ src/Mod/Path/PathScripts/example_post.py | 63 ++++++++++--------- src/Mod/Path/PathScripts/linuxcnc_post.py | 21 ++++--- 8 files changed, 104 insertions(+), 106 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathLoadTool.py b/src/Mod/Path/PathScripts/PathLoadTool.py index 7f31ddf36..b9f190d9c 100644 --- a/src/Mod/Path/PathScripts/PathLoadTool.py +++ b/src/Mod/Path/PathScripts/PathLoadTool.py @@ -62,13 +62,14 @@ class LoadTool: tool = PathUtils.getTool(obj, obj.ToolNumber) if tool is not None: - obj.Label = obj.Name + ": (" + tool.Name + ")" + obj.Label = obj.Name + ": " + tool.Name else: - obj.Label = obj.Name + ": (UNDEFINED TOOL)" + obj.Label = obj.Name + ": UNDEFINED TOOL" commands = "" - commands = 'M6T'+str(obj.ToolNumber)+'\n' + commands += "(" + obj.Label + ")"+'\n' + commands += 'M6T'+str(obj.ToolNumber)+'\n' if obj.SpindleDir == 'Forward': commands += 'M3S' + str(obj.SpindleSpeed) + '\n' @@ -77,7 +78,6 @@ class LoadTool: commands += 'M4S' + str(obj.SpindleSpeed) + '\n' obj.Path = Path.Path(commands) - # obj.Label = "TC: Tool"+str(obj.ToolNumber) def onChanged(self, obj, prop): mode = 2 diff --git a/src/Mod/Path/PathScripts/PathMachine.py b/src/Mod/Path/PathScripts/PathMachine.py index ff56c5874..b056e5288 100644 --- a/src/Mod/Path/PathScripts/PathMachine.py +++ b/src/Mod/Path/PathScripts/PathMachine.py @@ -75,7 +75,8 @@ class Machine: # need to filter this path out in post- only for visualization #gcode = 'G0 X' + str(obj.X.Value) + ' Y' + \ # str(obj.Y.Value) + ' Z' + str(obj.Z.Value) - gcode = '(' + str(obj.Label) + ')' + gcode = "" + gcode += '(' + str(obj.Label) + ')' obj.Path = Path.Path(gcode) def onChanged(self, obj, prop): diff --git a/src/Mod/Path/PathScripts/PathPocket.py b/src/Mod/Path/PathScripts/PathPocket.py index 13e029721..15cff974d 100644 --- a/src/Mod/Path/PathScripts/PathPocket.py +++ b/src/Mod/Path/PathScripts/PathPocket.py @@ -377,6 +377,8 @@ class ObjectPocket: obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name + output += "(" + obj.Label + ")" + if obj.UserLabel == "": obj.Label = obj.Name + " :" + obj.ToolDescription else: diff --git a/src/Mod/Path/PathScripts/PathProfile.py b/src/Mod/Path/PathScripts/PathProfile.py index 717b6a4ed..a8292b74a 100644 --- a/src/Mod/Path/PathScripts/PathProfile.py +++ b/src/Mod/Path/PathScripts/PathProfile.py @@ -263,6 +263,7 @@ print "y - " + str(point.y) def execute(self, obj): import Part # math #DraftGeomUtils output = "" + toolLoad = PathUtils.getLastToolLoad(obj) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 @@ -286,6 +287,11 @@ print "y - " + str(point.y) else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription + output += "(" + obj.Label + ")" + if obj.Side != "On": + output += "(Compensated Tool Path: " + str(self.radius) + ")" + else: + output += "(Uncompensated Tool Path)" if obj.Base: hfaces = [] diff --git a/src/Mod/Path/PathScripts/PathSurface.py b/src/Mod/Path/PathScripts/PathSurface.py index e2fdc1538..06e12ce67 100644 --- a/src/Mod/Path/PathScripts/PathSurface.py +++ b/src/Mod/Path/PathScripts/PathSurface.py @@ -138,16 +138,16 @@ class ObjectSurface: loopstring += "G0 Z" + str(obj.SafeHeight.Value) + "\n" loopstring += "G0 X" + \ str(fmt(p.x)) + " Y" + str(fmt(p.y)) + "\n" - loopstring += "G1 Z" + str(fmt(p.z)) + " F" + str(self.vertFeed) + "\n" + loopstring += "G1 Z" + str(fmt(p.z)) + "\n" for p in loop[1:]: loopstring += "G1 X" + \ str(fmt(p.x)) + " Y" + str(fmt(p.y)) + \ - " Z" + str(fmt(p.z)) + " F" + str(self.horizFeed)+ "\n" + " Z" + str(fmt(p.z)) + "\n" zheight = p.z p = loop[0] loopstring += "G1 X" + \ str(fmt(p.x)) + " Y" + str(fmt(p.y)) + \ - " Z" + str(fmt(zheight)) + " F" + str(self.vertFeed) + "\n" + " Z" + str(fmt(zheight)) + "\n" loopstring += "(loop end)" + "\n" print " loop ", nloop, " with ", len(loop), " points" nloop = nloop + 1 @@ -157,6 +157,8 @@ class ObjectSurface: depthparams = depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value) + # stlfile = "../../stl/gnu_tux_mod.stl" + # surface = STLSurfaceSource(stlfile) surface = s t_before = time.time() @@ -165,20 +167,12 @@ class ObjectSurface: # wl = ocl.AdaptiveWaterline() # this is slower, ca 60 seconds on i7 # CPU wl.setSTL(surface) - diam = self.radius * 2 - - # FIXME: Need to get tool length from tool object + diam = 0.5 length = 10.0 - - # FIXME: Need to get correct tool shape. Hard coding to ball cutter - # is bad. - # any ocl MillingCutter class should work here cutter = ocl.BallCutter(diam, length) - wl.setCutter(cutter) # this should be smaller than the smallest details in the STL file - wl.setSampling(obj.SampleInterval) # AdaptiveWaterline() also has settings for minimum sampling interval # (see c++ code) @@ -208,8 +202,6 @@ class ObjectSurface: pdc = ocl.PathDropCutter() # create a pdc pdc.setSTL(s) pdc.setCutter(cutter) - - # FIXME: need to set minimumZ to something real pdc.minimumZ = 0.25 pdc.setSampling(obj.SampleInterval) @@ -257,7 +249,7 @@ class ObjectSurface: for c in clp: output += "G1 X" + str(c.x) + " Y" + \ - str(c.y) + " Z" + str(c.z) + " F" + str(self.horizFeed) + "\n" + str(c.y) + " Z" + str(c.z) + "\n" return output @@ -289,6 +281,9 @@ class ObjectSurface: else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription + output += "(" + obj.Label + ")" + output += "(Compensated Tool Path: " + str(self.radius) + ")" + if obj.Base: for b in obj.Base: @@ -377,13 +372,7 @@ class CommandPathSurfacing: 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Surface", "Creates a Path Surfacing object")} def IsActive(self): - if FreeCAD.ActiveDocument is None: - active = False - elif PathUtils.findProj() is None: - active = False - else: - active = True - return active + return FreeCAD.ActiveDocument is not None def Activated(self): diff --git a/src/Mod/Path/PathScripts/dumper_post.py b/src/Mod/Path/PathScripts/dumper_post.py index 358daa937..c2dfea583 100644 --- a/src/Mod/Path/PathScripts/dumper_post.py +++ b/src/Mod/Path/PathScripts/dumper_post.py @@ -1,37 +1,37 @@ -#*************************************************************************** -#* (c) sliptonic (shopinthewoods@gmail.com) 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 * -#* * -#***************************************************************************/ +# *************************************************************************** +# * (c) sliptonic (shopinthewoods@gmail.com) 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 * +# * * +# ***************************************************************************/ ''' -Dumper is an extremely simple postprocessor file for the Path workbench. It is used +Dumper is an extremely simple postprocessor file for the Path workbench. It is used to dump the command list from one or more Path objects for simple inspection. This post -doesn't do any manipulation of the path and doesn't write anything to disk. It just -shows the dialog so you can see it. Useful for debugging, but not much else. +doesn't do any manipulation of the path and doesn't write anything to disk. It just +shows the dialog so you can see it. Useful for debugging, but not much else. ''' - import datetime -now = datetime.datetime.now() from PathScripts import PostUtils + +now = datetime.datetime.now() SHOW_EDITOR = True # to distinguish python built-in open function from the one declared below @@ -39,7 +39,7 @@ if open.__module__ == '__builtin__': pythonopen = open -def export(objectslist,filename): +def export(objectslist, filename): output = '''(This ouput produced with the dump post processor) (Dump is useful for inspecting the raw commands in your paths) (but is not useful for driving machines.) @@ -50,8 +50,8 @@ def export(objectslist,filename): "called when freecad exports a list of objects" for obj in objectslist: - - if not hasattr(obj,"Path"): + + if not hasattr(obj, "Path"): print "the object " + obj.Name + " is not a path. Please select only path and Compounds." return print "postprocessing..." @@ -70,17 +70,18 @@ def export(objectslist,filename): print "done postprocessing." + def parse(pathobj): out = "" - - if hasattr(pathobj,"Group"): #We have a compound or project. - out += "(compound: " + pathobj.Label + ")\n" + + if hasattr(pathobj, "Group"): # We have a compound or project. + out += "(Group: " + pathobj.Label + ")\n" for p in pathobj.Group: out += parse(p) - return out - else: #parsing simple path + return out + else: # parsing simple path - if not hasattr(pathobj,"Path"): #groups might contain non-path things like stock. + if not hasattr(pathobj, "Path"): # groups might contain non-path things like stock. return out out += "(Path: " + pathobj.Label + ")\n" @@ -90,4 +91,3 @@ def parse(pathobj): return out print __name__ + " gcode postprocessor loaded." - diff --git a/src/Mod/Path/PathScripts/example_post.py b/src/Mod/Path/PathScripts/example_post.py index 8dc85075f..cd482c145 100644 --- a/src/Mod/Path/PathScripts/example_post.py +++ b/src/Mod/Path/PathScripts/example_post.py @@ -1,25 +1,25 @@ -#*************************************************************************** -#* (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 * -#* * -#***************************************************************************/ +# *************************************************************************** +# * (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 * +# * * +# ***************************************************************************/ ''' @@ -39,17 +39,17 @@ if open.__module__ == '__builtin__': pythonopen = open -def export(objectslist,filename): +def export(objectslist, filename): "called when freecad exports a list of objects" if len(objectslist) > 1: print "This script is unable to write more than one Path object" return obj = objectslist[0] - if not hasattr(obj,"Path"): + if not hasattr(obj, "Path"): print "the given object is not a path" gcode = obj.Path.toGCode() gcode = parse(gcode) - gfile = pythonopen(filename,"wb") + gfile = pythonopen(filename, "wb") gfile.write(gcode) gfile.close() @@ -57,14 +57,14 @@ def export(objectslist,filename): def parse(inputstring): "parse(inputstring): returns a parsed output string" print "postprocessing..." - + output = "" - + # write some stuff first output += "N10 ;time:"+str(now)+"\n" output += "N20 G17 G20 G80 G40 G90\n" output += "N30 (Exported by FreeCAD)\n" - + linenr = 100 lastcommand = None # treat the input line by line @@ -72,7 +72,7 @@ def parse(inputstring): for line in lines: # split the G/M command from the arguments if " " in line: - command,args = line.split(" ",1) + command, args = line.split(" ", 1) else: # no space found, which means there are no arguments command = line @@ -87,16 +87,15 @@ def parse(inputstring): linenr += 10 # store the latest command lastcommand = command - + # write some more stuff at the end output += "N" + str(linenr) + " M05\n" output += "N" + str(linenr + 10) + " M25\n" output += "N" + str(linenr + 20) + " G00 X-1.0 Y1.0\n" output += "N" + str(linenr + 30) + " G17 G80 G40 G90\n" output += "N" + str(linenr + 40) + " M99\n" - + print "done postprocessing." return output print __name__ + " gcode postprocessor loaded." - diff --git a/src/Mod/Path/PathScripts/linuxcnc_post.py b/src/Mod/Path/PathScripts/linuxcnc_post.py index edc7189ad..10a5d71aa 100644 --- a/src/Mod/Path/PathScripts/linuxcnc_post.py +++ b/src/Mod/Path/PathScripts/linuxcnc_post.py @@ -1,5 +1,5 @@ # *************************************************************************** -# * (c) sliptonic (shopinthewoods@gmail.com) 2014 * +# * (c) sliptonic (shopinthewoods@gmail.com) 2014 * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -25,7 +25,7 @@ ''' This is a postprocessor file for the Path workbench. It is used to take a pseudo-gcode fragment outputted by a Path object, and output -real GCode suitable for a linuxcnc 3 axis mill. This postprocessor, once placed +real GCode suitable for a linuxcnc 3 axis mill. This postprocessor, once placed in the appropriate PathScripts folder, can be used directly from inside FreeCAD, via the GUI importer or via python scripts with: @@ -35,6 +35,7 @@ linuxcnc_post.export(object,"/path/to/file.ncc") import datetime from PathScripts import PostUtils + now = datetime.datetime.now() # These globals set common customization preferences @@ -48,7 +49,7 @@ LINENR = 100 # line number starting value # These globals will be reflected in the Machine configuration of the project UNITS = "G21" # G21 for metric, G20 for us standard -MACHINE_NAME = "LinuxCNC" +MACHINE_NAME = "Millstone" CORNER_MIN = {'x': 0, 'y': 0, 'z': 0} CORNER_MAX = {'x': 500, 'y': 300, 'z': 300} @@ -156,7 +157,7 @@ def export(objectslist, filename): print "done postprocessing." gfile = pythonopen(filename, "wb") - gfile.write(final) + gfile.write(gcode) gfile.close() @@ -178,8 +179,8 @@ def parse(pathobj): params = ['X', 'Y', 'Z', 'A', 'B', 'I', 'J', 'F', 'S', 'T', 'Q', 'R', 'L'] if hasattr(pathobj, "Group"): # We have a compound or project. - if OUTPUT_COMMENTS: - out += linenumber() + "(compound: " + pathobj.Label + ")\n" + # if OUTPUT_COMMENTS: + # out += linenumber() + "(compound: " + pathobj.Label + ")\n" for p in pathobj.Group: out += parse(p) return out @@ -189,8 +190,8 @@ def parse(pathobj): if not hasattr(pathobj, "Path"): return out - if OUTPUT_COMMENTS: - out += linenumber() + "(Path: " + pathobj.Label + ")\n" + # if OUTPUT_COMMENTS: + # out += linenumber() + "(" + pathobj.Label + ")\n" for c in pathobj.Path.Commands: outstring = [] @@ -219,8 +220,8 @@ def parse(pathobj): # Check for Tool Change: if command == 'M6': - if OUTPUT_COMMENTS: - out += linenumber() + "(begin toolchange)\n" + # if OUTPUT_COMMENTS: + # out += linenumber() + "(begin toolchange)\n" for line in TOOL_CHANGE.splitlines(True): out += linenumber() + line