CAM: Post Process only selected Operations
This commit is contained in:
@@ -39,6 +39,7 @@
|
||||
<file>icons/CAM_OperationB.svg</file>
|
||||
<file>icons/CAM_Pocket.svg</file>
|
||||
<file>icons/CAM_Post.svg</file>
|
||||
<file>icons/CAM_PostSelected.svg</file>
|
||||
<file>icons/CAM_Probe.svg</file>
|
||||
<file>icons/CAM_Profile_Edges.svg</file>
|
||||
<file>icons/CAM_Profile_Face.svg</file>
|
||||
|
||||
1195
src/Mod/CAM/Gui/Resources/icons/CAM_PostSelected.svg
Normal file
1195
src/Mod/CAM/Gui/Resources/icons/CAM_PostSelected.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 38 KiB |
@@ -124,7 +124,8 @@ class CAMWorkbench(Workbench):
|
||||
Path.GuiInit.Startup()
|
||||
|
||||
# build commands list
|
||||
projcmdlist = ["CAM_Job", "CAM_Post", "CAM_Sanity"]
|
||||
projcmdlist = ["CAM_Job", "CAM_Sanity"]
|
||||
postcmdlist = ["CAM_Post", "CAM_PostSelected"]
|
||||
toolcmdlist = ["CAM_Inspect", "CAM_SelectLoop", "CAM_OpActiveToggle"]
|
||||
|
||||
simcmdlist = ["CAM_SimulatorGL", "CAM_Simulator"]
|
||||
@@ -168,6 +169,14 @@ class CAMWorkbench(Workbench):
|
||||
toolcmdlist.extend(PathToolBitLibraryCmd.BarList)
|
||||
toolbitcmdlist = PathToolBitLibraryCmd.MenuList
|
||||
|
||||
postcmdgroup = ["CAM_PostTools"]
|
||||
FreeCADGui.addCommand(
|
||||
"CAM_PostTools",
|
||||
PathCommandGroup(
|
||||
postcmdlist,
|
||||
QT_TRANSLATE_NOOP("CAM_PostTools", "Post process Operations"),
|
||||
),
|
||||
)
|
||||
simcmdgroup = ["CAM_SimTools"]
|
||||
FreeCADGui.addCommand(
|
||||
"CAM_SimTools",
|
||||
@@ -253,7 +262,10 @@ class CAMWorkbench(Workbench):
|
||||
if not Path.Preferences.suppressOpenCamLibWarning():
|
||||
FreeCAD.Console.PrintError("OpenCamLib is not working!\n")
|
||||
|
||||
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "Project Setup"), projcmdlist)
|
||||
self.appendToolbar(
|
||||
QT_TRANSLATE_NOOP("Workbench", "Project Setup"),
|
||||
projcmdlist + postcmdgroup,
|
||||
)
|
||||
self.appendToolbar(
|
||||
QT_TRANSLATE_NOOP("Workbench", "Tool Commands"),
|
||||
simcmdgroup + toolcmdlist,
|
||||
@@ -271,6 +283,7 @@ class CAMWorkbench(Workbench):
|
||||
self.appendMenu(
|
||||
[QT_TRANSLATE_NOOP("Workbench", "&CAM")],
|
||||
projcmdlist
|
||||
+ postcmdlist
|
||||
+ ["CAM_ExportTemplate", "Separator"]
|
||||
+ simcmdlist
|
||||
+ toolcmdlist
|
||||
@@ -356,16 +369,17 @@ class CAMWorkbench(Workbench):
|
||||
import PathScripts
|
||||
|
||||
menuAppended = False
|
||||
if len(FreeCADGui.Selection.getSelection()) == 1:
|
||||
obj = FreeCADGui.Selection.getSelection()[0]
|
||||
selection = FreeCADGui.Selection.getSelection()
|
||||
if len(selection) == 1:
|
||||
obj = selection[0]
|
||||
selectedName = obj.Name
|
||||
if obj.isDerivedFrom("Path::Feature"):
|
||||
self.appendContextMenu("", "Separator")
|
||||
self.appendContextMenu("", ["CAM_Inspect"])
|
||||
selectedName = obj.Name
|
||||
if "Remote" in selectedName:
|
||||
self.appendContextMenu("", ["Refresh_Path"])
|
||||
if "Job" in selectedName:
|
||||
self.appendContextMenu("", ["CAM_ExportTemplate"] + self.toolbitctxmenu)
|
||||
self.appendContextMenu("", ["CAM_ExportTemplate"])
|
||||
menuAppended = True
|
||||
if isinstance(obj.Proxy, Path.Op.Base.ObjectOp):
|
||||
self.appendContextMenu("", ["CAM_OperationCopy", "CAM_OpActiveToggle"])
|
||||
@@ -388,6 +402,14 @@ class CAMWorkbench(Workbench):
|
||||
if isinstance(obj.Proxy, Path.Tool.ToolBit):
|
||||
self.appendContextMenu("", ["CAM_ToolBitSave", "CAM_ToolBitSaveAs"])
|
||||
menuAppended = True
|
||||
|
||||
if selection:
|
||||
for obj in selection:
|
||||
if not obj.isDerivedFrom("Path::Feature"):
|
||||
break
|
||||
else:
|
||||
self.appendContextMenu("", ["CAM_Post", "CAM_PostSelected"])
|
||||
|
||||
if menuAppended:
|
||||
self.appendContextMenu("", "Separator")
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ class JobPreferencesPage:
|
||||
self.form.stockCreateCylinder.hide()
|
||||
|
||||
def getPostProcessor(self, name):
|
||||
if not name in self.processor:
|
||||
if name not in self.processor:
|
||||
processor = PostProcessorFactory.get_post_processor(None, name)
|
||||
self.processor[name] = processor
|
||||
return processor
|
||||
|
||||
@@ -61,8 +61,7 @@ def _resolve_post_processor_name(job):
|
||||
|
||||
if valid_name and PostProcessor.exists(valid_name):
|
||||
return valid_name
|
||||
else:
|
||||
raise ValueError(f"Post processor not identified.")
|
||||
raise ValueError("Post processor not identified.")
|
||||
|
||||
|
||||
class DlgSelectPostProcessor:
|
||||
@@ -109,16 +108,15 @@ class CommandPathPost:
|
||||
"Pixmap": "CAM_Post",
|
||||
"MenuText": QT_TRANSLATE_NOOP("CAM_Post", "Post Process"),
|
||||
"Accel": "P, P",
|
||||
"ToolTip": QT_TRANSLATE_NOOP("CAM_Post", "Post Processes the selected job"),
|
||||
"ToolTip": QT_TRANSLATE_NOOP("CAM_Post", "Post Processes the selected Job"),
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
selected = FreeCADGui.Selection.getSelectionEx()
|
||||
if len(selected) != 1:
|
||||
selection = FreeCADGui.Selection.getSelection()
|
||||
if not selection:
|
||||
return False
|
||||
|
||||
selected_object = selected[0].Object
|
||||
self.candidate = PathUtils.findParentJob(selected_object)
|
||||
self.candidate = PathUtils.findParentJob(selection[0])
|
||||
|
||||
return self.candidate is not None
|
||||
|
||||
@@ -212,7 +210,10 @@ class CommandPathPost:
|
||||
return
|
||||
|
||||
# get a postprocessor
|
||||
postprocessor = PostProcessorFactory.get_post_processor(self.candidate, postprocessor_name)
|
||||
postprocessor = PostProcessorFactory.get_post_processor(
|
||||
self.candidate,
|
||||
postprocessor_name,
|
||||
)
|
||||
|
||||
post_data = postprocessor.export()
|
||||
# None is returned if there was an error during argument processing
|
||||
@@ -259,8 +260,105 @@ class CommandPathPost:
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
class CommandPathPostSelected(CommandPathPost):
|
||||
def GetResources(self):
|
||||
return {
|
||||
"Pixmap": "CAM_PostSelected",
|
||||
"MenuText": QT_TRANSLATE_NOOP("CAM_Post", "Post Process Selected"),
|
||||
"Accel": "P, O",
|
||||
"ToolTip": QT_TRANSLATE_NOOP("CAM_Post", "Post Processes the selected operations"),
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
selection = FreeCADGui.Selection.getSelection()
|
||||
if not selection:
|
||||
return False
|
||||
|
||||
return all(hasattr(op, "Path") and not op.Name.startswith("Job") for op in selection)
|
||||
|
||||
def Activated(self):
|
||||
"""
|
||||
Handles the activation of post processing, initiating the process based
|
||||
on user selection and document context.
|
||||
"""
|
||||
FreeCAD.ActiveDocument.openTransaction("Post Process the Selected operations")
|
||||
|
||||
selection = FreeCADGui.Selection.getSelection()
|
||||
job = PathUtils.findParentJob(selection[0])
|
||||
if (
|
||||
not job
|
||||
and hasattr(selection[0], "Base")
|
||||
and isinstance(selection[0].Base, list)
|
||||
and selection[0].Base
|
||||
):
|
||||
# find 'job' for operation inside 'Array' with multi tool controller
|
||||
baseOp = FreeCAD.ActiveDocument.getObject(selection[0].Base[0])
|
||||
job = PathUtils.findParentJob(baseOp)
|
||||
|
||||
opCandidates = [op for op in selection if hasattr(op, "Path") and "Job" not in op.Name]
|
||||
operations = []
|
||||
if opCandidates and job.Operations.Group != opCandidates:
|
||||
msgBox = QtGui.QMessageBox()
|
||||
msgBox.setWindowTitle("Post Process")
|
||||
msgBox.setText("<p align='center'>What needs to be exported?</p>")
|
||||
msgBox.setInformativeText(
|
||||
"<p align='center'>Check to make sure that you won't break anything by leaving out operations</p>"
|
||||
)
|
||||
msgBox.findChild(QtGui.QGridLayout).setColumnMinimumWidth(1, 250)
|
||||
btn1 = msgBox.addButton("Only selected", QtGui.QMessageBox.ButtonRole.YesRole)
|
||||
btn2 = msgBox.addButton("All", QtGui.QMessageBox.ButtonRole.NoRole)
|
||||
msgBox.setDefaultButton(btn2)
|
||||
msgBox.exec()
|
||||
|
||||
if msgBox.clickedButton() == btn1:
|
||||
print(
|
||||
f"Post process only selected operations: {', '.join([op.Name for op in opCandidates])}"
|
||||
)
|
||||
operations = opCandidates
|
||||
|
||||
postprocessor_name = _resolve_post_processor_name(job)
|
||||
Path.Log.debug(f"Post Processor: {postprocessor_name}")
|
||||
|
||||
if not postprocessor_name:
|
||||
FreeCAD.ActiveDocument.abortTransaction()
|
||||
return
|
||||
|
||||
# get a postprocessor
|
||||
postprocessor = PostProcessorFactory.get_post_processor(
|
||||
{"job": job, "operations": operations}, postprocessor_name
|
||||
)
|
||||
|
||||
post_data = postprocessor.export()
|
||||
# None is returned if there was an error during argument processing
|
||||
# otherwise the "usual" post_data data structure is returned.
|
||||
if not post_data:
|
||||
FreeCAD.ActiveDocument.abortTransaction()
|
||||
return
|
||||
|
||||
policy = Path.Preferences.defaultOutputPolicy()
|
||||
generator = FilenameGenerator(job=job)
|
||||
generated_filename = generator.generate_filenames()
|
||||
|
||||
for item in post_data:
|
||||
subpart, gcode = item
|
||||
|
||||
# get a name for the file
|
||||
subpart = "" if subpart == "allitems" else subpart
|
||||
Path.Log.debug(subpart)
|
||||
generator.set_subpartname(subpart)
|
||||
fname = next(generated_filename)
|
||||
|
||||
if gcode is not None:
|
||||
# write the results to the file
|
||||
self._write_file(fname, gcode, policy)
|
||||
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand("CAM_Post", CommandPathPost())
|
||||
FreeCADGui.addCommand("CAM_PostSelected", CommandPathPostSelected())
|
||||
|
||||
FreeCAD.Console.PrintLog("Loading PathPost… done\n")
|
||||
|
||||
@@ -116,6 +116,8 @@ class PostProcessorFactory:
|
||||
Path.Log.debug(f"Post processor {postname} is a script")
|
||||
return WrapperPost(job, module_path, module_name)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def needsTcOp(oldTc, newTc):
|
||||
return (
|
||||
@@ -133,11 +135,19 @@ class PostProcessor:
|
||||
self._tooltip = tooltip
|
||||
self._tooltipargs = tooltipargs
|
||||
self._units = units
|
||||
self._job = job
|
||||
self._args = args
|
||||
self._kwargs = kwargs
|
||||
self.reinitialize()
|
||||
|
||||
if isinstance(job, dict):
|
||||
# process only selected operations
|
||||
self._job = job["job"]
|
||||
self._operations = job["operations"]
|
||||
else:
|
||||
# get all operations from 'Operations' group
|
||||
self._job = job
|
||||
self._operations = getattr(job.Operations, "Group", [])
|
||||
|
||||
@classmethod
|
||||
def exists(cls, processor):
|
||||
return processor in Path.Preferences.allAvailablePostProcessors()
|
||||
@@ -203,7 +213,7 @@ class PostProcessor:
|
||||
sublist = [__fixtureSetup(index, f, self._job)]
|
||||
|
||||
# Now generate the gcode
|
||||
for obj in self._job.Operations.Group:
|
||||
for obj in self._operations:
|
||||
tc = PathUtil.toolControllerForOp(obj)
|
||||
if tc is not None and PathUtil.activeForOp(obj):
|
||||
if needsTcOp(currTc, tc):
|
||||
@@ -240,7 +250,7 @@ class PostProcessor:
|
||||
postlist.append((toolstring, sublist))
|
||||
|
||||
Path.Log.track(self._job.PostProcessorOutputFile)
|
||||
for idx, obj in enumerate(self._job.Operations.Group):
|
||||
for idx, obj in enumerate(self._operations):
|
||||
Path.Log.track(obj.Label)
|
||||
|
||||
# check if the operation is active
|
||||
@@ -286,7 +296,7 @@ class PostProcessor:
|
||||
currTc = None
|
||||
|
||||
# Now generate the gcode
|
||||
for obj in self._job.Operations.Group:
|
||||
for obj in self._operations:
|
||||
|
||||
# check if the operation is active
|
||||
if not PathUtil.activeForOp(obj):
|
||||
|
||||
Reference in New Issue
Block a user