From 4eb39c5c365c4ba35114bc9061094e51fa760dd1 Mon Sep 17 00:00:00 2001 From: vdwalts Date: Mon, 1 Aug 2016 21:56:39 +0100 Subject: [PATCH] FEM: constraint contact: object implementation --- src/Mod/Fem/App/AppFem.cpp | 2 + src/Mod/Fem/App/CMakeLists.txt | 2 + src/Mod/Fem/App/FemConstraintContact.cpp | 82 +++ src/Mod/Fem/App/FemConstraintContact.h | 72 +++ src/Mod/Fem/Gui/AppFemGui.cpp | 2 + src/Mod/Fem/Gui/CMakeLists.txt | 7 + src/Mod/Fem/Gui/Command.cpp | 48 +- src/Mod/Fem/Gui/TaskFemConstraintContact.cpp | 490 ++++++++++++++++++ src/Mod/Fem/Gui/TaskFemConstraintContact.h | 89 ++++ src/Mod/Fem/Gui/TaskFemConstraintContact.ui | 169 ++++++ .../Gui/ViewProviderFemConstraintContact.cpp | 169 ++++++ .../Gui/ViewProviderFemConstraintContact.h | 47 ++ src/Mod/Fem/Gui/Workbench.cpp | 8 +- 13 files changed, 1185 insertions(+), 2 deletions(-) create mode 100644 src/Mod/Fem/App/FemConstraintContact.cpp create mode 100644 src/Mod/Fem/App/FemConstraintContact.h create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintContact.cpp create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintContact.h create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintContact.ui create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintContact.cpp create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintContact.h diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index ea0eff09e..611a5ec69 100644 --- a/src/Mod/Fem/App/AppFem.cpp +++ b/src/Mod/Fem/App/AppFem.cpp @@ -51,6 +51,7 @@ #include "FemConstraintGear.h" #include "FemConstraintPulley.h" #include "FemConstraintDisplacement.h" +#include "FemConstraintContact.h" #include "FemResultObject.h" #include "FemSolverObject.h" @@ -147,6 +148,7 @@ PyMODINIT_FUNC initFem() Fem::ConstraintGear ::init(); Fem::ConstraintPulley ::init(); Fem::ConstraintDisplacement ::init(); + Fem::ConstraintContact ::init(); Fem::FemResultObject ::init(); Fem::FemSolverObject ::init(); diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index c4a2fee19..eab2910dd 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -200,6 +200,8 @@ SET(FemConstraints_SRCS FemConstraintPulley.h FemConstraintDisplacement.h FemConstraintDisplacement.cpp + FemConstraintContact.cpp + FemConstraintContact.h ) SOURCE_GROUP("Constraints" FILES ${FemConstraints_SRCS}) diff --git a/src/Mod/Fem/App/FemConstraintContact.cpp b/src/Mod/Fem/App/FemConstraintContact.cpp new file mode 100644 index 000000000..f43cef057 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintContact.cpp @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (c) 2013 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 "FemConstraintContact.h" + +using namespace Fem; + +PROPERTY_SOURCE(Fem::ConstraintContact, Fem::Constraint); + +ConstraintContact::ConstraintContact() +{ +/*Note: Initialise parameters here*/ + ADD_PROPERTY(Slope,(0.0)); + ADD_PROPERTY(Friction,(0.0)); +/* */ + + ADD_PROPERTY_TYPE(Points,(Base::Vector3d()),"ConstraintContact",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Points where symbols are drawn"); + ADD_PROPERTY_TYPE(Normals,(Base::Vector3d()),"ConstraintContact",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Normals where symbols are drawn"); + Points.setValues(std::vector()); + Normals.setValues(std::vector()); +} + +App::DocumentObjectExecReturn *ConstraintContact::execute(void) +{ + return Constraint::execute(); +} + +const char* ConstraintContact::getViewProviderName(void) const +{ + return "FemGui::ViewProviderFemConstraintContact"; +} + +void ConstraintContact::onChanged(const App::Property* prop) +{ + Constraint::onChanged(prop); + + if (prop == &References) { + std::vector points; + std::vector normals; + int scale = 1; //OvG: Enforce use of scale + if (getPoints(points, normals, &scale)) { + Points.setValues(points); + Normals.setValues(normals); + Scale.setValue(scale); //OvG: Scale + Points.touch(); // This triggers ViewProvider::updateData() + } + } +} diff --git a/src/Mod/Fem/App/FemConstraintContact.h b/src/Mod/Fem/App/FemConstraintContact.h new file mode 100644 index 000000000..00051d041 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintContact.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (c) 2013 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_CONSTRAINTCONTACT_H +#define FEM_CONSTRAINTCONTACT_H + +#include "FemConstraint.h" + +namespace Fem +{ + +class AppFemExport ConstraintContact : public Fem::Constraint +{ + PROPERTY_HEADER(Fem::ConstraintContact); + +public: + /// Constructor + ConstraintContact(void); + + // Read-only (calculated values). These trigger changes in the ViewProvider + App::PropertyVectorList Points; + App::PropertyVectorList Normals; + +/*Note*/ + //Constraint parameters + /****** + * Add the constraint parameters here, the variables or data + * that needs to be eventually send over to the calculix input file. + * This is only the definitions of the variables + ******/ + //ex. + App::PropertyFloat Slope; + App::PropertyFloat Friction; + + //etc +/* */ + + /// 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); + +}; + +} //namespace Fem + + +#endif // FEM_CONSTRAINTCONTACT_H diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index 97c27cc96..2967741ca 100644 --- a/src/Mod/Fem/Gui/AppFemGui.cpp +++ b/src/Mod/Fem/Gui/AppFemGui.cpp @@ -51,6 +51,7 @@ #include "ViewProviderFemConstraintGear.h" #include "ViewProviderFemConstraintPulley.h" #include "ViewProviderFemConstraintDisplacement.h" +#include "ViewProviderFemConstraintContact.h" #include "ViewProviderResult.h" #include "Workbench.h" @@ -116,6 +117,7 @@ PyMODINIT_FUNC initFemGui() FemGui::ViewProviderFemConstraintGear ::init(); FemGui::ViewProviderFemConstraintPulley ::init(); FemGui::ViewProviderFemConstraintDisplacement ::init(); + FemGui::ViewProviderFemConstraintContact ::init(); FemGui::ViewProviderResult ::init(); FemGui::ViewProviderResultPython ::init(); FemGui::PropertyFemMeshItem ::init(); diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index f8dad5bf8..8f0fd0f1d 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -64,6 +64,7 @@ set(FemGui_MOC_HDRS TaskFemConstraintGear.h TaskFemConstraintPulley.h TaskFemConstraintDisplacement.h + TaskFemConstraintContact.h TaskTetParameter.h TaskAnalysisInfo.h TaskDriver.h @@ -90,6 +91,7 @@ set(FemGui_UIC_SRCS TaskFemConstraintForce.ui TaskFemConstraintPressure.ui TaskFemConstraintDisplacement.ui + TaskFemConstraintContact.ui TaskTetParameter.ui TaskAnalysisInfo.ui TaskDriver.ui @@ -135,6 +137,9 @@ SET(FemGui_DLG_SRCS TaskFemConstraintDisplacement.ui TaskFemConstraintDisplacement.cpp TaskFemConstraintDisplacement.h + TaskFemConstraintContact.ui + TaskFemConstraintContact.cpp + TaskFemConstraintContact.h ) SOURCE_GROUP("Constraint-Dialogs" FILES ${FemGui_DLG_SRCS}) @@ -179,6 +184,8 @@ SET(FemGui_SRCS_ViewProvider ViewProviderFemConstraintPulley.h ViewProviderFemConstraintDisplacement.cpp ViewProviderFemConstraintDisplacement.h + ViewProviderFemConstraintContact.cpp + ViewProviderFemConstraintContact.h ViewProviderResult.cpp ViewProviderResult.h ) diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 874c8c5e7..9b577520b 100644 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -354,6 +354,51 @@ bool CmdFemConstraintFixed::isActive(void) //===================================================================================== +DEF_STD_CMD_A(CmdFemConstraintContact); + +CmdFemConstraintContact::CmdFemConstraintContact() + : Command("Fem_ConstraintContact") +{ + sAppModule = "Fem"; + sGroup = QT_TR_NOOP("Fem"); + sMenuText = QT_TR_NOOP("Constraint contact "); + sToolTipText = QT_TR_NOOP("Creates a FEM constraint for contact between faces"); + sWhatsThis = "Fem_ConstraintContact"; + sStatusTip = sToolTipText; + sPixmap = "fem-constraint-contact"; +} + +void CmdFemConstraintContact::activated(int iMsg) +{ + Fem::FemAnalysis *Analysis; + + if(getConstraintPrerequisits(&Analysis)) + return; + + std::string FeatName = getUniqueObjectName("FemConstraintContact"); + + openCommand("Make FEM constraint contact on face"); + doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintContact\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Slope = 1000000.00",FeatName.c_str()); //OvG: set default not equal to 0 + doCommand(Doc,"App.activeDocument().%s.Friction = 0.0",FeatName.c_str()); //OvG: set default not equal to 0 + doCommand(Doc,"App.activeDocument().%s.Scale = 1",FeatName.c_str()); //OvG: set initial scale to 1 + doCommand(Doc,"App.activeDocument().%s.Member = App.activeDocument().%s.Member + [App.activeDocument().%s]", + Analysis->getNameInDocument(),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 CmdFemConstraintContact::isActive(void) +{ + return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); +} + +//===================================================================================== + DEF_STD_CMD_A(CmdFemConstraintForce); CmdFemConstraintForce::CmdFemConstraintForce() @@ -1143,7 +1188,8 @@ void CreateFemCommands(void) rcCmdMgr.addCommand(new CmdFemConstraintGear()); rcCmdMgr.addCommand(new CmdFemConstraintPulley()); rcCmdMgr.addCommand(new CmdFemConstraintDisplacement()); - + rcCmdMgr.addCommand(new CmdFemConstraintContact()); + #ifdef FC_USE_VTK rcCmdMgr.addCommand(new CmdFemPostCreateClipFilter); rcCmdMgr.addCommand(new CmdFemPostCreateScalarClipFilter); diff --git a/src/Mod/Fem/Gui/TaskFemConstraintContact.cpp b/src/Mod/Fem/Gui/TaskFemConstraintContact.cpp new file mode 100644 index 000000000..e05ab38d4 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintContact.cpp @@ -0,0 +1,490 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Michael Hindley * + * Ruan Olwagen * + * Oswald van Ginkel * + * 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 +#endif + +#include "Mod/Fem/App/FemConstraintContact.h" +#include "TaskFemConstraintContact.h" +#include "ui_TaskFemConstraintContact.h" +#include +#include + + + +#include +#include + + +using namespace FemGui; +using namespace Gui; + +/* TRANSLATOR FemGui::TaskFemConstraintContact */ + +TaskFemConstraintContact::TaskFemConstraintContact(ViewProviderFemConstraintContact *ConstraintView,QWidget *parent) + : TaskFemConstraint(ConstraintView, parent, "fem-constraint-contact") +{ + proxy = new QWidget(this); + ui = new Ui_TaskFemConstraintContact(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + QAction* actionSlave = new QAction(tr("Delete"), ui->lw_referencesSlave); + actionSlave->connect(actionSlave, SIGNAL(triggered()), this, SLOT(onReferenceDeletedSlave())); + + QAction* actionMaster = new QAction(tr("Delete"), ui->lw_referencesMaster); + actionMaster->connect(actionMaster, SIGNAL(triggered()), this, SLOT(onReferenceDeletedMaster())); + + ui->lw_referencesSlave->addAction(actionSlave); + ui->lw_referencesSlave->setContextMenuPolicy(Qt::ActionsContextMenu); + + connect(ui->lw_referencesSlave, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + + ui->lw_referencesMaster->addAction(actionMaster); + ui->lw_referencesMaster->setContextMenuPolicy(Qt::ActionsContextMenu); + + connect(ui->lw_referencesMaster, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + + this->groupLayout()->addWidget(proxy); + +/* Note: */ + // Get the feature data + Fem::ConstraintContact* pcConstraint = static_cast(ConstraintView->getObject()); + + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + double S = pcConstraint->Slope.getValue(); + double F = pcConstraint->Friction.getValue(); + + // Fill data into dialog elements + ui->spSlope->setMinimum(1.0); + ui->spSlope->setValue(S); + ui->spFriction->setValue(F); + +/* */ + + ui->lw_referencesMaster->clear(); + ui->lw_referencesSlave->clear(); + if (Objects.size() > 0){ + for (std::size_t i = 1; i < Objects.size(); i++) { + ui->lw_referencesMaster->addItem(makeRefText(Objects[i], SubElements[i])); + } + + for (std::size_t i = 0; i < (Objects.size()-1); i++) { + ui->lw_referencesSlave->addItem(makeRefText(Objects[i], SubElements[i])); + } +} + + //Selection buttons + connect(ui->btnAddSlave, SIGNAL(clicked()), this, SLOT(addToSelectionSlave())); + connect(ui->btnRemoveSlave, SIGNAL(clicked()), this, SLOT(removeFromSelectionSlave())); + + connect(ui->btnAddMaster, SIGNAL(clicked()), this, SLOT(addToSelectionMaster())); + connect(ui->btnRemoveMaster, SIGNAL(clicked()), this, SLOT(removeFromSelectionMaster())); + + updateUI(); +} + +TaskFemConstraintContact::~TaskFemConstraintContact() +{ + delete ui; +} + +void TaskFemConstraintContact::updateUI() +{ + if (ui->lw_referencesSlave->model()->rowCount() == 0) { + // Go into reference selection mode if no reference has been selected yet + onButtonReference(true); + return; + } + if (ui->lw_referencesMaster->model()->rowCount() == 0) { + // Go into reference selection mode if no reference has been selected yet + onButtonReference(true); + return; + } +} + +void TaskFemConstraintContact::addToSelectionSlave() +{ + int rows = ui->lw_referencesSlave->model()->rowCount(); + std::vector selection = Gui::Selection().getSelectionEx();//gets vector of selected objects of active document + if (rows==1){ + QMessageBox::warning(this, tr("Selection error"), tr("Only one master face and one slave face for a contact constraint!")); + Gui::Selection().clearSelection(); + return; + } + + if (selection.size()==0){ + QMessageBox::warning(this, tr("Selection error"), tr("Nothing selected!")); + return; + } + + if ((rows==0) && (selection.size()>=2)){ + QMessageBox::warning(this, tr("Selection error"), tr("Only one slave face for a contact constraint!")); + Gui::Selection().clearSelection(); + return; + } + + Fem::ConstraintContact* 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 (static_cast(it->getTypeName()).substr(0,4).compare(std::string("Part"))!=0){ + 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()); + if (subNames.size()!=1){ + QMessageBox::warning(this, tr("Selection error"), tr("Only one slave face for a contact constraint!")); + Gui::Selection().clearSelection(); + return; + } + for (unsigned int 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){ + disconnect(ui->lw_referencesSlave, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + Objects.push_back(obj); + SubElements.push_back(subNames[subIt]); + ui->lw_referencesSlave->addItem(makeRefText(obj, subNames[subIt])); + connect(ui->lw_referencesSlave, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + } + } + } + //Update UI + pcConstraint->References.setValues(Objects,SubElements); + updateUI(); +} + +void TaskFemConstraintContact::removeFromSelectionSlave() +{ + 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::ConstraintContact* 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 (static_cast(it->getTypeName()).substr(0,4).compare(std::string("Part"))!=0){ + 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 (unsigned int 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 + disconnect(ui->lw_referencesSlave, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + + ui->lw_referencesSlave->clear(); + connect(ui->lw_referencesSlave, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + + pcConstraint->References.setValues(Objects,SubElements); + updateUI(); +} + +void TaskFemConstraintContact::addToSelectionMaster() +{ + int rows = ui->lw_referencesMaster->model()->rowCount(); + std::vector selection = Gui::Selection().getSelectionEx();//gets vector of selected objects of active document + if (rows==1){ + QMessageBox::warning(this, tr("Selection error"), tr("Only one master face and one slave face for a contact constraint!")); + Gui::Selection().clearSelection(); + return; + } + + if (selection.size()==0){ + QMessageBox::warning(this, tr("Selection error"), tr("Nothing selected!")); + return; + } + + if ((rows==0) && (selection.size()>=2)){ + QMessageBox::warning(this, tr("Selection error"), tr("Only one master for a contact constraint!")); + Gui::Selection().clearSelection(); + return; + } + + Fem::ConstraintContact* 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 (static_cast(it->getTypeName()).substr(0,4).compare(std::string("Part"))!=0){ + 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()); + if (subNames.size()!=1){ + QMessageBox::warning(this, tr("Selection error"), tr("Only one master face for a contact constraint!")); + Gui::Selection().clearSelection(); + return; + } + for (unsigned int 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){ + disconnect(ui->lw_referencesMaster, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + Objects.push_back(obj); + SubElements.push_back(subNames[subIt]); + ui->lw_referencesMaster->addItem(makeRefText(obj, subNames[subIt])); + connect(ui->lw_referencesMaster, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + } + } + } + //Update UI + pcConstraint->References.setValues(Objects,SubElements); + updateUI(); +} + +void TaskFemConstraintContact::removeFromSelectionMaster() +{ + 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::ConstraintContact* 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 (static_cast(it->getTypeName()).substr(0,4).compare(std::string("Part"))!=0){ + 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 (unsigned int 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 + disconnect(ui->lw_referencesMaster, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + + ui->lw_referencesMaster->clear(); + connect(ui->lw_referencesMaster, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + + pcConstraint->References.setValues(Objects,SubElements); + updateUI(); +} + +void TaskFemConstraintContact::setSelection(QListWidgetItem* item){ + std::string docName=ConstraintView->getObject()->getDocument()->getName(); + + std::string s = item->text().toStdString(); + std::string delimiter = ":"; + + size_t pos = 0; + std::string objName; + std::string subName; + pos = s.find(delimiter); + objName = s.substr(0, pos); + s.erase(0, pos + delimiter.length()); + subName=s; + + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(docName.c_str(),objName.c_str(),subName.c_str(),0,0,0); +} + +void TaskFemConstraintContact::onReferenceDeletedSlave() { + TaskFemConstraintContact::removeFromSelectionSlave(); +} + +void TaskFemConstraintContact::onReferenceDeletedMaster() { + TaskFemConstraintContact::removeFromSelectionMaster(); +} + +const std::string TaskFemConstraintContact::getReferences() const +{ + int rowsSlave = ui->lw_referencesSlave->model()->rowCount(); + std::vector items; + for (int r = 0; r < rowsSlave; r++) { + items.push_back(ui->lw_referencesSlave->item(r)->text().toStdString()); + } + + int rowsMaster = ui->lw_referencesMaster->model()->rowCount(); + for (int r = 0; r < rowsMaster; r++) { + items.push_back(ui->lw_referencesMaster->item(r)->text().toStdString()); + } + return TaskFemConstraint::getReferences(items); +} + +/* Note: */ +double TaskFemConstraintContact::get_Slope() const{return ui->spSlope->value();} +double TaskFemConstraintContact::get_Friction() const{return ui->spFriction->value();} + + + +void TaskFemConstraintContact::changeEvent(QEvent *e){ +} + +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraintContact::TaskDlgFemConstraintContact(ViewProviderFemConstraintContact *ConstraintView) +{ + this->ConstraintView = ConstraintView; + assert(ConstraintView); + this->parameter = new TaskFemConstraintContact(ConstraintView);; + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +void TaskDlgFemConstraintContact::open() +{ + // a transaction is already open at creation time of the panel + if (!Gui::Command::hasPendingCommand()) { + QString msg = QObject::tr("Constraint Contact"); + 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 TaskDlgFemConstraintContact::accept() +{ +/* Note: */ + std::string name = ConstraintView->getObject()->getNameInDocument(); + const TaskFemConstraintContact* parameterContact = static_cast(parameter); + + try { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Slope = %f", + name.c_str(), parameterContact->get_Slope()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Friction = %f", + name.c_str(), parameterContact->get_Friction()); + std::string scale = parameterContact->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 TaskDlgFemConstraintContact::reject() +{ + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::updateActive(); + + return true; +} +#include "moc_TaskFemConstraintContact.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintContact.h b/src/Mod/Fem/Gui/TaskFemConstraintContact.h new file mode 100644 index 000000000..fe07b71a9 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintContact.h @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Michael Hindley * + * Ruan Olwagen * + * Oswald van Ginkel * + * 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_TaskFemConstraintContact_H +#define GUI_TASKVIEW_TaskFemConstraintContact_H + +#include +#include +#include +#include + +#include "TaskFemConstraint.h" +#include "ViewProviderFemConstraintContact.h" + +#include +#include +#include +#include + +class Ui_TaskFemConstraintContact; + +namespace FemGui { +class TaskFemConstraintContact : public TaskFemConstraint +{ + Q_OBJECT + +public: + TaskFemConstraintContact(ViewProviderFemConstraintContact *ConstraintView,QWidget *parent = 0); + ~TaskFemConstraintContact(); + const std::string getReferences() const; + double get_Slope()const; + double get_Friction()const; + +private Q_SLOTS: + void onReferenceDeletedSlave(void); + void onReferenceDeletedMaster(void); + void addToSelectionSlave(); + void removeFromSelectionSlave(); + void addToSelectionMaster(); + void removeFromSelectionMaster(); + void setSelection(QListWidgetItem* item); + +protected: + void changeEvent(QEvent *e); + +private: + //void onSelectionChanged(const Gui::SelectionChanges& msg); + void updateUI(); + Ui_TaskFemConstraintContact* ui; + +}; + +class TaskDlgFemConstraintContact : public TaskDlgFemConstraint +{ + Q_OBJECT + +public: + TaskDlgFemConstraintContact(ViewProviderFemConstraintContact *ConstraintView); + void open(); + bool accept(); + bool reject(); +}; + +} //namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraintContact_H diff --git a/src/Mod/Fem/Gui/TaskFemConstraintContact.ui b/src/Mod/Fem/Gui/TaskFemConstraintContact.ui new file mode 100644 index 000000000..d19dd1e80 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintContact.ui @@ -0,0 +1,169 @@ + + + TaskFemConstraintContact + + + + 0 + 0 + 354 + 251 + + + + Form + + + + + + + + Select master face, click Add or Remove + + + + + + + + + Add + + + + + + + Remove + + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 31 + + + + + + + + + + Select slave face, click Add or Remove + + + + + + + + + Add + + + + + + + Remove + + + + + + + + + + + true + + + + 0 + 0 + + + + + 16777215 + 31 + + + + + + + + + + Contact Stiffness + + + + + + + 2 + + + 1000000000.000000000000000 + + + 1.000000000000000 + + + 1000000.000000000000000 + + + + + + + + + + + Friction coefficient + + + + + + + 1 + + + 1.000000000000000 + + + 0.100000000000000 + + + + + + + lbl_info + lw_referencesSlave + lw_referencesMaster + lbl_info_2 + + + + diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintContact.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintContact.cpp new file mode 100644 index 000000000..17b273c47 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintContact.cpp @@ -0,0 +1,169 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Michael Hindley * + * Ruan Olwagen * + * Oswald van Ginkel * + * 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 +#endif + +#include "Mod/Fem/App/FemConstraintContact.h" +#include "TaskFemConstraintContact.h" +#include "ViewProviderFemConstraintContact.h" +#include +#include + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintContact, FemGui::ViewProviderFemConstraint) + +ViewProviderFemConstraintContact::ViewProviderFemConstraintContact() +{ + sPixmap = "fem-constraint-contact"; + //Note change "Contact" in line above to new constraint name, make sure it is the same as in taskFem* cpp file + ADD_PROPERTY(FaceColor,(0.2f,0.3f,0.2f)); +} + +ViewProviderFemConstraintContact::~ViewProviderFemConstraintContact() +{ +} + +//FIXME setEdit needs a careful review +bool ViewProviderFemConstraintContact::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(); + TaskDlgFemConstraintContact *constrDlg = qobject_cast(dlg); + 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 TaskFemConstraintContact(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 TaskDlgFemConstraintContact(this)); + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); + } +} + +#define HEIGHT (0.5) +#define LENGTH (1.5) +#define WIDTH (0.5) + +//#define USE_MULTIPLE_COPY //OvG: MULTICOPY fails to update scaled display on initial drawing - so disable + +void ViewProviderFemConstraintContact::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + Fem::ConstraintContact* pcConstraint = static_cast(this->getObject()); + float scaledlength = LENGTH * pcConstraint->Scale.getValue(); //OvG: Calculate scaled values once only + float scaledheight = HEIGHT * pcConstraint->Scale.getValue(); + float scaledwidth = WIDTH * pcConstraint->Scale.getValue(); + + 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(); + + // Points and Normals are always updated together + pShapeSep->removeAllChildren(); + + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + //Define base and normal directions + SbVec3f base(p->x, p->y, p->z); + SbVec3f dir(n->x, n->y, n->z);//normal + + ///Visual indication + //define separator + SoSeparator* sep = new SoSeparator(); + + //first move to correct postion + SoTranslation* trans = new SoTranslation(); + SbVec3f newPos=base+scaledheight*dir*0.12; + trans->translation.setValue(newPos); + sep->addChild(trans); + + //adjust orientation + SoRotation* rot = new SoRotation(); + rot->rotation.setValue(SbRotation(SbVec3f(0,1,0),dir)); + sep->addChild(rot); + + //define color of shape + SoMaterial* myMaterial = new SoMaterial; + myMaterial->diffuseColor.set1Value(0,SbColor(1,1,1));//RGB + //myMaterial->diffuseColor.set1Value(1,SbColor(0,0,1));//possible to adjust sides separately + sep->addChild(myMaterial); + + //draw a cube + SoCube* cbe = new SoCube(); + cbe->depth.setValue(scaledlength*0.5); + cbe->height.setValue(scaledheight*0.25); + cbe->width.setValue(scaledwidth*0.75); + sep->addChild(cbe); + //translate postion + SoTranslation* trans2 = new SoTranslation(); + trans2->translation.setValue(SbVec3f(0,0,0)); + sep->addChild(trans2); + + + pShapeSep->addChild(sep); + n++; + } + } + // Gets called whenever a property of the attached object changes + ViewProviderFemConstraint::updateData(prop); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintContact.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintContact.h new file mode 100644 index 000000000..d404e3f6f --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintContact.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Michael Hindley * + * Ruan Olwagen * + * Oswald van Ginkel * + * 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_VIEWPROVIDERFEMCONSTRAINTCONTACT_H +#define GUI_VIEWPROVIDERFEMCONSTRAINTCONTACT_H + +#include "ViewProviderFemConstraint.h" + +namespace FemGui { + +class FemGuiExport ViewProviderFemConstraintContact : public FemGui::ViewProviderFemConstraint +{ + PROPERTY_HEADER(FemGui::ViewProviderFemConstraintContact); + +public: + ViewProviderFemConstraintContact(); + virtual ~ViewProviderFemConstraintContact(); + virtual void updateData(const App::Property*); + +protected: + virtual bool setEdit(int ModNum); +}; +} + +#endif // GUI_VIEWPROVIDERFEMCONSTRAINTContact_H diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index 97aaa785e..18f694027 100755 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -67,16 +67,19 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "Separator" << "Fem_ConstraintFixed" << "Fem_ConstraintDisplacement" + << "Fem_ConstraintContact" << "Separator" << "Fem_ConstraintSelfWeight" << "Fem_ConstraintForce" << "Fem_ConstraintPressure" + << "Separator" << "Fem_ConstraintBearing" << "Fem_ConstraintGear" << "Fem_ConstraintPulley" << "Separator" << "Fem_ControlSolver" << "Fem_RunSolver" + << "Separator" << "Fem_PurgeResults" << "Fem_ShowResult"; @@ -116,18 +119,21 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Separator" << "Fem_ConstraintFixed" << "Fem_ConstraintDisplacement" + << "Fem_ConstraintContact" << "Separator" << "Fem_ConstraintSelfWeight" << "Fem_ConstraintForce" << "Fem_ConstraintPressure" + << "Separator" << "Fem_ConstraintBearing" << "Fem_ConstraintGear" << "Fem_ConstraintPulley" << "Separator" << "Fem_ControlSolver" << "Fem_RunSolver" + << "Separator" << "Fem_PurgeResults" << "Fem_ShowResult"; return root; -} \ No newline at end of file +}