From b41e592441348efe0189bcae0270d7276cd32bfb Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Thu, 14 Jul 2022 11:59:46 +0530 Subject: [PATCH 1/8] [PartDesign] Add some dummy options for revolution These options correspond to "up to face" and "2 angles". They are expected to do nothing right now. However there is also some experimental code for "up to face" in this commit, whose behavior is not confirmed. --- src/Mod/PartDesign/App/FeatureRevolution.cpp | 54 +++++++++++++-- src/Mod/PartDesign/App/FeatureRevolution.h | 6 ++ .../Gui/TaskRevolutionParameters.cpp | 52 ++++++++++++-- .../PartDesign/Gui/TaskRevolutionParameters.h | 13 ++++ .../Gui/TaskRevolutionParameters.ui | 67 +++++++++++++++++++ 5 files changed, 180 insertions(+), 12 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 57312f172b..d6f3d96518 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include # include +# include # include # include # include @@ -42,6 +43,7 @@ using namespace PartDesign; namespace PartDesign { +const char* Revolution::TypeEnums[]= {"Angle", "UpToLast", "UpToFirst", "UpToFace", "TwoAngles", nullptr}; PROPERTY_SOURCE(PartDesign::Revolution, PartDesign::ProfileBased) @@ -51,9 +53,14 @@ Revolution::Revolution() { addSubType = FeatureAddSub::Additive; + ADD_PROPERTY_TYPE(Type, (0L), "Revolution", App::Prop_None, "Revolution type"); + Type.setEnums(TypeEnums); ADD_PROPERTY_TYPE(Base,(Base::Vector3d(0.0,0.0,0.0)),"Revolution", App::Prop_ReadOnly, "Base"); ADD_PROPERTY_TYPE(Axis,(Base::Vector3d(0.0,1.0,0.0)),"Revolution", App::Prop_ReadOnly, "Axis"); ADD_PROPERTY_TYPE(Angle,(360.0),"Revolution", App::Prop_None, "Angle"); + ADD_PROPERTY_TYPE(UpToFace, (nullptr), "Revolution", App::Prop_None, "Face where revolution will end"); + ADD_PROPERTY_TYPE(Angle2, (60.0), "Revolution", App::Prop_None, "Revolution length in 2nd direction"); + Angle.setConstraints(&floatAngle); ADD_PROPERTY_TYPE(ReferenceAxis,(nullptr),"Revolution",(App::Prop_None),"Reference axis of revolution"); } @@ -64,7 +71,9 @@ short Revolution::mustExecute() const ReferenceAxis.isTouched() || Axis.isTouched() || Base.isTouched() || - Angle.isTouched()) + UpToFace.isTouched() || + Angle.isTouched() || + Angle2.isTouched()) return 1; return ProfileBased::mustExecute(); } @@ -140,11 +149,46 @@ App::DocumentObjectExecReturn *Revolution::execute() return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Revolve axis intersects the sketch")); } - // revolve the face to a solid - BRepPrimAPI_MakeRevol RevolMaker(sketchshape, gp_Ax1(pnt, dir), angle); + TopoDS_Shape result; - if (RevolMaker.IsDone()) { - TopoDS_Shape result = RevolMaker.Shape(); + std::string method(Type.getValueAsString()); + if (method == "UpToFace") { + TopoDS_Face supportface = getSupportFace(); + supportface.Move(invObjLoc); + + TopoDS_Face upToFace; + if (method == "UpToFace") { + getFaceFromLinkSub(upToFace, UpToFace); + upToFace.Move(invObjLoc); + } + getUpToFace(upToFace, base, sketchshape, method, dir); + + // TODO: Make enum + int mode = 2; + BRepFeat_MakeRevol RevolMaker; + for (TopExp_Explorer xp(sketchshape, TopAbs_FACE); xp.More(); xp.Next()) { + RevolMaker.Init(base, xp.Current(), supportface, gp_Ax1(pnt, dir), mode, Standard_True); + RevolMaker.Perform(upToFace); + + if (!RevolMaker.IsDone()) + throw Base::RuntimeError("ProfileBased: Up to face: Could not revolve the sketch!"); + + base = RevolMaker.Shape(); + if (mode == 2) + mode = 1; + } + + result = base; + } + else { + // revolve the face to a solid + BRepPrimAPI_MakeRevol RevolMaker(sketchshape, gp_Ax1(pnt, dir), angle); + + if (RevolMaker.IsDone()) + result = RevolMaker.Shape(); + } + + if (!result.IsNull()) { result = refineShapeIfActive(result); // set the additive shape property for later usage in e.g. pattern this->AddSubShape.setValue(result); diff --git a/src/Mod/PartDesign/App/FeatureRevolution.h b/src/Mod/PartDesign/App/FeatureRevolution.h index 23478f46c2..210156f2ad 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.h +++ b/src/Mod/PartDesign/App/FeatureRevolution.h @@ -37,9 +37,11 @@ class PartDesignExport Revolution : public ProfileBased public: Revolution(); + App::PropertyEnumeration Type; App::PropertyVector Base; App::PropertyVector Axis; App::PropertyAngle Angle; + App::PropertyAngle Angle2; /** if this property is set to a valid link, both Axis and Base properties * are calculated according to the linked line @@ -65,11 +67,15 @@ public: /// suggests a value for Reversed flag so that material is always added to the support bool suggestReversed(); + protected: /// updates Axis from ReferenceAxis void updateAxis(); static const App::PropertyAngle::Constraints floatAngle; + +private: + static const char* TypeEnums[]; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 134bd92399..61c32d9cf5 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -59,10 +59,13 @@ TaskRevolutionParameters::TaskRevolutionParameters(PartDesignGui::ViewProvider* // bind property mirrors if (auto *rev = dynamic_cast(vp->getObject())) { this->propAngle = &(rev->Angle); + this->propAngle2 = &(rev->Angle2); this->propMidPlane = &(rev->Midplane); this->propReferenceAxis = &(rev->ReferenceAxis); this->propReversed = &(rev->Reversed); + this->propUpToFace = &(rev->UpToFace); ui->revolveAngle->bind(rev->Angle); + ui->revolveAngle2->bind(rev->Angle2); } else if (auto *rev = dynamic_cast(vp->getObject())) { this->propAngle = &(rev->Angle); @@ -75,18 +78,13 @@ TaskRevolutionParameters::TaskRevolutionParameters(PartDesignGui::ViewProvider* throw Base::TypeError("The object is neither a Groove nor a Revolution."); } - ui->checkBoxMidplane->setChecked(propMidPlane->getValue()); - ui->checkBoxReversed->setChecked(propReversed->getValue()); - - ui->revolveAngle->setValue(propAngle->getValue()); - ui->revolveAngle->setMaximum(propAngle->getMaximum()); - ui->revolveAngle->setMinimum(propAngle->getMinimum()); + setupDialog(); blockUpdate = false; updateUI(); connectSignals(); - setFocus (); + setFocus(); // show the parts coordinate system axis for selection PartDesign::Body * body = PartDesign::Body::findBodyOf ( vp->getObject () ); @@ -103,6 +101,31 @@ TaskRevolutionParameters::TaskRevolutionParameters(PartDesignGui::ViewProvider* } } +void TaskRevolutionParameters::setupDialog() +{ + PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); + ui->checkBoxMidplane->setChecked(propMidPlane->getValue()); + ui->checkBoxReversed->setChecked(propReversed->getValue()); + + ui->revolveAngle->setValue(propAngle->getValue()); + ui->revolveAngle->setMaximum(propAngle->getMaximum()); + ui->revolveAngle->setMinimum(propAngle->getMinimum()); + + int index = 0; + + // TODO: This should also be implemented for groove + if (pcFeat->isDerivedFrom(PartDesign::Revolution::getClassTypeId())) { + PartDesign::Revolution* rev = static_cast(vp->getObject()); + ui->revolveAngle2->setValue(propAngle2->getValue()); + ui->revolveAngle2->setMaximum(propAngle2->getMaximum()); + ui->revolveAngle2->setMinimum(propAngle2->getMinimum()); + + index = rev->Type.getValue(); + } + + translateModeList(index); +} + void TaskRevolutionParameters::fillAxisCombo(bool forceRefill) { Base::StateLocker lock(blockUpdate, true); @@ -217,6 +240,18 @@ void TaskRevolutionParameters::onSelectionChanged(const Gui::SelectionChanges& m } } +void TaskRevolutionParameters::translateModeList(int index) +{ + // Must correspond to values from PartDesign::Revolution::TypeEnums + ui->changeMode->clear(); + ui->changeMode->addItem(tr("Dimension")); + // ui->changeMode->addItem(tr("To last")); + // ui->changeMode->addItem(tr("To first")); + ui->changeMode->addItem(tr("Up to face")); + ui->changeMode->addItem(tr("Two dimensions")); + ui->changeMode->setCurrentIndex(index); +} + void TaskRevolutionParameters::onAngleChanged(double len) { @@ -354,6 +389,9 @@ void TaskRevolutionParameters::changeEvent(QEvent *event) TaskBox::changeEvent(event); if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(proxy); + + // Translate mode items + translateModeList(ui->changeMode->currentIndex()); } } diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h index 1d81ea59a4..07b574f1f7 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h @@ -49,6 +49,15 @@ public: void apply() override; + enum class Modes { + Dimension, + ThroughAll, + ToLast = ThroughAll, + ToFirst, + ToFace, + TwoDimensions + }; + /** * @brief fillAxisCombo fills the combo and selects the item according to * current value of revolution object's axis reference. @@ -71,17 +80,21 @@ protected: void getReferenceAxis(App::DocumentObject *&obj, std::vector &sub) const; bool getMidplane() const; bool getReversed() const; + void setupDialog(void); //mirrors of revolution's or groove's properties //should have been done by inheriting revolution and groove from common class... App::PropertyAngle* propAngle; + App::PropertyAngle* propAngle2; App::PropertyBool* propReversed; App::PropertyBool* propMidPlane; App::PropertyLinkSub* propReferenceAxis; + App::PropertyLinkSub* propUpToFace; private: void connectSignals(); void updateUI(); + void translateModeList(int index); private: std::unique_ptr ui; diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui index 5f55ae1e12..36affd62b4 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui @@ -14,6 +14,26 @@ Form + + + + + + Type + + + + + + + + Dimension + + + + + + @@ -109,6 +129,53 @@ + + + + + + 2nd angle + + + + + + + false + + + deg + + + 0.000000000000000 + + + 360.000000000000000 + + + 10.000000000000000 + + + 60.000000000000000 + + + + + + + + + + + Face + + + + + + + + From a7da1003fcb0275daaf3f73658f2b0e728bfae55 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Fri, 15 Jul 2022 13:10:30 +0530 Subject: [PATCH 2/8] [PartDesign] Some more dummy functionality for revolution [PD] Some more setup [PD] Some refactor in `TaskRevolutionParameters` --- .../Gui/TaskRevolutionParameters.cpp | 207 +++++++++++++++--- .../PartDesign/Gui/TaskRevolutionParameters.h | 11 +- .../Gui/TaskRevolutionParameters.ui | 3 + 3 files changed, 190 insertions(+), 31 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 61c32d9cf5..5e4fc65890 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -126,6 +126,17 @@ void TaskRevolutionParameters::setupDialog() translateModeList(index); } +void TaskRevolutionParameters::translateModeList(int index) +{ + ui->changeMode->clear(); + ui->changeMode->addItem(tr("Dimension")); + ui->changeMode->addItem(tr("To last")); + ui->changeMode->addItem(tr("To first")); + ui->changeMode->addItem(tr("Up to face")); + ui->changeMode->addItem(tr("Two dimensions")); + ui->changeMode->setCurrentIndex(index); +} + void TaskRevolutionParameters::fillAxisCombo(bool forceRefill) { Base::StateLocker lock(blockUpdate, true); @@ -204,19 +215,27 @@ void TaskRevolutionParameters::addAxisToCombo(App::DocumentObject* linkObj, void TaskRevolutionParameters::connectSignals() { - connect(ui->revolveAngle, qOverload(&QuantitySpinBox::valueChanged), this, - &TaskRevolutionParameters::onAngleChanged); - connect(ui->axis, qOverload(&QComboBox::activated), this, - &TaskRevolutionParameters::onAxisChanged); - connect(ui->checkBoxMidplane, &QCheckBox::toggled, this, - &TaskRevolutionParameters::onMidplane); - connect(ui->checkBoxReversed, &QCheckBox::toggled, this, - &TaskRevolutionParameters::onReversed); - connect(ui->checkBoxUpdateView, &QCheckBox::toggled, this, - &TaskRevolutionParameters::onUpdateView); + connect(ui->revolveAngle, qOverload(&Gui::QuantitySpinBox::valueChanged), + this, &TaskRevolutionParameters::onAngleChanged); + connect(ui->revolveAngle2, qOverload(&Gui::QuantitySpinBox::valueChanged), + this, &TaskRevolutionParameters::onAngle2Changed); + connect(ui->axis, qOverload(&QComboBox::activated), + this, &TaskRevolutionParameters::onAxisChanged); + connect(ui->checkBoxMidplane, &QCheckBox::toggled, + this, &TaskRevolutionParameters::onMidplane); + connect(ui->checkBoxReversed, &QCheckBox::toggled, + this, &TaskRevolutionParameters::onReversed); + connect(ui->checkBoxUpdateView, &QCheckBox::toggled, + this, &TaskRevolutionParameters::onUpdateView); + connect(ui->changeMode, qOverload(&QComboBox::currentIndexChanged), + this, &TaskRevolutionParameters::onModeChanged); + connect(ui->buttonFace, &QPushButton::toggled, + this, &TaskRevolutionParameters::onButtonFace); + connect(ui->lineFaceName, &QLineEdit::textEdited, + this, &TaskRevolutionParameters::onFaceName); } -void TaskRevolutionParameters::updateUI() +void TaskRevolutionParameters::updateUI(int /*index*/) { if (blockUpdate) return; @@ -227,31 +246,114 @@ void TaskRevolutionParameters::updateUI() void TaskRevolutionParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (selectionFace) { + QString refText = onAddSelection(msg); + if (refText.length() > 0) { + QSignalBlocker block(ui->lineFaceName); + ui->lineFaceName->setText(refText); + ui->lineFaceName->setProperty("FeatureName", QByteArray(msg.pObjectName)); + ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName)); + // Turn off reference selection mode + ui->buttonFace->setChecked(false); + } + else { + clearFaceName(); + } + } + else { + exitSelectionMode(); + std::vector axis; + App::DocumentObject* selObj; + if (getReferencedSelection(vp->getObject(), msg, selObj, axis) && selObj) { + propReferenceAxis->setValue(selObj, axis); - exitSelectionMode(); - std::vector axis; - App::DocumentObject* selObj; - if (getReferencedSelection(vp->getObject(), msg, selObj, axis) && selObj) { - propReferenceAxis->setValue(selObj, axis); + recomputeFeature(); + updateUI(); + } + } + } + else if (msg.Type == Gui::SelectionChanges::ClrSelection && selectionFace) { + clearFaceName(); + } +} - recomputeFeature(); - updateUI(); +void TaskRevolutionParameters::onButtonFace(const bool pressed) +{ + // to distinguish that this is the direction selection + selectionFace = true; + + // only faces are allowed + TaskSketchBasedParameters::onSelectReference(pressed ? AllowSelection::FACE : AllowSelection::NONE); +} + +void TaskRevolutionParameters::onFaceName(const QString& text) +{ + if (text.isEmpty()) { + // if user cleared the text field then also clear the properties + ui->lineFaceName->setProperty("FeatureName", QVariant()); + ui->lineFaceName->setProperty("FaceName", QVariant()); + } + else { + // expect that the label of an object is used + QStringList parts = text.split(QChar::fromLatin1(':')); + QString label = parts[0]; + QVariant name = objectNameByLabel(label, ui->lineFaceName->property("FeatureName")); + if (name.isValid()) { + parts[0] = name.toString(); + QString uptoface = parts.join(QString::fromLatin1(":")); + ui->lineFaceName->setProperty("FeatureName", name); + ui->lineFaceName->setProperty("FaceName", setUpToFace(uptoface)); + } + else { + ui->lineFaceName->setProperty("FeatureName", QVariant()); + ui->lineFaceName->setProperty("FaceName", QVariant()); } } } -void TaskRevolutionParameters::translateModeList(int index) +void TaskRevolutionParameters::translateFaceName() { - // Must correspond to values from PartDesign::Revolution::TypeEnums - ui->changeMode->clear(); - ui->changeMode->addItem(tr("Dimension")); - // ui->changeMode->addItem(tr("To last")); - // ui->changeMode->addItem(tr("To first")); - ui->changeMode->addItem(tr("Up to face")); - ui->changeMode->addItem(tr("Two dimensions")); - ui->changeMode->setCurrentIndex(index); + ui->lineFaceName->setPlaceholderText(tr("No face selected")); + QVariant featureName = ui->lineFaceName->property("FeatureName"); + if (featureName.isValid()) { + QStringList parts = ui->lineFaceName->text().split(QChar::fromLatin1(':')); + QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray(); + int faceId = -1; + bool ok = false; + if (upToFace.indexOf("Face") == 0) { + faceId = upToFace.remove(0,4).toInt(&ok); + } + + if (ok) { + ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3") + .arg(parts[0]) + .arg(tr("Face")) + .arg(faceId)); + } + else { + ui->lineFaceName->setText(parts[0]); + } + } } +QString TaskRevolutionParameters::getFaceName(void) const +{ + QVariant featureName = ui->lineFaceName->property("FeatureName"); + if (featureName.isValid()) { + QString faceName = ui->lineFaceName->property("FaceName").toString(); + return getFaceReference(featureName.toString(), faceName); + } + + return QString::fromLatin1("None"); +} + +void TaskRevolutionParameters::clearFaceName() +{ + QSignalBlocker block(ui->lineFaceName); + ui->lineFaceName->clear(); + ui->lineFaceName->setProperty("FeatureName", QVariant()); + ui->lineFaceName->setProperty("FaceName", QVariant()); +} void TaskRevolutionParameters::onAngleChanged(double len) { @@ -260,6 +362,14 @@ void TaskRevolutionParameters::onAngleChanged(double len) recomputeFeature(); } +void TaskRevolutionParameters::onAngle2Changed(double len) +{ + if (propAngle2) + propAngle2->setValue(len); + exitSelectionMode(); + recomputeFeature(); +} + void TaskRevolutionParameters::onAxisChanged(int num) { if (blockUpdate) @@ -336,6 +446,35 @@ void TaskRevolutionParameters::onReversed(bool on) recomputeFeature(); } +void TaskRevolutionParameters::onModeChanged(int index) +{ + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + + switch (static_cast(index)) { + case Modes::Dimension: + pcRevolution->Type.setValue("Angle"); + // Avoid error message + // if (ui->revolveAngle->value() < Base::Quantity(Precision::Angular(), Base::Unit::Angle)) // TODO: Ensure radians/degree consistency + // ui->revolveAngle->setValue(5.0); + break; + case Modes::ToLast: + pcRevolution->Type.setValue("UpToLast"); + break; + case Modes::ToFirst: + pcRevolution->Type.setValue("UpToFirst"); + break; + case Modes::ToFace: + pcRevolution->Type.setValue("UpToFace"); + break; + case Modes::TwoDimensions: + pcRevolution->Type.setValue("TwoAngles"); + break; + } + + updateUI(index); + recomputeFeature(); +} + void TaskRevolutionParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const { if (axesInList.empty()) @@ -399,14 +538,22 @@ void TaskRevolutionParameters::apply() { //Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Revolution changed")); ui->revolveAngle->apply(); + ui->revolveAngle2->apply(); std::vector sub; App::DocumentObject* obj; getReferenceAxis(obj, sub); std::string axis = buildLinkSingleSubPythonStr(obj, sub); auto tobj = vp->getObject(); - FCMD_OBJ_CMD(tobj,"ReferenceAxis = " << axis); - FCMD_OBJ_CMD(tobj,"Midplane = " << (getMidplane() ? 1 : 0)); - FCMD_OBJ_CMD(tobj,"Reversed = " << (getReversed() ? 1 : 0)); + FCMD_OBJ_CMD(tobj, "ReferenceAxis = " << axis); + FCMD_OBJ_CMD(tobj, "Midplane = " << (getMidplane() ? 1 : 0)); + FCMD_OBJ_CMD(tobj, "Reversed = " << (getReversed() ? 1 : 0)); + int mode = ui->changeMode->currentIndex(); + FCMD_OBJ_CMD(tobj, "Type = " << mode); + QString facename = QString::fromLatin1("None"); + if (static_cast(mode) == Modes::ToFace) { + facename = getFaceName(); + } + FCMD_OBJ_CMD(tobj, "UpToFace = " << facename.toLatin1().data()); } //************************************************************************** diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h index 07b574f1f7..0427f3a179 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h @@ -70,9 +70,13 @@ public: private Q_SLOTS: void onAngleChanged(double); + void onAngle2Changed(double); void onAxisChanged(int); void onMidplane(bool); void onReversed(bool); + void onModeChanged(int); + void onButtonFace(const bool pressed = true); + void onFaceName(const QString& text); protected: void onSelectionChanged(const Gui::SelectionChanges& msg) override; @@ -80,6 +84,7 @@ protected: void getReferenceAxis(App::DocumentObject *&obj, std::vector &sub) const; bool getMidplane() const; bool getReversed() const; + QString getFaceName() const; void setupDialog(void); //mirrors of revolution's or groove's properties @@ -93,12 +98,16 @@ protected: private: void connectSignals(); - void updateUI(); + void updateUI(int index=0); // TODO: Implement for index and remove default void translateModeList(int index); + // TODO: This is common with extrude. Maybe send to superclass. + void translateFaceName(); + void clearFaceName(); private: std::unique_ptr ui; QWidget *proxy; + bool selectionFace; /** * @brief axesInList is the list of links corresponding to axis combo; must diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui index 36affd62b4..595a24e6c2 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui @@ -169,6 +169,9 @@ Face + + true + From 6b1a1e1508ce010675a2c739f1f7fdf6b3a2dcd8 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Sat, 16 Jul 2022 19:58:34 +0530 Subject: [PATCH 3/8] [PartDesign] Refactor mode support in revolution Encodes support for "two angles". Clarifies that up-to-first and up-to-last is not supported. --- src/Mod/PartDesign/App/FeatureRevolution.cpp | 46 +++++++++++++++----- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index d6f3d96518..11a3fe910a 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -81,14 +81,17 @@ short Revolution::mustExecute() const App::DocumentObjectExecReturn *Revolution::execute() { // Validate parameters - double angle = Angle.getValue(); - if (angle > 360.0) + // All angles are in radians unless explicitly stated + double angleDeg = Angle.getValue(); + if (angleDeg > 360.0) return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Angle of revolution too large")); - angle = Base::toRadians(angle); + double angle = Base::toRadians(angleDeg); if (angle < Precision::Angular()) return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Angle of revolution too small")); + double angle2 = Base::toRadians(Angle2.getValue()); + // Reverse angle if selected if (Reversed.getValue() && !Midplane.getValue()) angle *= (-1.0); @@ -126,6 +129,8 @@ App::DocumentObjectExecReturn *Revolution::execute() if (sketchshape.IsNull()) return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Creating a face from sketch failed")); + std::string method(Type.getValueAsString()); + // Rotate the face by half the angle to get Revolution symmetric to sketch plane if (Midplane.getValue()) { gp_Trsf mov; @@ -133,6 +138,14 @@ App::DocumentObjectExecReturn *Revolution::execute() TopLoc_Location loc(mov); sketchshape.Move(loc); } + else if (method == "TwoAngles") { + gp_Trsf mov; + mov.SetRotation(gp_Ax1(pnt, dir), angle2 * (-1.0)); + TopLoc_Location loc(mov); + sketchshape.Move(loc); + + angle = angle + angle2; + } this->positionByPrevious(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); @@ -150,17 +163,18 @@ App::DocumentObjectExecReturn *Revolution::execute() } TopoDS_Shape result; + TopoDS_Face supportface = getSupportFace(); + supportface.Move(invObjLoc); - std::string method(Type.getValueAsString()); - if (method == "UpToFace") { - TopoDS_Face supportface = getSupportFace(); - supportface.Move(invObjLoc); - + if (method == "UpToFace" || method == "UpToFirst" || method == "UpToLast") { TopoDS_Face upToFace; if (method == "UpToFace") { getFaceFromLinkSub(upToFace, UpToFace); upToFace.Move(invObjLoc); } + else + throw Base::RuntimeError("ProfileBased: Revolution up to first/last is not yet supported"); + getUpToFace(upToFace, base, sketchshape, method, dir); // TODO: Make enum @@ -181,8 +195,20 @@ App::DocumentObjectExecReturn *Revolution::execute() result = base; } else { - // revolve the face to a solid - BRepPrimAPI_MakeRevol RevolMaker(sketchshape, gp_Ax1(pnt, dir), angle); + // TODO: Make enum + int mode = 2; + BRepFeat_MakeRevol RevolMaker; + for (TopExp_Explorer xp(sketchshape, TopAbs_FACE); xp.More(); xp.Next()) { + RevolMaker.Init(base, xp.Current(), supportface, gp_Ax1(pnt, dir), mode, Standard_True); + RevolMaker.Perform(angle); + + if (!RevolMaker.IsDone()) + throw Base::RuntimeError("ProfileBased: Could not revolve the sketch!"); + + base = RevolMaker.Shape(); + if (mode == 2) + mode = 1; + } if (RevolMaker.IsDone()) result = RevolMaker.Shape(); From 7e095899427ef428e405eb0e7bcb6e60a6d86cca Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Thu, 21 Jul 2022 00:01:08 +0530 Subject: [PATCH 4/8] [PD] Refactor `FeatureRevolution` further New methods created to reduce size of `execute`. Use BRepPrimAPI instead of BRepFeat whenever possible since otherwise there are some limitations. --- src/Mod/PartDesign/App/FeatureRevolution.cpp | 156 +++++++++++++------ src/Mod/PartDesign/App/FeatureRevolution.h | 33 ++++ 2 files changed, 138 insertions(+), 51 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 11a3fe910a..4b550638d1 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -92,10 +92,6 @@ App::DocumentObjectExecReturn *Revolution::execute() double angle2 = Base::toRadians(Angle2.getValue()); - // Reverse angle if selected - if (Reversed.getValue() && !Midplane.getValue()) - angle *= (-1.0); - TopoDS_Shape sketchshape; try { sketchshape = getVerifiedFace(); @@ -131,22 +127,6 @@ App::DocumentObjectExecReturn *Revolution::execute() std::string method(Type.getValueAsString()); - // Rotate the face by half the angle to get Revolution symmetric to sketch plane - if (Midplane.getValue()) { - gp_Trsf mov; - mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians(Angle.getValue()) * (-1.0) / 2.0); - TopLoc_Location loc(mov); - sketchshape.Move(loc); - } - else if (method == "TwoAngles") { - gp_Trsf mov; - mov.SetRotation(gp_Ax1(pnt, dir), angle2 * (-1.0)); - TopLoc_Location loc(mov); - sketchshape.Move(loc); - - angle = angle + angle2; - } - this->positionByPrevious(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); pnt.Transform(invObjLoc.Transformation()); @@ -162,6 +142,7 @@ App::DocumentObjectExecReturn *Revolution::execute() return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Revolve axis intersects the sketch")); } + // Create a fresh support even when base exists so that it can be used for patterns TopoDS_Shape result; TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); @@ -175,43 +156,25 @@ App::DocumentObjectExecReturn *Revolution::execute() else throw Base::RuntimeError("ProfileBased: Revolution up to first/last is not yet supported"); + // TODO: This method is designed for extrusions. needs to be adapted for revolutions. getUpToFace(upToFace, base, sketchshape, method, dir); - // TODO: Make enum - int mode = 2; - BRepFeat_MakeRevol RevolMaker; - for (TopExp_Explorer xp(sketchshape, TopAbs_FACE); xp.More(); xp.Next()) { - RevolMaker.Init(base, xp.Current(), supportface, gp_Ax1(pnt, dir), mode, Standard_True); - RevolMaker.Perform(upToFace); + TopoDS_Face supportface = getSupportFace(); + supportface.Move(invObjLoc); - if (!RevolMaker.IsDone()) - throw Base::RuntimeError("ProfileBased: Up to face: Could not revolve the sketch!"); + if (Reversed.getValue()) + dir.Reverse(); - base = RevolMaker.Shape(); - if (mode == 2) - mode = 1; - } - - result = base; + TopExp_Explorer Ex(supportface,TopAbs_WIRE); + if (!Ex.More()) + supportface = TopoDS_Face(); + RevolMode mode = RevolMode::None; + generateRevolution(result, method, base, sketchshape, supportface, upToFace, gp_Ax1(pnt, dir), mode, Standard_True); } else { - // TODO: Make enum - int mode = 2; - BRepFeat_MakeRevol RevolMaker; - for (TopExp_Explorer xp(sketchshape, TopAbs_FACE); xp.More(); xp.Next()) { - RevolMaker.Init(base, xp.Current(), supportface, gp_Ax1(pnt, dir), mode, Standard_True); - RevolMaker.Perform(angle); - - if (!RevolMaker.IsDone()) - throw Base::RuntimeError("ProfileBased: Could not revolve the sketch!"); - - base = RevolMaker.Shape(); - if (mode == 2) - mode = 1; - } - - if (RevolMaker.IsDone()) - result = RevolMaker.Shape(); + bool midplane = Midplane.getValue(); + bool reversed = Reversed.getValue(); + generateRevolution(result, sketchshape, method, gp_Ax1(pnt, dir), angle, angle2, midplane, reversed); } if (!result.IsNull()) { @@ -272,4 +235,95 @@ void Revolution::updateAxis() Axis.setValue(dir.x,dir.y,dir.z); } +void Revolution::generateRevolution(TopoDS_Shape& revol, + const TopoDS_Shape& sketchshape, + const std::string& method, + const gp_Ax1& axis, + const double angle, + const double angle2, + const bool midplane, + const bool reversed) +{ + if (method == "Angle" || method == "TwoAngles" || method == "ThroughAll") { + double angleTotal = angle; + double angleOffset = 0.; + + if (method == "TwoAngles") { + // Rotate the face by `angle2`/`angle` to get "second" angle + angleTotal += angle2; + angleOffset = angle2 * -1.0; + } + else if (midplane) { + // Rotate the face by half the angle to get Revolution symmetric to sketch plane + angleOffset = -angle / 2; + } + + if (fabs(angleTotal) < Precision::Angular()) + throw Base::ValueError("Cannot create a revolution with zero angle."); + + gp_Ax1 revolAx(axis); + if (reversed) { + revolAx.Reverse(); + } + + TopoDS_Shape from = sketchshape; + if (method == "TwoAngles" || midplane) { + gp_Trsf mov; + mov.SetRotation(revolAx, angleOffset); + TopLoc_Location loc(mov); + from.Move(loc); + } + + // revolve the face to a solid + // BRepPrimAPI is the only option that allows use of this shape for patterns. + // See https://forum.freecadweb.org/viewtopic.php?f=8&t=70185&p=611673#p611673. + BRepPrimAPI_MakeRevol RevolMaker(from, revolAx, angleTotal); + + if (!RevolMaker.IsDone()) + throw Base::RuntimeError("ProfileBased: RevolMaker failed! Could not revolve the sketch!"); + else + revol = RevolMaker.Shape(); + } + else { + std::stringstream str; + str << "ProfileBased: Internal error: Unknown method '" + << method << "' for generateRevolution()"; + throw Base::RuntimeError(str.str()); + } +} + +void Revolution::generateRevolution(TopoDS_Shape& revol, + const std::string& method, + const TopoDS_Shape& baseshape, + const TopoDS_Shape& profileshape, + const TopoDS_Face& supportface, + const TopoDS_Face& uptoface, + const gp_Ax1& axis, + RevolMode Mode, + Standard_Boolean Modify) +{ + if (method == "UpToFirst" || method == "UpToFace" || method == "UpToLast") { + BRepFeat_MakeRevol RevolMaker; + TopoDS_Shape base = baseshape; + for (TopExp_Explorer xp(profileshape, TopAbs_FACE); xp.More(); xp.Next()) { + RevolMaker.Init(base, xp.Current(), supportface, axis, Mode, Modify); + RevolMaker.Perform(uptoface); + if (!RevolMaker.IsDone()) + throw Base::RuntimeError("ProfileBased: Up to face: Could not revolve the sketch!"); + + base = RevolMaker.Shape(); + if (Mode == RevolMode::None) + Mode = RevolMode::FuseWithBase; + } + + revol = base; + } + else { + std::stringstream str; + str << "ProfileBased: Internal error: Unknown method '" + << method << "' for generateRevolution()"; + throw Base::RuntimeError(str.str()); + } +} + } diff --git a/src/Mod/PartDesign/App/FeatureRevolution.h b/src/Mod/PartDesign/App/FeatureRevolution.h index 210156f2ad..60da317a38 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.h +++ b/src/Mod/PartDesign/App/FeatureRevolution.h @@ -74,6 +74,39 @@ protected: static const App::PropertyAngle::Constraints floatAngle; + /** + * Generates a revolution of the input sketchshape and stores it in the given \a revol. + */ + void generateRevolution(TopoDS_Shape& revol, + const TopoDS_Shape& sketchshape, + const std::string& method, + const gp_Ax1& ax1, + const double angle, + const double angle2, + const bool midplane, + const bool reversed); + + // See BRepFeat_MakeRevol + enum RevolMode { + CutFromBase = 0, + FuseWithBase = 1, + None = 2 + }; + + /** + * Generates a revolution of the input \a profileshape. + * It will be a stand-alone solid created with BRepFeat_MakeRevol. + */ + void generateRevolution(TopoDS_Shape& revol, + const std::string& method, + const TopoDS_Shape& baseshape, + const TopoDS_Shape& profileshape, + const TopoDS_Face& supportface, + const TopoDS_Face& uptoface, + const gp_Ax1& ax1, + RevolMode Mode, + Standard_Boolean Modify); + private: static const char* TypeEnums[]; }; From 0829c96549aba99ccb4db4a170f9703054d8564e Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Sun, 24 Jul 2022 00:32:40 +0530 Subject: [PATCH 5/8] [PD] Update revolution properties based on method --- src/Mod/PartDesign/App/FeatureRevolution.cpp | 44 ++++++++++++++++++++ src/Mod/PartDesign/App/FeatureRevolution.h | 5 +++ 2 files changed, 49 insertions(+) diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 4b550638d1..99a548d927 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -197,6 +197,9 @@ App::DocumentObjectExecReturn *Revolution::execute() else return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Could not revolve the sketch!")); + // eventually disable some settings that are not valid for the current method + updateProperties(method); + return App::DocumentObject::StdReturn; } catch (Standard_Failure& e) { @@ -326,4 +329,45 @@ void Revolution::generateRevolution(TopoDS_Shape& revol, } } +void Revolution::updateProperties(const std::string &method) +{ + // disable settings that are not valid on the current method + // disable everything unless we are sure we need it + bool isAngleEnabled = false; + bool isAngle2Enabled = false; + bool isMidplaneEnabled = false; + bool isReversedEnabled = false; + bool isUpToFaceEnabled = false; + if (method == "Angle") { + isAngleEnabled = true; + isMidplaneEnabled = true; + isReversedEnabled = !Midplane.getValue(); + } + else if (method == "UpToLast") { + isReversedEnabled = true; + } + else if (method == "ThroughAll") { + isMidplaneEnabled = true; + isReversedEnabled = !Midplane.getValue(); + } + else if (method == "UpToFirst") { + isReversedEnabled = true; + } + else if (method == "UpToFace") { + isReversedEnabled = true; + isUpToFaceEnabled = true; + } + else if (method == "TwoAngles") { + isAngleEnabled = true; + isAngle2Enabled = true; + isReversedEnabled = true; + } + + Angle.setReadOnly(!isAngleEnabled); + Angle2.setReadOnly(!isAngle2Enabled); + Midplane.setReadOnly(!isMidplaneEnabled); + Reversed.setReadOnly(!isReversedEnabled); + UpToFace.setReadOnly(!isUpToFaceEnabled); +} + } diff --git a/src/Mod/PartDesign/App/FeatureRevolution.h b/src/Mod/PartDesign/App/FeatureRevolution.h index 60da317a38..79dbbfc196 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.h +++ b/src/Mod/PartDesign/App/FeatureRevolution.h @@ -107,6 +107,11 @@ protected: RevolMode Mode, Standard_Boolean Modify); + /** + * Disables settings that are not valid for the current method + */ + void updateProperties(const std::string &method); + private: static const char* TypeEnums[]; }; From 4c80e567c67f05166696543c75df497d6d3b3719 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Sun, 24 Jul 2022 01:33:51 +0530 Subject: [PATCH 6/8] [PD] Use enum class for revolution method --- src/Mod/PartDesign/App/FeatureRevolution.cpp | 65 ++++++++++++------- src/Mod/PartDesign/App/FeatureRevolution.h | 39 +++++++---- .../Gui/TaskRevolutionParameters.cpp | 14 ++-- .../PartDesign/Gui/TaskRevolutionParameters.h | 9 --- 4 files changed, 73 insertions(+), 54 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 99a548d927..769e2545ef 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -125,7 +125,7 @@ App::DocumentObjectExecReturn *Revolution::execute() if (sketchshape.IsNull()) return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Creating a face from sketch failed")); - std::string method(Type.getValueAsString()); + RevolMethod method = methodFromString(Type.getValueAsString()); this->positionByPrevious(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); @@ -147,9 +147,9 @@ App::DocumentObjectExecReturn *Revolution::execute() TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); - if (method == "UpToFace" || method == "UpToFirst" || method == "UpToLast") { + if (method == RevolMethod::ToFace || method == RevolMethod::ToFirst || method == RevolMethod::ToLast) { TopoDS_Face upToFace; - if (method == "UpToFace") { + if (method == RevolMethod::ToFace) { getFaceFromLinkSub(upToFace, UpToFace); upToFace.Move(invObjLoc); } @@ -157,7 +157,7 @@ App::DocumentObjectExecReturn *Revolution::execute() throw Base::RuntimeError("ProfileBased: Revolution up to first/last is not yet supported"); // TODO: This method is designed for extrusions. needs to be adapted for revolutions. - getUpToFace(upToFace, base, sketchshape, method, dir); + // getUpToFace(upToFace, base, supportface, sketchshape, method, dir); TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); @@ -169,12 +169,12 @@ App::DocumentObjectExecReturn *Revolution::execute() if (!Ex.More()) supportface = TopoDS_Face(); RevolMode mode = RevolMode::None; - generateRevolution(result, method, base, sketchshape, supportface, upToFace, gp_Ax1(pnt, dir), mode, Standard_True); + generateRevolution(result, base, sketchshape, supportface, upToFace, gp_Ax1(pnt, dir), method, mode, Standard_True); } else { bool midplane = Midplane.getValue(); bool reversed = Reversed.getValue(); - generateRevolution(result, sketchshape, method, gp_Ax1(pnt, dir), angle, angle2, midplane, reversed); + generateRevolution(result, sketchshape, gp_Ax1(pnt, dir), angle, angle2, midplane, reversed, method); } if (!result.IsNull()) { @@ -238,20 +238,39 @@ void Revolution::updateAxis() Axis.setValue(dir.x,dir.y,dir.z); } +Revolution::RevolMethod Revolution::methodFromString(const std::string& methodStr) +{ + if (methodStr == "Angle") + return RevolMethod::Dimension; + if (methodStr == "UpToLast") + return RevolMethod::ToLast; + if (methodStr == "ThroughAll") + return RevolMethod::ThroughAll; + if (methodStr == "UpToFirst") + return RevolMethod::ToFirst; + if (methodStr == "UpToFace") + return RevolMethod::ToFace; + if (methodStr == "TwoAngles") + return RevolMethod::TwoDimensions; + + throw Base::ValueError("Revolution:: No such method"); + return RevolMethod::Dimension; +} + void Revolution::generateRevolution(TopoDS_Shape& revol, const TopoDS_Shape& sketchshape, - const std::string& method, const gp_Ax1& axis, const double angle, const double angle2, const bool midplane, - const bool reversed) + const bool reversed, + RevolMethod method) { - if (method == "Angle" || method == "TwoAngles" || method == "ThroughAll") { + if (method == RevolMethod::Dimension || method == RevolMethod::TwoDimensions || method == RevolMethod::ThroughAll) { double angleTotal = angle; double angleOffset = 0.; - if (method == "TwoAngles") { + if (method == RevolMethod::TwoDimensions) { // Rotate the face by `angle2`/`angle` to get "second" angle angleTotal += angle2; angleOffset = angle2 * -1.0; @@ -270,7 +289,7 @@ void Revolution::generateRevolution(TopoDS_Shape& revol, } TopoDS_Shape from = sketchshape; - if (method == "TwoAngles" || midplane) { + if (method == RevolMethod::TwoDimensions || midplane) { gp_Trsf mov; mov.SetRotation(revolAx, angleOffset); TopLoc_Location loc(mov); @@ -289,23 +308,22 @@ void Revolution::generateRevolution(TopoDS_Shape& revol, } else { std::stringstream str; - str << "ProfileBased: Internal error: Unknown method '" - << method << "' for generateRevolution()"; + str << "ProfileBased: Internal error: Unknown method for generateRevolution()"; throw Base::RuntimeError(str.str()); } } void Revolution::generateRevolution(TopoDS_Shape& revol, - const std::string& method, const TopoDS_Shape& baseshape, const TopoDS_Shape& profileshape, const TopoDS_Face& supportface, const TopoDS_Face& uptoface, const gp_Ax1& axis, + RevolMethod method, RevolMode Mode, Standard_Boolean Modify) { - if (method == "UpToFirst" || method == "UpToFace" || method == "UpToLast") { + if (method == RevolMethod::ToFirst || method == RevolMethod::ToFace || method == RevolMethod::ToLast) { BRepFeat_MakeRevol RevolMaker; TopoDS_Shape base = baseshape; for (TopExp_Explorer xp(profileshape, TopAbs_FACE); xp.More(); xp.Next()) { @@ -323,13 +341,12 @@ void Revolution::generateRevolution(TopoDS_Shape& revol, } else { std::stringstream str; - str << "ProfileBased: Internal error: Unknown method '" - << method << "' for generateRevolution()"; + str << "ProfileBased: Internal error: Unknown method for generateRevolution()"; throw Base::RuntimeError(str.str()); } } -void Revolution::updateProperties(const std::string &method) +void Revolution::updateProperties(RevolMethod method) { // disable settings that are not valid on the current method // disable everything unless we are sure we need it @@ -338,26 +355,26 @@ void Revolution::updateProperties(const std::string &method) bool isMidplaneEnabled = false; bool isReversedEnabled = false; bool isUpToFaceEnabled = false; - if (method == "Angle") { + if (method == RevolMethod::Dimension) { isAngleEnabled = true; isMidplaneEnabled = true; isReversedEnabled = !Midplane.getValue(); } - else if (method == "UpToLast") { + else if (method == RevolMethod::ToLast) { isReversedEnabled = true; } - else if (method == "ThroughAll") { + else if (method == RevolMethod::ThroughAll) { isMidplaneEnabled = true; isReversedEnabled = !Midplane.getValue(); } - else if (method == "UpToFirst") { + else if (method == RevolMethod::ToFirst) { isReversedEnabled = true; } - else if (method == "UpToFace") { + else if (method == RevolMethod::ToFace) { isReversedEnabled = true; isUpToFaceEnabled = true; } - else if (method == "TwoAngles") { + else if (method == RevolMethod::TwoDimensions) { isAngleEnabled = true; isAngle2Enabled = true; isReversedEnabled = true; diff --git a/src/Mod/PartDesign/App/FeatureRevolution.h b/src/Mod/PartDesign/App/FeatureRevolution.h index 79dbbfc196..bf80298875 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.h +++ b/src/Mod/PartDesign/App/FeatureRevolution.h @@ -68,24 +68,21 @@ public: /// suggests a value for Reversed flag so that material is always added to the support bool suggestReversed(); + enum class RevolMethod { + Dimension, + ThroughAll, + ToLast = ThroughAll, + ToFirst, + ToFace, + TwoDimensions + }; + protected: /// updates Axis from ReferenceAxis void updateAxis(); static const App::PropertyAngle::Constraints floatAngle; - /** - * Generates a revolution of the input sketchshape and stores it in the given \a revol. - */ - void generateRevolution(TopoDS_Shape& revol, - const TopoDS_Shape& sketchshape, - const std::string& method, - const gp_Ax1& ax1, - const double angle, - const double angle2, - const bool midplane, - const bool reversed); - // See BRepFeat_MakeRevol enum RevolMode { CutFromBase = 0, @@ -93,24 +90,38 @@ protected: None = 2 }; + RevolMethod methodFromString(const std::string& methodStr); + + /** + * Generates a revolution of the input sketchshape and stores it in the given \a revol. + */ + void generateRevolution(TopoDS_Shape& revol, + const TopoDS_Shape& sketchshape, + const gp_Ax1& ax1, + const double angle, + const double angle2, + const bool midplane, + const bool reversed, + RevolMethod method); + /** * Generates a revolution of the input \a profileshape. * It will be a stand-alone solid created with BRepFeat_MakeRevol. */ void generateRevolution(TopoDS_Shape& revol, - const std::string& method, const TopoDS_Shape& baseshape, const TopoDS_Shape& profileshape, const TopoDS_Face& supportface, const TopoDS_Face& uptoface, const gp_Ax1& ax1, + RevolMethod method, RevolMode Mode, Standard_Boolean Modify); /** * Disables settings that are not valid for the current method */ - void updateProperties(const std::string &method); + void updateProperties(RevolMethod method); private: static const char* TypeEnums[]; diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 5e4fc65890..6a6bd25e89 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -450,23 +450,23 @@ void TaskRevolutionParameters::onModeChanged(int index) { PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); - switch (static_cast(index)) { - case Modes::Dimension: + switch (static_cast(index)) { + case PartDesign::Revolution::RevolMethod::Dimension: pcRevolution->Type.setValue("Angle"); // Avoid error message // if (ui->revolveAngle->value() < Base::Quantity(Precision::Angular(), Base::Unit::Angle)) // TODO: Ensure radians/degree consistency // ui->revolveAngle->setValue(5.0); break; - case Modes::ToLast: + case PartDesign::Revolution::RevolMethod::ToLast: pcRevolution->Type.setValue("UpToLast"); break; - case Modes::ToFirst: + case PartDesign::Revolution::RevolMethod::ToFirst: pcRevolution->Type.setValue("UpToFirst"); break; - case Modes::ToFace: + case PartDesign::Revolution::RevolMethod::ToFace: pcRevolution->Type.setValue("UpToFace"); break; - case Modes::TwoDimensions: + case PartDesign::Revolution::RevolMethod::TwoDimensions: pcRevolution->Type.setValue("TwoAngles"); break; } @@ -550,7 +550,7 @@ void TaskRevolutionParameters::apply() int mode = ui->changeMode->currentIndex(); FCMD_OBJ_CMD(tobj, "Type = " << mode); QString facename = QString::fromLatin1("None"); - if (static_cast(mode) == Modes::ToFace) { + if (static_cast(mode) == PartDesign::Revolution::RevolMethod::ToFace) { facename = getFaceName(); } FCMD_OBJ_CMD(tobj, "UpToFace = " << facename.toLatin1().data()); diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h index 0427f3a179..505c9baa20 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h @@ -49,15 +49,6 @@ public: void apply() override; - enum class Modes { - Dimension, - ThroughAll, - ToLast = ThroughAll, - ToFirst, - ToFace, - TwoDimensions - }; - /** * @brief fillAxisCombo fills the combo and selects the item according to * current value of revolution object's axis reference. From 2ae3c82606b67f81f3788de4c2e25126edc23279 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Mon, 25 Jul 2022 10:18:23 +0530 Subject: [PATCH 7/8] [PD] Support two-angle/up-to-face groove Elements copied from revolution and pocket feature. --- src/Mod/PartDesign/App/FeatureGroove.cpp | 261 ++++++++++++++++-- src/Mod/PartDesign/App/FeatureGroove.h | 55 ++++ .../Gui/TaskRevolutionParameters.cpp | 44 ++- .../PartDesign/Gui/TaskRevolutionParameters.h | 1 + 4 files changed, 324 insertions(+), 37 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp index 0370343b5e..a71c95f7ff 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.cpp +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include # include +# include # include # include # include @@ -41,9 +42,10 @@ using namespace PartDesign; namespace PartDesign { - /* TRANSLATOR PartDesign::Groove */ +const char* Groove::TypeEnums[]= {"Angle", "ThroughAll", "UpToFirst", "UpToFace", "TwoAngles", nullptr}; + PROPERTY_SOURCE(PartDesign::Groove, PartDesign::ProfileBased) const App::PropertyAngle::Constraints Groove::floatAngle = { Base::toDegrees(Precision::Angular()), 360.0, 1.0 }; @@ -52,11 +54,15 @@ Groove::Groove() { addSubType = FeatureAddSub::Subtractive; - ADD_PROPERTY_TYPE(Base,(Base::Vector3d(0.0f,0.0f,0.0f)),"Groove", App::Prop_ReadOnly, "Base"); - ADD_PROPERTY_TYPE(Axis,(Base::Vector3d(0.0f,1.0f,0.0f)),"Groove", App::Prop_ReadOnly, "Axis"); - ADD_PROPERTY_TYPE(Angle,(360.0),"Groove", App::Prop_None, "Angle"); + ADD_PROPERTY_TYPE(Type, (0L), "Groove", App::Prop_None, "Groove type"); + Type.setEnums(TypeEnums); + ADD_PROPERTY_TYPE(Base, (Base::Vector3d(0.0f,0.0f,0.0f)), "Groove", App::Prop_ReadOnly, "Base"); + ADD_PROPERTY_TYPE(Axis, (Base::Vector3d(0.0f,1.0f,0.0f)), "Groove", App::Prop_ReadOnly, "Axis"); + ADD_PROPERTY_TYPE(Angle, (360.0),"Groove", App::Prop_None, "Angle"); + ADD_PROPERTY_TYPE(Angle2, (60.0), "Groove", App::Prop_None, "Groove length in 2nd direction"); + ADD_PROPERTY_TYPE(UpToFace, (nullptr), "Groove", App::Prop_None, "Face where groove will end"); Angle.setConstraints(&floatAngle); - ADD_PROPERTY_TYPE(ReferenceAxis,(nullptr),"Groove",(App::PropertyType)(App::Prop_None),"Reference axis of Groove"); + ADD_PROPERTY_TYPE(ReferenceAxis, (nullptr), "Groove", (App::PropertyType)(App::Prop_None), "Reference axis of Groove"); } short Groove::mustExecute() const @@ -65,7 +71,9 @@ short Groove::mustExecute() const ReferenceAxis.isTouched() || Axis.isTouched() || Base.isTouched() || - Angle.isTouched()) + UpToFace.isTouched() || + Angle.isTouched() || + Angle2.isTouched()) return 1; return ProfileBased::mustExecute(); } @@ -73,17 +81,16 @@ short Groove::mustExecute() const App::DocumentObjectExecReturn *Groove::execute() { // Validate parameters - double angle = Angle.getValue(); - if (angle > 360.0) + // All angles are in radians unless explicitly stated + double angleDeg = Angle.getValue(); + if (angleDeg > 360.0) return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Angle of groove too large")); - angle = Base::toRadians(angle); + double angle = Base::toRadians(angleDeg); if (angle < Precision::Angular()) return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Angle of groove too small")); - // Reverse angle if selected - if (Reversed.getValue() && !Midplane.getValue()) - angle *= (-1.0); + double angle2 = Base::toRadians(Angle2.getValue()); TopoDS_Shape sketchshape; try { @@ -105,7 +112,12 @@ App::DocumentObjectExecReturn *Groove::execute() return new App::DocumentObjectExecReturn(text); } - updateAxis(); + // update Axis from ReferenceAxis + try { + updateAxis(); + } catch (const Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } // get revolve axis Base::Vector3d b = Base.getValue(); @@ -117,13 +129,7 @@ App::DocumentObjectExecReturn *Groove::execute() if (sketchshape.IsNull()) return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Creating a face from sketch failed")); - // Rotate the face by half the angle to get Groove symmetric to sketch plane - if (Midplane.getValue()) { - gp_Trsf mov; - mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians(Angle.getValue()) * (-1.0) / 2.0); - TopLoc_Location loc(mov); - sketchshape.Move(loc); - } + RevolMethod method = methodFromString(Type.getValueAsString()); this->positionByPrevious(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); @@ -140,11 +146,61 @@ App::DocumentObjectExecReturn *Groove::execute() return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Revolve axis intersects the sketch")); } - // revolve the face to a solid - BRepPrimAPI_MakeRevol RevolMaker(sketchshape, gp_Ax1(pnt, dir), angle); + // Create a fresh support even when base exists so that it can be used for patterns + TopoDS_Shape result; + TopoDS_Face supportface = getSupportFace(); + supportface.Move(invObjLoc); + + if (method == RevolMethod::ToFace || method == RevolMethod::ToFirst) { + TopoDS_Face upToFace; + if (method == RevolMethod::ToFace) { + getFaceFromLinkSub(upToFace, UpToFace); + upToFace.Move(invObjLoc); + } + else + throw Base::RuntimeError("ProfileBased: Groove up to first is not yet supported"); + + // TODO: This method is designed for extrusions. needs to be adapted for grooves. + // getUpToFace(upToFace, base, supportface, sketchshape, method, dir); + + TopoDS_Face supportface = getSupportFace(); + supportface.Move(invObjLoc); + + if (Reversed.getValue()) + dir.Reverse(); + + TopExp_Explorer Ex(supportface,TopAbs_WIRE); + if (!Ex.More()) + supportface = TopoDS_Face(); + RevolMode mode = RevolMode::CutFromBase; + generateRevolution(result, base, sketchshape, supportface, upToFace, gp_Ax1(pnt, dir), method, mode, Standard_True); + + result = refineShapeIfActive(result); + + // the result we get here is the shape _after_ the operation is done + // And the really expensive way to get the SubShape... + BRepAlgoAPI_Cut mkCut(base, result); + if (!mkCut.IsDone()) + return new App::DocumentObjectExecReturn("Groove: Up to face: Could not get SubShape!"); + // FIXME: In some cases this affects the Shape property: It is set to the same shape as the SubShape!!!! + TopoDS_Shape subshape = refineShapeIfActive(mkCut.Shape()); + this->AddSubShape.setValue(subshape); + + int resultCount = countSolids(result); + if (resultCount > 1) { + return new App::DocumentObjectExecReturn("Groove: Result has multiple solids. This is not supported at this time."); + } + + this->Shape.setValue(getSolid(result)); + } + else { + bool midplane = Midplane.getValue(); + bool reversed = Reversed.getValue(); + generateRevolution(result, sketchshape, gp_Ax1(pnt, dir), angle, angle2, midplane, reversed, method); + + if (result.IsNull()) + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Could not revolve the sketch!")); - if (RevolMaker.IsDone()) { - TopoDS_Shape result = RevolMaker.Shape(); // set the subtractive shape property for later usage in e.g. pattern result = refineShapeIfActive(result); this->AddSubShape.setValue(result); @@ -167,10 +223,10 @@ App::DocumentObjectExecReturn *Groove::execute() if (solidCount > 1) { return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: that is not currently supported.")); } - } - else - return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Could not revolve the sketch!")); + + // eventually disable some settings that are not valid for the current method + updateProperties(method); return App::DocumentObject::StdReturn; } @@ -207,4 +263,155 @@ void Groove::updateAxis() } } +Groove::RevolMethod Groove::methodFromString(const std::string& methodStr) +{ + if (methodStr == "Angle") + return RevolMethod::Dimension; + if (methodStr == "UpToLast") + return RevolMethod::ToLast; + if (methodStr == "ThroughAll") + return RevolMethod::ThroughAll; + if (methodStr == "UpToFirst") + return RevolMethod::ToFirst; + if (methodStr == "UpToFace") + return RevolMethod::ToFace; + if (methodStr == "TwoAngles") + return RevolMethod::TwoDimensions; + + throw Base::ValueError("Groove:: No such method"); + return RevolMethod::Dimension; +} + +void Groove::generateRevolution(TopoDS_Shape& revol, + const TopoDS_Shape& sketchshape, + const gp_Ax1& axis, + const double angle, + const double angle2, + const bool midplane, + const bool reversed, + RevolMethod method) +{ + if (method == RevolMethod::Dimension || method == RevolMethod::TwoDimensions || method == RevolMethod::ThroughAll) { + double angleTotal = angle; + double angleOffset = 0.; + + if (method == RevolMethod::TwoDimensions) { + // Rotate the face by `angle2`/`angle` to get "second" angle + angleTotal += angle2; + angleOffset = angle2 * -1.0; + } + else if (method == RevolMethod::ThroughAll) { + angleTotal = 2 * M_PI; + } + else if (midplane) { + // Rotate the face by half the angle to get Groove symmetric to sketch plane + angleOffset = -angle / 2; + } + + if (fabs(angleTotal) < Precision::Angular()) + throw Base::ValueError("Cannot create a revolution with zero angle."); + + TopoDS_Shape from = sketchshape; + if (method == RevolMethod::TwoDimensions || midplane) { + gp_Trsf mov; + mov.SetRotation(axis, angleOffset); + TopLoc_Location loc(mov); + from.Move(loc); + } + else if (reversed) { + angleTotal *= -1.0; + } + + // revolve the face to a solid + // BRepPrimAPI is the only option that allows use of this shape for patterns. + // See https://forum.freecadweb.org/viewtopic.php?f=8&t=70185&p=611673#p611673. + BRepPrimAPI_MakeRevol RevolMaker(from, axis, angleTotal); + + if (!RevolMaker.IsDone()) + throw Base::RuntimeError("ProfileBased: RevolMaker failed! Could not revolve the sketch!"); + else + revol = RevolMaker.Shape(); + } + else { + std::stringstream str; + str << "ProfileBased: Internal error: Unknown method for generateGroove()"; + throw Base::RuntimeError(str.str()); + } +} + +void Groove::generateRevolution(TopoDS_Shape& revol, + const TopoDS_Shape& baseshape, + const TopoDS_Shape& profileshape, + const TopoDS_Face& supportface, + const TopoDS_Face& uptoface, + const gp_Ax1& axis, + RevolMethod method, + RevolMode Mode, + Standard_Boolean Modify) +{ + if (method == RevolMethod::ToFirst || method == RevolMethod::ToFace || method == RevolMethod::ToLast) { + BRepFeat_MakeRevol RevolMaker; + TopoDS_Shape base = baseshape; + for (TopExp_Explorer xp(profileshape, TopAbs_FACE); xp.More(); xp.Next()) { + RevolMaker.Init(base, xp.Current(), supportface, axis, Mode, Modify); + RevolMaker.Perform(uptoface); + if (!RevolMaker.IsDone()) + throw Base::RuntimeError("ProfileBased: Up to face: Could not revolve the sketch!"); + + base = RevolMaker.Shape(); + if (Mode == RevolMode::None) + Mode = RevolMode::FuseWithBase; + } + + revol = base; + } + else { + std::stringstream str; + str << "ProfileBased: Internal error: Unknown method for generateRevolution()"; + throw Base::RuntimeError(str.str()); + } +} + +void Groove::updateProperties(RevolMethod method) +{ + // disable settings that are not valid on the current method + // disable everything unless we are sure we need it + bool isAngleEnabled = false; + bool isAngle2Enabled = false; + bool isMidplaneEnabled = false; + bool isReversedEnabled = false; + bool isUpToFaceEnabled = false; + if (method == RevolMethod::Dimension) { + isAngleEnabled = true; + isMidplaneEnabled = true; + isReversedEnabled = !Midplane.getValue(); + } + else if (method == RevolMethod::ToLast) { + isReversedEnabled = true; + } + else if (method == RevolMethod::ThroughAll) { + isMidplaneEnabled = true; + isReversedEnabled = !Midplane.getValue(); + } + else if (method == RevolMethod::ToFirst) { + isReversedEnabled = true; + } + else if (method == RevolMethod::ToFace) { + isReversedEnabled = true; + isUpToFaceEnabled = true; + } + else if (method == RevolMethod::TwoDimensions) { + isAngleEnabled = true; + isAngle2Enabled = true; + isReversedEnabled = true; + } + + Angle.setReadOnly(!isAngleEnabled); + Angle2.setReadOnly(!isAngle2Enabled); + Midplane.setReadOnly(!isMidplaneEnabled); + Reversed.setReadOnly(!isReversedEnabled); + UpToFace.setReadOnly(!isUpToFaceEnabled); +} + + } diff --git a/src/Mod/PartDesign/App/FeatureGroove.h b/src/Mod/PartDesign/App/FeatureGroove.h index 0ddd3f4960..8e9c2d40c6 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.h +++ b/src/Mod/PartDesign/App/FeatureGroove.h @@ -37,9 +37,11 @@ class PartDesignExport Groove : public ProfileBased public: Groove(); + App::PropertyEnumeration Type; App::PropertyVector Base; App::PropertyVector Axis; App::PropertyAngle Angle; + App::PropertyAngle Angle2; /** if this property is set to a valid link, both Axis and Base properties * are calculated according to the linked line @@ -65,11 +67,64 @@ public: /// suggests a value for Reversed flag so that material is always removed from the support bool suggestReversed(); + + enum class RevolMethod { + Dimension, + ThroughAll, + ToLast = ThroughAll, + ToFirst, + ToFace, + TwoDimensions + }; + protected: /// updates Axis from ReferenceAxis void updateAxis(); static const App::PropertyAngle::Constraints floatAngle; + + // See BRepFeat_MakeRevol + enum RevolMode { + CutFromBase = 0, + FuseWithBase = 1, + None = 2 + }; + + RevolMethod methodFromString(const std::string& methodStr); + + /** + * Generates a [groove] of the input sketchshape and stores it in the given \a revol. + */ + void generateRevolution(TopoDS_Shape& revol, + const TopoDS_Shape& sketchshape, + const gp_Ax1& ax1, + const double angle, + const double angle2, + const bool midplane, + const bool reversed, + RevolMethod method); + + /** + * Generates a [groove] of the input \a profileshape. + * It will be a stand-alone solid created with BRepFeat_MakeRevol. + */ + void generateRevolution(TopoDS_Shape& revol, + const TopoDS_Shape& baseshape, + const TopoDS_Shape& profileshape, + const TopoDS_Face& supportface, + const TopoDS_Face& uptoface, + const gp_Ax1& ax1, + RevolMethod method, + RevolMode Mode, + Standard_Boolean Modify); + + /** + * Disables settings that are not valid for the current method + */ + void updateProperties(RevolMethod method); + +private: + static const char* TypeEnums[]; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 6a6bd25e89..0a1e806952 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -49,7 +49,8 @@ using namespace Gui; TaskRevolutionParameters::TaskRevolutionParameters(PartDesignGui::ViewProvider* RevolutionView, QWidget *parent) : TaskSketchBasedParameters(RevolutionView, parent, "PartDesign_Revolution", tr("Revolution parameters")), ui(new Ui_TaskRevolutionParameters), - proxy(new QWidget(this)) + proxy(new QWidget(this)), + isGroove(false) { // we need a separate container widget to add all controls to ui->setupUi(proxy); @@ -68,11 +69,15 @@ TaskRevolutionParameters::TaskRevolutionParameters(PartDesignGui::ViewProvider* ui->revolveAngle2->bind(rev->Angle2); } else if (auto *rev = dynamic_cast(vp->getObject())) { + isGroove = true; this->propAngle = &(rev->Angle); + this->propAngle2 = &(rev->Angle2); this->propMidPlane = &(rev->Midplane); this->propReferenceAxis = &(rev->ReferenceAxis); this->propReversed = &(rev->Reversed); + this->propUpToFace = &(rev->UpToFace); ui->revolveAngle->bind(rev->Angle); + ui->revolveAngle2->bind(rev->Angle2); } else { throw Base::TypeError("The object is neither a Groove nor a Revolution."); @@ -103,7 +108,6 @@ TaskRevolutionParameters::TaskRevolutionParameters(PartDesignGui::ViewProvider* void TaskRevolutionParameters::setupDialog() { - PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); ui->checkBoxMidplane->setChecked(propMidPlane->getValue()); ui->checkBoxReversed->setChecked(propReversed->getValue()); @@ -114,7 +118,7 @@ void TaskRevolutionParameters::setupDialog() int index = 0; // TODO: This should also be implemented for groove - if (pcFeat->isDerivedFrom(PartDesign::Revolution::getClassTypeId())) { + if (!isGroove) { PartDesign::Revolution* rev = static_cast(vp->getObject()); ui->revolveAngle2->setValue(propAngle2->getValue()); ui->revolveAngle2->setMaximum(propAngle2->getMaximum()); @@ -122,6 +126,14 @@ void TaskRevolutionParameters::setupDialog() index = rev->Type.getValue(); } + else { + PartDesign::Groove* rev = static_cast(vp->getObject()); + ui->revolveAngle2->setValue(propAngle2->getValue()); + ui->revolveAngle2->setMaximum(propAngle2->getMaximum()); + ui->revolveAngle2->setMinimum(propAngle2->getMinimum()); + + index = rev->Type.getValue(); + } translateModeList(index); } @@ -130,7 +142,12 @@ void TaskRevolutionParameters::translateModeList(int index) { ui->changeMode->clear(); ui->changeMode->addItem(tr("Dimension")); - ui->changeMode->addItem(tr("To last")); + if (!isGroove) { + ui->changeMode->addItem(tr("To last")); + } + else { + ui->changeMode->addItem(tr("Through all")); + } ui->changeMode->addItem(tr("To first")); ui->changeMode->addItem(tr("Up to face")); ui->changeMode->addItem(tr("Two dimensions")); @@ -448,26 +465,33 @@ void TaskRevolutionParameters::onReversed(bool on) void TaskRevolutionParameters::onModeChanged(int index) { - PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + App::PropertyEnumeration* pcType; + if (!isGroove) + pcType = &(static_cast(vp->getObject())->Type); + else + pcType = &(static_cast(vp->getObject())->Type); switch (static_cast(index)) { case PartDesign::Revolution::RevolMethod::Dimension: - pcRevolution->Type.setValue("Angle"); + pcType->setValue("Angle"); // Avoid error message // if (ui->revolveAngle->value() < Base::Quantity(Precision::Angular(), Base::Unit::Angle)) // TODO: Ensure radians/degree consistency // ui->revolveAngle->setValue(5.0); break; case PartDesign::Revolution::RevolMethod::ToLast: - pcRevolution->Type.setValue("UpToLast"); + if (!isGroove) + pcType->setValue("UpToLast"); + else + pcType->setValue("ThroughAll"); break; case PartDesign::Revolution::RevolMethod::ToFirst: - pcRevolution->Type.setValue("UpToFirst"); + pcType->setValue("UpToFirst"); break; case PartDesign::Revolution::RevolMethod::ToFace: - pcRevolution->Type.setValue("UpToFace"); + pcType->setValue("UpToFace"); break; case PartDesign::Revolution::RevolMethod::TwoDimensions: - pcRevolution->Type.setValue("TwoAngles"); + pcType->setValue("TwoAngles"); break; } diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h index 505c9baa20..fbb0dde990 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h @@ -99,6 +99,7 @@ private: std::unique_ptr ui; QWidget *proxy; bool selectionFace; + bool isGroove; /** * @brief axesInList is the list of links corresponding to axis combo; must From 131c74045a7e1d1a99f1cb5ee6a47b8bd80f93b8 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Tue, 26 Jul 2022 14:09:59 +0530 Subject: [PATCH 8/8] [PD] Set revolution taskview items based on method --- .../Gui/TaskRevolutionParameters.cpp | 68 ++++++++++++++++++- .../PartDesign/Gui/TaskRevolutionParameters.h | 3 + .../Gui/TaskRevolutionParameters.ui | 2 +- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 0a1e806952..6db855f57f 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -230,6 +230,71 @@ void TaskRevolutionParameters::addAxisToCombo(App::DocumentObject* linkObj, lnk.setValue(linkObj,std::vector(1,linkSubname)); } +void TaskRevolutionParameters::setCheckboxes(PartDesign::Revolution::RevolMethod mode) +{ + // disable/hide everything unless we are sure we don't need it + // exception: the direction parameters are in any case visible + bool isRevolveAngleVisible = false; + bool isRevolveAngle2Visible = false; + bool isMidplaneEnabled = false; + bool isMidplaneVisible = false; + bool isReversedEnabled = false; + bool isFaceEditEnabled = false; + + if (mode == PartDesign::Revolution::RevolMethod::Dimension) { + isRevolveAngleVisible = true; + ui->revolveAngle->selectNumber(); + QMetaObject::invokeMethod(ui->revolveAngle, "setFocus", Qt::QueuedConnection); + isMidplaneVisible = true; + isMidplaneEnabled = true; + // Reverse only makes sense if Midplane is not true + isReversedEnabled = !ui->checkBoxMidplane->isChecked(); + } + else if (mode == PartDesign::Revolution::RevolMethod::ThroughAll && isGroove) { + isMidplaneEnabled = true; + isMidplaneVisible = true; + isReversedEnabled = !ui->checkBoxMidplane->isChecked(); + } + else if (mode == PartDesign::Revolution::RevolMethod::ToLast && !isGroove) { + isReversedEnabled = true; + } + else if (mode == PartDesign::Revolution::RevolMethod::ToFirst) { + isReversedEnabled = true; + } + else if (mode == PartDesign::Revolution::RevolMethod::ToFace) { + isReversedEnabled = true; + isFaceEditEnabled = true; + QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection); + // Go into reference selection mode if no face has been selected yet + if (ui->lineFaceName->property("FeatureName").isNull()) + ui->buttonFace->setChecked(true); + } + else if (mode == PartDesign::Revolution::RevolMethod::TwoDimensions) { + isRevolveAngleVisible = true; + isRevolveAngle2Visible = true; + isReversedEnabled = true; + } + + ui->revolveAngle->setVisible(isRevolveAngleVisible); + ui->revolveAngle->setEnabled(isRevolveAngleVisible); + ui->labelAngle->setVisible(isRevolveAngleVisible); + + ui->revolveAngle2->setVisible(isRevolveAngle2Visible); + ui->revolveAngle2->setEnabled(isRevolveAngle2Visible); + ui->labelAngle2->setVisible(isRevolveAngle2Visible); + + ui->checkBoxMidplane->setEnabled(isMidplaneEnabled); + ui->checkBoxMidplane->setVisible(isMidplaneVisible); + + ui->checkBoxReversed->setEnabled(isReversedEnabled); + + ui->buttonFace->setEnabled(isFaceEditEnabled); + ui->lineFaceName->setEnabled(isFaceEditEnabled); + if (!isFaceEditEnabled) { + ui->buttonFace->setChecked(false); + } +} + void TaskRevolutionParameters::connectSignals() { connect(ui->revolveAngle, qOverload(&Gui::QuantitySpinBox::valueChanged), @@ -252,12 +317,13 @@ void TaskRevolutionParameters::connectSignals() this, &TaskRevolutionParameters::onFaceName); } -void TaskRevolutionParameters::updateUI(int /*index*/) +void TaskRevolutionParameters::updateUI(int index) { if (blockUpdate) return; Base::StateLocker lock(blockUpdate, true); fillAxisCombo(); + setCheckboxes(static_cast(index)); } void TaskRevolutionParameters::onSelectionChanged(const Gui::SelectionChanges& msg) diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h index fbb0dde990..c00d7819b2 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h @@ -23,6 +23,8 @@ #ifndef GUI_TASKVIEW_TaskRevolutionParameters_H #define GUI_TASKVIEW_TaskRevolutionParameters_H +#include +#include #include "TaskSketchBasedParameters.h" #include "ViewProviderRevolution.h" @@ -77,6 +79,7 @@ protected: bool getReversed() const; QString getFaceName() const; void setupDialog(void); + void setCheckboxes(PartDesign::Revolution::RevolMethod mode); //mirrors of revolution's or groove's properties //should have been done by inheriting revolution and groove from common class... diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui index 595a24e6c2..d9c57167aa 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui @@ -82,7 +82,7 @@ - + Angle: