diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 0e86aa9bdb..11b078c97a 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -2027,6 +2027,7 @@ void Application::initTypes() App::PropertyMagneticFluxDensity ::init(); App::PropertyMagnetization ::init(); App::PropertyMass ::init(); + App::PropertyMoment ::init(); App::PropertyPressure ::init(); App::PropertyPower ::init(); App::PropertyShearModulus ::init(); diff --git a/src/App/PropertyUnits.cpp b/src/App/PropertyUnits.cpp index 6c0f60f8a8..867555456c 100644 --- a/src/App/PropertyUnits.cpp +++ b/src/App/PropertyUnits.cpp @@ -555,6 +555,17 @@ PropertyMass::PropertyMass() setUnit(Base::Unit::Mass); } +//************************************************************************** +// PropertyMoment +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TYPESYSTEM_SOURCE(App::PropertyMoment, App::PropertyQuantity) + +PropertyMoment::PropertyMoment() +{ + setUnit(Base::Unit::Moment); +} + //************************************************************************** // PropertyPressure //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/src/App/PropertyUnits.h b/src/App/PropertyUnits.h index fc32e080b1..c0854e47c1 100644 --- a/src/App/PropertyUnits.h +++ b/src/App/PropertyUnits.h @@ -540,6 +540,19 @@ public: ~PropertyMass() override = default; }; +/** Moment property + * This is a property for representing moment. It is basically a float + * property. On the Gui it has a quantity like N*m. + */ +class AppExport PropertyMoment: public PropertyQuantity +{ + TYPESYSTEM_HEADER_WITH_OVERRIDE(); + +public: + PropertyMoment(); + ~PropertyMoment() override = default; +}; + /** Pressure property * This is a property for representing pressure. It basically a float * property. On the Gui it has a quantity like Pa. diff --git a/src/Base/Unit.cpp b/src/Base/Unit.cpp index 7aa14c7526..46a5dbe3ef 100644 --- a/src/Base/Unit.cpp +++ b/src/Base/Unit.cpp @@ -623,6 +623,9 @@ QString Unit::getTypeString() const if (*this == Unit::YoungsModulus) { return QString::fromLatin1("YoungsModulus"); } + if (*this == Unit::Moment) { + return QString::fromLatin1("Moment"); + } return {}; } @@ -664,6 +667,7 @@ const Unit Unit::MagneticFieldStrength (-1,0,0,1); const Unit Unit::MagneticFlux (2,1,-2,-1); const Unit Unit::MagneticFluxDensity (0,1,-2,-1); const Unit Unit::Magnetization (-1,0,0,1); +const Unit Unit::Moment (2, 1, -2); const Unit Unit::Pressure (-1,1,-2); const Unit Unit::Power (2, 1, -3); const Unit Unit::ShearModulus (-1,1,-2); diff --git a/src/Base/Unit.h b/src/Base/Unit.h index 77b325a784..5e957a97a7 100644 --- a/src/Base/Unit.h +++ b/src/Base/Unit.h @@ -155,6 +155,7 @@ public: static const Unit Force; static const Unit Work; static const Unit Power; + static const Unit Moment; static const Unit SpecificEnergy; static const Unit ThermalConductivity; diff --git a/src/Base/UnitsSchemaInternal.cpp b/src/Base/UnitsSchemaInternal.cpp index 355e8307c7..4b141fd247 100644 --- a/src/Base/UnitsSchemaInternal.cpp +++ b/src/Base/UnitsSchemaInternal.cpp @@ -272,6 +272,24 @@ UnitsSchemaInternal::schemaTranslate(const Quantity& quant, double& factor, QStr factor = 1e9; } } + // else if (unit == Unit::Moment) { + // if (UnitValue < 1e6) { + // unitString = QString::fromLatin1("mNm"); + // factor = 1e3; + // } + // else if (UnitValue < 1e9) { + // unitString = QString::fromLatin1("Nm"); + // factor = 1e6; + // } + // else if (UnitValue < 1e12) { + // unitString = QString::fromLatin1("kNm"); + // factor = 1e9; + // } + // else { + // unitString = QString::fromLatin1("MNm"); + // factor = 1e12; + // } + // } else if (unit == Unit::Power) { if (UnitValue < 1e6) { unitString = QString::fromLatin1("mW"); diff --git a/src/Base/UnitsSchemaMKS.cpp b/src/Base/UnitsSchemaMKS.cpp index aba27295ab..96034a9495 100644 --- a/src/Base/UnitsSchemaMKS.cpp +++ b/src/Base/UnitsSchemaMKS.cpp @@ -261,6 +261,24 @@ QString UnitsSchemaMKS::schemaTranslate(const Quantity& quant, double& factor, Q factor = 1e9; } } + // else if (unit == Unit::Moment) { + // if (UnitValue < 1e6) { + // unitString = QString::fromLatin1("mNm"); + // factor = 1e3; + // } + // else if (UnitValue < 1e9) { + // unitString = QString::fromLatin1("Nm"); + // factor = 1e6; + // } + // else if (UnitValue < 1e12) { + // unitString = QString::fromLatin1("kNm"); + // factor = 1e9; + // } + // else { + // unitString = QString::fromLatin1("MNm"); + // factor = 1e12; + // } + // } else if (unit == Unit::Power) { if (UnitValue < 1e6) { unitString = QString::fromLatin1("mW"); diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index c37cb4f535..7649fc53fe 100644 --- a/src/Mod/Fem/App/AppFem.cpp +++ b/src/Mod/Fem/App/AppFem.cpp @@ -41,6 +41,7 @@ #include "FemConstraintPlaneRotation.h" #include "FemConstraintPressure.h" #include "FemConstraintPulley.h" +#include "FemConstraintRigidBody.h" #include "FemConstraintSpring.h" #include "FemConstraintTemperature.h" #include "FemConstraintTransform.h" @@ -142,6 +143,7 @@ PyMOD_INIT_FUNC(Fem) Fem::ConstraintContact ::init(); Fem::ConstraintDisplacement ::init(); Fem::ConstraintFixed ::init(); + Fem::ConstraintRigidBody ::init(); Fem::ConstraintFluidBoundary ::init(); Fem::ConstraintForce ::init(); Fem::ConstraintGear ::init(); diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index dd9250a00c..ab96acb6ed 100644 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -148,6 +148,8 @@ SET(FemConstraints_SRCS FemConstraintBearing.cpp FemConstraintFixed.cpp FemConstraintFixed.h + FemConstraintRigidBody.cpp + FemConstraintRigidBody.h FemConstraintForce.cpp FemConstraintForce.h FemConstraintFluidBoundary.cpp diff --git a/src/Mod/Fem/App/FemConstraintRigidBody.cpp b/src/Mod/Fem/App/FemConstraintRigidBody.cpp new file mode 100644 index 0000000000..8a10cf1315 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintRigidBody.cpp @@ -0,0 +1,128 @@ +/*************************************************************************** + * Copyright (c) 2022 Ajinkya Dahale * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#include "FemConstraintRigidBody.h" + + +using namespace Fem; + +PROPERTY_SOURCE(Fem::ConstraintRigidBody, Fem::Constraint) + +const char* ConstraintRigidBody::boundaryModeEnum[] = {"Free", "Constraint", "Load", nullptr}; + +ConstraintRigidBody::ConstraintRigidBody() +{ + ADD_PROPERTY_TYPE(ReferenceNode, + (0.0, 0.0, 0.0), + "ConstraintRigidBody", + App::Prop_Output, + "Reference node position"); + ADD_PROPERTY_TYPE(Displacement, + (0.0, 0.0, 0.0), + "ConstraintRigidBody", + App::Prop_Output, + "Reference node displacement"); + ADD_PROPERTY_TYPE(Rotation, + (Base::Rotation(0.0, 0.0, 0.0, 1.0)), + "ConstraintRigidBody", + App::Prop_Output, + "Reference node rotation"); + ADD_PROPERTY_TYPE(ForceX, + (0.0), + "ConstraintRigidBody", + App::Prop_Output, + "Applied force in X direction"); + ADD_PROPERTY_TYPE(ForceY, + (0.0), + "ConstraintRigidBody", + App::Prop_Output, + "Applied force in Y direction"); + ADD_PROPERTY_TYPE(ForceZ, + (0.0), + "ConstraintRigidBody", + App::Prop_Output, + "Applied force in Z direction"); + ADD_PROPERTY_TYPE(MomentX, + (0.0), + "ConstraintRigidBody", + App::Prop_Output, + "Applied moment in X direction"); + ADD_PROPERTY_TYPE(MomentY, + (0.0), + "ConstraintRigidBody", + App::Prop_Output, + "Applied moment in Y direction"); + ADD_PROPERTY_TYPE(MomentZ, + (0.0), + "ConstraintRigidBody", + App::Prop_Output, + "Applied moment in Z direction"); + ADD_PROPERTY_TYPE(TranslationalModeX, + ("Free"), + "ConstraintRigidBody", + App::Prop_Output, + "X-direction displacement/force mode"); + ADD_PROPERTY_TYPE(TranslationalModeY, + ("Free"), + "ConstraintRigidBody", + App::Prop_Output, + "Y-direction displacement/force mode"); + ADD_PROPERTY_TYPE(TranslationalModeZ, + ("Free"), + "ConstraintRigidBody", + App::Prop_Output, + "Z-direction displacement/force mode"); + ADD_PROPERTY_TYPE(RotationalModeX, + ("None"), + "ConstraintRigidBody", + App::Prop_Output, + "X-direction rotation/moment mode"); + ADD_PROPERTY_TYPE(RotationalModeY, + ("None"), + "ConstraintRigidBody", + App::Prop_Output, + "Y-direction rotation/moment mode"); + ADD_PROPERTY_TYPE(RotationalModeZ, + ("None"), + "ConstraintRigidBody", + App::Prop_Output, + "Z-direction rotation/moment mode"); + + TranslationalModeX.setEnums(boundaryModeEnum); + TranslationalModeY.setEnums(boundaryModeEnum); + TranslationalModeZ.setEnums(boundaryModeEnum); + RotationalModeX.setEnums(boundaryModeEnum); + RotationalModeY.setEnums(boundaryModeEnum); + RotationalModeZ.setEnums(boundaryModeEnum); +} + +App::DocumentObjectExecReturn* ConstraintRigidBody::execute() +{ + return Constraint::execute(); +} + +void ConstraintRigidBody::onChanged(const App::Property* prop) +{ + Constraint::onChanged(prop); +} diff --git a/src/Mod/Fem/App/FemConstraintRigidBody.h b/src/Mod/Fem/App/FemConstraintRigidBody.h new file mode 100644 index 0000000000..28ff18229a --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintRigidBody.h @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (c) 2022 Ajinkya Dahale * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef FEM_CONSTRAINTRIGIDBODY_H +#define FEM_CONSTRAINTRIGIDBODY_H + +#include "FemConstraint.h" + + +namespace Fem +{ + +class FemExport ConstraintRigidBody: public Fem::Constraint +{ + PROPERTY_HEADER_WITH_OVERRIDE(Fem::ConstraintRigidBody); + +public: + /// Constructor + ConstraintRigidBody(); + + // Rigid Body parameters + App::PropertyPosition ReferenceNode; + App::PropertyPosition Displacement; + App::PropertyRotation Rotation; + App::PropertyForce ForceX; + App::PropertyForce ForceY; + App::PropertyForce ForceZ; + App::PropertyMoment MomentX; + App::PropertyMoment MomentY; + App::PropertyMoment MomentZ; + App::PropertyEnumeration TranslationalModeX; + App::PropertyEnumeration TranslationalModeY; + App::PropertyEnumeration TranslationalModeZ; + App::PropertyEnumeration RotationalModeX; + App::PropertyEnumeration RotationalModeY; + App::PropertyEnumeration RotationalModeZ; + + /// recalculate the object + App::DocumentObjectExecReturn* execute() override; + + /// returns the type name of the ViewProvider + const char* getViewProviderName() const override + { + return "FemGui::ViewProviderFemConstraintRigidBody"; + } + +protected: + void onChanged(const App::Property* prop) override; + +private: + static const char* boundaryModeEnum[]; +}; + +} // namespace Fem + + +#endif // FEM_CONSTRAINTRIGIDBODY_H diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 91ed22746b..97a64ed510 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -231,6 +231,8 @@ SET(FemSolverCalculix_SRCS femsolver/calculix/write_constraint_initialtemperature.py femsolver/calculix/write_constraint_planerotation.py femsolver/calculix/write_constraint_pressure.py + femsolver/calculix/write_constraint_rigidbody.py + femsolver/calculix/write_constraint_rigidbody_step.py femsolver/calculix/write_constraint_sectionprint.py femsolver/calculix/write_constraint_selfweight.py femsolver/calculix/write_constraint_temperature.py diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index c4f36d46a2..23151146da 100644 --- a/src/Mod/Fem/Gui/AppFemGui.cpp +++ b/src/Mod/Fem/Gui/AppFemGui.cpp @@ -51,6 +51,7 @@ #include "ViewProviderFemConstraintContact.h" #include "ViewProviderFemConstraintDisplacement.h" #include "ViewProviderFemConstraintFixed.h" +#include "ViewProviderFemConstraintRigidBody.h" #include "ViewProviderFemConstraintForce.h" #include "ViewProviderFemConstraintFluidBoundary.h" #include "ViewProviderFemConstraintGear.h" @@ -120,6 +121,7 @@ PyMOD_INIT_FUNC(FemGui) FemGui::ViewProviderFemConstraintContact ::init(); FemGui::ViewProviderFemConstraintDisplacement ::init(); FemGui::ViewProviderFemConstraintFixed ::init(); + FemGui::ViewProviderFemConstraintRigidBody ::init(); FemGui::ViewProviderFemConstraintFluidBoundary ::init(); FemGui::ViewProviderFemConstraintForce ::init(); FemGui::ViewProviderFemConstraintGear ::init(); diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 1d07f4e4f3..65d871e137 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -63,6 +63,7 @@ set(FemGui_UIC_SRCS TaskFemConstraint.ui TaskFemConstraintBearing.ui TaskFemConstraintFixed.ui + TaskFemConstraintRigidBody.ui TaskFemConstraintForce.ui TaskFemConstraintFluidBoundary.ui TaskFemConstraintPressure.ui @@ -134,6 +135,9 @@ SET(FemGui_DLG_SRCS TaskFemConstraintFixed.ui TaskFemConstraintFixed.cpp TaskFemConstraintFixed.h + TaskFemConstraintRigidBody.ui + TaskFemConstraintRigidBody.cpp + TaskFemConstraintRigidBody.h TaskFemConstraintForce.ui TaskFemConstraintForce.cpp TaskFemConstraintForce.h @@ -210,6 +214,8 @@ SET(FemGui_SRCS_ViewProvider ViewProviderFemConstraintBearing.h ViewProviderFemConstraintFixed.cpp ViewProviderFemConstraintFixed.h + ViewProviderFemConstraintRigidBody.cpp + ViewProviderFemConstraintRigidBody.h ViewProviderFemConstraintForce.cpp ViewProviderFemConstraintForce.h ViewProviderFemConstraintFluidBoundary.cpp @@ -354,6 +360,7 @@ SET(FemGuiSymbol_IV Resources/symbols/ConstraintHeatFlux.iv Resources/symbols/ConstraintPlaneRotation.iv Resources/symbols/ConstraintPressure.iv + Resources/symbols/ConstraintRigidBody.iv Resources/symbols/ConstraintSpring.iv Resources/symbols/ConstraintTemperature.iv Resources/symbols/ConstraintTie.iv diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 9c4c8a7732..31d85d49a6 100644 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -387,6 +387,58 @@ bool CmdFemConstraintFixed::isActive() } +//================================================================================================ +DEF_STD_CMD_A(CmdFemConstraintRigidBody) + +CmdFemConstraintRigidBody::CmdFemConstraintRigidBody() + : Command("FEM_ConstraintRigidBody") +{ + sAppModule = "Fem"; + sGroup = QT_TR_NOOP("Fem"); + sMenuText = QT_TR_NOOP("Constraint rigid body"); + sToolTipText = QT_TR_NOOP("Creates a FEM constraint for a rigid body"); + sWhatsThis = "FEM_ConstraintRigidBody"; + sStatusTip = sToolTipText; + sPixmap = "FEM_ConstraintRigidBody"; +} + +void CmdFemConstraintRigidBody::activated(int) +{ + Fem::FemAnalysis* Analysis; + + if (getConstraintPrerequisits(&Analysis)) { + return; + } + + std::string FeatName = getUniqueObjectName("ConstraintRigidBody"); + + openCommand(QT_TRANSLATE_NOOP("Command", "Make FEM constraint fixed geometry")); + doCommand(Doc, + "App.activeDocument().addObject(\"Fem::ConstraintRigidBody\",\"%s\")", + FeatName.c_str()); + doCommand(Doc, + "App.activeDocument().%s.Scale = 1", + FeatName.c_str()); // OvG: set initial scale to 1 + doCommand(Doc, + "App.activeDocument().%s.addObject(App.activeDocument().%s)", + Analysis->getNameInDocument(), + FeatName.c_str()); + + doCommand(Doc, + "%s", + gethideMeshShowPartStr(FeatName).c_str()); // OvG: Hide meshes and show parts + + updateActive(); + + doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); +} + +bool CmdFemConstraintRigidBody::isActive() +{ + return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); +} + + //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintFluidBoundary) @@ -2625,6 +2677,7 @@ void CreateFemCommands() rcCmdMgr.addCommand(new CmdFemConstraintContact()); rcCmdMgr.addCommand(new CmdFemConstraintDisplacement()); rcCmdMgr.addCommand(new CmdFemConstraintFixed()); + rcCmdMgr.addCommand(new CmdFemConstraintRigidBody()); rcCmdMgr.addCommand(new CmdFemConstraintFluidBoundary()); rcCmdMgr.addCommand(new CmdFemConstraintForce()); rcCmdMgr.addCommand(new CmdFemConstraintGear()); diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc index 9fda988706..4ad05ea761 100755 --- a/src/Mod/Fem/Gui/Resources/Fem.qrc +++ b/src/Mod/Fem/Gui/Resources/Fem.qrc @@ -29,6 +29,7 @@ icons/FEM_ConstraintPlaneRotation.svg icons/FEM_ConstraintPressure.svg icons/FEM_ConstraintPulley.svg + icons/FEM_ConstraintRigidBody.svg icons/FEM_ConstraintSectionPrint.svg icons/FEM_ConstraintSelfWeight.svg icons/FEM_ConstraintSpring.svg diff --git a/src/Mod/Fem/Gui/Resources/icons/FEM_ConstraintRigidBody.svg b/src/Mod/Fem/Gui/Resources/icons/FEM_ConstraintRigidBody.svg new file mode 100644 index 0000000000..c35f004947 --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/icons/FEM_ConstraintRigidBody.svg @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + [vdwalts] + + + 2016-08-01 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/ + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Fem/Gui/Resources/symbols/ConstraintRigidBody.iv b/src/Mod/Fem/Gui/Resources/symbols/ConstraintRigidBody.iv new file mode 100644 index 0000000000..66d3d0fc8b --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/symbols/ConstraintRigidBody.iv @@ -0,0 +1,32 @@ +#Inventor V2.1 ascii + + +Separator { + + Separator { + + Translation { + translation 0 2.5 0 + } + Sphere { + radius 0.5 + + } + Translation { + translation 0 -1.25 0 + + } + Cylinder { + radius 0.25 + height 2.5 + + } + } + Separator { + + Sphere { + radius 0.25 + + } + } +} diff --git a/src/Mod/Fem/Gui/TaskFemConstraintRigidBody.cpp b/src/Mod/Fem/Gui/TaskFemConstraintRigidBody.cpp new file mode 100644 index 0000000000..596b0105af --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintRigidBody.cpp @@ -0,0 +1,747 @@ +/*************************************************************************** + * Copyright (c) 2022 Ajinkya Dahale * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "TaskFemConstraintRigidBody.h" +#include "ui_TaskFemConstraintRigidBody.h" + + +using namespace FemGui; +using namespace Gui; + +/* TRANSLATOR FemGui::TaskFemConstraintRigidBody */ + +TaskFemConstraintRigidBody::TaskFemConstraintRigidBody( + ViewProviderFemConstraintRigidBody* ConstraintView, + QWidget* parent) + : TaskFemConstraintOnBoundary(ConstraintView, parent, "FEM_ConstraintRigidBody") +{ // Note change "RigidBody" in line above to new constraint name + proxy = new QWidget(this); + ui = new Ui_TaskFemConstraintRigidBody(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + // create a context menu for the listview of the references + createDeleteAction(ui->lw_references); + deleteAction->connect(deleteAction, + &QAction::triggered, + this, + &TaskFemConstraintRigidBody::onReferenceDeleted); + + connect(ui->lw_references, + &QListWidget::currentItemChanged, + this, + &TaskFemConstraintRigidBody::setSelection); + connect(ui->lw_references, + &QListWidget::itemClicked, + this, + &TaskFemConstraintRigidBody::setSelection); + connect(ui->cb_x_trans_mode, + qOverload(&QComboBox::activated), + this, + &TaskFemConstraintRigidBody::onTransModeXChanged); + connect(ui->cb_y_trans_mode, + qOverload(&QComboBox::activated), + this, + &TaskFemConstraintRigidBody::onTransModeYChanged); + connect(ui->cb_z_trans_mode, + qOverload(&QComboBox::activated), + this, + &TaskFemConstraintRigidBody::onTransModeZChanged); + connect(ui->cb_x_rot_mode, + qOverload(&QComboBox::activated), + this, + &TaskFemConstraintRigidBody::onRotModeXChanged); + connect(ui->cb_y_rot_mode, + qOverload(&QComboBox::activated), + this, + &TaskFemConstraintRigidBody::onRotModeYChanged); + connect(ui->cb_z_rot_mode, + qOverload(&QComboBox::activated), + this, + &TaskFemConstraintRigidBody::onRotModeZChanged); + + this->groupLayout()->addWidget(proxy); + + /* Note: */ + // Get the feature data + auto pcConstraint = static_cast(ConstraintView->getObject()); + + const Base::Vector3d& refNode = pcConstraint->ReferenceNode.getValue(); + const Base::Vector3d& disp = pcConstraint->Displacement.getValue(); + Base::Vector3d rotDir; + double rotAngleRad; + pcConstraint->Rotation.getValue().getValue(rotDir, rotAngleRad); + Base::Quantity rotAngle(rotAngleRad, QString::fromUtf8("rad")); + Base::Quantity forceX = pcConstraint->ForceX.getQuantityValue(); + Base::Quantity forceY = pcConstraint->ForceY.getQuantityValue(); + Base::Quantity forceZ = pcConstraint->ForceZ.getQuantityValue(); + Base::Quantity momentX = pcConstraint->MomentX.getQuantityValue(); + Base::Quantity momentY = pcConstraint->MomentY.getQuantityValue(); + Base::Quantity momentZ = pcConstraint->MomentZ.getQuantityValue(); + + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + // Fill data into dialog elements + ui->qsb_ref_node_x->setValue(refNode.x); + ui->qsb_ref_node_y->setValue(refNode.y); + ui->qsb_ref_node_z->setValue(refNode.z); + ui->qsb_ref_node_x->bind( + App::ObjectIdentifier::parse(pcConstraint, std::string("ReferenceNode.x"))); + ui->qsb_ref_node_y->bind( + App::ObjectIdentifier::parse(pcConstraint, std::string("ReferenceNode.y"))); + ui->qsb_ref_node_z->bind( + App::ObjectIdentifier::parse(pcConstraint, std::string("ReferenceNode.z"))); + ui->qsb_ref_node_x->setMinimum(-FLOAT_MAX); + ui->qsb_ref_node_x->setMaximum(FLOAT_MAX); + ui->qsb_ref_node_y->setMinimum(-FLOAT_MAX); + ui->qsb_ref_node_y->setMaximum(FLOAT_MAX); + ui->qsb_ref_node_z->setMinimum(-FLOAT_MAX); + ui->qsb_ref_node_z->setMaximum(FLOAT_MAX); + + ui->qsb_disp_x->setValue(disp.x); + ui->qsb_disp_y->setValue(disp.y); + ui->qsb_disp_z->setValue(disp.z); + ui->qsb_disp_x->bind(App::ObjectIdentifier::parse(pcConstraint, std::string("Displacement.x"))); + ui->qsb_disp_y->bind(App::ObjectIdentifier::parse(pcConstraint, std::string("Displacement.y"))); + ui->qsb_disp_z->bind(App::ObjectIdentifier::parse(pcConstraint, std::string("Displacement.z"))); + ui->qsb_disp_x->setMinimum(-FLOAT_MAX); + ui->qsb_disp_x->setMaximum(FLOAT_MAX); + ui->qsb_disp_y->setMinimum(-FLOAT_MAX); + ui->qsb_disp_y->setMaximum(FLOAT_MAX); + ui->qsb_disp_z->setMinimum(-FLOAT_MAX); + ui->qsb_disp_z->setMaximum(FLOAT_MAX); + + ui->spb_rot_axis_x->setValue(rotDir.x); + ui->spb_rot_axis_y->setValue(rotDir.y); + ui->spb_rot_axis_z->setValue(rotDir.z); + ui->qsb_rot_angle->setValue(rotAngle.getValueAs(Base::Quantity::Degree)); + ui->spb_rot_axis_x->bind( + App::ObjectIdentifier::parse(pcConstraint, std::string("Rotation.Axis.x"))); + ui->spb_rot_axis_y->bind( + App::ObjectIdentifier::parse(pcConstraint, std::string("Rotation.Axis.y"))); + ui->spb_rot_axis_z->bind( + App::ObjectIdentifier::parse(pcConstraint, std::string("Rotation.Axis.z"))); + ui->qsb_rot_angle->bind( + App::ObjectIdentifier::parse(pcConstraint, std::string("Rotation.Angle"))); + ui->spb_rot_axis_x->setMinimum(-FLOAT_MAX); + ui->spb_rot_axis_x->setMaximum(FLOAT_MAX); + ui->spb_rot_axis_y->setMinimum(-FLOAT_MAX); + ui->spb_rot_axis_y->setMaximum(FLOAT_MAX); + ui->spb_rot_axis_z->setMinimum(-FLOAT_MAX); + ui->spb_rot_axis_z->setMaximum(FLOAT_MAX); + ui->qsb_rot_angle->setMinimum(-FLOAT_MAX); + ui->qsb_rot_angle->setMaximum(FLOAT_MAX); + + ui->qsb_force_x->setValue(forceX); + ui->qsb_force_y->setValue(forceY); + ui->qsb_force_z->setValue(forceZ); + ui->qsb_force_x->bind(pcConstraint->ForceX); + ui->qsb_force_y->bind(pcConstraint->ForceY); + ui->qsb_force_z->bind(pcConstraint->ForceZ); + ui->qsb_force_x->setMinimum(-FLOAT_MAX); + ui->qsb_force_x->setMaximum(FLOAT_MAX); + ui->qsb_force_y->setMinimum(-FLOAT_MAX); + ui->qsb_force_y->setMaximum(FLOAT_MAX); + ui->qsb_force_z->setMinimum(-FLOAT_MAX); + ui->qsb_force_z->setMaximum(FLOAT_MAX); + + ui->qsb_moment_x->setValue(momentX); + ui->qsb_moment_y->setValue(momentY); + ui->qsb_moment_z->setValue(momentZ); + ui->qsb_moment_x->bind(pcConstraint->MomentX); + ui->qsb_moment_y->bind(pcConstraint->MomentY); + ui->qsb_moment_z->bind(pcConstraint->MomentZ); + ui->qsb_moment_x->setMinimum(-FLOAT_MAX); + ui->qsb_moment_x->setMaximum(FLOAT_MAX); + ui->qsb_moment_y->setMinimum(-FLOAT_MAX); + ui->qsb_moment_y->setMaximum(FLOAT_MAX); + ui->qsb_moment_z->setMinimum(-FLOAT_MAX); + ui->qsb_moment_z->setMaximum(FLOAT_MAX); + + QStringList modeList; + + App::PropertyEnumeration* transMode = &pcConstraint->TranslationalModeX; + for (auto item : transMode->getEnumVector()) { + modeList << QString::fromUtf8(item.c_str()); + } + ui->cb_x_trans_mode->addItems(modeList); + ui->cb_y_trans_mode->addItems(modeList); + ui->cb_z_trans_mode->addItems(modeList); + ui->cb_x_trans_mode->setCurrentIndex(pcConstraint->TranslationalModeX.getValue()); + ui->cb_y_trans_mode->setCurrentIndex(pcConstraint->TranslationalModeY.getValue()); + ui->cb_z_trans_mode->setCurrentIndex(pcConstraint->TranslationalModeZ.getValue()); + + modeList.clear(); + App::PropertyEnumeration* rotMode = &pcConstraint->RotationalModeX; + for (auto item : rotMode->getEnumVector()) { + modeList << QString::fromUtf8(item.c_str()); + } + ui->cb_x_rot_mode->addItems(modeList); + ui->cb_y_rot_mode->addItems(modeList); + ui->cb_z_rot_mode->addItems(modeList); + ui->cb_x_rot_mode->setCurrentIndex(pcConstraint->RotationalModeX.getValue()); + ui->cb_y_rot_mode->setCurrentIndex(pcConstraint->RotationalModeY.getValue()); + ui->cb_z_rot_mode->setCurrentIndex(pcConstraint->RotationalModeZ.getValue()); + + onTransModeXChanged(pcConstraint->TranslationalModeX.getValue()); + onTransModeYChanged(pcConstraint->TranslationalModeY.getValue()); + onTransModeZChanged(pcConstraint->TranslationalModeZ.getValue()); + onRotModeXChanged(pcConstraint->RotationalModeX.getValue()); + onRotModeYChanged(pcConstraint->RotationalModeY.getValue()); + onRotModeZChanged(pcConstraint->RotationalModeZ.getValue()); + + ui->lw_references->clear(); + for (std::size_t i = 0; i < Objects.size(); i++) { + ui->lw_references->addItem(makeRefText(Objects[i], SubElements[i])); + } + if (!Objects.empty()) { + ui->lw_references->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); + } + + // Selection buttons + buttonGroup->addButton(ui->btnAdd, (int)SelectionChangeModes::refAdd); + buttonGroup->addButton(ui->btnRemove, (int)SelectionChangeModes::refRemove); + + updateUI(); +} + +TaskFemConstraintRigidBody::~TaskFemConstraintRigidBody() +{ + delete ui; +} + +void TaskFemConstraintRigidBody::updateUI() +{ + if (ui->lw_references->model()->rowCount() == 0) { + // Go into reference selection mode if no reference has been selected yet + onButtonReference(true); + return; + } +} + +void TaskFemConstraintRigidBody::addToSelection() +{ + std::vector selection = + Gui::Selection().getSelectionEx(); // gets vector of selected objects of active document + if (selection.empty()) { + QMessageBox::warning(this, tr("Selection error"), tr("Nothing selected!")); + return; + } + Fem::ConstraintRigidBody* pcConstraint = + static_cast(ConstraintView->getObject()); + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + for (std::vector::iterator it = selection.begin(); it != selection.end(); + ++it) { // for every selected object + if (!it->isObjectTypeOf(Part::Feature::getClassTypeId())) { + QMessageBox::warning(this, tr("Selection error"), tr("Selected object is not a part!")); + return; + } + std::vector subNames = it->getSubNames(); + App::DocumentObject* obj = + ConstraintView->getObject()->getDocument()->getObject(it->getFeatName()); + for (size_t subIt = 0; subIt < (subNames.size()); + ++subIt) { // for every selected sub element + bool addMe = true; + for (std::vector::iterator itr = + std::find(SubElements.begin(), SubElements.end(), subNames[subIt]); + itr != SubElements.end(); + itr = std::find(++itr, + SubElements.end(), + subNames[subIt])) { // for every sub element in selection that + // matches one in old list + if (obj + == Objects[std::distance( + SubElements.begin(), + itr)]) { // if selected sub element's object equals the one in old list + // then it was added before so don't add + addMe = false; + } + } + // limit constraint such that only vertexes or faces or edges can be used depending on + // what was selected first + std::string searchStr; + if (subNames[subIt].find("Vertex") != std::string::npos) { + searchStr = "Vertex"; + } + else if (subNames[subIt].find("Edge") != std::string::npos) { + searchStr = "Edge"; + } + else { + searchStr = "Face"; + } + for (size_t iStr = 0; iStr < (SubElements.size()); ++iStr) { + if (SubElements[iStr].find(searchStr) == std::string::npos) { + QString msg = tr( + "Only one type of selection (vertex,face or edge) per constraint allowed!"); + QMessageBox::warning(this, tr("Selection error"), msg); + addMe = false; + break; + } + } + if (addMe) { + QSignalBlocker block(ui->lw_references); + Objects.push_back(obj); + SubElements.push_back(subNames[subIt]); + ui->lw_references->addItem(makeRefText(obj, subNames[subIt])); + } + } + } + // Update UI + pcConstraint->References.setValues(Objects, SubElements); + updateUI(); +} + +void TaskFemConstraintRigidBody::removeFromSelection() +{ + std::vector selection = + Gui::Selection().getSelectionEx(); // gets vector of selected objects of active document + if (selection.empty()) { + QMessageBox::warning(this, tr("Selection error"), tr("Nothing selected!")); + return; + } + Fem::ConstraintRigidBody* pcConstraint = + static_cast(ConstraintView->getObject()); + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + std::vector itemsToDel; + for (std::vector::iterator it = selection.begin(); it != selection.end(); + ++it) { // for every selected object + if (!it->isObjectTypeOf(Part::Feature::getClassTypeId())) { + QMessageBox::warning(this, tr("Selection error"), tr("Selected object is not a part!")); + return; + } + const std::vector& subNames = it->getSubNames(); + App::DocumentObject* obj = it->getObject(); + + for (size_t subIt = 0; subIt < (subNames.size()); + ++subIt) { // for every selected sub element + for (std::vector::iterator itr = + std::find(SubElements.begin(), SubElements.end(), subNames[subIt]); + itr != SubElements.end(); + itr = std::find(++itr, + SubElements.end(), + subNames[subIt])) { // for every sub element in selection that + // matches one in old list + if (obj + == Objects[std::distance( + SubElements.begin(), + itr)]) { // if selected sub element's object equals the one in old list + // then it was added before so mark for deletion + itemsToDel.push_back(std::distance(SubElements.begin(), itr)); + } + } + } + } + std::sort(itemsToDel.begin(), itemsToDel.end()); + while (!itemsToDel.empty()) { + Objects.erase(Objects.begin() + itemsToDel.back()); + SubElements.erase(SubElements.begin() + itemsToDel.back()); + itemsToDel.pop_back(); + } + // Update UI + { + QSignalBlocker block(ui->lw_references); + ui->lw_references->clear(); + for (unsigned int j = 0; j < Objects.size(); j++) { + ui->lw_references->addItem(makeRefText(Objects[j], SubElements[j])); + } + } + pcConstraint->References.setValues(Objects, SubElements); + updateUI(); +} + +void TaskFemConstraintRigidBody::onReferenceDeleted() +{ + TaskFemConstraintRigidBody::removeFromSelection(); +} + +void TaskFemConstraintRigidBody::onRotModeXChanged(int item) +{ + const char* val = static_cast(ConstraintView->getObject()) + ->RotationalModeX.getEnumVector()[item] + .c_str(); + + if (strcmp(val, "Free") == 0) { + ui->spb_rot_axis_x->setEnabled(false); + ui->qsb_moment_x->setEnabled(false); + } + else if (strcmp(val, "Constraint") == 0) { + ui->spb_rot_axis_x->setEnabled(true); + ui->qsb_moment_x->setEnabled(false); + } + else if (strcmp(val, "Load") == 0) { + ui->spb_rot_axis_x->setEnabled(false); + ui->qsb_moment_x->setEnabled(true); + } +} +void TaskFemConstraintRigidBody::onRotModeYChanged(int item) +{ + const char* val = static_cast(ConstraintView->getObject()) + ->RotationalModeY.getEnumVector()[item] + .c_str(); + + if (strcmp(val, "Free") == 0) { + ui->spb_rot_axis_y->setEnabled(false); + ui->qsb_moment_y->setEnabled(false); + } + else if (strcmp(val, "Constraint") == 0) { + ui->spb_rot_axis_y->setEnabled(true); + ui->qsb_moment_y->setEnabled(false); + } + else if (strcmp(val, "Load") == 0) { + ui->spb_rot_axis_y->setEnabled(false); + ui->qsb_moment_y->setEnabled(true); + } +} +void TaskFemConstraintRigidBody::onRotModeZChanged(int item) +{ + const char* val = static_cast(ConstraintView->getObject()) + ->RotationalModeZ.getEnumVector()[item] + .c_str(); + + if (strcmp(val, "Free") == 0) { + ui->spb_rot_axis_z->setEnabled(false); + ui->qsb_moment_z->setEnabled(false); + } + else if (strcmp(val, "Constraint") == 0) { + ui->spb_rot_axis_z->setEnabled(true); + ui->qsb_moment_z->setEnabled(false); + } + else if (strcmp(val, "Load") == 0) { + ui->spb_rot_axis_z->setEnabled(false); + ui->qsb_moment_z->setEnabled(true); + } +} + +void TaskFemConstraintRigidBody::onTransModeXChanged(int item) +{ + const char* val = static_cast(ConstraintView->getObject()) + ->TranslationalModeX.getEnumVector()[item] + .c_str(); + + if (strcmp(val, "Free") == 0) { + ui->qsb_disp_x->setEnabled(false); + ui->qsb_force_x->setEnabled(false); + } + else if (strcmp(val, "Constraint") == 0) { + ui->qsb_disp_x->setEnabled(true); + ui->qsb_force_x->setEnabled(false); + } + else if (strcmp(val, "Load") == 0) { + ui->qsb_disp_x->setEnabled(false); + ui->qsb_force_x->setEnabled(true); + } +} +void TaskFemConstraintRigidBody::onTransModeYChanged(int item) +{ + const char* val = static_cast(ConstraintView->getObject()) + ->TranslationalModeY.getEnumVector()[item] + .c_str(); + + if (strcmp(val, "Free") == 0) { + ui->qsb_disp_y->setEnabled(false); + ui->qsb_force_y->setEnabled(false); + } + else if (strcmp(val, "Constraint") == 0) { + ui->qsb_disp_y->setEnabled(true); + ui->qsb_force_y->setEnabled(false); + } + else if (strcmp(val, "Load") == 0) { + ui->qsb_disp_y->setEnabled(false); + ui->qsb_force_y->setEnabled(true); + } +} +void TaskFemConstraintRigidBody::onTransModeZChanged(int item) +{ + const char* val = static_cast(ConstraintView->getObject()) + ->TranslationalModeZ.getEnumVector()[item] + .c_str(); + + if (strcmp(val, "Free") == 0) { + ui->qsb_disp_z->setEnabled(false); + ui->qsb_force_z->setEnabled(false); + } + else if (strcmp(val, "Constraint") == 0) { + ui->qsb_disp_z->setEnabled(true); + ui->qsb_force_z->setEnabled(false); + } + else if (strcmp(val, "Load") == 0) { + ui->qsb_disp_z->setEnabled(false); + ui->qsb_force_z->setEnabled(true); + } +} + + +const std::string TaskFemConstraintRigidBody::getReferences() const +{ + int rows = ui->lw_references->model()->rowCount(); + std::vector items; + for (int r = 0; r < rows; r++) { + items.push_back(ui->lw_references->item(r)->text().toStdString()); + } + return TaskFemConstraint::getReferences(items); +} + +Base::Vector3d TaskFemConstraintRigidBody::getReferenceNode() const +{ + double x = ui->qsb_ref_node_x->rawValue(); + double y = ui->qsb_ref_node_y->rawValue(); + double z = ui->qsb_ref_node_z->rawValue(); + + return Base::Vector3d(x, y, z); +} + +Base::Vector3d TaskFemConstraintRigidBody::getDisplacement() const +{ + double x = ui->qsb_disp_x->rawValue(); + double y = ui->qsb_disp_y->rawValue(); + double z = ui->qsb_disp_z->rawValue(); + + return Base::Vector3d(x, y, z); +} + +Base::Rotation TaskFemConstraintRigidBody::getRotation() const +{ + double x = ui->spb_rot_axis_x->value(); + double y = ui->spb_rot_axis_y->value(); + double z = ui->spb_rot_axis_z->value(); + double angle = ui->qsb_rot_angle->value().getValueAs(Base::Quantity::Radian); + + return Base::Rotation(Base::Vector3d(x, y, z), angle); +} + +std::vector TaskFemConstraintRigidBody::getForce() const +{ + std::string x = ui->qsb_force_x->value().getSafeUserString().toStdString(); + std::string y = ui->qsb_force_y->value().getSafeUserString().toStdString(); + std::string z = ui->qsb_force_z->value().getSafeUserString().toStdString(); + + return {x, y, z}; +} + +std::vector TaskFemConstraintRigidBody::getMoment() const +{ + std::string x = ui->qsb_moment_x->value().getSafeUserString().toStdString(); + std::string y = ui->qsb_moment_y->value().getSafeUserString().toStdString(); + std::string z = ui->qsb_moment_z->value().getSafeUserString().toStdString(); + + return std::vector({x, y, z}); +} + +std::vector TaskFemConstraintRigidBody::getTranslationalMode() const +{ + std::vector transModes(3); + transModes[0] = ui->cb_x_trans_mode->currentText().toStdString(); + transModes[1] = ui->cb_y_trans_mode->currentText().toStdString(); + transModes[2] = ui->cb_z_trans_mode->currentText().toStdString(); + + return transModes; +} + +std::vector TaskFemConstraintRigidBody::getRotationalMode() const +{ + std::vector rotModes(3); + rotModes[0] = ui->cb_x_rot_mode->currentText().toStdString(); + rotModes[1] = ui->cb_y_rot_mode->currentText().toStdString(); + rotModes[2] = ui->cb_z_rot_mode->currentText().toStdString(); + + return rotModes; +} + +bool TaskFemConstraintRigidBody::event(QEvent* e) +{ + return TaskFemConstraint::KeyEvent(e); +} + +void TaskFemConstraintRigidBody::changeEvent(QEvent*) +{} + +void TaskFemConstraintRigidBody::clearButtons(const SelectionChangeModes notThis) +{ + if (notThis != SelectionChangeModes::refAdd) { + ui->btnAdd->setChecked(false); + } + if (notThis != SelectionChangeModes::refRemove) { + ui->btnRemove->setChecked(false); + } +} + +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraintRigidBody::TaskDlgFemConstraintRigidBody( + ViewProviderFemConstraintRigidBody* ConstraintView) +{ + this->ConstraintView = ConstraintView; + assert(ConstraintView); + this->parameter = new TaskFemConstraintRigidBody(ConstraintView); + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +void TaskDlgFemConstraintRigidBody::open() +{ + // a transaction is already open at creation time of the panel + if (!Gui::Command::hasPendingCommand()) { + QString msg = QObject::tr("Constraint RigidBody"); + Gui::Command::openCommand((const char*)msg.toUtf8()); + ConstraintView->setVisible(true); + Gui::Command::doCommand( + Gui::Command::Doc, + ViewProviderFemConstraint::gethideMeshShowPartStr( + (static_cast(ConstraintView->getObject()))->getNameInDocument()) + .c_str()); // OvG: Hide meshes and show parts + } +} + +bool TaskDlgFemConstraintRigidBody::accept() +{ + std::string name = ConstraintView->getObject()->getNameInDocument(); + const TaskFemConstraintRigidBody* parameters = + static_cast(parameter); + try { + Base::Vector3d ref = parameters->getReferenceNode(); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.ReferenceNode = App.Vector(%f, %f, %f)", + name.c_str(), + ref.x, + ref.y, + ref.z); + + Base::Vector3d disp = parameters->getDisplacement(); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.Displacement = App.Vector(%f, %f, %f)", + name.c_str(), + disp.x, + disp.y, + disp.z); + + Base::Rotation rot = parameters->getRotation(); + Base::Vector3d axis; + double angle; + rot.getValue(axis, angle); + Gui::Command::doCommand( + Gui::Command::Doc, + "App.ActiveDocument.%s.Rotation = App.Rotation(App.Vector(%f,% f, %f), Radian=%f)", + name.c_str(), + axis.x, + axis.y, + axis.z, + angle); + + auto force = parameters->getForce(); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.ForceX = \"%s\"", + name.c_str(), + force[0].c_str()); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.ForceY = \"%s\"", + name.c_str(), + force[1].c_str()); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.ForceZ = \"%s\"", + name.c_str(), + force[2].c_str()); + + auto moment = parameters->getMoment(); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.MomentX = \"%s\"", + name.c_str(), + moment[0].c_str()); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.MomentY = \"%s\"", + name.c_str(), + moment[1].c_str()); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.MomentZ = \"%s\"", + name.c_str(), + moment[2].c_str()); + + auto transModes = parameters->getTranslationalMode(); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.TranslationalModeX = \"%s\"", + name.c_str(), + transModes[0].c_str()); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.TranslationalModeY = \"%s\"", + name.c_str(), + transModes[1].c_str()); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.TranslationalModeZ = \"%s\"", + name.c_str(), + transModes[2].c_str()); + + auto rotModes = parameters->getRotationalMode(); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.RotationalModeX = \"%s\"", + name.c_str(), + rotModes[0].c_str()); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.RotationalModeY = \"%s\"", + name.c_str(), + rotModes[1].c_str()); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.RotationalModeZ = \"%s\"", + name.c_str(), + rotModes[2].c_str()); + + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.Scale = %s", + name.c_str(), + parameters->getScale().c_str()); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); + return false; + } + return TaskDlgFemConstraint::accept(); +} + +bool TaskDlgFemConstraintRigidBody::reject() +{ + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeDocument().resetEdit()"); + Gui::Command::updateActive(); + + return true; +} + +#include "moc_TaskFemConstraintRigidBody.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintRigidBody.h b/src/Mod/Fem/Gui/TaskFemConstraintRigidBody.h new file mode 100644 index 0000000000..fc03f5b7eb --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintRigidBody.h @@ -0,0 +1,88 @@ +/*************************************************************************** + * Copyright (c) 2022 Ajinkya Dahale * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef GUI_TASKVIEW_TaskFemConstraintRigidBody_H +#define GUI_TASKVIEW_TaskFemConstraintRigidBody_H + +#include + +#include "TaskFemConstraintOnBoundary.h" +#include "ViewProviderFemConstraintRigidBody.h" + + +class Ui_TaskFemConstraintRigidBody; + +namespace FemGui +{ +class TaskFemConstraintRigidBody: public TaskFemConstraintOnBoundary +{ + Q_OBJECT + +public: + explicit TaskFemConstraintRigidBody(ViewProviderFemConstraintRigidBody* ConstraintView, + QWidget* parent = nullptr); + ~TaskFemConstraintRigidBody() override; + + const std::string getReferences() const override; + Base::Vector3d getReferenceNode() const; + Base::Vector3d getDisplacement() const; + Base::Rotation getRotation() const; + std::vector getForce() const; + std::vector getMoment() const; + std::vector getTranslationalMode() const; + std::vector getRotationalMode() const; + +private Q_SLOTS: + void onReferenceDeleted(); + void addToSelection() override; + void removeFromSelection() override; + void onTransModeXChanged(int); + void onTransModeYChanged(int); + void onTransModeZChanged(int); + void onRotModeXChanged(int); + void onRotModeYChanged(int); + void onRotModeZChanged(int); + +protected: + bool event(QEvent* e) override; + void changeEvent(QEvent* e) override; + void clearButtons(const SelectionChangeModes notThis) override; + +private: + void updateUI(); + Ui_TaskFemConstraintRigidBody* ui; +}; + +class TaskDlgFemConstraintRigidBody: public TaskDlgFemConstraint +{ + Q_OBJECT + +public: + explicit TaskDlgFemConstraintRigidBody(ViewProviderFemConstraintRigidBody* ConstraintView); + void open() override; + bool accept() override; + bool reject() override; +}; + +} // namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraintRigidBody_H diff --git a/src/Mod/Fem/Gui/TaskFemConstraintRigidBody.ui b/src/Mod/Fem/Gui/TaskFemConstraintRigidBody.ui new file mode 100644 index 0000000000..c255931ae2 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintRigidBody.ui @@ -0,0 +1,615 @@ + + + TaskFemConstraintRigidBody + + + + 0 + 0 + 296 + 587 + + + + Form + + + + + + Select multiple face(s), click Add or Remove + + + + + + + + + + 0 + 0 + + + + Add + + + true + + + + + + + + 0 + 0 + + + + Remove + + + true + + + + + + + + + + + + + + + 0 + 0 + + + + + + + Reference Node + + + + + + X: + + + + + + + 1.0 + + + 1000000000.0 + + + mm + + + 0.0 + + + + + + + Y: + + + + + + + 1.0 + + + 1000000000.0 + + + mm + + + 0.0 + + + + + + + Z: + + + + + + + 1.0 + + + 1000000000.0 + + + mm + + + 0.0 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + + + Translational Mode + + + + + + X: + + + + + + + Y: + + + + + + + Z: + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + Displacement + + + + + + X: + + + + + + + Y: + + + + + + + Z: + + + + + + + false + + + 1.00000000000000 + + + mm + + + + + + + false + + + 1.00000000000000 + + + mm + + + + + + + false + + + 1.00000000000000 + + + mm + + + + + + + + + + + 0 + 0 + + + + + + + Force + + + + + + X: + + + + + + + Y: + + + + + + + Z: + + + + + + + false + + + 1.00000000000000 + + + N + + + + + + + false + + + 1.00000000000000 + + + N + + + + + + + false + + + 1.00000000000000 + + + N + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + + + Rotational Mode + + + + + + X: + + + + + + + Y: + + + + + + + Z: + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + Rotation + + + + + + X: + + + + + + + Y: + + + + + + + Z: + + + + + + + false + + + 0.10000000000000 + + + + + + + false + + + 0.100000000000000 + + + + + + + false + + + 0.100000000000000 + + + + + + + Angle: + + + + + + + false + + + 1.00000000000000 + + + deg + + + + + + + + + + + 0 + 0 + + + + + + + Moment + + + + + + X: + + + + + + + Y: + + + + + + + Z: + + + + + + + false + + + 1.00000000000000 + + + N*m + + + + + + + false + + + 1.00000000000000 + + + N*m + + + + + + + false + + + 1.00000000000000 + + + N*m + + + + + + + + + + + + + Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
+
+ + Gui::DoubleSpinBox + QWidget +
Gui/SpinBox.h
+
+
+ + +
diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp index b0cc44ed82..cf567600c3 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,7 @@ ViewProviderFemConstraint::ViewProviderFemConstraint() : rotateSymbol(true) , pSymbol(nullptr) , pExtraSymbol(nullptr) + , pExtraTrans(nullptr) , ivFile(nullptr) , wizardWidget(nullptr) , wizardSubLayout(nullptr) @@ -70,6 +72,8 @@ ViewProviderFemConstraint::ViewProviderFemConstraint() pShapeSep->ref(); pMultCopy = new SoMultipleCopy(); pMultCopy->ref(); + pExtraTrans = new SoTransform(); + pExtraTrans->ref(); ShapeAppearance.setDiffuseColor(1.0f, 0.0f, 0.2f); ShapeAppearance.setSpecularColor(0.0f, 0.0f, 0.0f); @@ -80,6 +84,7 @@ ViewProviderFemConstraint::ViewProviderFemConstraint() ViewProviderFemConstraint::~ViewProviderFemConstraint() { pMultCopy->unref(); + pExtraTrans->unref(); pShapeSep->unref(); } @@ -129,6 +134,7 @@ void ViewProviderFemConstraint::loadSymbol(const char* fileName) if (nodes->getNumChildren() == 2) { pExtraSymbol = dynamic_cast(nodes->getChild(1)); if (pExtraSymbol) { + pShapeSep->addChild(pExtraTrans); pShapeSep->addChild(pExtraSymbol); } } @@ -221,6 +227,8 @@ void ViewProviderFemConstraint::updateSymbol() } pMultCopy->matrix.finishEditing(); + + transformExtraSymbol(); } void ViewProviderFemConstraint::transformSymbol(const Base::Vector3d& point, @@ -239,6 +247,17 @@ void ViewProviderFemConstraint::transformSymbol(const Base::Vector3d& point, mat.setTransform(tra, rot, scale); } +void ViewProviderFemConstraint::transformExtraSymbol() const +{ + if (pExtraTrans) { + auto obj = static_cast(this->getObject()); + float s = obj->getScaleFactor(); + SbMatrix mat; + mat.setScale(s); + pExtraTrans->setMatrix(mat); + } +} + // OvG: Visibility automation show parts and hide meshes on activation of a constraint std::string ViewProviderFemConstraint::gethideMeshShowPartStr(const std::string showConstr) diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h index e32d8f0c63..e887981291 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h @@ -36,6 +36,7 @@ class SbRotation; class SoMultipleCopy; +class SoTransform; namespace FemGui { @@ -68,6 +69,7 @@ public: SoSeparator* getSymbolSeparator() const; SoSeparator* getExtraSymbolSeparator() const; + SoTransform* getExtraSymbolTransform() const; // Apply rotation on copies of the constraint symbol void setRotateSymbol(bool rotate); bool getRotateSymbol() const; @@ -94,6 +96,7 @@ protected: void updateSymbol(); virtual void transformSymbol(const Base::Vector3d& point, const Base::Vector3d& normal, SbMatrix& mat) const; + virtual void transformExtraSymbol() const; static void createPlacement(SoSeparator* sep, const SbVec3f& base, const SbRotation& r); static void updatePlacement(const SoSeparator* sep, @@ -163,6 +166,7 @@ protected: SoSeparator* pShapeSep; SoSeparator* pSymbol; SoSeparator* pExtraSymbol; + SoTransform* pExtraTrans; SoMultipleCopy* pMultCopy; const char* ivFile; @@ -190,6 +194,11 @@ inline SoSeparator* ViewProviderFemConstraint::getExtraSymbolSeparator() const return pExtraSymbol; } +inline SoTransform* ViewProviderFemConstraint::getExtraSymbolTransform() const +{ + return pExtraTrans; +} + inline bool ViewProviderFemConstraint::getRotateSymbol() const { return rotateSymbol; diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintRigidBody.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintRigidBody.cpp new file mode 100644 index 0000000000..0364b65b12 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintRigidBody.cpp @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (c) 2022 Ajinkya Dahale * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#include +#include +#endif + +#include "Gui/Control.h" +#include + +#include "TaskFemConstraintRigidBody.h" +#include "ViewProviderFemConstraintRigidBody.h" + + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintRigidBody, + FemGui::ViewProviderFemConstraintOnBoundary) + + +ViewProviderFemConstraintRigidBody::ViewProviderFemConstraintRigidBody() +{ + sPixmap = "FEM_ConstraintRigidBody"; + loadSymbol((resourceSymbolDir + "ConstraintRigidBody.iv").c_str()); + ShapeAppearance.setDiffuseColor(0.0f, 0.5f, 0.0f); +} + +ViewProviderFemConstraintRigidBody::~ViewProviderFemConstraintRigidBody() = default; + +bool ViewProviderFemConstraintRigidBody::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default) { + // When double-clicking on the item for this constraint the + // object unsets and sets its edit mode without closing + // the task panel + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + TaskDlgFemConstraintRigidBody* constrDlg = + qobject_cast(dlg); + if (constrDlg && constrDlg->getConstraintView() != this) { + constrDlg = nullptr; // another constraint left open its task panel + } + if (dlg && !constrDlg) { + // This case will occur in the ShaftWizard application + checkForWizard(); + if (!wizardWidget || !wizardSubLayout) { + // No shaft wizard is running + QMessageBox msgBox; + msgBox.setText(QObject::tr("A dialog is already open in the task panel")); + msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + int ret = msgBox.exec(); + if (ret == QMessageBox::Yes) { + Gui::Control().reject(); + } + else { + return false; + } + } + else if (constraintDialog) { + // Another FemConstraint* dialog is already open inside the Shaft Wizard + // Ignore the request to open another dialog + return false; + } + else { + constraintDialog = new TaskFemConstraintRigidBody(this); + return true; + } + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (constrDlg) { + Gui::Control().showDialog(constrDlg); + } + else { + Gui::Control().showDialog(new TaskDlgFemConstraintRigidBody(this)); + } + + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); // clazy:exclude=skipped-base-method + } +} + +void ViewProviderFemConstraintRigidBody::updateData(const App::Property* prop) +{ + auto obj = static_cast(this->getObject()); + + if (prop == &obj->ReferenceNode) { + updateSymbol(); + } + + ViewProviderFemConstraint::updateData(prop); +} + +void ViewProviderFemConstraintRigidBody::transformExtraSymbol() const +{ + SoTransform* symTrans = getExtraSymbolTransform(); + if (symTrans) { + auto obj = static_cast(this->getObject()); + float s = obj->getScaleFactor(); + const Base::Vector3d& refNode = obj->ReferenceNode.getValue(); + SbVec3f tra(refNode.x, refNode.y, refNode.z); + SbVec3f sca(s, s, s); + SbRotation rot(SbVec3f(0, 0, 1), 0); + + SbMatrix mat; + mat.setTransform(tra, rot, sca); + + symTrans->setMatrix(mat); + } +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintRigidBody.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintRigidBody.h new file mode 100644 index 0000000000..5f35b4e0f8 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintRigidBody.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (c) 2022 Ajinkya Dahale * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_VIEWPROVIDERFEMCONSTRAINTRIGIDBODY_H +#define GUI_VIEWPROVIDERFEMCONSTRAINTRIGIDBODY_H + +#include "ViewProviderFemConstraintOnBoundary.h" + +namespace FemGui +{ + +class FemGuiExport ViewProviderFemConstraintRigidBody + : public FemGui::ViewProviderFemConstraintOnBoundary +{ + PROPERTY_HEADER_WITH_OVERRIDE(FemGui::ViewProviderFemConstraintRigidBody); + +public: + /// Constructor + ViewProviderFemConstraintRigidBody(); + ~ViewProviderFemConstraintRigidBody() override; + + void updateData(const App::Property*) override; + +protected: + bool setEdit(int ModNum) override; + + void transformExtraSymbol() const override; +}; + +} // namespace FemGui + + +#endif // GUI_VIEWPROVIDERFEMCONSTRAINTRIGIDBODY_H diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index eccc5ed9e7..d146a0887f 100644 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -132,6 +132,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* mech = new Gui::ToolBarItem(root); mech->setCommand("Mechanical boundary conditions and loads"); *mech << "FEM_ConstraintFixed" + << "FEM_ConstraintRigidBody" << "FEM_ConstraintDisplacement" << "FEM_ConstraintContact" << "FEM_ConstraintTie" @@ -263,6 +264,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const Gui::MenuItem* mech = new Gui::MenuItem; mech->setCommand("&Mechanical boundary conditions and loads"); *mech << "FEM_ConstraintFixed" + << "FEM_ConstraintRigidBody" << "FEM_ConstraintDisplacement" << "FEM_ConstraintContact" << "FEM_ConstraintTie" diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py index c1e6deb951..40f73d3945 100644 --- a/src/Mod/Fem/ObjectsFem.py +++ b/src/Mod/Fem/ObjectsFem.py @@ -173,6 +173,16 @@ def makeConstraintFixed( return obj +def makeConstraintRigidBody( + doc, + name="ConstraintRigidBody" +): + """makeConstraintRigidBody(document, [name]): + makes a Fem ConstraintRigidBody object""" + obj = doc.addObject("Fem::ConstraintRigidBody", name) + return obj + + def makeConstraintFlowVelocity( doc, name="ConstraintFlowVelocity" diff --git a/src/Mod/Fem/femmesh/meshsetsgetter.py b/src/Mod/Fem/femmesh/meshsetsgetter.py index 4ef2b31702..c84b2b31b0 100644 --- a/src/Mod/Fem/femmesh/meshsetsgetter.py +++ b/src/Mod/Fem/femmesh/meshsetsgetter.py @@ -139,6 +139,7 @@ class MeshSetsGetter(): # constraints node sets getter self.get_constraints_fixed_nodes() self.get_constraints_displacement_nodes() + self.get_constraints_rigidbody_nodes() self.get_constraints_planerotation_nodes() # constraints surface sets getter @@ -205,6 +206,21 @@ class MeshSetsGetter(): femobj["NodesSolid"] = set(nds_solid) femobj["NodesFaceEdge"] = set(nds_faceedge) + def get_constraints_rigidbody_nodes(self): + if not self.member.cons_rigidbody: + return + # get nodes + for femobj in self.member.cons_rigidbody: + # femobj --> dict, FreeCAD document object is femobj["Object"] + print_obj_info(femobj["Object"]) + femobj["Nodes"] = meshtools.get_femnodes_by_femobj_with_references( + self.femmesh, + femobj + ) + # add nodes to constraint_conflict_nodes, needed by constraint plane rotation + for node in femobj["Nodes"]: + self.constraint_conflict_nodes.append(node) + def get_constraints_displacement_nodes(self): if not self.member.cons_displacement: return diff --git a/src/Mod/Fem/femsolver/calculix/write_constraint_rigidbody.py b/src/Mod/Fem/femsolver/calculix/write_constraint_rigidbody.py new file mode 100644 index 0000000000..5d5e28c428 --- /dev/null +++ b/src/Mod/Fem/femsolver/calculix/write_constraint_rigidbody.py @@ -0,0 +1,79 @@ +# *************************************************************************** +# * Copyright (c) 2022 Ajinkya Dahale * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "FreeCAD FEM calculix constraint rigid body" +__author__ = "Ajinkya Dahale" +__url__ = "https://www.freecadweb.org" + + +def get_analysis_types(): + return "all" # write for all analysis types + + +def get_sets_name(): + return "constraints_rigidbody_node_sets" + + +def get_constraint_title(): + return "Rigid Body Constraints" + + +def get_before_write_meshdata_constraint(): + return "" + + +def get_after_write_meshdata_constraint(): + return "" + + +def get_before_write_constraint(): + return "" + + +def get_after_write_constraint(): + return "" + + +def write_meshdata_constraint(f, femobj, rb_obj, ccxwriter): + + f.write("*NSET,NSET=" + rb_obj.Name + "\n") + for n in femobj["Nodes"]: + f.write("{},\n".format(n)) + + +def write_constraint(f, femobj, rb_obj, ccxwriter): + + rb_obj_idx = ccxwriter.analysis.Group.index(rb_obj) + node_count = ccxwriter.mesh_object.FemMesh.NodeCount + # factor 2 is to prevent conflict with other rigid body constraint + ref_node_idx = node_count + 2*rb_obj_idx + 1 + rot_node_idx = node_count + 2*rb_obj_idx + 2 + + f.write("*NODE\n") + f.write("{},{},{},{}\n".format(ref_node_idx, *rb_obj.ReferenceNode)) + f.write("{},{},{},{}\n".format(rot_node_idx, *rb_obj.ReferenceNode)) + + kw_line = "*RIGID BODY, NSET={}, REF NODE={}, ROT NODE={}".format(rb_obj.Name, ref_node_idx, rot_node_idx) + + f.write(kw_line + "\n") + diff --git a/src/Mod/Fem/femsolver/calculix/write_constraint_rigidbody_step.py b/src/Mod/Fem/femsolver/calculix/write_constraint_rigidbody_step.py new file mode 100644 index 0000000000..ad7a27d56f --- /dev/null +++ b/src/Mod/Fem/femsolver/calculix/write_constraint_rigidbody_step.py @@ -0,0 +1,100 @@ +# *************************************************************************** +# * Copyright (c) 2022 Ajinkya Dahale * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "FreeCAD FEM calculix constraint rigid body" +__author__ = "Ajinkya Dahale" +__url__ = "https://www.freecadweb.org" + + +import FreeCAD + + +def get_analysis_types(): + return "all" # write for all analysis types + + +def get_sets_name(): + return "constraints_rigidbody_node_sets" + + +def get_constraint_title(): + return "Rigid Body Constraints" + + +def get_before_write_meshdata_constraint(): + return "" + + +def get_after_write_meshdata_constraint(): + return "" + + +def get_before_write_constraint(): + return "" + + +def get_after_write_constraint(): + return "" + + +def write_constraint(f, femobj, rb_obj, ccxwriter): + + rb_obj_idx = ccxwriter.analysis.Group.index(rb_obj) + node_count = ccxwriter.mesh_object.FemMesh.NodeCount + # factor 2 is to prevent conflict with other rigid body constraint + ref_node_idx = node_count + 2*rb_obj_idx + 1 + rot_node_idx = node_count + 2*rb_obj_idx + 2 + + def write_mode(mode, node, dof, constraint, load): + if mode == "Constraint": + f.write("*BOUNDARY\n") + f.write("{},{},{},{:.13G}\n".format(node, dof, dof, constraint)) + elif mode == "Load": + f.write("*CLOAD\n") + f.write("{},{},{:.13G}\n".format(node, dof, load)) + + mode = [rb_obj.TranslationalModeX, rb_obj.TranslationalModeY, rb_obj.TranslationalModeZ] + constraint = rb_obj.Displacement + load = [rb_obj.ForceX, rb_obj.ForceY, rb_obj.ForceZ] + + for i in range(3): + write_mode(mode[i], ref_node_idx, i + 1, constraint[i], load[i].getValueAs("N").Value) + + + mode = [rb_obj.RotationalModeX, rb_obj.RotationalModeY, rb_obj.RotationalModeZ] + load = [rb_obj.MomentX,rb_obj.MomentY, rb_obj.MomentZ] + + # write rotation components according to rotational mode + rot = rb_obj.Rotation + proj_axis = [rot.Axis[i] if mode[i] == "Constraint" else 0 for i in range(3)] + # proj_axis could be null + try: + constraint = FreeCAD.Vector(proj_axis).normalize() * rot.Angle + except: + constraint = FreeCAD.Vector(0, 0, 0) + + for i in range(3): + write_mode(mode[i], rot_node_idx, i + 1, constraint[i], load[i].getValueAs("N*mm").Value) + + + f.write("\n") diff --git a/src/Mod/Fem/femsolver/calculix/writer.py b/src/Mod/Fem/femsolver/calculix/writer.py index bf61f35baa..bee4afb173 100644 --- a/src/Mod/Fem/femsolver/calculix/writer.py +++ b/src/Mod/Fem/femsolver/calculix/writer.py @@ -45,6 +45,8 @@ from . import write_constraint_heatflux as con_heatflux from . import write_constraint_initialtemperature as con_itemp from . import write_constraint_planerotation as con_planerotation from . import write_constraint_pressure as con_pressure +from . import write_constraint_rigidbody as con_rigidbody +from . import write_constraint_rigidbody_step as con_rigidbody_step from . import write_constraint_sectionprint as con_sectionprint from . import write_constraint_selfweight as con_selfweight from . import write_constraint_temperature as con_temperature @@ -161,6 +163,7 @@ class FemInputWriterCcx(writerbase.FemInputWriter): # node sets self.write_constraints_meshsets(inpfile, self.member.cons_fixed, con_fixed) + self.write_constraints_meshsets(inpfile, self.member.cons_rigidbody, con_rigidbody) self.write_constraints_meshsets(inpfile, self.member.cons_displacement, con_displacement) self.write_constraints_meshsets(inpfile, self.member.cons_planerotation, con_planerotation) self.write_constraints_meshsets(inpfile, self.member.cons_transform, con_transform) @@ -181,12 +184,14 @@ class FemInputWriterCcx(writerbase.FemInputWriter): self.write_constraints_propdata(inpfile, self.member.cons_contact, con_contact) self.write_constraints_propdata(inpfile, self.member.cons_tie, con_tie) self.write_constraints_propdata(inpfile, self.member.cons_transform, con_transform) + self.write_constraints_propdata(inpfile, self.member.cons_rigidbody, con_rigidbody) # step equation write_step_equation.write_step_equation(inpfile, self) # constraints dependent from steps self.write_constraints_propdata(inpfile, self.member.cons_fixed, con_fixed) + self.write_constraints_propdata(inpfile, self.member.cons_rigidbody_step, con_rigidbody_step) self.write_constraints_propdata(inpfile, self.member.cons_displacement, con_displacement) self.write_constraints_propdata(inpfile, self.member.cons_sectionprint, con_sectionprint) self.write_constraints_propdata(inpfile, self.member.cons_selfweight, con_selfweight) diff --git a/src/Mod/Fem/femtest/app/test_object.py b/src/Mod/Fem/femtest/app/test_object.py index a435674e4b..dc5d64d62c 100644 --- a/src/Mod/Fem/femtest/app/test_object.py +++ b/src/Mod/Fem/femtest/app/test_object.py @@ -189,6 +189,10 @@ class TestObjectType(unittest.TestCase): "Fem::ConstraintFixed", type_of_obj(ObjectsFem.makeConstraintFixed(doc)) ) + self.assertEqual( + "Fem::ConstraintRigidBody", + type_of_obj(ObjectsFem.makeConstraintRigidBody(doc)) + ) self.assertEqual( "Fem::ConstraintFlowVelocity", type_of_obj(ObjectsFem.makeConstraintFlowVelocity(doc)) @@ -434,6 +438,10 @@ class TestObjectType(unittest.TestCase): ObjectsFem.makeConstraintFixed(doc), "Fem::ConstraintFixed" )) + self.assertTrue(is_of_type( + ObjectsFem.makeConstraintRigidBody(doc), + "Fem::ConstraintRigidBody" + )) self.assertTrue(is_of_type( ObjectsFem.makeConstraintFlowVelocity(doc), "Fem::ConstraintFlowVelocity" @@ -778,6 +786,21 @@ class TestObjectType(unittest.TestCase): "Fem::ConstraintFixed" )) + # ConstraintRigidBody + constraint_rigidbody = ObjectsFem.makeConstraintRigidBody(doc) + self.assertTrue(is_derived_from( + constraint_rigidbody, + "App::DocumentObject" + )) + self.assertTrue(is_derived_from( + constraint_rigidbody, + "Fem::Constraint" + )) + self.assertTrue(is_derived_from( + constraint_rigidbody, + "Fem::ConstraintRigidBody" + )) + # ConstraintFlowVelocity constraint_flow_velocity = ObjectsFem.makeConstraintFlowVelocity(doc) self.assertTrue(is_derived_from( @@ -1573,6 +1596,10 @@ class TestObjectType(unittest.TestCase): ObjectsFem.makeConstraintFixed( doc).isDerivedFrom("Fem::ConstraintFixed") ) + self.assertTrue( + ObjectsFem.makeConstraintRigidBody( + doc).isDerivedFrom("Fem::ConstraintRigidBody") + ) self.assertTrue( ObjectsFem.makeConstraintFlowVelocity( doc).isDerivedFrom("Fem::ConstraintPython") @@ -1844,6 +1871,7 @@ def create_all_fem_objects_doc( analysis.addObject(ObjectsFem.makeConstraintDisplacement(doc)) analysis.addObject(ObjectsFem.makeConstraintElectrostaticPotential(doc)) analysis.addObject(ObjectsFem.makeConstraintFixed(doc)) + analysis.addObject(ObjectsFem.makeConstraintRigidBody(doc)) analysis.addObject(ObjectsFem.makeConstraintFlowVelocity(doc)) analysis.addObject(ObjectsFem.makeConstraintFluidBoundary(doc)) analysis.addObject(ObjectsFem.makeConstraintSpring(doc)) diff --git a/src/Mod/Fem/femtools/membertools.py b/src/Mod/Fem/femtools/membertools.py index e75ce7d593..058ca710d5 100644 --- a/src/Mod/Fem/femtools/membertools.py +++ b/src/Mod/Fem/femtools/membertools.py @@ -207,6 +207,10 @@ class AnalysisMember(): list of fixed constraints from the analysis. [{"Object":fixed_obj, "NodeSupports":bool}, {}, ...] + constraints_rigidbody : list of dictionaries + list of displacements for the analysis. + [{"Object":rigidbody_obj, "xxxxxxxx":value}, {}, ...] + constraints_force : list of dictionaries list of force constraints from the analysis. [{"Object":force_obj, "NodeLoad":value}, {}, ... @@ -294,6 +298,12 @@ class AnalysisMember(): self.cons_fixed = self.get_several_member( "Fem::ConstraintFixed" ) + self.cons_rigidbody = self.get_several_member( + "Fem::ConstraintRigidBody" + ) + self.cons_rigidbody_step = self.get_several_member( + "Fem::ConstraintRigidBody" + ) self.cons_force = self.get_several_member( "Fem::ConstraintForce" )