From 072ecb2a4fc2c378d0e1f67a9d649dadbb1e6f75 Mon Sep 17 00:00:00 2001 From: marioalexis84 <53127171+marioalexis84@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:40:02 -0300 Subject: [PATCH] Fem: Add smoothing filter extension to contours filter (#18088) * Fem: Add smoothing filter extension to contours filter --- src/Mod/Fem/App/AppFem.cpp | 2 + src/Mod/Fem/App/FemPostFilter.cpp | 103 +++++++++++++++++++++++++++- src/Mod/Fem/App/FemPostFilter.h | 36 ++++++++++ src/Mod/Fem/Gui/TaskPostBoxes.cpp | 37 ++++++++-- src/Mod/Fem/Gui/TaskPostBoxes.h | 2 + src/Mod/Fem/Gui/TaskPostContours.ui | 58 +++++++++++++--- 6 files changed, 221 insertions(+), 17 deletions(-) diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index d9566c54fd..ef2cbfce19 100644 --- a/src/Mod/Fem/App/AppFem.cpp +++ b/src/Mod/Fem/App/AppFem.cpp @@ -181,6 +181,8 @@ PyMOD_INIT_FUNC(Fem) Fem::FemSolverObjectPython ::init(); #ifdef FC_USE_VTK + Fem::FemPostSmoothFilterExtension ::init(); + Fem::FemPostObject ::init(); Fem::FemPostPipeline ::init(); Fem::FemPostFilter ::init(); diff --git a/src/Mod/Fem/App/FemPostFilter.cpp b/src/Mod/Fem/App/FemPostFilter.cpp index 1e3a1ca27c..6522fcb423 100644 --- a/src/Mod/Fem/App/FemPostFilter.cpp +++ b/src/Mod/Fem/App/FemPostFilter.cpp @@ -515,6 +515,104 @@ DocumentObjectExecReturn* FemPostClipFilter::execute() return Fem::FemPostFilter::execute(); } +// *************************************************************************** +// smoothing filter extension +const App::PropertyQuantityConstraint::Constraints FemPostSmoothFilterExtension::angleRange = { + 0.0, + 180.0, + 1.0}; +const App::PropertyIntegerConstraint::Constraints FemPostSmoothFilterExtension::iterationRange = { + 0, + VTK_INT_MAX, + 1}; +const App::PropertyFloatConstraint::Constraints FemPostSmoothFilterExtension::relaxationRange = { + 0, + 1.0, + 0.01}; + +EXTENSION_PROPERTY_SOURCE(Fem::FemPostSmoothFilterExtension, App::DocumentObjectExtension) + +FemPostSmoothFilterExtension::FemPostSmoothFilterExtension() +{ + EXTENSION_ADD_PROPERTY_TYPE(BoundarySmoothing, + (true), + "Smoothing", + App::Prop_None, + "Smooth vertices on the boundary"); + EXTENSION_ADD_PROPERTY_TYPE(EdgeAngle, + (15), + "Smoothing", + App::Prop_None, + "Angle to control smoothing along edges"); + EXTENSION_ADD_PROPERTY_TYPE(EnableSmoothing, + (false), + "Smoothing", + App::Prop_None, + "Enable Laplacian smoothing"); + EXTENSION_ADD_PROPERTY_TYPE(FeatureAngle, + (45), + "Smoothing", + App::Prop_None, + "Angle for sharp edge identification"); + EXTENSION_ADD_PROPERTY_TYPE(EdgeSmoothing, + (false), + "Smoothing", + App::Prop_None, + "Smooth align sharp interior edges"); + EXTENSION_ADD_PROPERTY_TYPE(RelaxationFactor, + (0.05), + "Smoothing", + App::Prop_None, + "Factor to control vertex displacement"); + EXTENSION_ADD_PROPERTY_TYPE(Iterations, + (20), + "Smoothing", + App::Prop_None, + "Number of smoothing iterations"); + + EdgeAngle.setConstraints(&angleRange); + FeatureAngle.setConstraints(&angleRange); + Iterations.setConstraints(&iterationRange); + RelaxationFactor.setConstraints(&relaxationRange); + + m_smooth = vtkSmartPointer::New(); + // override default VTK values + m_smooth->SetNumberOfIterations(EnableSmoothing.getValue() ? Iterations.getValue() : 0); + m_smooth->SetBoundarySmoothing(BoundarySmoothing.getValue()); + m_smooth->SetEdgeAngle(EdgeAngle.getValue()); + m_smooth->SetFeatureAngle(FeatureAngle.getValue()); + m_smooth->SetFeatureEdgeSmoothing(EdgeSmoothing.getValue()); + m_smooth->SetRelaxationFactor(RelaxationFactor.getValue()); + + initExtensionType(FemPostSmoothFilterExtension::getExtensionClassTypeId()); +} + +void FemPostSmoothFilterExtension::extensionOnChanged(const App::Property* prop) +{ + if (prop == &EnableSmoothing || prop == &Iterations) { + // if disabled, set iterations to zero to do nothing + m_smooth->SetNumberOfIterations(EnableSmoothing.getValue() ? Iterations.getValue() : 0); + } + else if (prop == &BoundarySmoothing) { + m_smooth->SetBoundarySmoothing(static_cast(prop)->getValue()); + } + else if (prop == &EdgeAngle) { + m_smooth->SetEdgeAngle(static_cast(prop)->getValue()); + } + else if (prop == &FeatureAngle) { + m_smooth->SetFeatureAngle(static_cast(prop)->getValue()); + } + else if (prop == &EdgeSmoothing) { + m_smooth->SetFeatureEdgeSmoothing(static_cast(prop)->getValue()); + } + else if (prop == &RelaxationFactor) { + m_smooth->SetRelaxationFactor(static_cast(prop)->getValue()); + } + else { + DocumentObjectExtension::extensionOnChanged(prop); + } +} + // *************************************************************************** // contours filter PROPERTY_SOURCE(Fem::FemPostContoursFilter, Fem::FemPostFilter) @@ -543,10 +641,13 @@ FemPostContoursFilter::FemPostContoursFilter() FilterPipeline contours; m_contours = vtkSmartPointer::New(); m_contours->ComputeScalarsOn(); + smoothExtension.getFilter()->SetInputConnection(m_contours->GetOutputPort()); contours.source = m_contours; - contours.target = m_contours; + contours.target = smoothExtension.getFilter(); addFilterPipeline(contours, "contours"); setActiveFilterPipeline("contours"); + + smoothExtension.initExtension(this); } FemPostContoursFilter::~FemPostContoursFilter() = default; diff --git a/src/Mod/Fem/App/FemPostFilter.h b/src/Mod/Fem/App/FemPostFilter.h index bdb97daf83..8c7dd4420c 100644 --- a/src/Mod/Fem/App/FemPostFilter.h +++ b/src/Mod/Fem/App/FemPostFilter.h @@ -24,6 +24,7 @@ #define Fem_FemPostFilter_H #include +#include #include #include #include @@ -36,6 +37,7 @@ #include #include +#include #include "FemPostObject.h" @@ -77,6 +79,37 @@ private: std::string m_activePipeline; }; +class FemExport FemPostSmoothFilterExtension: public App::DocumentObjectExtension +{ + EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(Fem::FemPostSmoothFilterExtension); + +public: + FemPostSmoothFilterExtension(); + ~FemPostSmoothFilterExtension() override = default; + + App::PropertyBool BoundarySmoothing; + App::PropertyAngle EdgeAngle; + App::PropertyBool EdgeSmoothing; + App::PropertyBool EnableSmoothing; + App::PropertyAngle FeatureAngle; + App::PropertyIntegerConstraint Iterations; + App::PropertyFloatConstraint RelaxationFactor; + + vtkSmartPointer getFilter() const + { + return m_smooth; + } + +protected: + void extensionOnChanged(const App::Property* prop) override; + +private: + vtkSmartPointer m_smooth; + static const App::PropertyQuantityConstraint::Constraints angleRange; + static const App::PropertyIntegerConstraint::Constraints iterationRange; + static const App::PropertyFloatConstraint::Constraints relaxationRange; +}; + // *************************************************************************** // in the following, the different filters sorted alphabetically // *************************************************************************** @@ -210,11 +243,14 @@ public: protected: App::DocumentObjectExecReturn* execute() override; void onChanged(const App::Property* prop) override; + void recalculateContours(double min, double max); void refreshFields(); void refreshVectors(); bool m_blockPropertyChanges = false; + std::string contourFieldName; + FemPostSmoothFilterExtension smoothExtension; private: vtkSmartPointer m_contours; diff --git a/src/Mod/Fem/Gui/TaskPostBoxes.cpp b/src/Mod/Fem/Gui/TaskPostBoxes.cpp index 2cfdbc8071..8fff98bfaf 100644 --- a/src/Mod/Fem/Gui/TaskPostBoxes.cpp +++ b/src/Mod/Fem/Gui/TaskPostBoxes.cpp @@ -1437,19 +1437,25 @@ TaskPostContours::TaskPostContours(ViewProviderFemPostContours* view, QWidget* p QMetaObject::connectSlotsByName(this); this->groupLayout()->addWidget(proxy); + auto obj = getObject(); + // load filter settings - updateEnumerationList(getTypedObject()->Field, ui->fieldsCB); - updateEnumerationList(getTypedObject()->VectorMode, ui->vectorsCB); + updateEnumerationList(obj->Field, ui->fieldsCB); + updateEnumerationList(obj->VectorMode, ui->vectorsCB); // for a new filter, initialize the coloring - auto colorState = getObject()->NoColor.getValue(); + auto colorState = obj->NoColor.getValue(); if (!colorState && getTypedView()->Field.getValue() == 0) { getTypedView()->Field.setValue(1); } - ui->numberContoursSB->setValue( - getObject()->NumberOfContours.getValue()); + ui->numberContoursSB->setValue(obj->NumberOfContours.getValue()); ui->noColorCB->setChecked(colorState); + auto ext = obj->getExtension(); + ui->ckb_smoothing->setChecked(ext->EnableSmoothing.getValue()); + ui->dsb_relaxation->setValue(ext->RelaxationFactor.getValue()); + ui->dsb_relaxation->setEnabled(ext->EnableSmoothing.getValue()); + // connect connect(ui->fieldsCB, qOverload(&QComboBox::currentIndexChanged), @@ -1464,6 +1470,11 @@ TaskPostContours::TaskPostContours(ViewProviderFemPostContours* view, QWidget* p this, &TaskPostContours::onNumberOfContoursChanged); connect(ui->noColorCB, &QCheckBox::toggled, this, &TaskPostContours::onNoColorChanged); + connect(ui->ckb_smoothing, &QCheckBox::toggled, this, &TaskPostContours::onSmoothingChanged); + connect(ui->dsb_relaxation, + qOverload(&QDoubleSpinBox::valueChanged), + this, + &TaskPostContours::onRelaxationChanged); } TaskPostContours::~TaskPostContours() = default; @@ -1549,6 +1560,22 @@ void TaskPostContours::onNoColorChanged(bool state) recompute(); } +void TaskPostContours::onSmoothingChanged(bool state) +{ + auto ext = static_cast(getObject()) + ->getExtension(); + ext->EnableSmoothing.setValue(state); + ui->dsb_relaxation->setEnabled(state); + recompute(); +} + +void TaskPostContours::onRelaxationChanged(double value) +{ + auto ext = static_cast(getObject()) + ->getExtension(); + ext->RelaxationFactor.setValue(value); + recompute(); +} // *************************************************************************** // cut filter diff --git a/src/Mod/Fem/Gui/TaskPostBoxes.h b/src/Mod/Fem/Gui/TaskPostBoxes.h index 077a2b7869..45f70f3f81 100644 --- a/src/Mod/Fem/Gui/TaskPostBoxes.h +++ b/src/Mod/Fem/Gui/TaskPostBoxes.h @@ -412,6 +412,8 @@ private: void onVectorModeChanged(int idx); void onNumberOfContoursChanged(int number); void onNoColorChanged(bool state); + void onSmoothingChanged(bool state); + void onRelaxationChanged(double v); private: QWidget* proxy; diff --git a/src/Mod/Fem/Gui/TaskPostContours.ui b/src/Mod/Fem/Gui/TaskPostContours.ui index f342757339..eb6bd9df53 100644 --- a/src/Mod/Fem/Gui/TaskPostContours.ui +++ b/src/Mod/Fem/Gui/TaskPostContours.ui @@ -58,7 +58,7 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignLeft|Qt::AlignTrailing|Qt::AlignVCenter false @@ -71,18 +71,54 @@ + + + + Enable Laplacian smoothing + + + Smoothing + + + + + + + Relaxation Factor: + + + + + + + Qt::AlignLeft|Qt::AlignTrailing|Qt::AlignVCenter + + + Factor to control vertex displacement + + + 0.00000000000 + + + 1.00000000000 + + + 0.01000000000 + + + + + + + Contour lines will not be colored + + + No Color + + + - - - - Contour lines will not be colored - - - No color - - -