cherry-pick #1: initial Kindred branding + assembly joint fix
Cherry-picked 316d4f4b52 with conflict resolution:
- CMakeLists.txt: merged Kindred version vars with upstream 1.2.0-dev base
- src/Main/*.cpp: applied Kindred branding (banner, copyright, license)
- Resolved add/add conflicts for files already copied in Phase 1
- Includes assembly joint flip overconstrain fix
This commit is contained in:
@@ -165,9 +165,8 @@ int AssemblyObject::solve(bool enableRedo, bool updateJCS)
|
||||
|
||||
jointParts(joints);
|
||||
|
||||
if (enableRedo) {
|
||||
savePlacementsForUndo();
|
||||
}
|
||||
// Always save placements to enable orientation flip detection
|
||||
savePlacementsForUndo();
|
||||
|
||||
try {
|
||||
mbdAssembly->runPreDrag();
|
||||
@@ -186,8 +185,22 @@ int AssemblyObject::solve(bool enableRedo, bool updateJCS)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Validate that the solve didn't cause any parts to flip orientation
|
||||
if (!validateNewPlacements()) {
|
||||
// Restore previous placements - the solve found an invalid configuration
|
||||
undoSolve();
|
||||
lastSolverStatus = -2;
|
||||
updateSolveStatus();
|
||||
return -2;
|
||||
}
|
||||
|
||||
setNewPlacements();
|
||||
|
||||
// Clear undo history if the caller didn't want redo capability
|
||||
if (!enableRedo) {
|
||||
clearUndo();
|
||||
}
|
||||
|
||||
redrawJointPlacements(joints);
|
||||
|
||||
updateSolveStatus();
|
||||
@@ -480,8 +493,56 @@ bool AssemblyObject::validateNewPlacements()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: We could do further tests
|
||||
// For example check if the joints connectors are correctly aligned.
|
||||
// Check if any part has flipped orientation (rotation > 90 degrees from original)
|
||||
// This prevents joints from "breaking" when the solver finds an alternate configuration
|
||||
for (const auto& savedPair : previousPositions) {
|
||||
App::DocumentObject* obj = savedPair.first;
|
||||
if (!obj) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = objectPartMap.find(obj);
|
||||
if (it == objectPartMap.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::shared_ptr<MbD::ASMTPart> mbdPart = it->second.part;
|
||||
if (!mbdPart) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Base::Placement newPlacement = getMbdPlacement(mbdPart);
|
||||
if (!it->second.offsetPlc.isIdentity()) {
|
||||
newPlacement = newPlacement * it->second.offsetPlc;
|
||||
}
|
||||
|
||||
const Base::Placement& oldPlc = savedPair.second;
|
||||
|
||||
// Calculate the rotation difference between old and new orientations
|
||||
Base::Rotation oldRot = oldPlc.getRotation();
|
||||
Base::Rotation newRot = newPlacement.getRotation();
|
||||
|
||||
// Get the relative rotation: how much did the part rotate?
|
||||
Base::Rotation relativeRot = newRot * oldRot.inverse();
|
||||
|
||||
// Get the angle of this rotation
|
||||
Base::Vector3d axis;
|
||||
double angle;
|
||||
relativeRot.getRawValue(axis, angle);
|
||||
|
||||
// If the part rotated more than 90 degrees, consider it a flip
|
||||
// Use 91 degrees to allow for small numerical errors
|
||||
constexpr double maxAngle = 91.0 * M_PI / 180.0;
|
||||
if (std::abs(angle) > maxAngle) {
|
||||
Base::Console().warning(
|
||||
"Assembly : Ignoring bad solve, part (%s) flipped orientation (%.1f degrees).\n",
|
||||
obj->getFullLabel(),
|
||||
std::abs(angle) * 180.0 / M_PI
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user