Standardize the behaviour of constraints, by assigning them a

workplane: a free constraint works in three-space (e.g. true
distance), and a constraint in a workplane works in that plane
(e.g. projected distance). And make the solver go automatically,
though solver itself has lots of pieces missing.

[git-p4: depot-paths = "//depot/solvespace/": change = 1691]
This commit is contained in:
Jonathan Westhues 2008-04-26 21:00:12 -08:00
parent 15476d4732
commit bfc7109e0c
10 changed files with 173 additions and 113 deletions

View File

@ -2,6 +2,8 @@
hConstraint Constraint::AddConstraint(Constraint *c) { hConstraint Constraint::AddConstraint(Constraint *c) {
SS.constraint.AddAndAssignId(c); SS.constraint.AddAndAssignId(c);
if(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS) SS.Solve();
return c->h; return c->h;
} }
@ -9,22 +11,24 @@ void Constraint::ConstrainCoincident(hEntity ptA, hEntity ptB) {
Constraint c; Constraint c;
memset(&c, 0, sizeof(c)); memset(&c, 0, sizeof(c));
c.group = SS.GW.activeGroup; c.group = SS.GW.activeGroup;
c.workplane = SS.GW.activeWorkplane;
c.type = Constraint::POINTS_COINCIDENT; c.type = Constraint::POINTS_COINCIDENT;
c.ptA = ptA; c.ptA = ptA;
c.ptB = ptB; c.ptB = ptB;
SS.constraint.AddAndAssignId(&c); AddConstraint(&c);
} }
void Constraint::MenuConstrain(int id) { void Constraint::MenuConstrain(int id) {
Constraint c; Constraint c;
memset(&c, 0, sizeof(c)); memset(&c, 0, sizeof(c));
c.group = SS.GW.activeGroup; c.group = SS.GW.activeGroup;
c.workplane = SS.GW.activeWorkplane;
SS.GW.GroupSelection(); SS.GW.GroupSelection();
#define gs (SS.GW.gs) #define gs (SS.GW.gs)
switch(id) { switch(id) {
case GraphicsWindow::MNU_DISTANCE_DIA: case GraphicsWindow::MNU_DISTANCE_DIA: {
if(gs.points == 2 && gs.n == 2) { if(gs.points == 2 && gs.n == 2) {
c.type = PT_PT_DISTANCE; c.type = PT_PT_DISTANCE;
c.ptA = gs.point[0]; c.ptA = gs.point[0];
@ -38,11 +42,16 @@ void Constraint::MenuConstrain(int id) {
Error("Bad selection for distance / diameter constraint."); Error("Bad selection for distance / diameter constraint.");
return; return;
} }
c.disp.offset = Vector::MakeFrom(50, 50, 50); Vector n = SS.GW.projRight.Cross(SS.GW.projUp);
Vector a = SS.GetEntity(c.ptA)->PointGetCoords();
Vector b = SS.GetEntity(c.ptB)->PointGetCoords();
c.disp.offset = n.Cross(a.Minus(b)).WithMagnitude(50);
c.exprA = Expr::FromString("0")->DeepCopyKeep(); c.exprA = Expr::FromString("0")->DeepCopyKeep();
c.ModifyToSatisfy(); c.ModifyToSatisfy();
AddConstraint(&c); AddConstraint(&c);
break; break;
}
case GraphicsWindow::MNU_ON_ENTITY: case GraphicsWindow::MNU_ON_ENTITY:
if(gs.points == 2 && gs.n == 2) { if(gs.points == 2 && gs.n == 2) {
@ -75,6 +84,10 @@ void Constraint::MenuConstrain(int id) {
case GraphicsWindow::MNU_VERTICAL: case GraphicsWindow::MNU_VERTICAL:
case GraphicsWindow::MNU_HORIZONTAL: { case GraphicsWindow::MNU_HORIZONTAL: {
hEntity ha, hb; hEntity ha, hb;
if(c.workplane.v == Entity::FREE_IN_3D.v) {
Error("Select workplane before constraining horiz/vert.");
return;
}
if(gs.lineSegments == 1 && gs.n == 1) { if(gs.lineSegments == 1 && gs.n == 1) {
c.entityA = gs.entity[0]; c.entityA = gs.entity[0];
Entity *e = SS.GetEntity(c.entityA); Entity *e = SS.GetEntity(c.entityA);
@ -87,24 +100,6 @@ void Constraint::MenuConstrain(int id) {
Error("Bad selection for horizontal / vertical constraint."); Error("Bad selection for horizontal / vertical constraint.");
return; return;
} }
Entity *ea = SS.GetEntity(ha);
Entity *eb = SS.GetEntity(hb);
if(ea->workplane.v == Entity::FREE_IN_3D.v &&
eb->workplane.v == Entity::FREE_IN_3D.v)
{
Error("Horizontal/vertical constraint applies only to "
"entities drawn in a 2d coordinate system.");
return;
}
if(eb->workplane.v == SS.GW.activeWorkplane.v) {
// We are constraining two points in two different wrkpls; so
// we have two choices for the definitons of the coordinate
// directions. ptA's gets chosen, so make sure that's the
// active workplane.
hEntity t = c.ptA;
c.ptA = c.ptB;
c.ptB = t;
}
if(id == GraphicsWindow::MNU_HORIZONTAL) { if(id == GraphicsWindow::MNU_HORIZONTAL) {
c.type = HORIZONTAL; c.type = HORIZONTAL;
} else { } else {
@ -118,6 +113,15 @@ void Constraint::MenuConstrain(int id) {
SS.Solve(); SS.Solve();
return; return;
case GraphicsWindow::MNU_SOLVE_AUTO:
if(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS) {
SS.GW.solving = GraphicsWindow::DONT_SOLVE;
} else {
SS.GW.solving = GraphicsWindow::SOLVE_ALWAYS;
}
SS.GW.EnsureValidActives();
break;
default: oops(); default: oops();
} }
@ -125,33 +129,31 @@ void Constraint::MenuConstrain(int id) {
InvalidateGraphics(); InvalidateGraphics();
} }
Expr *Constraint::Distance(hEntity hpa, hEntity hpb) { Expr *Constraint::Distance(hEntity wrkpl, hEntity hpa, hEntity hpb) {
Entity *pa = SS.GetEntity(hpa); Entity *pa = SS.GetEntity(hpa);
Entity *pb = SS.GetEntity(hpb); Entity *pb = SS.GetEntity(hpb);
if(!(pa->IsPoint() && pb->IsPoint())) oops(); if(!(pa->IsPoint() && pb->IsPoint())) oops();
if(pa->type == Entity::POINT_IN_2D && if(wrkpl.v == Entity::FREE_IN_3D.v) {
pb->type == Entity::POINT_IN_2D && // This is true distance
pa->workplane.v == pb->workplane.v) ExprVector ea, eb, eab;
{ ea = pa->PointGetExprs();
// A nice case; they are both in the same workplane, so I can write eb = pb->PointGetExprs();
// the equation in terms of the basis vectors in that csys. eab = ea.Minus(eb);
Expr *du = Expr::FromParam(pa->param[0])->Minus(
Expr::FromParam(pb->param[0])); return eab.Magnitude();
Expr *dv = Expr::FromParam(pa->param[1])->Minus( } else {
Expr::FromParam(pb->param[1])); // This is projected distance, in the given workplane.
Expr *au, *av, *bu, *bv;
pa->PointGetExprsInWorkplane(wrkpl, &au, &av);
pb->PointGetExprsInWorkplane(wrkpl, &bu, &bv);
Expr *du = au->Minus(bu);
Expr *dv = av->Minus(bv);
return ((du->Square())->Plus(dv->Square()))->Sqrt(); return ((du->Square())->Plus(dv->Square()))->Sqrt();
} }
// The usual case, just write it in terms of the coordinates
ExprVector ea, eb, eab;
ea = pa->PointGetExprs();
eb = pb->PointGetExprs();
eab = ea.Minus(eb);
return eab.Magnitude();
} }
void Constraint::ModifyToSatisfy(void) { void Constraint::ModifyToSatisfy(void) {
@ -182,59 +184,39 @@ void Constraint::AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index) {
void Constraint::Generate(IdList<Equation,hEquation> *l) { void Constraint::Generate(IdList<Equation,hEquation> *l) {
switch(type) { switch(type) {
case PT_PT_DISTANCE: case PT_PT_DISTANCE:
AddEq(l, Distance(ptA, ptB)->Minus(exprA), 0); AddEq(l, Distance(workplane, ptA, ptB)->Minus(exprA), 0);
break; break;
case EQUAL_LENGTH_LINES: { case EQUAL_LENGTH_LINES: {
Entity *a = SS.GetEntity(entityA); Entity *a = SS.GetEntity(entityA);
Entity *b = SS.GetEntity(entityB); Entity *b = SS.GetEntity(entityB);
AddEq(l, Distance(a->point[0], a->point[1])->Minus( AddEq(l, Distance(workplane, a->point[0], a->point[1])->Minus(
Distance(b->point[0], b->point[1])), 0); Distance(workplane, b->point[0], b->point[1])), 0);
break; break;
} }
case POINTS_COINCIDENT: { case POINTS_COINCIDENT: {
Entity *a = SS.GetEntity(ptA); Entity *a = SS.GetEntity(ptA);
Entity *b = SS.GetEntity(ptB); Entity *b = SS.GetEntity(ptB);
if(!a->IsPointIn3d() && b->IsPointIn3d()) { if(workplane.v == Entity::FREE_IN_3D.v) {
Entity *t = a; ExprVector pa = a->PointGetExprs();
a = b; b = t; ExprVector pb = b->PointGetExprs();
} AddEq(l, pa.x->Minus(pb.x), 0);
if(a->IsPointIn3d() && b->IsPointIn3d()) { AddEq(l, pa.y->Minus(pb.y), 1);
// Easy case: both points have 3 DOF, so write three eqs. AddEq(l, pa.z->Minus(pb.z), 2);
ExprVector ea, eb, eab;
ea = a->PointGetExprs();
eb = b->PointGetExprs();
eab = ea.Minus(eb);
AddEq(l, eab.x, 0);
AddEq(l, eab.y, 1);
AddEq(l, eab.z, 2);
} else if(!(a->IsPointIn3d() || b->IsPointIn3d()) &&
(a->workplane.v == b->workplane.v))
{
// Both in same workplane, nice.
AddEq(l, Expr::FromParam(a->param[0])->Minus(
Expr::FromParam(b->param[0])), 0);
AddEq(l, Expr::FromParam(a->param[1])->Minus(
Expr::FromParam(b->param[1])), 1);
} else { } else {
// Either two 2 DOF points in different planes, or one Expr *au, *av;
// 3 DOF point and one 2 DOF point. Either way, write two Expr *bu, *bv;
// equations on the projection of a into b's plane. a->PointGetExprsInWorkplane(workplane, &au, &av);
ExprVector p3; b->PointGetExprsInWorkplane(workplane, &bu, &bv);
p3 = a->PointGetExprs(); AddEq(l, au->Minus(bu), 0);
Entity *w = SS.GetEntity(b->workplane); AddEq(l, av->Minus(bv), 1);
ExprVector offset = w->WorkplaneGetOffsetExprs();
p3 = p3.Minus(offset);
ExprVector u, v;
w->WorkplaneGetBasisExprs(&u, &v);
AddEq(l, Expr::FromParam(b->param[0])->Minus(p3.Dot(u)), 0);
AddEq(l, Expr::FromParam(b->param[1])->Minus(p3.Dot(v)), 1);
} }
break; break;
} }
case PT_IN_PLANE: { case PT_IN_PLANE: {
// This one works the same, whether projected or not.
ExprVector p, n; ExprVector p, n;
Expr *d; Expr *d;
p = SS.GetEntity(ptA)->PointGetExprs(); p = SS.GetEntity(ptA)->PointGetExprs();
@ -256,25 +238,12 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
} }
Entity *a = SS.GetEntity(ha); Entity *a = SS.GetEntity(ha);
Entity *b = SS.GetEntity(hb); Entity *b = SS.GetEntity(hb);
if(a->workplane.v == Entity::FREE_IN_3D.v) {
Entity *t = a; Expr *au, *av, *bu, *bv;
a = b; a->PointGetExprsInWorkplane(workplane, &au, &av);
b = t; b->PointGetExprsInWorkplane(workplane, &bu, &bv);
}
AddEq(l, (type == HORIZONTAL) ? av->Minus(bv) : au->Minus(bu), 0);
if(a->workplane.v == b->workplane.v) {
int i = (type == HORIZONTAL) ? 1 : 0;
AddEq(l, Expr::FromParam(a->param[i])->Minus(
Expr::FromParam(b->param[i])), 0);
} else {
Entity *w = SS.GetEntity(a->workplane);
ExprVector u, v;
w->WorkplaneGetBasisExprs(&u, &v);
ExprVector norm = (type == HORIZONTAL) ? v : u;
ExprVector pa = a->PointGetExprs();
ExprVector pb = b->PointGetExprs();
AddEq(l, (pa.Minus(pb)).Dot(norm), 0);
}
break; break;
} }

View File

@ -196,6 +196,43 @@ ExprVector Entity::PointGetExprs(void) {
return r; return r;
} }
void Entity::PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v) {
if(type == POINT_IN_2D && workplane.v == wrkpl.v) {
// They want our coordinates in the form that we've written them,
// very nice.
*u = Expr::FromParam(param[0]);
*v = Expr::FromParam(param[1]);
} else {
// Get the offset and basis vectors for this weird exotic csys.
Entity *w = SS.GetEntity(wrkpl);
ExprVector wp = w->WorkplaneGetOffsetExprs();
ExprVector wu, wv;
w->WorkplaneGetBasisExprs(&wu, &wv);
// Get our coordinates in three-space, and project them into that
// coordinate system.
ExprVector ev = PointGetExprs();
ev = ev.Minus(wp);
*u = ev.Dot(wu);
*v = ev.Dot(wv);
}
}
bool Entity::PointIsLocked(void) {
// A point is locked if none of its coordinates get assumed.
if(type == POINT_IN_3D) {
if(SS.GetParam(param[0])->assumed) return false;
if(SS.GetParam(param[1])->assumed) return false;
if(SS.GetParam(param[2])->assumed) return false;
} else if(type == POINT_IN_2D) {
if(SS.GetParam(param[0])->assumed) return false;
if(SS.GetParam(param[1])->assumed) return false;
} else {
oops();
}
return true;
}
void Entity::LineDrawOrGetDistance(Vector a, Vector b) { void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
if(dogd.drawing) { if(dogd.drawing) {
glBegin(GL_LINE_STRIP); glBegin(GL_LINE_STRIP);
@ -272,7 +309,9 @@ void Entity::DrawOrGetDistance(int order) {
glEnd(); glEnd();
} else { } else {
Point2d pp = SS.GW.ProjectPoint(v); Point2d pp = SS.GW.ProjectPoint(v);
dogd.dmin = pp.DistanceTo(dogd.mp) - 5; // Make a free point slightly easier to select, so that with
// coincident points, we select the free one.
dogd.dmin = pp.DistanceTo(dogd.mp) - (PointIsLocked() ? 3 : 4);
} }
break; break;
} }

View File

@ -75,6 +75,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'c', "Constraint.h.v", 'x', &(SS.sv.c.h.v) }, { 'c', "Constraint.h.v", 'x', &(SS.sv.c.h.v) },
{ 'c', "Constraint.type", 'd', &(SS.sv.c.type) }, { 'c', "Constraint.type", 'd', &(SS.sv.c.type) },
{ 'c', "Constraint.group.v", 'x', &(SS.sv.c.group.v) }, { 'c', "Constraint.group.v", 'x', &(SS.sv.c.group.v) },
{ 'c', "Constraint.workplane.v", 'x', &(SS.sv.c.workplane.v) },
{ 'c', "Constraint.exprA", 'E', &(SS.sv.c.exprA) }, { 'c', "Constraint.exprA", 'E', &(SS.sv.c.exprA) },
{ 'c', "Constraint.exprB", 'E', &(SS.sv.c.exprB) }, { 'c', "Constraint.exprB", 'E', &(SS.sv.c.exprB) },
{ 'c', "Constraint.ptA.v", 'x', &(SS.sv.c.ptA.v) }, { 'c', "Constraint.ptA.v", 'x', &(SS.sv.c.ptA.v) },

View File

@ -31,6 +31,8 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Zoom &Out\t-", MNU_ZOOM_OUT, '-', mView }, { 1, "Zoom &Out\t-", MNU_ZOOM_OUT, '-', mView },
{ 1, "Zoom To &Fit\tF", MNU_ZOOM_TO_FIT, 'F', mView }, { 1, "Zoom To &Fit\tF", MNU_ZOOM_TO_FIT, 'F', mView },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "Show Text &Window\tTab", MNU_SHOW_TEXT_WND, '\t', mView },
{ 1, NULL, 0, NULL },
{ 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, mView }, { 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, mView },
{ 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView }, { 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView },
@ -80,6 +82,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "Sym&bolic Equation\tShift+B", 0, 'B'|S, NULL }, { 1, "Sym&bolic Equation\tShift+B", 0, 'B'|S, NULL },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "Sol&ve Automatically\tShift+Tab", MNU_SOLVE_AUTO, '\t'|S, mCon },
{ 1, "Solve Once Now\tSpace", MNU_SOLVE_NOW, ' ', mCon }, { 1, "Solve Once Now\tSpace", MNU_SOLVE_NOW, ' ', mCon },
{ 0, "&Help", 0, NULL }, { 0, "&Help", 0, NULL },
@ -106,6 +109,11 @@ void GraphicsWindow::Init(void) {
showPoints = true; showPoints = true;
showAllGroups = true; showAllGroups = true;
showConstraints = true; showConstraints = true;
solving = SOLVE_ALWAYS;
showTextWindow = true;
ShowTextWindow(showTextWindow);
} }
void GraphicsWindow::NormalizeProjectionVectors(void) { void GraphicsWindow::NormalizeProjectionVectors(void) {
@ -174,6 +182,11 @@ void GraphicsWindow::MenuView(int id) {
case MNU_ZOOM_TO_FIT: case MNU_ZOOM_TO_FIT:
break; break;
case MNU_SHOW_TEXT_WND:
SS.GW.showTextWindow = !SS.GW.showTextWindow;
SS.GW.EnsureValidActives();
break;
case MNU_UNITS_MM: case MNU_UNITS_MM:
SS.GW.viewUnits = UNIT_MM; SS.GW.viewUnits = UNIT_MM;
SS.GW.EnsureValidActives(); SS.GW.EnsureValidActives();
@ -228,6 +241,11 @@ void GraphicsWindow::EnsureValidActives(void) {
} }
CheckMenuById(MNU_UNITS_MM, viewUnits == UNIT_MM); CheckMenuById(MNU_UNITS_MM, viewUnits == UNIT_MM);
CheckMenuById(MNU_UNITS_INCHES, viewUnits == UNIT_INCHES); CheckMenuById(MNU_UNITS_INCHES, viewUnits == UNIT_INCHES);
ShowTextWindow(SS.GW.showTextWindow);
CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow);
CheckMenuById(MNU_SOLVE_AUTO, (SS.GW.solving == SOLVE_ALWAYS));
} }
void GraphicsWindow::MenuEdit(int id) { void GraphicsWindow::MenuEdit(int id) {
@ -415,7 +433,9 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
UpdateDraggedPoint(&(c->disp.offset), x, y); UpdateDraggedPoint(&(c->disp.offset), x, y);
} else if(leftDown && pendingOperation == DRAGGING_POINT) { } else if(leftDown && pendingOperation == DRAGGING_POINT) {
UpdateDraggedEntity(pendingPoint, x, y); UpdateDraggedEntity(pendingPoint, x, y);
HitTestMakeSelection(mp); if(solving == SOLVE_ALWAYS) {
SS.Solve();
}
} }
// No buttons pressed. // No buttons pressed.
@ -543,6 +563,9 @@ hRequest GraphicsWindow::AddRequest(int type) {
r.type = type; r.type = type;
SS.request.AddAndAssignId(&r); SS.request.AddAndAssignId(&r);
SS.GenerateAll(); SS.GenerateAll();
if(solving == SOLVE_ALWAYS) SS.Solve();
return r.h; return r.h;
} }
@ -707,6 +730,7 @@ void GraphicsWindow::EditControlDone(char *s) {
Expr::FreeKeep(&(c->exprA)); Expr::FreeKeep(&(c->exprA));
c->exprA = e->DeepCopyKeep(); c->exprA = e->DeepCopyKeep();
HideGraphicsEditControl(); HideGraphicsEditControl();
if(SS.GW.solving == SOLVE_ALWAYS) SS.Solve();
} else { } else {
Error("Not a valid number or expression: '%s'", s); Error("Not a valid number or expression: '%s'", s);
} }

View File

@ -167,8 +167,10 @@ public:
bool IsPoint(void); bool IsPoint(void);
bool IsPointIn3d(void); bool IsPointIn3d(void);
// Applies for any of the point types // Applies for any of the point types
bool PointIsLocked(void);
Vector PointGetCoords(void); Vector PointGetCoords(void);
ExprVector PointGetExprs(void); ExprVector PointGetExprs(void);
void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v);
void PointForceTo(Vector v); void PointForceTo(Vector v);
bool PointIsFromReferences(void); bool PointIsFromReferences(void);
bool PointIsKnown(void); bool PointIsKnown(void);
@ -204,6 +206,7 @@ public:
double val; double val;
bool known; bool known;
bool assumed;
}; };
@ -287,7 +290,7 @@ public:
// Some helpers when generating symbolic constraint equations // Some helpers when generating symbolic constraint equations
void ModifyToSatisfy(void); void ModifyToSatisfy(void);
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index); void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
static Expr *Distance(hEntity pa, hEntity pb); static Expr *Distance(hEntity workplane, hEntity pa, hEntity pb);
static void ConstrainCoincident(hEntity ptA, hEntity ptB); static void ConstrainCoincident(hEntity ptA, hEntity ptB);
}; };

View File

@ -20,6 +20,7 @@ void SolveSpace::Init(char *cmdLine) {
void SolveSpace::GenerateAll(void) { void SolveSpace::GenerateAll(void) {
int i; int i;
// Don't lose our numerical guesses when we regenerate.
IdList<Param,hParam> prev; IdList<Param,hParam> prev;
param.MoveSelfInto(&prev); param.MoveSelfInto(&prev);
@ -28,10 +29,12 @@ void SolveSpace::GenerateAll(void) {
request.elem[i].Generate(&entity, &param); request.elem[i].Generate(&entity, &param);
} }
// Restore the numerical guesses.
for(i = 0; i < param.n; i++) { for(i = 0; i < param.n; i++) {
Param *p = prev.FindByIdNoOops(param.elem[i].h); Param *p = prev.FindByIdNoOops(param.elem[i].h);
if(p) { if(p) {
param.elem[i].val = p->val; param.elem[i].val = p->val;
param.elem[i].assumed = p->assumed;
} }
} }

View File

@ -40,10 +40,11 @@ void ShowGraphicsEditControl(int x, int y, char *s);
void HideGraphicsEditControl(void); void HideGraphicsEditControl(void);
BOOL GraphicsEditControlIsVisible(void); BOOL GraphicsEditControlIsVisible(void);
void InvalidateGraphics(void); void ShowTextWindow(BOOL visible);
void InvalidateText(void); void InvalidateText(void);
SDWORD GetMilliseconds(void); void InvalidateGraphics(void);
void PaintGraphics(void); void PaintGraphics(void);
SDWORD GetMilliseconds(void);
void dbp(char *str, ...); void dbp(char *str, ...);
void Error(char *str, ...); void Error(char *str, ...);

View File

@ -181,9 +181,6 @@ bool System::NewtonSolve(int tag) {
// Take the Newton step; // Take the Newton step;
// J(x_n) (x_{n+1} - x_n) = 0 - F(x_n) // J(x_n) (x_{n+1} - x_n) = 0 - F(x_n)
for(i = 0; i < mat.m; i++) { for(i = 0; i < mat.m; i++) {
dbp("mat.X[%d] = %.3f", i, mat.X[i]);
dbp("modifying param %08x, now %.3f", mat.param[i],
param.FindById(mat.param[i])->val);
(param.FindById(mat.param[i]))->val -= mat.X[i]; (param.FindById(mat.param[i]))->val -= mat.X[i];
} }
@ -210,10 +207,10 @@ bool System::NewtonSolve(int tag) {
bool System::Solve(void) { bool System::Solve(void) {
int i, j; int i, j;
dbp("%d equations", eq.n); /* dbp("%d equations", eq.n);
for(i = 0; i < eq.n; i++) { for(i = 0; i < eq.n; i++) {
dbp(" %s = 0", eq.elem[i].e->Print()); dbp(" %s = 0", eq.elem[i].e->Print());
} } */
param.ClearTags(); param.ClearTags();
eq.ClearTags(); eq.ClearTags();
@ -221,23 +218,30 @@ bool System::Solve(void) {
WriteJacobian(0, 0); WriteJacobian(0, 0);
EvalJacobian(); EvalJacobian();
/*
for(i = 0; i < mat.m; i++) { for(i = 0; i < mat.m; i++) {
for(j = 0; j < mat.n; j++) { for(j = 0; j < mat.n; j++) {
dbp("A[%d][%d] = %.3f", i, j, mat.A.num[i][j]); dbp("A[%d][%d] = %.3f", i, j, mat.A.num[i][j]);
} }
} } */
GaussJordan(); GaussJordan();
dbp("bound states:"); /* dbp("bound states:");
for(j = 0; j < mat.n; j++) { for(j = 0; j < mat.n; j++) {
dbp(" param %08x: %d", mat.param[j], mat.bound[j]); dbp(" param %08x: %d", mat.param[j], mat.bound[j]);
} } */
// Fix any still-free variables wherever they are now. // Fix any still-free variables wherever they are now.
for(j = 0; j < mat.n; j++) { for(j = 0; j < mat.n; j++) {
if(mat.bound[j]) continue; if(mat.bound[j]) continue;
param.FindById(mat.param[j])->tag = ASSUMED; Param *p = param.FindByIdNoOops(mat.param[j]);
if(!p) {
// This is parameter does not occur in this group, so it's
// not available to assume.
continue;
}
p->tag = ASSUMED;
} }
bool ok = NewtonSolve(0); bool ok = NewtonSolve(0);
@ -250,6 +254,9 @@ bool System::Solve(void) {
Param *pp = SS.GetParam(p->h); Param *pp = SS.GetParam(p->h);
pp->val = p->val; pp->val = p->val;
pp->known = true; pp->known = true;
// The main param table keeps track of what was assumed, to
// choose which point to drag so that it actually moves.
pp->assumed = (p->tag == ASSUMED);
} }
} }

13
ui.h
View File

@ -4,8 +4,8 @@
class TextWindow { class TextWindow {
public: public:
static const int MAX_COLS = 150; static const int MAX_COLS = 100;
static const int MAX_ROWS = 300; static const int MAX_ROWS = 200;
#ifndef RGB #ifndef RGB
#define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16)) #define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16))
@ -87,11 +87,12 @@ public:
MNU_ZOOM_IN, MNU_ZOOM_IN,
MNU_ZOOM_OUT, MNU_ZOOM_OUT,
MNU_ZOOM_TO_FIT, MNU_ZOOM_TO_FIT,
MNU_UNSELECT_ALL, MNU_SHOW_TEXT_WND,
MNU_UNITS_INCHES, MNU_UNITS_INCHES,
MNU_UNITS_MM, MNU_UNITS_MM,
// Edit // Edit
MNU_DELETE, MNU_DELETE,
MNU_UNSELECT_ALL,
// Request // Request
MNU_SEL_WORKPLANE, MNU_SEL_WORKPLANE,
MNU_FREE_IN_3D, MNU_FREE_IN_3D,
@ -105,6 +106,7 @@ public:
MNU_ON_ENTITY, MNU_ON_ENTITY,
MNU_HORIZONTAL, MNU_HORIZONTAL,
MNU_VERTICAL, MNU_VERTICAL,
MNU_SOLVE_AUTO,
MNU_SOLVE_NOW, MNU_SOLVE_NOW,
} MenuId; } MenuId;
typedef void MenuHandler(int id); typedef void MenuHandler(int id);
@ -201,9 +203,14 @@ public:
bool showPoints; bool showPoints;
bool showAllGroups; bool showAllGroups;
bool showConstraints; bool showConstraints;
bool showTextWindow;
static void ToggleBool(int link, DWORD v); static void ToggleBool(int link, DWORD v);
static void ToggleAnyDatumShown(int link, DWORD v); static void ToggleAnyDatumShown(int link, DWORD v);
static const int DONT_SOLVE = 0;
static const int SOLVE_ALWAYS = 1;
int solving;
void UpdateDraggedPoint(Vector *pos, double mx, double my); void UpdateDraggedPoint(Vector *pos, double mx, double my);
void UpdateDraggedEntity(hEntity hp, double mx, double my); void UpdateDraggedEntity(hEntity hp, double mx, double my);

View File

@ -332,6 +332,7 @@ static BOOL ProcessKeyDown(WPARAM wParam)
case VK_OEM_5: c = '\\'; break; case VK_OEM_5: c = '\\'; break;
case VK_SPACE: c = ' '; break; case VK_SPACE: c = ' '; break;
case VK_DELETE: c = 127; break; case VK_DELETE: c = 127; break;
case VK_TAB: c = '\t'; break;
default: default:
c = wParam; c = wParam;
@ -351,6 +352,11 @@ static BOOL ProcessKeyDown(WPARAM wParam)
return FALSE; return FALSE;
} }
void ShowTextWindow(BOOL visible)
{
ShowWindow(TextWnd, visible ? SW_SHOWNOACTIVATE : SW_HIDE);
}
static HGLRC CreateGlContext(HDC hdc) static HGLRC CreateGlContext(HDC hdc)
{ {
PIXELFORMATDESCRIPTOR pfd; PIXELFORMATDESCRIPTOR pfd;