diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index cb7c5f5a59..dd9250a00c 100644 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -51,7 +51,6 @@ endif() generate_from_xml(FemMeshPy) -generate_from_xml(FemPostPipelinePy) SET(Python_SRCS @@ -65,9 +64,13 @@ SET(Python_SRCS if(BUILD_FEM_VTK) SET(Python_SRCS ${Python_SRCS} + FemPostObjectPy.xml + FemPostObjectPyImp.cpp FemPostPipelinePy.xml FemPostPipelinePyImp.cpp ) + generate_from_xml(FemPostObjectPy) + generate_from_xml(FemPostPipelinePy) endif(BUILD_FEM_VTK) SOURCE_GROUP("Python" FILES ${Python_SRCS}) diff --git a/src/Mod/Fem/App/FemPostObject.cpp b/src/Mod/Fem/App/FemPostObject.cpp index afb7ff4953..1312514587 100644 --- a/src/Mod/Fem/App/FemPostObject.cpp +++ b/src/Mod/Fem/App/FemPostObject.cpp @@ -24,9 +24,13 @@ #ifndef _PreComp_ #include +#include #endif +#include + #include "FemPostObject.h" +#include "FemPostObjectPy.h" using namespace Fem; @@ -56,3 +60,80 @@ vtkBoundingBox FemPostObject::getBoundingBox() return box; } + +PyObject* FemPostObject::getPyObject() +{ + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new FemPostObjectPy(this), true); + } + + return Py::new_reference_to(PythonObject); +} + +namespace +{ + +template +void vtkWriter(const char* filename, const vtkSmartPointer& dataObject) +{ + if (vtkDataSet::SafeDownCast(dataObject)->GetNumberOfPoints() <= 0) { + throw Base::ValueError("Empty data object"); + } + + vtkSmartPointer writer = vtkSmartPointer::New(); + writer->SetFileName(filename); + writer->SetDataModeToBinary(); + writer->SetInputDataObject(dataObject); + writer->Write(); +} + +std::string vtkWriterExtension(const vtkSmartPointer& dataObject) +{ + std::string extension; + switch (dataObject->GetDataObjectType()) { + case VTK_POLY_DATA: + extension = "vtp"; + break; + case VTK_STRUCTURED_GRID: + extension = "vts"; + break; + case VTK_RECTILINEAR_GRID: + extension = "vtr"; + break; + case VTK_UNSTRUCTURED_GRID: + extension = "vtu"; + break; + case VTK_UNIFORM_GRID: + extension = "vti"; + break; + default: + break; + } + + return extension; +} + +} // namespace + +void FemPostObject::writeVTK(const char* filename) +{ + const vtkSmartPointer& data = Data.getValue(); + + // set appropriate filename extension + std::string name(filename); + std::string extension = vtkWriterExtension(data); + if (extension.empty()) { + throw Base::TypeError("Unsupported data type"); + } + + std::string::size_type pos = name.find_last_of("."); + if (pos != std::string::npos) { + name = name.substr(0, pos + 1).append(extension); + } + else { + name = name.append(".").append(extension); + } + + vtkWriter(name.c_str(), data); +} diff --git a/src/Mod/Fem/App/FemPostObject.h b/src/Mod/Fem/App/FemPostObject.h index 4f0c840436..3ef13d1319 100644 --- a/src/Mod/Fem/App/FemPostObject.h +++ b/src/Mod/Fem/App/FemPostObject.h @@ -45,7 +45,10 @@ public: Fem::PropertyPostDataObject Data; + PyObject* getPyObject() override; + vtkBoundingBox getBoundingBox(); + void writeVTK(const char* filename); }; } // namespace Fem diff --git a/src/Mod/Fem/App/FemPostObjectPy.xml b/src/Mod/Fem/App/FemPostObjectPy.xml new file mode 100644 index 0000000000..cc4d4dacef --- /dev/null +++ b/src/Mod/Fem/App/FemPostObjectPy.xml @@ -0,0 +1,28 @@ + + + + + + The FemPostObject class. + + + + writeVTK(filename) -> None + +Write data object to VTK file. + +filename: str + File extension is automatically detected from data type. + + + + + diff --git a/src/Mod/Fem/App/FemPostObjectPyImp.cpp b/src/Mod/Fem/App/FemPostObjectPyImp.cpp new file mode 100644 index 0000000000..81ee5119ac --- /dev/null +++ b/src/Mod/Fem/App/FemPostObjectPyImp.cpp @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2024 Mario Passaglia * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#endif + +#include "FemPostObjectPy.h" +#include "FemPostObjectPy.cpp" + + +using namespace Fem; + +// returns a string which represent the object e.g. when printed in python +std::string FemPostObjectPy::representation() const +{ + std::stringstream str; + str << ""; + + return str.str(); +} + +PyObject* FemPostObjectPy::writeVTK(PyObject* args) +{ + char* filename; + if (!PyArg_ParseTuple(args, "et", "utf-8", &filename)) { + return nullptr; + } + + std::string utf8Name(filename); + PyMem_Free(filename); + getFemPostObjectPtr()->writeVTK(utf8Name.c_str()); + + Py_Return; +} + +PyObject* FemPostObjectPy::getCustomAttributes(const char* /*attr*/) const +{ + return nullptr; +} + +int FemPostObjectPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} diff --git a/src/Mod/Fem/App/FemPostPipelinePy.xml b/src/Mod/Fem/App/FemPostPipelinePy.xml index 70aa69a4cc..3b84e84d75 100644 --- a/src/Mod/Fem/App/FemPostPipelinePy.xml +++ b/src/Mod/Fem/App/FemPostPipelinePy.xml @@ -1,14 +1,14 @@ + FatherInclude="Mod/Fem/App/FemPostObjectPy.h" + FatherNamespace="Fem"> The FemPostPipeline class. diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintPy.xml b/src/Mod/Fem/Gui/ViewProviderFemConstraintPy.xml index 0c3a40bbf3..9051a61062 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintPy.xml +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintPy.xml @@ -10,7 +10,7 @@ FatherInclude="Gui/ViewProviderDocumentObjectPy.h" FatherNamespace="Gui"> - + This is the ViewProviderFemConstraint class diff --git a/src/Mod/Fem/Init.py b/src/Mod/Fem/Init.py index e5d9366a04..e2d422c2ca 100644 --- a/src/Mod/Fem/Init.py +++ b/src/Mod/Fem/Init.py @@ -90,4 +90,4 @@ FreeCAD.addImportType("FEM result Z88 displacements (*o2.txt *O2.TXT)", "feminou if "BUILD_FEM_VTK" in FreeCAD.__cmake__: FreeCAD.addImportType("FEM result VTK (*.vtk *.VTK *.vtu *.VTU *.pvtu *.PVTU)", "feminout.importVTKResults") - FreeCAD.addExportType("FEM result VTK (*.vtk *.vtu)", "feminout.importVTKResults") + FreeCAD.addExportType("FEM result VTK (*.vtu *.vtp *.vts *.vtr *.vti)", "feminout.importVTKResults") diff --git a/src/Mod/Fem/feminout/importVTKResults.py b/src/Mod/Fem/feminout/importVTKResults.py index 73709d9a7e..7b1ca8be34 100644 --- a/src/Mod/Fem/feminout/importVTKResults.py +++ b/src/Mod/Fem/feminout/importVTKResults.py @@ -75,10 +75,8 @@ def export( return obj = objectslist[0] - if obj.isDerivedFrom("Fem::FemPostPipeline"): - Console.PrintError( - "Export of a VTK post object to vtk is not yet implemented!\n" - ) + if obj.isDerivedFrom("Fem::FemPostObject"): + obj.writeVTK(filename) return elif obj.isDerivedFrom("Fem::FemMeshObject"): Console.PrintError(