Skip to content

Commit

Permalink
In TryConstrain(), reject redundant constraints in overconstrained gr…
Browse files Browse the repository at this point in the history
…oups.

This keeps groups with allowed redundant constraints cleaner when
they are used together with automatic constraints.
  • Loading branch information
whitequark committed May 24, 2019
1 parent 5495659 commit cf2f0e5
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 24 deletions.
12 changes: 9 additions & 3 deletions src/constraint.cpp
Expand Up @@ -106,10 +106,16 @@ hConstraint Constraint::Constrain(Constraint::Type type, hEntity ptA, hEntity pt
hConstraint Constraint::TryConstrain(Constraint::Type type, hEntity ptA, hEntity ptB,
hEntity entityA, hEntity entityB,
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);
SolveResult solvedAfter = SS.TestRankForGroup(SS.GW.activeGroup);
if(solvedBefore == SolveResult::OKAY && solvedAfter == SolveResult::REDUNDANT_OKAY) {
SolveResult howAfter = SS.TestRankForGroup(SS.GW.activeGroup, &rankAfter);
// 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);
hc = {};
}
Expand Down
9 changes: 4 additions & 5 deletions src/generate.cpp
Expand Up @@ -539,7 +539,8 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
WriteEqSystemForGroup(hg);
Group *g = SK.GetGroup(hg);
g->solved.remove.Clear();
SolveResult how = sys.Solve(g, &(g->solved.dof),
SolveResult how = sys.Solve(g, NULL,
&(g->solved.dof),
&(g->solved.remove),
/*andFindBad=*/true,
/*andFindFree=*/andFindFree,
Expand All @@ -551,12 +552,10 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
FreeAllTemporary();
}

SolveResult SolveSpaceUI::TestRankForGroup(hGroup hg) {
SolveResult SolveSpaceUI::TestRankForGroup(hGroup hg, int *rank) {
WriteEqSystemForGroup(hg);
Group *g = SK.GetGroup(hg);
SolveResult result = sys.SolveRank(g, NULL, NULL,
/*andFindBad=*/false,
/*andFindFree=*/false);
SolveResult result = sys.SolveRank(g, rank);
FreeAllTemporary();
return result;
}
Expand Down
15 changes: 9 additions & 6 deletions src/solvespace.h
Expand Up @@ -289,7 +289,7 @@ class System {

static const double RANK_MAG_TOLERANCE, CONVERGE_TOLERANCE;
int CalculateRank();
bool TestRank();
bool TestRank(int *rank = NULL);
static bool SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
double B[], int N);
bool SolveLeastSquares();
Expand All @@ -308,11 +308,14 @@ class System {
void MarkParamsFree(bool findFree);
int CalculateDof();

SolveResult Solve(Group *g, int *dof, List<hConstraint> *bad,
bool andFindBad, bool andFindFree, bool forceDofCheck = false);
SolveResult Solve(Group *g, int *rank = NULL, int *dof = NULL,
List<hConstraint> *bad = NULL,
bool andFindBad = false, bool andFindFree = false,
bool forceDofCheck = false);

SolveResult SolveRank(Group *g, int *dof, List<hConstraint> *bad,
bool andFindBad, bool andFindFree);
SolveResult SolveRank(Group *g, int *rank = NULL, int *dof = NULL,
List<hConstraint> *bad = NULL,
bool andFindBad = false, bool andFindFree = false);

void Clear();
};
Expand Down Expand Up @@ -776,7 +779,7 @@ class SolveSpaceUI {
bool genForBBox = false);
void SolveGroup(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 MarkDraggedParams();
void ForceReferences();
Expand Down
19 changes: 9 additions & 10 deletions src/system.cpp
Expand Up @@ -170,9 +170,11 @@ int System::CalculateRank() {
return rank;
}

bool System::TestRank() {
bool System::TestRank(int *rank) {
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],
Expand Down Expand Up @@ -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)
{
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g);
Expand Down Expand Up @@ -459,14 +461,14 @@ SolveResult System::Solve(Group *g, int *dof, List<hConstraint> *bad,
return SolveResult::TOO_MANY_UNKNOWNS;
}

rankOk = TestRank();
rankOk = TestRank(rank);

// And do the leftovers as one big system
if(!NewtonSolve(0)) {
goto didnt_converge;
}

rankOk = TestRank();
rankOk = TestRank(rank);
if(!rankOk) {
if(!g->allowRedundant) {
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, forceDofCheck);
Expand Down Expand Up @@ -517,7 +519,7 @@ SolveResult System::Solve(Group *g, int *dof, List<hConstraint> *bad,
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)
{
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g);
Expand All @@ -532,15 +534,12 @@ SolveResult System::SolveRank(Group *g, int *dof, List<hConstraint> *bad,
return SolveResult::TOO_MANY_UNKNOWNS;
}

bool rankOk = TestRank();
bool rankOk = TestRank(rank);
if(!rankOk) {
if(!g->allowRedundant) {
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, /*forceDofCheck=*/true);
}
} 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();
MarkParamsFree(andFindFree);
}
Expand Down

0 comments on commit cf2f0e5

Please sign in to comment.