fix(assembly): classify datum plane references in Distance joints
Some checks failed
Build and Test / build (pull_request) Has been cancelled

When a Distance joint references a datum plane (XY_Plane, XZ_Plane,
YZ_Plane), getDistanceType() failed to recognize it because datum
plane sub-names yield an empty element type. This caused the fallback
to DistanceType::Other → BaseJointKind::Planar, which adds spurious
parallel-normal residuals that overconstrain the system.

For example, three vertex-to-datum-plane Distance joints produced
10 residuals (3×Planar) with 6 mutually contradictory orientation
constraints, causing the solver to find garbage least-squares
solutions.

Add early detection of App::Plane datum objects before the main
geometry classification chain. Datum planes are now correctly mapped:
- Vertex + DatumPlane → PointPlane → PointInPlane (1 residual)
- Edge + DatumPlane → LinePlane → LineInPlane
- Face/DatumPlane + DatumPlane → PlanePlane → Planar
This commit is contained in:
forbes
2026-02-21 22:04:18 -06:00
parent 58d98c6d92
commit e5b07449d7

View File

@@ -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;
// Face + datum or unknown + datum → PlanePlane
// Datum on Reference1 for consistency with Face+Face path.
if (!datum1) {
swapJCS(joint); // move datum from Ref2 → Ref1
}
// Unknown element + datum plane → best-effort planar
return DistanceType::PlanePlane;
}