Assembly: Insert flexible assembly grounds the correct part (#27206)

* Assembly: Insert flexible assembly grounds the correct part

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Assembly: Migrate ObjectToGround to PropertyLinkGlobal to support assembly links

* Update JointObject.py

* Assembly: ViewProviderAssembly fix assembly link deletion issue

* Assembly: ViewProviderAssembly: make sure no duplicates in canDelete

* Assembly CommandInsertLink fix typo

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
PaddleStroke
2026-02-02 17:43:45 +01:00
committed by GitHub
parent 212e4f07af
commit a3486b4dd2
3 changed files with 67 additions and 11 deletions

View File

@@ -495,7 +495,43 @@ class TaskAssemblyInsertLink(QtCore.QObject):
if len(self.insertionStack) != 1:
return
self.groundedObj = self.insertionStack[0]["addedObject"]
targetObj = self.insertionStack[0]["addedObject"]
# If the object is a flexible AssemblyLink, we should ground its internal 'base' part
if targetObj.isDerivedFrom("Assembly::AssemblyLink") and not targetObj.Rigid:
linkedAsm = targetObj.LinkedObject
if linkedAsm and hasattr(linkedAsm, "Group"):
srcGrounded = None
# Attempt to find the grounded joint in the source assembly
# We look for a joint where JointType is 'Grounded'
for obj in linkedAsm.InListRecursive:
if hasattr(obj, "ObjectToGround"):
srcGrounded = obj.ObjectToGround
break
# Search the sub-assembly group for the link pointing to the source grounded object
# Fallback to the first valid part if no grounded joint was found in source
candidate = None
for child in targetObj.Group:
if not candidate and (
child.isDerivedFrom("App::Link") or child.isDerivedFrom("Part::Feature")
):
candidate = child
if (
srcGrounded
and hasattr(child, "LinkedObject")
and child.LinkedObject == srcGrounded
):
candidate = child
break
if not candidate: # Nothing to ground
return
targetObj = candidate
self.groundedObj = targetObj
self.groundedJoint = CommandCreateJoint.createGroundedJoint(self.groundedObj)
def increment_counter(self, item):

View File

@@ -1345,20 +1345,24 @@ bool ViewProviderAssembly::canDelete(App::DocumentObject* objBeingDeleted) const
continue;
}
if (dynamic_cast<App::PropertyLink*>(parent->getPropertyByName("ObjectToGround"))) {
objToDel.push_back(parent);
if (parent->getPropertyByName("ObjectToGround")) {
if (std::ranges::find(objToDel, parent) == objToDel.end()) {
objToDel.push_back(parent);
}
}
}
}
// Deletes them.
for (auto* joint : objToDel) {
Gui::Command::doCommand(
Gui::Command::Doc,
"App.getDocument(\"%s\").removeObject(\"%s\")",
joint->getDocument()->getName(),
joint->getNameInDocument()
);
if (joint && joint->getNameInDocument() != nullptr) {
Gui::Command::doCommand(
Gui::Command::Doc,
"App.getDocument(\"%s\").removeObject(\"%s\")",
joint->getDocument()->getName(),
joint->getNameInDocument()
);
}
}
}
return res;

View File

@@ -1211,16 +1211,32 @@ class GroundedJoint:
joint.Proxy = self
self.joint = joint
self.createObjectToGroundProperty(joint, obj_to_ground)
def createObjectToGroundProperty(self, joint, obj_to_ground):
joint.addProperty(
"App::PropertyLink",
"App::PropertyLinkGlobal",
"ObjectToGround",
"Ground",
QT_TRANSLATE_NOOP("App::Property", "The object to ground"),
locked=True,
)
joint.ObjectToGround = obj_to_ground
def onDocumentRestored(self, joint):
self.migrationScript(joint)
def migrationScript(self, joint):
if (
hasattr(joint, "ObjectToGround")
and joint.getTypeIdOfProperty("ObjectToGround") == "App::PropertyLink"
):
obj_to_ground = joint.ObjectToGround
joint.setPropertyStatus("ObjectToGround", "-LockDynamic")
joint.removeProperty("ObjectToGround")
self.createObjectToGroundProperty(joint, obj_to_ground)
def dumps(self):
return None