From 2114da3bbbf27538e5fd53a19410ffc7997c302f Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Mon, 17 Jun 2024 15:20:20 +0200 Subject: [PATCH 1/6] Assembly: Limits: Set one checkbox for each limit. --- src/Mod/Assembly/App/AssemblyObject.cpp | 88 +++++---- .../panels/TaskAssemblyCreateJoint.ui | 181 ++++++++++-------- src/Mod/Assembly/JointObject.py | 112 +++++++---- 3 files changed, 232 insertions(+), 149 deletions(-) diff --git a/src/Mod/Assembly/App/AssemblyObject.cpp b/src/Mod/Assembly/App/AssemblyObject.cpp index 84ad387cf7..0dabd5b998 100644 --- a/src/Mod/Assembly/App/AssemblyObject.cpp +++ b/src/Mod/Assembly/App/AssemblyObject.cpp @@ -1142,25 +1142,34 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint) mbdJoint->setMarkerJ(fullMarkerNameJ); // Add limits if needed. - auto* prop = dynamic_cast(joint->getPropertyByName("EnableLimits")); - if (prop && prop->getValue()) { - if (jointType == JointType::Slider || jointType == JointType::Cylindrical) { - auto* propLenMin = - dynamic_cast(joint->getPropertyByName("LengthMin")); - auto* propLenMax = - dynamic_cast(joint->getPropertyByName("LengthMax")); + if (jointType == JointType::Slider || jointType == JointType::Cylindrical) { + auto* pLenMin = dynamic_cast(joint->getPropertyByName("LengthMin")); + auto* pLenMax = dynamic_cast(joint->getPropertyByName("LengthMax")); + auto* pMinEnabled = + dynamic_cast(joint->getPropertyByName("EnableLengthMin")); + auto* pMaxEnabled = + dynamic_cast(joint->getPropertyByName("EnableLengthMax")); - if (propLenMin && propLenMax) { - // Swap the values if necessary. - double minLength = propLenMin->getValue(); - double maxLength = propLenMax->getValue(); - if (minLength > maxLength) { - propLenMin->setValue(maxLength); - propLenMax->setValue(minLength); - minLength = maxLength; - maxLength = propLenMax->getValue(); - } + if (pLenMin && pLenMax && pMinEnabled && pMaxEnabled) { // Make sure properties do exist + // Swap the values if necessary. + bool minEnabled = pMinEnabled->getValue(); + bool maxEnabled = pMaxEnabled->getValue(); + double minLength = pLenMin->getValue(); + double maxLength = pLenMax->getValue(); + if ((minLength > maxLength) && minEnabled && maxEnabled) { + pLenMin->setValue(maxLength); + pLenMax->setValue(minLength); + minLength = maxLength; + maxLength = pLenMax->getValue(); + + pMinEnabled->setValue(maxEnabled); + pMaxEnabled->setValue(minEnabled); + minEnabled = maxEnabled; + maxEnabled = pMaxEnabled->getValue(); + } + + if (minEnabled) { auto limit = ASMTTranslationLimit::With(); limit->setName(joint->getFullName() + "-LimitLenMin"); limit->setMarkerI(fullMarkerNameI); @@ -1169,7 +1178,9 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint) limit->setlimit(std::to_string(minLength)); limit->settol("1.0e-9"); mbdAssembly->addLimit(limit); + } + if (maxEnabled) { auto limit2 = ASMTTranslationLimit::With(); limit2->setName(joint->getFullName() + "-LimitLenMax"); limit2->setMarkerI(fullMarkerNameI); @@ -1180,23 +1191,34 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint) mbdAssembly->addLimit(limit2); } } - if (jointType == JointType::Revolute || jointType == JointType::Cylindrical) { - auto* propRotMin = - dynamic_cast(joint->getPropertyByName("AngleMin")); - auto* propRotMax = - dynamic_cast(joint->getPropertyByName("AngleMax")); + } + if (jointType == JointType::Revolute || jointType == JointType::Cylindrical) { + auto* pRotMin = dynamic_cast(joint->getPropertyByName("AngleMin")); + auto* pRotMax = dynamic_cast(joint->getPropertyByName("AngleMax")); + auto* pMinEnabled = + dynamic_cast(joint->getPropertyByName("EnableAngleMin")); + auto* pMaxEnabled = + dynamic_cast(joint->getPropertyByName("EnableAngleMax")); - if (propRotMin && propRotMax) { - // Swap the values if necessary. - double minAngle = propRotMin->getValue(); - double maxAngle = propRotMax->getValue(); - if (minAngle > maxAngle) { - propRotMin->setValue(maxAngle); - propRotMax->setValue(minAngle); - minAngle = maxAngle; - maxAngle = propRotMax->getValue(); - } + if (pRotMin && pRotMax && pMinEnabled && pMaxEnabled) { // Make sure properties do exist + // Swap the values if necessary. + bool minEnabled = pMinEnabled->getValue(); + bool maxEnabled = pMaxEnabled->getValue(); + double minAngle = pRotMin->getValue(); + double maxAngle = pRotMax->getValue(); + if ((minAngle > maxAngle) && minEnabled && maxEnabled) { + pRotMin->setValue(maxAngle); + pRotMax->setValue(minAngle); + minAngle = maxAngle; + maxAngle = pRotMax->getValue(); + pMinEnabled->setValue(maxEnabled); + pMaxEnabled->setValue(minEnabled); + minEnabled = maxEnabled; + maxEnabled = pMaxEnabled->getValue(); + } + + if (minEnabled) { auto limit = ASMTRotationLimit::With(); limit->setName(joint->getFullName() + "-LimitRotMin"); limit->setMarkerI(fullMarkerNameI); @@ -1205,7 +1227,9 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint) limit->setlimit(std::to_string(minAngle) + "*pi/180.0"); limit->settol("1.0e-9"); mbdAssembly->addLimit(limit); + } + if (maxEnabled) { auto limit2 = ASMTRotationLimit::With(); limit2->setName(joint->getFullName() + "-LimiRotMax"); limit2->setMarkerI(fullMarkerNameI); diff --git a/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui b/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui index 58b40dcba6..1a71b19688 100644 --- a/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui +++ b/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui @@ -137,96 +137,107 @@ - - + + Limits - - false - + + + + + Min length + + + false + + + + + + + + 0 + 0 + + + + mm + + + + + + + Max length + + + false + + + + + + + + 0 + 0 + + + + mm + + + + + + + Min angle + + + false + + + + + + + + 0 + 0 + + + + deg + + + + + + + Max angle + + + false + + + + + + + + 0 + 0 + + + + deg + + + + - - - Length min - - - - - - - - 0 - 0 - - - - mm - - - - - - - Length max - - - - - - - - 0 - 0 - - - - mm - - - - - - - Angle min - - - - - - - - 0 - 0 - - - - deg - - - - - - - Angle max - - - - - - - - 0 - 0 - - - - deg - - - - Reverse rotation diff --git a/src/Mod/Assembly/JointObject.py b/src/Mod/Assembly/JointObject.py index 4ef2c223e4..20a340b52d 100644 --- a/src/Mod/Assembly/JointObject.py +++ b/src/Mod/Assembly/JointObject.py @@ -370,17 +370,53 @@ class Joint: ) joint.Activated = True - if not hasattr(joint, "EnableLimits"): + if not hasattr(joint, "EnableLengthMin"): joint.addProperty( "App::PropertyBool", - "EnableLimits", + "EnableLengthMin", "Limits", QT_TRANSLATE_NOOP( "App::Property", - "Is this joint using limits.", + "Enable the minimum length limit of the joint.", ), ) - joint.EnableLimits = False + joint.EnableLengthMin = False + + if not hasattr(joint, "EnableLengthMax"): + joint.addProperty( + "App::PropertyBool", + "EnableLengthMax", + "Limits", + QT_TRANSLATE_NOOP( + "App::Property", + "Enable the maximum length limit of the joint.", + ), + ) + joint.EnableLengthMax = False + + if not hasattr(joint, "EnableAngleMin"): + joint.addProperty( + "App::PropertyBool", + "EnableAngleMin", + "Limits", + QT_TRANSLATE_NOOP( + "App::Property", + "Enable the minimum angle limit of the joint.", + ), + ) + joint.EnableAngleMin = False + + if not hasattr(joint, "EnableAngleMax"): + joint.addProperty( + "App::PropertyBool", + "EnableAngleMax", + "Limits", + QT_TRANSLATE_NOOP( + "App::Property", + "Enable the minimum length of the joint.", + ), + ) + joint.EnableAngleMax = False if not hasattr(joint, "LengthMin"): joint.addProperty( @@ -1268,7 +1304,11 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.form.offsetSpinbox.valueChanged.connect(self.onOffsetChanged) self.form.rotationSpinbox.valueChanged.connect(self.onRotationChanged) self.form.PushButtonReverse.clicked.connect(self.onReverseClicked) - self.form.LimitCheckbox.stateChanged.connect(self.adaptUi) + + self.form.limitCheckbox1.stateChanged.connect(self.adaptUi) + self.form.limitCheckbox2.stateChanged.connect(self.adaptUi) + self.form.limitCheckbox3.stateChanged.connect(self.adaptUi) + self.form.limitCheckbox4.stateChanged.connect(self.adaptUi) self.form.limitLenMinSpinbox.valueChanged.connect(self.onLimitLenMinChanged) self.form.limitLenMaxSpinbox.valueChanged.connect(self.onLimitLenMaxChanged) self.form.limitRotMinSpinbox.valueChanged.connect(self.onLimitRotMinChanged) @@ -1545,37 +1585,42 @@ class TaskAssemblyCreateJoint(QtCore.QObject): needLengthLimits = jType in JointUsingLimitLength needAngleLimits = jType in JointUsingLimitAngle - showLimits = False if needLengthLimits or needAngleLimits: - self.form.LimitCheckbox.show() - showLimits = True - else: - self.form.LimitCheckbox.hide() + self.form.groupBox_limits.show() - showLimits = showLimits and self.form.LimitCheckbox.isChecked() - self.joint.EnableLimits = showLimits + self.joint.EnableLengthMin = self.form.limitCheckbox1.isChecked() + self.joint.EnableLengthMax = self.form.limitCheckbox2.isChecked() + self.joint.EnableAngleMin = self.form.limitCheckbox3.isChecked() + self.joint.EnableAngleMax = self.form.limitCheckbox4.isChecked() - if needLengthLimits and showLimits: - self.form.limitLenMinSpinboxLabel.show() - self.form.limitLenMaxSpinboxLabel.show() - self.form.limitLenMinSpinbox.show() - self.form.limitLenMaxSpinbox.show() - else: - self.form.limitLenMinSpinboxLabel.hide() - self.form.limitLenMaxSpinboxLabel.hide() - self.form.limitLenMinSpinbox.hide() - self.form.limitLenMaxSpinbox.hide() + if needLengthLimits: + self.form.limitCheckbox1.show() + self.form.limitCheckbox2.show() + self.form.limitLenMinSpinbox.show() + self.form.limitLenMaxSpinbox.show() + self.form.limitLenMinSpinbox.setEnabled(self.joint.EnableLengthMin) + self.form.limitLenMaxSpinbox.setEnabled(self.joint.EnableLengthMax) + else: + self.form.limitCheckbox1.hide() + self.form.limitCheckbox2.hide() + self.form.limitLenMinSpinbox.hide() + self.form.limitLenMaxSpinbox.hide() + + if needAngleLimits: + self.form.limitCheckbox3.show() + self.form.limitCheckbox4.show() + self.form.limitRotMinSpinbox.show() + self.form.limitRotMaxSpinbox.show() + self.form.limitRotMinSpinbox.setEnabled(self.joint.EnableAngleMin) + self.form.limitRotMaxSpinbox.setEnabled(self.joint.EnableAngleMax) + else: + self.form.limitCheckbox3.hide() + self.form.limitCheckbox4.hide() + self.form.limitRotMinSpinbox.hide() + self.form.limitRotMaxSpinbox.hide() - if needAngleLimits and showLimits: - self.form.limitRotMinSpinboxLabel.show() - self.form.limitRotMaxSpinboxLabel.show() - self.form.limitRotMinSpinbox.show() - self.form.limitRotMaxSpinbox.show() else: - self.form.limitRotMinSpinboxLabel.hide() - self.form.limitRotMaxSpinboxLabel.hide() - self.form.limitRotMinSpinbox.hide() - self.form.limitRotMaxSpinbox.hide() + self.form.groupBox_limits.hide() def updateTaskboxFromJoint(self): self.current_selection = [] @@ -1617,7 +1662,10 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.form.offsetSpinbox.setProperty("rawValue", self.joint.Offset.z) self.form.rotationSpinbox.setProperty("rawValue", self.joint.Rotation) - self.form.LimitCheckbox.setChecked(self.joint.EnableLimits) + self.form.limitCheckbox1.setChecked(self.joint.EnableLengthMin) + self.form.limitCheckbox2.setChecked(self.joint.EnableLengthMax) + self.form.limitCheckbox3.setChecked(self.joint.EnableAngleMin) + self.form.limitCheckbox4.setChecked(self.joint.EnableAngleMax) self.form.limitLenMinSpinbox.setProperty("rawValue", self.joint.LengthMin) self.form.limitLenMaxSpinbox.setProperty("rawValue", self.joint.LengthMax) self.form.limitRotMinSpinbox.setProperty("rawValue", self.joint.AngleMin) From 0a056923cb5487d8b79eaa3235f86dc478472f2c Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Thu, 27 Jun 2024 09:07:49 +0200 Subject: [PATCH 2/6] Assembly: Limits: Set one checkbox for each limit. --- .../Gui/Resources/panels/TaskAssemblyCreateJoint.ui | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui b/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui index 1a71b19688..05245ca40c 100644 --- a/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui +++ b/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui @@ -209,6 +209,12 @@ deg + + -180.0 + + + 180.0 + @@ -232,6 +238,12 @@ deg + + -180.0 + + + 180.0 + From bba868912b3ef18b470a793c02ca2f5aebd45541 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Wed, 26 Jun 2024 13:52:44 +0200 Subject: [PATCH 3/6] Assembly: Create Joint : fix untranslated strings. --- src/Mod/Assembly/JointObject.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mod/Assembly/JointObject.py b/src/Mod/Assembly/JointObject.py index 20a340b52d..bcff1ca936 100644 --- a/src/Mod/Assembly/JointObject.py +++ b/src/Mod/Assembly/JointObject.py @@ -1522,13 +1522,13 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.form.distanceLabel.show() self.form.distanceSpinbox.show() if jType == "Distance": - self.form.distanceLabel.setText("Distance") + self.form.distanceLabel.setText(translate("Assembly", "Distance")) elif jType == "Angle": - self.form.distanceLabel.setText("Angle") + self.form.distanceLabel.setText(translate("Assembly", "Angle")) elif jType == "Gears" or jType == "Belt": - self.form.distanceLabel.setText("Radius 1") + self.form.distanceLabel.setText(translate("Assembly", "Radius 1")) else: - self.form.distanceLabel.setText("Pitch radius") + self.form.distanceLabel.setText(translate("Assembly", "Pitch radius")) if jType == "Angle": self.form.distanceSpinbox.setProperty("unit", "deg") From 40feca037ca4684a9c05173e3d197bbc97459b1b Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Wed, 26 Jun 2024 13:53:22 +0200 Subject: [PATCH 4/6] Assembly: Create joint : Reduce heigth of list widget. --- .../panels/TaskAssemblyCreateJoint.ui | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui b/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui index 05245ca40c..4353934916 100644 --- a/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui +++ b/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateJoint.ui @@ -6,8 +6,8 @@ 0 0 - 376 - 387 + 150 + 150 @@ -18,7 +18,20 @@ - + + + + 16777215 + 75 + + + + + 0 + 0 + + + From a0c4a273bacfe85f54b685d1cc778b7b4056b837 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Wed, 26 Jun 2024 15:25:41 +0200 Subject: [PATCH 5/6] Assembly: Enable moving objects while making joints. --- src/Mod/Assembly/App/AssemblyObject.cpp | 2 +- src/Mod/Assembly/App/AssemblyObject.h | 2 +- src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 61 +++++++++++-------- src/Mod/Assembly/Gui/ViewProviderAssembly.h | 18 ++++++ .../Assembly/Gui/ViewProviderAssemblyPy.xml | 12 ++++ .../Gui/ViewProviderAssemblyPyImp.cpp | 20 ++++++ src/Mod/Assembly/JointObject.py | 46 ++++++++------ 7 files changed, 113 insertions(+), 48 deletions(-) diff --git a/src/Mod/Assembly/App/AssemblyObject.cpp b/src/Mod/Assembly/App/AssemblyObject.cpp index 0dabd5b998..336538ca86 100644 --- a/src/Mod/Assembly/App/AssemblyObject.cpp +++ b/src/Mod/Assembly/App/AssemblyObject.cpp @@ -528,7 +528,7 @@ std::vector AssemblyObject::getJoints(bool updateJCS, bool // add sub assemblies joints. for (auto& assembly : getSubAssemblies()) { - auto subJoints = assembly->getJoints(updateJCS); + auto subJoints = assembly->getJoints(updateJCS, delBadJoints); joints.insert(joints.end(), subJoints.begin(), subJoints.end()); } diff --git a/src/Mod/Assembly/App/AssemblyObject.h b/src/Mod/Assembly/App/AssemblyObject.h index c15229515b..4a8753f7ec 100644 --- a/src/Mod/Assembly/App/AssemblyObject.h +++ b/src/Mod/Assembly/App/AssemblyObject.h @@ -184,7 +184,7 @@ public: void jointParts(std::vector joints); JointGroup* getJointGroup(); ViewGroup* getExplodedViewGroup(); - std::vector getJoints(bool updateJCS = true, bool delBadJoints = true); + std::vector getJoints(bool updateJCS = true, bool delBadJoints = false); std::vector getGroundedJoints(); std::vector getJointsOfObj(App::DocumentObject* obj); std::vector getJointsOfPart(App::DocumentObject* part); diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index a780ea3ccb..22e647b42f 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -92,6 +92,8 @@ ViewProviderAssembly::ViewProviderAssembly() , canStartDragging(false) , partMoving(false) , enableMovement(true) + , moveOnlyPreselected(false) + , moveInCommand(true) , jointVisibilityBackup(false) , ctrlPressed(false) , docsToMove({}) @@ -139,7 +141,6 @@ bool ViewProviderAssembly::canDragObject(App::DocumentObject* obj) const // else if a solid is removed, remove associated joints if any. bool prompted = false; auto* assemblyPart = static_cast(getObject()); - std::vector joints = assemblyPart->getJoints(); // Combine the joints and groundedJoints vectors into one for simplicity. std::vector allJoints = assemblyPart->getJoints(); @@ -505,30 +506,33 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection return false; } - for (auto& selObj : Gui::Selection().getSelectionEx("", - App::DocumentObject::getClassTypeId(), - Gui::ResolveMode::NoResolve)) { - // getSubNames() returns ["Body001.Pad.Face14", "Body002.Pad.Face7"] - // if you have several objects within the same assembly selected. + if (!moveOnlyPreselected) { + for (auto& selObj : Gui::Selection().getSelectionEx("", + App::DocumentObject::getClassTypeId(), + Gui::ResolveMode::NoResolve)) { + // getSubNames() returns ["Body001.Pad.Face14", "Body002.Pad.Face7"] + // if you have several objects within the same assembly selected. - std::vector objsSubNames = selObj.getSubNames(); - for (auto& subNamesStr : objsSubNames) { - std::vector subNames = parseSubNames(subNamesStr); - if (subNames.empty()) { - continue; + std::vector objsSubNames = selObj.getSubNames(); + for (auto& subNamesStr : objsSubNames) { + std::vector subNames = parseSubNames(subNamesStr); + if (subNames.empty()) { + continue; + } + if (onlySolids && subNames.back() != "") { + continue; + } + + App::DocumentObject* obj = getObjectFromSubNames(subNames); + + if (!canDragObjectIn3d(obj)) { + continue; + } + + auto* pPlc = + dynamic_cast(obj->getPropertyByName("Placement")); + docsToMove.emplace_back(obj, pPlc->getValue()); } - if (onlySolids && subNames.back() != "") { - continue; - } - - App::DocumentObject* obj = getObjectFromSubNames(subNames); - - if (!canDragObjectIn3d(obj)) { - continue; - } - - auto* pPlc = dynamic_cast(obj->getPropertyByName("Placement")); - docsToMove.emplace_back(obj, pPlc->getValue()); } } @@ -557,7 +561,7 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection if (!alreadyIn) { auto* pPlc = dynamic_cast(obj->getPropertyByName("Placement")); - if (!ctrlPressed) { + if (!ctrlPressed && !moveOnlyPreselected) { Gui::Selection().clearSelection(); docsToMove.clear(); } @@ -772,8 +776,9 @@ void ViewProviderAssembly::initMove(const SbVec2s& cursorPos, Gui::View3DInvento prevPosition = initialPosition; } - - Gui::Command::openCommand(tr("Move part").toStdString().c_str()); + if (moveInCommand) { + Gui::Command::openCommand(tr("Move part").toStdString().c_str()); + } partMoving = true; // prevent selection while moving @@ -825,7 +830,9 @@ void ViewProviderAssembly::endMove() assemblyPart->setObjMasses({}); } - Gui::Command::commitCommand(); + if (moveInCommand) { + Gui::Command::commitCommand(); + } } void ViewProviderAssembly::initMoveDragger() diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.h b/src/Mod/Assembly/Gui/ViewProviderAssembly.h index e952b1c91a..70d671d663 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.h +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.h @@ -114,6 +114,22 @@ public: { return enableMovement; } + virtual void setMoveOnlyPreselected(bool enable = true) + { + moveOnlyPreselected = enable; + } + virtual bool getMoveOnlyPreselected() const + { + return moveOnlyPreselected; + } + virtual void setMoveInCommand(bool enable = true) + { + moveInCommand = enable; + } + virtual bool getMoveInCommand() const + { + return moveInCommand; + } bool canDragObjectIn3d(App::DocumentObject* obj) const; @@ -150,6 +166,8 @@ public: bool canStartDragging; bool partMoving; bool enableMovement; + bool moveOnlyPreselected; + bool moveInCommand; bool jointVisibilityBackup; bool ctrlPressed; int numberOfSel; diff --git a/src/Mod/Assembly/Gui/ViewProviderAssemblyPy.xml b/src/Mod/Assembly/Gui/ViewProviderAssemblyPy.xml index 8d2fac8863..8d0f9dfad9 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssemblyPy.xml +++ b/src/Mod/Assembly/Gui/ViewProviderAssemblyPy.xml @@ -31,6 +31,18 @@ + + + If enabled, only the preselected object will move. + + + + + + If enabled, each move will be wrapped in a command. + + + Show or hide the assembly dragger. diff --git a/src/Mod/Assembly/Gui/ViewProviderAssemblyPyImp.cpp b/src/Mod/Assembly/Gui/ViewProviderAssemblyPyImp.cpp index 4e3bd156c2..c733b11c17 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssemblyPyImp.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssemblyPyImp.cpp @@ -52,6 +52,26 @@ void ViewProviderAssemblyPy::setEnableMovement(Py::Boolean arg) getViewProviderAssemblyPtr()->setEnableMovement(arg); } +Py::Boolean ViewProviderAssemblyPy::getMoveOnlyPreselected() const +{ + return {getViewProviderAssemblyPtr()->getMoveOnlyPreselected()}; +} + +void ViewProviderAssemblyPy::setMoveOnlyPreselected(Py::Boolean arg) +{ + getViewProviderAssemblyPtr()->setMoveOnlyPreselected(arg); +} + +Py::Boolean ViewProviderAssemblyPy::getMoveInCommand() const +{ + return {getViewProviderAssemblyPtr()->getMoveInCommand()}; +} + +void ViewProviderAssemblyPy::setMoveInCommand(Py::Boolean arg) +{ + getViewProviderAssemblyPtr()->setMoveInCommand(arg); +} + Py::Boolean ViewProviderAssemblyPy::getDraggerVisibility() const { return {getViewProviderAssemblyPtr()->getDraggerVisibility()}; diff --git a/src/Mod/Assembly/JointObject.py b/src/Mod/Assembly/JointObject.py index bcff1ca936..63f6d85e5b 100644 --- a/src/Mod/Assembly/JointObject.py +++ b/src/Mod/Assembly/JointObject.py @@ -1223,14 +1223,6 @@ class MakeJointSelGate: # Only objects within the assembly. return False - if Gui.Selection.isSelected(obj, sub, Gui.Selection.ResolveMode.NoResolve): - # If it's to deselect then it's ok - return True - - if len(self.taskbox.current_selection) >= 2: - # No more than 2 elements can be selected for basic joints. - return False - full_obj_name = ".".join(objs_names) full_element_name = full_obj_name + "." + element_name selected_object = UtilsAssembly.getObject(full_element_name) @@ -1247,15 +1239,6 @@ class MakeJointSelGate: else: return False - part_containing_selected_object = UtilsAssembly.getContainingPart( - full_element_name, selected_object, self.assembly - ) - - for selection_dict in self.taskbox.current_selection: - if selection_dict["part"] == part_containing_selected_object: - # Can't join a solid to itself. So the user need to select 2 different parts. - return False - return True @@ -1285,7 +1268,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): return if self.activeType == "Assembly": - self.assembly.ViewObject.EnableMovement = False + self.assembly.ViewObject.MoveOnlyPreselected = True + self.assembly.ViewObject.MoveInCommand = False self.form = Gui.PySideUic.loadUi(":/panels/TaskAssemblyCreateJoint.ui") @@ -1358,6 +1342,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.form.featureList.installEventFilter(self) + self.addition_rejected = False + def accept(self): if len(self.current_selection) != 2: App.Console.PrintWarning( @@ -1389,7 +1375,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): if self.activeType == "Assembly": self.assembly.clearUndo() - self.assembly.ViewObject.EnableMovement = True + self.assembly.ViewObject.MoveOnlyPreselected = False + self.assembly.ViewObject.MoveInCommand = True Gui.Selection.removeSelectionGate() Gui.Selection.removeObserver(self) @@ -1831,6 +1818,23 @@ class TaskAssemblyCreateJoint(QtCore.QObject): element_name = UtilsAssembly.getElementName(full_element_name) part_containing_selected_object = self.getContainingPart(full_element_name, selected_object) + # Check if the addition is acceptable (we are not doing this in selection gate to let user move objects) + acceptable = True + if len(self.current_selection) >= 2: + # No more than 2 elements can be selected for basic joints. + acceptable = False + + for selection_dict in self.current_selection: + if selection_dict["part"] == part_containing_selected_object: + # Can't join a solid to itself. So the user need to select 2 different parts. + acceptable = False + + if not acceptable: + self.addition_rejected = True + Gui.Selection.removeSelection(doc_name, obj_name, sub_name) + return + + # Selection is acceptable so add it selection_dict = { "object": selected_object, "part": part_containing_selected_object, @@ -1851,6 +1855,10 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.joint.ViewObject.Proxy.showPreviewJCS(False) def removeSelection(self, doc_name, obj_name, sub_name, mousePos=None): + if self.addition_rejected: + self.addition_rejected = False + return + full_element_name = UtilsAssembly.getFullElementName(obj_name, sub_name) selected_object = UtilsAssembly.getObject(full_element_name) element_name = UtilsAssembly.getElementName(full_element_name) From 632780ce359f45b4561979433f26ac7a1d7f5145 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Wed, 26 Jun 2024 17:05:04 +0200 Subject: [PATCH 6/6] Assembly: Create Joint limit: Moving objects updates the spinboxes values if they are disabled. --- src/Mod/Assembly/JointObject.py | 35 +++++++++++++++++++++++++++---- src/Mod/Assembly/UtilsAssembly.py | 25 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/Mod/Assembly/JointObject.py b/src/Mod/Assembly/JointObject.py index 63f6d85e5b..87cbfce3ca 100644 --- a/src/Mod/Assembly/JointObject.py +++ b/src/Mod/Assembly/JointObject.py @@ -1482,16 +1482,20 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.joint.Rotation = self.form.rotationSpinbox.property("rawValue") def onLimitLenMinChanged(self, quantity): - self.joint.LengthMin = self.form.limitLenMinSpinbox.property("rawValue") + if self.form.limitCheckbox1.isChecked(): + self.joint.LengthMin = self.form.limitLenMinSpinbox.property("rawValue") def onLimitLenMaxChanged(self, quantity): - self.joint.LengthMax = self.form.limitLenMaxSpinbox.property("rawValue") + if self.form.limitCheckbox2.isChecked(): + self.joint.LengthMax = self.form.limitLenMaxSpinbox.property("rawValue") def onLimitRotMinChanged(self, quantity): - self.joint.AngleMin = self.form.limitRotMinSpinbox.property("rawValue") + if self.form.limitCheckbox3.isChecked(): + self.joint.AngleMin = self.form.limitRotMinSpinbox.property("rawValue") def onLimitRotMaxChanged(self, quantity): - self.joint.AngleMax = self.form.limitRotMaxSpinbox.property("rawValue") + if self.form.limitCheckbox4.isChecked(): + self.joint.AngleMax = self.form.limitRotMaxSpinbox.property("rawValue") def onReverseClicked(self): self.joint.Proxy.flipOnePart(self.joint) @@ -1587,6 +1591,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.form.limitLenMaxSpinbox.show() self.form.limitLenMinSpinbox.setEnabled(self.joint.EnableLengthMin) self.form.limitLenMaxSpinbox.setEnabled(self.joint.EnableLengthMax) + self.onLimitLenMinChanged(0) # dummy value + self.onLimitLenMaxChanged(0) else: self.form.limitCheckbox1.hide() self.form.limitCheckbox2.hide() @@ -1600,6 +1606,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.form.limitRotMaxSpinbox.show() self.form.limitRotMinSpinbox.setEnabled(self.joint.EnableAngleMin) self.form.limitRotMaxSpinbox.setEnabled(self.joint.EnableAngleMax) + self.onLimitRotMinChanged(0) + self.onLimitRotMaxChanged(0) else: self.form.limitCheckbox3.hide() self.form.limitCheckbox4.hide() @@ -1721,6 +1729,23 @@ class TaskAssemblyCreateJoint(QtCore.QObject): simplified_names.append(sname) self.form.featureList.addItems(simplified_names) + def updateLimits(self): + needLengthLimits = self.jType in JointUsingLimitLength + needAngleLimits = self.jType in JointUsingLimitAngle + if needLengthLimits: + distance = UtilsAssembly.getJointDistance(self.joint) + if not self.form.limitCheckbox1.isChecked(): + self.form.limitLenMinSpinbox.setProperty("rawValue", distance) + if not self.form.limitCheckbox2.isChecked(): + self.form.limitLenMaxSpinbox.setProperty("rawValue", distance) + + if needAngleLimits: + angle = UtilsAssembly.getJointXYAngle(self.joint) / math.pi * 180 + if not self.form.limitCheckbox3.isChecked(): + self.form.limitRotMinSpinbox.setProperty("rawValue", angle) + if not self.form.limitCheckbox4.isChecked(): + self.form.limitRotMaxSpinbox.setProperty("rawValue", angle) + def moveMouse(self, info): if len(self.current_selection) >= 2 or ( len(self.current_selection) == 1 @@ -1730,6 +1755,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): ) ): self.joint.ViewObject.Proxy.showPreviewJCS(False) + if len(self.current_selection) >= 2: + self.updateLimits() return cursor_pos = self.view.getCursorPos() diff --git a/src/Mod/Assembly/UtilsAssembly.py b/src/Mod/Assembly/UtilsAssembly.py index f6fa9bb15e..8f778d1ba6 100644 --- a/src/Mod/Assembly/UtilsAssembly.py +++ b/src/Mod/Assembly/UtilsAssembly.py @@ -21,6 +21,8 @@ # * # **************************************************************************/ +import math + import FreeCAD as App import Part @@ -1044,3 +1046,26 @@ def getAssemblyShapes(assembly): shapes.append(part.Shape) return shapes + + +def getJointDistance(joint): + plc1 = getJcsGlobalPlc(joint.Placement1, joint.Object1, joint.Part1) + plc2 = getJcsGlobalPlc(joint.Placement2, joint.Object2, joint.Part2) + + # Find the sign + sign = 1 + plc3 = plc1.inverse() * plc2 # plc3 is plc2 relative to plc1 + if plc3.Base.z < 0: + sign = -1 + + return sign * (plc1.Base - plc2.Base).Length + + +def getJointXYAngle(joint): + plc1 = getJcsGlobalPlc(joint.Placement1, joint.Object1, joint.Part1) + plc2 = getJcsGlobalPlc(joint.Placement2, joint.Object2, joint.Part2) + + plc3 = plc1.inverse() * plc2 # plc3 is plc2 relative to plc1 + x_axis = plc3.Rotation.multVec(App.Vector(1, 0, 0)) + + return math.atan2(x_axis.y, x_axis.x)