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.
|
drag the point from the source sketch.
|
||||||
* When dragging an arc or rectangle point, it will be automatically
|
* When dragging an arc or rectangle point, it will be automatically
|
||||||
constrained to other points with a click.
|
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:
|
New export/import features:
|
||||||
* Three.js: allow configuring projection for exported model, and initially
|
* 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");
|
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();
|
SS.GW.ClearSelection();
|
||||||
InvalidateGraphics();
|
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;
|
int i;
|
||||||
// Clear out the system to be solved.
|
// Clear out the system to be solved.
|
||||||
sys.entity.Clear();
|
sys.entity.Clear();
|
||||||
|
@ -528,6 +528,11 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkDraggedParams();
|
MarkDraggedParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
||||||
|
WriteEqSystemForGroup(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, &(g->solved.dof),
|
||||||
&(g->solved.remove),
|
&(g->solved.remove),
|
||||||
|
@ -541,6 +546,15 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
||||||
FreeAllTemporary();
|
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() {
|
bool SolveSpaceUI::ActiveGroupsOkay() {
|
||||||
for(int i = 0; i < SK.groupOrder.n; i++) {
|
for(int i = 0; i < SK.groupOrder.n; i++) {
|
||||||
Group *g = SK.GetGroup(SK.groupOrder.elem[i]);
|
Group *g = SK.GetGroup(SK.groupOrder.elem[i]);
|
||||||
|
|
|
@ -397,9 +397,15 @@ public:
|
||||||
|
|
||||||
bool NewtonSolve(int tag);
|
bool NewtonSolve(int tag);
|
||||||
|
|
||||||
|
void MarkParamsFree(bool findFree);
|
||||||
|
int CalculateDof();
|
||||||
|
|
||||||
SolveResult Solve(Group *g, int *dof, List<hConstraint> *bad,
|
SolveResult Solve(Group *g, int *dof, List<hConstraint> *bad,
|
||||||
bool andFindBad, bool andFindFree, bool forceDofCheck = false);
|
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();
|
void Clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -847,6 +853,8 @@ 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);
|
||||||
|
void WriteEqSystemForGroup(hGroup hg);
|
||||||
void MarkDraggedParams();
|
void MarkDraggedParams();
|
||||||
void ForceReferences();
|
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
|
// This is not the full Jacobian, but any substitutions or single-eq
|
||||||
// solves removed one equation and one unknown, therefore no effect
|
// solves removed one equation and one unknown, therefore no effect
|
||||||
// on the number of DOF.
|
// on the number of DOF.
|
||||||
if(dof) *dof = mat.n - mat.m;
|
if(dof) *dof = CalculateDof();
|
||||||
|
MarkParamsFree(andFindFree);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// System solved correctly, so write the new values back in to the
|
// System solved correctly, so write the new values back in to the
|
||||||
// main parameter table.
|
// main parameter table.
|
||||||
|
@ -537,9 +517,71 @@ 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,
|
||||||
|
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() {
|
void System::Clear() {
|
||||||
entity.Clear();
|
entity.Clear();
|
||||||
param.Clear();
|
param.Clear();
|
||||||
eq.Clear();
|
eq.Clear();
|
||||||
dragged.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