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:
parent
441b2a36e9
commit
8d656bc600
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
1
sketch.h
1
sketch.h
|
@ -425,6 +425,7 @@ public:
|
|||
|
||||
double val;
|
||||
bool known;
|
||||
bool free;
|
||||
|
||||
// Used only in the solver
|
||||
hParam substd;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
24
system.cpp
24
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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user