Merge pull request #14738 from Ondsel-Development/asm_limits
Assembly: Limits: Set one checkbox for each limit.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user