diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index 1ce09fc7c..7ec067c31 100644 --- a/src/Mod/Fem/App/AppFem.cpp +++ b/src/Mod/Fem/App/AppFem.cpp @@ -56,6 +56,7 @@ #include "FemConstraintInitialTemperature.h" #include "FemConstraintPlaneRotation.h" #include "FemConstraintContact.h" +#include "FemConstraintFluidBoundary.h" #include "FemResultObject.h" #include "FemSolverObject.h" @@ -157,7 +158,8 @@ PyMODINIT_FUNC initFem() Fem::ConstraintInitialTemperature ::init(); Fem::ConstraintPlaneRotation ::init(); Fem::ConstraintContact ::init(); - + Fem::ConstraintFluidBoundary ::init(); + Fem::FemResultObject ::init(); Fem::FemSolverObject ::init(); Fem::FemSolverObjectPython ::init(); diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index fa3d05cdb..33fd1d226 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -197,6 +197,8 @@ SET(FemConstraints_SRCS FemConstraintFixed.h FemConstraintForce.cpp FemConstraintForce.h + FemConstraintFluidBoundary.cpp + FemConstraintFluidBoundary.h FemConstraintPressure.cpp FemConstraintPressure.h FemConstraintGear.cpp diff --git a/src/Mod/Fem/App/FemConstraintFluidBoundary.cpp b/src/Mod/Fem/App/FemConstraintFluidBoundary.cpp new file mode 100644 index 000000000..bdfc74962 --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintFluidBoundary.cpp @@ -0,0 +1,197 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "FemConstraintFluidBoundary.h" + +#include +#include + +using namespace Fem; + +PROPERTY_SOURCE(Fem::ConstraintFluidBoundary, Fem::Constraint); + +// also defined in TaskFemConstraintFluidBoundary.cpp and foamcasebuilder/basicbuilder.py, +// please update simultaneously +// the second (index 1) is the default enum, as index 0 causes compiling error +static const char* BoundaryTypes[] = {"inlet","wall","outlet","interface","freestream", NULL}; +static const char* WallSubtypes[] = {"unspecific", "fixed", "slip", "moving", NULL}; +static const char* InletSubtypes[] = {"unspecific","totalPressure","uniformVelocity","volumetricFlowRate","massFlowRate", NULL}; +static const char* OutletSubtypes[] = {"unspecific","totalPressure","staticPressure","uniformVelocity", "outFlow", NULL}; +static const char* InterfaceSubtypes[] = {"unspecific","symmetry","wedge","cyclic","empty", NULL}; +static const char* FreestreamSubtypes[] = {"unspecific", "freestream",NULL}; + +// see Ansys fluet manual: Turbulence Specification method +static const char* TurbulenceSpecifications[] = {"Intensity&LengthScale","Intensity&HydraulicDiameter",NULL}; +// activate the heat transfer and radiation model in Solver object explorer +/* only used in TaskPanel +static const char* TurbulenceSpecificationHelpTexts[] = {"see Ansys fluet manual: Turbulence Specification method", + "or fully devloped internal flow, Turbulence intensity (0-1.0) 0.05 typical", NULL}; +*/ + +//HTC value type, not sure it is supported in OpenFOAM +static const char* ThermalBoundaryTypes[] = {"fixedValue","zeroGradient", "fixedGradient", "mixed", "HTC","coupled", NULL}; +/* only used in TaskPanel +static const char* ThermalBoundaryHelpTexts[] = {"fixed Temperature [K]", "no heat transfer ()", "fixed value heat flux [W/m2]", + "mixed fixedGradient and fixedValue", "Heat transfer coeff [W/(M2)/K]", "conjugate heat transfer with solid", NULL}; +*/ + +ConstraintFluidBoundary::ConstraintFluidBoundary() +{ + // momemtum boundary: pressure and velocity + ADD_PROPERTY_TYPE(BoundaryType,(1),"FluidBoundary",(App::PropertyType)(App::Prop_None), + "Basic boundary type like inlet, wall, outlet,etc"); + BoundaryType.setEnums(BoundaryTypes); + ADD_PROPERTY_TYPE(Subtype,(1),"FluidBoundary",(App::PropertyType)(App::Prop_None), + "Subtype defines value type or more specific type"); + Subtype.setEnums(WallSubtypes); + ADD_PROPERTY_TYPE(BoundaryValue,(0.0),"FluidBoundary",(App::PropertyType)(App::Prop_None), + "Scaler value for the specific value subtype, like pressure, velocity"); + ADD_PROPERTY_TYPE(Direction,(0),"FluidBoundary",(App::PropertyType)(App::Prop_None), + "Element giving vector direction of constraint"); + + ADD_PROPERTY_TYPE(TurbulenceSpecification,(1),"Turbulence",(App::PropertyType)(App::Prop_None), + "Turbulence boundary type"); + TurbulenceSpecification.setEnums(TurbulenceSpecifications); //Turbulence Specification Method + ADD_PROPERTY_TYPE(TurbulentIntensityValue,(0.0),"Turbulence",(App::PropertyType)(App::Prop_None), + "Scaler value for Turbulent intensity etc"); + ADD_PROPERTY_TYPE(TurbulentLengthValue,(0.0),"Turbulence",(App::PropertyType)(App::Prop_None), + "Scaler value for Turbulent length scale, hydraulic diameter etc"); + // consider the newly added Fem::ConstraintTemperature + ADD_PROPERTY_TYPE(ThermalBoundaryType,(1),"HeatTransfer",(App::PropertyType)(App::Prop_None), + "Thermal boundary type"); + ThermalBoundaryType.setEnums(ThermalBoundaryTypes); + ADD_PROPERTY_TYPE(TemperatureValue,(0.0),"HeatTransfer",(App::PropertyType)(App::Prop_None), + "Temperature value for thermal boundary condition"); + ADD_PROPERTY_TYPE(HeatFluxValue,(0.0),"HeatTransfer",(App::PropertyType)(App::Prop_None), + "Heat flux value for thermal boundary condition"); + ADD_PROPERTY_TYPE(HTCoeffValue,(0.0),"HeatTransfer",(App::PropertyType)(App::Prop_None), + "Heat transfer coefficient for convective boundary condition"); + // geometry rendering related properties + ADD_PROPERTY(Reversed,(0)); + ADD_PROPERTY_TYPE(Points,(Base::Vector3d()),"FluidBoundary",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Points where arrows are drawn"); + ADD_PROPERTY_TYPE(DirectionVector,(Base::Vector3d(0,0,1)),"FluidBoundary",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Direction of arrows"); + naturalDirectionVector = Base::Vector3d(0,0,0); // by default use the null vector to indication an invalid value + Points.setValues(std::vector()); + // property from: FemConstraintFixed object + ADD_PROPERTY_TYPE(Normals,(Base::Vector3d()),"FluidBoundary",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Normals where symbols are drawn"); + Normals.setValues(std::vector()); +} + +App::DocumentObjectExecReturn *ConstraintFluidBoundary::execute(void) +{ + return Constraint::execute(); +} + +void ConstraintFluidBoundary::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 == &BoundaryType) + { + std::string boundaryType = BoundaryType.getValueAsString(); + if (boundaryType == "wall") + { + Subtype.setEnums(WallSubtypes); + } + else if (boundaryType == "interface") + { + Subtype.setEnums(InterfaceSubtypes); + } + else if (boundaryType == "freestream") + { + Subtype.setEnums(FreestreamSubtypes); + } + else if(boundaryType == "inlet") + { + Subtype.setEnums(InletSubtypes); + } + else if(boundaryType == "outlet") + { + Subtype.setEnums(OutletSubtypes); + } + else + { + Base::Console().Message(boundaryType.c_str()); + Base::Console().Message(" Error: this boundaryType is not defined\n"); + } + //need to trigger ViewProvider::updateData() for redraw in 3D view + } + + 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() + } + } else if (prop == &Direction) { + Base::Vector3d direction = getDirection(Direction); + if (direction.Length() < Precision::Confusion()) + return; + naturalDirectionVector = direction; + if (Reversed.getValue()) + direction = -direction; + DirectionVector.setValue(direction); + } else if (prop == &Reversed) { + // if the direction is invalid try to compute it again + if (naturalDirectionVector.Length() < Precision::Confusion()) { + naturalDirectionVector = getDirection(Direction); + } + if (naturalDirectionVector.Length() >= Precision::Confusion()) { + if (Reversed.getValue() && (DirectionVector.getValue() == naturalDirectionVector)) { + DirectionVector.setValue(-naturalDirectionVector); + } else if (!Reversed.getValue() && (DirectionVector.getValue() != naturalDirectionVector)) { + DirectionVector.setValue(naturalDirectionVector); + } + } + } else if (prop == &NormalDirection) { + // Set a default direction if no direction reference has been given + if (Direction.getValue() == NULL) { + Base::Vector3d direction = NormalDirection.getValue(); + if (Reversed.getValue()) + direction = -direction; + DirectionVector.setValue(direction); + naturalDirectionVector = direction; + } + } +} diff --git a/src/Mod/Fem/App/FemConstraintFluidBoundary.h b/src/Mod/Fem/App/FemConstraintFluidBoundary.h new file mode 100644 index 000000000..98e8b920e --- /dev/null +++ b/src/Mod/Fem/App/FemConstraintFluidBoundary.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef FEM_FLUIDBOUNDARY_H +#define FEM_FLUIDBOUNDARY_H + +#include +#include +#include +#include + +#include "FemConstraint.h" + +namespace Fem +{ + +class AppFemExport ConstraintFluidBoundary: public Fem::Constraint +{ + PROPERTY_HEADER(Fem::ConstraintFluidBoundary); + +public: + /// Constructor + ConstraintFluidBoundary(void); + // + App::PropertyEnumeration BoundaryType; + App::PropertyEnumeration Subtype; + App::PropertyFloat BoundaryValue; + App::PropertyLinkSub Direction; + + App::PropertyEnumeration TurbulenceSpecification; + App::PropertyFloat TurbulentIntensityValue; + App::PropertyFloat TurbulentLengthValue; + + App::PropertyEnumeration ThermalBoundaryType; + App::PropertyFloat TemperatureValue; + App::PropertyFloat HeatFluxValue; + App::PropertyFloat HTCoeffValue; + + App::PropertyBool Reversed; + // Read-only (calculated values). These trigger changes in the ViewProvider + App::PropertyVectorList Points; + App::PropertyVectorList Normals; // needed to draw diff BoundaryType + App::PropertyVector DirectionVector; + + /// recalculate the object + virtual App::DocumentObjectExecReturn *execute(void); + + /// returns the type name of the ViewProvider + const char* getViewProviderName(void) const { + return "FemGui::ViewProviderFemConstraintFluidBoundary"; + } + +protected: + virtual void onChanged(const App::Property* prop); + +private: + Base::Vector3d naturalDirectionVector; +}; + +} //namespace Fem + + +#endif // FEM_FLUIDBOUNDARY_H diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index 06488582b..eb74aa946 100644 --- a/src/Mod/Fem/Gui/AppFemGui.cpp +++ b/src/Mod/Fem/Gui/AppFemGui.cpp @@ -48,6 +48,7 @@ #include "ViewProviderFemConstraintBearing.h" #include "ViewProviderFemConstraintFixed.h" #include "ViewProviderFemConstraintForce.h" +#include "ViewProviderFemConstraintFluidBoundary.h" #include "ViewProviderFemConstraintPressure.h" #include "ViewProviderFemConstraintGear.h" #include "ViewProviderFemConstraintPulley.h" @@ -118,6 +119,7 @@ PyMODINIT_FUNC initFemGui() FemGui::ViewProviderFemConstraintBearing ::init(); FemGui::ViewProviderFemConstraintFixed ::init(); FemGui::ViewProviderFemConstraintForce ::init(); + FemGui::ViewProviderFemConstraintFluidBoundary ::init(); FemGui::ViewProviderFemConstraintPressure ::init(); FemGui::ViewProviderFemConstraintGear ::init(); FemGui::ViewProviderFemConstraintPulley ::init(); diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index a00609f9c..d0ceac945 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -61,6 +61,7 @@ set(FemGui_MOC_HDRS TaskFemConstraintBearing.h TaskFemConstraintFixed.h TaskFemConstraintForce.h + TaskFemConstraintFluidBoundary.h TaskFemConstraintPressure.h TaskFemConstraintGear.h TaskFemConstraintPulley.h @@ -95,6 +96,7 @@ set(FemGui_UIC_SRCS TaskFemConstraintBearing.ui TaskFemConstraintFixed.ui TaskFemConstraintForce.ui + TaskFemConstraintFluidBoundary.ui TaskFemConstraintPressure.ui TaskFemConstraintDisplacement.ui TaskFemConstraintTemperature.ui @@ -140,6 +142,9 @@ SET(FemGui_DLG_SRCS TaskFemConstraintForce.ui TaskFemConstraintForce.cpp TaskFemConstraintForce.h + TaskFemConstraintFluidBoundary.ui + TaskFemConstraintFluidBoundary.cpp + TaskFemConstraintFluidBoundary.h TaskFemConstraintPressure.ui TaskFemConstraintPressure.cpp TaskFemConstraintPressure.h @@ -201,6 +206,8 @@ SET(FemGui_SRCS_ViewProvider ViewProviderFemConstraintFixed.h ViewProviderFemConstraintForce.cpp ViewProviderFemConstraintForce.h + ViewProviderFemConstraintFluidBoundary.cpp + ViewProviderFemConstraintFluidBoundary.h ViewProviderFemConstraintPressure.cpp ViewProviderFemConstraintPressure.h ViewProviderFemConstraintGear.cpp diff --git a/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.cpp b/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.cpp new file mode 100644 index 000000000..d7fa5cd77 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.cpp @@ -0,0 +1,729 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * Copyright (c) 2016 Qingfeng Xia * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "ui_TaskFemConstraintFluidBoundary.h" +#include "TaskFemConstraintFluidBoundary.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ActiveAnalysisObserver.h" + +#include +#include + +using namespace FemGui; +using namespace Gui; +using namespace Fem; + +//also defined in FemConstrainFluidBoundary and foamcasebuilder/basicbuilder.py, please update simultaneously +//the second (index 1) is the default enum, as index 0 causes compiling error +//static const char* BoundaryTypes[] = {"inlet","wall","outlet","interface","freestream", NULL}; +static const char* WallSubtypes[] = {"unspecific", "fixed", "slip", "moving", NULL}; +static const char* InletSubtypes[] = {"unspecific","totalPressure","uniformVelocity","volumetricFlowRate","massFlowRate",NULL}; +static const char* OutletSubtypes[] = {"unspecific","totalPressure","staticPressure","uniformVelocity", "outFlow", NULL}; +static const char* InterfaceSubtypes[] = {"unspecific","symmetry","wedge","cyclic","empty", NULL}; +static const char* FreestreamSubtypes[] = {"unspecific", "freestream",NULL}; + +// see Ansys fluet manual: Turbulence Specification method +//static const char* TurbulenceSpecifications[] = {"Intensity&LengthScale","Intensity&HydraulicDiameter",NULL}; +//activate the heat transfer and radiation model in Solver object explorer +static const char* TurbulenceSpecificationHelpTexts[] = {"see Ansys fluet manual: Turbulence Specification method", + "or fully devloped internal flow, Turbulence intensity (0-1.0) 0.05 typical", NULL}; + +//static const char* ThermalBoundaryTypes[] = {"fixedValue","zeroGradient", "fixedGradient", "mixed", "HTC","coupled", NULL}; +//const char* ThermalBoundaryTypes[] = {"fixedValue","zeroGradient", "fixedGradient", "mixed", "coupled",NULL}; +static const char* ThermalBoundaryHelpTexts[] = {"fixed Temperature [K]", "no heat transfer ()", "fixed value heat flux [W/m2]", + "mixed fixedGradient and fixedValue", "Heat transfer coeff [W/(M2)/K]", "conjugate heat transfer with solid", NULL}; + + +// internal function not declared in header file +void initComboBox(QComboBox* combo, const std::vector& textItems, const char* sItem) +{ + combo->blockSignals(true); + + int iItem = 1; // the first one is "unspecific" (index 0) + combo->clear(); + for (unsigned int it = 0; it < textItems.size(); it++) + { + combo->insertItem(it, Base::Tools::fromStdString(textItems[it])); + if (sItem == textItems[it]) + { + iItem = it; + } + } + combo->blockSignals(false); + combo->setCurrentIndex(iItem); +} + +/* TRANSLATOR FemGui::TaskFemConstraintFluidBoundary */ +TaskFemConstraintFluidBoundary::TaskFemConstraintFluidBoundary(ViewProviderFemConstraintFluidBoundary *ConstraintView,QWidget *parent) + : TaskFemConstraint(ConstraintView, parent, "fem-constraint-fluid-boundary") +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskFemConstraintFluidBoundary(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + // Create a context menu for the listview of the references + QAction* action = new QAction(tr("Delete"), ui->listReferences); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onReferenceDeleted())); + ui->listReferences->addAction(action); + ui->listReferences->setContextMenuPolicy(Qt::ActionsContextMenu); + + connect(ui->comboBoundaryType, SIGNAL(currentIndexChanged(int)), + this, SLOT(onBoundaryTypeChanged(void))); + connect(ui->comboSubtype, SIGNAL(currentIndexChanged(int)), + this, SLOT(onSubtypeChanged(void))); + connect(ui->spinBoundaryValue, SIGNAL(valueChanged(double)), + this, SLOT(onBoundaryValueChanged(double))); + + connect(ui->comboTurbulenceSpecification, SIGNAL(currentIndexChanged(int)), + this, SLOT(onTurbulenceSpecificationChanged(void))); + connect(ui->comboThermalBoundaryType, SIGNAL(currentIndexChanged(int)), + this, SLOT(onThermalBoundaryTypeChanged(void))); + + connect(ui->buttonReference, SIGNAL(pressed()), + this, SLOT(onButtonReference())); + connect(ui->buttonDirection, SIGNAL(pressed()), + this, SLOT(onButtonDirection())); + connect(ui->checkReverse, SIGNAL(toggled(bool)), + this, SLOT(onCheckReverse(bool))); + + this->groupLayout()->addWidget(proxy); + + // Temporarily prevent unnecessary feature recomputes + ui->spinBoundaryValue->blockSignals(true); + ui->listReferences->blockSignals(true); + + ui->buttonReference->blockSignals(true); + ui->buttonDirection->blockSignals(true); + ui->checkReverse->blockSignals(true); + + // Get the feature data + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(ConstraintView->getObject()); + + Fem::FemSolverObject* pcSolver = NULL; + if (FemGui::ActiveAnalysisObserver::instance()->hasActiveObject()) { + Fem::FemAnalysis* pcAnalysis = FemGui::ActiveAnalysisObserver::instance()->getActiveObject(); + //Fem::FemSolverObject is derived from DocumentObject + std::vector fem = pcAnalysis->Member.getValues(); + for (std::vector::iterator it = fem.begin(); it != fem.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(Fem::FemSolverObject::getClassTypeId())) + pcSolver = static_cast(*it); + } + } + pHeatTransfering = NULL; + pTurbulenceModel = NULL; + if(pcSolver != NULL){ + //if only it is CFD solver, otherwise exit by SIGSEGV error, detect getPropertyByName() != NULL + if(pcSolver->getPropertyByName("HeatTransfering")){ + pHeatTransfering = static_cast(pcSolver->getPropertyByName("HeatTransfering")); + if (pHeatTransfering->getValue()){ + ui->tabThermalBoundary->setVisible(true); + initComboBox(ui->comboThermalBoundaryType, pcConstraint->ThermalBoundaryType.getEnumVector(), + pcConstraint->ThermalBoundaryType.getValueAsString()); + updateThermalBoundaryUI(); + } + else{ + ui->tabThermalBoundary->setVisible(false); + //Base::Console().Message("retrieve solver property HeatTransfering as false\n"); + } + } + else{ + ui->tabThermalBoundary->setVisible(false); + } + if (pcSolver->getPropertyByName("TurbulenceModel")){ + pTurbulenceModel = static_cast(pcSolver->getPropertyByName("TurbulenceModel")); + if (pTurbulenceModel->getValueAsString() == std::string("laminar")){ + ui->tabTurbulenceBoundary->setVisible(false); + } + else{ + ui->tabTurbulenceBoundary->setVisible(true); + ui->groupTurbulence->setTitle(Base::Tools::fromStdString( + pTurbulenceModel->getValueAsString())); + initComboBox(ui->comboTurbulenceSpecification, pcConstraint->TurbulenceSpecification.getEnumVector(), + pcConstraint->TurbulenceSpecification.getValueAsString()); + updateTurbulenceUI(); + } + } + else{ + ui->tabTurbulenceBoundary->setVisible(false); + } + } + else{ + Base::Console().Message("Warning: No solver object inside FemAnalysis object\n"); + } + ui->tabWidget->setTabText(0, tr("Basic")); + ui->tabWidget->setTabText(1, tr("Turbulence")); + ui->tabWidget->setTabText(2, tr("Thermal")); + ui->labelHelpText->setText(tr("select boundary type, faces and set value")); + + initComboBox(ui->comboBoundaryType, pcConstraint->BoundaryType.getEnumVector(), + pcConstraint->BoundaryType.getValueAsString()); + updateBoundaryTypeUI(); + updateSubtypeUI(); + + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + std::vector dirStrings = pcConstraint->Direction.getSubValues(); + QString dir; + if (!dirStrings.empty()) + dir = makeRefText(pcConstraint->Direction.getValue(), dirStrings.front()); + //bool reversed = pcConstraint->Reversed.getValue(); + + // Fill data into dialog elements + double f = pcConstraint->BoundaryValue.getValue(); + ui->spinBoundaryValue->setMinimum(0); + ui->spinBoundaryValue->setMaximum(FLOAT_MAX); + ui->spinBoundaryValue->setValue(f); + ui->listReferences->clear(); + for (std::size_t i = 0; i < Objects.size(); i++) + ui->listReferences->addItem(makeRefText(Objects[i], SubElements[i])); + if (Objects.size() > 0) + ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); + ui->lineDirection->setText(dir.isEmpty() ? tr("") : dir); + //ui->checkReverse->setChecked(reversed); + ui->checkReverse->setVisible(false); // no need such UI for fluid boundary + + ui->listReferences->blockSignals(false); + ui->buttonReference->blockSignals(false); + + ui->spinBoundaryValue->blockSignals(false); + ui->buttonDirection->blockSignals(false); + ui->checkReverse->blockSignals(false); + updateSelectionUI(); +} + +void TaskFemConstraintFluidBoundary::updateBoundaryTypeUI() +{ + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(ConstraintView->getObject()); + std::string boundaryType = pcConstraint->BoundaryType.getValueAsString(); + + // Update subtypes, any change here should be written back to FemConstraintFluidBoundary.cpp + if (boundaryType == "wall") + { + ui->tabBasicBoundary->setVisible(false); + //todo: hidden only for fixed wall + pcConstraint->Subtype.setEnums(WallSubtypes); + } + else if (boundaryType == "interface") + { + ui->tabBasicBoundary->setVisible(false); + pcConstraint->Subtype.setEnums(InterfaceSubtypes); + } + else if (boundaryType == "freestream") + { + ui->tabBasicBoundary->setVisible(false); + pcConstraint->Subtype.setEnums(FreestreamSubtypes); + } + else if(boundaryType == "inlet") + { + ui->tabBasicBoundary->setVisible(true); + ui->labelSubtype->setText(QString::fromUtf8("valueType")); + pcConstraint->Subtype.setEnums(InletSubtypes); + pcConstraint->Reversed.setValue(true); // inlet must point into volume + } + else if(boundaryType == "outlet") + { + ui->tabBasicBoundary->setVisible(true); + ui->labelSubtype->setText(QString::fromUtf8("valueType")); + pcConstraint->Subtype.setEnums(OutletSubtypes); + pcConstraint->Reversed.setValue(false); // inlet must point outside + } + else + { + Base::Console().Message(boundaryType.c_str()); + Base::Console().Message("Error boundaryType is not defined\n"); + } + + std::vector subtypes = pcConstraint->Subtype.getEnumVector(); + initComboBox(ui->comboSubtype, subtypes, pcConstraint->Subtype.getValueAsString()); +} + + +void TaskFemConstraintFluidBoundary::updateSubtypeUI() +{ + + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(ConstraintView->getObject()); + //* Subtype PropertyEnumeration is updated if BoundaryType is changed + std::string boundaryType = pcConstraint->BoundaryType.getValueAsString(); + + if(boundaryType == "inlet" || boundaryType == "outlet") + { + std::string subtype = Base::Tools::toStdString(ui->comboSubtype->currentText()); + + if (subtype == "totalPressure" || subtype == "staticPressure") + { + ui->labelBoundaryValue->setText(QString::fromUtf8("pressure [Pa]")); //* tr() + } + else if (subtype == "uniformVelocity") + { + ui->labelBoundaryValue->setText(QString::fromUtf8("velocity [m/s]")); + } + else if (subtype == "flowrate") + { + ui->labelBoundaryValue->setText(QString::fromUtf8("flowrate [kg/s]")); + } + else + { + ui->labelBoundaryValue->setText(QString::fromUtf8("unspecific")); + } + } + +} + +/// hide/disable UI only happend in constructor, update helptext and valuetext here +void TaskFemConstraintFluidBoundary::updateTurbulenceUI() +{ + ui->labelHelpText->setText(tr(TurbulenceSpecificationHelpTexts[ui->comboTurbulenceSpecification->currentIndex()])); +} + +void TaskFemConstraintFluidBoundary::updateThermalBoundaryUI() +{ + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(ConstraintView->getObject()); + std::string thermalBoundaryType = pcConstraint->ThermalBoundaryType.getValueAsString(); + //to hide/disable UI + ui->labelHelpText->setText(tr(ThermalBoundaryHelpTexts[ui->comboThermalBoundaryType->currentIndex()])); +} + + +void TaskFemConstraintFluidBoundary::updateSelectionUI() +{ + if (ui->listReferences->model()->rowCount() == 0) { + // Go into reference selection mode if no reference has been selected yet + onButtonReference(true); + return; + } + + /** not needed for fluid boundary, as it must be Face + std::string ref = ui->listReferences->item(0)->text().toStdString(); + int pos = ref.find_last_of(":"); + if (ref.substr(pos+1, 6) == "Vertex") + ui->labelForce->setText(tr("Point load")); + else if (ref.substr(pos+1, 4) == "Edge") + ui->labelForce->setText(tr("Line load")); + else if (ref.substr(pos+1, 4) == "Face") + ui->labelForce->setText(tr("Area load")); + */ +} + +void TaskFemConstraintFluidBoundary::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + // Don't allow selection in other document + if (strcmp(msg.pDocName, ConstraintView->getObject()->getDocument()->getName()) != 0) + return; + + if (!msg.pSubName || msg.pSubName[0] == '\0') + return; + std::string subName(msg.pSubName); + + if (selectionMode == selnone) + return; + + std::vector references(1,subName); + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(ConstraintView->getObject()); + App::DocumentObject* obj = ConstraintView->getObject()->getDocument()->getObject(msg.pObjectName); + Part::Feature* feat = static_cast(obj); + TopoDS_Shape ref = feat->Shape.getShape().getSubShape(subName.c_str()); + //* string conversion: toStdString()/fromStdString() + if (selectionMode == selref) { + std::vector Objects = pcConstraint->References.getValues(); + std::vector SubElements = pcConstraint->References.getSubValues(); + + // Ensure we don't have mixed reference types + if (SubElements.size() > 0) { + if (subName.substr(0,4) != SubElements.front().substr(0,4)) { + QMessageBox::warning(this, tr("Selection error"), tr("Mixed shape types are not possible. Use a second constraint instead")); + return; + } + } + else { + if ((subName.substr(0,4) != "Face")) { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces can be picked for fluid boundary")); + return; + } + } + + // Avoid duplicates + std::size_t pos = 0; + for (; pos < Objects.size(); pos++) { + if (obj == Objects[pos]) { + break; + } + } + + if (pos != Objects.size()) { + if (subName == SubElements[pos]) { + return; + } + } + + // add the new reference + Objects.push_back(obj); + SubElements.push_back(subName); + pcConstraint->References.setValues(Objects,SubElements); + ui->listReferences->addItem(makeRefText(obj, subName)); + + // Turn off reference selection mode + onButtonReference(false); + } + else if (selectionMode == seldir) { + if (subName.substr(0,4) == "Face") { + if (!Fem::Tools::isPlanar(TopoDS::Face(ref))) { + QMessageBox::warning(this, tr("Selection error"), tr("Only planar faces can be picked")); + return; + } + } + else { + QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked")); + return; + } + pcConstraint->Direction.setValue(obj, references); + ui->lineDirection->setText(makeRefText(obj, subName)); + // Turn off direction selection mode + onButtonDirection(false); + } + + Gui::Selection().clearSelection(); + updateSelectionUI(); + } +} + +void TaskFemConstraintFluidBoundary::onBoundaryTypeChanged(void) +{ + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->BoundaryType.setValue(ui->comboBoundaryType->currentIndex()); + updateBoundaryTypeUI(); + //ConstraintView->updateData(&pcConstraint->BoundaryType); //force a 3D redraw + //however, there is a bug of cube normal is not correct in redraw, close task panel , redraw is correct +} + +void TaskFemConstraintFluidBoundary::onSubtypeChanged(void) +{ + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Subtype.setValue(ui->comboSubtype->currentIndex()); + updateSubtypeUI(); +} + + +void TaskFemConstraintFluidBoundary::onTurbulenceSpecificationChanged(void) +{ + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->TurbulenceSpecification.setValue(ui->comboTurbulenceSpecification->currentIndex()); + updateTurbulenceUI(); +} + +void TaskFemConstraintFluidBoundary::onThermalBoundaryTypeChanged(void) +{ + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->ThermalBoundaryType.setValue(ui->comboThermalBoundaryType->currentIndex()); + updateThermalBoundaryUI(); +} + +void TaskFemConstraintFluidBoundary::onReferenceDeleted() { + int row = ui->listReferences->currentIndex().row(); + TaskFemConstraint::onReferenceDeleted(row); + ui->listReferences->model()->removeRow(row); + ui->listReferences->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); +} + +void TaskFemConstraintFluidBoundary::onButtonDirection(const bool pressed) { + if (pressed) { + selectionMode = seldir; + } else { + selectionMode = selnone; + } + ui->buttonDirection->setChecked(pressed); + Gui::Selection().clearSelection(); +} + +void TaskFemConstraintFluidBoundary::onCheckReverse(const bool pressed) +{ + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(ConstraintView->getObject()); + pcConstraint->Reversed.setValue(pressed); +} + +std::string TaskFemConstraintFluidBoundary::getBoundaryType(void) const +{ + return Base::Tools::toStdString(ui->comboBoundaryType->currentText()); +} + +std::string TaskFemConstraintFluidBoundary::getSubtype(void) const +{ + return Base::Tools::toStdString(ui->comboSubtype->currentText()); +} + +double TaskFemConstraintFluidBoundary::getBoundaryValue(void) const +{ + return ui->spinBoundaryValue->value(); +} + + +std::string TaskFemConstraintFluidBoundary::getTurbulenceModel(void) const +{ + if(pTurbulenceModel){ + return pTurbulenceModel->getValueAsString(); + } + else{ + return "wall"; + } +} +std::string TaskFemConstraintFluidBoundary::getTurbulenceSpecification(void) const +{ + return Base::Tools::toStdString(ui->comboTurbulenceSpecification->currentText()); +} +double TaskFemConstraintFluidBoundary::getTurbulentIntensityValue(void) const +{ + return ui->spinTurbulentIntensityValue->value(); +} +double TaskFemConstraintFluidBoundary::getTurbulentLengthValue(void) const +{ + return ui->spinTurbulentLengthValue->value(); +} + + +bool TaskFemConstraintFluidBoundary::getHeatTransfering(void) const +{ + if(pHeatTransfering){ + return pHeatTransfering->getValue(); + } + else{ + return false; + } +} +std::string TaskFemConstraintFluidBoundary::getThermalBoundaryType(void) const +{ + return Base::Tools::toStdString(ui->comboThermalBoundaryType->currentText()); +} + +double TaskFemConstraintFluidBoundary::getTemperatureValue(void) const +{ + return ui->spinTemperatureValue->value(); +} + +double TaskFemConstraintFluidBoundary::getHeatFluxValue(void) const +{ + return ui->spinHeatFluxValue->value(); +} +double TaskFemConstraintFluidBoundary::getHTCoeffValue(void) const +{ + return ui->spinHTCoeffValue->value(); +} + + +const std::string TaskFemConstraintFluidBoundary::getReferences() const +{ + int rows = ui->listReferences->model()->rowCount(); + + std::vector items; + for (int r = 0; r < rows; r++) + items.push_back(ui->listReferences->item(r)->text().toStdString()); + return TaskFemConstraint::getReferences(items); +} + +const std::string TaskFemConstraintFluidBoundary::getDirectionName(void) const +{ + std::string dir = ui->lineDirection->text().toStdString(); + if (dir.empty()) + return ""; + + int pos = dir.find_last_of(":"); + return dir.substr(0, pos).c_str(); +} + +const std::string TaskFemConstraintFluidBoundary::getDirectionObject(void) const +{ + std::string dir = ui->lineDirection->text().toStdString(); + if (dir.empty()) + return ""; + + int pos = dir.find_last_of(":"); + return dir.substr(pos+1).c_str(); +} + +bool TaskFemConstraintFluidBoundary::getReverse() const +{ + return ui->checkReverse->isChecked(); +} + +TaskFemConstraintFluidBoundary::~TaskFemConstraintFluidBoundary() +{ + delete ui; +} + +void TaskFemConstraintFluidBoundary::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->spinBoundaryValue->blockSignals(true); + //more ui widget? those UI are does not support tr yet! + ui->retranslateUi(proxy); + + ui->spinBoundaryValue->blockSignals(false); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgFemConstraintFluidBoundary::TaskDlgFemConstraintFluidBoundary(ViewProviderFemConstraintFluidBoundary *ConstraintView) +{ + this->ConstraintView = ConstraintView; + assert(ConstraintView); + this->parameter = new TaskFemConstraintFluidBoundary(ConstraintView);; + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +void TaskDlgFemConstraintFluidBoundary::open() +{ + // a transaction is already open at creation time of the panel + if (!Gui::Command::hasPendingCommand()) { + QString msg = QObject::tr("Constraint fluid boundary"); + Gui::Command::openCommand((const char*)msg.toUtf8()); + } +} + +bool TaskDlgFemConstraintFluidBoundary::accept() +{ + std::string name = ConstraintView->getObject()->getNameInDocument(); + const TaskFemConstraintFluidBoundary* boundary = static_cast(parameter); + + try { + //Gui::Command::openCommand("Fluid boundary condition changed"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.BoundaryType = '%s'", + name.c_str(), boundary->getBoundaryType().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Subtype = '%s'", + name.c_str(), boundary->getSubtype().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.BoundaryValue = %f", + name.c_str(), boundary->getBoundaryValue()); + + std::string dirname = boundary->getDirectionName().data(); + std::string dirobj = boundary->getDirectionObject().data(); + + if (!dirname.empty()) { + QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); + buf = buf.arg(QString::fromStdString(dirname)); + buf = buf.arg(QString::fromStdString(dirobj)); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = %s", name.c_str(), buf.toStdString().c_str()); + } else { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str()); + } + //Reverse control is done at BoundaryType selection, this UI is hiden from user + //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %s", name.c_str(), boundary->getReverse() ? "True" : "False"); + + std::string scale = "1"; + scale = boundary->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 + + //solver specific setting + Fem::FemSolverObject* pcSolver = NULL; + if (FemGui::ActiveAnalysisObserver::instance()->hasActiveObject()) { + Fem::FemAnalysis* pcAnalysis = FemGui::ActiveAnalysisObserver::instance()->getActiveObject(); + //Fem::FemSolverObject is derived from DocumentObject + std::vector fem = pcAnalysis->Member.getValues(); + for (std::vector::iterator it = fem.begin(); it != fem.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(Fem::FemSolverObject::getClassTypeId())) + pcSolver = static_cast(*it); + } + } + if(pcSolver){ + App::PropertyBool* pHeatTransfering = NULL; + App::PropertyEnumeration* pTurbulenceModel = NULL; + pHeatTransfering = static_cast(pcSolver->getPropertyByName("HeatTransfering")); + pTurbulenceModel = static_cast(pcSolver->getPropertyByName("TurbulenceModel")); + + if(pHeatTransfering && pHeatTransfering->getValue()){ + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThermalBoundaryType = '%s'",name.c_str(), boundary->getThermalBoundaryType().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.TemperatureValue = %f",name.c_str(), boundary->getTemperatureValue()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.HeatFluxValue = %f",name.c_str(), boundary->getHeatFluxValue()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.HTCoeffValue = %f",name.c_str(), boundary->getHTCoeffValue()); + } + if(pTurbulenceModel && std::string(pTurbulenceModel->getValueAsString()) != "laminar"){ + //update turbulence and thermal boundary settings, only if those models are activated + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.TurbulenceSpecification = '%s'",name.c_str(), boundary->getTurbulenceSpecification().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.TurbulentIntensityValue = %f",name.c_str(), boundary->getTurbulentIntensityValue()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.TurbulentLengthValue = %f",name.c_str(), boundary->getTurbulentLengthValue()); + } + } + //rename document obj according to boundaryType: + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); + return false; + } + + return TaskDlgFemConstraint::accept(); +} + +bool TaskDlgFemConstraintFluidBoundary::reject() +{ + // roll back the changes + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::updateActive(); + + return true; +} + +#include "moc_TaskFemConstraintFluidBoundary.cpp" diff --git a/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.h b/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.h new file mode 100644 index 000000000..45ebd3419 --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.h @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (c) 2016 Qingfeng Xia * + * * + * 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_TaskFemConstraintFluidBoundary_H +#define GUI_TASKVIEW_TaskFemConstraintFluidBoundary_H + +#include +#include +#include +#include + +#include "TaskFemConstraint.h" +#include "ViewProviderFemConstraintFluidBoundary.h" + +class Ui_TaskFemConstraintFluidBoundary; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace FemGui { + +class TaskFemConstraintFluidBoundary : public TaskFemConstraint +{ + Q_OBJECT + +public: + TaskFemConstraintFluidBoundary(ViewProviderFemConstraintFluidBoundary *ConstraintView,QWidget *parent = 0); + virtual ~TaskFemConstraintFluidBoundary(); + + std::string getBoundaryType(void) const; + std::string getSubtype(void) const; + double getBoundaryValue(void) const; + + std::string getTurbulenceModel(void) const; + std::string getTurbulenceSpecification(void) const; + double getTurbulentIntensityValue(void) const; + double getTurbulentLengthValue(void) const; + + bool getHeatTransfering(void) const; + std::string getThermalBoundaryType(void) const; + double getTemperatureValue(void) const; + double getHeatFluxValue(void) const; + double getHTCoeffValue(void) const; + + virtual const std::string getReferences() const; + const std::string getDirectionName(void) const; + const std::string getDirectionObject(void) const; + bool getReverse(void) const; + +private Q_SLOTS: + void onBoundaryTypeChanged(void); + void onSubtypeChanged(void); + void onTurbulenceSpecificationChanged(void); + void onThermalBoundaryTypeChanged(void); + void onReferenceDeleted(void); + void onButtonDirection(const bool pressed = true); + void onCheckReverse(bool); + +protected: + virtual void changeEvent(QEvent *e); + +private: + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + void updateSelectionUI(); + void updateBoundaryTypeUI(); + void updateSubtypeUI(); + void updateThermalBoundaryUI(); + void updateTurbulenceUI(); + +private: + Ui_TaskFemConstraintFluidBoundary* ui; + App::PropertyBool* pHeatTransfering; + App::PropertyEnumeration* pTurbulenceModel; +}; + +/// simulation dialog for the TaskView +class TaskDlgFemConstraintFluidBoundary : public TaskDlgFemConstraint +{ + Q_OBJECT + +public: + TaskDlgFemConstraintFluidBoundary(ViewProviderFemConstraintFluidBoundary *ConstraintView); + + /// is called by the framework if the dialog is accepted (Ok) + virtual void open(); + virtual bool accept(); + virtual bool reject(); + +}; + +} //namespace FemGui + +#endif // GUI_TASKVIEW_TaskFemConstraintFluidBoundary_H diff --git a/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.ui b/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.ui new file mode 100644 index 000000000..18f27440a --- /dev/null +++ b/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.ui @@ -0,0 +1,376 @@ + + + TaskFemConstraintFluidBoundary + + + + 0 + 0 + 280 + 475 + + + + Form + + + + + + + + + 0 + 0 + + + + Boundary + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Subtype + + + + + + + + 0 + 0 + + + + + + + + + + Add geometry reference + + + + + + + + 0 + 0 + + + + + 16777215 + 120 + + + + + 0 + 30 + + + + + + + + HelpText + + + true + + + + + + + true + + + 2 + + + + true + + + Tab 1 + + + + true + + + + 10 + 90 + 148 + 22 + + + + Reverse direction + + + + + + 10 + 10 + 241 + 71 + + + + + + + true + + + + 100 + 0 + + + + Value [Unit] + + + + + + + true + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 0.000000000000000 + + + + + + + Direction + + + + + + + + 0 + 0 + + + + + 75 + 0 + + + + + 0 + 0 + + + + + + + + + + Page + + + + true + + + + 0 + 0 + 261 + 151 + + + + + 0 + 0 + + + + + 0 + 100 + + + + Turbulence specification + + + false + + + false + + + + + + + 0 + 0 + + + + + + + + + + Intensity + + + + + + + + + + + + + + Length [m] + + + + + + + + + + comboTurbulenceSpecification + + + + + + Tab 2 + + + + + + + + Type + + + + + + + + + + Temp[K] + + + + + + + -273.149999999999977 + + + 9999.000000000000000 + + + + + + + Heat flux + + + + + + + 0.000000000000000 + + + 99999.000000000000000 + + + 0.000000000000000 + + + + + + + HT coeff + + + + + + + 0.000000000000000 + + + 99999.000000000000000 + + + 0.000000000000000 + + + + + + + + + + + + + + diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintFluidBoundary.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintFluidBoundary.cpp new file mode 100644 index 000000000..202713e9d --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintFluidBoundary.cpp @@ -0,0 +1,297 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "ViewProviderFemConstraintFluidBoundary.h" +#include +#include "TaskFemConstraintFluidBoundary.h" +#include "Gui/Control.h" + +#include + +using namespace FemGui; + +PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintFluidBoundary, FemGui::ViewProviderFemConstraint) + + +ViewProviderFemConstraintFluidBoundary::ViewProviderFemConstraintFluidBoundary() +{ + sPixmap = "fem-constraint-fluid-boundary"; +} + +ViewProviderFemConstraintFluidBoundary::~ViewProviderFemConstraintFluidBoundary() +{ +} + +bool ViewProviderFemConstraintFluidBoundary::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default ) { + // When double-clicking on the item for this constraint, + // object unsets and sets its edit mode without closing the task panel + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + TaskDlgFemConstraintFluidBoundary *constrDlg = qobject_cast(dlg); + if (constrDlg && constrDlg->getConstraintView() != this) + constrDlg = 0; // another constraint left open its task panel + if (dlg && !constrDlg) { + // This case will occur in the ShaftWizard application + checkForWizard(); + if ((wizardWidget == NULL) || (wizardSubLayout == NULL)) { + // No shaft wizard is running + QMessageBox msgBox; + msgBox.setText(QObject::tr("A dialog is already open in the task panel")); + msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + int ret = msgBox.exec(); + if (ret == QMessageBox::Yes) + Gui::Control().reject(); + else + return false; + } else if (constraintDialog != NULL) { + // Another FemConstraint* dialog is already open inside the Shaft Wizard + // Ignore the request to open another dialog + return false; + } else { + constraintDialog = new TaskFemConstraintFluidBoundary(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 TaskDlgFemConstraintFluidBoundary(this)); + + return true; + } + else { + return ViewProviderDocumentObject::setEdit(ModNum); + } +} + +//Rendering: Combination of ConstraintFixed and ConstraintForce +#define ARROWLENGTH (4) +#define ARROWHEADRADIUS (ARROWLENGTH/3) +#define WIDTH (2) +#define HEIGHT (1) +//#define USE_MULTIPLE_COPY //OvG: MULTICOPY fails to update scaled display on initial drawing - so disable + +void ViewProviderFemConstraintFluidBoundary::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + Fem::ConstraintFluidBoundary* pcConstraint = static_cast(this->getObject()); + float scaledwidth = WIDTH * pcConstraint->Scale.getValue(); //OvG: Calculate scaled values once only + float scaledheight = HEIGHT * pcConstraint->Scale.getValue(); + + float scaledheadradius = ARROWHEADRADIUS * pcConstraint->Scale.getValue(); //OvG: Calculate scaled values once only + float scaledlength = ARROWLENGTH * pcConstraint->Scale.getValue(); + + std::string boundaryType = pcConstraint->BoundaryType.getValueAsString(); + if (strcmp(prop->getName(),"BoundaryType") == 0) + { + if (boundaryType == "wall") + { + FaceColor.setValue(0.0,1.0,1.0); + } + else if (boundaryType == "interface") + { + FaceColor.setValue(0.0,1.0,0.0); + } + else if (boundaryType == "freestream") + { + FaceColor.setValue(1.0,1.0,0.0); + } + else if(boundaryType == "inlet") + { + FaceColor.setValue(1.0,0.0,0.0); + } + else //(boundaryType == "outlet") + { + FaceColor.setValue(0.0,0.0,1.0); + } + } + + if (boundaryType == "inlet" || boundaryType == "outlet"){ +#ifdef USE_MULTIPLE_COPY + //OvG: need access to cp for scaling + SoMultipleCopy* cp = new SoMultipleCopy(); + if (pShapeSep->getNumChildren() == 0) { + // Set up the nodes + cp->matrix.setNum(0); + cp->addChild((SoNode*)createArrow(scaledlength , scaledheadradius)); //OvG: Scaling + pShapeSep->addChild(cp); + } +#endif + + if (strcmp(prop->getName(),"Points") == 0) { + const std::vector& points = pcConstraint->Points.getValues(); + +#ifdef USE_MULTIPLE_COPY + cp = static_cast(pShapeSep->getChild(0)); + cp->matrix.setNum(points.size()); + SbMatrix* matrices = cp->matrix.startEditing(); + int idx = 0; +#else + // Redraw all arrows + pShapeSep->removeAllChildren(); +#endif + // This should always point outside of the solid + Base::Vector3d normal = pcConstraint->NormalDirection.getValue(); + + // Get default direction (on first call to method) + Base::Vector3d forceDirection = pcConstraint->DirectionVector.getValue(); + if (forceDirection.Length() < Precision::Confusion()) + forceDirection = normal; + + SbVec3f dir(forceDirection.x, forceDirection.y, forceDirection.z); + SbRotation rot(SbVec3f(0,1,0), dir); + + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + SbVec3f base(p->x, p->y, p->z); + if (forceDirection.GetAngle(normal) < M_PI_2) // Move arrow so it doesn't disappear inside the solid + base = base + dir * scaledlength; //OvG: Scaling +#ifdef USE_MULTIPLE_COPY + SbMatrix m; + m.setTransform(base, rot, SbVec3f(1,1,1)); + matrices[idx] = m; + idx++; +#else + SoSeparator* sep = new SoSeparator(); + createPlacement(sep, base, rot); + createArrow(sep, scaledlength, scaledheadradius); //OvG: Scaling + pShapeSep->addChild(sep); +#endif + } +#ifdef USE_MULTIPLE_COPY + cp->matrix.finishEditing(); +#endif + } + else if (strcmp(prop->getName(),"DirectionVector") == 0) { // Note: "Reversed" also triggers "DirectionVector" + // Re-orient all arrows + Base::Vector3d normal = pcConstraint->NormalDirection.getValue(); + Base::Vector3d forceDirection = pcConstraint->DirectionVector.getValue(); + if (forceDirection.Length() < Precision::Confusion()) + forceDirection = normal; + + SbVec3f dir(forceDirection.x, forceDirection.y, forceDirection.z); + SbRotation rot(SbVec3f(0,1,0), dir); + + const std::vector& points = pcConstraint->Points.getValues(); + +#ifdef USE_MULTIPLE_COPY + SoMultipleCopy* cp = static_cast(pShapeSep->getChild(0)); + cp->matrix.setNum(points.size()); + SbMatrix* matrices = cp->matrix.startEditing(); +#endif + int idx = 0; + + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + SbVec3f base(p->x, p->y, p->z); + if (forceDirection.GetAngle(normal) < M_PI_2) + base = base + dir * scaledlength; //OvG: Scaling +#ifdef USE_MULTIPLE_COPY + SbMatrix m; + m.setTransform(base, rot, SbVec3f(1,1,1)); + matrices[idx] = m; +#else + SoSeparator* sep = static_cast(pShapeSep->getChild(idx)); + updatePlacement(sep, 0, base, rot); + updateArrow(sep, 2, scaledlength, scaledheadradius); //OvG: Scaling +#endif + idx++; + } +#ifdef USE_MULTIPLE_COPY + cp->matrix.finishEditing(); +#endif + } + } + else{// not inlet or outlet boundary type + +#ifdef USE_MULTIPLE_COPY + //OvG: always need access to cp for scaling + SoMultipleCopy* cp = new SoMultipleCopy(); + if (pShapeSep->getNumChildren() == 0) { + // Set up the nodes + cp->matrix.setNum(0); + cp->addChild((SoNode*)createFixed(scaledheight, scaledwidth)); //OvG: Scaling + pShapeSep->addChild(cp); + } +#endif + + if (strcmp(prop->getName(),"Points") == 0) { + const std::vector& points = pcConstraint->Points.getValues(); + const std::vector& normals = pcConstraint->Normals.getValues(); + if (points.size() != normals.size()) + return; + std::vector::const_iterator n = normals.begin(); + +#ifdef USE_MULTIPLE_COPY + cp = static_cast(pShapeSep->getChild(0)); + cp->matrix.setNum(points.size()); + SbMatrix* matrices = cp->matrix.startEditing(); + int idx = 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 dir(n->x, n->y, n->z); + SbRotation rot(SbVec3f(0,-1,0), dir); +#ifdef USE_MULTIPLE_COPY + SbMatrix m; + m.setTransform(base, rot, SbVec3f(1,1,1)); + matrices[idx] = m; + idx++; +#else + SoSeparator* sep = new SoSeparator(); + createPlacement(sep, base, rot); + createFixed(sep, scaledheight, scaledwidth); //OvG: Scaling + pShapeSep->addChild(sep); +#endif + n++; + } +#ifdef USE_MULTIPLE_COPY + cp->matrix.finishEditing(); +#endif + } + } + + ViewProviderFemConstraint::updateData(prop); +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintFluidBoundary.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintFluidBoundary.h new file mode 100644 index 000000000..150bc338f --- /dev/null +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintFluidBoundary.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_VIEWPROVIDERFEMFLUIDBOUNDARY_H +#define GUI_VIEWPROVIDERFEMFLUIDBOUNDARY_H + +#include "ViewProviderFemConstraint.h" + +namespace FemGui +{ + +class FemGuiExport ViewProviderFemConstraintFluidBoundary : public FemGui::ViewProviderFemConstraint +{ + PROPERTY_HEADER(FemGui::ViewProviderFemConstraintFluidBoundary); + +public: + /// Constructor + ViewProviderFemConstraintFluidBoundary(); + virtual ~ViewProviderFemConstraintFluidBoundary(); + + virtual void updateData(const App::Property*); + //virtual void onChanged(const App::Property*); //no further property for viewProvider +protected: + virtual bool setEdit(int ModNum); + +private: + /// Direction of the force + Base::Vector3f forceDirection; +}; + +} //namespace FemGui + + +#endif // GUI_VIEWPROVIDERFEMConstraintFluidBoundary_H