diff --git a/src/Mod/Fem/App/FemPostPipeline.cpp b/src/Mod/Fem/App/FemPostPipeline.cpp index 953a2957bf..64e3f56c8f 100644 --- a/src/Mod/Fem/App/FemPostPipeline.cpp +++ b/src/Mod/Fem/App/FemPostPipeline.cpp @@ -73,10 +73,17 @@ FemPostPipeline::FemPostPipeline() App::Prop_None, "The frame used to calculate the data in the pipeline processing (read only, " "set via pipeline object)."); + ADD_PROPERTY_TYPE(MergeDuplicate, + (false), + "Pipeline", + App::Prop_None, + "Remove coindent elements."); // create our source algorithm m_source_algorithm = vtkSmartPointer::New(); + m_clean_filter = vtkSmartPointer::New(); + m_clean_filter->SetPointDataWeighingStrategy(vtkCleanUnstructuredGrid::AVERAGING); m_transform_filter->SetInputConnection(m_source_algorithm->GetOutputPort(0)); } @@ -276,6 +283,19 @@ void FemPostPipeline::onChanged(const Property* prop) recomputeChildren(); } + if (prop == &MergeDuplicate) { + if (MergeDuplicate.getValue()) { + m_clean_filter->SetInputConnection(m_source_algorithm->GetOutputPort(0)); + m_transform_filter->SetInputConnection(m_clean_filter->GetOutputPort(0)); + } + else { + m_transform_filter->SetInputConnection(m_source_algorithm->GetOutputPort(0)); + } + m_transform_filter->Update(); + updateData(); + recomputeChildren(); + } + // use the correct data as source if (prop == &Data && !m_block_property) { m_source_algorithm->setDataObject(Data.getValue()); diff --git a/src/Mod/Fem/App/FemPostPipeline.h b/src/Mod/Fem/App/FemPostPipeline.h index 3ba9108f5e..62a5dfdad7 100644 --- a/src/Mod/Fem/App/FemPostPipeline.h +++ b/src/Mod/Fem/App/FemPostPipeline.h @@ -32,6 +32,11 @@ #include "FemResultObject.h" #include "VTKExtensions/vtkFemFrameSourceAlgorithm.h" +#if VTK_VERSION_NUMBER < VTK_VERSION_CHECK(9, 3, 0) +#include "VTKExtensions/vtkCleanUnstructuredGrid.h" +#else +#include +#endif #include @@ -47,7 +52,7 @@ public: FemPostPipeline(); App::PropertyEnumeration Frame; - + App::PropertyBool MergeDuplicate; virtual vtkDataSet* getDataSet() override; Fem::FemPostFunctionProvider* getFunctionProvider(); @@ -108,6 +113,7 @@ private: App::Enumeration m_frameEnum; vtkSmartPointer m_source_algorithm; + vtkSmartPointer m_clean_filter; bool m_block_property = false; bool m_data_updated = false; diff --git a/src/Mod/Fem/Gui/DlgSettingsFemElmer.ui b/src/Mod/Fem/Gui/DlgSettingsFemElmer.ui index 205c3d2e2c..9efc747758 100644 --- a/src/Mod/Fem/Gui/DlgSettingsFemElmer.ui +++ b/src/Mod/Fem/Gui/DlgSettingsFemElmer.ui @@ -15,7 +15,7 @@ - + 0 @@ -169,25 +169,6 @@ - - - - Merge mesh volume regions processed by each CPU core to make boundaries invisible. - - - Filter results - - - true - - - FilterMultiCPUResults - - - Mod/Fem/Elmer - - - diff --git a/src/Mod/Fem/Gui/DlgSettingsFemElmerImp.cpp b/src/Mod/Fem/Gui/DlgSettingsFemElmerImp.cpp index a40fa3c9b7..82183bf115 100644 --- a/src/Mod/Fem/Gui/DlgSettingsFemElmerImp.cpp +++ b/src/Mod/Fem/Gui/DlgSettingsFemElmerImp.cpp @@ -59,7 +59,6 @@ void DlgSettingsFemElmerImp::saveSettings() ui->sb_num_processes->onSave(); - ui->cb_filtering->onSave(); ui->ckb_binary_format->onSave(); ui->ckb_geom_id->onSave(); } @@ -71,7 +70,6 @@ void DlgSettingsFemElmerImp::loadSettings() ui->sb_num_processes->onRestore(); - ui->cb_filtering->onRestore(); ui->ckb_binary_format->onRestore(); ui->ckb_geom_id->onRestore(); } diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp index 9205e2d708..10820b350f 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp @@ -515,7 +515,6 @@ void ViewProviderFemPostObject::updateProperties() void ViewProviderFemPostObject::update3D() { - vtkPolyData* pd = m_currentAlgorithm->GetOutput(); vtkPointData* pntData; @@ -802,79 +801,6 @@ void ViewProviderFemPostObject::updateData(const App::Property* p) } } -void ViewProviderFemPostObject::filterArtifacts(vtkDataSet* dset) -{ - // The problem is that in the surface view the boundary regions of the volumes - // calculated by the different CPU cores is always visible, independent of the - // transparency setting. Elmer is not to blame because this is a property of the - // partial VTK file reader. So this can happen with various inputs - // since FreeCAD can also be used to view VTK files without the need to perform - // an analysis. Therefore it is impossible to know in advance when a filter - // is necessary or not. - // Only for pure CCX analyses we know that no filtering is necessary. However, - // the effort to catch this case is not worth it since the filtering is - // only as time-consuming as enabling the surface filter. In fact, it is like - // performing the surface filter twice. - - // We need to set the filter clipping plane below the z-minimum of the data. - // We can either do this by checking the VTK data or by getting the info from - // the 3D view. We use here the latter because this is much faster. - - // since we will set the filter according to the visible bounding box - // assure the object is visible - bool visibility = this->Visibility.getValue(); - if (!visibility) { - this->Visibility.setValue(true); - } - m_blockPropertyChanges = true; - - Gui::Document* doc = this->getDocument(); - Gui::View3DInventor* view = - qobject_cast(doc->getViewOfViewProvider(this)); - - if (view) { - Gui::View3DInventorViewer* viewer = view->getViewer(); - SbBox3f boundingBox; - boundingBox = viewer->getBoundingBox(); - if (boundingBox.hasVolume()) { - // setup - vtkSmartPointer m_implicit; - auto m_plane = vtkSmartPointer::New(); - m_implicit = m_plane; - m_plane->SetNormal(0., 0., 1.); - auto extractor = vtkSmartPointer::New(); - float dx, dy, dz; - boundingBox.getSize(dx, dy, dz); - // Set plane below the minimum to assure there are - // no boundary cells (touching the function) and for Warp filters - // the user might change the warp factor a lot. Thus set - // 10 times dz to be safe even for unrealistic warp deformations - m_plane->SetOrigin(0., 0., -10 * dz); - extractor->SetClipFunction(m_implicit); - extractor->SetInputData(dset); - extractor->Update(); - auto extractorResult = extractor->GetOutputDataObject(0); - if (extractorResult) { - m_surface->SetInputData(extractorResult); - } - else { - m_surface->SetInputData(dset); - } - } - else { - // for the case that there are only 2D objects - m_surface->SetInputData(dset); - } - } - - m_blockPropertyChanges = false; - - // restore initial vsibility - if (!visibility) { - this->Visibility.setValue(visibility); - } -} - bool ViewProviderFemPostObject::setupPipeline() { if (m_blockPropertyChanges) { @@ -882,9 +808,6 @@ bool ViewProviderFemPostObject::setupPipeline() } auto postObject = getObject(); - - // check all fields if there is a real/imaginary one and if so - // add a field with an absolute value vtkDataSet* dset = postObject->getDataSet(); if (!dset) { return false; @@ -893,26 +816,7 @@ bool ViewProviderFemPostObject::setupPipeline() m_outline->SetInputData(dset); m_points->SetInputData(dset); m_wireframe->SetInputData(dset); - - // Filtering artifacts is necessary for partial VTU files (*.pvtu) independent of the - // current Elmer CPU core settings because the user might load an external file. - // It is only necessary for the surface filter. - // The problem is that when opening an existing FreeCAD file, we get no information how the - // Data of the postObject was once created. The vtkDataObject type does not provide this info. - // Therefore the only way is the hack to filter only if the used Elmer CPU cores are > 1. - auto hGrp = App::GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Mod/Fem/Elmer"); - bool FilterMultiCPUResults = hGrp->GetBool("FilterMultiCPUResults", true); - int UseNumberOfCores = hGrp->GetInt("UseNumberOfCores", 1); - // filtering is only necessary for pipelines and warp filters - if (FilterMultiCPUResults && (UseNumberOfCores > 1) - && ((postObject->getTypeId() == Base::Type::fromName("Fem::FemPostPipeline")) - || (postObject->getTypeId() == Base::Type::fromName("Fem::FemPostWarpVectorFilter")))) { - filterArtifacts(dset); - } - else { - m_surface->SetInputData(dset); - } + m_surface->SetInputData(dset); return true; } diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostObject.h b/src/Mod/Fem/Gui/ViewProviderFemPostObject.h index 948ad96f13..13f1522ecd 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostObject.h +++ b/src/Mod/Fem/Gui/ViewProviderFemPostObject.h @@ -155,7 +155,6 @@ protected: vtkSmartPointer m_points, m_pointsSurface; private: - void filterArtifacts(vtkDataSet* data); void updateProperties(); void update3D(); void WritePointData(vtkPoints* points, vtkDataArray* normals, vtkDataArray* tcoords); diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp index 2a14b7a47c..4a19bf0ea2 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp @@ -63,6 +63,9 @@ void ViewProviderFemPostPipeline::updateData(const App::Property* prop) updateFunctionSize(); updateColorBars(); } + else if (prop == &pipeline->MergeDuplicate) { + updateVtk(); + } } void ViewProviderFemPostPipeline::updateFunctionSize()