From b51eec232fe29235849c338fab57d7865ca8314e Mon Sep 17 00:00:00 2001 From: marioalexis Date: Fri, 10 Mar 2023 12:41:27 -0300 Subject: [PATCH] Fem: Add box filter function --- src/Mod/Fem/App/AppFem.cpp | 1 + src/Mod/Fem/App/FemPostFunction.cpp | 45 ++++ src/Mod/Fem/App/FemPostFunction.h | 29 +++ src/Mod/Fem/Gui/AppFemGui.cpp | 1 + src/Mod/Fem/Gui/BoxWidget.ui | 197 ++++++++++++++++ src/Mod/Fem/Gui/CMakeLists.txt | 2 + src/Mod/Fem/Gui/Command.cpp | 31 +++ .../Fem/Gui/ViewProviderFemPostFunction.cpp | 220 ++++++++++++++++++ src/Mod/Fem/Gui/ViewProviderFemPostFunction.h | 41 ++++ 9 files changed, 567 insertions(+) create mode 100644 src/Mod/Fem/Gui/BoxWidget.ui diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index f604ad1149..e2e4f4a6c2 100644 --- a/src/Mod/Fem/App/AppFem.cpp +++ b/src/Mod/Fem/App/AppFem.cpp @@ -187,6 +187,7 @@ PyMOD_INIT_FUNC(Fem) Fem::FemPostFunction ::init(); Fem::FemPostFunctionProvider ::init(); + Fem::FemPostBoxFunction ::init(); Fem::FemPostCylinderFunction ::init(); Fem::FemPostPlaneFunction ::init(); Fem::FemPostSphereFunction ::init(); diff --git a/src/Mod/Fem/App/FemPostFunction.cpp b/src/Mod/Fem/App/FemPostFunction.cpp index 56e61fc684..4d36f4b97a 100644 --- a/src/Mod/Fem/App/FemPostFunction.cpp +++ b/src/Mod/Fem/App/FemPostFunction.cpp @@ -59,6 +59,51 @@ DocumentObjectExecReturn* FemPostFunction::execute() { return DocumentObject::StdReturn; } +// *************************************************************************** +// box function +PROPERTY_SOURCE(Fem::FemPostBoxFunction, Fem::FemPostFunction) + +FemPostBoxFunction::FemPostBoxFunction() + : FemPostFunction() +{ + ADD_PROPERTY(Center, (Base::Vector3d(0.0, 0.0, 0.0))); + ADD_PROPERTY(Length, (10.0)); + ADD_PROPERTY(Width, (10.0)); + ADD_PROPERTY(Height, (10.0)); + + m_box = vtkSmartPointer::New(); + m_implicit = m_box; + + m_box->SetBounds(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0); +} + +FemPostBoxFunction::~FemPostBoxFunction() +{ +} + +void FemPostBoxFunction::onChanged(const Property* prop) +{ + if (prop == &Center || prop == &Length || prop == &Width || prop == &Height) { + const Base::Vector3d& vec = Center.getValue(); + float l = Length.getValue(); + float w = Width.getValue(); + float h = Height.getValue(); + m_box->SetBounds( + vec[0] - l/2, vec[0] + l/2, + vec[1] - w/2, vec[1] + w/2, + vec[2] - h/2, vec[2] + h/2); + } + + Fem::FemPostFunction::onChanged(prop); +} + +void FemPostBoxFunction::onDocumentRestored() +{ + // This is to notify the view provider that the document has been fully restored + Center.touch(); +} + + // *************************************************************************** // cylinder function PROPERTY_SOURCE(Fem::FemPostCylinderFunction, Fem::FemPostFunction) diff --git a/src/Mod/Fem/App/FemPostFunction.h b/src/Mod/Fem/App/FemPostFunction.h index 91b7890e47..f5d12cea01 100644 --- a/src/Mod/Fem/App/FemPostFunction.h +++ b/src/Mod/Fem/App/FemPostFunction.h @@ -24,6 +24,7 @@ #define Fem_FemPostFunction_H #include +#include #include #include #include @@ -84,6 +85,34 @@ protected: // --------------------------------------------------------------------------- +class FemExport FemPostBoxFunction : public FemPostFunction +{ + PROPERTY_HEADER_WITH_OVERRIDE(Fem::FemPostBoxFunction); + +public: + + FemPostBoxFunction(); + ~FemPostBoxFunction() override; + + App::PropertyVectorDistance Center; + App::PropertyDistance Length; + App::PropertyDistance Width; + App::PropertyDistance Height; + + const char* getViewProviderName() const override { + return "FemGui::ViewProviderFemPostBoxFunction"; + } + +protected: + void onChanged(const App::Property* prop) override; + /// get called after a document has been fully restored + void onDocumentRestored() override; + + vtkSmartPointer m_box; +}; + +// --------------------------------------------------------------------------- + class FemExport FemPostCylinderFunction : public FemPostFunction { PROPERTY_HEADER_WITH_OVERRIDE(Fem::FemPostCylinderFunction); diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index 58c962ad88..1ee1296103 100644 --- a/src/Mod/Fem/Gui/AppFemGui.cpp +++ b/src/Mod/Fem/Gui/AppFemGui.cpp @@ -161,6 +161,7 @@ PyMOD_INIT_FUNC(FemGui) FemGui::ViewProviderFemPostFunction ::init(); FemGui::ViewProviderFemPostFunctionProvider ::init(); + FemGui::ViewProviderFemPostBoxFunction ::init(); FemGui::ViewProviderFemPostCylinderFunction ::init(); FemGui::ViewProviderFemPostPlaneFunction ::init(); FemGui::ViewProviderFemPostSphereFunction ::init(); diff --git a/src/Mod/Fem/Gui/BoxWidget.ui b/src/Mod/Fem/Gui/BoxWidget.ui new file mode 100644 index 0000000000..74991bc3b6 --- /dev/null +++ b/src/Mod/Fem/Gui/BoxWidget.ui @@ -0,0 +1,197 @@ + + + BoxWidget + + + + 0 + 0 + 280 + 85 + + + + Form + + + + + + + + x + + + Qt::AlignCenter + + + + + + + y + + + Qt::AlignCenter + + + + + + + z + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + Center + + + Qt::AlignCenter + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + Length + + + Qt::AlignCenter + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + Width + + + Qt::AlignCenter + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + Height + + + Qt::AlignCenter + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
+
+ + Gui::PrefQuantitySpinBox + Gui::QuantitySpinBox +
Gui/PrefWidgets.h
+
+
+ + +
diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 13bf23dd56..86751cd2e9 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -91,6 +91,7 @@ set(FemGui_UIC_SRCS if(BUILD_FEM_VTK) set(FemGui_UIC_SRCS ${FemGui_UIC_SRCS} + BoxWidget.ui CylinderWidget.ui PlaneWidget.ui SphereWidget.ui @@ -270,6 +271,7 @@ SET(FemGui_SRCS_TaskBoxes if(BUILD_FEM_VTK) SET(FemGui_SRCS_TaskBoxes ${FemGui_SRCS_TaskBoxes} + BoxWidget.ui CylinderWidget.ui PlaneWidget.ui SphereWidget.ui diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 8b72d2cc47..a12f904012 100644 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -2106,6 +2106,8 @@ void CmdFemPostFunctions::activated(int iMsg) name = "Sphere"; else if (iMsg == 2) name = "Cylinder"; + else if (iMsg == 3) + name = "Box"; else return; @@ -2184,6 +2186,26 @@ void CmdFemPostFunctions::activated(int iMsg) FeatName.c_str(), box.GetDiagonalLength() / 3.6); // make cylinder a bit higher than the box } + else if (iMsg == 3) { + doCommand(Doc, + "App.ActiveDocument.%s.Center = App.Vector(%f, %f, %f)", + FeatName.c_str(), + center[0], + center[1] + box.GetLength(1) / 2, + center[2] + box.GetLength(2) / 2); + doCommand(Doc, + "App.ActiveDocument.%s.Length = %f", + FeatName.c_str(), + box.GetLength(0)); + doCommand(Doc, + "App.ActiveDocument.%s.Width = %f", + FeatName.c_str(), + box.GetLength(1)); + doCommand(Doc, + "App.ActiveDocument.%s.Height = %f", + FeatName.c_str(), + box.GetLength(2)); + } this->updateActive(); //most of the times functions are added inside of a filter, make sure this still works @@ -2220,6 +2242,9 @@ Gui::Action* CmdFemPostFunctions::createAction() QAction* cmd2 = pcAction->addAction(QString()); cmd2->setIcon(Gui::BitmapFactory().iconFromTheme("fem-post-geo-cylinder")); + QAction* cmd3 = pcAction->addAction(QString()); + cmd3->setIcon(Gui::BitmapFactory().iconFromTheme("fem-post-geo-box")); + _pcAction = pcAction; languageChange(); @@ -2256,6 +2281,12 @@ void CmdFemPostFunctions::languageChange() cmd->setToolTip(QApplication::translate( "FEM_PostCreateFunctions", "Create a cylinder function, defined by its center, axis and radius")); cmd->setStatusTip(cmd->toolTip()); + + cmd = a[3]; + cmd->setText(QApplication::translate("CmdFemPostFunctions", "Box")); + cmd->setToolTip(QApplication::translate( + "FEM_PostCreateFunctions", "Create a box function, defined by its center, length, width and height")); + cmd->setStatusTip(cmd->toolTip()); } bool CmdFemPostFunctions::isActive() diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostFunction.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.cpp index aa22774d6c..562817ef64 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostFunction.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.cpp @@ -57,6 +57,7 @@ #include "FemSettings.h" #include "TaskPostBoxes.h" +#include "ui_BoxWidget.h" #include "ui_CylinderWidget.h" #include "ui_PlaneWidget.h" #include "ui_SphereWidget.h" @@ -379,6 +380,183 @@ void ViewProviderFemPostFunction::onChanged(const App::Property* prop) { } +// *************************************************************************** + +PROPERTY_SOURCE(FemGui::ViewProviderFemPostBoxFunction, FemGui::ViewProviderFemPostFunction) + +ViewProviderFemPostBoxFunction::ViewProviderFemPostBoxFunction() +{ + sPixmap = "fem-post-geo-box"; + + setAutoScale(false); + + // setup the visualisation geometry + getGeometryNode()->addChild(ShapeNodes::postBox()); +} + +ViewProviderFemPostBoxFunction::~ViewProviderFemPostBoxFunction() +{ +} + +void ViewProviderFemPostBoxFunction::draggerUpdate(SoDragger* m) +{ + Fem::FemPostBoxFunction* func = static_cast(getObject()); + SoHandleBoxDragger* dragger = static_cast(m); + + const SbVec3f& center = dragger->translation.getValue(); + SbVec3f scale = dragger->scaleFactor.getValue(); + + func->Center.setValue(center[0], center[1], center[2]); + func->Length.setValue(scale[0]); + func->Width.setValue(scale[1]); + func->Height.setValue(scale[2]); +} + +void ViewProviderFemPostBoxFunction::updateData(const App::Property* p) +{ + Fem::FemPostBoxFunction* func = static_cast(getObject()); + if (!isDragging() && + (p == &func->Center || p == &func->Length || p == &func->Width || p == &func->Height)) { + const Base::Vector3d& center = func->Center.getValue(); + float l = func->Length.getValue(); + float w = func->Width.getValue(); + float h = func->Height.getValue(); + + SbMatrix s, t; + s.setScale(SbVec3f(l, w, h)); + t.setTranslate(SbVec3f(center.x, center.y, center.z)); + s.multRight(t); + getManipulator()->setMatrix(s); + } + Gui::ViewProviderDocumentObject::updateData(p); +} + +SoTransformManip* ViewProviderFemPostBoxFunction::setupManipulator() +{ + return new SoHandleBoxManip; +} + +FunctionWidget* ViewProviderFemPostBoxFunction::createControlWidget() +{ + return new BoxWidget(); +} + +BoxWidget::BoxWidget() +{ + ui = new Ui_BoxWidget(); + ui->setupUi(this); + + QSize size = ui->centerX->sizeForText(QStringLiteral("000000000000")); + ui->centerX->setMinimumWidth(size.width()); + ui->centerY->setMinimumWidth(size.width()); + ui->centerZ->setMinimumWidth(size.width()); + ui->length->setMinimumWidth(size.width()); + ui->width->setMinimumWidth(size.width()); + ui->height->setMinimumWidth(size.width()); + + int UserDecimals = Base::UnitsApi::getDecimals(); + ui->centerX->setDecimals(UserDecimals); + ui->centerY->setDecimals(UserDecimals); + ui->centerZ->setDecimals(UserDecimals); + ui->length->setDecimals(UserDecimals); + ui->width->setDecimals(UserDecimals); + ui->height->setDecimals(UserDecimals); + + connect(ui->centerX, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &BoxWidget::centerChanged); + connect(ui->centerY, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &BoxWidget::centerChanged); + connect(ui->centerZ, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &BoxWidget::centerChanged); + connect(ui->length, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &BoxWidget::lengthChanged); + connect(ui->width, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &BoxWidget::widthChanged); + connect(ui->height, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &BoxWidget::heightChanged); +} + +BoxWidget::~BoxWidget() +{ +} + +void BoxWidget::applyPythonCode() +{ +} + +void BoxWidget::setViewProvider(ViewProviderFemPostFunction* view) +{ + FemGui::FunctionWidget::setViewProvider(view); + setBlockObjectUpdates(true); + Base::Unit unit = static_cast(getObject())->Center.getUnit(); + ui->centerX->setUnit(unit); + ui->centerY->setUnit(unit); + ui->centerZ->setUnit(unit); + unit = static_cast(getObject())->Length.getUnit(); + ui->length->setUnit(unit); + unit = static_cast(getObject())->Width.getUnit(); + ui->width->setUnit(unit); + unit = static_cast(getObject())->Height.getUnit(); + ui->height->setUnit(unit); + setBlockObjectUpdates(false); + onChange(static_cast(getObject())->Center); + onChange(static_cast(getObject())->Length); + onChange(static_cast(getObject())->Width); + onChange(static_cast(getObject())->Height); +} + +void BoxWidget::onChange(const App::Property& p) +{ + setBlockObjectUpdates(true); + Fem::FemPostBoxFunction* func = static_cast(getObject()); + if (&p == &func->Center) { + const Base::Vector3d& vec = static_cast(&p)->getValue(); + ui->centerX->setValue(vec.x); + ui->centerY->setValue(vec.y); + ui->centerZ->setValue(vec.z); + } + else if (&p == &func->Length) { + double l = static_cast(&p)->getValue(); + ui->length->setValue(l); + } + else if (&p == &func->Width) { + double w = static_cast(&p)->getValue(); + ui->width->setValue(w); + } + else if (&p == &func->Height) { + double h = static_cast(&p)->getValue(); + ui->height->setValue(h); + } + setBlockObjectUpdates(false); +} + +void BoxWidget::centerChanged(double) { + if (!blockObjectUpdates()) { + Base::Vector3d vec(ui->centerX->value().getValue(), ui->centerY->value().getValue(), + ui->centerZ->value().getValue()); + static_cast(getObject())->Center.setValue(vec); + } +} + +void BoxWidget::lengthChanged(double) +{ + if (!blockObjectUpdates()) { + double l = ui->length->value().getValue(); + static_cast(getObject())->Length.setValue(l); + } +} + +void BoxWidget::widthChanged(double) +{ + if (!blockObjectUpdates()) { + double w = ui->width->value().getValue(); + static_cast(getObject())->Width.setValue(w); + } +} + +void BoxWidget::heightChanged(double) +{ + if (!blockObjectUpdates()) { + double h = ui->height->value().getValue(); + static_cast(getObject())->Height.setValue(h); + } +} + + // *************************************************************************** PROPERTY_SOURCE(FemGui::ViewProviderFemPostCylinderFunction, FemGui::ViewProviderFemPostFunction) @@ -882,6 +1060,48 @@ namespace FemGui namespace ShapeNodes { +SoGroup* postBox() +{ + SoCoordinate3* points = new SoCoordinate3(); + points->point.setNum(18); + points->point.set1Value(0, -0.5, -0.5, -0.5); + points->point.set1Value(1, 0.5, -0.5, -0.5); + points->point.set1Value(2, 0.5, 0.5, -0.5); + points->point.set1Value(3, -0.5, 0.5, -0.5); + points->point.set1Value(4, -0.5, -0.5, -0.5); + points->point.set1Value(5, -0.5, -0.5, 0.5); + points->point.set1Value(6, 0.5, -0.5, 0.5); + points->point.set1Value(7, 0.5, 0.5, 0.5); + points->point.set1Value(8, -0.5, 0.5, 0.5); + points->point.set1Value(9, -0.5, -0.5, 0.5); + points->point.set1Value(10, -0.5, -0.5, -0.5); + points->point.set1Value(11, -0.5, -0.5, 0.5); + points->point.set1Value(12, 0.5, -0.5, -0.5); + points->point.set1Value(13, 0.5, -0.5, 0.5); + points->point.set1Value(14, 0.5, 0.5, -0.5); + points->point.set1Value(15, 0.5, 0.5, 0.5); + points->point.set1Value(16, -0.5, 0.5, -0.5); + points->point.set1Value(17, -0.5, 0.5, 0.5); + + int vert[6]; + vert[0] = 5; + vert[1] = 5; + vert[2] = 2; + vert[3] = 2; + vert[4] = 2; + vert[5] = 2; + + SoGroup* group = new SoGroup(); + SoLineSet* line = new SoLineSet(); + + line->numVertices.setValues(0, 6, vert); + + group->addChild(points); + group->addChild(line); + + return group; +} + SoGroup* postCylinder() { SoCoordinate3* points = new SoCoordinate3(); diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h index 9e67f91c8f..053118f324 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h +++ b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h @@ -39,6 +39,7 @@ class SoScale; class SoSphere; class SoSurroundScale; class SoTransformManip; +class Ui_BoxWidget; class Ui_CylinderWidget; class Ui_PlaneWidget; class Ui_SphereWidget; @@ -153,6 +154,45 @@ private: bool m_autoscale, m_isDragging, m_autoRecompute; }; +// *************************************************************************** +class FemGuiExport BoxWidget : public FunctionWidget { + + Q_OBJECT +public: + BoxWidget(); + ~BoxWidget() override; + + void applyPythonCode() override; + void onChange(const App::Property& p) override; + void setViewProvider(ViewProviderFemPostFunction* view) override; + +private Q_SLOTS: + void centerChanged(double); + void lengthChanged(double); + void widthChanged(double); + void heightChanged(double); + +private: + Ui_BoxWidget* ui; +}; + +class FemGuiExport ViewProviderFemPostBoxFunction : public ViewProviderFemPostFunction +{ + PROPERTY_HEADER_WITH_OVERRIDE(FemGui::ViewProviderFemPostBoxFunction); + +public: + ViewProviderFemPostBoxFunction(); + ~ViewProviderFemPostBoxFunction() override; + + SoTransformManip* setupManipulator() override; + FunctionWidget* createControlWidget() override; + +protected: + void draggerUpdate(SoDragger* mat) override; + void updateData(const App::Property*) override; +}; + + // *************************************************************************** class FemGuiExport CylinderWidget : public FunctionWidget { @@ -273,6 +313,7 @@ protected: namespace ShapeNodes { + SoGroup* postBox(); SoGroup* postCylinder(); SoGroup* postPlane(); SoGroup* postSphere();