fix(assembly): classify datum plane references in Distance joints
All checks were successful
Build and Test / build (pull_request) Successful in 41m13s
All checks were successful
Build and Test / build (pull_request) Successful in 41m13s
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:
@@ -164,6 +164,39 @@ DistanceType getDistanceType(App::DocumentObject* joint)
|
||||
auto* obj1 = getLinkedObjFromRef(joint, "Reference1");
|
||||
auto* obj2 = getLinkedObjFromRef(joint, "Reference2");
|
||||
|
||||
// Datum planes (App::Plane) have empty element types because their
|
||||
// sub-name ends with "." and yields no Face/Edge/Vertex element.
|
||||
// Detect them here and classify before the main geometry chain,
|
||||
// which cannot handle the empty element type.
|
||||
const bool datum1 = type1.empty() && obj1 && obj1->isDerivedFrom<App::Plane>();
|
||||
const bool datum2 = type2.empty() && obj2 && obj2->isDerivedFrom<App::Plane>();
|
||||
|
||||
if (datum1 || datum2) {
|
||||
if (datum1 && datum2) {
|
||||
return DistanceType::PlanePlane;
|
||||
}
|
||||
|
||||
// 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.
|
||||
const auto& otherType = datum1 ? type2 : type1;
|
||||
if (!datum1) {
|
||||
swapJCS(joint);
|
||||
}
|
||||
|
||||
if (otherType == "Vertex") {
|
||||
return DistanceType::PointPlane;
|
||||
}
|
||||
if (otherType == "Edge") {
|
||||
return DistanceType::LinePlane;
|
||||
}
|
||||
if (otherType == "Face") {
|
||||
return DistanceType::PlanePlane;
|
||||
}
|
||||
// Unknown element + datum plane → best-effort planar
|
||||
return DistanceType::PlanePlane;
|
||||
}
|
||||
|
||||
if (type1 == "Vertex" && type2 == "Vertex") {
|
||||
return DistanceType::PointPoint;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user