Skip to content

Commit 6e2ea6f

Browse files
committed
Fem: Export PostObject data to VTK - fixes FreeCAD#5816
1 parent bcf54d3 commit 6e2ea6f

9 files changed

+189
-10
lines changed

src/Mod/Fem/App/CMakeLists.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ endif()
5151

5252

5353
generate_from_xml(FemMeshPy)
54-
generate_from_xml(FemPostPipelinePy)
5554

5655

5756
SET(Python_SRCS
@@ -65,9 +64,13 @@ SET(Python_SRCS
6564
if(BUILD_FEM_VTK)
6665
SET(Python_SRCS
6766
${Python_SRCS}
67+
FemPostObjectPy.xml
68+
FemPostObjectPyImp.cpp
6869
FemPostPipelinePy.xml
6970
FemPostPipelinePyImp.cpp
7071
)
72+
generate_from_xml(FemPostObjectPy)
73+
generate_from_xml(FemPostPipelinePy)
7174
endif(BUILD_FEM_VTK)
7275
SOURCE_GROUP("Python" FILES ${Python_SRCS})
7376

src/Mod/Fem/App/FemPostObject.cpp

+81
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,13 @@
2424

2525
#ifndef _PreComp_
2626
#include <vtkDataSet.h>
27+
#include <vtkXMLDataSetWriter.h>
2728
#endif
2829

30+
#include <Base/Exception.h>
31+
2932
#include "FemPostObject.h"
33+
#include "FemPostObjectPy.h"
3034

3135

3236
using namespace Fem;
@@ -56,3 +60,80 @@ vtkBoundingBox FemPostObject::getBoundingBox()
5660

5761
return box;
5862
}
63+
64+
PyObject* FemPostObject::getPyObject()
65+
{
66+
if (PythonObject.is(Py::_None())) {
67+
// ref counter is set to 1
68+
PythonObject = Py::Object(new FemPostObjectPy(this), true);
69+
}
70+
71+
return Py::new_reference_to(PythonObject);
72+
}
73+
74+
namespace
75+
{
76+
77+
template<typename T>
78+
void vtkWriter(const char* filename, const vtkSmartPointer<vtkDataObject>& dataObject)
79+
{
80+
if (vtkDataSet::SafeDownCast(dataObject)->GetNumberOfPoints() <= 0) {
81+
throw Base::ValueError("Empty data object");
82+
}
83+
84+
vtkSmartPointer<T> writer = vtkSmartPointer<T>::New();
85+
writer->SetFileName(filename);
86+
writer->SetDataModeToBinary();
87+
writer->SetInputDataObject(dataObject);
88+
writer->Write();
89+
}
90+
91+
std::string vtkWriterExtension(const vtkSmartPointer<vtkDataObject>& dataObject)
92+
{
93+
std::string extension;
94+
switch (dataObject->GetDataObjectType()) {
95+
case VTK_POLY_DATA:
96+
extension = "vtp";
97+
break;
98+
case VTK_STRUCTURED_GRID:
99+
extension = "vts";
100+
break;
101+
case VTK_RECTILINEAR_GRID:
102+
extension = "vtr";
103+
break;
104+
case VTK_UNSTRUCTURED_GRID:
105+
extension = "vtu";
106+
break;
107+
case VTK_UNIFORM_GRID:
108+
extension = "vti";
109+
break;
110+
default:
111+
break;
112+
}
113+
114+
return extension;
115+
}
116+
117+
} // namespace
118+
119+
void FemPostObject::writeVTK(const char* filename)
120+
{
121+
const vtkSmartPointer<vtkDataObject>& data = Data.getValue();
122+
123+
// set appropriate filename extension
124+
std::string name(filename);
125+
std::string extension = vtkWriterExtension(data);
126+
if (extension.empty()) {
127+
throw Base::TypeError("Unsupported data type");
128+
}
129+
130+
std::string::size_type pos = name.find_last_of(".");
131+
if (pos != std::string::npos) {
132+
name = name.substr(0, pos + 1).append(extension);
133+
}
134+
else {
135+
name = name.append(".").append(extension);
136+
}
137+
138+
vtkWriter<vtkXMLDataSetWriter>(name.c_str(), data);
139+
}

src/Mod/Fem/App/FemPostObject.h

+3
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ class FemExport FemPostObject: public App::GeoFeature
4545

4646
Fem::PropertyPostDataObject Data;
4747

48+
PyObject* getPyObject() override;
49+
4850
vtkBoundingBox getBoundingBox();
51+
void writeVTK(const char* filename);
4952
};
5053

5154
} // namespace Fem

src/Mod/Fem/App/FemPostObjectPy.xml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
3+
<PythonExport
4+
Father="GeoFeaturePy"
5+
Name="FemPostObjectPy"
6+
Twin="FemPostObject"
7+
TwinPointer="FemPostObject"
8+
Include="Mod/Fem/App/FemPostObject.h"
9+
Namespace="Fem"
10+
FatherInclude="App/GeoFeaturePy.h"
11+
FatherNamespace="App">
12+
<Documentation>
13+
<Author Licence="LGPL" Name="Mario Passaglia" EMail="[email protected]" />
14+
<UserDocu>The FemPostObject class.</UserDocu>
15+
</Documentation>
16+
<Methode Name="writeVTK">
17+
<Documentation>
18+
<UserDocu>writeVTK(filename) -> None
19+
20+
Write data object to VTK file.
21+
22+
filename: str
23+
File extension is automatically detected from data type.</UserDocu>
24+
</Documentation>
25+
</Methode>
26+
27+
</PythonExport>
28+
</GenerateModel>
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-License-Identifier: LGPL-2.1-or-later
2+
3+
/***************************************************************************
4+
* Copyright (c) 2024 Mario Passaglia <mpassaglia[at]cbc.uba.ar> *
5+
* *
6+
* This file is part of FreeCAD. *
7+
* *
8+
* FreeCAD is free software: you can redistribute it and/or modify it *
9+
* under the terms of the GNU Lesser General Public License as *
10+
* published by the Free Software Foundation, either version 2.1 of the *
11+
* License, or (at your option) any later version. *
12+
* *
13+
* FreeCAD is distributed in the hope that it will be useful, but *
14+
* WITHOUT ANY WARRANTY; without even the implied warranty of *
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16+
* Lesser General Public License for more details. *
17+
* *
18+
* You should have received a copy of the GNU Lesser General Public *
19+
* License along with FreeCAD. If not, see *
20+
* <https://www.gnu.org/licenses/>. *
21+
* *
22+
**************************************************************************/
23+
24+
#include "PreCompiled.h"
25+
#ifndef _PreComp_
26+
#include <Python.h>
27+
#endif
28+
29+
#include "FemPostObjectPy.h"
30+
#include "FemPostObjectPy.cpp"
31+
32+
33+
using namespace Fem;
34+
35+
// returns a string which represent the object e.g. when printed in python
36+
std::string FemPostObjectPy::representation() const
37+
{
38+
std::stringstream str;
39+
str << "<FemPostObject object at " << getFemPostObjectPtr() << ">";
40+
41+
return str.str();
42+
}
43+
44+
PyObject* FemPostObjectPy::writeVTK(PyObject* args)
45+
{
46+
char* filename;
47+
if (!PyArg_ParseTuple(args, "et", "utf-8", &filename)) {
48+
return nullptr;
49+
}
50+
51+
std::string utf8Name(filename);
52+
PyMem_Free(filename);
53+
getFemPostObjectPtr()->writeVTK(utf8Name.c_str());
54+
55+
Py_Return;
56+
}
57+
58+
PyObject* FemPostObjectPy::getCustomAttributes(const char* /*attr*/) const
59+
{
60+
return nullptr;
61+
}
62+
63+
int FemPostObjectPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
64+
{
65+
return 0;
66+
}

src/Mod/Fem/App/FemPostPipelinePy.xml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
33
<PythonExport
4-
Father="GeoFeaturePy"
4+
Father="FemPostObjectPy"
55
Name="FemPostPipelinePy"
66
Twin="FemPostPipeline"
77
TwinPointer="FemPostPipeline"
88
Include="Mod/Fem/App/FemPostPipeline.h"
99
Namespace="Fem"
10-
FatherInclude="App/GeoFeaturePy.h"
11-
FatherNamespace="App">
10+
FatherInclude="Mod/Fem/App/FemPostObjectPy.h"
11+
FatherNamespace="Fem">
1212
<Documentation>
1313
<Author Licence="LGPL" Name="Werner Mayer" EMail="[email protected]" />
1414
<UserDocu>The FemPostPipeline class.</UserDocu>

src/Mod/Fem/Gui/ViewProviderFemConstraintPy.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
FatherInclude="Gui/ViewProviderDocumentObjectPy.h"
1111
FatherNamespace="Gui">
1212
<Documentation>
13-
<Author Licence="LGPL" Name="Mario Passaglia" EMail="mpassaglia@cbc.ub.ar" />
13+
<Author Licence="LGPL" Name="Mario Passaglia" EMail="mpassaglia@cbc.uba.ar" />
1414
<UserDocu>This is the ViewProviderFemConstraint class</UserDocu>
1515
</Documentation>
1616
<Attribute Name="SymbolNode" ReadOnly="true">

src/Mod/Fem/Init.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,4 @@
9090

9191
if "BUILD_FEM_VTK" in FreeCAD.__cmake__:
9292
FreeCAD.addImportType("FEM result VTK (*.vtk *.VTK *.vtu *.VTU *.pvtu *.PVTU)", "feminout.importVTKResults")
93-
FreeCAD.addExportType("FEM result VTK (*.vtk *.vtu)", "feminout.importVTKResults")
93+
FreeCAD.addExportType("FEM result VTK (*.vtu *.vtp *.vts *.vtr *.vti)", "feminout.importVTKResults")

src/Mod/Fem/feminout/importVTKResults.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,8 @@ def export(
7575
return
7676

7777
obj = objectslist[0]
78-
if obj.isDerivedFrom("Fem::FemPostPipeline"):
79-
Console.PrintError(
80-
"Export of a VTK post object to vtk is not yet implemented!\n"
81-
)
78+
if obj.isDerivedFrom("Fem::FemPostObject"):
79+
obj.writeVTK(filename)
8280
return
8381
elif obj.isDerivedFrom("Fem::FemMeshObject"):
8482
Console.PrintError(

0 commit comments

Comments
 (0)