From 2b1108439f1bff3e4d174e3cd2e0474b7c592cfc Mon Sep 17 00:00:00 2001 From: al Date: Thu, 12 May 2022 00:52:05 +1200 Subject: [PATCH 1/3] PD: Add offset / overall length modes for LinearPattern This commit adds support for two separate modes of defining distance between elements in PD's Linear Pattern. 1. Overall Length - which works exactly like it works before, 2. Spacing - which allows user to explicitly define distance (offset) between features. --- .../PartDesign/App/FeatureLinearPattern.cpp | 44 +++++++- src/Mod/PartDesign/App/FeatureLinearPattern.h | 29 ++++- .../Gui/TaskLinearPatternParameters.cpp | 62 ++++++++++- .../Gui/TaskLinearPatternParameters.h | 5 + .../Gui/TaskLinearPatternParameters.ui | 103 +++++++++++++++--- 5 files changed, 221 insertions(+), 22 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureLinearPattern.cpp b/src/Mod/PartDesign/App/FeatureLinearPattern.cpp index fe862b5099..7826abf175 100644 --- a/src/Mod/PartDesign/App/FeatureLinearPattern.cpp +++ b/src/Mod/PartDesign/App/FeatureLinearPattern.cpp @@ -51,25 +51,42 @@ PROPERTY_SOURCE(PartDesign::LinearPattern, PartDesign::Transformed) const App::PropertyIntegerConstraint::Constraints LinearPattern::intOccurrences = { 1, INT_MAX, 1 }; +const char* LinearPattern::ModeEnums[] = { "length", "offset", nullptr }; + LinearPattern::LinearPattern() { + auto initialMode = LinearPatternMode::length; + ADD_PROPERTY_TYPE(Direction,(nullptr),"LinearPattern",(App::PropertyType)(App::Prop_None),"Direction"); ADD_PROPERTY(Reversed,(0)); + ADD_PROPERTY(Mode, (long(initialMode))); ADD_PROPERTY(Length,(100.0)); + ADD_PROPERTY(Offset,(10.0)); ADD_PROPERTY(Occurrences,(3)); Occurrences.setConstraints(&intOccurrences); + Mode.setEnums(ModeEnums); + setReadWriteStatusForMode(initialMode); } short LinearPattern::mustExecute() const { if (Direction.isTouched() || Reversed.isTouched() || - Length.isTouched() || + Mode.isTouched() || + // Length and Offset are mutually exclusive, only one could be updated at once + Length.isTouched() || + Offset.isTouched() || Occurrences.isTouched()) return 1; return Transformed::mustExecute(); } +void LinearPattern::setReadWriteStatusForMode(LinearPatternMode mode) +{ + Length.setReadOnly(mode != LinearPatternMode::length); + Offset.setReadOnly(mode != LinearPatternMode::offset); +} + const std::list LinearPattern::getTransformations(const std::vector) { int occurrences = Occurrences.getValue(); @@ -173,7 +190,20 @@ const std::list LinearPattern::getTransformations(const std::vector(Mode.getValue())) { + case LinearPatternMode::length: + offset *= distance / (occurrences - 1); + break; + + case LinearPatternMode::offset: + offset *= Offset.getValue(); + break; + + default: + throw Base::ValueError("Invalid mode"); + } + if (reversed) offset.Reverse(); @@ -206,4 +236,14 @@ void LinearPattern::handleChangedPropertyType(Base::XMLReader& reader, const cha } } +void LinearPattern::onChanged(const App::Property* prop) +{ + if (prop == &Mode) { + auto mode = static_cast(Mode.getValue()); + setReadWriteStatusForMode(mode); + } + + Transformed::onChanged(prop); +} + } diff --git a/src/Mod/PartDesign/App/FeatureLinearPattern.h b/src/Mod/PartDesign/App/FeatureLinearPattern.h index 19e6d860be..f538335958 100644 --- a/src/Mod/PartDesign/App/FeatureLinearPattern.h +++ b/src/Mod/PartDesign/App/FeatureLinearPattern.h @@ -29,6 +29,10 @@ namespace PartDesign { +enum class LinearPatternMode { + length, + offset +}; class PartDesignExport LinearPattern : public PartDesign::Transformed { @@ -37,9 +41,11 @@ class PartDesignExport LinearPattern : public PartDesign::Transformed public: LinearPattern(); - App::PropertyLinkSub Direction; - App::PropertyBool Reversed; - App::PropertyLength Length; + App::PropertyLinkSub Direction; + App::PropertyBool Reversed; + App::PropertyEnumeration Mode; + App::PropertyLength Length; + App::PropertyLength Offset; App::PropertyIntegerConstraint Occurrences; /** @name methods override feature */ @@ -54,11 +60,18 @@ public: /** Create transformations * Returns a list of (Occurrences - 1) transformations since the first, untransformed instance - * is not counted. Each transformation will move the shape it is applied to by the distance - * (Length / (Occurrences - 1)) so that the transformations will cover the total Length. + * is not counted. + * + * Depending on Mode selection list will be constructed differently: + * 1. For "Overall Length" each transformation will move the shape it is applied to by the distance + * (Length / (Occurrences - 1)) so that the transformations will cover the total Length. + * 2. For "Spacing" each transformation will move the shape by the distance explicitly given in + * the Offset parameter. + * * If Direction contains a feature and a face name, then the transformation direction will be * the normal of the given face, which must be planar. If it contains an edge name, then the * transformation direction will be parallel to the given edge, which must be linear + * * If Reversed is true, the direction of transformation will be opposite */ const std::list getTransformations(const std::vector ) override; @@ -66,6 +79,12 @@ public: protected: void handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property* prop) override; static const App::PropertyIntegerConstraint::Constraints intOccurrences; + void onChanged(const App::Property* prop) override; + +private: + static const char* ModeEnums[]; + + void setReadWriteStatusForMode(LinearPatternMode mode); }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index f28fcb9e5d..8ed53aac18 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -127,8 +127,12 @@ void TaskLinearPatternParameters::connectSignals() this, &TaskLinearPatternParameters::onDirectionChanged); connect(ui->checkReverse, &QCheckBox::toggled, this, &TaskLinearPatternParameters::onCheckReverse); + connect(ui->comboMode, qOverload(&QComboBox::activated), + this, &TaskLinearPatternParameters::onModeChanged); connect(ui->spinLength, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &TaskLinearPatternParameters::onLength); + connect(ui->spinOffset, qOverload(&Gui::QuantitySpinBox::valueChanged), + this, &TaskLinearPatternParameters::onOffset); connect(ui->spinOccurrences, &Gui::UIntSpinBox::unsignedChanged, this, &TaskLinearPatternParameters::onOccurrences); connect(ui->checkBoxUpdateView, &QCheckBox::toggled, @@ -153,16 +157,22 @@ void TaskLinearPatternParameters::setupUI() // --------------------- ui->spinLength->bind(pcLinearPattern->Length); + ui->spinOffset->bind(pcLinearPattern->Offset); ui->spinOccurrences->bind(pcLinearPattern->Occurrences); ui->spinOccurrences->setMaximum(pcLinearPattern->Occurrences.getMaximum()); ui->spinOccurrences->setMinimum(pcLinearPattern->Occurrences.getMinimum()); ui->comboDirection->setEnabled(true); ui->checkReverse->setEnabled(true); + ui->comboMode->setEnabled(true); ui->spinLength->blockSignals(true); ui->spinLength->setEnabled(true); ui->spinLength->setUnit(Base::Unit::Length); ui->spinLength->blockSignals(false); + ui->spinOffset->blockSignals(true); + ui->spinOffset->setEnabled(true); + ui->spinOffset->setUnit(Base::Unit::Length); + ui->spinOffset->blockSignals(false); ui->spinOccurrences->setEnabled(true); dirLinks.setCombo(*(ui->comboDirection)); @@ -187,6 +197,7 @@ void TaskLinearPatternParameters::setupUI() } } + adaptVisibilityToMode(); updateUI(); connectSignals(); } @@ -198,9 +209,11 @@ void TaskLinearPatternParameters::updateUI() blockUpdate = true; PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + PartDesign::LinearPatternMode mode = static_cast(pcLinearPattern->Mode.getValue()); bool reverse = pcLinearPattern->Reversed.getValue(); double length = pcLinearPattern->Length.getValue(); + double offset = pcLinearPattern->Offset.getValue(); unsigned occurrences = pcLinearPattern->Occurrences.getValue(); if (dirLinks.setCurrentLink(pcLinearPattern->Direction) == -1){ @@ -210,15 +223,26 @@ void TaskLinearPatternParameters::updateUI() dirLinks.setCurrentLink(pcLinearPattern->Direction); } - // Note: These three lines would trigger onLength(), on Occurrences() and another updateUI() if we - // didn't check for blockUpdate + // Note: This block of code would trigger change signal handlers (e.g. onOccurrences()) + // and another updateUI() if we didn't check for blockUpdate ui->checkReverse->setChecked(reverse); + ui->comboMode->setCurrentIndex((long)mode); ui->spinLength->setValue(length); + ui->spinOffset->setValue(offset); ui->spinOccurrences->setValue(occurrences); blockUpdate = false; } +void TaskLinearPatternParameters::adaptVisibilityToMode() +{ + auto pcLinearPattern = static_cast(getObject()); + auto mode = static_cast(pcLinearPattern->Mode.getValue()); + + ui->lengthWrapper->setVisible(mode == PartDesign::LinearPatternMode::length); + ui->offsetWrapper->setVisible(mode == PartDesign::LinearPatternMode::offset); +} + void TaskLinearPatternParameters::onUpdateViewTimer() { setupTransaction(); @@ -294,6 +318,18 @@ void TaskLinearPatternParameters::onCheckReverse(const bool on) { kickUpdateViewTimer(); } +void TaskLinearPatternParameters::onModeChanged(const int mode) { + if (blockUpdate) + return; + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + pcLinearPattern->Mode.setValue(mode); + + adaptVisibilityToMode(); + + exitSelectionMode(); + kickUpdateViewTimer(); +} + void TaskLinearPatternParameters::onLength(const double l) { if (blockUpdate) return; @@ -304,6 +340,16 @@ void TaskLinearPatternParameters::onLength(const double l) { kickUpdateViewTimer(); } +void TaskLinearPatternParameters::onOffset(const double o) { + if (blockUpdate) + return; + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + pcLinearPattern->Offset.setValue(o); + + exitSelectionMode(); + kickUpdateViewTimer(); +} + void TaskLinearPatternParameters::onOccurrences(const uint n) { if (blockUpdate) return; @@ -352,6 +398,7 @@ void TaskLinearPatternParameters::onUpdateView(bool on) pcLinearPattern->Direction.setValue(obj,directions); pcLinearPattern->Reversed.setValue(getReverse()); pcLinearPattern->Length.setValue(getLength()); + pcLinearPattern->Offset.setValue(getOffset()); pcLinearPattern->Occurrences.setValue(getOccurrences()); recomputeFeature(); @@ -386,11 +433,21 @@ bool TaskLinearPatternParameters::getReverse() const return ui->checkReverse->isChecked(); } +int TaskLinearPatternParameters::getMode() const +{ + return ui->comboMode->currentIndex(); +} + double TaskLinearPatternParameters::getLength() const { return ui->spinLength->value().getValue(); } +double TaskLinearPatternParameters::getOffset() const +{ + return ui->spinOffset->value().getValue(); +} + unsigned TaskLinearPatternParameters::getOccurrences() const { return ui->spinOccurrences->value(); @@ -436,6 +493,7 @@ void TaskLinearPatternParameters::apply() FCMD_OBJ_CMD(tobj,"Reversed = " << getReverse()); ui->spinLength->apply(); + ui->spinOffset->apply(); ui->spinOccurrences->apply(); } diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h index 7edc47f5d0..41cb67733e 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h @@ -59,7 +59,9 @@ private Q_SLOTS: void onUpdateViewTimer(); void onDirectionChanged(int num); void onCheckReverse(const bool on); + void onModeChanged(const int mode); void onLength(const double l); + void onOffset(const double o); void onOccurrences(const uint n); void onUpdateView(bool) override; void onFeatureDeleted() override; @@ -72,13 +74,16 @@ protected: void clearButtons() override; void getDirection(App::DocumentObject*& obj, std::vector& sub) const; bool getReverse() const; + int getMode() const; double getLength() const; + double getOffset() const; unsigned getOccurrences() const; private: void connectSignals(); void setupUI(); void updateUI(); + void adaptVisibilityToMode(); void kickUpdateViewTimer() const; private: diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui index 751eccc4b0..7c97a94511 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui @@ -70,29 +70,106 @@ - + - + - Length + Mode - - - false - - - mm - - - 100.000000000000000 - + + + + Overall Length + + + + + Offset + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Length + + + + + + + false + + + mm + + + 100.000000000000000 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Offset + + + + + + + false + + + mm + + + 10.000000000000000 + + + + + + From 6d7fea506c67e66f574ed76ae4b0260199253a0a Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sat, 26 Aug 2023 16:00:03 +0200 Subject: [PATCH 2/3] PD: Add offset / overall angle modes for PolarPatterns This commit adds two separate modes for defining angular spacing between elements in the PD's Polar Pattern: 1. Overall Angle - which behaves exactly like it behaved before, 2. Offset Angle - which allows user to specify separation angle between consecutive elements. This change is analogue to that introduced for LinearPattern in previous commits. --- src/Mod/PartDesign/App/FeatureLinearPattern.h | 3 +- .../PartDesign/App/FeaturePolarPattern.cpp | 68 ++++++++-- src/Mod/PartDesign/App/FeaturePolarPattern.h | 36 +++++- .../Gui/TaskPolarPatternParameters.cpp | 49 ++++++- .../Gui/TaskPolarPatternParameters.h | 3 + .../Gui/TaskPolarPatternParameters.ui | 121 +++++++++++++++--- 6 files changed, 239 insertions(+), 41 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureLinearPattern.h b/src/Mod/PartDesign/App/FeatureLinearPattern.h index f538335958..8876f2646a 100644 --- a/src/Mod/PartDesign/App/FeatureLinearPattern.h +++ b/src/Mod/PartDesign/App/FeatureLinearPattern.h @@ -78,9 +78,10 @@ public: protected: void handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property* prop) override; - static const App::PropertyIntegerConstraint::Constraints intOccurrences; void onChanged(const App::Property* prop) override; + static const App::PropertyIntegerConstraint::Constraints intOccurrences; + private: static const char* ModeEnums[]; diff --git a/src/Mod/PartDesign/App/FeaturePolarPattern.cpp b/src/Mod/PartDesign/App/FeaturePolarPattern.cpp index 66f5ad4dfb..c8436fc896 100644 --- a/src/Mod/PartDesign/App/FeaturePolarPattern.cpp +++ b/src/Mod/PartDesign/App/FeaturePolarPattern.cpp @@ -51,21 +51,34 @@ PROPERTY_SOURCE(PartDesign::PolarPattern, PartDesign::Transformed) const App::PropertyIntegerConstraint::Constraints PolarPattern::intOccurrences = { 1, INT_MAX, 1 }; const App::PropertyAngle::Constraints PolarPattern::floatAngle = { Base::toDegrees(Precision::Angular()), 360.0, 1.0 }; +const char* PolarPattern::ModeEnums[] = {"angle", "offset", nullptr}; + PolarPattern::PolarPattern() { + auto initialMode = PolarPatternMode::angle; + ADD_PROPERTY_TYPE(Axis, (nullptr), "PolarPattern", (App::PropertyType)(App::Prop_None), "Direction"); ADD_PROPERTY(Reversed, (0)); + ADD_PROPERTY(Mode, (long(initialMode))); + Mode.setEnums(PolarPattern::ModeEnums); ADD_PROPERTY(Angle, (360.0)); + ADD_PROPERTY(Offset, (120.0)); Angle.setConstraints(&floatAngle); + Offset.setConstraints(&floatAngle); ADD_PROPERTY(Occurrences, (3)); Occurrences.setConstraints(&intOccurrences); + + setReadWriteStatusForMode(initialMode); } short PolarPattern::mustExecute() const { if (Axis.isTouched() || Reversed.isTouched() || - Angle.isTouched() || + Mode.isTouched() || + // Angle and Offset are mutually exclusive, only one could be updated at once + Angle.isTouched() || + Offset.isTouched() || Occurrences.isTouched()) return 1; return Transformed::mustExecute(); @@ -80,17 +93,7 @@ const std::list PolarPattern::getTransformations(const std::vector(angle); - if (radians < Precision::Angular()) - throw Base::ValueError("Pattern angle too small"); - bool reversed = Reversed.getValue(); - double offset; - if (std::fabs(angle - 360.0) < Precision::Confusion()) - offset = radians / occurrences; // Because e.g. two occurrences in 360 degrees need to be 180 degrees apart - else - offset = radians / (occurrences - 1); App::DocumentObject* refObject = Axis.getValue(); if (!refObject) @@ -166,6 +169,32 @@ const std::list PolarPattern::getTransformations(const std::vector(Mode.getValue())) { + case PolarPatternMode::angle: + angle = Angle.getValue(); + + if (std::fabs(angle - 360.0) < Precision::Confusion()) + angle /= occurrences; // Because e.g. two occurrences in 360 degrees need to be 180 degrees apart + else + angle /= occurrences - 1; + + break; + + case PolarPatternMode::offset: + angle = Offset.getValue(); + break; + + default: + throw Base::ValueError("Invalid mode"); + } + + double offset = Base::toRadians(angle); + + if (offset < Precision::Angular()) + throw Base::ValueError("Pattern angle too small"); + std::list transformations; gp_Trsf trans; transformations.push_back(trans); @@ -195,4 +224,21 @@ void PolarPattern::handleChangedPropertyType(Base::XMLReader& reader, const char } } + +void PolarPattern::onChanged(const App::Property* prop) +{ + if (prop == &Mode) { + auto mode = static_cast(Mode.getValue()); + setReadWriteStatusForMode(mode); + } + + Transformed::onChanged(prop); +} + +void PolarPattern::setReadWriteStatusForMode(PolarPatternMode mode) +{ + Offset.setReadOnly(mode != PolarPatternMode::offset); + Angle.setReadOnly(mode != PolarPatternMode::angle); +} + } diff --git a/src/Mod/PartDesign/App/FeaturePolarPattern.h b/src/Mod/PartDesign/App/FeaturePolarPattern.h index 7362f311a5..f250820fec 100644 --- a/src/Mod/PartDesign/App/FeaturePolarPattern.h +++ b/src/Mod/PartDesign/App/FeaturePolarPattern.h @@ -31,6 +31,10 @@ namespace PartDesign { +enum class PolarPatternMode { + angle, + offset +}; class PartDesignExport PolarPattern : public PartDesign::Transformed { @@ -39,9 +43,11 @@ class PartDesignExport PolarPattern : public PartDesign::Transformed public: PolarPattern(); - App::PropertyLinkSub Axis; - App::PropertyBool Reversed; - App::PropertyAngle Angle; + App::PropertyLinkSub Axis; + App::PropertyBool Reversed; + App::PropertyEnumeration Mode; + App::PropertyAngle Angle; + App::PropertyAngle Offset; App::PropertyIntegerConstraint Occurrences; /** @name methods override feature */ @@ -55,21 +61,37 @@ public: //@} /** Create transformations + * * Returns a list of (Occurrences - 1) transformations since the first, untransformed instance - * is not counted. Each transformation will rotate the shape it is applied to by the angle - * (Angle / (Occurrences - 1)) so that the transformations will cover the total Angle. The only - * exception is Angle = 360 degrees in which case the transformation angle will be - * (Angle / Occurrences) so that the last transformed shape is not identical with the original shape + * is not counted. Each transformation will rotate the shape it is applied to by the supplied angle. + * + * Depending on Mode selection list will be constructed differently: + * 1. For "angle" mode each feature will be rotated by (Angle / (Occurrences - 1)) so + * that the transformations will cover the total Angle. The only exception is Angle = 360 degrees in + * which case the transformation angle will be (Angle / Occurrences) so that the last transformed shape + * is not identical with the original shape. + * 2. For "offset" mode each feature will be rotated using exact angle from Offset parameter. It can + * potentially result in transformation that extends beyond full rotation or results in overlapping shapes. + * This situations are considered as potential user errors and should be solved by user. + * * If Axis contains a feature and an edge name, then the transformation axis will be * the given edge, which must be linear. + * * If Reversed is true, the direction of rotation will be opposite. */ const std::list getTransformations(const std::vector) override; protected: void handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property* prop) override; + void onChanged(const App::Property* prop) override; + static const App::PropertyIntegerConstraint::Constraints intOccurrences; static const App::PropertyAngle::Constraints floatAngle; + +private: + static const char* ModeEnums[]; + + void setReadWriteStatusForMode(PolarPatternMode mode); }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp index f3764ed5f8..92bdb55912 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp @@ -131,10 +131,14 @@ void TaskPolarPatternParameters::connectSignals() this, &TaskPolarPatternParameters::onUpdateViewTimer); connect(ui->comboAxis, qOverload(&QComboBox::activated), this, &TaskPolarPatternParameters::onAxisChanged); + connect(ui->comboMode, qOverload(&QComboBox::activated), + this, &TaskPolarPatternParameters::onModeChanged); connect(ui->checkReverse, &QCheckBox::toggled, this, &TaskPolarPatternParameters::onCheckReverse); connect(ui->polarAngle, qOverload(&Gui::QuantitySpinBox::valueChanged), this, &TaskPolarPatternParameters::onAngle); + connect(ui->angleOffset, qOverload(&Gui::QuantitySpinBox::valueChanged), + this, &TaskPolarPatternParameters::onOffset); connect(ui->spinOccurrences, &Gui::UIntSpinBox::unsignedChanged, this, &TaskPolarPatternParameters::onOccurrences); connect(ui->checkBoxUpdateView, &QCheckBox::toggled, @@ -159,11 +163,14 @@ void TaskPolarPatternParameters::setupUI() // --------------------- ui->polarAngle->bind(pcPolarPattern->Angle); + ui->angleOffset->bind(pcPolarPattern->Offset); + ui->spinOccurrences->bind(pcPolarPattern->Occurrences); ui->spinOccurrences->setMaximum(pcPolarPattern->Occurrences.getMaximum()); ui->spinOccurrences->setMinimum(pcPolarPattern->Occurrences.getMinimum()); ui->comboAxis->setEnabled(true); + ui->comboMode->setEnabled(true); ui->checkReverse->setEnabled(true); ui->polarAngle->setEnabled(true); ui->spinOccurrences->setEnabled(true); @@ -191,6 +198,7 @@ void TaskPolarPatternParameters::setupUI() } } + adaptVisibilityToMode(); updateUI(); connectSignals(); } @@ -203,20 +211,24 @@ void TaskPolarPatternParameters::updateUI() PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + PartDesign::PolarPatternMode mode = static_cast(pcPolarPattern->Mode.getValue()); bool reverse = pcPolarPattern->Reversed.getValue(); double angle = pcPolarPattern->Angle.getValue(); + double offset = pcPolarPattern->Offset.getValue(); unsigned occurrences = pcPolarPattern->Occurrences.getValue(); - if (axesLinks.setCurrentLink(pcPolarPattern->Axis) == -1){ + if (axesLinks.setCurrentLink(pcPolarPattern->Axis) == -1) { //failed to set current, because the link isn't in the list yet axesLinks.addLink(pcPolarPattern->Axis, getRefStr(pcPolarPattern->Axis.getValue(),pcPolarPattern->Axis.getSubValues())); axesLinks.setCurrentLink(pcPolarPattern->Axis); } - // Note: These three lines would trigger onLength(), on Occurrences() and another updateUI() if we - // didn't check for blockUpdate + // Note: This block of code would trigger change signal handlers (e.g. onOccurrences()) + // and another updateUI() if we didn't check for blockUpdate ui->checkReverse->setChecked(reverse); + ui->comboMode->setCurrentIndex((long)mode); ui->polarAngle->setValue(angle); + ui->angleOffset->setValue(offset); ui->spinOccurrences->setValue(occurrences); blockUpdate = false; @@ -233,6 +245,15 @@ void TaskPolarPatternParameters::kickUpdateViewTimer() const updateViewTimer->start(); } +void TaskPolarPatternParameters::adaptVisibilityToMode() +{ + auto pcLinearPattern = static_cast(getObject()); + auto mode = static_cast(pcLinearPattern->Mode.getValue()); + + ui->polarAngleWrapper->setVisible(mode == PartDesign::PolarPatternMode::angle); + ui->angleOffsetWrapper->setVisible(mode == PartDesign::PolarPatternMode::offset); +} + void TaskPolarPatternParameters::addObject(App::DocumentObject* obj) { QString label = QString::fromUtf8(obj->Label.getValue()); @@ -292,6 +313,18 @@ void TaskPolarPatternParameters::onCheckReverse(const bool on) { kickUpdateViewTimer(); } +void TaskPolarPatternParameters::onModeChanged(const int mode) { + if (blockUpdate) + return; + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + pcPolarPattern->Mode.setValue(mode); + + adaptVisibilityToMode(); + + exitSelectionMode(); + kickUpdateViewTimer(); +} + void TaskPolarPatternParameters::onAngle(const double a) { if (blockUpdate) return; @@ -302,6 +335,16 @@ void TaskPolarPatternParameters::onAngle(const double a) { kickUpdateViewTimer(); } +void TaskPolarPatternParameters::onOffset(const double a) { + if (blockUpdate) + return; + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + pcPolarPattern->Offset.setValue(a); + + exitSelectionMode(); + kickUpdateViewTimer(); +} + void TaskPolarPatternParameters::onOccurrences(const uint n) { if (blockUpdate) return; diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h index 0408574993..b01121c23c 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h @@ -58,8 +58,10 @@ public: private Q_SLOTS: void onUpdateViewTimer(); void onAxisChanged(int num); + void onModeChanged(const int mode); void onCheckReverse(const bool on); void onAngle(const double a); + void onOffset(const double a); void onOccurrences(const uint n); void onUpdateView(bool) override; void onFeatureDeleted() override; @@ -82,6 +84,7 @@ private: void setupUI(); void updateUI(); void kickUpdateViewTimer() const; + void adaptVisibilityToMode(); private: std::unique_ptr ui; diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.ui b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.ui index 9e26831d5a..b95832289f 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.ui @@ -70,35 +70,118 @@ - + - + - Angle + Mode - - - false - - - deg - - - 0.000000000000000 - - - 360.000000000000000 - - - 360.000000000000000 - + + + + Overall Angle + + + + + Offset Angle + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Angle + + + + + + + false + + + deg + + + 0.000000000000000 + + + 360.000000000000000 + + + 360.000000000000000 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Offset + + + + + + + false + + + deg + + + 0.000000000000000 + + + 360.000000000000000 + + + 360.000000000000000 + + + + + + From 1c70983c60c604b7f96ec919128926b8163715f5 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sat, 26 Aug 2023 20:02:28 +0200 Subject: [PATCH 3/3] PD: Keep Length and Offset in sync for LinearPattern As Length and Offset represents the same concept in different way it is useful to keep them in sync when it is possible. Update to one of them will update the other with approperiate value. This behaviour behaviour works only if both properties are not coming from expression engine - those will stay not touched. --- src/Mod/PartDesign/App/FeatureLinearPattern.cpp | 12 +++++++++++- .../PartDesign/Gui/TaskLinearPatternParameters.cpp | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureLinearPattern.cpp b/src/Mod/PartDesign/App/FeatureLinearPattern.cpp index 7826abf175..2ba1df02a2 100644 --- a/src/Mod/PartDesign/App/FeatureLinearPattern.cpp +++ b/src/Mod/PartDesign/App/FeatureLinearPattern.cpp @@ -238,11 +238,21 @@ void LinearPattern::handleChangedPropertyType(Base::XMLReader& reader, const cha void LinearPattern::onChanged(const App::Property* prop) { + auto mode = static_cast(Mode.getValue()); + if (prop == &Mode) { - auto mode = static_cast(Mode.getValue()); setReadWriteStatusForMode(mode); } + // Keep Length in sync with Offset + if (mode == LinearPatternMode::offset && prop == &Offset && !Length.testStatus(App::Property::Status::Immutable)) { + Length.setValue(Offset.getValue() * (Occurrences.getValue() - 1)); + } + + if (mode == LinearPatternMode::length && prop == &Length && !Offset.testStatus(App::Property::Status::Immutable)) { + Offset.setValue(Length.getValue() / (Occurrences.getValue() - 1)); + } + Transformed::onChanged(prop); } diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index 8ed53aac18..b0e6c13d64 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -198,7 +198,6 @@ void TaskLinearPatternParameters::setupUI() } adaptVisibilityToMode(); - updateUI(); connectSignals(); } @@ -241,6 +240,8 @@ void TaskLinearPatternParameters::adaptVisibilityToMode() ui->lengthWrapper->setVisible(mode == PartDesign::LinearPatternMode::length); ui->offsetWrapper->setVisible(mode == PartDesign::LinearPatternMode::offset); + + updateUI(); } void TaskLinearPatternParameters::onUpdateViewTimer()