From 0217a2176e5507c75eb939b2a23e731b32cf6903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 14 Apr 2025 20:48:58 +0200 Subject: [PATCH] Fem: make python filter build process more elegant --- cMake/FreeCAD_Helpers/SetupSalomeSMESH.cmake | 6 ++-- src/Mod/Fem/App/FemPostFilterPyImp.cpp | 6 ++-- src/Mod/Fem/App/PropertyPostDataObject.cpp | 19 +++++++++++-- src/Mod/Fem/CMakeLists.txt | 30 ++++++++++++++++++-- src/Mod/Fem/Gui/Workbench.cpp | 5 +++- src/Mod/Fem/ObjectsFem.py | 2 +- src/Mod/Fem/femcommands/commands.py | 6 ++-- src/Mod/Fem/femcommands/manager.py | 17 ++++++++--- 8 files changed, 72 insertions(+), 19 deletions(-) diff --git a/cMake/FreeCAD_Helpers/SetupSalomeSMESH.cmake b/cMake/FreeCAD_Helpers/SetupSalomeSMESH.cmake index 31899c8b3d..978416d088 100644 --- a/cMake/FreeCAD_Helpers/SetupSalomeSMESH.cmake +++ b/cMake/FreeCAD_Helpers/SetupSalomeSMESH.cmake @@ -64,9 +64,11 @@ macro(SetupSalomeSMESH) set(BUILD_FEM_VTK ON) - # check if PythonWrapperCore was found (vtk 9 only) + # Check if PythonWrapperCore was found + # Note: vtk 9 only, as the implementations use the vtk modules introduced in 9.0 + # VTK_WrappingPythonCore_FOUND is named differently for versions <9.0 if (${VTK_WrappingPythonCore_FOUND}) - add_compile_definitions(BUILD_FEM_VTK_WRAPPER) + set(BUILD_FEM_VTK_PYTHON 1) message(STATUS "VTK python wrapper: available") else() message(STATUS "VTK python wrapper: NOT available") diff --git a/src/Mod/Fem/App/FemPostFilterPyImp.cpp b/src/Mod/Fem/App/FemPostFilterPyImp.cpp index 349b3bbaec..479e6d55d2 100644 --- a/src/Mod/Fem/App/FemPostFilterPyImp.cpp +++ b/src/Mod/Fem/App/FemPostFilterPyImp.cpp @@ -35,7 +35,7 @@ #include "FemPostFilterPy.cpp" // clang-format on -#ifdef BUILD_FEM_VTK_WRAPPER +#ifdef FC_USE_VTK_PYTHON #include #include #endif //BUILD_FEM_VTK @@ -54,7 +54,7 @@ std::string FemPostFilterPy::representation() const PyObject* FemPostFilterPy::addFilterPipeline(PyObject* args) { -#ifdef BUILD_FEM_VTK_WRAPPER +#ifdef FC_USE_VTK_PYTHON const char* name; PyObject *source = nullptr; PyObject *target = nullptr; @@ -116,7 +116,7 @@ PyObject* FemPostFilterPy::getParentPostGroup(PyObject* args) PyObject* FemPostFilterPy::getInputData(PyObject* args) { -#ifdef BUILD_FEM_VTK_WRAPPER +#ifdef FC_USE_VTK_PYTHON // we take no arguments if (!PyArg_ParseTuple(args, "")) { return nullptr; diff --git a/src/Mod/Fem/App/PropertyPostDataObject.cpp b/src/Mod/Fem/App/PropertyPostDataObject.cpp index a11a57d58b..302c2dc704 100644 --- a/src/Mod/Fem/App/PropertyPostDataObject.cpp +++ b/src/Mod/Fem/App/PropertyPostDataObject.cpp @@ -42,7 +42,7 @@ #include #endif -#ifdef BUILD_FEM_VTK_WRAPPER +#ifdef FC_USE_VTK_PYTHON #include #endif @@ -166,7 +166,7 @@ int PropertyPostDataObject::getDataType() PyObject* PropertyPostDataObject::getPyObject() { -#ifdef BUILD_FEM_VTK_WRAPPER +#ifdef FC_USE_VTK_PYTHON //create a copy first auto copy = static_cast(Copy()); @@ -182,9 +182,22 @@ PyObject* PropertyPostDataObject::getPyObject() #endif } -void PropertyPostDataObject::setPyObject(PyObject* /*value*/) +void PropertyPostDataObject::setPyObject(PyObject* value) { +#ifdef FC_USE_VTK_PYTHON + vtkObjectBase *obj = vtkPythonUtil::GetPointerFromObject(value, "vtkDataObject"); + if (!obj) { + throw Base::TypeError("Can only set vtkDataObject"); + } + auto dobj = static_cast(obj); + createDataObjectByExternalType(dobj); + + aboutToSetValue(); + m_dataObject->DeepCopy(dobj); + hasSetValue(); +#else throw Base::NotImplementedError(); +#endif } App::Property* PropertyPostDataObject::Copy() const diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 1f7d602b07..42258b391c 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -1,6 +1,12 @@ if(BUILD_FEM_VTK) add_definitions(-DFC_USE_VTK) + + # we may use VTK but do not have the python wrappers available + if(BUILD_FEM_VTK_PYTHON) + add_definitions(-DFC_USE_VTK_PYTHON) + endif(BUILD_FEM_VTK_PYTHON) + endif(BUILD_FEM_VTK) @@ -202,12 +208,18 @@ SET(FemObjects_SRCS femobjects/mesh_netgen.py femobjects/mesh_region.py femobjects/mesh_result.py - femobjects/post_glyphfilter.py femobjects/result_mechanical.py femobjects/solver_calculix.py femobjects/solver_ccxtools.py ) +if(BUILD_FEM_VTK_PYTHON) + SET(FemObjects_SRCS + ${FemObjects_SRCS} + femobjects/post_glyphfilter.py + ) +endif(BUILD_FEM_VTK_PYTHON) + SET(FemResult_SRCS femresult/__init__.py femresult/resulttools.py @@ -605,12 +617,18 @@ SET(FemGuiTaskPanels_SRCS femtaskpanels/task_mesh_group.py femtaskpanels/task_mesh_region.py femtaskpanels/task_mesh_netgen.py - femtaskpanels/task_post_glyphfilter.py femtaskpanels/task_result_mechanical.py femtaskpanels/task_solver_calculix.py femtaskpanels/task_solver_ccxtools.py ) +if(BUILD_FEM_VTK_PYTHON) + SET(FemGuiTaskPanels_SRCS + ${FemGuiTaskPanels_SRCS} + femtaskpanels/task_post_glyphfilter.py + ) +endif(BUILD_FEM_VTK_PYTHON) + SET(FemGuiTests_SRCS femtest/gui/__init__.py femtest/gui/test_open.py @@ -656,12 +674,18 @@ SET(FemGuiViewProvider_SRCS femviewprovider/view_mesh_netgen.py femviewprovider/view_mesh_region.py femviewprovider/view_mesh_result.py - femviewprovider/view_post_glyphfilter.py femviewprovider/view_result_mechanical.py femviewprovider/view_solver_calculix.py femviewprovider/view_solver_ccxtools.py ) +if(BUILD_FEM_VTK_PYTHON) + SET(FemGuiViewProvider_SRCS + ${FemGuiViewProvider_SRCS} + femviewprovider/view_post_glyphfilter.py + ) +endif(BUILD_FEM_VTK_PYTHON) + SET(FemGuiPreferencePages_SRCS fempreferencepages/__init__.py fempreferencepages/dlg_settings_netgen.py diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index 0ed5cc1bc6..3ae3219705 100644 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -206,7 +206,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "FEM_PostFilterCutFunction" << "FEM_PostFilterClipRegion" << "FEM_PostFilterContours" -#ifdef BUILD_FEM_VTK_WRAPPER +#ifdef FC_USE_VTK_PYTHON << "FEM_PostFilterGlyph" #endif << "FEM_PostFilterDataAlongLine" @@ -358,6 +358,9 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "FEM_PostFilterCutFunction" << "FEM_PostFilterClipRegion" << "FEM_PostFilterContours" +#ifdef FC_USE_VTK_PYTHON + << "FEM_PostFilterGlyph" +#endif << "FEM_PostFilterDataAlongLine" << "FEM_PostFilterLinearizedStresses" << "FEM_PostFilterDataAtPoint" diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py index e60c23c521..92ca918d40 100644 --- a/src/Mod/Fem/ObjectsFem.py +++ b/src/Mod/Fem/ObjectsFem.py @@ -652,7 +652,7 @@ def makePostVtkFilterContours(doc, base_vtk_result, name="VtkFilterContours"): base_vtk_result.addObject(obj) return obj -def makePostVtkFilterGlyph(doc, base_vtk_result, name="Glyph"): +def makePostFilterGlyph(doc, base_vtk_result, name="Glyph"): """makePostVtkFilterGlyph(document, [name]): creates a FEM post processing filter that visualizes vector fields with glyphs """ diff --git a/src/Mod/Fem/femcommands/commands.py b/src/Mod/Fem/femcommands/commands.py index 66217b3cf0..5e260f7765 100644 --- a/src/Mod/Fem/femcommands/commands.py +++ b/src/Mod/Fem/femcommands/commands.py @@ -1225,7 +1225,7 @@ class _PostFilterGlyph(CommandManager): self.accel = "F, G" self.tooltip = Qt.QT_TRANSLATE_NOOP("FEM_PostFilterGlyph", "Post processing filter that adds glyphs to the mesh vertices for vertex data visualization") self.is_active = "with_vtk_selresult" - self.do_activated = "add_filter" + self.do_activated = "add_filter_set_edit" # the string in add command will be the page name on FreeCAD wiki @@ -1282,4 +1282,6 @@ FreeCADGui.addCommand("FEM_SolverElmer", _SolverElmer()) FreeCADGui.addCommand("FEM_SolverMystran", _SolverMystran()) FreeCADGui.addCommand("FEM_SolverRun", _SolverRun()) FreeCADGui.addCommand("FEM_SolverZ88", _SolverZ88()) -FreeCADGui.addCommand("FEM_PostFilterGlyph", _PostFilterGlyph()) + +if "BUILD_FEM_VTK_PYTHON" in FreeCAD.__cmake__: + FreeCADGui.addCommand("FEM_PostFilterGlyph", _PostFilterGlyph()) diff --git a/src/Mod/Fem/femcommands/manager.py b/src/Mod/Fem/femcommands/manager.py index 81da4da431..f82301d0c7 100644 --- a/src/Mod/Fem/femcommands/manager.py +++ b/src/Mod/Fem/femcommands/manager.py @@ -148,8 +148,8 @@ class CommandManager: self.add_obj_on_gui_selobj_set_edit(self.__class__.__name__.lstrip("_")) elif self.do_activated == "add_obj_on_gui_selobj_expand_noset_edit": self.add_obj_on_gui_selobj_expand_noset_edit(self.__class__.__name__.lstrip("_")) - elif self.do_activated == "add_filter": - self.add_filter(self.__class__.__name__.lstrip("_")) + elif self.do_activated == "add_filter_set_edit": + self.add_filter_set_edit(self.__class__.__name__.lstrip("_")) # in all other cases Activated is implemented it the command class def results_present(self): @@ -377,7 +377,7 @@ class CommandManager: # expand selobj in tree view expandParentObject() - def add_filter(self, filtertype): + def add_filter_set_edit(self, filtertype): # like add_obj_on_gui_selobj_noset_edit but the selection is kept # and the selobj is expanded in the tree to see the added obj @@ -404,5 +404,14 @@ class CommandManager: "FreeCAD.ActiveDocument.{}.ViewObject.Visibility = False".format(self.selobj.Name) ) - # expand selobj in tree view + # recompute, expand selobj in tree view expandParentObject() + FreeCADGui.doCommand( + "FreeCAD.ActiveDocument.ActiveObject.recompute()" + ) + + # set edit + FreeCADGui.Selection.clearSelection() + FreeCADGui.doCommand( + "FreeCADGui.ActiveDocument.setEdit(FreeCAD.ActiveDocument.ActiveObject.Name)" + )