Many user interface additions. Now I report when the solver fails,
and in the case of a singular Jacobian, report which constraints can be removed to fix it. Also a mechanism to hover and select entities and constraints from the text window. [git-p4: depot-paths = "//depot/solvespace/": change = 1746]
This commit is contained in:
parent
727ac126fb
commit
b484c26493
|
@ -1,5 +1,7 @@
|
|||
#include "solvespace.h"
|
||||
|
||||
const hConstraint Constraint::NO_CONSTRAINT = { 0 };
|
||||
|
||||
char *Constraint::DescriptionString(void) {
|
||||
static char ret[1024];
|
||||
sprintf(ret, "c%03x", h.v);
|
||||
|
|
|
@ -28,6 +28,7 @@ void Constraint::LineDrawOrGetDistance(Vector a, Vector b) {
|
|||
double d = dogd.mp.DistanceToLine(ap, bp.Minus(ap), true);
|
||||
dogd.dmin = min(dogd.dmin, d);
|
||||
}
|
||||
dogd.refp = (a.Plus(b)).ScaledBy(0.5);
|
||||
}
|
||||
|
||||
double Constraint::EllipticalInterpolation(double rx, double ry, double theta) {
|
||||
|
@ -56,6 +57,7 @@ void Constraint::DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu) {
|
|||
} else {
|
||||
Point2d o = SS.GW.ProjectPoint(ref);
|
||||
dogd.dmin = min(dogd.dmin, o.DistanceTo(dogd.mp) - 10);
|
||||
dogd.refp = ref;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,6 +199,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
// same center; so if the point is visible, then this
|
||||
// constraint cannot be selected. But that's okay.
|
||||
dogd.dmin = min(dogd.dmin, pp.DistanceTo(dogd.mp) - 3);
|
||||
dogd.refp = p;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -449,7 +452,8 @@ s:
|
|||
(type == AT_MIDPOINT) ? "M" : NULL)));
|
||||
glPopMatrix();
|
||||
} else {
|
||||
Point2d ref = SS.GW.ProjectPoint(m.Plus(offset));
|
||||
dogd.refp = m.Plus(offset);
|
||||
Point2d ref = SS.GW.ProjectPoint(dogd.refp);
|
||||
dogd.dmin = min(dogd.dmin, ref.DistanceTo(dogd.mp)-10);
|
||||
}
|
||||
} else {
|
||||
|
@ -518,3 +522,12 @@ Vector Constraint::GetLabelPos(void) {
|
|||
return p;
|
||||
}
|
||||
|
||||
Vector Constraint::GetReferencePos(void) {
|
||||
dogd.drawing = false;
|
||||
|
||||
dogd.refp = SS.GW.offset.ScaledBy(-1);
|
||||
DrawOrGetDistance(NULL);
|
||||
|
||||
return dogd.refp;
|
||||
}
|
||||
|
||||
|
|
13
entity.cpp
13
entity.cpp
|
@ -522,6 +522,7 @@ void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
|
|||
double d = dogd.mp.DistanceToLine(ap, bp.Minus(ap), true);
|
||||
dogd.dmin = min(dogd.dmin, d);
|
||||
}
|
||||
dogd.refp = (a.Plus(b)).ScaledBy(0.5);
|
||||
}
|
||||
|
||||
void Entity::LineDrawOrGetDistanceOrEdge(Vector a, Vector b) {
|
||||
|
@ -555,6 +556,16 @@ double Entity::GetDistance(Point2d mp) {
|
|||
return dogd.dmin;
|
||||
}
|
||||
|
||||
Vector Entity::GetReferencePos(void) {
|
||||
dogd.drawing = false;
|
||||
dogd.edges = NULL;
|
||||
|
||||
dogd.refp = SS.GW.offset.ScaledBy(-1);
|
||||
DrawOrGetDistance(-1);
|
||||
|
||||
return dogd.refp;
|
||||
}
|
||||
|
||||
void Entity::DrawOrGetDistance(int order) {
|
||||
Group *g = SS.GetGroup(group);
|
||||
// If an entity is invisible, then it doesn't get shown, and it doesn't
|
||||
|
@ -615,7 +626,6 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
case NORMAL_IN_3D:
|
||||
case NORMAL_IN_2D: {
|
||||
if(order >= 0 && order != 2) break;
|
||||
if(!SS.GW.showNormals) break;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < 2; i++) {
|
||||
|
@ -630,6 +640,7 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
} else {
|
||||
glxColor3d(0, 0.4, 0.4);
|
||||
if(i > 0) break;
|
||||
if(!SS.GW.showNormals) break;
|
||||
}
|
||||
|
||||
Quaternion q = NormalGetNum();
|
||||
|
|
|
@ -320,7 +320,7 @@ void GraphicsWindow::MenuEdit(int id) {
|
|||
SS.GW.ClearSuper();
|
||||
// And regenerate to get rid of what it generates, plus anything
|
||||
// that references it (since the regen code checks for that).
|
||||
SS.GW.GeneratePerSolving();
|
||||
SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS, 0, INT_MAX);
|
||||
SS.GW.EnsureValidActives();
|
||||
SS.TW.Show();
|
||||
break;
|
||||
|
@ -624,7 +624,9 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
|
||||
default: oops();
|
||||
}
|
||||
SS.GW.GeneratePerSolving();
|
||||
if(pending.operation != 0 && pending.operation != DRAGGING_CONSTRAINT) {
|
||||
SS.GW.GeneratePerSolving();
|
||||
}
|
||||
havePainted = false;
|
||||
}
|
||||
|
||||
|
@ -640,10 +642,34 @@ bool GraphicsWindow::Selection::IsEmpty(void) {
|
|||
}
|
||||
void GraphicsWindow::Selection::Clear(void) {
|
||||
entity.v = constraint.v = 0;
|
||||
emphasized = false;
|
||||
}
|
||||
void GraphicsWindow::Selection::Draw(void) {
|
||||
if(entity.v) SS.GetEntity (entity )->Draw(-1);
|
||||
if(constraint.v) SS.GetConstraint(constraint)->Draw();
|
||||
Vector refp;
|
||||
if(entity.v) {
|
||||
Entity *e = SS.GetEntity(entity);
|
||||
e->Draw(-1);
|
||||
if(emphasized) refp = e->GetReferencePos();
|
||||
}
|
||||
if(constraint.v) {
|
||||
Constraint *c = SS.GetConstraint(constraint);
|
||||
c->Draw();
|
||||
if(emphasized) refp = c->GetReferencePos();
|
||||
}
|
||||
if(emphasized && (constraint.v || entity.v)) {
|
||||
double s = 0.501/SS.GW.scale;
|
||||
Vector topLeft = SS.GW.projRight.ScaledBy(-SS.GW.width*s);
|
||||
topLeft = topLeft.Plus(SS.GW.projUp.ScaledBy(SS.GW.height*s));
|
||||
topLeft = topLeft.Minus(SS.GW.offset);
|
||||
|
||||
glLineWidth(40);
|
||||
glColor4d(1.0, 1.0, 0, 0.2);
|
||||
glBegin(GL_LINES);
|
||||
glxVertex3v(topLeft);
|
||||
glxVertex3v(refp);
|
||||
glEnd();
|
||||
glLineWidth(1);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsWindow::ClearSuper(void) {
|
||||
|
@ -998,7 +1024,9 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
SS.GW.GeneratePerSolving();
|
||||
if(pending.operation != 0 && pending.operation != DRAGGING_CONSTRAINT) {
|
||||
SS.GW.GeneratePerSolving();
|
||||
}
|
||||
|
||||
SS.TW.Show();
|
||||
InvalidateGraphics();
|
||||
|
|
|
@ -98,6 +98,7 @@ void Group::MenuGroup(int id) {
|
|||
Vector offsetf = (e->WorkplaneGetOffset()).ScaledBy(-1);
|
||||
SS.GW.AnimateOnto(quatf, offsetf);
|
||||
}
|
||||
TextWindow::ScreenSelectGroup(0, g.h.v);
|
||||
SS.TW.Show();
|
||||
}
|
||||
|
||||
|
@ -517,7 +518,7 @@ void Group::Draw(void) {
|
|||
glxFillMesh(&mesh);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
// glxDebugMesh(&mesh);
|
||||
glxDebugMesh(&mesh);
|
||||
|
||||
if(polyError.yes) {
|
||||
glxColor4d(1, 0, 0, 0.2);
|
||||
|
@ -534,7 +535,7 @@ void Group::Draw(void) {
|
|||
glxWriteText("not closed contour!");
|
||||
glPopMatrix();
|
||||
} else {
|
||||
glxColor4d(0, 1.0, 1.0, 0.1);
|
||||
glxColor4d(0, 1.0, 1.0, 0.05);
|
||||
glPolygonOffset(-1, -1);
|
||||
glxFillPolygon(&poly);
|
||||
glPolygonOffset(0, 0);
|
||||
|
|
15
sketch.h
15
sketch.h
|
@ -10,6 +10,7 @@ class hParam;
|
|||
class Entity;
|
||||
class Param;
|
||||
|
||||
class hConstraint;
|
||||
class hEquation;
|
||||
class Equation;
|
||||
|
||||
|
@ -88,6 +89,14 @@ public:
|
|||
hGroup opB;
|
||||
bool visible;
|
||||
|
||||
static const int SOLVED_OKAY = 0;
|
||||
static const int DIDNT_CONVERGE = 10;
|
||||
static const int SINGULAR_JACOBIAN = 11;
|
||||
struct {
|
||||
int how;
|
||||
SList<hConstraint> remove;
|
||||
} solved;
|
||||
|
||||
static const int WORKPLANE_BY_POINT_ORTHO = 6000;
|
||||
static const int WORKPLANE_BY_LINE_SEGMENTS = 6001;
|
||||
static const int EXTRUDE_ONE_SIDED = 7000;
|
||||
|
@ -288,6 +297,7 @@ public:
|
|||
Point2d mp;
|
||||
double dmin;
|
||||
SEdgeList *edges;
|
||||
Vector refp;
|
||||
} dogd; // state for drawing or getting distance (for hit testing)
|
||||
void LineDrawOrGetDistance(Vector a, Vector b);
|
||||
void LineDrawOrGetDistanceOrEdge(Vector a, Vector b);
|
||||
|
@ -296,6 +306,7 @@ public:
|
|||
void Draw(int order);
|
||||
double GetDistance(Point2d mp);
|
||||
void GenerateEdges(SEdgeList *el);
|
||||
Vector GetReferencePos(void);
|
||||
|
||||
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
|
||||
void GenerateEquations(IdList<Equation,hEquation> *l);
|
||||
|
@ -328,6 +339,8 @@ public:
|
|||
|
||||
class Constraint {
|
||||
public:
|
||||
static const hConstraint NO_CONSTRAINT;
|
||||
|
||||
static const int USER_EQUATION = 10;
|
||||
static const int POINTS_COINCIDENT = 20;
|
||||
static const int PT_PT_DISTANCE = 30;
|
||||
|
@ -382,6 +395,7 @@ public:
|
|||
bool drawing;
|
||||
Point2d mp;
|
||||
double dmin;
|
||||
Vector refp;
|
||||
} dogd; // state for drawing or getting distance (for hit testing)
|
||||
void LineDrawOrGetDistance(Vector a, Vector b);
|
||||
void DrawOrGetDistance(Vector *labelPos);
|
||||
|
@ -391,6 +405,7 @@ public:
|
|||
|
||||
double GetDistance(Point2d mp);
|
||||
Vector GetLabelPos(void);
|
||||
Vector GetReferencePos(void);
|
||||
void Draw(void);
|
||||
|
||||
bool HasLabel(void);
|
||||
|
|
|
@ -14,8 +14,8 @@ void SolveSpace::Init(char *cmdLine) {
|
|||
TW.Init();
|
||||
GW.Init();
|
||||
|
||||
GenerateAll(true, 0, INT_MAX);
|
||||
TW.Show();
|
||||
GenerateAll(false, 0, INT_MAX);
|
||||
}
|
||||
|
||||
bool SolveSpace::PruneOrphans(void) {
|
||||
|
@ -127,7 +127,8 @@ void SolveSpace::GenerateAll(bool andSolve) {
|
|||
int firstShown = INT_MAX, lastShown = 0;
|
||||
// The references don't count, so start from group 1
|
||||
for(i = 1; i < group.n; i++) {
|
||||
if(group.elem[i].visible) {
|
||||
Group *g = &(group.elem[i]);
|
||||
if(g->visible || (g->solved.how != Group::SOLVED_OKAY)) {
|
||||
firstShown = min(firstShown, i);
|
||||
lastShown = max(lastShown, i);
|
||||
}
|
||||
|
@ -182,6 +183,7 @@ void SolveSpace::GenerateAll(bool andSolve, int first, int last) {
|
|||
|
||||
if(g->h.v == Group::HGROUP_REFERENCES.v) {
|
||||
ForceReferences();
|
||||
g->solved.how = Group::SOLVED_OKAY;
|
||||
} else {
|
||||
if(i >= first && i <= last) {
|
||||
// The group falls inside the range, so really solve it,
|
||||
|
@ -271,7 +273,7 @@ void SolveSpace::ForceReferences(void) {
|
|||
}
|
||||
}
|
||||
|
||||
bool SolveSpace::SolveGroup(hGroup hg) {
|
||||
void SolveSpace::SolveGroup(hGroup hg) {
|
||||
int i;
|
||||
// Clear out the system to be solved.
|
||||
sys.entity.Clear();
|
||||
|
@ -293,26 +295,9 @@ bool SolveSpace::SolveGroup(hGroup hg) {
|
|||
p->known = false;
|
||||
p->val = GetParam(p->h)->val;
|
||||
}
|
||||
// And generate all the equations from constraints in this group
|
||||
for(i = 0; i < constraint.n; i++) {
|
||||
Constraint *c = &(constraint.elem[i]);
|
||||
if(c->group.v != hg.v) continue;
|
||||
|
||||
c->Generate(&(sys.eq));
|
||||
}
|
||||
// And the equations from entities
|
||||
for(i = 0; i < entity.n; i++) {
|
||||
Entity *e = &(entity.elem[i]);
|
||||
if(e->group.v != hg.v) continue;
|
||||
|
||||
e->GenerateEquations(&(sys.eq));
|
||||
}
|
||||
// And from the groups themselves
|
||||
g->GenerateEquations(&(sys.eq));
|
||||
|
||||
bool r = sys.Solve();
|
||||
sys.Solve(g);
|
||||
FreeAllTemporary();
|
||||
return r;
|
||||
}
|
||||
|
||||
void SolveSpace::MenuFile(int id) {
|
||||
|
|
|
@ -162,12 +162,14 @@ public:
|
|||
void WriteJacobian(int eqTag, int paramTag);
|
||||
void EvalJacobian(void);
|
||||
|
||||
void WriteEquationsExceptFor(hConstraint hc, hGroup hg);
|
||||
void FindWhichToRemoveToFixJacobian(Group *g);
|
||||
void SolveBySubstitution(void);
|
||||
|
||||
static bool IsDragged(hParam p);
|
||||
|
||||
bool NewtonSolve(int tag);
|
||||
bool Solve(void);
|
||||
void Solve(Group *g);
|
||||
};
|
||||
|
||||
|
||||
|
@ -236,7 +238,7 @@ public:
|
|||
|
||||
void GenerateAll(bool andSolve);
|
||||
void GenerateAll(bool andSolve, int first, int last);
|
||||
bool SolveGroup(hGroup hg);
|
||||
void SolveGroup(hGroup hg);
|
||||
void ForceReferences(void);
|
||||
|
||||
// The system to be solved.
|
||||
|
|
72
system.cpp
72
system.cpp
|
@ -349,17 +349,60 @@ bool System::NewtonSolve(int tag) {
|
|||
}
|
||||
} while(iter++ < 50 && !converged);
|
||||
|
||||
if(converged) {
|
||||
return true;
|
||||
} else {
|
||||
dbp("no convergence");
|
||||
return false;
|
||||
return converged;
|
||||
}
|
||||
|
||||
void System::WriteEquationsExceptFor(hConstraint hc, hGroup hg) {
|
||||
int i;
|
||||
// Generate all the equations from constraints in this group
|
||||
for(i = 0; i < SS.constraint.n; i++) {
|
||||
Constraint *c = &(SS.constraint.elem[i]);
|
||||
if(c->group.v != hg.v) continue;
|
||||
if(c->h.v == hc.v) continue;
|
||||
|
||||
c->Generate(&eq);
|
||||
}
|
||||
// And the equations from entities
|
||||
for(i = 0; i < SS.entity.n; i++) {
|
||||
Entity *e = &(SS.entity.elem[i]);
|
||||
if(e->group.v != hg.v) continue;
|
||||
|
||||
e->GenerateEquations(&eq);
|
||||
}
|
||||
// And from the groups themselves
|
||||
(SS.GetGroup(hg))->GenerateEquations(&eq);
|
||||
}
|
||||
|
||||
void System::FindWhichToRemoveToFixJacobian(Group *g) {
|
||||
int i;
|
||||
(g->solved.remove).Clear();
|
||||
|
||||
for(i = 0; i < SS.constraint.n; i++) {
|
||||
Constraint *c = &(SS.constraint.elem[i]);
|
||||
if(c->group.v != g->h.v) continue;
|
||||
|
||||
param.ClearTags();
|
||||
eq.Clear();
|
||||
WriteEquationsExceptFor(c->h, g->h);
|
||||
eq.ClearTags();
|
||||
|
||||
WriteJacobian(0, 0);
|
||||
EvalJacobian();
|
||||
|
||||
int rank = GaussJordan();
|
||||
if(rank == mat.m) {
|
||||
// We fixed it by removing this constraint
|
||||
(g->solved.remove).Add(&(c->h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool System::Solve(void) {
|
||||
void System::Solve(Group *g) {
|
||||
g->solved.remove.Clear();
|
||||
|
||||
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g->h);
|
||||
|
||||
int i, j = 0;
|
||||
|
||||
/*
|
||||
dbp("%d equations", eq.n);
|
||||
for(i = 0; i < eq.n; i++) {
|
||||
|
@ -391,6 +434,12 @@ bool System::Solve(void) {
|
|||
} */
|
||||
|
||||
int rank = GaussJordan();
|
||||
if(rank != mat.m) {
|
||||
FindWhichToRemoveToFixJacobian(g);
|
||||
g->solved.how = Group::SINGULAR_JACOBIAN;
|
||||
TextWindow::ReportHowGroupSolved(g->h);
|
||||
return;
|
||||
}
|
||||
|
||||
/* dbp("bound states:");
|
||||
for(j = 0; j < mat.n; j++) {
|
||||
|
@ -417,8 +466,13 @@ bool System::Solve(void) {
|
|||
// The main param table keeps track of what was assumed.
|
||||
pp->assumed = (p->tag == VAR_ASSUMED);
|
||||
}
|
||||
if(g->solved.how != Group::SOLVED_OKAY) {
|
||||
g->solved.how = Group::SOLVED_OKAY;
|
||||
TextWindow::ReportHowGroupSolved(g->h);
|
||||
}
|
||||
} else {
|
||||
g->solved.how = Group::DIDNT_CONVERGE;
|
||||
TextWindow::ReportHowGroupSolved(g->h);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
103
textwin.cpp
103
textwin.cpp
|
@ -5,15 +5,16 @@ const TextWindow::Color TextWindow::fgColors[] = {
|
|||
{ 'd', RGB(255, 255, 255) },
|
||||
{ 'l', RGB(100, 100, 255) },
|
||||
{ 't', RGB(255, 200, 0) },
|
||||
{ 'h', RGB(170, 0, 0) },
|
||||
{ 'h', RGB( 90, 90, 90) },
|
||||
{ 's', RGB( 40, 255, 40) },
|
||||
{ 'm', RGB(200, 200, 0) },
|
||||
{ 'r', RGB( 0, 0, 0) },
|
||||
{ 'x', RGB(255, 20, 20) },
|
||||
{ 0, 0 },
|
||||
};
|
||||
const TextWindow::Color TextWindow::bgColors[] = {
|
||||
{ 'd', RGB( 0, 0, 0) },
|
||||
{ 't', RGB( 40, 20, 40) },
|
||||
{ 't', RGB( 34, 15, 15) },
|
||||
{ 'a', RGB( 20, 20, 20) },
|
||||
{ 'r', RGB(255, 255, 255) },
|
||||
{ 0, 0 },
|
||||
|
@ -59,7 +60,7 @@ void TextWindow::Printf(bool halfLine, char *fmt, ...) {
|
|||
int fg = 'd', bg = 'd';
|
||||
int link = NOT_A_LINK;
|
||||
DWORD data = 0;
|
||||
LinkFunction *f = NULL;
|
||||
LinkFunction *f = NULL, *h = NULL;
|
||||
|
||||
c = 0;
|
||||
while(*fmt) {
|
||||
|
@ -91,6 +92,7 @@ void TextWindow::Printf(bool halfLine, char *fmt, ...) {
|
|||
link = NOT_A_LINK;
|
||||
data = 0;
|
||||
f = NULL;
|
||||
h = NULL;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
|
@ -121,6 +123,10 @@ void TextWindow::Printf(bool halfLine, char *fmt, ...) {
|
|||
f = va_arg(vl, LinkFunction *);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
h = va_arg(vl, LinkFunction *);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
data = va_arg(vl, DWORD);
|
||||
break;
|
||||
|
@ -142,6 +148,7 @@ void TextWindow::Printf(bool halfLine, char *fmt, ...) {
|
|||
meta[r][c].link = link;
|
||||
meta[r][c].data = data;
|
||||
meta[r][c].f = f;
|
||||
meta[r][c].h = h;
|
||||
c++;
|
||||
}
|
||||
|
||||
|
@ -160,6 +167,9 @@ done:
|
|||
void TextWindow::Show(void) {
|
||||
if(!(SS.GW.pending.operation)) SS.GW.ClearPending();
|
||||
|
||||
SS.GW.GroupSelection();
|
||||
#define gs (SS.GW.gs)
|
||||
|
||||
ShowHeader();
|
||||
|
||||
if(SS.GW.pending.description) {
|
||||
|
@ -174,8 +184,7 @@ void TextWindow::Show(void) {
|
|||
// fall through
|
||||
case SCREEN_LIST_OF_GROUPS: ShowListOfGroups(); break;
|
||||
case SCREEN_GROUP_INFO: ShowGroupInfo(); break;
|
||||
case SCREEN_REQUEST_INFO: ShowRequestInfo(); break;
|
||||
case SCREEN_CONSTRAINT_INFO: ShowConstraintInfo(); break;
|
||||
case SCREEN_GROUP_SOLVE_INFO: ShowGroupSolveInfo(); break;
|
||||
}
|
||||
}
|
||||
InvalidateText();
|
||||
|
@ -297,18 +306,32 @@ void TextWindow::ScreenActivateGroup(int link, DWORD v) {
|
|||
}
|
||||
SS.GW.ClearSuper();
|
||||
}
|
||||
void TextWindow::ReportHowGroupSolved(hGroup hg) {
|
||||
SS.TW.OneScreenForwardTo(SCREEN_GROUP_SOLVE_INFO);
|
||||
SS.TW.shown->group.v = hg.v;
|
||||
SS.TW.Show();
|
||||
}
|
||||
void TextWindow::ScreenHowGroupSolved(int link, DWORD v) {
|
||||
if(SS.GW.activeGroup.v != v) {
|
||||
ScreenActivateGroup(link, v);
|
||||
}
|
||||
SS.TW.OneScreenForwardTo(SCREEN_GROUP_SOLVE_INFO);
|
||||
SS.TW.shown->group.v = v;
|
||||
}
|
||||
void TextWindow::ShowListOfGroups(void) {
|
||||
Printf(true, "%Ftactive show group-name%E");
|
||||
Printf(true, "%Ftactv show ok group-name%E");
|
||||
int i;
|
||||
for(i = 0; i < SS.group.n; i++) {
|
||||
Group *g = &(SS.group.elem[i]);
|
||||
char *s = g->DescriptionString();
|
||||
bool active = (g->h.v == SS.GW.activeGroup.v);
|
||||
bool shown = g->visible;
|
||||
bool ok = (g->solved.how == Group::SOLVED_OKAY);
|
||||
bool ref = (g->h.v == Group::HGROUP_REFERENCES.v);
|
||||
Printf(false, "%Bp%Fd "
|
||||
"%Fp%D%f%s%Ll%s%E%s "
|
||||
Printf(false, "%Bp%Fd "
|
||||
"%Fp%D%f%s%Ll%s%E%s "
|
||||
"%Fp%D%f%Ll%s%E%s "
|
||||
"%Fp%D%f%s%Ll%s%E "
|
||||
"%Fl%Ll%D%f%s",
|
||||
// Alternate between light and dark backgrounds, for readability
|
||||
(i & 1) ? 'd' : 'a',
|
||||
|
@ -321,6 +344,10 @@ void TextWindow::ShowListOfGroups(void) {
|
|||
shown ? 's' : 'h', g->h.v, (&TextWindow::ScreenToggleGroupShown),
|
||||
shown ? "yes" : "no",
|
||||
shown ? "" : " ",
|
||||
// Link to the errors, if a problem occured while solving
|
||||
ok ? 's' : 'x', g->h.v, (&TextWindow::ScreenHowGroupSolved),
|
||||
ok ? "ok" : "",
|
||||
ok ? "" : "NO",
|
||||
// Link to a screen that gives more details on the group
|
||||
g->h.v, (&TextWindow::ScreenSelectGroup), s);
|
||||
}
|
||||
|
@ -332,13 +359,25 @@ void TextWindow::ShowListOfGroups(void) {
|
|||
}
|
||||
|
||||
|
||||
void TextWindow::ScreenHoverConstraint(int link, DWORD v) {
|
||||
SS.GW.hover.Clear();
|
||||
SS.GW.hover.constraint.v = v;
|
||||
SS.GW.hover.emphasized = true;
|
||||
}
|
||||
void TextWindow::ScreenHoverRequest(int link, DWORD v) {
|
||||
SS.GW.hover.Clear();
|
||||
hRequest hr = { v };
|
||||
SS.GW.hover.entity = hr.entity(0);
|
||||
SS.GW.hover.emphasized = true;
|
||||
}
|
||||
void TextWindow::ScreenSelectConstraint(int link, DWORD v) {
|
||||
SS.TW.OneScreenForwardTo(SCREEN_CONSTRAINT_INFO);
|
||||
SS.TW.shown->constraint.v = v;
|
||||
SS.GW.ClearSelection();
|
||||
SS.GW.selection[0].constraint.v = v;
|
||||
}
|
||||
void TextWindow::ScreenSelectRequest(int link, DWORD v) {
|
||||
SS.TW.OneScreenForwardTo(SCREEN_REQUEST_INFO);
|
||||
SS.TW.shown->request.v = v;
|
||||
hRequest hr = { v };
|
||||
SS.GW.ClearSelection();
|
||||
SS.GW.selection[0].entity = hr.entity(0);
|
||||
}
|
||||
void TextWindow::ScreenChangeExtrudeSides(int link, DWORD v) {
|
||||
Group *g = SS.GetGroup(SS.TW.shown->group);
|
||||
|
@ -396,9 +435,10 @@ void TextWindow::ShowGroupInfo(void) {
|
|||
|
||||
if(r->group.v == shown->group.v) {
|
||||
char *s = r->DescriptionString();
|
||||
Printf(false, "%Bp %Fl%Ll%D%f%s%E",
|
||||
Printf(false, "%Bp %Fl%Ll%D%f%h%s%E",
|
||||
(a & 1) ? 'd' : 'a',
|
||||
r->h.v, (&TextWindow::ScreenSelectRequest), s);
|
||||
r->h.v, (&TextWindow::ScreenSelectRequest),
|
||||
&(TextWindow::ScreenHoverRequest), s);
|
||||
a++;
|
||||
}
|
||||
}
|
||||
|
@ -411,15 +451,46 @@ void TextWindow::ShowGroupInfo(void) {
|
|||
|
||||
if(c->group.v == shown->group.v) {
|
||||
char *s = c->DescriptionString();
|
||||
Printf(false, "%Bp %Fl%Ll%D%f%s%E",
|
||||
Printf(false, "%Bp %Fl%Ll%D%f%h%s%E",
|
||||
(a & 1) ? 'd' : 'a',
|
||||
c->h.v, (&TextWindow::ScreenSelectConstraint), s);
|
||||
c->h.v, (&TextWindow::ScreenSelectConstraint),
|
||||
(&TextWindow::ScreenHoverConstraint), s);
|
||||
a++;
|
||||
}
|
||||
}
|
||||
if(a == 0) Printf(false, "%Ba (none)");
|
||||
}
|
||||
|
||||
void TextWindow::ShowGroupSolveInfo(void) {
|
||||
Group *g = SS.group.FindById(shown->group);
|
||||
Printf(true, "%FtGROUP %E%s", g->DescriptionString());
|
||||
|
||||
switch(g->solved.how) {
|
||||
case Group::SOLVED_OKAY:
|
||||
Printf(true, " %Fsgroup solved okay%E");
|
||||
break;
|
||||
|
||||
case Group::DIDNT_CONVERGE:
|
||||
Printf(true, " %FxSOLVE FAILED!%Fd no convergence");
|
||||
break;
|
||||
|
||||
case Group::SINGULAR_JACOBIAN: {
|
||||
Printf(true, "%FxSOLVE FAILED!%Fd inconsistent system");
|
||||
Printf(true, "remove any one of these to fix it");
|
||||
for(int i = 0; i < g->solved.remove.n; i++) {
|
||||
hConstraint hc = g->solved.remove.elem[i];
|
||||
Constraint *c = SS.GetConstraint(hc);
|
||||
Printf(false, "%Bp %Fl%Ll%D%f%h%s%E",
|
||||
(i & 1) ? 'd' : 'a',
|
||||
c->h.v, (&TextWindow::ScreenSelectConstraint),
|
||||
(&TextWindow::ScreenHoverConstraint),
|
||||
c->DescriptionString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextWindow::ShowRequestInfo(void) {
|
||||
Request *r = SS.GetRequest(shown->request);
|
||||
|
||||
|
|
14
ui.h
14
ui.h
|
@ -27,6 +27,7 @@ public:
|
|||
int link;
|
||||
DWORD data;
|
||||
LinkFunction *f;
|
||||
LinkFunction *h;
|
||||
} meta[MAX_ROWS][MAX_COLS];
|
||||
int top[MAX_ROWS]; // in half-line units, or -1 for unused
|
||||
|
||||
|
@ -41,9 +42,7 @@ public:
|
|||
// State for the screen that we are showing in the text window.
|
||||
static const int SCREEN_LIST_OF_GROUPS = 0;
|
||||
static const int SCREEN_GROUP_INFO = 1;
|
||||
static const int SCREEN_REQUEST_INFO = 2;
|
||||
static const int SCREEN_ENTIY_INFO = 3;
|
||||
static const int SCREEN_CONSTRAINT_INFO = 4;
|
||||
static const int SCREEN_GROUP_SOLVE_INFO = 2;
|
||||
typedef struct {
|
||||
int screen;
|
||||
hGroup group;
|
||||
|
@ -56,6 +55,8 @@ public:
|
|||
int history;
|
||||
ShownState *shown;
|
||||
|
||||
static void ReportHowGroupSolved(hGroup hg);
|
||||
|
||||
void ShowHeader(void);
|
||||
// These are self-contained screens, that show some information about
|
||||
// the sketch.
|
||||
|
@ -64,15 +65,20 @@ public:
|
|||
void ShowRequestInfo(void);
|
||||
void ShowEntityInfo(void);
|
||||
void ShowConstraintInfo(void);
|
||||
void ShowGroupSolveInfo(void);
|
||||
|
||||
void OneScreenForwardTo(int screen);
|
||||
static void ScreenSelectGroup(int link, DWORD v);
|
||||
static void ScreenActivateGroup(int link, DWORD v);
|
||||
static void ScreenToggleGroupShown(int link, DWORD v);
|
||||
static void ScreenHowGroupSolved(int link, DWORD v);
|
||||
static void ScreenShowGroupsSpecial(int link, DWORD v);
|
||||
|
||||
static void ScreenHoverConstraint(int link, DWORD v);
|
||||
static void ScreenHoverRequest(int link, DWORD v);
|
||||
static void ScreenSelectRequest(int link, DWORD v);
|
||||
static void ScreenSelectConstraint(int link, DWORD v);
|
||||
|
||||
static void ScreenChangeExtrudeSides(int link, DWORD v);
|
||||
static void ScreenChangeMeshCombine(int link, DWORD v);
|
||||
|
||||
|
@ -218,6 +224,8 @@ public:
|
|||
public:
|
||||
hEntity entity;
|
||||
hConstraint constraint;
|
||||
|
||||
bool emphasized;
|
||||
|
||||
void Draw(void);
|
||||
|
||||
|
|
|
@ -288,6 +288,9 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_MOUSEMOVE: {
|
||||
GraphicsWindow::Selection ps = SS.GW.hover;
|
||||
SS.GW.hover.Clear();
|
||||
|
||||
int x = LOWORD(lParam);
|
||||
int y = HIWORD(lParam);
|
||||
|
||||
|
@ -303,25 +306,30 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
if(r >= SS.TW.rows) {
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
break;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#define META (SS.TW.meta[r][c])
|
||||
if(msg == WM_MOUSEMOVE) {
|
||||
if(SS.TW.meta[r][c].link) {
|
||||
if(META.link) {
|
||||
SetCursor(LoadCursor(NULL, IDC_HAND));
|
||||
if(META.h) {
|
||||
(META.h)(META.link, META.data);
|
||||
}
|
||||
} else {
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
}
|
||||
} else {
|
||||
if(SS.TW.meta[r][c].link && SS.TW.meta[r][c].f) {
|
||||
(SS.TW.meta[r][c].f)(
|
||||
SS.TW.meta[r][c].link,
|
||||
SS.TW.meta[r][c].data
|
||||
);
|
||||
if(META.link && META.f) {
|
||||
(META.f)(META.link, META.data);
|
||||
SS.TW.Show();
|
||||
InvalidateGraphics();
|
||||
}
|
||||
}
|
||||
done:
|
||||
if(!ps.Equals(&(SS.GW.hover))) {
|
||||
InvalidateGraphics();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -361,6 +369,12 @@ static BOOL ProcessKeyDown(WPARAM wParam)
|
|||
}
|
||||
}
|
||||
|
||||
if(wParam == VK_BACK && !GraphicsEditControlIsVisible()) {
|
||||
TextWindow::ScreenNavigation('b', 0);
|
||||
SS.TW.Show();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int c;
|
||||
switch(wParam) {
|
||||
case VK_OEM_PLUS: c = '+'; break;
|
||||
|
|
Loading…
Reference in New Issue
Block a user