diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 219ae4ebb1..9120c2fd65 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -46,11 +46,14 @@ set(FemGui_LIBS generate_from_xml(ViewProviderFemMeshPy) +generate_from_xml(ViewProviderFemPostPipelinePy) SET(Python_SRCS ViewProviderFemMeshPy.xml ViewProviderFemMeshPyImp.cpp + ViewProviderFemPostPipelinePy.xml + ViewProviderFemPostPipelinePyImp.cpp ) SOURCE_GROUP("Python" FILES ${Python_SRCS}) diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp index ee4ba1dd73..e166f60375 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp @@ -22,14 +22,20 @@ #include "PreCompiled.h" +#ifndef _PreComp_ +#include +#endif + +#include #include #include #include #include #include -#include "ViewProviderAnalysis.h" #include "ViewProviderFemPostPipeline.h" +#include "ViewProviderFemPostPipelinePy.h" +#include "ViewProviderAnalysis.h" #include "ViewProviderFemPostFunction.h" @@ -122,3 +128,69 @@ void ViewProviderFemPostPipeline::onSelectionChanged(const Gui::SelectionChanges } } } + +void ViewProviderFemPostPipeline::transformField(char *FieldName, double FieldFactor) +{ + Fem::FemPostPipeline *obj = static_cast(getObject()); + + vtkSmartPointer data = obj->Data.getValue(); + if (!data || !data->IsA("vtkDataSet")) + return; + + vtkDataSet *dset = vtkDataSet::SafeDownCast(data); + vtkDataArray *pdata = dset->GetPointData()->GetArray(FieldName); + if (!pdata) + return; + + auto strFieldName = std::string(FieldName); + + // for EigenModes, we need to step through all available modes + if (strFieldName.find("EigenMode") != std::string::npos) { + int modeCount; + std::string testFieldName; + // since a valid FieldName must have been passed + // we assume the mode number was < 10 and we can strip the last char + strFieldName.pop_back(); + for (modeCount = 1; pdata; ++modeCount) { + testFieldName = strFieldName + std::to_string(modeCount); + pdata = dset->GetPointData()->GetArray(testFieldName.c_str()); + if (pdata) { + scaleField(dset, pdata, FieldFactor); + } + } + } + else + scaleField(dset, pdata, FieldFactor); +} + +void ViewProviderFemPostPipeline::scaleField(vtkDataSet *dset, vtkDataArray *pdata, double FieldFactor) +{ + //safe guard + if (!dset || !pdata) + return; + + // step through all mesh points and scale them + for (int i = 0; i < dset->GetNumberOfPoints(); ++i) { + double value = 0; + if (pdata->GetNumberOfComponents() == 1) { + value = pdata->GetComponent(i, 0); + pdata->SetComponent(i, 0, value * FieldFactor); + } + // if field is a vector + else { + for (int j = 0; j < pdata->GetNumberOfComponents(); ++j) { + value = pdata->GetComponent(i, j); + pdata->SetComponent(i, j, value * FieldFactor); + } + } + } +} + +PyObject *ViewProviderFemPostPipeline::getPyObject(void) +{ + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new ViewProviderFemPostPipelinePy(this), true); + } + return Py::new_reference_to(PythonObject); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.h b/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.h index 8bda582375..cea1b1efef 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.h +++ b/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.h @@ -25,6 +25,8 @@ #define FEM_VIEWPROVIDERFEMPOSTPIPELINE_H #include "ViewProviderFemPostObject.h" +#include +#include namespace FemGui { @@ -42,6 +44,12 @@ public: virtual std::vector< App::DocumentObject* > claimChildren3D(void) const; virtual void updateData(const App::Property* prop); virtual void onSelectionChanged(const Gui::SelectionChanges &sel); + void transformField(char *FieldName, double FieldFactor); + void scaleField(vtkDataSet *dset, vtkDataArray *pdata, double FieldFactor); + PyObject *getPyObject(); + +private: + Py::Object PythonObject; protected: void updateFunctionSize(); diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostPipelinePy.xml b/src/Mod/Fem/Gui/ViewProviderFemPostPipelinePy.xml new file mode 100644 index 0000000000..72c305b6c0 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemPostPipelinePy.xml @@ -0,0 +1,24 @@ + + + + + + ViewProviderFemPostPipeline class + + + + + + + + diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostPipelinePyImp.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostPipelinePyImp.cpp new file mode 100644 index 0000000000..25e74fbec1 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemPostPipelinePyImp.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (c) 2022 Uwe Stöhr * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#include +#include + +#include "ViewProviderFemPostPipeline.h" + +// inclusion of the generated files (generated out of ViewProviderFemPostPipelinePy.xml) +#include "ViewProviderFemPostPipelinePy.h" +#include "ViewProviderFemPostPipelinePy.cpp" + + +using namespace FemGui; + +// returns a string which represents the object e.g. when printed in python +std::string ViewProviderFemPostPipelinePy::representation(void) const +{ + return std::string(""); +} + +PyObject *ViewProviderFemPostPipelinePy::transformField(PyObject *args) +{ + char *FieldName; + double FieldFactor; + + if (!PyArg_ParseTuple(args, "sd", &FieldName, &FieldFactor)) + return nullptr; + + this->getViewProviderFemPostPipelinePtr()->transformField(FieldName, FieldFactor); + + Py_Return; +} + +PyObject *ViewProviderFemPostPipelinePy::getCustomAttributes(const char * /*attr*/) const +{ + return nullptr; +} + +int ViewProviderFemPostPipelinePy::setCustomAttributes(const char * /*attr*/, PyObject * /*obj*/) +{ + return 0; +} diff --git a/src/Mod/Fem/femsolver/elmer/tasks.py b/src/Mod/Fem/femsolver/elmer/tasks.py index 17197738d8..7f982c94be 100644 --- a/src/Mod/Fem/femsolver/elmer/tasks.py +++ b/src/Mod/Fem/femsolver/elmer/tasks.py @@ -255,6 +255,11 @@ class Results(run.Results): # at the moment we scale the mesh back using Elmer # this might be changed in future, therefore leave this # self.solver.ElmerResult.scale(1000) + + # it might be necessary to scale some result fields + # this would be done by this call: + # self.solver.ElmerResult.ViewObject.transformField("displacement EigenMode1", 0.001) + self.solver.ElmerResult.recomputeChildren() self.solver.Document.recompute()