Don't keep a dimension or group's user-entered numerical value as

an Expr *, since that complicates multiple units and also memory
management. Now it's just a double.

[git-p4: depot-paths = "//depot/solvespace/": change = 1791]
solver
Jonathan Westhues 2008-06-14 00:43:38 -08:00
parent 1674443ab2
commit 28e3f0abab
10 changed files with 32 additions and 87 deletions

View File

@ -115,7 +115,7 @@ void Constraint::MenuConstrain(int id) {
c.disp.offset = Vector::From(0, 0, 0);
}
c.exprA = Expr::From("0")->DeepCopyKeep();
c.valA = 0;
c.ModifyToSatisfy();
AddConstraint(&c);
break;
@ -175,7 +175,7 @@ void Constraint::MenuConstrain(int id) {
return;
}
c.exprA = Expr::From("0")->DeepCopyKeep();
c.valA = 0;
c.ModifyToSatisfy();
AddConstraint(&c);
break;
@ -327,7 +327,7 @@ void Constraint::MenuConstrain(int id) {
c.type = ANGLE;
c.entityA = gs.vector[0];
c.entityB = gs.vector[1];
c.exprA = Expr::From(0.0)->DeepCopyKeep();
c.valA = 0;
c.otherAngle = true;
} else {
Error("Bad selection for angle constraint.");
@ -352,7 +352,7 @@ void Constraint::MenuConstrain(int id) {
case GraphicsWindow::MNU_COMMENT:
c.type = COMMENT;
c.comment.strcpy("NEW COMMENT -- DOUBLE-CLICK TO EDIT");
c.disp.offset = SS.GW.offset;
c.disp.offset = SS.GW.offset.ScaledBy(-1);
AddConstraint(&c);
break;
@ -485,9 +485,7 @@ void Constraint::ModifyToSatisfy(void) {
b = b.ProjectVectorInto(workplane);
}
double c = (a.Dot(b))/(a.Magnitude() * b.Magnitude());
double theta = acos(c)*180/PI;
Expr::FreeKeep(&exprA);
exprA = Expr::From(theta)->DeepCopyKeep();
valA = acos(c)*180/PI;
} else {
// We'll fix these ones up by looking at their symbolic equation;
// that means no extra work.
@ -499,11 +497,8 @@ void Constraint::ModifyToSatisfy(void) {
if(l.n != 1) oops();
// These equations are written in the form f(...) - d = 0, where
// d is the value of the exprA.
double v = (l.elem[0].e)->Eval();
double nd = exprA->Eval() + v;
Expr::FreeKeep(&exprA);
exprA = Expr::From(nd)->DeepCopyKeep();
// d is the value of the valA.
valA += (l.elem[0].e)->Eval();
l.Clear();
}
@ -522,8 +517,7 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
}
}
void Constraint::GenerateReal(IdList<Equation,hEquation> *l) {
Expr *exA = NULL;
if(exprA) exA = exprA->DeepCopy();
Expr *exA = Expr::From(valA);
switch(type) {
case PT_PT_DISTANCE:
@ -546,7 +540,7 @@ void Constraint::GenerateReal(IdList<Equation,hEquation> *l) {
Entity *f = SS.GetEntity(entityA);
ExprVector p0 = f->FaceGetPointExprs();
ExprVector n = f->FaceGetNormalExprs();
AddEq(l, (pt.Minus(p0)).Dot(n)->Minus(exprA), 0);
AddEq(l, (pt.Minus(p0)).Dot(n)->Minus(exA), 0);
break;
}

View File

@ -556,8 +556,8 @@ void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
Vector p3 = c->GetLabelPos();
Point2d p2 = ProjectPoint(p3);
char *s = (c->type == Constraint::COMMENT) ? c->comment.str :
c->exprA->Print();
ShowGraphicsEditControl((int)p2.x, (int)p2.y, s);
ToString(c->valA);
ShowGraphicsEditControl((int)p2.x, (int)p2.y-4, s);
}
}
@ -575,8 +575,7 @@ void GraphicsWindow::EditControlDone(char *s) {
if(e) {
SS.UndoRemember();
Expr::FreeKeep(&(c->exprA));
c->exprA = e->DeepCopyKeep();
c->valA = e->Eval();
SS.MarkGroupDirty(c->group);
SS.GenerateAll();

View File

@ -44,14 +44,14 @@ double Constraint::EllipticalInterpolation(double rx, double ry, double theta) {
char *Constraint::Label(void) {
static char Ret[1024];
if(type == ANGLE) {
sprintf(Ret, "%.2f", exprA->Eval());
sprintf(Ret, "%.2f", valA);
} else if(type == LENGTH_RATIO) {
sprintf(Ret, "%.3f:1", exprA->Eval());
sprintf(Ret, "%.3f:1", valA);
} else if(type == COMMENT) {
strcpy(Ret, comment.str);
} else {
// exprA has units of distance
strcpy(Ret, SS.GW.ToString(exprA->Eval()));
// valA has units of distance
strcpy(Ret, SS.GW.ToString(valA));
}
if(reference) {
strcat(Ret, " REF");

View File

@ -268,28 +268,6 @@ Expr *Expr::DeepCopy(void) {
return n;
}
Expr *Expr::DeepCopyKeep(void) {
Expr *n = (Expr *)MemAlloc(sizeof(Expr));
*n = *this;
n->marker = 0xbad2feed;
n->a = n->b = NULL;
int c = n->Children();
if(c > 0) n->a = a->DeepCopyKeep();
if(c > 1) n->b = b->DeepCopyKeep();
return n;
}
void Expr::FreeKeep(Expr **e) {
if(!(*e)) oops();
int c = (*e)->Children();
if(c > 0) FreeKeep(&((*e)->a));
if(c > 1) FreeKeep(&((*e)->b));
if((*e)->marker != 0xbad2feed) oops();
MemFree(*e);
*e = NULL;
}
Expr *Expr::DeepCopyWithParamsAsPointers(IdList<Param,hParam> *firstTry,
IdList<Param,hParam> *thenTry)
{

8
expr.h
View File

@ -84,17 +84,13 @@ public:
char *Print(void);
void PrintW(void); // worker
// Make a copy of an expression that won't get blown away when we
// do a FreeAllExprs(), or free it later.
Expr *DeepCopyKeep(void);
static void FreeKeep(Expr **f);
// or a copy that will
Expr *DeepCopy(void);
// number of child nodes: 0 (e.g. constant), 1 (sqrt), or 2 (+)
int Children(void);
// total number of nodes in the tree
int Nodes(void);
// Make a simple copy
Expr *DeepCopy(void);
// Make a copy, with the parameters (usually referenced by hParam)
// resolved to pointers to the actual value. This speeds things up
// considerably.

View File

@ -65,7 +65,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'g', "Group.name", 'N', &(SS.sv.g.name) },
{ 'g', "Group.activeWorkplane.v", 'x', &(SS.sv.g.activeWorkplane.v) },
{ 'g', "Group.opA.v", 'x', &(SS.sv.g.opA.v) },
{ 'g', "Group.exprA", 'E', &(SS.sv.g.exprA) },
{ 'g', "Group.valA", 'f', &(SS.sv.g.valA) },
{ 'g', "Group.color", 'x', &(SS.sv.g.color) },
{ 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) },
{ 'g', "Group.skipFirst", 'b', &(SS.sv.g.skipFirst) },
@ -118,7 +118,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'c', "Constraint.type", 'd', &(SS.sv.c.type) },
{ '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.valA", 'f', &(SS.sv.c.valA) },
{ 'c', "Constraint.ptA.v", 'x', &(SS.sv.c.ptA.v) },
{ 'c', "Constraint.ptB.v", 'x', &(SS.sv.c.ptB.v) },
{ 'c', "Constraint.ptC.v", 'x', &(SS.sv.c.ptC.v) },
@ -154,7 +154,6 @@ void SolveSpace::SaveUsingTable(int type) {
case 'f': fprintf(fh, "%.20f", *((double *)p)); break;
case 'N': fprintf(fh, "%s", ((NameStr *)p)->str); break;
case 'P': fprintf(fh, "%s", (char *)p); break;
case 'E': fprintf(fh, "%s", (*((Expr **)p))->Print()); break;
case 'M': {
int j;
@ -223,9 +222,6 @@ bool SolveSpace::SaveToFile(char *filename) {
SMesh *m = &(group.elem[group.n-1].mesh);
for(i = 0; i < m->l.n; i++) {
STriangle *tr = &(m->l.elem[i]);
/*
double mag = tr->Normal().Magnitude();
dbp("triangle: mag=%.5f", mag); */
fprintf(fh, "Triangle %08x %08x "
"%.20f %.20f %.20f %.20f %.20f %.20f %.20f %.20f %.20f\n",
tr->meta.face, tr->meta.color,
@ -248,12 +244,6 @@ void SolveSpace::LoadUsingTable(char *key, char *val) {
case 'x': sscanf(val, "%x", (DWORD *)p); break;
case 'f': *((double *)p) = atof(val); break;
case 'N': ((NameStr *)p)->strcpy(val); break;
case 'E':
Expr *e;
e = Expr::From(val);
if(!e) e = Expr::From(0.0);
*((Expr **)p) = e->DeepCopyKeep();
break;
case 'P':
if(strlen(val)+1 < MAX_PATH) strcpy((char *)p, val);
@ -371,7 +361,6 @@ bool SolveSpace::LoadEntitiesFromFile(char *file, EntityList *le, SMesh *m) {
} else if(strcmp(line, "AddGroup")==0) {
// Don't leak memory; these get allocated whether we want them
// or not.
if(sv.g.exprA) Expr::FreeKeep(&(sv.g.exprA));
sv.g.remap.Clear();
} else if(strcmp(line, "AddParam")==0) {
@ -381,7 +370,7 @@ bool SolveSpace::LoadEntitiesFromFile(char *file, EntityList *le, SMesh *m) {
} else if(strcmp(line, "AddRequest")==0) {
} else if(strcmp(line, "AddConstraint")==0) {
if(sv.c.exprA) Expr::FreeKeep(&(sv.c.exprA));
} else if(strcmp(line, VERSION_STRING)==0) {
} else if(memcmp(line, "Triangle", 8)==0) {

View File

@ -115,7 +115,7 @@ void Group::MenuGroup(int id) {
}
g.type = ROTATE;
g.opA = SS.GW.activeGroup;
g.exprA = Expr::From(3)->DeepCopyKeep();
g.valA = 3;
g.subtype = ONE_SIDED;
g.name.strcpy("rotate");
SS.GW.ClearSelection();
@ -125,7 +125,7 @@ void Group::MenuGroup(int id) {
case GraphicsWindow::MNU_GROUP_TRANS:
g.type = TRANSLATE;
g.opA = SS.GW.activeGroup;
g.exprA = Expr::From(3)->DeepCopyKeep();
g.valA = 3;
g.subtype = ONE_SIDED;
g.predef.entityB = SS.GW.ActiveWorkplane();
g.activeWorkplane = SS.GW.ActiveWorkplane();
@ -293,7 +293,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
AddParam(param, h.param(1), gp.y);
AddParam(param, h.param(2), gp.z);
int n = (int)(exprA->Eval()), a0 = 0;
int n = (int)valA, a0 = 0;
if(subtype == ONE_SIDED && skipFirst) {
a0++; n++;
}
@ -325,7 +325,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
AddParam(param, h.param(5), gn.y);
AddParam(param, h.param(6), gn.z);
int n = (int)(exprA->Eval()), a0 = 0;
int n = (int)valA, a0 = 0;
if(subtype == ONE_SIDED && skipFirst) {
a0++; n++;
}

View File

@ -91,7 +91,7 @@ public:
bool visible;
bool clean;
hEntity activeWorkplane;
Expr *exprA;
double valA;
DWORD color;
static const int SOLVED_OKAY = 0;
@ -442,7 +442,7 @@ public:
hEntity workplane;
// These are the parameters for the constraint.
Expr *exprA;
double valA;
hEntity ptA;
hEntity ptB;
hEntity ptC;

View File

@ -640,7 +640,9 @@ void TextWindow::ScreenChangeExprA(int link, DWORD v) {
// There's an extra line for the skipFirst parameter in one-sided groups.
int r = (g->subtype == Group::ONE_SIDED) ? 15 : 13;
ShowTextEditControl(r, 9, g->exprA->Print());
char str[1024];
sprintf(str, "%d", (int)g->valA);
ShowTextEditControl(r, 9, str);
SS.TW.edit.meaning = EDIT_TIMES_REPEATED;
SS.TW.edit.group.v = v;
}
@ -724,7 +726,7 @@ void TextWindow::ShowGroupInfo(void) {
space = true;
}
int times = (int)(g->exprA->Eval());
int times = (int)(g->valA);
Printf(space, "%Ft%s%E %d time%s %Fl%Ll%D%f[change]%E",
s2, times, times == 1 ? "" : "s",
g->h.v, &TextWindow::ScreenChangeExprA);
@ -916,8 +918,7 @@ void TextWindow::EditControlDone(char *s) {
SS.UndoRemember();
Group *g = SS.GetGroup(edit.group);
Expr::FreeKeep(&(g->exprA));
g->exprA = e->DeepCopyKeep();
g->valA = e->Eval();
SS.MarkGroupDirty(g->h);
SS.later.generateAll = true;

View File

@ -45,7 +45,6 @@ void SolveSpace::PushFromCurrentOnto(UndoStack *uk) {
// And then clean up all the stuff that needs to be a deep copy,
// and zero out all the dynamic stuff that will get regenerated.
dest.clean = false;
if(src->exprA) dest.exprA = src->exprA->DeepCopyKeep();
ZERO(&(dest.solved));
ZERO(&(dest.poly));
ZERO(&(dest.polyError));
@ -65,7 +64,6 @@ void SolveSpace::PushFromCurrentOnto(UndoStack *uk) {
for(i = 0; i < constraint.n; i++) {
Constraint *src = &(constraint.elem[i]);
Constraint dest = *src;
if(src->exprA) dest.exprA = src->exprA->DeepCopyKeep();
ZERO(&(dest.dogd));
ut->constraint.Add(&dest);
}
@ -88,7 +86,6 @@ void SolveSpace::PopOntoCurrentFrom(UndoStack *uk) {
// Free everything in the main copy of the program before replacing it
for(i = 0; i < group.n; i++) {
Group *g = &(group.elem[i]);
if(g->exprA) Expr::FreeKeep(&(g->exprA));
g->poly.Clear();
g->mesh.Clear();
g->meshError.interferesAt.Clear();
@ -96,10 +93,6 @@ void SolveSpace::PopOntoCurrentFrom(UndoStack *uk) {
g->impMesh.Clear();
g->impEntity.Clear();
}
for(i = 0; i < constraint.n; i++) {
Constraint *c = &(constraint.elem[i]);
if(c->exprA) Expr::FreeKeep(&(c->exprA));
}
group.Clear();
request.Clear();
constraint.Clear();
@ -138,15 +131,10 @@ void SolveSpace::UndoClearState(UndoState *ut) {
for(i = 0; i < ut->group.n; i++) {
Group *g = &(ut->group.elem[i]);
if(g->exprA) Expr::FreeKeep(&(g->exprA));
g->remap.Clear();
}
ut->group.Clear();
ut->request.Clear();
for(i = 0; i < ut->constraint.n; i++) {
Constraint *c = &(ut->constraint.elem[i]);
if(c->exprA) Expr::FreeKeep(&(c->exprA));
}
ut->constraint.Clear();
ut->param.Clear();
ZERO(ut);