Add a setting that permits a group to include redundant constraints.
This setting is generally useful, but it especially shines when assembling, since the "same orientation" and "parallel" constraints remove three and two rotational degrees of freedom, which makes them impossible to use with 3d "point on line" constraint that removes two spatial and two rotational degrees of freedom. The setting is not enabled for all imported groups by default because it exhibits some edge case failures. For example: * draw two line segments sharing a point, * constrain lengths of line segments, * constrain line segments perpendicular, * constrain line segments to a 90° angle. This is a truly degenerate case and so it is not considered very important. However, we can fix this later by using Eigen::SparseQR.
This commit is contained in:
parent
2b388e7da4
commit
46ab541444
|
@ -109,6 +109,7 @@ const SolveSpaceUI::SaveTable SolveSpaceUI::SAVED[] = {
|
||||||
{ 'g', "Group.visible", 'b', &(SS.sv.g.visible) },
|
{ 'g', "Group.visible", 'b', &(SS.sv.g.visible) },
|
||||||
{ 'g', "Group.suppress", 'b', &(SS.sv.g.suppress) },
|
{ 'g', "Group.suppress", 'b', &(SS.sv.g.suppress) },
|
||||||
{ 'g', "Group.relaxConstraints", 'b', &(SS.sv.g.relaxConstraints) },
|
{ 'g', "Group.relaxConstraints", 'b', &(SS.sv.g.relaxConstraints) },
|
||||||
|
{ 'g', "Group.allowRedundant", 'b', &(SS.sv.g.allowRedundant) },
|
||||||
{ 'g', "Group.allDimsReference", 'b', &(SS.sv.g.allDimsReference) },
|
{ 'g', "Group.allDimsReference", 'b', &(SS.sv.g.allDimsReference) },
|
||||||
{ 'g', "Group.scale", 'f', &(SS.sv.g.scale) },
|
{ 'g', "Group.scale", 'f', &(SS.sv.g.scale) },
|
||||||
{ 'g', "Group.remap", 'M', &(SS.sv.g.remap) },
|
{ 'g', "Group.remap", 'M', &(SS.sv.g.remap) },
|
||||||
|
|
|
@ -469,8 +469,9 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
||||||
g->solved.remove.Clear();
|
g->solved.remove.Clear();
|
||||||
int how = sys.Solve(g, &(g->solved.dof),
|
int how = sys.Solve(g, &(g->solved.dof),
|
||||||
&(g->solved.remove), true, andFindFree);
|
&(g->solved.remove), true, andFindFree);
|
||||||
if((how != System::SOLVED_OKAY) ||
|
bool isOkay = how == System::SOLVED_OKAY ||
|
||||||
(how == System::SOLVED_OKAY && g->solved.how != System::SOLVED_OKAY))
|
(g->allowRedundant && how == System::REDUNDANT_OKAY);
|
||||||
|
if(!isOkay || (isOkay && !g->IsSolvedOkay()))
|
||||||
{
|
{
|
||||||
TextWindow::ReportHowGroupSolved(g->h);
|
TextWindow::ReportHowGroupSolved(g->h);
|
||||||
}
|
}
|
||||||
|
@ -478,14 +479,11 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
||||||
FreeAllTemporary();
|
FreeAllTemporary();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SolveSpaceUI::AllGroupsOkay(void) {
|
bool SolveSpaceUI::AllGroupsOkay() {
|
||||||
int i;
|
for(int i = 0; i < SK.group.n; i++) {
|
||||||
bool allOk = true;
|
if(!SK.group.elem[i].IsSolvedOkay())
|
||||||
for(i = 0; i < SK.group.n; i++) {
|
return false;
|
||||||
if(SK.group.elem[i].solved.how != System::SOLVED_OKAY) {
|
|
||||||
allOk = false;
|
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
return allOk;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -513,6 +513,11 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Group::IsSolvedOkay() {
|
||||||
|
return this->solved.how == System::SOLVED_OKAY ||
|
||||||
|
this->allowRedundant && this->solved.how == System::REDUNDANT_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
void Group::AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index) {
|
void Group::AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index) {
|
||||||
Equation eq;
|
Equation eq;
|
||||||
eq.e = expr;
|
eq.e = expr;
|
||||||
|
|
|
@ -110,6 +110,7 @@ public:
|
||||||
bool visible;
|
bool visible;
|
||||||
bool suppress;
|
bool suppress;
|
||||||
bool relaxConstraints;
|
bool relaxConstraints;
|
||||||
|
bool allowRedundant;
|
||||||
bool allDimsReference;
|
bool allDimsReference;
|
||||||
double scale;
|
double scale;
|
||||||
|
|
||||||
|
@ -204,6 +205,7 @@ public:
|
||||||
|
|
||||||
static void AddParam(ParamList *param, hParam hp, double v);
|
static void AddParam(ParamList *param, hParam hp, double v);
|
||||||
void Generate(EntityList *entity, ParamList *param);
|
void Generate(EntityList *entity, ParamList *param);
|
||||||
|
bool IsSolvedOkay();
|
||||||
void TransformImportedBy(Vector t, Quaternion q);
|
void TransformImportedBy(Vector t, Quaternion q);
|
||||||
// When a request generates entities from entities, and the source
|
// When a request generates entities from entities, and the source
|
||||||
// entities may have come from multiple requests, it's necessary to
|
// entities may have come from multiple requests, it's necessary to
|
||||||
|
|
|
@ -459,10 +459,13 @@ int System::Solve(Group *g, int *dof, List<hConstraint> *bad,
|
||||||
goto didnt_converge;
|
goto didnt_converge;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!TestRank()) {
|
rankOk = TestRank();
|
||||||
|
if(!rankOk) {
|
||||||
|
if(!g->allowRedundant) {
|
||||||
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad);
|
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad);
|
||||||
return System::REDUNDANT_OKAY;
|
return System::REDUNDANT_OKAY;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -505,7 +508,7 @@ int System::Solve(Group *g, int *dof, List<hConstraint> *bad,
|
||||||
pp->known = true;
|
pp->known = true;
|
||||||
pp->free = p->free;
|
pp->free = p->free;
|
||||||
}
|
}
|
||||||
return System::SOLVED_OKAY;
|
return rankOk ? System::SOLVED_OKAY : System::REDUNDANT_OKAY;
|
||||||
|
|
||||||
didnt_converge:
|
didnt_converge:
|
||||||
SK.constraint.ClearTags();
|
SK.constraint.ClearTags();
|
||||||
|
|
|
@ -112,7 +112,7 @@ void TextWindow::ShowListOfGroups(void) {
|
||||||
std::string s = g->DescriptionString();
|
std::string s = g->DescriptionString();
|
||||||
bool active = (g->h.v == SS.GW.activeGroup.v);
|
bool active = (g->h.v == SS.GW.activeGroup.v);
|
||||||
bool shown = g->visible;
|
bool shown = g->visible;
|
||||||
bool ok = (g->solved.how == System::SOLVED_OKAY);
|
bool ok = g->IsSolvedOkay();
|
||||||
bool ref = (g->h.v == Group::HGROUP_REFERENCES.v);
|
bool ref = (g->h.v == Group::HGROUP_REFERENCES.v);
|
||||||
Printf(false, "%Bp%Fd "
|
Printf(false, "%Bp%Fd "
|
||||||
"%Ft%s%Fb%D%f%Ll%s%E "
|
"%Ft%s%Fb%D%f%Ll%s%E "
|
||||||
|
@ -205,6 +205,8 @@ void TextWindow::ScreenChangeGroupOption(int link, uint32_t v) {
|
||||||
|
|
||||||
case 'r': g->relaxConstraints = !(g->relaxConstraints); break;
|
case 'r': g->relaxConstraints = !(g->relaxConstraints); break;
|
||||||
|
|
||||||
|
case 'e': g->allowRedundant = !(g->allowRedundant); break;
|
||||||
|
|
||||||
case 'v': g->visible = !(g->visible); break;
|
case 'v': g->visible = !(g->visible); break;
|
||||||
|
|
||||||
case 'd': g->allDimsReference = !(g->allDimsReference); break;
|
case 'd': g->allDimsReference = !(g->allDimsReference); break;
|
||||||
|
@ -405,6 +407,10 @@ void TextWindow::ShowGroupInfo(void) {
|
||||||
&TextWindow::ScreenChangeGroupOption,
|
&TextWindow::ScreenChangeGroupOption,
|
||||||
g->relaxConstraints ? CHECK_TRUE : CHECK_FALSE);
|
g->relaxConstraints ? CHECK_TRUE : CHECK_FALSE);
|
||||||
|
|
||||||
|
Printf(false, " %f%Le%Fd%s allow redundant constraints",
|
||||||
|
&TextWindow::ScreenChangeGroupOption,
|
||||||
|
g->allowRedundant ? CHECK_TRUE : CHECK_FALSE);
|
||||||
|
|
||||||
Printf(false, " %f%Ld%Fd%s treat all dimensions as reference",
|
Printf(false, " %f%Ld%Fd%s treat all dimensions as reference",
|
||||||
&TextWindow::ScreenChangeGroupOption,
|
&TextWindow::ScreenChangeGroupOption,
|
||||||
g->allDimsReference ? CHECK_TRUE : CHECK_FALSE);
|
g->allDimsReference ? CHECK_TRUE : CHECK_FALSE);
|
||||||
|
@ -459,9 +465,18 @@ list_items:
|
||||||
// what failed, and (if the problem is a singular Jacobian) a list of
|
// what failed, and (if the problem is a singular Jacobian) a list of
|
||||||
// constraints that could be removed to fix it.
|
// constraints that could be removed to fix it.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
void TextWindow::ScreenAllowRedundant(int link, uint32_t v) {
|
||||||
|
SS.UndoRemember();
|
||||||
|
|
||||||
|
Group *g = SK.GetGroup(SS.TW.shown.group);
|
||||||
|
g->allowRedundant = true;
|
||||||
|
|
||||||
|
SS.TW.shown.screen = SCREEN_GROUP_INFO;
|
||||||
|
SS.TW.Show();
|
||||||
|
}
|
||||||
void TextWindow::ShowGroupSolveInfo(void) {
|
void TextWindow::ShowGroupSolveInfo(void) {
|
||||||
Group *g = SK.group.FindById(shown.group);
|
Group *g = SK.group.FindById(shown.group);
|
||||||
if(g->solved.how == System::SOLVED_OKAY) {
|
if(g->IsSolvedOkay()) {
|
||||||
// Go back to the default group info screen
|
// Go back to the default group info screen
|
||||||
shown.screen = SCREEN_GROUP_INFO;
|
shown.screen = SCREEN_GROUP_INFO;
|
||||||
Show();
|
Show();
|
||||||
|
@ -504,6 +519,13 @@ void TextWindow::ShowGroupSolveInfo(void) {
|
||||||
|
|
||||||
Printf(true, "It may be possible to fix the problem ");
|
Printf(true, "It may be possible to fix the problem ");
|
||||||
Printf(false, "by selecting Edit -> Undo.");
|
Printf(false, "by selecting Edit -> Undo.");
|
||||||
|
|
||||||
|
if(g->solved.how == System::REDUNDANT_OKAY) {
|
||||||
|
Printf(true, "It is possible to suppress this error ");
|
||||||
|
Printf(false, "by %Fl%f%Llallowing redundant constraints%E in ",
|
||||||
|
&TextWindow::ScreenAllowRedundant);
|
||||||
|
Printf(false, "this group.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
2
src/ui.h
2
src/ui.h
|
@ -278,6 +278,8 @@ public:
|
||||||
static void ScreenChangeCanvasSize(int link, uint32_t v);
|
static void ScreenChangeCanvasSize(int link, uint32_t v);
|
||||||
static void ScreenChangeShadedTriangles(int link, uint32_t v);
|
static void ScreenChangeShadedTriangles(int link, uint32_t v);
|
||||||
|
|
||||||
|
static void ScreenAllowRedundant(int link, uint32_t v);
|
||||||
|
|
||||||
static void ScreenStepDimSteps(int link, uint32_t v);
|
static void ScreenStepDimSteps(int link, uint32_t v);
|
||||||
static void ScreenStepDimFinish(int link, uint32_t v);
|
static void ScreenStepDimFinish(int link, uint32_t v);
|
||||||
static void ScreenStepDimGo(int link, uint32_t v);
|
static void ScreenStepDimGo(int link, uint32_t v);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user