diff --git a/src/Mod/Fem/App/FemConstraintTransform.cpp b/src/Mod/Fem/App/FemConstraintTransform.cpp index 163f190c60..462202649d 100644 --- a/src/Mod/Fem/App/FemConstraintTransform.cpp +++ b/src/Mod/Fem/App/FemConstraintTransform.cpp @@ -23,8 +23,10 @@ #include "PreCompiled.h" -#include "FemConstraintTransform.h" +#include +#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 points; - std::vector 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 ref = References.getValues(); + std::vector subRef = References.getSubValues(); + if (ref.empty()) { + return; } + + Part::Feature* feat = static_cast(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); + } } diff --git a/src/Mod/Fem/App/FemConstraintTransform.h b/src/Mod/Fem/App/FemConstraintTransform.h index 3c77fc948c..ecbdbb99cf 100644 --- a/src/Mod/Fem/App/FemConstraintTransform.h +++ b/src/Mod/Fem/App/FemConstraintTransform.h @@ -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; }; diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 63afa186a2..6fede03fac 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -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 ) diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 5cd5b29be7..2c0d734b2e 100644 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -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)", diff --git a/src/Mod/Fem/Gui/Resources/symbols/ConstraintTransform.iv b/src/Mod/Fem/Gui/Resources/symbols/ConstraintTransform.iv new file mode 100644 index 0000000000..f001b5daa1 --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/symbols/ConstraintTransform.iv @@ -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 + + } + } + } + } +} diff --git a/src/Mod/Fem/Gui/TaskFemConstraintTransform.cpp b/src/Mod/Fem/Gui/TaskFemConstraintTransform.cpp index 08a0b49824..b669dee265 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintTransform.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintTransform.cpp @@ -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(&DoubleSpinBox::valueChanged), + this, + &TaskFemConstraintTransform::xAxisChanged); + connect(ui->spb_rot_axis_y, + qOverload(&DoubleSpinBox::valueChanged), + this, + &TaskFemConstraintTransform::yAxisChanged); + connect(ui->spb_rot_axis_z, + qOverload(&DoubleSpinBox::valueChanged), + this, + &TaskFemConstraintTransform::zAxisChanged); + connect(ui->qsb_rot_angle, qOverload(&QuantitySpinBox::valueChanged), this, - &TaskFemConstraintTransform::x_Changed); - connect(ui->sp_Y, - qOverload(&QuantitySpinBox::valueChanged), - this, - &TaskFemConstraintTransform::y_Changed); - connect(ui->sp_Z, - qOverload(&QuantitySpinBox::valueChanged), - this, - &TaskFemConstraintTransform::z_Changed); + &TaskFemConstraintTransform::angleChanged); // Get the feature data Fem::ConstraintTransform* pcConstraint = @@ -109,9 +113,33 @@ TaskFemConstraintTransform::TaskFemConstraintTransform( std::vector 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(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 Objects = pcConstraint->References.getValues(); - std::vector 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(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 Objects = pcConstraint->References.getValues(); - std::vector 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(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 Objects = pcConstraint->References.getValues(); - std::vector 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(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(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())); diff --git a/src/Mod/Fem/Gui/TaskFemConstraintTransform.h b/src/Mod/Fem/Gui/TaskFemConstraintTransform.h index a570128e9d..d6e087c5a5 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintTransform.h +++ b/src/Mod/Fem/Gui/TaskFemConstraintTransform.h @@ -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; diff --git a/src/Mod/Fem/Gui/TaskFemConstraintTransform.ui b/src/Mod/Fem/Gui/TaskFemConstraintTransform.ui index a4792249f6..9adc553c4d 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintTransform.ui +++ b/src/Mod/Fem/Gui/TaskFemConstraintTransform.ui @@ -105,76 +105,84 @@ - - - - - Rotation about X-Axis + + + System Rotation + + + + + + X: + + + + + + + false + + + 0.10000000000000 - - - - - deg + + + + + Y: + + + + + + + false - - -360.000000000000000 - - - 360.000000000000000 + + 0.10000000000000 - - - - - - - - - Rotation about Y-Axis + + + + + Z: + + + + + + + false + + + 0.10000000000000 - - - - - deg - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - - - - Rotation about Z-Axis - - - - - - - deg - - - -360.000000000000000 - - - 360.000000000000000 - - - - + + + + + Angle: + + + + + + + deg + + + -360.000000000000000 + + + 360.000000000000000 + + + + + @@ -222,6 +230,11 @@ QWidget
Gui/QuantitySpinBox.h
+ + Gui::DoubleSpinBox + QWidget +
Gui/SpinBox.h
+
diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintTransform.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintTransform.cpp index ad903451f9..f891d5789d 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintTransform.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintTransform.cpp @@ -27,10 +27,12 @@ #include "PreCompiled.h" #ifndef _PreComp_ +#include #include -#include +#include #include -#include +#include +#include #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(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(this->getObject()); - if (prop == &pcConstraint->Points) { - const std::vector& points = pcConstraint->Points.getValues(); - const std::vector& 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(getSymbolSeparator()->getChild(0)); + auto swExtra = static_cast(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::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& points = pcConstraint->Points.getValues(); - const std::vector& normals = pcConstraint->Normals.getValues(); - - if (points.size() != normals.size()) { - return; - } - std::vector::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(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(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); + } +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintTransform.h b/src/Mod/Fem/Gui/ViewProviderFemConstraintTransform.h index 42beaeb1b0..5b356473f2 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintTransform.h +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintTransform.h @@ -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 diff --git a/src/Mod/Fem/femexamples/constraint_transform_beam_hinged.py b/src/Mod/Fem/femexamples/constraint_transform_beam_hinged.py index 04fcbac1ad..ab1bc43824 100644 --- a/src/Mod/Fem/femexamples/constraint_transform_beam_hinged.py +++ b/src/Mod/Fem/femexamples/constraint_transform_beam_hinged.py @@ -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 diff --git a/src/Mod/Fem/femexamples/constraint_transform_torque.py b/src/Mod/Fem/femexamples/constraint_transform_torque.py index 209d34f973..312cdbeb46 100644 --- a/src/Mod/Fem/femexamples/constraint_transform_torque.py +++ b/src/Mod/Fem/femexamples/constraint_transform_torque.py @@ -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 diff --git a/src/Mod/Fem/femsolver/calculix/write_constraint_transform.py b/src/Mod/Fem/femsolver/calculix/write_constraint_transform.py index 6b012dd7d4..949d8384d9 100644 --- a/src/Mod/Fem/femsolver/calculix/write_constraint_transform.py +++ b/src/Mod/Fem/femsolver/calculix/write_constraint_transform.py @@ -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, diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp b/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp index 3f39638f93..1725927172 100644 --- a/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp +++ b/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp @@ -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 diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp b/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp index b5747c0145..a4f0b4dc22 100644 --- a/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp +++ b/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp @@ -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 diff --git a/src/Mod/Fem/femtools/geomtools.py b/src/Mod/Fem/femtools/geomtools.py index 34ddf29a27..bd3f502df7 100644 --- a/src/Mod/Fem/femtools/geomtools.py +++ b/src/Mod/Fem/femtools/geomtools.py @@ -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)