Merge pull request #14738 from Ondsel-Development/asm_limits

Assembly: Limits: Set one checkbox for each limit.
This commit is contained in:
Chris Hennes
2024-07-01 10:54:19 -05:00
committed by GitHub
9 changed files with 433 additions and 208 deletions

View File

@@ -528,7 +528,7 @@ std::vector<App::DocumentObject*> 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());
}
@@ -1142,25 +1142,34 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint)
mbdJoint->setMarkerJ(fullMarkerNameJ);
// Add limits if needed.
auto* prop = dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("EnableLimits"));
if (prop && prop->getValue()) {
if (jointType == JointType::Slider || jointType == JointType::Cylindrical) {
auto* propLenMin =
dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("LengthMin"));
auto* propLenMax =
dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("LengthMax"));
if (jointType == JointType::Slider || jointType == JointType::Cylindrical) {
auto* pLenMin = dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("LengthMin"));
auto* pLenMax = dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("LengthMax"));
auto* pMinEnabled =
dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("EnableLengthMin"));
auto* pMaxEnabled =
dynamic_cast<App::PropertyBool*>(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<App::PropertyFloat*>(joint->getPropertyByName("AngleMin"));
auto* propRotMax =
dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("AngleMax"));
}
if (jointType == JointType::Revolute || jointType == JointType::Cylindrical) {
auto* pRotMin = dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("AngleMin"));
auto* pRotMax = dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("AngleMax"));
auto* pMinEnabled =
dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("EnableAngleMin"));
auto* pMaxEnabled =
dynamic_cast<App::PropertyBool*>(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);

View File

@@ -184,7 +184,7 @@ public:
void jointParts(std::vector<App::DocumentObject*> joints);
JointGroup* getJointGroup();
ViewGroup* getExplodedViewGroup();
std::vector<App::DocumentObject*> getJoints(bool updateJCS = true, bool delBadJoints = true);
std::vector<App::DocumentObject*> getJoints(bool updateJCS = true, bool delBadJoints = false);
std::vector<App::DocumentObject*> getGroundedJoints();
std::vector<App::DocumentObject*> getJointsOfObj(App::DocumentObject* obj);
std::vector<App::DocumentObject*> getJointsOfPart(App::DocumentObject* part);

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>376</width>
<height>387</height>
<width>150</width>
<height>150</height>
</rect>
</property>
<property name="windowTitle">
@@ -18,7 +18,20 @@
<widget class="QComboBox" name="jointType"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QListWidget" name="featureList"/>
<widget class="QListWidget" name="featureList">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>75</height>
</size>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="hLayoutDistance">
@@ -137,96 +150,119 @@
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="LimitCheckbox">
<property name="text">
<widget class="QGroupBox" name="groupBox_limits">
<property name="title">
<string>Limits</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_limits">
<item row="0" column="0">
<widget class="QCheckBox" name="limitCheckbox1">
<property name="text">
<string>Min length</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::QuantitySpinBox" name="limitLenMinSpinbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="limitCheckbox2">
<property name="text">
<string>Max length</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::QuantitySpinBox" name="limitLenMaxSpinbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="limitCheckbox3">
<property name="text">
<string>Min angle</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::QuantitySpinBox" name="limitRotMinSpinbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true">deg</string>
</property>
<property name="minimum">
<double>-180.0</double>
</property>
<property name="maximum">
<double>180.0</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="limitCheckbox4">
<property name="text">
<string>Max angle</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="Gui::QuantitySpinBox" name="limitRotMaxSpinbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true">deg</string>
</property>
<property name="minimum">
<double>-180.0</double>
</property>
<property name="maximum">
<double>180.0</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="limitLenMinSpinboxLabel">
<property name="text">
<string>Length min</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="Gui::QuantitySpinBox" name="limitLenMinSpinbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="limitLenMaxSpinboxLabel">
<property name="text">
<string>Length max</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="Gui::QuantitySpinBox" name="limitLenMaxSpinbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="limitRotMinSpinboxLabel">
<property name="text">
<string>Angle min</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="Gui::QuantitySpinBox" name="limitRotMinSpinbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true">deg</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="limitRotMaxSpinboxLabel">
<property name="text">
<string>Angle max</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="Gui::QuantitySpinBox" name="limitRotMaxSpinbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true">deg</string>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QCheckBox" name="reverseRotCheckbox">
<property name="text">
<string>Reverse rotation</string>

View File

@@ -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<AssemblyObject*>(getObject());
std::vector<App::DocumentObject*> joints = assemblyPart->getJoints();
// Combine the joints and groundedJoints vectors into one for simplicity.
std::vector<App::DocumentObject*> 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<std::string> objsSubNames = selObj.getSubNames();
for (auto& subNamesStr : objsSubNames) {
std::vector<std::string> subNames = parseSubNames(subNamesStr);
if (subNames.empty()) {
continue;
std::vector<std::string> objsSubNames = selObj.getSubNames();
for (auto& subNamesStr : objsSubNames) {
std::vector<std::string> 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<App::PropertyPlacement*>(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<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
docsToMove.emplace_back(obj, pPlc->getValue());
}
}
@@ -557,7 +561,7 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection
if (!alreadyIn) {
auto* pPlc =
dynamic_cast<App::PropertyPlacement*>(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()

View File

@@ -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;

View File

@@ -31,6 +31,18 @@
</Documentation>
<Parameter Name="EnableMoving" Type="Boolean" />
</Attribute>
<Attribute Name="MoveOnlyPreselected">
<Documentation>
<UserDocu>If enabled, only the preselected object will move.</UserDocu>
</Documentation>
<Parameter Name="MoveOnlyPreselected" Type="Boolean" />
</Attribute>
<Attribute Name="MoveInCommand">
<Documentation>
<UserDocu>If enabled, each move will be wrapped in a command.</UserDocu>
</Documentation>
<Parameter Name="MoveInCommand" Type="Boolean" />
</Attribute>
<Attribute Name="DraggerVisibility">
<Documentation>
<UserDocu>Show or hide the assembly dragger.</UserDocu>

View File

@@ -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()};

View File

@@ -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(
@@ -1187,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)
@@ -1211,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
@@ -1249,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")
@@ -1268,7 +1288,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)
@@ -1323,6 +1347,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(
@@ -1354,7 +1380,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)
@@ -1460,16 +1487,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)
@@ -1487,13 +1518,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")
@@ -1550,37 +1581,46 @@ 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)
self.onLimitLenMinChanged(0) # dummy value
self.onLimitLenMaxChanged(0)
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)
self.onLimitRotMinChanged(0)
self.onLimitRotMaxChanged(0)
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 = []
@@ -1622,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)
@@ -1691,6 +1734,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
@@ -1700,6 +1760,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()
@@ -1788,6 +1850,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,
@@ -1808,6 +1887,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)

View File

@@ -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)