/*************************************************************************** * Copyright (c) 2022 Peter McB * * Copyright (c) 2008 Jürgen Riegel * * * * 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 #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 "ActiveAnalysisObserver.h" #include "FemSettings.h" #ifdef FC_USE_VTK # include # include # include #endif using namespace std; //================================================================================================ //================================================================================================ // helpers static bool getConstraintPrerequisits(Fem::FemAnalysis** Analysis) { if (!FemGui::ActiveAnalysisObserver::instance()->hasActiveObject()) { QMessageBox::warning( Gui::getMainWindow(), QObject::tr("No active Analysis"), QObject::tr("You need to create or activate a Analysis") ); return true; } *Analysis = FemGui::ActiveAnalysisObserver::instance()->getActiveObject(); // return with no error return false; } // OvG: Visibility automation show parts and hide meshes on activation of a constraint static std::string gethideMeshShowPartStr(std::string showConstr = "") { return "for amesh in App.activeDocument().Objects:\n\ if \"" + showConstr + "\" == amesh.Name:\n\ amesh.ViewObject.Visibility = True\n\ elif \"Mesh\" in amesh.TypeId:\n\ aparttoshow = amesh.Name.replace(\"_Mesh\",\"\")\n\ for apart in App.activeDocument().Objects:\n\ if aparttoshow == apart.Name:\n\ apart.ViewObject.Visibility = True\n\ amesh.ViewObject.Visibility = False\n"; } static std::string getSelectedNodes(Gui::View3DInventorViewer* view) { Gui::SelectionRole role; std::vector clPoly = view->getGLPolygon(&role); if (clPoly.size() < 3) { return {}; } if (clPoly.front() != clPoly.back()) { clPoly.push_back(clPoly.front()); } SoCamera* cam = view->getSoRenderManager()->getCamera(); SbViewVolume vv = cam->getViewVolume(); Gui::ViewVolumeProjection proj(vv); Base::Polygon2d polygon; for (auto it : clPoly) { polygon.Add(Base::Vector2d(it[0], it[1])); } std::vector docObj = Gui::Selection().getObjectsOfType( Fem::FemMeshObject::getClassTypeId() ); if (docObj.size() != 1) { return {}; } const SMESHDS_Mesh* data = static_cast(docObj[0])->FemMesh.getValue().getSMesh()->GetMeshDS(); SMDS_NodeIteratorPtr aNodeIter = data->nodesIterator(); Base::Vector3f pt2d; std::set IntSet; while (aNodeIter->more()) { const SMDS_MeshNode* aNode = aNodeIter->next(); Base::Vector3f vec(aNode->X(), aNode->Y(), aNode->Z()); pt2d = proj(vec); if (polygon.Contains(Base::Vector2d(pt2d.x, pt2d.y))) { IntSet.insert(aNode->GetID()); } } std::stringstream set; set << "["; for (auto it = IntSet.cbegin(); it != IntSet.cend(); ++it) { if (it == IntSet.begin()) { set << *it; } else { set << "," << *it; } } set << "]"; return set.str(); } //================================================================================================ //================================================================================================ // commands Part, Analysis, Solver //================================================================================================ /* ATM no gui command implemented in workbench.cpp, user does it in single steps DEF_STD_CMD_A(CmdFemAddPart) CmdFemAddPart::CmdFemAddPart() : Command("FEM_FemAddPart") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Add a part to the analysis"); sToolTipText = QT_TR_NOOP("Add a part to the Analysis"); sWhatsThis = "FEM_FemAddPart"; sStatusTip = sToolTipText; sPixmap = "fem-add-fem-mesh"; } void CmdFemAddPart::activated(int) { #ifndef FCWithNetgen QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Your FreeCAD is built without NETGEN support. Meshing will not work....")); return; #endif std::vector selection = getSelection().getSelectionEx(); if (selection.size() != 1) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select an edge, face, or body. Only one body is allowed.")); return; } if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), QObject::tr("Fillet works only on parts")); return; } Part::Feature *base = static_cast(selection[0].getObject()); std::string AnalysisName = getUniqueObjectName("FemAnalysis"); std::string MeshName = getUniqueObjectName((std::string(base->getNameInDocument()) +"_Mesh").c_str()); openCommand(QT_TRANSLATE_NOOP("Command", "Create FEM analysis")); doCommand(Doc,"App.activeDocument().addObject('Fem::FemAnalysis','%s')",AnalysisName.c_str()); doCommand(Doc,"App.activeDocument().addObject('Fem::FemMeshShapeNetgenObject','%s')",MeshName.c_str()); doCommand(Doc,"App.activeDocument().ActiveObject.Shape = App.activeDocument().%s",base->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)",AnalysisName.c_str(),MeshName.c_str()); addModule(Gui,"FemGui"); doCommand(Gui,"FemGui.setActiveAnalysis(App.activeDocument().%s)",AnalysisName.c_str()); commitCommand(); updateActive(); } bool CmdFemAddPart::isActive(void) { if (Gui::Control().activeDialog()) return false; return Gui::Selection().countObjectsOfType(type) > 0; } */ //================================================================================================ //================================================================================================ // commands Constraints //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintBearing) CmdFemConstraintBearing::CmdFemConstraintBearing() : Command("FEM_ConstraintBearing") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Bearing Constraint"); sToolTipText = QT_TR_NOOP("Creates a bearing constraint"); sWhatsThis = "FEM_ConstraintBearing"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintBearing"; } void CmdFemConstraintBearing::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintBearing"); openCommand(QT_TRANSLATE_NOOP("Command", "Make bearing constraint")); doCommand(Doc, "App.activeDocument().addObject(\"Fem::ConstraintBearing\",\"%s\")", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintBearing::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintContact) CmdFemConstraintContact::CmdFemConstraintContact() : Command("FEM_ConstraintContact") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Contact Constraint"); sToolTipText = QT_TR_NOOP("Creates a contact constraint between faces"); sWhatsThis = "FEM_ConstraintContact"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintContact"; } void CmdFemConstraintContact::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintContact"); openCommand(QT_TRANSLATE_NOOP("Command", "Make contact constraint on a face")); doCommand(Doc, "App.activeDocument().addObject(\"Fem::ConstraintContact\",\"%s\")", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.Slope = \"1e6 GPa/m\"", FeatName.c_str() ); // OvG: set default not equal to 0 doCommand( Doc, "App.activeDocument().%s.Adjust = 0.0", FeatName.c_str() ); // OvG: set default equal to 0 doCommand( Doc, "App.activeDocument().%s.Friction = False", FeatName.c_str() ); // OvG: set default equal to 0 doCommand( Doc, "App.activeDocument().%s.FrictionCoefficient = 0.0", FeatName.c_str() ); // OvG: set default equal to 0 doCommand( Doc, "App.activeDocument().%s.StickSlope = \"1e4 GPa/m\"", FeatName.c_str() ); // OvG: set default not equal to 0 doCommand( Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str() ); // OvG: set initial scale to 1 doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintContact::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintDisplacement) CmdFemConstraintDisplacement::CmdFemConstraintDisplacement() : Command("FEM_ConstraintDisplacement") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Displacement Boundary Condition"); sToolTipText = QT_TR_NOOP("Creates a displacement boundary condition for a geometric entity"); sWhatsThis = "FEM_ConstraintDisplacement"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintDisplacement"; } void CmdFemConstraintDisplacement::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintDisplacement"); openCommand(QT_TRANSLATE_NOOP("Command", "Make displacement boundary condition on face")); doCommand( Doc, "App.activeDocument().addObject(\"Fem::ConstraintDisplacement\",\"%s\")", FeatName.c_str() ); // OvG: set initial scale to 1 doCommand(Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintDisplacement::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintFixed) CmdFemConstraintFixed::CmdFemConstraintFixed() : Command("FEM_ConstraintFixed") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Fixed Boundary Condition"); sToolTipText = QT_TR_NOOP("Creates a fixed boundary condition for a geometric entity"); sWhatsThis = "FEM_ConstraintFixed"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintFixed"; } void CmdFemConstraintFixed::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintFixed"); openCommand(QT_TRANSLATE_NOOP("Command", "Make fixed boundary condition for geometry")); doCommand(Doc, "App.activeDocument().addObject(\"Fem::ConstraintFixed\",\"%s\")", FeatName.c_str()); // OvG: set initial scale to 1 doCommand(Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintFixed::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintRigidBody) CmdFemConstraintRigidBody::CmdFemConstraintRigidBody() : Command("FEM_ConstraintRigidBody") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Rigid Body Constraint"); sToolTipText = QT_TR_NOOP("Creates a rigid body constraint for a geometric entity"); sWhatsThis = "FEM_ConstraintRigidBody"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintRigidBody"; } void CmdFemConstraintRigidBody::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintRigidBody"); openCommand(QT_TRANSLATE_NOOP("Command", "Make rigid body constraint")); doCommand( Doc, "App.activeDocument().addObject(\"Fem::ConstraintRigidBody\",\"%s\")", FeatName.c_str() ); doCommand( Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str() ); // OvG: set initial scale to 1 doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); doCommand( Doc, "%s", gethideMeshShowPartStr(FeatName).c_str() ); // OvG: Hide meshes and show parts updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintRigidBody::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintFluidBoundary) CmdFemConstraintFluidBoundary::CmdFemConstraintFluidBoundary() : Command("FEM_ConstraintFluidBoundary") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Fluid Boundary Condition"); sToolTipText = QT_TR_NOOP( "Create fluid boundary condition on face entity for Computional Fluid Dynamics" ); sWhatsThis = "FEM_ConstraintFluidBoundary"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintFluidBoundary"; } void CmdFemConstraintFluidBoundary::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintFluidBoundary"); openCommand(QT_TRANSLATE_NOOP("Command", "Create fluid boundary condition")); doCommand( Doc, "App.activeDocument().addObject(\"Fem::ConstraintFluidBoundary\",\"%s\")", FeatName.c_str() ); doCommand( Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str() ); // OvG: set initial scale to 1 // BoundaryValue is already the default value, zero is acceptable doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintFluidBoundary::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintForce) CmdFemConstraintForce::CmdFemConstraintForce() : Command("FEM_ConstraintForce") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Force Load"); sToolTipText = QT_TR_NOOP("Creates a force load applied to a geometric entity"); sWhatsThis = "FEM_ConstraintForce"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintForce"; } void CmdFemConstraintForce::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintForce"); openCommand(QT_TRANSLATE_NOOP("Command", "Make force load on geometry")); doCommand(Doc, "App.activeDocument().addObject(\"Fem::ConstraintForce\",\"%s\")", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.Force = \"1 N\"", FeatName.c_str() ); // OvG: set default to 1 N doCommand( Doc, "App.activeDocument().%s.Reversed = False", FeatName.c_str() ); // OvG: set default to False doCommand( Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str() ); // OvG: set initial scale to 1 doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintForce::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintGear) CmdFemConstraintGear::CmdFemConstraintGear() : Command("FEM_ConstraintGear") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Gear Constraint"); sToolTipText = QT_TR_NOOP("Creates a gear constraint"); sWhatsThis = "FEM_ConstraintGear"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintGear"; } void CmdFemConstraintGear::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintGear"); openCommand(QT_TRANSLATE_NOOP("Command", "Make gear constraint")); doCommand(Doc, "App.activeDocument().addObject(\"Fem::ConstraintGear\",\"%s\")", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.Diameter = 100.0", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintGear::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintHeatflux) CmdFemConstraintHeatflux::CmdFemConstraintHeatflux() : Command("FEM_ConstraintHeatflux") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Heat Flux Load"); sToolTipText = QT_TR_NOOP("Creates a heat flux load acting on a face"); sWhatsThis = "FEM_ConstraintHeatflux"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintHeatflux"; } void CmdFemConstraintHeatflux::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintHeatflux"); openCommand(QT_TRANSLATE_NOOP("Command", "Make heat flux load on face")); doCommand( Doc, "App.activeDocument().addObject(\"Fem::ConstraintHeatflux\",\"%s\")", FeatName.c_str() ); doCommand(Doc, "App.activeDocument().%s.ConstraintType = \"DFlux\"", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.AmbientTemp = 300.0", FeatName.c_str() ); // OvG: set default not equal to 0 doCommand( Doc, "App.activeDocument().%s.FilmCoef = 10.0", FeatName.c_str() ); // OvG: set default not equal to 0 doCommand( Doc, "App.activeDocument().%s.Emissivity = 1.0", FeatName.c_str() ); // OvG: set default not equal to 0 doCommand( Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str() ); // OvG: set initial scale to 1 doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr().c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintHeatflux::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintInitialTemperature) CmdFemConstraintInitialTemperature::CmdFemConstraintInitialTemperature() : Command("FEM_ConstraintInitialTemperature") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Initial Temperature"); sToolTipText = QT_TR_NOOP("Creates an initial temperature acting on a body"); sWhatsThis = "FEM_ConstraintInitialTemperature"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintInitialTemperature"; } void CmdFemConstraintInitialTemperature::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintInitialTemperature"); openCommand(QT_TRANSLATE_NOOP("Command", "Make initial temperature condition on body")); doCommand( Doc, "App.activeDocument().addObject(\"Fem::ConstraintInitialTemperature\",\"%s\")", FeatName.c_str() ); doCommand( Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str() ); // OvG: set initial scale to 1 doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr().c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintInitialTemperature::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintPlaneRotation) CmdFemConstraintPlaneRotation::CmdFemConstraintPlaneRotation() : Command("FEM_ConstraintPlaneRotation") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Plane Multi-Point Constraint"); sToolTipText = QT_TR_NOOP("Creates a plane multi-point constraint for a face"); sWhatsThis = "FEM_ConstraintPlaneRotation"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintPlaneRotation"; } void CmdFemConstraintPlaneRotation::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintPlaneRotation"); openCommand(QT_TRANSLATE_NOOP("Command", "Make plane multi-point constraint on face")); doCommand( Doc, "App.activeDocument().addObject(\"Fem::ConstraintPlaneRotation\",\"%s\")", FeatName.c_str() ); doCommand( Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str() ); // OvG: set initial scale to 1 doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintPlaneRotation::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintPressure) CmdFemConstraintPressure::CmdFemConstraintPressure() : Command("FEM_ConstraintPressure") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Pressure Load"); sToolTipText = QT_TR_NOOP("Creates a pressure load acting on a face"); sWhatsThis = "FEM_ConstraintPressure"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintPressure"; } void CmdFemConstraintPressure::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintPressure"); openCommand(QT_TRANSLATE_NOOP("Command", "Make pressure load on face")); doCommand( Doc, "App.activeDocument().addObject(\"Fem::ConstraintPressure\",\"%s\")", FeatName.c_str() ); doCommand( Doc, "App.activeDocument().%s.Pressure = 0.1", FeatName.c_str() ); // OvG: set default not equal to 0 doCommand( Doc, "App.activeDocument().%s.Reversed = False", FeatName.c_str() ); // OvG: set default to False // OvG: set initial scale to 1 doCommand(Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintPressure::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintSpring) CmdFemConstraintSpring::CmdFemConstraintSpring() : Command("FEM_ConstraintSpring") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Spring Boundary Condition"); sToolTipText = QT_TR_NOOP("Creates a spring boundary condition on a face"); sWhatsThis = "FEM_ConstraintSpring"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintSpring"; } void CmdFemConstraintSpring::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintSpring"); openCommand(QT_TRANSLATE_NOOP("Command", "Make Spring Constraint")); doCommand(Doc, "App.activeDocument().addObject(\"Fem::ConstraintSpring\",\"%s\")", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.NormalStiffness = 1.0", FeatName.c_str() ); // OvG: set default not equal to 0 doCommand( Doc, "App.activeDocument().%s.TangentialStiffness = 0.0", FeatName.c_str() ); // OvG: set default to False // OvG: set initial scale to 1 doCommand(Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintSpring::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintPulley) CmdFemConstraintPulley::CmdFemConstraintPulley() : Command("FEM_ConstraintPulley") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Pulley Constraint"); sToolTipText = QT_TR_NOOP("Creates a pulley constraint"); sWhatsThis = "FEM_ConstraintPulley"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintPulley"; } void CmdFemConstraintPulley::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintPulley"); openCommand(QT_TRANSLATE_NOOP("Command", "Make pulley constraint")); doCommand(Doc, "App.activeDocument().addObject(\"Fem::ConstraintPulley\",\"%s\")", 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()); doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintPulley::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintTemperature) CmdFemConstraintTemperature::CmdFemConstraintTemperature() : Command("FEM_ConstraintTemperature") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Temperature Boundary Condition"); sToolTipText = QT_TR_NOOP("Creates a temperature/concentrated heat flux load acting on a face"); sWhatsThis = "FEM_ConstraintTemperature"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintTemperature"; } void CmdFemConstraintTemperature::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintTemperature"); openCommand(QT_TRANSLATE_NOOP("Command", "Make temperature boundary condition on face")); doCommand( Doc, "App.activeDocument().addObject(\"Fem::ConstraintTemperature\",\"%s\")", FeatName.c_str() ); doCommand( Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str() ); // OvG: set initial scale to 1 doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr().c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintTemperature::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ DEF_STD_CMD_A(CmdFemConstraintTransform) CmdFemConstraintTransform::CmdFemConstraintTransform() : Command("FEM_ConstraintTransform") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Local Coordinate System"); sToolTipText = QT_TR_NOOP("Creates a local coordinate system on a face"); sWhatsThis = "FEM_ConstraintTransform"; sStatusTip = sToolTipText; sPixmap = "FEM_ConstraintTransform"; } void CmdFemConstraintTransform::activated(int) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } std::string FeatName = getUniqueObjectName("ConstraintTransform"); openCommand(QT_TRANSLATE_NOOP("Command", "Make local coordinate system on face")); doCommand( Doc, "App.activeDocument().addObject(\"Fem::ConstraintTransform\",\"%s\")", FeatName.c_str() ); doCommand(Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)", Analysis->getNameInDocument(), FeatName.c_str() ); // OvG: Hide meshes and show parts doCommand(Doc, "%s", gethideMeshShowPartStr(FeatName).c_str()); updateActive(); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } bool CmdFemConstraintTransform::isActive() { return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //================================================================================================ //================================================================================================ // commands mesh //================================================================================================ DEF_STD_CMD_A(CmdFemDefineNodesSet) static void DefineNodesCallback(void* ud, SoEventCallback* n) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } // show the wait cursor because this could take quite some time Gui::WaitCursor wc; // When this callback function is invoked we must in either case leave the edit mode Gui::View3DInventorViewer* view = static_cast(n->getUserData()); view->setEditing(false); view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), DefineNodesCallback, ud); n->setHandled(); std::string str = getSelectedNodes(view); if (!str.empty()) { Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Place robot")); Gui::Command::doCommand( Gui::Command::Doc, "App.ActiveDocument.addObject('Fem::FemSetNodesObject','NodeSet')" ); Gui::Command::doCommand( Gui::Command::Doc, "App.ActiveDocument.ActiveObject.Nodes = %s", str.c_str() ); Gui::Command::doCommand( Gui::Command::Doc, "App.activeDocument().%s.addObject(App.activeDocument().NodeSet)", Analysis->getNameInDocument() ); Gui::Command::commitCommand(); } } CmdFemDefineNodesSet::CmdFemDefineNodesSet() : Command("FEM_DefineNodesSet") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Node Set by Polygon"); sToolTipText = QT_TR_NOOP("Creates a node set by polygon selection"); sWhatsThis = "FEM_DefineNodesSet"; sStatusTip = sToolTipText; sPixmap = "FEM_CreateNodesSet"; } void CmdFemDefineNodesSet::activated(int) { std::vector docObj = Gui::Selection().getObjectsOfType( Fem::FemMeshObject::getClassTypeId() ); for (std::vector::iterator it = docObj.begin(); it != docObj.end(); ++it) { if (it == docObj.begin()) { Gui::Document* doc = getActiveGuiDocument(); Gui::MDIView* view = doc->getActiveView(); if (view->isDerivedFrom()) { Gui::View3DInventorViewer* viewer = ((Gui::View3DInventor*)view)->getViewer(); viewer->setEditing(true); viewer->startSelection(Gui::View3DInventorViewer::Clip); viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), DefineNodesCallback); } else { return; } } // Gui::ViewProvider* pVP = getActiveGuiDocument()->getViewProvider(*it); // if (pVP->isVisible()) // pVP->startEditing(); } } bool CmdFemDefineNodesSet::isActive() { // Check for the selected mesh feature (all Mesh types) if (getSelection().countObjectsOfType() != 1) { return false; } Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); if (view && view->isDerivedFrom()) { Gui::View3DInventorViewer* viewer = static_cast(view)->getViewer(); return !viewer->isEditing(); } return false; } //================================================================================================ DEF_STD_CMD_A(CmdFemCreateNodesSet) CmdFemCreateNodesSet::CmdFemCreateNodesSet() : Command("FEM_CreateNodesSet") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Nodes Set"); sToolTipText = QT_TR_NOOP("Creates a FEM mesh nodes set"); sWhatsThis = "FEM_CreateNodesSet"; sStatusTip = sToolTipText; sPixmap = "FEM_CreateNodesSet"; } void CmdFemCreateNodesSet::activated(int) { Gui::SelectionFilter ObjectFilter("SELECT Fem::FemSetNodesObject COUNT 1"); Gui::SelectionFilter FemMeshFilter("SELECT Fem::FemMeshObject COUNT 1"); if (ObjectFilter.match()) { Fem::FemSetNodesObject* NodesObj = static_cast( ObjectFilter.Result[0][0].getObject() ); openCommand(QT_TRANSLATE_NOOP("Command", "Edit nodes set")); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", NodesObj->getNameInDocument()); } else if (FemMeshFilter.match()) { Fem::FemMeshObject* MeshObj = static_cast( FemMeshFilter.Result[0][0].getObject() ); std::string FeatName = getUniqueObjectName("NodesSet"); openCommand(QT_TRANSLATE_NOOP("Command", "Create nodes set")); doCommand(Doc, "App.activeDocument().addObject('Fem::FemSetNodesObject','%s')", FeatName.c_str()); doCommand( Gui, "App.activeDocument().%s.FemMesh = App.activeDocument().%s", FeatName.c_str(), MeshObj->getNameInDocument() ); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } else { QMessageBox::warning( Gui::getMainWindow(), qApp->translate("CmdFemCreateNodesSet", "Wrong selection"), qApp->translate("CmdFemCreateNodesSet", "Select a single FEM mesh or nodes set.") ); } } bool CmdFemCreateNodesSet::isActive() { return hasActiveDocument(); } //=========================================================================== // start of Erase Elements code //=========================================================================== DEF_STD_CMD_A(CmdFemDefineElementsSet); static void DefineElementsCallback(void* ud, SoEventCallback* n) { Fem::FemAnalysis* Analysis; if (getConstraintPrerequisits(&Analysis)) { return; } // show the wait cursor because this could take quite some time Gui::WaitCursor wc; // When this callback function is invoked we must in either case leave the edit mode Gui::View3DInventorViewer* view = static_cast(n->getUserData()); view->setEditing(false); view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), DefineElementsCallback, ud); n->setHandled(); std::string str = getSelectedNodes(view); if (!str.empty()) { Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Place robot")); Gui::Command::doCommand( Gui::Command::Doc, "App.ActiveDocument.addObject('Fem::FemSetElementNodesObject','ElementSet')" ); Gui::Command::doCommand( Gui::Command::Doc, "App.ActiveDocument.ActiveObject.Nodes = %s", str.c_str() ); Gui::Command::doCommand( Gui::Command::Doc, "App.activeDocument().%s.addObject(App.activeDocument().ElementSet)", Analysis->getNameInDocument() ); Gui::Command::commitCommand(); } } CmdFemDefineElementsSet::CmdFemDefineElementsSet() : Command("FEM_DefineElementsSet") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Element Set From Polygon"); sToolTipText = QT_TR_NOOP("Creates a collection of elements selected by a polygon"); sWhatsThis = "FEM_DefineElementsSet"; sStatusTip = sToolTipText; sPixmap = "FEM_CreateElementsSet"; } void CmdFemDefineElementsSet::activated(int) { std::vector docObj = Gui::Selection().getObjectsOfType( Fem::FemMeshObject::getClassTypeId() ); for (std::vector::iterator it = docObj.begin(); it != docObj.end(); ++it) { if (it == docObj.begin()) { Gui::Document* doc = getActiveGuiDocument(); Gui::MDIView* view = doc->getActiveView(); if (view->isDerivedFrom()) { Gui::View3DInventorViewer* viewer = ((Gui::View3DInventor*)view)->getViewer(); viewer->setEditing(true); viewer->startSelection(Gui::View3DInventorViewer::Clip); viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), DefineElementsCallback); } else { return; } } } } bool CmdFemDefineElementsSet::isActive() { // Check for the selected mesh feature (all Mesh types) if (getSelection().countObjectsOfType() != 1) { return false; } Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); if (view && view->isDerivedFrom()) { Gui::View3DInventorViewer* viewer = static_cast(view)->getViewer(); return !viewer->isEditing(); } return false; } //================================================================================================ DEF_STD_CMD_A(CmdFemCreateElementsSet); CmdFemCreateElementsSet::CmdFemCreateElementsSet() : Command("FEM_CreateElementsSet") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Erase Elements"); sToolTipText = QT_TR_NOOP("Creates a FEM mesh elements set"); sWhatsThis = "FEM_CreateElementsSet"; sStatusTip = sToolTipText; sPixmap = "FEM_CreateElementsSet"; } void CmdFemCreateElementsSet::activated(int) { Gui::SelectionFilter ObjectFilter("SELECT Fem::FemSetElementNodesObject COUNT 1"); Gui::SelectionFilter FemMeshFilter("SELECT Fem::FemMeshObject COUNT 1"); if (ObjectFilter.match()) { Fem::FemSetElementNodesObject* NodesObj = static_cast( ObjectFilter.Result[0][0].getObject() ); openCommand(QT_TRANSLATE_NOOP("Command", "Edit Elements set")); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", NodesObj->getNameInDocument()); } // start else if (FemMeshFilter.match()) { Fem::FemMeshObject* MeshObj = static_cast( FemMeshFilter.Result[0][0].getObject() ); std::string elementsName = Fem::FemSetElementNodesObject::getElementName(); std::string uniqueElementsName = Command::getUniqueObjectName(elementsName.c_str()); openCommand(QT_TRANSLATE_NOOP("Command", "Create Elements set")); doCommand( Doc, "App.activeDocument().addObject('Fem::FemSetElementNodesObject','%s')", uniqueElementsName.c_str() ); doCommand( Gui, "App.activeDocument().%s.FemMesh = App.activeDocument().%s", uniqueElementsName.c_str(), MeshObj->getNameInDocument() ); doCommand(Gui, "Gui.activeDocument().setEdit('%s')", uniqueElementsName.c_str()); } else { QMessageBox::warning( Gui::getMainWindow(), qApp->translate("CmdFemCreateElementsSet", "Wrong selection"), qApp->translate("CmdFemCreateNodesSet", "Select a single FEM Mesh.") ); } } bool CmdFemCreateElementsSet::isActive() { return hasActiveDocument(); } //=========================================================================== // end of Erase Elements code //=========================================================================== //=========================================================================== // FEM_CompEmConstraints (dropdown toolbar button for electromagnetic constraints) //=========================================================================== DEF_STD_CMD_ACL(CmdFemCompEmConstraints) CmdFemCompEmConstraints::CmdFemCompEmConstraints() : Command("FEM_CompEmConstraints") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Electromagnetic Boundary Conditions"); sToolTipText = QT_TR_NOOP("Electromagnetic boundary conditions"); sWhatsThis = "FEM_CompEmConstraints"; sStatusTip = sToolTipText; } void CmdFemCompEmConstraints::activated(int iMsg) { Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); if (iMsg == 0) { rcCmdMgr.runCommandByName("FEM_ConstraintElectrostaticPotential"); } else if (iMsg == 1) { rcCmdMgr.runCommandByName("FEM_ConstraintCurrentDensity"); } else if (iMsg == 2) { rcCmdMgr.runCommandByName("FEM_ConstraintMagnetization"); } else if (iMsg == 3) { rcCmdMgr.runCommandByName("FEM_ConstraintElectricChargeDensity"); } else { return; } // Since the default icon is reset when enabling/disabling the command we have // to explicitly set the icon of the used command. Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); assert(iMsg < a.size()); pcAction->setIcon(a[iMsg]->icon()); } Gui::Action* CmdFemCompEmConstraints::createAction() { Gui::ActionGroup* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow()); pcAction->setDropDownMenu(true); applyCommandData(this->className(), pcAction); QAction* cmd0 = pcAction->addAction(QString()); cmd0->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_ConstraintElectrostaticPotential")); QAction* cmd1 = pcAction->addAction(QString()); cmd1->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_ConstraintCurrentDensity")); QAction* cmd2 = pcAction->addAction(QString()); cmd2->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_ConstraintMagnetization")); QAction* cmd3 = pcAction->addAction(QString()); cmd3->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_ConstraintElectricChargeDensity")); _pcAction = pcAction; languageChange(); pcAction->setIcon(cmd0->icon()); int defaultId = 0; pcAction->setProperty("defaultAction", QVariant(defaultId)); return pcAction; } void CmdFemCompEmConstraints::languageChange() { Command::languageChange(); if (!_pcAction) { return; } Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); Gui::Command* ConstraintElectrostaticPotential = rcCmdMgr.getCommandByName( "FEM_ConstraintElectrostaticPotential" ); if (ConstraintElectrostaticPotential) { QAction* cmd0 = a[0]; cmd0->setText( QApplication::translate( "FEM_ConstraintElectrostaticPotential", ConstraintElectrostaticPotential->getMenuText() ) ); cmd0->setToolTip( QApplication::translate( "FEM_ConstraintElectrostaticPotential", ConstraintElectrostaticPotential->getToolTipText() ) ); cmd0->setStatusTip( QApplication::translate( "FEM_ConstraintElectrostaticPotential", ConstraintElectrostaticPotential->getStatusTip() ) ); } Gui::Command* ConstraintCurrentDensity = rcCmdMgr.getCommandByName("FEM_ConstraintCurrentDensity"); if (ConstraintCurrentDensity) { QAction* cmd1 = a[1]; cmd1->setText( QApplication::translate( "FEM_ConstraintCurrentDensity", ConstraintCurrentDensity->getMenuText() ) ); cmd1->setToolTip( QApplication::translate( "FEM_ConstraintCurrentDensity", ConstraintCurrentDensity->getToolTipText() ) ); cmd1->setStatusTip( QApplication::translate( "FEM_ConstraintCurrentDensity", ConstraintCurrentDensity->getStatusTip() ) ); } Gui::Command* ConstraintMagnetization = rcCmdMgr.getCommandByName("FEM_ConstraintMagnetization"); if (ConstraintMagnetization) { QAction* cmd2 = a[2]; cmd2->setText( QApplication::translate("FEM_ConstraintMagnetization", ConstraintMagnetization->getMenuText()) ); cmd2->setToolTip( QApplication::translate( "FEM_ConstraintMagnetization", ConstraintMagnetization->getToolTipText() ) ); cmd2->setStatusTip( QApplication::translate( "FEM_ConstraintMagnetization", ConstraintMagnetization->getStatusTip() ) ); } Gui::Command* ConstraintElectricChargeDensity = rcCmdMgr.getCommandByName( "FEM_ConstraintElectricChargeDensity" ); if (ConstraintElectricChargeDensity) { QAction* cmd3 = a[3]; cmd3->setText( QApplication::translate( "FEM_ConstraintElectricChargeDensity", ConstraintElectricChargeDensity->getMenuText() ) ); cmd3->setToolTip( QApplication::translate( "FEM_ConstraintElectricChargeDensity", ConstraintElectricChargeDensity->getToolTipText() ) ); cmd3->setStatusTip( QApplication::translate( "FEM_ConstraintElectricChargeDensity", ConstraintElectricChargeDensity->getStatusTip() ) ); } } bool CmdFemCompEmConstraints::isActive() { // only if there is an active analysis return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //=========================================================================== // FEM_CompEmEquations (dropdown toolbar button for electromagnetic equations) //=========================================================================== DEF_STD_CMD_ACL(CmdFemCompEmEquations) CmdFemCompEmEquations::CmdFemCompEmEquations() : Command("FEM_CompEmEquations") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Electromagnetic Equations"); sToolTipText = QT_TR_NOOP("Electromagnetic equations for the Elmer solver"); sWhatsThis = "FEM_CompEmEquations"; sStatusTip = sToolTipText; } void CmdFemCompEmEquations::activated(int iMsg) { Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); if (iMsg == 0) { rcCmdMgr.runCommandByName("FEM_EquationElectrostatic"); } else if (iMsg == 1) { rcCmdMgr.runCommandByName("FEM_EquationElectricforce"); } else if (iMsg == 2) { rcCmdMgr.runCommandByName("FEM_EquationMagnetodynamic"); } else if (iMsg == 3) { rcCmdMgr.runCommandByName("FEM_EquationMagnetodynamic2D"); } else if (iMsg == 4) { rcCmdMgr.runCommandByName("FEM_EquationStaticCurrent"); } else { return; } // Since the default icon is reset when enabling/disabling the command we have // to explicitly set the icon of the used command. Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); assert(iMsg < a.size()); pcAction->setIcon(a[iMsg]->icon()); } Gui::Action* CmdFemCompEmEquations::createAction() { Gui::ActionGroup* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow()); pcAction->setDropDownMenu(true); applyCommandData(this->className(), pcAction); QAction* cmd0 = pcAction->addAction(QString()); cmd0->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_EquationElectrostatic")); QAction* cmd1 = pcAction->addAction(QString()); cmd1->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_EquationElectricforce")); QAction* cmd2 = pcAction->addAction(QString()); cmd2->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_EquationMagnetodynamic")); QAction* cmd3 = pcAction->addAction(QString()); cmd3->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_EquationMagnetodynamic2D")); QAction* cmd4 = pcAction->addAction(QString()); cmd4->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_EquationStaticCurrent")); _pcAction = pcAction; languageChange(); pcAction->setIcon(cmd0->icon()); int defaultId = 0; pcAction->setProperty("defaultAction", QVariant(defaultId)); return pcAction; } void CmdFemCompEmEquations::languageChange() { Command::languageChange(); if (!_pcAction) { return; } Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); Gui::Command* EquationElectrostatic = rcCmdMgr.getCommandByName("FEM_EquationElectrostatic"); if (EquationElectrostatic) { QAction* cmd0 = a[0]; cmd0->setText( QApplication::translate("FEM_EquationElectrostatic", EquationElectrostatic->getMenuText()) ); cmd0->setToolTip( QApplication::translate("FEM_EquationElectrostatic", EquationElectrostatic->getToolTipText()) ); cmd0->setStatusTip( QApplication::translate("FEM_EquationElectrostatic", EquationElectrostatic->getStatusTip()) ); } Gui::Command* EquationElectricforce = rcCmdMgr.getCommandByName("FEM_EquationElectricforce"); if (EquationElectricforce) { QAction* cmd1 = a[1]; cmd1->setText( QApplication::translate("FEM_EquationElectricforce", EquationElectricforce->getMenuText()) ); cmd1->setToolTip( QApplication::translate("FEM_EquationElectricforce", EquationElectricforce->getToolTipText()) ); cmd1->setStatusTip( QApplication::translate("FEM_EquationElectricforce", EquationElectricforce->getStatusTip()) ); } Gui::Command* EquationMagnetodynamic = rcCmdMgr.getCommandByName("FEM_EquationMagnetodynamic"); if (EquationMagnetodynamic) { QAction* cmd2 = a[2]; cmd2->setText( QApplication::translate("FEM_EquationMagnetodynamic", EquationMagnetodynamic->getMenuText()) ); cmd2->setToolTip( QApplication::translate( "FEM_EquationMagnetodynamic", EquationMagnetodynamic->getToolTipText() ) ); cmd2->setStatusTip( QApplication::translate("FEM_EquationMagnetodynamic", EquationMagnetodynamic->getStatusTip()) ); } Gui::Command* EquationMagnetodynamic2D = rcCmdMgr.getCommandByName("FEM_EquationMagnetodynamic2D"); if (EquationMagnetodynamic2D) { QAction* cmd3 = a[3]; cmd3->setText( QApplication::translate( "FEM_EquationMagnetodynamic2D", EquationMagnetodynamic2D->getMenuText() ) ); cmd3->setToolTip( QApplication::translate( "FEM_EquationMagnetodynamic2D", EquationMagnetodynamic2D->getToolTipText() ) ); cmd3->setStatusTip( QApplication::translate( "FEM_EquationMagnetodynamic2D", EquationMagnetodynamic2D->getStatusTip() ) ); } Gui::Command* EquationStaticCurrent = rcCmdMgr.getCommandByName("FEM_EquationStaticCurrent"); if (EquationStaticCurrent) { QAction* cmd4 = a[4]; cmd4->setText( QApplication::translate("FEM_EquationStaticCurrent", EquationStaticCurrent->getMenuText()) ); cmd4->setToolTip( QApplication::translate("FEM_EquationStaticCurrent", EquationStaticCurrent->getToolTipText()) ); cmd4->setStatusTip( QApplication::translate("FEM_EquationStaticCurrent", EquationStaticCurrent->getStatusTip()) ); } } bool CmdFemCompEmEquations::isActive() { // only if there is an active analysis if (!FemGui::ActiveAnalysisObserver::instance()->hasActiveObject()) { return false; } // only activate if a single Elmer object is selected auto results = getSelection().getSelectionEx( nullptr, App::DocumentObject::getClassTypeId(), Gui::ResolveMode::FollowLink ); if (results.size() == 1) { auto object = results.begin()->getObject(); // FIXME: this is not unique since the Ccx solver object has the same type std::string Type = "Fem::FemSolverObjectPython"; if (Type.compare(object->getTypeId().getName()) == 0) { return true; } } return false; } //=========================================================================== // FEM_CompMechEquations (dropdown toolbar button for mechanical equations) //=========================================================================== DEF_STD_CMD_ACL(CmdFemCompMechEquations) CmdFemCompMechEquations::CmdFemCompMechEquations() : Command("FEM_CompMechEquations") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Mechanical Equations"); sToolTipText = QT_TR_NOOP("Mechanical equations for the Elmer solver"); sWhatsThis = "FEM_CompMechEquations"; sStatusTip = sToolTipText; } void CmdFemCompMechEquations::activated(int iMsg) { Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); if (iMsg == 0) { rcCmdMgr.runCommandByName("FEM_EquationElasticity"); } else if (iMsg == 1) { rcCmdMgr.runCommandByName("FEM_EquationDeformation"); } else { return; } // Since the default icon is reset when enabling/disabling the command we have // to explicitly set the icon of the used command. Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); assert(iMsg < a.size()); pcAction->setIcon(a[iMsg]->icon()); } Gui::Action* CmdFemCompMechEquations::createAction() { Gui::ActionGroup* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow()); pcAction->setDropDownMenu(true); applyCommandData(this->className(), pcAction); QAction* cmd0 = pcAction->addAction(QString()); cmd0->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_EquationElasticity")); QAction* cmd1 = pcAction->addAction(QString()); cmd1->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_EquationDeformation")); _pcAction = pcAction; languageChange(); pcAction->setIcon(cmd0->icon()); int defaultId = 0; pcAction->setProperty("defaultAction", QVariant(defaultId)); return pcAction; } void CmdFemCompMechEquations::languageChange() { Command::languageChange(); if (!_pcAction) { return; } Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); Gui::Command* EquationElasticity = rcCmdMgr.getCommandByName("FEM_EquationElasticity"); if (EquationElasticity) { QAction* cmd1 = a[0]; cmd1->setText( QApplication::translate("FEM_EquationElasticity", EquationElasticity->getMenuText()) ); cmd1->setToolTip( QApplication::translate("FEM_EquationElasticity", EquationElasticity->getToolTipText()) ); cmd1->setStatusTip( QApplication::translate("FEM_EquationElasticity", EquationElasticity->getStatusTip()) ); } Gui::Command* EquationDeformation = rcCmdMgr.getCommandByName("FEM_EquationDeformation"); if (EquationDeformation) { QAction* cmd0 = a[1]; cmd0->setText( QApplication::translate("FEM_EquationDeformation", EquationDeformation->getMenuText()) ); cmd0->setToolTip( QApplication::translate("FEM_EquationDeformation", EquationDeformation->getToolTipText()) ); cmd0->setStatusTip( QApplication::translate("FEM_EquationDeformation", EquationDeformation->getStatusTip()) ); } } bool CmdFemCompMechEquations::isActive() { // only if there is an active analysis if (!FemGui::ActiveAnalysisObserver::instance()->hasActiveObject()) { return false; } // only activate if a single Elmer object is selected auto results = getSelection().getSelectionEx( nullptr, App::DocumentObject::getClassTypeId(), Gui::ResolveMode::FollowLink ); if (results.size() == 1) { auto object = results.begin()->getObject(); // FIXME: this is not unique since the Ccx solver object has the same type std::string Type = "Fem::FemSolverObjectPython"; if (Type.compare(object->getTypeId().getName()) == 0) { return true; } } return false; } //================================================================================================ //================================================================================================ // commands vtk post processing #ifdef FC_USE_VTK //================================================================================================ // helper vtk post processing void setupFilter(Gui::Command* cmd, std::string Name) { // In the isActive() functions it is already assured that the filters are // only active on allowed objects // For the case the clip filter is set by Python code, we check that the input // is a post object and issue an error if not. if (Gui::Selection().getSelection().size() > 1) { QMessageBox::warning( Gui::getMainWindow(), qApp->translate("setupFilter", "Error: A filter can only be applied to a single object."), qApp->translate("setupFilter", "The filter could not be set up.") ); return; } auto selObject = Gui::Selection().getSelection()[0].pObject; // issue error if no filter object if (!(selObject->isDerivedFrom())) { QMessageBox::warning( Gui::getMainWindow(), qApp->translate("setupFilter", "Error: no post processing object selected."), qApp->translate("setupFilter", "The filter could not be set up.") ); return; } std::string FeatName = cmd->getUniqueObjectName(Name.c_str()); // at first we must determine the pipeline of the selection object // (which can be a pipeline itself) App::DocumentObject* pipeline = nullptr; if (selObject->hasExtension(Fem::FemPostGroupExtension::getExtensionClassTypeId())) { pipeline = selObject; } else { pipeline = Fem::FemPostGroupExtension::getGroupOfObject(selObject); if (!pipeline || !pipeline->isDerivedFrom()) { QMessageBox::warning( Gui::getMainWindow(), qApp->translate("setupFilter", "Error: Object not in a post processing group"), qApp->translate( "setupFilter", "The filter could not be set up: Object not in a post processing group." ) ); return; } } // create the object and add it to the pipeline cmd->openCommand(QT_TRANSLATE_NOOP("Command", "Create filter")); cmd->doCommand( Gui::Command::Doc, "App.activeDocument().addObject('Fem::FemPost%sFilter','%s')", Name.c_str(), FeatName.c_str() ); // add it as subobject to the pipeline cmd->doCommand( Gui::Command::Doc, "App.ActiveDocument.%s.addObject(App.ActiveDocument.%s)", pipeline->getNameInDocument(), FeatName.c_str() ); // set display to assure the user sees the new object cmd->doCommand( Gui::Command::Doc, "App.activeDocument().ActiveObject.ViewObject.DisplayMode = \"Surface\"" ); // Set SelectionStyle to BoundBox because the idea is that the user gets the useful result // from the colors. The default would be to highlight the shape but then the colors are changed // by every highlighting leading to confusions for the user. cmd->doCommand( Gui::Command::Doc, "App.activeDocument().ActiveObject.ViewObject.SelectionStyle = \"BoundBox\"" ); auto objFilter = App::GetApplication().getActiveDocument()->getActiveObject(); auto femFilter = static_cast(objFilter); // TODO: FIX /* auto selObjectView = static_cast( Gui::Application::Instance->getViewProvider(selObject)); cmd->doCommand(Gui::Command::Doc, "App.activeDocument().ActiveObject.ViewObject.Field = \"%s\"", selObjectView->Field.getValueAsString()); cmd->doCommand(Gui::Command::Doc, "App.activeDocument().ActiveObject.ViewObject.VectorMode = \"%s\"", selObjectView->VectorMode.getValueAsString()); */ // hide selected filter if (!femFilter->isDerivedFrom() && !femFilter->isDerivedFrom()) { cmd->doCommand( Gui::Command::Doc, "App.activeDocument().%s.ViewObject.Visibility = False", selObject->getNameInDocument() ); } cmd->updateActive(); // open the dialog to edit the filter cmd->doCommand(Gui::Command::Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } std::string Plot() { auto xAxisLabel = QCoreApplication::translate( "CmdFemPostLinearizedStressesFilter", "Thickness [mm]", "Plot X-Axis Label" ) .toStdString(); auto yAxisLabel = QCoreApplication::translate( "CmdFemPostLinearizedStressesFilter", "Stress [MPa]", "Plot Y-Axis Label" ) .toStdString(); auto titleLabel = QCoreApplication::translate( "CmdFemPostLinearizedStressesFilter", "Linearized Stresses", "Plot title" ) .toStdString(); auto legendEntryA = QCoreApplication::translate( "CmdFemPostLinearizedStressesFilter", "Membrane", "Plot legend item label" ) .toStdString(); auto legendEntryB = QCoreApplication::translate( "CmdFemPostLinearizedStressesFilter", "Membrane and Bending", "Plot legend item label" ) .toStdString(); auto legendEntryC = QCoreApplication::translate( "CmdFemPostLinearizedStressesFilter", "Total", "Plot legend item label" ) .toStdString(); std::ostringstream oss; oss << "t=t_coords[len(t_coords)-1]\n\ for i in range(len(t_coords)):\n\ dum = t_coords[i]\n\ t_coords[i] = dum - t_coords[len(t_coords)-1]*0.5\n\ m = 0\n\ for i in range(len(sValues)-1):\n\ m = m +(t_coords[i+1] - t_coords[i])*(sValues[i+1]+sValues[i])\n\ m = (1/t)*0.5*m\n\ membrane = []\n\ for i in range(len(sValues)):\n\ membrane.append(m)\n\ b = 0\n\ for i in range(len(sValues)-1):\n\ d = (t_coords[i+1] - t_coords[i])\n\ b = b + d*(-3/t**2)*(sValues[i+1]*t_coords[i+1] + sValues[i]*t_coords[i])\n\ b2 = -b\n\ bending =[]\n\ for i in range(len(t_coords)):\n\ func = ((b2-b)/t)*t_coords[i]\n\ bending.append(func)\n\ peak = []\n\ mb = []\n\ for i in range(len(sValues)):\n\ peak.append(sValues[i])\n\ mb.append(bending[i] + membrane[0])\n\ import FreeCAD\n\ from PySide import QtCore\n\ import numpy as np\n\ from matplotlib import pyplot as plt\n\ plt.figure(\"" << titleLabel << "\")\n\ plt.plot(t_coords, membrane, \"k--\")\n\ plt.plot(t_coords, mb, \"b*-\")\n\ plt.plot(t_coords, peak, \"r-x\")\n\ plt.annotate(str(round(membrane[0],2)), xy=(t_coords[0], membrane[0]), xytext=(t_coords[0], membrane[0]))\n\ plt.annotate(str(round(mb[0],2)), xy=(t_coords[0], mb[0]), xytext=(t_coords[0], mb[0]))\n\ plt.annotate(str(round(mb[len(t_coords)-1],2)), xy=(t_coords[len(t_coords)-1], mb[len(t_coords)-1]), xytext=(t_coords[len(t_coords)-1], mb[len(t_coords)-1]))\n\ plt.annotate(str(round(peak[0],2)), xy=(t_coords[0], peak[0]), xytext=(t_coords[0], peak[0]))\n\ plt.annotate(str(round(peak[len(t_coords)-1],2)), xy=(t_coords[len(t_coords)-1], peak[len(t_coords)-1]), xytext=(t_coords[len(t_coords)-1], peak[len(t_coords)-1]))\n\ FreeCAD.Console.PrintError('membrane stress = ')\n\ FreeCAD.Console.PrintError([str(round(membrane[0],2))])\n\ FreeCAD.Console.PrintError('membrane + bending min = ')\n\ FreeCAD.Console.PrintError([str(round(mb[0],2))])\n\ FreeCAD.Console.PrintError('membrane + bending max = ')\n\ FreeCAD.Console.PrintError([str(round(mb[len(t_coords)-1],2))])\n\ FreeCAD.Console.PrintError('Total stress min = ')\n\ FreeCAD.Console.PrintError([str(round(peak[0],2))])\n\ FreeCAD.Console.PrintError('Total stress max = ')\n\ FreeCAD.Console.PrintError([str(round(peak[len(t_coords)-1],2))])\n\ plt.ioff()\n\ plt.legend([\"" << legendEntryA << "\", \"" << legendEntryB << "\", \"" << legendEntryC << "\"], loc = \"best\")\n\ plt.xlabel(\"" << xAxisLabel << "\")\n\ plt.ylabel(\"" << yAxisLabel << "\")\n\ plt.title(\"" << titleLabel << "\")\n\ plt.grid()\n\ fig_manager = plt.get_current_fig_manager()\n\ fig_manager.window.setParent(FreeCADGui.getMainWindow())\n\ fig_manager.window.setWindowFlag(QtCore.Qt.Tool)\n\ plt.show()\n"; return oss.str(); } //================================================================================================ DEF_STD_CMD_A(CmdFemPostClipFilter) CmdFemPostClipFilter::CmdFemPostClipFilter() : Command("FEM_PostFilterClipRegion") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Region Clip Filter"); sToolTipText = QT_TR_NOOP( "Defines a clip filter which uses functions to define the clipped region" ); sWhatsThis = "FEM_PostFilterClipRegion"; sStatusTip = sToolTipText; sPixmap = "FEM_PostFilterClipRegion"; } void CmdFemPostClipFilter::activated(int) { setupFilter(this, "Clip"); } bool CmdFemPostClipFilter::isActive() { // only allow one object auto selection = getSelection().getSelection(); if (selection.size() > 1) { return false; } // only activate if a post object is selected for (auto obj : selection) { if (obj.pObject->isDerivedFrom()) { return true; } } return false; } //================================================================================================ DEF_STD_CMD_A(CmdFemPostCutFilter) CmdFemPostCutFilter::CmdFemPostCutFilter() : Command("FEM_PostFilterCutFunction") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Function Cut Filter"); sToolTipText = QT_TR_NOOP("Cuts the data along an implicit function"); sWhatsThis = "FEM_PostFilterCutFunction"; sStatusTip = sToolTipText; sPixmap = "FEM_PostFilterCutFunction"; } void CmdFemPostCutFilter::activated(int) { setupFilter(this, "Cut"); } bool CmdFemPostCutFilter::isActive() { // only allow one object auto selection = getSelection().getSelection(); if (selection.size() > 1) { return false; } // only activate if a post object is selected for (auto obj : selection) { if (obj.pObject->isDerivedFrom()) { return true; } } return false; } //================================================================================================ DEF_STD_CMD_A(CmdFemPostDataAlongLineFilter) CmdFemPostDataAlongLineFilter::CmdFemPostDataAlongLineFilter() : Command("FEM_PostFilterDataAlongLine") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Line Clip Filter"); sToolTipText = QT_TR_NOOP("Defines a clip filter which clips a field along a line"); sWhatsThis = "FEM_PostFilterDataAlongLine"; sStatusTip = sToolTipText; sPixmap = "FEM_PostFilterDataAlongLine"; } void CmdFemPostDataAlongLineFilter::activated(int) { setupFilter(this, "DataAlongLine"); } bool CmdFemPostDataAlongLineFilter::isActive() { // only allow one object auto selection = getSelection().getSelection(); if (selection.size() > 1) { return false; } // only activate if a post object is selected for (auto obj : selection) { if (obj.pObject->isDerivedFrom()) { return true; } } return false; } //================================================================================================ DEF_STD_CMD_A(CmdFemPostDataAtPointFilter) CmdFemPostDataAtPointFilter::CmdFemPostDataAtPointFilter() : Command("FEM_PostFilterDataAtPoint") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Data at Point Clip Filter"); sToolTipText = QT_TR_NOOP("Defines a clip filter which clips a field data at point"); sWhatsThis = "FEM_PostFilterDataAtPoint"; sStatusTip = sToolTipText; sPixmap = "FEM_PostFilterDataAtPoint"; } void CmdFemPostDataAtPointFilter::activated(int) { setupFilter(this, "DataAtPoint"); } bool CmdFemPostDataAtPointFilter::isActive() { // only allow one object auto selection = getSelection().getSelection(); if (selection.size() > 1) { return false; } // only activate if a post object is selected for (auto obj : selection) { if (obj.pObject->isDerivedFrom()) { return true; } } return false; } //================================================================================================ DEF_STD_CMD_A(CmdFemPostLinearizedStressesFilter) CmdFemPostLinearizedStressesFilter::CmdFemPostLinearizedStressesFilter() : Command("FEM_PostFilterLinearizedStresses") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Stress Linearization Plot"); sToolTipText = QT_TR_NOOP("Defines a stress linearization plot"); sWhatsThis = "FEM_PostFilterLinearizedStresses"; sStatusTip = sToolTipText; sPixmap = "FEM_PostFilterLinearizedStresses"; } void CmdFemPostLinearizedStressesFilter::activated(int) { Gui::SelectionFilter DataAlongLineFilter("SELECT Fem::FemPostDataAlongLineFilter COUNT 1"); if (DataAlongLineFilter.match()) { Fem::FemPostDataAlongLineFilter* DataAlongLine = static_cast( DataAlongLineFilter.Result[0][0].getObject() ); std::string FieldName = DataAlongLine->PlotData.getValue(); if ( (FieldName == "Tresca Stress") || (FieldName == "von Mises Stress") || (FieldName == "Major Principal Stress") || (FieldName == "Intermediate Principal Stress") || (FieldName == "Minor Principal Stress") || (FieldName == "Stress xx component") || (FieldName == "Stress xy component") || (FieldName == "Stress xz component") || (FieldName == "Stress yy component") || (FieldName == "Stress yz component") || (FieldName == "Stress zz component") // names need to match with names in FemVTKTools.cpp, this is not failsafe, // but at the moment there is no better way for test on a stress result in vtk pipeline ) { // TODO FIXME only works if the data along the line object has the name DataAlongLine // we should get the selected data along the line object App::DocumentObjectT objT(DataAlongLine); std::string ObjName = objT.getObjectPython(); Gui::doCommandT(Gui::Command::Doc, "t_coords = %s.XAxisData", ObjName); Gui::doCommandT(Gui::Command::Doc, "sValues = %s.YAxisData", ObjName); Gui::doCommandT(Gui::Command::Doc, Plot().c_str()); } else { QMessageBox::warning( Gui::getMainWindow(), qApp->translate("CmdFemPostLinearizedStressesFilter", "Wrong selection"), qApp->translate( "CmdFemPostLinearizedStressesFilter", "Select a clip filter which clips a stress field along a line" ) ); } } else { QMessageBox::warning( Gui::getMainWindow(), qApp->translate("CmdFemPostLinearizedStressesFilter", "Wrong selection"), qApp->translate( "CmdFemPostLinearizedStressesFilter", "Select a clip filter which clips a stress field along a line" ) ); } } bool CmdFemPostLinearizedStressesFilter::isActive() { // only allow one object if (getSelection().getSelection().size() > 1) { return false; } // we purposely allow it also not non-along line filters because we issue an error message that // also explains what the feature is for and how it is set up return hasActiveDocument(); } //================================================================================================ DEF_STD_CMD_A(CmdFemPostScalarClipFilter) CmdFemPostScalarClipFilter::CmdFemPostScalarClipFilter() : Command("FEM_PostFilterClipScalar") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Scalar Clip Filter"); sToolTipText = QT_TR_NOOP("Defines a clip filter which clips a field with a scalar value"); sWhatsThis = "FEM_PostFilterClipScalar"; sStatusTip = sToolTipText; sPixmap = "FEM_PostFilterClipScalar"; } void CmdFemPostScalarClipFilter::activated(int) { setupFilter(this, "ScalarClip"); } bool CmdFemPostScalarClipFilter::isActive() { // only allow one object auto selection = getSelection().getSelection(); if (selection.size() > 1) { return false; } // only activate if a post object is selected for (auto obj : selection) { if (obj.pObject->isDerivedFrom()) { return true; } } return false; } //================================================================================================ DEF_STD_CMD_A(CmdFemPostWarpVectorFilter) CmdFemPostWarpVectorFilter::CmdFemPostWarpVectorFilter() : Command("FEM_PostFilterWarp") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Warp Filter"); sToolTipText = QT_TR_NOOP("Warps the geometry along a vector field by a certain factor"); sWhatsThis = "FEM_PostFilterWarp"; sStatusTip = sToolTipText; sPixmap = "FEM_PostFilterWarp"; } void CmdFemPostWarpVectorFilter::activated(int) { setupFilter(this, "WarpVector"); } bool CmdFemPostWarpVectorFilter::isActive() { // only allow one object auto selection = getSelection().getSelection(); if (selection.size() > 1) { return false; } // only activate if a post object is selected for (auto obj : selection) { if (obj.pObject->isDerivedFrom()) { return true; } } return false; } //================================================================================================ DEF_STD_CMD_A(CmdFemPostContoursFilter) CmdFemPostContoursFilter::CmdFemPostContoursFilter() : Command("FEM_PostFilterContours") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Contours Filter"); sToolTipText = QT_TR_NOOP("Define/create a contours filter which displays iso contours"); sWhatsThis = "FEM_PostFilterContours"; sStatusTip = sToolTipText; sPixmap = "FEM_PostFilterContours"; } void CmdFemPostContoursFilter::activated(int) { setupFilter(this, "Contours"); } bool CmdFemPostContoursFilter::isActive() { // only allow one object auto selection = getSelection().getSelection(); if (selection.size() > 1) { return false; } // only activate if a post object is selected for (auto obj : selection) { if (obj.pObject->isDerivedFrom()) { return true; } } return false; } //================================================================================================ DEF_STD_CMD_A(CmdFemPostCalculatorFilter) CmdFemPostCalculatorFilter::CmdFemPostCalculatorFilter() : Command("FEM_PostFilterCalculator") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Calculator Filter"); sToolTipText = QT_TR_NOOP("Creates a new field from current data"); sWhatsThis = "FEM_PostFilterCalculator"; sStatusTip = sToolTipText; sPixmap = "FEM_PostFilterCalculator"; } void CmdFemPostCalculatorFilter::activated(int) { setupFilter(this, "Calculator"); } bool CmdFemPostCalculatorFilter::isActive() { // only allow one object auto selection = getSelection().getSelection(); if (selection.size() > 1) { return false; } for (auto obj : selection) { if (obj.pObject->isDerivedFrom()) { return true; } } return false; } //================================================================================================ DEF_STD_CMD_ACL(CmdFemPostFunctions) CmdFemPostFunctions::CmdFemPostFunctions() : Command("FEM_PostCreateFunctions") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Filter Functions"); sToolTipText = QT_TR_NOOP("Functions for use in postprocessing filter"); sWhatsThis = "FEM_PostCreateFunctions"; sStatusTip = sToolTipText; eType = eType | ForEdit; } void CmdFemPostFunctions::activated(int iMsg) { std::string name; if (iMsg == 0) { name = "Plane"; } else if (iMsg == 1) { name = "Sphere"; } else if (iMsg == 2) { name = "Cylinder"; } else if (iMsg == 3) { name = "Box"; } else { return; } // create the object std::vector pipelines = App::GetApplication().getActiveDocument()->getObjectsOfType(); if (!pipelines.empty()) { Fem::FemPostPipeline* pipeline = pipelines.front(); openCommand(QT_TRANSLATE_NOOP("Command", "Create function")); // check if the pipeline has a filter provider and add one if needed Fem::FemPostFunctionProvider* provider = pipeline->getFunctionProvider(); if (!provider) { std::string FuncName = getUniqueObjectName("Functions"); doCommand( Doc, "App.ActiveDocument.addObject('Fem::FemPostFunctionProvider','%s')", FuncName.c_str() ); doCommand( Doc, "App.ActiveDocument.%s.addObject(App.ActiveDocument.%s)", pipeline->getNameInDocument(), FuncName.c_str() ); provider = pipeline->getFunctionProvider(); } // build the object std::string FeatName = getUniqueObjectName(name.c_str()); doCommand( Doc, "App.activeDocument().addObject('Fem::FemPost%sFunction','%s')", name.c_str(), FeatName.c_str() ); doCommand( Doc, "App.ActiveDocument.%s.addObject(App.ActiveDocument.%s)", provider->getNameInDocument(), FeatName.c_str() ); // set the default values, for this get the bounding box vtkBoundingBox box = pipeline->getBoundingBox(); double center[3]; box.GetCenter(center); if (iMsg == 0) { // Plane doCommand( Doc, "App.ActiveDocument.%s.Origin = App.Vector(%f, %f, %f)", FeatName.c_str(), center[0], center[1], center[2] ); doCommand(Doc, "Gui.ActiveDocument.%s.Scale = %f", FeatName.c_str(), box.GetDiagonalLength()); } else if (iMsg == 1) { // Sphere doCommand( Doc, "App.ActiveDocument.%s.Center = App.Vector(%f, %f, %f)", FeatName.c_str(), center[0], center[1] + box.GetLength(1) / 2, center[2] + box.GetLength(2) / 2 ); doCommand( Doc, "App.ActiveDocument.%s.Radius = %f", FeatName.c_str(), box.GetDiagonalLength() / 2 ); } else if (iMsg == 2) { // Cylinder doCommand( Doc, "App.ActiveDocument.%s.Center = App.Vector(%f, %f, %f)", FeatName.c_str(), center[0], center[1] + box.GetLength(1) / 2, center[2] ); doCommand( Doc, "App.ActiveDocument.%s.Radius = %f", FeatName.c_str(), box.GetDiagonalLength() / 3.6 ); // make cylinder a bit higher than the box } else if (iMsg == 3) { // Box doCommand( Doc, "App.ActiveDocument.%s.Center = App.Vector(%f, %f, %f)", FeatName.c_str(), center[0] + box.GetLength(0) / 2, center[1] + box.GetLength(1) / 2, center[2] ); doCommand(Doc, "App.ActiveDocument.%s.Length = %f", FeatName.c_str(), box.GetLength(0)); doCommand(Doc, "App.ActiveDocument.%s.Width = %f", FeatName.c_str(), box.GetLength(1)); doCommand( Doc, "App.ActiveDocument.%s.Height = %f", FeatName.c_str(), // purposely a bit higher to avoid rendering artifacts at the box border 1.1 * box.GetLength(2) ); } this->updateActive(); // most of the times functions are added inside of a filter, make sure this still works if (!Gui::Application::Instance->activeDocument()->getInEdit()) { doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str()); } } else { QMessageBox::warning( Gui::getMainWindow(), qApp->translate("CmdFemPostClipFilter", "Wrong selection"), qApp->translate("CmdFemPostClipFilter", "Select a pipeline.") ); } // Since the default icon is reset when enabling/disabling the command we have // to explicitly set the icon of the used command. Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); assert(iMsg < a.size()); pcAction->setIcon(a[iMsg]->icon()); } Gui::Action* CmdFemPostFunctions::createAction() { Gui::ActionGroup* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow()); pcAction->setDropDownMenu(true); applyCommandData(this->className(), pcAction); QAction* cmd0 = pcAction->addAction(QString()); cmd0->setIcon(Gui::BitmapFactory().iconFromTheme("fem-post-geo-plane")); QAction* cmd1 = pcAction->addAction(QString()); cmd1->setIcon(Gui::BitmapFactory().iconFromTheme("fem-post-geo-sphere")); QAction* cmd2 = pcAction->addAction(QString()); cmd2->setIcon(Gui::BitmapFactory().iconFromTheme("fem-post-geo-cylinder")); QAction* cmd3 = pcAction->addAction(QString()); cmd3->setIcon(Gui::BitmapFactory().iconFromTheme("fem-post-geo-box")); _pcAction = pcAction; languageChange(); pcAction->setIcon(cmd1->icon()); int defaultId = 0; pcAction->setProperty("defaultAction", QVariant(defaultId)); return pcAction; } void CmdFemPostFunctions::languageChange() { Command::languageChange(); if (!_pcAction) { return; } Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); QAction* cmd = a[0]; cmd->setText(QApplication::translate("CmdFemPostFunctions", "Plane")); cmd->setToolTip( QApplication::translate( "FEM_PostCreateFunctions", "Create a plane function, defined by its origin and normal" ) ); cmd->setStatusTip(cmd->toolTip()); cmd = a[1]; cmd->setText(QApplication::translate("CmdFemPostFunctions", "Sphere")); cmd->setToolTip( QApplication::translate( "FEM_PostCreateFunctions", "Create a sphere function, defined by its center and radius" ) ); cmd->setStatusTip(cmd->toolTip()); cmd = a[2]; cmd->setText(QApplication::translate("CmdFemPostFunctions", "Cylinder")); cmd->setToolTip( QApplication::translate( "FEM_PostCreateFunctions", "Create a cylinder function, defined by its center, axis and radius" ) ); cmd->setStatusTip(cmd->toolTip()); cmd = a[3]; cmd->setText(QApplication::translate("CmdFemPostFunctions", "Box")); cmd->setToolTip( QApplication::translate( "FEM_PostCreateFunctions", "Create a box function, defined by its center, length, width and height" ) ); cmd->setStatusTip(cmd->toolTip()); } bool CmdFemPostFunctions::isActive() { if (getActiveGuiDocument()) { return true; } else { return false; } } //================================================================================================ DEF_STD_CMD_AC(CmdFemPostApllyChanges) CmdFemPostApllyChanges::CmdFemPostApllyChanges() : Command("FEM_PostApplyChanges") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Apply Changes to Pipeline"); sToolTipText = QT_TR_NOOP("Applies changes to parameters directly and not on recompute only"); sWhatsThis = "FEM_PostApplyChanges"; sStatusTip = sToolTipText; sPixmap = "view-refresh"; eType = eType | ForEdit; } void CmdFemPostApllyChanges::activated(int iMsg) { FemGui::FemSettings().setPostAutoRecompute(iMsg == 1); } bool CmdFemPostApllyChanges::isActive() { if (getActiveGuiDocument()) { return true; } else { return false; } } Gui::Action* CmdFemPostApllyChanges::createAction() { Gui::Action* pcAction = Command::createAction(); pcAction->setCheckable(true); pcAction->setChecked(FemGui::FemSettings().getPostAutoRecompute()); return pcAction; } //================================================================================================ DEF_STD_CMD_A(CmdFemPostPipelineFromResult) CmdFemPostPipelineFromResult::CmdFemPostPipelineFromResult() : Command("FEM_PostPipelineFromResult") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Post Pipeline From Result"); sToolTipText = QT_TR_NOOP("Creates a post processing pipeline from a result object"); sWhatsThis = "FEM_PostPipelineFromResult"; sStatusTip = sToolTipText; sPixmap = "FEM_PostPipelineFromResult"; } void CmdFemPostPipelineFromResult::activated(int) { /* Gui::SelectionFilter ResultFilter("SELECT Fem::FemResultObject COUNT 1"); if (ResultFilter.match()) { Base::Console().message("Debug: `SELECT Fem::FemResultObject COUNT 1` has matched obj"); Fem::FemResultObject* result = static_cast(ResultFilter.Result[0][0].getObject()); //static_cast failed here Base::Console().message("Debug: FemResultObject pointer = %p", result ); */ // go through active document change some Visibility Gui::Document* doc = Gui::Application::Instance->activeDocument(); App::Document* app = doc->getDocument(); const std::vector obj = app->getObjectsOfType( App::DocumentObject::getClassTypeId() ); for (auto it : obj) { doCommand( Gui, "Gui.getDocument(\"%s\").getObject(\"%s\").Visibility=False", app->getName(), it->getNameInDocument() ); } // we need single result object to attach the pipeline to std::vector results = getSelection().getObjectsOfType(); if (results.size() == 1) { // the pipeline should be inside the analysis container if possible bool foundAnalysis = false; Fem::FemAnalysis* pcAnalysis; std::string FeatName = getUniqueObjectName("ResultPipeline"); auto parents = results[0]->getInList(); if (!parents.empty()) { for (auto parentObject : parents) { if (parentObject->getTypeId() == Base::Type::fromName("Fem::FemAnalysis")) { pcAnalysis = static_cast(parentObject); foundAnalysis = true; } } } // create the pipeline object openCommand(QT_TRANSLATE_NOOP("Command", "Create pipeline from result")); if (foundAnalysis) { pcAnalysis->addObject(FeatName.c_str()); } else { doCommand( Doc, "App.activeDocument().addObject('Fem::FemPostPipeline','%s')", FeatName.c_str() ); } // load the contents of the result object to the pipeline doCommand( Doc, "App.activeDocument().ActiveObject.load(" "App.activeDocument().getObject(\"%s\"))", results[0]->getNameInDocument() ); // set display to assure the user sees the new object doCommand(Doc, "App.activeDocument().ActiveObject.ViewObject.DisplayMode = \"Surface\""); // Set SelectionStyle to BoundBox because the idea is that the user gets the useful result // from the colors. The default would be to highlight the shape but then the colors are // changed by every highlighting leading to confusions for the user. doCommand(Doc, "App.activeDocument().ActiveObject.ViewObject.SelectionStyle = \"BoundBox\""); commitCommand(); this->updateActive(); } else { QMessageBox::warning( Gui::getMainWindow(), qApp->translate("CmdFemPostPipelineFromResult", "Wrong selection type"), qApp->translate("CmdFemPostPipelineFromResult", "Select a result object.") ); } } bool CmdFemPostPipelineFromResult::isActive() { // only activate if a result object is selected from which the pipeline can be loaded std::vector results = getSelection().getObjectsOfType(); return (results.size() == 1) ? true : false; } //================================================================================================ DEF_STD_CMD_A(CmdFemPostBranchFilter) CmdFemPostBranchFilter::CmdFemPostBranchFilter() : Command("FEM_PostBranchFilter") { sAppModule = "Fem"; sGroup = QT_TR_NOOP("Fem"); sMenuText = QT_TR_NOOP("Pipeline Branch"); sToolTipText = QT_TR_NOOP("Branches the pipeline into a new path"); sWhatsThis = "FEM_PostBranchFilter"; sStatusTip = sToolTipText; sPixmap = "FEM_PostBranchFilter"; } void CmdFemPostBranchFilter::activated(int) { setupFilter(this, "Branch"); } bool CmdFemPostBranchFilter::isActive() { // only allow one object auto selection = getSelection().getSelection(); if (selection.size() > 1) { return false; } // only activate if a post object is selected for (auto obj : selection) { if (obj.pObject->isDerivedFrom()) { return true; } } return false; } #endif //================================================================================================ //================================================================================================ void CreateFemCommands() { Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); // part, analysis, solver // rcCmdMgr.addCommand(new CmdFemAddPart()); // not implemented as GUI menu or click icon // rcCmdMgr.addCommand(new CmdFemCreateAnalysis()); // Analysis is created in python // rcCmdMgr.addCommand(new CmdFemCreateSolver()); // Solver will be extended and created // in python // constraints rcCmdMgr.addCommand(new CmdFemConstraintBearing()); rcCmdMgr.addCommand(new CmdFemConstraintContact()); rcCmdMgr.addCommand(new CmdFemConstraintDisplacement()); rcCmdMgr.addCommand(new CmdFemConstraintFixed()); rcCmdMgr.addCommand(new CmdFemConstraintRigidBody()); rcCmdMgr.addCommand(new CmdFemConstraintFluidBoundary()); rcCmdMgr.addCommand(new CmdFemConstraintForce()); rcCmdMgr.addCommand(new CmdFemConstraintGear()); rcCmdMgr.addCommand(new CmdFemConstraintHeatflux()); rcCmdMgr.addCommand(new CmdFemConstraintInitialTemperature()); rcCmdMgr.addCommand(new CmdFemConstraintPlaneRotation()); rcCmdMgr.addCommand(new CmdFemConstraintPressure()); rcCmdMgr.addCommand(new CmdFemConstraintPulley()); rcCmdMgr.addCommand(new CmdFemConstraintTemperature()); rcCmdMgr.addCommand(new CmdFemConstraintTransform()); rcCmdMgr.addCommand(new CmdFemConstraintSpring()); rcCmdMgr.addCommand(new CmdFemCompEmConstraints()); rcCmdMgr.addCommand(new CmdFemCompMechEquations()); // mesh rcCmdMgr.addCommand(new CmdFemCreateNodesSet()); rcCmdMgr.addCommand(new CmdFemDefineNodesSet()); rcCmdMgr.addCommand(new CmdFemCreateElementsSet()); rcCmdMgr.addCommand(new CmdFemDefineElementsSet()); // equations rcCmdMgr.addCommand(new CmdFemCompEmEquations()); // vtk post processing #ifdef FC_USE_VTK rcCmdMgr.addCommand(new CmdFemPostApllyChanges); rcCmdMgr.addCommand(new CmdFemPostCalculatorFilter); rcCmdMgr.addCommand(new CmdFemPostClipFilter); rcCmdMgr.addCommand(new CmdFemPostContoursFilter); rcCmdMgr.addCommand(new CmdFemPostCutFilter); rcCmdMgr.addCommand(new CmdFemPostDataAlongLineFilter); rcCmdMgr.addCommand(new CmdFemPostDataAtPointFilter); rcCmdMgr.addCommand(new CmdFemPostLinearizedStressesFilter); rcCmdMgr.addCommand(new CmdFemPostFunctions); rcCmdMgr.addCommand(new CmdFemPostPipelineFromResult); rcCmdMgr.addCommand(new CmdFemPostBranchFilter); rcCmdMgr.addCommand(new CmdFemPostScalarClipFilter); rcCmdMgr.addCommand(new CmdFemPostWarpVectorFilter); #endif }