Merge pull request 'feat(assembly): add diagnostic logging to solver and assembly' (#313) from feat/solver-diagnostic-logging into main
Some checks failed
Build and Test / build (push) Has been cancelled
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #313
This commit was merged in pull request #313.
This commit is contained in:
@@ -176,6 +176,10 @@ KCSolve::IKCSolver* AssemblyObject::getOrCreateSolver()
|
||||
std::string solverName = hGrp->GetASCII("Solver", "");
|
||||
solver_ = KCSolve::SolverRegistry::instance().get(solverName);
|
||||
// get("") returns the registry default (first registered solver)
|
||||
if (solver_) {
|
||||
FC_LOG("Assembly : loaded solver '" << solver_->name()
|
||||
<< "' (requested='" << solverName << "')");
|
||||
}
|
||||
}
|
||||
return solver_.get();
|
||||
}
|
||||
@@ -212,14 +216,22 @@ int AssemblyObject::solve(bool enableRedo, bool updateJCS)
|
||||
|
||||
auto groundedObjs = getGroundedParts();
|
||||
if (groundedObjs.empty()) {
|
||||
FC_LOG("Assembly : solve skipped — no grounded parts");
|
||||
return -6;
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> joints = getJoints(updateJCS);
|
||||
removeUnconnectedJoints(joints, groundedObjs);
|
||||
|
||||
FC_LOG("Assembly : solve on '" << getFullLabel()
|
||||
<< "' — " << groundedObjs.size() << " grounded, "
|
||||
<< joints.size() << " joints");
|
||||
|
||||
KCSolve::SolveContext ctx = buildSolveContext(joints);
|
||||
|
||||
FC_LOG("Assembly : solve context — " << ctx.parts.size() << " parts, "
|
||||
<< ctx.constraints.size() << " constraints");
|
||||
|
||||
// Always save placements to enable orientation flip detection
|
||||
savePlacementsForUndo();
|
||||
|
||||
@@ -241,6 +253,13 @@ int AssemblyObject::solve(bool enableRedo, bool updateJCS)
|
||||
}
|
||||
|
||||
if (lastResult_.status == KCSolve::SolveStatus::Failed) {
|
||||
FC_LOG("Assembly : solve failed — status="
|
||||
<< static_cast<int>(lastResult_.status)
|
||||
<< ", " << lastResult_.diagnostics.size() << " diagnostics");
|
||||
for (const auto& d : lastResult_.diagnostics) {
|
||||
Base::Console().warning("Assembly : diagnostic [%s]: %s\n",
|
||||
d.constraint_id.c_str(), d.detail.c_str());
|
||||
}
|
||||
updateSolveStatus();
|
||||
return -1;
|
||||
}
|
||||
@@ -248,6 +267,7 @@ int AssemblyObject::solve(bool enableRedo, bool updateJCS)
|
||||
// Validate that the solve didn't cause any parts to flip orientation
|
||||
if (!validateNewPlacements()) {
|
||||
// Restore previous placements - the solve found an invalid configuration
|
||||
FC_LOG("Assembly : solve rejected — placement validation failed, undoing");
|
||||
undoSolve();
|
||||
lastSolverStatus = -2;
|
||||
updateSolveStatus();
|
||||
@@ -265,6 +285,9 @@ int AssemblyObject::solve(bool enableRedo, bool updateJCS)
|
||||
|
||||
updateSolveStatus();
|
||||
|
||||
FC_LOG("Assembly : solve succeeded — dof=" << lastResult_.dof
|
||||
<< ", " << lastResult_.placements.size() << " placements");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -415,6 +438,8 @@ size_t Assembly::AssemblyObject::numberOfFrames()
|
||||
void AssemblyObject::preDrag(std::vector<App::DocumentObject*> dragParts)
|
||||
{
|
||||
bundleFixed = true;
|
||||
dragStepCount_ = 0;
|
||||
dragStepRejected_ = 0;
|
||||
|
||||
auto* solver = getOrCreateSolver();
|
||||
if (!solver) {
|
||||
@@ -427,6 +452,7 @@ void AssemblyObject::preDrag(std::vector<App::DocumentObject*> dragParts)
|
||||
|
||||
auto groundedObjs = getGroundedParts();
|
||||
if (groundedObjs.empty()) {
|
||||
FC_LOG("Assembly : preDrag skipped — no grounded parts");
|
||||
bundleFixed = false;
|
||||
return;
|
||||
}
|
||||
@@ -480,6 +506,10 @@ void AssemblyObject::preDrag(std::vector<App::DocumentObject*> dragParts)
|
||||
}
|
||||
}
|
||||
|
||||
FC_LOG("Assembly : preDrag — " << dragPartIds.size() << " drag part(s), "
|
||||
<< joints.size() << " joints, " << ctx.parts.size() << " parts, "
|
||||
<< ctx.constraints.size() << " constraints");
|
||||
|
||||
savePlacementsForUndo();
|
||||
|
||||
try {
|
||||
@@ -488,11 +518,13 @@ void AssemblyObject::preDrag(std::vector<App::DocumentObject*> dragParts)
|
||||
}
|
||||
catch (...) {
|
||||
// If pre_drag fails, we still need to be in a valid state
|
||||
FC_LOG("Assembly : preDrag — solver pre_drag threw exception");
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyObject::doDragStep()
|
||||
{
|
||||
dragStepCount_++;
|
||||
try {
|
||||
std::vector<KCSolve::SolveResult::PartResult> dragPlacements;
|
||||
|
||||
@@ -512,6 +544,10 @@ void AssemblyObject::doDragStep()
|
||||
|
||||
lastResult_ = solver_->drag_step(dragPlacements);
|
||||
|
||||
if (lastResult_.status == KCSolve::SolveStatus::Failed) {
|
||||
FC_LOG("Assembly : dragStep #" << dragStepCount_ << " — solver failed");
|
||||
}
|
||||
|
||||
if (validateNewPlacements()) {
|
||||
setNewPlacements();
|
||||
|
||||
@@ -531,9 +567,12 @@ void AssemblyObject::doDragStep()
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
dragStepRejected_++;
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
// We do nothing if a solve step fails.
|
||||
FC_LOG("Assembly : dragStep #" << dragStepCount_ << " — exception");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,6 +684,8 @@ bool AssemblyObject::validateNewPlacements()
|
||||
|
||||
void AssemblyObject::postDrag()
|
||||
{
|
||||
FC_LOG("Assembly : postDrag — " << dragStepCount_ << " steps, "
|
||||
<< dragStepRejected_ << " rejected");
|
||||
if (solver_) {
|
||||
solver_->post_drag();
|
||||
}
|
||||
@@ -1356,6 +1397,23 @@ KCSolve::SolveContext AssemblyObject::buildSolveContext(
|
||||
ctx.simulation = sp;
|
||||
}
|
||||
|
||||
// Log context summary
|
||||
{
|
||||
int nGrounded = 0, nFree = 0, nLimits = 0;
|
||||
for (const auto& p : ctx.parts) {
|
||||
if (p.grounded) nGrounded++;
|
||||
else nFree++;
|
||||
}
|
||||
for (const auto& c : ctx.constraints) {
|
||||
if (!c.limits.empty()) nLimits++;
|
||||
}
|
||||
FC_LOG("Assembly : buildSolveContext — "
|
||||
<< nGrounded << " grounded + " << nFree << " free parts, "
|
||||
<< ctx.constraints.size() << " constraints"
|
||||
<< (nLimits ? (std::string(", ") + std::to_string(nLimits) + " with limits") : "")
|
||||
<< (ctx.bundle_fixed ? ", bundle_fixed=true" : ""));
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user