[FEM] improve displacement constraint

- use a Distance and Angle property to get the unit handling right
This commit is contained in:
Uwe
2023-03-22 18:02:35 +01:00
parent 633eb24f88
commit 7fd12f8454
10 changed files with 215 additions and 103 deletions

View File

@@ -27,6 +27,7 @@
#include <App/DocumentObject.h>
#include <App/FeaturePython.h>
#include <App/PropertyLinks.h>
#include <App/PropertyUnits.h>
#include <Base/Vector3D.h>
#include <Mod/Fem/FemGlobal.h>

View File

@@ -104,6 +104,45 @@ const char* ConstraintDisplacement::getViewProviderName() const
return "FemGui::ViewProviderFemConstraintDisplacement";
}
void ConstraintDisplacement::handleChangedPropertyType(Base::XMLReader& reader,
const char* TypeName,
App::Property* prop)
{
// properties _Displacement had App::PropertyFloat and were changed to App::PropertyDistance
if (prop == &xDisplacement && strcmp(TypeName, "App::PropertyFloat") == 0) {
App::PropertyDistance xDisplacementProperty;
// restore the PropertyFloat to be able to set its value
xDisplacementProperty.Restore(reader);
xDisplacement.setValue(xDisplacementProperty.getValue());
}
else if (prop == &yDisplacement && strcmp(TypeName, "App::PropertyFloat") == 0) {
App::PropertyDistance yDisplacementProperty;
yDisplacementProperty.Restore(reader);
yDisplacement.setValue(yDisplacementProperty.getValue());
}
else if (prop == &zDisplacement && strcmp(TypeName, "App::PropertyFloat") == 0) {
App::PropertyDistance zDisplacementProperty;
zDisplacementProperty.Restore(reader);
zDisplacement.setValue(zDisplacementProperty.getValue());
}
// properties _Displacement had App::PropertyFloat and were changed to App::PropertyAngle
else if (prop == &xRotation && strcmp(TypeName, "App::PropertyFloat") == 0) {
App::PropertyDistance xRotationProperty;
xRotationProperty.Restore(reader);
xRotation.setValue(xRotationProperty.getValue());
}
else if (prop == &yRotation && strcmp(TypeName, "App::PropertyFloat") == 0) {
App::PropertyDistance yRotationProperty;
yRotationProperty.Restore(reader);
yRotation.setValue(yRotationProperty.getValue());
}
else if (prop == &zRotation && strcmp(TypeName, "App::PropertyFloat") == 0) {
App::PropertyDistance zRotationProperty;
zRotationProperty.Restore(reader);
zRotation.setValue(zRotationProperty.getValue());
}
}
void ConstraintDisplacement::onChanged(const App::Property* prop)
{
// Note: If we call this at the end, then the arrows are not oriented correctly initially

View File

@@ -23,12 +23,12 @@
* *
***************************************************************************/
#ifndef FEM_CONSTRAINTDISPLACEMENT_H
#define FEM_CONSTRAINTDISPLACEMENT_H
#include "FemConstraint.h"
namespace Fem
{
@@ -45,12 +45,12 @@ public:
App::PropertyVectorList Normals;
//Displacement parameters
App::PropertyFloat xDisplacement;
App::PropertyFloat yDisplacement;
App::PropertyFloat zDisplacement;
App::PropertyFloat xRotation;
App::PropertyFloat yRotation;
App::PropertyFloat zRotation;
App::PropertyDistance xDisplacement;
App::PropertyDistance yDisplacement;
App::PropertyDistance zDisplacement;
App::PropertyAngle xRotation;
App::PropertyAngle yRotation;
App::PropertyAngle zRotation;
App::PropertyString xDisplacementFormula;
App::PropertyString yDisplacementFormula;
App::PropertyString zDisplacementFormula;
@@ -78,6 +78,8 @@ public:
const char* getViewProviderName() const override;
protected:
void handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName,
App::Property* prop) override;
void onChanged(const App::Property* prop) override;
};

View File

@@ -82,15 +82,15 @@ TaskFemConstraintDisplacement::TaskFemConstraintDisplacement(
// Get the feature data
Fem::ConstraintDisplacement* pcConstraint =
static_cast<Fem::ConstraintDisplacement*>(ConstraintView->getObject());
double fStates[6] {};
Base::Quantity fStates[6] {};
const char* sStates[3] {};
bool bStates[16] {};
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();
fStates[0] = pcConstraint->xDisplacement.getQuantityValue();
fStates[1] = pcConstraint->yDisplacement.getQuantityValue();
fStates[2] = pcConstraint->zDisplacement.getQuantityValue();
fStates[3] = pcConstraint->xRotation.getQuantityValue();
fStates[4] = pcConstraint->yRotation.getQuantityValue();
fStates[5] = pcConstraint->zRotation.getQuantityValue();
sStates[0] = pcConstraint->xDisplacementFormula.getValue();
sStates[1] = pcConstraint->yDisplacementFormula.getValue();
sStates[2] = pcConstraint->zDisplacementFormula.getValue();
@@ -170,6 +170,14 @@ TaskFemConstraintDisplacement::TaskFemConstraintDisplacement(
buttonGroup->addButton(ui->btnAdd, (int)SelectionChangeModes::refAdd);
buttonGroup->addButton(ui->btnRemove, (int)SelectionChangeModes::refRemove);
// Bind input fields to properties
ui->spinxDisplacement->bind(pcConstraint->xDisplacement);
ui->spinyDisplacement->bind(pcConstraint->yDisplacement);
ui->spinzDisplacement->bind(pcConstraint->zDisplacement);
ui->spinxRotation->bind(pcConstraint->xRotation);
ui->spinyRotation->bind(pcConstraint->yRotation);
ui->spinzRotation->bind(pcConstraint->zRotation);
updateUI();
}
@@ -432,34 +440,34 @@ const std::string TaskFemConstraintDisplacement::getReferences() const
return TaskFemConstraint::getReferences(items);
}
double TaskFemConstraintDisplacement::get_spinxDisplacement() const
std::string TaskFemConstraintDisplacement::get_spinxDisplacement() const
{
return ui->spinxDisplacement->value();
return ui->spinxDisplacement->value().getSafeUserString().toStdString();
}
double TaskFemConstraintDisplacement::get_spinyDisplacement() const
std::string TaskFemConstraintDisplacement::get_spinyDisplacement() const
{
return ui->spinyDisplacement->value();
return ui->spinyDisplacement->value().getSafeUserString().toStdString();
}
double TaskFemConstraintDisplacement::get_spinzDisplacement() const
std::string TaskFemConstraintDisplacement::get_spinzDisplacement() const
{
return ui->spinzDisplacement->value();
return ui->spinzDisplacement->value().getSafeUserString().toStdString();
}
double TaskFemConstraintDisplacement::get_spinxRotation() const
std::string TaskFemConstraintDisplacement::get_spinxRotation() const
{
return ui->spinxRotation->value();
return ui->spinxRotation->value().getSafeUserString().toStdString();
}
double TaskFemConstraintDisplacement::get_spinyRotation() const
std::string TaskFemConstraintDisplacement::get_spinyRotation() const
{
return ui->spinyRotation->value();
return ui->spinyRotation->value().getSafeUserString().toStdString();
}
double TaskFemConstraintDisplacement::get_spinzRotation() const
std::string TaskFemConstraintDisplacement::get_spinzRotation() const
{
return ui->spinzRotation->value();
return ui->spinzRotation->value().getSafeUserString().toStdString();
}
std::string TaskFemConstraintDisplacement::get_xFormula() const
@@ -625,27 +633,31 @@ bool TaskDlgFemConstraintDisplacement::accept()
static_cast<const TaskFemConstraintDisplacement*>(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.xDisplacement = \"%s\"",
name.c_str(),
parameterDisplacement->get_spinxDisplacement().c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.xDisplacementFormula = \"%s\"",
name.c_str(), parameterDisplacement->get_xFormula().c_str());
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.yDisplacement = \"%s\"",
name.c_str(),
parameterDisplacement->get_spinyDisplacement().c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.yDisplacementFormula = \"%s\"",
name.c_str(), parameterDisplacement->get_yFormula().c_str());
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.zDisplacement = \"%s\"",
name.c_str(),
parameterDisplacement->get_spinzDisplacement().c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.zDisplacementFormula = \"%s\"",
name.c_str(), parameterDisplacement->get_zFormula().c_str());
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.xRotation = %f",
name.c_str(), parameterDisplacement->get_spinxRotation());
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.yRotation = %f",
name.c_str(), parameterDisplacement->get_spinyRotation());
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.zRotation = %f",
name.c_str(), parameterDisplacement->get_spinzRotation());
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.xRotation = \"%s\"",
name.c_str(), parameterDisplacement->get_spinxRotation().c_str());
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.yRotation = \"%s\"",
name.c_str(), parameterDisplacement->get_spinyRotation().c_str());
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.zRotation = \"%s\"",
name.c_str(),
parameterDisplacement->get_spinzRotation().c_str());
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.xFree = %s",
name.c_str(),
parameterDisplacement->get_dispxfree() ? "True" : "False");
@@ -696,7 +708,7 @@ bool TaskDlgFemConstraintDisplacement::accept()
name.c_str(),
parameterDisplacement->get_useFlowSurfaceForce() ? "True"
: "False");
std::string scale = parameterDisplacement->getScale();// OvG: determine modified scale
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.Scale = %s",

View File

@@ -48,31 +48,32 @@ public:
explicit TaskFemConstraintDisplacement(ViewProviderFemConstraintDisplacement* ConstraintView,
QWidget* parent = nullptr);
~TaskFemConstraintDisplacement() override;
const std::string getReferences() const override;
double get_spinxDisplacement()const;
double get_spinyDisplacement()const;
double get_spinzDisplacement()const;
double get_spinxRotation()const;
double get_spinyRotation()const;
double get_spinzRotation()const;
std::string get_spinxDisplacement() const;
std::string get_spinyDisplacement() const;
std::string get_spinzDisplacement() const;
std::string get_spinxRotation() const;
std::string get_spinyRotation() const;
std::string get_spinzRotation() const;
std::string get_xFormula() const;
std::string get_yFormula() const;
std::string get_zFormula() const;
bool get_dispxfix()const;
bool get_dispxfree()const;
bool get_dispxfix() const;
bool get_dispxfree() const;
bool get_hasDispXFormula() const;
bool get_dispyfix()const;
bool get_dispyfree()const;
bool get_dispyfix() const;
bool get_dispyfree() const;
bool get_hasDispYFormula() const;
bool get_dispzfix()const;
bool get_dispzfree()const;
bool get_dispzfix() const;
bool get_dispzfree() const;
bool get_hasDispZFormula() 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;
bool get_rotxfix() const;
bool get_rotxfree() const;
bool get_rotyfix() const;
bool get_rotyfree() const;
bool get_rotzfix() const;
bool get_rotzfree() const;
bool get_useFlowSurfaceForce() const;
private Q_SLOTS:

View File

@@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>300</width>
<height>617</height>
<height>649</height>
</rect>
</property>
<property name="sizePolicy">
@@ -110,8 +110,8 @@
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="spinxDisplacement"/>
<item row="2" column="0">
<widget class="QLineEdit" name="DisplacementXFormulaLE"/>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="dispxfix">
@@ -120,10 +120,7 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="DisplacementXFormulaLE"/>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QCheckBox" name="DisplacementXFormulaCB">
<property name="toolTip">
<string>Formulas are only valid
@@ -134,6 +131,13 @@ for the Emer solver</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="Gui::QuantitySpinBox" name="spinxDisplacement">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -146,8 +150,19 @@ for the Emer solver</string>
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="spinyDisplacement"/>
<item row="2" column="0">
<widget class="QLineEdit" name="DisplacementYFormulaLE"/>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="DisplacementYFormulaCB">
<property name="toolTip">
<string>Formulas are only valid
for the Emer solver</string>
</property>
<property name="text">
<string>Formula</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="dispyfix">
@@ -156,17 +171,10 @@ for the Emer solver</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="DisplacementYFormulaLE"/>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="DisplacementYFormulaCB">
<property name="toolTip">
<string>Formulas are only valid
for the Emer solver</string>
</property>
<property name="text">
<string>Formula</string>
<item row="0" column="0">
<widget class="Gui::QuantitySpinBox" name="spinyDisplacement">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
@@ -182,8 +190,8 @@ for the Emer solver</string>
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="spinzDisplacement"/>
<item row="2" column="0">
<widget class="QLineEdit" name="DisplacementZFormulaLE"/>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="dispzfix">
@@ -192,10 +200,7 @@ for the Emer solver</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="DisplacementZFormulaLE"/>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QCheckBox" name="DisplacementZFormulaCB">
<property name="toolTip">
<string>Formulas are only valid
@@ -206,6 +211,13 @@ for the Emer solver</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="Gui::QuantitySpinBox" name="spinzDisplacement">
<property name="unit" stdset="0">
<string>mm</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -265,7 +277,11 @@ generated by the flow
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="spinxRotation"/>
<widget class="Gui::QuantitySpinBox" name="spinxRotation">
<property name="unit" stdset="0">
<string notr="true">deg</string>
</property>
</widget>
</item>
</layout>
</widget>
@@ -279,9 +295,6 @@ generated by the flow
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="spinyRotation"/>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="rotyfix">
<property name="text">
@@ -289,6 +302,13 @@ generated by the flow
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="Gui::QuantitySpinBox" name="spinyRotation">
<property name="unit" stdset="0">
<string notr="true">deg</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -301,9 +321,6 @@ generated by the flow
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="spinzRotation"/>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="rotzfix">
<property name="text">
@@ -311,11 +328,25 @@ generated by the flow
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="Gui::QuantitySpinBox" name="spinzRotation">
<property name="unit" stdset="0">
<string notr="true">deg</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::QuantitySpinBox</class>
<extends>QWidget</extends>
<header>Gui/QuantitySpinBox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>

View File

@@ -25,6 +25,8 @@ __title__ = "FreeCAD FEM calculix constraint displacement"
__author__ = "Bernd Hahnebach"
__url__ = "https://www.freecadweb.org"
import FreeCAD
def get_analysis_types():
return "all" # write for all analysis types
@@ -68,26 +70,50 @@ def write_constraint(f, femobj, disp_obj, ccxwriter):
if disp_obj.xFix:
f.write("{},1\n".format(disp_obj.Name))
elif not disp_obj.xFree:
f.write("{},1,1,{:.13G}\n".format(disp_obj.Name, disp_obj.xDisplacement))
f.write(
"{},1,1,{}\n".format(
disp_obj.Name, FreeCAD.Units.Quantity(disp_obj.xDisplacement.getValueAs("mm"))
)
)
if disp_obj.yFix:
f.write("{},2\n".format(disp_obj.Name))
elif not disp_obj.yFree:
f.write("{},2,2,{:.13G}\n".format(disp_obj.Name, disp_obj.yDisplacement))
f.write(
"{},2,2,{}\n".format(
disp_obj.Name, FreeCAD.Units.Quantity(disp_obj.yDisplacement.getValueAs("mm"))
)
)
if disp_obj.zFix:
f.write("{},3\n".format(disp_obj.Name))
elif not disp_obj.zFree:
f.write("{},3,3,{:.13G}\n".format(disp_obj.Name, disp_obj.zDisplacement))
f.write(
"{},3,3,{}\n".format(
disp_obj.Name, FreeCAD.Units.Quantity(disp_obj.zDisplacement.getValueAs("mm"))
)
)
if ccxwriter.member.geos_beamsection or ccxwriter.member.geos_shellthickness:
if disp_obj.rotxFix:
f.write("{},4\n".format(disp_obj.Name))
elif not disp_obj.rotxFree:
f.write("{},4,4,{:.13G}\n".format(disp_obj.Name, disp_obj.xRotation))
f.write(
"{},4,4,{}\n".format(
disp_obj.Name, FreeCAD.Units.Quantity(disp_obj.xRotation.getValueAs("deg"))
)
)
if disp_obj.rotyFix:
f.write("{},5\n".format(disp_obj.Name))
elif not disp_obj.rotyFree:
f.write("{},5,5,{:.13G}\n".format(disp_obj.Name, disp_obj.yRotation))
f.write(
"{},5,5,{}\n".format(
disp_obj.Name, FreeCAD.Units.Quantity(disp_obj.yRotation.getValueAs("deg"))
)
)
if disp_obj.rotzFix:
f.write("{},6\n".format(disp_obj.Name))
elif not disp_obj.rotzFree:
f.write("{},6,6,{:.13G}\n".format(disp_obj.Name, disp_obj.zRotation))
f.write(
"{},6,6,{}\n".format(
disp_obj.Name, FreeCAD.Units.Quantity(disp_obj.zRotation.getValueAs("deg"))
)
)

View File

@@ -113,19 +113,19 @@ class DeformationWriter:
continue
if not obj.xFree:
if not obj.hasXFormula:
displacement = obj.xDisplacement * 0.001
displacement = float(obj.xDisplacement.getValueAs("m"))
else:
displacement = obj.xDisplacementFormula
self.write.boundary(name, "Displacement 1", displacement)
if not obj.yFree:
if not obj.hasYFormula:
displacement = obj.yDisplacement * 0.001
displacement = float(obj.yDisplacement.getValueAs("m"))
else:
displacement = obj.yDisplacementFormula
self.write.boundary(name, "Displacement 2", displacement)
if not obj.zFree:
if not obj.hasZFormula:
displacement = obj.zDisplacement * 0.001
displacement = float(obj.zDisplacement.getValueAs("m"))
else:
displacement = obj.zDisplacementFormula
self.write.boundary(name, "Displacement 3", displacement)

View File

@@ -329,19 +329,19 @@ class ElasticityWriter:
continue
if not obj.xFree:
if not obj.hasXFormula:
displacement = obj.xDisplacement * 0.001
displacement = float(obj.xDisplacement.getValueAs("m"))
else:
displacement = obj.xDisplacementFormula
self.write.boundary(name, "Displacement 1", displacement)
if not obj.yFree:
if not obj.hasYFormula:
displacement = obj.yDisplacement * 0.001
displacement = float(obj.yDisplacement.getValueAs("m"))
else:
displacement = obj.yDisplacementFormula
self.write.boundary(name, "Displacement 2", displacement)
if not obj.zFree:
if not obj.hasZFormula:
displacement = obj.zDisplacement * 0.001
displacement = float(obj.zDisplacement.getValueAs("m"))
else:
displacement = obj.zDisplacementFormula
self.write.boundary(name, "Displacement 3", displacement)

View File

@@ -394,7 +394,7 @@ ConstraintFixed,3
** Displacement constraint applied
** ConstraintDisplacmentPrescribed
*BOUNDARY
ConstraintDisplacmentPrescribed,3,3,-250
ConstraintDisplacmentPrescribed,3,3,-250.0
***********************************************************