diff --git a/src/Mod/Assembly/App/AssemblyUtils.cpp b/src/Mod/Assembly/App/AssemblyUtils.cpp index 852dff3799..064b777ce0 100644 --- a/src/Mod/Assembly/App/AssemblyUtils.cpp +++ b/src/Mod/Assembly/App/AssemblyUtils.cpp @@ -177,23 +177,33 @@ DistanceType getDistanceType(App::DocumentObject* joint) } // One side is a datum plane, the other has a real element type. - // Ensure the datum (plane) side is Reference1 for consistent - // convention (face/plane first), matching the existing swap logic. + // For PointPlane/LinePlane, the solver's PointInPlaneConstraint + // reads the plane normal from marker_j (Reference2). Unlike + // real Face+Vertex joints (where both Placements carry the + // face normal from findPlacement), datum planes only carry + // their normal through computeMarkerTransform. So the datum + // must end up on Reference2 for the normal to reach marker_j. + // + // For PlanePlane the convention matches the existing Face+Face + // path (plane on Reference1). const auto& otherType = datum1 ? type2 : type1; - if (!datum1) { - swapJCS(joint); - } - if (otherType == "Vertex") { - return DistanceType::PointPlane; - } - if (otherType == "Edge") { + if (otherType == "Vertex" || otherType == "Edge") { + // Datum must be on Reference2 (j side). + if (datum1) { + swapJCS(joint); // move datum from Ref1 → Ref2 + } + if (otherType == "Vertex") { + return DistanceType::PointPlane; + } return DistanceType::LinePlane; } - if (otherType == "Face") { - return DistanceType::PlanePlane; - } - // Unknown element + datum plane → best-effort planar + + // Face + datum or unknown + datum → PlanePlane. + // No swap needed: PlanarConstraint is symmetric (uses both + // z_i and z_j), and preserving the original Reference order + // keeps the initial Placement values consistent so the solver + // stays in the correct orientation branch. return DistanceType::PlanePlane; }