diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index 97f38e44d..df7c93b30 100644 --- a/src/Mod/Fem/App/AppFem.cpp +++ b/src/Mod/Fem/App/AppFem.cpp @@ -50,6 +50,7 @@ #include "FemConstraintPressure.h" #include "FemConstraintGear.h" #include "FemConstraintPulley.h" +#include "FemConstraintDisplacement.h" #include "FemResultObject.h" #include "FemSolverObject.h" @@ -138,6 +139,7 @@ PyMODINIT_FUNC initFem() Fem::ConstraintPressure ::init(); Fem::ConstraintGear ::init(); Fem::ConstraintPulley ::init(); + Fem::ConstraintDisplacement ::init(); Fem::FemResultObject ::init(); Fem::FemResultObjectPython ::init(); diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index 956d9d4e8..1ef8c6f23 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -110,6 +110,7 @@ SET(FemScripts_SRCS MechanicalMaterial.py SelectionObserverFem.py TestFem.py + ccxInpWriterFemConstraintDisplacement.py TaskPanelFemBeamSection.ui TaskPanelFemShellThickness.ui @@ -184,6 +185,8 @@ SET(FemConstraints_SRCS FemConstraintGear.h FemConstraintPulley.cpp FemConstraintPulley.h + FemConstraintDisplacement.h + FemConstraintDisplacement.cpp ) SOURCE_GROUP("Constraints" FILES ${FemConstraints_SRCS}) diff --git a/src/Mod/Fem/App/FemConstraint.cpp b/src/Mod/Fem/App/FemConstraint.cpp index e6eb67e16..6c4909f36 100644 --- a/src/Mod/Fem/App/FemConstraint.cpp +++ b/src/Mod/Fem/App/FemConstraint.cpp @@ -173,9 +173,9 @@ const bool Constraint::getPoints(std::vector &points, std::vecto normals.push_back(NormalDirection.getValue()); //OvG: Scale by whole object mass in case of a vertex GProp_GProps props; - BRepGProp::VolumeProperties(toposhape._Shape, props); - double lx = props.Mass(); - *scale = this->calcDrawScaleFactor(sqrt(lx)); //OvG: setup draw scale for constraint + BRepGProp::VolumeProperties(toposhape._Shape, props); + double lx = props.Mass(); + *scale = this->calcDrawScaleFactor(sqrt(lx)*0.5); //OvG: setup draw scale for constraint } else if (sh.ShapeType() == TopAbs_EDGE) { BRepAdaptor_Curve curve(TopoDS::Edge(sh)); double fp = curve.FirstParameter(); @@ -185,7 +185,7 @@ const bool Constraint::getPoints(std::vector &points, std::vecto 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 >= 100) //OvG: Increase 10 units distance proportionately to l for larger objects. + if (l >= 30) //OvG: Increase 10 units distance proportionately to l for larger objects. { *scale = this->calcDrawScaleFactor(l); //OvG: setup draw scale for constraint steps = (int)round(l / (10*( *scale))); @@ -232,7 +232,7 @@ const bool Constraint::getPoints(std::vector &points, std::vecto isoc.Load(GeomAbs_IsoV, ulp); double lu = (l + GCPnts_AbscissaPoint::Length(isoc, Precision::Confusion()))/2.0; int stepsv; - if (lv >= 100) //OvG: Increase 10 units distance proportionately to lv for larger objects. + if (lv >= 30) //OvG: Increase 10 units distance proportionately to lv for larger objects. { *scale = this->calcDrawScaleFactor(lv,lu); //OvG: setup draw scale for constraint stepsv = (int)round(lv / (10*( *scale))); @@ -250,7 +250,7 @@ const bool Constraint::getPoints(std::vector &points, std::vecto } stepsv = stepsv>CONSTRAINTSTEPLIMIT?CONSTRAINTSTEPLIMIT:stepsv; //OvG: Place upper limit on number of steps int stepsu; - if (lu >= 100) //OvG: Increase 10 units distance proportionately to lu for larger objects. + if (lu >= 30) //OvG: Increase 10 units distance proportionately to lu for larger objects. { *scale = this->calcDrawScaleFactor(lv,lu); //OvG: setup draw scale for constraint stepsu = (int)round(lu / (10*( *scale))); diff --git a/src/Mod/Fem/App/FemConstraintDisplacement.cpp b/src/Mod/Fem/App/FemConstraintDisplacement.cpp new file mode 100644 index 000000000..806e5ee31 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintDisplacement.cpp @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Michael Hindley * + * Ruan Olwagen * + * Oswald van Ginkel * + * Based on Force constraint by Jan Rheinländer * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "FemConstraintDisplacement.h" + +using namespace Fem; + +PROPERTY_SOURCE(Fem::ConstraintDisplacement, Fem::Constraint); + +ConstraintDisplacement::ConstraintDisplacement() +{ + ADD_PROPERTY(xDisplacement,(0.0)); + ADD_PROPERTY(yDisplacement,(0.0)); + ADD_PROPERTY(zDisplacement,(0.0)); + ADD_PROPERTY(xRotation,(0.0)); + ADD_PROPERTY(yRotation,(0.0)); + ADD_PROPERTY(zRotation,(0.0)); + ADD_PROPERTY(xFree,(1)); + ADD_PROPERTY(yFree,(1)); + ADD_PROPERTY(zFree,(1)); + ADD_PROPERTY(xFix,(0)); + ADD_PROPERTY(yFix,(0)); + ADD_PROPERTY(zFix,(0)); + ADD_PROPERTY(rotxFree,(1)); + ADD_PROPERTY(rotyFree,(1)); + ADD_PROPERTY(rotzFree,(1)); + ADD_PROPERTY(rotxFix,(0)); + ADD_PROPERTY(rotyFix,(0)); + ADD_PROPERTY(rotzFix,(0)); + + ADD_PROPERTY_TYPE(Points,(Base::Vector3d()),"ConstraintFixed",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Points where symbols are drawn"); + ADD_PROPERTY_TYPE(Normals,(Base::Vector3d()),"ConstraintFixed",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Normals where symbols are drawn"); + Points.setValues(std::vector()); + Normals.setValues(std::vector()); +} + +App::DocumentObjectExecReturn *ConstraintDisplacement::execute(void) +{ + return Constraint::execute(); +} + +const char* ConstraintDisplacement::getViewProviderName(void) const +{ + return "FemGui::ViewProviderFemConstraintDisplacement"; +} + +void ConstraintDisplacement::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; + int scale = 1; //OvG: Enforce use of scale + if (getPoints(points, normals, &scale)) { + Points.setValues(points); + Normals.setValues(normals); + Scale.setValue(scale); //OvG: Scale + Points.touch(); // This triggers ViewProvider::updateData() + } + } +} diff --git a/src/Mod/Fem/App/FemConstraintDisplacement.h b/src/Mod/Fem/App/FemConstraintDisplacement.h new file mode 100644 index 000000000..d2670411d --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintDisplacement.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Michael Hindley * + * Ruan Olwagen * + * Oswald van Ginkel * + * Based on Force constraint by Jan Rheinländer * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef FEM_CONSTRAINTDISPLACEMENT_H +#define FEM_CONSTRAINTDISPLACEMENT_H + +#include "FemConstraint.h" + +namespace Fem +{ + +class AppFemExport ConstraintDisplacement : public Fem::Constraint +{ + PROPERTY_HEADER(Fem::ConstraintDisplacement); + +public: + /// Constructor + ConstraintDisplacement(void); + + // Read-only (calculated values). These trigger changes in the ViewProvider + App::PropertyVectorList Points; + App::PropertyVectorList Normals; + + //Displacement parameters + App::PropertyFloat xDisplacement; + App::PropertyFloat yDisplacement; + App::PropertyFloat zDisplacement; + App::PropertyFloat xRotation; + App::PropertyFloat yRotation; + App::PropertyFloat zRotation; + App::PropertyBool xFree; + App::PropertyBool yFree; + App::PropertyBool zFree; + App::PropertyBool xFix; + App::PropertyBool yFix; + App::PropertyBool zFix; + App::PropertyBool rotxFree; + App::PropertyBool rotyFree; + App::PropertyBool rotzFree; + App::PropertyBool rotxFix; + App::PropertyBool rotyFix; + App::PropertyBool rotzFix; + //App::PropertyBool element; + + /// recalculate the object + virtual App::DocumentObjectExecReturn *execute(void); + + /// returns the type name of the ViewProvider + const char* getViewProviderName(void) const; + +protected: + virtual void onChanged(const App::Property* prop); + +}; + +} //namespace Fem + + +#endif // FEM_CONSTRAINTDISPLACEMENT_H diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index b2fedbe7a..59b7a89f2 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -11,6 +11,8 @@ INSTALL( Init.py InitGui.py + ccxInpWriterFemConstraintDisplacement.py + convert2TetGen.py SelectionObserverFem.py @@ -28,6 +30,7 @@ INSTALL( _CommandMechanicalShowResult.py _TaskPanelResultControl.py + TaskPanelShowDisplacement.ui _FemAnalysis.py diff --git a/src/Mod/Fem/FemCommands.py b/src/Mod/Fem/FemCommands.py index 0ff8f06e0..c9bfb2508 100644 --- a/src/Mod/Fem/FemCommands.py +++ b/src/Mod/Fem/FemCommands.py @@ -97,3 +97,27 @@ class FemCommands(object): return True else: return False + + def hide_parts_constraints_show_meshes(self): + if FreeCAD.GuiUp: + for acnstrmesh in FreeCAD.activeDocument().Objects: + if "Constraint" in acnstrmesh.TypeId: + acnstrmesh.ViewObject.Visibility = False + if "Mesh" in acnstrmesh.TypeId: + aparttoshow = acnstrmesh.Name.replace("_Mesh","") + for apart in FreeCAD.activeDocument().Objects: + if aparttoshow == apart.Name: + apart.ViewObject.Visibility = False + acnstrmesh.ViewObject.Visibility = True #OvG: Hide constraints and parts and show meshes + + def hide_meshes_show_parts_constraints(self): + if FreeCAD.GuiUp: + for acnstrmesh in FreeCAD.activeDocument().Objects: + if "Constraint" in acnstrmesh.TypeId: + acnstrmesh.ViewObject.Visibility = True + if "Mesh" in acnstrmesh.TypeId: + aparttoshow = acnstrmesh.Name.replace("_Mesh","") + for apart in FreeCAD.activeDocument().Objects: + if aparttoshow == apart.Name: + apart.ViewObject.Visibility = True + acnstrmesh.ViewObject.Visibility = False #OvG: Hide meshes and show constraints and meshed part e.g. on purging results diff --git a/src/Mod/Fem/FemTools.py b/src/Mod/Fem/FemTools.py index ed642a37b..46782bced 100644 --- a/src/Mod/Fem/FemTools.py +++ b/src/Mod/Fem/FemTools.py @@ -175,13 +175,17 @@ class FemTools(QtCore.QRunnable, QtCore.QObject): # Individual constraints are "Fem::ConstraintPressure" type self.pressure_constraints = [] ## @var beam_sections - # set of beam sections from the analyis. Updated with update_objects + # set of beam sections from the analysis. Updated with update_objects # Individual beam sections are Proxy.Type "FemBeamSection" self.beam_sections = [] ## @var shell_thicknesses - # set of shell thicknesses from the analyis. Updated with update_objects + # set of shell thicknesses from the analysis. Updated with update_objects # Individual shell thicknesses are Proxy.Type "FemShellThickness" self.shell_thicknesses = [] + ## @var displacement_constraints + # set of displacements for the analysis. Updated with update_objects + # Individual displacement_constraints are Proxy.Type "FemConstraintDisplacement" + self.displacement_constraints = [] for m in self.analysis.Member: if m.isDerivedFrom("Fem::FemSolverObjectPython"): @@ -210,6 +214,10 @@ class FemTools(QtCore.QRunnable, QtCore.QObject): PressureObjectDict = {} PressureObjectDict['Object'] = m self.pressure_constraints.append(PressureObjectDict) + elif m.isDerivedFrom("Fem::ConstraintDisplacement"): #OvG: Replacement reference to C++ implementation of Displacement Constraint + displacement_constraint_dict = {} + displacement_constraint_dict['Object'] = m + self.displacement_constraints.append(displacement_constraint_dict) elif hasattr(m, "Proxy") and m.Proxy.Type == "FemBeamSection": beam_section_dict = {} beam_section_dict['Object'] = m @@ -240,7 +248,7 @@ class FemTools(QtCore.QRunnable, QtCore.QObject): if has_no_references is True: message += "More than one Material has empty References list (Only one empty References list is allowed!).\n" has_no_references = True - if not self.fixed_constraints: + if not (self.fixed_constraints): message += "No fixed-constraint nodes defined in the Analysis\n" if self.analysis_type == "static": if not (self.force_constraints or self.pressure_constraints): @@ -269,6 +277,7 @@ class FemTools(QtCore.QRunnable, QtCore.QObject): inp_writer = iw.inp_writer(self.analysis, self.mesh, self.materials, self.fixed_constraints, self.force_constraints, self.pressure_constraints, + self.displacement_constraints, #OvG: Stick to naming convention self.beam_sections, self.shell_thicknesses, self.analysis_type, self.eigenmode_parameters, self.working_dir) diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index c7491a03f..90f025a3c 100644 --- a/src/Mod/Fem/Gui/AppFemGui.cpp +++ b/src/Mod/Fem/Gui/AppFemGui.cpp @@ -50,6 +50,7 @@ #include "ViewProviderFemConstraintPressure.h" #include "ViewProviderFemConstraintGear.h" #include "ViewProviderFemConstraintPulley.h" +#include "ViewProviderFemConstraintDisplacement.h" #include "ViewProviderResult.h" #include "Workbench.h" @@ -83,28 +84,29 @@ PyMODINIT_FUNC initFemGui() CreateFemCommands(); // addition objects - FemGui::Workbench ::init(); - FemGui::ViewProviderFemAnalysis ::init(); - FemGui::ViewProviderFemAnalysisPython ::init(); - FemGui::ViewProviderFemMesh ::init(); - FemGui::ViewProviderFemMeshShape ::init(); - FemGui::ViewProviderFemMeshShapeNetgen ::init(); - FemGui::ViewProviderSolver ::init(); - FemGui::ViewProviderSolverPython ::init(); - FemGui::ViewProviderSetNodes ::init(); - FemGui::ViewProviderSetElements ::init(); - FemGui::ViewProviderSetFaces ::init(); - FemGui::ViewProviderSetGeometry ::init(); - FemGui::ViewProviderFemConstraint ::init(); - FemGui::ViewProviderFemConstraintBearing ::init(); - FemGui::ViewProviderFemConstraintFixed ::init(); - FemGui::ViewProviderFemConstraintForce ::init(); - FemGui::ViewProviderFemConstraintPressure ::init(); - FemGui::ViewProviderFemConstraintGear ::init(); - FemGui::ViewProviderFemConstraintPulley ::init(); - FemGui::ViewProviderResult ::init(); - FemGui::ViewProviderResultPython ::init(); - FemGui::PropertyFemMeshItem ::init(); + FemGui::Workbench ::init(); + FemGui::ViewProviderFemAnalysis ::init(); + FemGui::ViewProviderFemAnalysisPython ::init(); + FemGui::ViewProviderFemMesh ::init(); + FemGui::ViewProviderFemMeshShape ::init(); + FemGui::ViewProviderFemMeshShapeNetgen ::init(); + FemGui::ViewProviderSolver ::init(); + FemGui::ViewProviderSolverPython ::init(); + FemGui::ViewProviderSetNodes ::init(); + FemGui::ViewProviderSetElements ::init(); + FemGui::ViewProviderSetFaces ::init(); + FemGui::ViewProviderSetGeometry ::init(); + FemGui::ViewProviderFemConstraint ::init(); + FemGui::ViewProviderFemConstraintBearing ::init(); + FemGui::ViewProviderFemConstraintFixed ::init(); + FemGui::ViewProviderFemConstraintForce ::init(); + FemGui::ViewProviderFemConstraintPressure ::init(); + FemGui::ViewProviderFemConstraintGear ::init(); + FemGui::ViewProviderFemConstraintPulley ::init(); + FemGui::ViewProviderFemConstraintDisplacement ::init(); + FemGui::ViewProviderResult ::init(); + FemGui::ViewProviderResultPython ::init(); + FemGui::PropertyFemMeshItem ::init(); // register preferences pages new Gui::PrefPageProducer ("FEM"); diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 420e3981e..83ec8fda1 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -53,6 +53,7 @@ set(FemGui_MOC_HDRS TaskFemConstraintPressure.h TaskFemConstraintGear.h TaskFemConstraintPulley.h + TaskFemConstraintDisplacement.h TaskTetParameter.h TaskAnalysisInfo.h TaskDriver.h @@ -71,6 +72,7 @@ set(FemGui_UIC_SRCS TaskFemConstraintFixed.ui TaskFemConstraintForce.ui TaskFemConstraintPressure.ui + TaskFemConstraintDisplacement.ui TaskTetParameter.ui TaskAnalysisInfo.ui TaskDriver.ui @@ -101,6 +103,9 @@ SET(FemGui_DLG_SRCS TaskFemConstraintGear.h TaskFemConstraintPulley.cpp TaskFemConstraintPulley.h + TaskFemConstraintDisplacement.ui + TaskFemConstraintDisplacement.cpp + TaskFemConstraintDisplacement.h ) SOURCE_GROUP("Constraint-Dialogs" FILES ${FemGui_DLG_SRCS}) @@ -143,6 +148,8 @@ SET(FemGui_SRCS_ViewProvider ViewProviderFemConstraintGear.h ViewProviderFemConstraintPulley.cpp ViewProviderFemConstraintPulley.h + ViewProviderFemConstraintDisplacement.cpp + ViewProviderFemConstraintDisplacement.h ViewProviderResult.cpp ViewProviderResult.h ) diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 71867b5b3..5c4e2a6b1 100644 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -80,6 +80,18 @@ bool getConstraintPrerequisits(Fem::FemAnalysis **Analysis) } +//OvG: Visibility automation show parts and hide meshes on activation of a constraint +std::string gethideMeshShowPartStr() +{ + return + "for amesh in App.activeDocument().Objects:\n\ + if \"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"; +} //===================================================================================== DEF_STD_CMD_A(CmdFemCreateAnalysis); @@ -155,7 +167,7 @@ CmdFemAddPart::CmdFemAddPart() sToolTipText = QT_TR_NOOP("Add a part to the Analysis"); sWhatsThis = "Fem_FemAddPart"; sStatusTip = sToolTipText; - sPixmap = "fem-add-fem-mesh"; + sPixmap = "fem-add-fem-mesh"; } void CmdFemAddPart::activated(int iMsg) @@ -278,6 +290,9 @@ void CmdFemConstraintBearing::activated(int iMsg) openCommand("Make FEM constraint for bearing"); doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintBearing\",\"%s\")",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Member = App.activeDocument().%s.Member + [App.activeDocument().%s]",Analysis->getNameInDocument(),Analysis->getNameInDocument(),FeatName.c_str()); + + doCommand(Doc,"%s",gethideMeshShowPartStr().c_str()); //OvG: Hide meshes and show parts + updateActive(); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -285,7 +300,7 @@ void CmdFemConstraintBearing::activated(int iMsg) bool CmdFemConstraintBearing::isActive(void) { - return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); + return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //===================================================================================== @@ -317,6 +332,9 @@ void CmdFemConstraintFixed::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintFixed\",\"%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.Member = App.activeDocument().%s.Member + [App.activeDocument().%s]",Analysis->getNameInDocument(),Analysis->getNameInDocument(),FeatName.c_str()); + + doCommand(Doc,"%s",gethideMeshShowPartStr().c_str()); //OvG: Hide meshes and show parts + updateActive(); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -324,7 +342,7 @@ void CmdFemConstraintFixed::activated(int iMsg) bool CmdFemConstraintFixed::isActive(void) { - return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); + return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //===================================================================================== @@ -358,6 +376,9 @@ void CmdFemConstraintForce::activated(int iMsg) 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.Member = App.activeDocument().%s.Member + [App.activeDocument().%s]",Analysis->getNameInDocument(),Analysis->getNameInDocument(),FeatName.c_str()); + + doCommand(Doc,"%s",gethideMeshShowPartStr().c_str()); //OvG: Hide meshes and show parts + updateActive(); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -365,7 +386,7 @@ void CmdFemConstraintForce::activated(int iMsg) bool CmdFemConstraintForce::isActive(void) { - return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); + return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //===================================================================================== @@ -400,6 +421,9 @@ void CmdFemConstraintPressure::activated(int iMsg) doCommand(Doc,"App.activeDocument().%s.Scale = 1",FeatName.c_str()); //OvG: set initial scale to 1 doCommand(Doc,"App.activeDocument().%s.Member = App.activeDocument().%s.Member + [App.activeDocument().%s]", Analysis->getNameInDocument(),Analysis->getNameInDocument(),FeatName.c_str()); + + doCommand(Doc,"%s",gethideMeshShowPartStr().c_str()); //OvG: Hide meshes and show parts + updateActive(); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -407,7 +431,7 @@ void CmdFemConstraintPressure::activated(int iMsg) bool CmdFemConstraintPressure::isActive(void) { - return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); + return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //===================================================================================== @@ -438,6 +462,9 @@ void CmdFemConstraintGear::activated(int iMsg) 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.Member = App.activeDocument().%s.Member + [App.activeDocument().%s]",Analysis->getNameInDocument(),Analysis->getNameInDocument(),FeatName.c_str()); + + doCommand(Doc,"%s",gethideMeshShowPartStr().c_str()); //OvG: Hide meshes and show parts + updateActive(); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -445,7 +472,7 @@ void CmdFemConstraintGear::activated(int iMsg) bool CmdFemConstraintGear::isActive(void) { - return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); + return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); } //===================================================================================== @@ -481,6 +508,9 @@ void CmdFemConstraintPulley::activated(int iMsg) 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.Member = App.activeDocument().%s.Member + [App.activeDocument().%s]",Analysis->getNameInDocument(),Analysis->getNameInDocument(),FeatName.c_str()); + + doCommand(Doc,"%s",gethideMeshShowPartStr().c_str()); //OvG: Hide meshes and show parts + updateActive(); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -488,9 +518,50 @@ void CmdFemConstraintPulley::activated(int iMsg) bool CmdFemConstraintPulley::isActive(void) { - return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); + 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("Create FEM displacement constraint"); + sToolTipText = QT_TR_NOOP("Create FEM constraint for a displacement acting on a face"); + sWhatsThis = "Fem_ConstraintDisplacement"; + sStatusTip = sToolTipText; + sPixmap = "fem-constraint-displacement"; } +void CmdFemConstraintDisplacement::activated(int iMsg) +{ + Fem::FemAnalysis *Analysis; + + if(getConstraintPrerequisits(&Analysis)) + return; + + std::string FeatName = getUniqueObjectName("FemConstraintDisplacement"); + + openCommand("Make FEM constraint displacement on face"); + doCommand(Doc,"App.activeDocument().addObject(\"Fem::ConstraintDisplacement\",\"%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.Member = App.activeDocument().%s.Member + [App.activeDocument().%s]", + Analysis->getNameInDocument(),Analysis->getNameInDocument(),FeatName.c_str()); + + doCommand(Doc,"%s",gethideMeshShowPartStr().c_str()); //OvG: Hide meshes and show parts + + updateActive(); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +} + +bool CmdFemConstraintDisplacement::isActive(void) +{ + return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject(); +} // ##################################################################################################### @@ -702,4 +773,5 @@ void CreateFemCommands(void) rcCmdMgr.addCommand(new CmdFemConstraintPressure()); rcCmdMgr.addCommand(new CmdFemConstraintGear()); rcCmdMgr.addCommand(new CmdFemConstraintPulley()); + rcCmdMgr.addCommand(new CmdFemConstraintDisplacement()); } diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc index f60d928e2..0b60ce9f1 100755 --- a/src/Mod/Fem/Gui/Resources/Fem.qrc +++ b/src/Mod/Fem/Gui/Resources/Fem.qrc @@ -4,6 +4,7 @@ icons/fem-fem-mesh-create-node-by-poly.svg icons/fem-analysis.svg icons/fem-solver.svg + icons/fem-constraint-displacement.svg icons/fem-constraint-force.svg icons/fem-constraint-fixed.svg icons/fem-constraint-pressure.svg diff --git a/src/Mod/Fem/Gui/Resources/icons/fem-constraint-displacement.svg b/src/Mod/Fem/Gui/Resources/icons/fem-constraint-displacement.svg new file mode 100644 index 000000000..c6769d86c --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/icons/fem-constraint-displacement.svg @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + D + + diff --git a/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.cpp b/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.cpp new file mode 100644 index 000000000..6d87aaf4a --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.cpp @@ -0,0 +1,655 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Michael Hindley * + * Ruan Olwagen * + * Oswald van Ginkel * + * Based on Force constraint by Jan Rheinländer * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "Mod/Fem/App/FemConstraintDisplacement.h" +#include "TaskFemConstraintDisplacement.h" +#include "ui_TaskFemConstraintDisplacement.h" +#include +#include + + + +#include +#include + + +using namespace FemGui; +using namespace Gui; + +/* TRANSLATOR FemGui::TaskFemConstraintDisplacement */ + +TaskFemConstraintDisplacement::TaskFemConstraintDisplacement(ViewProviderFemConstraintDisplacement *ConstraintView,QWidget *parent) + : TaskFemConstraint(ConstraintView, parent, "fem-constraint-displacement") +{ + proxy = new QWidget(this); + ui = new Ui_TaskFemConstraintDisplacement(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + QAction* action = new QAction(tr("Delete"), ui->lw_references); + action->connect(action, SIGNAL(triggered()), this, SLOT(onReferenceDeleted())); + ui->lw_references->addAction(action); + ui->lw_references->setContextMenuPolicy(Qt::ActionsContextMenu); + + connect(ui->lw_references, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + + this->groupLayout()->addWidget(proxy); + + // Connect decimal value inputs + connect(ui->spinxDisplacement, SIGNAL(valueChanged(double)), this, SLOT(x_changed(double))); + connect(ui->spinyDisplacement, SIGNAL(valueChanged(double)), this, SLOT(y_changed(double))); + connect(ui->spinzDisplacement, SIGNAL(valueChanged(double)), this, SLOT(z_changed(double))); + connect(ui->rotxv, SIGNAL(valueChanged(double)), this, SLOT(x_rot(double))); + connect(ui->rotyv, SIGNAL(valueChanged(double)), this, SLOT(y_rot(double))); + connect(ui->rotzv, SIGNAL(valueChanged(double)), this, SLOT(z_rot(double))); + // Connect check box values displacements + connect(ui->dispxfix, SIGNAL(stateChanged(int)), this, SLOT(fixx(int))); + connect(ui->dispxfree, SIGNAL(stateChanged(int)), this, SLOT(freex(int))); + connect(ui->dispyfix, SIGNAL(stateChanged(int)), this, SLOT(fixy(int))); + connect(ui->dispyfree, SIGNAL(stateChanged(int)), this, SLOT(freey(int))); + connect(ui->dispzfix, SIGNAL(stateChanged(int)), this, SLOT(fixz(int))); + connect(ui->dispzfree, SIGNAL(stateChanged(int)), this, SLOT(freez(int))); + // Connect to check box values for rotations + connect(ui->rotxfix, SIGNAL(stateChanged(int)), this, SLOT(rotfixx(int))); + connect(ui->rotxfree, SIGNAL(stateChanged(int)), this, SLOT(rotfreex(int))); + connect(ui->rotyfix, SIGNAL(stateChanged(int)), this, SLOT(rotfixy(int))); + connect(ui->rotyfree, SIGNAL(stateChanged(int)), this, SLOT(rotfreey(int))); + connect(ui->rotzfix, SIGNAL(stateChanged(int)), this, SLOT(rotfixz(int))); + connect(ui->rotzfree, SIGNAL(stateChanged(int)), this, SLOT(rotfreez(int))); + + // Temporarily prevent unnecessary feature recomputes + ui->spinxDisplacement->blockSignals(true); + ui->spinyDisplacement->blockSignals(true); + ui->spinzDisplacement->blockSignals(true); + ui->rotxv->blockSignals(true); + ui->rotyv->blockSignals(true); + ui->rotzv->blockSignals(true); + ui->dispxfix->blockSignals(true); + ui->dispxfree->blockSignals(true); + ui->dispyfix->blockSignals(true); + ui->dispyfree->blockSignals(true); + ui->dispzfix->blockSignals(true); + ui->dispzfree->blockSignals(true); + ui->rotxfix->blockSignals(true); + ui->rotxfree->blockSignals(true); + ui->rotyfix->blockSignals(true); + ui->rotyfree->blockSignals(true); + ui->rotzfix->blockSignals(true); + ui->rotzfree->blockSignals(true); + + // Get the feature data + Fem::ConstraintDisplacement* pcConstraint = static_cast(ConstraintView->getObject()); + double fStates[6]; + bool bStates[12]; + fStates[0]=pcConstraint->xDisplacement.getValue(); + fStates[1]=pcConstraint->yDisplacement.getValue(); + fStates[2]=pcConstraint->zDisplacement.getValue(); + fStates[3]=pcConstraint->xRotation.getValue(); + fStates[4]=pcConstraint->yRotation.getValue(); + fStates[5]=pcConstraint->zRotation.getValue(); + bStates[0]=pcConstraint->xFix.getValue(); + bStates[1]=pcConstraint->xFree.getValue(); + bStates[2]=pcConstraint->yFix.getValue(); + bStates[3]=pcConstraint->yFree.getValue(); + bStates[4]=pcConstraint->zFix.getValue(); + bStates[5]=pcConstraint->zFree.getValue(); + bStates[6]=pcConstraint->rotxFix.getValue(); + bStates[7]=pcConstraint->rotxFree.getValue(); + bStates[8]=pcConstraint->rotyFix.getValue(); + bStates[9]=pcConstraint->rotyFree.getValue(); + bStates[10]=pcConstraint->rotzFix.getValue(); + bStates[11]=pcConstraint->rotzFree.getValue(); + + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + // Fill data into dialog elements + ui->spinxDisplacement->setValue(fStates[0]); + ui->spinyDisplacement->setValue(fStates[1]); + ui->spinzDisplacement->setValue(fStates[2]); + ui->rotxv->setValue(fStates[3]); + ui->rotyv->setValue(fStates[4]); + ui->rotzv->setValue(fStates[5]); + ui->dispxfix->setChecked(bStates[0]); + ui->dispxfree->setChecked(bStates[1]); + ui->dispyfix->setChecked(bStates[2]); + ui->dispyfree->setChecked(bStates[3]); + ui->dispzfix->setChecked(bStates[4]); + ui->dispzfree->setChecked(bStates[5]); + ui->rotxfix->setChecked(bStates[6]); + ui->rotxfree->setChecked(bStates[7]); + ui->rotyfix->setChecked(bStates[8]); + ui->rotyfree->setChecked(bStates[9]); + ui->rotzfix->setChecked(bStates[10]); + ui->rotzfree->setChecked(bStates[11]); + + ui->lw_references->clear(); + for (std::size_t i = 0; i < Objects.size(); i++) { + ui->lw_references->addItem(makeRefText(Objects[i], SubElements[i])); + } + if (Objects.size() > 0) { + ui->lw_references->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); + } + + //Allow signals again + ui->spinxDisplacement->blockSignals(false); + ui->spinyDisplacement->blockSignals(false); + ui->spinzDisplacement->blockSignals(false); + ui->rotxv->blockSignals(false); + ui->rotyv->blockSignals(false); + ui->rotzv->blockSignals(false); + ui->dispxfix->blockSignals(false); + ui->dispxfree->blockSignals(false); + ui->dispyfix->blockSignals(false); + ui->dispyfree->blockSignals(false); + ui->dispzfix->blockSignals(false); + ui->dispzfree->blockSignals(false); + ui->rotxfix->blockSignals(false); + ui->rotxfree->blockSignals(false); + ui->rotyfix->blockSignals(false); + ui->rotyfree->blockSignals(false); + ui->rotzfix->blockSignals(false); + ui->rotzfree->blockSignals(false); + + //Selection buttons + connect(ui->btnAdd, SIGNAL(clicked()), this, SLOT(addToSelection())); + connect(ui->btnRemove, SIGNAL(clicked()), this, SLOT(removeFromSelection())); + + updateUI(); +} + +TaskFemConstraintDisplacement::~TaskFemConstraintDisplacement() +{ + delete ui; +} + +void TaskFemConstraintDisplacement::updateUI() +{ + if (ui->lw_references->model()->rowCount() == 0) { + // Go into reference selection mode if no reference has been selected yet + onButtonReference(true); + return; + } +} + +void TaskFemConstraintDisplacement::x_changed(double val){ + if (val!=0) + { + ui->dispxfree->setChecked(false); + ui->dispxfix->setChecked(false); + } +} + +void TaskFemConstraintDisplacement::y_changed(double val){ + if (val!=0) + { + ui->dispyfree->setChecked(false); + ui->dispyfix->setChecked(false); + } +} + +void TaskFemConstraintDisplacement::z_changed(double val){ + if (val!=0) + { + ui->dispzfree->setChecked(false); + ui->dispzfix->setChecked(false); + } +} + +void TaskFemConstraintDisplacement::x_rot(double val){ + if (val!=0) + { + ui->rotxfree->setChecked(false); + ui->rotxfix->setChecked(false); + } +} + +void TaskFemConstraintDisplacement::y_rot(double val){ + if (val!=0) + { + ui->rotyfree->setChecked(false); + ui->rotyfix->setChecked(false); + } +} + +void TaskFemConstraintDisplacement::z_rot(double val){ + if (val!=0) + { + ui->rotzfree->setChecked(false); + ui->rotzfix->setChecked(false); + } +} + +void TaskFemConstraintDisplacement::fixx(int val){ + if (val==2) + { + ui->dispxfree->setChecked(false); + ui->spinxDisplacement->setValue(0); + } + else if (ui->spinxDisplacement->value()==0) + { + ui->dispxfree->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::freex(int val){ + if (val==2) + { + ui->dispxfix->setChecked(false); + ui->spinxDisplacement->setValue(0); + } + else if (ui->spinxDisplacement->value()==0) + { + ui->dispxfix->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::fixy(int val){ + if (val==2) + { + ui->dispyfree->setChecked(false); + ui->spinyDisplacement->setValue(0); + } + else if (ui->spinyDisplacement->value()==0) + { + ui->dispyfree->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::freey(int val){ + if (val==2) + { + ui->dispyfix->setChecked(false); + ui->spinyDisplacement->setValue(0); + } + else if (ui->spinyDisplacement->value()==0) + { + ui->dispyfix->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::fixz(int val){ + if (val==2) + { + ui->dispzfree->setChecked(false); + ui->spinzDisplacement->setValue(0); + } + else if (ui->spinzDisplacement->value()==0) + { + ui->dispzfree->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::freez(int val){ + if (val==2) + { + ui->dispzfix->setChecked(false); + ui->spinzDisplacement->setValue(0); + } + else if (ui->spinzDisplacement->value()==0) + { + ui->dispzfix->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::rotfixx(int val){ + if (val==2) + { + ui->rotxfree->setChecked(false); + ui->rotxv->setValue(0); + } + else if (ui->rotxv->value()==0) + { + ui->rotxfree->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::rotfreex(int val){ + if (val==2) + { + ui->rotxfix->setChecked(false); + ui->rotxv->setValue(0); + } + else if (ui->rotxv->value()==0) + { + ui->rotxfix->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::rotfixy(int val){ + if (val==2) + { + ui->rotyfree->setChecked(false); + ui->rotyv->setValue(0); + } + else if (ui->rotyv->value()==0) + { + ui->rotyfree->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::rotfreey(int val){ + if (val==2) + { + ui->rotyfix->setChecked(false); + ui->rotyv->setValue(0); + } + else if (ui->rotyv->value()==0) + { + ui->rotyfix->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::rotfixz(int val){ + if (val==2) + { + ui->rotzfree->setChecked(false); + ui->rotzv->setValue(0); + } + else if (ui->rotzv->value()==0) + { + ui->rotzfree->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::rotfreez(int val){ + if (val==2) + { + ui->rotzfix->setChecked(false); + ui->rotzv->setValue(0); + } + else if (ui->rotzv->value()==0) + { + ui->rotzfix->setChecked(true); + } +} + +void TaskFemConstraintDisplacement::addToSelection() +{ + std::vector selection = Gui::Selection().getSelectionEx(); //gets vector of selected objects of active document + if (selection.size()==0){ + QMessageBox::warning(this, tr("Selection error"), tr("Nothing selected!")); + return; + } + + Fem::ConstraintDisplacement* pcConstraint = static_cast(ConstraintView->getObject()); + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + for (std::vector::iterator it = selection.begin(); it != selection.end(); ++it){//for every selected object + if (static_cast(it->getTypeName()).substr(0,4).compare(std::string("Part"))!=0){ + QMessageBox::warning(this, tr("Selection error"),tr("Selected object is not a part!")); + return; + } + + std::vector subNames=it->getSubNames(); + App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(it->getFeatName()); + for (unsigned int subIt=0;subIt<(subNames.size());++subIt){// for every selected sub element + bool addMe=true; + for (std::vector::iterator itr=std::find(SubElements.begin(),SubElements.end(),subNames[subIt]); + itr!= SubElements.end(); + itr = std::find(++itr,SubElements.end(),subNames[subIt])) + {// for every sub element in selection that matches one in old list + if (obj==Objects[std::distance(SubElements.begin(),itr)]){//if selected sub element's object equals the one in old list then it was added before so don't add + addMe=false; + } + } + if (addMe){ + Objects.push_back(obj); + SubElements.push_back(subNames[subIt]); + ui->lw_references->addItem(makeRefText(obj, subNames[subIt])); + } + } + } + //Update UI + pcConstraint->References.setValues(Objects,SubElements); + updateUI(); +} + +void TaskFemConstraintDisplacement::removeFromSelection() +{ + std::vector selection = Gui::Selection().getSelectionEx(); //gets vector of selected objects of active document + if (selection.size()==0){ + QMessageBox::warning(this, tr("Selection error"), tr("Nothing selected!")); + return; + } + + Fem::ConstraintDisplacement* pcConstraint = static_cast(ConstraintView->getObject()); + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + std::vector itemsToDel; + for (std::vector::iterator it = selection.begin(); it != selection.end(); ++it){//for every selected object + if (static_cast(it->getTypeName()).substr(0,4).compare(std::string("Part"))!=0){ + QMessageBox::warning(this, tr("Selection error"),tr("Selected object is not a part!")); + return; + } + + std::vector subNames=it->getSubNames(); + App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(it->getFeatName()); + + for (unsigned int subIt=0;subIt<(subNames.size());++subIt){// for every selected sub element + for (std::vector::iterator itr=std::find(SubElements.begin(),SubElements.end(),subNames[subIt]); + itr!= SubElements.end(); + itr = std::find(++itr,SubElements.end(),subNames[subIt])) + {// for every sub element in selection that matches one in old list + if (obj==Objects[std::distance(SubElements.begin(),itr)]){//if selected sub element's object equals the one in old list then it was added before so mark for deletion + itemsToDel.push_back(std::distance(SubElements.begin(),itr)); + } + } + } + } + + while (itemsToDel.size()>0){ + Objects.erase(Objects.begin()+itemsToDel.back()); + SubElements.erase(SubElements.begin()+itemsToDel.back()); + itemsToDel.pop_back(); + } + //Update UI + disconnect(ui->lw_references, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + + ui->lw_references->clear(); + for (unsigned int j=0;jlw_references->addItem(makeRefText(Objects[j], SubElements[j])); + } + connect(ui->lw_references, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(setSelection(QListWidgetItem*))); + + pcConstraint->References.setValues(Objects,SubElements); + updateUI(); +} + +void TaskFemConstraintDisplacement::setSelection(QListWidgetItem* item){ + std::string docName=ConstraintView->getObject()->getDocument()->getName(); + + std::string s = item->text().toStdString(); + std::string delimiter = ":"; + + size_t pos = 0; + std::string objName; + std::string subName; + pos = s.find(delimiter); + objName = s.substr(0, pos); + s.erase(0, pos + delimiter.length()); + subName=s; + + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(docName.c_str(),objName.c_str(),subName.c_str(),0,0,0); +} + +void TaskFemConstraintDisplacement::onReferenceDeleted() { + int row = ui->lw_references->currentIndex().row(); + TaskFemConstraint::onReferenceDeleted(row); + ui->lw_references->model()->removeRow(row); + ui->lw_references->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); +} + +const std::string TaskFemConstraintDisplacement::getReferences() const +{ + int rows = ui->lw_references->model()->rowCount(); + std::vector items; + for (int r = 0; r < rows; r++) { + items.push_back(ui->lw_references->item(r)->text().toStdString()); + } + return TaskFemConstraint::getReferences(items); +} + +double TaskFemConstraintDisplacement::get_spinxDisplacement() const{return ui->spinxDisplacement->value();} +double TaskFemConstraintDisplacement::get_spinyDisplacement() const{return ui->spinyDisplacement->value();} +double TaskFemConstraintDisplacement::get_spinzDisplacement() const{return ui->spinzDisplacement->value();} +double TaskFemConstraintDisplacement::get_rotxv() const{return ui->rotxv->value();} +double TaskFemConstraintDisplacement::get_rotyv() const{return ui->rotyv->value();} +double TaskFemConstraintDisplacement::get_rotzv() const{return ui->rotzv->value();} + +bool TaskFemConstraintDisplacement::get_dispxfix() const{return ui->dispxfix->isChecked();} +bool TaskFemConstraintDisplacement::get_dispxfree() const{return ui->dispxfree->isChecked();} +bool TaskFemConstraintDisplacement::get_dispyfix() const{return ui->dispyfix->isChecked();} +bool TaskFemConstraintDisplacement::get_dispyfree() const{return ui->dispyfree->isChecked();} +bool TaskFemConstraintDisplacement::get_dispzfix() const{return ui->dispzfix->isChecked();} +bool TaskFemConstraintDisplacement::get_dispzfree() const{return ui->dispzfree->isChecked();} +bool TaskFemConstraintDisplacement::get_rotxfix() const{return ui->rotxfix->isChecked();} +bool TaskFemConstraintDisplacement::get_rotxfree() const{return ui->rotxfree->isChecked();} +bool TaskFemConstraintDisplacement::get_rotyfix() const{return ui->rotyfix->isChecked();} +bool TaskFemConstraintDisplacement::get_rotyfree() const{return ui->rotyfree->isChecked();} +bool TaskFemConstraintDisplacement::get_rotzfix() const{return ui->rotzfix->isChecked();} +bool TaskFemConstraintDisplacement::get_rotzfree() const{return ui->rotzfree->isChecked();} + +void TaskFemConstraintDisplacement::changeEvent(QEvent *e) +{ +// TaskBox::changeEvent(e); +// if (e->type() == QEvent::LanguageChange) { +// ui->if_pressure->blockSignals(true); +// ui->retranslateUi(proxy); +// ui->if_pressure->blockSignals(false); +// } +} + +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraintDisplacement::TaskDlgFemConstraintDisplacement(ViewProviderFemConstraintDisplacement *ConstraintView) +{ + this->ConstraintView = ConstraintView; + assert(ConstraintView); + this->parameter = new TaskFemConstraintDisplacement(ConstraintView);; + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +void TaskDlgFemConstraintDisplacement::open() +{ + // a transaction is already open at creation time of the panel + if (!Gui::Command::hasPendingCommand()) { + QString msg = QObject::tr("Constraint normal stress"); + Gui::Command::openCommand((const char*)msg.toUtf8()); + } +} + +bool TaskDlgFemConstraintDisplacement::accept() +{ + std::string name = ConstraintView->getObject()->getNameInDocument(); + const TaskFemConstraintDisplacement* parameterDisplacement = static_cast(parameter); + + try { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.xDisplacement = %f", + name.c_str(), parameterDisplacement->get_spinxDisplacement()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.yDisplacement = %f", + name.c_str(), parameterDisplacement->get_spinyDisplacement()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.zDisplacement = %f", + name.c_str(), parameterDisplacement->get_spinzDisplacement()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.xRotation = %f", + name.c_str(), parameterDisplacement->get_rotxv()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.yRotation = %f", + name.c_str(), parameterDisplacement->get_rotyv()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.zRotation = %f", + name.c_str(), parameterDisplacement->get_rotzv()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.xFree = %s", + name.c_str(), parameterDisplacement->get_dispxfree() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.xFix = %s", + name.c_str(), parameterDisplacement->get_dispxfix() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.yFree = %s", + name.c_str(), parameterDisplacement->get_dispyfree() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.yFix = %s", + name.c_str(), parameterDisplacement->get_dispyfix() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.zFree = %s", + name.c_str(), parameterDisplacement->get_dispzfree() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.zFix = %s", + name.c_str(), parameterDisplacement->get_dispzfix() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.rotxFree = %s", + name.c_str(), parameterDisplacement->get_rotxfree() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.rotxFix = %s", + name.c_str(), parameterDisplacement->get_rotxfix() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.rotyFree = %s", + name.c_str(), parameterDisplacement->get_rotyfree() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.rotyFix = %s", + name.c_str(), parameterDisplacement->get_rotyfix() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.rotzFree = %s", + name.c_str(), parameterDisplacement->get_rotzfree() ? "True" : "False"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.rotzFix = %s", + name.c_str(), parameterDisplacement->get_rotzfix() ? "True" : "False"); + + std::string scale = parameterDisplacement->getScale(); //OvG: determine modified scale + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Scale = %s", name.c_str(), scale.c_str()); //OvG: implement modified scale + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); + return false; + } + + return TaskDlgFemConstraint::accept(); +} + +bool TaskDlgFemConstraintDisplacement::reject() +{ + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::updateActive(); + + return true; +} + +#include "moc_TaskFemConstraintDisplacement.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.h b/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.h new file mode 100644 index 000000000..7b289deb0 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.h @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Michael Hindley * + * Ruan Olwagen * + * Oswald van Ginkel * + * Based on Force constraint by Jan Rheinländer * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_TASKVIEW_TaskFemConstraintDisplacement_H +#define GUI_TASKVIEW_TaskFemConstraintDisplacement_H + +#include +#include +#include +#include + +#include "TaskFemConstraint.h" +#include "ViewProviderFemConstraintDisplacement.h" + +#include +#include +#include +#include + +class Ui_TaskFemConstraintDisplacement; + +namespace FemGui { +class TaskFemConstraintDisplacement : public TaskFemConstraint +{ + Q_OBJECT + +public: + TaskFemConstraintDisplacement(ViewProviderFemConstraintDisplacement *ConstraintView,QWidget *parent = 0); + ~TaskFemConstraintDisplacement(); + const std::string getReferences() const; + double get_spinxDisplacement()const; + double get_spinyDisplacement()const; + double get_spinzDisplacement()const; + double get_rotxv()const; + double get_rotyv()const; + double get_rotzv()const; + bool get_dispxfix()const; + bool get_dispxfree()const; + bool get_dispyfix()const; + bool get_dispyfree()const; + bool get_dispzfix()const; + bool get_dispzfree()const; + bool get_rotxfix()const; + bool get_rotxfree()const; + bool get_rotyfix()const; + bool get_rotyfree()const; + bool get_rotzfix()const; + bool get_rotzfree()const; + +private Q_SLOTS: + void onReferenceDeleted(void); + void x_changed(double); + void y_changed(double); + void z_changed(double); + void x_rot(double); + void y_rot(double); + void z_rot(double); + void fixx(int); + void freex(int); + void fixy(int); + void freey(int); + void fixz(int); + void freez(int); + void rotfixx(int); + void rotfreex(int); + void rotfixy(int); + void rotfreey(int); + void rotfixz(int); + void rotfreez(int); + + void addToSelection(); + void removeFromSelection(); + void setSelection(QListWidgetItem* item); + +protected: + void changeEvent(QEvent *e); + +private: + //void onSelectionChanged(const Gui::SelectionChanges& msg); + void updateUI(); + Ui_TaskFemConstraintDisplacement* ui; + +}; + +class TaskDlgFemConstraintDisplacement : public TaskDlgFemConstraint +{ + Q_OBJECT + +public: + TaskDlgFemConstraintDisplacement(ViewProviderFemConstraintDisplacement *ConstraintView); + void open(); + bool accept(); + bool reject(); +}; + +} //namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraintDisplacement_H diff --git a/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.ui b/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.ui new file mode 100644 index 000000000..60f973f88 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.ui @@ -0,0 +1,368 @@ + + + TaskFemConstraintDisplacement + + + true + + + + 0 + 0 + 400 + 800 + + + + + 3 + 80 + + + + + 400 + 800 + + + + + 400 + 800 + + + + Prescribed Displacement + + + + + 40 + 0 + 311 + 743 + + + + + + + Select multiple face(s), click Add or Remove + + + + + + + + + Add + + + + + + + Remove + + + + + + + + + + 0 + 0 + + + + + 0 + 100 + + + + + + + + + + + + Displacement x + + + + + + + + + Free + + + + + + + Fixed + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 0.000000000000000 + + + + + + + + + + + + + Displacement y + + + + + + + + + Free + + + + + + + Fixed + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 0.000000000000000 + + + + + + + + + + + + + Displacement z + + + + + + + + + Free + + + + + + + Fixed + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 0.000000000000000 + + + + + + + + + + + + 400 + 16777215 + + + + Rotations are only valid for Beam and Shell elements. + + + false + + + true + + + + + + + + + Rotation x + + + + + + + + + Free + + + + + + + Fixed + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + + + + + + + + + + + Rotation y + + + + + + + + + Free + + + + + + + Fixed + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + + + + + + + + + + + Rotation z + + + + + + + + + true + + + Free + + + + + + + true + + + Fixed + + + + + + + true + + + -99999.000000000000000 + + + 99999.000000000000000 + + + + + + + + + + + + + + + diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp index 932f91d95..f5387339e 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp @@ -395,6 +395,46 @@ void ViewProviderFemConstraint::updateFixed(const SoNode* node, const int idx, c updateCube(sep, idx+CONE_CHILDREN+PLACEMENT_CHILDREN, width, width, width/4); } +void ViewProviderFemConstraint::createDisplacement(SoSeparator* sep, const double height, const double width, const bool gap) +{ + createCone(sep, height, width); + createPlacement(sep, SbVec3f(0, -(height)/2-width/8 - (gap ? 1.0 : 0.1) * width/8, 0), SbRotation()); +} + +SoSeparator* ViewProviderFemConstraint::createDisplacement(const double height, const double width, const bool gap) +{ + SoSeparator* sep = new SoSeparator(); + createDisplacement(sep, height, width, gap); + return sep; +} + +void ViewProviderFemConstraint::updateDisplacement(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); + updatePlacement(sep, idx+CONE_CHILDREN, SbVec3f(0, -(height)/2-width/8 - (gap ? 1.0 : 0.0) * width/8, 0), SbRotation()); +} + +void ViewProviderFemConstraint::createRotation(SoSeparator* sep, const double height, const double width, const bool gap) +{ + createCylinder(sep, width/2, height/2); + createPlacement(sep, SbVec3f(0, -(height)*2-width/8 - (gap ? 1.0 : 0.1) * width/8, 0), SbRotation()); +} + +SoSeparator* ViewProviderFemConstraint::createRotation(const double height, const double width, const bool gap) +{ + SoSeparator* sep = new SoSeparator(); + createRotation(sep, height, width, gap); + return sep; +} + +void ViewProviderFemConstraint::updateRotation(const SoNode* node, const int idx, const double height, const double width, const bool gap) +{ + const SoSeparator* sep = static_cast(node); + updateCylinder(sep, idx, height/2, width/2); + updatePlacement(sep, idx+CYLINDER_CHILDREN, SbVec3f(0, -(height)*2-width/8 - (gap ? 1.0 : 0.0) * width/8, 0), SbRotation()); +} + QObject* ViewProviderFemConstraint::findChildByName(const QObject* parent, const QString& name) { for (QObjectList::const_iterator o = parent->children().begin(); o != parent->children().end(); o++) { diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h index 4c05edef2..2bfe344a3 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h @@ -87,6 +87,12 @@ protected: 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); + static void createDisplacement(SoSeparator* sep, const double height, const double width, const bool gap = false); + static SoSeparator* createDisplacement(const double height, const double width, const bool gap = false); + static void updateDisplacement(const SoNode* node, const int idx, const double height, const double width, const bool gap = false); + static void createRotation(SoSeparator* sep, const double height, const double width, const bool gap = false); + static SoSeparator* createRotation(const double height, const double width, const bool gap = false); + static void updateRotation(const SoNode* node, const int idx, const double height, const double width, const bool gap = false); private: SoFontStyle * pFont; diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintDisplacement.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintDisplacement.cpp new file mode 100644 index 000000000..3aabe1528 --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintDisplacement.cpp @@ -0,0 +1,309 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Michael Hindley * + * Ruan Olwagen * + * Oswald van Ginkel * + * Based on Force constraint by Jan Rheinländer * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +#endif + +#include "Mod/Fem/App/FemConstraintDisplacement.h" +#include "TaskFemConstraintDisplacement.h" +#include "ViewProviderFemConstraintDisplacement.h" +#include +#include + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintDisplacement, FemGui::ViewProviderFemConstraint) + +ViewProviderFemConstraintDisplacement::ViewProviderFemConstraintDisplacement() +{ + sPixmap = "fem-constraint-displacement"; + ADD_PROPERTY(FaceColor,(0.2f,0.3f,0.2f)); +} + +ViewProviderFemConstraintDisplacement::~ViewProviderFemConstraintDisplacement() +{ +} + +//FIXME setEdit needs a careful review +bool ViewProviderFemConstraintDisplacement::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(); + TaskDlgFemConstraintDisplacement *constrDlg = qobject_cast(dlg); + if (constrDlg && constrDlg->getConstraintView() != this) + constrDlg = 0; // another constraint left open its task panel + if (dlg && !constrDlg) { + if (constraintDialog != NULL) { + // Ignore the request to open another dialog + return false; + } else { + constraintDialog = new TaskFemConstraintDisplacement(this); + return true; + } + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (constrDlg) + Gui::Control().showDialog(constrDlg); + else + Gui::Control().showDialog(new TaskDlgFemConstraintDisplacement(this)); + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); + } +} + +#define HEIGHT (4) +#define WIDTH (0.3) +//#define USE_MULTIPLE_COPY //OvG: MULTICOPY fails to update scaled display on initial drawing - so disable + +void ViewProviderFemConstraintDisplacement::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + Fem::ConstraintDisplacement* pcConstraint = static_cast(this->getObject()); + float scaledwidth = WIDTH * pcConstraint->Scale.getValue(); //OvG: Calculate scaled values once only + float scaledheight = HEIGHT * pcConstraint->Scale.getValue(); + bool xFree = pcConstraint->xFree.getValue(); + bool yFree = pcConstraint->yFree.getValue(); + bool zFree = pcConstraint->zFree.getValue(); + bool rotxFree = pcConstraint->rotxFree.getValue(); + bool rotyFree = pcConstraint->rotyFree.getValue(); + bool rotzFree = pcConstraint->rotzFree.getValue(); + +#ifdef USE_MULTIPLE_COPY + //OvG: always need access to cp for scaling + SoMultipleCopy* cpx = new SoMultipleCopy(); + SoMultipleCopy* cpy = new SoMultipleCopy(); + SoMultipleCopy* cpz = new SoMultipleCopy(); + SoMultipleCopy* cprotx = new SoMultipleCopy(); + SoMultipleCopy* cproty = new SoMultipleCopy(); + SoMultipleCopy* cprotz = new SoMultipleCopy(); + if (pShapeSep->getNumChildren() == 0) { + // Set up the nodes + cpx->matrix.setNum(0); + cpx->addChild((SoNode*)createDisplacement(scaledheight, scaledwidth)); //OvG: Scaling + + cpy->matrix.setNum(0); + cpy->addChild((SoNode*)createDisplacement(scaledheight, scaledwidth)); //OvG: Scaling + + cpz->matrix.setNum(0); + cpz->addChild((SoNode*)createDisplacement(scaledheight, scaledwidth)); //OvG: Scaling + + cprotx->matrix.setNum(0); + cprotx->addChild((SoNode*)createRotation(scaledheight, scaledwidth)); //OvG: Scaling + + cproty->matrix.setNum(0); + cproty->addChild((SoNode*)createRotation(scaledheight, scaledwidth)); //OvG: Scaling + + cprotz->matrix.setNum(0); + cprotz->addChild((SoNode*)createRotation(scaledheight, scaledwidth)); //OvG: Scaling + + pShapeSep->addChild(cpx); + pShapeSep->addChild(cpy); + pShapeSep->addChild(cpz); + pShapeSep->addChild(cprotx); + pShapeSep->addChild(cproty); + pShapeSep->addChild(cprotz; + } +#endif + + if (strcmp(prop->getName(),"Points") == 0) { + const std::vector& points = pcConstraint->Points.getValues(); + const std::vector& normals = pcConstraint->Normals.getValues(); + if (points.size() != normals.size()) + return; + std::vector::const_iterator n = normals.begin(); + +#ifdef USE_MULTIPLE_COPY + cpx = static_cast(pShapeSep->getChild(0)); + cpx->matrix.setNum(points.size()); + SbMatrix* matricesx = cpx->matrix.startEditing(); + + cpy = static_cast(pShapeSep->getChild(1)); + cpy->matrix.setNum(points.size()); + SbMatrix* matricesy = cpy->matrix.startEditing(); + + cpz = static_cast(pShapeSep->getChild(2)); + cpz->matrix.setNum(points.size()); + SbMatrix* matricesz = cpz->matrix.startEditing(); + + cprotx = static_cast(pShapeSep->getChild(3)); + cprotx->matrix.setNum(points.size()); + SbMatrix* matricesrotx = cprotx->matrix.startEditing(); + + cproty = static_cast(pShapeSep->getChild(4)); + cproty->matrix.setNum(points.size()); + SbMatrix* matricesroty = cproty->matrix.startEditing(); + + cprotz = static_cast(pShapeSep->getChild(5)); + cprotz->matrix.setNum(points.size()); + SbMatrix* matricesrotz = cprotz->matrix.startEditing(); + + int idx = 0; + int idy = 0; + int idz = 0; + int idrotx = 0; + int idroty = 0; + int idrotz = 0; +#else + // Note: Points and Normals are always updated together + pShapeSep->removeAllChildren(); +#endif + + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + SbVec3f base(p->x, p->y, p->z); + SbVec3f dirx(1,0,0); //OvG: Make relevant to global axes + SbVec3f diry(0,1,0); //OvG: Make relevant to global axes + SbVec3f dirz(0,0,1); //OvG: Make relevant to global axes + SbRotation rotx(SbVec3f(0,-1,0), dirx); //OvG Tri-cones + SbRotation roty(SbVec3f(0,-1,0), diry); + SbRotation rotz(SbVec3f(0,-1,0), dirz); +#ifdef USE_MULTIPLE_COPY + SbMatrix mx; + SbMatrix my; + SbMatrix mz; + //OvG: Translation indication + if(!xFree) + { + SbMatrix mx; + mx.setTransform(base, rotx, SbVec3f(1,1,1)); + matricesx[idx] = mx; + idx++; + } + if(!yFree) + { + SbMatrix my; + my.setTransform(base, roty, SbVec3f(1,1,1)); + matricesy[idy] = my; + idy++; + } + if(!zFree) + { + SbMatrix mz; + mz.setTransform(base, rotz, SbVec3f(1,1,1)); + matricesz[idz] = mz; + idz++; + } + + //OvG: Rotation indication + if(!rotxFree) + { + SbMatrix mrotx; + mrotx.setTransform(base, rotx, SbVec3f(1,1,1)); + matricesrotx[idrotx] = mrotx; + idrotx++; + } + if(!rotyFree) + { + SbMatrix mroty; + mroty.setTransform(base, roty, SbVec3f(1,1,1)); + matricesroty[idroty] = mroty; + idroty++; + } + if(!rotzFree) + { + SbMatrix mrotz; + mrotz.setTransform(base, rotz, SbVec3f(1,1,1)); + matricesrotz[idrotz] = mrotz; + idrotz++; + } +#else + //OvG: Translation indication + if(!xFree) + { + SoSeparator* sepx = new SoSeparator(); + createPlacement(sepx, base, rotx); + createDisplacement(sepx, scaledheight, scaledwidth); //OvG: Scaling + pShapeSep->addChild(sepx); + } + if(!yFree) + { + SoSeparator* sepy = new SoSeparator(); + createPlacement(sepy, base, roty); + createDisplacement(sepy, scaledheight, scaledwidth); //OvG: Scaling + pShapeSep->addChild(sepy); + } + if(!zFree) + { + SoSeparator* sepz = new SoSeparator(); + createPlacement(sepz, base, rotz); + createDisplacement(sepz, scaledheight, scaledwidth); //OvG: Scaling + pShapeSep->addChild(sepz); + } + + //OvG: Rotation indication + if(!rotxFree) + { + SoSeparator* sepx = new SoSeparator(); + createPlacement(sepx, base, rotx); + createRotation(sepx, scaledheight, scaledwidth); //OvG: Scaling + pShapeSep->addChild(sepx); + } + if(!rotyFree) + { + SoSeparator* sepy = new SoSeparator(); + createPlacement(sepy, base, roty); + createRotation(sepy, scaledheight, scaledwidth); //OvG: Scaling + pShapeSep->addChild(sepy); + } + if(!rotzFree) + { + SoSeparator* sepz = new SoSeparator(); + createPlacement(sepz, base, rotz); + createRotation(sepz, scaledheight, scaledwidth); //OvG: Scaling + pShapeSep->addChild(sepz); + } +#endif + n++; + } +#ifdef USE_MULTIPLE_COPY + cpx->matrix.finishEditing(); + cpy->matrix.finishEditing(); + cpz->matrix.finishEditing(); + cprotx->matrix.finishEditing(); + cproty->matrix.finishEditing(); + cprotz->matrix.finishEditing(); +#endif + } + + // Gets called whenever a property of the attached object changes + ViewProviderFemConstraint::updateData(prop); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintDisplacement.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintDisplacement.h new file mode 100644 index 000000000..06939eaeb --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintDisplacement.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (c) 2015 FreeCAD Developers * + * Authors: Michael Hindley * + * Ruan Olwagen * + * Oswald van Ginkel * + * Based on Force constraint by Jan Rheinländer * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef GUI_VIEWPROVIDERFEMCONSTRAINTDISPLACEMENT_H +#define GUI_VIEWPROVIDERFEMCONSTRAINTDISPLACEMENT_H + +#include "ViewProviderFemConstraint.h" + +namespace FemGui { + +class FemGuiExport ViewProviderFemConstraintDisplacement : public FemGui::ViewProviderFemConstraint +{ + PROPERTY_HEADER(FemGui::ViewProviderFemConstraintDisplacement); + +public: + ViewProviderFemConstraintDisplacement(); + virtual ~ViewProviderFemConstraintDisplacement(); + virtual void updateData(const App::Property*); + +protected: + virtual bool setEdit(int ModNum); +}; + +} + +#endif // GUI_VIEWPROVIDERFEMCONSTRAINTDISPLACEMENT_H diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp index 7d2080876..4e5c701e6 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintFixed.cpp @@ -105,8 +105,8 @@ bool ViewProviderFemConstraintFixed::setEdit(int ModNum) } } -#define HEIGHT 4 -#define WIDTH (1.5*HEIGHT) +#define WIDTH (2) +#define HEIGHT (1) //#define USE_MULTIPLE_COPY //OvG: MULTICOPY fails to update scaled display on initial drawing - so disable void ViewProviderFemConstraintFixed::updateData(const App::Property* prop) diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp index ba8ffb4df..0a08e0640 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintForce.cpp @@ -105,7 +105,7 @@ bool ViewProviderFemConstraintForce::setEdit(int ModNum) } } -#define ARROWLENGTH 9 +#define ARROWLENGTH (4) #define ARROWHEADRADIUS (ARROWLENGTH/3) //#define USE_MULTIPLE_COPY //OvG: MULTICOPY fails to update scaled arrows on initial drawing - so disable diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintPressure.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintPressure.cpp index b87a2c3b5..15b68e5ef 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintPressure.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintPressure.cpp @@ -89,7 +89,7 @@ bool ViewProviderFemConstraintPressure::setEdit(int ModNum) } } -#define ARROWLENGTH (6) +#define ARROWLENGTH (4) #define ARROWHEADRADIUS (ARROWLENGTH/3) //#define USE_MULTIPLE_COPY //OvG: MULTICOPY fails to update scaled arrows on initial drawing - so disable diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index 2c093ee3c..c115eebf0 100755 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -65,6 +65,8 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "Fem_CreateNodesSet" << "Separator" << "Fem_ConstraintFixed" + << "Fem_ConstraintDisplacement" + << "Separator" << "Fem_ConstraintForce" << "Fem_ConstraintPressure" << "Fem_ConstraintBearing" @@ -95,6 +97,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Fem_CreateNodesSet" << "Separator" << "Fem_ConstraintFixed" + << "Fem_ConstraintDisplacement" + << "Separator" << "Fem_ConstraintForce" << "Fem_ConstraintPressure" << "Fem_ConstraintBearing" diff --git a/src/Mod/Fem/_CommandMechanicalShowResult.py b/src/Mod/Fem/_CommandMechanicalShowResult.py index c7d0764f0..527df2d6e 100644 --- a/src/Mod/Fem/_CommandMechanicalShowResult.py +++ b/src/Mod/Fem/_CommandMechanicalShowResult.py @@ -49,6 +49,8 @@ class _CommandMechanicalShowResult(FemCommands): QtGui.QMessageBox.critical(None, "Missing prerequisite", "No result found in active Analysis") return + self.hide_parts_constraints_show_meshes() + import _TaskPanelResultControl taskd = _TaskPanelResultControl._TaskPanelResultControl() FreeCADGui.Control.showDialog(taskd) diff --git a/src/Mod/Fem/_CommandPurgeFemResults.py b/src/Mod/Fem/_CommandPurgeFemResults.py index 16331923d..bff5a718c 100644 --- a/src/Mod/Fem/_CommandPurgeFemResults.py +++ b/src/Mod/Fem/_CommandPurgeFemResults.py @@ -46,6 +46,7 @@ class _CommandPurgeFemResults(FemCommands): fea = FemTools() fea.reset_all() + self.hide_meshes_show_parts_constraints() if FreeCAD.GuiUp: FreeCADGui.addCommand('Fem_PurgeResults', _CommandPurgeFemResults()) diff --git a/src/Mod/Fem/_CommandQuickAnalysis.py b/src/Mod/Fem/_CommandQuickAnalysis.py index 264d3dd54..0ab67c428 100644 --- a/src/Mod/Fem/_CommandQuickAnalysis.py +++ b/src/Mod/Fem/_CommandQuickAnalysis.py @@ -47,6 +47,8 @@ class _CommandQuickAnalysis(FemCommands): if ret_code == 0: self.fea.load_results() self.show_results_on_mesh() + self.hide_parts_constraints_show_meshes() + else: print ("CalculiX failed ccx finished with error {}".format(ret_code)) diff --git a/src/Mod/Fem/_CommandSolverJobControl.py b/src/Mod/Fem/_CommandSolverJobControl.py index 585d9df6c..4a52ea8f3 100644 --- a/src/Mod/Fem/_CommandSolverJobControl.py +++ b/src/Mod/Fem/_CommandSolverJobControl.py @@ -43,6 +43,9 @@ class _CommandSolverJobControl(FemCommands): self.is_active = 'with_solver' def Activated(self): + + self.hide_parts_constraints_show_meshes() + solver_obj = FreeCADGui.Selection.getSelection()[0] FreeCADGui.ActiveDocument.setEdit(solver_obj, 0) diff --git a/src/Mod/Fem/ccxInpWriter.py b/src/Mod/Fem/ccxInpWriter.py index 3a0ac42c0..dd0f4110b 100644 --- a/src/Mod/Fem/ccxInpWriter.py +++ b/src/Mod/Fem/ccxInpWriter.py @@ -37,6 +37,7 @@ class inp_writer: def __init__(self, analysis_obj, mesh_obj, mat_obj, fixed_obj, force_obj, pressure_obj, + displacement_obj, beamsection_obj, shellthickness_obj, analysis_type=None, eigenmode_parameters=None, dir_name=None): @@ -47,6 +48,7 @@ class inp_writer: self.fixed_objects = fixed_obj self.force_objects = force_obj self.pressure_objects = pressure_obj + self.displacement_objects = displacement_obj if eigenmode_parameters: self.no_of_eigenfrequencies = eigenmode_parameters[0] self.eigenfrequeny_range_low = eigenmode_parameters[1] @@ -71,12 +73,14 @@ class inp_writer: inpfile.write('\n\n') self.write_element_sets_material_and_femelement_type(inpfile) self.write_node_sets_constraints_fixed(inpfile) + self.write_displacement_nodes(inpfile) if self.analysis_type is None or self.analysis_type == "static": self.write_node_sets_constraints_force(inpfile) self.write_materials(inpfile) self.write_femelementsets(inpfile) self.write_step_begin(inpfile) self.write_constraints_fixed(inpfile) + self.write_displacement(inpfile) if self.analysis_type is None or self.analysis_type == "static": self.write_constraints_force(inpfile) self.write_constraints_pressure(inpfile) @@ -144,6 +148,25 @@ class inp_writer: for i in n: f.write(str(i) + ',\n') + def write_displacement_nodes(self,f): + f.write('\n***********************************************************\n') + f.write('** Node sets for prescribed displacement constraint\n') + f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name)) + for fobj in self.displacement_objects: + disp_obj = fobj['Object'] + f.write('*NSET,NSET='+disp_obj.Name + '\n') + for o, elem in disp_obj.References: + fo = o.Shape.getElement(elem) + n = [] + if fo.ShapeType == 'Face': + n = self.mesh_object.FemMesh.getNodesByFace(fo) + elif fo.ShapeType == 'Edge': + n = self.mesh_object.FemMesh.getNodesByEdge(fo) + elif fo.ShapeType == 'Vertex': + n = self.mesh_object.FemMesh.getNodesByVertex(fo) + for i in n: + f.write(str(i) + ',\n') + def write_node_sets_constraints_force(self, f): f.write('\n***********************************************************\n') f.write('** Node sets for loads\n') @@ -263,6 +286,41 @@ class inp_writer: f.write(fix_obj_name + ',6\n') f.write('\n') + def write_displacement(self,f): + f.write('\n***********************************************************\n') + f.write('** Displacement constraint applied\n') + f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name)) + for disp_obj in self.displacement_objects: + disp_obj_name = disp_obj['Object'].Name + f.write('*BOUNDARY\n') + if disp_obj['Object'].xFix == True: + f.write(disp_obj_name + ',1\n') + elif disp_obj['Object'].xFree == False: + f.write(disp_obj_name + ',1,1,'+str(disp_obj['Object'].xDisplacement)+'\n') + if disp_obj['Object'].yFix == True: + f.write(disp_obj_name + ',2\n') + elif disp_obj['Object'].yFree == False: + f.write(disp_obj_name + ',2,2,'+str(disp_obj['Object'].yDisplacement)+'\n') + if disp_obj['Object'].zFix == True: + f.write(disp_obj_name + ',3\n') + elif disp_obj['Object'].zFree == False: + f.write(disp_obj_name + ',3,3,'+str(disp_obj['Object'].zDisplacement)+'\n') + + if self.beamsection_objects or self.shellthickness_objects: + if disp_obj['Object'].rotxFix == True: + f.write(disp_obj_name + ',4\n') + elif disp_obj['Object'].rotxFree == False: + f.write(disp_obj_name + ',4,4,'+str(disp_obj['Object'].xRotation)+'\n') + if disp_obj['Object'].rotyFix == True: + f.write(disp_obj_name + ',5\n') + elif disp_obj['Object'].rotyFree == False: + f.write(disp_obj_name + ',5,5,'+str(disp_obj['Object'].yRotation)+'\n') + if disp_obj['Object'].rotzFix == True: + f.write(disp_obj_name + ',6\n') + elif disp_obj['Object'].rotzFree == False: + f.write(disp_obj_name + ',6,6,'+str(disp_obj['Object'].zRotation)+'\n') + f.write('\n') + def write_constraints_force(self, f): f.write('\n***********************************************************\n') f.write('** Node loads\n') diff --git a/src/Mod/Fem/ccxInpWriterFemConstraintDisplacement.py b/src/Mod/Fem/ccxInpWriterFemConstraintDisplacement.py new file mode 100644 index 000000000..3dbec76d0 --- /dev/null +++ b/src/Mod/Fem/ccxInpWriterFemConstraintDisplacement.py @@ -0,0 +1,94 @@ +import FreeCAD +import os + +class ccxInpWriterFemConstraintDisplacement: + def __init__(self): + displacement_constraints = [] + beam_sections = [] + shell_thicknesses = [] + f_mesh = None + dir_name=None + file_name=None + + def writeFile(self): + print('started FemConstraintDisplacementInpFile') + import FemGui + f_analysis = FemGui.getActiveAnalysis() + displacement_constraints = [] + beam_sections = [] + shell_thicknesses = [] + f_mesh = None + dir_name=None + file_name=None + for m in f_analysis.Member: + if m.isDerivedFrom("Fem::ConstraintDisplacement"): + displacement_constraint_dict = {} + displacement_constraint_dict['Object'] = m + displacement_constraints.append(displacement_constraint_dict) + elif m.isDerivedFrom("Fem::FemMeshObject"): + f_mesh=m + elif hasattr(m, "Proxy") and m.Proxy.Type == 'FemBeamSection': + beam_section_dict = {} + beam_section_dict['Object'] = m + beam_sections.append(beam_section_dict) + elif hasattr(m, "Proxy") and m.Proxy.Type == "FemShellThickness": + shell_thickness_dict = {} + shell_thickness_dict['Object'] = m + shell_thicknesses.append(shell_thickness_dict) + dir_name = FreeCAD.ActiveDocument.TransientDir.replace('\\', '/') + '/FemConstraints' + if not os.path.isdir(dir_name): + os.mkdir(dir_name) + file_name = dir_name + '/' + 'FemConstraintDisplacement.txt' + print(file_name) + inpfile = open(file_name, 'w') + inpfile.write('\n***********************************************************\n') + inpfile.write('** Node sets for prescribed displacement constraint\n') + #inpfile.write('** written by {} function\n'.format(sys._getframe().f_code.co_name)) + for fobj in displacement_constraints: + disp_obj = fobj['Object'] + inpfile.write('*NSET,NSET='+disp_obj.Name + '\n') + for o, elem in disp_obj.References: + fo = o.Shape.getElement(elem) + n = [] + if fo.ShapeType == 'Face': + n = f_mesh.FemMesh.getNodesByFace(fo) + elif fo.ShapeType == 'Edge': + n = f_mesh.FemMesh.getNodesByEdge(fo) + elif fo.ShapeType == 'Vertex': + n = f_mesh.FemMesh.getNodesByVertex(fo) + for i in n: + inpfile.write(str(i) + ',\n') + inpfile.write('\n***********************************************************\n') + inpfile.write('** Displacement constraint applied\n') + #f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name)) + for disp_obj in displacement_constraints: + disp_obj_name = disp_obj['Object'].Name + inpfile.write('*BOUNDARY\n') + if disp_obj['Object'].xFix == True: + inpfile.write(disp_obj_name + ',1\n') + elif disp_obj['Object'].xFree == False: + inpfile.write(disp_obj_name + ',1,1,'+str(disp_obj['Object'].xDisplacement)+'\n') + if disp_obj['Object'].yFix == True: + inpfile.write(disp_obj_name + ',2\n') + elif disp_obj['Object'].yFree == False: + inpfile.write(disp_obj_name + ',2,2,'+str(disp_obj['Object'].yDisplacement)+'\n') + if disp_obj['Object'].zFix == True: + inpfile.write(disp_obj_name + ',3\n') + elif disp_obj['Object'].zFree == False: + inpfile.write(disp_obj_name + ',3,3,'+str(disp_obj['Object'].zDisplacement)+'\n') + + if beam_sections or shell_thicknesses: + if disp_obj['Object'].rotxFix == True: + inpfile.write(disp_obj_name + ',4\n') + elif disp_obj['Object'].rotxFree == False: + inpfile.write(disp_obj_name + ',4,4,'+str(disp_obj['Object'].xRotation)+'\n') + if disp_obj['Object'].rotyFix == True: + inpfile.write(disp_obj_name + ',5\n') + elif disp_obj['Object'].rotyFree == False: + inpfile.write(disp_obj_name + ',5,5,'+str(disp_obj['Object'].yRotation)+'\n') + if disp_obj['Object'].rotzFix == True: + inpfile.write(disp_obj_name + ',6\n') + elif disp_obj['Object'].rotzFree == False: + inpfile.write(disp_obj_name + ',6,6,'+str(disp_obj['Object'].zRotation)+'\n') + inpfile.close() + print('completed FemConstraintDisplacementInpFile')