Add feature to find the degrees of freedom; strike the

corresponding to each param from the Jacobian, and see if it loses
rank. If it does then that one was important, so it's bound. Then
display a big blue square around its point until the next normal
solve.

[git-p4: depot-paths = "//depot/solvespace/": change = 1887]
This commit is contained in:
Jonathan Westhues 2009-01-04 04:01:46 -08:00
parent 441b2a36e9
commit 8d656bc600
8 changed files with 68 additions and 10 deletions

View File

@ -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));

View File

@ -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();
}

View File

@ -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 },

View File

@ -425,6 +425,7 @@ public:
double val;
bool known;
bool free;
// Used only in the solver
hParam substd;

View File

@ -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];

View File

@ -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);

View File

@ -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;

1
ui.h
View File

@ -238,6 +238,7 @@ public:
MNU_COMMENT,
// Analyze
MNU_VOLUME,
MNU_SHOW_DOF,
MNU_TRACE_PT,
MNU_STOP_TRACING,
MNU_STEP_DIM,