diff --git a/src/Mod/Path/PathScripts/PathContour.py b/src/Mod/Path/PathScripts/PathContour.py index a8386299a..7cdc90cf6 100644 --- a/src/Mod/Path/PathScripts/PathContour.py +++ b/src/Mod/Path/PathScripts/PathContour.py @@ -28,10 +28,11 @@ from FreeCAD import Vector import TechDraw from PathScripts import PathUtils from PathScripts.PathUtils import depth_params +from PySide import QtCore if FreeCAD.GuiUp: import FreeCADGui - from PySide import QtCore, QtGui + from PySide import QtGui # Qt tanslation handling try: _encoding = QtGui.QApplication.UnicodeUTF8 @@ -258,7 +259,8 @@ class ObjectContour: if obj.Active: path = Path.Path(output) obj.Path = path - obj.ViewObject.Visibility = True + if obj.ViewObject: + obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") diff --git a/src/Mod/Path/PathScripts/PathLoadTool.py b/src/Mod/Path/PathScripts/PathLoadTool.py index a115a099c..41e47743f 100644 --- a/src/Mod/Path/PathScripts/PathLoadTool.py +++ b/src/Mod/Path/PathScripts/PathLoadTool.py @@ -181,13 +181,14 @@ PathUtils.addToJob(obj) FreeCAD.ActiveDocument.recompute() @staticmethod - def Create(jobname = None): + def Create(jobname = None, assignViewProvider = True): import PathScripts import PathUtils obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "TC") PathScripts.PathLoadTool.LoadTool(obj) - PathScripts.PathLoadTool._ViewProviderLoadTool(obj.ViewObject) + if assignViewProvider: + PathScripts.PathLoadTool._ViewProviderLoadTool(obj.ViewObject) PathUtils.addToJob(obj, jobname) diff --git a/src/Mod/Path/PathScripts/PathPost.py b/src/Mod/Path/PathScripts/PathPost.py index 9b7cd71fd..1827b3d04 100644 --- a/src/Mod/Path/PathScripts/PathPost.py +++ b/src/Mod/Path/PathScripts/PathPost.py @@ -79,7 +79,7 @@ class DlgSelectPostProcessor: class CommandPathPost: def resolveFileName(self, job): - print("resolveFileName(%s)" % job.Label) + #print("resolveFileName(%s)" % job.Label) path = PathPreferences.defaultOutputFile() if job.OutputFile: path = job.OutputFile @@ -134,7 +134,7 @@ class CommandPathPost: else: filename = None - print("resolveFileName(%s, %s) -> '%s'" % (path, policy, filename)) + #print("resolveFileName(%s, %s) -> '%s'" % (path, policy, filename)) return filename def resolvePostProcessor(self, job): @@ -179,35 +179,44 @@ class CommandPathPost: job = PathUtils.findParentJob(obj) if job: jobs.add(job) + + fail = True + rc = '' if len(jobs) != 1: FreeCAD.Console.PrintError("Please select a single job or other path object\n") - FreeCAD.ActiveDocument.abortTransaction() else: job = jobs.pop() print("Job for selected objects = %s" % job.Name) + (fail, rc) = exportObjectsWith(selected, job) - # check if the user has a project and has set the default post and - # output filename - postArgs = PathPreferences.defaultPostProcessorArgs() - if hasattr(job, "PostProcessorArgs") and job.PostProcessorArgs: - postArgs = job.PostProcessorArgs - elif hasattr(job, "PostProcessor") and job.PostProcessor: - postArgs = '' - - postname = self.resolvePostProcessor(job) - if postname: - filename = self.resolveFileName(job) - - if postname and filename: - print("post: %s(%s, %s)" % (postname, filename, postArgs)) - processor = PostProcessor.load(postname) - processor.export(selected, filename, postArgs) - - FreeCAD.ActiveDocument.commitTransaction() - else: - FreeCAD.ActiveDocument.abortTransaction() + if fail: + FreeCAD.ActiveDocument.abortTransaction() + else: + FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() + def exportObjectsWith(self, objs, job, needFilename = True): + # check if the user has a project and has set the default post and + # output filename + postArgs = PathPreferences.defaultPostProcessorArgs() + if hasattr(job, "PostProcessorArgs") and job.PostProcessorArgs: + postArgs = job.PostProcessorArgs + elif hasattr(job, "PostProcessor") and job.PostProcessor: + postArgs = '' + + postname = self.resolvePostProcessor(job) + filename = '-' + if postname and needFilename: + filename = self.resolveFileName(job) + + if postname and filename: + print("post: %s(%s, %s)" % (postname, filename, postArgs)) + processor = PostProcessor.load(postname) + gcode = processor.export(objs, filename, postArgs) + return (False, gcode) + else: + return (True, '') + if FreeCAD.GuiUp: # register the FreeCAD command FreeCADGui.addCommand('Path_Post', CommandPathPost()) diff --git a/src/Mod/Path/PathScripts/PathPostProcessor.py b/src/Mod/Path/PathScripts/PathPostProcessor.py index d302ab161..618123fd3 100644 --- a/src/Mod/Path/PathScripts/PathPostProcessor.py +++ b/src/Mod/Path/PathScripts/PathPostProcessor.py @@ -78,4 +78,4 @@ class PostProcessor: self.script = script def export(self, obj, filename, args): - self.script.export(obj, filename, args) + return self.script.export(obj, filename, args) diff --git a/src/Mod/Path/PathScripts/linuxcnc_post.py b/src/Mod/Path/PathScripts/linuxcnc_post.py index 1d9f00ac3..4d625c5fe 100644 --- a/src/Mod/Path/PathScripts/linuxcnc_post.py +++ b/src/Mod/Path/PathScripts/linuxcnc_post.py @@ -38,6 +38,7 @@ Arguments for linuxcnc: --header,--no-header ... output headers (--header) --comments,--no-comments ... output comments (--comments) --line-numbers,--no-line-numbers ... prefix with line numbers (--no-lin-numbers) + --show-editor, --no-show-editor ... pop up editor before writing output(--show-editor) ''' import datetime @@ -90,6 +91,7 @@ def processArguments(argstring): global OUTPUT_HEADER global OUTPUT_COMMENTS global OUTPUT_LINE_NUMBERS + global SHOW_EDITOR for arg in argstring.split(): if arg == '--header': OUTPUT_HEADER = True @@ -103,6 +105,10 @@ def processArguments(argstring): OUTPUT_LINE_NUMBERS = True elif arg == '--no-line-numbers': OUTPUT_LINE_NUMBERS = False + elif arg == '--show-editor': + SHOW_EDITOR = True + elif arg == '--no-show-editor': + SHOW_EDITOR = False def export(objectslist, filename, argstring): processArguments(argstring) @@ -179,9 +185,12 @@ def export(objectslist, filename, argstring): print "done postprocessing." - gfile = pythonopen(filename, "wb") - gfile.write(gcode) - gfile.close() + if not filename == '-': + gfile = pythonopen(filename, "wb") + gfile.write(final) + gfile.close() + + return final def linenumber(): diff --git a/src/Mod/Path/PathTests/TestPathPost.py b/src/Mod/Path/PathTests/TestPathPost.py index 1907fccb1..1a2a384b3 100644 --- a/src/Mod/Path/PathTests/TestPathPost.py +++ b/src/Mod/Path/PathTests/TestPathPost.py @@ -23,10 +23,16 @@ # *************************************************************************** import FreeCAD +import Path +import PathScripts +import PathScripts.PathContour +import PathScripts.PathJob +import PathScripts.PathLoadTool +import PathScripts.PathPost +import PathScripts.PathUtils +import difflib import unittest -from PathScripts import PathPost - class PathPostTestCases(unittest.TestCase): def setUp(self): self.doc = FreeCAD.newDocument("PathPostTest") @@ -34,8 +40,58 @@ class PathPostTestCases(unittest.TestCase): def tearDown(self): FreeCAD.closeDocument("PathPostTest") - def testCommand(self): - self.box = self.doc.addObject("Part::Box", "Box") - print("Running command test") + def testLinuxCNC(self): + # first create something to generate a path for + box = self.doc.addObject("Part::Box", "Box") + + # Create job and setup tool library + default tool + job = self.doc.addObject("Path::FeatureCompoundPython", "Job") + PathScripts.PathJob.ObjectPathJob(job) + job.Base = self.doc.Box + PathScripts.PathLoadTool.CommandPathLoadTool.Create(job.Name, False) + toolLib = job.Group[0] + tool1 = Path.Tool() + tool1.Diameter = 5.0 + tool1.Name = "Default Tool" + tool1.CuttingEdgeHeight = 15.0 + tool1.ToolType = "EndMill" + tool1.Material = "HighSpeedSteel" + job.Tooltable.addTools(tool1) + toolLib.ToolNumber = 1 self.failUnless(True) + self.doc.getObject("TC").ToolNumber = 2 + self.doc.recompute() + + contour = self.doc.addObject("Path::FeaturePython", "Contour") + PathScripts.PathContour.ObjectContour(contour) + contour.Active = True + contour.ClearanceHeight = 20.0 + contour.StepDown = 1.0 + contour.StartDepth= 10.0 + contour.FinalDepth=0.0 + contour.SafeHeight = 12.0 + contour.OffsetExtra = 0.0 + contour.Direction = 'CW' + contour.UseComp = True + contour.PlungeAngle = 90.0 + PathScripts.PathUtils.addToJob(contour) + PathScripts.PathContour.ObjectContour.setDepths(contour.Proxy, contour) + self.doc.recompute() + + job.PostProcessor = 'linuxcnc' + job.PostProcessorArgs = '--no-header --no-line-numbers --no-comments --no-show-editor' + + post = PathScripts.PathPost.CommandPathPost() + (fail, gcode) = post.exportObjectsWith([job], job, False) + self.assertFalse(fail) + + referenceFile = FreeCAD.getHomePath() + 'Mod/Path/PathTests/test_linuxcnc_00.ngc' + with open(referenceFile, 'r') as fp: + refGCode = fp.read() + + if gcode != refGCode: + msg = ''.join(difflib.ndiff(gcode.splitlines(True), refGCode.splitlines(True))) + self.fail("linuxcnc output doesn't match: " + msg) + + diff --git a/src/Mod/Path/PathTests/test_linuxcnc_00.ngc b/src/Mod/Path/PathTests/test_linuxcnc_00.ngc new file mode 100644 index 000000000..d1ac7f01b --- /dev/null +++ b/src/Mod/Path/PathTests/test_linuxcnc_00.ngc @@ -0,0 +1,62 @@ +G17 G90 +G21 +(Contour :TC) +(Uncompensated Tool Path) +G0 Z15.0000 +G00 X-0.2500 Y0.0000 +G00 Z23.0000 +G01 X-0.2500 Y0.0000 Z9.0000 F0.00 +G01 X-0.2500 Y10.0000 Z9.0000 F0.00 +G02 X0.2500 Y10.0000 Z9.0000 I0.2500 J0.0000 F0.00 +G01 X0.2500 Y0.0000 Z9.0000 F0.00 +G02 X-0.2500 Y0.0000 Z9.0000 I-0.2500 J0.0000 F0.00 +G01 X-0.2500 Y0.0000 Z8.0000 F0.00 +G01 X-0.2500 Y10.0000 Z8.0000 F0.00 +G02 X0.2500 Y10.0000 Z8.0000 I0.2500 J0.0000 F0.00 +G01 X0.2500 Y0.0000 Z8.0000 F0.00 +G02 X-0.2500 Y0.0000 Z8.0000 I-0.2500 J0.0000 F0.00 +G01 X-0.2500 Y0.0000 Z7.0000 F0.00 +G01 X-0.2500 Y10.0000 Z7.0000 F0.00 +G02 X0.2500 Y10.0000 Z7.0000 I0.2500 J0.0000 F0.00 +G01 X0.2500 Y0.0000 Z7.0000 F0.00 +G02 X-0.2500 Y0.0000 Z7.0000 I-0.2500 J0.0000 F0.00 +G01 X-0.2500 Y0.0000 Z6.0000 F0.00 +G01 X-0.2500 Y10.0000 Z6.0000 F0.00 +G02 X0.2500 Y10.0000 Z6.0000 I0.2500 J0.0000 F0.00 +G01 X0.2500 Y0.0000 Z6.0000 F0.00 +G02 X-0.2500 Y0.0000 Z6.0000 I-0.2500 J0.0000 F0.00 +G01 X-0.2500 Y0.0000 Z5.0000 F0.00 +G01 X-0.2500 Y10.0000 Z5.0000 F0.00 +G02 X0.2500 Y10.0000 Z5.0000 I0.2500 J0.0000 F0.00 +G01 X0.2500 Y0.0000 Z5.0000 F0.00 +G02 X-0.2500 Y0.0000 Z5.0000 I-0.2500 J0.0000 F0.00 +G01 X-0.2500 Y0.0000 Z4.0000 F0.00 +G01 X-0.2500 Y10.0000 Z4.0000 F0.00 +G02 X0.2500 Y10.0000 Z4.0000 I0.2500 J0.0000 F0.00 +G01 X0.2500 Y0.0000 Z4.0000 F0.00 +G02 X-0.2500 Y0.0000 Z4.0000 I-0.2500 J0.0000 F0.00 +G01 X-0.2500 Y0.0000 Z3.0000 F0.00 +G01 X-0.2500 Y10.0000 Z3.0000 F0.00 +G02 X0.2500 Y10.0000 Z3.0000 I0.2500 J0.0000 F0.00 +G01 X0.2500 Y0.0000 Z3.0000 F0.00 +G02 X-0.2500 Y0.0000 Z3.0000 I-0.2500 J0.0000 F0.00 +G01 X-0.2500 Y0.0000 Z2.0000 F0.00 +G01 X-0.2500 Y10.0000 Z2.0000 F0.00 +G02 X0.2500 Y10.0000 Z2.0000 I0.2500 J0.0000 F0.00 +G01 X0.2500 Y0.0000 Z2.0000 F0.00 +G02 X-0.2500 Y0.0000 Z2.0000 I-0.2500 J0.0000 F0.00 +G01 X-0.2500 Y0.0000 Z1.0000 F0.00 +G01 X-0.2500 Y10.0000 Z1.0000 F0.00 +G02 X0.2500 Y10.0000 Z1.0000 I0.2500 J0.0000 F0.00 +G01 X0.2500 Y0.0000 Z1.0000 F0.00 +G02 X-0.2500 Y0.0000 Z1.0000 I-0.2500 J0.0000 F0.00 +G01 X-0.2500 Y0.0000 Z0.0000 F0.00 +G01 X-0.2500 Y10.0000 Z0.0000 F0.00 +G02 X0.2500 Y10.0000 Z0.0000 I0.2500 J0.0000 F0.00 +G01 X0.2500 Y0.0000 Z0.0000 F0.00 +G02 X-0.2500 Y0.0000 Z0.0000 I-0.2500 J0.0000 F0.00 +G00 Z15.0000 +M05 +G00 X-1.0 Y1.0 +G17 G90 +M2