diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index fe004396fc..f604ad1149 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::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 0cf7540cee..c65ff6cea3 100644 --- a/src/Mod/Fem/App/FemPostFunction.cpp +++ b/src/Mod/Fem/App/FemPostFunction.cpp @@ -59,6 +59,44 @@ DocumentObjectExecReturn* FemPostFunction::execute() { return DocumentObject::StdReturn; } +// *************************************************************************** +// cylinder function +PROPERTY_SOURCE(Fem::FemPostCylinderFunction, Fem::FemPostFunction) + +FemPostCylinderFunction::FemPostCylinderFunction() : FemPostFunction() +{ + ADD_PROPERTY(Center, (Base::Vector3d(0.0, 0.0, 0.0))); + ADD_PROPERTY(Axis, (Base::Vector3d(0.0, 0.0, 1.0))); + ADD_PROPERTY(Radius, (5.)); + + m_cylinder = vtkSmartPointer::New(); + m_implicit = m_cylinder; + + m_cylinder->SetAxis(0., 0., 1.); + m_cylinder->SetCenter(0., 0., 0.); + m_cylinder->SetRadius(5.); +} + +FemPostCylinderFunction::~FemPostCylinderFunction() +{ +} + +void FemPostCylinderFunction::onChanged(const Property* prop) +{ + if (prop == &Axis) { + const Base::Vector3d& vec = Axis.getValue(); + m_cylinder->SetAxis(vec[0], vec[1], vec[2]); + } + else if (prop == &Center) { + const Base::Vector3d& vec = Center.getValue(); + m_cylinder->SetCenter(vec[0], vec[1], vec[2]); + } + else if (prop == &Radius) { + m_cylinder->SetRadius(Radius.getValue()); + } + + Fem::FemPostFunction::onChanged(prop); +} // *************************************************************************** // plane function diff --git a/src/Mod/Fem/App/FemPostFunction.h b/src/Mod/Fem/App/FemPostFunction.h index 6c6cffc06b..db8e70006e 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 @@ -81,6 +82,32 @@ protected: void onChanged(const App::Property* prop) override; }; +// --------------------------------------------------------------------------- + +class FemExport FemPostCylinderFunction : public FemPostFunction +{ + PROPERTY_HEADER_WITH_OVERRIDE(Fem::FemPostCylinderFunction); + +public: + + FemPostCylinderFunction(); + ~FemPostCylinderFunction() override; + + App::PropertyVector Axis; + App::PropertyVectorDistance Center; + App::PropertyDistance Radius; + + const char* getViewProviderName() const override { + return "FemGui::ViewProviderFemPostCylinderFunction"; + } + +protected: + void onChanged(const App::Property* prop) override; + /// get called after a document has been fully restored +// void onDocumentRestored() override; + + vtkSmartPointer m_cylinder; +}; // --------------------------------------------------------------------------- diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index 88d93ab3ba..58c962ad88 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::ViewProviderFemPostCylinderFunction ::init(); FemGui::ViewProviderFemPostPlaneFunction ::init(); FemGui::ViewProviderFemPostSphereFunction ::init(); #endif diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index a7e84a43b5..85b8e2b754 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -99,6 +99,7 @@ if(BUILD_FEM_VTK) TaskPostScalarClip.ui TaskPostWarpVector.ui TaskPostCut.ui + CylinderWidget.ui PlaneWidget.ui SphereWidget.ui ) @@ -269,6 +270,7 @@ SET(FemGui_SRCS_TaskBoxes if(BUILD_FEM_VTK) SET(FemGui_SRCS_TaskBoxes ${FemGui_SRCS_TaskBoxes} + CylinderWidget.ui PlaneWidget.ui SphereWidget.ui TaskPostClip.ui diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 5ad3c39a00..fe3762d7ee 100644 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -2104,6 +2104,8 @@ void CmdFemPostFunctions::activated(int iMsg) name = "Plane"; else if (iMsg == 1) name = "Sphere"; + else if (iMsg == 2) + name = "Cylinder"; else return; @@ -2170,6 +2172,18 @@ void CmdFemPostFunctions::activated(int iMsg) FeatName.c_str(), box.GetDiagonalLength() / 2); } + else if (iMsg == 2) { + 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.Radius = %f", + FeatName.c_str(), + box.GetDiagonalLength() / 2); + } this->updateActive(); @@ -2204,6 +2218,9 @@ Gui::Action* CmdFemPostFunctions::createAction() QAction* cmd1 = pcAction->addAction(QString()); cmd1->setIcon(Gui::BitmapFactory().iconFromTheme("fem-post-geo-sphere")); + QAction* cmd2 = pcAction->addAction(QString()); + cmd2->setIcon(Gui::BitmapFactory().iconFromTheme("fem-post-geo-cylinder")); + _pcAction = pcAction; languageChange(); @@ -2235,6 +2252,11 @@ void CmdFemPostFunctions::languageChange() "FEM_PostCreateFunctions", "Create a sphere function, defined by its center and radius")); cmd->setStatusTip(cmd->toolTip()); + cmd = a[2]; + cmd->setText(QApplication::translate("CmdFemPostFunctions", "Cylinder")); + cmd->setToolTip(QApplication::translate( + "FEM_PostCreateFunctions", "Create a cylinder function, defined by its center, axis and radius")); + cmd->setStatusTip(cmd->toolTip()); } bool CmdFemPostFunctions::isActive() diff --git a/src/Mod/Fem/Gui/CylinderWidget.ui b/src/Mod/Fem/Gui/CylinderWidget.ui new file mode 100644 index 0000000000..9b773db345 --- /dev/null +++ b/src/Mod/Fem/Gui/CylinderWidget.ui @@ -0,0 +1,197 @@ + + + CylinderWidget + + + + 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 + + + + Axis + + + 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 + + + + Radius + + + 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/ViewProviderFemPostFunction.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.cpp index 565b56fbc0..64b15d7167 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_CylinderWidget.h" #include "ui_PlaneWidget.h" #include "ui_SphereWidget.h" @@ -378,6 +379,164 @@ void ViewProviderFemPostFunction::onChanged(const App::Property* prop) { } +// *************************************************************************** + +PROPERTY_SOURCE(FemGui::ViewProviderFemPostCylinderFunction, FemGui::ViewProviderFemPostFunction) + +ViewProviderFemPostCylinderFunction::ViewProviderFemPostCylinderFunction() +{ + sPixmap = "fem-post-geo-cylinder"; + + setAutoScale(false); + + getGeometryNode()->addChild(ShapeNodes::postCylinder()); +} + +ViewProviderFemPostCylinderFunction::~ViewProviderFemPostCylinderFunction() +{ +} + +void ViewProviderFemPostCylinderFunction::draggerUpdate(SoDragger* m) +{ + Fem::FemPostCylinderFunction* func = static_cast(getObject()); + SoJackDragger* dragger = static_cast(m); + const SbVec3f& center = dragger->translation.getValue(); + SbVec3f norm(0, 0, 1); + dragger->rotation.getValue().multVec(norm, norm); + func->Center.setValue(center[0], center[1], center[2]); + func->Radius.setValue(dragger->scaleFactor.getValue()[0]); + func->Axis.setValue(norm[0], norm[1], norm[2]); +} + +void ViewProviderFemPostCylinderFunction::updateData(const App::Property* p) { + + Fem::FemPostCylinderFunction* func = static_cast(getObject()); + if (!isDragging() && (p == &func->Center || p == &func->Radius || p == &func->Axis)) { + Base::Vector3d trans = func->Center.getValue(); + Base::Vector3d axis = func->Axis.getValue(); + double radius = func->Radius.getValue(); + + SbMatrix translate; + SbRotation rot(SbVec3f(0,0,1), SbVec3f(axis.x, axis.y, axis.z)); + translate.setTransform(SbVec3f(trans.x, trans.y, trans.z), rot, SbVec3f(radius,radius,radius)); + getManipulator()->setMatrix(translate); + } + + Gui::ViewProviderDocumentObject::updateData(p); +} + +SoTransformManip* ViewProviderFemPostCylinderFunction::setupManipulator() +{ + return new SoJackManip; +} + +FunctionWidget* ViewProviderFemPostCylinderFunction::createControlWidget() +{ + return new CylinderWidget(); +} + +CylinderWidget::CylinderWidget() +{ + ui = new Ui_CylinderWidget(); + 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->axisX->setMinimumWidth(size.width()); + ui->axisY->setMinimumWidth(size.width()); + ui->axisZ->setMinimumWidth(size.width()); + ui->radius->setMinimumWidth(size.width()); + + int UserDecimals = Base::UnitsApi::getDecimals(); + ui->centerX->setDecimals(UserDecimals); + ui->centerY->setDecimals(UserDecimals); + ui->centerZ->setDecimals(UserDecimals); + ui->axisX->setDecimals(UserDecimals); + ui->axisY->setDecimals(UserDecimals); + ui->axisZ->setDecimals(UserDecimals); + + connect(ui->centerX, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &CylinderWidget::centerChanged); + connect(ui->centerY, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &CylinderWidget::centerChanged); + connect(ui->centerZ, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &CylinderWidget::centerChanged); + connect(ui->axisX, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &CylinderWidget::axisChanged); + connect(ui->axisY, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &CylinderWidget::axisChanged); + connect(ui->axisZ, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &CylinderWidget::axisChanged); + connect(ui->radius, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &CylinderWidget::radiusChanged); +} + +CylinderWidget::~CylinderWidget() +{ +} + +void CylinderWidget::applyPythonCode() +{ +} + +void CylinderWidget::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())->Radius.getUnit(); + ui->radius->setUnit(unit); + setBlockObjectUpdates(false); + onChange(static_cast(getObject())->Center); + onChange(static_cast(getObject())->Radius); + onChange(static_cast(getObject())->Axis); +} + +void CylinderWidget::onChange(const App::Property& p) +{ + setBlockObjectUpdates(true); + if (strcmp(p.getName(), "Axis") == 0) { + const Base::Vector3d& vec = static_cast(&p)->getValue(); + ui->axisX->setValue(vec.x); + ui->axisY->setValue(vec.y); + ui->axisZ->setValue(vec.z); + } + else if (strcmp(p.getName(), "Center") == 0) { + 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 (strcmp(p.getName(), "Radius") == 0) { + double val = static_cast(&p)->getValue(); + ui->radius->setValue(val); + } + setBlockObjectUpdates(false); +} + +void CylinderWidget::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 CylinderWidget::axisChanged(double) +{ + if (!blockObjectUpdates()) { + Base::Vector3d vec(ui->axisX->value().getValue(), ui->axisY->value().getValue(), + ui->axisZ->value().getValue()); + static_cast(getObject())->Axis.setValue(vec); + } +} + +void CylinderWidget::radiusChanged(double) +{ + if (!blockObjectUpdates()) { + static_cast(getObject())->Radius.setValue(ui->radius->value().getValue()); + } +} + + // *************************************************************************** PROPERTY_SOURCE(FemGui::ViewProviderFemPostPlaneFunction, FemGui::ViewProviderFemPostFunction) @@ -395,16 +554,7 @@ ViewProviderFemPostPlaneFunction::ViewProviderFemPostPlaneFunction() setAutoScale(true); //setup the visualisation geometry - SoCoordinate3* points = new SoCoordinate3(); - points->point.setNum(4); - points->point.set1Value(0, -0.5, -0.5, 0); - points->point.set1Value(1, -0.5, 0.5, 0); - points->point.set1Value(2, 0.5, 0.5, 0); - points->point.set1Value(3, 0.5, -0.5, 0); - points->point.set1Value(4, -0.5, -0.5, 0); - SoLineSet* line = new SoLineSet(); - getGeometryNode()->addChild(points); - getGeometryNode()->addChild(line); + getGeometryNode()->addChild(ShapeNodes::postPlane()); } ViewProviderFemPostPlaneFunction::~ViewProviderFemPostPlaneFunction() { @@ -588,29 +738,7 @@ ViewProviderFemPostSphereFunction::ViewProviderFemPostSphereFunction() { setAutoScale(false); //setup the visualisation geometry - SoCoordinate3* points = new SoCoordinate3(); - points->point.setNum(2 * 84); - int idx = 0; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 21; j++) { - points->point.set1Value(idx, SbVec3f(std::sin(2 * M_PI / 20 * j) * std::cos(M_PI / 4 * i), - std::sin(2 * M_PI / 20 * j) * std::sin(M_PI / 4 * i), - std::cos(2 * M_PI / 20 * j))); - ++idx; - } - } - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 21; j++) { - points->point.set1Value(idx, SbVec3f(std::sin(M_PI / 4 * i) * std::cos(2 * M_PI / 20 * j), - std::sin(M_PI / 4 * i) * std::sin(2 * M_PI / 20 * j), - std::cos(M_PI / 4 * i))); - ++idx; - } - } - - SoLineSet* line = new SoLineSet(); - getGeometryNode()->addChild(points); - getGeometryNode()->addChild(line); + getGeometryNode()->addChild(ShapeNodes::postSphere()); } ViewProviderFemPostSphereFunction::~ViewProviderFemPostSphereFunction() { @@ -747,4 +875,109 @@ void SphereWidget::radiusChanged(double) { } } +namespace FemGui +{ + +namespace ShapeNodes +{ + +SoGroup* postCylinder() +{ + SoCoordinate3* points = new SoCoordinate3(); + int nCirc = 20; + int nSide = 8; + float h = 3.; + points->point.setNum(2*(nCirc + 1 + nSide)); + + int idx = 0; + // top and bottom + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < nCirc + 1; ++j) { + points->point.set1Value(idx, SbVec3f(std::cos(2*M_PI/nCirc*j), + std::sin(2*M_PI/nCirc*j), + -h/2. + h*i)); + ++idx; + } + + } + // sides + for (int i = 0; i < nSide; ++i) { + for (int j = 0; j < 2; ++j) { + points->point.set1Value(idx, SbVec3f(std::cos(2*M_PI/nSide*i), + std::sin(2*M_PI/nSide*i), + -h/2. + h*j)); + ++idx; + } + } + // numVertices + int vert[nSide + 2]; + vert[0] = nCirc + 1; + vert[1] = nCirc + 1; + for (int i = 0; i < nSide; ++i) { + vert[i+2] = 2; + } + + SoLineSet* line = new SoLineSet(); + SoGroup* group = new SoGroup(); + line->numVertices.setValues(0,nSide + 2, vert); + + group->addChild(points); + group->addChild(line); + + return group; +} + +SoGroup* postPlane() +{ + SoCoordinate3* points = new SoCoordinate3(); + points->point.setNum(4); + points->point.set1Value(0, -0.5, -0.5, 0); + points->point.set1Value(1, -0.5, 0.5, 0); + points->point.set1Value(2, 0.5, 0.5, 0); + points->point.set1Value(3, 0.5, -0.5, 0); + points->point.set1Value(4, -0.5, -0.5, 0); + SoGroup* group = new SoGroup(); + SoLineSet* line = new SoLineSet(); + + group->addChild(points); + group->addChild(line); + + return group; +} + +SoGroup* postSphere() +{ + SoCoordinate3* points = new SoCoordinate3(); + points->point.setNum(2 * 84); + int idx = 0; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 21; j++) { + points->point.set1Value(idx, SbVec3f(std::sin(2 * M_PI / 20 * j) * std::cos(M_PI / 4 * i), + std::sin(2 * M_PI / 20 * j) * std::sin(M_PI / 4 * i), + std::cos(2 * M_PI / 20 * j))); + ++idx; + } + } + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 21; j++) { + points->point.set1Value(idx, SbVec3f(std::sin(M_PI / 4 * i) * std::cos(2 * M_PI / 20 * j), + std::sin(M_PI / 4 * i) * std::sin(2 * M_PI / 20 * j), + std::cos(M_PI / 4 * i))); + ++idx; + } + } + + SoGroup* group = new SoGroup(); + SoLineSet* line = new SoLineSet(); + + group->addChild(points); + group->addChild(line); + + return group; +} + +} //namespace ShapeNodes + +} //namespace FemGui + #include "moc_ViewProviderFemPostFunction.cpp" diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h index ca86b5df5c..9e67f91c8f 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h +++ b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h @@ -31,13 +31,15 @@ #include +class SoComposeMatrix; +class SoDragger; +class SoGroup; +class SoMatrixTransform; class SoScale; +class SoSphere; class SoSurroundScale; class SoTransformManip; -class SoComposeMatrix; -class SoMatrixTransform; -class SoDragger; -class SoSphere; +class Ui_CylinderWidget; class Ui_PlaneWidget; class Ui_SphereWidget; @@ -151,6 +153,43 @@ private: bool m_autoscale, m_isDragging, m_autoRecompute; }; +// *************************************************************************** +class FemGuiExport CylinderWidget : public FunctionWidget { + + Q_OBJECT +public: + CylinderWidget(); + ~CylinderWidget() override; + + void applyPythonCode() override; + void onChange(const App::Property& p) override; + void setViewProvider(ViewProviderFemPostFunction* view) override; + +private Q_SLOTS: + void centerChanged(double); + void axisChanged(double); + void radiusChanged(double); + +private: + Ui_CylinderWidget* ui; +}; + +class FemGuiExport ViewProviderFemPostCylinderFunction : public ViewProviderFemPostFunction +{ + PROPERTY_HEADER_WITH_OVERRIDE(FemGui::ViewProviderFemPostCylinderFunction); + +public: + ViewProviderFemPostCylinderFunction(); + ~ViewProviderFemPostCylinderFunction() override; + + SoTransformManip* setupManipulator() override; + FunctionWidget* createControlWidget() override; + +protected: + void draggerUpdate(SoDragger* mat) override; + void updateData(const App::Property*) override; +}; + // *************************************************************************** class FemGuiExport PlaneWidget : public FunctionWidget { @@ -231,6 +270,15 @@ protected: void updateData(const App::Property*) override; }; +namespace ShapeNodes +{ + + SoGroup* postCylinder(); + SoGroup* postPlane(); + SoGroup* postSphere(); + +} //namespace ShapeNodes + } //namespace FemGui