diff --git a/drawentity.cpp b/drawentity.cpp index 2c23168..5dda1e7 100644 --- a/drawentity.cpp +++ b/drawentity.cpp @@ -48,6 +48,31 @@ void Entity::DrawAll(void) { if(e->forceHidden) continue; Vector v = e->PointGetNum(); + + bool free = false; + if(e->type == POINT_IN_3D) { + Param *px = SS.GetParam(e->param[0]), + *py = SS.GetParam(e->param[1]), + *pz = SS.GetParam(e->param[2]); + + free = (px->free) || (py->free) || (pz->free); + } else if(e->type == POINT_IN_2D) { + Param *pu = SS.GetParam(e->param[0]), + *pv = SS.GetParam(e->param[1]); + + free = (pu->free) || (pv->free); + } + if(free) { + Vector re = r.ScaledBy(2.5), de = d.ScaledBy(2.5); + + glxColor3d(0, 1.0, 1.0); + glxVertex3v(v.Plus (re).Plus (de)); + glxVertex3v(v.Plus (re).Minus(de)); + glxVertex3v(v.Minus(re).Minus(de)); + glxVertex3v(v.Minus(re).Plus (de)); + glxColor3d(0, 0.8, 0); + } + glxVertex3v(v.Plus (r).Plus (d)); glxVertex3v(v.Plus (r).Minus(d)); glxVertex3v(v.Minus(r).Minus(d)); diff --git a/generate.cpp b/generate.cpp index a8376cc..e8d8b9f 100644 --- a/generate.cpp +++ b/generate.cpp @@ -156,7 +156,7 @@ void SolveSpace::GenerateAll(void) { } } -void SolveSpace::GenerateAll(int first, int last) { +void SolveSpace::GenerateAll(int first, int last, bool andFindFree) { int i, j; // Remove any requests or constraints that refer to a nonexistent @@ -221,7 +221,7 @@ void SolveSpace::GenerateAll(int first, int last) { } // The group falls inside the range, so really solve it, // and then regenerate the mesh based on the solved stuff. - SolveGroup(g->h); + SolveGroup(g->h, andFindFree); g->GeneratePolygon(); g->GenerateMesh(); g->clean = true; @@ -341,7 +341,7 @@ void SolveSpace::ForceReferences(void) { } } -void SolveSpace::SolveGroup(hGroup hg) { +void SolveSpace::SolveGroup(hGroup hg, bool andFindFree) { int i; // Clear out the system to be solved. sys.entity.Clear(); @@ -364,7 +364,7 @@ void SolveSpace::SolveGroup(hGroup hg) { p->val = GetParam(p->h)->val; } - sys.Solve(g); + sys.Solve(g, andFindFree); FreeAllTemporary(); } diff --git a/graphicswin.cpp b/graphicswin.cpp index ec617b3..e694997 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -40,7 +40,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, "Zoom To &Fit\tF", MNU_ZOOM_TO_FIT, 'F', mView }, { 1, NULL, 0, NULL }, { 1, "Nearest &Ortho View\tF1", MNU_NEAREST_ORTHO, F(1), mView }, -{ 1, "Nearest &Iso View\tF2", MNU_NEAREST_ISO, F(2), mView }, +{ 1, "Nearest &Isometric View\tF2", MNU_NEAREST_ISO, F(2), mView }, { 1, NULL, 0, NULL }, { 1, "Show Text &Window\tTab", MNU_SHOW_TEXT_WND, '\t', mView }, { 1, "Show &Toolbar", MNU_SHOW_TOOLBAR, 0, mView }, @@ -102,7 +102,9 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, "Comment\t;", MNU_COMMENT, ';', mCon }, { 0, "&Analyze", 0, NULL }, -{ 1, "Measure &Volume", MNU_VOLUME, 0, mAna }, +{ 1, "Measure &Volume\tCtrl+Shift+V", MNU_VOLUME, 'V'|S|C,mAna }, +{ 1, NULL, 0, NULL }, +{ 1, "Show Degrees of &Freedom\tCtrl+Shift+F", MNU_SHOW_DOF, 'F'|S|C,mAna }, { 1, NULL, 0, NULL }, { 1, "&Trace Point\tCtrl+Shift+T", MNU_TRACE_PT, 'T'|S|C,mAna }, { 1, "&Stop Tracing...\tCtrl+Shift+S", MNU_STOP_TRACING, 'S'|S|C,mAna }, diff --git a/sketch.h b/sketch.h index cd2fedb..bd77362 100644 --- a/sketch.h +++ b/sketch.h @@ -425,6 +425,7 @@ public: double val; bool known; + bool free; // Used only in the solver hParam substd; diff --git a/solvespace.cpp b/solvespace.cpp index 656a126..1070ef4 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -453,6 +453,12 @@ void SolveSpace::MenuAnalyze(int id) { break; } + case GraphicsWindow::MNU_SHOW_DOF: + // This works like a normal solve, except that it calculates + // which variables are free/bound at the same time. + SS.GenerateAll(0, INT_MAX, true); + break; + case GraphicsWindow::MNU_TRACE_PT: if(gs.points == 1 && gs.n == 1) { SS.traced.point = gs.point[0]; diff --git a/solvespace.h b/solvespace.h index 386522e..a38864b 100644 --- a/solvespace.h +++ b/solvespace.h @@ -192,6 +192,7 @@ public: // In general, the tag indicates the subsys that a variable/equation // has been assigned to; these are exceptions for variables: static const int VAR_SUBSTITUTED = 10000; + static const int VAR_DOF_TEST = 10001; // and for equations: static const int EQ_SUBSTITUTED = 20000; @@ -240,7 +241,7 @@ public: static bool IsDragged(hParam p); bool NewtonSolve(int tag); - void Solve(Group *g); + void Solve(Group *g, bool andFindFree); }; class TtfFont { @@ -466,8 +467,8 @@ public: bool PruneConstraints(hGroup hg); void GenerateAll(void); - void GenerateAll(int first, int last); - void SolveGroup(hGroup hg); + void GenerateAll(int first, int last, bool andFindFree=false); + void SolveGroup(hGroup hg, bool andFindFree); void ForceReferences(void); bool AllGroupsOkay(void); diff --git a/system.cpp b/system.cpp index 1e36e32..5757a56 100644 --- a/system.cpp +++ b/system.cpp @@ -398,7 +398,7 @@ void System::FindWhichToRemoveToFixJacobian(Group *g) { } } -void System::Solve(Group *g) { +void System::Solve(Group *g, bool andFindFree) { g->solved.remove.Clear(); WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g->h); @@ -469,6 +469,27 @@ void System::Solve(Group *g) { goto didnt_converge; } + // 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(); + rank = CalculateRank(); + if(rank == mat.m) { + p->free = true; + } + p->tag = 0; + } + } + } + // System solved correctly, so write the new values back in to the // main parameter table. for(i = 0; i < param.n; i++) { @@ -482,6 +503,7 @@ void System::Solve(Group *g) { Param *pp = SS.GetParam(p->h); pp->val = val; pp->known = true; + pp->free = p->free; } if(g->solved.how != Group::SOLVED_OKAY) { g->solved.how = Group::SOLVED_OKAY; diff --git a/ui.h b/ui.h index 0f66a74..9bda2e1 100644 --- a/ui.h +++ b/ui.h @@ -238,6 +238,7 @@ public: MNU_COMMENT, // Analyze MNU_VOLUME, + MNU_SHOW_DOF, MNU_TRACE_PT, MNU_STOP_TRACING, MNU_STEP_DIM,