diff --git a/src/Mod/Path/PathScripts/PathPreferences.py b/src/Mod/Path/PathScripts/PathPreferences.py index b4a3248823..2021a56013 100644 --- a/src/Mod/Path/PathScripts/PathPreferences.py +++ b/src/Mod/Path/PathScripts/PathPreferences.py @@ -54,7 +54,7 @@ UseAbsoluteToolPaths = "UseAbsoluteToolPaths" # Linear tolerance to use when generating Paths, eg when tessellating geometry GeometryTolerance = "GeometryTolerance" -LibAreaCurveAccuracy = "LibAreaCurveAccuarcy" +LibAreaCurveAccuracy = "LibAreaCurveAccuracy" WarningSuppressRapidSpeeds = "WarningSuppressRapidSpeeds" WarningSuppressAllSpeeds = "WarningSuppressAllSpeeds" diff --git a/src/Mod/Path/PathScripts/PostUtils.py b/src/Mod/Path/PathScripts/PostUtils.py index 4d554188f7..60c0744ed8 100644 --- a/src/Mod/Path/PathScripts/PostUtils.py +++ b/src/Mod/Path/PathScripts/PostUtils.py @@ -28,6 +28,10 @@ These are a common functions and classes for creating custom post processors. from PySide import QtCore, QtGui import FreeCAD +from PathMachineState import MachineState +import Path +import Part +from PathScripts.PathGeom import CmdMoveArc, edgeForCmd, cmdsForEdge translate = FreeCAD.Qt.translate @@ -193,3 +197,32 @@ def fcoms(string, commentsym): else: return string return comment + +def splitArcs(path): + """filters a path object and replaces at G2/G3 moves with discrete G1 + returns a Path object""" + prefGrp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path") + deflection = prefGrp.GetFloat("LibAreaCurveAccuarcy", 0.01) + + results = [] + if not isinstance(path, Path.Path): + raise TypeError("path must be a Path object") + + machine = MachineState() + for command in path.Commands: + + if command.Name not in CmdMoveArc: + machine.addCommand(command) + results.append(command) + continue + + edge = edgeForCmd(command, machine.getPosition()) + pts =edge.discretize(Deflection=deflection) + edges = [Part.makeLine(v1, v2) for v1, v2 in zip(pts, pts[1:])] + for edge in edges: + results.extend(cmdsForEdge(edge)) + + machine.addCommand(command) + + return Path.Path(results) + diff --git a/src/Mod/Path/PathTests/TestPathPost.py b/src/Mod/Path/PathTests/TestPathPost.py index eb047397d8..81d975690e 100644 --- a/src/Mod/Path/PathTests/TestPathPost.py +++ b/src/Mod/Path/PathTests/TestPathPost.py @@ -28,15 +28,17 @@ import PathScripts.PathJob import PathScripts.PathPost import PathScripts.PathToolController import PathScripts.PathUtil +import PathScripts.PostUtils as PostUtils import difflib import unittest +import Path WriteDebugOutput = False -class PathPostTestCases(unittest.TestCase): +class PathPostTestCases(unittest.TestCase): def setUp(self): - testfile = FreeCAD.getHomePath() + 'Mod/Path/PathTests/boxtest.fcstd' + testfile = FreeCAD.getHomePath() + "Mod/Path/PathTests/boxtest.fcstd" self.doc = FreeCAD.open(testfile) self.job = FreeCAD.ActiveDocument.getObject("Job") self.postlist = [] @@ -54,54 +56,100 @@ class PathPostTestCases(unittest.TestCase): def testLinuxCNC(self): from PathScripts.post import linuxcnc_post as postprocessor - args = '--no-header --no-line-numbers --no-comments --no-show-editor --precision=2' - gcode = postprocessor.export(self.postlist, 'gcode.tmp', args) - referenceFile = FreeCAD.getHomePath() + 'Mod/Path/PathTests/test_linuxcnc_00.ngc' - with open(referenceFile, 'r') as fp: + args = ( + "--no-header --no-line-numbers --no-comments --no-show-editor --precision=2" + ) + gcode = postprocessor.export(self.postlist, "gcode.tmp", args) + + referenceFile = ( + FreeCAD.getHomePath() + "Mod/Path/PathTests/test_linuxcnc_00.ngc" + ) + with open(referenceFile, "r") as fp: refGCode = fp.read() # Use if this test fails in order to have a real good look at the changes if WriteDebugOutput: - with open('testLinuxCNC.tmp', 'w') as fp: + with open("testLinuxCNC.tmp", "w") as fp: fp.write(gcode) if gcode != refGCode: - msg = ''.join(difflib.ndiff(gcode.splitlines(True), refGCode.splitlines(True))) + msg = "".join( + difflib.ndiff(gcode.splitlines(True), refGCode.splitlines(True)) + ) self.fail("linuxcnc output doesn't match: " + msg) def testLinuxCNCImperial(self): from PathScripts.post import linuxcnc_post as postprocessor - args = '--no-header --no-line-numbers --no-comments --no-show-editor --precision=2 --inches' - gcode = postprocessor.export(self.postlist, 'gcode.tmp', args) - referenceFile = FreeCAD.getHomePath() + 'Mod/Path/PathTests/test_linuxcnc_10.ngc' - with open(referenceFile, 'r') as fp: + args = "--no-header --no-line-numbers --no-comments --no-show-editor --precision=2 --inches" + gcode = postprocessor.export(self.postlist, "gcode.tmp", args) + + referenceFile = ( + FreeCAD.getHomePath() + "Mod/Path/PathTests/test_linuxcnc_10.ngc" + ) + with open(referenceFile, "r") as fp: refGCode = fp.read() # Use if this test fails in order to have a real good look at the changes if WriteDebugOutput: - with open('testLinuxCNCImplerial.tmp', 'w') as fp: + with open("testLinuxCNCImplerial.tmp", "w") as fp: fp.write(gcode) if gcode != refGCode: - msg = ''.join(difflib.ndiff(gcode.splitlines(True), refGCode.splitlines(True))) + msg = "".join( + difflib.ndiff(gcode.splitlines(True), refGCode.splitlines(True)) + ) self.fail("linuxcnc output doesn't match: " + msg) def testCentroid(self): from PathScripts.post import centroid_post as postprocessor - args = '--no-header --no-line-numbers --no-comments --no-show-editor --axis-precision=2 --feed-precision=2' - gcode = postprocessor.export(self.postlist, 'gcode.tmp', args) - referenceFile = FreeCAD.getHomePath() + 'Mod/Path/PathTests/test_centroid_00.ngc' - with open(referenceFile, 'r') as fp: + args = "--no-header --no-line-numbers --no-comments --no-show-editor --axis-precision=2 --feed-precision=2" + gcode = postprocessor.export(self.postlist, "gcode.tmp", args) + + referenceFile = ( + FreeCAD.getHomePath() + "Mod/Path/PathTests/test_centroid_00.ngc" + ) + with open(referenceFile, "r") as fp: refGCode = fp.read() # Use if this test fails in order to have a real good look at the changes if WriteDebugOutput: - with open('testCentroid.tmp', 'w') as fp: + with open("testCentroid.tmp", "w") as fp: fp.write(gcode) if gcode != refGCode: - msg = ''.join(difflib.ndiff(gcode.splitlines(True), refGCode.splitlines(True))) + msg = "".join( + difflib.ndiff(gcode.splitlines(True), refGCode.splitlines(True)) + ) self.fail("linuxcnc output doesn't match: " + msg) + + +class TestPathPostUtils(unittest.TestCase): + def testSplitArcs(self): + + commands = [ + Path.Command("G1 X-7.5 Y5.0 Z0.0"), + Path.Command("G2 I2.5 J0.0 K0.0 X-5.0 Y7.5 Z0.0"), + Path.Command("G1 X5.0 Y7.5 Z0.0"), + Path.Command("G2 I0.0 J-2.5 K0.0 X7.5 Y5.0 Z0.0"), + Path.Command("G1 X7.5 Y-5.0 Z0.0"), + Path.Command("G2 I-2.5 J0.0 K0.0 X5.0 Y-7.5 Z0.0"), + Path.Command("G1 X-5.0 Y-7.5 Z0.0"), + Path.Command("G2 I0.0 J2.5 K0.0 X-7.5 Y-5.0 Z0.0"), + Path.Command("G1 X-7.5 Y0.0 Z0.0"), + ] + + testpath = Path.Path(commands) + self.assertTrue(len(testpath.Commands) == 9) + self.assertTrue(len([c for c in testpath.Commands if c.Name in ['G2', 'G3']]) == 4) + + results = PostUtils.splitArcs(testpath) + self.assertTrue(len(results.Commands) == 117) + self.assertTrue(len([c for c in results.Commands if c.Name in ['G2', 'G3']]) == 0) + + + + + diff --git a/src/Mod/Path/TestPathApp.py b/src/Mod/Path/TestPathApp.py index 797f7fc410..df94f86591 100644 --- a/src/Mod/Path/TestPathApp.py +++ b/src/Mod/Path/TestPathApp.py @@ -37,6 +37,7 @@ from PathTests.TestPathHelixGenerator import TestPathHelixGenerator from PathTests.TestPathLog import TestPathLog from PathTests.TestPathOpTools import TestPathOpTools # from PathTests.TestPathPost import PathPostTestCases +from PathTests.TestPathPost import TestPathPostUtils from PathTests.TestPathPreferences import TestPathPreferences from PathTests.TestPathPropertyBag import TestPathPropertyBag from PathTests.TestPathRotationGenerator import TestPathRotationGenerator @@ -66,6 +67,7 @@ False if TestPathHelpers.__name__ else True False if TestPathLog.__name__ else True False if TestPathOpTools.__name__ else True # False if TestPathPost.__name__ else True +False if TestPathPostUtils.__name__ else True False if TestPathPreferences.__name__ else True False if TestPathPropertyBag.__name__ else True False if TestPathRotationGenerator.__name__ else True