In TryConstrain(), reject redundant constraints in overconstrained groups.
This keeps groups with allowed redundant constraints cleaner when they are used together with automatic constraints.
This commit is contained in:
parent
549565958f
commit
cf2f0e5d44
@ -106,10 +106,16 @@ hConstraint Constraint::Constrain(Constraint::Type type, hEntity ptA, hEntity pt
|
|||||||
hConstraint Constraint::TryConstrain(Constraint::Type type, hEntity ptA, hEntity ptB,
|
hConstraint Constraint::TryConstrain(Constraint::Type type, hEntity ptA, hEntity ptB,
|
||||||
hEntity entityA, hEntity entityB,
|
hEntity entityA, hEntity entityB,
|
||||||
bool other, bool other2) {
|
bool other, bool other2) {
|
||||||
SolveResult solvedBefore = SS.TestRankForGroup(SS.GW.activeGroup);
|
int rankBefore, rankAfter;
|
||||||
|
SolveResult howBefore = SS.TestRankForGroup(SS.GW.activeGroup, &rankBefore);
|
||||||
hConstraint hc = Constrain(type, ptA, ptB, entityA, entityB, other, other2);
|
hConstraint hc = Constrain(type, ptA, ptB, entityA, entityB, other, other2);
|
||||||
SolveResult solvedAfter = SS.TestRankForGroup(SS.GW.activeGroup);
|
SolveResult howAfter = SS.TestRankForGroup(SS.GW.activeGroup, &rankAfter);
|
||||||
if(solvedBefore == SolveResult::OKAY && solvedAfter == SolveResult::REDUNDANT_OKAY) {
|
// There are two cases where the constraint is clearly redundant:
|
||||||
|
// * If the group wasn't overconstrained and now it is;
|
||||||
|
// * If the group was overconstrained, and adding the constraint doesn't change rank at all.
|
||||||
|
if((howBefore == SolveResult::OKAY && howAfter == SolveResult::REDUNDANT_OKAY) ||
|
||||||
|
(howBefore == SolveResult::REDUNDANT_OKAY && howAfter == SolveResult::REDUNDANT_OKAY &&
|
||||||
|
rankBefore == rankAfter)) {
|
||||||
SK.constraint.RemoveById(hc);
|
SK.constraint.RemoveById(hc);
|
||||||
hc = {};
|
hc = {};
|
||||||
}
|
}
|
||||||
|
@ -539,7 +539,8 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
|||||||
WriteEqSystemForGroup(hg);
|
WriteEqSystemForGroup(hg);
|
||||||
Group *g = SK.GetGroup(hg);
|
Group *g = SK.GetGroup(hg);
|
||||||
g->solved.remove.Clear();
|
g->solved.remove.Clear();
|
||||||
SolveResult how = sys.Solve(g, &(g->solved.dof),
|
SolveResult how = sys.Solve(g, NULL,
|
||||||
|
&(g->solved.dof),
|
||||||
&(g->solved.remove),
|
&(g->solved.remove),
|
||||||
/*andFindBad=*/true,
|
/*andFindBad=*/true,
|
||||||
/*andFindFree=*/andFindFree,
|
/*andFindFree=*/andFindFree,
|
||||||
@ -551,12 +552,10 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
|||||||
FreeAllTemporary();
|
FreeAllTemporary();
|
||||||
}
|
}
|
||||||
|
|
||||||
SolveResult SolveSpaceUI::TestRankForGroup(hGroup hg) {
|
SolveResult SolveSpaceUI::TestRankForGroup(hGroup hg, int *rank) {
|
||||||
WriteEqSystemForGroup(hg);
|
WriteEqSystemForGroup(hg);
|
||||||
Group *g = SK.GetGroup(hg);
|
Group *g = SK.GetGroup(hg);
|
||||||
SolveResult result = sys.SolveRank(g, NULL, NULL,
|
SolveResult result = sys.SolveRank(g, rank);
|
||||||
/*andFindBad=*/false,
|
|
||||||
/*andFindFree=*/false);
|
|
||||||
FreeAllTemporary();
|
FreeAllTemporary();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -289,7 +289,7 @@ public:
|
|||||||
|
|
||||||
static const double RANK_MAG_TOLERANCE, CONVERGE_TOLERANCE;
|
static const double RANK_MAG_TOLERANCE, CONVERGE_TOLERANCE;
|
||||||
int CalculateRank();
|
int CalculateRank();
|
||||||
bool TestRank();
|
bool TestRank(int *rank = NULL);
|
||||||
static bool SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
|
static bool SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
|
||||||
double B[], int N);
|
double B[], int N);
|
||||||
bool SolveLeastSquares();
|
bool SolveLeastSquares();
|
||||||
@ -308,11 +308,14 @@ public:
|
|||||||
void MarkParamsFree(bool findFree);
|
void MarkParamsFree(bool findFree);
|
||||||
int CalculateDof();
|
int CalculateDof();
|
||||||
|
|
||||||
SolveResult Solve(Group *g, int *dof, List<hConstraint> *bad,
|
SolveResult Solve(Group *g, int *rank = NULL, int *dof = NULL,
|
||||||
bool andFindBad, bool andFindFree, bool forceDofCheck = false);
|
List<hConstraint> *bad = NULL,
|
||||||
|
bool andFindBad = false, bool andFindFree = false,
|
||||||
|
bool forceDofCheck = false);
|
||||||
|
|
||||||
SolveResult SolveRank(Group *g, int *dof, List<hConstraint> *bad,
|
SolveResult SolveRank(Group *g, int *rank = NULL, int *dof = NULL,
|
||||||
bool andFindBad, bool andFindFree);
|
List<hConstraint> *bad = NULL,
|
||||||
|
bool andFindBad = false, bool andFindFree = false);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
};
|
};
|
||||||
@ -776,7 +779,7 @@ public:
|
|||||||
bool genForBBox = false);
|
bool genForBBox = false);
|
||||||
void SolveGroup(hGroup hg, bool andFindFree);
|
void SolveGroup(hGroup hg, bool andFindFree);
|
||||||
void SolveGroupAndReport(hGroup hg, bool andFindFree);
|
void SolveGroupAndReport(hGroup hg, bool andFindFree);
|
||||||
SolveResult TestRankForGroup(hGroup hg);
|
SolveResult TestRankForGroup(hGroup hg, int *rank = NULL);
|
||||||
void WriteEqSystemForGroup(hGroup hg);
|
void WriteEqSystemForGroup(hGroup hg);
|
||||||
void MarkDraggedParams();
|
void MarkDraggedParams();
|
||||||
void ForceReferences();
|
void ForceReferences();
|
||||||
|
@ -170,9 +170,11 @@ int System::CalculateRank() {
|
|||||||
return rank;
|
return rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::TestRank() {
|
bool System::TestRank(int *rank) {
|
||||||
EvalJacobian();
|
EvalJacobian();
|
||||||
return CalculateRank() == mat.m;
|
int jacobianRank = CalculateRank();
|
||||||
|
if(rank) *rank = jacobianRank;
|
||||||
|
return jacobianRank == mat.m;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
|
bool System::SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
|
||||||
@ -396,7 +398,7 @@ void System::FindWhichToRemoveToFixJacobian(Group *g, List<hConstraint> *bad, bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SolveResult System::Solve(Group *g, int *dof, List<hConstraint> *bad,
|
SolveResult System::Solve(Group *g, int *rank, int *dof, List<hConstraint> *bad,
|
||||||
bool andFindBad, bool andFindFree, bool forceDofCheck)
|
bool andFindBad, bool andFindFree, bool forceDofCheck)
|
||||||
{
|
{
|
||||||
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g);
|
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g);
|
||||||
@ -459,14 +461,14 @@ SolveResult System::Solve(Group *g, int *dof, List<hConstraint> *bad,
|
|||||||
return SolveResult::TOO_MANY_UNKNOWNS;
|
return SolveResult::TOO_MANY_UNKNOWNS;
|
||||||
}
|
}
|
||||||
|
|
||||||
rankOk = TestRank();
|
rankOk = TestRank(rank);
|
||||||
|
|
||||||
// And do the leftovers as one big system
|
// And do the leftovers as one big system
|
||||||
if(!NewtonSolve(0)) {
|
if(!NewtonSolve(0)) {
|
||||||
goto didnt_converge;
|
goto didnt_converge;
|
||||||
}
|
}
|
||||||
|
|
||||||
rankOk = TestRank();
|
rankOk = TestRank(rank);
|
||||||
if(!rankOk) {
|
if(!rankOk) {
|
||||||
if(!g->allowRedundant) {
|
if(!g->allowRedundant) {
|
||||||
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, forceDofCheck);
|
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, forceDofCheck);
|
||||||
@ -517,7 +519,7 @@ didnt_converge:
|
|||||||
return rankOk ? SolveResult::DIDNT_CONVERGE : SolveResult::REDUNDANT_DIDNT_CONVERGE;
|
return rankOk ? SolveResult::DIDNT_CONVERGE : SolveResult::REDUNDANT_DIDNT_CONVERGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SolveResult System::SolveRank(Group *g, int *dof, List<hConstraint> *bad,
|
SolveResult System::SolveRank(Group *g, int *rank, int *dof, List<hConstraint> *bad,
|
||||||
bool andFindBad, bool andFindFree)
|
bool andFindBad, bool andFindFree)
|
||||||
{
|
{
|
||||||
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g);
|
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g);
|
||||||
@ -532,15 +534,12 @@ SolveResult System::SolveRank(Group *g, int *dof, List<hConstraint> *bad,
|
|||||||
return SolveResult::TOO_MANY_UNKNOWNS;
|
return SolveResult::TOO_MANY_UNKNOWNS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rankOk = TestRank();
|
bool rankOk = TestRank(rank);
|
||||||
if(!rankOk) {
|
if(!rankOk) {
|
||||||
if(!g->allowRedundant) {
|
if(!g->allowRedundant) {
|
||||||
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, /*forceDofCheck=*/true);
|
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, /*forceDofCheck=*/true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is not the full Jacobian, but any substitutions or single-eq
|
|
||||||
// solves removed one equation and one unknown, therefore no effect
|
|
||||||
// on the number of DOF.
|
|
||||||
if(dof) *dof = CalculateDof();
|
if(dof) *dof = CalculateDof();
|
||||||
MarkParamsFree(andFindFree);
|
MarkParamsFree(andFindFree);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user