fix(assembly): classify datum plane references in Distance joints
Some checks failed
Build and Test / build (pull_request) Has been cancelled
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:
@@ -54,10 +54,56 @@
|
||||
|
||||
namespace PartApp = Part;
|
||||
|
||||
FC_LOG_LEVEL_INIT("Assembly", true, true, true)
|
||||
|
||||
// ======================================= Utils ======================================
|
||||
namespace Assembly
|
||||
{
|
||||
|
||||
const char* distanceTypeName(DistanceType dt)
|
||||
{
|
||||
switch (dt) {
|
||||
case DistanceType::PointPoint: return "PointPoint";
|
||||
case DistanceType::LineLine: return "LineLine";
|
||||
case DistanceType::LineCircle: return "LineCircle";
|
||||
case DistanceType::CircleCircle: return "CircleCircle";
|
||||
case DistanceType::PlanePlane: return "PlanePlane";
|
||||
case DistanceType::PlaneCylinder: return "PlaneCylinder";
|
||||
case DistanceType::PlaneSphere: return "PlaneSphere";
|
||||
case DistanceType::PlaneCone: return "PlaneCone";
|
||||
case DistanceType::PlaneTorus: return "PlaneTorus";
|
||||
case DistanceType::CylinderCylinder: return "CylinderCylinder";
|
||||
case DistanceType::CylinderSphere: return "CylinderSphere";
|
||||
case DistanceType::CylinderCone: return "CylinderCone";
|
||||
case DistanceType::CylinderTorus: return "CylinderTorus";
|
||||
case DistanceType::ConeCone: return "ConeCone";
|
||||
case DistanceType::ConeTorus: return "ConeTorus";
|
||||
case DistanceType::ConeSphere: return "ConeSphere";
|
||||
case DistanceType::TorusTorus: return "TorusTorus";
|
||||
case DistanceType::TorusSphere: return "TorusSphere";
|
||||
case DistanceType::SphereSphere: return "SphereSphere";
|
||||
case DistanceType::PointPlane: return "PointPlane";
|
||||
case DistanceType::PointCylinder: return "PointCylinder";
|
||||
case DistanceType::PointSphere: return "PointSphere";
|
||||
case DistanceType::PointCone: return "PointCone";
|
||||
case DistanceType::PointTorus: return "PointTorus";
|
||||
case DistanceType::LinePlane: return "LinePlane";
|
||||
case DistanceType::LineCylinder: return "LineCylinder";
|
||||
case DistanceType::LineSphere: return "LineSphere";
|
||||
case DistanceType::LineCone: return "LineCone";
|
||||
case DistanceType::LineTorus: return "LineTorus";
|
||||
case DistanceType::CurvePlane: return "CurvePlane";
|
||||
case DistanceType::CurveCylinder: return "CurveCylinder";
|
||||
case DistanceType::CurveSphere: return "CurveSphere";
|
||||
case DistanceType::CurveCone: return "CurveCone";
|
||||
case DistanceType::CurveTorus: return "CurveTorus";
|
||||
case DistanceType::PointLine: return "PointLine";
|
||||
case DistanceType::PointCurve: return "PointCurve";
|
||||
case DistanceType::Other: return "Other";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
void swapJCS(const App::DocumentObject* joint)
|
||||
{
|
||||
if (!joint) {
|
||||
@@ -173,6 +219,8 @@ DistanceType getDistanceType(App::DocumentObject* joint)
|
||||
|
||||
if (datum1 || datum2) {
|
||||
if (datum1 && datum2) {
|
||||
FC_LOG("Assembly : getDistanceType('" << joint->getFullName()
|
||||
<< "') — datum+datum → PlanePlane");
|
||||
return DistanceType::PlanePlane;
|
||||
}
|
||||
|
||||
@@ -193,17 +241,22 @@ DistanceType getDistanceType(App::DocumentObject* joint)
|
||||
if (datum1) {
|
||||
swapJCS(joint); // move datum from Ref1 → Ref2
|
||||
}
|
||||
if (otherType == "Vertex") {
|
||||
return DistanceType::PointPlane;
|
||||
}
|
||||
return DistanceType::LinePlane;
|
||||
DistanceType result = (otherType == "Vertex")
|
||||
? DistanceType::PointPlane : DistanceType::LinePlane;
|
||||
FC_LOG("Assembly : getDistanceType('" << joint->getFullName()
|
||||
<< "') — datum+" << otherType << " → "
|
||||
<< distanceTypeName(result)
|
||||
<< (datum1 ? " (swapped)" : ""));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Face + datum or unknown + datum → PlanePlane
|
||||
// Datum on Reference1 for consistency with Face+Face path.
|
||||
if (!datum1) {
|
||||
swapJCS(joint); // move datum from Ref2 → Ref1
|
||||
}
|
||||
// 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.
|
||||
FC_LOG("Assembly : getDistanceType('" << joint->getFullName()
|
||||
<< "') — datum+" << otherType << " → PlanePlane");
|
||||
return DistanceType::PlanePlane;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user