Fem: Update constraint transform

This commit is contained in:
marioalexis
2024-05-28 00:37:08 -03:00
parent 536a2b0aad
commit f17ad4f143
16 changed files with 535 additions and 498 deletions

View File

@@ -23,8 +23,10 @@
#include "PreCompiled.h"
#include "FemConstraintTransform.h"
#include <Mod/Part/App/PartFeature.h>
#include "FemConstraintTransform.h"
#include "FemTools.h"
using namespace Fem;
@@ -34,9 +36,11 @@ static const char* TransformTypes[] = {"Cylindrical", "Rectangular", nullptr};
ConstraintTransform::ConstraintTransform()
{
ADD_PROPERTY(X_rot, (0.0));
ADD_PROPERTY(Y_rot, (0.0));
ADD_PROPERTY(Z_rot, (0.0));
ADD_PROPERTY_TYPE(Rotation,
(Base::Rotation(0.0, 0.0, 0.0, 1.0)),
"ConstraintTransform",
App::Prop_Output,
"Rectangular system transform");
ADD_PROPERTY_TYPE(TransformType,
(1),
"ConstraintTransform",
@@ -78,54 +82,141 @@ const char* ConstraintTransform::getViewProviderName() const
return "FemGui::ViewProviderFemConstraintTransform";
}
void ConstraintTransform::handleChangedPropertyType(Base::XMLReader& reader,
const char* TypeName,
App::Property* prop)
{
// properties _rot had App::PropertyFloat and were changed to App::PropertyAngle
if (prop == &X_rot && strcmp(TypeName, "App::PropertyFloat") == 0) {
App::PropertyFloat X_rotProperty;
X_rotProperty.Restore(reader);
X_rot.setValue(X_rotProperty.getValue());
}
else if (prop == &Y_rot && strcmp(TypeName, "App::PropertyFloat") == 0) {
App::PropertyFloat Y_rotProperty;
Y_rotProperty.Restore(reader);
Y_rot.setValue(Y_rotProperty.getValue());
}
else if (prop == &Z_rot && strcmp(TypeName, "App::PropertyFloat") == 0) {
App::PropertyFloat Z_rotProperty;
Z_rotProperty.Restore(reader);
Z_rot.setValue(Z_rotProperty.getValue());
}
else {
Constraint::handleChangedPropertyType(reader, TypeName, prop);
}
}
void ConstraintTransform::onChanged(const App::Property* prop)
{
Constraint::onChanged(prop);
if (prop == &References) {
std::vector<Base::Vector3d> points;
std::vector<Base::Vector3d> normals;
double scale = 1; // OvG: Enforce use of scale
if (getPoints(points, normals, &scale)) {
std::string transform_type = TransformType.getValueAsString();
if (transform_type == "Cylindrical") {
// Find data of cylinder
double radius, height;
Base::Vector3d base, axis;
if (!getCylinder(radius, height, base, axis)) {
return;
}
Axis.setValue(axis);
// Update base point
base = base + axis * height / 2;
BasePoint.setValue(base);
BasePoint.touch(); // This triggers ViewProvider::updateData()
std::string transform_type = TransformType.getValueAsString();
if (transform_type == "Cylindrical") {
// Extract geometry from References
std::vector<App::DocumentObject*> ref = References.getValues();
std::vector<std::string> subRef = References.getSubValues();
if (ref.empty()) {
return;
}
Part::Feature* feat = static_cast<Part::Feature*>(ref.front());
TopoDS_Shape sh = Tools::getFeatureSubShape(feat, subRef.front().c_str(), true);
Base::Vector3d axis, base;
double height, radius;
if (!Tools::getCylinderParams(sh, base, axis, height, radius)) {
return;
}
BasePoint.setValue(base);
Axis.setValue(axis);
}
}
Constraint::onChanged(prop);
}
namespace
{
Base::Rotation anglesToRotation(double xAngle, double yAngle, double zAngle)
{
static Base::Vector3d a(1, 0, 0);
static Base::Vector3d b(0, 1, 0);
static int count = 0;
double xRad = xAngle * D_PI / 180.0;
double yRad = yAngle * D_PI / 180.0;
double zRad = zAngle * D_PI / 180.0;
if (xAngle != 0) {
a[1] = 0;
a[2] = 0;
b[1] = std::cos(xRad);
b[2] = -std::sin(xRad);
}
if (yAngle != 0) {
a[0] = std::cos(yRad);
a[2] = std::sin(yRad);
b[0] = 0;
b[2] = 0;
}
if (zAngle != 0) {
a[0] = std::cos(zRad);
a[1] = -std::sin(zRad);
b[0] = 0;
b[1] = 0;
}
++count;
count %= 3;
if (!count) {
Base::Vector3d X = a.Normalize();
Base::Vector3d Y = b.Normalize();
Base::Vector3d Z = X.Cross(Y);
Z.Normalize();
Y = Z.Cross(X);
a.x = 1;
a.y = 0;
a.z = 0;
b.x = 0;
b.y = 1;
b.z = 0;
Base::Matrix4D m;
m.setCol(0, X);
m.setCol(1, Y);
m.setCol(2, Z);
return Base::Rotation(m);
}
return Base::Rotation();
}
} // namespace
void ConstraintTransform::handleChangedPropertyName(Base::XMLReader& reader,
const char* typeName,
const char* propName)
{
if (strcmp(propName, "X_rot") == 0) {
double xAngle;
if (strcmp(typeName, "App::PropertyFloat") == 0) {
App::PropertyFloat X_rotProperty;
X_rotProperty.Restore(reader);
xAngle = X_rotProperty.getValue();
}
else if (strcmp(typeName, "App::PropertyAngle") == 0) {
App::PropertyAngle X_rotProperty;
X_rotProperty.Restore(reader);
xAngle = X_rotProperty.getValue();
}
anglesToRotation(xAngle, 0, 0);
}
else if (strcmp(propName, "Y_rot") == 0) {
double yAngle;
if (strcmp(typeName, "App::PropertyFloat") == 0) {
App::PropertyFloat Y_rotProperty;
Y_rotProperty.Restore(reader);
yAngle = Y_rotProperty.getValue();
}
else if (strcmp(typeName, "App::PropertyAngle") == 0) {
App::PropertyAngle Y_rotProperty;
Y_rotProperty.Restore(reader);
yAngle = Y_rotProperty.getValue();
}
anglesToRotation(0, yAngle, 0);
}
else if (strcmp(propName, "Z_rot") == 0) {
double zAngle;
if (strcmp(typeName, "App::PropertyFloat") == 0) {
App::PropertyFloat Z_rotProperty;
Z_rotProperty.Restore(reader);
zAngle = Z_rotProperty.getValue();
}
else if (strcmp(typeName, "App::PropertyAngle") == 0) {
App::PropertyAngle Z_rotProperty;
Z_rotProperty.Restore(reader);
zAngle = Z_rotProperty.getValue();
}
Rotation.setValue(anglesToRotation(0, 0, zAngle));
}
else {
Constraint::handleChangedPropertyName(reader, typeName, propName);
}
}

View File

@@ -42,12 +42,9 @@ public:
App::PropertyLinkList NameDispl;
App::PropertyVector BasePoint;
App::PropertyVector Axis;
App::PropertyAngle X_rot;
App::PropertyAngle Y_rot;
App::PropertyAngle Z_rot;
App::PropertyRotation Rotation;
App::PropertyEnumeration TransformType;
// etc
/* */
/// recalculate the object
App::DocumentObjectExecReturn* execute() override;
@@ -56,9 +53,9 @@ public:
const char* getViewProviderName() const override;
protected:
void handleChangedPropertyType(Base::XMLReader& reader,
const char* TypeName,
App::Property* prop) override;
void handleChangedPropertyName(Base::XMLReader& reader,
const char* typeName,
const char* propName) override;
void onChanged(const App::Property* prop) override;
};

View File

@@ -366,6 +366,7 @@ SET(FemGuiSymbol_IV
Resources/symbols/ConstraintSectionPrint.iv
Resources/symbols/ConstraintSpring.iv
Resources/symbols/ConstraintTemperature.iv
Resources/symbols/ConstraintTransform.iv
Resources/symbols/ConstraintTie.iv
)

View File

@@ -1002,9 +1002,6 @@ void CmdFemConstraintTransform::activated(int)
doCommand(Doc,
"App.activeDocument().addObject(\"Fem::ConstraintTransform\",\"%s\")",
FeatName.c_str());
doCommand(Doc, "App.activeDocument().%s.X_rot = 0.0", FeatName.c_str());
doCommand(Doc, "App.activeDocument().%s.Y_rot = 0.0", FeatName.c_str());
doCommand(Doc, "App.activeDocument().%s.Z_rot = 0.0", FeatName.c_str());
doCommand(Doc, "App.activeDocument().%s.Scale = 1", FeatName.c_str());
doCommand(Doc,
"App.activeDocument().%s.addObject(App.activeDocument().%s)",

View File

@@ -0,0 +1,120 @@
#Inventor V2.1 ascii
Separator {
Separator {
DEF REC_TRANSFORM Switch {
Separator {
BaseColor {
rgb 0.0 1.0 0.0
}
DEF AXIS Separator {
Translation {
translation 0 2.5 0
}
Cone {
bottomRadius 0.4
height 1.0
}
Translation {
translation 0 -1.5 0
}
Cylinder {
radius 0.15
height 2.0
}
}
Separator {
BaseColor {
rgb 1.0 0.0 0.0
}
Rotation {
rotation 0 0 1 -1.5707964
}
USE AXIS
}
Separator {
BaseColor {
rgb 0.0 0.0 1.0
}
Rotation {
rotation 1 0 0 1.5707964
}
USE AXIS
}
}
Separator {
BaseColor {
rgb 1.0 0.0 0.0
}
Translation {
translation 0 2.5 0
}
Cone {
bottomRadius 0.4
height 1.0
}
Translation {
translation 0 -1.5 0
}
Cylinder {
radius 0.15
height 2.0
}
}
}
}
Separator {
Switch {
Separator {
BaseColor {
rgb 0.0 0.0 1.0
}
Translation {
translation 0 12.0 0
}
Cone {
bottomRadius 0.4
height 1.0
}
Translation {
translation 0 -12.5 0
}
Cylinder {
radius 0.15
height 24.0
}
}
}
}
}

View File

@@ -88,18 +88,22 @@ TaskFemConstraintTransform::TaskFemConstraintTransform(
connect(ui->rb_rect, &QRadioButton::clicked, this, &TaskFemConstraintTransform::Rect);
connect(ui->rb_cylin, &QRadioButton::clicked, this, &TaskFemConstraintTransform::Cyl);
connect(ui->sp_X,
connect(ui->spb_rot_axis_x,
qOverload<double>(&DoubleSpinBox::valueChanged),
this,
&TaskFemConstraintTransform::xAxisChanged);
connect(ui->spb_rot_axis_y,
qOverload<double>(&DoubleSpinBox::valueChanged),
this,
&TaskFemConstraintTransform::yAxisChanged);
connect(ui->spb_rot_axis_z,
qOverload<double>(&DoubleSpinBox::valueChanged),
this,
&TaskFemConstraintTransform::zAxisChanged);
connect(ui->qsb_rot_angle,
qOverload<double>(&QuantitySpinBox::valueChanged),
this,
&TaskFemConstraintTransform::x_Changed);
connect(ui->sp_Y,
qOverload<double>(&QuantitySpinBox::valueChanged),
this,
&TaskFemConstraintTransform::y_Changed);
connect(ui->sp_Z,
qOverload<double>(&QuantitySpinBox::valueChanged),
this,
&TaskFemConstraintTransform::z_Changed);
&TaskFemConstraintTransform::angleChanged);
// Get the feature data
Fem::ConstraintTransform* pcConstraint =
@@ -109,9 +113,33 @@ TaskFemConstraintTransform::TaskFemConstraintTransform(
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
// Fill data into dialog elements
ui->sp_X->setValue(pcConstraint->X_rot.getQuantityValue());
ui->sp_Y->setValue(pcConstraint->Y_rot.getQuantityValue());
ui->sp_Z->setValue(pcConstraint->Z_rot.getQuantityValue());
Base::Vector3d axis;
double angle;
pcConstraint->Rotation.getValue().getValue(axis, angle);
ui->spb_rot_axis_x->setValue(axis.x);
ui->spb_rot_axis_y->setValue(axis.y);
ui->spb_rot_axis_z->setValue(axis.z);
Base::Quantity rotAngle(angle, QString::fromUtf8("rad"));
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);
std::string transform_type = pcConstraint->TransformType.getValueAsString();
if (transform_type == "Rectangular") {
ui->sw_transform->setCurrentIndex(0);
@@ -167,11 +195,6 @@ TaskFemConstraintTransform::TaskFemConstraintTransform(
this,
&TaskFemConstraintTransform::removeFromSelection);
// Bind input fields to properties
ui->sp_X->bind(pcConstraint->X_rot);
ui->sp_Y->bind(pcConstraint->Y_rot);
ui->sp_Z->bind(pcConstraint->Z_rot);
updateUI();
if ((p == 0) && (!Objects.empty())) {
@@ -199,43 +222,40 @@ void TaskFemConstraintTransform::updateUI()
}
}
void TaskFemConstraintTransform::x_Changed(int i)
void TaskFemConstraintTransform::xAxisChanged(double x)
{
(void)x;
Base::Rotation rot = getRotation();
Fem::ConstraintTransform* pcConstraint =
static_cast<Fem::ConstraintTransform*>(ConstraintView->getObject());
double x = i;
pcConstraint->X_rot.setValue(x);
std::string name = ConstraintView->getObject()->getNameInDocument();
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.X_rot = %f", name.c_str(), x);
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
pcConstraint->References.setValues(Objects, SubElements);
pcConstraint->Rotation.setValue(rot);
}
void TaskFemConstraintTransform::y_Changed(int i)
void TaskFemConstraintTransform::yAxisChanged(double y)
{
(void)y;
Base::Rotation rot = getRotation();
Fem::ConstraintTransform* pcConstraint =
static_cast<Fem::ConstraintTransform*>(ConstraintView->getObject());
double y = i;
pcConstraint->Y_rot.setValue(y);
std::string name = ConstraintView->getObject()->getNameInDocument();
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.Y_rot = %f", name.c_str(), y);
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
pcConstraint->References.setValues(Objects, SubElements);
pcConstraint->Rotation.setValue(rot);
}
void TaskFemConstraintTransform::z_Changed(int i)
void TaskFemConstraintTransform::zAxisChanged(double z)
{
(void)z;
Base::Rotation rot = getRotation();
Fem::ConstraintTransform* pcConstraint =
static_cast<Fem::ConstraintTransform*>(ConstraintView->getObject());
double z = i;
pcConstraint->Z_rot.setValue(z);
std::string name = ConstraintView->getObject()->getNameInDocument();
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.Z_rot = %f", name.c_str(), z);
std::vector<App::DocumentObject*> Objects = pcConstraint->References.getValues();
std::vector<std::string> SubElements = pcConstraint->References.getSubValues();
pcConstraint->References.setValues(Objects, SubElements);
pcConstraint->Rotation.setValue(rot);
}
void TaskFemConstraintTransform::angleChanged(double a)
{
(void)a;
Base::Rotation rot = getRotation();
Fem::ConstraintTransform* pcConstraint =
static_cast<Fem::ConstraintTransform*>(ConstraintView->getObject());
pcConstraint->Rotation.setValue(rot);
}
void TaskFemConstraintTransform::Rect()
@@ -258,9 +278,6 @@ void TaskFemConstraintTransform::Rect()
void TaskFemConstraintTransform::Cyl()
{
ui->sw_transform->setCurrentIndex(1);
ui->sp_X->setValue(0);
ui->sp_Y->setValue(0);
ui->sp_Z->setValue(0);
std::string name = ConstraintView->getObject()->getNameInDocument();
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.TransformType = %s",
@@ -391,35 +408,15 @@ void TaskFemConstraintTransform::addToSelection()
updateUI();
if (ui->rb_rect->isChecked()) {
Base::Vector3d normal = pcConstraint->NormalDirection.getValue();
double n = normal.x;
double m = normal.y;
double l = normal.z;
// about Z-axis
double about_z;
double mag_norm_z = sqrt(n * n + m * m); // normal vector mapped onto XY plane
if (mag_norm_z == 0) {
about_z = 0;
}
else {
about_z = (-1 * (acos(m / mag_norm_z) * 180 / M_PI) + 180);
}
if (n > 0) {
about_z = about_z * (-1);
}
// rotation to ZY plane
double m_p = n * sin(about_z * M_PI / 180) + m * cos(about_z * M_PI / 180);
double l_p = l;
// about X-axis
double about_x;
double mag_norm_x = sqrt(m_p * m_p + l_p * l_p);
if (mag_norm_x == 0) {
about_x = 0;
}
else {
about_x = -(acos(l_p / mag_norm_x) * 180 / M_PI); // rotation to the Z axis
}
ui->sp_X->setValue(round(about_x));
ui->sp_Z->setValue(round(about_z));
Base::Rotation rot(Base::Vector3d(0, 0, 1), normal);
Base::Vector3d axis;
double angle;
rot.getValue(axis, angle);
ui->spb_rot_axis_x->setValue(axis.x);
ui->spb_rot_axis_y->setValue(axis.y);
ui->spb_rot_axis_z->setValue(axis.z);
Base::Quantity rotAngle(angle, QString::fromUtf8("rad"));
ui->qsb_rot_angle->setValue(rotAngle.getValueAs(Base::Quantity::Degree));
}
}
@@ -475,9 +472,10 @@ void TaskFemConstraintTransform::removeFromSelection()
}
pcConstraint->References.setValues(Objects, SubElements);
updateUI();
ui->sp_X->setValue(0);
ui->sp_Y->setValue(0);
ui->sp_Z->setValue(0);
ui->spb_rot_axis_x->setValue(0);
ui->spb_rot_axis_y->setValue(0);
ui->spb_rot_axis_z->setValue(1);
ui->qsb_rot_angle->setValue(0);
}
const std::string TaskFemConstraintTransform::getReferences() const
@@ -490,6 +488,16 @@ const std::string TaskFemConstraintTransform::getReferences() const
return TaskFemConstraint::getReferences(items);
}
Base::Rotation TaskFemConstraintTransform::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);
}
void TaskFemConstraintTransform::onReferenceDeleted()
{
TaskFemConstraintTransform::removeFromSelection();
@@ -535,19 +543,6 @@ else:\n\
+ showConstr + ".NameDispl = []\n";
}
std::string TaskFemConstraintTransform::get_X_rot() const
{
return ui->sp_X->value().getSafeUserString().toStdString();
}
std::string TaskFemConstraintTransform::get_Y_rot() const
{
return ui->sp_Y->value().getSafeUserString().toStdString();
}
std::string TaskFemConstraintTransform::get_Z_rot() const
{
return ui->sp_Z->value().getSafeUserString().toStdString();
}
std::string TaskFemConstraintTransform::get_transform_type() const
{
std::string transform;
@@ -607,27 +602,29 @@ bool TaskDlgFemConstraintTransform::accept()
static_cast<const TaskFemConstraintTransform*>(parameter);
try {
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.X_rot = \"%s\"",
name.c_str(),
parameters->get_X_rot().c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.Y_rot = \"%s\"",
name.c_str(),
parameters->get_Y_rot().c_str());
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.Z_rot = \"%s\"",
name.c_str(),
parameters->get_Z_rot().c_str());
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);
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.TransformType = %s",
name.c_str(),
parameters->get_transform_type().c_str());
std::string scale = parameters->getScale(); // OvG: determine modified scale
std::string scale = parameters->getScale();
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.Scale = %s",
name.c_str(),
scale.c_str()); // OvG: implement modified scale
scale.c_str());
}
catch (const Base::Exception& e) {
QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what()));

View File

@@ -47,9 +47,7 @@ public:
QWidget* parent = nullptr);
~TaskFemConstraintTransform() override;
const std::string getReferences() const override;
std::string get_X_rot() const;
std::string get_Y_rot() const;
std::string get_Z_rot() const;
Base::Rotation getRotation() const;
std::string get_transform_type() const;
static std::string getSurfaceReferences(const std::string showConstr);
@@ -59,9 +57,10 @@ private Q_SLOTS:
void Cyl();
void addToSelection();
void removeFromSelection();
void x_Changed(int x);
void y_Changed(int y);
void z_Changed(int z);
void xAxisChanged(double x);
void yAxisChanged(double y);
void zAxisChanged(double z);
void angleChanged(double a);
protected:
bool event(QEvent* e) override;

View File

@@ -105,76 +105,84 @@
<widget class="QWidget" name="page">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Rotation about X-Axis</string>
<widget class="QGroupBox" name="groupBox_0">
<property name="title">
<string>System Rotation</string>
</property>
<layout class="QGridLayout" name="horizontalLayout_7">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>X:</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>
<widget class="Gui::QuantitySpinBox" name="sp_X">
<property name="unit" stdset="0">
<string notr="true">deg</string>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Y:</string>
</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="minimum">
<double>-360.000000000000000</double>
</property>
<property name="maximum">
<double>360.000000000000000</double>
<property name="singleStep">
<double>0.10000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Rotation about Y-Axis</string>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Z:</string>
</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.10000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="Gui::QuantitySpinBox" name="sp_Y">
<property name="unit" stdset="0">
<string notr="true">deg</string>
</property>
<property name="minimum">
<double>-360.000000000000000</double>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Rotation about Z-Axis</string>
</property>
</widget>
</item>
<item>
<widget class="Gui::QuantitySpinBox" name="sp_Z">
<property name="unit" stdset="0">
<string notr="true">deg</string>
</property>
<property name="minimum">
<double>-360.000000000000000</double>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lb_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="unit" stdset="0">
<string notr="true">deg</string>
</property>
<property name="minimum">
<double>-360.000000000000000</double>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
@@ -222,6 +230,11 @@
<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/>

View File

@@ -27,10 +27,12 @@
#include "PreCompiled.h"
#ifndef _PreComp_
#include <Inventor/SbMatrix.h>
#include <Inventor/SbRotation.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/SbVec3f.h>
#include <Inventor/nodes/SoSeparator.h>
#include <cmath>
#include <Inventor/nodes/SoSwitch.h>
#include <Inventor/nodes/SoTransform.h>
#endif
#include "Mod/Fem/App/FemConstraintTransform.h"
@@ -46,6 +48,7 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemConstraintTransform, FemGui::ViewProvider
ViewProviderFemConstraintTransform::ViewProviderFemConstraintTransform()
{
sPixmap = "FEM_ConstraintTransform";
loadSymbol((resourceSymbolDir + "ConstraintTransform.iv").c_str());
}
ViewProviderFemConstraintTransform::~ViewProviderFemConstraintTransform() = default;
@@ -91,215 +94,82 @@ bool ViewProviderFemConstraintTransform::setEdit(int ModNum)
}
}
#define HEIGHTAXIS (20)
#define RADIUSAXIS (0.8)
#define ARROWLENGTH (3)
#define ARROWHEADRADIUS (ARROWLENGTH / 3)
#define LENGTHDISC (0.25)
#define RADIUSDISC (0.8)
void ViewProviderFemConstraintTransform::updateData(const App::Property* prop)
{
// Gets called whenever a property of the attached object changes
Fem::ConstraintTransform* pcConstraint =
static_cast<Fem::ConstraintTransform*>(this->getObject());
float scaledradiusaxis =
RADIUSAXIS * pcConstraint->Scale.getValue(); // OvG: Calculate scaled values once only
float scaledheightaxis = HEIGHTAXIS * pcConstraint->Scale.getValue();
float scaledheadradiusA =
ARROWHEADRADIUS * pcConstraint->Scale.getValue(); // OvG: Calculate scaled values once only
float scaledlengthA = ARROWLENGTH * pcConstraint->Scale.getValue();
std::string transform_type = pcConstraint->TransformType.getValueAsString();
if (transform_type == "Rectangular") {
auto obj = static_cast<Fem::ConstraintTransform*>(this->getObject());
if (prop == &pcConstraint->Points) {
const std::vector<Base::Vector3d>& points = pcConstraint->Points.getValues();
const std::vector<Base::Vector3d>& normals = pcConstraint->Normals.getValues();
if (points.size() != normals.size()) {
return;
if (prop == &obj->Rotation) {
updateSymbol();
}
else if (prop == &obj->TransformType || prop == &obj->References) {
std::string transType = obj->TransformType.getValueAsString();
auto sw = static_cast<SoSwitch*>(getSymbolSeparator()->getChild(0));
auto swExtra = static_cast<SoSwitch*>(getExtraSymbolSeparator()->getChild(0));
if (transType == "Rectangular") {
sw->whichChild.setValue(0);
swExtra->whichChild.setValue(-1);
}
else if (transType == "Cylindrical") {
sw->whichChild.setValue(1);
if (obj->References.getSize()) {
swExtra->whichChild.setValue(0);
}
std::vector<Base::Vector3d>::const_iterator n = normals.begin();
// Points and Normals are always updated together
Gui::coinRemoveAllChildren(pShapeSep);
for (const auto& point : points) {
SbVec3f base(point.x, point.y, point.z);
SbVec3f basex(point.x, point.y, point.z);
SbVec3f basey(point.x, point.y, point.z);
double x_axis_x = 1;
double x_axis_y = 0;
double x_axis_z = 0;
double y_axis_x = 0;
double y_axis_y = 1;
double y_axis_z = 0;
double z_axis_x = 0;
double z_axis_y = 0;
double z_axis_z = 1;
double rot_x = (pcConstraint->X_rot.getValue() * (M_PI / 180));
double rot_y = (pcConstraint->Y_rot.getValue() * (M_PI / 180));
double rot_z = (pcConstraint->Z_rot.getValue() * (M_PI / 180));
double x_axis_x_p;
double x_axis_y_p;
double x_axis_z_p;
double y_axis_x_p;
double y_axis_y_p;
double y_axis_z_p;
double z_axis_x_p;
double z_axis_y_p;
double z_axis_z_p;
if (rot_x != 0) {
x_axis_z_p = x_axis_z * cos(rot_x) - x_axis_y * sin(rot_x);
x_axis_y_p = x_axis_y * cos(rot_x) + x_axis_z * sin(rot_x);
x_axis_z = x_axis_z_p;
x_axis_y = x_axis_y_p;
y_axis_z_p = y_axis_z * cos(rot_x) - y_axis_y * sin(rot_x);
y_axis_y_p = y_axis_y * cos(rot_x) + y_axis_z * sin(rot_x);
y_axis_z = y_axis_z_p;
y_axis_y = y_axis_y_p;
z_axis_z_p = z_axis_z * cos(rot_x) - z_axis_y * sin(rot_x);
z_axis_y_p = z_axis_y * cos(rot_x) + z_axis_z * sin(rot_x);
z_axis_z = z_axis_z_p;
z_axis_y = z_axis_y_p;
}
if (rot_y != 0) {
x_axis_z_p = x_axis_z * cos(rot_y) + x_axis_x * sin(rot_y);
x_axis_x_p = x_axis_x * cos(rot_y) - x_axis_z * sin(rot_y);
x_axis_z = x_axis_z_p;
x_axis_x = x_axis_x_p;
y_axis_z_p = y_axis_z * cos(rot_y) + y_axis_x * sin(rot_y);
y_axis_x_p = y_axis_x * cos(rot_y) - y_axis_z * sin(rot_y);
y_axis_z = y_axis_z_p;
y_axis_x = y_axis_x_p;
z_axis_z_p = z_axis_z * cos(rot_y) + z_axis_x * sin(rot_y);
z_axis_x_p = z_axis_x * cos(rot_y) - z_axis_z * sin(rot_y);
z_axis_z = z_axis_z_p;
z_axis_x = z_axis_x_p;
}
if (rot_z != 0) {
x_axis_x_p = x_axis_x * cos(rot_z) + x_axis_y * sin(rot_z);
x_axis_y_p = x_axis_y * cos(rot_z) - x_axis_x * sin(rot_z);
x_axis_x = x_axis_x_p;
x_axis_y = x_axis_y_p;
y_axis_x_p = y_axis_x * cos(rot_z) + y_axis_y * sin(rot_z);
y_axis_y_p = y_axis_y * cos(rot_z) - y_axis_x * sin(rot_z);
y_axis_x = y_axis_x_p;
y_axis_y = y_axis_y_p;
z_axis_x_p = z_axis_x * cos(rot_z) + z_axis_y * sin(rot_z);
z_axis_y_p = z_axis_y * cos(rot_z) - z_axis_x * sin(rot_z);
z_axis_x = z_axis_x_p;
z_axis_y = z_axis_y_p;
}
SbVec3f dirz(z_axis_x, z_axis_y, z_axis_z);
SbRotation rot(SbVec3f(0, 1, 0), dirz);
SbVec3f dirx(x_axis_x, x_axis_y, x_axis_z);
SbRotation rotx(SbVec3f(0, 1, 0), dirx);
SbVec3f diry(y_axis_x, y_axis_y, y_axis_z);
SbRotation roty(SbVec3f(0, 1, 0), diry);
base = base + dirz * scaledlengthA * 0.75f;
basex = basex + dirx * scaledlengthA * 0.65f;
basey = basey + diry * scaledlengthA * 0.65f;
SoSeparator* sep = new SoSeparator();
SoMaterial* myMaterial = new SoMaterial;
myMaterial->diffuseColor.set1Value(0, SbColor(0, 0, 1)); // RGB
sep->addChild(myMaterial);
createPlacement(sep, base, rot);
createArrow(sep, scaledlengthA * 0.75, scaledheadradiusA * 0.9); // OvG: Scaling
pShapeSep->addChild(sep);
SoSeparator* sepx = new SoSeparator();
SoMaterial* myMaterialx = new SoMaterial;
myMaterialx->diffuseColor.set1Value(0, SbColor(1, 0, 0)); // RGB
sepx->addChild(myMaterialx);
createPlacement(sepx, basex, rotx);
createArrow(sepx, scaledlengthA * 0.65, scaledheadradiusA * 0.65); // OvG: Scaling
pShapeSep->addChild(sepx);
SoSeparator* sepy = new SoSeparator();
SoMaterial* myMaterialy = new SoMaterial;
myMaterialy->diffuseColor.set1Value(0, SbColor(0, 1, 0)); // RGB
sepy->addChild(myMaterialy);
createPlacement(sepy, basey, roty);
createArrow(sepy, scaledlengthA * 0.65, scaledheadradiusA * 0.65); // OvG: Scaling
pShapeSep->addChild(sepy);
n++;
else {
swExtra->whichChild.setValue(-1);
}
}
updateSymbol();
}
else if (transform_type == "Cylindrical") {
// Points and Normals are always updated together
Gui::coinRemoveAllChildren(pShapeSep);
const std::vector<Base::Vector3d>& points = pcConstraint->Points.getValues();
const std::vector<Base::Vector3d>& normals = pcConstraint->Normals.getValues();
if (points.size() != normals.size()) {
return;
}
std::vector<Base::Vector3d>::const_iterator n = normals.begin();
if (!points.empty()) {
Base::Vector3d base = pcConstraint->BasePoint.getValue();
Base::Vector3d axis = pcConstraint->Axis.getValue();
SbVec3f b(base.x, base.y, base.z);
SbVec3f ax(axis.x, axis.y, axis.z);
SbRotation rots(SbVec3f(0, -1, 0), ax);
b = b - ax * scaledheightaxis / 2;
SoSeparator* sepAx = new SoSeparator();
SoMaterial* myMaterial = new SoMaterial;
myMaterial->diffuseColor.set1Value(0, SbColor(0, 0, 1)); // RGB
sepAx->addChild(myMaterial);
createPlacement(sepAx, b, rots);
createArrow(sepAx, scaledheightaxis, scaledradiusaxis);
pShapeSep->addChild(sepAx);
}
for (const auto& point : points) {
SbVec3f base(point.x, point.y, point.z);
SbVec3f dir(n->x, n->y, n->z);
base = base + dir * scaledlengthA; // OvG: Scaling
SbRotation rot(SbVec3f(0, 1, 0), dir);
SoSeparator* sep = new SoSeparator();
SoMaterial* myMaterials = new SoMaterial;
myMaterials->diffuseColor.set1Value(0, SbColor(1, 0, 0)); // RGB
sep->addChild(myMaterials);
createPlacement(sep, base, rot);
createArrow(sep, scaledlengthA, scaledheadradiusA); // OvG: Scaling
pShapeSep->addChild(sep);
n++;
}
else if (prop == &obj->BasePoint || prop == &obj->Axis) {
updateSymbol();
}
// Gets called whenever a property of the attached object changes
ViewProviderFemConstraint::updateData(prop);
}
void ViewProviderFemConstraintTransform::transformSymbol(const Base::Vector3d& point,
const Base::Vector3d& normal,
SbMatrix& mat) const
{
auto obj = static_cast<const Fem::ConstraintTransform*>(this->getObject());
std::string transType = obj->TransformType.getValueAsString();
if (transType == "Rectangular") {
Base::Rotation rot = obj->Rotation.getValue();
Base::Vector3d axis;
double angle;
rot.getValue(axis, angle);
float s = obj->getScaleFactor();
mat.setTransform(SbVec3f(point.x, point.y, point.z),
SbRotation(SbVec3f(axis.x, axis.y, axis.z), angle),
SbVec3f(s, s, s));
}
else if (transType == "Cylindrical") {
float s = obj->getScaleFactor();
mat.setTransform(SbVec3f(point.x, point.y, point.z),
SbRotation(SbVec3f(0, 1, 0), SbVec3f(normal.x, normal.y, normal.z)),
SbVec3f(s, s, s));
}
}
void ViewProviderFemConstraintTransform::transformExtraSymbol() const
{
auto obj = static_cast<const Fem::ConstraintTransform*>(this->getObject());
std::string transType = obj->TransformType.getValueAsString();
if (transType == "Cylindrical") {
SoTransform* trans = getExtraSymbolTransform();
Base::Vector3d point = obj->BasePoint.getValue();
Base::Vector3d axis = obj->Axis.getValue();
float s = obj->getScaleFactor();
SbMatrix mat;
mat.setTransform(SbVec3f(point.x, point.y, point.z),
SbRotation(SbVec3f(0, 1, 0), SbVec3f(axis.x, axis.y, axis.z)),
SbVec3f(s, s, s));
trans->setMatrix(mat);
}
}

View File

@@ -43,6 +43,10 @@ public:
protected:
bool setEdit(int ModNum) override;
void transformSymbol(const Base::Vector3d& point,
const Base::Vector3d& normal,
SbMatrix& mat) const override;
void transformExtraSymbol() const override;
};
} // namespace FemGui

View File

@@ -160,17 +160,11 @@ def setup(doc=None, solvertype="ccxtools"):
con_transform1 = ObjectsFem.makeConstraintTransform(doc, name="FemConstraintTransform1")
con_transform1.References = [(geom_obj, "Face4")]
con_transform1.TransformType = "Cylindrical"
con_transform1.X_rot = 0.0
con_transform1.Y_rot = 0.0
con_transform1.Z_rot = 0.0
analysis.addObject(con_transform1)
con_transform2 = ObjectsFem.makeConstraintTransform(doc, name="FemConstraintTransform2")
con_transform2.References = [(geom_obj, "Face5")]
con_transform2.TransformType = "Cylindrical"
con_transform2.X_rot = 0.0
con_transform2.Y_rot = 0.0
con_transform2.Z_rot = 0.0
analysis.addObject(con_transform2)
# mesh

View File

@@ -156,9 +156,6 @@ def setup(doc=None, solvertype="ccxtools"):
con_transform = ObjectsFem.makeConstraintTransform(doc, name="ConstraintTransform")
con_transform.References = [(geom_obj, "Face1")]
con_transform.TransformType = "Cylindrical"
con_transform.X_rot = 0.0
con_transform.Y_rot = 0.0
con_transform.Z_rot = 0.0
analysis.addObject(con_transform)
# mesh

View File

@@ -26,6 +26,8 @@ __author__ = "Bernd Hahnebach"
__url__ = "https://www.freecad.org"
import FreeCAD
from femtools import geomtools
@@ -75,11 +77,15 @@ def write_constraint(f, femobj, trans_obj, ccxwriter):
if trans_obj.TransformType == "Rectangular":
trans_name = "Rect"
trans_type = "R"
coords = geomtools.get_rectangular_coords(trans_obj)
x = trans_obj.Rotation * FreeCAD.Vector(1, 0, 0)
y = trans_obj.Rotation * FreeCAD.Vector(0, 1, 0)
coords = list(x) + list(y)
elif trans_obj.TransformType == "Cylindrical":
trans_name = "Cylin"
trans_type = "C"
coords = geomtools.get_cylindrical_coords(trans_obj)
base = trans_obj.BasePoint
axis = trans_obj.Axis
coords = list(base) + list(base + axis)
f.write("*TRANSFORM, NSET={}{}, TYPE={}\n".format(
trans_name,
trans_obj.Name,

View File

@@ -3635,10 +3635,10 @@ Evolumes
** Transform Constraints
** FemConstraintTransform1
*TRANSFORM, NSET=CylinFemConstraintTransform1, TYPE=C
10,27,10,10,7,10
10,5,10,10,6,10
** FemConstraintTransform2
*TRANSFORM, NSET=CylinFemConstraintTransform2, TYPE=C
190,27,10,190,7,10
190,5,10,190,6,10
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD

View File

@@ -10979,7 +10979,7 @@ Evolumes
** Transform Constraints
** ConstraintTransform
*TRANSFORM, NSET=CylinConstraintTransform, TYPE=C
0,0,-35,0,0,-15
0,0,25,0,0,24
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD

View File

@@ -187,52 +187,3 @@ def get_element(
return part.Shape.Solids[index] # Solid
else:
return part.Shape.getElement(element) # Face, Edge, Vertex
# ************************************************************************************************
def get_rectangular_coords(
obj
):
from math import cos, sin, radians
A = [1, 0, 0]
B = [0, 1, 0]
a_x = A[0]
a_y = A[1]
a_z = A[2]
b_x = B[0]
b_y = B[1]
b_z = B[2]
x_rot = radians(obj.X_rot)
y_rot = radians(obj.Y_rot)
z_rot = radians(obj.Z_rot)
if obj.X_rot != 0:
a_y = A[1] * cos(x_rot) + A[2] * sin(x_rot)
a_z = A[2] * cos(x_rot) - A[1] * sin(x_rot)
b_y = B[1] * cos(x_rot) + B[2] * sin(x_rot)
b_z = B[2] * cos(x_rot) - B[1] * sin(x_rot)
if obj.Y_rot != 0:
a_x = A[0] * cos(y_rot) - A[2] * sin(y_rot)
a_z = A[2] * cos(y_rot) + A[0] * sin(y_rot)
b_x = B[0] * cos(y_rot) - B[2] * sin(y_rot)
b_z = B[2] * cos(y_rot) + B[0] * sin(z_rot)
if obj.Z_rot != 0:
a_x = A[0] * cos(z_rot) + A[1] * sin(z_rot)
a_y = A[1] * cos(z_rot) - A[0] * sin(z_rot)
b_x = B[0] * cos(z_rot) + B[1] * sin(z_rot)
b_y = B[1] * cos(z_rot) - B[0] * sin(z_rot)
return (a_x, a_y, a_z, b_x, b_y, b_z)
# ************************************************************************************************
def get_cylindrical_coords(
obj
):
vec = obj.Axis
base = obj.BasePoint
a_x = base[0] + 10 * vec[0]
a_y = base[1] + 10 * vec[1]
a_z = base[2] + 10 * vec[2]
b_x = base[0] - 10 * vec[0]
b_y = base[1] - 10 * vec[1]
b_z = base[2] - 10 * vec[2]
return (a_x, a_y, a_z, b_x, b_y, b_z)