diff --git a/src/App/GroupExtension.pyi b/src/App/GroupExtension.pyi index 8d50bc416b..d5d66a924b 100644 --- a/src/App/GroupExtension.pyi +++ b/src/App/GroupExtension.pyi @@ -61,6 +61,13 @@ class GroupExtension(DocumentObjectExtension): """ ... + def getObjectsOfType(self, typename: str) -> List[Any]: + """ + Returns all object in the group of given type + @param typename The Freecad type identifier + """ + ... + def hasObject(self, obj: Any, recursive: bool = False) -> bool: """ hasObject(obj, recursive=false) diff --git a/src/App/GroupExtensionPyImp.cpp b/src/App/GroupExtensionPyImp.cpp index fc281215d8..72e2eacc80 100644 --- a/src/App/GroupExtensionPyImp.cpp +++ b/src/App/GroupExtensionPyImp.cpp @@ -278,6 +278,22 @@ PyObject* GroupExtensionPy::getObject(PyObject* args) } } +PyObject* GroupExtensionPy::getObjectsOfType(PyObject* args) +{ + char* pcName; + if (!PyArg_ParseTuple(args, "s", &pcName)) { + return nullptr; + } + + std::vector objs = getGroupExtensionPtr()->getObjectsOfType(Base::Type::fromName(pcName)); + Py::List result; + for (App::DocumentObject* obj : objs) { + result.append(Py::asObject(obj->getPyObject())); + } + + return Py::new_reference_to(result); +} + PyObject* GroupExtensionPy::hasObject(PyObject* args) { PyObject* object; diff --git a/src/Mod/Fem/App/FemPostGroupExtension.cpp b/src/Mod/Fem/App/FemPostGroupExtension.cpp index 5ecad291be..d7f8771c97 100644 --- a/src/Mod/Fem/App/FemPostGroupExtension.cpp +++ b/src/Mod/Fem/App/FemPostGroupExtension.cpp @@ -109,11 +109,8 @@ App::DocumentObject* FemPostGroupExtension::getGroupOfObject(const App::Document void FemPostGroupExtension::onExtendedUnsetupObject() { - // remove all children! - auto document = getExtendedObject()->getDocument(); - for (const auto& obj : Group.getValues()) { - document->removeObject(obj->getNameInDocument()); - } + // remove all children (if not already removed)! + removeObjectsFromDocument(); } bool FemPostGroupExtension::allowObject(App::DocumentObject* obj) diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp index a78af62cd7..2a14b7a47c 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp @@ -58,9 +58,10 @@ void ViewProviderFemPostPipeline::updateData(const App::Property* prop) FemGui::ViewProviderFemPostObject::updateData(prop); Fem::FemPostPipeline* pipeline = getObject(); - if ((prop == &pipeline->Data) || (prop == &pipeline->Group)) { + if ((prop == &pipeline->Data) || (prop == &pipeline->Group) || (prop == &pipeline->Frame)) { updateFunctionSize(); + updateColorBars(); } } @@ -150,7 +151,7 @@ void ViewProviderFemPostPipeline::updateColorBars() } // if pipeline is visible, update it - if (this->isVisible()) { + if (this->Visibility.getValue()) { updateMaterial(); } } diff --git a/src/Mod/Fem/femcommands/commands.py b/src/Mod/Fem/femcommands/commands.py index 7618b13f76..8e4d08039f 100644 --- a/src/Mod/Fem/femcommands/commands.py +++ b/src/Mod/Fem/femcommands/commands.py @@ -926,7 +926,9 @@ class _ResultsPurge(CommandManager): def Activated(self): import femresult.resulttools as resulttools + FreeCAD.ActiveDocument.openTransaction("Purge FEM results") resulttools.purge_results(self.active_analysis) + FreeCAD.ActiveDocument.commitTransaction() class _SolverCalculixContextManager: diff --git a/src/Mod/Fem/feminout/importCcxFrdResults.py b/src/Mod/Fem/feminout/importCcxFrdResults.py index 32735e28ff..f833887f16 100644 --- a/src/Mod/Fem/feminout/importCcxFrdResults.py +++ b/src/Mod/Fem/feminout/importCcxFrdResults.py @@ -66,21 +66,33 @@ def setupPipeline(doc, analysis, results_name, result_data): if not "BUILD_FEM_VTK" in FreeCAD.__cmake__: return - # create a results pipeline if not already existing + # create a results pipeline (dependend on user settings) pipeline_name = "Pipeline_" + results_name - pipeline_obj = doc.getObject(pipeline_name) - if pipeline_obj is None: + pipelines = analysis.getObjectsOfType("Fem::FemPostPipeline") + fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General") + keep_results_on_rerun = fem_prefs.GetBool("KeepResultsOnReRun", False) + if not pipelines or keep_results_on_rerun: + # needs to create a new pipeline! pipeline_obj = ObjectsFem.makePostVtkResult(doc, result_data, results_name) pipeline_visibility = True if analysis: analysis.addObject(pipeline_obj) else: + # by default get the last one + pipeline_obj = pipelines[-1] + # maybe there is one with the correct name + named_pipeline = analysis.getObject(pipeline_name) + if named_pipeline: + pipeline_obj = named_pipeline + if FreeCAD.GuiUp: # store pipeline visibility because pipeline_obj.load makes the # pipeline always visible pipeline_visibility = pipeline_obj.ViewObject.Visibility + # relabel the pipeline and load the data into it + pipeline_obj.Label = pipeline_name pipeline_obj.load(*result_data) # update the pipeline diff --git a/src/Mod/Fem/femobjects/base_fempostvisualizations.py b/src/Mod/Fem/femobjects/base_fempostvisualizations.py index 5c7465d5bc..49797971d5 100644 --- a/src/Mod/Fem/femobjects/base_fempostvisualizations.py +++ b/src/Mod/Fem/femobjects/base_fempostvisualizations.py @@ -80,6 +80,7 @@ class PostVisualization(base_fempythonobject.BaseFemPythonObject): def __init__(self, obj): super().__init__(obj) + self.Type = "Fem::FemPostVisualization" obj.addExtension("App::GroupExtensionPython") self._setup_properties(obj) diff --git a/src/Mod/Fem/femresult/resulttools.py b/src/Mod/Fem/femresult/resulttools.py index 4b4bb2d39e..d434a64396 100644 --- a/src/Mod/Fem/femresult/resulttools.py +++ b/src/Mod/Fem/femresult/resulttools.py @@ -34,7 +34,7 @@ import FreeCAD from femtools.femutils import is_of_type -def purge_results(analysis): +def purge_result_objects(analysis): """Removes all result objects and result meshes from an analysis group. Parameters @@ -43,11 +43,6 @@ def purge_results(analysis): analysis group as a container for all objects needed for the analysis """ - # if analysis type check is used, result mesh - # without result obj is created in the analysis - # we could run into trouble in one loop because - # we will delete objects and try to access them later - # result object for m in analysis.Group: if m.isDerivedFrom("Fem::FemResultObject"): @@ -68,6 +63,16 @@ def purge_results(analysis): analysis.Document.removeObject(m.Name) analysis.Document.recompute() + +def purge_postprocessing_objects(analysis): + """Removes all postprocessing objects and visualizations form the analysis + + Parameters + ---------- + analysis : Fem::FemAnalysis + analysis group as a container for all objects needed for the analysis + """ + # result pipeline and filter for m in analysis.Group: if is_of_type(m, "Fem::FemPostPipeline"): @@ -75,6 +80,30 @@ def purge_results(analysis): analysis.Document.removeObject(m.Name) analysis.Document.recompute() + # remove visulizations + for m in analysis.Group: + if is_of_type(m, "Fem::FemPostVisualization"): + analysis.Document.removeObject(m.Name) + analysis.Document.recompute() + + +def purge_results(analysis): + """Removes all result and postprocessing objects and result meshes from an analysis group. + + Parameters + ---------- + analysis : Fem::FemAnalysis + analysis group as a container for all objects needed for the analysis + """ + + # if analysis type check is used, result mesh + # without result obj is created in the analysis + # we could run into trouble in one loop because + # we will delete objects and try to access them later + + purge_result_objects(analysis) + purge_postprocessing_objects(analysis) + def reset_mesh_deformation(resultobj): """Resets result mesh deformation. diff --git a/src/Mod/Fem/femtools/ccxtools.py b/src/Mod/Fem/femtools/ccxtools.py index 9589db4a6b..311ae865a6 100644 --- a/src/Mod/Fem/femtools/ccxtools.py +++ b/src/Mod/Fem/femtools/ccxtools.py @@ -162,7 +162,12 @@ class FemToolsCcx(QtCore.QRunnable, QtCore.QObject): self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General") keep_results_on_rerun = self.fem_prefs.GetBool("KeepResultsOnReRun", False) if not keep_results_on_rerun: - self.purge_results() + # we remove the result objects only, not the postprocessing ones. + # Reason: "Not keep results" means for the user override the data. For postprocessing + # this means keeping all filters, just change the data. + from femresult.resulttools import purge_result_objects as purge + + purge(self.analysis) def reset_all(self): """Reset mesh color, deformation and removes all result objects"""