diff --git a/src/file.cpp b/src/file.cpp index 95eefe5..a436a85 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -109,6 +109,7 @@ const SolveSpaceUI::SaveTable SolveSpaceUI::SAVED[] = { { 'g', "Group.visible", 'b', &(SS.sv.g.visible) }, { 'g', "Group.suppress", 'b', &(SS.sv.g.suppress) }, { '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.scale", 'f', &(SS.sv.g.scale) }, { 'g', "Group.remap", 'M', &(SS.sv.g.remap) }, diff --git a/src/generate.cpp b/src/generate.cpp index 53cca0b..10d0573 100644 --- a/src/generate.cpp +++ b/src/generate.cpp @@ -469,8 +469,9 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) { g->solved.remove.Clear(); int how = sys.Solve(g, &(g->solved.dof), &(g->solved.remove), true, andFindFree); - if((how != System::SOLVED_OKAY) || - (how == System::SOLVED_OKAY && g->solved.how != System::SOLVED_OKAY)) + bool isOkay = how == System::SOLVED_OKAY || + (g->allowRedundant && how == System::REDUNDANT_OKAY); + if(!isOkay || (isOkay && !g->IsSolvedOkay())) { TextWindow::ReportHowGroupSolved(g->h); } @@ -478,14 +479,11 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) { FreeAllTemporary(); } -bool SolveSpaceUI::AllGroupsOkay(void) { - int i; - bool allOk = true; - for(i = 0; i < SK.group.n; i++) { - if(SK.group.elem[i].solved.how != System::SOLVED_OKAY) { - allOk = false; - } +bool SolveSpaceUI::AllGroupsOkay() { + for(int i = 0; i < SK.group.n; i++) { + if(!SK.group.elem[i].IsSolvedOkay()) + return false; } - return allOk; + return true; } diff --git a/src/group.cpp b/src/group.cpp index 2babcba..f736774 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -513,6 +513,11 @@ void Group::Generate(IdList *entity, } } +bool Group::IsSolvedOkay() { + return this->solved.how == System::SOLVED_OKAY || + this->allowRedundant && this->solved.how == System::REDUNDANT_OKAY; +} + void Group::AddEq(IdList *l, Expr *expr, int index) { Equation eq; eq.e = expr; diff --git a/src/sketch.h b/src/sketch.h index c14bd43..23abe5a 100644 --- a/src/sketch.h +++ b/src/sketch.h @@ -110,6 +110,7 @@ public: bool visible; bool suppress; bool relaxConstraints; + bool allowRedundant; bool allDimsReference; double scale; @@ -204,6 +205,7 @@ public: static void AddParam(ParamList *param, hParam hp, double v); void Generate(EntityList *entity, ParamList *param); + bool IsSolvedOkay(); void TransformImportedBy(Vector t, Quaternion q); // When a request generates entities from entities, and the source // entities may have come from multiple requests, it's necessary to diff --git a/src/system.cpp b/src/system.cpp index 3a04ec4..4fe704d 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -459,9 +459,12 @@ int System::Solve(Group *g, int *dof, List *bad, goto didnt_converge; } - if(!TestRank()) { - if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad); - return System::REDUNDANT_OKAY; + rankOk = TestRank(); + if(!rankOk) { + if(!g->allowRedundant) { + if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad); + return System::REDUNDANT_OKAY; + } } // This is not the full Jacobian, but any substitutions or single-eq @@ -505,7 +508,7 @@ int System::Solve(Group *g, int *dof, List *bad, pp->known = true; pp->free = p->free; } - return System::SOLVED_OKAY; + return rankOk ? System::SOLVED_OKAY : System::REDUNDANT_OKAY; didnt_converge: SK.constraint.ClearTags(); diff --git a/src/textscreens.cpp b/src/textscreens.cpp index 807113e..fecb8b6 100644 --- a/src/textscreens.cpp +++ b/src/textscreens.cpp @@ -112,7 +112,7 @@ void TextWindow::ShowListOfGroups(void) { std::string s = g->DescriptionString(); bool active = (g->h.v == SS.GW.activeGroup.v); 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); Printf(false, "%Bp%Fd " "%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 'e': g->allowRedundant = !(g->allowRedundant); break; + case 'v': g->visible = !(g->visible); break; case 'd': g->allDimsReference = !(g->allDimsReference); break; @@ -405,6 +407,10 @@ void TextWindow::ShowGroupInfo(void) { &TextWindow::ScreenChangeGroupOption, 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", &TextWindow::ScreenChangeGroupOption, 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 // 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) { 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 shown.screen = SCREEN_GROUP_INFO; Show(); @@ -504,6 +519,13 @@ void TextWindow::ShowGroupSolveInfo(void) { Printf(true, "It may be possible to fix the problem "); 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."); + } } //----------------------------------------------------------------------------- diff --git a/src/ui.h b/src/ui.h index 705a2e8..028cba7 100644 --- a/src/ui.h +++ b/src/ui.h @@ -278,6 +278,8 @@ public: static void ScreenChangeCanvasSize(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 ScreenStepDimFinish(int link, uint32_t v); static void ScreenStepDimGo(int link, uint32_t v);