From 1ceaa09d179832c5fd785ff7e6c24c25ec76ce61 Mon Sep 17 00:00:00 2001 From: Preslav Date: Tue, 31 Aug 2021 12:16:11 +0100 Subject: [PATCH] Added spring boundary condition --- src/Mod/Fem/App/AppFem.cpp | 2 + src/Mod/Fem/App/CMakeLists.txt | 2 + src/Mod/Fem/App/FemConstraintSpring.cpp | 81 +++++ src/Mod/Fem/App/FemConstraintSpring.h | 56 +++ src/Mod/Fem/Gui/AppFemGui.cpp | 2 + src/Mod/Fem/Gui/CMakeLists.txt | 6 + src/Mod/Fem/Gui/Command.cpp | 46 +++ src/Mod/Fem/Gui/Resources/Fem.qrc | 1 + .../Resources/icons/FEM_ConstraintSpring.svg | 134 ++++++++ src/Mod/Fem/Gui/TaskFemConstraintSpring.cpp | 322 ++++++++++++++++++ src/Mod/Fem/Gui/TaskFemConstraintSpring.h | 83 +++++ src/Mod/Fem/Gui/TaskFemConstraintSpring.ui | 116 +++++++ src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp | 24 ++ src/Mod/Fem/Gui/ViewProviderFemConstraint.h | 3 + .../Gui/ViewProviderFemConstraintSpring.cpp | 156 +++++++++ .../Fem/Gui/ViewProviderFemConstraintSpring.h | 46 +++ src/Mod/Fem/Gui/Workbench.cpp | 2 + src/Mod/Fem/ObjectsFem.py | 10 + src/Mod/Fem/femtest/app/test_object.py | 29 ++ 19 files changed, 1121 insertions(+) create mode 100644 src/Mod/Fem/App/FemConstraintSpring.cpp create mode 100644 src/Mod/Fem/App/FemConstraintSpring.h create mode 100644 src/Mod/Fem/Gui/Resources/icons/FEM_ConstraintSpring.svg create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintSpring.cpp create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintSpring.h create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintSpring.ui create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintSpring.cpp create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintSpring.h diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index bcb6c4dbe8..5473efd7c4 100644 --- a/src/Mod/Fem/App/AppFem.cpp +++ b/src/Mod/Fem/App/AppFem.cpp @@ -59,6 +59,7 @@ #include "FemConstraintContact.h" #include "FemConstraintFluidBoundary.h" #include "FemConstraintTransform.h" +#include "FemConstraintSpring.h" #include "FemResultObject.h" #include "FemSolverObject.h" @@ -156,6 +157,7 @@ PyMOD_INIT_FUNC(Fem) Fem::ConstraintPulley ::init(); Fem::ConstraintTemperature ::init(); Fem::ConstraintTransform ::init(); + Fem::ConstraintSpring ::init(); Fem::FemMesh ::init(); Fem::FemMeshObject ::init(); diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index aafd14d98a..6ca4f157f3 100644 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -158,6 +158,8 @@ SET(FemConstraints_SRCS FemConstraintFluidBoundary.h FemConstraintPressure.cpp FemConstraintPressure.h + FemConstraintSpring.cpp + FemConstraintSpring.h FemConstraintGear.cpp FemConstraintGear.h FemConstraintPulley.cpp diff --git a/src/Mod/Fem/App/FemConstraintSpring.cpp b/src/Mod/Fem/App/FemConstraintSpring.cpp new file mode 100644 index 0000000000..20ffe69338 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintSpring.cpp @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (c) 2021 FreeCAD Developers * + * Author: Preslav Aleksandrov * + * Based on Force constraint by Jan Rheinländer * + * 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 +#include +#include +#include +#include +#endif + +#include "FemConstraintSpring.h" + +using namespace Fem; + +PROPERTY_SOURCE(Fem::ConstraintSpring, Fem::Constraint) + +ConstraintSpring::ConstraintSpring() +{ + ADD_PROPERTY(normalStiffness,(0.0)); + ADD_PROPERTY(tangentialStiffness,(0.0)); + ADD_PROPERTY_TYPE(Points,(Base::Vector3d()),"ConstraintSpring", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Points where arrows are drawn"); + ADD_PROPERTY_TYPE(Normals,(Base::Vector3d()),"ConstraintSpring", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Normals where symbols are drawn"); + Points.setValues(std::vector()); + Normals.setValues(std::vector()); +} + +App::DocumentObjectExecReturn *ConstraintSpring::execute(void) +{ + return Constraint::execute(); +} + +const char* ConstraintSpring::getViewProviderName(void) const +{ + return "FemGui::ViewProviderFemConstraintSpring"; +} + +void ConstraintSpring::onChanged(const App::Property* prop) +{ + Constraint::onChanged(prop); + + if (prop == &References) { + std::vector points; + std::vector normals; + int scale = Scale.getValue(); + if (getPoints(points, normals, &scale)) { + Points.setValues(points); + Normals.setValues(normals); + Scale.setValue(scale); + Points.touch(); + } + } +} diff --git a/src/Mod/Fem/App/FemConstraintSpring.h b/src/Mod/Fem/App/FemConstraintSpring.h new file mode 100644 index 0000000000..585564b6de --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintSpring.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (c) 2021 FreeCAD Developers * + * Author: Preslav Aleksandrov * + * Based on Force constraint by Jan Rheinländer * + * 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_CONSTRAINTPSPRING_H +#define FEM_CONSTRAINTPSPRING_H + +#include "FemConstraint.h" + +namespace Fem { + +class AppFemExport ConstraintSpring : public Fem::Constraint +{ + PROPERTY_HEADER(Fem::ConstraintSpring); + +public: + ConstraintSpring(void); + + App::PropertyFloat normalStiffness; + App::PropertyFloat tangentialStiffness; + App::PropertyVectorList Points; + App::PropertyVectorList Normals; + + /// recalculate the object + virtual App::DocumentObjectExecReturn *execute(void); + + /// returns the type name of the ViewProvider + const char* getViewProviderName(void) const; + +protected: + virtual void onChanged(const App::Property* prop); +}; + +} + +#endif // FEM_CONSTRAINTPSPRING_H diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index fad9b28703..36424fec8a 100644 --- a/src/Mod/Fem/Gui/AppFemGui.cpp +++ b/src/Mod/Fem/Gui/AppFemGui.cpp @@ -57,6 +57,7 @@ #include "ViewProviderFemConstraintForce.h" #include "ViewProviderFemConstraintFluidBoundary.h" #include "ViewProviderFemConstraintPressure.h" +#include "ViewProviderFemConstraintSpring.h" #include "ViewProviderFemConstraintGear.h" #include "ViewProviderFemConstraintPulley.h" #include "ViewProviderFemConstraintDisplacement.h" @@ -129,6 +130,7 @@ PyMOD_INIT_FUNC(FemGui) FemGui::ViewProviderFemConstraintPulley ::init(); FemGui::ViewProviderFemConstraintTemperature ::init(); FemGui::ViewProviderFemConstraintTransform ::init(); + FemGui::ViewProviderFemConstraintSpring ::init(); FemGui::ViewProviderFemMesh ::init(); FemGui::ViewProviderFemMeshPython ::init(); diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index b70a41634d..cb1d00273c 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -80,6 +80,7 @@ set(FemGui_UIC_SRCS TaskFemConstraintPlaneRotation.ui TaskFemConstraintContact.ui TaskFemConstraintTransform.ui + TaskFemConstraintSpring.ui TaskTetParameter.ui TaskAnalysisInfo.ui TaskDriver.ui @@ -154,6 +155,9 @@ SET(FemGui_DLG_SRCS TaskFemConstraintPressure.ui TaskFemConstraintPressure.cpp TaskFemConstraintPressure.h + TaskFemConstraintSpring.ui + TaskFemConstraintSpring.cpp + TaskFemConstraintSpring.h TaskFemConstraintGear.cpp TaskFemConstraintGear.h TaskFemConstraintPulley.cpp @@ -224,6 +228,8 @@ SET(FemGui_SRCS_ViewProvider ViewProviderFemConstraintFluidBoundary.h ViewProviderFemConstraintPressure.cpp ViewProviderFemConstraintPressure.h + ViewProviderFemConstraintSpring.cpp + ViewProviderFemConstraintSpring.h ViewProviderFemConstraintGear.cpp ViewProviderFemConstraintGear.h ViewProviderFemConstraintPulley.cpp diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 24556d5df9..6620d24f3a 100644 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -759,6 +759,51 @@ bool CmdFemConstraintPressure::isActive(void) } +//================================================================================================ +DEF_STD_CMD_A(CmdFemConstraintSpring) + +CmdFemConstraintSpring::CmdFemConstraintSpring() + : Command("FEM_ConstraintSpring") +{ + sAppModule = "Fem"; + sGroup = QT_TR_NOOP("Fem"); + sMenuText = QT_TR_NOOP("Constraint spring"); + sToolTipText = QT_TR_NOOP("Creates a FEM constraint for a spring acting on a face"); + sWhatsThis = "FEM_ConstraintSpring"; + sStatusTip = sToolTipText; + sPixmap = "FEM_ConstraintSpring"; +} + +void CmdFemConstraintSpring::activated(int) +{ + Fem::FemAnalysis *Analysis; + + if(getConstraintPrerequisits(&Analysis)) + return; + + std::string FeatName = getUniqueObjectName("ConstraintSpring"); + + openCommand(QT_TRANSLATE_NOOP("Command", "Make FEM constraint spring on face")); + doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintSpring\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.normalStiffness = 1.0",FeatName.c_str()); //OvG: set default not equal to 0 + doCommand(Doc,"App.activeDocument().%s.tangentialStiffness = 0.0",FeatName.c_str()); //OvG: set default to False + 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 CmdFemConstraintSpring::isActive(void) +{ + return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); +} + + //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintPulley) @@ -1687,6 +1732,7 @@ void CreateFemCommands(void) rcCmdMgr.addCommand(new CmdFemConstraintPulley()); rcCmdMgr.addCommand(new CmdFemConstraintTemperature()); rcCmdMgr.addCommand(new CmdFemConstraintTransform()); + rcCmdMgr.addCommand(new CmdFemConstraintSpring()); // mesh rcCmdMgr.addCommand(new CmdFemCreateNodesSet()); diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc index caf67b0333..d8ac00bb62 100755 --- a/src/Mod/Fem/Gui/Resources/Fem.qrc +++ b/src/Mod/Fem/Gui/Resources/Fem.qrc @@ -30,6 +30,7 @@ icons/FEM_ConstraintTemperature.svg icons/FEM_ConstraintTie.svg icons/FEM_ConstraintTransform.svg + icons/FEM_ConstraintSpring.svg icons/FEM_ElementFluid1D.svg diff --git a/src/Mod/Fem/Gui/Resources/icons/FEM_ConstraintSpring.svg b/src/Mod/Fem/Gui/Resources/icons/FEM_ConstraintSpring.svg new file mode 100644 index 0000000000..d434552239 --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/icons/FEM_ConstraintSpring.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Fem/Gui/TaskFemConstraintSpring.cpp b/src/Mod/Fem/Gui/TaskFemConstraintSpring.cpp new file mode 100644 index 0000000000..005b56c591 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintSpring.cpp @@ -0,0 +1,322 @@ +/*************************************************************************** + * Copyright (c) 2021 FreeCAD Developers * + * Author: Preslav Aleksandrov * + * Based on Force constraint by Jan Rheinländer * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# include +#endif + +#include "Mod/Fem/App/FemConstraintSpring.h" +#include "TaskFemConstraintSpring.h" +#include "ui_TaskFemConstraintSpring.h" +#include +#include +#include +#include +#include +#include + + +using namespace FemGui; +using namespace Gui; + +/* TRANSLATOR FemGui::TaskFemConstraintSpring */ + +TaskFemConstraintSpring::TaskFemConstraintSpring(ViewProviderFemConstraintSpring *ConstraintView, QWidget *parent) + : TaskFemConstraint(ConstraintView, parent, "FEM_ConstraintSpring") +{ + proxy = new QWidget(this); + ui = new Ui_TaskFemConstraintSpring(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + // create a context menu for the listview of the references + createDeleteAction(ui->lw_references); + deleteAction->connect(deleteAction, SIGNAL(triggered()), this, SLOT(onReferenceDeleted())); + + connect(ui->lw_references, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + connect(ui->lw_references, SIGNAL(itemClicked(QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + + this->groupLayout()->addWidget(proxy); + +/* Note: */ + // Get the feature data + Fem::ConstraintSpring* pcConstraint = static_cast(ConstraintView->getObject()); + + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + // Fill data into dialog elements + ui->if_norm->setMinimum(0); // TODO fix this ------------------------------------------------------------------- + ui->if_norm->setMaximum(FLOAT_MAX); + Base::Quantity ns = Base::Quantity((pcConstraint->normalStiffness.getValue()), Base::Unit::Stiffness); + ui->if_norm->setValue(ns); + + // Fill data into dialog elements + ui->if_tan->setMinimum(0); // TODO fix this ------------------------------------------------------------------- + ui->if_tan->setMaximum(FLOAT_MAX); + Base::Quantity ts = Base::Quantity((pcConstraint->tangentialStiffness.getValue()), Base::Unit::Stiffness); + ui->if_tan->setValue(ts); + +/* */ + + 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.size() > 0) { + ui->lw_references->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); + } + + //Selection buttons + connect(ui->btnAdd, SIGNAL(clicked()), this, SLOT(addToSelection())); + connect(ui->btnRemove, SIGNAL(clicked()), this, SLOT(removeFromSelection())); + + updateUI(); +} + +TaskFemConstraintSpring::~TaskFemConstraintSpring() +{ + delete ui; +} + +void TaskFemConstraintSpring::updateUI() +{ + if (ui->lw_references->model()->rowCount() == 0) { + // Go into reference selection mode if no reference has been selected yet + onButtonReference(true); + return; + } +} + + +void TaskFemConstraintSpring::addToSelection() +{ + std::vector selection = Gui::Selection().getSelectionEx(); //gets vector of selected objects of active document + if (selection.size() == 0){ + QMessageBox::warning(this, tr("Selection error"), tr("Nothing selected!")); + return; + } + Fem::ConstraintSpring* 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; + } + 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 + bool addMe = true; + if (subNames[subIt].substr(0, 4) != "Face") { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces can be picked")); + return; + } + 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; + } + } + 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 TaskFemConstraintSpring::removeFromSelection() +{ + std::vector selection = Gui::Selection().getSelectionEx(); //gets vector of selected objects of active document + if (selection.size() == 0){ + QMessageBox::warning(this, tr("Selection error"), tr("Nothing selected!")); + return; + } + Fem::ConstraintSpring* 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.size() > 0){ + 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 TaskFemConstraintSpring::onReferenceDeleted() { + TaskFemConstraintSpring::removeFromSelection(); +} + +const std::string TaskFemConstraintSpring::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); +} + +/* Note: */ +double TaskFemConstraintSpring::get_normalStiffness() const +{ + Base::Quantity stiffness = ui->if_norm->getQuantity(); + double stiffness_double = stiffness.getValueAs(Base::Quantity::NewtonPerMeter); + return stiffness_double; +} + +double TaskFemConstraintSpring::get_tangentialStiffness() const +{ + Base::Quantity stiffness = ui->if_tan->getQuantity(); + double stiffness_double = stiffness.getValueAs(Base::Quantity::NewtonPerMeter); + return stiffness_double; +} + + +bool TaskFemConstraintSpring::event(QEvent *e) +{ + return TaskFemConstraint::KeyEvent(e); +} + +void TaskFemConstraintSpring::changeEvent(QEvent *) +{ +} + +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraintSpring::TaskDlgFemConstraintSpring(ViewProviderFemConstraintSpring *ConstraintView) +{ + this->ConstraintView = ConstraintView; + assert(ConstraintView); + this->parameter = new TaskFemConstraintSpring(ConstraintView); + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +void TaskDlgFemConstraintSpring::open() +{ + // a transaction is already open at creation time of the panel + if (!Gui::Command::hasPendingCommand()) { + QString msg = QObject::tr("Constraint spring"); + 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 TaskDlgFemConstraintSpring::accept() +{ +/* Note: */ + std::string name = ConstraintView->getObject()->getNameInDocument(); + const TaskFemConstraintSpring* parameterStiffness = static_cast(parameter); + //const TaskFemConstraintSpring* parameterTan = static_cast(parameter); + + try { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.normalStiffness = %f", + name.c_str(), parameterStiffness->get_normalStiffness()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.tangentialStiffness = %f", + name.c_str(), parameterStiffness->get_tangentialStiffness()); + std::string scale = parameterStiffness->getScale(); //OvG: determine modified scale + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Scale = %s", name.c_str(), scale.c_str()); //OvG: implement modified scale + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); + return false; + } +/* */ + return TaskDlgFemConstraint::accept(); +} + +bool TaskDlgFemConstraintSpring::reject() +{ + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::updateActive(); + + return true; +} + +#include "moc_TaskFemConstraintSpring.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintSpring.h b/src/Mod/Fem/Gui/TaskFemConstraintSpring.h new file mode 100644 index 0000000000..08d515478a --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintSpring.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Preslav Aleksandrov * + * Based on Force constraint by Jan Rheinländer * + * 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_TaskFemConstraintSpring_H +#define GUI_TASKVIEW_TaskFemConstraintSpring_H + +#include +#include +#include +#include + +#include "TaskFemConstraint.h" +#include "ViewProviderFemConstraintSpring.h" + +#include +#include +#include +#include + +class Ui_TaskFemConstraintSpring; + +namespace FemGui { +class TaskFemConstraintSpring : public TaskFemConstraint +{ + Q_OBJECT + +public: + TaskFemConstraintSpring(ViewProviderFemConstraintSpring *ConstraintView,QWidget *parent = 0); + ~TaskFemConstraintSpring(); + const std::string getReferences() const; + double get_normalStiffness()const; + double get_tangentialStiffness()const; + +private Q_SLOTS: + void onReferenceDeleted(void); + void addToSelection(); + void removeFromSelection(); + +protected: + bool event(QEvent *e); + void changeEvent(QEvent *e); + +private: + void updateUI(); + Ui_TaskFemConstraintSpring* ui; + +}; + +class TaskDlgFemConstraintSpring : public TaskDlgFemConstraint +{ + Q_OBJECT + +public: + TaskDlgFemConstraintSpring(ViewProviderFemConstraintSpring *ConstraintView); + void open(); + bool accept(); + bool reject(); +}; + +} //namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraintSpring_H diff --git a/src/Mod/Fem/Gui/TaskFemConstraintSpring.ui b/src/Mod/Fem/Gui/TaskFemConstraintSpring.ui new file mode 100644 index 0000000000..244619cde1 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintSpring.ui @@ -0,0 +1,116 @@ + + + TaskFemConstraintSpring + + + + 0 + 0 + 313 + 321 + + + + Form + + + + + + Select multiple face(s), click Add or Remove + + + + + + + + + Add + + + + + + + Remove + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + + + + 0 + 0 + + + + + + + + + + + 0 + + + + + + + + + + Normal Stiffness + + + + + + + + 0 + 0 + + + + Tangential Stiffness + + + + + + + + + + Gui::InputField + QLineEdit +
Gui/InputField.h
+
+
+ + +
diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp index 33ac5c4c9c..ffdc33782d 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp @@ -394,6 +394,30 @@ void ViewProviderFemConstraint::updateArrow(const SoNode* node, const int idx, c updateCylinder(sep, idx+CONE_CHILDREN+PLACEMENT_CHILDREN, length-radius, radius/5); } +#define SPRING_CHILDREN (CUBE_CHILDREN + PLACEMENT_CHILDREN + CYLINDER_CHILDREN) + +void ViewProviderFemConstraint::createSpring(SoSeparator* sep, const double length, const double width) +{ + createCube(sep, width, width, length/2); + createPlacement(sep, SbVec3f(0, -length/2, 0), SbRotation()); + createCylinder(sep, length/2, width/4); +} + +SoSeparator* ViewProviderFemConstraint::createSpring(const double length, const double width) +{ + SoSeparator* sep = new SoSeparator(); + createSpring(sep, length, width); + return sep; +} + +void ViewProviderFemConstraint::updateSpring(const SoNode* node, const int idx, const double length, const double width) +{ + const SoSeparator* sep = static_cast(node); + updateCube(sep, idx, width, width, length/2); + updatePlacement(sep, idx+CUBE_CHILDREN, SbVec3f(0, -length/2, 0), SbRotation()); + updateCylinder(sep, idx+CUBE_CHILDREN+PLACEMENT_CHILDREN, length/2, width/4); +} + #define FIXED_CHILDREN (CONE_CHILDREN + PLACEMENT_CHILDREN + CUBE_CHILDREN) void ViewProviderFemConstraint::createFixed(SoSeparator* sep, const double height, const double width, const bool gap) diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h index f32687b473..4eb076dd48 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h @@ -89,6 +89,9 @@ protected: static void createArrow(SoSeparator* sep, const double length, const double radius); static SoSeparator* createArrow(const double length, const double radius); static void updateArrow(const SoNode* node, const int idx, const double length, const double radius); + static void createSpring(SoSeparator* sep, const double length, const double width); + static SoSeparator* createSpring(const double length, const double width); + static void updateSpring(const SoNode* node, const int idx, const double length, const double width); static void createFixed(SoSeparator* sep, const double height, const double width, const bool gap = false); static SoSeparator* createFixed(const double height, const double width, const bool gap = false); static void updateFixed(const SoNode* node, const int idx, const double height, const double width, const bool gap = false); diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintSpring.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintSpring.cpp new file mode 100644 index 0000000000..f6c5ab5f29 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintSpring.cpp @@ -0,0 +1,156 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Author: Preslav Aleksandrov * + * Based on Force constraint by Jan Rheinländer * + * 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 +# include +# include +# include +#endif + +#include "Mod/Fem/App/FemConstraintSpring.h" +#include "TaskFemConstraintSpring.h" //TODO do next +#include "ViewProviderFemConstraintSpring.h" +#include +#include + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintSpring, FemGui::ViewProviderFemConstraint) + +ViewProviderFemConstraintSpring::ViewProviderFemConstraintSpring() +{ + sPixmap = "FEM_ConstraintSpring"; + ADD_PROPERTY(FaceColor,(0.0f,0.2f,0.8f)); +} + +ViewProviderFemConstraintSpring::~ViewProviderFemConstraintSpring() +{ +} + +//FIXME setEdit needs a careful review +bool ViewProviderFemConstraintSpring::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(); + TaskDlgFemConstraintSpring *constrDlg = qobject_cast(dlg); // check this out too + if (constrDlg && constrDlg->getConstraintView() != this) + constrDlg = 0; // another constraint left open its task panel + if (dlg && !constrDlg) { + if (constraintDialog != NULL) { + // Ignore the request to open another dialog + return false; + } else { + constraintDialog = new TaskFemConstraintSpring(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 TaskDlgFemConstraintSpring(this)); + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); + } +} + +#define WIDTH (1) +#define LENGTH (2) +//#define USE_MULTIPLE_COPY //OvG: MULTICOPY fails to update scaled arrows on initial drawing - so disable + +void ViewProviderFemConstraintSpring::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + Fem::ConstraintSpring* pcConstraint = static_cast(this->getObject()); + float scaledwidth = WIDTH * pcConstraint->Scale.getValue(); //OvG: Calculate scaled values once only + float scaledlength = LENGTH * pcConstraint->Scale.getValue(); + +#ifdef USE_MULTIPLE_COPY + //OvG: always need access to cp for scaling + SoMultipleCopy* cp = new SoMultipleCopy(); + if (pShapeSep->getNumChildren() == 0) { + // Set up the nodes + cp->matrix.setNum(0); + cp->addChild((SoNode*)createSpring(scaledlength, scaledwidth)); //OvG: Scaling + pShapeSep->addChild(cp); + } +#endif + + if (strcmp(prop->getName(),"Points") == 0) { + const std::vector& points = pcConstraint->Points.getValues(); + const std::vector& normals = pcConstraint->Normals.getValues(); + if (points.size() != normals.size()) { + return; + } + std::vector::const_iterator n = normals.begin(); + +#ifdef USE_MULTIPLE_COPY + cp = static_cast(pShapeSep->getChild(0)); //OvG: Use top cp + cp->matrix.setNum(points.size()); + SbMatrix* matrices = cp->matrix.startEditing(); + int idx = 0; +#else + // Redraw all cylinders + Gui::coinRemoveAllChildren(pShapeSep); +#endif + + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + SbVec3f base(p->x, p->y, p->z); + SbVec3f dir(n->x, n->y, n->z); + SbRotation rot(SbVec3f(0, -1.0, 0), dir); +#ifdef USE_MULTIPLE_COPY + SbMatrix m; + m.setTransform(base, rot, SbVec3f(1,1,1)); + matrices[idx] = m; + idx++; +#else + SoSeparator* sep = new SoSeparator(); + createPlacement(sep, base, rot); + createSpring(sep, scaledlength , scaledwidth); //OvG: Scaling + pShapeSep->addChild(sep); +#endif + n++; + } +#ifdef USE_MULTIPLE_COPY + cp->matrix.finishEditing(); +#endif + } + + ViewProviderFemConstraint::updateData(prop); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintSpring.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintSpring.h new file mode 100644 index 0000000000..c9e9aa32d8 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintSpring.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (c) 2021 FreeCAD Developers * + * Author: Preslav Aleksandrov * + * Based on Force constraint by Jan Rheinländer * + * 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_VIEWPROVIDERFEMCONSTRAINTSPRING_H +#define GUI_VIEWPROVIDERFEMCONSTRAINTSPRING_H + +#include "ViewProviderFemConstraint.h" + +namespace FemGui { + +class FemGuiExport ViewProviderFemConstraintSpring : public FemGui::ViewProviderFemConstraint +{ + PROPERTY_HEADER(FemGui::ViewProviderFemConstraintSpring); + +public: + ViewProviderFemConstraintSpring(); + virtual ~ViewProviderFemConstraintSpring(); + virtual void updateData(const App::Property*); + +protected: + virtual bool setEdit(int ModNum); +}; + +} + +#endif // GUI_VIEWPROVIDERFEMCONSTRAINTSPRING_H diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index 238c31a142..2dd0114567 100755 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -139,6 +139,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "FEM_ConstraintDisplacement" << "FEM_ConstraintContact" << "FEM_ConstraintTie" + << "FEM_ConstraintSpring" << "Separator" << "FEM_ConstraintForce" << "FEM_ConstraintPressure" @@ -266,6 +267,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "FEM_ConstraintDisplacement" << "FEM_ConstraintContact" << "FEM_ConstraintTie" + << "FEM_ConstraintSpring" << "Separator" << "FEM_ConstraintForce" << "FEM_ConstraintPressure" diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py index bc99add23a..5d9a8b51cd 100644 --- a/src/Mod/Fem/ObjectsFem.py +++ b/src/Mod/Fem/ObjectsFem.py @@ -335,6 +335,16 @@ def makeConstraintSectionPrint( return obj +def makeConstraintSpring( + doc, + name="ConstraintSpring" +): + """makeConstraintSpring(document, [name]): + makes a Fem ConstraintSpring object""" + obj = doc.addObject("Fem::ConstraintSpring", name) + return obj + + # ********* element definition objects *********************************************************** def makeElementFluid1D( doc, diff --git a/src/Mod/Fem/femtest/app/test_object.py b/src/Mod/Fem/femtest/app/test_object.py index 89371f1714..1ec683da3e 100644 --- a/src/Mod/Fem/femtest/app/test_object.py +++ b/src/Mod/Fem/femtest/app/test_object.py @@ -193,6 +193,10 @@ class TestObjectType(unittest.TestCase): "Fem::ConstraintFluidBoundary", type_of_obj(ObjectsFem.makeConstraintFluidBoundary(doc)) ) + self.assertEqual( + "Fem::ConstraintSpring", + type_of_obj(ObjectsFem.makeConstraintSpring(doc)) + ) self.assertEqual( "Fem::ConstraintForce", type_of_obj(ObjectsFem.makeConstraintForce(doc)) @@ -410,6 +414,10 @@ class TestObjectType(unittest.TestCase): ObjectsFem.makeConstraintFluidBoundary(doc), "Fem::ConstraintFluidBoundary" )) + self.assertTrue(is_of_type( + ObjectsFem.makeConstraintSpring(doc), + "Fem::ConstraintSpring" + )) self.assertTrue(is_of_type( ObjectsFem.makeConstraintForce(doc), "Fem::ConstraintForce" @@ -737,6 +745,21 @@ class TestObjectType(unittest.TestCase): "Fem::ConstraintFluidBoundary" )) + # ConstraintSpring + constraint_spring = ObjectsFem.makeConstraintSpring(doc) + self.assertTrue(is_derived_from( + constraint_spring, + "App::DocumentObject" + )) + self.assertTrue(is_derived_from( + constraint_spring, + "Fem::Constraint" + )) + self.assertTrue(is_derived_from( + constraint_spring, + "Fem::ConstraintSpring" + )) + # ConstraintForce constraint_force = ObjectsFem.makeConstraintForce(doc) self.assertTrue(is_derived_from( @@ -1415,6 +1438,11 @@ class TestObjectType(unittest.TestCase): doc ).isDerivedFrom("Fem::ConstraintFluidBoundary") ) + self.assertTrue( + ObjectsFem.makeConstraintSpring( + doc + ).isDerivedFrom("Fem::ConstraintSpring") + ) self.assertTrue( ObjectsFem.makeConstraintForce( doc @@ -1645,6 +1673,7 @@ def create_all_fem_objects_doc( analysis.addObject(ObjectsFem.makeConstraintFixed(doc)) analysis.addObject(ObjectsFem.makeConstraintFlowVelocity(doc)) analysis.addObject(ObjectsFem.makeConstraintFluidBoundary(doc)) + analysis.addObject(ObjectsFem.makeConstraintSpring(doc)) analysis.addObject(ObjectsFem.makeConstraintForce(doc)) analysis.addObject(ObjectsFem.makeConstraintGear(doc)) analysis.addObject(ObjectsFem.makeConstraintHeatflux(doc))