From e20b42e484d9cd3a313e15c4d0405dbbf77c54f0 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Mon, 9 Mar 2026 18:15:01 +0100 Subject: [PATCH] Assembly: fix joint creation not working on draft links (#26085) * Assembly: add support for draft links * Update AssemblyObject.cpp * Update ViewProviderAssembly.cpp * Update GeoFeature.cpp * Update JointObject.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * [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> --- src/App/GeoFeature.cpp | 3 ++- src/Mod/Assembly/App/AssemblyObject.cpp | 26 +++++++++---------- src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 2 +- src/Mod/Assembly/JointObject.py | 2 ++ src/Mod/Assembly/UtilsAssembly.py | 18 +++---------- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp index d5a3657ecb..96b62c0738 100644 --- a/src/App/GeoFeature.cpp +++ b/src/App/GeoFeature.cpp @@ -328,7 +328,7 @@ Base::Placement GeoFeature::getGlobalPlacement(App::DocumentObject* targetObj, Base::Placement GeoFeature::getGlobalPlacement(App::DocumentObject* targetObj, App::PropertyXLinkSub* prop) { - if (!targetObj || !prop) { + if (!prop) { return Base::Placement(); } @@ -357,3 +357,4 @@ Base::Placement GeoFeature::getGlobalPlacement(const DocumentObject* obj) return placementProperty->getValue(); } + diff --git a/src/Mod/Assembly/App/AssemblyObject.cpp b/src/Mod/Assembly/App/AssemblyObject.cpp index 93b6100ae0..7ef900a306 100644 --- a/src/Mod/Assembly/App/AssemblyObject.cpp +++ b/src/Mod/Assembly/App/AssemblyObject.cpp @@ -1657,20 +1657,20 @@ std::string AssemblyObject::handleOneSideOfJoint( Base::Placement plc = getPlacementFromProp(joint, propPlcName); // Now we have plc which is the JCS placement, but its relative to the Object, not to the // containing Part. - - if (obj->getNameInDocument() != part->getNameInDocument()) { - - auto* ref = dynamic_cast(joint->getPropertyByName(propRefName)); - if (!ref) { - return ""; - } - - Base::Placement obj_global_plc = getGlobalPlacement(obj, ref); - plc = obj_global_plc * plc; - - Base::Placement part_global_plc = getGlobalPlacement(part, ref); - plc = part_global_plc.inverse() * plc; + auto* ref = dynamic_cast(joint->getPropertyByName(propRefName)); + if (!ref) { + return ""; } + + // This plc adjustment should be necessary only if obj != part. But for some objects like + // draft links, we can have obj == part and still need to get global placement to adjust + // by the element placement. + Base::Placement obj_global_plc = getGlobalPlacement(nullptr, ref); + plc = obj_global_plc * plc; + // Note part is supposed to be root of ref, so we could use part.Placement directly. + Base::Placement part_global_plc = getGlobalPlacement(part, ref); + plc = part_global_plc.inverse() * plc; + // check if we need to add an offset in case of bundled parts. if (!data.offsetPlc.isIdentity()) { plc = data.offsetPlc * plc; diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 49db0de28e..ad164ea430 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -979,7 +979,7 @@ ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode() return DragMode::Translation; } auto* obj = getObjFromJointRef(movingJoint, pName.c_str()); - Base::Placement global_plc = App::GeoFeature::getGlobalPlacement(obj, ref); + Base::Placement global_plc = App::GeoFeature::getGlobalPlacement(nullptr, ref); jcsGlobalPlc = global_plc * jcsPlc; // Add downstream parts so that they move together diff --git a/src/Mod/Assembly/JointObject.py b/src/Mod/Assembly/JointObject.py index 8bd59f936e..84bed3dfd0 100644 --- a/src/Mod/Assembly/JointObject.py +++ b/src/Mod/Assembly/JointObject.py @@ -2219,6 +2219,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.presel_ref = None return + sub_name = UtilsAssembly.fixBodyExtraFeatureInSub(doc_name, sub_name) + rootObj = App.getDocument(doc_name).getObject(obj_name) comp, new_sub = UtilsAssembly.getComponentReference(self.assembly, rootObj, sub_name) diff --git a/src/Mod/Assembly/UtilsAssembly.py b/src/Mod/Assembly/UtilsAssembly.py index 5a7cd74142..29a5ab4c1a 100644 --- a/src/Mod/Assembly/UtilsAssembly.py +++ b/src/Mod/Assembly/UtilsAssembly.py @@ -364,11 +364,6 @@ def getGlobalPlacement(ref, targetObj=None): if not isRefValid(ref, 1): return App.Placement() - if targetObj is None: # If no targetObj is given, we consider it's the getObject(ref) - targetObj = getObject(ref) - if targetObj is None: - return App.Placement() - rootObj = ref[0] subName = ref[1][0] # ref[0] is no longer the root object. Now it's the moving part. @@ -1098,9 +1093,9 @@ def findPlacement(ref, ignoreVertex=False): if hasattr(surface, "Rotation") and surface.Rotation is not None: plc.Rotation = App.Rotation(surface.Rotation) - # Now plc is the placement relative to the origin determined by the object placement. - # But it does not take into account Part placements. So if the solid is in a part and - # if the part has a placement then plc is wrong. + if hasattr(obj, "ExpandArray"): + # For draft arrays, the Shape has both the array placement and the base placement. + plc = obj.Base.Placement.inverse() * plc # change plc to be relative to the object placement. plc = obj.Placement.inverse() * plc @@ -1114,13 +1109,6 @@ def findPlacement(ref, ignoreVertex=False): plane = Part.Plane(plane_origin, plane_normal) plc.Rotation = App.Rotation(plane.Rotation) - # change plc to be relative to the origin of the document. - # global_plc = getGlobalPlacement(obj, part) - # plc = global_plc * plc - - # change plc to be relative to the assembly. - # plc = activeAssembly().Placement.inverse() * plc - return plc