Merge pull request #13900 from marioalexis84/fem-constraint_rigid_body

Fem: Add constraint rigid body
This commit is contained in:
Chris Hennes
2024-05-16 21:19:30 -04:00
committed by GitHub
33 changed files with 2590 additions and 0 deletions

View File

@@ -2027,6 +2027,7 @@ void Application::initTypes()
App::PropertyMagneticFluxDensity ::init();
App::PropertyMagnetization ::init();
App::PropertyMass ::init();
App::PropertyMoment ::init();
App::PropertyPressure ::init();
App::PropertyPower ::init();
App::PropertyShearModulus ::init();

View File

@@ -555,6 +555,17 @@ PropertyMass::PropertyMass()
setUnit(Base::Unit::Mass);
}
//**************************************************************************
// PropertyMoment
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyMoment, App::PropertyQuantity)
PropertyMoment::PropertyMoment()
{
setUnit(Base::Unit::Moment);
}
//**************************************************************************
// PropertyPressure
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

View File

@@ -540,6 +540,19 @@ public:
~PropertyMass() override = default;
};
/** Moment property
* This is a property for representing moment. It is basically a float
* property. On the Gui it has a quantity like N*m.
*/
class AppExport PropertyMoment: public PropertyQuantity
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
PropertyMoment();
~PropertyMoment() override = default;
};
/** Pressure property
* This is a property for representing pressure. It basically a float
* property. On the Gui it has a quantity like Pa.

View File

@@ -623,6 +623,9 @@ QString Unit::getTypeString() const
if (*this == Unit::YoungsModulus) {
return QString::fromLatin1("YoungsModulus");
}
if (*this == Unit::Moment) {
return QString::fromLatin1("Moment");
}
return {};
}
@@ -664,6 +667,7 @@ const Unit Unit::MagneticFieldStrength (-1,0,0,1);
const Unit Unit::MagneticFlux (2,1,-2,-1);
const Unit Unit::MagneticFluxDensity (0,1,-2,-1);
const Unit Unit::Magnetization (-1,0,0,1);
const Unit Unit::Moment (2, 1, -2);
const Unit Unit::Pressure (-1,1,-2);
const Unit Unit::Power (2, 1, -3);
const Unit Unit::ShearModulus (-1,1,-2);

View File

@@ -155,6 +155,7 @@ public:
static const Unit Force;
static const Unit Work;
static const Unit Power;
static const Unit Moment;
static const Unit SpecificEnergy;
static const Unit ThermalConductivity;

View File

@@ -272,6 +272,24 @@ UnitsSchemaInternal::schemaTranslate(const Quantity& quant, double& factor, QStr
factor = 1e9;
}
}
// else if (unit == Unit::Moment) {
// if (UnitValue < 1e6) {
// unitString = QString::fromLatin1("mNm");
// factor = 1e3;
// }
// else if (UnitValue < 1e9) {
// unitString = QString::fromLatin1("Nm");
// factor = 1e6;
// }
// else if (UnitValue < 1e12) {
// unitString = QString::fromLatin1("kNm");
// factor = 1e9;
// }
// else {
// unitString = QString::fromLatin1("MNm");
// factor = 1e12;
// }
// }
else if (unit == Unit::Power) {
if (UnitValue < 1e6) {
unitString = QString::fromLatin1("mW");

View File

@@ -261,6 +261,24 @@ QString UnitsSchemaMKS::schemaTranslate(const Quantity& quant, double& factor, Q
factor = 1e9;
}
}
// else if (unit == Unit::Moment) {
// if (UnitValue < 1e6) {
// unitString = QString::fromLatin1("mNm");
// factor = 1e3;
// }
// else if (UnitValue < 1e9) {
// unitString = QString::fromLatin1("Nm");
// factor = 1e6;
// }
// else if (UnitValue < 1e12) {
// unitString = QString::fromLatin1("kNm");
// factor = 1e9;
// }
// else {
// unitString = QString::fromLatin1("MNm");
// factor = 1e12;
// }
// }
else if (unit == Unit::Power) {
if (UnitValue < 1e6) {
unitString = QString::fromLatin1("mW");

View File

@@ -41,6 +41,7 @@
#include "FemConstraintPlaneRotation.h"
#include "FemConstraintPressure.h"
#include "FemConstraintPulley.h"
#include "FemConstraintRigidBody.h"
#include "FemConstraintSpring.h"
#include "FemConstraintTemperature.h"
#include "FemConstraintTransform.h"
@@ -142,6 +143,7 @@ PyMOD_INIT_FUNC(Fem)
Fem::ConstraintContact ::init();
Fem::ConstraintDisplacement ::init();
Fem::ConstraintFixed ::init();
Fem::ConstraintRigidBody ::init();
Fem::ConstraintFluidBoundary ::init();
Fem::ConstraintForce ::init();
Fem::ConstraintGear ::init();

View File

@@ -148,6 +148,8 @@ SET(FemConstraints_SRCS
FemConstraintBearing.cpp
FemConstraintFixed.cpp
FemConstraintFixed.h
FemConstraintRigidBody.cpp
FemConstraintRigidBody.h
FemConstraintForce.cpp
FemConstraintForce.h
FemConstraintFluidBoundary.cpp

View File

@@ -0,0 +1,128 @@
/***************************************************************************
* Copyright (c) 2022 Ajinkya Dahale <dahale.a.p@gmail.com> *
* *
* 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"
#include "FemConstraintRigidBody.h"
using namespace Fem;
PROPERTY_SOURCE(Fem::ConstraintRigidBody, Fem::Constraint)
const char* ConstraintRigidBody::boundaryModeEnum[] = {"Free", "Constraint", "Load", nullptr};
ConstraintRigidBody::ConstraintRigidBody()
{
ADD_PROPERTY_TYPE(ReferenceNode,
(0.0, 0.0, 0.0),
"ConstraintRigidBody",
App::Prop_Output,
"Reference node position");
ADD_PROPERTY_TYPE(Displacement,
(0.0, 0.0, 0.0),
"ConstraintRigidBody",
App::Prop_Output,
"Reference node displacement");
ADD_PROPERTY_TYPE(Rotation,
(Base::Rotation(0.0, 0.0, 0.0, 1.0)),
"ConstraintRigidBody",
App::Prop_Output,
"Reference node rotation");
ADD_PROPERTY_TYPE(ForceX,
(0.0),
"ConstraintRigidBody",
App::Prop_Output,
"Applied force in X direction");
ADD_PROPERTY_TYPE(ForceY,
(0.0),
"ConstraintRigidBody",
App::Prop_Output,
"Applied force in Y direction");
ADD_PROPERTY_TYPE(ForceZ,
(0.0),
"ConstraintRigidBody",
App::Prop_Output,
"Applied force in Z direction");
ADD_PROPERTY_TYPE(MomentX,
(0.0),
"ConstraintRigidBody",
App::Prop_Output,
"Applied moment in X direction");
ADD_PROPERTY_TYPE(MomentY,
(0.0),
"ConstraintRigidBody",
App::Prop_Output,
"Applied moment in Y direction");
ADD_PROPERTY_TYPE(MomentZ,
(0.0),
"ConstraintRigidBody",
App::Prop_Output,
"Applied moment in Z direction");
ADD_PROPERTY_TYPE(TranslationalModeX,
("Free"),
"ConstraintRigidBody",
App::Prop_Output,
"X-direction displacement/force mode");
ADD_PROPERTY_TYPE(TranslationalModeY,
("Free"),
"ConstraintRigidBody",
App::Prop_Output,
"Y-direction displacement/force mode");
ADD_PROPERTY_TYPE(TranslationalModeZ,
("Free"),
"ConstraintRigidBody",
App::Prop_Output,
"Z-direction displacement/force mode");
ADD_PROPERTY_TYPE(RotationalModeX,
("None"),
"ConstraintRigidBody",
App::Prop_Output,
"X-direction rotation/moment mode");
ADD_PROPERTY_TYPE(RotationalModeY,
("None"),
"ConstraintRigidBody",
App::Prop_Output,
"Y-direction rotation/moment mode");
ADD_PROPERTY_TYPE(RotationalModeZ,
("None"),
"ConstraintRigidBody",
App::Prop_Output,
"Z-direction rotation/moment mode");
TranslationalModeX.setEnums(boundaryModeEnum);
TranslationalModeY.setEnums(boundaryModeEnum);
TranslationalModeZ.setEnums(boundaryModeEnum);
RotationalModeX.setEnums(boundaryModeEnum);
RotationalModeY.setEnums(boundaryModeEnum);
RotationalModeZ.setEnums(boundaryModeEnum);
}
App::DocumentObjectExecReturn* ConstraintRigidBody::execute()
{
return Constraint::execute();
}
void ConstraintRigidBody::onChanged(const App::Property* prop)
{
Constraint::onChanged(prop);
}

View File

@@ -0,0 +1,76 @@
/***************************************************************************
* Copyright (c) 2022 Ajinkya Dahale <dahale.a.p@gmail.com> *
* *
* 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_CONSTRAINTRIGIDBODY_H
#define FEM_CONSTRAINTRIGIDBODY_H
#include "FemConstraint.h"
namespace Fem
{
class FemExport ConstraintRigidBody: public Fem::Constraint
{
PROPERTY_HEADER_WITH_OVERRIDE(Fem::ConstraintRigidBody);
public:
/// Constructor
ConstraintRigidBody();
// Rigid Body parameters
App::PropertyPosition ReferenceNode;
App::PropertyPosition Displacement;
App::PropertyRotation Rotation;
App::PropertyForce ForceX;
App::PropertyForce ForceY;
App::PropertyForce ForceZ;
App::PropertyMoment MomentX;
App::PropertyMoment MomentY;
App::PropertyMoment MomentZ;
App::PropertyEnumeration TranslationalModeX;
App::PropertyEnumeration TranslationalModeY;
App::PropertyEnumeration TranslationalModeZ;
App::PropertyEnumeration RotationalModeX;
App::PropertyEnumeration RotationalModeY;
App::PropertyEnumeration RotationalModeZ;
/// recalculate the object
App::DocumentObjectExecReturn* execute() override;
/// returns the type name of the ViewProvider
const char* getViewProviderName() const override
{
return "FemGui::ViewProviderFemConstraintRigidBody";
}
protected:
void onChanged(const App::Property* prop) override;
private:
static const char* boundaryModeEnum[];
};
} // namespace Fem
#endif // FEM_CONSTRAINTRIGIDBODY_H

View File

@@ -231,6 +231,8 @@ SET(FemSolverCalculix_SRCS
femsolver/calculix/write_constraint_initialtemperature.py
femsolver/calculix/write_constraint_planerotation.py
femsolver/calculix/write_constraint_pressure.py
femsolver/calculix/write_constraint_rigidbody.py
femsolver/calculix/write_constraint_rigidbody_step.py
femsolver/calculix/write_constraint_sectionprint.py
femsolver/calculix/write_constraint_selfweight.py
femsolver/calculix/write_constraint_temperature.py

View File

@@ -51,6 +51,7 @@
#include "ViewProviderFemConstraintContact.h"
#include "ViewProviderFemConstraintDisplacement.h"
#include "ViewProviderFemConstraintFixed.h"
#include "ViewProviderFemConstraintRigidBody.h"
#include "ViewProviderFemConstraintForce.h"
#include "ViewProviderFemConstraintFluidBoundary.h"
#include "ViewProviderFemConstraintGear.h"
@@ -120,6 +121,7 @@ PyMOD_INIT_FUNC(FemGui)
FemGui::ViewProviderFemConstraintContact ::init();
FemGui::ViewProviderFemConstraintDisplacement ::init();
FemGui::ViewProviderFemConstraintFixed ::init();
FemGui::ViewProviderFemConstraintRigidBody ::init();
FemGui::ViewProviderFemConstraintFluidBoundary ::init();
FemGui::ViewProviderFemConstraintForce ::init();
FemGui::ViewProviderFemConstraintGear ::init();

View File

@@ -63,6 +63,7 @@ set(FemGui_UIC_SRCS
TaskFemConstraint.ui
TaskFemConstraintBearing.ui
TaskFemConstraintFixed.ui
TaskFemConstraintRigidBody.ui
TaskFemConstraintForce.ui
TaskFemConstraintFluidBoundary.ui
TaskFemConstraintPressure.ui
@@ -134,6 +135,9 @@ SET(FemGui_DLG_SRCS
TaskFemConstraintFixed.ui
TaskFemConstraintFixed.cpp
TaskFemConstraintFixed.h
TaskFemConstraintRigidBody.ui
TaskFemConstraintRigidBody.cpp
TaskFemConstraintRigidBody.h
TaskFemConstraintForce.ui
TaskFemConstraintForce.cpp
TaskFemConstraintForce.h
@@ -210,6 +214,8 @@ SET(FemGui_SRCS_ViewProvider
ViewProviderFemConstraintBearing.h
ViewProviderFemConstraintFixed.cpp
ViewProviderFemConstraintFixed.h
ViewProviderFemConstraintRigidBody.cpp
ViewProviderFemConstraintRigidBody.h
ViewProviderFemConstraintForce.cpp
ViewProviderFemConstraintForce.h
ViewProviderFemConstraintFluidBoundary.cpp
@@ -354,6 +360,7 @@ SET(FemGuiSymbol_IV
Resources/symbols/ConstraintHeatFlux.iv
Resources/symbols/ConstraintPlaneRotation.iv
Resources/symbols/ConstraintPressure.iv
Resources/symbols/ConstraintRigidBody.iv
Resources/symbols/ConstraintSpring.iv
Resources/symbols/ConstraintTemperature.iv
Resources/symbols/ConstraintTie.iv

View File

@@ -387,6 +387,58 @@ bool CmdFemConstraintFixed::isActive()
}
//================================================================================================
DEF_STD_CMD_A(CmdFemConstraintRigidBody)
CmdFemConstraintRigidBody::CmdFemConstraintRigidBody()
: Command("FEM_ConstraintRigidBody")
{
sAppModule = "Fem";
sGroup = QT_TR_NOOP("Fem");
sMenuText = QT_TR_NOOP("Constraint rigid body");
sToolTipText = QT_TR_NOOP("Creates a FEM constraint for a rigid body");
sWhatsThis = "FEM_ConstraintRigidBody";
sStatusTip = sToolTipText;
sPixmap = "FEM_ConstraintRigidBody";
}
void CmdFemConstraintRigidBody::activated(int)
{
Fem::FemAnalysis* Analysis;
if (getConstraintPrerequisits(&Analysis)) {
return;
}
std::string FeatName = getUniqueObjectName("ConstraintRigidBody");
openCommand(QT_TRANSLATE_NOOP("Command", "Make FEM constraint fixed geometry"));
doCommand(Doc,
"App.activeDocument().addObject(\"Fem::ConstraintRigidBody\",\"%s\")",
FeatName.c_str());
doCommand(Doc,
"App.activeDocument().%s.Scale = 1",
FeatName.c_str()); // OvG: set initial scale to 1
doCommand(Doc,
"App.activeDocument().%s.addObject(App.activeDocument().%s)",
Analysis->getNameInDocument(),
FeatName.c_str());
doCommand(Doc,
"%s",
gethideMeshShowPartStr(FeatName).c_str()); // OvG: Hide meshes and show parts
updateActive();
doCommand(Gui, "Gui.activeDocument().setEdit('%s')", FeatName.c_str());
}
bool CmdFemConstraintRigidBody::isActive()
{
return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject();
}
//================================================================================================
DEF_STD_CMD_A(CmdFemConstraintFluidBoundary)
@@ -2625,6 +2677,7 @@ void CreateFemCommands()
rcCmdMgr.addCommand(new CmdFemConstraintContact());
rcCmdMgr.addCommand(new CmdFemConstraintDisplacement());
rcCmdMgr.addCommand(new CmdFemConstraintFixed());
rcCmdMgr.addCommand(new CmdFemConstraintRigidBody());
rcCmdMgr.addCommand(new CmdFemConstraintFluidBoundary());
rcCmdMgr.addCommand(new CmdFemConstraintForce());
rcCmdMgr.addCommand(new CmdFemConstraintGear());

View File

@@ -29,6 +29,7 @@
<file>icons/FEM_ConstraintPlaneRotation.svg</file>
<file>icons/FEM_ConstraintPressure.svg</file>
<file>icons/FEM_ConstraintPulley.svg</file>
<file>icons/FEM_ConstraintRigidBody.svg</file>
<file>icons/FEM_ConstraintSectionPrint.svg</file>
<file>icons/FEM_ConstraintSelfWeight.svg</file>
<file>icons/FEM_ConstraintSpring.svg</file>

View File

@@ -0,0 +1,300 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64px"
height="64px"
id="svg2860"
sodipodi:version="0.32"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
sodipodi:docname="Rigid body icon 2.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2862">
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2868" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3851-7-2"
id="linearGradient3367"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-19.999999,-5.9999984)"
spreadMethod="reflect"
x1="-11"
y1="26"
x2="-18"
y2="14" />
<linearGradient
inkscape:collect="always"
id="linearGradient3851-7-2">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop3853-9-4" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop3855-8-4" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3838-1"
id="linearGradient3371"
gradientUnits="userSpaceOnUse"
x1="2802.9631"
y1="538.36249"
x2="2859.7263"
y2="786.05646" />
<linearGradient
inkscape:collect="always"
id="linearGradient3838-1">
<stop
style="stop-color:#34e0e2;stop-opacity:1"
offset="0"
id="stop3840-2" />
<stop
style="stop-color:#06989a;stop-opacity:1"
offset="1"
id="stop3842-0" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3859-3-8"
id="linearGradient3369"
gradientUnits="userSpaceOnUse"
x1="32.557789"
y1="32.917992"
x2="26.30212"
y2="12.206754" />
<linearGradient
inkscape:collect="always"
id="linearGradient3859-3-8">
<stop
style="stop-color:#edd400;stop-opacity:1"
offset="0"
id="stop3861-1-7" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop3863-2-4" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="9.03125"
inkscape:cx="-0.88581315"
inkscape:cy="34.435986"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-global="true"
inkscape:snap-bbox="true"
inkscape:snap-nodes="true"
inkscape:object-nodes="true"
inkscape:snap-grids="false"
inkscape:object-paths="false"
inkscape:snap-intersection-paths="true"
inkscape:snap-smooth-nodes="true"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showguides="false">
<inkscape:grid
type="xygrid"
id="grid3077"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2865">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>[vdwalts]</dc:title>
</cc:Agent>
</dc:creator>
<dc:date>2016-08-01</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3350"
transform="matrix(1.2132401,0,0,1.2243031,94.541045,3.2214691)">
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3063-1"
d="M -60.49828,12.297578 -44.276817,1.6539792 c 11.343458,-4.6432832 24.728769,13.2093768 12.401376,22.2560528 l -15.695501,9.840822 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:#edd400;fill-opacity:1;fill-rule:nonzero;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3063-3-0"
d="M -61.579091,15.205413 -45.631684,4.7575543 c 10.364771,-7.6968104 23.945833,10.6256217 12.009914,17.8715007 l -15.695501,9.840823 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3367);fill-opacity:1;fill-rule:nonzero;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3875-5-7"
d="m -51.199941,6 c 11.999989,-0.9999991 18.571392,11.000001 14.571396,20.999994"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3895-60"
d="M -51.999998,13 -35.000001,2.000001"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3895-6-1"
d="M -44.000006,21.999999 -27.000008,11.000001"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<g
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3371);fill-opacity:1;fill-rule:nonzero;stroke:#042a2a;stroke-width:15.059;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
transform="matrix(0.92148168,0.21647657,-0.04656812,0.97752701,-67.128334,5.0954655)"
id="g3031-0">
<path
inkscape:connector-curvature="0"
id="path3011-2"
d="m 44,22 c 0,6.627417 -5.372583,12 -12,12 -6.627417,0 -12,-5.372583 -12,-12 0,-6.627417 5.372583,-12 12,-12 6.627417,0 12,5.372583 12,12 z"
style="fill:#ef2929;stroke:#a40000;stroke-width:2.09559;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4"
transform="translate(-17,-7)" />
<path
inkscape:connector-curvature="0"
id="path3011-3-5"
d="m 44,22 c 0,6.627417 -5.372583,12 -12,12 -6.627417,0 -12,-5.372583 -12,-12 0,-6.627417 5.372583,-12 12,-12 6.627417,0 12,5.372583 12,12 z"
style="fill:url(#linearGradient3369);fill-opacity:1;stroke:#ef2929;stroke-width:2.5147;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4"
transform="matrix(0.83333334,0,0,0.83333333,-11.666667,-3.3333333)" />
</g>
<g
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#042a2a;stroke-width:15.059;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
transform="matrix(0.92148168,0.21647657,-0.04656812,0.97752701,-67.195852,5.0728652)"
id="g3031-3">
<path
inkscape:connector-curvature="0"
id="path3011-5"
d="m 44,22 c 0,6.627417 -5.372583,12 -12,12 -6.627417,0 -12,-5.372583 -12,-12 0,-6.627417 5.372583,-12 12,-12 6.627417,0 12,5.372583 12,12 z"
style="fill:none;stroke:#a40000;stroke-width:2.09559;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
transform="translate(-17,-7)" />
<path
inkscape:connector-curvature="0"
id="path3011-3-6"
d="m 44,22 c 0,6.627417 -5.372583,12 -12,12 -6.627417,0 -12,-5.372583 -12,-12 0,-6.627417 5.372583,-12 12,-12 6.627417,0 12,5.372583 12,12 z"
style="fill:none;stroke:#ef2929;stroke-width:2.5147;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4"
transform="matrix(0.83333334,0,0,0.83333333,-11.666667,-3.3333333)" />
</g>
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3867-1"
d="M -50.999999,12 V 34.999991"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#a40000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3869-9"
d="M -58.000006,12 V 32.99999"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#a40000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3871-7"
d="m -64,16 20.999994,6.999998"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#a40000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3873-1"
d="m -64.999999,22.999998 20.999993,6.999993"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:54.2152px;font-family:Arial;-inkscape-font-specification:Arial;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#a40000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
</g>
<path
style="fill:none;stroke:#008800;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 16.715031,24.075792 6.472382,54.966195 39.936147,39.616646"
id="path1766"
sodipodi:nodetypes="ccc" />
<path
style="fill:#008800;fill-opacity:1;stroke:#008900;stroke-width:2.19669;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path2789"
sodipodi:type="arc"
sodipodi:cx="5.4048667"
sodipodi:cy="56.144741"
sodipodi:rx="3.6746972"
sodipodi:ry="3.3471732"
sodipodi:start="0"
sodipodi:end="6.1171338"
sodipodi:arc-type="slice"
d="M 9.0795639,56.144741 A 3.6746972,3.3471732 0 0 1 5.5573701,59.489031 3.6746972,3.3471732 0 0 1 1.7428276,56.422323 3.6746972,3.3471732 0 0 1 4.948407,52.823491 3.6746972,3.3471732 0 0 1 9.0290188,55.591489 L 5.4048667,56.144741 Z" />
<path
style="fill:none;stroke:#008900;stroke-width:4.28125;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 11.053259,50.370761 29.542791,29.937553"
id="path555"
sodipodi:nodetypes="cc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,32 @@
#Inventor V2.1 ascii
Separator {
Separator {
Translation {
translation 0 2.5 0
}
Sphere {
radius 0.5
}
Translation {
translation 0 -1.25 0
}
Cylinder {
radius 0.25
height 2.5
}
}
Separator {
Sphere {
radius 0.25
}
}
}

View File

@@ -0,0 +1,747 @@
/***************************************************************************
* Copyright (c) 2022 Ajinkya Dahale <dahale.a.p@gmail.com> *
* *
* 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 <QAction>
#include <QMessageBox>
#include <sstream>
#endif
#include <App/Document.h>
#include <Gui/Command.h>
#include <Gui/SelectionObject.h>
#include <Mod/Fem/App/FemConstraintRigidBody.h>
#include "TaskFemConstraintRigidBody.h"
#include "ui_TaskFemConstraintRigidBody.h"
using namespace FemGui;
using namespace Gui;
/* TRANSLATOR FemGui::TaskFemConstraintRigidBody */
TaskFemConstraintRigidBody::TaskFemConstraintRigidBody(
ViewProviderFemConstraintRigidBody* ConstraintView,
QWidget* parent)
: TaskFemConstraintOnBoundary(ConstraintView, parent, "FEM_ConstraintRigidBody")
{ // Note change "RigidBody" in line above to new constraint name
proxy = new QWidget(this);
ui = new Ui_TaskFemConstraintRigidBody();
ui->setupUi(proxy);
QMetaObject::connectSlotsByName(this);
// create a context menu for the listview of the references
createDeleteAction(ui->lw_references);
deleteAction->connect(deleteAction,
&QAction::triggered,
this,
&TaskFemConstraintRigidBody::onReferenceDeleted);
connect(ui->lw_references,
&QListWidget::currentItemChanged,
this,
&TaskFemConstraintRigidBody::setSelection);
connect(ui->lw_references,
&QListWidget::itemClicked,
this,
&TaskFemConstraintRigidBody::setSelection);
connect(ui->cb_x_trans_mode,
qOverload<int>(&QComboBox::activated),
this,
&TaskFemConstraintRigidBody::onTransModeXChanged);
connect(ui->cb_y_trans_mode,
qOverload<int>(&QComboBox::activated),
this,
&TaskFemConstraintRigidBody::onTransModeYChanged);
connect(ui->cb_z_trans_mode,
qOverload<int>(&QComboBox::activated),
this,
&TaskFemConstraintRigidBody::onTransModeZChanged);
connect(ui->cb_x_rot_mode,
qOverload<int>(&QComboBox::activated),
this,
&TaskFemConstraintRigidBody::onRotModeXChanged);
connect(ui->cb_y_rot_mode,
qOverload<int>(&QComboBox::activated),
this,
&TaskFemConstraintRigidBody::onRotModeYChanged);
connect(ui->cb_z_rot_mode,
qOverload<int>(&QComboBox::activated),
this,
&TaskFemConstraintRigidBody::onRotModeZChanged);
this->groupLayout()->addWidget(proxy);
/* Note: */
// Get the feature data
auto pcConstraint = static_cast<Fem::ConstraintRigidBody*>(ConstraintView->getObject());
const Base::Vector3d& refNode = pcConstraint->ReferenceNode.getValue();
const Base::Vector3d& disp = pcConstraint->Displacement.getValue();
Base::Vector3d rotDir;
double rotAngleRad;
pcConstraint->Rotation.getValue().getValue(rotDir, rotAngleRad);
Base::Quantity rotAngle(rotAngleRad, QString::fromUtf8("rad"));
Base::Quantity forceX = pcConstraint->ForceX.getQuantityValue();
Base::Quantity forceY = pcConstraint->ForceY.getQuantityValue();
Base::Quantity forceZ = pcConstraint->ForceZ.getQuantityValue();
Base::Quantity momentX = pcConstraint->MomentX.getQuantityValue();
Base::Quantity momentY = pcConstraint->MomentY.getQuantityValue();
Base::Quantity momentZ = pcConstraint->MomentZ.getQuantityValue();
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
// Fill data into dialog elements
ui->qsb_ref_node_x->setValue(refNode.x);
ui->qsb_ref_node_y->setValue(refNode.y);
ui->qsb_ref_node_z->setValue(refNode.z);
ui->qsb_ref_node_x->bind(
App::ObjectIdentifier::parse(pcConstraint, std::string("ReferenceNode.x")));
ui->qsb_ref_node_y->bind(
App::ObjectIdentifier::parse(pcConstraint, std::string("ReferenceNode.y")));
ui->qsb_ref_node_z->bind(
App::ObjectIdentifier::parse(pcConstraint, std::string("ReferenceNode.z")));
ui->qsb_ref_node_x->setMinimum(-FLOAT_MAX);
ui->qsb_ref_node_x->setMaximum(FLOAT_MAX);
ui->qsb_ref_node_y->setMinimum(-FLOAT_MAX);
ui->qsb_ref_node_y->setMaximum(FLOAT_MAX);
ui->qsb_ref_node_z->setMinimum(-FLOAT_MAX);
ui->qsb_ref_node_z->setMaximum(FLOAT_MAX);
ui->qsb_disp_x->setValue(disp.x);
ui->qsb_disp_y->setValue(disp.y);
ui->qsb_disp_z->setValue(disp.z);
ui->qsb_disp_x->bind(App::ObjectIdentifier::parse(pcConstraint, std::string("Displacement.x")));
ui->qsb_disp_y->bind(App::ObjectIdentifier::parse(pcConstraint, std::string("Displacement.y")));
ui->qsb_disp_z->bind(App::ObjectIdentifier::parse(pcConstraint, std::string("Displacement.z")));
ui->qsb_disp_x->setMinimum(-FLOAT_MAX);
ui->qsb_disp_x->setMaximum(FLOAT_MAX);
ui->qsb_disp_y->setMinimum(-FLOAT_MAX);
ui->qsb_disp_y->setMaximum(FLOAT_MAX);
ui->qsb_disp_z->setMinimum(-FLOAT_MAX);
ui->qsb_disp_z->setMaximum(FLOAT_MAX);
ui->spb_rot_axis_x->setValue(rotDir.x);
ui->spb_rot_axis_y->setValue(rotDir.y);
ui->spb_rot_axis_z->setValue(rotDir.z);
ui->qsb_rot_angle->setValue(rotAngle.getValueAs(Base::Quantity::Degree));
ui->spb_rot_axis_x->bind(
App::ObjectIdentifier::parse(pcConstraint, std::string("Rotation.Axis.x")));
ui->spb_rot_axis_y->bind(
App::ObjectIdentifier::parse(pcConstraint, std::string("Rotation.Axis.y")));
ui->spb_rot_axis_z->bind(
App::ObjectIdentifier::parse(pcConstraint, std::string("Rotation.Axis.z")));
ui->qsb_rot_angle->bind(
App::ObjectIdentifier::parse(pcConstraint, std::string("Rotation.Angle")));
ui->spb_rot_axis_x->setMinimum(-FLOAT_MAX);
ui->spb_rot_axis_x->setMaximum(FLOAT_MAX);
ui->spb_rot_axis_y->setMinimum(-FLOAT_MAX);
ui->spb_rot_axis_y->setMaximum(FLOAT_MAX);
ui->spb_rot_axis_z->setMinimum(-FLOAT_MAX);
ui->spb_rot_axis_z->setMaximum(FLOAT_MAX);
ui->qsb_rot_angle->setMinimum(-FLOAT_MAX);
ui->qsb_rot_angle->setMaximum(FLOAT_MAX);
ui->qsb_force_x->setValue(forceX);
ui->qsb_force_y->setValue(forceY);
ui->qsb_force_z->setValue(forceZ);
ui->qsb_force_x->bind(pcConstraint->ForceX);
ui->qsb_force_y->bind(pcConstraint->ForceY);
ui->qsb_force_z->bind(pcConstraint->ForceZ);
ui->qsb_force_x->setMinimum(-FLOAT_MAX);
ui->qsb_force_x->setMaximum(FLOAT_MAX);
ui->qsb_force_y->setMinimum(-FLOAT_MAX);
ui->qsb_force_y->setMaximum(FLOAT_MAX);
ui->qsb_force_z->setMinimum(-FLOAT_MAX);
ui->qsb_force_z->setMaximum(FLOAT_MAX);
ui->qsb_moment_x->setValue(momentX);
ui->qsb_moment_y->setValue(momentY);
ui->qsb_moment_z->setValue(momentZ);
ui->qsb_moment_x->bind(pcConstraint->MomentX);
ui->qsb_moment_y->bind(pcConstraint->MomentY);
ui->qsb_moment_z->bind(pcConstraint->MomentZ);
ui->qsb_moment_x->setMinimum(-FLOAT_MAX);
ui->qsb_moment_x->setMaximum(FLOAT_MAX);
ui->qsb_moment_y->setMinimum(-FLOAT_MAX);
ui->qsb_moment_y->setMaximum(FLOAT_MAX);
ui->qsb_moment_z->setMinimum(-FLOAT_MAX);
ui->qsb_moment_z->setMaximum(FLOAT_MAX);
QStringList modeList;
App::PropertyEnumeration* transMode = &pcConstraint->TranslationalModeX;
for (auto item : transMode->getEnumVector()) {
modeList << QString::fromUtf8(item.c_str());
}
ui->cb_x_trans_mode->addItems(modeList);
ui->cb_y_trans_mode->addItems(modeList);
ui->cb_z_trans_mode->addItems(modeList);
ui->cb_x_trans_mode->setCurrentIndex(pcConstraint->TranslationalModeX.getValue());
ui->cb_y_trans_mode->setCurrentIndex(pcConstraint->TranslationalModeY.getValue());
ui->cb_z_trans_mode->setCurrentIndex(pcConstraint->TranslationalModeZ.getValue());
modeList.clear();
App::PropertyEnumeration* rotMode = &pcConstraint->RotationalModeX;
for (auto item : rotMode->getEnumVector()) {
modeList << QString::fromUtf8(item.c_str());
}
ui->cb_x_rot_mode->addItems(modeList);
ui->cb_y_rot_mode->addItems(modeList);
ui->cb_z_rot_mode->addItems(modeList);
ui->cb_x_rot_mode->setCurrentIndex(pcConstraint->RotationalModeX.getValue());
ui->cb_y_rot_mode->setCurrentIndex(pcConstraint->RotationalModeY.getValue());
ui->cb_z_rot_mode->setCurrentIndex(pcConstraint->RotationalModeZ.getValue());
onTransModeXChanged(pcConstraint->TranslationalModeX.getValue());
onTransModeYChanged(pcConstraint->TranslationalModeY.getValue());
onTransModeZChanged(pcConstraint->TranslationalModeZ.getValue());
onRotModeXChanged(pcConstraint->RotationalModeX.getValue());
onRotModeYChanged(pcConstraint->RotationalModeY.getValue());
onRotModeZChanged(pcConstraint->RotationalModeZ.getValue());
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.empty()) {
ui->lw_references->setCurrentRow(0, QItemSelectionModel::ClearAndSelect);
}
// Selection buttons
buttonGroup->addButton(ui->btnAdd, (int)SelectionChangeModes::refAdd);
buttonGroup->addButton(ui->btnRemove, (int)SelectionChangeModes::refRemove);
updateUI();
}
TaskFemConstraintRigidBody::~TaskFemConstraintRigidBody()
{
delete ui;
}
void TaskFemConstraintRigidBody::updateUI()
{
if (ui->lw_references->model()->rowCount() == 0) {
// Go into reference selection mode if no reference has been selected yet
onButtonReference(true);
return;
}
}
void TaskFemConstraintRigidBody::addToSelection()
{
std::vector<Gui::SelectionObject> selection =
Gui::Selection().getSelectionEx(); // gets vector of selected objects of active document
if (selection.empty()) {
QMessageBox::warning(this, tr("Selection error"), tr("Nothing selected!"));
return;
}
Fem::ConstraintRigidBody* pcConstraint =
static_cast<Fem::ConstraintRigidBody*>(ConstraintView->getObject());
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
for (std::vector<Gui::SelectionObject>::iterator it = selection.begin(); it != selection.end();
++it) { // for every selected object
if (!it->isObjectTypeOf(Part::Feature::getClassTypeId())) {
QMessageBox::warning(this, tr("Selection error"), tr("Selected object is not a part!"));
return;
}
std::vector<std::string> subNames = it->getSubNames();
App::DocumentObject* obj =
ConstraintView->getObject()->getDocument()->getObject(it->getFeatName());
for (size_t subIt = 0; subIt < (subNames.size());
++subIt) { // for every selected sub element
bool addMe = true;
for (std::vector<std::string>::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;
}
}
// limit constraint such that only vertexes or faces or edges can be used depending on
// what was selected first
std::string searchStr;
if (subNames[subIt].find("Vertex") != std::string::npos) {
searchStr = "Vertex";
}
else if (subNames[subIt].find("Edge") != std::string::npos) {
searchStr = "Edge";
}
else {
searchStr = "Face";
}
for (size_t iStr = 0; iStr < (SubElements.size()); ++iStr) {
if (SubElements[iStr].find(searchStr) == std::string::npos) {
QString msg = tr(
"Only one type of selection (vertex,face or edge) per constraint allowed!");
QMessageBox::warning(this, tr("Selection error"), msg);
addMe = false;
break;
}
}
if (addMe) {
QSignalBlocker block(ui->lw_references);
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 TaskFemConstraintRigidBody::removeFromSelection()
{
std::vector<Gui::SelectionObject> selection =
Gui::Selection().getSelectionEx(); // gets vector of selected objects of active document
if (selection.empty()) {
QMessageBox::warning(this, tr("Selection error"), tr("Nothing selected!"));
return;
}
Fem::ConstraintRigidBody* pcConstraint =
static_cast<Fem::ConstraintRigidBody*>(ConstraintView->getObject());
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
std::vector<size_t> itemsToDel;
for (std::vector<Gui::SelectionObject>::iterator it = selection.begin(); it != selection.end();
++it) { // for every selected object
if (!it->isObjectTypeOf(Part::Feature::getClassTypeId())) {
QMessageBox::warning(this, tr("Selection error"), tr("Selected object is not a part!"));
return;
}
const std::vector<std::string>& subNames = it->getSubNames();
App::DocumentObject* obj = it->getObject();
for (size_t subIt = 0; subIt < (subNames.size());
++subIt) { // for every selected sub element
for (std::vector<std::string>::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));
}
}
}
}
std::sort(itemsToDel.begin(), itemsToDel.end());
while (!itemsToDel.empty()) {
Objects.erase(Objects.begin() + itemsToDel.back());
SubElements.erase(SubElements.begin() + itemsToDel.back());
itemsToDel.pop_back();
}
// Update UI
{
QSignalBlocker block(ui->lw_references);
ui->lw_references->clear();
for (unsigned int j = 0; j < Objects.size(); j++) {
ui->lw_references->addItem(makeRefText(Objects[j], SubElements[j]));
}
}
pcConstraint->References.setValues(Objects, SubElements);
updateUI();
}
void TaskFemConstraintRigidBody::onReferenceDeleted()
{
TaskFemConstraintRigidBody::removeFromSelection();
}
void TaskFemConstraintRigidBody::onRotModeXChanged(int item)
{
const char* val = static_cast<Fem::ConstraintRigidBody*>(ConstraintView->getObject())
->RotationalModeX.getEnumVector()[item]
.c_str();
if (strcmp(val, "Free") == 0) {
ui->spb_rot_axis_x->setEnabled(false);
ui->qsb_moment_x->setEnabled(false);
}
else if (strcmp(val, "Constraint") == 0) {
ui->spb_rot_axis_x->setEnabled(true);
ui->qsb_moment_x->setEnabled(false);
}
else if (strcmp(val, "Load") == 0) {
ui->spb_rot_axis_x->setEnabled(false);
ui->qsb_moment_x->setEnabled(true);
}
}
void TaskFemConstraintRigidBody::onRotModeYChanged(int item)
{
const char* val = static_cast<Fem::ConstraintRigidBody*>(ConstraintView->getObject())
->RotationalModeY.getEnumVector()[item]
.c_str();
if (strcmp(val, "Free") == 0) {
ui->spb_rot_axis_y->setEnabled(false);
ui->qsb_moment_y->setEnabled(false);
}
else if (strcmp(val, "Constraint") == 0) {
ui->spb_rot_axis_y->setEnabled(true);
ui->qsb_moment_y->setEnabled(false);
}
else if (strcmp(val, "Load") == 0) {
ui->spb_rot_axis_y->setEnabled(false);
ui->qsb_moment_y->setEnabled(true);
}
}
void TaskFemConstraintRigidBody::onRotModeZChanged(int item)
{
const char* val = static_cast<Fem::ConstraintRigidBody*>(ConstraintView->getObject())
->RotationalModeZ.getEnumVector()[item]
.c_str();
if (strcmp(val, "Free") == 0) {
ui->spb_rot_axis_z->setEnabled(false);
ui->qsb_moment_z->setEnabled(false);
}
else if (strcmp(val, "Constraint") == 0) {
ui->spb_rot_axis_z->setEnabled(true);
ui->qsb_moment_z->setEnabled(false);
}
else if (strcmp(val, "Load") == 0) {
ui->spb_rot_axis_z->setEnabled(false);
ui->qsb_moment_z->setEnabled(true);
}
}
void TaskFemConstraintRigidBody::onTransModeXChanged(int item)
{
const char* val = static_cast<Fem::ConstraintRigidBody*>(ConstraintView->getObject())
->TranslationalModeX.getEnumVector()[item]
.c_str();
if (strcmp(val, "Free") == 0) {
ui->qsb_disp_x->setEnabled(false);
ui->qsb_force_x->setEnabled(false);
}
else if (strcmp(val, "Constraint") == 0) {
ui->qsb_disp_x->setEnabled(true);
ui->qsb_force_x->setEnabled(false);
}
else if (strcmp(val, "Load") == 0) {
ui->qsb_disp_x->setEnabled(false);
ui->qsb_force_x->setEnabled(true);
}
}
void TaskFemConstraintRigidBody::onTransModeYChanged(int item)
{
const char* val = static_cast<Fem::ConstraintRigidBody*>(ConstraintView->getObject())
->TranslationalModeY.getEnumVector()[item]
.c_str();
if (strcmp(val, "Free") == 0) {
ui->qsb_disp_y->setEnabled(false);
ui->qsb_force_y->setEnabled(false);
}
else if (strcmp(val, "Constraint") == 0) {
ui->qsb_disp_y->setEnabled(true);
ui->qsb_force_y->setEnabled(false);
}
else if (strcmp(val, "Load") == 0) {
ui->qsb_disp_y->setEnabled(false);
ui->qsb_force_y->setEnabled(true);
}
}
void TaskFemConstraintRigidBody::onTransModeZChanged(int item)
{
const char* val = static_cast<Fem::ConstraintRigidBody*>(ConstraintView->getObject())
->TranslationalModeZ.getEnumVector()[item]
.c_str();
if (strcmp(val, "Free") == 0) {
ui->qsb_disp_z->setEnabled(false);
ui->qsb_force_z->setEnabled(false);
}
else if (strcmp(val, "Constraint") == 0) {
ui->qsb_disp_z->setEnabled(true);
ui->qsb_force_z->setEnabled(false);
}
else if (strcmp(val, "Load") == 0) {
ui->qsb_disp_z->setEnabled(false);
ui->qsb_force_z->setEnabled(true);
}
}
const std::string TaskFemConstraintRigidBody::getReferences() const
{
int rows = ui->lw_references->model()->rowCount();
std::vector<std::string> items;
for (int r = 0; r < rows; r++) {
items.push_back(ui->lw_references->item(r)->text().toStdString());
}
return TaskFemConstraint::getReferences(items);
}
Base::Vector3d TaskFemConstraintRigidBody::getReferenceNode() const
{
double x = ui->qsb_ref_node_x->rawValue();
double y = ui->qsb_ref_node_y->rawValue();
double z = ui->qsb_ref_node_z->rawValue();
return Base::Vector3d(x, y, z);
}
Base::Vector3d TaskFemConstraintRigidBody::getDisplacement() const
{
double x = ui->qsb_disp_x->rawValue();
double y = ui->qsb_disp_y->rawValue();
double z = ui->qsb_disp_z->rawValue();
return Base::Vector3d(x, y, z);
}
Base::Rotation TaskFemConstraintRigidBody::getRotation() const
{
double x = ui->spb_rot_axis_x->value();
double y = ui->spb_rot_axis_y->value();
double z = ui->spb_rot_axis_z->value();
double angle = ui->qsb_rot_angle->value().getValueAs(Base::Quantity::Radian);
return Base::Rotation(Base::Vector3d(x, y, z), angle);
}
std::vector<std::string> TaskFemConstraintRigidBody::getForce() const
{
std::string x = ui->qsb_force_x->value().getSafeUserString().toStdString();
std::string y = ui->qsb_force_y->value().getSafeUserString().toStdString();
std::string z = ui->qsb_force_z->value().getSafeUserString().toStdString();
return {x, y, z};
}
std::vector<std::string> TaskFemConstraintRigidBody::getMoment() const
{
std::string x = ui->qsb_moment_x->value().getSafeUserString().toStdString();
std::string y = ui->qsb_moment_y->value().getSafeUserString().toStdString();
std::string z = ui->qsb_moment_z->value().getSafeUserString().toStdString();
return std::vector<std::string>({x, y, z});
}
std::vector<std::string> TaskFemConstraintRigidBody::getTranslationalMode() const
{
std::vector<std::string> transModes(3);
transModes[0] = ui->cb_x_trans_mode->currentText().toStdString();
transModes[1] = ui->cb_y_trans_mode->currentText().toStdString();
transModes[2] = ui->cb_z_trans_mode->currentText().toStdString();
return transModes;
}
std::vector<std::string> TaskFemConstraintRigidBody::getRotationalMode() const
{
std::vector<std::string> rotModes(3);
rotModes[0] = ui->cb_x_rot_mode->currentText().toStdString();
rotModes[1] = ui->cb_y_rot_mode->currentText().toStdString();
rotModes[2] = ui->cb_z_rot_mode->currentText().toStdString();
return rotModes;
}
bool TaskFemConstraintRigidBody::event(QEvent* e)
{
return TaskFemConstraint::KeyEvent(e);
}
void TaskFemConstraintRigidBody::changeEvent(QEvent*)
{}
void TaskFemConstraintRigidBody::clearButtons(const SelectionChangeModes notThis)
{
if (notThis != SelectionChangeModes::refAdd) {
ui->btnAdd->setChecked(false);
}
if (notThis != SelectionChangeModes::refRemove) {
ui->btnRemove->setChecked(false);
}
}
//**************************************************************************
// TaskDialog
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TaskDlgFemConstraintRigidBody::TaskDlgFemConstraintRigidBody(
ViewProviderFemConstraintRigidBody* ConstraintView)
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintRigidBody(ConstraintView);
Content.push_back(parameter);
}
//==== calls from the TaskView ===============================================================
void TaskDlgFemConstraintRigidBody::open()
{
// a transaction is already open at creation time of the panel
if (!Gui::Command::hasPendingCommand()) {
QString msg = QObject::tr("Constraint RigidBody");
Gui::Command::openCommand((const char*)msg.toUtf8());
ConstraintView->setVisible(true);
Gui::Command::doCommand(
Gui::Command::Doc,
ViewProviderFemConstraint::gethideMeshShowPartStr(
(static_cast<Fem::Constraint*>(ConstraintView->getObject()))->getNameInDocument())
.c_str()); // OvG: Hide meshes and show parts
}
}
bool TaskDlgFemConstraintRigidBody::accept()
{
std::string name = ConstraintView->getObject()->getNameInDocument();
const TaskFemConstraintRigidBody* parameters =
static_cast<const TaskFemConstraintRigidBody*>(parameter);
try {
Base::Vector3d ref = parameters->getReferenceNode();
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.ReferenceNode = App.Vector(%f, %f, %f)",
name.c_str(),
ref.x,
ref.y,
ref.z);
Base::Vector3d disp = parameters->getDisplacement();
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.Displacement = App.Vector(%f, %f, %f)",
name.c_str(),
disp.x,
disp.y,
disp.z);
Base::Rotation rot = parameters->getRotation();
Base::Vector3d axis;
double angle;
rot.getValue(axis, angle);
Gui::Command::doCommand(
Gui::Command::Doc,
"App.ActiveDocument.%s.Rotation = App.Rotation(App.Vector(%f,% f, %f), Radian=%f)",
name.c_str(),
axis.x,
axis.y,
axis.z,
angle);
auto force = parameters->getForce();
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.ForceX = \"%s\"",
name.c_str(),
force[0].c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.ForceY = \"%s\"",
name.c_str(),
force[1].c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.ForceZ = \"%s\"",
name.c_str(),
force[2].c_str());
auto moment = parameters->getMoment();
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.MomentX = \"%s\"",
name.c_str(),
moment[0].c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.MomentY = \"%s\"",
name.c_str(),
moment[1].c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.MomentZ = \"%s\"",
name.c_str(),
moment[2].c_str());
auto transModes = parameters->getTranslationalMode();
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.TranslationalModeX = \"%s\"",
name.c_str(),
transModes[0].c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.TranslationalModeY = \"%s\"",
name.c_str(),
transModes[1].c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.TranslationalModeZ = \"%s\"",
name.c_str(),
transModes[2].c_str());
auto rotModes = parameters->getRotationalMode();
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.RotationalModeX = \"%s\"",
name.c_str(),
rotModes[0].c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.RotationalModeY = \"%s\"",
name.c_str(),
rotModes[1].c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.RotationalModeZ = \"%s\"",
name.c_str(),
rotModes[2].c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.Scale = %s",
name.c_str(),
parameters->getScale().c_str());
}
catch (const Base::Exception& e) {
QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what()));
return false;
}
return TaskDlgFemConstraint::accept();
}
bool TaskDlgFemConstraintRigidBody::reject()
{
Gui::Command::abortCommand();
Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeDocument().resetEdit()");
Gui::Command::updateActive();
return true;
}
#include "moc_TaskFemConstraintRigidBody.cpp"

View File

@@ -0,0 +1,88 @@
/***************************************************************************
* Copyright (c) 2022 Ajinkya Dahale <dahale.a.p@gmail.com> *
* *
* 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_TaskFemConstraintRigidBody_H
#define GUI_TASKVIEW_TaskFemConstraintRigidBody_H
#include <QObject>
#include "TaskFemConstraintOnBoundary.h"
#include "ViewProviderFemConstraintRigidBody.h"
class Ui_TaskFemConstraintRigidBody;
namespace FemGui
{
class TaskFemConstraintRigidBody: public TaskFemConstraintOnBoundary
{
Q_OBJECT
public:
explicit TaskFemConstraintRigidBody(ViewProviderFemConstraintRigidBody* ConstraintView,
QWidget* parent = nullptr);
~TaskFemConstraintRigidBody() override;
const std::string getReferences() const override;
Base::Vector3d getReferenceNode() const;
Base::Vector3d getDisplacement() const;
Base::Rotation getRotation() const;
std::vector<std::string> getForce() const;
std::vector<std::string> getMoment() const;
std::vector<std::string> getTranslationalMode() const;
std::vector<std::string> getRotationalMode() const;
private Q_SLOTS:
void onReferenceDeleted();
void addToSelection() override;
void removeFromSelection() override;
void onTransModeXChanged(int);
void onTransModeYChanged(int);
void onTransModeZChanged(int);
void onRotModeXChanged(int);
void onRotModeYChanged(int);
void onRotModeZChanged(int);
protected:
bool event(QEvent* e) override;
void changeEvent(QEvent* e) override;
void clearButtons(const SelectionChangeModes notThis) override;
private:
void updateUI();
Ui_TaskFemConstraintRigidBody* ui;
};
class TaskDlgFemConstraintRigidBody: public TaskDlgFemConstraint
{
Q_OBJECT
public:
explicit TaskDlgFemConstraintRigidBody(ViewProviderFemConstraintRigidBody* ConstraintView);
void open() override;
bool accept() override;
bool reject() override;
};
} // namespace FemGui
#endif // GUI_TASKVIEW_TaskFemConstraintRigidBody_H

View File

@@ -0,0 +1,615 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskFemConstraintRigidBody</class>
<widget class="QWidget" name="TaskFemConstraintRigidBody">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>296</width>
<height>587</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lbl_info">
<property name="text">
<string>Select multiple face(s), click Add or Remove</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="hLayout1">
<item>
<widget class="QToolButton" name="btnAdd">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Add</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnRemove">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Remove</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="lw_references"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="gpb_ref_mode">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
<property name="title">
<string>Reference Node</string>
</property>
<layout class="QFormLayout" name="f_layout_ref_node">
<item row="0" column="0">
<widget class="QLabel" name="lbl_ref_node_x">
<property name="text">
<string>X:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_ref_node_x">
<property name="singleStep">
<double>1.0</double>
</property>
<property name="maximum">
<double>1000000000.0</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
<property name="value" stdset="0">
<double>0.0</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbl_ref_node_y">
<property name="text">
<string>Y:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_ref_node_y">
<property name="singleStep">
<double>1.0</double>
</property>
<property name="maximum">
<double>1000000000.0</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
<property name="value" stdset="0">
<double>0.0</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_ref_node_z">
<property name="text">
<string>Z:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_ref_node_z">
<property name="singleStep">
<double>1.0</double>
</property>
<property name="maximum">
<double>1000000000.0</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
<property name="value" stdset="0">
<double>0.0</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="gpb_trans_parameter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
<property name="title">
<string>Translational Mode</string>
</property>
<layout class="QFormLayout" name="f_layout_trans_mode">
<item row="0" column="0">
<widget class="QLabel" name="lbl_trans_x_mode">
<property name="text">
<string>X:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbl_trans_y_mode">
<property name="text">
<string>Y:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_trans_z_mode">
<property name="text">
<string>Z:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cb_x_trans_mode"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cb_y_trans_mode"/>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="cb_z_trans_mode"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gpb_trans_disp">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
<property name="title">
<string>Displacement</string>
</property>
<layout class="QFormLayout" name="f_layout_trans_disp">
<item row="0" column="0">
<widget class="QLabel" name="lbl_trans_x_disp">
<property name="text">
<string>X:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbl_trans_y_disp">
<property name="text">
<string>Y:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_trans_z_disp">
<property name="text">
<string>Z:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_disp_x">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>1.00000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_disp_y">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>1.00000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_disp_z">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>1.00000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gpb_trans_force">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
<property name="title">
<string>Force</string>
</property>
<layout class="QFormLayout" name="f_layout_trans_force">
<item row="0" column="0">
<widget class="QLabel" name="lbl_trans_x_force">
<property name="text">
<string>X:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbl_trans_y_force">
<property name="text">
<string>Y:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_trans_z_force">
<property name="text">
<string>Z:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_force_x">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>1.00000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">N</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_force_y">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>1.00000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">N</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_force_z">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>1.00000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">N</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer1">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="gpb_rot_mode">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
<property name="title">
<string>Rotational Mode</string>
</property>
<layout class="QFormLayout" name="f_layout_rot_mode">
<item row="0" column="0">
<widget class="QLabel" name="lbl_rot_x_mode">
<property name="text">
<string>X:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbl_rot_y_mode">
<property name="text">
<string>Y:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_rot_z_mode">
<property name="text">
<string>Z:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cb_x_rot_mode"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cb_y_rot_mode"/>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="cb_z_rot_mode"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gpb_rot_rot">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
<property name="title">
<string>Rotation</string>
</property>
<layout class="QFormLayout" name="f_layout_rot_rot">
<item row="0" column="0">
<widget class="QLabel" name="lbl_rot_x_axis">
<property name="text">
<string>X:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbl_rot_y_axis">
<property name="text">
<string>Y:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_rot_z_axis">
<property name="text">
<string>Z:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::DoubleSpinBox" name="spb_rot_axis_x">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>0.10000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::DoubleSpinBox" name="spb_rot_axis_y">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::DoubleSpinBox" name="spb_rot_axis_z">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lbl_rot_angle">
<property name="text">
<string>Angle:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_rot_angle">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>1.00000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">deg</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gpb_rot_moment">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
<property name="title">
<string>Moment</string>
</property>
<layout class="QFormLayout" name="f_layout_rot_moment">
<item row="0" column="0">
<widget class="QLabel" name="lbl_rot_x_moment">
<property name="text">
<string>X:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbl_rot_y_moment">
<property name="text">
<string>Y:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_rot_z_rot">
<property name="text">
<string>Z:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_moment_x">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>1.00000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">N*m</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_moment_y">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>1.00000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">N*m</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::QuantitySpinBox" name="qsb_moment_z">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="singleStep">
<double>1.00000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">N*m</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::QuantitySpinBox</class>
<extends>QWidget</extends>
<header>Gui/QuantitySpinBox.h</header>
</customwidget>
<customwidget>
<class>Gui::DoubleSpinBox</class>
<extends>QWidget</extends>
<header>Gui/SpinBox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -33,6 +33,7 @@
#include <Inventor/nodes/SoRotation.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoShapeHints.h>
#include <Inventor/nodes/SoTransform.h>
#include <Inventor/nodes/SoTranslation.h>
#include <QAction>
#include <QDockWidget>
@@ -61,6 +62,7 @@ ViewProviderFemConstraint::ViewProviderFemConstraint()
: rotateSymbol(true)
, pSymbol(nullptr)
, pExtraSymbol(nullptr)
, pExtraTrans(nullptr)
, ivFile(nullptr)
, wizardWidget(nullptr)
, wizardSubLayout(nullptr)
@@ -70,6 +72,8 @@ ViewProviderFemConstraint::ViewProviderFemConstraint()
pShapeSep->ref();
pMultCopy = new SoMultipleCopy();
pMultCopy->ref();
pExtraTrans = new SoTransform();
pExtraTrans->ref();
ShapeAppearance.setDiffuseColor(1.0f, 0.0f, 0.2f);
ShapeAppearance.setSpecularColor(0.0f, 0.0f, 0.0f);
@@ -80,6 +84,7 @@ ViewProviderFemConstraint::ViewProviderFemConstraint()
ViewProviderFemConstraint::~ViewProviderFemConstraint()
{
pMultCopy->unref();
pExtraTrans->unref();
pShapeSep->unref();
}
@@ -129,6 +134,7 @@ void ViewProviderFemConstraint::loadSymbol(const char* fileName)
if (nodes->getNumChildren() == 2) {
pExtraSymbol = dynamic_cast<SoSeparator*>(nodes->getChild(1));
if (pExtraSymbol) {
pShapeSep->addChild(pExtraTrans);
pShapeSep->addChild(pExtraSymbol);
}
}
@@ -221,6 +227,8 @@ void ViewProviderFemConstraint::updateSymbol()
}
pMultCopy->matrix.finishEditing();
transformExtraSymbol();
}
void ViewProviderFemConstraint::transformSymbol(const Base::Vector3d& point,
@@ -239,6 +247,17 @@ void ViewProviderFemConstraint::transformSymbol(const Base::Vector3d& point,
mat.setTransform(tra, rot, scale);
}
void ViewProviderFemConstraint::transformExtraSymbol() const
{
if (pExtraTrans) {
auto obj = static_cast<const Fem::Constraint*>(this->getObject());
float s = obj->getScaleFactor();
SbMatrix mat;
mat.setScale(s);
pExtraTrans->setMatrix(mat);
}
}
// OvG: Visibility automation show parts and hide meshes on activation of a constraint
std::string ViewProviderFemConstraint::gethideMeshShowPartStr(const std::string showConstr)

View File

@@ -36,6 +36,7 @@
class SbRotation;
class SoMultipleCopy;
class SoTransform;
namespace FemGui
{
@@ -68,6 +69,7 @@ public:
SoSeparator* getSymbolSeparator() const;
SoSeparator* getExtraSymbolSeparator() const;
SoTransform* getExtraSymbolTransform() const;
// Apply rotation on copies of the constraint symbol
void setRotateSymbol(bool rotate);
bool getRotateSymbol() const;
@@ -94,6 +96,7 @@ protected:
void updateSymbol();
virtual void
transformSymbol(const Base::Vector3d& point, const Base::Vector3d& normal, SbMatrix& mat) const;
virtual void transformExtraSymbol() const;
static void createPlacement(SoSeparator* sep, const SbVec3f& base, const SbRotation& r);
static void updatePlacement(const SoSeparator* sep,
@@ -163,6 +166,7 @@ protected:
SoSeparator* pShapeSep;
SoSeparator* pSymbol;
SoSeparator* pExtraSymbol;
SoTransform* pExtraTrans;
SoMultipleCopy* pMultCopy;
const char* ivFile;
@@ -190,6 +194,11 @@ inline SoSeparator* ViewProviderFemConstraint::getExtraSymbolSeparator() const
return pExtraSymbol;
}
inline SoTransform* ViewProviderFemConstraint::getExtraSymbolTransform() const
{
return pExtraTrans;
}
inline bool ViewProviderFemConstraint::getRotateSymbol() const
{
return rotateSymbol;

View File

@@ -0,0 +1,138 @@
/***************************************************************************
* Copyright (c) 2022 Ajinkya Dahale <dahale.a.p@gmail.com> *
* *
* 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 <QMessageBox>
#include <Inventor/nodes/SoTransform.h>
#endif
#include "Gui/Control.h"
#include <Mod/Fem/App/FemConstraintRigidBody.h>
#include "TaskFemConstraintRigidBody.h"
#include "ViewProviderFemConstraintRigidBody.h"
using namespace FemGui;
PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintRigidBody,
FemGui::ViewProviderFemConstraintOnBoundary)
ViewProviderFemConstraintRigidBody::ViewProviderFemConstraintRigidBody()
{
sPixmap = "FEM_ConstraintRigidBody";
loadSymbol((resourceSymbolDir + "ConstraintRigidBody.iv").c_str());
ShapeAppearance.setDiffuseColor(0.0f, 0.5f, 0.0f);
}
ViewProviderFemConstraintRigidBody::~ViewProviderFemConstraintRigidBody() = default;
bool ViewProviderFemConstraintRigidBody::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();
TaskDlgFemConstraintRigidBody* constrDlg =
qobject_cast<TaskDlgFemConstraintRigidBody*>(dlg);
if (constrDlg && constrDlg->getConstraintView() != this) {
constrDlg = nullptr; // another constraint left open its task panel
}
if (dlg && !constrDlg) {
// This case will occur in the ShaftWizard application
checkForWizard();
if (!wizardWidget || !wizardSubLayout) {
// 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) {
// Another FemConstraint* dialog is already open inside the Shaft Wizard
// Ignore the request to open another dialog
return false;
}
else {
constraintDialog = new TaskFemConstraintRigidBody(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 TaskDlgFemConstraintRigidBody(this));
}
return true;
}
else {
return ViewProviderDocumentObject::setEdit(ModNum); // clazy:exclude=skipped-base-method
}
}
void ViewProviderFemConstraintRigidBody::updateData(const App::Property* prop)
{
auto obj = static_cast<Fem::ConstraintRigidBody*>(this->getObject());
if (prop == &obj->ReferenceNode) {
updateSymbol();
}
ViewProviderFemConstraint::updateData(prop);
}
void ViewProviderFemConstraintRigidBody::transformExtraSymbol() const
{
SoTransform* symTrans = getExtraSymbolTransform();
if (symTrans) {
auto obj = static_cast<const Fem::ConstraintRigidBody*>(this->getObject());
float s = obj->getScaleFactor();
const Base::Vector3d& refNode = obj->ReferenceNode.getValue();
SbVec3f tra(refNode.x, refNode.y, refNode.z);
SbVec3f sca(s, s, s);
SbRotation rot(SbVec3f(0, 0, 1), 0);
SbMatrix mat;
mat.setTransform(tra, rot, sca);
symTrans->setMatrix(mat);
}
}

View File

@@ -0,0 +1,53 @@
/***************************************************************************
* Copyright (c) 2022 Ajinkya Dahale <dahale.a.p@gmail.com> *
* *
* 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_VIEWPROVIDERFEMCONSTRAINTRIGIDBODY_H
#define GUI_VIEWPROVIDERFEMCONSTRAINTRIGIDBODY_H
#include "ViewProviderFemConstraintOnBoundary.h"
namespace FemGui
{
class FemGuiExport ViewProviderFemConstraintRigidBody
: public FemGui::ViewProviderFemConstraintOnBoundary
{
PROPERTY_HEADER_WITH_OVERRIDE(FemGui::ViewProviderFemConstraintRigidBody);
public:
/// Constructor
ViewProviderFemConstraintRigidBody();
~ViewProviderFemConstraintRigidBody() override;
void updateData(const App::Property*) override;
protected:
bool setEdit(int ModNum) override;
void transformExtraSymbol() const override;
};
} // namespace FemGui
#endif // GUI_VIEWPROVIDERFEMCONSTRAINTRIGIDBODY_H

View File

@@ -132,6 +132,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
Gui::ToolBarItem* mech = new Gui::ToolBarItem(root);
mech->setCommand("Mechanical boundary conditions and loads");
*mech << "FEM_ConstraintFixed"
<< "FEM_ConstraintRigidBody"
<< "FEM_ConstraintDisplacement"
<< "FEM_ConstraintContact"
<< "FEM_ConstraintTie"
@@ -263,6 +264,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
Gui::MenuItem* mech = new Gui::MenuItem;
mech->setCommand("&Mechanical boundary conditions and loads");
*mech << "FEM_ConstraintFixed"
<< "FEM_ConstraintRigidBody"
<< "FEM_ConstraintDisplacement"
<< "FEM_ConstraintContact"
<< "FEM_ConstraintTie"

View File

@@ -173,6 +173,16 @@ def makeConstraintFixed(
return obj
def makeConstraintRigidBody(
doc,
name="ConstraintRigidBody"
):
"""makeConstraintRigidBody(document, [name]):
makes a Fem ConstraintRigidBody object"""
obj = doc.addObject("Fem::ConstraintRigidBody", name)
return obj
def makeConstraintFlowVelocity(
doc,
name="ConstraintFlowVelocity"

View File

@@ -139,6 +139,7 @@ class MeshSetsGetter():
# constraints node sets getter
self.get_constraints_fixed_nodes()
self.get_constraints_displacement_nodes()
self.get_constraints_rigidbody_nodes()
self.get_constraints_planerotation_nodes()
# constraints surface sets getter
@@ -205,6 +206,21 @@ class MeshSetsGetter():
femobj["NodesSolid"] = set(nds_solid)
femobj["NodesFaceEdge"] = set(nds_faceedge)
def get_constraints_rigidbody_nodes(self):
if not self.member.cons_rigidbody:
return
# get nodes
for femobj in self.member.cons_rigidbody:
# femobj --> dict, FreeCAD document object is femobj["Object"]
print_obj_info(femobj["Object"])
femobj["Nodes"] = meshtools.get_femnodes_by_femobj_with_references(
self.femmesh,
femobj
)
# add nodes to constraint_conflict_nodes, needed by constraint plane rotation
for node in femobj["Nodes"]:
self.constraint_conflict_nodes.append(node)
def get_constraints_displacement_nodes(self):
if not self.member.cons_displacement:
return

View File

@@ -0,0 +1,79 @@
# ***************************************************************************
# * Copyright (c) 2022 Ajinkya Dahale <dahale.a.p@gmail.com> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program 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 program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
__title__ = "FreeCAD FEM calculix constraint rigid body"
__author__ = "Ajinkya Dahale"
__url__ = "https://www.freecadweb.org"
def get_analysis_types():
return "all" # write for all analysis types
def get_sets_name():
return "constraints_rigidbody_node_sets"
def get_constraint_title():
return "Rigid Body Constraints"
def get_before_write_meshdata_constraint():
return ""
def get_after_write_meshdata_constraint():
return ""
def get_before_write_constraint():
return ""
def get_after_write_constraint():
return ""
def write_meshdata_constraint(f, femobj, rb_obj, ccxwriter):
f.write("*NSET,NSET=" + rb_obj.Name + "\n")
for n in femobj["Nodes"]:
f.write("{},\n".format(n))
def write_constraint(f, femobj, rb_obj, ccxwriter):
rb_obj_idx = ccxwriter.analysis.Group.index(rb_obj)
node_count = ccxwriter.mesh_object.FemMesh.NodeCount
# factor 2 is to prevent conflict with other rigid body constraint
ref_node_idx = node_count + 2*rb_obj_idx + 1
rot_node_idx = node_count + 2*rb_obj_idx + 2
f.write("*NODE\n")
f.write("{},{},{},{}\n".format(ref_node_idx, *rb_obj.ReferenceNode))
f.write("{},{},{},{}\n".format(rot_node_idx, *rb_obj.ReferenceNode))
kw_line = "*RIGID BODY, NSET={}, REF NODE={}, ROT NODE={}".format(rb_obj.Name, ref_node_idx, rot_node_idx)
f.write(kw_line + "\n")

View File

@@ -0,0 +1,100 @@
# ***************************************************************************
# * Copyright (c) 2022 Ajinkya Dahale <dahale.a.p@gmail.com> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program 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 program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
__title__ = "FreeCAD FEM calculix constraint rigid body"
__author__ = "Ajinkya Dahale"
__url__ = "https://www.freecadweb.org"
import FreeCAD
def get_analysis_types():
return "all" # write for all analysis types
def get_sets_name():
return "constraints_rigidbody_node_sets"
def get_constraint_title():
return "Rigid Body Constraints"
def get_before_write_meshdata_constraint():
return ""
def get_after_write_meshdata_constraint():
return ""
def get_before_write_constraint():
return ""
def get_after_write_constraint():
return ""
def write_constraint(f, femobj, rb_obj, ccxwriter):
rb_obj_idx = ccxwriter.analysis.Group.index(rb_obj)
node_count = ccxwriter.mesh_object.FemMesh.NodeCount
# factor 2 is to prevent conflict with other rigid body constraint
ref_node_idx = node_count + 2*rb_obj_idx + 1
rot_node_idx = node_count + 2*rb_obj_idx + 2
def write_mode(mode, node, dof, constraint, load):
if mode == "Constraint":
f.write("*BOUNDARY\n")
f.write("{},{},{},{:.13G}\n".format(node, dof, dof, constraint))
elif mode == "Load":
f.write("*CLOAD\n")
f.write("{},{},{:.13G}\n".format(node, dof, load))
mode = [rb_obj.TranslationalModeX, rb_obj.TranslationalModeY, rb_obj.TranslationalModeZ]
constraint = rb_obj.Displacement
load = [rb_obj.ForceX, rb_obj.ForceY, rb_obj.ForceZ]
for i in range(3):
write_mode(mode[i], ref_node_idx, i + 1, constraint[i], load[i].getValueAs("N").Value)
mode = [rb_obj.RotationalModeX, rb_obj.RotationalModeY, rb_obj.RotationalModeZ]
load = [rb_obj.MomentX,rb_obj.MomentY, rb_obj.MomentZ]
# write rotation components according to rotational mode
rot = rb_obj.Rotation
proj_axis = [rot.Axis[i] if mode[i] == "Constraint" else 0 for i in range(3)]
# proj_axis could be null
try:
constraint = FreeCAD.Vector(proj_axis).normalize() * rot.Angle
except:
constraint = FreeCAD.Vector(0, 0, 0)
for i in range(3):
write_mode(mode[i], rot_node_idx, i + 1, constraint[i], load[i].getValueAs("N*mm").Value)
f.write("\n")

View File

@@ -45,6 +45,8 @@ from . import write_constraint_heatflux as con_heatflux
from . import write_constraint_initialtemperature as con_itemp
from . import write_constraint_planerotation as con_planerotation
from . import write_constraint_pressure as con_pressure
from . import write_constraint_rigidbody as con_rigidbody
from . import write_constraint_rigidbody_step as con_rigidbody_step
from . import write_constraint_sectionprint as con_sectionprint
from . import write_constraint_selfweight as con_selfweight
from . import write_constraint_temperature as con_temperature
@@ -161,6 +163,7 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# node sets
self.write_constraints_meshsets(inpfile, self.member.cons_fixed, con_fixed)
self.write_constraints_meshsets(inpfile, self.member.cons_rigidbody, con_rigidbody)
self.write_constraints_meshsets(inpfile, self.member.cons_displacement, con_displacement)
self.write_constraints_meshsets(inpfile, self.member.cons_planerotation, con_planerotation)
self.write_constraints_meshsets(inpfile, self.member.cons_transform, con_transform)
@@ -181,12 +184,14 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
self.write_constraints_propdata(inpfile, self.member.cons_contact, con_contact)
self.write_constraints_propdata(inpfile, self.member.cons_tie, con_tie)
self.write_constraints_propdata(inpfile, self.member.cons_transform, con_transform)
self.write_constraints_propdata(inpfile, self.member.cons_rigidbody, con_rigidbody)
# step equation
write_step_equation.write_step_equation(inpfile, self)
# constraints dependent from steps
self.write_constraints_propdata(inpfile, self.member.cons_fixed, con_fixed)
self.write_constraints_propdata(inpfile, self.member.cons_rigidbody_step, con_rigidbody_step)
self.write_constraints_propdata(inpfile, self.member.cons_displacement, con_displacement)
self.write_constraints_propdata(inpfile, self.member.cons_sectionprint, con_sectionprint)
self.write_constraints_propdata(inpfile, self.member.cons_selfweight, con_selfweight)

View File

@@ -189,6 +189,10 @@ class TestObjectType(unittest.TestCase):
"Fem::ConstraintFixed",
type_of_obj(ObjectsFem.makeConstraintFixed(doc))
)
self.assertEqual(
"Fem::ConstraintRigidBody",
type_of_obj(ObjectsFem.makeConstraintRigidBody(doc))
)
self.assertEqual(
"Fem::ConstraintFlowVelocity",
type_of_obj(ObjectsFem.makeConstraintFlowVelocity(doc))
@@ -434,6 +438,10 @@ class TestObjectType(unittest.TestCase):
ObjectsFem.makeConstraintFixed(doc),
"Fem::ConstraintFixed"
))
self.assertTrue(is_of_type(
ObjectsFem.makeConstraintRigidBody(doc),
"Fem::ConstraintRigidBody"
))
self.assertTrue(is_of_type(
ObjectsFem.makeConstraintFlowVelocity(doc),
"Fem::ConstraintFlowVelocity"
@@ -778,6 +786,21 @@ class TestObjectType(unittest.TestCase):
"Fem::ConstraintFixed"
))
# ConstraintRigidBody
constraint_rigidbody = ObjectsFem.makeConstraintRigidBody(doc)
self.assertTrue(is_derived_from(
constraint_rigidbody,
"App::DocumentObject"
))
self.assertTrue(is_derived_from(
constraint_rigidbody,
"Fem::Constraint"
))
self.assertTrue(is_derived_from(
constraint_rigidbody,
"Fem::ConstraintRigidBody"
))
# ConstraintFlowVelocity
constraint_flow_velocity = ObjectsFem.makeConstraintFlowVelocity(doc)
self.assertTrue(is_derived_from(
@@ -1573,6 +1596,10 @@ class TestObjectType(unittest.TestCase):
ObjectsFem.makeConstraintFixed(
doc).isDerivedFrom("Fem::ConstraintFixed")
)
self.assertTrue(
ObjectsFem.makeConstraintRigidBody(
doc).isDerivedFrom("Fem::ConstraintRigidBody")
)
self.assertTrue(
ObjectsFem.makeConstraintFlowVelocity(
doc).isDerivedFrom("Fem::ConstraintPython")
@@ -1844,6 +1871,7 @@ def create_all_fem_objects_doc(
analysis.addObject(ObjectsFem.makeConstraintDisplacement(doc))
analysis.addObject(ObjectsFem.makeConstraintElectrostaticPotential(doc))
analysis.addObject(ObjectsFem.makeConstraintFixed(doc))
analysis.addObject(ObjectsFem.makeConstraintRigidBody(doc))
analysis.addObject(ObjectsFem.makeConstraintFlowVelocity(doc))
analysis.addObject(ObjectsFem.makeConstraintFluidBoundary(doc))
analysis.addObject(ObjectsFem.makeConstraintSpring(doc))

View File

@@ -207,6 +207,10 @@ class AnalysisMember():
list of fixed constraints from the analysis.
[{"Object":fixed_obj, "NodeSupports":bool}, {}, ...]
constraints_rigidbody : list of dictionaries
list of displacements for the analysis.
[{"Object":rigidbody_obj, "xxxxxxxx":value}, {}, ...]
constraints_force : list of dictionaries
list of force constraints from the analysis.
[{"Object":force_obj, "NodeLoad":value}, {}, ...
@@ -294,6 +298,12 @@ class AnalysisMember():
self.cons_fixed = self.get_several_member(
"Fem::ConstraintFixed"
)
self.cons_rigidbody = self.get_several_member(
"Fem::ConstraintRigidBody"
)
self.cons_rigidbody_step = self.get_several_member(
"Fem::ConstraintRigidBody"
)
self.cons_force = self.get_several_member(
"Fem::ConstraintForce"
)