diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt
index 12538fbe55..13135a8a24 100644
--- a/src/Mod/Path/CMakeLists.txt
+++ b/src/Mod/Path/CMakeLists.txt
@@ -34,6 +34,7 @@ SET(PathScripts_SRCS
PathScripts/PathComment.py
PathScripts/PathCopy.py
PathScripts/PathCustom.py
+ PathScripts/PathCustomGui.py
PathScripts/PathDeburr.py
PathScripts/PathDeburrGui.py
PathScripts/PathDressup.py
diff --git a/src/Mod/Path/Gui/Resources/Path.qrc b/src/Mod/Path/Gui/Resources/Path.qrc
index 59eea1c06b..e328fca04c 100644
--- a/src/Mod/Path/Gui/Resources/Path.qrc
+++ b/src/Mod/Path/Gui/Resources/Path.qrc
@@ -98,6 +98,7 @@
panels/PageBaseLocationEdit.ui
panels/PageDepthsEdit.ui
panels/PageHeightsEdit.ui
+ panels/PageOpCustomEdit.ui
panels/PageOpDeburrEdit.ui
panels/PageOpDrillingEdit.ui
panels/PageOpEngraveEdit.ui
diff --git a/src/Mod/Path/Gui/Resources/panels/PageOpCustomEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageOpCustomEdit.ui
new file mode 100644
index 0000000000..ac1d20e165
--- /dev/null
+++ b/src/Mod/Path/Gui/Resources/panels/PageOpCustomEdit.ui
@@ -0,0 +1,93 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 424
+ 376
+
+
+
+ Form
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ <html><head/><body><p>The tool and its settings to be used for this operation.</p></body></html>
+
+
+
+ -
+
+
+ ToolController
+
+
+
+ -
+
+
+ Coolant Mode
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+ G Gode
+
+
+
+ -
+
+
+ QTextEdit::NoWrap
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
diff --git a/src/Mod/Path/PathScripts/PathCustom.py b/src/Mod/Path/PathScripts/PathCustom.py
index a06b8b51ef..217ec244f0 100644
--- a/src/Mod/Path/PathScripts/PathCustom.py
+++ b/src/Mod/Path/PathScripts/PathCustom.py
@@ -22,84 +22,58 @@
# ***************************************************************************
import FreeCAD
-import FreeCADGui
import Path
+
+import PathScripts.PathOp as PathOp
+import PathScripts.PathLog as PathLog
+
from PySide import QtCore
-from copy import copy
+__title__ = "Path Custom Operation"
+__author__ = "sliptonic (Brad Collette)"
+__url__ = "http://www.freecadweb.org"
+__doc__ = "Path Custom object and FreeCAD command"
-__doc__ = """Path Custom object and FreeCAD command"""
+if False:
+ PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
+ PathLog.trackModule(PathLog.thisModule())
+else:
+ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
-movecommands = ['G0', 'G00', 'G1', 'G01', 'G2', 'G02', 'G3', 'G03']
# Qt translation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
-class ObjectCustom:
- def __init__(self, obj):
+class ObjectCustom(PathOp.ObjectOp):
+ def opFeatures(self, obj):
+ return PathOp.FeatureTool | PathOp.FeatureCoolant
+
+ def initOperation(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")
obj.Proxy = self
- def __getstate__(self):
- return None
-
- def __setstate__(self, state):
- return None
-
- def execute(self, obj):
- newpath = Path.Path()
+ def opExecute(self, obj):
+ self.commandlist.append(Path.Command("(Begin Custom)"))
if obj.Gcode:
for l in obj.Gcode:
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
+ self.commandlist.append(newcommand)
- newpath.insertCommand(newcommand)
-
- obj.Path=newpath
+ self.commandlist.append(Path.Command("(End Custom)"))
-
-class CommandPathCustom:
-
- def GetResources(self):
- return {'Pixmap': 'Path-Custom',
- 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Custom", "Custom"),
- 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Custom", "Creates a path object based on custom G-code")}
-
- def IsActive(self):
- if FreeCAD.ActiveDocument is not None:
- for o in FreeCAD.ActiveDocument.Objects:
- if o.Name[:3] == "Job":
- return True
- return False
-
- def Activated(self):
- 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('PathScripts.PathCustom.ObjectCustom(obj)')
- FreeCADGui.doCommand('obj.ViewObject.Proxy = 0')
- FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
- FreeCADGui.doCommand('obj.ToolController = PathScripts.PathUtils.findToolController(obj)')
- FreeCAD.ActiveDocument.commitTransaction()
- FreeCAD.ActiveDocument.recompute()
+def SetupProperties():
+ setup = []
+ return setup
-if FreeCAD.GuiUp:
- # register the FreeCAD command
- FreeCADGui.addCommand('Path_Custom', CommandPathCustom())
\ No newline at end of file
+def Create(name, obj=None):
+ '''Create(name) ... Creates and returns a Custom operation.'''
+ if obj is None:
+ obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
+ proxy = ObjectCustom(obj, name)
+ return obj
diff --git a/src/Mod/Path/PathScripts/PathCustomGui.py b/src/Mod/Path/PathScripts/PathCustomGui.py
new file mode 100644
index 0000000000..3ec21091f7
--- /dev/null
+++ b/src/Mod/Path/PathScripts/PathCustomGui.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+
+# ***************************************************************************
+# * *
+# * Copyright (c) 2017 sliptonic *
+# * *
+# * 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. *
+# * *
+# * This program 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 Library General Public License for more details. *
+# * *
+# * You should have received a copy of the GNU Library General Public *
+# * License along with this program; if not, write to the Free Software *
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+# * USA *
+# * *
+# ***************************************************************************
+
+import FreeCAD
+import FreeCADGui
+import PathScripts.PathCustom as PathCustom
+import PathScripts.PathOpGui as PathOpGui
+
+from PySide import QtCore
+
+__title__ = "Path Custom Operation UI"
+__author__ = "sliptonic (Brad Collette)"
+__url__ = "http://www.freecadweb.org"
+__doc__ = "Custom operation page controller and command implementation."
+
+
+# Qt translation handling
+def translate(context, text, disambig=None):
+ return QtCore.QCoreApplication.translate(context, text, disambig)
+
+
+# class TaskPanelBaseGeometryPage(PathOpGui.TaskPanelBaseGeometryPage):
+# '''Page controller for the base geometry.'''
+
+# def getForm(self):
+# return None
+
+
+class TaskPanelOpPage(PathOpGui.TaskPanelPage):
+ '''Page controller class for the Custom operation.'''
+
+ def getForm(self):
+ '''getForm() ... returns UI'''
+ return FreeCADGui.PySideUic.loadUi(":/panels/PageOpCustomEdit.ui")
+
+ def getFields(self, obj):
+ '''getFields(obj) ... transfers values from UI to obj's properties'''
+ self.updateToolController(obj, self.form.toolController)
+ self.updateCoolant(obj, self.form.coolantController)
+
+ def setFields(self, obj):
+ '''setFields(obj) ... transfers obj's property values to UI'''
+ self.setupToolController(obj, self.form.toolController)
+ self.form.txtGCode.setText("\n".join(obj.Gcode))
+ self.setupCoolant(obj, self.form.coolantController)
+
+ def getSignalsForUpdate(self, obj):
+ '''getSignalsForUpdate(obj) ... return list of signals for updating obj'''
+ signals = []
+ signals.append(self.form.toolController.currentIndexChanged)
+ signals.append(self.form.coolantController.currentIndexChanged)
+ self.form.txtGCode.textChanged.connect(self.setGCode)
+ return signals
+
+ def setGCode(self):
+ self.obj.Gcode = self.form.txtGCode.toPlainText().splitlines()
+
+
+Command = PathOpGui.SetupOperation('Custom', PathCustom.Create, TaskPanelOpPage,
+ 'Path-Custom',
+ QtCore.QT_TRANSLATE_NOOP("Custom", "Custom"),
+ QtCore.QT_TRANSLATE_NOOP("Custom", "Create custom gcode snippet"),
+ PathCustom.SetupProperties)
+
+FreeCAD.Console.PrintLog("Loading PathCustomGui... done\n")
diff --git a/src/Mod/Path/PathScripts/PathGuiInit.py b/src/Mod/Path/PathScripts/PathGuiInit.py
index 21aadba1d5..81d6b911c2 100644
--- a/src/Mod/Path/PathScripts/PathGuiInit.py
+++ b/src/Mod/Path/PathScripts/PathGuiInit.py
@@ -43,7 +43,8 @@ def Startup():
from PathScripts import PathAdaptiveGui
from PathScripts import PathArray
from PathScripts import PathComment
- from PathScripts import PathCustom
+ # from PathScripts import PathCustom
+ from PathScripts import PathCustomGui
from PathScripts import PathDeburrGui
from PathScripts import PathDressupAxisMap
from PathScripts import PathDressupDogbone
diff --git a/src/Mod/Path/PathScripts/PathOp.py b/src/Mod/Path/PathScripts/PathOp.py
index 098c4bfc90..6c21ea8c9a 100644
--- a/src/Mod/Path/PathScripts/PathOp.py
+++ b/src/Mod/Path/PathScripts/PathOp.py
@@ -65,7 +65,7 @@ FeatureBasePanels = 0x0800 # Base
FeatureLocations = 0x1000 # Locations
FeatureCoolant = 0x2000 # Coolant
-FeatureBaseGeometry = FeatureBaseVertexes | FeatureBaseFaces | FeatureBaseEdges | FeatureBasePanels | FeatureCoolant
+FeatureBaseGeometry = FeatureBaseVertexes | FeatureBaseFaces | FeatureBaseEdges | FeatureBasePanels
class ObjectOp(object):
@@ -245,7 +245,7 @@ class ObjectOp(object):
def opFeatures(self, obj):
'''opFeatures(obj) ... returns the OR'ed list of features used and supported by the operation.
- The default implementation returns "FeatureTool | FeatureDeptsh | FeatureHeights | FeatureStartPoint"
+ The default implementation returns "FeatureTool | FeatureDepths | FeatureHeights | FeatureStartPoint"
Should be overwritten by subclasses.'''
# pylint: disable=unused-argument
return FeatureTool | FeatureDepths | FeatureHeights | FeatureStartPoint | FeatureBaseGeometry | FeatureFinishDepth | FeatureCoolant
diff --git a/src/Mod/Path/PathScripts/PathOpGui.py b/src/Mod/Path/PathScripts/PathOpGui.py
index 02561a47ba..4101cb6c87 100644
--- a/src/Mod/Path/PathScripts/PathOpGui.py
+++ b/src/Mod/Path/PathScripts/PathOpGui.py
@@ -91,6 +91,11 @@ class ViewProvider(object):
PathLog.track()
return hasattr(self, 'deleteOnReject') and self.deleteOnReject
+ def setDeleteObjectsOnReject(self, state=False):
+ PathLog.track()
+ self.deleteOnReject = state
+ return self.deleteOnReject
+
def setEdit(self, vobj=None, mode=0):
'''setEdit(vobj, mode=0) ... initiate editing of receivers model.'''
PathLog.track()
@@ -198,7 +203,7 @@ class TaskPanelPage(object):
Do not overwrite, implement initPage(obj) instead.'''
self.obj = obj
self.job = PathUtils.findParentJob(obj)
- self.form = self.getForm() # pylint: disable=assignment-from-no-return
+ self.form = self.getForm() # pylint: disable=assignment-from-no-return
self.signalDirtyChanged = None
self.setClean()
self.setTitle('-')
@@ -285,32 +290,32 @@ class TaskPanelPage(object):
Note that this function is invoked after all page controllers have been created.
Should be overwritten by subclasses.'''
# pylint: disable=unused-argument
- pass # pylint: disable=unnecessary-pass
+ pass # pylint: disable=unnecessary-pass
def cleanupPage(self, obj):
'''cleanupPage(obj) ... overwrite to perform any cleanup tasks before page is destroyed.
Can safely be overwritten by subclasses.'''
- pass # pylint: disable=unnecessary-pass
+ pass # pylint: disable=unnecessary-pass
def modifyStandardButtons(self, buttonBox):
'''modifyStandardButtons(buttonBox) ... overwrite if the task panel standard buttons need to be modified.
Can safely be overwritten by subclasses.'''
- pass # pylint: disable=unnecessary-pass
+ pass # pylint: disable=unnecessary-pass
def getForm(self):
'''getForm() ... return UI form for this page.
Must be overwritten by subclasses.'''
- pass # pylint: disable=unnecessary-pass
+ pass # pylint: disable=unnecessary-pass
def getFields(self, obj):
'''getFields(obj) ... overwrite to transfer values from UI to obj's properties.
Can safely be overwritten by subclasses.'''
- pass # pylint: disable=unnecessary-pass
+ pass # pylint: disable=unnecessary-pass
def setFields(self, obj):
'''setFields(obj) ... overwrite to transfer obj's property values to UI.
Can safely be overwritten by subclasses.'''
- pass # pylint: disable=unnecessary-pass
+ pass # pylint: disable=unnecessary-pass
def getSignalsForUpdate(self, obj):
'''getSignalsForUpdate(obj) ... return signals which, when triggered, cause the receiver to update the model.
@@ -326,7 +331,7 @@ class TaskPanelPage(object):
manually.
Can safely be overwritten by subclasses.'''
# pylint: disable=unused-argument
- pass # pylint: disable=unnecessary-pass
+ pass # pylint: disable=unnecessary-pass
def updateData(self, obj, prop):
'''updateData(obj, prop) ... overwrite if the receiver needs to react to property changes that might not have been caused by the receiver itself.
@@ -339,13 +344,13 @@ class TaskPanelPage(object):
In such a scenario the first property assignment will cause all changes in the UI of the other fields to be overwritten by setFields(obj).
You have been warned.'''
# pylint: disable=unused-argument
- pass # pylint: disable=unnecessary-pass
+ pass # pylint: disable=unnecessary-pass
def updateSelection(self, obj, sel):
'''updateSelection(obj, sel) ... overwrite to customize UI depending on current selection.
Can safely be overwritten by subclasses.'''
# pylint: disable=unused-argument
- pass # pylint: disable=unnecessary-pass
+ pass # pylint: disable=unnecessary-pass
# helpers
def selectInComboBox(self, name, combo):
@@ -432,7 +437,6 @@ class TaskPanelBaseGeometryPage(TaskPanelPage):
if len(availableOps) > 0:
# Populate the operations list
- addInputs = True
panel.geometryImportList.blockSignals(True)
panel.geometryImportList.clear()
availableOps.sort()
@@ -738,7 +742,7 @@ class TaskPanelHeightsPage(TaskPanelPage):
self.safeHeight.updateProperty()
self.clearanceHeight.updateProperty()
- def setFields(self, obj):
+ def setFields(self, obj):
self.safeHeight.updateSpinBox()
self.clearanceHeight.updateSpinBox()
@@ -933,7 +937,7 @@ class TaskPanel(object):
else:
self.featurePages.append(TaskPanelBaseLocationPage(obj, features))
- if PathOp.FeatureDepths & features or PathOp.FeatureStepDown:
+ if PathOp.FeatureDepths & features or PathOp.FeatureStepDown & features:
if hasattr(opPage, 'taskPanelDepthsPage'):
self.featurePages.append(opPage.taskPanelDepthsPage(obj, features))
else:
@@ -1186,9 +1190,9 @@ class CommandPathOp:
self.res = resources
def GetResources(self):
- ress = {'Pixmap': self.res.pixmap,
+ ress = {'Pixmap': self.res.pixmap,
'MenuText': self.res.menuText,
- 'ToolTip': self.res.toolTip}
+ 'ToolTip': self.res.toolTip}
if self.res.accelKey:
ress['Accel'] = self.res.accelKey
return ress
@@ -1236,7 +1240,7 @@ def SetupOperation(name,
command = CommandPathOp(res)
FreeCADGui.addCommand("Path_%s" % name.replace(' ', '_'), command)
- if not setupProperties is None:
+ if setupProperties is not None:
PathSetupSheet.RegisterOperation(name, objFactory, setupProperties)
return command
diff --git a/src/Mod/Path/PathScripts/PathSelection.py b/src/Mod/Path/PathScripts/PathSelection.py
index 943d6ae28a..ab00ae93ee 100644
--- a/src/Mod/Path/PathScripts/PathSelection.py
+++ b/src/Mod/Path/PathScripts/PathSelection.py
@@ -290,6 +290,10 @@ def probeselect():
FreeCADGui.Selection.addSelectionGate(PROBEGate())
FreeCAD.Console.PrintWarning("Probe Select Mode\n")
+def customselect():
+ FreeCAD.Console.PrintWarning("Custom Select Mode\n")
+
+
def select(op):
opsel = {}
@@ -309,6 +313,7 @@ def select(op):
opsel['Waterline'] = surfaceselect
opsel['Adaptive'] = adaptiveselect
opsel['Probe'] = probeselect
+ opsel['Custom'] = customselect
return opsel[op]
diff --git a/src/Mod/Path/PathScripts/post/example_pre.py b/src/Mod/Path/PathScripts/post/example_pre.py
index 48ceb433bf..18e2abe79b 100644
--- a/src/Mod/Path/PathScripts/post/example_pre.py
+++ b/src/Mod/Path/PathScripts/post/example_pre.py
@@ -25,7 +25,8 @@
'''
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.
+in FreeCAD. This preprocessor will not add imported gcode to an existing
+job. For a more useful preprocessor, look at the gcode_pre.py file
Read the Path Workbench documentation to know how to create Path objects
from GCode.
@@ -76,8 +77,8 @@ def parse(inputstring):
PathLog.track(inputstring)
# split the input by line
lines = inputstring.split("\n")
- output = [] #""
- lastcommand = None
+ output = []
+ lastcommand = None
for lin in lines:
# remove any leftover trailing and preceding spaces
@@ -98,8 +99,7 @@ def parse(inputstring):
continue
if lin[0].upper() in ["G", "M"]:
# found a G or M command: we store it
- #output += lin + "\n"
- output.append(Path.Command(str(lin))) # + "\n"
+ output.append(Path.Command(str(lin)))
last = lin[0].upper()
for c in lin[1:]:
if not c.isdigit():
@@ -109,7 +109,7 @@ def parse(inputstring):
lastcommand = last
elif lastcommand:
# no G or M command: we repeat the last one
- output.append(Path.Command(str(lastcommand + " " + lin))) # + "\n"
+ output.append(Path.Command(str(lastcommand + " " + lin)))
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
index 053c39c229..795192257b 100644
--- a/src/Mod/Path/PathScripts/post/gcode_pre.py
+++ b/src/Mod/Path/PathScripts/post/gcode_pre.py
@@ -27,16 +27,29 @@ 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.
+This preprocessor will split gcode on tool changes and create one or more
+PathCustom objects in the job. Tool Change commands themselves are not
+preserved. It is up to the user to create and assign appropriate tool
+controllers.
+
+Only gcodes that are supported by Path are imported. Thus things like G43
+are suppressed.
+
+Importing gcode is inherently dangerous because context cannot be safely
+assumed. The user should carefully examine the resulting gcode!
+
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.PathUtils as PathUtils
import PathScripts.PathLog as PathLog
import re
+import PathScripts.PathCustom as PathCustom
+import PathScripts.PathCustomGui as PathCustomGui
+import PathScripts.PathOpGui as PathOpGui
# LEVEL = PathLog.Level.DEBUG
LEVEL = PathLog.Level.INFO
@@ -59,71 +72,109 @@ def open(filename):
insert(filename, doc.Name)
+def matchToolController(op, toolnumber):
+ """Try to match a tool controller in the job by number"""
+ toolcontrollers = PathUtils.getToolControllers(op)
+ for tc in toolcontrollers:
+ if tc.ToolNumber == toolnumber:
+ return tc
+ return toolcontrollers[0]
+
+
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:]
+
+ # Regular expression to match tool changes in the format 'M6 Tn'
+ p = re.compile('[mM]+?\s?0?6\s?T\d*\s')
+
+ # split the gcode on tool changes
+ paths = re.split('([mM]+?\s?0?6\s?T\d*\s)', gcode)
+
+ # iterate the gcode sections and add customs for each
+ toolnumber = 0
+
for path in paths:
+
+ # if the section is a tool change, extract the tool number
+ m = p.match(path)
+ if m:
+ toolnumber = int(m.group().split('T')[-1])
+ continue
+
+ # Parse the gcode and throw away any empty lists
gcode = parse(path)
- doc = FreeCAD.getDocument(docname)
- obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "Custom")
- PathScripts.PathCustom.ObjectCustom(obj)
- obj.ViewObject.Proxy = 0
+ if len(gcode) == 0:
+ continue
+
+ # Create a custom and viewobject
+ obj = PathCustom.Create("Custom")
+ res = PathOpGui.CommandResources('Custom', PathCustom.Create, PathCustomGui.TaskPanelOpPage, 'Path-Custom', 'Path-Custom', '', '')
+ obj.ViewObject.Proxy = PathOpGui.ViewProvider(obj.ViewObject, res)
+ obj.ViewObject.Proxy.setDeleteObjectsOnReject(False)
+
+ # Set the gcode and try to match a tool controller
obj.Gcode = gcode
- PathScripts.PathUtils.addToJob(obj)
- obj.ToolController = PathScripts.PathUtils.findToolController(obj)
+ obj.ToolController = matchToolController(obj, toolnumber)
+
FreeCAD.ActiveDocument.recompute()
def parse(inputstring):
"parse(inputstring): returns a parsed output string"
+
+ supported = ['G0', 'G00',
+ 'G1', 'G01',
+ 'G2', 'G02',
+ 'G3', 'G03',
+ 'G81', 'G82', 'G83',
+ 'G90', 'G91']
+
+ axis = ["X", "Y", "Z", "A", "B", "C", "U", "V", "W"]
+
print("preprocessing...")
PathLog.track(inputstring)
# split the input by line
- lines = inputstring.split("\n")
- output = [] #""
- lastcommand = None
+ lines = inputstring.splitlines()
+ output = []
+ lastcommand = None
for lin in lines:
# remove any leftover trailing and preceding spaces
lin = lin.strip()
+
+ # discard empty lines
if not lin:
- # discard empty lines
continue
+
+ # remove line numbers
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
+ # Anything else not a G/M code or an axis move is ignored.
+ if lin[0] not in ["G", "M", "X", "Y", "Z", "A", "B", "C", "U", "V", "W"]:
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"
+
+ # if the remaining line is supported, store it
+ currcommand = lin.split()[0]
+
+ if currcommand in supported:
+ output.append(lin)
+ lastcommand = currcommand
+
+ # modal commands have no G or M but have axis moves. append those too.
+ elif currcommand[0] in axis and lastcommand:
+ output.append(lastcommand + " " + lin)
print("done preprocessing.")
return output
+
print(__name__ + " gcode preprocessor loaded.")