From 918291f81fbc1fb7b900cc2dfae526c417837bf4 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 7 Feb 2013 11:09:43 +0430 Subject: [PATCH 1/9] Created FEM constraint document object --- src/Mod/Fem/App/AppFem.cpp | 2 + src/Mod/Fem/App/CMakeLists.txt | 2 + src/Mod/Fem/App/FemConstraint.cpp | 70 ++ src/Mod/Fem/App/FemConstraint.h | 71 ++ src/Mod/Fem/Gui/AppFemGui.cpp | 14 +- src/Mod/Fem/Gui/CMakeLists.txt | 22 +- src/Mod/Fem/Gui/Command.cpp | 35 + src/Mod/Fem/Gui/TaskFemConstraint.cpp | 752 ++++++++++++++++ src/Mod/Fem/Gui/TaskFemConstraint.h | 131 +++ src/Mod/Fem/Gui/TaskFemConstraint.ui | 208 +++++ src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp | 819 ++++++++++++++++++ src/Mod/Fem/Gui/ViewProviderFemConstraint.h | 98 +++ src/Mod/Fem/Gui/Workbench.cpp | 8 +- 13 files changed, 2221 insertions(+), 11 deletions(-) create mode 100644 src/Mod/Fem/App/FemConstraint.cpp create mode 100644 src/Mod/Fem/App/FemConstraint.h create mode 100644 src/Mod/Fem/Gui/TaskFemConstraint.cpp create mode 100644 src/Mod/Fem/Gui/TaskFemConstraint.h create mode 100644 src/Mod/Fem/Gui/TaskFemConstraint.ui create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraint.h diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index a317d61334..7a29fcada2 100755 --- a/src/Mod/Fem/App/AppFem.cpp +++ b/src/Mod/Fem/App/AppFem.cpp @@ -41,6 +41,7 @@ #include "FemSetNodesObject.h" #include "HypothesisPy.h" +#include "FemConstraint.h" extern struct PyMethodDef Fem_methods[]; @@ -115,6 +116,7 @@ void AppFemExport initFem() Fem::FemSetGeometryObject ::init(); Fem::FemSetNodesObject ::init(); + Fem::Constraint ::init(); } } // extern "C" diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index 5dd69680bd..ba16889993 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -64,6 +64,8 @@ SET(Fem_SRCS FemMesh.h FemMeshProperty.cpp FemMeshProperty.h + FemConstraint.cpp + FemConstraint.h ${Mod_SRCS} ${Python_SRCS} ) diff --git a/src/Mod/Fem/App/FemConstraint.cpp b/src/Mod/Fem/App/FemConstraint.cpp new file mode 100644 index 0000000000..ae9ef45ec5 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraint.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + * 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_ +#endif + +#include "FemConstraint.h" + +#include + +using namespace Fem; + +const char* Constraint::TypeEnums[]= {"Force on geometry","Fixed", + "Bearing (radial free)", "Bearing (radial fixed)", + "Pulley", "Gear (straight toothed)", NULL}; + +PROPERTY_SOURCE(Fem::Constraint, App::DocumentObject); + +Constraint::Constraint() +{ + ADD_PROPERTY(Type,((long)0)); + Type.setEnums(TypeEnums); + ADD_PROPERTY(Force,(0.0)); + ADD_PROPERTY_TYPE(References,(0,0),"Constraint",(App::PropertyType)(App::Prop_None),"Elements where the constraint is applied"); + ADD_PROPERTY_TYPE(Direction,(0),"Constraint",(App::PropertyType)(App::Prop_None),"Element giving direction of constraint"); + ADD_PROPERTY(Reversed,(0)); + ADD_PROPERTY(Distance,(0.0)); + ADD_PROPERTY_TYPE(Location,(0),"Constraint",(App::PropertyType)(App::Prop_None),"Element giving location where constraint is applied"); + ADD_PROPERTY(Diameter,(0.0)); + ADD_PROPERTY(OtherDiameter,(0.0)); + ADD_PROPERTY(CenterDistance,(0.0)); +} + +Constraint::~Constraint() +{ +} + +App::DocumentObjectExecReturn *Constraint::execute(void) +{ + // Ensure that the constraint symbols follow the changed geometry + References.touch(); + return DocumentObject::StdReturn; +} + +void Constraint::onChanged(const App::Property* prop) +{ + DocumentObject::onChanged(prop); +} diff --git a/src/Mod/Fem/App/FemConstraint.h b/src/Mod/Fem/App/FemConstraint.h new file mode 100644 index 0000000000..625ba95aec --- /dev/null +++ b/src/Mod/Fem/App/FemConstraint.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * 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_CONSTRAINT_H +#define FEM_CONSTRAINT_H + +#include +#include + +namespace Fem +{ + +class AppFemExport Constraint : public App::DocumentObject +{ + PROPERTY_HEADER(Fem::Constraint); + +public: + /// Constructor + Constraint(void); + virtual ~Constraint(); + + App::PropertyEnumeration Type; + App::PropertyLinkSubList References; + App::PropertyFloat Force; + App::PropertyLinkSub Direction; + App::PropertyBool Reversed; + App::PropertyLinkSub Location; + App::PropertyFloat Distance; + App::PropertyFloat Diameter; + App::PropertyFloat OtherDiameter; + App::PropertyFloat CenterDistance; + + /// recalculate the object + virtual App::DocumentObjectExecReturn *execute(void); + + /// returns the type name of the ViewProvider + const char* getViewProviderName(void) const { + return "FemGui::ViewProviderFemConstraint"; + } + +protected: + virtual void onChanged(const App::Property* prop); + +private: + static const char* TypeEnums[]; +}; + +} //namespace Fem + + +#endif // FEM_CONSTRAINT_H diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index d36865d91f..46e20afe8f 100755 --- a/src/Mod/Fem/Gui/AppFemGui.cpp +++ b/src/Mod/Fem/Gui/AppFemGui.cpp @@ -34,6 +34,7 @@ #include "ViewProviderSetElements.h" #include "ViewProviderSetFaces.h" #include "ViewProviderSetGeometry.h" +#include "ViewProviderFemConstraint.h" #include "Workbench.h" //#include "resources/qrc_Fem.cpp" @@ -63,16 +64,17 @@ void FemGuiExport initFemGui() (void) Py_InitModule("FemGui", FemGui_Import_methods); /* mod name, table ptr */ Base::Console().Log("Loading GUI of Fem module... done\n"); - // instanciating the commands + // instantiating the commands CreateFemCommands(); // addition objects FemGui::Workbench ::init(); - FemGui::ViewProviderFemMesh ::init(); - FemGui::ViewProviderSetNodes ::init(); - FemGui::ViewProviderSetElements ::init(); - FemGui::ViewProviderSetFaces ::init(); - FemGui::ViewProviderSetGeometry ::init(); + FemGui::ViewProviderFemMesh ::init(); + FemGui::ViewProviderSetNodes ::init(); + FemGui::ViewProviderSetElements ::init(); + FemGui::ViewProviderSetFaces ::init(); + FemGui::ViewProviderSetGeometry ::init(); + FemGui::ViewProviderFemConstraint ::init(); // add resources and reloads the translators loadFemResource(); diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 6a36cfbec2..52c1c0dd79 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -34,6 +34,7 @@ set(FemGui_MOC_HDRS TaskObjectName.h TaskCreateNodeSet.h TaskDlgCreateNodeSet.h + TaskFemConstraint.h ) fc_wrap_cpp(FemGui_MOC_SRCS ${FemGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${FemGui_MOC_SRCS}) @@ -42,9 +43,21 @@ set(FemGui_UIC_SRCS Hypothesis.ui TaskCreateNodeSet.ui TaskObjectName.ui + TaskFemConstraint.ui ) qt4_wrap_ui(FemGui_UIC_HDRS ${FemGui_UIC_SRCS}) +SET(FemGui_DLG_SRCS + ${FemGui_UIC_HDRS} + Hypothesis.ui + Hypothesis.cpp + Hypothesis.h + TaskFemConstraint.ui + TaskFemConstraint.cpp + TaskFemConstraint.h +) +SOURCE_GROUP("Dialogs" FILES ${FemGui_DLG_SRCS}) + qt4_add_resources(FemResource_SRCS Resources/Fem.qrc) SOURCE_GROUP("Resources" FILES ${FemResource_SRCS}) @@ -62,14 +75,16 @@ SET(FemGui_SRCS_ViewProvider ViewProviderSetGeometry.h FemSelectionGate.cpp FemSelectionGate.h + ViewProviderFemConstraint.cpp + ViewProviderFemConstraint.h ) SOURCE_GROUP("ViewProvider" FILES ${FemGui_SRCS_ViewProvider}) SET(FemGui_SRCS_TaskBoxes - TaskObjectName.ui + TaskObjectName.ui TaskObjectName.cpp TaskObjectName.h - TaskCreateNodeSet.ui + TaskCreateNodeSet.ui TaskCreateNodeSet.cpp TaskCreateNodeSet.h ) @@ -81,6 +96,9 @@ SET(FemGui_SRCS_TaskDlg Hypothesis.ui Hypothesis.cpp Hypothesis.h + TaskFemConstraint.ui + TaskFemConstraint.cpp + TaskFemConstraint.h ) SOURCE_GROUP("Task_Dialogs" FILES ${FemGui_SRCS_TaskDlg}) diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 655879f22d..cd58e9714e 100755 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -52,8 +52,10 @@ #include #include #include +#include #include "Hypothesis.h" +#include "TaskFemConstraint.h" using namespace std; @@ -85,6 +87,38 @@ bool CmdFemCreateFromShape::isActive(void) return Gui::Selection().countObjectsOfType(type) > 0; } +DEF_STD_CMD_A(CmdFemConstraint); + +CmdFemConstraint::CmdFemConstraint() + : Command("Fem_Constraint") +{ + sAppModule = "Fem"; + sGroup = QT_TR_NOOP("Fem"); + sMenuText = QT_TR_NOOP("Create FEM constraint"); + sToolTipText = QT_TR_NOOP("Create FEM constraint"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Fem_Constraint"; +} + +void CmdFemConstraint::activated(int iMsg) +{ + std::string FeatName = getUniqueObjectName("FemConstraint"); + + openCommand("Make FEM constraint"); + doCommand(Doc,"App.activeDocument().addObject(\"Fem::Constraint\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Force = 0.0",FeatName.c_str()); + updateActive(); + + Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(App::GetApplication().getActiveDocument()->getActiveObject()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +} + +bool CmdFemConstraint::isActive(void) +{ + return hasActiveDocument(); +} // ##################################################################################################### @@ -281,4 +315,5 @@ void CreateFemCommands(void) rcCmdMgr.addCommand(new CmdFemCreateFromShape()); rcCmdMgr.addCommand(new CmdFemCreateNodesSet()); rcCmdMgr.addCommand(new CmdFemDefineNodesSet()); + rcCmdMgr.addCommand(new CmdFemConstraint()); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraint.cpp b/src/Mod/Fem/Gui/TaskFemConstraint.cpp new file mode 100644 index 0000000000..b415eedebe --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraint.cpp @@ -0,0 +1,752 @@ +/*************************************************************************** + * 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 +# include +# include +# include +# include +# include +# include +#endif + +#include "ui_TaskFemConstraint.h" +#include "TaskFemConstraint.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace FemGui; +using namespace Gui; + +/* TRANSLATOR FemGui::TaskFemConstraint */ + +const QString makeRefText(const App::DocumentObject* obj, const std::string& subName) +{ + return QString::fromUtf8((std::string(obj->getNameInDocument()) + ":" + subName).c_str()); +} + +TaskFemConstraint::TaskFemConstraint(ViewProviderFemConstraint *ConstraintView,QWidget *parent) + : TaskBox(Gui::BitmapFactory().pixmap("Fem_Constraint"),tr("FEM constraint parameters"),true, parent),ConstraintView(ConstraintView) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskFemConstraint(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + // Create a context menu for the listview of the references + QAction* action = new QAction(tr("Delete"), ui->listReferences); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onReferenceDeleted())); + ui->listReferences->addAction(action); + ui->listReferences->setContextMenuPolicy(Qt::ActionsContextMenu); + + connect(ui->comboType, SIGNAL(currentIndexChanged(int)), + this, SLOT(onTypeChanged(int))); + connect(ui->spinForce, SIGNAL(valueChanged(double)), + this, SLOT(onForceChanged(double))); + connect(ui->buttonReference, SIGNAL(pressed()), + this, SLOT(onButtonReference())); + connect(ui->buttonDirection, SIGNAL(pressed()), + this, SLOT(onButtonDirection())); + connect(ui->checkReverse, SIGNAL(toggled(bool)), + this, SLOT(onCheckReverse(bool))); + connect(ui->buttonLocation, SIGNAL(pressed()), + this, SLOT(onButtonLocation())); + connect(ui->spinDistance, SIGNAL(valueChanged(double)), + this, SLOT(onDistanceChanged(double))); + connect(ui->spinDiameter, SIGNAL(valueChanged(double)), + this, SLOT(onDiameterChanged(double))); + connect(ui->spinOtherDia, SIGNAL(valueChanged(double)), + this, SLOT(onOtherDiameterChanged(double))); + connect(ui->spinCenterDistance, SIGNAL(valueChanged(double)), + this, SLOT(onCenterDistanceChanged(double))); + + this->groupLayout()->addWidget(proxy); + + // Temporarily prevent unnecessary feature recomputes + ui->comboType->blockSignals(true); + ui->spinForce->blockSignals(true); + ui->listReferences->blockSignals(true); + ui->buttonReference->blockSignals(true); + ui->buttonDirection->blockSignals(true); + ui->checkReverse->blockSignals(true); + ui->buttonLocation->blockSignals(true); + ui->spinDistance->blockSignals(true); + ui->spinDiameter->blockSignals(true); + ui->spinOtherDia->blockSignals(true); + ui->spinCenterDistance->blockSignals(true); + + // Get the feature data + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + int index = pcConstraint->Type.getValue(); + double f = pcConstraint->Force.getValue(); + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + std::vector dirStrings = pcConstraint->Direction.getSubValues(); + QString dir; + if (!dirStrings.empty()) + dir = makeRefText(pcConstraint->Direction.getValue(), dirStrings.front()); + bool reversed = pcConstraint->Reversed.getValue(); + std::vector locStrings = pcConstraint->Location.getSubValues(); + QString loc; + if (!locStrings.empty()) + loc = makeRefText(pcConstraint->Location.getValue(), locStrings.front()); + double d = pcConstraint->Distance.getValue(); + double dia = pcConstraint->Diameter.getValue(); + double otherdia = pcConstraint->OtherDiameter.getValue(); + double centerdist = pcConstraint->CenterDistance.getValue(); + + // Fill data into dialog elements + ui->comboType->clear(); + ui->comboType->insertItem(0, tr("Force on geometry")); + ui->comboType->insertItem(1, tr("Fixed")); + ui->comboType->insertItem(2, tr("Bearing (axial free)")); + ui->comboType->insertItem(3, tr("Bearing (axial fixed)")); + ui->comboType->insertItem(4, tr("Pulley")); + ui->comboType->insertItem(5, tr("Gear (straight toothed)")); + ui->comboType->setCurrentIndex(index); + ui->spinForce->setMinimum(0); + ui->spinForce->setMaximum(INT_MAX); + ui->spinForce->setValue(f); + ui->listReferences->clear(); + + for (int i = 0; i < Objects.size(); i++) + ui->listReferences->addItem(makeRefText(Objects[i], SubElements[i])); + if (Objects.size() > 0) + ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); + ui->lineDirection->setText(dir.isEmpty() ? tr("") : dir); + ui->checkReverse->setChecked(reversed); + ui->lineDirection->setText(loc.isEmpty() ? tr("") : loc); + ui->spinDistance->setMinimum(INT_MIN); + ui->spinDistance->setMaximum(INT_MAX); + ui->spinDistance->setValue(d); + ui->spinDiameter->setMinimum(0); + ui->spinDiameter->setMaximum(INT_MAX); + ui->spinDiameter->setValue(dia); + ui->spinOtherDia->setMinimum(0); + ui->spinOtherDia->setMaximum(INT_MAX); + ui->spinOtherDia->setValue(otherdia); + ui->spinCenterDistance->setMinimum(0); + ui->spinCenterDistance->setMaximum(INT_MAX); + ui->spinCenterDistance->setValue(centerdist); + + // activate and de-activate dialog elements as appropriate + ui->comboType->blockSignals(false); + ui->spinForce->blockSignals(false); + ui->listReferences->blockSignals(false); + ui->buttonReference->blockSignals(false); + ui->buttonDirection->blockSignals(false); + ui->checkReverse->blockSignals(false); + ui->buttonLocation->blockSignals(false); + ui->spinDistance->blockSignals(false); + ui->spinDiameter->blockSignals(false); + ui->spinOtherDia->blockSignals(false); + ui->spinCenterDistance->blockSignals(false); + + selectionMode = selref; + updateUI(); +} + +void TaskFemConstraint::updateUI() +{ + if (ui->comboType->currentIndex() == 0) { + ui->labelForce->setVisible(true); + ui->spinForce->setVisible(true); + ui->buttonDirection->setVisible(true); + ui->lineDirection->setVisible(true); + ui->checkReverse->setVisible(true); + ui->buttonLocation->setVisible(false); + ui->lineLocation->setVisible(false); + ui->labelDistance->setVisible(false); + ui->spinDistance->setVisible(false); + ui->labelDiameter->setVisible(false); + ui->spinDiameter->setVisible(false); + ui->labelOtherDia->setVisible(false); + ui->spinOtherDia->setVisible(false); + ui->labelCenterDistance->setVisible(false); + ui->spinCenterDistance->setVisible(false); + } else if (ui->comboType->currentIndex() == 1) { + ui->labelForce->setVisible(false); + ui->spinForce->setVisible(false); + ui->buttonDirection->setVisible(false); + ui->lineDirection->setVisible(false); + ui->checkReverse->setVisible(false); + ui->buttonLocation->setVisible(false); + ui->lineLocation->setVisible(false); + ui->labelDistance->setVisible(false); + ui->spinDistance->setVisible(false); + ui->labelDiameter->setVisible(false); + ui->spinDiameter->setVisible(false); + ui->labelOtherDia->setVisible(false); + ui->spinOtherDia->setVisible(false); + ui->labelCenterDistance->setVisible(false); + ui->spinCenterDistance->setVisible(false); + } else if ((ui->comboType->currentIndex() == 2) || (ui->comboType->currentIndex() == 3)) { + ui->labelForce->setVisible(false); + ui->spinForce->setVisible(false); + ui->buttonDirection->setVisible(false); + ui->lineDirection->setVisible(false); + ui->checkReverse->setVisible(false); + ui->buttonLocation->setVisible(true); + ui->lineLocation->setVisible(true); + ui->labelDistance->setVisible(true); + ui->spinDistance->setVisible(true); + ui->labelDiameter->setVisible(false); + ui->spinDiameter->setVisible(false); + ui->labelOtherDia->setVisible(false); + ui->spinOtherDia->setVisible(false); + ui->labelCenterDistance->setVisible(false); + ui->spinCenterDistance->setVisible(false); + } else if (ui->comboType->currentIndex() == 4) { + ui->labelForce->setVisible(false); + ui->spinForce->setVisible(false); + ui->buttonDirection->setVisible(false); + ui->lineDirection->setVisible(false); + ui->checkReverse->setVisible(false); + ui->buttonLocation->setVisible(true); + ui->lineLocation->setVisible(true); + ui->labelDistance->setVisible(true); + ui->spinDistance->setVisible(true); + ui->labelDiameter->setVisible(true); + ui->spinDiameter->setVisible(true); + ui->labelOtherDia->setVisible(true); + ui->spinOtherDia->setVisible(true); + ui->labelCenterDistance->setVisible(true); + ui->spinCenterDistance->setVisible(true); + } else if (ui->comboType->currentIndex() == 5) { + ui->labelForce->setVisible(false); + ui->spinForce->setVisible(false); + ui->buttonDirection->setVisible(false); + ui->lineDirection->setVisible(false); + ui->checkReverse->setVisible(false); + ui->buttonLocation->setVisible(true); + ui->lineLocation->setVisible(true); + ui->labelDistance->setVisible(true); + ui->spinDistance->setVisible(true); + ui->labelDiameter->setVisible(true); + ui->spinDiameter->setVisible(true); + ui->labelOtherDia->setVisible(true); + ui->spinOtherDia->setVisible(true); + ui->labelCenterDistance->setVisible(false); + ui->spinCenterDistance->setVisible(false); + } + + if (ui->listReferences->model()->rowCount() == 0) { + // Go into reference selection mode if no reference has been selected yet + onButtonReference(true); + return; + } + + if (ui->comboType->currentIndex() == 0) { + std::string ref = ui->listReferences->item(0)->text().toStdString(); + int pos = ref.find_last_of(":"); + if (ref.substr(pos+1, 6) == "Vertex") + ui->labelForce->setText(tr("Force [N]")); + else if (ref.substr(pos+1, 4) == "Edge") + ui->labelForce->setText(tr("Force [N/mm]")); + else if (ref.substr(pos+1, 4) == "Face") + ui->labelForce->setText(tr("Force [N/mm²]")); + } +} + +void TaskFemConstraint::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + // Don't allow selection in other document + if (strcmp(msg.pDocName, ConstraintView->getObject()->getDocument()->getName()) != 0) + return; + + if (!msg.pSubName || msg.pSubName[0] == '\0') + return; + std::string subName(msg.pSubName); + + if (selectionMode == selnone) + return; + + std::vector references(1,subName); + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(msg.pObjectName); + //if (!obj->getClassTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + // return; + Part::Feature* feat = static_cast(obj); + TopoDS_Shape ref = feat->Shape.getShape().getSubShape(subName.c_str()); + + if (selectionMode == selref) { + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + if (pcConstraint->Type.getValue() == 0) { + // Force on geometry elements: + // Ensure we don't have mixed reference types + if (SubElements.size() > 0) { + if (subName.substr(0,4) != SubElements.front().substr(0,4)) { + QMessageBox::warning(this, tr("Selection error"), tr("Mixed shape types are not possible. Use a second constraint instead")); + return; + } + } else { + if ((subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge") && (subName.substr(0,6) != "Vertex")) { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces, edges and vertices can be picked")); + return; + } + } + + // Avoid duplicates + int pos = 0; + for (; pos < Objects.size(); pos++) + if (obj == Objects[pos]) + break; + + if (pos != Objects.size()) + if (subName == SubElements[pos]) + return; + } else if (pcConstraint->Type.getValue() == 1) { + // Fixed + if ((subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge") && (subName.substr(0,6) != "Vertex")) { + QMessageBox::warning(this, tr("Selection error"), tr("Mixed shape types are not possible. Use a second constraint instead")); + return; + } + + // Avoid duplicates + int pos = 0; + for (; pos < Objects.size(); pos++) + if (obj == Objects[pos]) + break; + + if (pos != Objects.size()) + if (subName == SubElements[pos]) + return; + } else if ((pcConstraint->Type.getValue() >= 2) && (pcConstraint->Type.getValue() <= 5)) { + // Bearing, pulley, gear + if (Objects.size() > 0) { + QMessageBox::warning(this, tr("Selection error"), tr("Please use only a single reference for bearing constraint")); + return; + } + // Only cylindrical faces allowed + if (subName.substr(0,4) != "Face") { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces can be picked")); + return; + } + + BRepAdaptor_Surface surface(TopoDS::Face(ref)); + if (surface.GetType() != GeomAbs_Cylinder) { + QMessageBox::warning(this, tr("Selection error"), tr("Only cylindrical faces can be picked")); + return; + } + } else { + return; + } + + // add the new reference + Objects.push_back(obj); + SubElements.push_back(subName); + pcConstraint->References.setValues(Objects,SubElements); + ui->listReferences->addItem(makeRefText(obj, subName)); + + // Turn off reference selection mode + onButtonReference(false); + } else if ((selectionMode == seldir) || (selectionMode == selloc)) { + if (subName.substr(0,4) == "Face") { + BRepAdaptor_Surface surface(TopoDS::Face(ref)); + if (surface.GetType() != GeomAbs_Plane) { + QMessageBox::warning(this, tr("Selection error"), tr("Only planar faces can be picked")); + return; + } + } else if (subName.substr(0,4) == "Edge") { + BRepAdaptor_Curve line(TopoDS::Edge(ref)); + if (line.GetType() != GeomAbs_Line) { + QMessageBox::warning(this, tr("Selection error"), tr("Only linear edges can be picked")); + return; + } + } else { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked")); + return; + } + if (selectionMode == seldir) { + pcConstraint->Direction.setValue(obj, references); + ui->lineDirection->setText(makeRefText(obj, subName)); + + // Turn off direction selection mode + onButtonDirection(false); + } else { + pcConstraint->Location.setValue(obj, references); + ui->lineLocation->setText(makeRefText(obj, subName)); + + // Turn off direction selection mode + onButtonLocation(false); + } + } + updateUI(); + } +} + +void TaskFemConstraint::onTypeChanged(int index) +{ + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + int oldType = pcConstraint->Type.getValue(); + pcConstraint->Type.setValue(index); + + if (((oldType == 2) && (index == 3)) || ((oldType == 3) && (index == 2))) { + pcConstraint->References.touch(); // Update visual + updateUI(); + } else { + // Clear all references if the old and new type mismatch + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + Objects.clear(); + SubElements.clear(); + pcConstraint->References.setValues(Objects, SubElements); + + ui->listReferences->clear(); //model()->removeRows(0, ui->listReferences->model()->rowCount()); + updateUI(); + } +} + +void TaskFemConstraint::onForceChanged(double f) +{ + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Force.setValue((float)f); +} + +void TaskFemConstraint::onDistanceChanged(double f) +{ + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Distance.setValue((float)f); +} + +void TaskFemConstraint::onDiameterChanged(double f) +{ + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Diameter.setValue((float)f); +} + +void TaskFemConstraint::onOtherDiameterChanged(double f) +{ + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->OtherDiameter.setValue((float)f); +} + +void TaskFemConstraint::onCenterDistanceChanged(double d) +{ + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->CenterDistance.setValue((float)d); +} + +void TaskFemConstraint::onButtonReference(const bool pressed) { + if (pressed) + selectionMode = selref; + else + selectionMode = selnone; + ui->buttonReference->setChecked(pressed); + Gui::Selection().clearSelection(); +} + +void TaskFemConstraint::onReferenceDeleted() { + int row = ui->listReferences->currentIndex().row(); + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + Objects.erase(Objects.begin() + row); + SubElements.erase(SubElements.begin() + row); + pcConstraint->References.setValues(Objects, SubElements); + + ui->listReferences->model()->removeRow(row); + ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); +} + +void TaskFemConstraint::onButtonDirection(const bool pressed) { + if (pressed) { + selectionMode = seldir; + } else { + selectionMode = selnone; + } + ui->buttonDirection->setChecked(pressed); + Gui::Selection().clearSelection(); +} + +void TaskFemConstraint::onButtonLocation(const bool pressed) { + if (pressed) { + selectionMode = selloc; + } else { + selectionMode = selnone; + } + ui->buttonLocation->setChecked(pressed); + Gui::Selection().clearSelection(); +} + +void TaskFemConstraint::onCheckReverse(const bool pressed) +{ + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Reversed.setValue(pressed); +} + +int TaskFemConstraint::getType(void) const +{ + return ui->comboType->currentIndex(); +} + +double TaskFemConstraint::getForce(void) const +{ + return ui->spinForce->value(); +} + +double TaskFemConstraint::getDistance(void) const +{ + return ui->spinDistance->value(); +} + +double TaskFemConstraint::getDiameter(void) const +{ + return ui->spinDiameter->value(); +} + +double TaskFemConstraint::getOtherDiameter(void) const +{ + return ui->spinOtherDia->value(); +} + +double TaskFemConstraint::getCenterDistance(void) const +{ + return ui->spinCenterDistance->value(); +} + +const std::string TaskFemConstraint::getReferences(void) const +{ + int rows = ui->listReferences->model()->rowCount(); + if (rows == 0) + return ""; + + std::string result; + for (int r = 0; r < rows; r++) { + std::string item = ui->listReferences->item(r)->text().toStdString(); + int pos = item.find_last_of(":"); + std::string objStr = "App.ActiveDocument." + item.substr(0, pos); + std::string refStr = "\"" + item.substr(pos+1) + "\""; + result = result + (r > 0 ? ", " : "") + "(" + objStr + "," + refStr + ")"; + } + + return result; +} + +const std::string TaskFemConstraint::getDirectionName(void) const +{ + std::string dir = ui->lineDirection->text().toStdString(); + if (dir.empty()) + return ""; + + int pos = dir.find_last_of(":"); + return dir.substr(0, pos).c_str(); +} + +const std::string TaskFemConstraint::getDirectionObject(void) const +{ + std::string dir = ui->lineDirection->text().toStdString(); + if (dir.empty()) + return ""; + + int pos = dir.find_last_of(":"); + return dir.substr(pos+1).c_str(); +} + +const std::string TaskFemConstraint::getLocationName(void) const +{ + std::string loc = ui->lineLocation->text().toStdString(); + if (loc.empty()) + return ""; + + int pos = loc.find_last_of(":"); + return loc.substr(0, pos).c_str(); +} + +const std::string TaskFemConstraint::getLocationObject(void) const +{ + std::string loc = ui->lineLocation->text().toStdString(); + if (loc.empty()) + return ""; + + int pos = loc.find_last_of(":"); + return loc.substr(pos+1).c_str(); +} + +bool TaskFemConstraint::getReverse() const +{ + return ui->checkReverse->isChecked(); +} + +TaskFemConstraint::~TaskFemConstraint() +{ + delete ui; +} + +void TaskFemConstraint::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->comboType->blockSignals(true); + ui->spinForce->blockSignals(true); + ui->spinDistance->blockSignals(true); + int index = ui->comboType->currentIndex(); + ui->comboType->clear(); + ui->comboType->insertItem(0, tr("Force on geometry")); + ui->comboType->insertItem(1, tr("Fixed")); + ui->comboType->insertItem(2, tr("Bearing (axial free)")); + ui->comboType->insertItem(3, tr("Bearing (axial fixed)")); + ui->comboType->insertItem(4, tr("Pulley")); + ui->comboType->insertItem(5, tr("Gear (straight toothed)")); + ui->comboType->setCurrentIndex(index); + ui->retranslateUi(proxy); + ui->comboType->blockSignals(false); + ui->spinForce->blockSignals(false); + ui->spinDistance->blockSignals(false); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraint::TaskDlgFemConstraint(ViewProviderFemConstraint *ConstraintView) + : TaskDialog(),ConstraintView(ConstraintView) +{ + assert(ConstraintView); + parameter = new TaskFemConstraint(ConstraintView); + + Content.push_back(parameter); +} + +TaskDlgFemConstraint::~TaskDlgFemConstraint() +{ + +} + +//==== calls from the TaskView =============================================================== + + +void TaskDlgFemConstraint::open() +{ + +} + +void TaskDlgFemConstraint::clicked(int) +{ + +} + +bool TaskDlgFemConstraint::accept() +{ + std::string name = ConstraintView->getObject()->getNameInDocument(); + + try { + //Gui::Command::openCommand("FEM constraint changed"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getType()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Force = %f",name.c_str(),parameter->getForce()); + std::string refs = parameter->getReferences(); + + if (!refs.empty()) { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.References = [%s]", name.c_str(), refs.c_str()); + } else { + QMessageBox::warning(parameter, tr("Input error"), tr("You must specify at least one reference")); + return false; + } + + std::string dirname = parameter->getDirectionName().data(); + std::string dirobj = parameter->getDirectionObject().data(); + + if (!dirname.empty()) { + QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); + buf = buf.arg(QString::fromStdString(dirname)); + buf = buf.arg(QString::fromStdString(dirobj)); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = %s", name.c_str(), buf.toStdString().c_str()); + } else { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str()); + } + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %s", name.c_str(), parameter->getReverse() ? "True" : "False"); + + std::string locname = parameter->getLocationName().data(); + std::string locobj = parameter->getLocationObject().data(); + + if (!locname.empty()) { + QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); + buf = buf.arg(QString::fromStdString(locname)); + buf = buf.arg(QString::fromStdString(locobj)); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Location = %s", name.c_str(), buf.toStdString().c_str()); + } else { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str()); + } + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Distance = %f",name.c_str(),parameter->getDistance()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Diameter = %f",name.c_str(),parameter->getDiameter()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.OtherDiameter = %f",name.c_str(),parameter->getOtherDiameter()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.CenterDistance = %f",name.c_str(),parameter->getCenterDistance()); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (!ConstraintView->getObject()->isValid()) + throw Base::Exception(ConstraintView->getObject()->getStatusString()); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromAscii(e.what())); + return false; + } + + return true; +} + +bool TaskDlgFemConstraint::reject() +{ + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + return true; +} + + + +#include "moc_TaskFemConstraint.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraint.h b/src/Mod/Fem/Gui/TaskFemConstraint.h new file mode 100644 index 0000000000..d27da19839 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraint.h @@ -0,0 +1,131 @@ +/*************************************************************************** + * 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 GUI_TASKVIEW_TaskFemConstraint_H +#define GUI_TASKVIEW_TaskFemConstraint_H + +#include +#include +#include + +#include "ViewProviderFemConstraint.h" + +class Ui_TaskFemConstraint; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace FemGui { + +class TaskFemConstraint : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +{ + Q_OBJECT + +public: + TaskFemConstraint(ViewProviderFemConstraint *ConstraintView,QWidget *parent = 0); + ~TaskFemConstraint(); + + int getType(void) const; + double getForce(void) const; + const std::string getReferences(void) const; + const std::string getDirectionName(void) const; + const std::string getDirectionObject(void) const; + const std::string getLocationName(void) const; + const std::string getLocationObject(void) const; + double getDistance(void) const; + bool getReverse(void) const; + double getDiameter(void) const; + double getOtherDiameter(void) const; + double getCenterDistance(void) const; + +private Q_SLOTS: + void onTypeChanged(int); + void onReferenceDeleted(); + void onForceChanged(double); + void onButtonReference(const bool pressed = true); + void onButtonDirection(const bool pressed = true); + void onButtonLocation(const bool pressed = true); + void onDistanceChanged(double); + void onCheckReverse(bool); + void onDiameterChanged(double); + void onOtherDiameterChanged(double); + void onCenterDistanceChanged(double); + +protected: + void changeEvent(QEvent *e); + +private: + void onSelectionChanged(const Gui::SelectionChanges& msg); + void updateUI(); + +private: + QWidget* proxy; + Ui_TaskFemConstraint* ui; + ViewProviderFemConstraint *ConstraintView; + enum {seldir, selref, selloc, selnone} selectionMode; +}; + +/// simulation dialog for the TaskView +class TaskDlgFemConstraint : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgFemConstraint(ViewProviderFemConstraint *ConstraintView); + ~TaskDlgFemConstraint(); + + ViewProviderFemConstraint* getConstraintView() const + { return ConstraintView; } + + +public: + /// is called the TaskView when the dialog is opened + virtual void open(); + /// is called by the framework if an button is clicked which has no accept or reject role + virtual void clicked(int); + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + /// is called by the framework if the user presses the help button + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +protected: + ViewProviderFemConstraint *ConstraintView; + + TaskFemConstraint *parameter; +}; + +} //namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraint_H diff --git a/src/Mod/Fem/Gui/TaskFemConstraint.ui b/src/Mod/Fem/Gui/TaskFemConstraint.ui new file mode 100644 index 0000000000..2ca053720b --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraint.ui @@ -0,0 +1,208 @@ + + + TaskFemConstraint + + + + 0 + 0 + 257 + 461 + + + + Form + + + + + + + + + Add reference + + + + + + + + + + + + Load [N] + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 500.000000000000000 + + + + + + + + + + + Diameter + + + + + + + 3 + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 100.000000000000000 + + + + + + + + + + + Other diameter + + + + + + + 3 + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 200.000000000000000 + + + + + + + + + + + Center distance + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 500.000000000000000 + + + + + + + + + + + Direction + + + + + + + + + + + + Reverse direction + + + + + + + + + Location + + + + + + + + + + + + + + Distance + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 10.000000000000000 + + + + + + + + + Qt::Vertical + + + + 17 + 56 + + + + + + + + + diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp new file mode 100644 index 0000000000..2a58cc4bc2 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp @@ -0,0 +1,819 @@ +/*************************************************************************** + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "ViewProviderFemConstraint.h" +#include "TaskFemConstraint.h" +#include "Gui/SoFCSelection.h" +#include "Gui/Application.h" +#include "Gui/Control.h" +#include "Gui/Command.h" +#include "Gui/Document.h" +#include "Gui/View3DInventorViewer.h" +#include "App/Document.h" + + +#include +#include +#include +#include +#include + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraint, Gui::ViewProviderDocumentObject) + + +ViewProviderFemConstraint::ViewProviderFemConstraint() +{ + ADD_PROPERTY(TextColor,(0.0f,0.0f,0.0f)); + ADD_PROPERTY(FaceColor,(1.0f,0.0f,0.2f)); + ADD_PROPERTY(FontSize,(18)); + ADD_PROPERTY(DistFactor,(1.0)); + ADD_PROPERTY(Mirror,(false)); + + pFont = new SoFontStyle(); + pFont->ref(); + pLabel = new SoText2(); + pLabel->ref(); + pColor = new SoBaseColor(); + pColor->ref(); + pTextColor = new SoBaseColor(); + pTextColor->ref(); + pTranslation = new SoTranslation(); + pTranslation->ref(); + + TextColor.touch(); + FontSize.touch(); + FaceColor.touch(); + + pCoords = new SoCoordinate3(); + pCoords->ref(); + pCoords->point.setNum(0); + + pFaces = new SoIndexedFaceSet(); + pFaces->ref(); + pFaces->coordIndex.setNum(0); + + sPixmap = "view-femconstraint"; + + normalDirection = new SbVec3f(0, 0, 1); + arrowDirection = NULL; +} + +ViewProviderFemConstraint::~ViewProviderFemConstraint() +{ + pFont->unref(); + pLabel->unref(); + pColor->unref(); + pTextColor->unref(); + pTranslation->unref(); + pCoords->unref(); + pFaces->unref(); + delete arrowDirection; + delete normalDirection; +} + +std::vector ViewProviderFemConstraint::claimChildren(void)const +{ + return std::vector(); +} + +void ViewProviderFemConstraint::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr("Edit constraint"), receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + ViewProviderDocumentObject::setupContextMenu(menu, receiver, member); +} + +void ViewProviderFemConstraint::onChanged(const App::Property* prop) +{ + if (this->getObject() != NULL) + Base::Console().Error("%s: onChanged: %s\n", this->getObject()->getNameInDocument(), prop->getName()); + else + Base::Console().Error("Anonymous: onChanged: %s\n", prop->getName()); + + if (prop == &Mirror || prop == &DistFactor) { + updateData(prop); + } + else if (prop == &TextColor) { + const App::Color& c = TextColor.getValue(); + pTextColor->rgb.setValue(c.r,c.g,c.b); + } + else if (prop == &FaceColor) { + const App::Color& c = FaceColor.getValue(); + pColor->rgb.setValue(c.r,c.g,c.b); + } + else if (prop == &FontSize) { + pFont->size = FontSize.getValue(); + } + else { + ViewProviderDocumentObject::onChanged(prop); + } +} + +bool ViewProviderFemConstraint::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(); + TaskDlgFemConstraint *constrDlg = qobject_cast(dlg); + if (constrDlg && constrDlg->getConstraintView() != this) + constrDlg = 0; // another constraint left open its task panel + if (dlg && !constrDlg) { + 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().closeDialog(); + else + return false; + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (constrDlg) + Gui::Control().showDialog(constrDlg); + else + Gui::Control().showDialog(new TaskDlgFemConstraint(this)); + + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); + } +} + +void ViewProviderFemConstraint::unsetEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default) { + // when pressing ESC make sure to close the dialog + Gui::Control().closeDialog(); + } + else { + ViewProviderDocumentObject::unsetEdit(ModNum); + } +} + +std::vector ViewProviderFemConstraint::getDisplayModes(void) const +{ + // add modes + std::vector StrList; + StrList.push_back("Base"); + return StrList; +} + +void ViewProviderFemConstraint::setDisplayMode(const char* ModeName) +{ + if (strcmp(ModeName, "Base") == 0) + setDisplayMaskMode("Base"); + ViewProviderDocumentObject::setDisplayMode(ModeName); +} + +void ViewProviderFemConstraint::attach(App::DocumentObject* pcObject) +{ + ViewProviderDocumentObject::attach(pcObject); + + SoPickStyle* ps = new SoPickStyle(); + ps->style = SoPickStyle::UNPICKABLE; + + SoSeparator *faceSep = new SoSeparator(); + faceSep->addChild(ps); + faceSep->addChild(pColor); + faceSep->addChild(pCoords); + faceSep->addChild(pFaces); + + SoSeparator* sep = new SoSeparator(); + sep->addChild(faceSep); + addDisplayMaskMode(sep, "Base"); +} + +// Create a local coordinate system with the z-axis given in dir +void getLocalCoordinateSystem(const SbVec3f& z, SbVec3f& y, SbVec3f& x) +{ + // Find the y axis in an arbitrary direction, normal to z + // Conditions: + // y1 * z1 + y2 * z2 + y3 * z3 = |y| |z| cos(90°) = 0 + // |y| = sqrt(y1^2 + y2^2 + y3^2) = 1 + float z1, z2, z3; + z.getValue(z1, z2, z3); + float y1, y2, y3; + if (fabs(z1) > Precision::Confusion()) { + // Choose: y3 = 0 + // Solution: + // y1 * z1 + y2 * z2 = 0 + // y1 = - z2/z1 y2 + // sqrt(z2^2/z1^2 y2^2 + y2^2) = 1 + // y2^2 ( 1 + z2^2/z1^2)) = +-1 -> choose +1 otherwise no solution + // y2 = +- sqrt(1 / (1 + z2^2/z1^2)) + y3 = 0; + y2 = sqrt(1 / (1 + z2*z2 / (z1*z1))); + y1 = -z2/z1 * y2; + // Note: result might be (0, 1, 0) + } else if (fabs(z2) > Precision::Confusion()) { + // Given: z1 = 0 + // Choose: y1 = 0 + // Solution: + // y2 * z2 + y3 * z3 = 0 + // y2 = - z3/z2 y3 + // sqrt(z3^2/z2^2 y3^3 + y3^2) = 1 + // y3^2 (1 + z3^2/z2^2)) = +1 + // y3 = +- sqrt(1 / (1 + z3^2/z2^2)) + y1 = 0; + y3 = sqrt(1 / (1 + z3*z3 / (z2*z2))); + y2 = -z3/z2 * y3; + // Note: result might be (0, 0, 1) + } else if (fabs(z3) > Precision::Confusion()) { + // Given: z1 = z2 = 0 + // Choose the remaining possible axis + y1 = 1; + y2 = 0; + y3 = 0; + } + + y = SbVec3f(y1, y2, y3); + x = y.cross(z); +} + +#define FACETS 12 +#define CONEPOINTS (FACETS + 1) +#define CONEFACETPOINTS (FACETS * 4 + FACETS + 1) + +void createCone(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir, + const double height, const double radius, const bool update = false) +{ + SbVec3f x, y; + getLocalCoordinateSystem(dir, y, x); + + point.set1Value(ipoints, base); // tip + + SbVec3f midpoint(base + dir * height); // centre of the circle + for (int i = 0; i < FACETS; i++) { + float angle = 2 * M_PI / FACETS * i; + point.set1Value(ipoints + i + 1, midpoint + cos(angle) * x * radius + sin(angle) * y * radius); + } + + if (update) + return; + + int32_t faces[CONEFACETPOINTS]; + int start_index = 1; + for (int f = 0; f < FACETS; f++) { + faces[f * 4] = ipoints; // tip of arrow + int idx = start_index; + faces[f * 4 + 1] = ipoints + idx; + idx++; + if (idx > FACETS) idx = 1; // Happens in the last iteration + faces[f * 4 + 2] = ipoints + idx; + faces[f * 4 + 3] = -1; + start_index++; + } + for (int f = 0; f < FACETS; f++) + faces[FACETS * 4 + f] = ipoints + f + 1; + faces[CONEFACETPOINTS - 1] = -1; + refs.setValues(ifaces, CONEFACETPOINTS, faces); +} + +#define CYLPOINTS (FACETS * 2) +#define CYLFACETPOINTS (FACETS * 5 + 2 * FACETS + 2) + +void createCylinder(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir, + const double height, const double radius, const bool update = false) +{ + SbVec3f x, y; + getLocalCoordinateSystem(dir, y, x); + + for (int i = 0; i < CYLPOINTS; i+=2) { + float angle = 2 * M_PI / FACETS * i/2; + point.set1Value(ipoints + i, base + cos(angle) * x * radius + sin(angle) * y * radius); + point.set1Value(ipoints + i + 1, base + dir * height + cos(angle) * x * radius + sin(angle) * y * radius); + } + + if (update) + return; + + int32_t faces[CYLFACETPOINTS]; + int start_index = 0; + for (int f = 0; f < FACETS; f++) { + int idx = start_index; + faces[f * 5] = ipoints + idx; + idx++; + faces[f * 5 + 1] = ipoints + idx; + idx++; + if (idx >= CYLPOINTS) idx = 0; // Happens in the last iteration + faces[f * 5 + 3] = ipoints + idx; + idx++; + faces[f * 5 + 2] = ipoints + idx; + faces[f * 5 + 4] = -1; + start_index += 2; + } + for (int f = 0; f < FACETS; f++) { + faces[FACETS * 5 + f] = ipoints + 2 * f; + faces[FACETS * 5 + FACETS + f + 1] = ipoints + 1 + 2 * f; + } + faces[FACETS * 5 + FACETS] = -1; + faces[CYLFACETPOINTS - 1] = -1; + refs.setValues(ifaces, CYLFACETPOINTS, faces); +} + +#define ARROWPOINTS (CONEPOINTS + CYLPOINTS) +#define ARROWFACETPOINTS (CONEFACETPOINTS + CYLFACETPOINTS) + +void createArrow(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir, + const double length, const double radius, const bool update = false) +{ + createCone(point, refs, ipoints, ifaces, base, dir, radius, radius, update); + createCylinder(point, refs, ipoints + CONEPOINTS, ifaces + CONEFACETPOINTS, base + dir * radius, dir, length-radius, radius/3, update); +} + +#define BOXPOINTS 8 +#define BOXFACEPOINTS 30 + +void createBox(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir, + const double width, const double length, const double height, const bool update = false) +{ + SbVec3f x, y; + getLocalCoordinateSystem(dir, y, x); + + point.set1Value(ipoints, base + width/2 * y + length/2 * x); + point.set1Value(ipoints+1, base + width/2 * y - length/2 * x); + point.set1Value(ipoints+2, base - width/2 * y - length/2 * x); + point.set1Value(ipoints+3, base - width/2 * y + length/2 * x); + point.set1Value(ipoints+4, base + dir * height + width/2 * y + length/2 * x); + point.set1Value(ipoints+5, base + dir * height + width/2 * y - length/2 * x); + point.set1Value(ipoints+6, base + dir * height - width/2 * y - length/2 * x); + point.set1Value(ipoints+7, base + dir * height - width/2 * y + length/2 * x); + + if (update) + return; + + int32_t faces[BOXFACEPOINTS] = { + ipoints, ipoints+1, ipoints+2, ipoints+3, -1, + ipoints, ipoints+1, ipoints+5, ipoints+4, -1, + ipoints+1, ipoints+2, ipoints+6, ipoints+5, -1, + ipoints+2, ipoints+3, ipoints+7, ipoints+6, -1, + ipoints+3, ipoints, ipoints+4, ipoints+7, -1, + ipoints+4, ipoints+5, ipoints+6, ipoints+7, -1}; + refs.setValues(ifaces, BOXFACEPOINTS, faces); +} + +void ViewProviderFemConstraint::findCylinderData(SbVec3f& z, SbVec3f& y, SbVec3f& x, SbVec3f& p, double& radius, double& height) { + Fem::Constraint* pcConstraint = static_cast(this->getObject()); + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + if (Objects.empty()) + return; + App::DocumentObject* obj = Objects[0]; + Part::Feature* feat = static_cast(obj); + TopoDS_Shape sh = feat->Shape.getShape().getSubShape(SubElements[0].c_str()); + + TopoDS_Face face = TopoDS::Face(sh); + BRepAdaptor_Surface surface(face); + gp_Cylinder cyl = surface.Cylinder(); + gp_Pnt start = surface.Value(surface.FirstUParameter(), surface.FirstVParameter()); + gp_Pnt end = surface.Value(surface.FirstUParameter(), surface.LastVParameter()); + height = start.Distance(end); + radius = cyl.Radius(); + gp_Dir dirz = cyl.Axis().Direction(); + z = SbVec3f(dirz.X(), dirz.Y(), dirz.Z()); + gp_Dir diry = cyl.YAxis().Direction(); + y = SbVec3f(diry.X(), diry.Y(), diry.Z()); + gp_Dir dirx = cyl.XAxis().Direction(); + x = SbVec3f(dirx.X(), dirx.Y(), dirx.Z()); + + if (pcConstraint->Location.getValue() == NULL) { + // Get a point in the middle of the cylindrical face. + gp_Pnt centre = cyl.Location(); + SbVec3f base(centre.X(), centre.Y(), centre.Z()); + p = base + z * height/2; + } else { + // Get the point specified by Location and Distance + App::DocumentObject* objLoc = pcConstraint->Location.getValue(); + std::string subName = pcConstraint->Location.getSubValues().front(); + Part::Feature* featLoc = static_cast(objLoc); + TopoDS_Shape shloc = featLoc->Shape.getShape().getSubShape(subName.c_str()); + // Get a plane from the Location reference + gp_Pln plane; + if (shloc.ShapeType() == TopAbs_FACE) { + BRepAdaptor_Surface surface(TopoDS::Face(shloc)); + plane = surface.Plane(); + } else { + BRepAdaptor_Curve curve(TopoDS::Edge(shloc)); + gp_Lin line = curve.Line(); + gp_Dir tang = line.Direction().Crossed(dirz); + gp_Dir norm = line.Direction().Crossed(tang); + plane = gp_Pln(line.Location(), norm); + } + // Translate the plane in direction of the cylinder (for positive values of Distance) + Handle_Geom_Plane pln = new Geom_Plane(plane); + GeomAPI_ProjectPointOnSurf proj(cyl.Location(), pln); + if (!proj.IsDone()) + return; + gp_Pnt projPnt = proj.NearestPoint(); + plane.Translate(gp_Vec(projPnt, cyl.Location()).Normalized().Multiplied(pcConstraint->Distance.getValue())); + Handle_Geom_Plane plnt = new Geom_Plane(plane); + // Intersect translated plane with cylinder axis + Handle_Geom_Curve crv = new Geom_Line(cyl.Axis()); + GeomAPI_IntCS intersector(crv, plnt); + if (!intersector.IsDone()) + return; + gp_Pnt inter = intersector.Point(1); + p.setValue(inter.X(), inter.Y(), inter.Z()); + } +} + +void ViewProviderFemConstraint::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + if (this->getObject() != NULL) + Base::Console().Error("%s: updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); + else + Base::Console().Error("Anonymous: updateData: %s\n", prop->getName()); + Fem::Constraint* pcConstraint = static_cast(this->getObject()); + + if (strcmp(prop->getName(),"References") == 0) { + const App::PropertyLinkSubList* pr = static_cast(prop); + std::vector Objects = pr->getValues(); + std::vector SubElements = pr->getSubValues(); + + // Remove all arrows + pCoords->point.deleteValues(0, pCoords->point.getNum()); + pFaces->coordIndex.deleteValues(0, pFaces->coordIndex.getNum()); + if (Objects.empty()) { + Base::Console().Error(" updateData: No references\n"); + Objects = pcConstraint->References.getValues(); + SubElements = pcConstraint->References.getSubValues(); + if (Objects.empty()) + return; + } + + Base::Console().Error(" updateData: Found %u references\n", Objects.size()); + + // Re-create all arrows + int type = pcConstraint->Type.getValue(); + + if ((type == 0) || (type == 1)) { + // Force on geometry + std::vector points; + TopoDS_Shape sh; + + for (int i = 0; i < Objects.size(); i++) { + App::DocumentObject* obj = Objects[i]; + Part::Feature* feat = static_cast(obj); + const Part::TopoShape& toposhape = feat->Shape.getShape(); + if (toposhape.isNull()) { + Base::Console().Error(" updateData: Empty toposhape\n"); + return; + } + sh = toposhape.getSubShape(SubElements[i].c_str()); + + if (sh.ShapeType() == TopAbs_VERTEX) { + const TopoDS_Vertex& vertex = TopoDS::Vertex(sh); + gp_Pnt p = BRep_Tool::Pnt(vertex); + points.push_back(p); + } else if (sh.ShapeType() == TopAbs_EDGE) { + BRepAdaptor_Curve curve(TopoDS::Edge(sh)); + double fp = curve.FirstParameter(); + double lp = curve.LastParameter(); + GProp_GProps props; + BRepGProp::LinearProperties(sh, props); + double l = props.Mass(); + int steps = round(l / 3); // TODO: Make number of steps depend on actual screen size of element! + double step = (lp - fp) / steps; + if (steps < 1) { + points.push_back(curve.Value(fp)); + points.push_back(curve.Value(lp)); + } else { + for (int i = 0; i < steps + 1; i++) + points.push_back(curve.Value(i * step)); + } + } else if (sh.ShapeType() == TopAbs_FACE) { + TopoDS_Face face = TopoDS::Face(sh); + BRepAdaptor_Surface surface(face); + double ufp = surface.FirstUParameter(); + double ulp = surface.LastUParameter(); + double vfp = surface.FirstVParameter(); + double vlp = surface.LastVParameter(); + double ustep = (ulp - ufp) / 6.0; + double vstep = (vlp - vfp) / 6.0; + // TODO: How to find the distance between ufp and ulp to get the number of steps? + for (int i = 0; i < 7; i++) { + for (int j = 0; j < 7; j++) { + gp_Pnt p = surface.Value(ufp + i * ustep, vfp + j * vstep); + BRepClass_FaceClassifier classifier(face, p, Precision::Confusion()); + if (classifier.State() != TopAbs_OUT) + points.push_back(p); + } + } + } + } + + // Get default direction (on first call to method) + if (arrowDirection == NULL) { + if (sh.ShapeType() == TopAbs_FACE) { + // Get face normal in center point + TopoDS_Face face = TopoDS::Face(sh); + BRepGProp_Face prop(face); + gp_Vec normal; + gp_Pnt center; + double u1,u2,v1,v2; + prop.Bounds(u1,u2,v1,v2); + prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal); + normal.Normalize(); + normalDirection->setValue(normal.X(), normal.Y(), normal.Z()); + } // else use z axis + + arrowDirection = new SbVec3f(*normalDirection); + } + + if (type == 0) { + // Force on geometry + pCoords->point.setNum(ARROWPOINTS * points.size()); + pFaces->coordIndex.setNum(ARROWFACETPOINTS * points.size()); + int index = 0; + + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + SbVec3f v(p->X(), p->Y(), p->Z()); + if (*arrowDirection != *normalDirection) // Turn arrow around + v = v + *normalDirection * 5.0; + createArrow(pCoords->point, pFaces->coordIndex, + index * ARROWPOINTS, index * ARROWFACETPOINTS, + v, *arrowDirection, 5.0, 1.0); + index++; + } + } else if (type == 1) { + // Fixed + pCoords->point.setNum((CONEPOINTS + BOXPOINTS) * points.size()); + pFaces->coordIndex.setNum((CONEFACETPOINTS + BOXFACEPOINTS) * points.size()); + int index = 0; + + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + SbVec3f v(p->X(), p->Y(), p->Z()); + createCone(pCoords->point, pFaces->coordIndex, + index * (CONEPOINTS + BOXPOINTS), index * (CONEFACETPOINTS + BOXFACEPOINTS), + v, *normalDirection, 2.0, 1.0); + createBox(pCoords->point, pFaces->coordIndex, + index * (CONEPOINTS + BOXPOINTS) + CONEPOINTS, index * (CONEFACETPOINTS + BOXFACEPOINTS) + CONEFACETPOINTS, + v + *normalDirection * 2.0, *normalDirection, 2.0, 2.0, 0.5); + index++; + } + } + } else if ((type == 2) || (type == 3)) { + // Bearing. Note that only one face is allowed for this constraint + SbVec3f z, y, x, p; + double radius, height; + findCylinderData(z, y, x, p, radius, height); + p = p + y * radius; + + pCoords->point.setNum(CONEPOINTS + BOXPOINTS); + pFaces->coordIndex.setNum(CONEFACETPOINTS + BOXFACEPOINTS); + if (type == 2) + // axial free + createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2.5, radius/4); + else + // axial fixed + createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2, radius/4); + + createBox(pCoords->point, pFaces->coordIndex, CONEPOINTS, CONEFACETPOINTS, p + y * radius/2, y, radius, radius, radius/10); + } else if ((type == 4) || (type == 5)) { + // Pulley, Gear + SbVec3f z, y, x, p; + double radius, height; + findCylinderData(z, y, x, p, radius, height); + + double dia = pcConstraint->Diameter.getValue(); + if (dia < Precision::Confusion()) + dia = radius * 4; + double otherdia = pcConstraint->OtherDiameter.getValue(); + if (otherdia < Precision::Confusion()) + otherdia = radius * 2; + double centerdist = pcConstraint->CenterDistance.getValue(); + if (fabs(centerdist) < Precision::Confusion()) + centerdist = 500; + + if (type == 4) { + // Pulley + pCoords->point.setNum(CYLPOINTS + 2 * ARROWPOINTS); + pFaces->coordIndex.setNum(CYLFACETPOINTS + 2 * ARROWFACETPOINTS); + createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia); + + double angle = asin((dia - otherdia)/2/centerdist); + SbVec3f p1 = p + y * dia * cos(angle) + x * dia * sin(angle); + SbVec3f dir1 = x - y * sin(angle); + dir1.normalize(); + p1 = p1 + dir1 * 2 * radius; + dir1.negate(); + SbVec3f p2 = p - y * dia * cos(angle) + x * dia * sin(angle); + SbVec3f dir2 = x + y * sin(angle); + dir2.normalize(); + p2 = p2 + dir2 * 2 * radius; + dir2.negate(); + createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, dir1, 2 * radius, radius/5); + createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS+ARROWPOINTS, CYLFACETPOINTS+ARROWFACETPOINTS, p2, dir2, 2 * radius, radius/5); + } else if (type == 5) { + // Gear + pCoords->point.setNum(CYLPOINTS + ARROWPOINTS); + pFaces->coordIndex.setNum(CYLFACETPOINTS + ARROWFACETPOINTS); + createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia); + SbVec3f p1 = p + y * dia; + createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, x, radius, radius/5); + } + } + } else if (strcmp(prop->getName(),"Direction") == 0) { + if (arrowDirection == NULL) + return; + const App::PropertyLinkSub* pr = static_cast(prop); + App::DocumentObject* obj = pr->getValue(); + std::vector names = pr->getSubValues(); + if (names.size() == 0) + return; + std::string subName = names.front(); + Part::Feature* feat = static_cast(obj); + TopoDS_Shape sh = feat->Shape.getShape().getSubShape(subName.c_str()); + + if (sh.ShapeType() == TopAbs_FACE) { + BRepAdaptor_Surface surface(TopoDS::Face(sh)); + if (surface.GetType() == GeomAbs_Plane) { + gp_Dir dir = surface.Plane().Axis().Direction(); + arrowDirection->setValue(dir.X(), dir.Y(), dir.Z()); + } else { + return; // Not a planar face + } + } else if (sh.ShapeType() == TopAbs_EDGE) { + BRepAdaptor_Curve line(TopoDS::Edge(sh)); + if (line.GetType() == GeomAbs_Line) { + gp_Dir dir = line.Line().Direction(); + arrowDirection->setValue(dir.X(), dir.Y(), dir.Z()); + } else { + return; // Not a linear edge + } + } + + // TODO: Check whether direction points inside or outside of solid? But for which reference? + + arrowDirection->normalize(); + + *normalDirection = *arrowDirection; + bool reversed = pcConstraint->Reversed.getValue(); + if (reversed) + arrowDirection->negate(); + + // Re-orient all arrows + int numArrows = pCoords->point.getNum()/ARROWPOINTS; + + for (int i = 0; i < numArrows; i++) { + // Note: for update=true the pFaces->coordIndex is not touched + SbVec3f p = pCoords->point[i * ARROWPOINTS]; + if (reversed) + p = p + *normalDirection * 5.0; + createArrow(pCoords->point, pFaces->coordIndex, + i * ARROWPOINTS, 0, + p, *arrowDirection, 5.0, 1.0, true); + } + } else if (strcmp(prop->getName(),"Reversed") == 0) { + if (arrowDirection == NULL) + return; + bool reversed = static_cast(prop)->getValue(); + bool isReversed = (*arrowDirection != *normalDirection); + if (reversed == isReversed) + return; + + *arrowDirection = *normalDirection; + if (reversed) + arrowDirection->negate(); + + // Reverse all arrows + int numArrows = pCoords->point.getNum()/ARROWPOINTS; + + for (int i = 0; i < numArrows; i++) { + createArrow(pCoords->point, pFaces->coordIndex, + i * ARROWPOINTS, 0, + pCoords->point[i * ARROWPOINTS], *arrowDirection, 5.0, 1.0, true); + } + } else if ((strcmp(prop->getName(),"Location") == 0) || (strcmp(prop->getName(),"Distance") == 0)) { + // Move bearing constraint + SbVec3f z, y, x, p; + double radius, height; + findCylinderData(z, y, x, p, radius, height); + + int type = pcConstraint->Type.getValue(); + if (type == 2) { + // axial free + createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2.5, radius/4, true); + createBox(pCoords->point, pFaces->coordIndex, CONEPOINTS, CONEFACETPOINTS, p + y * radius/2, y, radius, radius, radius/10, true); + } else if (type == 3) { + // axial fixed + createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2, radius/4, true); + createBox(pCoords->point, pFaces->coordIndex, CONEPOINTS, CONEFACETPOINTS, p + y * radius/2, y, radius, radius, radius/10, true); + } else if ((type == 4) || (type == 5)) { + createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, pcConstraint->Diameter.getValue(), true); + } + } else if ((strcmp(prop->getName(),"Diameter") == 0) || (strcmp(prop->getName(),"OtherDiameter") == 0) || + (strcmp(prop->getName(),"CenterDistance") == 0)) { + // Update pulley/gear constraint + SbVec3f z, y, x, p; + double radius, height; + findCylinderData(z, y, x, p, radius, height); + + double dia = pcConstraint->Diameter.getValue(); + if (dia < Precision::Confusion()) + dia = radius * 4; + double otherdia = pcConstraint->OtherDiameter.getValue(); + if (otherdia < Precision::Confusion()) + otherdia = radius * 2; + double centerdist = pcConstraint->CenterDistance.getValue(); + if (fabs(centerdist) < Precision::Confusion()) + centerdist = 500; + int type = pcConstraint->Type.getValue(); + + if (type == 4) { + // Pulley + createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia, true); + + double angle = asin((dia - otherdia)/2/centerdist); + SbVec3f p1 = p + y * dia * cos(angle) + x * dia * sin(angle); + SbVec3f dir1 = x - y * sin(angle); + dir1.normalize(); + p1 = p1 + dir1 * 2 * radius; + dir1.negate(); + SbVec3f p2 = p - y * dia * cos(angle) + x * dia * sin(angle); + SbVec3f dir2 = x + y * sin(angle); + dir2.normalize(); + p2 = p2 + dir2 * 2 * radius; + dir2.negate(); + createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, dir1, 2 * radius, radius/5, true); + createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS+ARROWPOINTS, CYLFACETPOINTS+ARROWFACETPOINTS, p2, dir2, 2 * radius, radius/5, true); + } else if (type == 5) { + // Gear + createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia, true); + SbVec3f p1 = p + y * dia; + createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, x, 2 * radius, radius/5, true); + } + } + ViewProviderDocumentObject::updateData(prop); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h new file mode 100644 index 0000000000..94b434d2ad --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * 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 GUI_VIEWPROVIDERFEMCONSTRAINT_H +#define GUI_VIEWPROVIDERFEMCONSTRAINT_H + +#include + +#include "Gui/ViewProviderGeometryObject.h" +#include + +class SoFontStyle; +class SoText2; +class SoBaseColor; +class SoTranslation; +class SoCoordinate3; +class SoIndexedLineSet; +class SoIndexedFaceSet; +class SoEventCallback; +class SoMarkerSet; + +namespace Gui { +class View3DInventorViewer; +} + +namespace FemGui +{ + +class FemGuiExport ViewProviderFemConstraint : public Gui::ViewProviderGeometryObject +{ + PROPERTY_HEADER(FemGui::ViewProviderFemConstraint); + +public: + /// Constructor + ViewProviderFemConstraint(void); + virtual ~ViewProviderFemConstraint(); + + // Display properties + App::PropertyColor TextColor; + App::PropertyColor FaceColor; + App::PropertyInteger FontSize; + App::PropertyFloat DistFactor; + App::PropertyBool Mirror; + + void attach(App::DocumentObject *); + void updateData(const App::Property*); + std::vector getDisplayModes(void) const; + void setDisplayMode(const char* ModeName); + + std::vector claimChildren(void)const; + void setupContextMenu(QMenu*, QObject*, const char*); + +protected: + void onChanged(const App::Property* prop); + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); + +private: + SoFontStyle * pFont; + SoText2 * pLabel; + SoBaseColor * pColor; + SoBaseColor * pTextColor; + SoTranslation * pTranslation; + SoCoordinate3 * pCoords; + SoIndexedFaceSet * pFaces; + + /// Direction pointing outside of the solid + SbVec3f * normalDirection; + /// Direction of the force + SbVec3f * arrowDirection; + + void findCylinderData(SbVec3f& z, SbVec3f& y, SbVec3f& x, SbVec3f& p, double& radius, double& height); +}; + +} //namespace FemGui + + +#endif // GUI_VIEWPROVIDERFEMCONSTRAINT_H diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index e638ad8062..c4d3a73673 100755 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -29,7 +29,7 @@ #include "Workbench.h" #include -#include +#include using namespace FemGui; @@ -56,7 +56,8 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* fem = new Gui::ToolBarItem(root); fem->setCommand("FEM"); *fem << "Fem_CreateFromShape" - << "Fem_CreateNodesSet"; + << "Fem_CreateNodesSet" + << "Fem_Constraint"; return root; } @@ -68,7 +69,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const root->insertItem(item, fem); fem->setCommand("&FEM"); *fem << "Fem_CreateFromShape" - << "Fem_CreateNodesSet"; + << "Fem_CreateNodesSet" + << "Fem_Constraint"; return root; } From d48542cf5659359774d920580ccecd283a22b90a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 20 Feb 2013 20:24:38 +0430 Subject: [PATCH 2/9] Split code into separate files for each constraint type --- src/Mod/Fem/App/AppFem.cpp | 11 +- src/Mod/Fem/App/CMakeLists.txt | 18 +- src/Mod/Fem/App/FemConstraint.cpp | 252 +++++- src/Mod/Fem/App/FemConstraint.h | 25 +- src/Mod/Fem/App/FemConstraintBearing.cpp | 116 +++ src/Mod/Fem/App/FemConstraintBearing.h | 68 ++ src/Mod/Fem/App/FemConstraintFixed.cpp | 83 ++ src/Mod/Fem/App/FemConstraintFixed.h | 63 ++ src/Mod/Fem/App/FemConstraintForce.cpp | 125 +++ src/Mod/Fem/App/FemConstraintForce.h | 69 ++ src/Mod/Fem/App/FemConstraintGear.cpp | 58 ++ src/Mod/Fem/App/FemConstraintGear.h | 61 ++ src/Mod/Fem/App/FemConstraintPulley.cpp | 69 ++ src/Mod/Fem/App/FemConstraintPulley.h | 65 ++ src/Mod/Fem/Gui/AppFemGui.cpp | 10 + src/Mod/Fem/Gui/CMakeLists.txt | 65 +- src/Mod/Fem/Gui/Command.cpp | 156 +++- src/Mod/Fem/Gui/TaskFemConstraint.cpp | 639 +------------ src/Mod/Fem/Gui/TaskFemConstraint.h | 64 +- src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp | 345 +++++++ src/Mod/Fem/Gui/TaskFemConstraintBearing.h | 93 ++ .../Fem/Gui/TaskFemConstraintCylindrical.ui | 161 ++++ src/Mod/Fem/Gui/TaskFemConstraintFixed.cpp | 217 +++++ src/Mod/Fem/Gui/TaskFemConstraintFixed.h | 84 ++ src/Mod/Fem/Gui/TaskFemConstraintFixed.ui | 44 + src/Mod/Fem/Gui/TaskFemConstraintForce.cpp | 363 ++++++++ src/Mod/Fem/Gui/TaskFemConstraintForce.h | 92 ++ src/Mod/Fem/Gui/TaskFemConstraintForce.ui | 89 ++ src/Mod/Fem/Gui/TaskFemConstraintGear.cpp | 150 ++++ src/Mod/Fem/Gui/TaskFemConstraintGear.h | 78 ++ src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp | 185 ++++ src/Mod/Fem/Gui/TaskFemConstraintPulley.h | 82 ++ src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp | 847 +++++------------- src/Mod/Fem/Gui/ViewProviderFemConstraint.h | 46 +- .../Gui/ViewProviderFemConstraintBearing.cpp | 142 +++ .../Gui/ViewProviderFemConstraintBearing.h | 74 ++ .../Gui/ViewProviderFemConstraintFixed.cpp | 147 +++ .../Fem/Gui/ViewProviderFemConstraintFixed.h | 74 ++ .../Gui/ViewProviderFemConstraintForce.cpp | 196 ++++ .../Fem/Gui/ViewProviderFemConstraintForce.h | 78 ++ .../Fem/Gui/ViewProviderFemConstraintGear.cpp | 154 ++++ .../Fem/Gui/ViewProviderFemConstraintGear.h | 74 ++ .../Gui/ViewProviderFemConstraintPulley.cpp | 166 ++++ .../Fem/Gui/ViewProviderFemConstraintPulley.h | 74 ++ src/Mod/Fem/Gui/Workbench.cpp | 12 +- src/Mod/PartDesign/WizardShaft/InitGui.py | 76 -- 46 files changed, 4703 insertions(+), 1457 deletions(-) create mode 100644 src/Mod/Fem/App/FemConstraintBearing.cpp create mode 100644 src/Mod/Fem/App/FemConstraintBearing.h create mode 100644 src/Mod/Fem/App/FemConstraintFixed.cpp create mode 100644 src/Mod/Fem/App/FemConstraintFixed.h create mode 100644 src/Mod/Fem/App/FemConstraintForce.cpp create mode 100644 src/Mod/Fem/App/FemConstraintForce.h create mode 100644 src/Mod/Fem/App/FemConstraintGear.cpp create mode 100644 src/Mod/Fem/App/FemConstraintGear.h create mode 100644 src/Mod/Fem/App/FemConstraintPulley.cpp create mode 100644 src/Mod/Fem/App/FemConstraintPulley.h create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintBearing.h create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintCylindrical.ui create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintFixed.cpp create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintFixed.h create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintFixed.ui create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintForce.cpp create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintForce.h create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintForce.ui create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintGear.cpp create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintGear.h create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp create mode 100644 src/Mod/Fem/Gui/TaskFemConstraintPulley.h create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.h create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.h create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintForce.h create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintGear.h create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp create mode 100644 src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.h delete mode 100644 src/Mod/PartDesign/WizardShaft/InitGui.py diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index 7a29fcada2..8f8d024eb2 100755 --- a/src/Mod/Fem/App/AppFem.cpp +++ b/src/Mod/Fem/App/AppFem.cpp @@ -41,7 +41,11 @@ #include "FemSetNodesObject.h" #include "HypothesisPy.h" -#include "FemConstraint.h" +#include "FemConstraintBearing.h" +#include "FemConstraintFixed.h" +#include "FemConstraintForce.h" +#include "FemConstraintGear.h" +#include "FemConstraintPulley.h" extern struct PyMethodDef Fem_methods[]; @@ -117,6 +121,11 @@ void AppFemExport initFem() Fem::FemSetNodesObject ::init(); Fem::Constraint ::init(); + Fem::ConstraintBearing ::init(); + Fem::ConstraintFixed ::init(); + Fem::ConstraintForce ::init(); + Fem::ConstraintGear ::init(); + Fem::ConstraintPulley ::init(); } } // extern "C" diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index ba16889993..62dd1bf105 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -24,10 +24,10 @@ set(Fem_LIBS Mesh FreeCADApp ) - -if(SMESH_FOUND) - include_directories( ${SMESH_INCLUDE_DIR} ) - list( APPEND Fem_LIBS ${SMESH_LIBRARIES} ) + +if(SMESH_FOUND) + include_directories( ${SMESH_INCLUDE_DIR} ) + list( APPEND Fem_LIBS ${SMESH_LIBRARIES} ) endif(SMESH_FOUND) generate_from_xml(FemMeshPy) @@ -66,6 +66,16 @@ SET(Fem_SRCS FemMeshProperty.h FemConstraint.cpp FemConstraint.h + FemConstraintBearing.h + FemConstraintBearing.cpp + FemConstraintFixed.cpp + FemConstraintFixed.h + FemConstraintForce.cpp + FemConstraintForce.h + FemConstraintGear.cpp + FemConstraintGear.h + FemConstraintPulley.cpp + FemConstraintPulley.h ${Mod_SRCS} ${Python_SRCS} ) diff --git a/src/Mod/Fem/App/FemConstraint.cpp b/src/Mod/Fem/App/FemConstraint.cpp index ae9ef45ec5..008c0ec2a3 100644 --- a/src/Mod/Fem/App/FemConstraint.cpp +++ b/src/Mod/Fem/App/FemConstraint.cpp @@ -24,33 +24,46 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include #endif #include "FemConstraint.h" +#include #include using namespace Fem; -const char* Constraint::TypeEnums[]= {"Force on geometry","Fixed", - "Bearing (radial free)", "Bearing (radial fixed)", - "Pulley", "Gear (straight toothed)", NULL}; - PROPERTY_SOURCE(Fem::Constraint, App::DocumentObject); Constraint::Constraint() { - ADD_PROPERTY(Type,((long)0)); - Type.setEnums(TypeEnums); - ADD_PROPERTY(Force,(0.0)); ADD_PROPERTY_TYPE(References,(0,0),"Constraint",(App::PropertyType)(App::Prop_None),"Elements where the constraint is applied"); - ADD_PROPERTY_TYPE(Direction,(0),"Constraint",(App::PropertyType)(App::Prop_None),"Element giving direction of constraint"); - ADD_PROPERTY(Reversed,(0)); - ADD_PROPERTY(Distance,(0.0)); - ADD_PROPERTY_TYPE(Location,(0),"Constraint",(App::PropertyType)(App::Prop_None),"Element giving location where constraint is applied"); - ADD_PROPERTY(Diameter,(0.0)); - ADD_PROPERTY(OtherDiameter,(0.0)); - ADD_PROPERTY(CenterDistance,(0.0)); + ADD_PROPERTY_TYPE(NormalDirection,(Base::Vector3f(0,0,1)),"Constraint",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output),"Normal direction pointing outside of solid"); } Constraint::~Constraint() @@ -59,12 +72,219 @@ Constraint::~Constraint() App::DocumentObjectExecReturn *Constraint::execute(void) { - // Ensure that the constraint symbols follow the changed geometry References.touch(); - return DocumentObject::StdReturn; + return StdReturn; } void Constraint::onChanged(const App::Property* prop) { + //Base::Console().Error("Constraint::onChanged()\n"); + if (prop == &References) { + Base::Console().Error("References\n"); + // If References are changed, recalculate the normal direction. If no useful reference is found, + // use z axis or previous value. If several faces are selected, only the first one is used + std::vector Objects = References.getValues(); + std::vector SubElements = References.getSubValues(); + + // Extract geometry from References + TopoDS_Shape sh; + + for (int i = 0; i < Objects.size(); i++) { + App::DocumentObject* obj = Objects[i]; + Part::Feature* feat = static_cast(obj); + const Part::TopoShape& toposhape = feat->Shape.getShape(); + if (!toposhape._Shape.IsNull()) { + sh = toposhape.getSubShape(SubElements[i].c_str()); + + if (sh.ShapeType() == TopAbs_FACE) { + // Get face normal in center point + TopoDS_Face face = TopoDS::Face(sh); + BRepGProp_Face props(face); + gp_Vec normal; + gp_Pnt center; + double u1,u2,v1,v2; + props.Bounds(u1,u2,v1,v2); + props.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal); + normal.Normalize(); + NormalDirection.setValue(normal.X(), normal.Y(), normal.Z()); + // One face is enough... + DocumentObject::onChanged(prop); + return; + } + } + } + } + DocumentObject::onChanged(prop); } + +void Constraint::onDocumentRestored() +{ + Base::Console().Error("onDocumentRestored\n"); +} + + +void Constraint::onSettingDocument() +{ + Base::Console().Error("onSettingDocument\n"); +} + +void Constraint::getPoints(std::vector &points, std::vector &normals) const +{ + std::vector Objects = References.getValues(); + std::vector SubElements = References.getSubValues(); + + // Extract geometry from References + TopoDS_Shape sh; + + for (int i = 0; i < Objects.size(); i++) { + App::DocumentObject* obj = Objects[i]; + Part::Feature* feat = static_cast(obj); + const Part::TopoShape& toposhape = feat->Shape.getShape(); + sh = toposhape.getSubShape(SubElements[i].c_str()); + + if (sh.ShapeType() == TopAbs_VERTEX) { + const TopoDS_Vertex& vertex = TopoDS::Vertex(sh); + gp_Pnt p = BRep_Tool::Pnt(vertex); + points.push_back(Base::Vector3f(p.X(), p.Y(), p.Z())); + normals.push_back(NormalDirection.getValue()); + } else if (sh.ShapeType() == TopAbs_EDGE) { + BRepAdaptor_Curve curve(TopoDS::Edge(sh)); + double fp = curve.FirstParameter(); + double lp = curve.LastParameter(); + GProp_GProps props; + BRepGProp::LinearProperties(TopoDS::Edge(sh), props); + double l = props.Mass(); + // Create points with 10 units distance, but at least one at the beginning and end of the edge + int steps; + if (l >= 20) + steps = round(l / 10); + else + steps = 1; + double step = (lp - fp) / steps; + for (int i = 0; i < steps + 1; i++) { + gp_Pnt p = curve.Value(i * step); + points.push_back(Base::Vector3f(p.X(), p.Y(), p.Z())); + normals.push_back(NormalDirection.getValue()); + } + } else if (sh.ShapeType() == TopAbs_FACE) { + TopoDS_Face face = TopoDS::Face(sh); + // Surface boundaries + BRepAdaptor_Surface surface(face); + double ufp = surface.FirstUParameter(); + double ulp = surface.LastUParameter(); + double vfp = surface.FirstVParameter(); + double vlp = surface.LastVParameter(); + // Surface normals + BRepGProp_Face props(face); + gp_Vec normal; + gp_Pnt center; + // Get an estimate for the number of arrows by finding the average length of curves + Handle(Adaptor3d_HSurface) hsurf; + hsurf = new BRepAdaptor_HSurface(surface); + Adaptor3d_IsoCurve isoc(hsurf, GeomAbs_IsoU, vfp); + double l = GCPnts_AbscissaPoint::Length(isoc, Precision::Confusion()); + isoc.Load(GeomAbs_IsoU, vlp); + double lv = (l + GCPnts_AbscissaPoint::Length(isoc, Precision::Confusion()))/2.0; + isoc.Load(GeomAbs_IsoV, ufp); + l = GCPnts_AbscissaPoint::Length(isoc, Precision::Confusion()); + isoc.Load(GeomAbs_IsoV, ulp); + double lu = (l + GCPnts_AbscissaPoint::Length(isoc, Precision::Confusion()))/2.0; + int stepsv; + if (lv >= 20.0) + stepsv = round(lv / 10); + else + stepsv = 2; // Minimum of three arrows to ensure (as much as possible) that at least one is displayed + int stepsu; + if (lu >= 20.0) + stepsu = round(lu / 10); + else + stepsu = 2; + double stepv = (vlp - vfp) / stepsv; + double stepu = (ulp - ufp) / stepsu; + // Create points and normals + for (int i = 0; i < stepsv + 1; i++) { + for (int j = 0; j < stepsu + 1; j++) { + double v = vfp + i * stepv; + double u = ufp + j * stepu; + gp_Pnt p = surface.Value(u, v); + BRepClass_FaceClassifier classifier(face, p, Precision::Confusion()); + if (classifier.State() != TopAbs_OUT) { + points.push_back(Base::Vector3f(p.X(), p.Y(), p.Z())); + props.Normal(u, v,center,normal); + normal.Normalize(); + normals.push_back(Base::Vector3f(normal.X(), normal.Y(), normal.Z())); + } + } + } + } + } +} + +void Constraint::getCylinder(float& radius, float& height, Base::Vector3f& base, Base::Vector3f& axis) const +{ + std::vector Objects = References.getValues(); + std::vector SubElements = References.getSubValues(); + if (Objects.empty()) + return; + App::DocumentObject* obj = Objects[0]; + Part::Feature* feat = static_cast(obj); + TopoDS_Shape sh = feat->Shape.getShape().getSubShape(SubElements[0].c_str()); + + TopoDS_Face face = TopoDS::Face(sh); + BRepAdaptor_Surface surface(face); + gp_Cylinder cyl = surface.Cylinder(); + gp_Pnt start = surface.Value(surface.FirstUParameter(), surface.FirstVParameter()); + gp_Pnt end = surface.Value(surface.FirstUParameter(), surface.LastVParameter()); + height = start.Distance(end); + radius = cyl.Radius(); + + gp_Pnt b = cyl.Location(); + base = Base::Vector3f(b.X(), b.Y(), b.Z()); + gp_Dir dir = cyl.Axis().Direction(); + axis = Base::Vector3f(dir.X(), dir.Y(), dir.Z()); +} + +Base::Vector3f Constraint::getBasePoint(const Base::Vector3f& base, const Base::Vector3f& axis, + const App::PropertyLinkSub& location, const float& dist) +{ + // Get the point specified by Location and Distance + App::DocumentObject* objLoc = location.getValue(); + std::string subName = location.getSubValues().front(); + Part::Feature* featLoc = static_cast(objLoc); + TopoDS_Shape shloc = featLoc->Shape.getShape().getSubShape(subName.c_str()); + + // Get a plane from the Location reference + gp_Pln plane; + gp_Dir cylaxis(axis.x, axis.y, axis.z); + if (shloc.ShapeType() == TopAbs_FACE) { + BRepAdaptor_Surface surface(TopoDS::Face(shloc)); + plane = surface.Plane(); + } else { + BRepAdaptor_Curve curve(TopoDS::Edge(shloc)); + gp_Lin line = curve.Line(); + gp_Dir tang = line.Direction().Crossed(cylaxis); + gp_Dir norm = line.Direction().Crossed(tang); + plane = gp_Pln(line.Location(), norm); + } + + // Translate the plane in direction of the cylinder (for positive values of Distance) + Handle_Geom_Plane pln = new Geom_Plane(plane); + gp_Pnt cylbase(base.x, base.y, base.z); + GeomAPI_ProjectPointOnSurf proj(cylbase, pln); + if (!proj.IsDone()) + return Base::Vector3f(0,0,0); + + gp_Pnt projPnt = proj.NearestPoint(); + if ((fabs(dist) > Precision::Confusion()) && (projPnt.IsEqual(cylbase, Precision::Confusion()) == Standard_False)) + plane.Translate(gp_Vec(projPnt, cylbase).Normalized().Multiplied(dist)); + Handle_Geom_Plane plnt = new Geom_Plane(plane); + + // Intersect translated plane with cylinder axis + Handle_Geom_Curve crv = new Geom_Line(cylbase, cylaxis); + GeomAPI_IntCS intersector(crv, plnt); + if (!intersector.IsDone()) + return Base::Vector3f(0,0,0); + gp_Pnt inter = intersector.Point(1); + return Base::Vector3f(inter.X(), inter.Y(), inter.Z()); +} diff --git a/src/Mod/Fem/App/FemConstraint.h b/src/Mod/Fem/App/FemConstraint.h index 625ba95aec..02c0bfd9d5 100644 --- a/src/Mod/Fem/App/FemConstraint.h +++ b/src/Mod/Fem/App/FemConstraint.h @@ -24,8 +24,10 @@ #ifndef FEM_CONSTRAINT_H #define FEM_CONSTRAINT_H +#include #include #include +#include namespace Fem { @@ -39,30 +41,29 @@ public: Constraint(void); virtual ~Constraint(); - App::PropertyEnumeration Type; App::PropertyLinkSubList References; - App::PropertyFloat Force; - App::PropertyLinkSub Direction; - App::PropertyBool Reversed; - App::PropertyLinkSub Location; - App::PropertyFloat Distance; - App::PropertyFloat Diameter; - App::PropertyFloat OtherDiameter; - App::PropertyFloat CenterDistance; + App::PropertyVector NormalDirection; /// recalculate the object virtual App::DocumentObjectExecReturn *execute(void); /// returns the type name of the ViewProvider - const char* getViewProviderName(void) const { + virtual const char* getViewProviderName(void) const { return "FemGui::ViewProviderFemConstraint"; } protected: virtual void onChanged(const App::Property* prop); + virtual void onDocumentRestored(); + virtual void onSettingDocument(); + +protected: + /// Calculate the points where symbols should be drawn + void getPoints(std::vector& points, std::vector& normals) const; + void getCylinder(float& radius, float& height, Base::Vector3f& base, Base::Vector3f& axis) const; + Base::Vector3f getBasePoint(const Base::Vector3f& base, const Base::Vector3f& axis, + const App::PropertyLinkSub &location, const float& dist); -private: - static const char* TypeEnums[]; }; } //namespace Fem diff --git a/src/Mod/Fem/App/FemConstraintBearing.cpp b/src/Mod/Fem/App/FemConstraintBearing.cpp new file mode 100644 index 0000000000..3ecf7ea4c4 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintBearing.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + * 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 "FemConstraintBearing.h" + +#include +#include + +using namespace Fem; + +PROPERTY_SOURCE(Fem::ConstraintBearing, Fem::Constraint); + +ConstraintBearing::ConstraintBearing() +{ + ADD_PROPERTY_TYPE(Location,(0),"ConstraintBearing",(App::PropertyType)(App::Prop_None), + "Element giving axial location of constraint"); + ADD_PROPERTY(Dist,(0.0)); + ADD_PROPERTY(AxialFree,(0)); + ADD_PROPERTY(Radius,(0.0)); + ADD_PROPERTY(Height,(0.0)); + ADD_PROPERTY_TYPE(BasePoint,(Base::Vector3f(0,0,0)),"ConstraintBearing",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Base point of cylindrical bearing seat"); + ADD_PROPERTY_TYPE(Axis,(Base::Vector3f(0,1,0)),"ConstraintBearing",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Axis of bearing seat"); +} + +App::DocumentObjectExecReturn *ConstraintBearing::execute(void) +{ + return Constraint::execute(); +} + +void ConstraintBearing::onChanged(const App::Property* prop) +{ + // Note: If we call this at the end, then the symbol ist not oriented correctly initially + // because the NormalDirection has not been calculated yet + Constraint::onChanged(prop); + + if (prop == &References) { + // Find data of cylinder + float radius, height; + Base::Vector3f base, axis; + getCylinder(radius, height, base, axis); + Radius.setValue(radius); + Axis.setValue(axis); + Height.setValue(height); + // Update base point + base = base + axis * height/2; + if (Location.getValue() != NULL) { + base = getBasePoint(base, axis, Location, Dist.getValue()); + } + Base::Console().Error("Basepoint2: %f, %f, %f\n", base.x, base.y, base.z); + BasePoint.setValue(base); + BasePoint.touch(); // This triggers ViewProvider::updateData() + } else if ((prop == &Location) || (prop == &Dist)) { + App::DocumentObject* obj = Location.getValue(); + std::vector names = Location.getSubValues(); + if (names.size() == 0) { + return; + } + std::string subName = names.front(); + Part::Feature* feat = static_cast(obj); + TopoDS_Shape sh = feat->Shape.getShape().getSubShape(subName.c_str()); + + if (sh.ShapeType() == TopAbs_FACE) { + BRepAdaptor_Surface surface(TopoDS::Face(sh)); + if (surface.GetType() != GeomAbs_Plane) { + return; // "Location must be a planar face or linear edge" + } + } else if (sh.ShapeType() == TopAbs_EDGE) { + BRepAdaptor_Curve line(TopoDS::Edge(sh)); + if (line.GetType() != GeomAbs_Line) { + return; // "Location must be a planar face or linear edge" + } + } + + float radius, height; + Base::Vector3f base, axis; + getCylinder(radius, height, base, axis); + base = getBasePoint(base + axis * height/2, axis, Location, Dist.getValue()); + Base::Console().Error("Basepoint: %f, %f, %f\n", base.x, base.y, base.z); + BasePoint.setValue(base); + BasePoint.touch(); + } +} diff --git a/src/Mod/Fem/App/FemConstraintBearing.h b/src/Mod/Fem/App/FemConstraintBearing.h new file mode 100644 index 0000000000..6385e6b483 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintBearing.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * 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_CONSTRAINTBEARING_H +#define FEM_CONSTRAINTBEARING_H + +#include +#include +#include + +#include "FemConstraint.h" + +namespace Fem +{ + +class AppFemExport ConstraintBearing : public Fem::Constraint +{ + PROPERTY_HEADER(Fem::ConstraintBearing); + +public: + /// Constructor + ConstraintBearing(void); + + App::PropertyLinkSub Location; + App::PropertyFloat Dist; + App::PropertyBool AxialFree; + // Read-only (calculated values). These trigger changes in the ViewProvider + App::PropertyFloat Radius; + App::PropertyFloat Height; + App::PropertyVector BasePoint; + App::PropertyVector Axis; + + /// recalculate the object + virtual App::DocumentObjectExecReturn *execute(void); + + /// returns the type name of the ViewProvider + const char* getViewProviderName(void) const { + return "FemGui::ViewProviderFemConstraintBearing"; + } + +protected: + virtual void onChanged(const App::Property* prop); +}; + +} //namespace Fem + + +#endif // FEM_CONSTRAINTBEARING_H diff --git a/src/Mod/Fem/App/FemConstraintFixed.cpp b/src/Mod/Fem/App/FemConstraintFixed.cpp new file mode 100644 index 0000000000..1cde0061fa --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintFixed.cpp @@ -0,0 +1,83 @@ +/*************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "FemConstraintFixed.h" + +#include +#include + +using namespace Fem; + +PROPERTY_SOURCE(Fem::ConstraintFixed, Fem::Constraint); + +ConstraintFixed::ConstraintFixed() +{ + ADD_PROPERTY_TYPE(Points,(Base::Vector3f()),"ConstraintFixed",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Points where symbols are drawn"); + ADD_PROPERTY_TYPE(Normals,(Base::Vector3f()),"ConstraintFixed",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Normals where symbols are drawn"); + Points.setValues(std::vector()); + Normals.setValues(std::vector()); +} + +App::DocumentObjectExecReturn *ConstraintFixed::execute(void) +{ + return Constraint::execute(); +} + +void ConstraintFixed::onChanged(const App::Property* prop) +{ + // Note: If we call this at the end, then the symbols are not oriented correctly initially + // because the NormalDirection has not been calculated yet + Constraint::onChanged(prop); + + if (prop == &References) { + std::vector points; + std::vector normals; + getPoints(points, normals); + Points.setValues(points); + Normals.setValues(normals); + Points.touch(); // This triggers ViewProvider::updateData() + } +} diff --git a/src/Mod/Fem/App/FemConstraintFixed.h b/src/Mod/Fem/App/FemConstraintFixed.h new file mode 100644 index 0000000000..0294fbdaa3 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintFixed.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * 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_CONSTRAINTFIXED_H +#define FEM_CONSTRAINTFIXED_H + +#include +#include +#include + +#include "FemConstraint.h" + +namespace Fem +{ + +class AppFemExport ConstraintFixed : public Fem::Constraint +{ + PROPERTY_HEADER(Fem::ConstraintFixed); + +public: + /// Constructor + ConstraintFixed(void); + + // Read-only (calculated values). These trigger changes in the ViewProvider + 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 { + return "FemGui::ViewProviderFemConstraintFixed"; + } + +protected: + virtual void onChanged(const App::Property* prop); +}; + +} //namespace Fem + + +#endif // FEM_CONSTRAINTFIXED_H diff --git a/src/Mod/Fem/App/FemConstraintForce.cpp b/src/Mod/Fem/App/FemConstraintForce.cpp new file mode 100644 index 0000000000..2fa97b7778 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintForce.cpp @@ -0,0 +1,125 @@ +/*************************************************************************** + * 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 "FemConstraintForce.h" + +#include +#include + +using namespace Fem; + +PROPERTY_SOURCE(Fem::ConstraintForce, Fem::Constraint); + +ConstraintForce::ConstraintForce() +{ + ADD_PROPERTY(Force,(0.0)); + ADD_PROPERTY_TYPE(Direction,(0),"ConstraintForce",(App::PropertyType)(App::Prop_None), + "Element giving direction of constraint"); + ADD_PROPERTY(Reversed,(0)); + ADD_PROPERTY_TYPE(Points,(Base::Vector3f()),"ConstraintForce",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Points where arrows are drawn"); + ADD_PROPERTY_TYPE(DirectionVector,(Base::Vector3f(0,0,1)),"ConstraintForce",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Direction of arrows"); + naturalDirectionVector = Base::Vector3f(0,0,1); + Points.setValues(std::vector()); +} + +App::DocumentObjectExecReturn *ConstraintForce::execute(void) +{ + return Constraint::execute(); +} + +void ConstraintForce::onChanged(const App::Property* prop) +{ + // Note: If we call this at the end, then the arrows are not oriented correctly initially + // because the NormalDirection has not been calculated yet + Constraint::onChanged(prop); + + if (prop == &References) { + std::vector points; + std::vector normals; + getPoints(points, normals); + Points.setValues(points); // We don't use the normals because all arrows should have the same direction + Points.touch(); // This triggers ViewProvider::updateData() + } else if (prop == &Direction) { + App::DocumentObject* obj = Direction.getValue(); + std::vector names = Direction.getSubValues(); + if (names.size() == 0) { + return; + } + std::string subName = names.front(); + Part::Feature* feat = static_cast(obj); + TopoDS_Shape sh = feat->Shape.getShape().getSubShape(subName.c_str()); + gp_Dir dir; + + if (sh.ShapeType() == TopAbs_FACE) { + BRepAdaptor_Surface surface(TopoDS::Face(sh)); + if (surface.GetType() == GeomAbs_Plane) { + dir = surface.Plane().Axis().Direction(); + } else { + return; // "Direction must be a planar face or linear edge" + } + } else if (sh.ShapeType() == TopAbs_EDGE) { + BRepAdaptor_Curve line(TopoDS::Edge(sh)); + if (line.GetType() == GeomAbs_Line) { + dir = line.Line().Direction(); + } else { + return; // "Direction must be a planar face or linear edge" + } + } + + Base::Vector3f direction(dir.X(), dir.Y(), dir.Z()); + direction.Normalize(); + naturalDirectionVector = direction; + if (Reversed.getValue()) + direction = -direction; + DirectionVector.setValue(direction); + DirectionVector.touch(); + } else if (prop == &Reversed) { + if (Reversed.getValue() && (DirectionVector.getValue() == naturalDirectionVector)) { + DirectionVector.setValue(-naturalDirectionVector); + DirectionVector.touch(); + } else if (!Reversed.getValue() && (DirectionVector.getValue() != naturalDirectionVector)) { + DirectionVector.setValue(naturalDirectionVector); + DirectionVector.touch(); + } + } else if (prop == &NormalDirection) { + // Set a default direction if no direction reference has been given + if (Direction.getValue() == NULL) { + DirectionVector.setValue(NormalDirection.getValue()); + naturalDirectionVector = NormalDirection.getValue(); + } + } +} diff --git a/src/Mod/Fem/App/FemConstraintForce.h b/src/Mod/Fem/App/FemConstraintForce.h new file mode 100644 index 0000000000..1386e7d7d0 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintForce.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * 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_CONSTRAINTFORCE_H +#define FEM_CONSTRAINTFORCE_H + +#include +#include +#include + +#include "FemConstraint.h" + +namespace Fem +{ + +class AppFemExport ConstraintForce : public Fem::Constraint +{ + PROPERTY_HEADER(Fem::ConstraintForce); + +public: + /// Constructor + ConstraintForce(void); + + App::PropertyFloat Force; + App::PropertyLinkSub Direction; + App::PropertyBool Reversed; + // Read-only (calculated values). These trigger changes in the ViewProvider + App::PropertyVectorList Points; + App::PropertyVector DirectionVector; + + /// recalculate the object + virtual App::DocumentObjectExecReturn *execute(void); + + /// returns the type name of the ViewProvider + const char* getViewProviderName(void) const { + return "FemGui::ViewProviderFemConstraintForce"; + } + +protected: + virtual void onChanged(const App::Property* prop); + +private: + Base::Vector3f naturalDirectionVector; +}; + +} //namespace Fem + + +#endif // FEM_CONSTRAINTFORCE_H diff --git a/src/Mod/Fem/App/FemConstraintGear.cpp b/src/Mod/Fem/App/FemConstraintGear.cpp new file mode 100644 index 0000000000..7505b8bbf3 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintGear.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + * 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 "FemConstraintGear.h" + +#include +#include + +using namespace Fem; + +PROPERTY_SOURCE(Fem::ConstraintGear, Fem::ConstraintBearing); + +ConstraintGear::ConstraintGear() +{ + ADD_PROPERTY(Diameter,(0)); +} + +App::DocumentObjectExecReturn *ConstraintGear::execute(void) +{ + return ConstraintBearing::execute(); +} + +void ConstraintGear::onChanged(const App::Property* prop) +{ + ConstraintBearing::onChanged(prop); +} diff --git a/src/Mod/Fem/App/FemConstraintGear.h b/src/Mod/Fem/App/FemConstraintGear.h new file mode 100644 index 0000000000..a18053ff0a --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintGear.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * 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_CONSTRAINTGear_H +#define FEM_CONSTRAINTGear_H + +#include +#include +#include + +#include "FemConstraintBearing.h" + +namespace Fem +{ + +class AppFemExport ConstraintGear : public Fem::ConstraintBearing +{ + PROPERTY_HEADER(Fem::ConstraintGear); + +public: + /// Constructor + ConstraintGear(void); + + App::PropertyFloat Diameter; + + /// recalculate the object + virtual App::DocumentObjectExecReturn *execute(void); + + /// returns the type name of the ViewProvider + const char* getViewProviderName(void) const { + return "FemGui::ViewProviderFemConstraintGear"; + } + +protected: + virtual void onChanged(const App::Property* prop); +}; + +} //namespace Fem + + +#endif // FEM_CONSTRAINTGear_H diff --git a/src/Mod/Fem/App/FemConstraintPulley.cpp b/src/Mod/Fem/App/FemConstraintPulley.cpp new file mode 100644 index 0000000000..d4c5efbbe4 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintPulley.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** + * 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 "FemConstraintPulley.h" + +#include +#include + +using namespace Fem; + +PROPERTY_SOURCE(Fem::ConstraintPulley, Fem::ConstraintBearing); + +ConstraintPulley::ConstraintPulley() +{ + ADD_PROPERTY(Diameter,(0)); + ADD_PROPERTY(OtherDiameter,(0)); + ADD_PROPERTY(CenterDistance,(0)); + ADD_PROPERTY_TYPE(Angle,(0),"ConstraintPulley",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Angle of pulley forces"); +} + +App::DocumentObjectExecReturn *ConstraintPulley::execute(void) +{ + return ConstraintBearing::execute(); +} + +void ConstraintPulley::onChanged(const App::Property* prop) +{ + ConstraintBearing::onChanged(prop); + + if ((prop == &Diameter) || (prop == &OtherDiameter) || (prop == &CenterDistance)) { + if (CenterDistance.getValue() > Precision::Confusion()) { + Angle.setValue(asin((Diameter.getValue() - OtherDiameter.getValue())/2/CenterDistance.getValue())); + Angle.touch(); + } + } +} diff --git a/src/Mod/Fem/App/FemConstraintPulley.h b/src/Mod/Fem/App/FemConstraintPulley.h new file mode 100644 index 0000000000..5540d0ba63 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintPulley.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * 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_CONSTRAINTPulley_H +#define FEM_CONSTRAINTPulley_H + +#include +#include +#include + +#include "FemConstraintBearing.h" + +namespace Fem +{ + +class AppFemExport ConstraintPulley : public Fem::ConstraintBearing +{ + PROPERTY_HEADER(Fem::ConstraintPulley); + +public: + /// Constructor + ConstraintPulley(void); + + App::PropertyFloat Diameter; + App::PropertyFloat OtherDiameter; + App::PropertyFloat CenterDistance; + // Read-only (calculated values). These trigger changes in the ViewProvider + App::PropertyFloat Angle; + + /// recalculate the object + virtual App::DocumentObjectExecReturn *execute(void); + + /// returns the type name of the ViewProvider + const char* getViewProviderName(void) const { + return "FemGui::ViewProviderFemConstraintPulley"; + } + +protected: + virtual void onChanged(const App::Property* prop); +}; + +} //namespace Fem + + +#endif // FEM_CONSTRAINTPulley_H diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index 46e20afe8f..f591b18a7d 100755 --- a/src/Mod/Fem/Gui/AppFemGui.cpp +++ b/src/Mod/Fem/Gui/AppFemGui.cpp @@ -35,6 +35,11 @@ #include "ViewProviderSetFaces.h" #include "ViewProviderSetGeometry.h" #include "ViewProviderFemConstraint.h" +#include "ViewProviderFemConstraintBearing.h" +#include "ViewProviderFemConstraintFixed.h" +#include "ViewProviderFemConstraintForce.h" +#include "ViewProviderFemConstraintGear.h" +#include "ViewProviderFemConstraintPulley.h" #include "Workbench.h" //#include "resources/qrc_Fem.cpp" @@ -75,6 +80,11 @@ void FemGuiExport initFemGui() FemGui::ViewProviderSetFaces ::init(); FemGui::ViewProviderSetGeometry ::init(); FemGui::ViewProviderFemConstraint ::init(); + FemGui::ViewProviderFemConstraintBearing ::init(); + FemGui::ViewProviderFemConstraintFixed ::init(); + FemGui::ViewProviderFemConstraintForce ::init(); + FemGui::ViewProviderFemConstraintGear ::init(); + FemGui::ViewProviderFemConstraintPulley ::init(); // add resources and reloads the translators loadFemResource(); diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 52c1c0dd79..162e3efaaf 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -23,10 +23,10 @@ set(FemGui_LIBS Fem FreeCADGui ) - -if(SMESH_FOUND) - include_directories( ${SMESH_INCLUDE_DIR} ) - list( APPEND FemGui_LIBS ${SMESH_LIBRARIES} ) + +if(SMESH_FOUND) + include_directories( ${SMESH_INCLUDE_DIR} ) + list( APPEND FemGui_LIBS ${SMESH_LIBRARIES} ) endif(SMESH_FOUND) set(FemGui_MOC_HDRS @@ -35,6 +35,11 @@ set(FemGui_MOC_HDRS TaskCreateNodeSet.h TaskDlgCreateNodeSet.h TaskFemConstraint.h + TaskFemConstraintBearing.h + TaskFemConstraintFixed.h + TaskFemConstraintForce.h + TaskFemConstraintGear.h + TaskFemConstraintPulley.h ) fc_wrap_cpp(FemGui_MOC_SRCS ${FemGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${FemGui_MOC_SRCS}) @@ -44,6 +49,9 @@ set(FemGui_UIC_SRCS TaskCreateNodeSet.ui TaskObjectName.ui TaskFemConstraint.ui + TaskFemConstraintCylindrical.ui + TaskFemConstraintFixed.ui + TaskFemConstraintForce.ui ) qt4_wrap_ui(FemGui_UIC_HDRS ${FemGui_UIC_SRCS}) @@ -55,8 +63,21 @@ SET(FemGui_DLG_SRCS TaskFemConstraint.ui TaskFemConstraint.cpp TaskFemConstraint.h -) -SOURCE_GROUP("Dialogs" FILES ${FemGui_DLG_SRCS}) + TaskFemConstraintCylindrical.ui + TaskFemConstraintBearing.cpp + TaskFemConstraintBearing.h + TaskFemConstraintFixed.ui + TaskFemConstraintFixed.cpp + TaskFemConstraintFixed.h + TaskFemConstraintForce.ui + TaskFemConstraintForce.cpp + TaskFemConstraintForce.h + TaskFemConstraintGear.cpp + TaskFemConstraintGear.h + TaskFemConstraintPulley.cpp + TaskFemConstraintPulley.h +) +SOURCE_GROUP("Dialogs" FILES ${FemGui_DLG_SRCS}) qt4_add_resources(FemResource_SRCS Resources/Fem.qrc) @@ -77,6 +98,16 @@ SET(FemGui_SRCS_ViewProvider FemSelectionGate.h ViewProviderFemConstraint.cpp ViewProviderFemConstraint.h + ViewProviderFemConstraintBearing.cpp + ViewProviderFemConstraintBearing.h + ViewProviderFemConstraintFixed.cpp + ViewProviderFemConstraintFixed.h + ViewProviderFemConstraintForce.cpp + ViewProviderFemConstraintForce.h + ViewProviderFemConstraintGear.cpp + ViewProviderFemConstraintGear.h + ViewProviderFemConstraintPulley.cpp + ViewProviderFemConstraintPulley.h ) SOURCE_GROUP("ViewProvider" FILES ${FemGui_SRCS_ViewProvider}) @@ -122,6 +153,18 @@ SET(FemGui_SRCS ${FemGui_SRCS_TaskDlg} ${FemGui_SRCS_TaskBoxes} ${FemGui_SRCS_Module} + ViewProviderFemConstraint.cpp + ViewProviderFemConstraint.h + ViewProviderFemConstraintBearing.cpp + ViewProviderFemConstraintBearing.h + ViewProviderFemConstraintFixed.cpp + ViewProviderFemConstraintFixed.h + ViewProviderFemConstraintForce.cpp + ViewProviderFemConstraintForce.h + ViewProviderFemConstraintGear.cpp + ViewProviderFemConstraintGear.h + ViewProviderFemConstraintPulley.cpp + ViewProviderFemConstraintPulley.h ) @@ -129,11 +172,11 @@ SET(FemGui_SRCS add_library(FemGui SHARED ${FemGui_SRCS}) target_link_libraries(FemGui ${FemGui_LIBS}) - -fc_target_copy_resource(FemGui - ${CMAKE_SOURCE_DIR}/src/Mod/Fem - ${CMAKE_BINARY_DIR}/Mod/Fem - InitGui.py) + +fc_target_copy_resource(FemGui + ${CMAKE_SOURCE_DIR}/src/Mod/Fem + ${CMAKE_BINARY_DIR}/Mod/Fem + InitGui.py) if(MSVC) set_target_properties(FemGui PROPERTIES SUFFIX ".pyd") diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index cd58e9714e..f5bdf54dae 100755 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -55,7 +55,6 @@ #include #include "Hypothesis.h" -#include "TaskFemConstraint.h" using namespace std; @@ -87,35 +86,157 @@ bool CmdFemCreateFromShape::isActive(void) return Gui::Selection().countObjectsOfType(type) > 0; } -DEF_STD_CMD_A(CmdFemConstraint); +DEF_STD_CMD_A(CmdFemConstraintBearing); -CmdFemConstraint::CmdFemConstraint() - : Command("Fem_Constraint") +CmdFemConstraintBearing::CmdFemConstraintBearing() + : Command("Fem_ConstraintBearing") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); - sMenuText = QT_TR_NOOP("Create FEM constraint"); - sToolTipText = QT_TR_NOOP("Create FEM constraint"); + sMenuText = QT_TR_NOOP("Create FEM bearing constraint"); + sToolTipText = QT_TR_NOOP("Create FEM constraint for a bearing"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; - sPixmap = "Fem_Constraint"; + sPixmap = "Fem_ConstraintBearing"; } -void CmdFemConstraint::activated(int iMsg) +void CmdFemConstraintBearing::activated(int iMsg) { - std::string FeatName = getUniqueObjectName("FemConstraint"); + std::string FeatName = getUniqueObjectName("FemConstraintBearing"); - openCommand("Make FEM constraint"); - doCommand(Doc,"App.activeDocument().addObject(\"Fem::Constraint\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Force = 0.0",FeatName.c_str()); + openCommand("Make FEM constraint for bearing"); + doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintBearing\",\"%s\")",FeatName.c_str()); updateActive(); - Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(App::GetApplication().getActiveDocument()->getActiveObject()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } -bool CmdFemConstraint::isActive(void) +bool CmdFemConstraintBearing::isActive(void) +{ + return hasActiveDocument(); +} + +DEF_STD_CMD_A(CmdFemConstraintFixed); + +CmdFemConstraintFixed::CmdFemConstraintFixed() + : Command("Fem_ConstraintFixed") +{ + sAppModule = "Fem"; + sGroup = QT_TR_NOOP("Fem"); + sMenuText = QT_TR_NOOP("Create FEM fixed constraint"); + sToolTipText = QT_TR_NOOP("Create FEM constraint for a fixed geometric entity"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Fem_ConstraintFixed"; +} + +void CmdFemConstraintFixed::activated(int iMsg) +{ + std::string FeatName = getUniqueObjectName("FemConstraintFixed"); + + openCommand("Make FEM constraint fixed geometry"); + doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintFixed\",\"%s\")",FeatName.c_str()); + updateActive(); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +} + +bool CmdFemConstraintFixed::isActive(void) +{ + return hasActiveDocument(); +} + +DEF_STD_CMD_A(CmdFemConstraintForce); + +CmdFemConstraintForce::CmdFemConstraintForce() + : Command("Fem_ConstraintForce") +{ + sAppModule = "Fem"; + sGroup = QT_TR_NOOP("Fem"); + sMenuText = QT_TR_NOOP("Create FEM force constraint"); + sToolTipText = QT_TR_NOOP("Create FEM constraint for a force acting on a geometric entity"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Fem_ConstraintForce"; +} + +void CmdFemConstraintForce::activated(int iMsg) +{ + std::string FeatName = getUniqueObjectName("FemConstraintForce"); + + openCommand("Make FEM constraint force on geometry"); + doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintForce\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Force = 0.0",FeatName.c_str()); + updateActive(); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +} + +bool CmdFemConstraintForce::isActive(void) +{ + return hasActiveDocument(); +} + +DEF_STD_CMD_A(CmdFemConstraintGear); + +CmdFemConstraintGear::CmdFemConstraintGear() + : Command("Fem_ConstraintGear") +{ + sAppModule = "Fem"; + sGroup = QT_TR_NOOP("Fem"); + sMenuText = QT_TR_NOOP("Create FEM gear constraint"); + sToolTipText = QT_TR_NOOP("Create FEM constraint for a gear"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Fem_ConstraintGear"; +} + +void CmdFemConstraintGear::activated(int iMsg) +{ + std::string FeatName = getUniqueObjectName("FemConstraintGear"); + + openCommand("Make FEM constraint for gear"); + doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintGear\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Diameter = 100.0",FeatName.c_str()); + updateActive(); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +} + +bool CmdFemConstraintGear::isActive(void) +{ + return hasActiveDocument(); +} + +DEF_STD_CMD_A(CmdFemConstraintPulley); + +CmdFemConstraintPulley::CmdFemConstraintPulley() + : Command("Fem_ConstraintPulley") +{ + sAppModule = "Fem"; + sGroup = QT_TR_NOOP("Fem"); + sMenuText = QT_TR_NOOP("Create FEM pulley constraint"); + sToolTipText = QT_TR_NOOP("Create FEM constraint for a pulley"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Fem_ConstraintPulley"; +} + +void CmdFemConstraintPulley::activated(int iMsg) +{ + std::string FeatName = getUniqueObjectName("FemConstraintPulley"); + + openCommand("Make FEM constraint for pulley"); + doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintPulley\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Diameter = 100.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.OtherDiameter = 200.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.CenterDistance = 500.0",FeatName.c_str()); + updateActive(); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +} + +bool CmdFemConstraintPulley::isActive(void) { return hasActiveDocument(); } @@ -316,4 +437,9 @@ void CreateFemCommands(void) rcCmdMgr.addCommand(new CmdFemCreateNodesSet()); rcCmdMgr.addCommand(new CmdFemDefineNodesSet()); rcCmdMgr.addCommand(new CmdFemConstraint()); + rcCmdMgr.addCommand(new CmdFemConstraintBearing()); + rcCmdMgr.addCommand(new CmdFemConstraintFixed()); + rcCmdMgr.addCommand(new CmdFemConstraintForce()); + rcCmdMgr.addCommand(new CmdFemConstraintGear()); + rcCmdMgr.addCommand(new CmdFemConstraintPulley()); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraint.cpp b/src/Mod/Fem/Gui/TaskFemConstraint.cpp index b415eedebe..2a54ed9560 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraint.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraint.cpp @@ -43,7 +43,7 @@ #include "TaskFemConstraint.h" #include #include -#include +//#include #include #include #include @@ -61,430 +61,26 @@ using namespace Gui; /* TRANSLATOR FemGui::TaskFemConstraint */ -const QString makeRefText(const App::DocumentObject* obj, const std::string& subName) +TaskFemConstraint::TaskFemConstraint(ViewProviderFemConstraint *ConstraintView,QWidget *parent,const char* pixmapname) + : TaskBox(Gui::BitmapFactory().pixmap(pixmapname),tr("FEM constraint parameters"),true, parent),ConstraintView(ConstraintView) { - return QString::fromUtf8((std::string(obj->getNameInDocument()) + ":" + subName).c_str()); -} - -TaskFemConstraint::TaskFemConstraint(ViewProviderFemConstraint *ConstraintView,QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("Fem_Constraint"),tr("FEM constraint parameters"),true, parent),ConstraintView(ConstraintView) -{ - // we need a separate container widget to add all controls to - proxy = new QWidget(this); - ui = new Ui_TaskFemConstraint(); - ui->setupUi(proxy); - QMetaObject::connectSlotsByName(this); - - // Create a context menu for the listview of the references - QAction* action = new QAction(tr("Delete"), ui->listReferences); - action->connect(action, SIGNAL(triggered()), - this, SLOT(onReferenceDeleted())); - ui->listReferences->addAction(action); - ui->listReferences->setContextMenuPolicy(Qt::ActionsContextMenu); - - connect(ui->comboType, SIGNAL(currentIndexChanged(int)), - this, SLOT(onTypeChanged(int))); - connect(ui->spinForce, SIGNAL(valueChanged(double)), - this, SLOT(onForceChanged(double))); - connect(ui->buttonReference, SIGNAL(pressed()), - this, SLOT(onButtonReference())); - connect(ui->buttonDirection, SIGNAL(pressed()), - this, SLOT(onButtonDirection())); - connect(ui->checkReverse, SIGNAL(toggled(bool)), - this, SLOT(onCheckReverse(bool))); - connect(ui->buttonLocation, SIGNAL(pressed()), - this, SLOT(onButtonLocation())); - connect(ui->spinDistance, SIGNAL(valueChanged(double)), - this, SLOT(onDistanceChanged(double))); - connect(ui->spinDiameter, SIGNAL(valueChanged(double)), - this, SLOT(onDiameterChanged(double))); - connect(ui->spinOtherDia, SIGNAL(valueChanged(double)), - this, SLOT(onOtherDiameterChanged(double))); - connect(ui->spinCenterDistance, SIGNAL(valueChanged(double)), - this, SLOT(onCenterDistanceChanged(double))); - - this->groupLayout()->addWidget(proxy); - - // Temporarily prevent unnecessary feature recomputes - ui->comboType->blockSignals(true); - ui->spinForce->blockSignals(true); - ui->listReferences->blockSignals(true); - ui->buttonReference->blockSignals(true); - ui->buttonDirection->blockSignals(true); - ui->checkReverse->blockSignals(true); - ui->buttonLocation->blockSignals(true); - ui->spinDistance->blockSignals(true); - ui->spinDiameter->blockSignals(true); - ui->spinOtherDia->blockSignals(true); - ui->spinCenterDistance->blockSignals(true); - - // Get the feature data - Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); - int index = pcConstraint->Type.getValue(); - double f = pcConstraint->Force.getValue(); - std::vector Objects = pcConstraint->References.getValues(); - std::vector SubElements = pcConstraint->References.getSubValues(); - std::vector dirStrings = pcConstraint->Direction.getSubValues(); - QString dir; - if (!dirStrings.empty()) - dir = makeRefText(pcConstraint->Direction.getValue(), dirStrings.front()); - bool reversed = pcConstraint->Reversed.getValue(); - std::vector locStrings = pcConstraint->Location.getSubValues(); - QString loc; - if (!locStrings.empty()) - loc = makeRefText(pcConstraint->Location.getValue(), locStrings.front()); - double d = pcConstraint->Distance.getValue(); - double dia = pcConstraint->Diameter.getValue(); - double otherdia = pcConstraint->OtherDiameter.getValue(); - double centerdist = pcConstraint->CenterDistance.getValue(); - - // Fill data into dialog elements - ui->comboType->clear(); - ui->comboType->insertItem(0, tr("Force on geometry")); - ui->comboType->insertItem(1, tr("Fixed")); - ui->comboType->insertItem(2, tr("Bearing (axial free)")); - ui->comboType->insertItem(3, tr("Bearing (axial fixed)")); - ui->comboType->insertItem(4, tr("Pulley")); - ui->comboType->insertItem(5, tr("Gear (straight toothed)")); - ui->comboType->setCurrentIndex(index); - ui->spinForce->setMinimum(0); - ui->spinForce->setMaximum(INT_MAX); - ui->spinForce->setValue(f); - ui->listReferences->clear(); - - for (int i = 0; i < Objects.size(); i++) - ui->listReferences->addItem(makeRefText(Objects[i], SubElements[i])); - if (Objects.size() > 0) - ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); - ui->lineDirection->setText(dir.isEmpty() ? tr("") : dir); - ui->checkReverse->setChecked(reversed); - ui->lineDirection->setText(loc.isEmpty() ? tr("") : loc); - ui->spinDistance->setMinimum(INT_MIN); - ui->spinDistance->setMaximum(INT_MAX); - ui->spinDistance->setValue(d); - ui->spinDiameter->setMinimum(0); - ui->spinDiameter->setMaximum(INT_MAX); - ui->spinDiameter->setValue(dia); - ui->spinOtherDia->setMinimum(0); - ui->spinOtherDia->setMaximum(INT_MAX); - ui->spinOtherDia->setValue(otherdia); - ui->spinCenterDistance->setMinimum(0); - ui->spinCenterDistance->setMaximum(INT_MAX); - ui->spinCenterDistance->setValue(centerdist); - - // activate and de-activate dialog elements as appropriate - ui->comboType->blockSignals(false); - ui->spinForce->blockSignals(false); - ui->listReferences->blockSignals(false); - ui->buttonReference->blockSignals(false); - ui->buttonDirection->blockSignals(false); - ui->checkReverse->blockSignals(false); - ui->buttonLocation->blockSignals(false); - ui->spinDistance->blockSignals(false); - ui->spinDiameter->blockSignals(false); - ui->spinOtherDia->blockSignals(false); - ui->spinCenterDistance->blockSignals(false); - selectionMode = selref; - updateUI(); } -void TaskFemConstraint::updateUI() +const std::string TaskFemConstraint::getReferences(const std::vector& items) const { - if (ui->comboType->currentIndex() == 0) { - ui->labelForce->setVisible(true); - ui->spinForce->setVisible(true); - ui->buttonDirection->setVisible(true); - ui->lineDirection->setVisible(true); - ui->checkReverse->setVisible(true); - ui->buttonLocation->setVisible(false); - ui->lineLocation->setVisible(false); - ui->labelDistance->setVisible(false); - ui->spinDistance->setVisible(false); - ui->labelDiameter->setVisible(false); - ui->spinDiameter->setVisible(false); - ui->labelOtherDia->setVisible(false); - ui->spinOtherDia->setVisible(false); - ui->labelCenterDistance->setVisible(false); - ui->spinCenterDistance->setVisible(false); - } else if (ui->comboType->currentIndex() == 1) { - ui->labelForce->setVisible(false); - ui->spinForce->setVisible(false); - ui->buttonDirection->setVisible(false); - ui->lineDirection->setVisible(false); - ui->checkReverse->setVisible(false); - ui->buttonLocation->setVisible(false); - ui->lineLocation->setVisible(false); - ui->labelDistance->setVisible(false); - ui->spinDistance->setVisible(false); - ui->labelDiameter->setVisible(false); - ui->spinDiameter->setVisible(false); - ui->labelOtherDia->setVisible(false); - ui->spinOtherDia->setVisible(false); - ui->labelCenterDistance->setVisible(false); - ui->spinCenterDistance->setVisible(false); - } else if ((ui->comboType->currentIndex() == 2) || (ui->comboType->currentIndex() == 3)) { - ui->labelForce->setVisible(false); - ui->spinForce->setVisible(false); - ui->buttonDirection->setVisible(false); - ui->lineDirection->setVisible(false); - ui->checkReverse->setVisible(false); - ui->buttonLocation->setVisible(true); - ui->lineLocation->setVisible(true); - ui->labelDistance->setVisible(true); - ui->spinDistance->setVisible(true); - ui->labelDiameter->setVisible(false); - ui->spinDiameter->setVisible(false); - ui->labelOtherDia->setVisible(false); - ui->spinOtherDia->setVisible(false); - ui->labelCenterDistance->setVisible(false); - ui->spinCenterDistance->setVisible(false); - } else if (ui->comboType->currentIndex() == 4) { - ui->labelForce->setVisible(false); - ui->spinForce->setVisible(false); - ui->buttonDirection->setVisible(false); - ui->lineDirection->setVisible(false); - ui->checkReverse->setVisible(false); - ui->buttonLocation->setVisible(true); - ui->lineLocation->setVisible(true); - ui->labelDistance->setVisible(true); - ui->spinDistance->setVisible(true); - ui->labelDiameter->setVisible(true); - ui->spinDiameter->setVisible(true); - ui->labelOtherDia->setVisible(true); - ui->spinOtherDia->setVisible(true); - ui->labelCenterDistance->setVisible(true); - ui->spinCenterDistance->setVisible(true); - } else if (ui->comboType->currentIndex() == 5) { - ui->labelForce->setVisible(false); - ui->spinForce->setVisible(false); - ui->buttonDirection->setVisible(false); - ui->lineDirection->setVisible(false); - ui->checkReverse->setVisible(false); - ui->buttonLocation->setVisible(true); - ui->lineLocation->setVisible(true); - ui->labelDistance->setVisible(true); - ui->spinDistance->setVisible(true); - ui->labelDiameter->setVisible(true); - ui->spinDiameter->setVisible(true); - ui->labelOtherDia->setVisible(true); - ui->spinOtherDia->setVisible(true); - ui->labelCenterDistance->setVisible(false); - ui->spinCenterDistance->setVisible(false); + std::string result; + for (std::vector::const_iterator i = items.begin(); i != items.end(); i++) { + int pos = i->find_last_of(":"); + std::string objStr = "App.ActiveDocument." + i->substr(0, pos); + std::string refStr = "\"" + i->substr(pos+1) + "\""; + result = result + (i != items.begin() ? ", " : "") + "(" + objStr + "," + refStr + ")"; } - if (ui->listReferences->model()->rowCount() == 0) { - // Go into reference selection mode if no reference has been selected yet - onButtonReference(true); - return; - } - - if (ui->comboType->currentIndex() == 0) { - std::string ref = ui->listReferences->item(0)->text().toStdString(); - int pos = ref.find_last_of(":"); - if (ref.substr(pos+1, 6) == "Vertex") - ui->labelForce->setText(tr("Force [N]")); - else if (ref.substr(pos+1, 4) == "Edge") - ui->labelForce->setText(tr("Force [N/mm]")); - else if (ref.substr(pos+1, 4) == "Face") - ui->labelForce->setText(tr("Force [N/mm²]")); - } + return result; } -void TaskFemConstraint::onSelectionChanged(const Gui::SelectionChanges& msg) -{ - if (msg.Type == Gui::SelectionChanges::AddSelection) { - // Don't allow selection in other document - if (strcmp(msg.pDocName, ConstraintView->getObject()->getDocument()->getName()) != 0) - return; - - if (!msg.pSubName || msg.pSubName[0] == '\0') - return; - std::string subName(msg.pSubName); - - if (selectionMode == selnone) - return; - - std::vector references(1,subName); - Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); - App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(msg.pObjectName); - //if (!obj->getClassTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - // return; - Part::Feature* feat = static_cast(obj); - TopoDS_Shape ref = feat->Shape.getShape().getSubShape(subName.c_str()); - - if (selectionMode == selref) { - std::vector Objects = pcConstraint->References.getValues(); - std::vector SubElements = pcConstraint->References.getSubValues(); - - if (pcConstraint->Type.getValue() == 0) { - // Force on geometry elements: - // Ensure we don't have mixed reference types - if (SubElements.size() > 0) { - if (subName.substr(0,4) != SubElements.front().substr(0,4)) { - QMessageBox::warning(this, tr("Selection error"), tr("Mixed shape types are not possible. Use a second constraint instead")); - return; - } - } else { - if ((subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge") && (subName.substr(0,6) != "Vertex")) { - QMessageBox::warning(this, tr("Selection error"), tr("Only faces, edges and vertices can be picked")); - return; - } - } - - // Avoid duplicates - int pos = 0; - for (; pos < Objects.size(); pos++) - if (obj == Objects[pos]) - break; - - if (pos != Objects.size()) - if (subName == SubElements[pos]) - return; - } else if (pcConstraint->Type.getValue() == 1) { - // Fixed - if ((subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge") && (subName.substr(0,6) != "Vertex")) { - QMessageBox::warning(this, tr("Selection error"), tr("Mixed shape types are not possible. Use a second constraint instead")); - return; - } - - // Avoid duplicates - int pos = 0; - for (; pos < Objects.size(); pos++) - if (obj == Objects[pos]) - break; - - if (pos != Objects.size()) - if (subName == SubElements[pos]) - return; - } else if ((pcConstraint->Type.getValue() >= 2) && (pcConstraint->Type.getValue() <= 5)) { - // Bearing, pulley, gear - if (Objects.size() > 0) { - QMessageBox::warning(this, tr("Selection error"), tr("Please use only a single reference for bearing constraint")); - return; - } - // Only cylindrical faces allowed - if (subName.substr(0,4) != "Face") { - QMessageBox::warning(this, tr("Selection error"), tr("Only faces can be picked")); - return; - } - - BRepAdaptor_Surface surface(TopoDS::Face(ref)); - if (surface.GetType() != GeomAbs_Cylinder) { - QMessageBox::warning(this, tr("Selection error"), tr("Only cylindrical faces can be picked")); - return; - } - } else { - return; - } - - // add the new reference - Objects.push_back(obj); - SubElements.push_back(subName); - pcConstraint->References.setValues(Objects,SubElements); - ui->listReferences->addItem(makeRefText(obj, subName)); - - // Turn off reference selection mode - onButtonReference(false); - } else if ((selectionMode == seldir) || (selectionMode == selloc)) { - if (subName.substr(0,4) == "Face") { - BRepAdaptor_Surface surface(TopoDS::Face(ref)); - if (surface.GetType() != GeomAbs_Plane) { - QMessageBox::warning(this, tr("Selection error"), tr("Only planar faces can be picked")); - return; - } - } else if (subName.substr(0,4) == "Edge") { - BRepAdaptor_Curve line(TopoDS::Edge(ref)); - if (line.GetType() != GeomAbs_Line) { - QMessageBox::warning(this, tr("Selection error"), tr("Only linear edges can be picked")); - return; - } - } else { - QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked")); - return; - } - if (selectionMode == seldir) { - pcConstraint->Direction.setValue(obj, references); - ui->lineDirection->setText(makeRefText(obj, subName)); - - // Turn off direction selection mode - onButtonDirection(false); - } else { - pcConstraint->Location.setValue(obj, references); - ui->lineLocation->setText(makeRefText(obj, subName)); - - // Turn off direction selection mode - onButtonLocation(false); - } - } - updateUI(); - } -} - -void TaskFemConstraint::onTypeChanged(int index) -{ - Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); - int oldType = pcConstraint->Type.getValue(); - pcConstraint->Type.setValue(index); - - if (((oldType == 2) && (index == 3)) || ((oldType == 3) && (index == 2))) { - pcConstraint->References.touch(); // Update visual - updateUI(); - } else { - // Clear all references if the old and new type mismatch - std::vector Objects = pcConstraint->References.getValues(); - std::vector SubElements = pcConstraint->References.getSubValues(); - - Objects.clear(); - SubElements.clear(); - pcConstraint->References.setValues(Objects, SubElements); - - ui->listReferences->clear(); //model()->removeRows(0, ui->listReferences->model()->rowCount()); - updateUI(); - } -} - -void TaskFemConstraint::onForceChanged(double f) -{ - Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); - pcConstraint->Force.setValue((float)f); -} - -void TaskFemConstraint::onDistanceChanged(double f) -{ - Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); - pcConstraint->Distance.setValue((float)f); -} - -void TaskFemConstraint::onDiameterChanged(double f) -{ - Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); - pcConstraint->Diameter.setValue((float)f); -} - -void TaskFemConstraint::onOtherDiameterChanged(double f) -{ - Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); - pcConstraint->OtherDiameter.setValue((float)f); -} - -void TaskFemConstraint::onCenterDistanceChanged(double d) -{ - Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); - pcConstraint->CenterDistance.setValue((float)d); -} - -void TaskFemConstraint::onButtonReference(const bool pressed) { - if (pressed) - selectionMode = selref; - else - selectionMode = selnone; - ui->buttonReference->setChecked(pressed); - Gui::Selection().clearSelection(); -} - -void TaskFemConstraint::onReferenceDeleted() { - int row = ui->listReferences->currentIndex().row(); +void TaskFemConstraint::onReferenceDeleted(const int row) { Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); std::vector Objects = pcConstraint->References.getValues(); std::vector SubElements = pcConstraint->References.getSubValues(); @@ -492,156 +88,20 @@ void TaskFemConstraint::onReferenceDeleted() { Objects.erase(Objects.begin() + row); SubElements.erase(SubElements.begin() + row); pcConstraint->References.setValues(Objects, SubElements); - - ui->listReferences->model()->removeRow(row); - ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); } -void TaskFemConstraint::onButtonDirection(const bool pressed) { - if (pressed) { - selectionMode = seldir; - } else { +void TaskFemConstraint::onButtonReference(const bool pressed) { + if (pressed) + selectionMode = selref; + else selectionMode = selnone; - } - ui->buttonDirection->setChecked(pressed); + //ui->buttonReference->setChecked(pressed); Gui::Selection().clearSelection(); } -void TaskFemConstraint::onButtonLocation(const bool pressed) { - if (pressed) { - selectionMode = selloc; - } else { - selectionMode = selnone; - } - ui->buttonLocation->setChecked(pressed); - Gui::Selection().clearSelection(); -} - -void TaskFemConstraint::onCheckReverse(const bool pressed) +const QString TaskFemConstraint::makeRefText(const App::DocumentObject* obj, const std::string& subName) const { - Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); - pcConstraint->Reversed.setValue(pressed); -} - -int TaskFemConstraint::getType(void) const -{ - return ui->comboType->currentIndex(); -} - -double TaskFemConstraint::getForce(void) const -{ - return ui->spinForce->value(); -} - -double TaskFemConstraint::getDistance(void) const -{ - return ui->spinDistance->value(); -} - -double TaskFemConstraint::getDiameter(void) const -{ - return ui->spinDiameter->value(); -} - -double TaskFemConstraint::getOtherDiameter(void) const -{ - return ui->spinOtherDia->value(); -} - -double TaskFemConstraint::getCenterDistance(void) const -{ - return ui->spinCenterDistance->value(); -} - -const std::string TaskFemConstraint::getReferences(void) const -{ - int rows = ui->listReferences->model()->rowCount(); - if (rows == 0) - return ""; - - std::string result; - for (int r = 0; r < rows; r++) { - std::string item = ui->listReferences->item(r)->text().toStdString(); - int pos = item.find_last_of(":"); - std::string objStr = "App.ActiveDocument." + item.substr(0, pos); - std::string refStr = "\"" + item.substr(pos+1) + "\""; - result = result + (r > 0 ? ", " : "") + "(" + objStr + "," + refStr + ")"; - } - - return result; -} - -const std::string TaskFemConstraint::getDirectionName(void) const -{ - std::string dir = ui->lineDirection->text().toStdString(); - if (dir.empty()) - return ""; - - int pos = dir.find_last_of(":"); - return dir.substr(0, pos).c_str(); -} - -const std::string TaskFemConstraint::getDirectionObject(void) const -{ - std::string dir = ui->lineDirection->text().toStdString(); - if (dir.empty()) - return ""; - - int pos = dir.find_last_of(":"); - return dir.substr(pos+1).c_str(); -} - -const std::string TaskFemConstraint::getLocationName(void) const -{ - std::string loc = ui->lineLocation->text().toStdString(); - if (loc.empty()) - return ""; - - int pos = loc.find_last_of(":"); - return loc.substr(0, pos).c_str(); -} - -const std::string TaskFemConstraint::getLocationObject(void) const -{ - std::string loc = ui->lineLocation->text().toStdString(); - if (loc.empty()) - return ""; - - int pos = loc.find_last_of(":"); - return loc.substr(pos+1).c_str(); -} - -bool TaskFemConstraint::getReverse() const -{ - return ui->checkReverse->isChecked(); -} - -TaskFemConstraint::~TaskFemConstraint() -{ - delete ui; -} - -void TaskFemConstraint::changeEvent(QEvent *e) -{ - TaskBox::changeEvent(e); - if (e->type() == QEvent::LanguageChange) { - ui->comboType->blockSignals(true); - ui->spinForce->blockSignals(true); - ui->spinDistance->blockSignals(true); - int index = ui->comboType->currentIndex(); - ui->comboType->clear(); - ui->comboType->insertItem(0, tr("Force on geometry")); - ui->comboType->insertItem(1, tr("Fixed")); - ui->comboType->insertItem(2, tr("Bearing (axial free)")); - ui->comboType->insertItem(3, tr("Bearing (axial fixed)")); - ui->comboType->insertItem(4, tr("Pulley")); - ui->comboType->insertItem(5, tr("Gear (straight toothed)")); - ui->comboType->setCurrentIndex(index); - ui->retranslateUi(proxy); - ui->comboType->blockSignals(false); - ui->spinForce->blockSignals(false); - ui->spinDistance->blockSignals(false); - } + return QString::fromUtf8((std::string(obj->getNameInDocument()) + ":" + subName).c_str()); } //************************************************************************** @@ -649,41 +109,14 @@ void TaskFemConstraint::changeEvent(QEvent *e) // TaskDialog //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -TaskDlgFemConstraint::TaskDlgFemConstraint(ViewProviderFemConstraint *ConstraintView) - : TaskDialog(),ConstraintView(ConstraintView) -{ - assert(ConstraintView); - parameter = new TaskFemConstraint(ConstraintView); - - Content.push_back(parameter); -} - -TaskDlgFemConstraint::~TaskDlgFemConstraint() -{ - -} - //==== calls from the TaskView =============================================================== -void TaskDlgFemConstraint::open() -{ - -} - -void TaskDlgFemConstraint::clicked(int) -{ - -} - bool TaskDlgFemConstraint::accept() { std::string name = ConstraintView->getObject()->getNameInDocument(); try { - //Gui::Command::openCommand("FEM constraint changed"); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getType()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Force = %f",name.c_str(),parameter->getForce()); std::string refs = parameter->getReferences(); if (!refs.empty()) { @@ -693,37 +126,6 @@ bool TaskDlgFemConstraint::accept() return false; } - std::string dirname = parameter->getDirectionName().data(); - std::string dirobj = parameter->getDirectionObject().data(); - - if (!dirname.empty()) { - QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromStdString(dirname)); - buf = buf.arg(QString::fromStdString(dirobj)); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = %s", name.c_str(), buf.toStdString().c_str()); - } else { - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str()); - } - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %s", name.c_str(), parameter->getReverse() ? "True" : "False"); - - std::string locname = parameter->getLocationName().data(); - std::string locobj = parameter->getLocationObject().data(); - - if (!locname.empty()) { - QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromStdString(locname)); - buf = buf.arg(QString::fromStdString(locobj)); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Location = %s", name.c_str(), buf.toStdString().c_str()); - } else { - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str()); - } - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Distance = %f",name.c_str(),parameter->getDistance()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Diameter = %f",name.c_str(),parameter->getDiameter()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.OtherDiameter = %f",name.c_str(),parameter->getOtherDiameter()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.CenterDistance = %f",name.c_str(),parameter->getCenterDistance()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); if (!ConstraintView->getObject()->isValid()) throw Base::Exception(ConstraintView->getObject()->getStatusString()); @@ -740,7 +142,7 @@ bool TaskDlgFemConstraint::accept() bool TaskDlgFemConstraint::reject() { - // roll back the done things + // roll back the changes Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); @@ -748,5 +150,4 @@ bool TaskDlgFemConstraint::reject() } - #include "moc_TaskFemConstraint.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraint.h b/src/Mod/Fem/Gui/TaskFemConstraint.h index d27da19839..f4d7ee0bde 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraint.h +++ b/src/Mod/Fem/Gui/TaskFemConstraint.h @@ -29,9 +29,7 @@ #include #include "ViewProviderFemConstraint.h" - -class Ui_TaskFemConstraint; - +/* namespace App { class Property; } @@ -39,7 +37,7 @@ class Property; namespace Gui { class ViewProvider; } - +*/ namespace FemGui { class TaskFemConstraint : public Gui::TaskView::TaskBox, public Gui::SelectionObserver @@ -47,45 +45,25 @@ class TaskFemConstraint : public Gui::TaskView::TaskBox, public Gui::SelectionOb Q_OBJECT public: - TaskFemConstraint(ViewProviderFemConstraint *ConstraintView,QWidget *parent = 0); - ~TaskFemConstraint(); + TaskFemConstraint(ViewProviderFemConstraint *ConstraintView,QWidget *parent = 0,const char* pixmapname = ""); + virtual ~TaskFemConstraint() {} - int getType(void) const; - double getForce(void) const; - const std::string getReferences(void) const; - const std::string getDirectionName(void) const; - const std::string getDirectionObject(void) const; - const std::string getLocationName(void) const; - const std::string getLocationObject(void) const; - double getDistance(void) const; - bool getReverse(void) const; - double getDiameter(void) const; - double getOtherDiameter(void) const; - double getCenterDistance(void) const; + virtual const std::string getReferences(void) const {} + const std::string getReferences(const std::vector& items) const; -private Q_SLOTS: - void onTypeChanged(int); - void onReferenceDeleted(); - void onForceChanged(double); +protected Q_SLOTS: + void onReferenceDeleted(const int row); void onButtonReference(const bool pressed = true); - void onButtonDirection(const bool pressed = true); - void onButtonLocation(const bool pressed = true); - void onDistanceChanged(double); - void onCheckReverse(bool); - void onDiameterChanged(double); - void onOtherDiameterChanged(double); - void onCenterDistanceChanged(double); protected: - void changeEvent(QEvent *e); + virtual void changeEvent(QEvent *e) {} + const QString makeRefText(const App::DocumentObject* obj, const std::string& subName) const; private: - void onSelectionChanged(const Gui::SelectionChanges& msg); - void updateUI(); + virtual void onSelectionChanged(const Gui::SelectionChanges& msg) {} -private: +protected: QWidget* proxy; - Ui_TaskFemConstraint* ui; ViewProviderFemConstraint *ConstraintView; enum {seldir, selref, selloc, selnone} selectionMode; }; @@ -95,19 +73,11 @@ class TaskDlgFemConstraint : public Gui::TaskView::TaskDialog { Q_OBJECT -public: - TaskDlgFemConstraint(ViewProviderFemConstraint *ConstraintView); - ~TaskDlgFemConstraint(); - - ViewProviderFemConstraint* getConstraintView() const - { return ConstraintView; } - - public: /// is called the TaskView when the dialog is opened - virtual void open(); + virtual void open() {} /// is called by the framework if an button is clicked which has no accept or reject role - virtual void clicked(int); + virtual void clicked(int) {} /// is called by the framework if the dialog is accepted (Ok) virtual bool accept(); /// is called by the framework if the dialog is rejected (Cancel) @@ -120,9 +90,11 @@ public: virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } -protected: - ViewProviderFemConstraint *ConstraintView; + ViewProviderFemConstraint* getConstraintView() const + { return ConstraintView; } +protected: + ViewProviderFemConstraint *ConstraintView; TaskFemConstraint *parameter; }; diff --git a/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp b/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp new file mode 100644 index 0000000000..cf5b4374f0 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp @@ -0,0 +1,345 @@ +/*************************************************************************** + * 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 +# include +# include +# include +# include +# include +# include +#endif + +#include "ui_TaskFemConstraintCylindrical.h" +#include "TaskFemConstraintBearing.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace FemGui; +using namespace Gui; + +/* TRANSLATOR FemGui::TaskFemConstraintBearing */ + +TaskFemConstraintBearing::TaskFemConstraintBearing(ViewProviderFemConstraint *ConstraintView,QWidget *parent, const char *pixmapname) + : TaskFemConstraint(ConstraintView, parent, pixmapname) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskFemConstraintCylindrical(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + // Create a context menu for the listview of the references + QAction* action = new QAction(tr("Delete"), ui->listReferences); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onReferenceDeleted())); + ui->listReferences->addAction(action); + ui->listReferences->setContextMenuPolicy(Qt::ActionsContextMenu); + + connect(ui->spinDistance, SIGNAL(valueChanged(double)), + this, SLOT(onDistanceChanged(double))); + connect(ui->buttonReference, SIGNAL(pressed()), + this, SLOT(onButtonReference())); + connect(ui->buttonLocation, SIGNAL(pressed()), + this, SLOT(onButtonLocation())); + connect(ui->checkAxial, SIGNAL(toggled(bool)), + this, SLOT(onCheckAxial(bool))); + + this->groupLayout()->addWidget(proxy); + + // Temporarily prevent unnecessary feature recomputes + ui->spinDistance->blockSignals(true); + ui->listReferences->blockSignals(true); + ui->buttonReference->blockSignals(true); + ui->buttonLocation->blockSignals(true); + ui->checkAxial->blockSignals(true); + + // Get the feature data + Fem::ConstraintBearing* pcConstraint = static_cast(ConstraintView->getObject()); + double d = pcConstraint->Dist.getValue(); + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + std::vector locStrings = pcConstraint->Location.getSubValues(); + QString loc; + if (!locStrings.empty()) + loc = makeRefText(pcConstraint->Location.getValue(), locStrings.front()); + bool axialfree = pcConstraint->AxialFree.getValue(); + + // Fill data into dialog elements + ui->spinDistance->setMinimum(INT_MIN); + ui->spinDistance->setMaximum(INT_MAX); + ui->spinDistance->setValue(d); + ui->listReferences->clear(); + for (int i = 0; i < Objects.size(); i++) + ui->listReferences->addItem(makeRefText(Objects[i], SubElements[i])); + if (Objects.size() > 0) + ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); + ui->lineLocation->setText(loc); + ui->checkAxial->setChecked(axialfree); + + // Adjust ui to constraint type + ui->labelDiameter->setVisible(false); + ui->spinDiameter->setVisible(false); + ui->labelOtherDiameter->setVisible(false); + ui->spinOtherDiameter->setVisible(false); + ui->labelCenterDistance->setVisible(false); + ui->spinCenterDistance->setVisible(false); + + ui->spinDistance->blockSignals(false); + ui->listReferences->blockSignals(false); + ui->buttonReference->blockSignals(false); + ui->buttonLocation->blockSignals(false); + ui->checkAxial->blockSignals(false); + + onButtonReference(true); +} + +void TaskFemConstraintBearing::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + // Don't allow selection in other document + if (strcmp(msg.pDocName, ConstraintView->getObject()->getDocument()->getName()) != 0) + return; + + if (!msg.pSubName || msg.pSubName[0] == '\0') + return; + std::string subName(msg.pSubName); + + if (selectionMode == selnone) + return; + + std::vector references(1,subName); + Fem::ConstraintBearing* pcConstraint = static_cast(ConstraintView->getObject()); + App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(msg.pObjectName); + Part::Feature* feat = static_cast(obj); + TopoDS_Shape ref = feat->Shape.getShape().getSubShape(subName.c_str()); + + if (selectionMode == selref) { + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + if (Objects.size() > 0) { + QMessageBox::warning(this, tr("Selection error"), tr("Please use only a single reference for bearing constraint")); + return; + } + // Only cylindrical faces allowed + if (subName.substr(0,4) != "Face") { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces can be picked")); + return; + } + + BRepAdaptor_Surface surface(TopoDS::Face(ref)); + if (surface.GetType() != GeomAbs_Cylinder) { + QMessageBox::warning(this, tr("Selection error"), tr("Only cylindrical faces can be picked")); + return; + } + + // add the new reference + Objects.push_back(obj); + SubElements.push_back(subName); + pcConstraint->References.setValues(Objects,SubElements); + ui->listReferences->addItem(makeRefText(obj, subName)); + + // Turn off reference selection mode + onButtonReference(false); + } else if (selectionMode == selloc) { + if (subName.substr(0,4) == "Face") { + BRepAdaptor_Surface surface(TopoDS::Face(ref)); + if (surface.GetType() != GeomAbs_Plane) { + QMessageBox::warning(this, tr("Selection error"), tr("Only planar faces can be picked")); + return; + } + } else if (subName.substr(0,4) == "Edge") { + BRepAdaptor_Curve line(TopoDS::Edge(ref)); + if (line.GetType() != GeomAbs_Line) { + QMessageBox::warning(this, tr("Selection error"), tr("Only linear edges can be picked")); + return; + } + } else { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked")); + return; + } + pcConstraint->Location.setValue(obj, references); + ui->lineLocation->setText(makeRefText(obj, subName)); + + // Turn off location selection mode + onButtonLocation(false); + } + + Gui::Selection().clearSelection(); + } +} + +void TaskFemConstraintBearing::onDistanceChanged(double l) +{ + Fem::ConstraintBearing* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Dist.setValue((float)l); +} + +void TaskFemConstraintBearing::onReferenceDeleted() { + int row = ui->listReferences->currentIndex().row(); + TaskFemConstraint::onReferenceDeleted(row); + ui->listReferences->model()->removeRow(row); + ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); +} + +void TaskFemConstraintBearing::onButtonLocation(const bool pressed) { + if (pressed) { + selectionMode = selloc; + } else { + selectionMode = selnone; + } + ui->buttonLocation->setChecked(pressed); + Gui::Selection().clearSelection(); +} + +void TaskFemConstraintBearing::onCheckAxial(const bool pressed) +{ + Fem::ConstraintBearing* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->AxialFree.setValue(pressed); +} + +double TaskFemConstraintBearing::getDistance(void) const +{ + return ui->spinDistance->value(); +} + +const std::string TaskFemConstraintBearing::getReferences() const +{ + int rows = ui->listReferences->model()->rowCount(); + + std::vector items; + for (int r = 0; r < rows; r++) + items.push_back(ui->listReferences->item(r)->text().toStdString()); + return TaskFemConstraint::getReferences(items); +} + +const std::string TaskFemConstraintBearing::getLocationName(void) const +{ + std::string loc = ui->lineLocation->text().toStdString(); + if (loc.empty()) + return ""; + + int pos = loc.find_last_of(":"); + return loc.substr(0, pos).c_str(); +} + +const std::string TaskFemConstraintBearing::getLocationObject(void) const +{ + std::string loc = ui->lineLocation->text().toStdString(); + if (loc.empty()) + return ""; + + int pos = loc.find_last_of(":"); + return loc.substr(pos+1).c_str(); +} + +bool TaskFemConstraintBearing::getAxial() const +{ + return ui->checkAxial->isChecked(); +} + +TaskFemConstraintBearing::~TaskFemConstraintBearing() +{ + delete ui; +} + +void TaskFemConstraintBearing::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->spinDistance->blockSignals(true); + ui->retranslateUi(proxy); + ui->spinDistance->blockSignals(false); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraintBearing::TaskDlgFemConstraintBearing(ViewProviderFemConstraintBearing *ConstraintView) +{ + this->ConstraintView = ConstraintView; + assert(ConstraintView); + this->parameter = new TaskFemConstraintBearing(ConstraintView); + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +bool TaskDlgFemConstraintBearing::accept() +{ + std::string name = ConstraintView->getObject()->getNameInDocument(); + const TaskFemConstraintBearing* parameterBearing = static_cast(parameter); + + try { + //Gui::Command::openCommand("FEM force constraint changed"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Dist = %f",name.c_str(), parameterBearing->getDistance()); + + std::string locname = parameterBearing->getLocationName().data(); + std::string locobj = parameterBearing->getLocationObject().data(); + + if (!locname.empty()) { + QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); + buf = buf.arg(QString::fromStdString(locname)); + buf = buf.arg(QString::fromStdString(locobj)); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Location = %s", name.c_str(), buf.toStdString().c_str()); + } else { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Location = None", name.c_str()); + } + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.AxialFree = %s", name.c_str(), parameterBearing->getAxial() ? "True" : "False"); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromAscii(e.what())); + return false; + } + + return TaskDlgFemConstraint::accept(); +} + +#include "moc_TaskFemConstraintBearing.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintBearing.h b/src/Mod/Fem/Gui/TaskFemConstraintBearing.h new file mode 100644 index 0000000000..671d114b44 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintBearing.h @@ -0,0 +1,93 @@ +/*************************************************************************** + * 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 GUI_TASKVIEW_TaskFemConstraintBearing_H +#define GUI_TASKVIEW_TaskFemConstraintBearing_H + +#include +#include +#include + +#include "TaskFemConstraint.h" +#include "ViewProviderFemConstraintBearing.h" + +class Ui_TaskFemConstraintCylindrical; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace FemGui { + +class TaskFemConstraintBearing : public TaskFemConstraint +{ + Q_OBJECT + +public: + TaskFemConstraintBearing(ViewProviderFemConstraint *ConstraintView, QWidget *parent = 0, + const char* pixmapname = "Fem_ConstraintBearing"); + virtual ~TaskFemConstraintBearing(); + + double getDistance(void) const; + virtual const std::string getReferences() const; + const std::string getLocationName(void) const; + const std::string getLocationObject(void) const; + bool getAxial(void) const; + +private Q_SLOTS: + void onReferenceDeleted(void); + void onDistanceChanged(double l); + void onButtonLocation(const bool pressed = true); + void onCheckAxial(bool); + +protected: + virtual void changeEvent(QEvent *e); + +private: + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + +protected: + Ui_TaskFemConstraintCylindrical* ui; +}; + +/// simulation dialog for the TaskView +class TaskDlgFemConstraintBearing : public TaskDlgFemConstraint +{ + Q_OBJECT + +public: + TaskDlgFemConstraintBearing() {} + TaskDlgFemConstraintBearing(ViewProviderFemConstraintBearing *ConstraintView); + + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + +}; + +} //namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraintBearing_H diff --git a/src/Mod/Fem/Gui/TaskFemConstraintCylindrical.ui b/src/Mod/Fem/Gui/TaskFemConstraintCylindrical.ui new file mode 100644 index 0000000000..c0ee3cb291 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintCylindrical.ui @@ -0,0 +1,161 @@ + + + TaskFemConstraintCylindrical + + + + 0 + 0 + 257 + 338 + + + + Form + + + + + + Add reference + + + + + + + + + + + + Gear diameter + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 100.000000000000000 + + + + + + + + + + + Other diameter + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 200.000000000000000 + + + + + + + + + + + Center distance + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 500.000000000000000 + + + + + + + + + + + Location + + + + + + + + + + + + + + Distance + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 0.000000000000000 + + + + + + + + + Qt::Vertical + + + + 17 + 56 + + + + + + + + Axial free + + + + + + + + diff --git a/src/Mod/Fem/Gui/TaskFemConstraintFixed.cpp b/src/Mod/Fem/Gui/TaskFemConstraintFixed.cpp new file mode 100644 index 0000000000..cc9ad5217e --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintFixed.cpp @@ -0,0 +1,217 @@ +/*************************************************************************** + * 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 +# include +# include +# include +# include +# include +# include +#endif + +#include "ui_TaskFemConstraintFixed.h" +#include "TaskFemConstraintFixed.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace FemGui; +using namespace Gui; + +/* TRANSLATOR FemGui::TaskFemConstraintFixed */ + +TaskFemConstraintFixed::TaskFemConstraintFixed(ViewProviderFemConstraintFixed *ConstraintView,QWidget *parent) + : TaskFemConstraint(ConstraintView, parent, "Fem_ConstraintFixed") +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskFemConstraintFixed(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + // Create a context menu for the listview of the references + QAction* action = new QAction(tr("Delete"), ui->listReferences); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onReferenceDeleted())); + ui->listReferences->addAction(action); + ui->listReferences->setContextMenuPolicy(Qt::ActionsContextMenu); + + connect(ui->buttonReference, SIGNAL(pressed()), + this, SLOT(onButtonReference())); + + this->groupLayout()->addWidget(proxy); + + // Temporarily prevent unnecessary feature recomputes + ui->listReferences->blockSignals(true); + ui->buttonReference->blockSignals(true); + + // Get the feature data + Fem::ConstraintFixed* pcConstraint = static_cast(ConstraintView->getObject()); + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + // Fill data into dialog elements + ui->listReferences->clear(); + for (int i = 0; i < Objects.size(); i++) + ui->listReferences->addItem(makeRefText(Objects[i], SubElements[i])); + if (Objects.size() > 0) + ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); + + ui->listReferences->blockSignals(false); + ui->buttonReference->blockSignals(false); + + // Selection mode can be always on since there is nothing else in the UI + onButtonReference(true); +} + +void TaskFemConstraintFixed::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + // Don't allow selection in other document + if (strcmp(msg.pDocName, ConstraintView->getObject()->getDocument()->getName()) != 0) + return; + + if (!msg.pSubName || msg.pSubName[0] == '\0') + return; + std::string subName(msg.pSubName); + + if (selectionMode == selnone) + return; + + std::vector references(1,subName); + Fem::ConstraintFixed* pcConstraint = static_cast(ConstraintView->getObject()); + App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(msg.pObjectName); + Part::Feature* feat = static_cast(obj); + TopoDS_Shape ref = feat->Shape.getShape().getSubShape(subName.c_str()); + + if (selectionMode == selref) { + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + // Ensure we don't have mixed reference types + if (SubElements.size() > 0) { + if (subName.substr(0,4) != SubElements.front().substr(0,4)) { + QMessageBox::warning(this, tr("Selection error"), tr("Mixed shape types are not possible. Use a second constraint instead")); + return; + } + } else { + if ((subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge") && (subName.substr(0,6) != "Vertex")) { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces, edges and vertices can be picked")); + return; + } + } + + // Avoid duplicates + int pos = 0; + for (; pos < Objects.size(); pos++) + if (obj == Objects[pos]) + break; + + if (pos != Objects.size()) + if (subName == SubElements[pos]) + return; + + // add the new reference + Objects.push_back(obj); + SubElements.push_back(subName); + pcConstraint->References.setValues(Objects,SubElements); + ui->listReferences->addItem(makeRefText(obj, subName)); + } + + Gui::Selection().clearSelection(); + } +} + +void TaskFemConstraintFixed::onReferenceDeleted() { + int row = ui->listReferences->currentIndex().row(); + TaskFemConstraint::onReferenceDeleted(row); + ui->listReferences->model()->removeRow(row); + ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); +} + +const std::string TaskFemConstraintFixed::getReferences() const +{ + int rows = ui->listReferences->model()->rowCount(); + + std::vector items; + for (int r = 0; r < rows; r++) + items.push_back(ui->listReferences->item(r)->text().toStdString()); + return TaskFemConstraint::getReferences(items); +} + +TaskFemConstraintFixed::~TaskFemConstraintFixed() +{ + delete ui; +} + +void TaskFemConstraintFixed::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(proxy); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraintFixed::TaskDlgFemConstraintFixed(ViewProviderFemConstraintFixed *ConstraintView) +{ + this->ConstraintView = ConstraintView; + assert(ConstraintView); + this->parameter = new TaskFemConstraintFixed(ConstraintView);; + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +bool TaskDlgFemConstraintFixed::accept() +{ + return TaskDlgFemConstraint::accept(); +} + +#include "moc_TaskFemConstraintFixed.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintFixed.h b/src/Mod/Fem/Gui/TaskFemConstraintFixed.h new file mode 100644 index 0000000000..d6c4042821 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintFixed.h @@ -0,0 +1,84 @@ +/*************************************************************************** + * 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 GUI_TASKVIEW_TaskFemConstraintFixed_H +#define GUI_TASKVIEW_TaskFemConstraintFixed_H + +#include +#include +#include + +#include "TaskFemConstraint.h" +#include "ViewProviderFemConstraintFixed.h" + +class Ui_TaskFemConstraintFixed; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace FemGui { + +class TaskFemConstraintFixed : public TaskFemConstraint +{ + Q_OBJECT + +public: + TaskFemConstraintFixed(ViewProviderFemConstraintFixed *ConstraintView,QWidget *parent = 0); + virtual ~TaskFemConstraintFixed(); + + virtual const std::string getReferences() const; + +private Q_SLOTS: + void onReferenceDeleted(void); + +protected: + virtual void changeEvent(QEvent *e); + +private: + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + +private: + Ui_TaskFemConstraintFixed* ui; +}; + +/// simulation dialog for the TaskView +class TaskDlgFemConstraintFixed : public TaskDlgFemConstraint +{ + Q_OBJECT + +public: + TaskDlgFemConstraintFixed(ViewProviderFemConstraintFixed *ConstraintView); + + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + +}; + +} //namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraintFixed_H diff --git a/src/Mod/Fem/Gui/TaskFemConstraintFixed.ui b/src/Mod/Fem/Gui/TaskFemConstraintFixed.ui new file mode 100644 index 0000000000..799fe1bb1b --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintFixed.ui @@ -0,0 +1,44 @@ + + + TaskFemConstraintFixed + + + + 0 + 0 + 257 + 233 + + + + Form + + + + + + Add reference + + + + + + + + + + Qt::Vertical + + + + 17 + 56 + + + + + + + + + diff --git a/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp b/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp new file mode 100644 index 0000000000..4d0d5c3ff9 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp @@ -0,0 +1,363 @@ +/*************************************************************************** + * 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 +# include +# include +# include +# include +# include +# include +#endif + +#include "ui_TaskFemConstraintForce.h" +#include "TaskFemConstraintForce.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace FemGui; +using namespace Gui; + +/* TRANSLATOR FemGui::TaskFemConstraintForce */ + +TaskFemConstraintForce::TaskFemConstraintForce(ViewProviderFemConstraintForce *ConstraintView,QWidget *parent) + : TaskFemConstraint(ConstraintView, parent, "Fem_ConstraintForce") +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskFemConstraintForce(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + // Create a context menu for the listview of the references + QAction* action = new QAction(tr("Delete"), ui->listReferences); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onReferenceDeleted())); + ui->listReferences->addAction(action); + ui->listReferences->setContextMenuPolicy(Qt::ActionsContextMenu); + + connect(ui->spinForce, SIGNAL(valueChanged(double)), + this, SLOT(onForceChanged(double))); + connect(ui->buttonReference, SIGNAL(pressed()), + this, SLOT(onButtonReference())); + connect(ui->buttonDirection, SIGNAL(pressed()), + this, SLOT(onButtonDirection())); + connect(ui->checkReverse, SIGNAL(toggled(bool)), + this, SLOT(onCheckReverse(bool))); + + this->groupLayout()->addWidget(proxy); + + // Temporarily prevent unnecessary feature recomputes + ui->spinForce->blockSignals(true); + ui->listReferences->blockSignals(true); + ui->buttonReference->blockSignals(true); + ui->buttonDirection->blockSignals(true); + ui->checkReverse->blockSignals(true); + + // Get the feature data + Fem::ConstraintForce* pcConstraint = static_cast(ConstraintView->getObject()); + double f = pcConstraint->Force.getValue(); + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + std::vector dirStrings = pcConstraint->Direction.getSubValues(); + QString dir; + if (!dirStrings.empty()) + dir = makeRefText(pcConstraint->Direction.getValue(), dirStrings.front()); + bool reversed = pcConstraint->Reversed.getValue(); + + // Fill data into dialog elements + ui->spinForce->setMinimum(0); + ui->spinForce->setMaximum(INT_MAX); + ui->spinForce->setValue(f); + ui->listReferences->clear(); + for (int i = 0; i < Objects.size(); i++) + ui->listReferences->addItem(makeRefText(Objects[i], SubElements[i])); + if (Objects.size() > 0) + ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); + ui->lineDirection->setText(dir.isEmpty() ? tr("") : dir); + ui->checkReverse->setChecked(reversed); + + ui->spinForce->blockSignals(false); + ui->listReferences->blockSignals(false); + ui->buttonReference->blockSignals(false); + ui->buttonDirection->blockSignals(false); + ui->checkReverse->blockSignals(false); + + updateUI(); +} + +void TaskFemConstraintForce::updateUI() +{ + if (ui->listReferences->model()->rowCount() == 0) { + // Go into reference selection mode if no reference has been selected yet + onButtonReference(true); + return; + } + + std::string ref = ui->listReferences->item(0)->text().toStdString(); + int pos = ref.find_last_of(":"); + if (ref.substr(pos+1, 6) == "Vertex") + ui->labelForce->setText(tr("Force [N]")); + else if (ref.substr(pos+1, 4) == "Edge") + ui->labelForce->setText(tr("Force [N/mm]")); + else if (ref.substr(pos+1, 4) == "Face") + ui->labelForce->setText(tr("Force [N/mm²]")); +} + +void TaskFemConstraintForce::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + // Don't allow selection in other document + if (strcmp(msg.pDocName, ConstraintView->getObject()->getDocument()->getName()) != 0) + return; + + if (!msg.pSubName || msg.pSubName[0] == '\0') + return; + std::string subName(msg.pSubName); + + if (selectionMode == selnone) + return; + + std::vector references(1,subName); + Fem::ConstraintForce* pcConstraint = static_cast(ConstraintView->getObject()); + App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(msg.pObjectName); + Part::Feature* feat = static_cast(obj); + TopoDS_Shape ref = feat->Shape.getShape().getSubShape(subName.c_str()); + + if (selectionMode == selref) { + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + // Ensure we don't have mixed reference types + if (SubElements.size() > 0) { + if (subName.substr(0,4) != SubElements.front().substr(0,4)) { + QMessageBox::warning(this, tr("Selection error"), tr("Mixed shape types are not possible. Use a second constraint instead")); + return; + } + } else { + if ((subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge") && (subName.substr(0,6) != "Vertex")) { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces, edges and vertices can be picked")); + return; + } + } + + // Avoid duplicates + int pos = 0; + for (; pos < Objects.size(); pos++) + if (obj == Objects[pos]) + break; + + if (pos != Objects.size()) + if (subName == SubElements[pos]) + return; + + // add the new reference + Objects.push_back(obj); + SubElements.push_back(subName); + pcConstraint->References.setValues(Objects,SubElements); + ui->listReferences->addItem(makeRefText(obj, subName)); + + // Turn off reference selection mode + onButtonReference(false); + } else if (selectionMode == seldir) { + if (subName.substr(0,4) == "Face") { + BRepAdaptor_Surface surface(TopoDS::Face(ref)); + if (surface.GetType() != GeomAbs_Plane) { + QMessageBox::warning(this, tr("Selection error"), tr("Only planar faces can be picked")); + return; + } + } else if (subName.substr(0,4) == "Edge") { + BRepAdaptor_Curve line(TopoDS::Edge(ref)); + if (line.GetType() != GeomAbs_Line) { + QMessageBox::warning(this, tr("Selection error"), tr("Only linear edges can be picked")); + return; + } + } else { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked")); + return; + } + pcConstraint->Direction.setValue(obj, references); + ui->lineDirection->setText(makeRefText(obj, subName)); + + // Turn off direction selection mode + onButtonDirection(false); + } + + Gui::Selection().clearSelection(); + updateUI(); + } +} + +void TaskFemConstraintForce::onForceChanged(double f) +{ + Fem::ConstraintForce* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Force.setValue((float)f); +} + +void TaskFemConstraintForce::onReferenceDeleted() { + int row = ui->listReferences->currentIndex().row(); + TaskFemConstraint::onReferenceDeleted(row); + ui->listReferences->model()->removeRow(row); + ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); +} + +void TaskFemConstraintForce::onButtonDirection(const bool pressed) { + if (pressed) { + selectionMode = seldir; + } else { + selectionMode = selnone; + } + ui->buttonDirection->setChecked(pressed); + Gui::Selection().clearSelection(); +} + +void TaskFemConstraintForce::onCheckReverse(const bool pressed) +{ + Fem::ConstraintForce* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Reversed.setValue(pressed); +} + +double TaskFemConstraintForce::getForce(void) const +{ + return ui->spinForce->value(); +} + +const std::string TaskFemConstraintForce::getReferences() const +{ + int rows = ui->listReferences->model()->rowCount(); + + std::vector items; + for (int r = 0; r < rows; r++) + items.push_back(ui->listReferences->item(r)->text().toStdString()); + return TaskFemConstraint::getReferences(items); +} + +const std::string TaskFemConstraintForce::getDirectionName(void) const +{ + std::string dir = ui->lineDirection->text().toStdString(); + if (dir.empty()) + return ""; + + int pos = dir.find_last_of(":"); + return dir.substr(0, pos).c_str(); +} + +const std::string TaskFemConstraintForce::getDirectionObject(void) const +{ + std::string dir = ui->lineDirection->text().toStdString(); + if (dir.empty()) + return ""; + + int pos = dir.find_last_of(":"); + return dir.substr(pos+1).c_str(); +} + +bool TaskFemConstraintForce::getReverse() const +{ + return ui->checkReverse->isChecked(); +} + +TaskFemConstraintForce::~TaskFemConstraintForce() +{ + delete ui; +} + +void TaskFemConstraintForce::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->spinForce->blockSignals(true); + ui->retranslateUi(proxy); + ui->spinForce->blockSignals(false); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraintForce::TaskDlgFemConstraintForce(ViewProviderFemConstraintForce *ConstraintView) +{ + this->ConstraintView = ConstraintView; + assert(ConstraintView); + this->parameter = new TaskFemConstraintForce(ConstraintView);; + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +bool TaskDlgFemConstraintForce::accept() +{ + std::string name = ConstraintView->getObject()->getNameInDocument(); + const TaskFemConstraintForce* parameterForce = static_cast(parameter); + + try { + //Gui::Command::openCommand("FEM force constraint changed"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Force = %f",name.c_str(), parameterForce->getForce()); + + std::string dirname = parameterForce->getDirectionName().data(); + std::string dirobj = parameterForce->getDirectionObject().data(); + + if (!dirname.empty()) { + QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); + buf = buf.arg(QString::fromStdString(dirname)); + buf = buf.arg(QString::fromStdString(dirobj)); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = %s", name.c_str(), buf.toStdString().c_str()); + } else { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str()); + } + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %s", name.c_str(), parameterForce->getReverse() ? "True" : "False"); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromAscii(e.what())); + return false; + } + + return TaskDlgFemConstraint::accept(); +} + +#include "moc_TaskFemConstraintForce.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintForce.h b/src/Mod/Fem/Gui/TaskFemConstraintForce.h new file mode 100644 index 0000000000..5da5923609 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintForce.h @@ -0,0 +1,92 @@ +/*************************************************************************** + * 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 GUI_TASKVIEW_TaskFemConstraintForce_H +#define GUI_TASKVIEW_TaskFemConstraintForce_H + +#include +#include +#include + +#include "TaskFemConstraint.h" +#include "ViewProviderFemConstraintForce.h" + +class Ui_TaskFemConstraintForce; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace FemGui { + +class TaskFemConstraintForce : public TaskFemConstraint +{ + Q_OBJECT + +public: + TaskFemConstraintForce(ViewProviderFemConstraintForce *ConstraintView,QWidget *parent = 0); + virtual ~TaskFemConstraintForce(); + + double getForce(void) const; + virtual const std::string getReferences() const; + const std::string getDirectionName(void) const; + const std::string getDirectionObject(void) const; + bool getReverse(void) const; + +private Q_SLOTS: + void onReferenceDeleted(void); + void onForceChanged(double); + void onButtonDirection(const bool pressed = true); + void onCheckReverse(bool); + +protected: + virtual void changeEvent(QEvent *e); + +private: + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + void updateUI(); + +private: + Ui_TaskFemConstraintForce* ui; +}; + +/// simulation dialog for the TaskView +class TaskDlgFemConstraintForce : public TaskDlgFemConstraint +{ + Q_OBJECT + +public: + TaskDlgFemConstraintForce(ViewProviderFemConstraintForce *ConstraintView); + + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + +}; + +} //namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraintForce_H diff --git a/src/Mod/Fem/Gui/TaskFemConstraintForce.ui b/src/Mod/Fem/Gui/TaskFemConstraintForce.ui new file mode 100644 index 0000000000..83536403d2 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintForce.ui @@ -0,0 +1,89 @@ + + + TaskFemConstraintForce + + + + 0 + 0 + 257 + 233 + + + + Form + + + + + + Add reference + + + + + + + + + + + + Load [N] + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 500.000000000000000 + + + + + + + + + + + Direction + + + + + + + + + + + + Reverse direction + + + + + + + Qt::Vertical + + + + 17 + 56 + + + + + + + + + diff --git a/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp b/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp new file mode 100644 index 0000000000..0ee3868e11 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp @@ -0,0 +1,150 @@ +/*************************************************************************** + * 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 +# include +# include +# include +# include +# include +# include +*/ +#endif + +#include "ui_TaskFemConstraintCylindrical.h" +#include "TaskFemConstraintGear.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace FemGui; +using namespace Gui; + +/* TRANSLATOR FemGui::TaskFemConstraintGear */ + +TaskFemConstraintGear::TaskFemConstraintGear(ViewProviderFemConstraintGear *ConstraintView,QWidget *parent) + : TaskFemConstraintBearing(ConstraintView, parent, "Fem_ConstraintGear") +{ + // we need a separate container widget to add all controls to + connect(ui->spinDiameter, SIGNAL(valueChanged(double)), + this, SLOT(onDiameterChanged(double))); + + // Temporarily prevent unnecessary feature recomputes + ui->spinDiameter->blockSignals(true); + + // Get the feature data + Fem::ConstraintGear* pcConstraint = static_cast(ConstraintView->getObject()); + double dia = pcConstraint->Diameter.getValue(); + + // Fill data into dialog elements + ui->spinDiameter->setMinimum(0); + ui->spinDiameter->setMaximum(INT_MAX); + ui->spinDiameter->setValue(dia); + + // Adjust ui to specific constraint type + ui->checkAxial->setVisible(false); + ui->spinDiameter->setVisible(true); + ui->labelDiameter->setVisible(true); + + ui->spinDiameter->blockSignals(false); + + onButtonReference(true); +} +void TaskFemConstraintGear::onDiameterChanged(double l) +{ + Fem::ConstraintGear* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Diameter.setValue((float)l); +} + +double TaskFemConstraintGear::getDiameter(void) const +{ + return ui->spinDiameter->value(); +} + +void TaskFemConstraintGear::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->spinDiameter->blockSignals(true); + ui->spinDistance->blockSignals(true); + ui->retranslateUi(proxy); + ui->spinDiameter->blockSignals(false); + ui->spinDistance->blockSignals(false); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraintGear::TaskDlgFemConstraintGear(ViewProviderFemConstraintGear *ConstraintView) +{ + this->ConstraintView = ConstraintView; + assert(ConstraintView); + this->parameter = new TaskFemConstraintGear(ConstraintView);; + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +bool TaskDlgFemConstraintGear::accept() +{ + std::string name = ConstraintView->getObject()->getNameInDocument(); + const TaskFemConstraintGear* parameterGear = static_cast(parameter); + + try { + //Gui::Command::openCommand("FEM force constraint changed"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Diameter = %f",name.c_str(), parameterGear->getDiameter()); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromAscii(e.what())); + return false; + } + + return TaskDlgFemConstraintBearing::accept(); +} + +#include "moc_TaskFemConstraintGear.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintGear.h b/src/Mod/Fem/Gui/TaskFemConstraintGear.h new file mode 100644 index 0000000000..bfc8eee099 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintGear.h @@ -0,0 +1,78 @@ +/*************************************************************************** + * 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 GUI_TASKVIEW_TaskFemConstraintGear_H +#define GUI_TASKVIEW_TaskFemConstraintGear_H + +#include +#include +#include + +#include "TaskFemConstraintBearing.h" +#include "ViewProviderFemConstraintGear.h" + +class Ui_TaskFemConstraintGear; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace FemGui { + +class TaskFemConstraintGear : public TaskFemConstraintBearing +{ + Q_OBJECT + +public: + TaskFemConstraintGear(ViewProviderFemConstraintGear *ConstraintView,QWidget *parent = 0); + + double getDiameter(void) const; + +private Q_SLOTS: + void onDiameterChanged(double dia); + +protected: + virtual void changeEvent(QEvent *e); + +}; + +/// simulation dialog for the TaskView +class TaskDlgFemConstraintGear : public TaskDlgFemConstraintBearing +{ + Q_OBJECT + +public: + TaskDlgFemConstraintGear(ViewProviderFemConstraintGear *ConstraintView); + + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + +}; + +} //namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraintGear_H diff --git a/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp b/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp new file mode 100644 index 0000000000..f239a37ec4 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp @@ -0,0 +1,185 @@ +/*************************************************************************** + * 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_ +#endif + +#include "ui_TaskFemConstraintCylindrical.h" +#include "TaskFemConstraintPulley.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace FemGui; +using namespace Gui; + +/* TRANSLATOR FemGui::TaskFemConstraintPulley */ + +TaskFemConstraintPulley::TaskFemConstraintPulley(ViewProviderFemConstraintPulley *ConstraintView,QWidget *parent) + : TaskFemConstraintBearing(ConstraintView, parent, "Fem_ConstraintPulley") +{ + // we need a separate container widget to add all controls to + connect(ui->spinDiameter, SIGNAL(valueChanged(double)), + this, SLOT(onDiameterChanged(double))); + connect(ui->spinOtherDiameter, SIGNAL(valueChanged(double)), + this, SLOT(onOtherDiameterChanged(double))); + connect(ui->spinCenterDistance, SIGNAL(valueChanged(double)), + this, SLOT(onCenterDistanceChanged(double))); + + // Temporarily prevent unnecessary feature recomputes + ui->spinDiameter->blockSignals(true); + ui->spinOtherDiameter->blockSignals(true); + ui->spinCenterDistance->blockSignals(true); + + // Get the feature data + Fem::ConstraintPulley* pcConstraint = static_cast(ConstraintView->getObject()); + double dia = pcConstraint->Diameter.getValue(); + double otherdia = pcConstraint->OtherDiameter.getValue(); + double centerdist = pcConstraint->CenterDistance.getValue(); + + // Fill data into dialog elements + ui->spinDiameter->setMinimum(0); + ui->spinDiameter->setMaximum(INT_MAX); + ui->spinDiameter->setValue(dia); + ui->spinOtherDiameter->setMinimum(0); + ui->spinOtherDiameter->setMaximum(INT_MAX); + ui->spinOtherDiameter->setValue(otherdia); + ui->spinCenterDistance->setMinimum(INT_MIN); + ui->spinCenterDistance->setMaximum(INT_MAX); + ui->spinCenterDistance->setValue(centerdist); + + // Adjust ui to specific constraint type + ui->checkAxial->setVisible(false); + ui->spinDiameter->setVisible(true); + ui->labelDiameter->setVisible(true); + ui->labelDiameter->setText(tr("Pulley diameter")); + ui->labelOtherDiameter->setVisible(true); + ui->spinOtherDiameter->setVisible(true); + ui->labelCenterDistance->setVisible(true); + ui->spinCenterDistance->setVisible(true); + + ui->spinDiameter->blockSignals(false); + ui->spinOtherDiameter->blockSignals(false); + ui->spinCenterDistance->blockSignals(false); + + onButtonReference(true); +} + +void TaskFemConstraintPulley::onDiameterChanged(double l) +{ + Fem::ConstraintPulley* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Diameter.setValue((float)l); +} + +void TaskFemConstraintPulley::onOtherDiameterChanged(double l) +{ + Fem::ConstraintPulley* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->OtherDiameter.setValue((float)l); +} + +void TaskFemConstraintPulley::onCenterDistanceChanged(double l) +{ + Fem::ConstraintPulley* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->CenterDistance.setValue((float)l); +} + +double TaskFemConstraintPulley::getDiameter(void) const +{ + return ui->spinDiameter->value(); +} + +double TaskFemConstraintPulley::getOtherDiameter(void) const +{ + return ui->spinOtherDiameter->value(); +} + +double TaskFemConstraintPulley::getCenterDistance(void) const +{ + return ui->spinCenterDistance->value(); +} + +void TaskFemConstraintPulley::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->spinDiameter->blockSignals(true); + ui->spinDistance->blockSignals(true); + ui->spinOtherDiameter->blockSignals(true); + ui->spinCenterDistance->blockSignals(true); + ui->retranslateUi(proxy); + ui->spinDiameter->blockSignals(false); + ui->spinDistance->blockSignals(false); + ui->spinOtherDiameter->blockSignals(false); + ui->spinCenterDistance->blockSignals(false); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraintPulley::TaskDlgFemConstraintPulley(ViewProviderFemConstraintPulley *ConstraintView) +{ + this->ConstraintView = ConstraintView; + assert(ConstraintView); + this->parameter = new TaskFemConstraintPulley(ConstraintView);; + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +bool TaskDlgFemConstraintPulley::accept() +{ + std::string name = ConstraintView->getObject()->getNameInDocument(); + const TaskFemConstraintPulley* parameterPulley = static_cast(parameter); + + try { + //Gui::Command::openCommand("FEM force constraint changed"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Diameter = %f",name.c_str(), parameterPulley->getDiameter()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.OtherDiameter = %f",name.c_str(), parameterPulley->getOtherDiameter()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.CenterDistance = %f",name.c_str(), parameterPulley->getCenterDistance()); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromAscii(e.what())); + return false; + } + + return TaskDlgFemConstraintBearing::accept(); +} + +#include "moc_TaskFemConstraintPulley.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintPulley.h b/src/Mod/Fem/Gui/TaskFemConstraintPulley.h new file mode 100644 index 0000000000..11196dafeb --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintPulley.h @@ -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 * + * * + ***************************************************************************/ + + +#ifndef GUI_TASKVIEW_TaskFemConstraintPulley_H +#define GUI_TASKVIEW_TaskFemConstraintPulley_H + +#include +#include +#include + +#include "TaskFemConstraintBearing.h" +#include "ViewProviderFemConstraintPulley.h" + +class Ui_TaskFemConstraintPulley; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace FemGui { + +class TaskFemConstraintPulley : public TaskFemConstraintBearing +{ + Q_OBJECT + +public: + TaskFemConstraintPulley(ViewProviderFemConstraintPulley *ConstraintView,QWidget *parent = 0); + + double getDiameter(void) const; + double getOtherDiameter(void) const; + double getCenterDistance(void) const; + +private Q_SLOTS: + void onDiameterChanged(double dia); + void onOtherDiameterChanged(double dia); + void onCenterDistanceChanged(double dia); + +protected: + virtual void changeEvent(QEvent *e); + +}; + +/// simulation dialog for the TaskView +class TaskDlgFemConstraintPulley : public TaskDlgFemConstraintBearing +{ + Q_OBJECT + +public: + TaskDlgFemConstraintPulley(ViewProviderFemConstraintPulley *ConstraintView); + + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + +}; + +} //namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraintPulley_H diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp index 2a58cc4bc2..4bb6dabe31 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp @@ -24,56 +24,25 @@ #include "PreCompiled.h" #ifndef _PreComp_ -# include # include -# include -# include # include # include # include -# include # include # include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include +# include +# include +# include +# include +# include +# include #endif #include "ViewProviderFemConstraint.h" #include "TaskFemConstraint.h" -#include "Gui/SoFCSelection.h" -#include "Gui/Application.h" + #include "Gui/Control.h" -#include "Gui/Command.h" -#include "Gui/Document.h" -#include "Gui/View3DInventorViewer.h" -#include "App/Document.h" - -#include -#include -#include -#include #include using namespace FemGui; @@ -85,6 +54,7 @@ ViewProviderFemConstraint::ViewProviderFemConstraint() { ADD_PROPERTY(TextColor,(0.0f,0.0f,0.0f)); ADD_PROPERTY(FaceColor,(1.0f,0.0f,0.2f)); + ADD_PROPERTY(ShapeColor,(1.0f,0.0f,0.2f)); ADD_PROPERTY(FontSize,(18)); ADD_PROPERTY(DistFactor,(1.0)); ADD_PROPERTY(Mirror,(false)); @@ -93,42 +63,66 @@ ViewProviderFemConstraint::ViewProviderFemConstraint() pFont->ref(); pLabel = new SoText2(); pLabel->ref(); - pColor = new SoBaseColor(); - pColor->ref(); pTextColor = new SoBaseColor(); pTextColor->ref(); - pTranslation = new SoTranslation(); - pTranslation->ref(); + + pMaterials = new SoMaterial(); + pMaterials->ref(); + pMaterials->diffuseColor.setValue(1.0f, 0.0f, 0.2f); + pMaterials->transparency.setValue(0.1); + //pMaterials->ambientColor.setValue(0.8f, 0.8f, 0.8f); + //pMaterials->shininess.setValue(1.0); + + pShapeSep = new SoSeparator(); + pShapeSep->ref(); TextColor.touch(); FontSize.touch(); - FaceColor.touch(); + FaceColor.touch(); - pCoords = new SoCoordinate3(); - pCoords->ref(); - pCoords->point.setNum(0); - - pFaces = new SoIndexedFaceSet(); - pFaces->ref(); - pFaces->coordIndex.setNum(0); - - sPixmap = "view-femconstraint"; - - normalDirection = new SbVec3f(0, 0, 1); - arrowDirection = NULL; + oldDlg = NULL; } ViewProviderFemConstraint::~ViewProviderFemConstraint() { pFont->unref(); pLabel->unref(); - pColor->unref(); pTextColor->unref(); - pTranslation->unref(); - pCoords->unref(); - pFaces->unref(); - delete arrowDirection; - delete normalDirection; + pMaterials->unref(); + pShapeSep->unref(); +} + +void ViewProviderFemConstraint::attach(App::DocumentObject* pcObject) +{ + ViewProviderDocumentObject::attach(pcObject); + + SoPickStyle* ps = new SoPickStyle(); + ps->style = SoPickStyle::UNPICKABLE; + + SoSeparator* sep = new SoSeparator(); + SoShapeHints* hints = new SoShapeHints(); + hints->shapeType.setValue(SoShapeHints::UNKNOWN_SHAPE_TYPE); + hints->vertexOrdering.setValue(SoShapeHints::COUNTERCLOCKWISE); + sep->addChild(ps); + sep->addChild(hints); + sep->addChild(pMaterials); + sep->addChild(pShapeSep); + addDisplayMaskMode(sep, "Base"); +} + +std::vector ViewProviderFemConstraint::getDisplayModes(void) const +{ + // add modes + std::vector StrList; + StrList.push_back("Base"); + return StrList; +} + +void ViewProviderFemConstraint::setDisplayMode(const char* ModeName) +{ + if (strcmp(ModeName, "Base") == 0) + setDisplayMaskMode("Base"); + ViewProviderDocumentObject::setDisplayMode(ModeName); } std::vector ViewProviderFemConstraint::claimChildren(void)const @@ -147,9 +141,9 @@ void ViewProviderFemConstraint::setupContextMenu(QMenu* menu, QObject* receiver, void ViewProviderFemConstraint::onChanged(const App::Property* prop) { if (this->getObject() != NULL) - Base::Console().Error("%s: onChanged: %s\n", this->getObject()->getNameInDocument(), prop->getName()); + Base::Console().Error("%s: VP onChanged: %s\n", this->getObject()->getNameInDocument(), prop->getName()); else - Base::Console().Error("Anonymous: onChanged: %s\n", prop->getName()); + Base::Console().Error("Anonymous: VP onChanged: %s\n", prop->getName()); if (prop == &Mirror || prop == &DistFactor) { updateData(prop); @@ -160,7 +154,7 @@ void ViewProviderFemConstraint::onChanged(const App::Property* prop) } else if (prop == &FaceColor) { const App::Color& c = FaceColor.getValue(); - pColor->rgb.setValue(c.r,c.g,c.b); + pMaterials->diffuseColor.setValue(c.r,c.g,c.b); } else if (prop == &FontSize) { pFont->size = FontSize.getValue(); @@ -170,45 +164,6 @@ void ViewProviderFemConstraint::onChanged(const App::Property* prop) } } -bool ViewProviderFemConstraint::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(); - TaskDlgFemConstraint *constrDlg = qobject_cast(dlg); - if (constrDlg && constrDlg->getConstraintView() != this) - constrDlg = 0; // another constraint left open its task panel - if (dlg && !constrDlg) { - 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().closeDialog(); - else - return false; - } - - // clear the selection (convenience) - Gui::Selection().clearSelection(); - - // start the edit dialog - if (constrDlg) - Gui::Control().showDialog(constrDlg); - else - Gui::Control().showDialog(new TaskDlgFemConstraint(this)); - - return true; - } - else { - return ViewProviderDocumentObject::setEdit(ModNum); - } -} - void ViewProviderFemConstraint::unsetEdit(int ModNum) { if (ModNum == ViewProvider::Default) { @@ -218,41 +173,13 @@ void ViewProviderFemConstraint::unsetEdit(int ModNum) else { ViewProviderDocumentObject::unsetEdit(ModNum); } + + if (oldDlg != NULL) { + Gui::Control().showDialog(oldDlg); + oldDlg = NULL; + } } - -std::vector ViewProviderFemConstraint::getDisplayModes(void) const -{ - // add modes - std::vector StrList; - StrList.push_back("Base"); - return StrList; -} - -void ViewProviderFemConstraint::setDisplayMode(const char* ModeName) -{ - if (strcmp(ModeName, "Base") == 0) - setDisplayMaskMode("Base"); - ViewProviderDocumentObject::setDisplayMode(ModeName); -} - -void ViewProviderFemConstraint::attach(App::DocumentObject* pcObject) -{ - ViewProviderDocumentObject::attach(pcObject); - - SoPickStyle* ps = new SoPickStyle(); - ps->style = SoPickStyle::UNPICKABLE; - - SoSeparator *faceSep = new SoSeparator(); - faceSep->addChild(ps); - faceSep->addChild(pColor); - faceSep->addChild(pCoords); - faceSep->addChild(pFaces); - - SoSeparator* sep = new SoSeparator(); - sep->addChild(faceSep); - addDisplayMaskMode(sep, "Base"); -} - +/* // Create a local coordinate system with the z-axis given in dir void getLocalCoordinateSystem(const SbVec3f& z, SbVec3f& y, SbVec3f& x) { @@ -299,521 +226,163 @@ void getLocalCoordinateSystem(const SbVec3f& z, SbVec3f& y, SbVec3f& x) y = SbVec3f(y1, y2, y3); x = y.cross(z); } +*/ +#define PLACEMENT_CHILDREN 2 -#define FACETS 12 -#define CONEPOINTS (FACETS + 1) -#define CONEFACETPOINTS (FACETS * 4 + FACETS + 1) - -void createCone(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir, - const double height, const double radius, const bool update = false) +void ViewProviderFemConstraint::createPlacement(SoSeparator* sep, const SbVec3f &base, const SbRotation &r) { - SbVec3f x, y; - getLocalCoordinateSystem(dir, y, x); - - point.set1Value(ipoints, base); // tip - - SbVec3f midpoint(base + dir * height); // centre of the circle - for (int i = 0; i < FACETS; i++) { - float angle = 2 * M_PI / FACETS * i; - point.set1Value(ipoints + i + 1, midpoint + cos(angle) * x * radius + sin(angle) * y * radius); - } - - if (update) - return; - - int32_t faces[CONEFACETPOINTS]; - int start_index = 1; - for (int f = 0; f < FACETS; f++) { - faces[f * 4] = ipoints; // tip of arrow - int idx = start_index; - faces[f * 4 + 1] = ipoints + idx; - idx++; - if (idx > FACETS) idx = 1; // Happens in the last iteration - faces[f * 4 + 2] = ipoints + idx; - faces[f * 4 + 3] = -1; - start_index++; - } - for (int f = 0; f < FACETS; f++) - faces[FACETS * 4 + f] = ipoints + f + 1; - faces[CONEFACETPOINTS - 1] = -1; - refs.setValues(ifaces, CONEFACETPOINTS, faces); + SoTranslation* trans = new SoTranslation(); + trans->ref(); + trans->translation.setValue(base); + sep->addChild(trans); + SoRotation* rot = new SoRotation(); + rot->ref(); + rot->rotation.setValue(r); + sep->addChild(rot); } -#define CYLPOINTS (FACETS * 2) -#define CYLFACETPOINTS (FACETS * 5 + 2 * FACETS + 2) - -void createCylinder(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir, - const double height, const double radius, const bool update = false) +void ViewProviderFemConstraint::updatePlacement(const SoSeparator* sep, const int idx, const SbVec3f &base, const SbRotation &r) { - SbVec3f x, y; - getLocalCoordinateSystem(dir, y, x); - - for (int i = 0; i < CYLPOINTS; i+=2) { - float angle = 2 * M_PI / FACETS * i/2; - point.set1Value(ipoints + i, base + cos(angle) * x * radius + sin(angle) * y * radius); - point.set1Value(ipoints + i + 1, base + dir * height + cos(angle) * x * radius + sin(angle) * y * radius); - } - - if (update) - return; - - int32_t faces[CYLFACETPOINTS]; - int start_index = 0; - for (int f = 0; f < FACETS; f++) { - int idx = start_index; - faces[f * 5] = ipoints + idx; - idx++; - faces[f * 5 + 1] = ipoints + idx; - idx++; - if (idx >= CYLPOINTS) idx = 0; // Happens in the last iteration - faces[f * 5 + 3] = ipoints + idx; - idx++; - faces[f * 5 + 2] = ipoints + idx; - faces[f * 5 + 4] = -1; - start_index += 2; - } - for (int f = 0; f < FACETS; f++) { - faces[FACETS * 5 + f] = ipoints + 2 * f; - faces[FACETS * 5 + FACETS + f + 1] = ipoints + 1 + 2 * f; - } - faces[FACETS * 5 + FACETS] = -1; - faces[CYLFACETPOINTS - 1] = -1; - refs.setValues(ifaces, CYLFACETPOINTS, faces); + SoTranslation* trans = static_cast(sep->getChild(idx)); + trans->translation.setValue(base); + SoRotation* rot = static_cast(sep->getChild(idx+1)); + rot->rotation.setValue(r); } -#define ARROWPOINTS (CONEPOINTS + CYLPOINTS) -#define ARROWFACETPOINTS (CONEFACETPOINTS + CYLFACETPOINTS) +#define CONE_CHILDREN 2 -void createArrow(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir, - const double length, const double radius, const bool update = false) +void ViewProviderFemConstraint::createCone(SoSeparator* sep, const double height, const double radius) { - createCone(point, refs, ipoints, ifaces, base, dir, radius, radius, update); - createCylinder(point, refs, ipoints + CONEPOINTS, ifaces + CONEFACETPOINTS, base + dir * radius, dir, length-radius, radius/3, update); + // Adjust cone so that the tip is on base + SoTranslation* trans = new SoTranslation(); + trans->ref(); + trans->translation.setValue(SbVec3f(0,-height/2,0)); + sep->addChild(trans); + SoCone* cone = new SoCone(); + cone->ref(); + cone->height.setValue(height); + cone->bottomRadius.setValue(radius); + sep->addChild(cone); } -#define BOXPOINTS 8 -#define BOXFACEPOINTS 30 - -void createBox(SoMFVec3f& point, SoMFInt32& refs, const int ipoints, const int ifaces, const SbVec3f& base, const SbVec3f& dir, - const double width, const double length, const double height, const bool update = false) +SoSeparator* ViewProviderFemConstraint::createCone(const double height, const double radius) { - SbVec3f x, y; - getLocalCoordinateSystem(dir, y, x); - - point.set1Value(ipoints, base + width/2 * y + length/2 * x); - point.set1Value(ipoints+1, base + width/2 * y - length/2 * x); - point.set1Value(ipoints+2, base - width/2 * y - length/2 * x); - point.set1Value(ipoints+3, base - width/2 * y + length/2 * x); - point.set1Value(ipoints+4, base + dir * height + width/2 * y + length/2 * x); - point.set1Value(ipoints+5, base + dir * height + width/2 * y - length/2 * x); - point.set1Value(ipoints+6, base + dir * height - width/2 * y - length/2 * x); - point.set1Value(ipoints+7, base + dir * height - width/2 * y + length/2 * x); - - if (update) - return; - - int32_t faces[BOXFACEPOINTS] = { - ipoints, ipoints+1, ipoints+2, ipoints+3, -1, - ipoints, ipoints+1, ipoints+5, ipoints+4, -1, - ipoints+1, ipoints+2, ipoints+6, ipoints+5, -1, - ipoints+2, ipoints+3, ipoints+7, ipoints+6, -1, - ipoints+3, ipoints, ipoints+4, ipoints+7, -1, - ipoints+4, ipoints+5, ipoints+6, ipoints+7, -1}; - refs.setValues(ifaces, BOXFACEPOINTS, faces); + // Create a new cone node + SoSeparator* sep = new SoSeparator(); + createCone(sep, height, radius); + return sep; } -void ViewProviderFemConstraint::findCylinderData(SbVec3f& z, SbVec3f& y, SbVec3f& x, SbVec3f& p, double& radius, double& height) { - Fem::Constraint* pcConstraint = static_cast(this->getObject()); - std::vector Objects = pcConstraint->References.getValues(); - std::vector SubElements = pcConstraint->References.getSubValues(); - if (Objects.empty()) - return; - App::DocumentObject* obj = Objects[0]; - Part::Feature* feat = static_cast(obj); - TopoDS_Shape sh = feat->Shape.getShape().getSubShape(SubElements[0].c_str()); - - TopoDS_Face face = TopoDS::Face(sh); - BRepAdaptor_Surface surface(face); - gp_Cylinder cyl = surface.Cylinder(); - gp_Pnt start = surface.Value(surface.FirstUParameter(), surface.FirstVParameter()); - gp_Pnt end = surface.Value(surface.FirstUParameter(), surface.LastVParameter()); - height = start.Distance(end); - radius = cyl.Radius(); - gp_Dir dirz = cyl.Axis().Direction(); - z = SbVec3f(dirz.X(), dirz.Y(), dirz.Z()); - gp_Dir diry = cyl.YAxis().Direction(); - y = SbVec3f(diry.X(), diry.Y(), diry.Z()); - gp_Dir dirx = cyl.XAxis().Direction(); - x = SbVec3f(dirx.X(), dirx.Y(), dirx.Z()); - - if (pcConstraint->Location.getValue() == NULL) { - // Get a point in the middle of the cylindrical face. - gp_Pnt centre = cyl.Location(); - SbVec3f base(centre.X(), centre.Y(), centre.Z()); - p = base + z * height/2; - } else { - // Get the point specified by Location and Distance - App::DocumentObject* objLoc = pcConstraint->Location.getValue(); - std::string subName = pcConstraint->Location.getSubValues().front(); - Part::Feature* featLoc = static_cast(objLoc); - TopoDS_Shape shloc = featLoc->Shape.getShape().getSubShape(subName.c_str()); - // Get a plane from the Location reference - gp_Pln plane; - if (shloc.ShapeType() == TopAbs_FACE) { - BRepAdaptor_Surface surface(TopoDS::Face(shloc)); - plane = surface.Plane(); - } else { - BRepAdaptor_Curve curve(TopoDS::Edge(shloc)); - gp_Lin line = curve.Line(); - gp_Dir tang = line.Direction().Crossed(dirz); - gp_Dir norm = line.Direction().Crossed(tang); - plane = gp_Pln(line.Location(), norm); - } - // Translate the plane in direction of the cylinder (for positive values of Distance) - Handle_Geom_Plane pln = new Geom_Plane(plane); - GeomAPI_ProjectPointOnSurf proj(cyl.Location(), pln); - if (!proj.IsDone()) - return; - gp_Pnt projPnt = proj.NearestPoint(); - plane.Translate(gp_Vec(projPnt, cyl.Location()).Normalized().Multiplied(pcConstraint->Distance.getValue())); - Handle_Geom_Plane plnt = new Geom_Plane(plane); - // Intersect translated plane with cylinder axis - Handle_Geom_Curve crv = new Geom_Line(cyl.Axis()); - GeomAPI_IntCS intersector(crv, plnt); - if (!intersector.IsDone()) - return; - gp_Pnt inter = intersector.Point(1); - p.setValue(inter.X(), inter.Y(), inter.Z()); - } -} - -void ViewProviderFemConstraint::updateData(const App::Property* prop) +void ViewProviderFemConstraint::updateCone(const SoNode* node, const int idx, const double height, const double radius) { - // Gets called whenever a property of the attached object changes - if (this->getObject() != NULL) - Base::Console().Error("%s: updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); - else - Base::Console().Error("Anonymous: updateData: %s\n", prop->getName()); - Fem::Constraint* pcConstraint = static_cast(this->getObject()); - - if (strcmp(prop->getName(),"References") == 0) { - const App::PropertyLinkSubList* pr = static_cast(prop); - std::vector Objects = pr->getValues(); - std::vector SubElements = pr->getSubValues(); - - // Remove all arrows - pCoords->point.deleteValues(0, pCoords->point.getNum()); - pFaces->coordIndex.deleteValues(0, pFaces->coordIndex.getNum()); - if (Objects.empty()) { - Base::Console().Error(" updateData: No references\n"); - Objects = pcConstraint->References.getValues(); - SubElements = pcConstraint->References.getSubValues(); - if (Objects.empty()) - return; - } - - Base::Console().Error(" updateData: Found %u references\n", Objects.size()); - - // Re-create all arrows - int type = pcConstraint->Type.getValue(); - - if ((type == 0) || (type == 1)) { - // Force on geometry - std::vector points; - TopoDS_Shape sh; - - for (int i = 0; i < Objects.size(); i++) { - App::DocumentObject* obj = Objects[i]; - Part::Feature* feat = static_cast(obj); - const Part::TopoShape& toposhape = feat->Shape.getShape(); - if (toposhape.isNull()) { - Base::Console().Error(" updateData: Empty toposhape\n"); - return; - } - sh = toposhape.getSubShape(SubElements[i].c_str()); - - if (sh.ShapeType() == TopAbs_VERTEX) { - const TopoDS_Vertex& vertex = TopoDS::Vertex(sh); - gp_Pnt p = BRep_Tool::Pnt(vertex); - points.push_back(p); - } else if (sh.ShapeType() == TopAbs_EDGE) { - BRepAdaptor_Curve curve(TopoDS::Edge(sh)); - double fp = curve.FirstParameter(); - double lp = curve.LastParameter(); - GProp_GProps props; - BRepGProp::LinearProperties(sh, props); - double l = props.Mass(); - int steps = round(l / 3); // TODO: Make number of steps depend on actual screen size of element! - double step = (lp - fp) / steps; - if (steps < 1) { - points.push_back(curve.Value(fp)); - points.push_back(curve.Value(lp)); - } else { - for (int i = 0; i < steps + 1; i++) - points.push_back(curve.Value(i * step)); - } - } else if (sh.ShapeType() == TopAbs_FACE) { - TopoDS_Face face = TopoDS::Face(sh); - BRepAdaptor_Surface surface(face); - double ufp = surface.FirstUParameter(); - double ulp = surface.LastUParameter(); - double vfp = surface.FirstVParameter(); - double vlp = surface.LastVParameter(); - double ustep = (ulp - ufp) / 6.0; - double vstep = (vlp - vfp) / 6.0; - // TODO: How to find the distance between ufp and ulp to get the number of steps? - for (int i = 0; i < 7; i++) { - for (int j = 0; j < 7; j++) { - gp_Pnt p = surface.Value(ufp + i * ustep, vfp + j * vstep); - BRepClass_FaceClassifier classifier(face, p, Precision::Confusion()); - if (classifier.State() != TopAbs_OUT) - points.push_back(p); - } - } - } - } - - // Get default direction (on first call to method) - if (arrowDirection == NULL) { - if (sh.ShapeType() == TopAbs_FACE) { - // Get face normal in center point - TopoDS_Face face = TopoDS::Face(sh); - BRepGProp_Face prop(face); - gp_Vec normal; - gp_Pnt center; - double u1,u2,v1,v2; - prop.Bounds(u1,u2,v1,v2); - prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal); - normal.Normalize(); - normalDirection->setValue(normal.X(), normal.Y(), normal.Z()); - } // else use z axis - - arrowDirection = new SbVec3f(*normalDirection); - } - - if (type == 0) { - // Force on geometry - pCoords->point.setNum(ARROWPOINTS * points.size()); - pFaces->coordIndex.setNum(ARROWFACETPOINTS * points.size()); - int index = 0; - - for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { - SbVec3f v(p->X(), p->Y(), p->Z()); - if (*arrowDirection != *normalDirection) // Turn arrow around - v = v + *normalDirection * 5.0; - createArrow(pCoords->point, pFaces->coordIndex, - index * ARROWPOINTS, index * ARROWFACETPOINTS, - v, *arrowDirection, 5.0, 1.0); - index++; - } - } else if (type == 1) { - // Fixed - pCoords->point.setNum((CONEPOINTS + BOXPOINTS) * points.size()); - pFaces->coordIndex.setNum((CONEFACETPOINTS + BOXFACEPOINTS) * points.size()); - int index = 0; - - for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { - SbVec3f v(p->X(), p->Y(), p->Z()); - createCone(pCoords->point, pFaces->coordIndex, - index * (CONEPOINTS + BOXPOINTS), index * (CONEFACETPOINTS + BOXFACEPOINTS), - v, *normalDirection, 2.0, 1.0); - createBox(pCoords->point, pFaces->coordIndex, - index * (CONEPOINTS + BOXPOINTS) + CONEPOINTS, index * (CONEFACETPOINTS + BOXFACEPOINTS) + CONEFACETPOINTS, - v + *normalDirection * 2.0, *normalDirection, 2.0, 2.0, 0.5); - index++; - } - } - } else if ((type == 2) || (type == 3)) { - // Bearing. Note that only one face is allowed for this constraint - SbVec3f z, y, x, p; - double radius, height; - findCylinderData(z, y, x, p, radius, height); - p = p + y * radius; - - pCoords->point.setNum(CONEPOINTS + BOXPOINTS); - pFaces->coordIndex.setNum(CONEFACETPOINTS + BOXFACEPOINTS); - if (type == 2) - // axial free - createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2.5, radius/4); - else - // axial fixed - createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2, radius/4); - - createBox(pCoords->point, pFaces->coordIndex, CONEPOINTS, CONEFACETPOINTS, p + y * radius/2, y, radius, radius, radius/10); - } else if ((type == 4) || (type == 5)) { - // Pulley, Gear - SbVec3f z, y, x, p; - double radius, height; - findCylinderData(z, y, x, p, radius, height); - - double dia = pcConstraint->Diameter.getValue(); - if (dia < Precision::Confusion()) - dia = radius * 4; - double otherdia = pcConstraint->OtherDiameter.getValue(); - if (otherdia < Precision::Confusion()) - otherdia = radius * 2; - double centerdist = pcConstraint->CenterDistance.getValue(); - if (fabs(centerdist) < Precision::Confusion()) - centerdist = 500; - - if (type == 4) { - // Pulley - pCoords->point.setNum(CYLPOINTS + 2 * ARROWPOINTS); - pFaces->coordIndex.setNum(CYLFACETPOINTS + 2 * ARROWFACETPOINTS); - createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia); - - double angle = asin((dia - otherdia)/2/centerdist); - SbVec3f p1 = p + y * dia * cos(angle) + x * dia * sin(angle); - SbVec3f dir1 = x - y * sin(angle); - dir1.normalize(); - p1 = p1 + dir1 * 2 * radius; - dir1.negate(); - SbVec3f p2 = p - y * dia * cos(angle) + x * dia * sin(angle); - SbVec3f dir2 = x + y * sin(angle); - dir2.normalize(); - p2 = p2 + dir2 * 2 * radius; - dir2.negate(); - createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, dir1, 2 * radius, radius/5); - createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS+ARROWPOINTS, CYLFACETPOINTS+ARROWFACETPOINTS, p2, dir2, 2 * radius, radius/5); - } else if (type == 5) { - // Gear - pCoords->point.setNum(CYLPOINTS + ARROWPOINTS); - pFaces->coordIndex.setNum(CYLFACETPOINTS + ARROWFACETPOINTS); - createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia); - SbVec3f p1 = p + y * dia; - createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, x, radius, radius/5); - } - } - } else if (strcmp(prop->getName(),"Direction") == 0) { - if (arrowDirection == NULL) - return; - const App::PropertyLinkSub* pr = static_cast(prop); - App::DocumentObject* obj = pr->getValue(); - std::vector names = pr->getSubValues(); - if (names.size() == 0) - return; - std::string subName = names.front(); - Part::Feature* feat = static_cast(obj); - TopoDS_Shape sh = feat->Shape.getShape().getSubShape(subName.c_str()); - - if (sh.ShapeType() == TopAbs_FACE) { - BRepAdaptor_Surface surface(TopoDS::Face(sh)); - if (surface.GetType() == GeomAbs_Plane) { - gp_Dir dir = surface.Plane().Axis().Direction(); - arrowDirection->setValue(dir.X(), dir.Y(), dir.Z()); - } else { - return; // Not a planar face - } - } else if (sh.ShapeType() == TopAbs_EDGE) { - BRepAdaptor_Curve line(TopoDS::Edge(sh)); - if (line.GetType() == GeomAbs_Line) { - gp_Dir dir = line.Line().Direction(); - arrowDirection->setValue(dir.X(), dir.Y(), dir.Z()); - } else { - return; // Not a linear edge - } - } - - // TODO: Check whether direction points inside or outside of solid? But for which reference? - - arrowDirection->normalize(); - - *normalDirection = *arrowDirection; - bool reversed = pcConstraint->Reversed.getValue(); - if (reversed) - arrowDirection->negate(); - - // Re-orient all arrows - int numArrows = pCoords->point.getNum()/ARROWPOINTS; - - for (int i = 0; i < numArrows; i++) { - // Note: for update=true the pFaces->coordIndex is not touched - SbVec3f p = pCoords->point[i * ARROWPOINTS]; - if (reversed) - p = p + *normalDirection * 5.0; - createArrow(pCoords->point, pFaces->coordIndex, - i * ARROWPOINTS, 0, - p, *arrowDirection, 5.0, 1.0, true); - } - } else if (strcmp(prop->getName(),"Reversed") == 0) { - if (arrowDirection == NULL) - return; - bool reversed = static_cast(prop)->getValue(); - bool isReversed = (*arrowDirection != *normalDirection); - if (reversed == isReversed) - return; - - *arrowDirection = *normalDirection; - if (reversed) - arrowDirection->negate(); - - // Reverse all arrows - int numArrows = pCoords->point.getNum()/ARROWPOINTS; - - for (int i = 0; i < numArrows; i++) { - createArrow(pCoords->point, pFaces->coordIndex, - i * ARROWPOINTS, 0, - pCoords->point[i * ARROWPOINTS], *arrowDirection, 5.0, 1.0, true); - } - } else if ((strcmp(prop->getName(),"Location") == 0) || (strcmp(prop->getName(),"Distance") == 0)) { - // Move bearing constraint - SbVec3f z, y, x, p; - double radius, height; - findCylinderData(z, y, x, p, radius, height); - - int type = pcConstraint->Type.getValue(); - if (type == 2) { - // axial free - createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2.5, radius/4, true); - createBox(pCoords->point, pFaces->coordIndex, CONEPOINTS, CONEFACETPOINTS, p + y * radius/2, y, radius, radius, radius/10, true); - } else if (type == 3) { - // axial fixed - createCone(pCoords->point, pFaces->coordIndex, 0, 0, p, y, radius/2, radius/4, true); - createBox(pCoords->point, pFaces->coordIndex, CONEPOINTS, CONEFACETPOINTS, p + y * radius/2, y, radius, radius, radius/10, true); - } else if ((type == 4) || (type == 5)) { - createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, pcConstraint->Diameter.getValue(), true); - } - } else if ((strcmp(prop->getName(),"Diameter") == 0) || (strcmp(prop->getName(),"OtherDiameter") == 0) || - (strcmp(prop->getName(),"CenterDistance") == 0)) { - // Update pulley/gear constraint - SbVec3f z, y, x, p; - double radius, height; - findCylinderData(z, y, x, p, radius, height); - - double dia = pcConstraint->Diameter.getValue(); - if (dia < Precision::Confusion()) - dia = radius * 4; - double otherdia = pcConstraint->OtherDiameter.getValue(); - if (otherdia < Precision::Confusion()) - otherdia = radius * 2; - double centerdist = pcConstraint->CenterDistance.getValue(); - if (fabs(centerdist) < Precision::Confusion()) - centerdist = 500; - int type = pcConstraint->Type.getValue(); - - if (type == 4) { - // Pulley - createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia, true); - - double angle = asin((dia - otherdia)/2/centerdist); - SbVec3f p1 = p + y * dia * cos(angle) + x * dia * sin(angle); - SbVec3f dir1 = x - y * sin(angle); - dir1.normalize(); - p1 = p1 + dir1 * 2 * radius; - dir1.negate(); - SbVec3f p2 = p - y * dia * cos(angle) + x * dia * sin(angle); - SbVec3f dir2 = x + y * sin(angle); - dir2.normalize(); - p2 = p2 + dir2 * 2 * radius; - dir2.negate(); - createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, dir1, 2 * radius, radius/5, true); - createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS+ARROWPOINTS, CYLFACETPOINTS+ARROWFACETPOINTS, p2, dir2, 2 * radius, radius/5, true); - } else if (type == 5) { - // Gear - createCylinder(pCoords->point, pFaces->coordIndex, 0, 0, p - z * height * 0.4, z, height * 0.8, dia, true); - SbVec3f p1 = p + y * dia; - createArrow(pCoords->point, pFaces->coordIndex, CYLPOINTS, CYLFACETPOINTS, p1, x, 2 * radius, radius/5, true); - } - } - ViewProviderDocumentObject::updateData(prop); + const SoSeparator* sep = static_cast(node); + SoTranslation* trans = static_cast(sep->getChild(idx)); + trans->translation.setValue(SbVec3f(0,-height/2,0)); + SoCone* cone = static_cast(sep->getChild(idx+1)); + cone->height.setValue(height); + cone->bottomRadius.setValue(radius); } + +#define CYLINDER_CHILDREN 1 + +void ViewProviderFemConstraint::createCylinder(SoSeparator* sep, const double height, const double radius) +{ + SoCylinder* cyl = new SoCylinder(); + cyl->ref(); + cyl->height.setValue(height); + cyl->radius.setValue(radius); + sep->addChild(cyl); +} + +SoSeparator* ViewProviderFemConstraint::createCylinder(const double height, const double radius) +{ + // Create a new cylinder node + SoSeparator* sep = new SoSeparator(); + createCylinder(sep, height, radius); + return sep; +} + +void ViewProviderFemConstraint::updateCylinder(const SoNode* node, const int idx, const double height, const double radius) +{ + const SoSeparator* sep = static_cast(node); + SoCylinder* cyl = static_cast(sep->getChild(idx)); + cyl->height.setValue(height); + cyl->radius.setValue(radius); +} + +#define CUBE_CHILDREN 1 + +void ViewProviderFemConstraint::createCube(SoSeparator* sep, const double width, const double length, const double height) +{ + SoCube* cube = new SoCube(); + cube->ref(); + cube->width.setValue(width); + cube->depth.setValue(length); + cube->height.setValue(height); + sep->addChild(cube); +} + +SoSeparator* ViewProviderFemConstraint::createCube(const double width, const double length, const double height) +{ + SoSeparator* sep = new SoSeparator(); + createCube(sep, width, length, height); + return sep; +} + +void ViewProviderFemConstraint::updateCube(const SoNode* node, const int idx, const double width, const double length, const double height) +{ + const SoSeparator* sep = static_cast(node); + SoCube* cube = static_cast(sep->getChild(idx)); + cube->width.setValue(width); + cube->depth.setValue(length); + cube->height.setValue(height); +} + +#define ARROW_CHILDREN (CONE_CHILDREN + PLACEMENT_CHILDREN + CYLINDER_CHILDREN) + +void ViewProviderFemConstraint::createArrow(SoSeparator* sep, const double length, const double radius) +{ + createCone(sep, radius, radius/2); + createPlacement(sep, SbVec3f(0, -radius/2-(length-radius)/2, 0), SbRotation()); + createCylinder(sep, length-radius, radius/5); +} + +SoSeparator* ViewProviderFemConstraint::createArrow(const double length, const double radius) +{ + SoSeparator* sep = new SoSeparator(); + createArrow(sep, length, radius); + return sep; +} + +void ViewProviderFemConstraint::updateArrow(const SoNode* node, const int idx, const double length, const double radius) +{ + const SoSeparator* sep = static_cast(node); + updateCone(sep, idx, radius, radius/2); + updatePlacement(sep, idx+CONE_CHILDREN, SbVec3f(0, -radius/2-(length-radius)/2, 0), SbRotation()); + updateCylinder(sep, idx+CONE_CHILDREN+PLACEMENT_CHILDREN, length-radius, radius/5); +} + +#define FIXED_CHILDREN (CONE_CHILDREN + PLACEMENT_CHILDREN + CUBE_CHILDREN) + +void ViewProviderFemConstraint::createFixed(SoSeparator* sep, const double height, const double width, const bool gap) +{ + createCone(sep, height-width/4, height-width/4); + createPlacement(sep, SbVec3f(0, -(height-width/4)/2-width/8 - (gap ? 1.0 : 0.1) * width/8, 0), SbRotation()); + createCube(sep, width, width, width/4); +} + +SoSeparator* ViewProviderFemConstraint::createFixed(const double height, const double width, const bool gap) +{ + SoSeparator* sep = new SoSeparator(); + createFixed(sep, height, width, gap); + return sep; +} + +void ViewProviderFemConstraint::updateFixed(const SoNode* node, const int idx, const double height, const double width, const bool gap) +{ + const SoSeparator* sep = static_cast(node); + updateCone(sep, idx, height-width/4, height-width/4); + updatePlacement(sep, idx+CONE_CHILDREN, SbVec3f(0, -(height-width/4)/2-width/8 - (gap ? 1.0 : 0.0) * width/8, 0), SbRotation()); + updateCube(sep, idx+CONE_CHILDREN+PLACEMENT_CHILDREN, width, width, width/4); +} + diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h index 94b434d2ad..09ca86eaf6 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h @@ -33,14 +33,14 @@ class SoFontStyle; class SoText2; class SoBaseColor; class SoTranslation; -class SoCoordinate3; -class SoIndexedLineSet; -class SoIndexedFaceSet; -class SoEventCallback; -class SoMarkerSet; +class SbRotation; +class SoMaterial; namespace Gui { class View3DInventorViewer; + namespace TaskView { + class TaskDialog; + } } namespace FemGui @@ -58,12 +58,13 @@ public: // Display properties App::PropertyColor TextColor; App::PropertyColor FaceColor; + App::PropertyColor ShapeColor; App::PropertyInteger FontSize; App::PropertyFloat DistFactor; App::PropertyBool Mirror; void attach(App::DocumentObject *); - void updateData(const App::Property*); + virtual void updateData(const App::Property*) {} std::vector getDisplayModes(void) const; void setDisplayMode(const char* ModeName); @@ -72,24 +73,37 @@ public: protected: void onChanged(const App::Property* prop); - virtual bool setEdit(int ModNum); + virtual bool setEdit(int ModNum) {} virtual void unsetEdit(int ModNum); + static void createPlacement(SoSeparator* sep, const SbVec3f &base, const SbRotation &r); + static void updatePlacement(const SoSeparator* sep, const int idx, const SbVec3f &base, const SbRotation &r); + static void createCone(SoSeparator* sep, const double height, const double radius); + static SoSeparator* createCone(const double height, const double radius); + static void updateCone(const SoNode* node, const int idx, const double height, const double radius); + static void createCylinder(SoSeparator* sep, const double height, const double radius); + static SoSeparator* createCylinder(const double height, const double radius); + static void updateCylinder(const SoNode* node, const int idx, const double height, const double radius); + static void createCube(SoSeparator* sep, const double width, const double length, const double height); + static SoSeparator* createCube(const double width, const double length, const double height); + static void updateCube(const SoNode* node, const int idx, const double width, const double length, const double height); + 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 createFixed(SoSeparator* sep, const double height, const double width, const bool gap); + 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); + private: SoFontStyle * pFont; SoText2 * pLabel; - SoBaseColor * pColor; SoBaseColor * pTextColor; - SoTranslation * pTranslation; - SoCoordinate3 * pCoords; - SoIndexedFaceSet * pFaces; + SoMaterial * pMaterials; - /// Direction pointing outside of the solid - SbVec3f * normalDirection; - /// Direction of the force - SbVec3f * arrowDirection; +protected: + SoSeparator * pShapeSep; - void findCylinderData(SbVec3f& z, SbVec3f& y, SbVec3f& x, SbVec3f& p, double& radius, double& height); + Gui::TaskView::TaskDialog *oldDlg; }; } //namespace FemGui diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp new file mode 100644 index 0000000000..bf6a7cf412 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp @@ -0,0 +1,142 @@ +/*************************************************************************** + * 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 +#endif + +#include "ViewProviderFemConstraintBearing.h" +#include +#include "TaskFemConstraintBearing.h" +#include "Gui/Control.h" + +#include + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintBearing, FemGui::ViewProviderFemConstraint) + + +ViewProviderFemConstraintBearing::ViewProviderFemConstraintBearing() +{ + sPixmap = "view-femconstraintbearing"; +} + +ViewProviderFemConstraintBearing::~ViewProviderFemConstraintBearing() +{ +} + +bool ViewProviderFemConstraintBearing::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(); + TaskDlgFemConstraintBearing *constrDlg = qobject_cast(dlg); + if (constrDlg && constrDlg->getConstraintView() != this) + constrDlg = 0; // another constraint left open its task panel + if (dlg && !constrDlg) { + // Allow stacking of dialogs, for ShaftWizard application + // Note: If other features start to allow stacking, we need to check for oldDlg != NULL + oldDlg = dlg; + /* + 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().closeDialog(); + else + return false; + */ + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (constrDlg) + Gui::Control().showDialog(constrDlg); + else + Gui::Control().showDialog(new TaskDlgFemConstraintBearing(this)); + + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); + } +} + +void ViewProviderFemConstraintBearing::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + Fem::ConstraintBearing* pcConstraint = static_cast(this->getObject()); + if (this->getObject() != NULL) + Base::Console().Error("%s: VP updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); + else + Base::Console().Error("Anonymous: VP updateData: %s\n", prop->getName()); + + if (strcmp(prop->getName(),"BasePoint") == 0) { + // Remove and recreate the symbol + pShapeSep->removeAllChildren(); + + // This should always point outside of the cylinder + Base::Vector3f normal = pcConstraint->NormalDirection.getValue(); + Base::Vector3f base = pcConstraint->BasePoint.getValue(); + float radius = pcConstraint->Radius.getValue(); + base = base + radius * normal; + + SbVec3f b(base.x, base.y, base.z); + SbVec3f dir(normal.x, normal.y, normal.z); + SbRotation rot(SbVec3f(0,-1,0), dir); + + createPlacement(pShapeSep, b, rot); + pShapeSep->addChild(createFixed(radius/2, radius/2 * 1.5, pcConstraint->AxialFree.getValue())); + } else if (strcmp(prop->getName(),"AxialFree") == 0) { + if (pShapeSep->getNumChildren() > 0) { + // Change the symbol + Base::Vector3f normal = pcConstraint->NormalDirection.getValue(); + Base::Vector3f base = pcConstraint->BasePoint.getValue(); + float radius = pcConstraint->Radius.getValue(); + base = base + radius * normal; + + SbVec3f b(base.x, base.y, base.z); + SbVec3f dir(normal.x, normal.y, normal.z); + SbRotation rot(SbVec3f(0,-1,0), dir); + + updatePlacement(pShapeSep, 0, b, rot); + const SoSeparator* sep = static_cast(pShapeSep->getChild(2)); + updateFixed(sep, 0, radius/2, radius/2 * 1.5, pcConstraint->AxialFree.getValue()); + } + } + + ViewProviderFemConstraint::updateData(prop); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.h new file mode 100644 index 0000000000..a7ceff6dfe --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * 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 GUI_VIEWPROVIDERFEMCONSTRAINTBEARING_H +#define GUI_VIEWPROVIDERFEMCONSTRAINTBEARING_H + +#include + +#include "ViewProviderFemConstraint.h" +#include + +class SoFontStyle; +class SoText2; +class SoBaseColor; +class SoTranslation; +class SbRotation; +class SoMaterial; +class SoLightModel; +class SoCoordinate3; +class SoIndexedLineSet; +class SoIndexedFaceSet; +class SoEventCallback; +class SoMarkerSet; + +namespace Gui { +class View3DInventorViewer; + namespace TaskView { + class TaskDialog; + } +} + +namespace FemGui +{ + +class FemGuiExport ViewProviderFemConstraintBearing : public FemGui::ViewProviderFemConstraint +{ + PROPERTY_HEADER(FemGui::ViewProviderFemConstraintBearing); + +public: + /// Constructor + ViewProviderFemConstraintBearing(); + virtual ~ViewProviderFemConstraintBearing(); + + virtual void updateData(const App::Property*); + +protected: + virtual bool setEdit(int ModNum); + +}; + +} //namespace FemGui + + +#endif // GUI_VIEWPROVIDERFEMCONSTRAINTBEARING_H diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp new file mode 100644 index 0000000000..74727e5ac3 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp @@ -0,0 +1,147 @@ +/*************************************************************************** + * 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 + +#endif + +#include "ViewProviderFemConstraintFixed.h" +#include +#include "TaskFemConstraintFixed.h" + +#include "Gui/Control.h" + +#include + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintFixed, FemGui::ViewProviderFemConstraint) + + +ViewProviderFemConstraintFixed::ViewProviderFemConstraintFixed() +{ + sPixmap = "view-femconstraintfixed"; +} + +ViewProviderFemConstraintFixed::~ViewProviderFemConstraintFixed() +{ +} + +bool ViewProviderFemConstraintFixed::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(); + TaskDlgFemConstraintFixed *constrDlg = qobject_cast(dlg); + if (constrDlg && constrDlg->getConstraintView() != this) + constrDlg = 0; // another constraint left open its task panel + if (dlg && !constrDlg) { + // Allow stacking of dialogs, for ShaftWizard application + // Note: If other features start to allow stacking, we need to check for oldDlg != NULL + oldDlg = dlg; + /* + 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().closeDialog(); + else + return false; + */ + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (constrDlg) + Gui::Control().showDialog(constrDlg); + else + Gui::Control().showDialog(new TaskDlgFemConstraintFixed(this)); + + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); + } +} + +#define HEIGHT 4 +#define WIDTH (1.5*HEIGHT) + +void ViewProviderFemConstraintFixed::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + if (this->getObject() != NULL) + Base::Console().Error("%s: VPF updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); + else + Base::Console().Error("Anonymous: VPF updateData: %s\n", prop->getName()); + + Fem::ConstraintFixed* pcConstraint = static_cast(this->getObject()); + + if (pShapeSep->getNumChildren() == 0) { + // Set up the nodes + SoMultipleCopy* cp = new SoMultipleCopy(); + cp->ref(); + cp->matrix.setNum(0); + cp->addChild((SoNode*)createFixed(HEIGHT, WIDTH)); + pShapeSep->addChild(cp); + } + + if (strcmp(prop->getName(),"Points") == 0) { + // Note: Points and Normals are always updated together + + const std::vector& points = pcConstraint->Points.getValues(); + const std::vector& normals = pcConstraint->Normals.getValues(); + std::vector::const_iterator n = normals.begin(); + SoMultipleCopy* cp = static_cast(pShapeSep->getChild(0)); + cp->matrix.setNum(points.size()); + int idx = 0; + + 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), dir); + SbMatrix m; + m.setTransform(base, rot, SbVec3f(1,1,1)); + cp->matrix.set1Value(idx, m); + n++; + idx++; + } + } + + ViewProviderFemConstraint::updateData(prop); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.h new file mode 100644 index 0000000000..ff9825e8a0 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * 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 GUI_VIEWPROVIDERFEMCONSTRAINTFIXED_H +#define GUI_VIEWPROVIDERFEMCONSTRAINTFIXED_H + +#include + +#include "ViewProviderFemConstraint.h" +#include + +class SoFontStyle; +class SoText2; +class SoBaseColor; +class SoTranslation; +class SbRotation; +class SoMaterial; +class SoLightModel; +class SoCoordinate3; +class SoIndexedLineSet; +class SoIndexedFaceSet; +class SoEventCallback; +class SoMarkerSet; + +namespace Gui { +class View3DInventorViewer; + namespace TaskView { + class TaskDialog; + } +} + +namespace FemGui +{ + +class FemGuiExport ViewProviderFemConstraintFixed : public FemGui::ViewProviderFemConstraint +{ + PROPERTY_HEADER(FemGui::ViewProviderFemConstraintFixed); + +public: + /// Constructor + ViewProviderFemConstraintFixed(); + virtual ~ViewProviderFemConstraintFixed(); + + virtual void updateData(const App::Property*); + +protected: + virtual bool setEdit(int ModNum); + +}; + +} //namespace FemGui + + +#endif // GUI_VIEWPROVIDERFEMCONSTRAINTFIXED_H diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp new file mode 100644 index 0000000000..b29a65f9a5 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp @@ -0,0 +1,196 @@ +/*************************************************************************** + * 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 + +#endif + +#include "ViewProviderFemConstraintForce.h" +#include +#include "TaskFemConstraintForce.h" +#include "Gui/Control.h" + +#include + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintForce, FemGui::ViewProviderFemConstraint) + + +ViewProviderFemConstraintForce::ViewProviderFemConstraintForce() +{ + sPixmap = "view-femconstraintforce"; +} + +ViewProviderFemConstraintForce::~ViewProviderFemConstraintForce() +{ +} + +bool ViewProviderFemConstraintForce::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(); + TaskDlgFemConstraintForce *constrDlg = qobject_cast(dlg); + if (constrDlg && constrDlg->getConstraintView() != this) + constrDlg = 0; // another constraint left open its task panel + if (dlg && !constrDlg) { + // Allow stacking of dialogs, for ShaftWizard application + // Note: If other features start to allow stacking, we need to check for oldDlg != NULL + oldDlg = dlg; + /* + 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().closeDialog(); + else + return false; + */ + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (constrDlg) + Gui::Control().showDialog(constrDlg); + else + Gui::Control().showDialog(new TaskDlgFemConstraintForce(this)); + + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); + } +} + +#define ARROWLENGTH 9 +#define ARROWHEADRADIUS (ARROWLENGTH/3) + +void ViewProviderFemConstraintForce::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + if (this->getObject() != NULL) + Base::Console().Error("%s: VPF updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); + else + Base::Console().Error("Anonymous: VPF updateData: %s\n", prop->getName()); + + Fem::ConstraintForce* pcConstraint = static_cast(this->getObject()); + + /* + if (pShapeSep->getNumChildren() == 0) { + // Set up the nodes + SoMultipleCopy* cp = new SoMultipleCopy(); + cp->ref(); + cp->matrix.setNum(0); + cp->addChild((SoNode*)createArrow(ARROWLENGTH, ARROWHEADRADIUS)); + pShapeSep->addChild(cp); + } + */ + + if (strcmp(prop->getName(),"Points") == 0) { + // Redraw all arrows + pShapeSep->removeAllChildren(); + + // This should always point outside of the solid + Base::Vector3f normal = pcConstraint->NormalDirection.getValue(); + + // Get default direction (on first call to method) + Base::Vector3f forceDirection = pcConstraint->DirectionVector.getValue(); + if (forceDirection.Length() < Precision::Confusion()) + forceDirection = normal; + + SbVec3f dir(forceDirection.x, forceDirection.y, forceDirection.z); + SbRotation rot(SbVec3f(0,1,0), dir); + + const std::vector& points = pcConstraint->Points.getValues(); + + /* + SoMultipleCopy* cp = static_cast(pShapeSep->getChild(0)); + cp->matrix.setNum(points.size()); + int idx = 0;*/ + + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + SbVec3f base(p->x, p->y, p->z); + if (forceDirection.GetAngle(normal) < M_PI_2) // Move arrow so it doesn't disappear inside the solid + base = base + dir * ARROWLENGTH; + /* + SbMatrix m; + m.setTransform(base, rot, SbVec3f(1,1,1)); + cp->matrix.set1Value(idx, m); + idx++; + */ + SoSeparator* sep = new SoSeparator(); + createPlacement(sep, base, rot); + createArrow(sep, ARROWLENGTH, ARROWHEADRADIUS); + pShapeSep->addChild(sep); + } + } else if (strcmp(prop->getName(),"DirectionVector") == 0) { // Note: "Reversed" also triggers "DirectionVector" + // Re-orient all arrows + Base::Vector3f normal = pcConstraint->NormalDirection.getValue(); + Base::Vector3f forceDirection = pcConstraint->DirectionVector.getValue(); + if (forceDirection.Length() < Precision::Confusion()) + forceDirection = normal; + + SbVec3f dir(forceDirection.x, forceDirection.y, forceDirection.z); + SbRotation rot(SbVec3f(0,1,0), dir); + + const std::vector& points = pcConstraint->Points.getValues(); + + /* + SoMultipleCopy* cp = static_cast(pShapeSep->getChild(0)); + cp->matrix.setNum(points.size()); + */ + int idx = 0; + + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + SbVec3f base(p->x, p->y, p->z); + if (forceDirection.GetAngle(normal) < M_PI_2) + base = base + dir * ARROWLENGTH; + /* + SbMatrix m; + m.setTransform(base, rot, SbVec3f(1,1,1)); + cp->matrix.set1Value(idx, m);*/ + + SoSeparator* sep = static_cast(pShapeSep->getChild(idx)); + updatePlacement(sep, 0, base, rot); + updateArrow(sep, 2, ARROWLENGTH, ARROWHEADRADIUS); + idx++; + } + } + + ViewProviderFemConstraint::updateData(prop); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.h new file mode 100644 index 0000000000..ba6027fc61 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.h @@ -0,0 +1,78 @@ +/*************************************************************************** + * 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 GUI_VIEWPROVIDERFEMCONSTRAINTFORCE_H +#define GUI_VIEWPROVIDERFEMCONSTRAINTFORCE_H + +#include + +#include "ViewProviderFemConstraint.h" +#include + +class SoFontStyle; +class SoText2; +class SoBaseColor; +class SoTranslation; +class SbRotation; +class SoMaterial; +class SoLightModel; +class SoCoordinate3; +class SoIndexedLineSet; +class SoIndexedFaceSet; +class SoEventCallback; +class SoMarkerSet; + +namespace Gui { +class View3DInventorViewer; + namespace TaskView { + class TaskDialog; + } +} + +namespace FemGui +{ + +class FemGuiExport ViewProviderFemConstraintForce : public FemGui::ViewProviderFemConstraint +{ + PROPERTY_HEADER(FemGui::ViewProviderFemConstraintForce); + +public: + /// Constructor + ViewProviderFemConstraintForce(); + virtual ~ViewProviderFemConstraintForce(); + + virtual void updateData(const App::Property*); + +protected: + virtual bool setEdit(int ModNum); + +private: + /// Direction of the force + Base::Vector3f forceDirection; + +}; + +} //namespace FemGui + + +#endif // GUI_VIEWPROVIDERFEMCONSTRAINTFORCE_H diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp new file mode 100644 index 0000000000..16ff06f50a --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp @@ -0,0 +1,154 @@ +/*************************************************************************** + * 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 +#endif + +#include "ViewProviderFemConstraintGear.h" +#include +#include "TaskFemConstraintGear.h" +#include "Gui/Control.h" + +#include + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintGear, FemGui::ViewProviderFemConstraint) + + +ViewProviderFemConstraintGear::ViewProviderFemConstraintGear() +{ + sPixmap = "view-femconstraintgear"; +} + +ViewProviderFemConstraintGear::~ViewProviderFemConstraintGear() +{ +} + +bool ViewProviderFemConstraintGear::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(); + TaskDlgFemConstraintGear *constrDlg = qobject_cast(dlg); + if (constrDlg && constrDlg->getConstraintView() != this) + constrDlg = 0; // another constraint left open its task panel + if (dlg && !constrDlg) { + // Allow stacking of dialogs, for ShaftWizard application + // Note: If other features start to allow stacking, we need to check for oldDlg != NULL + oldDlg = dlg; + /* + 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().closeDialog(); + else + return false; + */ + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (constrDlg) + Gui::Control().showDialog(constrDlg); + else + Gui::Control().showDialog(new TaskDlgFemConstraintGear(this)); + + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); + } +} + +void ViewProviderFemConstraintGear::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + Fem::ConstraintGear* pcConstraint = static_cast(this->getObject()); + if (this->getObject() != NULL) + Base::Console().Error("%s: VP updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); + else + Base::Console().Error("Anonymous: VP updateData: %s\n", prop->getName()); + + if (strcmp(prop->getName(),"BasePoint") == 0) { + if (pcConstraint->Height.getValue() > Precision::Confusion()) { + // Remove and recreate the symbol + pShapeSep->removeAllChildren(); + + // This should always point outside of the cylinder + Base::Vector3f base = pcConstraint->BasePoint.getValue(); + Base::Vector3f axis = pcConstraint->Axis.getValue(); + float radius = pcConstraint->Radius.getValue(); + float dia = pcConstraint->Diameter.getValue(); + if (dia < 2 * radius) + dia = 2 * radius; + + SbVec3f b(base.x, base.y, base.z); + SbVec3f dir(axis.x, axis.y, axis.z); + SbRotation rot(SbVec3f(0,1,0), dir); + + createPlacement(pShapeSep, b, rot); + pShapeSep->addChild(createCylinder(pcConstraint->Height.getValue() * 0.8, dia/2)); + createPlacement(pShapeSep, SbVec3f(0,0,dia/2), SbRotation(SbVec3f(0,1,0), SbVec3f(1,0,0))); + pShapeSep->addChild(createArrow(dia/2, dia/8)); + } + } else if (strcmp(prop->getName(),"Diameter") == 0) { + if (pShapeSep->getNumChildren() > 0) { + // Change the symbol + Base::Vector3f base = pcConstraint->BasePoint.getValue(); + Base::Vector3f axis = pcConstraint->Axis.getValue(); + //float radius = pcConstraint->Radius.getValue(); + float dia = pcConstraint->Diameter.getValue(); + float radius = pcConstraint->Radius.getValue(); + if (dia < 2 * radius) + dia = 2 * radius; + + SbVec3f b(base.x, base.y, base.z); + SbVec3f dir(axis.x, axis.y, axis.z); + SbRotation rot(SbVec3f(0,1,0), dir); + + updatePlacement(pShapeSep, 0, b, rot); + const SoSeparator* sep = static_cast(pShapeSep->getChild(2)); + updateCylinder(sep, 0, pcConstraint->Height.getValue() * 0.8, dia/2); + updatePlacement(pShapeSep, 3, SbVec3f(0,0,dia/2), SbRotation(SbVec3f(0,1,0), SbVec3f(1,0,0))); + sep = static_cast(pShapeSep->getChild(5)); + updateArrow(sep, 0, dia/2, dia/8); + } + } + + ViewProviderFemConstraint::updateData(prop); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.h new file mode 100644 index 0000000000..55f08a1adf --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * 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 GUI_VIEWPROVIDERFEMCONSTRAINTGear_H +#define GUI_VIEWPROVIDERFEMCONSTRAINTGear_H + +#include + +#include "ViewProviderFemConstraint.h" +#include + +class SoFontStyle; +class SoText2; +class SoBaseColor; +class SoTranslation; +class SbRotation; +class SoMaterial; +class SoLightModel; +class SoCoordinate3; +class SoIndexedLineSet; +class SoIndexedFaceSet; +class SoEventCallback; +class SoMarkerSet; + +namespace Gui { +class View3DInventorViewer; + namespace TaskView { + class TaskDialog; + } +} + +namespace FemGui +{ + +class FemGuiExport ViewProviderFemConstraintGear : public FemGui::ViewProviderFemConstraint +{ + PROPERTY_HEADER(FemGui::ViewProviderFemConstraintGear); + +public: + /// Constructor + ViewProviderFemConstraintGear(); + virtual ~ViewProviderFemConstraintGear(); + + virtual void updateData(const App::Property*); + +protected: + virtual bool setEdit(int ModNum); + +}; + +} //namespace FemGui + + +#endif // GUI_VIEWPROVIDERFEMCONSTRAINTGear_H diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp new file mode 100644 index 0000000000..abdd3ec3e3 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp @@ -0,0 +1,166 @@ +/*************************************************************************** + * 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 +#endif + +#include "ViewProviderFemConstraintPulley.h" +#include +#include "TaskFemConstraintPulley.h" +#include "Gui/Control.h" + +#include + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintPulley, FemGui::ViewProviderFemConstraint) + + +ViewProviderFemConstraintPulley::ViewProviderFemConstraintPulley() +{ + sPixmap = "view-femconstraintpulley"; +} + +ViewProviderFemConstraintPulley::~ViewProviderFemConstraintPulley() +{ +} + +bool ViewProviderFemConstraintPulley::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(); + TaskDlgFemConstraintPulley *constrDlg = qobject_cast(dlg); + if (constrDlg && constrDlg->getConstraintView() != this) + constrDlg = 0; // another constraint left open its task panel + if (dlg && !constrDlg) { + // Allow stacking of dialogs, for ShaftWizard application + // Note: If other features start to allow stacking, we need to check for oldDlg != NULL + oldDlg = dlg; + /* + 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().closeDialog(); + else + return false; + */ + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (constrDlg) + Gui::Control().showDialog(constrDlg); + else + Gui::Control().showDialog(new TaskDlgFemConstraintPulley(this)); + + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); + } +} + +void ViewProviderFemConstraintPulley::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + Fem::ConstraintPulley* pcConstraint = static_cast(this->getObject()); + if (this->getObject() != NULL) + Base::Console().Error("%s: VP updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); + else + Base::Console().Error("Anonymous: VP updateData: %s\n", prop->getName()); + + if (strcmp(prop->getName(),"BasePoint") == 0) { + if (pcConstraint->Height.getValue() > Precision::Confusion()) { + // Remove and recreate the symbol + pShapeSep->removeAllChildren(); + + // This should always point outside of the cylinder + Base::Vector3f base = pcConstraint->BasePoint.getValue(); + Base::Vector3f axis = pcConstraint->Axis.getValue(); + float radius = pcConstraint->Radius.getValue(); + float dia = pcConstraint->Diameter.getValue(); + if (dia < 2 * radius) + dia = 2 * radius; + float angle = pcConstraint->Angle.getValue(); + + SbVec3f b(base.x, base.y, base.z); + SbVec3f dir(axis.x, axis.y, axis.z); + SbRotation rot(SbVec3f(0,-1,0), dir); + + createPlacement(pShapeSep, b, rot); // child 0 and 1 + pShapeSep->addChild(createCylinder(pcConstraint->Height.getValue() * 0.8, dia/2)); // child 2 + SoSeparator* sep = new SoSeparator(); + createPlacement(sep, SbVec3f(dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(sin(angle),0,cos(angle)))); + sep->addChild(createArrow(dia/2, dia/8)); + pShapeSep->addChild(sep); // child 3 + sep = new SoSeparator(); + createPlacement(sep, SbVec3f(-dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(-sin(angle),0,cos(angle)))); + sep->addChild(createArrow(dia/2, dia/8)); + pShapeSep->addChild(sep); // child 4 + } + } else if (strcmp(prop->getName(),"Angle") == 0) { + if (pShapeSep->getNumChildren() > 0) { + // Change the symbol + Base::Vector3f base = pcConstraint->BasePoint.getValue(); + Base::Vector3f axis = pcConstraint->Axis.getValue(); + float radius = pcConstraint->Radius.getValue(); + float dia = pcConstraint->Diameter.getValue(); + if (dia < 2 * radius) + dia = 2 * radius; + float angle = pcConstraint->Angle.getValue(); + + SbVec3f b(base.x, base.y, base.z); + SbVec3f dir(axis.x, axis.y, axis.z); + SbRotation rot(SbVec3f(0,-1,0), dir); + + updatePlacement(pShapeSep, 0, b, rot); + const SoSeparator* sep = static_cast(pShapeSep->getChild(2)); + updateCylinder(sep, 0, pcConstraint->Height.getValue() * 0.8, dia/2); + sep = static_cast(pShapeSep->getChild(3)); + updatePlacement(sep, 0, SbVec3f(0,0,dia/2), SbRotation(SbVec3f(0,1,0), SbVec3f(cos(angle),0,sin(angle)))); + const SoSeparator* subsep = static_cast(sep->getChild(2)); + updateArrow(subsep, 0, dia/2, dia/8); + sep = static_cast(pShapeSep->getChild(4)); + updatePlacement(sep, 0, SbVec3f(0,0,-dia/2), SbRotation(SbVec3f(0,1,0), SbVec3f(cos(angle),0,-sin(angle)))); + subsep = static_cast(sep->getChild(2)); + updateArrow(subsep, 0, dia/2, dia/8); + } + } + + ViewProviderFemConstraint::updateData(prop); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.h new file mode 100644 index 0000000000..50d14d6507 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * 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 GUI_VIEWPROVIDERFEMCONSTRAINTPulley_H +#define GUI_VIEWPROVIDERFEMCONSTRAINTPulley_H + +#include + +#include "ViewProviderFemConstraint.h" +#include + +class SoFontStyle; +class SoText2; +class SoBaseColor; +class SoTranslation; +class SbRotation; +class SoMaterial; +class SoLightModel; +class SoCoordinate3; +class SoIndexedLineSet; +class SoIndexedFaceSet; +class SoEventCallback; +class SoMarkerSet; + +namespace Gui { +class View3DInventorViewer; + namespace TaskView { + class TaskDialog; + } +} + +namespace FemGui +{ + +class FemGuiExport ViewProviderFemConstraintPulley : public FemGui::ViewProviderFemConstraint +{ + PROPERTY_HEADER(FemGui::ViewProviderFemConstraintPulley); + +public: + /// Constructor + ViewProviderFemConstraintPulley(); + virtual ~ViewProviderFemConstraintPulley(); + + virtual void updateData(const App::Property*); + +protected: + virtual bool setEdit(int ModNum); + +}; + +} //namespace FemGui + + +#endif // GUI_VIEWPROVIDERFEMCONSTRAINTPulley_H diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index c4d3a73673..763c204759 100755 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -57,7 +57,11 @@ Gui::ToolBarItem* Workbench::setupToolBars() const fem->setCommand("FEM"); *fem << "Fem_CreateFromShape" << "Fem_CreateNodesSet" - << "Fem_Constraint"; + << "Fem_ConstraintFixed" + << "Fem_ConstraintForce" + << "Fem_ConstraintBearing" + << "Fem_ConstraintGear" + << "Fem_ConstraintPulley"; return root; } @@ -70,7 +74,11 @@ Gui::MenuItem* Workbench::setupMenuBar() const fem->setCommand("&FEM"); *fem << "Fem_CreateFromShape" << "Fem_CreateNodesSet" - << "Fem_Constraint"; + << "Fem_ConstraintFixed" + << "Fem_ConstraintForce" + << "Fem_ConstraintBearing" + << "Fem_ConstraintGear" + << "Fem_ConstraintPulley"; return root; } diff --git a/src/Mod/PartDesign/WizardShaft/InitGui.py b/src/Mod/PartDesign/WizardShaft/InitGui.py deleted file mode 100644 index 73e570ce2a..0000000000 --- a/src/Mod/PartDesign/WizardShaft/InitGui.py +++ /dev/null @@ -1,76 +0,0 @@ -# PartDesign gui init module -# (c) 2003 Juergen Riegel -# -# Gathering all the information to start FreeCAD -# This is the second one of three init scripts, the third one -# runs when the gui is up - -#*************************************************************************** -#* (c) Juergen Riegel (juergen.riegel@web.de) 2002 * -#* * -#* 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 General Public License (GPL) * -#* 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. * -#* * -#* FreeCAD 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 FreeCAD; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#* Juergen Riegel 2002 * -#***************************************************************************/ - -class PartDesignWorkbench ( Workbench ): - "PartDesign workbench object" - from WizardShaft import WizardShaft - Icon = """ - /* XPM */ - static char * partdesign_xpm[] = { - "16 16 9 1", - " c None", - ". c #040006", - "+ c #070F38", - "@ c #002196", - "# c #0030F3", - "$ c #5A4D20", - "% c #858EB2", - "& c #DEB715", - "* c #BFB99D", - " & ........ ", - "&&&$..@@@@@@+...", - "&&&&$@#####@..@.", - "&&&&&$......@#@.", - "&&&&&&@@@+.###@.", - "$&&&&&&@#@.###@.", - ".$&&&&&%#@.###@.", - ".@*&&&*%#@.###@.", - ".@#*&**%#@.###@.", - ".@#@%%%.@@.###@.", - ".@@@@@@@#@.###@.", - ".@#######@.###@.", - ".@#######@.##+. ", - ".+@@@####@.@.. ", - " ......+++.. ", - " ... "}; - """ - MenuText = "Part Design" - ToolTip = "Part Design workbench" - - def Initialize(self): - # load the module - import PartDesignGui - import PartDesign - def GetClassName(self): - return "PartDesignGui::Workbench" - -Gui.addWorkbench(PartDesignWorkbench()) - From 517443fb595b3beca0aba034e993d950e159ba0f Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 22 Feb 2013 16:16:03 +0430 Subject: [PATCH 3/9] Fixed problems with loading of FEM constraint objects --- src/Mod/Fem/App/FemConstraint.cpp | 34 +++++++++++-------- src/Mod/Fem/App/FemConstraint.h | 5 ++- src/Mod/Fem/App/FemConstraintBearing.cpp | 10 +++--- src/Mod/Fem/App/FemConstraintFixed.cpp | 9 ++--- src/Mod/Fem/App/FemConstraintForce.cpp | 7 ++-- src/Mod/Fem/Gui/TaskFemConstraint.h | 6 ++-- src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp | 2 ++ src/Mod/Fem/Gui/ViewProviderFemConstraint.h | 6 ++-- .../Gui/ViewProviderFemConstraintBearing.cpp | 8 +++-- .../Gui/ViewProviderFemConstraintFixed.cpp | 16 ++++++++- .../Gui/ViewProviderFemConstraintForce.cpp | 2 ++ .../Fem/Gui/ViewProviderFemConstraintGear.cpp | 4 +-- .../Gui/ViewProviderFemConstraintPulley.cpp | 4 +-- 13 files changed, 72 insertions(+), 41 deletions(-) diff --git a/src/Mod/Fem/App/FemConstraint.cpp b/src/Mod/Fem/App/FemConstraint.cpp index 008c0ec2a3..98d7fc92f1 100644 --- a/src/Mod/Fem/App/FemConstraint.cpp +++ b/src/Mod/Fem/App/FemConstraint.cpp @@ -78,9 +78,8 @@ App::DocumentObjectExecReturn *Constraint::execute(void) void Constraint::onChanged(const App::Property* prop) { - //Base::Console().Error("Constraint::onChanged()\n"); + Base::Console().Error("Constraint::onChanged() %s\n", prop->getName()); if (prop == &References) { - Base::Console().Error("References\n"); // If References are changed, recalculate the normal direction. If no useful reference is found, // use z axis or previous value. If several faces are selected, only the first one is used std::vector Objects = References.getValues(); @@ -108,28 +107,24 @@ void Constraint::onChanged(const App::Property* prop) normal.Normalize(); NormalDirection.setValue(normal.X(), normal.Y(), normal.Z()); // One face is enough... - DocumentObject::onChanged(prop); + App::DocumentObject::onChanged(prop); return; } } } } - DocumentObject::onChanged(prop); + App::DocumentObject::onChanged(prop); } void Constraint::onDocumentRestored() { - Base::Console().Error("onDocumentRestored\n"); + // This seems to be the only way to make the ViewProvider display the constraint + References.touch(); + App::DocumentObject::onDocumentRestored(); } - -void Constraint::onSettingDocument() -{ - Base::Console().Error("onSettingDocument\n"); -} - -void Constraint::getPoints(std::vector &points, std::vector &normals) const +const bool Constraint::getPoints(std::vector &points, std::vector &normals) const { std::vector Objects = References.getValues(); std::vector SubElements = References.getSubValues(); @@ -141,6 +136,8 @@ void Constraint::getPoints(std::vector &points, std::vector(obj); const Part::TopoShape& toposhape = feat->Shape.getShape(); + if (toposhape.isNull()) + return false; sh = toposhape.getSubShape(SubElements[i].c_str()); if (sh.ShapeType() == TopAbs_VERTEX) { @@ -219,17 +216,22 @@ void Constraint::getPoints(std::vector &points, std::vector Objects = References.getValues(); std::vector SubElements = References.getSubValues(); if (Objects.empty()) - return; + return false; App::DocumentObject* obj = Objects[0]; Part::Feature* feat = static_cast(obj); - TopoDS_Shape sh = feat->Shape.getShape().getSubShape(SubElements[0].c_str()); + Part::TopoShape toposhape = feat->Shape.getShape(); + if (toposhape.isNull()) + return false; + TopoDS_Shape sh = toposhape.getSubShape(SubElements[0].c_str()); TopoDS_Face face = TopoDS::Face(sh); BRepAdaptor_Surface surface(face); @@ -243,6 +245,8 @@ void Constraint::getCylinder(float& radius, float& height, Base::Vector3f& base, base = Base::Vector3f(b.X(), b.Y(), b.Z()); gp_Dir dir = cyl.Axis().Direction(); axis = Base::Vector3f(dir.X(), dir.Y(), dir.Z()); + + return true; } Base::Vector3f Constraint::getBasePoint(const Base::Vector3f& base, const Base::Vector3f& axis, diff --git a/src/Mod/Fem/App/FemConstraint.h b/src/Mod/Fem/App/FemConstraint.h index 02c0bfd9d5..1814183278 100644 --- a/src/Mod/Fem/App/FemConstraint.h +++ b/src/Mod/Fem/App/FemConstraint.h @@ -55,12 +55,11 @@ public: protected: virtual void onChanged(const App::Property* prop); virtual void onDocumentRestored(); - virtual void onSettingDocument(); protected: /// Calculate the points where symbols should be drawn - void getPoints(std::vector& points, std::vector& normals) const; - void getCylinder(float& radius, float& height, Base::Vector3f& base, Base::Vector3f& axis) const; + const bool getPoints(std::vector& points, std::vector& normals) const; + const bool getCylinder(float& radius, float& height, Base::Vector3f& base, Base::Vector3f& axis) const; Base::Vector3f getBasePoint(const Base::Vector3f& base, const Base::Vector3f& axis, const App::PropertyLinkSub &location, const float& dist); diff --git a/src/Mod/Fem/App/FemConstraintBearing.cpp b/src/Mod/Fem/App/FemConstraintBearing.cpp index 3ecf7ea4c4..51aa790d0d 100644 --- a/src/Mod/Fem/App/FemConstraintBearing.cpp +++ b/src/Mod/Fem/App/FemConstraintBearing.cpp @@ -58,11 +58,13 @@ ConstraintBearing::ConstraintBearing() App::DocumentObjectExecReturn *ConstraintBearing::execute(void) { + Base::Console().Error("ConstraintBearing: execute()\n"); return Constraint::execute(); } void ConstraintBearing::onChanged(const App::Property* prop) { + Base::Console().Error("ConstraintBearing: onChanged %s\n", prop->getName()); // Note: If we call this at the end, then the symbol ist not oriented correctly initially // because the NormalDirection has not been calculated yet Constraint::onChanged(prop); @@ -71,7 +73,8 @@ void ConstraintBearing::onChanged(const App::Property* prop) // Find data of cylinder float radius, height; Base::Vector3f base, axis; - getCylinder(radius, height, base, axis); + if (!getCylinder(radius, height, base, axis)) + return; Radius.setValue(radius); Axis.setValue(axis); Height.setValue(height); @@ -80,7 +83,6 @@ void ConstraintBearing::onChanged(const App::Property* prop) if (Location.getValue() != NULL) { base = getBasePoint(base, axis, Location, Dist.getValue()); } - Base::Console().Error("Basepoint2: %f, %f, %f\n", base.x, base.y, base.z); BasePoint.setValue(base); BasePoint.touch(); // This triggers ViewProvider::updateData() } else if ((prop == &Location) || (prop == &Dist)) { @@ -107,9 +109,9 @@ void ConstraintBearing::onChanged(const App::Property* prop) float radius, height; Base::Vector3f base, axis; - getCylinder(radius, height, base, axis); + if (!getCylinder(radius, height, base, axis)) + return; base = getBasePoint(base + axis * height/2, axis, Location, Dist.getValue()); - Base::Console().Error("Basepoint: %f, %f, %f\n", base.x, base.y, base.z); BasePoint.setValue(base); BasePoint.touch(); } diff --git a/src/Mod/Fem/App/FemConstraintFixed.cpp b/src/Mod/Fem/App/FemConstraintFixed.cpp index 1cde0061fa..762b63d891 100644 --- a/src/Mod/Fem/App/FemConstraintFixed.cpp +++ b/src/Mod/Fem/App/FemConstraintFixed.cpp @@ -75,9 +75,10 @@ void ConstraintFixed::onChanged(const App::Property* prop) if (prop == &References) { std::vector points; std::vector normals; - getPoints(points, normals); - Points.setValues(points); - Normals.setValues(normals); - Points.touch(); // This triggers ViewProvider::updateData() + if (getPoints(points, normals)) { + Points.setValues(points); + Normals.setValues(normals); + Points.touch(); // This triggers ViewProvider::updateData() + } } } diff --git a/src/Mod/Fem/App/FemConstraintForce.cpp b/src/Mod/Fem/App/FemConstraintForce.cpp index 2fa97b7778..034acaae96 100644 --- a/src/Mod/Fem/App/FemConstraintForce.cpp +++ b/src/Mod/Fem/App/FemConstraintForce.cpp @@ -70,9 +70,10 @@ void ConstraintForce::onChanged(const App::Property* prop) if (prop == &References) { std::vector points; std::vector normals; - getPoints(points, normals); - Points.setValues(points); // We don't use the normals because all arrows should have the same direction - Points.touch(); // This triggers ViewProvider::updateData() + if (getPoints(points, normals)) { + Points.setValues(points); // We don't use the normals because all arrows should have the same direction + Points.touch(); // This triggers ViewProvider::updateData() + } } else if (prop == &Direction) { App::DocumentObject* obj = Direction.getValue(); std::vector names = Direction.getSubValues(); diff --git a/src/Mod/Fem/Gui/TaskFemConstraint.h b/src/Mod/Fem/Gui/TaskFemConstraint.h index f4d7ee0bde..ada7965734 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraint.h +++ b/src/Mod/Fem/Gui/TaskFemConstraint.h @@ -56,11 +56,11 @@ protected Q_SLOTS: void onButtonReference(const bool pressed = true); protected: - virtual void changeEvent(QEvent *e) {} + virtual void changeEvent(QEvent *e) { TaskBox::changeEvent(e); } const QString makeRefText(const App::DocumentObject* obj, const std::string& subName) const; private: - virtual void onSelectionChanged(const Gui::SelectionChanges& msg) {} + virtual void onSelectionChanged(const Gui::SelectionChanges&) {} protected: QWidget* proxy; @@ -74,11 +74,13 @@ class TaskDlgFemConstraint : public Gui::TaskView::TaskDialog Q_OBJECT public: + /* /// is called the TaskView when the dialog is opened virtual void open() {} /// is called by the framework if an button is clicked which has no accept or reject role virtual void clicked(int) {} /// is called by the framework if the dialog is accepted (Ok) + */ virtual bool accept(); /// is called by the framework if the dialog is rejected (Cancel) virtual bool reject(); diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp index 4bb6dabe31..778b59b3af 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp @@ -36,6 +36,7 @@ # include # include # include +# include #endif #include "ViewProviderFemConstraint.h" @@ -94,6 +95,7 @@ ViewProviderFemConstraint::~ViewProviderFemConstraint() void ViewProviderFemConstraint::attach(App::DocumentObject* pcObject) { + Base::Console().Error("VP FemConstraint attach %s\n", pcObject->getNameInDocument()); ViewProviderDocumentObject::attach(pcObject); SoPickStyle* ps = new SoPickStyle(); diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h index 09ca86eaf6..015f8d38c4 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h @@ -64,7 +64,7 @@ public: App::PropertyBool Mirror; void attach(App::DocumentObject *); - virtual void updateData(const App::Property*) {} + virtual void updateData(const App::Property* prop) { Gui::ViewProviderGeometryObject::updateData(prop); } std::vector getDisplayModes(void) const; void setDisplayMode(const char* ModeName); @@ -73,7 +73,7 @@ public: protected: void onChanged(const App::Property* prop); - virtual bool setEdit(int ModNum) {} + virtual bool setEdit(int ModNum) { return Gui::ViewProviderGeometryObject::setEdit(ModNum); } virtual void unsetEdit(int ModNum); static void createPlacement(SoSeparator* sep, const SbVec3f &base, const SbRotation &r); @@ -90,7 +90,7 @@ 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 createFixed(SoSeparator* sep, const double height, const double width, const bool gap); + 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/ViewProviderFemConstraintBearing.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp index bf6a7cf412..f19849181f 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp @@ -97,13 +97,17 @@ bool ViewProviderFemConstraintBearing::setEdit(int ModNum) void ViewProviderFemConstraintBearing::updateData(const App::Property* prop) { - // Gets called whenever a property of the attached object changes - Fem::ConstraintBearing* pcConstraint = static_cast(this->getObject()); if (this->getObject() != NULL) Base::Console().Error("%s: VP updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); else Base::Console().Error("Anonymous: VP updateData: %s\n", prop->getName()); + // Gets called whenever a property of the attached object changes + Fem::ConstraintBearing* pcConstraint = static_cast(this->getObject()); + + if (strcmp(prop->getName(),"References") == 0) + Base::Console().Error("\n"); // enable a breakpoint here + if (strcmp(prop->getName(),"BasePoint") == 0) { // Remove and recreate the symbol pShapeSep->removeAllChildren(); diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp index 74727e5ac3..88fdf84cb7 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp @@ -112,6 +112,9 @@ void ViewProviderFemConstraintFixed::updateData(const App::Property* prop) Fem::ConstraintFixed* pcConstraint = static_cast(this->getObject()); + /* + // This has a HUGE performance penalty as opposed to separate nodes for every symbol + // The problem seems to be SoCone if (pShapeSep->getNumChildren() == 0) { // Set up the nodes SoMultipleCopy* cp = new SoMultipleCopy(); @@ -120,26 +123,37 @@ void ViewProviderFemConstraintFixed::updateData(const App::Property* prop) cp->addChild((SoNode*)createFixed(HEIGHT, WIDTH)); pShapeSep->addChild(cp); } + */ if (strcmp(prop->getName(),"Points") == 0) { // Note: Points and Normals are always updated together + pShapeSep->removeAllChildren(); const std::vector& points = pcConstraint->Points.getValues(); const std::vector& normals = pcConstraint->Normals.getValues(); std::vector::const_iterator n = normals.begin(); + /* SoMultipleCopy* cp = static_cast(pShapeSep->getChild(0)); cp->matrix.setNum(points.size()); int idx = 0; + */ 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), dir); + /* SbMatrix m; m.setTransform(base, rot, SbVec3f(1,1,1)); cp->matrix.set1Value(idx, m); + idx++ + */ + SoSeparator* sep = new SoSeparator(); + createPlacement(sep, base, rot); + createFixed(sep, HEIGHT, WIDTH); + pShapeSep->addChild(sep); + n++; - idx++; } } diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp index b29a65f9a5..8003f45e8b 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp @@ -111,6 +111,8 @@ void ViewProviderFemConstraintForce::updateData(const App::Property* prop) Fem::ConstraintForce* pcConstraint = static_cast(this->getObject()); /* + // This has a HUGE performance penalty as opposed to separate nodes for every symbol + // The problem seems to be SoCone if (pShapeSep->getNumChildren() == 0) { // Set up the nodes SoMultipleCopy* cp = new SoMultipleCopy(); diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp index 16ff06f50a..e30aecb78c 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp @@ -123,7 +123,7 @@ void ViewProviderFemConstraintGear::updateData(const App::Property* prop) createPlacement(pShapeSep, b, rot); pShapeSep->addChild(createCylinder(pcConstraint->Height.getValue() * 0.8, dia/2)); - createPlacement(pShapeSep, SbVec3f(0,0,dia/2), SbRotation(SbVec3f(0,1,0), SbVec3f(1,0,0))); + createPlacement(pShapeSep, SbVec3f(-dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(0,0,1))); pShapeSep->addChild(createArrow(dia/2, dia/8)); } } else if (strcmp(prop->getName(),"Diameter") == 0) { @@ -144,7 +144,7 @@ void ViewProviderFemConstraintGear::updateData(const App::Property* prop) updatePlacement(pShapeSep, 0, b, rot); const SoSeparator* sep = static_cast(pShapeSep->getChild(2)); updateCylinder(sep, 0, pcConstraint->Height.getValue() * 0.8, dia/2); - updatePlacement(pShapeSep, 3, SbVec3f(0,0,dia/2), SbRotation(SbVec3f(0,1,0), SbVec3f(1,0,0))); + updatePlacement(pShapeSep, 3, SbVec3f(-dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(0,0,1))); sep = static_cast(pShapeSep->getChild(5)); updateArrow(sep, 0, dia/2, dia/8); } diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp index abdd3ec3e3..df47623648 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp @@ -152,11 +152,11 @@ void ViewProviderFemConstraintPulley::updateData(const App::Property* prop) const SoSeparator* sep = static_cast(pShapeSep->getChild(2)); updateCylinder(sep, 0, pcConstraint->Height.getValue() * 0.8, dia/2); sep = static_cast(pShapeSep->getChild(3)); - updatePlacement(sep, 0, SbVec3f(0,0,dia/2), SbRotation(SbVec3f(0,1,0), SbVec3f(cos(angle),0,sin(angle)))); + updatePlacement(sep, 0, SbVec3f(dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(sin(angle),0,cos(angle)))); const SoSeparator* subsep = static_cast(sep->getChild(2)); updateArrow(subsep, 0, dia/2, dia/8); sep = static_cast(pShapeSep->getChild(4)); - updatePlacement(sep, 0, SbVec3f(0,0,-dia/2), SbRotation(SbVec3f(0,1,0), SbVec3f(cos(angle),0,-sin(angle)))); + updatePlacement(sep, 0, SbVec3f(-dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(-sin(angle),0,cos(angle)))); subsep = static_cast(sep->getChild(2)); updateArrow(subsep, 0, dia/2, dia/8); } From f5c6e4eae35e0f7a281301eb52e5de129f5caa5a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 8 Mar 2013 19:59:08 +0430 Subject: [PATCH 4/9] Improvements to FEM constraint objects --- src/Mod/Fem/App/FemConstraint.cpp | 39 +++- src/Mod/Fem/App/FemConstraint.h | 2 + src/Mod/Fem/App/FemConstraintBearing.cpp | 3 +- src/Mod/Fem/App/FemConstraintBearing.h | 3 + src/Mod/Fem/App/FemConstraintForce.cpp | 29 +-- src/Mod/Fem/App/FemConstraintGear.cpp | 28 +++ src/Mod/Fem/App/FemConstraintGear.h | 9 + src/Mod/Fem/App/FemConstraintPulley.cpp | 41 +++- src/Mod/Fem/App/FemConstraintPulley.h | 16 +- src/Mod/Fem/Gui/CMakeLists.txt | 4 +- src/Mod/Fem/Gui/Command.cpp | 6 +- src/Mod/Fem/Gui/TaskFemConstraint.cpp | 63 +++++- src/Mod/Fem/Gui/TaskFemConstraint.h | 18 +- src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp | 29 ++- src/Mod/Fem/Gui/TaskFemConstraintBearing.h | 7 +- ...ndrical.ui => TaskFemConstraintBearing.ui} | 141 +++++++++++-- src/Mod/Fem/Gui/TaskFemConstraintForce.cpp | 2 +- src/Mod/Fem/Gui/TaskFemConstraintGear.cpp | 199 ++++++++++++++++-- src/Mod/Fem/Gui/TaskFemConstraintGear.h | 25 +-- src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp | 95 ++++++--- src/Mod/Fem/Gui/TaskFemConstraintPulley.h | 24 +-- src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp | 85 ++++++-- src/Mod/Fem/Gui/ViewProviderFemConstraint.h | 16 +- .../Gui/ViewProviderFemConstraintBearing.cpp | 45 ++-- .../Gui/ViewProviderFemConstraintBearing.h | 1 + .../Gui/ViewProviderFemConstraintFixed.cpp | 44 ++-- .../Gui/ViewProviderFemConstraintForce.cpp | 44 ++-- .../Fem/Gui/ViewProviderFemConstraintGear.cpp | 98 ++++++--- .../Gui/ViewProviderFemConstraintPulley.cpp | 141 +++++++++---- 29 files changed, 939 insertions(+), 318 deletions(-) rename src/Mod/Fem/Gui/{TaskFemConstraintCylindrical.ui => TaskFemConstraintBearing.ui} (54%) diff --git a/src/Mod/Fem/App/FemConstraint.cpp b/src/Mod/Fem/App/FemConstraint.cpp index 98d7fc92f1..32c8bcd263 100644 --- a/src/Mod/Fem/App/FemConstraint.cpp +++ b/src/Mod/Fem/App/FemConstraint.cpp @@ -78,7 +78,7 @@ App::DocumentObjectExecReturn *Constraint::execute(void) void Constraint::onChanged(const App::Property* prop) { - Base::Console().Error("Constraint::onChanged() %s\n", prop->getName()); + //Base::Console().Error("Constraint::onChanged() %s\n", prop->getName()); if (prop == &References) { // If References are changed, recalculate the normal direction. If no useful reference is found, // use z axis or previous value. If several faces are selected, only the first one is used @@ -254,7 +254,10 @@ Base::Vector3f Constraint::getBasePoint(const Base::Vector3f& base, const Base:: { // Get the point specified by Location and Distance App::DocumentObject* objLoc = location.getValue(); - std::string subName = location.getSubValues().front(); + std::vector names = location.getSubValues(); + if (names.size() == 0) + return Base::Vector3f(0,0,0); + std::string subName = names.front(); Part::Feature* featLoc = static_cast(objLoc); TopoDS_Shape shloc = featLoc->Shape.getShape().getSubShape(subName.c_str()); @@ -292,3 +295,35 @@ Base::Vector3f Constraint::getBasePoint(const Base::Vector3f& base, const Base:: gp_Pnt inter = intersector.Point(1); return Base::Vector3f(inter.X(), inter.Y(), inter.Z()); } + +const Base::Vector3f Constraint::getDirection(const App::PropertyLinkSub &direction) +{ + App::DocumentObject* obj = direction.getValue(); + std::vector names = direction.getSubValues(); + if (names.size() == 0) + return Base::Vector3f(0,0,0); + std::string subName = names.front(); + Part::Feature* feat = static_cast(obj); + TopoDS_Shape sh = feat->Shape.getShape().getSubShape(subName.c_str()); + gp_Dir dir; + + if (sh.ShapeType() == TopAbs_FACE) { + BRepAdaptor_Surface surface(TopoDS::Face(sh)); + if (surface.GetType() == GeomAbs_Plane) { + dir = surface.Plane().Axis().Direction(); + } else { + return Base::Vector3f(0,0,0); // "Direction must be a planar face or linear edge" + } + } else if (sh.ShapeType() == TopAbs_EDGE) { + BRepAdaptor_Curve line(TopoDS::Edge(sh)); + if (line.GetType() == GeomAbs_Line) { + dir = line.Line().Direction(); + } else { + return Base::Vector3f(0,0,0); // "Direction must be a planar face or linear edge" + } + } + + Base::Vector3f the_direction(dir.X(), dir.Y(), dir.Z()); + the_direction.Normalize(); + return the_direction; +} diff --git a/src/Mod/Fem/App/FemConstraint.h b/src/Mod/Fem/App/FemConstraint.h index 1814183278..157d76285b 100644 --- a/src/Mod/Fem/App/FemConstraint.h +++ b/src/Mod/Fem/App/FemConstraint.h @@ -42,6 +42,7 @@ public: virtual ~Constraint(); App::PropertyLinkSubList References; + // Read-only (calculated values). These trigger changes in the ViewProvider App::PropertyVector NormalDirection; /// recalculate the object @@ -62,6 +63,7 @@ protected: const bool getCylinder(float& radius, float& height, Base::Vector3f& base, Base::Vector3f& axis) const; Base::Vector3f getBasePoint(const Base::Vector3f& base, const Base::Vector3f& axis, const App::PropertyLinkSub &location, const float& dist); + const Base::Vector3f getDirection(const App::PropertyLinkSub &direction); }; diff --git a/src/Mod/Fem/App/FemConstraintBearing.cpp b/src/Mod/Fem/App/FemConstraintBearing.cpp index 51aa790d0d..ed399bd026 100644 --- a/src/Mod/Fem/App/FemConstraintBearing.cpp +++ b/src/Mod/Fem/App/FemConstraintBearing.cpp @@ -58,13 +58,12 @@ ConstraintBearing::ConstraintBearing() App::DocumentObjectExecReturn *ConstraintBearing::execute(void) { - Base::Console().Error("ConstraintBearing: execute()\n"); return Constraint::execute(); } void ConstraintBearing::onChanged(const App::Property* prop) { - Base::Console().Error("ConstraintBearing: onChanged %s\n", prop->getName()); + //Base::Console().Error("ConstraintBearing: onChanged %s\n", prop->getName()); // Note: If we call this at the end, then the symbol ist not oriented correctly initially // because the NormalDirection has not been calculated yet Constraint::onChanged(prop); diff --git a/src/Mod/Fem/App/FemConstraintBearing.h b/src/Mod/Fem/App/FemConstraintBearing.h index 6385e6b483..66fcd0e070 100644 --- a/src/Mod/Fem/App/FemConstraintBearing.h +++ b/src/Mod/Fem/App/FemConstraintBearing.h @@ -41,8 +41,11 @@ public: /// Constructor ConstraintBearing(void); + /// Location reference App::PropertyLinkSub Location; + /// Distance from location reference App::PropertyFloat Dist; + /// Is the bearing free to move in axial direction? App::PropertyBool AxialFree; // Read-only (calculated values). These trigger changes in the ViewProvider App::PropertyFloat Radius; diff --git a/src/Mod/Fem/App/FemConstraintForce.cpp b/src/Mod/Fem/App/FemConstraintForce.cpp index 034acaae96..771929d23a 100644 --- a/src/Mod/Fem/App/FemConstraintForce.cpp +++ b/src/Mod/Fem/App/FemConstraintForce.cpp @@ -75,34 +75,9 @@ void ConstraintForce::onChanged(const App::Property* prop) Points.touch(); // This triggers ViewProvider::updateData() } } else if (prop == &Direction) { - App::DocumentObject* obj = Direction.getValue(); - std::vector names = Direction.getSubValues(); - if (names.size() == 0) { + Base::Vector3f direction = getDirection(Direction); + if (direction.Length() < Precision::Confusion()) return; - } - std::string subName = names.front(); - Part::Feature* feat = static_cast(obj); - TopoDS_Shape sh = feat->Shape.getShape().getSubShape(subName.c_str()); - gp_Dir dir; - - if (sh.ShapeType() == TopAbs_FACE) { - BRepAdaptor_Surface surface(TopoDS::Face(sh)); - if (surface.GetType() == GeomAbs_Plane) { - dir = surface.Plane().Axis().Direction(); - } else { - return; // "Direction must be a planar face or linear edge" - } - } else if (sh.ShapeType() == TopAbs_EDGE) { - BRepAdaptor_Curve line(TopoDS::Edge(sh)); - if (line.GetType() == GeomAbs_Line) { - dir = line.Line().Direction(); - } else { - return; // "Direction must be a planar face or linear edge" - } - } - - Base::Vector3f direction(dir.X(), dir.Y(), dir.Z()); - direction.Normalize(); naturalDirectionVector = direction; if (Reversed.getValue()) direction = -direction; diff --git a/src/Mod/Fem/App/FemConstraintGear.cpp b/src/Mod/Fem/App/FemConstraintGear.cpp index 7505b8bbf3..cc4a68ca5a 100644 --- a/src/Mod/Fem/App/FemConstraintGear.cpp +++ b/src/Mod/Fem/App/FemConstraintGear.cpp @@ -45,6 +45,14 @@ PROPERTY_SOURCE(Fem::ConstraintGear, Fem::ConstraintBearing); ConstraintGear::ConstraintGear() { ADD_PROPERTY(Diameter,(0)); + ADD_PROPERTY(Force,(0.0)); + ADD_PROPERTY(ForceAngle,(0.0)); + ADD_PROPERTY_TYPE(Direction,(0),"ConstraintGear",(App::PropertyType)(App::Prop_None), + "Element giving direction of gear force"); + ADD_PROPERTY(Reversed,(0)); + ADD_PROPERTY_TYPE(DirectionVector,(Base::Vector3f(0,1,0)),"ConstraintGear",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Direction of gear force"); + naturalDirectionVector = Base::Vector3f(0,1,0); } App::DocumentObjectExecReturn *ConstraintGear::execute(void) @@ -55,4 +63,24 @@ App::DocumentObjectExecReturn *ConstraintGear::execute(void) void ConstraintGear::onChanged(const App::Property* prop) { ConstraintBearing::onChanged(prop); + + if (prop == &Direction) { + Base::Vector3f direction = getDirection(Direction); + if (direction.Length() < Precision::Confusion()) + return; + naturalDirectionVector = direction; + if (Reversed.getValue()) + direction = -direction; + DirectionVector.setValue(direction); + DirectionVector.touch(); + } else if (prop == &Reversed) { + if (Reversed.getValue() && (DirectionVector.getValue() == naturalDirectionVector)) { + DirectionVector.setValue(-naturalDirectionVector); + DirectionVector.touch(); + } else if (!Reversed.getValue() && (DirectionVector.getValue() != naturalDirectionVector)) { + DirectionVector.setValue(naturalDirectionVector); + DirectionVector.touch(); + } + } + // The computation for the force angle is simpler in the ViewProvider directly } diff --git a/src/Mod/Fem/App/FemConstraintGear.h b/src/Mod/Fem/App/FemConstraintGear.h index a18053ff0a..11926f3504 100644 --- a/src/Mod/Fem/App/FemConstraintGear.h +++ b/src/Mod/Fem/App/FemConstraintGear.h @@ -42,6 +42,12 @@ public: ConstraintGear(void); App::PropertyFloat Diameter; + App::PropertyFloat Force; + App::PropertyFloat ForceAngle; + App::PropertyLinkSub Direction; + App::PropertyBool Reversed; + // Read-only (calculated values). These trigger changes in the ViewProvider + App::PropertyVector DirectionVector; /// recalculate the object virtual App::DocumentObjectExecReturn *execute(void); @@ -53,6 +59,9 @@ public: protected: virtual void onChanged(const App::Property* prop); + +private: + Base::Vector3f naturalDirectionVector; }; } //namespace Fem diff --git a/src/Mod/Fem/App/FemConstraintPulley.cpp b/src/Mod/Fem/App/FemConstraintPulley.cpp index d4c5efbbe4..7b83d6b349 100644 --- a/src/Mod/Fem/App/FemConstraintPulley.cpp +++ b/src/Mod/Fem/App/FemConstraintPulley.cpp @@ -40,15 +40,23 @@ using namespace Fem; -PROPERTY_SOURCE(Fem::ConstraintPulley, Fem::ConstraintBearing); +PROPERTY_SOURCE(Fem::ConstraintPulley, Fem::ConstraintGear); ConstraintPulley::ConstraintPulley() { - ADD_PROPERTY(Diameter,(0)); ADD_PROPERTY(OtherDiameter,(0)); ADD_PROPERTY(CenterDistance,(0)); - ADD_PROPERTY_TYPE(Angle,(0),"ConstraintPulley",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Angle of pulley forces"); + ADD_PROPERTY(IsDriven,(0)); + ADD_PROPERTY(TensionForce,(0.0)); + + ADD_PROPERTY_TYPE(BeltAngle,(0),"ConstraintPulley",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Angle of belt forces"); + ADD_PROPERTY_TYPE(BeltForce1,(0.0),"ConstraintPulley",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "First belt force"); + ADD_PROPERTY_TYPE(BeltForce2,(0.0),"ConstraintPulley",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Second belt force"); + ForceAngle.setValue(90.0); + Diameter.setValue(300.0); } App::DocumentObjectExecReturn *ConstraintPulley::execute(void) @@ -58,12 +66,31 @@ App::DocumentObjectExecReturn *ConstraintPulley::execute(void) void ConstraintPulley::onChanged(const App::Property* prop) { - ConstraintBearing::onChanged(prop); + ConstraintGear::onChanged(prop); if ((prop == &Diameter) || (prop == &OtherDiameter) || (prop == &CenterDistance)) { if (CenterDistance.getValue() > Precision::Confusion()) { - Angle.setValue(asin((Diameter.getValue() - OtherDiameter.getValue())/2/CenterDistance.getValue())); - Angle.touch(); + BeltAngle.setValue(asin((Diameter.getValue() - OtherDiameter.getValue())/2/CenterDistance.getValue())); + BeltAngle.touch(); } + } else if ((prop == &Force) || (prop == &TensionForce) || (prop == &IsDriven)) { + double radius = Diameter.getValue() / 2.0; + if (radius < Precision::Confusion()) + return; + double force = Force.getValue() / (radius/1000); + if (fabs(force) < Precision::Confusion()) + return; + bool neg = (force < 0.0); + if (neg) + force *= -1.0; + + if ((IsDriven.getValue() && neg) || (!IsDriven.getValue() && !neg)) { + BeltForce1.setValue(force + TensionForce.getValue()); + BeltForce2.setValue(TensionForce.getValue()); + } else { + BeltForce2.setValue(force + TensionForce.getValue()); + BeltForce1.setValue(TensionForce.getValue()); + } + BeltForce1.touch(); } } diff --git a/src/Mod/Fem/App/FemConstraintPulley.h b/src/Mod/Fem/App/FemConstraintPulley.h index 5540d0ba63..611652570a 100644 --- a/src/Mod/Fem/App/FemConstraintPulley.h +++ b/src/Mod/Fem/App/FemConstraintPulley.h @@ -28,12 +28,12 @@ #include #include -#include "FemConstraintBearing.h" +#include "FemConstraintGear.h" namespace Fem { -class AppFemExport ConstraintPulley : public Fem::ConstraintBearing +class AppFemExport ConstraintPulley : public Fem::ConstraintGear { PROPERTY_HEADER(Fem::ConstraintPulley); @@ -41,11 +41,18 @@ public: /// Constructor ConstraintPulley(void); - App::PropertyFloat Diameter; + /// Other pulley diameter App::PropertyFloat OtherDiameter; + /// Center distance between the pulleys App::PropertyFloat CenterDistance; + /// Driven pulley or driving pulley? + App::PropertyBool IsDriven; + /// Belt tension force + App::PropertyFloat TensionForce; // Read-only (calculated values). These trigger changes in the ViewProvider - App::PropertyFloat Angle; + App::PropertyFloat BeltAngle; + App::PropertyFloat BeltForce1; + App::PropertyFloat BeltForce2; /// recalculate the object virtual App::DocumentObjectExecReturn *execute(void); @@ -57,6 +64,7 @@ public: protected: virtual void onChanged(const App::Property* prop); + }; } //namespace Fem diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 162e3efaaf..3c9c080bc2 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -49,7 +49,7 @@ set(FemGui_UIC_SRCS TaskCreateNodeSet.ui TaskObjectName.ui TaskFemConstraint.ui - TaskFemConstraintCylindrical.ui + TaskFemConstraintBearing.ui TaskFemConstraintFixed.ui TaskFemConstraintForce.ui ) @@ -63,7 +63,7 @@ SET(FemGui_DLG_SRCS TaskFemConstraint.ui TaskFemConstraint.cpp TaskFemConstraint.h - TaskFemConstraintCylindrical.ui + TaskFemConstraintBearing.ui TaskFemConstraintBearing.cpp TaskFemConstraintBearing.h TaskFemConstraintFixed.ui diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index f5bdf54dae..95618a625d 100755 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -228,9 +228,11 @@ void CmdFemConstraintPulley::activated(int iMsg) openCommand("Make FEM constraint for pulley"); doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintPulley\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Diameter = 100.0",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.OtherDiameter = 200.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Diameter = 300.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.OtherDiameter = 100.0",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.CenterDistance = 500.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Force = 100.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.TensionForce = 100.0",FeatName.c_str()); updateActive(); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); diff --git a/src/Mod/Fem/Gui/TaskFemConstraint.cpp b/src/Mod/Fem/Gui/TaskFemConstraint.cpp index 2a54ed9560..1169971f0d 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraint.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraint.cpp @@ -43,7 +43,6 @@ #include "TaskFemConstraint.h" #include #include -//#include #include #include #include @@ -65,6 +64,39 @@ TaskFemConstraint::TaskFemConstraint(ViewProviderFemConstraint *ConstraintView,Q : TaskBox(Gui::BitmapFactory().pixmap(pixmapname),tr("FEM constraint parameters"),true, parent),ConstraintView(ConstraintView) { selectionMode = selref; + + // Setup the dialog inside the Shaft Wizard dialog + if ((ConstraintView->wizardWidget != NULL) && (ConstraintView->wizardSubLayout != NULL)) { + // Hide the shaft wizard table widget to make more space + ConstraintView->wizardSubLayout->itemAt(0)->widget()->hide(); + QGridLayout* buttons = ConstraintView->wizardSubLayout->findChild(); + for (int b = 0; b < buttons->count(); b++) + buttons->itemAt(b)->widget()->hide(); + + // Show this dialog for the FEM constraint + ConstraintView->wizardWidget->addWidget(this); + + // Add buttons to finish editing the constraint without closing the shaft wizard dialog + okButton = new QPushButton(QObject::tr("Ok")); + cancelButton = new QPushButton(QObject::tr("Cancel")); + buttonBox = new QDialogButtonBox(); + buttonBox->addButton(okButton, QDialogButtonBox::AcceptRole); + buttonBox->addButton(cancelButton, QDialogButtonBox::RejectRole); + QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(onButtonWizOk())); + QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(onButtonWizCancel())); + ConstraintView->wizardWidget->addWidget(buttonBox); + } +} + +void TaskFemConstraint::keyPressEvent(QKeyEvent *ke) +{ + if ((ConstraintView->wizardWidget != NULL) && (ConstraintView->wizardSubLayout != NULL)) + // Prevent from closing this dialog AND the shaft wizard dialog + // TODO: This should trigger an update in the shaft wizard but its difficult to access a python dialog from here... + if (ke->key() == Qt::Key_Return) + return; + + TaskBox::keyPressEvent(ke); } const std::string TaskFemConstraint::getReferences(const std::vector& items) const @@ -95,10 +127,37 @@ void TaskFemConstraint::onButtonReference(const bool pressed) { selectionMode = selref; else selectionMode = selnone; - //ui->buttonReference->setChecked(pressed); Gui::Selection().clearSelection(); } +void TaskFemConstraint::onButtonWizOk() +{ + // Remove dialog elements + buttonBox->removeButton(okButton); + delete okButton; + buttonBox->removeButton(cancelButton); + delete cancelButton; + ConstraintView->wizardWidget->removeWidget(buttonBox); + delete buttonBox; + ConstraintView->wizardWidget->removeWidget(this); + + // Show the wizard shaft dialog again + ConstraintView->wizardSubLayout->itemAt(0)->widget()->show(); + QGridLayout* buttons = ConstraintView->wizardSubLayout->findChild(); + for (int b = 0; b < buttons->count(); b++) + buttons->itemAt(b)->widget()->show(); + + Gui::Application::Instance->activeDocument()->resetEdit(); // Reaches ViewProviderFemConstraint::unsetEdit() eventually +} + +void TaskFemConstraint::onButtonWizCancel() +{ + Fem::Constraint* pcConstraint = static_cast(ConstraintView->getObject()); + if (pcConstraint != NULL) + pcConstraint->getDocument()->remObject(pcConstraint->getNameInDocument()); + onButtonWizOk(); +} + const QString TaskFemConstraint::makeRefText(const App::DocumentObject* obj, const std::string& subName) const { return QString::fromUtf8((std::string(obj->getNameInDocument()) + ":" + subName).c_str()); diff --git a/src/Mod/Fem/Gui/TaskFemConstraint.h b/src/Mod/Fem/Gui/TaskFemConstraint.h index ada7965734..72390e113a 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraint.h +++ b/src/Mod/Fem/Gui/TaskFemConstraint.h @@ -29,15 +29,7 @@ #include #include "ViewProviderFemConstraint.h" -/* -namespace App { -class Property; -} -namespace Gui { -class ViewProvider; -} -*/ namespace FemGui { class TaskFemConstraint : public Gui::TaskView::TaskBox, public Gui::SelectionObserver @@ -54,10 +46,14 @@ public: protected Q_SLOTS: void onReferenceDeleted(const int row); void onButtonReference(const bool pressed = true); + // Shaft Wizard integration + void onButtonWizOk(); + void onButtonWizCancel(); protected: virtual void changeEvent(QEvent *e) { TaskBox::changeEvent(e); } const QString makeRefText(const App::DocumentObject* obj, const std::string& subName) const; + virtual void keyPressEvent(QKeyEvent * ke); private: virtual void onSelectionChanged(const Gui::SelectionChanges&) {} @@ -66,6 +62,12 @@ protected: QWidget* proxy; ViewProviderFemConstraint *ConstraintView; enum {seldir, selref, selloc, selnone} selectionMode; + +private: + // This seems to be the only way to access the widgets again in order to remove them from the dialog + QDialogButtonBox* buttonBox; + QPushButton* okButton; + QPushButton* cancelButton; }; /// simulation dialog for the TaskView diff --git a/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp b/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp index cf5b4374f0..cf98b3003c 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp @@ -39,7 +39,7 @@ # include #endif -#include "ui_TaskFemConstraintCylindrical.h" +#include "ui_TaskFemConstraintBearing.h" #include "TaskFemConstraintBearing.h" #include #include @@ -61,12 +61,13 @@ using namespace Gui; /* TRANSLATOR FemGui::TaskFemConstraintBearing */ -TaskFemConstraintBearing::TaskFemConstraintBearing(ViewProviderFemConstraint *ConstraintView,QWidget *parent, const char *pixmapname) +TaskFemConstraintBearing::TaskFemConstraintBearing(ViewProviderFemConstraint *ConstraintView,QWidget *parent, + const char *pixmapname) : TaskFemConstraint(ConstraintView, parent, pixmapname) { // we need a separate container widget to add all controls to proxy = new QWidget(this); - ui = new Ui_TaskFemConstraintCylindrical(); + ui = new Ui_TaskFemConstraintBearing(); ui->setupUi(proxy); QMetaObject::connectSlotsByName(this); @@ -107,8 +108,8 @@ TaskFemConstraintBearing::TaskFemConstraintBearing(ViewProviderFemConstraint *Co bool axialfree = pcConstraint->AxialFree.getValue(); // Fill data into dialog elements - ui->spinDistance->setMinimum(INT_MIN); - ui->spinDistance->setMaximum(INT_MAX); + ui->spinDistance->setMinimum(-FLOAT_MAX); + ui->spinDistance->setMaximum(FLOAT_MAX); ui->spinDistance->setValue(d); ui->listReferences->clear(); for (int i = 0; i < Objects.size(); i++) @@ -118,13 +119,23 @@ TaskFemConstraintBearing::TaskFemConstraintBearing(ViewProviderFemConstraint *Co ui->lineLocation->setText(loc); ui->checkAxial->setChecked(axialfree); - // Adjust ui to constraint type + // Hide unwanted ui elements ui->labelDiameter->setVisible(false); ui->spinDiameter->setVisible(false); ui->labelOtherDiameter->setVisible(false); ui->spinOtherDiameter->setVisible(false); ui->labelCenterDistance->setVisible(false); ui->spinCenterDistance->setVisible(false); + ui->checkIsDriven->setVisible(false); + ui->labelForce->setVisible(false); + ui->spinForce->setVisible(false); + ui->labelTensionForce->setVisible(false); + ui->spinTensionForce->setVisible(false); + ui->labelForceAngle->setVisible(false); + ui->spinForceAngle->setVisible(false); + ui->buttonDirection->setVisible(false); + ui->lineDirection->setVisible(false); + ui->checkReversed->setVisible(false); ui->spinDistance->blockSignals(false); ui->listReferences->blockSignals(false); @@ -149,7 +160,6 @@ void TaskFemConstraintBearing::onSelectionChanged(const Gui::SelectionChanges& m if (selectionMode == selnone) return; - std::vector references(1,subName); Fem::ConstraintBearing* pcConstraint = static_cast(ConstraintView->getObject()); App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(msg.pObjectName); Part::Feature* feat = static_cast(obj); @@ -162,13 +172,13 @@ void TaskFemConstraintBearing::onSelectionChanged(const Gui::SelectionChanges& m if (Objects.size() > 0) { QMessageBox::warning(this, tr("Selection error"), tr("Please use only a single reference for bearing constraint")); return; - } - // Only cylindrical faces allowed + } if (subName.substr(0,4) != "Face") { QMessageBox::warning(this, tr("Selection error"), tr("Only faces can be picked")); return; } + // Only cylindrical faces allowed BRepAdaptor_Surface surface(TopoDS::Face(ref)); if (surface.GetType() != GeomAbs_Cylinder) { QMessageBox::warning(this, tr("Selection error"), tr("Only cylindrical faces can be picked")); @@ -200,6 +210,7 @@ void TaskFemConstraintBearing::onSelectionChanged(const Gui::SelectionChanges& m QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked")); return; } + std::vector references(1,subName); pcConstraint->Location.setValue(obj, references); ui->lineLocation->setText(makeRefText(obj, subName)); diff --git a/src/Mod/Fem/Gui/TaskFemConstraintBearing.h b/src/Mod/Fem/Gui/TaskFemConstraintBearing.h index 671d114b44..e6a566f483 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintBearing.h +++ b/src/Mod/Fem/Gui/TaskFemConstraintBearing.h @@ -31,7 +31,7 @@ #include "TaskFemConstraint.h" #include "ViewProviderFemConstraintBearing.h" -class Ui_TaskFemConstraintCylindrical; +class Ui_TaskFemConstraintBearing; namespace App { class Property; @@ -66,12 +66,11 @@ private Q_SLOTS: protected: virtual void changeEvent(QEvent *e); - -private: virtual void onSelectionChanged(const Gui::SelectionChanges& msg); protected: - Ui_TaskFemConstraintCylindrical* ui; + Ui_TaskFemConstraintBearing* ui; + }; /// simulation dialog for the TaskView diff --git a/src/Mod/Fem/Gui/TaskFemConstraintCylindrical.ui b/src/Mod/Fem/Gui/TaskFemConstraintBearing.ui similarity index 54% rename from src/Mod/Fem/Gui/TaskFemConstraintCylindrical.ui rename to src/Mod/Fem/Gui/TaskFemConstraintBearing.ui index c0ee3cb291..e838590049 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintCylindrical.ui +++ b/src/Mod/Fem/Gui/TaskFemConstraintBearing.ui @@ -1,13 +1,13 @@ - TaskFemConstraintCylindrical - + TaskFemConstraintBearing + 0 0 257 - 338 + 534 @@ -25,9 +25,12 @@ - + + + true + Gear diameter @@ -49,11 +52,14 @@ - + + + true + - Other diameter + Other pulley dia @@ -66,14 +72,14 @@ 99999.000000000000000 - 200.000000000000000 + 100.000000000000000 - + @@ -90,12 +96,122 @@ 99999.000000000000000 - 500.000000000000000 + 1000.000000000000000 + + + + + + Force + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 1000.000000000000000 + + + + + + + + + + + Belt tension force + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 1000.000000000000000 + + + + + + + + + Driven pulley + + + + + + + + + Force location [deg] + + + + + + + 1 + + + 0.000000000000000 + + + 360.000000000000000 + + + 0.000000000000000 + + + + + + + + + + + Force Direction + + + + + + + + + + + + Reversed direction + + + + + + + Axial free + + + @@ -147,13 +263,6 @@ - - - - Axial free - - - diff --git a/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp b/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp index 4d0d5c3ff9..8a51a99e48 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp @@ -108,7 +108,7 @@ TaskFemConstraintForce::TaskFemConstraintForce(ViewProviderFemConstraintForce *C // Fill data into dialog elements ui->spinForce->setMinimum(0); - ui->spinForce->setMaximum(INT_MAX); + ui->spinForce->setMaximum(FLOAT_MAX); ui->spinForce->setValue(f); ui->listReferences->clear(); for (int i = 0; i < Objects.size(); i++) diff --git a/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp b/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp index 0ee3868e11..b7acec743c 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp @@ -29,7 +29,7 @@ # include # include # include -# include +# include */ # include # include # include @@ -38,10 +38,9 @@ # include # include # include -*/ #endif -#include "ui_TaskFemConstraintCylindrical.h" +#include "ui_TaskFemConstraintBearing.h" #include "TaskFemConstraintGear.h" #include #include @@ -63,40 +62,187 @@ using namespace Gui; /* TRANSLATOR FemGui::TaskFemConstraintGear */ -TaskFemConstraintGear::TaskFemConstraintGear(ViewProviderFemConstraintGear *ConstraintView,QWidget *parent) - : TaskFemConstraintBearing(ConstraintView, parent, "Fem_ConstraintGear") +TaskFemConstraintGear::TaskFemConstraintGear(ViewProviderFemConstraint *ConstraintView,QWidget *parent, const char *pixmapname) + : TaskFemConstraintBearing(ConstraintView, parent, pixmapname) { - // we need a separate container widget to add all controls to connect(ui->spinDiameter, SIGNAL(valueChanged(double)), this, SLOT(onDiameterChanged(double))); + connect(ui->spinForce, SIGNAL(valueChanged(double)), + this, SLOT(onForceChanged(double))); + connect(ui->spinForceAngle, SIGNAL(valueChanged(double)), + this, SLOT(onForceAngleChanged(double))); + connect(ui->buttonDirection, SIGNAL(pressed()), + this, SLOT(onButtonDirection())); + connect(ui->checkReversed, SIGNAL(toggled(bool)), + this, SLOT(onCheckReversed(bool))); // Temporarily prevent unnecessary feature recomputes ui->spinDiameter->blockSignals(true); + ui->spinForce->blockSignals(true); + ui->spinForceAngle->blockSignals(true); + ui->checkReversed->blockSignals(true); // Get the feature data - Fem::ConstraintGear* pcConstraint = static_cast(ConstraintView->getObject()); + Fem::ConstraintGear* pcConstraint = static_cast(ConstraintView->getObject()); double dia = pcConstraint->Diameter.getValue(); + double force = pcConstraint->Force.getValue(); + double angle = pcConstraint->ForceAngle.getValue(); + std::vector dirStrings = pcConstraint->Direction.getSubValues(); + QString dir; + if (!dirStrings.empty()) + dir = makeRefText(pcConstraint->Direction.getValue(), dirStrings.front()); + bool reversed = pcConstraint->Reversed.getValue(); // Fill data into dialog elements ui->spinDiameter->setMinimum(0); - ui->spinDiameter->setMaximum(INT_MAX); + ui->spinDiameter->setMaximum(FLOAT_MAX); ui->spinDiameter->setValue(dia); + ui->spinForce->setMinimum(0); + ui->spinForce->setMaximum(FLOAT_MAX); + ui->spinForce->setValue(force); + ui->spinForceAngle->setMinimum(0); + ui->spinForceAngle->setMaximum(360); + ui->spinForceAngle->setValue(angle); + ui->lineDirection->setText(dir); + ui->checkReversed->setChecked(reversed); - // Adjust ui to specific constraint type - ui->checkAxial->setVisible(false); - ui->spinDiameter->setVisible(true); + // Adjust ui ui->labelDiameter->setVisible(true); + ui->spinDiameter->setVisible(true); + ui->labelForce->setVisible(true); + ui->spinForce->setVisible(true); + ui->labelForceAngle->setVisible(true); + ui->spinForceAngle->setVisible(true); + ui->buttonDirection->setVisible(true); + ui->lineDirection->setVisible(true); + ui->checkReversed->setVisible(true); + ui->checkAxial->setVisible(false); ui->spinDiameter->blockSignals(false); - - onButtonReference(true); + ui->spinForce->blockSignals(false); + ui->spinForceAngle->blockSignals(false); + ui->checkReversed->blockSignals(false); } + +void TaskFemConstraintGear::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + TaskFemConstraintBearing::onSelectionChanged(msg); + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + // Don't allow selection in other document + if (strcmp(msg.pDocName, ConstraintView->getObject()->getDocument()->getName()) != 0) + return; + + if (!msg.pSubName || msg.pSubName[0] == '\0') + return; + std::string subName(msg.pSubName); + + if (selectionMode == selnone) + return; + + std::vector references(1,subName); + Fem::ConstraintGear* pcConstraint = static_cast(ConstraintView->getObject()); + App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(msg.pObjectName); + Part::Feature* feat = static_cast(obj); + TopoDS_Shape ref = feat->Shape.getShape().getSubShape(subName.c_str()); + + if (selectionMode == seldir) { + if (subName.substr(0,4) == "Face") { + BRepAdaptor_Surface surface(TopoDS::Face(ref)); + if (surface.GetType() != GeomAbs_Plane) { + QMessageBox::warning(this, tr("Selection error"), tr("Only planar faces can be picked")); + return; + } + } else if (subName.substr(0,4) == "Edge") { + BRepAdaptor_Curve line(TopoDS::Edge(ref)); + if (line.GetType() != GeomAbs_Line) { + QMessageBox::warning(this, tr("Selection error"), tr("Only linear edges can be picked")); + return; + } + } else { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked")); + return; + } + pcConstraint->Direction.setValue(obj, references); + ui->lineDirection->setText(makeRefText(obj, subName)); + + // Turn off direction selection mode + onButtonDirection(false); + } + + Gui::Selection().clearSelection(); + } +} + void TaskFemConstraintGear::onDiameterChanged(double l) { Fem::ConstraintGear* pcConstraint = static_cast(ConstraintView->getObject()); pcConstraint->Diameter.setValue((float)l); } +void TaskFemConstraintGear::onForceChanged(double f) +{ + Fem::ConstraintGear* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Force.setValue((float)f); +} + +void TaskFemConstraintGear::onForceAngleChanged(double a) +{ + Fem::ConstraintGear* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->ForceAngle.setValue((float)a); +} + +void TaskFemConstraintGear::onButtonDirection(const bool pressed) { + if (pressed) { + selectionMode = seldir; + } else { + selectionMode = selnone; + } + ui->buttonDirection->setChecked(pressed); + Gui::Selection().clearSelection(); +} + +void TaskFemConstraintGear::onCheckReversed(const bool pressed) +{ + Fem::ConstraintGear* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Reversed.setValue(pressed); +} + +double TaskFemConstraintGear::getForce(void) const +{ + return ui->spinForce->value(); +} + +double TaskFemConstraintGear::getForceAngle(void) const +{ + return ui->spinForceAngle->value(); +} + +const std::string TaskFemConstraintGear::getDirectionName(void) const +{ + std::string dir = ui->lineDirection->text().toStdString(); + if (dir.empty()) + return ""; + + int pos = dir.find_last_of(":"); + return dir.substr(0, pos).c_str(); +} + +const std::string TaskFemConstraintGear::getDirectionObject(void) const +{ + std::string dir = ui->lineDirection->text().toStdString(); + if (dir.empty()) + return ""; + + int pos = dir.find_last_of(":"); + return dir.substr(pos+1).c_str(); +} + +bool TaskFemConstraintGear::getReverse() const +{ + return ui->checkReversed->isChecked(); +} + double TaskFemConstraintGear::getDiameter(void) const { return ui->spinDiameter->value(); @@ -107,10 +253,14 @@ void TaskFemConstraintGear::changeEvent(QEvent *e) TaskBox::changeEvent(e); if (e->type() == QEvent::LanguageChange) { ui->spinDiameter->blockSignals(true); - ui->spinDistance->blockSignals(true); + ui->spinForce->blockSignals(true); + ui->spinForceAngle->blockSignals(true); + ui->checkReversed->blockSignals(true); ui->retranslateUi(proxy); ui->spinDiameter->blockSignals(false); - ui->spinDistance->blockSignals(false); + ui->spinForce->blockSignals(false); + ui->spinForceAngle->blockSignals(true); + ui->checkReversed->blockSignals(false); } } @@ -123,7 +273,7 @@ TaskDlgFemConstraintGear::TaskDlgFemConstraintGear(ViewProviderFemConstraintGear { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintGear(ConstraintView);; + this->parameter = new TaskFemConstraintGear(ConstraintView, 0, "Fem_ConstraintGear"); Content.push_back(parameter); } @@ -137,8 +287,23 @@ bool TaskDlgFemConstraintGear::accept() try { //Gui::Command::openCommand("FEM force constraint changed"); + std::string dirname = parameterGear->getDirectionName().data(); + std::string dirobj = parameterGear->getDirectionObject().data(); + + if (!dirname.empty()) { + QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); + buf = buf.arg(QString::fromStdString(dirname)); + buf = buf.arg(QString::fromStdString(dirobj)); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = %s", name.c_str(), buf.toStdString().c_str()); + } else { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str()); + } + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %s", name.c_str(), parameterGear->getReverse() ? "True" : "False"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Diameter = %f",name.c_str(), parameterGear->getDiameter()); - } + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Force = %f",name.c_str(), parameterGear->getForce()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ForceAngle = %f",name.c_str(), parameterGear->getForceAngle()); + } catch (const Base::Exception& e) { QMessageBox::warning(parameter, tr("Input error"), QString::fromAscii(e.what())); return false; diff --git a/src/Mod/Fem/Gui/TaskFemConstraintGear.h b/src/Mod/Fem/Gui/TaskFemConstraintGear.h index bfc8eee099..048d9d6963 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintGear.h +++ b/src/Mod/Fem/Gui/TaskFemConstraintGear.h @@ -31,16 +31,6 @@ #include "TaskFemConstraintBearing.h" #include "ViewProviderFemConstraintGear.h" -class Ui_TaskFemConstraintGear; - -namespace App { -class Property; -} - -namespace Gui { -class ViewProvider; -} - namespace FemGui { class TaskFemConstraintGear : public TaskFemConstraintBearing @@ -48,16 +38,26 @@ class TaskFemConstraintGear : public TaskFemConstraintBearing Q_OBJECT public: - TaskFemConstraintGear(ViewProviderFemConstraintGear *ConstraintView,QWidget *parent = 0); + TaskFemConstraintGear(ViewProviderFemConstraint *ConstraintView,QWidget *parent = 0, + const char* pixmapname = "Fem_ConstraintGear"); double getDiameter(void) const; + double getForce(void) const; + double getForceAngle(void) const; + const std::string getDirectionName(void) const; + const std::string getDirectionObject(void) const; + bool getReverse(void) const; private Q_SLOTS: void onDiameterChanged(double dia); + void onForceChanged(double force); + void onForceAngleChanged(double angle); + void onButtonDirection(const bool pressed = true); + void onCheckReversed(bool); protected: virtual void changeEvent(QEvent *e); - + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); }; /// simulation dialog for the TaskView @@ -66,6 +66,7 @@ class TaskDlgFemConstraintGear : public TaskDlgFemConstraintBearing Q_OBJECT public: + TaskDlgFemConstraintGear() {} TaskDlgFemConstraintGear(ViewProviderFemConstraintGear *ConstraintView); /// is called by the framework if the dialog is accepted (Ok) diff --git a/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp b/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp index f239a37ec4..e6d7c55ce1 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp @@ -26,7 +26,7 @@ #ifndef _PreComp_ #endif -#include "ui_TaskFemConstraintCylindrical.h" +#include "ui_TaskFemConstraintBearing.h" #include "TaskFemConstraintPulley.h" #include #include @@ -49,59 +49,61 @@ using namespace Gui; /* TRANSLATOR FemGui::TaskFemConstraintPulley */ TaskFemConstraintPulley::TaskFemConstraintPulley(ViewProviderFemConstraintPulley *ConstraintView,QWidget *parent) - : TaskFemConstraintBearing(ConstraintView, parent, "Fem_ConstraintPulley") + : TaskFemConstraintGear(ConstraintView, parent, "Fem_ConstraintPulley") { - // we need a separate container widget to add all controls to - connect(ui->spinDiameter, SIGNAL(valueChanged(double)), - this, SLOT(onDiameterChanged(double))); connect(ui->spinOtherDiameter, SIGNAL(valueChanged(double)), this, SLOT(onOtherDiameterChanged(double))); connect(ui->spinCenterDistance, SIGNAL(valueChanged(double)), this, SLOT(onCenterDistanceChanged(double))); + connect(ui->checkIsDriven, SIGNAL(toggled(bool)), + this, SLOT(onCheckIsDriven(bool))); + connect(ui->spinTensionForce, SIGNAL(valueChanged(double)), + this, SLOT(onTensionForceChanged(double))); // Temporarily prevent unnecessary feature recomputes - ui->spinDiameter->blockSignals(true); ui->spinOtherDiameter->blockSignals(true); ui->spinCenterDistance->blockSignals(true); + ui->checkIsDriven->blockSignals(true); + ui->spinTensionForce->blockSignals(true); // Get the feature data Fem::ConstraintPulley* pcConstraint = static_cast(ConstraintView->getObject()); - double dia = pcConstraint->Diameter.getValue(); double otherdia = pcConstraint->OtherDiameter.getValue(); double centerdist = pcConstraint->CenterDistance.getValue(); + bool isdriven = pcConstraint->IsDriven.getValue(); + double tensionforce = pcConstraint->TensionForce.getValue(); // Fill data into dialog elements - ui->spinDiameter->setMinimum(0); - ui->spinDiameter->setMaximum(INT_MAX); - ui->spinDiameter->setValue(dia); ui->spinOtherDiameter->setMinimum(0); - ui->spinOtherDiameter->setMaximum(INT_MAX); + ui->spinOtherDiameter->setMaximum(FLOAT_MAX); ui->spinOtherDiameter->setValue(otherdia); - ui->spinCenterDistance->setMinimum(INT_MIN); - ui->spinCenterDistance->setMaximum(INT_MAX); + ui->spinCenterDistance->setMinimum(0); + ui->spinCenterDistance->setMaximum(FLOAT_MAX); ui->spinCenterDistance->setValue(centerdist); + ui->checkIsDriven->setChecked(isdriven); + ui->spinForce->setMinimum(-FLOAT_MAX); + ui->spinTensionForce->setMinimum(0); + ui->spinTensionForce->setMaximum(FLOAT_MAX); + ui->spinTensionForce->setValue(tensionforce); - // Adjust ui to specific constraint type - ui->checkAxial->setVisible(false); - ui->spinDiameter->setVisible(true); - ui->labelDiameter->setVisible(true); + // Adjust ui + ui->buttonDirection->setVisible(false); + ui->lineDirection->setVisible(false); + ui->checkReversed->setVisible(false); ui->labelDiameter->setText(tr("Pulley diameter")); + ui->labelForce->setText(tr("Torque [Nm]")); ui->labelOtherDiameter->setVisible(true); ui->spinOtherDiameter->setVisible(true); ui->labelCenterDistance->setVisible(true); ui->spinCenterDistance->setVisible(true); + ui->checkIsDriven->setVisible(true); + ui->labelTensionForce->setVisible(true); + ui->spinTensionForce->setVisible(true); - ui->spinDiameter->blockSignals(false); ui->spinOtherDiameter->blockSignals(false); ui->spinCenterDistance->blockSignals(false); - - onButtonReference(true); -} - -void TaskFemConstraintPulley::onDiameterChanged(double l) -{ - Fem::ConstraintPulley* pcConstraint = static_cast(ConstraintView->getObject()); - pcConstraint->Diameter.setValue((float)l); + ui->checkIsDriven->blockSignals(false); + ui->spinTensionForce->blockSignals(false); } void TaskFemConstraintPulley::onOtherDiameterChanged(double l) @@ -116,9 +118,31 @@ void TaskFemConstraintPulley::onCenterDistanceChanged(double l) pcConstraint->CenterDistance.setValue((float)l); } -double TaskFemConstraintPulley::getDiameter(void) const +void TaskFemConstraintPulley::onTensionForceChanged(double force) { - return ui->spinDiameter->value(); + Fem::ConstraintPulley* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->TensionForce.setValue((float)force); +} + +void TaskFemConstraintPulley::onCheckIsDriven(const bool pressed) +{ + Fem::ConstraintPulley* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->IsDriven.setValue(pressed); +} + +double TaskFemConstraintPulley::getTorque(void) const +{ + return ui->spinForce->value(); +} + +double TaskFemConstraintPulley::getTensionForce(void) const +{ + return ui->spinTensionForce->value(); +} + +bool TaskFemConstraintPulley::getIsDriven() const +{ + return ui->checkIsDriven->isChecked(); } double TaskFemConstraintPulley::getOtherDiameter(void) const @@ -135,15 +159,15 @@ void TaskFemConstraintPulley::changeEvent(QEvent *e) { TaskBox::changeEvent(e); if (e->type() == QEvent::LanguageChange) { - ui->spinDiameter->blockSignals(true); - ui->spinDistance->blockSignals(true); ui->spinOtherDiameter->blockSignals(true); ui->spinCenterDistance->blockSignals(true); + ui->checkIsDriven->blockSignals(true); + ui->spinTensionForce->blockSignals(true); ui->retranslateUi(proxy); - ui->spinDiameter->blockSignals(false); - ui->spinDistance->blockSignals(false); ui->spinOtherDiameter->blockSignals(false); ui->spinCenterDistance->blockSignals(false); + ui->checkIsDriven->blockSignals(false); + ui->spinTensionForce->blockSignals(false); } } @@ -169,17 +193,18 @@ bool TaskDlgFemConstraintPulley::accept() const TaskFemConstraintPulley* parameterPulley = static_cast(parameter); try { - //Gui::Command::openCommand("FEM force constraint changed"); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Diameter = %f",name.c_str(), parameterPulley->getDiameter()); + //Gui::Command::openCommand("FEM pulley constraint changed"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.OtherDiameter = %f",name.c_str(), parameterPulley->getOtherDiameter()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.CenterDistance = %f",name.c_str(), parameterPulley->getCenterDistance()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.IsDriven = %s",name.c_str(), parameterPulley->getIsDriven() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.TensionForce = %f",name.c_str(), parameterPulley->getTensionForce()); } catch (const Base::Exception& e) { QMessageBox::warning(parameter, tr("Input error"), QString::fromAscii(e.what())); return false; } - return TaskDlgFemConstraintBearing::accept(); + return TaskDlgFemConstraintGear::accept(); } #include "moc_TaskFemConstraintPulley.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintPulley.h b/src/Mod/Fem/Gui/TaskFemConstraintPulley.h index 11196dafeb..f2b92c5b9e 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintPulley.h +++ b/src/Mod/Fem/Gui/TaskFemConstraintPulley.h @@ -28,44 +28,36 @@ #include #include -#include "TaskFemConstraintBearing.h" +#include "TaskFemConstraintGear.h" #include "ViewProviderFemConstraintPulley.h" -class Ui_TaskFemConstraintPulley; - -namespace App { -class Property; -} - -namespace Gui { -class ViewProvider; -} - namespace FemGui { -class TaskFemConstraintPulley : public TaskFemConstraintBearing +class TaskFemConstraintPulley : public TaskFemConstraintGear { Q_OBJECT public: TaskFemConstraintPulley(ViewProviderFemConstraintPulley *ConstraintView,QWidget *parent = 0); - double getDiameter(void) const; double getOtherDiameter(void) const; double getCenterDistance(void) const; + double getTensionForce(void) const; + double getTorque(void) const; + bool getIsDriven(void) const; private Q_SLOTS: - void onDiameterChanged(double dia); void onOtherDiameterChanged(double dia); void onCenterDistanceChanged(double dia); + void onTensionForceChanged(double force); + void onCheckIsDriven(bool); protected: virtual void changeEvent(QEvent *e); - }; /// simulation dialog for the TaskView -class TaskDlgFemConstraintPulley : public TaskDlgFemConstraintBearing +class TaskDlgFemConstraintPulley : public TaskDlgFemConstraintGear { Q_OBJECT diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp index 778b59b3af..0668c05f89 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp @@ -43,6 +43,10 @@ #include "TaskFemConstraint.h" #include "Gui/Control.h" +#include "Gui/MainWindow.h" +#include "Gui/Command.h" +#include "Gui/Application.h" +#include "Gui/Document.h" #include @@ -79,9 +83,11 @@ ViewProviderFemConstraint::ViewProviderFemConstraint() TextColor.touch(); FontSize.touch(); - FaceColor.touch(); + FaceColor.touch(); - oldDlg = NULL; + wizardWidget = NULL; + wizardSubLayout = NULL; + constraintDialog = NULL; } ViewProviderFemConstraint::~ViewProviderFemConstraint() @@ -95,7 +101,6 @@ ViewProviderFemConstraint::~ViewProviderFemConstraint() void ViewProviderFemConstraint::attach(App::DocumentObject* pcObject) { - Base::Console().Error("VP FemConstraint attach %s\n", pcObject->getNameInDocument()); ViewProviderDocumentObject::attach(pcObject); SoPickStyle* ps = new SoPickStyle(); @@ -142,11 +147,6 @@ void ViewProviderFemConstraint::setupContextMenu(QMenu* menu, QObject* receiver, void ViewProviderFemConstraint::onChanged(const App::Property* prop) { - if (this->getObject() != NULL) - Base::Console().Error("%s: VP onChanged: %s\n", this->getObject()->getNameInDocument(), prop->getName()); - else - Base::Console().Error("Anonymous: VP onChanged: %s\n", prop->getName()); - if (prop == &Mirror || prop == &DistFactor) { updateData(prop); } @@ -166,19 +166,30 @@ void ViewProviderFemConstraint::onChanged(const App::Property* prop) } } +bool ViewProviderFemConstraint::setEdit(int ModNum) +{ + return Gui::ViewProviderGeometryObject::setEdit(ModNum); +} + void ViewProviderFemConstraint::unsetEdit(int ModNum) { - if (ModNum == ViewProvider::Default) { - // when pressing ESC make sure to close the dialog - Gui::Control().closeDialog(); - } - else { - ViewProviderDocumentObject::unsetEdit(ModNum); - } + if ((wizardWidget != NULL) && (wizardSubLayout != NULL) && (constraintDialog != NULL)) { + wizardWidget = NULL; + wizardSubLayout = NULL; + delete constraintDialog; + constraintDialog = NULL; - if (oldDlg != NULL) { - Gui::Control().showDialog(oldDlg); - oldDlg = NULL; + // Notify the Shaft Wizard that we have finished editing + // See WizardShaft.py on why we do it this way + Gui::Command::runCommand(Gui::Command::Doc, "Gui.runCommand('PartDesign_WizardShaftCallBack')"); + } else { + if (ModNum == ViewProvider::Default) { + // when pressing ESC make sure to close the dialog + Gui::Control().closeDialog(); + } + else { + ViewProviderDocumentObject::unsetEdit(ModNum); + } } } /* @@ -388,3 +399,41 @@ void ViewProviderFemConstraint::updateFixed(const SoNode* node, const int idx, c updateCube(sep, idx+CONE_CHILDREN+PLACEMENT_CHILDREN, width, width, width/4); } +QObject* ViewProviderFemConstraint::findChildByName(const QObject* parent, const QString& name) +{ + for (QObjectList::const_iterator o = parent->children().begin(); o != parent->children().end(); o++) { + if ((*o)->objectName() == name) + return *o; + if (!(*o)->children().empty()) { + QObject* result = findChildByName(*o, name); + if (result != NULL) + return result; + } + } + + return NULL; +} + +void ViewProviderFemConstraint::checkForWizard() +{ + wizardWidget= NULL; + wizardSubLayout = NULL; + Gui::MainWindow* mw = Gui::getMainWindow(); + if (mw == NULL) return; + QDockWidget* dw = mw->findChild(QObject::tr("Combo View")); + if (dw == NULL) return; + QWidget* cw = dw->findChild(QObject::tr("Combo View")); + if (cw == NULL) return; + QTabWidget* tw = cw->findChild(QObject::tr("combiTab")); + if (tw == NULL) return; + QStackedWidget* sw = tw->findChild(QObject::tr("qt_tabwidget_stackedwidget")); + if (sw == NULL) return; + QScrollArea* sa = sw->findChild(); + if (sa== NULL) return; + QWidget* wd = sa->widget(); // This is the reason why we cannot use findChildByName() right away!!! + if (wd == NULL) return; + QObject* wiz = findChildByName(wd, QObject::tr("ShaftWizard")); // FIXME: Actually, we don't want to translate this... + if (wiz != NULL) + wizardWidget = static_cast(wiz); + wizardSubLayout = wiz->findChild(QObject::tr("ShaftWizardLayout")); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h index 015f8d38c4..82e1803d5b 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h @@ -28,6 +28,8 @@ #include "Gui/ViewProviderGeometryObject.h" #include +#include +#include class SoFontStyle; class SoText2; @@ -46,6 +48,8 @@ class View3DInventorViewer; namespace FemGui { +class TaskFemConstraint; + class FemGuiExport ViewProviderFemConstraint : public Gui::ViewProviderGeometryObject { PROPERTY_HEADER(FemGui::ViewProviderFemConstraint); @@ -73,7 +77,7 @@ public: protected: void onChanged(const App::Property* prop); - virtual bool setEdit(int ModNum) { return Gui::ViewProviderGeometryObject::setEdit(ModNum); } + virtual bool setEdit(int ModNum); virtual void unsetEdit(int ModNum); static void createPlacement(SoSeparator* sep, const SbVec3f &base, const SbRotation &r); @@ -103,7 +107,15 @@ private: protected: SoSeparator * pShapeSep; - Gui::TaskView::TaskDialog *oldDlg; + // Shaft design wizard integration +protected: + friend class TaskFemConstraint; + QVBoxLayout* wizardWidget; + QVBoxLayout* wizardSubLayout; + TaskFemConstraint* constraintDialog; + + void checkForWizard(); + static QObject* findChildByName(const QObject* parent, const QString& name); }; } //namespace FemGui diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp index f19849181f..9c29278a4e 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp @@ -34,6 +34,7 @@ #include #include "TaskFemConstraintBearing.h" #include "Gui/Control.h" +#include "Gui/MainWindow.h" #include @@ -45,6 +46,7 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintBearing, FemGui::ViewProviderFe ViewProviderFemConstraintBearing::ViewProviderFemConstraintBearing() { sPixmap = "view-femconstraintbearing"; + wizardWidget = NULL; } ViewProviderFemConstraintBearing::~ViewProviderFemConstraintBearing() @@ -53,6 +55,9 @@ ViewProviderFemConstraintBearing::~ViewProviderFemConstraintBearing() bool ViewProviderFemConstraintBearing::setEdit(int ModNum) { + Base::Console().Error("ViewProviderFemConstraintBearing::setEdit()\n"); + Base::Console().Error("Active dialog: %s\n", Gui::Control().activeDialog()->objectName().toStdString().c_str()); + if (ModNum == ViewProvider::Default ) { // When double-clicking on the item for this constraint the // object unsets and sets its edit mode without closing @@ -62,21 +67,28 @@ bool ViewProviderFemConstraintBearing::setEdit(int ModNum) if (constrDlg && constrDlg->getConstraintView() != this) constrDlg = 0; // another constraint left open its task panel if (dlg && !constrDlg) { - // Allow stacking of dialogs, for ShaftWizard application - // Note: If other features start to allow stacking, we need to check for oldDlg != NULL - oldDlg = dlg; - /* - 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().closeDialog(); - else + // This case will occur in the ShaftWizard application + checkForWizard(); + if ((wizardWidget == NULL) || (wizardSubLayout == NULL)) { + // 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().closeDialog(); + else + return false; + } else if (constraintDialog != NULL) { + // Another FemConstraint* dialog is already open inside the Shaft Wizard + // Ignore the request to open another dialog return false; - */ + } else { + constraintDialog = new TaskFemConstraintBearing(this); + return true; + } } // clear the selection (convenience) @@ -97,11 +109,6 @@ bool ViewProviderFemConstraintBearing::setEdit(int ModNum) void ViewProviderFemConstraintBearing::updateData(const App::Property* prop) { - if (this->getObject() != NULL) - Base::Console().Error("%s: VP updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); - else - Base::Console().Error("Anonymous: VP updateData: %s\n", prop->getName()); - // Gets called whenever a property of the attached object changes Fem::ConstraintBearing* pcConstraint = static_cast(this->getObject()); diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.h index a7ceff6dfe..603a043137 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.h +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.h @@ -28,6 +28,7 @@ #include "ViewProviderFemConstraint.h" #include +#include class SoFontStyle; class SoText2; diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp index 88fdf84cb7..ca08541d60 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp @@ -57,6 +57,7 @@ ViewProviderFemConstraintFixed::~ViewProviderFemConstraintFixed() bool ViewProviderFemConstraintFixed::setEdit(int ModNum) { + Base::Console().Error("ViewProviderFemConstraintFixed::setEdit()\n"); if (ModNum == ViewProvider::Default ) { // When double-clicking on the item for this constraint the // object unsets and sets its edit mode without closing @@ -66,21 +67,28 @@ bool ViewProviderFemConstraintFixed::setEdit(int ModNum) if (constrDlg && constrDlg->getConstraintView() != this) constrDlg = 0; // another constraint left open its task panel if (dlg && !constrDlg) { - // Allow stacking of dialogs, for ShaftWizard application - // Note: If other features start to allow stacking, we need to check for oldDlg != NULL - oldDlg = dlg; - /* - 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().closeDialog(); - else + // This case will occur in the ShaftWizard application + checkForWizard(); + if ((wizardWidget == NULL) || (wizardSubLayout == NULL)) { + // 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().closeDialog(); + else + return false; + } else if (constraintDialog != NULL) { + // Another FemConstraint* dialog is already open inside the Shaft Wizard + // Ignore the request to open another dialog return false; - */ + } else { + constraintDialog = new TaskFemConstraintFixed(this); + return true; + } } // clear the selection (convenience) @@ -93,8 +101,7 @@ bool ViewProviderFemConstraintFixed::setEdit(int ModNum) Gui::Control().showDialog(new TaskDlgFemConstraintFixed(this)); return true; - } - else { + } else { return ViewProviderDocumentObject::setEdit(ModNum); } } @@ -105,11 +112,6 @@ bool ViewProviderFemConstraintFixed::setEdit(int ModNum) void ViewProviderFemConstraintFixed::updateData(const App::Property* prop) { // Gets called whenever a property of the attached object changes - if (this->getObject() != NULL) - Base::Console().Error("%s: VPF updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); - else - Base::Console().Error("Anonymous: VPF updateData: %s\n", prop->getName()); - Fem::ConstraintFixed* pcConstraint = static_cast(this->getObject()); /* diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp index 8003f45e8b..fd82e3381c 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp @@ -46,7 +46,7 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintForce, FemGui::ViewProviderFemC ViewProviderFemConstraintForce::ViewProviderFemConstraintForce() { - sPixmap = "view-femconstraintforce"; + sPixmap = "view-femconstraintforce"; } ViewProviderFemConstraintForce::~ViewProviderFemConstraintForce() @@ -55,6 +55,8 @@ ViewProviderFemConstraintForce::~ViewProviderFemConstraintForce() bool ViewProviderFemConstraintForce::setEdit(int ModNum) { + Base::Console().Error("ViewProviderFemConstraintForce::setEdit(%u)\n", ModNum); + if (ModNum == ViewProvider::Default ) { // When double-clicking on the item for this constraint the // object unsets and sets its edit mode without closing @@ -64,21 +66,28 @@ bool ViewProviderFemConstraintForce::setEdit(int ModNum) if (constrDlg && constrDlg->getConstraintView() != this) constrDlg = 0; // another constraint left open its task panel if (dlg && !constrDlg) { - // Allow stacking of dialogs, for ShaftWizard application - // Note: If other features start to allow stacking, we need to check for oldDlg != NULL - oldDlg = dlg; - /* - 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().closeDialog(); - else + // This case will occur in the ShaftWizard application + checkForWizard(); + if ((wizardWidget == NULL) || (wizardSubLayout == NULL)) { + // 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().closeDialog(); + else + return false; + } else if (constraintDialog != NULL) { + // Another FemConstraint* dialog is already open inside the Shaft Wizard + // Ignore the request to open another dialog return false; - */ + } else { + constraintDialog = new TaskFemConstraintForce(this); + return true; + } } // clear the selection (convenience) @@ -103,11 +112,6 @@ bool ViewProviderFemConstraintForce::setEdit(int ModNum) void ViewProviderFemConstraintForce::updateData(const App::Property* prop) { // Gets called whenever a property of the attached object changes - if (this->getObject() != NULL) - Base::Console().Error("%s: VPF updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); - else - Base::Console().Error("Anonymous: VPF updateData: %s\n", prop->getName()); - Fem::ConstraintForce* pcConstraint = static_cast(this->getObject()); /* diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp index e30aecb78c..c8b4417554 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp @@ -27,6 +27,7 @@ # include # include # include +# include # include #endif @@ -53,6 +54,7 @@ ViewProviderFemConstraintGear::~ViewProviderFemConstraintGear() bool ViewProviderFemConstraintGear::setEdit(int ModNum) { + Base::Console().Error("ViewProviderFemConstraintGear::setEdit()\n"); if (ModNum == ViewProvider::Default ) { // When double-clicking on the item for this constraint the // object unsets and sets its edit mode without closing @@ -62,21 +64,28 @@ bool ViewProviderFemConstraintGear::setEdit(int ModNum) if (constrDlg && constrDlg->getConstraintView() != this) constrDlg = 0; // another constraint left open its task panel if (dlg && !constrDlg) { - // Allow stacking of dialogs, for ShaftWizard application - // Note: If other features start to allow stacking, we need to check for oldDlg != NULL - oldDlg = dlg; - /* - 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().closeDialog(); - else + // This case will occur in the ShaftWizard application + checkForWizard(); + if ((wizardWidget == NULL) || (wizardSubLayout == NULL)) { + // 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().closeDialog(); + else + return false; + } else if (constraintDialog != NULL) { + // Another FemConstraint* dialog is already open inside the Shaft Wizard + // Ignore the request to open another dialog return false; - */ + } else { + constraintDialog = new TaskFemConstraintGear(this); + return true; + } } // clear the selection (convenience) @@ -97,57 +106,84 @@ bool ViewProviderFemConstraintGear::setEdit(int ModNum) void ViewProviderFemConstraintGear::updateData(const App::Property* prop) { - // Gets called whenever a property of the attached object changes Fem::ConstraintGear* pcConstraint = static_cast(this->getObject()); - if (this->getObject() != NULL) - Base::Console().Error("%s: VP updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); - else - Base::Console().Error("Anonymous: VP updateData: %s\n", prop->getName()); + // Gets called whenever a property of the attached object changes if (strcmp(prop->getName(),"BasePoint") == 0) { if (pcConstraint->Height.getValue() > Precision::Confusion()) { // Remove and recreate the symbol pShapeSep->removeAllChildren(); - // This should always point outside of the cylinder Base::Vector3f base = pcConstraint->BasePoint.getValue(); Base::Vector3f axis = pcConstraint->Axis.getValue(); + Base::Vector3f direction = pcConstraint->DirectionVector.getValue(); + if (direction.Length() < Precision::Confusion()) + direction = Base::Vector3f(0,1,0); float radius = pcConstraint->Radius.getValue(); float dia = pcConstraint->Diameter.getValue(); if (dia < 2 * radius) dia = 2 * radius; + float angle = pcConstraint->ForceAngle.getValue() / 180 * M_PI; SbVec3f b(base.x, base.y, base.z); - SbVec3f dir(axis.x, axis.y, axis.z); - SbRotation rot(SbVec3f(0,1,0), dir); + SbVec3f ax(axis.x, axis.y, axis.z); + SbVec3f dir(direction.x, direction.y, direction.z); - createPlacement(pShapeSep, b, rot); + createPlacement(pShapeSep, b, SbRotation(SbVec3f(0,1,0), ax)); pShapeSep->addChild(createCylinder(pcConstraint->Height.getValue() * 0.8, dia/2)); - createPlacement(pShapeSep, SbVec3f(-dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(0,0,1))); + createPlacement(pShapeSep, SbVec3f(dia/2 * sin(angle), 0, dia/2 * cos(angle)), SbRotation(ax, dir)); pShapeSep->addChild(createArrow(dia/2, dia/8)); } } else if (strcmp(prop->getName(),"Diameter") == 0) { if (pShapeSep->getNumChildren() > 0) { // Change the symbol - Base::Vector3f base = pcConstraint->BasePoint.getValue(); Base::Vector3f axis = pcConstraint->Axis.getValue(); - //float radius = pcConstraint->Radius.getValue(); + Base::Vector3f direction = pcConstraint->DirectionVector.getValue(); + if (direction.Length() < Precision::Confusion()) + direction = Base::Vector3f(0,1,0); float dia = pcConstraint->Diameter.getValue(); float radius = pcConstraint->Radius.getValue(); if (dia < 2 * radius) dia = 2 * radius; + float angle = pcConstraint->ForceAngle.getValue() / 180 * M_PI; - SbVec3f b(base.x, base.y, base.z); - SbVec3f dir(axis.x, axis.y, axis.z); - SbRotation rot(SbVec3f(0,1,0), dir); + SbVec3f ax(axis.x, axis.y, axis.z); + SbVec3f dir(direction.x, direction.y, direction.z); - updatePlacement(pShapeSep, 0, b, rot); const SoSeparator* sep = static_cast(pShapeSep->getChild(2)); updateCylinder(sep, 0, pcConstraint->Height.getValue() * 0.8, dia/2); - updatePlacement(pShapeSep, 3, SbVec3f(-dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(0,0,1))); + updatePlacement(pShapeSep, 3, SbVec3f(dia/2 * sin(angle), 0, dia/2 * cos(angle)), SbRotation(ax, dir)); sep = static_cast(pShapeSep->getChild(5)); updateArrow(sep, 0, dia/2, dia/8); } + } else if ((strcmp(prop->getName(),"DirectionVector") == 0) || (strcmp(prop->getName(),"ForceAngle") == 0)) { + // Note: "Reversed" also triggers "DirectionVector" + if (pShapeSep->getNumChildren() > 0) { + // Re-orient the symbol + Base::Vector3f axis = pcConstraint->Axis.getValue(); + Base::Vector3f direction = pcConstraint->DirectionVector.getValue(); + if (direction.Length() < Precision::Confusion()) + direction = Base::Vector3f(0,1,0); + float dia = pcConstraint->Diameter.getValue(); + float angle = pcConstraint->ForceAngle.getValue() / 180 * M_PI; + + SbVec3f ax(axis.x, axis.y, axis.z); + SbVec3f dir(direction.x, direction.y, direction.z); + /*Base::Console().Error("Axis: %f, %f, %f\n", axis.x, axis.y, axis.z); + Base::Console().Error("Direction: %f, %f, %f\n", direction.x, direction.y, direction.z); + SbRotation rot = SbRotation(ax, dir); + SbMatrix m; + rot.getValue(m); + SbMat m2; + m.getValue(m2); + Base::Console().Error("Matrix: %f, %f, %f, %f\n", m[0][0], m[1][0], m[2][0], m[3][0]); + // Note: In spite of the fact that the rotation matrix takes on 3 different values if 3 + // normal directions are chosen, the resulting arrow will only point in two different + // directions when ax = (1,0,0) (but for ax=(0,1,0) it points in 3 different directions!) + */ + + updatePlacement(pShapeSep, 3, SbVec3f(dia/2 * sin(angle), 0, dia/2 * cos(angle)), SbRotation(ax, dir)); + } } ViewProviderFemConstraint::updateData(prop); diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp index df47623648..518b4b4873 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp @@ -53,6 +53,7 @@ ViewProviderFemConstraintPulley::~ViewProviderFemConstraintPulley() bool ViewProviderFemConstraintPulley::setEdit(int ModNum) { + Base::Console().Error("ViewProviderFemConstraintPulley::setEdit()\n"); if (ModNum == ViewProvider::Default ) { // When double-clicking on the item for this constraint the // object unsets and sets its edit mode without closing @@ -62,21 +63,28 @@ bool ViewProviderFemConstraintPulley::setEdit(int ModNum) if (constrDlg && constrDlg->getConstraintView() != this) constrDlg = 0; // another constraint left open its task panel if (dlg && !constrDlg) { - // Allow stacking of dialogs, for ShaftWizard application - // Note: If other features start to allow stacking, we need to check for oldDlg != NULL - oldDlg = dlg; - /* - 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().closeDialog(); - else + // This case will occur in the ShaftWizard application + checkForWizard(); + if ((wizardWidget == NULL) || (wizardSubLayout == NULL)) { + // 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().closeDialog(); + else + return false; + } else if (constraintDialog != NULL) { + // Another FemConstraint* dialog is already open inside the Shaft Wizard + // Ignore the request to open another dialog return false; - */ + } else { + constraintDialog = new TaskFemConstraintPulley(this); + return true; + } } // clear the selection (convenience) @@ -99,10 +107,6 @@ void ViewProviderFemConstraintPulley::updateData(const App::Property* prop) { // Gets called whenever a property of the attached object changes Fem::ConstraintPulley* pcConstraint = static_cast(this->getObject()); - if (this->getObject() != NULL) - Base::Console().Error("%s: VP updateData: %s\n", this->getObject()->getNameInDocument(), prop->getName()); - else - Base::Console().Error("Anonymous: VP updateData: %s\n", prop->getName()); if (strcmp(prop->getName(),"BasePoint") == 0) { if (pcConstraint->Height.getValue() > Precision::Confusion()) { @@ -116,49 +120,104 @@ void ViewProviderFemConstraintPulley::updateData(const App::Property* prop) float dia = pcConstraint->Diameter.getValue(); if (dia < 2 * radius) dia = 2 * radius; - float angle = pcConstraint->Angle.getValue(); + float forceAngle = pcConstraint->ForceAngle.getValue() / 180 * M_PI; + float beltAngle = pcConstraint->BeltAngle.getValue(); + double rat1 = 0.8, rat2 = 0.2; + float f1 = pcConstraint->BeltForce1.getValue(); + float f2 = pcConstraint->BeltForce2.getValue(); + if (f1+f2 > Precision::Confusion()) { + rat1 = f1 / (f1+f2); + rat2 = f2 / (f1+f2); + } SbVec3f b(base.x, base.y, base.z); - SbVec3f dir(axis.x, axis.y, axis.z); - SbRotation rot(SbVec3f(0,-1,0), dir); + SbVec3f ax(axis.x, axis.y, axis.z); - createPlacement(pShapeSep, b, rot); // child 0 and 1 + createPlacement(pShapeSep, b, SbRotation(SbVec3f(0,1,0), ax)); // child 0 and 1 pShapeSep->addChild(createCylinder(pcConstraint->Height.getValue() * 0.8, dia/2)); // child 2 SoSeparator* sep = new SoSeparator(); - createPlacement(sep, SbVec3f(dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(sin(angle),0,cos(angle)))); - sep->addChild(createArrow(dia/2, dia/8)); + createPlacement(sep, SbVec3f(dia/2 * sin(forceAngle+beltAngle), 0, dia/2 * cos(forceAngle+beltAngle)), + SbRotation(SbVec3f(0,1,0), SbVec3f(sin(forceAngle+beltAngle+M_PI_2),0,cos(forceAngle+beltAngle+M_PI_2)))); + createPlacement(sep, SbVec3f(0, dia/8 + dia/2 * rat1, 0), SbRotation()); + sep->addChild(createArrow(dia/8 + dia/2 * rat1, dia/8)); pShapeSep->addChild(sep); // child 3 sep = new SoSeparator(); - createPlacement(sep, SbVec3f(-dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(-sin(angle),0,cos(angle)))); - sep->addChild(createArrow(dia/2, dia/8)); + createPlacement(sep, SbVec3f(-dia/2 * sin(forceAngle-beltAngle), 0, -dia/2 * cos(forceAngle-beltAngle)), + SbRotation(SbVec3f(0,1,0), SbVec3f(-sin(forceAngle-beltAngle-M_PI_2),0,-cos(forceAngle-beltAngle-M_PI_2)))); + createPlacement(sep, SbVec3f(0, dia/8 + dia/2 * rat2, 0), SbRotation()); + sep->addChild(createArrow(dia/8 + dia/2 * rat2, dia/8)); pShapeSep->addChild(sep); // child 4 } - } else if (strcmp(prop->getName(),"Angle") == 0) { + } else if (strcmp(prop->getName(),"Diameter") == 0) { if (pShapeSep->getNumChildren() > 0) { // Change the symbol - Base::Vector3f base = pcConstraint->BasePoint.getValue(); - Base::Vector3f axis = pcConstraint->Axis.getValue(); float radius = pcConstraint->Radius.getValue(); float dia = pcConstraint->Diameter.getValue(); if (dia < 2 * radius) dia = 2 * radius; - float angle = pcConstraint->Angle.getValue(); + float forceAngle = pcConstraint->ForceAngle.getValue() / 180 * M_PI; + float beltAngle = pcConstraint->BeltAngle.getValue(); + double rat1 = 0.8, rat2 = 0.2; + float f1 = pcConstraint->BeltForce1.getValue(); + float f2 = pcConstraint->BeltForce2.getValue(); + if (f1+f2 > Precision::Confusion()) { + rat1 = f1 / (f1+f2); + rat2 = f2 / (f1+f2); + } - SbVec3f b(base.x, base.y, base.z); - SbVec3f dir(axis.x, axis.y, axis.z); - SbRotation rot(SbVec3f(0,-1,0), dir); - - updatePlacement(pShapeSep, 0, b, rot); const SoSeparator* sep = static_cast(pShapeSep->getChild(2)); updateCylinder(sep, 0, pcConstraint->Height.getValue() * 0.8, dia/2); sep = static_cast(pShapeSep->getChild(3)); - updatePlacement(sep, 0, SbVec3f(dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(sin(angle),0,cos(angle)))); - const SoSeparator* subsep = static_cast(sep->getChild(2)); - updateArrow(subsep, 0, dia/2, dia/8); + updatePlacement(sep, 0, SbVec3f(dia/2 * sin(forceAngle+beltAngle), 0, dia/2 * cos(forceAngle+beltAngle)), + SbRotation(SbVec3f(0,1,0), SbVec3f(sin(forceAngle+beltAngle+M_PI_2),0,cos(forceAngle+beltAngle+M_PI_2)))); + updatePlacement(sep, 2, SbVec3f(0, dia/8 + dia/2 * rat1, 0), SbRotation()); + const SoSeparator* subsep = static_cast(sep->getChild(4)); + updateArrow(subsep, 0, dia/8 + dia/2 * rat1, dia/8); sep = static_cast(pShapeSep->getChild(4)); - updatePlacement(sep, 0, SbVec3f(-dia/2,0,0), SbRotation(SbVec3f(0,1,0), SbVec3f(-sin(angle),0,cos(angle)))); - subsep = static_cast(sep->getChild(2)); - updateArrow(subsep, 0, dia/2, dia/8); + updatePlacement(sep, 0, SbVec3f(-dia/2 * sin(forceAngle-beltAngle), 0, -dia/2 * cos(forceAngle-beltAngle)), + SbRotation(SbVec3f(0,1,0), SbVec3f(-sin(forceAngle-beltAngle-M_PI_2),0,-cos(forceAngle-beltAngle-M_PI_2)))); + updatePlacement(sep, 2, SbVec3f(0, dia/8 + dia/2 * rat2, 0), SbRotation()); + subsep = static_cast(sep->getChild(4)); + updateArrow(subsep, 0, dia/8 + dia/2 * rat2, dia/8); + } + } else if ((strcmp(prop->getName(), "ForceAngle") == 0) || (strcmp(prop->getName(), "BeltAngle") == 0)) { + if (pShapeSep->getNumChildren() > 0) { + float radius = pcConstraint->Radius.getValue(); + float dia = pcConstraint->Diameter.getValue(); + if (dia < 2 * radius) + dia = 2 * radius; + float forceAngle = pcConstraint->ForceAngle.getValue() / 180 * M_PI; + float beltAngle = pcConstraint->BeltAngle.getValue(); + + const SoSeparator* sep = static_cast(pShapeSep->getChild(3)); + updatePlacement(sep, 0, SbVec3f(dia/2 * sin(forceAngle+beltAngle), 0, dia/2 * cos(forceAngle+beltAngle)), + SbRotation(SbVec3f(0,1,0), SbVec3f(sin(forceAngle+beltAngle+M_PI_2),0,cos(forceAngle+beltAngle+M_PI_2)))); + sep = static_cast(pShapeSep->getChild(4)); + updatePlacement(sep, 0, SbVec3f(-dia/2 * sin(forceAngle-beltAngle), 0, -dia/2 * cos(forceAngle-beltAngle)), + SbRotation(SbVec3f(0,1,0), SbVec3f(-sin(forceAngle-beltAngle-M_PI_2),0,-cos(forceAngle-beltAngle-M_PI_2)))); + } + } else if ((strcmp(prop->getName(), "BeltForce1") == 0) || (strcmp(prop->getName(), "BeltForce2") == 0)) { + if (pShapeSep->getNumChildren() > 0) { + float radius = pcConstraint->Radius.getValue(); + float dia = pcConstraint->Diameter.getValue(); + if (dia < 2 * radius) + dia = 2 * radius; + double rat1 = 0.8, rat2 = 0.2; + float f1 = pcConstraint->BeltForce1.getValue(); + float f2 = pcConstraint->BeltForce2.getValue(); + if (f1+f2 > Precision::Confusion()) { + rat1 = f1 / (f1+f2); + rat2 = f2 / (f1+f2); + } + + const SoSeparator* sep = static_cast(pShapeSep->getChild(3)); + updatePlacement(sep, 2, SbVec3f(0, dia/8 + dia/2 * rat1, 0), SbRotation()); + const SoSeparator* subsep = static_cast(sep->getChild(4)); + updateArrow(subsep, 0, dia/8 + dia/2 * rat1, dia/8); + sep = static_cast(pShapeSep->getChild(4)); + updatePlacement(sep, 2, SbVec3f(0, dia/8 + dia/2 * rat2, 0), SbRotation()); + subsep = static_cast(sep->getChild(4)); + updateArrow(subsep, 0, dia/8 + dia/2 * rat2, dia/8); } } From 20fdeb3d862347fac61711517a40be595d26c53e Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 13 Mar 2013 16:28:53 +0430 Subject: [PATCH 5/9] Added icons for FEM constraints, courtesy of jmaustpc --- src/Mod/Fem/Gui/Resources/Fem.qrc | 5 + .../Resources/icons/Fem_ConstraintBearing.svg | 435 ++++++ .../Resources/icons/Fem_ConstraintFixed.svg | 192 +++ .../Resources/icons/Fem_ConstraintForce.svg | 204 +++ .../Resources/icons/Fem_ConstraintGear.svg | 1175 +++++++++++++++++ .../Resources/icons/Fem_ConstraintPulley.svg | 1069 +++++++++++++++ .../Gui/ViewProviderFemConstraintBearing.cpp | 2 +- .../Gui/ViewProviderFemConstraintFixed.cpp | 2 +- .../Gui/ViewProviderFemConstraintForce.cpp | 2 +- .../Fem/Gui/ViewProviderFemConstraintGear.cpp | 2 +- .../Gui/ViewProviderFemConstraintPulley.cpp | 2 +- 11 files changed, 3085 insertions(+), 5 deletions(-) create mode 100644 src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintBearing.svg create mode 100644 src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintFixed.svg create mode 100644 src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintForce.svg create mode 100644 src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintGear.svg create mode 100644 src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintPulley.svg diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc index e63839105d..a93dcf0990 100755 --- a/src/Mod/Fem/Gui/Resources/Fem.qrc +++ b/src/Mod/Fem/Gui/Resources/Fem.qrc @@ -2,6 +2,11 @@ icons/Fem_FemMesh.svg icons/Fem_FemMesh_createnodebypoly.svg + icons/Fem_ConstraintForce.svg + icons/Fem_ConstraintFixed.svg + icons/Fem_ConstraintBearing.svg + icons/Fem_ConstraintGear.svg + icons/Fem_ConstraintPulley.svg translations/Fem_af.qm translations/Fem_de.qm translations/Fem_fi.qm diff --git a/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintBearing.svg b/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintBearing.svg new file mode 100644 index 0000000000..8b9904b4ae --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintBearing.svg @@ -0,0 +1,435 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintFixed.svg b/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintFixed.svg new file mode 100644 index 0000000000..9c42928d6d --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintFixed.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintForce.svg b/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintForce.svg new file mode 100644 index 0000000000..16968d60b2 --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintForce.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintGear.svg b/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintGear.svg new file mode 100644 index 0000000000..186772d3dd --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintGear.svg @@ -0,0 +1,1175 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintPulley.svg b/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintPulley.svg new file mode 100644 index 0000000000..3515aa933d --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/icons/Fem_ConstraintPulley.svg @@ -0,0 +1,1069 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp index 9c29278a4e..a2186df8ff 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintBearing.cpp @@ -45,7 +45,7 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintBearing, FemGui::ViewProviderFe ViewProviderFemConstraintBearing::ViewProviderFemConstraintBearing() { - sPixmap = "view-femconstraintbearing"; + sPixmap = "Fem_ConstraintBearing"; wizardWidget = NULL; } diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp index ca08541d60..d82603353f 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp @@ -48,7 +48,7 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintFixed, FemGui::ViewProviderFemC ViewProviderFemConstraintFixed::ViewProviderFemConstraintFixed() { - sPixmap = "view-femconstraintfixed"; + sPixmap = "Fem_ConstraintFixed"; } ViewProviderFemConstraintFixed::~ViewProviderFemConstraintFixed() diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp index fd82e3381c..56b49b0bd2 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp @@ -46,7 +46,7 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintForce, FemGui::ViewProviderFemC ViewProviderFemConstraintForce::ViewProviderFemConstraintForce() { - sPixmap = "view-femconstraintforce"; + sPixmap = "Fem_ConstraintForce"; } ViewProviderFemConstraintForce::~ViewProviderFemConstraintForce() diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp index c8b4417554..cc9fbf04fa 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp @@ -45,7 +45,7 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintGear, FemGui::ViewProviderFemCo ViewProviderFemConstraintGear::ViewProviderFemConstraintGear() { - sPixmap = "view-femconstraintgear"; + sPixmap = "Fem_ConstraintGear"; } ViewProviderFemConstraintGear::~ViewProviderFemConstraintGear() diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp index 518b4b4873..ed10aa5249 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintPulley.cpp @@ -44,7 +44,7 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintPulley, FemGui::ViewProviderFem ViewProviderFemConstraintPulley::ViewProviderFemConstraintPulley() { - sPixmap = "view-femconstraintpulley"; + sPixmap = "Fem_ConstraintPulley"; } ViewProviderFemConstraintPulley::~ViewProviderFemConstraintPulley() From af43eff2c25bee28d5cfacad5427a29a3d8beadd Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 21 Mar 2013 16:37:09 +0430 Subject: [PATCH 6/9] Minor changes to FEM constraint visuals --- src/Mod/Fem/App/FemConstraintGear.cpp | 8 ++++---- src/Mod/Fem/App/FemConstraintPulley.cpp | 8 +++++--- src/Mod/Fem/Gui/TaskFemConstraintBearing.ui | 2 +- src/Mod/Fem/Gui/TaskFemConstraintGear.cpp | 2 +- src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp | 1 + 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Mod/Fem/App/FemConstraintGear.cpp b/src/Mod/Fem/App/FemConstraintGear.cpp index cc4a68ca5a..ec62a294cc 100644 --- a/src/Mod/Fem/App/FemConstraintGear.cpp +++ b/src/Mod/Fem/App/FemConstraintGear.cpp @@ -44,15 +44,15 @@ PROPERTY_SOURCE(Fem::ConstraintGear, Fem::ConstraintBearing); ConstraintGear::ConstraintGear() { - ADD_PROPERTY(Diameter,(0)); - ADD_PROPERTY(Force,(0.0)); + ADD_PROPERTY(Diameter,(100.0)); + ADD_PROPERTY(Force,(1000.0)); ADD_PROPERTY(ForceAngle,(0.0)); ADD_PROPERTY_TYPE(Direction,(0),"ConstraintGear",(App::PropertyType)(App::Prop_None), "Element giving direction of gear force"); ADD_PROPERTY(Reversed,(0)); - ADD_PROPERTY_TYPE(DirectionVector,(Base::Vector3f(0,1,0)),"ConstraintGear",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + ADD_PROPERTY_TYPE(DirectionVector,(Base::Vector3f(1,1,1).Normalize()),"ConstraintGear",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), "Direction of gear force"); - naturalDirectionVector = Base::Vector3f(0,1,0); + naturalDirectionVector = Base::Vector3f(1,1,1).Normalize(); } App::DocumentObjectExecReturn *ConstraintGear::execute(void) diff --git a/src/Mod/Fem/App/FemConstraintPulley.cpp b/src/Mod/Fem/App/FemConstraintPulley.cpp index 7b83d6b349..4c933b4d9f 100644 --- a/src/Mod/Fem/App/FemConstraintPulley.cpp +++ b/src/Mod/Fem/App/FemConstraintPulley.cpp @@ -44,8 +44,8 @@ PROPERTY_SOURCE(Fem::ConstraintPulley, Fem::ConstraintGear); ConstraintPulley::ConstraintPulley() { - ADD_PROPERTY(OtherDiameter,(0)); - ADD_PROPERTY(CenterDistance,(0)); + ADD_PROPERTY(OtherDiameter,(100.0)); + ADD_PROPERTY(CenterDistance,(500.0)); ADD_PROPERTY(IsDriven,(0)); ADD_PROPERTY(TensionForce,(0.0)); @@ -55,8 +55,10 @@ ConstraintPulley::ConstraintPulley() "First belt force"); ADD_PROPERTY_TYPE(BeltForce2,(0.0),"ConstraintPulley",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), "Second belt force"); - ForceAngle.setValue(90.0); + ForceAngle.setValue(00.0); Diameter.setValue(300.0); + // calculate initial values of read-only properties + onChanged(&Force); } App::DocumentObjectExecReturn *ConstraintPulley::execute(void) diff --git a/src/Mod/Fem/Gui/TaskFemConstraintBearing.ui b/src/Mod/Fem/Gui/TaskFemConstraintBearing.ui index e838590049..f451990943 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintBearing.ui +++ b/src/Mod/Fem/Gui/TaskFemConstraintBearing.ui @@ -172,7 +172,7 @@ 1 - 0.000000000000000 + -360.000000000000000 360.000000000000000 diff --git a/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp b/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp index b7acec743c..4f4f3adf9b 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp @@ -100,7 +100,7 @@ TaskFemConstraintGear::TaskFemConstraintGear(ViewProviderFemConstraint *Constrai ui->spinForce->setMinimum(0); ui->spinForce->setMaximum(FLOAT_MAX); ui->spinForce->setValue(force); - ui->spinForceAngle->setMinimum(0); + ui->spinForceAngle->setMinimum(-360); ui->spinForceAngle->setMaximum(360); ui->spinForceAngle->setValue(angle); ui->lineDirection->setText(dir); diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp index cc9fbf04fa..f5df203590 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintGear.cpp @@ -128,6 +128,7 @@ void ViewProviderFemConstraintGear::updateData(const App::Property* prop) SbVec3f b(base.x, base.y, base.z); SbVec3f ax(axis.x, axis.y, axis.z); SbVec3f dir(direction.x, direction.y, direction.z); + //Base::Console().Error("DirectionVector: %f, %f, %f\n", direction.x, direction.y, direction.z); createPlacement(pShapeSep, b, SbRotation(SbVec3f(0,1,0), ax)); pShapeSep->addChild(createCylinder(pcConstraint->Height.getValue() * 0.8, dia/2)); From ac91d8b0ec45decd0ae30f56b1b8ed9f6b66fa58 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 21 Mar 2013 16:37:47 +0430 Subject: [PATCH 7/9] Enhancements to Shaft Design Wizard, e.g. display of stresses for three axes and bending curve for shaft --- .../PartDesign/WizardShaft/SegmentFunction.py | 253 +++++++- src/Mod/PartDesign/WizardShaft/Shaft.py | 583 ++++++++++++++---- .../PartDesign/WizardShaft/ShaftDiagram.py | 7 +- src/Mod/PartDesign/WizardShaft/WizardShaft.py | 138 ++++- .../WizardShaft/WizardShaftTable.py | 117 ++-- 5 files changed, 882 insertions(+), 216 deletions(-) diff --git a/src/Mod/PartDesign/WizardShaft/SegmentFunction.py b/src/Mod/PartDesign/WizardShaft/SegmentFunction.py index a9e7c501e2..35e3b4d4e5 100644 --- a/src/Mod/PartDesign/WizardShaft/SegmentFunction.py +++ b/src/Mod/PartDesign/WizardShaft/SegmentFunction.py @@ -21,6 +21,7 @@ # ******************************************************************************/ import FreeCAD # just for debug printing to console... +import numpy as np class SegmentFunctionSegment: "One segment of a segment function" @@ -39,6 +40,10 @@ class SegmentFunctionSegment: "Return true if the start of this segment is xval" #FIXME: 1E-9 is arbitrary here. But since units are in meters, 1E-9 is a nanometer... return abs(self.start - xval) < 1E-9 + + def isZero(self): + #FIXME: 1E-9 is arbitrary here. But since units are in meters, 1E-9 is a nanometer... + return abs(self.coefficient) < 1E-5 def value(self, xval): if xval < self.start: @@ -48,13 +53,21 @@ class SegmentFunctionSegment: def clone(self): return SegmentFunctionSegment(self.start, self.variable, self.coefficient, self.exponent) - + def negate(self): self.coefficient *= -1 + return self + + def negated(self): + return SegmentFunctionSegment(self.start, self.variable, self.coefficient * -1.0, self.exponent) + + def __mul__(self, value): + return SegmentFunctionSegment(self.start, self.variable, self.coefficient * value, self.exponent) def integrate(self): self.exponent = self.exponent + 1 self.coefficient = self.coefficient * 1 / self.exponent + return self def asString(self): return "%f * {%s - %f}^%i" % (self.coefficient, self.variable, self.start, self.exponent) @@ -69,11 +82,38 @@ class SegmentFunction: self.variable = "x" self.segments = [] self.name = name + + def findSegment(self, xval): + "Find segment valid for the given xval" + for s in self.segments: + if s.start <= xval: + return s + return self.segments[len(self.segments)] + + def isZero(self): + for s in self.segments: + if not s.isZero(): + return False + return True def negate(self): for s in self.segments: s.negate() return self + + def negated(self): + result = SegmentFunction() + result.variable = self.variable + for s in self.segments: + result.segments.append(s.negated()) + return result + + def __mul__(self, value): + result = SegmentFunction() + result.variable = self.variable + for s in self.segments: + result.segments.append(s * value) + return result def index(self, xval): "Find insert position for start value xval" @@ -90,11 +130,14 @@ class SegmentFunction: for key in sorted(dict.iterkeys()): #if abs(dict[key]) > 1E-9: self.segments.append(SegmentFunctionSegment(key, var, dict[key], 0)) + + def addSegment(self, st, coeff, exp = 0.0): + if abs(coeff) > 1E-9: + self.segments.insert(self.index(st), SegmentFunctionSegment(st, self.variable, coeff, exp)) def addSegments(self, dict): for key in sorted(dict.iterkeys()): - if abs(dict[key]) > 1E-9: - self.segments.insert(self.index(key), SegmentFunctionSegment(key, self.variable, dict[key], 0)) + self.addSegment(key, dict[key]) def setMaxX(self, mx): self.maxX = mx @@ -124,6 +167,7 @@ class SegmentFunction: "Integrate all segments with respect to the variable" for s in self.segments: s.integrate() + return self def integrated(self): "Return a copy of self integrated with respect to the variable" @@ -156,3 +200,206 @@ class SegmentFunction: FreeCAD.Console.PrintMessage(" + ") FreeCAD.Console.PrintMessage("\n") +class IntervalFunction: + "Function defined in intervals" + intervals = [] # vector of tuples (begin, length) + values = [] # vector of constant values applicable for this interval + + def __init__(self): + self.intervals = [] + self.values = [] + + def addInterval(self, begin, length, value): + self.intervals.append((begin, length)) + self.values.append(value) + + def value(self, xval): + for i in range(len(self.intervals)): + if xval >= self.intervals[i][0] and xval < self.intervals[i][0] + self.intervals[i][1]: + return self.values[i] + return self.values[len(self.values)-1] + + def lowervalue(self, xval): + return self.value(xval - 1E-8) + + def index(self, xval): + lastStart = 0.0 + for i in range(len(self.intervals)): + newStart = self.intervals[i][0] + if (xval >= lastStart) and (xval < newStart): + return i-1 + lastStart = newStart + return len(self.intervals)-1 + + def interval(self, xval): + "Return interval (begin, length) for this xval" + return self.intervals[self.index(xval)] + + def begin(self, xval): + return self.intervals[self.index(xval)][0] + + def length(self, xval): + return self.intervals[self.index(xval)][1] + +class StressFunction: + "Specialization for segment-wise display of stresses" + # The hairy thing about this is that the segments of the segfunc usually do not correspond with the intervals of the intfunc! + segfunc = None # The segment function for the force/moment + intfunc = None # The divisors, an interval function giving a specific value for each interval + name = "sigma" + + def __init__(self, f, i): + self.segfunc = f + self.intfunc = i + + def isZero(self): + return self.segfunc.isZero() + + def evaluate(self, maxX, pointsX): + # Note: This usually creates a few more points than specified in pointsX + offset = (maxX - self.segfunc.segments[0].start) / (pointsX - 1) + xvals = set([self.segfunc.segments[0].start + s * offset for s in range(pointsX)]) + starts = set([self.segfunc.segments[i].start for i in range(len(self.segfunc.segments))]) + xvals = xvals.union(starts) # Make sure we have a point on each segment start + divs = set([self.intfunc.intervals[i][0] for i in range(len(self.intfunc.intervals))]) + xvals = xvals.union(divs) + + xresult = [] + yresult = [] + for xval in sorted(xvals): + if xval in starts: + # create double point at segment border + xresult.append(xval) + yresult.append(self.segfunc.lowervalue(xval) / self.intfunc.value(xval)) + if (xval in divs): + # create double point at divisor border + xresult.append(xval) + yresult.append(self.segfunc.value(xval) / self.intfunc.lowervalue(xval)) + xresult.append(xval) + yresult.append(self.segfunc.value(xval) / self.intfunc.value(xval)) + return (xresult, yresult) + +class TranslationFunction: + "Specialization for segment-wise display of translations" + tangfunc = None # The segment function for the tangent to the bending line + transfunc = None # The segment function for translations of the shaft (the bending line) + intfunc = None # The divisors, a vector of tuples (location, divisor) + boundaries = {} # The boundary conditions, dictionary of location:[left boundary, right boundary] + module = 210000.0 + name = "w" + + def __init__(self, f, E, d, tangents, translations): + if f.isZero(): + return + # Note: Integration has to be segment-wise because the area moment is not constant in different segments. But this only becomes relevant + # when boundary conditions are being applied + # E I_i w_i'(x) = tangfunc + C_i0 + self.tangfunc = f.integrated() + self.tangfunc.name = "w'" + self.tangfunc.output() + # E I_i w_i(x) = transfunc + C_i0 x + C_i1 + self.transfunc = self.tangfunc.integrated() # + C_i0 * x + C_i1 (integration constants for interval number i) + self.transfunc.name = "w" + self.transfunc.output() + self.module = E + self.intfunc = d + + # Solve boundary conditions. There are two types: + # External boundary conditions, e.g. a given tangent direction or translation value at a given x-value + # Internal boundary conditions, i.e. at the segment borders the tangent direction and translation of the lines must be equal + # Note that the relevant boundaries are those of the intfunc (where the area moment of the shaft cross-section changes) + # Every interval of the transfunc has two integration constants C_i0 and C_i1 that need to be defined + # Matrix of coefficients + A = np.zeros(shape = (2 * len(self.intfunc.intervals), 2 * len(self.intfunc.intervals))) + # Vector of RHS values + b = np.zeros(shape = 2 * len(self.intfunc.intervals)) + # Current row where coefficients of next equation will be added + row = 0 + + # First look at external boundary conditions + for bound in tangents: + xval = bound[0] + tang = bound[1] + i = self.intfunc.index(xval) # index of this segment + I_i = self.intfunc.value(xval) # Area moment of this segment + # w_i'(xval) = tang => (tangfunc(xval) + C_i0) / (E * I_i) = tang => C_i0 = tang * (E * I_i) - tangfunc(xval) + A[row][2 * i] = 1.0 + b[row] = tang * E * I_i - self.tangfunc.value(xval) + row += 1 + for bound in translations: + xval = bound[0] + trans = bound[1] + i = self.intfunc.index(xval) # index of this segment + I_i = self.intfunc.value(xval) # Area moment of this segment + # w_i(xval) = trans => (transfunc(xval) + C_i0 * xval + C_i1) / (E * I_i) = trans => xval / (E * I_i) * C_i0 + 1 / (E * I_i) * C_i1 = trans - transfunc(xval) / (E * I_i) + A[row][2 * i] = xval / (E * I_i) + A[row][2 * i + 1] = 1 / (E * I_i) + b[row] = trans - self.transfunc.value(xval) / (E * I_i) + row += 1 + + # Now look at internal boundary conditions (n intervals have n-1 common segment boundaries) + for i in range(len(self.intfunc.intervals) - 1): + x_start = self.intfunc.intervals[i][0] + x_end = x_start + self.intfunc.intervals[i][1] + I_i = self.intfunc.value(x_start) # Area moment of this segment + I_ip1 = self.intfunc.value(x_end) + # w_i'(x_end) = w_i+1'(xend) => (tangfunc(x_end) + C_i0) / (E * I_i) = (tangfunc(x_end) * C_i+1,0) / (E * I_i+1) + # => 1 / (E * I_i) C_i0 - 1 / (E * I_i+1) * C_i+1,0 = tangfunc(x_end) / (E * I_i+1) - tangfunc(x_end) / (E * I_i) + A[row][2 * i] = 1 / (E * I_i) + A[row][2 * (i+1)] = -1 / (E * I_ip1) + b[row] = self.tangfunc.value(x_end) / (E * I_ip1) - self.tangfunc.value(x_end) / (E * I_i) + row += 1 + # w_i(x_end) = w_i+1(xend) => (transfunc(x_end) + C_i0 * x_end + C_i1) / (E * I_i) = (transfunc(x_end) * C_i+1,0) * x_end + C_i+1,1) / (E * I_i+1) + # => x_end / (E * I_i) C_i0 + 1 / (E * I_i) C_i1 - x_end / (E * I_i+1) * C_i+1,0 - 1 / (E * I_i+1) * C_i+1,1 = transfunc(x_end) / (E * I_i+1) - transfunc(x_end) / (E * I_i) + A[row][2 * i] = x_end / (E * I_i) + A[row][2 * i + 1] = 1 / (E * I_i) + A[row][2 * (i+1)] = -x_end / (E * I_ip1) + A[row][2 * (i+1) + 1] = -1 / (E * I_ip1) + b[row] = self.transfunc.value(x_end) / (E * I_ip1) - self.transfunc.value(x_end) / (E * I_i) + row += 1 + + #FreeCAD.Console.PrintMessage(A) + #FreeCAD.Console.PrintMessage(" * x = ") + #FreeCAD.Console.PrintMessage(b) + #FreeCAD.Console.PrintMessage("\n") + + try: + self.boundaries = np.linalg.solve(A, b) # A * self.boundaries = b + except np.linalg.linalg.LinAlgError, e: + FreeCAD.Console.PrintMessage(e.message) + FreeCAD.Console.PrintMessage(". No solution possible.\n") + return + + def isZero(self): + if self.transfunc is None: + return True + return self.transfunc.isZero() + + def evaluate(self, maxX, pointsX): + # Note: This usually creates a few more points than specified in pointsX + offset = (maxX - self.transfunc.segments[0].start) / (pointsX - 1) + xvals = set([self.transfunc.segments[0].start + s * offset for s in range(pointsX)]) + starts = set([self.transfunc.segments[i].start for i in range(len(self.transfunc.segments))]) + xvals = xvals.union(starts) # Make sure we have a point on each segment start + divs = set([self.intfunc.intervals[i][0] for i in range(len(self.intfunc.intervals))]) + xvals = xvals.union(divs) + E = self.module + + xresult = [] + yresult = [] + for xval in sorted(xvals): + if xval in divs: + i = self.intfunc.index(xval) + (begin, length) = self.intfunc.interval(xval) + I_i = self.intfunc.value(xval) + C_i0 = self.boundaries[2 * i] + C_i1 = self.boundaries[2 * i + 1] + FreeCAD.Console.PrintMessage("Interval %u: %f to %f, I_i: %f, C_i0: %f, C_i1: %f\n" % (i, begin, length, I_i, C_i0, C_i1)) + + xresult.append(xval) + # w(xval) = (transfunc(xval) + C_i0 * xval + C_i1) / (E * I_i) + value = (self.transfunc.value(xval) + C_i0 * xval + C_i1) / (E * I_i) + yresult.append(value) + + return (xresult, yresult) + diff --git a/src/Mod/PartDesign/WizardShaft/Shaft.py b/src/Mod/PartDesign/WizardShaft/Shaft.py index e426812c85..032111c044 100644 --- a/src/Mod/PartDesign/WizardShaft/Shaft.py +++ b/src/Mod/PartDesign/WizardShaft/Shaft.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- #/****************************************************************************** # * Copyright (c)2012 Jan Rheinlaender * # * * @@ -20,18 +21,18 @@ # * * # ******************************************************************************/ -import FreeCAD, FreeCADGui # FreeCAD just required for debug printing to the console... -from SegmentFunction import SegmentFunction +import FreeCAD, FreeCADGui +from SegmentFunction import SegmentFunction, IntervalFunction, StressFunction, TranslationFunction from ShaftFeature import ShaftFeature from ShaftDiagram import Diagram +import math class ShaftSegment: length = 0.0 diameter = 0.0 innerdiameter = 0.0 - loadType = "None" - loadSize = 0.0 - loadLocation = 0.0 + constraintType = "None" + constraint = None def __init__(self, l, d, di): self.length = l @@ -40,22 +41,47 @@ class ShaftSegment: class Shaft: "The axis of the shaft is always assumed to correspond to the X-axis" + parent = None + doc = None # List of shaft segments (each segment has a different diameter) segments = [] - # The sketch - sketch = 0 - #featureWindow = None + # The feature + feature = 0 # The diagrams diagrams = {} # map of function name against Diagram object # Calculation of shaft - Qy = 0 # force in direction of y axis - Qz = 0 # force in direction of z axis - Mbz = 0 # bending moment around z axis - Mby = 0 # bending moment around y axis - Mtz = 0 # torsion moment around z axis + F = [None, None, None] # force in direction of [x,y,z]-axis + M = [None, None, None] # bending moment around [x,z,y]-axis + w = [None, None, None] # Shaft translation due to bending + sigmaN = [None, None, None] # normal stress in direction of x-axis, shear stress in direction of [y,z]-axis + sigmaB = [None, None, None] # # torque stress around x-axis, maximum bending stress in direction of [y,z]-axis + # Names (note Qy corresponds with Mz, and Qz with My) + Fstr = ["Nx","Qy","Qz"] # Forces + Mstr = ["Mx","Mz","My"] # Moments + wstr = ["", "wy", "wz"] # Translations + sigmaNstr = ["sigmax","sigmay","sigmaz"] # Normal/shear stresses + sigmaBstr = ["taut","sigmabz", "sigmaby"] # Torsion/bending stresses + # For diagram labelling + Qstrings = (("Normal force [x]", "x", "mm", "N_x", "N"), + ("Shear force [y]", "x", "mm", "Q_y", "N"), + ("Shear force [z]", "x", "mm", "Q_z", "N")) + Mstrings = (("Torque [x]", "x", "mm", "M_t", "Nm"), + ("Bending moment [z]", "x", "mm", "M_{b,z}", "Nm"), + ("Bending moment [y]", "x", "mm", "M_{b,y}", "Nm")) + wstrings = (("", "", "", "", ""), + ("Translation [y]", "x", "mm", "w_y", "mm"), + ("Translation [z]", "x", "mm", "w_z", "mm")) + sigmaNstrings = (("Normal stress [x]", "x", "mm", "\sigma_x", u"N/mm²"), + ("Shear stress [y]", "x", "mm", "\sigma_y", u"N/mm²"), + ("Shear stress [z]", "x", "mm", "\sigma_z", u"N/mm²")) + sigmaBstrings = (("Torque stress [x]", "x", "mm", "\tau_t", u"N/mm²"), + ("Bending stress [z]", "x", "mm", "\sigma_{b,z}", u"N/mm²"), + ("Bending stress [y]", "x", "mm", "\sigma_{b,y}", u"N/mm²")) - def __init__(self, doc): - self.sketch = ShaftFeature(doc) + def __init__(self, parent): + self.parent = parent + self.doc = parent.doc + self.feature = ShaftFeature(self.doc) def getLengthTo(self, index): "Get the total length of all segments up to the given one" @@ -65,40 +91,81 @@ class Shaft: return result def addSegment(self, l, d, di): - #print "Adding segment: ", l, " : ", d self.segments.append(ShaftSegment(l,d,di)) - self.sketch.addSegment(l, d, di) - # We don't call equilibrium() here because the new segment has no loads defined yet + self.feature.addSegment(l, d, di) + # We don't call equilibrium() here because the new segment has no constraints defined yet + # Fix face reference of fixed segment if it is the last one + for i in range(1, len(self.segments)): + if self.segments[i].constraintType is not "Fixed": + continue + if i == len(self.segments) - 1: + self.segments[index].constraint.References = [( self.feature.feature, "Face%u" % (2 * (index+1) + 1) )] + else: + # Remove reference since it is now in the middle of the shaft (which is not allowed) + self.segments[index].constraint.References = [(None, "")] def updateSegment(self, index, length = None, diameter = None, innerdiameter = None): oldLength = self.segments[index].length - #print "Old length of ", index, ": ", oldLength, ", new Length: ", length, " diameter: ", diameter + if length is not None: self.segments[index].length = length if diameter is not None: self.segments[index].diameter = diameter if innerdiameter is not None: self.segments[index].innerdiameter = innerdiameter - self.sketch.updateSegment(index, oldLength, self.segments[index].length, - self.segments[index].diameter, self.segments[index].innerdiameter) + + self.feature.updateSegment(index, oldLength, self.segments[index].length, self.segments[index].diameter, self.segments[index].innerdiameter) self.equilibrium() self.updateDiagrams() - def updateLoad(self, index, loadType = None, loadSize = None, loadLocation = None): - if (loadType is not None): - self.segments[index].loadType = loadType - if (loadSize is not None): - self.segments[index].loadSize = loadSize - if (loadLocation is not None): - if (loadLocation >= 0) and (loadLocation <= self.segments[index].length): - self.segments[index].loadLocation = loadLocation - else: - # TODO: Show warning - FreeCAD.Console.PrintMessage("Load location must be inside segment\n") - - #self.feature.updateForces() graphical representation of the forces + def updateConstraint(self, index, constraintType): + if (constraintType is not None): + # Did the constraint type change? + if (self.segments[index].constraintType != "None") and (self.segments[index].constraintType != constraintType): + self.doc.removeObject(self.segments[index].constraint.Name) + self.segments[index].constraint = None + + self.segments[index].constraintType = constraintType + + # Create constraint if it does not exist yet or has changed + if self.segments[index].constraint is None: + if (constraintType == "Force"): + # TODO: Create a reference point and put the force onto it + constraint = self.doc.addObject("Fem::ConstraintForce","ShaftConstraintForce") + constraint.Force = 1000.0 + self.segments[index].constraint = constraint + elif (constraintType == "Fixed"): + # TODO: Use robust reference as soon as it is available for the face + constraint = self.doc.addObject("Fem::ConstraintFixed","ShaftConstraintFixed") + if index == 0: + constraint.References = [( self.feature.feature, "Face1")] + elif index == len(self.segments) - 1: + constraint.References = [( self.feature.feature, "Face%u" % (2 * (index+1) + 1) )] + self.segments[index].constraint = constraint + elif (constraintType == "Bearing"): + # TODO: Use robust reference as soon as it is available for the cylindrical face reference + constraint = self.doc.addObject("Fem::ConstraintBearing","ShaftConstraintBearing") + constraint.References = [( self.feature.feature, "Face%u" % (2 * (index+1)) )] + constraint.AxialFree = True + self.segments[index].constraint = constraint + elif (constraintType == "Pulley"): + constraint= self.doc.addObject("Fem::ConstraintPulley","ShaftConstraintPulley") + constraint.References = [( self.feature.feature, "Face%u" % (2 * (index+1)) )] + self.segments[index].constraint = constraint + elif (constraintType == "Gear"): + constraint = self.doc.addObject("Fem::ConstraintGear","ShaftConstraintGear") + constraint.References = [( self.feature.feature, "Face%u" % (2 * (index+1)) )] + self.segments[index].constraint = constraint + self.equilibrium() self.updateDiagrams() + + def editConstraint(self, index): + if (self.segments[index].constraint is not None): + FreeCADGui.activeDocument().setEdit(self.segments[index].constraint.Name) + + def getConstraint(self, index): + return self.segments[index].constraint def updateEdge(self, column, start): App.Console.PrintMessage("Not implemented yet - waiting for robust references...") @@ -132,114 +199,372 @@ class Shaft: # FIXME: This is impossible without robust references anchored in the sketch!!! return - def updateDiagrams(self): - if (self.Qy == 0) or (self.Mbz == 0): - return - if self.Qy.name in self.diagrams: - # Update diagram - self.diagrams[self.Qy.name].update(self.Qy, self.getLengthTo(len(self.segments)) / 1000.0) - else: - # Create diagram - self.diagrams[self.Qy.name] = Diagram() - self.diagrams[self.Qy.name].create("Shear force", self.Qy, self.getLengthTo(len(self.segments)) / 1000.0, "x", "mm", 1000.0, "Q_y", "N", 1.0, 10) - if self.Mbz.name in self.diagrams: - # Update diagram - self.diagrams[self.Mbz.name].update(self.Mbz, self.getLengthTo(len(self.segments)) / 1000.0) - else: - # Create diagram - self.diagrams[self.Mbz.name] = Diagram() - self.diagrams[self.Mbz.name].create("Bending moment", self.Mbz, self.getLengthTo(len(self.segments)) / 1000.0, "x", "mm", 1000.0, "M_{b,z}", "Nm", 1.0, 10) + def updateDiagrams(self): + for ax in range(3): + if self.F[ax] is not None: + if self.F[ax].name in self.diagrams: + self.diagrams[self.F[ax].name].update(self.F[ax], self.getLengthTo(len(self.segments)) / 1000.0) + if self.M[ax] is not None: + if self.M[ax].name in self.diagrams: + self.diagrams[self.M[ax].name].update(self.M[ax], self.getLengthTo(len(self.segments)) / 1000.0) + if self.w[ax] is not None: + if self.w[ax].name in self.diagrams: + self.diagrams[self.w[ax].name].update(self.w[ax], self.getLengthTo(len(self.segments)) / 1000.0) + if self.sigmaN[ax] is not None: + if self.sigmaN[ax].name in self.diagrams: + self.diagrams[self.sigmaN[ax].name].update(self.sigmaN[ax], self.getLengthTo(len(self.segments)) / 1000.0) + if self.sigmaB[ax] is not None: + if self.sigmaB[ax].name in self.diagrams: + self.diagrams[self.sigmaB[ax].name].update(self.sigmaB[ax], self.getLengthTo(len(self.segments)) / 1000.0) + def showDiagram(self, which): + if which in self.Fstr: + ax = self.Fstr.index(which) + text = self.Qstrings[ax] + if self.F[ax] == None: + # No data + return + if self.F[ax].name in self.diagrams: + # Diagram is already open, close it again + self.diagrams[self.F[ax].name].close() + del (self.diagrams[self.F[ax].name]) + return + self.diagrams[self.F[ax].name] = Diagram() + self.diagrams[self.F[ax].name].create(text[0], self.F[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1.0, 10) + elif which in self.Mstr: + ax = self.Mstr.index(which) + text = self.Mstrings[ax] + if self.M[ax] == None: + # No data + return + if self.M[ax].name in self.diagrams: + # Diagram is already open, close it again + self.diagrams[self.M[ax].name].close() + del (self.diagrams[self.M[ax].name]) + return + self.diagrams[self.M[ax].name] = Diagram() + self.diagrams[self.M[ax].name].create(text[0], self.M[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1.0, 20) + elif which in self.wstr: + ax = self.wstr.index(which) + text = self.wstrings[ax] + if self.w[ax] == None: + # No data + return + if self.w[ax].name in self.diagrams: + # Diagram is already open, close it again + self.diagrams[self.w[ax].name].close() + del (self.diagrams[self.w[ax].name]) + return + self.diagrams[self.w[ax].name] = Diagram() + self.diagrams[self.w[ax].name].create(text[0], self.w[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1.0, 30) + elif which in self.sigmaNstr: + ax = self.sigmaNstr.index(which) + text = self.sigmaNstrings[ax] + if self.sigmaN[ax] == None: + # No data + return + if self.sigmaN[ax].name in self.diagrams: + # Diagram is already open, close it again + self.diagrams[self.sigmaN[ax].name].close() + del (self.diagrams[self.sigmaN[ax].name]) + return + self.diagrams[self.sigmaN[ax].name] = Diagram() + self.diagrams[self.sigmaN[ax].name].create(text[0], self.sigmaN[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1.0, 10) + elif which in self.sigmaBstr: + ax = self.sigmaBstr.index(which) + text = self.sigmaBstrings[ax] + if self.sigmaB[ax] == None: + # No data + return + if self.sigmaB[ax].name in self.diagrams: + # Diagram is already open, close it again + self.diagrams[self.sigmaB[ax].name].close() + del (self.diagrams[self.sigmaB[ax].name]) + return + self.diagrams[self.sigmaB[ax].name] = Diagram() + self.diagrams[self.sigmaB[ax].name].create(text[0], self.sigmaB[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1.0, 20) + + def addTo(self, dict, location, value): + if location not in dict: + dict[location] = value + else: + dict[location] += value + def equilibrium(self): # Build equilibrium equations - forces = {0.0:0.0} # dictionary of (location : outer force) - moments = {0.0:0.0} # dictionary of (location : outer moment) - variableNames = [""] # names of all variables - locations = {} # dictionary of (variableName : location) - coefficientsFy = [0] # force equilibrium equation - coefficientsMbz = [0] # moment equilibrium equation - - for i in range(len(self.segments)): - lType = self.segments[i].loadType - load = -1 # -1 means unknown (just for debug printing) - location = -1 - - if lType == "Fixed": - # Fixed segment - if i == 0: - location = 0 - variableNames.append("Fy%u" % i) - coefficientsFy.append(1) - coefficientsMbz.append(0) - variableNames.append("Mz%u" % i) - coefficientsFy.append(0) - coefficientsMbz.append(1) # Force does not contribute because location is zero - elif i == len(self.segments) - 1: - location = self.getLengthTo(len(self.segments)) / 1000 - variableNames.append("Fy%u" % i) - coefficientsFy.append(1) - coefficientsMbz.append(location) - variableNames.append("Mz%u" % i) - coefficientsFy.append(0) - coefficientsMbz.append(1) - else: - # TODO: Better error message - FreeCAD.Console.PrintMessage("Fixed constraint must be at beginning or end of shaft\n") - return - - locations["Fy%u" % i] = location - locations["Mz%u" % i] = location - elif lType == "Static": - # Static load (currently force only) - load = self.segments[i].loadSize - location = (self.getLengthTo(i) + self.segments[i].loadLocation) / 1000 # convert to meters - coefficientsFy[0] = coefficientsFy[0] - load - forces[location] = load - coefficientsMbz[0] = coefficientsMbz[0] - load * location - moments[location] = 0 - #elif lType == "None": - # # No loads on segment - - FreeCAD.Console.PrintMessage("Segment: %u, type: %s, load: %f, location: %f\n" % (i, lType, load, location)) - - self.printEquilibrium(variableNames, coefficientsFy) - self.printEquilibrium(variableNames, coefficientsMbz) - - # Build matrix and vector for linear algebra solving algorithm try: import numpy as np except ImportError: FreeCAD.Console.PrintMessage("numpy is not installed on your system\n") raise ImportError("numpy not installed") - if (len(coefficientsFy) < 3) or (len(coefficientsMbz) < 3): - return - A = np.array([coefficientsFy[1:], coefficientsMbz[1:]]) - b = np.array([coefficientsFy[0], coefficientsMbz[0]]) - solution = np.linalg.solve(A, b) + + # Initialization of structures. All three axes are handled separately so everything is 3-fold + # dictionaries of (location : outer force/moment) with reverse sign, which means that the segment functions for the section force and section moment + # created from them will have signs as by the convention in + # http://www.umwelt-campus.de/ucb/fileadmin/users/90_t.preussler/dokumente/Skripte/TEMECH/TMI/Ebene_Balkenstatik.pdf (page 10) + # (see also example on page 19) + forces = [{0.0:0.0}, {0.0:0.0}, {0.0:0.0}] + moments = [{0.0:0.0}, {0.0:0.0}, {0.0:0.0}] + # Boundary conditions for shaft bending line + tangents = [[], [], []] # Tangents to shaft bending line + translations = [[], [], []] # Shaft displacement + # Variable names, e.g. Fx, Mz. Because the system must be exactly determined, not more than two independent variables for each + # force/moment per axis are possible (if there are more no solution is calculated) + variableNames = [[""], [""], [""]] + # # dictionary of (variableName : location) giving the x-coordinate at which the force/moment represented by the variable acts on the shaft + locations = {} + # Coefficients of the equilibrium equations in the form a = b * F1 + c * F2 and d = e * M1 + f * M2 + # LHS (variables a1, a2, a3, d3) initialized to zero + coefficientsF = [[0], [0], [0]] + coefficientsM = [[0], [0], [0]] - # Complete dictionary of forces and moments - if variableNames[1][0] == "F": - forces[locations[variableNames[1]]] = solution[0] - else: - moments[locations[variableNames[1]]] = solution[0] + for i in range(len(self.segments)): + cType = self.segments[i].constraintType + constraint = self.segments[i].constraint + + if cType == "Fixed": + # Fixed segment + if i == 0: + # At beginning of shaft + location = 0 + elif i == len(self.segments) - 1: + # At end of shaft + location = self.getLengthTo(len(self.segments)) / 1000.0 # convert to meters + else: + # TODO: Better error message + FreeCAD.Console.PrintMessage("Fixed constraint must be at beginning or end of shaft\n") + return + + for ax in range(3): + # Create a new reaction force + variableNames[ax].append("%s%u" % (self.Fstr[ax], i)) + coefficientsF[ax].append(1) + # Register location of reaction force + locations["%s%u" % (self.Fstr[ax], i)] = location + # Boundary conditions for the translations + tangents[ax].append((location, 0.0)) + translations[ax].append((location, 0.0)) + coefficientsM[0].append(0) # Reaction force contributes no moment around x axis + coefficientsM[1].append(location) # Reaction force contributes a positive moment around z axis + coefficientsM[2].append(-location) # Reaction force contributes a negative moment around y axis + + for ax in range(3): + # Create a new reaction moment + variableNames[ax].append("%s%u" % (self.Mstr[ax], i)) + coefficientsF[ax].append(0) + coefficientsM[ax].append(1) + locations["%s%u" % (self.Mstr[ax], i)] = location + + elif cType == "Force": + # Static force (currently force on midpoint of segment only) + force = constraint.DirectionVector.multiply(constraint.Force) + # TODO: Extract value of the location from geometry + location = (self.getLengthTo(i) + self.segments[i].length/2.0) / 1000.0 + # The force itself + for ax in range(3): + if abs(force[ax]) > 0.0: + coefficientsF[ax][0] = coefficientsF[ax][0] - force[ax] # neg. because this coefficient is on the LHS of the equilibrium equation + self.addTo(forces[ax], location, -force[ax]) # neg. to fulfill the convention mentioned above + # Moments created by the force (by definition no moment is created by the force in x-direction) + if abs(force[1]) > 0.0: + coefficientsM[1][0] = coefficientsM[1][0] - force[1] * location # moment around z-axis + self.addTo(moments[1], location, 0) + if abs(force[2]) > 0.0: + coefficientsM[2][0] = coefficientsM[2][0] + force[2] * location # moment around y-axis + self.addTo(moments[2], location, 0) # No outer moment acts here! + + elif cType == "Bearing": + location = constraint.BasePoint.x / 1000.0 # TODO: This assumes that the shaft feature starts with the first segment at (0,0,0) and its axis corresponds to the x-axis + # Bearing reaction forces. TODO: the bearing is assumed to not induce any reaction moments + start = (0 if constraint.AxialFree == False else 1) + for ax in range(start, 3): + variableNames[ax].append("%s%u" % (self.Fstr[ax], i)) + coefficientsF[ax].append(1) + locations["%s%u" % (self.Fstr[ax], i)] = location + # Boundary condition + translations[ax].append((location, 0.0)) + if constraint.AxialFree == False: + coefficientsM[0].append(0) # Reaction force contributes no moment around x axis + coefficientsM[1].append(location) # Reaction force contributes a positive moment around z axis + coefficientsM[2].append(-location) # Reaction force contributes a negative moment around y axis + + elif cType == "Gear": + force = constraint.DirectionVector.multiply(constraint.Force) + location = constraint.BasePoint.x / 1000.0 + lever = [0, constraint.Diameter/2.0/1000.0 * math.sin(constraint.ForceAngle / 180.0 * math.pi), + constraint.Diameter/2.0 /1000.0* math.cos(constraint.ForceAngle / 180.0 * math.pi)] + + # Effect of the gear force + for ax in range(3): + if abs(force[ax]) > 0.0: + # Effect of the force + coefficientsF[ax][0] = coefficientsF[ax][0] - force[ax] + self.addTo(forces[ax], location, -force[ax]) + # Moments created by the force (by definition no moment is created by the force in x-direction) + if abs(force[1]) > 0.0: + coefficientsM[1][0] = coefficientsM[1][0] - force[1] * location # moment around z-axis + self.addTo(moments[1], location, 0) + if abs(force[2]) > 0.0: + coefficientsM[2][0] = coefficientsM[2][0] + force[2] * location # moment around y-axis + self.addTo(moments[2], location, 0) # No outer moment acts here! + + # Moments created by the force and lever + if abs(force[0]) > 0.0: + momenty = force[0] * lever[2] + momentz = force[0] * lever[1] + coefficientsM[1][0] = coefficientsM[1][0] + momentz # moment around z-axis + self.addTo(moments[1], location, momentz) + coefficientsM[2][0] = coefficientsM[2][0] - momenty # moment around y-axis + self.addTo(moments[2], location, -momenty) + if abs(force[1]) > 0.0: + moment = force[1] * lever[2] + coefficientsM[0][0] = coefficientsM[0][0] + moment + self.addTo(moments[0], location, moment) + if abs(force[2]) > 0.0: + moment = force[2] * lever[1] + coefficientsM[0][0] = coefficientsM[0][0] - moment + self.addTo(moments[0], location, -moment) + elif cType == "Pulley": + forceAngle1 = (constraint.ForceAngle + constraint.BeltAngle + 90.0) / 180.0 * math.pi + forceAngle2 = (constraint.ForceAngle - constraint.BeltAngle + 90.0) / 180.0 * math.pi + #FreeCAD.Console.PrintMessage("BeltForce1: %f, BeltForce2: %f\n" % (constraint.BeltForce1, constraint.BeltForce2)) + #FreeCAD.Console.PrintMessage("Angle1: %f, Angle2: %f\n" % (forceAngle1, forceAngle2)) + force = [0, -constraint.BeltForce1 * math.sin(forceAngle1) - constraint.BeltForce2 * math.sin(forceAngle2), + constraint.BeltForce1 * math.cos(forceAngle1) + constraint.BeltForce2 * math.cos(forceAngle2)] + location = constraint.BasePoint.x / 1000.0 + + # Effect of the pulley forces + for ax in range(3): + if abs(force[ax]) > 0.0: + # Effect of the force + coefficientsF[ax][0] = coefficientsF[ax][0] - force[ax] + self.addTo(forces[ax], location, -force[ax]) + # Moments created by the force (by definition no moment is created by the force in x-direction) + if abs(force[1] ) > 0.0: + coefficientsM[1][0] = coefficientsM[1][0] - force[1] * location # moment around z-axis + self.addTo(moments[1], location, 0) + if abs(force[2]) > 0.0: + coefficientsM[2][0] = coefficientsM[2][0] + force[2] * location # moment around y-axis + self.addTo(moments[2], location, 0) # No outer moment acts here! + + # Torque + moment = constraint.Force * (1 if constraint.IsDriven is True else -1) + coefficientsM[0][0] = coefficientsM[0][0] + moment + self.addTo(moments[0], location, moment) - if variableNames[2][0] == "F": - forces[locations[variableNames[2]]] = solution[1] - else: - moments[locations[variableNames[2]]] = solution[1] + areas = [None, None, None] + areamoments = [None, None, None] + torquemoments = [None, None, None] + + for ax in range(3): + FreeCAD.Console.PrintMessage("Axis: %u\n" % ax) + self.printEquilibrium(variableNames[ax], coefficientsF[ax]) + self.printEquilibrium(variableNames[ax], coefficientsM[ax]) - FreeCAD.Console.PrintMessage(forces) - FreeCAD.Console.PrintMessage(moments) - self.Qy = SegmentFunction("Qy") - self.Qy.buildFromDict("x", forces) - self.Qy.output() - self.Mbz = self.Qy.integrated().negate() - self.Mbz.addSegments(moments) # takes care of boundary conditions - self.Mbz.name = "Mbz" - self.Mbz.output() + if len(coefficientsF[ax]) <= 1: + # Note: coefficientsF and coefficientsM always have the same length + FreeCAD.Console.PrintMessage("Matrix is singular, no solution possible\n") + self.parent.updateButtons(ax, False) + continue + + # Handle special cases. Note that the code above should ensure that coefficientsF and coefficientsM always have same length + solution = [None, None] + if len(coefficientsF[ax]) == 2: + if coefficientsF[ax][1] != 0.0 and coefficientsF[ax][0] != 0.0: + solution[0] = coefficientsF[ax][0] / coefficientsF[ax][1] + if coefficientsM[ax][1] != 0.0 and coefficientsM[ax][0] != 0.0: + solution[1] = coefficientsM[ax][0] / coefficientsM[ax][1] + if abs(solution[0] - solution[1]) < 1E9: + FreeCAD.Console.PrintMessage("System is statically undetermined. No solution possible.\n") + self.parent.updateButtons(ax, False) + continue + else: + # Build matrix and vector for linear algebra solving algorithm + # TODO: This could easily be done manually... there are only 2 variables and 6 coefficients + A = np.array([coefficientsF[ax][1:], coefficientsM[ax][1:]]) + b = np.array([coefficientsF[ax][0], coefficientsM[ax][0]]) + try: + solution = np.linalg.solve(A, b) # A * solution = b + except np.linalg.linalg.LinAlgError, e: + FreeCAD.Console.PrintMessage(e.message) + FreeCAD.Console.PrintMessage(". No solution possible.\n") + self.parent.updateButtons(ax, False) + continue + + # Complete dictionary of forces and moments with the two reaction forces that were calculated + for i in range(2): + if solution[i] is None: + continue + FreeCAD.Console.PrintMessage("Reaction force/moment: %s = %f\n" % (variableNames[ax][i+1], solution[i])) + if variableNames[ax][i+1][0] == "M": + moments[ax][locations[variableNames[ax][i+1]]] = -solution[i] + else: + forces[ax][locations[variableNames[ax][i+1]]] = -solution[i] + + FreeCAD.Console.PrintMessage(forces[ax]) + FreeCAD.Console.PrintMessage("\n") + FreeCAD.Console.PrintMessage(moments[ax]) + FreeCAD.Console.PrintMessage("\n") + + # Forces + self.F[ax] = SegmentFunction(self.Fstr[ax]) + self.F[ax].buildFromDict("x", forces[ax]) + self.parent.updateButton(1, ax, not self.F[ax].isZero()) + self.F[ax].output() + # Moments + if ax == 0: + self.M[0] = SegmentFunction(self.Mstr[0]) + self.M[0].buildFromDict("x", moments[0]) + elif ax == 1: + self.M[1] = self.F[1].integrated().negate() + self.M[1].name = self.Mstr[1] + self.M[1].addSegments(moments[1]) # takes care of boundary conditions + elif ax == 2: + self.M[2] = self.F[2].integrated() + self.M[2].name = self.Mstr[2] + self.M[2].addSegments(moments[2]) # takes care of boundary conditions + self.parent.updateButton(2, ax, not self.M[ax].isZero()) + self.M[ax].output() + + # Areas and area moments + location = 0.0 + areas[ax] = IntervalFunction() + areamoments[ax] = IntervalFunction() + torquemoments[ax] = IntervalFunction() + + for i in range(len(self.segments)): + od = self.segments[i].diameter + id = self.segments[i].innerdiameter + length = self.segments[i].length/1000.0 + areas[ax].addInterval(location, length, math.pi/4.0 * (math.pow(self.segments[i].diameter, 2.0) - math.pow(self.segments[i].innerdiameter, 2.0))) + areamoment = math.pi/32.0 * (math.pow(self.segments[i].diameter, 4.0) - math.pow(self.segments[i].innerdiameter, 4.0)) / self.segments[i].diameter + areamoments[ax].addInterval(location, length, areamoment) + torquemoments[ax].addInterval(location, length, 2 * areamoment) + location += length + + # Bending line + if ax > 0: + if len(tangents[ax])+ len(translations[ax]) == 2: + # TODO: Get Young's module from material type instead of using 210000 N/mm² + self.w[ax] = TranslationFunction(self.M[ax].negated() * 1000.0, 210000, areamoments[ax], tangents[ax], translations[ax]) + self.w[ax].name= self.wstr[ax] + self.parent.updateButton(3, ax, not self.w[ax].isZero()) + else: + self.parent.updateButton(3, ax, False) + + # Normal/shear stresses and torque/bending stresses + self.sigmaN[ax] = StressFunction(self.F[ax], areas[ax]) + self.sigmaN[ax].name = self.sigmaNstr[ax] + self.parent.updateButton(4, ax, not self.sigmaN[ax].isZero()) + if ax == 0: + self.sigmaB[ax] = StressFunction(self.M[ax] * 1000.0, torquemoments[ax]) + else: + self.sigmaB[ax] = StressFunction(self.M[ax] * 1000.0, areamoments[ax]) + self.sigmaB[ax].name = self.sigmaBstr[ax] + self.parent.updateButton(5, ax, not self.sigmaB[ax].isZero()) def printEquilibrium(self, var, coeff): - # Auxiliary method for debugging purposes + # Auxiliary method for debugging purposes for i in range(len(var)): if i == 0: FreeCAD.Console.PrintMessage("%f = " % coeff[i]) diff --git a/src/Mod/PartDesign/WizardShaft/ShaftDiagram.py b/src/Mod/PartDesign/WizardShaft/ShaftDiagram.py index 097b571c06..3954da8474 100644 --- a/src/Mod/PartDesign/WizardShaft/ShaftDiagram.py +++ b/src/Mod/PartDesign/WizardShaft/ShaftDiagram.py @@ -38,6 +38,7 @@ class Diagram: ypoints = [] # Plot object thePlot = None + win = None def create(self, title, function, xlength, xname, xunit, xscale, yname, yunit, yscale, numxpoints): # Initialize @@ -54,7 +55,7 @@ class Diagram: self.numxpoints = numxpoints # Create a plot window - win = Plot.figure(title) + self.win = Plot.figure(title) # Get the plot object from the window self.thePlot = Plot.getPlot() # Format the plot object @@ -96,3 +97,7 @@ class Diagram: axes.set_xlim(right = max(self.xpoints) * 1.05) axes.set_ylim(min(self.ypoints) * 1.05, max(self.ypoints) * 1.05) self.thePlot.update() + + def close(self): + # Close the associated mdiSubWindow + self.win.parent().close() diff --git a/src/Mod/PartDesign/WizardShaft/WizardShaft.py b/src/Mod/PartDesign/WizardShaft/WizardShaft.py index 799effb7df..15b3f1b721 100644 --- a/src/Mod/PartDesign/WizardShaft/WizardShaft.py +++ b/src/Mod/PartDesign/WizardShaft/WizardShaft.py @@ -21,7 +21,6 @@ # ******************************************************************************/ import FreeCAD, FreeCADGui -#import os from PyQt4 import QtCore, QtGui from WizardShaftTable import WizardShaftTable from Shaft import Shaft @@ -38,6 +37,8 @@ class TaskWizardShaft: shaft = 0 # Feature featureWindow = 0 + # Buttons + buttons = [[None, None, None], [None, None, None], [None, None, None], [None, None, None], [None, None, None], [None, None, None]] def __init__(self, doc): mw = QtGui.qApp.activeWindow() @@ -54,15 +55,97 @@ class TaskWizardShaft: featureWindow = cw.subWindowList()[-1] else: featureWindow = cw.activeSubWindow() - + + # Buttons for diagram display + buttons = QtGui.QGridLayout() + bnames = [["All [x]", "All [y]", "All [z]" ], + ["N [x]", "Q [y]", "Q [z]"], + ["Mt [x]", "Mb [z]", "Mb [y]"], + ["", "w [y]", "w [z]"], + ["sigma [x]", "sigma [y]", "sigma [z]"], + ["tau [x]", "sigmab [z]", "sigmab [y]"]] + slots = [[self.slotAllx, self.slotAlly, self.slotAllz], + [self.slotFx, self.slotQy, self.slotQz], + [self.slotMx, self.slotMz, self.slotMy], + [self.slotNone, self.slotWy, self.slotWz], + [self.slotSigmax, self.slotSigmay, self.slotSigmaz], + [self.slotTaut, self.slotSigmabz, self.slotSigmaby]] + for col in range(3): + for row in range(6): + button = QtGui.QPushButton(bnames[row][col]) + buttons.addWidget(button, row, col) + self.buttons[row][col] = button + button.clicked.connect(slots[row][col]) + # Create Shaft object - self.shaft = Shaft(self.doc) - - # Assign a table widget to the dock window - self.table = WizardShaftTable(self, self.shaft) - self.form = self.table.widget - self.form.setWindowTitle("Shaft wizard") - + self.shaft = Shaft(self) + # Create table widget + self.form = QtGui.QWidget() + self.table = WizardShaftTable(self, self.shaft) + + # The top layout will contain the Shaft Wizard layout plus the elements of the FEM constraints dialog + layout = QtGui.QVBoxLayout() + layout.setObjectName("ShaftWizard") # Do not change or translate: Required to detect whether Shaft Wizard is running in FemGui::ViewProviderFemConstraintXXX + sublayout = QtGui.QVBoxLayout() + sublayout.setObjectName("ShaftWizardLayout") # Do not change or translate + sublayout.addWidget(self.table.widget) + sublayout.addLayout(buttons) + layout.addLayout(sublayout) + self.form.setLayout(layout) + + # Switch to feature window + mdi=QtGui.qApp.activeWindow().findChild(QtGui.QMdiArea) + cw.setActiveSubWindow(featureWindow) + + def slotAllx(self): + self.shaft.showDiagram("Allx") + def slotAlly(self): + self.shaft.showDiagram("Ally") + def slotAllz(self): + self.shaft.showDiagram("Allz") + + def slotFx(self): + self.shaft.showDiagram("Nx") + def slotQy(self): + self.shaft.showDiagram("Qy") + def slotQz(self): + self.shaft.showDiagram("Qz") + + def slotMx(self): + self.shaft.showDiagram("Mx") + def slotMz(self): + self.shaft.showDiagram("Mz") + def slotMy(self): + self.shaft.showDiagram("My") + + def slotNone(self): + pass + def slotWy(self): + self.shaft.showDiagram("wy") + def slotWz(self): + self.shaft.showDiagram("wz") + + def slotSigmax(self): + self.shaft.showDiagram("sigmax") + def slotSigmay(self): + self.shaft.showDiagram("sigmay") + def slotSigmaz(self): + self.shaft.showDiagram("sigmaz") + + def slotTaut(self): + self.shaft.showDiagram("taut") + def slotSigmabz(self): + self.shaft.showDiagram("sigmabz") + def slotSigmaby(self): + self.shaft.showDiagram("sigmaby") + + def updateButton(self, row, col, flag): + self.buttons[row][col].setEnabled(flag) + + def updateButtons(self, col, flag): + for row in range(len(self.buttons)): + self.updateButton(row, col, flag) + def getStandardButtons(self): return int(QtGui.QDialogButtonBox.Ok) @@ -75,10 +158,20 @@ class TaskWizardShaft: del self.form return True -class WizardShaftGui: - def Activated(self): - FreeCADGui.Control.showDialog(TaskWizardShaft(FreeCAD.ActiveDocument)) +# Work-around to allow a callback +# Problem: From the FemConstraint ViewProvider, we need to tell the Shaft instance that the user finished editing the constraint +# We can find the Shaft Wizard dialog object from C++, but there is not way to reach the Shaft instance +# Also it seems to be impossible to access the active dialog from Python, so Gui::Command::runCommand() is not an option either +# Note: Another way would be to create a hidden widget in the Shaft Wizard dialog and write some data to it, triggering a slot +# in the python code +WizardShaftDlg = None +class WizardShaftGui: + def Activated(self): + global WizardShaftDlg + WizardShaftDlg = TaskWizardShaft(FreeCAD.ActiveDocument) + FreeCADGui.Control.showDialog(WizardShaftDlg) + def GetResources(self): IconPath = FreeCAD.ConfigGet("AppHomePath") + "Mod/PartDesign/WizardShaft/WizardShaft.svg" MenuText = 'Shaft design wizard...' @@ -87,8 +180,29 @@ class WizardShaftGui: def IsActive(self): return FreeCAD.ActiveDocument != None + + def __del__(self): + global WizardShaftDlg + WizardShaftDlg = None + +class WizardShaftGuiCallback: + def Activated(self): + global WizardShaftDlg + if WizardShaftDlg != None and WizardShaftDlg.table != None: + WizardShaftDlg.table.finishEditConstraint() + + def isActive(self): + global WizardShaftDlg + return (WizardShaftDlg is not None) + + def GetResources(self): + IconPath = FreeCAD.ConfigGet("AppHomePath") + "Mod/PartDesign/WizardShaft/WizardShaft.svg" + MenuText = 'Shaft design wizard...' + ToolTip = 'Start the shaft design wizard' + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} FreeCADGui.addCommand('PartDesign_WizardShaft', WizardShaftGui()) +FreeCADGui.addCommand('PartDesign_WizardShaftCallBack', WizardShaftGuiCallback()) #Note: Start wizard in Python Console with # Gui.runCommand('PartDesign_WizardShaft') diff --git a/src/Mod/PartDesign/WizardShaft/WizardShaftTable.py b/src/Mod/PartDesign/WizardShaft/WizardShaftTable.py index 4120521751..0d73da049b 100644 --- a/src/Mod/PartDesign/WizardShaft/WizardShaftTable.py +++ b/src/Mod/PartDesign/WizardShaft/WizardShaftTable.py @@ -31,21 +31,18 @@ class WizardShaftTable: "Length" : 0, "Diameter" : 1, "InnerDiameter" : 2, - "LoadType" : 3, - "LoadSize" : 4, - "LoadLocation" : 5, - "StartEdgeType" : 6, - "StartEdgeSize" : 7, - "EndEdgeType" : 8, - "EndEdgeSize" : 9 + "ConstraintType" : 3, + "StartEdgeType" : 4, + "StartEdgeSize" : 5, + "EndEdgeType" : 6, + "EndEdgeSize" : 7 } rowDictReverse = {} - headers = ["Length [mm]", + headers = [ + "Length [mm]", "Diameter [mm]", "Inner diameter [mm]", - "Load type", - "Load [N]", - "Location [mm]", + "Constraint type", "Start edge type", "Start edge size", "End edge type", @@ -54,6 +51,8 @@ class WizardShaftTable: widget = 0 wizard = 0 shaft = 0 + editedRow = None + editedColumn = None def __init__(self, w, s): for key in self.rowDict.iterkeys(): @@ -62,9 +61,10 @@ class WizardShaftTable: self.wizard = w self.shaft = s # Create table widget - self.widget = QtGui.QTableWidget(len(self.rowDict), 0) + self.widget = QtGui.QTableWidget(len(self.rowDict), 0) + self.widget.setObjectName("ShaftWizardTable") # Do not change or translate: Used in ViewProviderFemConstraintXXX + self.widget.setWindowTitle("Shaft wizard") self.widget.resize(QtCore.QSize(300,200)) - #self.widget.setFocusPolicy(QtCore.Qt.StrongFocus) # Label rows and columns self.widget.setVerticalHeaderLabels(self.headers) @@ -82,14 +82,12 @@ class WizardShaftTable: self.addColumn() self.setLength(0, 40.0) self.setDiameter(0, 50.0) - self.setLoadType(0, "Static") - self.setLoadSize(0, 1000.0) - self.setLoadLocation(0, 25.0) + self.setConstraintType(0, "Bearing") # Section 2 self.addColumn() self.setLength(1, 80.0) self.setDiameter(1, 60.0) - self.setLoadType(1, "Fixed") + self.setConstraintType(1, "Force") def slotInsertColumn(self, point): # FIXME: Allow inserting columns, not just adding at the end @@ -144,32 +142,21 @@ class WizardShaftTable: widget.setValue(innerdiameter) widget.valueChanged.connect(self.slotValueChanged) widget.editingFinished.connect(self.slotEditingFinished) - # Load type + # Constraint type widget = QtGui.QComboBox(self.widget) widget.insertItem(0, "None") widget.insertItem(1, "Fixed") - widget.insertItem(2, "Static") + widget.insertItem(2, "Force") widget.insertItem(3, "Bearing") - widget.insertItem(4, "Pulley") - self.widget.setCellWidget(self.rowDict["LoadType"], index, widget) + widget.insertItem(4, "Gear") + widget.insertItem(5, "Pulley") + action = QtGui.QAction("Edit constraint", widget) + action.triggered.connect(self.slotEditConstraint) + widget.addAction(action) + widget.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) + self.widget.setCellWidget(self.rowDict["ConstraintType"], index, widget) widget.setCurrentIndex(0) - self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotLoadType) - # Load size - widget = QtGui.QDoubleSpinBox(self.widget) - widget.setMinimum(-1E9) - widget.setMaximum(1E9) - self.widget.setCellWidget(self.rowDict["LoadSize"], index, widget) - widget.setValue(0) - widget.valueChanged.connect(self.slotValueChanged) - widget.editingFinished.connect(self.slotEditingFinished) - # Load location - widget = QtGui.QDoubleSpinBox(self.widget) - widget.setMinimum(0) - widget.setMaximum(1E9) - self.widget.setCellWidget(self.rowDict["LoadLocation"], index, widget) - widget.setValue(0) - widget.valueChanged.connect(self.slotValueChanged) - widget.editingFinished.connect(self.slotEditingFinished) + self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotConstraintType) # Start edge type widget = QtGui.QComboBox(self.widget) widget.insertItem(0, "None",) @@ -177,7 +164,7 @@ class WizardShaftTable: widget.insertItem(2, "Fillet") self.widget.setCellWidget(self.rowDict["StartEdgeType"],index, widget) widget.setCurrentIndex(0) - self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotLoadType) + #self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotLoadType) # Start edge size widget = QtGui.QDoubleSpinBox(self.widget) widget.setMinimum(0) @@ -193,7 +180,7 @@ class WizardShaftTable: widget.insertItem(2, "Fillet") self.widget.setCellWidget(self.rowDict["EndEdgeType"],index, widget) widget.setCurrentIndex(0) - self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotLoadType) + #self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotLoadType) # End edge size widget = QtGui.QDoubleSpinBox(self.widget) widget.setMinimum(0) @@ -208,6 +195,8 @@ class WizardShaftTable: self.editedValue = value def slotEditingFinished(self): + if self.editedRow == None: + return rowName = self.rowDictReverse[self.editedRow] if rowName is None: return @@ -217,12 +206,8 @@ class WizardShaftTable: self.shaft.updateSegment(self.editedColumn, diameter = self.getDoubleValue(rowName, self.editedColumn)) elif rowName == "InnerDiameter": self.shaft.updateSegment(self.editedColumn, innerdiameter = self.getDoubleValue(rowName, self.editedColumn)) - elif rowName == "LoadType": - self.shaft.updateLoad(self.editedColumn, loadType = self.getListValue(rowName, self.editedColumn)) - elif rowName == "LoadSize": - self.shaft.updateLoad(self.editedColumn, loadSize = self.getDoubleValue(rowName, self.editedColumn)) - elif rowName == "LoadLocation": - self.shaft.updateLoad(self.editedColumn, loadLocation = self.getDoubleValue(rowName, self.editedColumn)) + elif rowName == "Constraintype": + self.shaft.updateConstraint(self.editedColumn, self.getListValue(rowName, self.editedColumn)) elif rowName == "StartEdgeType": pass elif rowName == "StartEdgeSize": @@ -232,6 +217,13 @@ class WizardShaftTable: elif rowName == "EndEdgeSize": pass + def slotEditConstraint(self): + (self.editedRow, self.editedColumn) = self.getFocusedCell() # Because finishEditConstraint() will trigger slotEditingFinished() which requires this information + self.shaft.editConstraint(self.editedColumn) + + def finishEditConstraint(self): + self.shaft.updateConstraint(self.editedColumn, self.getConstraintType(self.editedColumn)) + def setLength(self, column, l): self.setDoubleValue("Length", column, l) self.shaft.updateSegment(column, length = l) @@ -254,32 +246,15 @@ class WizardShaftTable: return self.getDoubleValue("InnerDiameter", column) @QtCore.pyqtSlot('QString') - def slotLoadType(self, text): - if text != "Fixed": - if (self.getLoadSize is None) or (self.getLoadLocation is None): - return - self.shaft.updateLoad(self.getFocusedColumn(), loadType = text) + def slotConstraintType(self, text): + self.shaft.updateConstraint(self.getFocusedColumn(), text) - def setLoadType(self, column, t): - self.setListValue("LoadType", column, t) - self.shaft.updateLoad(column, loadType = t) + def setConstraintType(self, column, t): + self.setListValue("ConstraintType", column, t) + self.shaft.updateConstraint(column, t) - def getLoadType(self, column): - return self.getListValue("LoadType", column) - - def setLoadSize(self, column, s): - self.setDoubleValue("LoadSize", column, s) - self.shaft.updateLoad(column, loadSize = s) - - def getLoadSize(self, column): - return self.getDoubleValue("LoadSize", column) - - def setLoadLocation(self, column, l): - self.setDoubleValue("LoadLocation", column, l) - self.shaft.updateLoad(column, loadLocation = l) - - def getLoadLocation(self, column): - return self.getDoubleValue("LoadLocation", column) + def getConstraintType(self, column): + return self.getListValue("ConstraintType", column) def slotStartEdgeType(self, old, new): pass @@ -334,7 +309,7 @@ class WizardShaftTable: def getListValue(self, row, column): widget = self.widget.cellWidget(self.rowDict[row], column) if widget is not None: - return widget.currentText().toAscii()[0].upper() + return widget.currentText().toAscii() #[0].upper() else: return None From 3a06458a2cbf04c748b84818075df09ce26547b5 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 21 Mar 2013 18:08:56 +0430 Subject: [PATCH 8/9] Fixed error after rebase --- src/Mod/Fem/Gui/Command.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 95618a625d..490e53f844 100755 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -438,7 +438,6 @@ void CreateFemCommands(void) rcCmdMgr.addCommand(new CmdFemCreateFromShape()); rcCmdMgr.addCommand(new CmdFemCreateNodesSet()); rcCmdMgr.addCommand(new CmdFemDefineNodesSet()); - rcCmdMgr.addCommand(new CmdFemConstraint()); rcCmdMgr.addCommand(new CmdFemConstraintBearing()); rcCmdMgr.addCommand(new CmdFemConstraintFixed()); rcCmdMgr.addCommand(new CmdFemConstraintForce()); From d6dadf0a3be8f51e86a2cc7d5e9b5338dad7b26f Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 22 Mar 2013 08:12:05 +0430 Subject: [PATCH 9/9] Fixed unit mismatches in Shaft Wizard --- .../PartDesign/WizardShaft/SegmentFunction.py | 2 +- src/Mod/PartDesign/WizardShaft/Shaft.py | 33 ++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/Mod/PartDesign/WizardShaft/SegmentFunction.py b/src/Mod/PartDesign/WizardShaft/SegmentFunction.py index 35e3b4d4e5..365aa30a11 100644 --- a/src/Mod/PartDesign/WizardShaft/SegmentFunction.py +++ b/src/Mod/PartDesign/WizardShaft/SegmentFunction.py @@ -285,7 +285,7 @@ class TranslationFunction: transfunc = None # The segment function for translations of the shaft (the bending line) intfunc = None # The divisors, a vector of tuples (location, divisor) boundaries = {} # The boundary conditions, dictionary of location:[left boundary, right boundary] - module = 210000.0 + module = 2.1E12 name = "w" def __init__(self, f, E, d, tangents, translations): diff --git a/src/Mod/PartDesign/WizardShaft/Shaft.py b/src/Mod/PartDesign/WizardShaft/Shaft.py index 032111c044..6503e7c314 100644 --- a/src/Mod/PartDesign/WizardShaft/Shaft.py +++ b/src/Mod/PartDesign/WizardShaft/Shaft.py @@ -256,7 +256,7 @@ class Shaft: del (self.diagrams[self.w[ax].name]) return self.diagrams[self.w[ax].name] = Diagram() - self.diagrams[self.w[ax].name].create(text[0], self.w[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1.0, 30) + self.diagrams[self.w[ax].name].create(text[0], self.w[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1000.0, 30) elif which in self.sigmaNstr: ax = self.sigmaNstr.index(which) text = self.sigmaNstrings[ax] @@ -269,7 +269,7 @@ class Shaft: del (self.diagrams[self.sigmaN[ax].name]) return self.diagrams[self.sigmaN[ax].name] = Diagram() - self.diagrams[self.sigmaN[ax].name].create(text[0], self.sigmaN[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1.0, 10) + self.diagrams[self.sigmaN[ax].name].create(text[0], self.sigmaN[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1.0E-6, 10) elif which in self.sigmaBstr: ax = self.sigmaBstr.index(which) text = self.sigmaBstrings[ax] @@ -282,7 +282,7 @@ class Shaft: del (self.diagrams[self.sigmaB[ax].name]) return self.diagrams[self.sigmaB[ax].name] = Diagram() - self.diagrams[self.sigmaB[ax].name].create(text[0], self.sigmaB[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1.0, 20) + self.diagrams[self.sigmaB[ax].name].create(text[0], self.sigmaB[ax], self.getLengthTo(len(self.segments)) / 1000.0, text[1], text[2], 1000.0, text[3], text[4], 1.0E-6, 20) def addTo(self, dict, location, value): if location not in dict: @@ -454,6 +454,7 @@ class Shaft: areas = [None, None, None] areamoments = [None, None, None] + bendingmoments = [None, None, None] torquemoments = [None, None, None] for ax in range(3): @@ -528,25 +529,27 @@ class Shaft: # Areas and area moments location = 0.0 - areas[ax] = IntervalFunction() - areamoments[ax] = IntervalFunction() - torquemoments[ax] = IntervalFunction() + areas[ax] = IntervalFunction() # A [m²] + areamoments[ax] = IntervalFunction() # I [m⁴] + bendingmoments[ax] = IntervalFunction() # W_b [m³] + torquemoments[ax] = IntervalFunction() # W_t [m³] for i in range(len(self.segments)): - od = self.segments[i].diameter - id = self.segments[i].innerdiameter + od = self.segments[i].diameter/1000.0 + id = self.segments[i].innerdiameter/1000.0 length = self.segments[i].length/1000.0 - areas[ax].addInterval(location, length, math.pi/4.0 * (math.pow(self.segments[i].diameter, 2.0) - math.pow(self.segments[i].innerdiameter, 2.0))) - areamoment = math.pi/32.0 * (math.pow(self.segments[i].diameter, 4.0) - math.pow(self.segments[i].innerdiameter, 4.0)) / self.segments[i].diameter + areas[ax].addInterval(location, length, math.pi/4.0 * (math.pow(od, 2.0) - math.pow(id, 2.0))) + areamoment = math.pi/64.0 * (math.pow(od, 4.0) - math.pow(id, 4.0)) areamoments[ax].addInterval(location, length, areamoment) - torquemoments[ax].addInterval(location, length, 2 * areamoment) + bendingmoments[ax].addInterval(location, length, areamoment / (od / 2.0)) + torquemoments[ax].addInterval(location, length, 2 * (areamoment / (od / 2.0))) location += length # Bending line if ax > 0: if len(tangents[ax])+ len(translations[ax]) == 2: - # TODO: Get Young's module from material type instead of using 210000 N/mm² - self.w[ax] = TranslationFunction(self.M[ax].negated() * 1000.0, 210000, areamoments[ax], tangents[ax], translations[ax]) + # TODO: Get Young's module from material type instead of using 210000 N/mm² = 2.1E12 N/m² + self.w[ax] = TranslationFunction(self.M[ax].negated(), 2.1E12, areamoments[ax], tangents[ax], translations[ax]) self.w[ax].name= self.wstr[ax] self.parent.updateButton(3, ax, not self.w[ax].isZero()) else: @@ -557,9 +560,9 @@ class Shaft: self.sigmaN[ax].name = self.sigmaNstr[ax] self.parent.updateButton(4, ax, not self.sigmaN[ax].isZero()) if ax == 0: - self.sigmaB[ax] = StressFunction(self.M[ax] * 1000.0, torquemoments[ax]) + self.sigmaB[ax] = StressFunction(self.M[ax] , torquemoments[ax]) else: - self.sigmaB[ax] = StressFunction(self.M[ax] * 1000.0, areamoments[ax]) + self.sigmaB[ax] = StressFunction(self.M[ax], bendingmoments[ax]) self.sigmaB[ax].name = self.sigmaBstr[ax] self.parent.updateButton(5, ax, not self.sigmaB[ax].isZero())