Add functions to deep-copy Exprs, for those generated from user

expressions that we wish to keep around. And make the 2d coordinate
system (that causes points to generate 2 unknowns, not 3) an
attribute of the request, not the group, and add user interface to
change that.

[git-p4: depot-paths = "//depot/solvespace/": change = 1670]
This commit is contained in:
Jonathan Westhues 2008-04-17 23:06:37 -08:00
parent 1fa7865024
commit 2f4a3917c5
14 changed files with 168 additions and 53 deletions

View File

@ -28,6 +28,8 @@ void Constraint::MenuConstrain(int id) {
return; return;
} }
c.disp.offset = Vector::MakeFrom(50, 50, 50); c.disp.offset = Vector::MakeFrom(50, 50, 50);
c.exprA = Expr::FromString("1+3+2")->DeepCopyKeep();
FreeAllExprs();
AddConstraint(&c); AddConstraint(&c);
break; break;

View File

@ -41,7 +41,7 @@ void Constraint::DrawOrGetDistance(void) {
glPushMatrix(); glPushMatrix();
glxTranslatev(ref); glxTranslatev(ref);
glxOntoCsys(gr, gu); glxOntoCsys(gr, gu);
glxWriteText("ABCDEFG"); glxWriteText(exprA->Print());
glPopMatrix(); glPopMatrix();
} else { } else {
Point2d o = SS.GW.ProjectPoint(ref); Point2d o = SS.GW.ProjectPoint(ref);

2
dsc.h
View File

@ -69,7 +69,7 @@ public:
void Add(T *t) { void Add(T *t) {
if(elems >= elemsAllocated) { if(elems >= elemsAllocated) {
elemsAllocated = (elemsAllocated + 32)*2; elemsAllocated = (elemsAllocated + 32)*2;
elem = (Elem *)realloc(elem, elemsAllocated*sizeof(elem[0])); elem = (Elem *)MemRealloc(elem, elemsAllocated*sizeof(elem[0]));
if(!elem) oops(); if(!elem) oops();
} }

View File

@ -1,5 +1,10 @@
#include "solvespace.h" #include "solvespace.h"
char *Entity::DescriptionString(void) {
Request *r = SS.GetRequest(request());
return r->DescriptionString();
}
void Entity::Get2dCsysBasisVectors(Vector *u, Vector *v) { void Entity::Get2dCsysBasisVectors(Vector *u, Vector *v) {
double q[4]; double q[4];
for(int i = 0; i < 4; i++) { for(int i = 0; i < 4; i++) {

View File

@ -22,6 +22,49 @@ Expr *Expr::AnyOp(int newOp, Expr *b) {
return r; return r;
} }
int Expr::Children(void) {
switch(op) {
case PARAM:
case PARAM_PTR:
case CONSTANT:
return 0;
case PLUS:
case MINUS:
case TIMES:
case DIV:
return 2;
case NEGATE:
case SQRT:
case SQUARE:
case SIN:
case COS:
return 1;
default: oops();
}
}
Expr *Expr::DeepCopy(void) {
Expr *n = AllocExpr();
*n = *this;
int c = n->Children();
if(c > 0) n->a = a->DeepCopy();
if(c > 1) n->b = b->DeepCopy();
return n;
}
Expr *Expr::DeepCopyKeep(void) {
Expr *n = (Expr *)MemAlloc(sizeof(Expr));
*n = *this;
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;
}
double Expr::Eval(void) { double Expr::Eval(void) {
switch(op) { switch(op) {
case PARAM: return SS.GetParam(x.parh)->val; case PARAM: return SS.GetParam(x.parh)->val;

6
expr.h
View File

@ -78,7 +78,11 @@ public:
// Make a copy of an expression that won't get blown away when we // Make a copy of an expression that won't get blown away when we
// do a FreeAllExprs() // do a FreeAllExprs()
Expr *Keep(void); Expr *DeepCopyKeep(void);
// or a copy that will
Expr *DeepCopy(void);
// number of child nodes: 0 (e.g. constant), 1 (sqrt), or 2 (+)
int Children(void);
static Expr *FromString(char *in); static Expr *FromString(char *in);
static void Lex(char *in); static void Lex(char *in);

View File

@ -36,6 +36,9 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Dimensions in &Millimeters", 0, NULL }, { 1, "Dimensions in &Millimeters", 0, NULL },
{ 0, "&Request", 0, NULL }, { 0, "&Request", 0, NULL },
{ 1, "Dra&w in 2d Coordinate System\tW", MNU_SEL_CSYS, 'W', mReq },
{ 1, "Draw Anywhere in 3d\tF", MNU_NO_CSYS, 'Q', mReq },
{ 1, NULL, 0, NULL },
{ 1, "Datum &Point\tP", MNU_DATUM_POINT, 'P', mReq }, { 1, "Datum &Point\tP", MNU_DATUM_POINT, 'P', mReq },
{ 1, "Datum A&xis\tX", 0, 'X', mReq }, { 1, "Datum A&xis\tX", 0, 'X', mReq },
{ 1, "Datum Pla&ne\tN", 0, 'N', mReq }, { 1, "Datum Pla&ne\tN", 0, 'N', mReq },
@ -85,7 +88,7 @@ void GraphicsWindow::Init(void) {
projRight.x = 1; projRight.y = projRight.z = 0; projRight.x = 1; projRight.y = projRight.z = 0;
projUp.y = 1; projUp.z = projUp.x = 0; projUp.y = 1; projUp.z = projUp.x = 0;
EnsureValidActiveGroup(); EnsureValidActives();
show2dCsyss = true; show2dCsyss = true;
showAxes = true; showAxes = true;
@ -147,12 +150,11 @@ void GraphicsWindow::MenuView(int id) {
InvalidateGraphics(); InvalidateGraphics();
} }
void GraphicsWindow::EnsureValidActiveGroup(void) { void GraphicsWindow::EnsureValidActives(void) {
bool change = false;
// The active group must exist, and not be the references.
Group *g = SS.group.FindByIdNoOops(activeGroup); Group *g = SS.group.FindByIdNoOops(activeGroup);
if(g && g->h.v != Group::HGROUP_REFERENCES.v) { if((!g) || (g->h.v == Group::HGROUP_REFERENCES.v)) {
return;
}
int i; int i;
for(i = 0; i < SS.group.elems; i++) { for(i = 0; i < SS.group.elems; i++) {
if(SS.group.elem[i].t.h.v != Group::HGROUP_REFERENCES.v) { if(SS.group.elem[i].t.h.v != Group::HGROUP_REFERENCES.v) {
@ -161,6 +163,17 @@ void GraphicsWindow::EnsureValidActiveGroup(void) {
} }
if(i >= SS.group.elems) oops(); if(i >= SS.group.elems) oops();
activeGroup = SS.group.elem[i].t.h; activeGroup = SS.group.elem[i].t.h;
change = true;
}
// The active coordinate system must also exist.
if(activeCsys.v != Entity::NO_CSYS.v &&
!SS.entity.FindByIdNoOops(activeCsys))
{
activeCsys = Entity::NO_CSYS;
change = true;
}
if(change) SS.TW.Show();
} }
void GraphicsWindow::MenuEdit(int id) { void GraphicsWindow::MenuEdit(int id) {
@ -206,6 +219,25 @@ void GraphicsWindow::MenuEdit(int id) {
void GraphicsWindow::MenuRequest(int id) { void GraphicsWindow::MenuRequest(int id) {
char *s; char *s;
switch(id) { switch(id) {
case MNU_SEL_CSYS:
SS.GW.GroupSelection();
if(SS.GW.gs.n == 1 && SS.GW.gs.csyss == 1) {
SS.GW.activeCsys = SS.GW.gs.entity[0];
SS.GW.ClearSelection();
} else {
Error("Select 2d coordinate system (e.g., the XY plane) "
"before locking on.");
}
SS.GW.EnsureValidActives();
SS.TW.Show();
break;
case MNU_NO_CSYS:
SS.GW.activeCsys = Entity::NO_CSYS;
SS.GW.EnsureValidActives();
SS.TW.Show();
break;
case MNU_DATUM_POINT: s = "click to place datum point"; goto c; case MNU_DATUM_POINT: s = "click to place datum point"; goto c;
case MNU_LINE_SEGMENT: s = "click first point of line segment"; goto c; case MNU_LINE_SEGMENT: s = "click first point of line segment"; goto c;
c: c:
@ -400,6 +432,7 @@ hRequest GraphicsWindow::AddRequest(int type) {
Request r; Request r;
memset(&r, 0, sizeof(r)); memset(&r, 0, sizeof(r));
r.group = activeGroup; r.group = activeGroup;
r.csys = activeCsys;
r.type = type; r.type = type;
SS.request.AddAndAssignId(&r); SS.request.AddAndAssignId(&r);
SS.GenerateAll(); SS.GenerateAll();

View File

@ -58,8 +58,9 @@ c: {
for(i = 0; i < points; i++) { for(i = 0; i < points; i++) {
Point pt; Point pt;
memset(&pt, 0, sizeof(pt)); memset(&pt, 0, sizeof(pt));
pt.csys = csys;
pt.h = e.point(16 + 3*i); pt.h = e.point(16 + 3*i);
if(g->csys.v == Entity::NO_CSYS.v) { if(csys.v == Entity::NO_CSYS.v) {
pt.type = Point::IN_FREE_SPACE; pt.type = Point::IN_FREE_SPACE;
// params for x y z // params for x y z
AddParam(param, &e, 16 + 3*i + 0); AddParam(param, &e, 16 + 3*i + 0);
@ -67,7 +68,6 @@ c: {
AddParam(param, &e, 16 + 3*i + 2); AddParam(param, &e, 16 + 3*i + 2);
} else { } else {
pt.type = Point::IN_2D_CSYS; pt.type = Point::IN_2D_CSYS;
pt.csys = g->csys;
// params for u v // params for u v
AddParam(param, &e, 16 + 3*i + 0); AddParam(param, &e, 16 + 3*i + 0);
AddParam(param, &e, 16 + 3*i + 1); AddParam(param, &e, 16 + 3*i + 1);

View File

@ -56,17 +56,13 @@ public:
inline bool isFromReferences(void); inline bool isFromReferences(void);
}; };
// A set of requests. Every request must have an associated group. A group // A set of requests. Every request must have an associated group.
// may have an associated 2-d coordinate system, in which cases lines or
// curves that belong to the group are automatically constrained into that
// plane; otherwise they are free in 3-space.
class Group { class Group {
public: public:
static const hGroup HGROUP_REFERENCES; static const hGroup HGROUP_REFERENCES;
hGroup h; hGroup h;
hEntity csys; // or Entity::NO_CSYS, if it's not locked in a 2d csys
NameStr name; NameStr name;
char *DescriptionString(void); char *DescriptionString(void);
@ -81,6 +77,8 @@ public:
static const hRequest HREQUEST_REFERENCE_YZ; static const hRequest HREQUEST_REFERENCE_YZ;
static const hRequest HREQUEST_REFERENCE_ZX; static const hRequest HREQUEST_REFERENCE_ZX;
hRequest h;
// Types of requests // Types of requests
static const int CSYS_2D = 10; static const int CSYS_2D = 10;
static const int DATUM_POINT = 11; static const int DATUM_POINT = 11;
@ -88,7 +86,7 @@ public:
int type; int type;
hRequest h; hEntity csys; // or Entity::NO_CSYS
hGroup group; hGroup group;
@ -125,6 +123,8 @@ public:
inline hPoint point(int i) inline hPoint point(int i)
{ hPoint r; r.v = ((this->h.v) << 7) | i; return r; } { hPoint r; r.v = ((this->h.v) << 7) | i; return r; }
char *DescriptionString(void);
void Get2dCsysBasisVectors(Vector *u, Vector *v); void Get2dCsysBasisVectors(Vector *u, Vector *v);
struct { struct {

View File

@ -14,12 +14,11 @@ void SolveSpace::Init(void) {
// Our initial group, that contains the references. // Our initial group, that contains the references.
Group g; Group g;
memset(&g, 0, sizeof(g)); memset(&g, 0, sizeof(g));
g.csys = Entity::NO_CSYS;
g.name.strcpy("#references"); g.name.strcpy("#references");
g.h = Group::HGROUP_REFERENCES; g.h = Group::HGROUP_REFERENCES;
group.Add(&g); group.Add(&g);
g.csys.v = Request::HREQUEST_REFERENCE_XY.v << 10; // And an empty group, for the first stuff the user draws.
g.name.strcpy(""); g.name.strcpy("");
group.AddAndAssignId(&g); group.AddAndAssignId(&g);
@ -30,6 +29,7 @@ void SolveSpace::Init(void) {
memset(&r, 0, sizeof(r)); memset(&r, 0, sizeof(r));
r.type = Request::CSYS_2D; r.type = Request::CSYS_2D;
r.group = Group::HGROUP_REFERENCES; r.group = Group::HGROUP_REFERENCES;
r.csys = Entity::NO_CSYS;
r.name.strcpy("#XY-csys"); r.name.strcpy("#XY-csys");
r.h = Request::HREQUEST_REFERENCE_XY; r.h = Request::HREQUEST_REFERENCE_XY;

View File

@ -27,12 +27,16 @@ class Expr;
// From the platform-specific code. // From the platform-specific code.
void CheckMenuById(int id, BOOL checked); void CheckMenuById(int id, BOOL checked);
void EnableMenuById(int id, BOOL checked);
void InvalidateGraphics(void); void InvalidateGraphics(void);
void InvalidateText(void); void InvalidateText(void);
void dbp(char *str, ...); void dbp(char *str, ...);
void Error(char *str, ...); void Error(char *str, ...);
Expr *AllocExpr(void); Expr *AllocExpr(void);
void FreeAllExprs(void); void FreeAllExprs(void);
void *MemRealloc(void *p, int n);
void *MemAlloc(int n);
void MemFree(void *p);
#include "dsc.h" #include "dsc.h"

View File

@ -8,8 +8,8 @@ const TextWindow::Color TextWindow::colors[] = {
{ RGB(170, 0, 0), COLOR_BG_HEADER, }, // 1 hidden label { RGB(170, 0, 0), COLOR_BG_HEADER, }, // 1 hidden label
{ RGB( 40, 255, 40), COLOR_BG_HEADER, }, // 2 shown label { RGB( 40, 255, 40), COLOR_BG_HEADER, }, // 2 shown label
{ RGB(200, 200, 0), COLOR_BG_HEADER, }, // 3 mixed label { RGB(200, 200, 0), COLOR_BG_HEADER, }, // 3 mixed label
{ RGB(255, 200, 40), COLOR_BG_HEADER, }, // 4 header text { RGB(255, 200, 40), COLOR_BG_HEADER, }, // 4 yellow text
{ RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 5 { RGB(255, 255, 255), COLOR_BG_HEADER, }, // 5 white text
{ RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 6 { RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 6
{ RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 7 { RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 7
@ -155,14 +155,14 @@ void TextWindow::Show(void) {
} else { } else {
switch(shown->screen) { switch(shown->screen) {
default: default:
shown->screen = SCREEN_GROUP_LIST; shown->screen = SCREEN_ALL_GROUPS;
// fall through // fall through
case SCREEN_GROUP_LIST: case SCREEN_ALL_GROUPS:
ShowGroupList(); ShowAllGroups();
break; break;
case SCREEN_REQUEST_LIST: case SCREEN_REQUESTS_IN_GROUP:
ShowRequestList(); ShowRequestsInGroup();
break; break;
} }
} }
@ -181,7 +181,7 @@ void TextWindow::ScreenNavigaton(int link, DWORD v) {
default: default:
case 'h': case 'h':
SS.TW.OneScreenForward(); SS.TW.OneScreenForward();
SS.TW.shown->screen = SCREEN_GROUP_LIST; SS.TW.shown->screen = SCREEN_ALL_GROUPS;
break; break;
case 'b': case 'b':
@ -202,17 +202,23 @@ void TextWindow::ScreenNavigaton(int link, DWORD v) {
void TextWindow::ShowHeader(void) { void TextWindow::ShowHeader(void) {
ClearScreen(); ClearScreen();
SS.GW.EnsureValidActiveGroup(); SS.GW.EnsureValidActives();
if(SS.GW.pendingDescription) { if(SS.GW.pendingDescription) {
Printf(" %C4 group:%s", Printf(" %C4 group:%s",
SS.group.FindById(SS.GW.activeGroup)->DescriptionString()); SS.group.FindById(SS.GW.activeGroup)->DescriptionString());
} else { } else {
// Navigation buttons // Navigation buttons
Printf(" %Lb%f<<%E %Lh%fhome%E %C4 group:%s", char *cd;
if(SS.GW.activeCsys.v == Entity::NO_CSYS.v) {
cd = "free in 3d";
} else {
cd = SS.GetEntity(SS.GW.activeCsys)->DescriptionString();
}
Printf(" %Lb%f<<%E %Lh%fhome%E %C4 csys:%C5 %s",
(DWORD)(&TextWindow::ScreenNavigaton), (DWORD)(&TextWindow::ScreenNavigaton),
(DWORD)(&TextWindow::ScreenNavigaton), (DWORD)(&TextWindow::ScreenNavigaton),
SS.group.FindById(SS.GW.activeGroup)->DescriptionString()); cd);
} }
int datumColor; int datumColor;
@ -245,7 +251,7 @@ void TextWindow::ShowHeader(void) {
); );
} }
void TextWindow::ShowGroupList(void) { void TextWindow::ShowAllGroups(void) {
Printf("%C8[[all groups in sketch follow]]%E"); Printf("%C8[[all groups in sketch follow]]%E");
int i; int i;
for(i = 0; i <= SS.group.elems; i++) { for(i = 0; i <= SS.group.elems; i++) {
@ -265,27 +271,23 @@ void TextWindow::ShowGroupList(void) {
void TextWindow::ScreenSelectGroup(int link, DWORD v) { void TextWindow::ScreenSelectGroup(int link, DWORD v) {
SS.TW.OneScreenForward(); SS.TW.OneScreenForward();
SS.TW.shown->screen = SCREEN_REQUEST_LIST; SS.TW.shown->screen = SCREEN_REQUESTS_IN_GROUP;
SS.TW.shown->group.v = v; SS.TW.shown->group.v = v;
SS.TW.Show(); SS.TW.Show();
} }
void TextWindow::ShowRequestList(void) { void TextWindow::ShowRequestsInGroup(void) {
if(shown->group.v == 0) { if(shown->group.v == 0) {
Printf("%C8[[requests in all groups]]%E"); Printf("%C8[[requests in all groups]]%E");
} else { } else {
Group *g = SS.group.FindById(shown->group); Group *g = SS.group.FindById(shown->group);
if(SS.GW.activeGroup.v == shown->group.v) { if(SS.GW.activeGroup.v == shown->group.v) {
Printf("%C8[[this is the active group]]"); Printf("%C8[[this is the active group]]");
} else if(shown->group.v == Group::HGROUP_REFERENCES.v) {
Printf("%C8[[this group contains the references]]");
} else { } else {
Printf("%C8[[not active; %Llactivate this group%E%C8]]"); Printf("%C8[[not active; %C9%Llactivate this group%E%C8]]");
}
if(g->csys.v == Entity::NO_CSYS.v) {
Printf("[[points may go anywhere in 3d]]");
} else {
Printf("[[locked into plane %s]]",
SS.request.FindById(g->csys.request())->DescriptionString());
} }
Printf("%C8[[requests in group %s]]%E", g->DescriptionString()); Printf("%C8[[requests in group %s]]%E", g->DescriptionString());
} }
@ -301,3 +303,4 @@ void TextWindow::ShowRequestList(void) {
} }
} }

14
ui.h
View File

@ -45,8 +45,8 @@ public:
void Show(void); void Show(void);
// State for the screen that we are showing in the text window. // State for the screen that we are showing in the text window.
static const int SCREEN_GROUP_LIST = 0; static const int SCREEN_ALL_GROUPS = 0;
static const int SCREEN_REQUEST_LIST = 1; static const int SCREEN_REQUESTS_IN_GROUP = 1;
typedef struct { typedef struct {
int screen; int screen;
hGroup group; hGroup group;
@ -60,8 +60,9 @@ public:
void ShowHeader(void); void ShowHeader(void);
// These are self-contained screens, that show some information about // These are self-contained screens, that show some information about
// the sketch. // the sketch.
void ShowGroupList(void); void ShowAllGroups(void);
void ShowRequestList(void); void ShowRequestsInGroup(void);
void OneScreenForward(void); void OneScreenForward(void);
static void ScreenSelectGroup(int link, DWORD v); static void ScreenSelectGroup(int link, DWORD v);
static void ScreenNavigaton(int link, DWORD v); static void ScreenNavigaton(int link, DWORD v);
@ -83,6 +84,8 @@ public:
// Edit // Edit
MNU_DELETE, MNU_DELETE,
// Request // Request
MNU_SEL_CSYS,
MNU_NO_CSYS,
MNU_DATUM_POINT, MNU_DATUM_POINT,
MNU_LINE_SEGMENT, MNU_LINE_SEGMENT,
// Constrain // Constrain
@ -122,7 +125,8 @@ public:
Point2d ProjectPoint(Vector p); Point2d ProjectPoint(Vector p);
hGroup activeGroup; hGroup activeGroup;
void EnsureValidActiveGroup(); hEntity activeCsys;
void EnsureValidActives();
// Operations that must be completed by doing something with the mouse // Operations that must be completed by doing something with the mouse
// are noted here. // are noted here.

View File

@ -73,6 +73,10 @@ void FreeAllExprs(void)
Heap = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0); Heap = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
} }
void *MemRealloc(void *p, int n) { return realloc(p, n); }
void *MemAlloc(int n) { return malloc(n); }
void MemFree(void *p) { free(p); }
static void PaintTextWnd(HDC hdc) static void PaintTextWnd(HDC hdc)
{ {
RECT rect; RECT rect;
@ -442,7 +446,7 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
return 1; return 1;
} }
void CheckMenuById(int id, BOOL checked) static void MenuById(int id, BOOL yes, BOOL check)
{ {
int i; int i;
int subMenu = -1; int subMenu = -1;
@ -454,13 +458,26 @@ void CheckMenuById(int id, BOOL checked)
if(subMenu < 0) oops(); if(subMenu < 0) oops();
if(subMenu >= (sizeof(SubMenus)/sizeof(SubMenus[0]))) oops(); if(subMenu >= (sizeof(SubMenus)/sizeof(SubMenus[0]))) oops();
if(check) {
CheckMenuItem(SubMenus[subMenu], id, CheckMenuItem(SubMenus[subMenu], id,
checked ? MF_CHECKED : MF_UNCHECKED); yes ? MF_CHECKED : MF_UNCHECKED);
} else {
EnableMenuItem(SubMenus[subMenu], id,
yes ? MF_ENABLED : MF_GRAYED);
}
return; return;
} }
} }
oops(); oops();
} }
void CheckMenuById(int id, BOOL checked)
{
MenuById(id, checked, TRUE);
}
void EnableMenuById(int id, BOOL enabled)
{
MenuById(id, enabled, FALSE);
}
HMENU CreateGraphicsWindowMenus(void) HMENU CreateGraphicsWindowMenus(void)
{ {