Fem: Add smoothing filter extension to contours filter (#18088)

* Fem: Add smoothing filter extension to contours filter
This commit is contained in:
marioalexis84
2024-12-16 13:40:02 -03:00
committed by GitHub
parent 0d4e7ac27f
commit 072ecb2a4f
6 changed files with 221 additions and 17 deletions

View File

@@ -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();

View File

@@ -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<vtkSmoothPolyDataFilter>::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<const App::PropertyBool*>(prop)->getValue());
}
else if (prop == &EdgeAngle) {
m_smooth->SetEdgeAngle(static_cast<const App::PropertyAngle*>(prop)->getValue());
}
else if (prop == &FeatureAngle) {
m_smooth->SetFeatureAngle(static_cast<const App::PropertyAngle*>(prop)->getValue());
}
else if (prop == &EdgeSmoothing) {
m_smooth->SetFeatureEdgeSmoothing(static_cast<const App::PropertyBool*>(prop)->getValue());
}
else if (prop == &RelaxationFactor) {
m_smooth->SetRelaxationFactor(static_cast<const App::PropertyFloat*>(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<vtkContourFilter>::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;

View File

@@ -24,6 +24,7 @@
#define Fem_FemPostFilter_H
#include <vtkContourFilter.h>
#include <vtkSmoothPolyDataFilter.h>
#include <vtkCutter.h>
#include <vtkExtractGeometry.h>
#include <vtkExtractVectorComponents.h>
@@ -36,6 +37,7 @@
#include <vtkWarpVector.h>
#include <App/PropertyUnits.h>
#include <App/DocumentObjectExtension.h>
#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<vtkSmoothPolyDataFilter> getFilter() const
{
return m_smooth;
}
protected:
void extensionOnChanged(const App::Property* prop) override;
private:
vtkSmartPointer<vtkSmoothPolyDataFilter> 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<vtkContourFilter> m_contours;

View File

@@ -1437,19 +1437,25 @@ TaskPostContours::TaskPostContours(ViewProviderFemPostContours* view, QWidget* p
QMetaObject::connectSlotsByName(this);
this->groupLayout()->addWidget(proxy);
auto obj = getObject<Fem::FemPostContoursFilter>();
// load filter settings
updateEnumerationList(getTypedObject<Fem::FemPostContoursFilter>()->Field, ui->fieldsCB);
updateEnumerationList(getTypedObject<Fem::FemPostContoursFilter>()->VectorMode, ui->vectorsCB);
updateEnumerationList(obj->Field, ui->fieldsCB);
updateEnumerationList(obj->VectorMode, ui->vectorsCB);
// for a new filter, initialize the coloring
auto colorState = getObject<Fem::FemPostContoursFilter>()->NoColor.getValue();
auto colorState = obj->NoColor.getValue();
if (!colorState && getTypedView<ViewProviderFemPostObject>()->Field.getValue() == 0) {
getTypedView<ViewProviderFemPostObject>()->Field.setValue(1);
}
ui->numberContoursSB->setValue(
getObject<Fem::FemPostContoursFilter>()->NumberOfContours.getValue());
ui->numberContoursSB->setValue(obj->NumberOfContours.getValue());
ui->noColorCB->setChecked(colorState);
auto ext = obj->getExtension<Fem::FemPostSmoothFilterExtension>();
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<int>(&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<double>(&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<Fem::FemPostContoursFilter*>(getObject())
->getExtension<Fem::FemPostSmoothFilterExtension>();
ext->EnableSmoothing.setValue(state);
ui->dsb_relaxation->setEnabled(state);
recompute();
}
void TaskPostContours::onRelaxationChanged(double value)
{
auto ext = static_cast<Fem::FemPostContoursFilter*>(getObject())
->getExtension<Fem::FemPostSmoothFilterExtension>();
ext->RelaxationFactor.setValue(value);
recompute();
}
// ***************************************************************************
// cut filter

View File

@@ -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;

View File

@@ -58,7 +58,7 @@
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignLeft|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="keyboardTracking">
<bool>false</bool>
@@ -71,18 +71,54 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="ckb_smoothing">
<property name="toolTip">
<string>Enable Laplacian smoothing</string>
</property>
<property name="text">
<string>Smoothing</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lbl_relaxation">
<property name="text">
<string notr="true">Relaxation Factor:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="dsb_relaxation">
<property name="alignment">
<set>Qt::AlignLeft|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="toolTip">
<string>Factor to control vertex displacement</string>
</property>
<property name="minimum">
<double>0.00000000000</double>
</property>
<property name="maximum">
<double>1.00000000000</double>
</property>
<property name="singleStep">
<double>0.01000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="noColorCB">
<property name="toolTip">
<string>Contour lines will not be colored</string>
</property>
<property name="text">
<string>No Color</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="noColorCB">
<property name="toolTip">
<string>Contour lines will not be colored</string>
</property>
<property name="text">
<string>No color</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>