Turn newly created redundant constraints with a label into references.
This is a fairly standard CAD feature; it conveys the same information and has the same recovery path, without erroring out, so seems like an obvious win.
This commit is contained in:
parent
c00ab25740
commit
43db2201fd
@ -22,6 +22,8 @@ New sketch features:
|
||||
drag the point from the source sketch.
|
||||
* When dragging an arc or rectangle point, it will be automatically
|
||||
constrained to other points with a click.
|
||||
* When adding a constraint which has a label and is redundant with another
|
||||
constraint, the constraint is added as a reference, avoiding an error.
|
||||
|
||||
New export/import features:
|
||||
* Three.js: allow configuring projection for exported model, and initially
|
||||
|
@ -733,6 +733,14 @@ void Constraint::MenuConstrain(Command id) {
|
||||
default: ssassert(false, "Unexpected menu ID");
|
||||
}
|
||||
|
||||
if(SK.constraint.FindByIdNoOops(c.h)) {
|
||||
Constraint *constraint = SK.GetConstraint(c.h);
|
||||
if(SS.TestRankForGroup(c.group) == SolveResult::REDUNDANT_OKAY &&
|
||||
constraint->HasLabel()) {
|
||||
constraint->reference = true;
|
||||
}
|
||||
}
|
||||
|
||||
SS.GW.ClearSelection();
|
||||
InvalidateGraphics();
|
||||
}
|
||||
|
@ -498,7 +498,7 @@ void SolveSpaceUI::SolveGroupAndReport(hGroup hg, bool andFindFree) {
|
||||
}
|
||||
}
|
||||
|
||||
void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
||||
void SolveSpaceUI::WriteEqSystemForGroup(hGroup hg) {
|
||||
int i;
|
||||
// Clear out the system to be solved.
|
||||
sys.entity.Clear();
|
||||
@ -528,6 +528,11 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
||||
}
|
||||
|
||||
MarkDraggedParams();
|
||||
}
|
||||
|
||||
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),
|
||||
&(g->solved.remove),
|
||||
@ -541,6 +546,15 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
||||
FreeAllTemporary();
|
||||
}
|
||||
|
||||
SolveResult SolveSpaceUI::TestRankForGroup(hGroup hg) {
|
||||
WriteEqSystemForGroup(hg);
|
||||
Group *g = SK.GetGroup(hg);
|
||||
SolveResult result = sys.SolveRank(g, NULL, NULL, false, false,
|
||||
/*forceDofCheck=*/!g->dofCheckOk);
|
||||
FreeAllTemporary();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SolveSpaceUI::ActiveGroupsOkay() {
|
||||
for(int i = 0; i < SK.groupOrder.n; i++) {
|
||||
Group *g = SK.GetGroup(SK.groupOrder.elem[i]);
|
||||
|
@ -397,9 +397,15 @@ public:
|
||||
|
||||
bool NewtonSolve(int tag);
|
||||
|
||||
void MarkParamsFree(bool findFree);
|
||||
int CalculateDof();
|
||||
|
||||
SolveResult Solve(Group *g, int *dof, List<hConstraint> *bad,
|
||||
bool andFindBad, bool andFindFree, bool forceDofCheck = false);
|
||||
|
||||
SolveResult SolveRank(Group *g, int *dof, List<hConstraint> *bad,
|
||||
bool andFindBad, bool andFindFree, bool forceDofCheck = false);
|
||||
|
||||
void Clear();
|
||||
};
|
||||
|
||||
@ -847,6 +853,8 @@ public:
|
||||
bool genForBBox = false);
|
||||
void SolveGroup(hGroup hg, bool andFindFree);
|
||||
void SolveGroupAndReport(hGroup hg, bool andFindFree);
|
||||
SolveResult TestRankForGroup(hGroup hg);
|
||||
void WriteEqSystemForGroup(hGroup hg);
|
||||
void MarkDraggedParams();
|
||||
void ForceReferences();
|
||||
|
||||
|
@ -475,28 +475,8 @@ SolveResult System::Solve(Group *g, int *dof, List<hConstraint> *bad,
|
||||
// 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 = mat.n - mat.m;
|
||||
|
||||
// If requested, find all the free (unbound) variables. This might be
|
||||
// more than the number of degrees of freedom. Don't always do this,
|
||||
// because the display would get annoying and it's slow.
|
||||
for(i = 0; i < param.n; i++) {
|
||||
Param *p = &(param.elem[i]);
|
||||
p->free = false;
|
||||
|
||||
if(andFindFree) {
|
||||
if(p->tag == 0) {
|
||||
p->tag = VAR_DOF_TEST;
|
||||
WriteJacobian(0);
|
||||
EvalJacobian();
|
||||
int rank = CalculateRank();
|
||||
if(rank == mat.m) {
|
||||
p->free = true;
|
||||
}
|
||||
p->tag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(dof) *dof = CalculateDof();
|
||||
MarkParamsFree(andFindFree);
|
||||
}
|
||||
// System solved correctly, so write the new values back in to the
|
||||
// main parameter table.
|
||||
@ -537,9 +517,71 @@ didnt_converge:
|
||||
return rankOk ? SolveResult::DIDNT_CONVERGE : SolveResult::REDUNDANT_DIDNT_CONVERGE;
|
||||
}
|
||||
|
||||
SolveResult System::SolveRank(Group *g, int *dof, List<hConstraint> *bad,
|
||||
bool andFindBad, bool andFindFree, bool forceDofCheck)
|
||||
{
|
||||
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g);
|
||||
|
||||
// All params and equations are assigned to group zero.
|
||||
param.ClearTags();
|
||||
eq.ClearTags();
|
||||
|
||||
if(!forceDofCheck) {
|
||||
SolveBySubstitution();
|
||||
}
|
||||
|
||||
// Now write the Jacobian, and do a rank test; that
|
||||
// tells us if the system is inconsistently constrained.
|
||||
if(!WriteJacobian(0)) {
|
||||
return SolveResult::TOO_MANY_UNKNOWNS;
|
||||
}
|
||||
|
||||
bool rankOk = TestRank();
|
||||
if(!rankOk) {
|
||||
if(!g->allowRedundant) {
|
||||
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, forceDofCheck);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
return rankOk ? SolveResult::OKAY : SolveResult::REDUNDANT_OKAY;
|
||||
}
|
||||
|
||||
void System::Clear() {
|
||||
entity.Clear();
|
||||
param.Clear();
|
||||
eq.Clear();
|
||||
dragged.Clear();
|
||||
}
|
||||
|
||||
void System::MarkParamsFree(bool find) {
|
||||
// If requested, find all the free (unbound) variables. This might be
|
||||
// more than the number of degrees of freedom. Don't always do this,
|
||||
// because the display would get annoying and it's slow.
|
||||
for(int i = 0; i < param.n; i++) {
|
||||
Param *p = &(param.elem[i]);
|
||||
p->free = false;
|
||||
|
||||
if(find) {
|
||||
if(p->tag == 0) {
|
||||
p->tag = VAR_DOF_TEST;
|
||||
WriteJacobian(0);
|
||||
EvalJacobian();
|
||||
int rank = CalculateRank();
|
||||
if(rank == mat.m) {
|
||||
p->free = true;
|
||||
}
|
||||
p->tag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int System::CalculateDof() {
|
||||
return mat.n - mat.m;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user