From 2f4a3917c5b9a411c64dfca02949df0db5f71abd Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Thu, 17 Apr 2008 23:06:37 -0800 Subject: [PATCH] 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] --- constraint.cpp | 2 ++ drawconstraint.cpp | 2 +- dsc.h | 2 +- entity.cpp | 5 +++++ expr.cpp | 43 ++++++++++++++++++++++++++++++++++++ expr.h | 6 ++++- graphicswin.cpp | 55 ++++++++++++++++++++++++++++++++++++---------- sketch.cpp | 4 ++-- sketch.h | 12 +++++----- solvespace.cpp | 4 ++-- solvespace.h | 4 ++++ textwin.cpp | 45 +++++++++++++++++++------------------ ui.h | 14 +++++++----- win32/w32main.cpp | 23 ++++++++++++++++--- 14 files changed, 168 insertions(+), 53 deletions(-) diff --git a/constraint.cpp b/constraint.cpp index 40fb4e15..1baf71a2 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -28,6 +28,8 @@ void Constraint::MenuConstrain(int id) { return; } c.disp.offset = Vector::MakeFrom(50, 50, 50); + c.exprA = Expr::FromString("1+3+2")->DeepCopyKeep(); + FreeAllExprs(); AddConstraint(&c); break; diff --git a/drawconstraint.cpp b/drawconstraint.cpp index 2074da8e..d9f4c556 100644 --- a/drawconstraint.cpp +++ b/drawconstraint.cpp @@ -41,7 +41,7 @@ void Constraint::DrawOrGetDistance(void) { glPushMatrix(); glxTranslatev(ref); glxOntoCsys(gr, gu); - glxWriteText("ABCDEFG"); + glxWriteText(exprA->Print()); glPopMatrix(); } else { Point2d o = SS.GW.ProjectPoint(ref); diff --git a/dsc.h b/dsc.h index 63cdaadd..e00a4367 100644 --- a/dsc.h +++ b/dsc.h @@ -69,7 +69,7 @@ public: void Add(T *t) { if(elems >= elemsAllocated) { elemsAllocated = (elemsAllocated + 32)*2; - elem = (Elem *)realloc(elem, elemsAllocated*sizeof(elem[0])); + elem = (Elem *)MemRealloc(elem, elemsAllocated*sizeof(elem[0])); if(!elem) oops(); } diff --git a/entity.cpp b/entity.cpp index 54caa083..00b700c4 100644 --- a/entity.cpp +++ b/entity.cpp @@ -1,5 +1,10 @@ #include "solvespace.h" +char *Entity::DescriptionString(void) { + Request *r = SS.GetRequest(request()); + return r->DescriptionString(); +} + void Entity::Get2dCsysBasisVectors(Vector *u, Vector *v) { double q[4]; for(int i = 0; i < 4; i++) { diff --git a/expr.cpp b/expr.cpp index e0466bff..967bedc5 100644 --- a/expr.cpp +++ b/expr.cpp @@ -22,6 +22,49 @@ Expr *Expr::AnyOp(int newOp, Expr *b) { 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) { switch(op) { case PARAM: return SS.GetParam(x.parh)->val; diff --git a/expr.h b/expr.h index 047c83f1..d512caef 100644 --- a/expr.h +++ b/expr.h @@ -78,7 +78,11 @@ public: // Make a copy of an expression that won't get blown away when we // 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 void Lex(char *in); diff --git a/graphicswin.cpp b/graphicswin.cpp index a2293005..2766aa74 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -36,6 +36,9 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, "Dimensions in &Millimeters", 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 A&xis\tX", 0, 'X', 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; projUp.y = 1; projUp.z = projUp.x = 0; - EnsureValidActiveGroup(); + EnsureValidActives(); show2dCsyss = true; showAxes = true; @@ -147,20 +150,30 @@ void GraphicsWindow::MenuView(int id) { 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); - if(g && g->h.v != Group::HGROUP_REFERENCES.v) { - return; + if((!g) || (g->h.v == Group::HGROUP_REFERENCES.v)) { + int i; + for(i = 0; i < SS.group.elems; i++) { + if(SS.group.elem[i].t.h.v != Group::HGROUP_REFERENCES.v) { + break; + } + } + if(i >= SS.group.elems) oops(); + activeGroup = SS.group.elem[i].t.h; + change = true; } - int i; - for(i = 0; i < SS.group.elems; i++) { - if(SS.group.elem[i].t.h.v != Group::HGROUP_REFERENCES.v) { - break; - } + // 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(i >= SS.group.elems) oops(); - activeGroup = SS.group.elem[i].t.h; + if(change) SS.TW.Show(); } void GraphicsWindow::MenuEdit(int id) { @@ -206,6 +219,25 @@ void GraphicsWindow::MenuEdit(int id) { void GraphicsWindow::MenuRequest(int id) { char *s; 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_LINE_SEGMENT: s = "click first point of line segment"; goto c; c: @@ -400,6 +432,7 @@ hRequest GraphicsWindow::AddRequest(int type) { Request r; memset(&r, 0, sizeof(r)); r.group = activeGroup; + r.csys = activeCsys; r.type = type; SS.request.AddAndAssignId(&r); SS.GenerateAll(); diff --git a/sketch.cpp b/sketch.cpp index 761f9984..e8ab248c 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -58,8 +58,9 @@ c: { for(i = 0; i < points; i++) { Point pt; memset(&pt, 0, sizeof(pt)); + pt.csys = csys; 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; // params for x y z AddParam(param, &e, 16 + 3*i + 0); @@ -67,7 +68,6 @@ c: { AddParam(param, &e, 16 + 3*i + 2); } else { pt.type = Point::IN_2D_CSYS; - pt.csys = g->csys; // params for u v AddParam(param, &e, 16 + 3*i + 0); AddParam(param, &e, 16 + 3*i + 1); diff --git a/sketch.h b/sketch.h index 8903e52d..925264f8 100644 --- a/sketch.h +++ b/sketch.h @@ -56,17 +56,13 @@ public: inline bool isFromReferences(void); }; -// A set of requests. Every request must have an associated group. A 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. +// A set of requests. Every request must have an associated group. class Group { public: static const hGroup HGROUP_REFERENCES; hGroup h; - hEntity csys; // or Entity::NO_CSYS, if it's not locked in a 2d csys NameStr name; char *DescriptionString(void); @@ -81,6 +77,8 @@ public: static const hRequest HREQUEST_REFERENCE_YZ; static const hRequest HREQUEST_REFERENCE_ZX; + hRequest h; + // Types of requests static const int CSYS_2D = 10; static const int DATUM_POINT = 11; @@ -88,7 +86,7 @@ public: int type; - hRequest h; + hEntity csys; // or Entity::NO_CSYS hGroup group; @@ -125,6 +123,8 @@ public: inline hPoint point(int i) { hPoint r; r.v = ((this->h.v) << 7) | i; return r; } + char *DescriptionString(void); + void Get2dCsysBasisVectors(Vector *u, Vector *v); struct { diff --git a/solvespace.cpp b/solvespace.cpp index e9da0166..0502dbfb 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -14,12 +14,11 @@ void SolveSpace::Init(void) { // Our initial group, that contains the references. Group g; memset(&g, 0, sizeof(g)); - g.csys = Entity::NO_CSYS; g.name.strcpy("#references"); g.h = Group::HGROUP_REFERENCES; 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(""); group.AddAndAssignId(&g); @@ -30,6 +29,7 @@ void SolveSpace::Init(void) { memset(&r, 0, sizeof(r)); r.type = Request::CSYS_2D; r.group = Group::HGROUP_REFERENCES; + r.csys = Entity::NO_CSYS; r.name.strcpy("#XY-csys"); r.h = Request::HREQUEST_REFERENCE_XY; diff --git a/solvespace.h b/solvespace.h index 5e833df2..fa5f5124 100644 --- a/solvespace.h +++ b/solvespace.h @@ -27,12 +27,16 @@ class Expr; // From the platform-specific code. void CheckMenuById(int id, BOOL checked); +void EnableMenuById(int id, BOOL checked); void InvalidateGraphics(void); void InvalidateText(void); void dbp(char *str, ...); void Error(char *str, ...); Expr *AllocExpr(void); void FreeAllExprs(void); +void *MemRealloc(void *p, int n); +void *MemAlloc(int n); +void MemFree(void *p); #include "dsc.h" diff --git a/textwin.cpp b/textwin.cpp index 425b7946..7f4faafd 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -8,8 +8,8 @@ const TextWindow::Color TextWindow::colors[] = { { RGB(170, 0, 0), COLOR_BG_HEADER, }, // 1 hidden label { RGB( 40, 255, 40), COLOR_BG_HEADER, }, // 2 shown label { RGB(200, 200, 0), COLOR_BG_HEADER, }, // 3 mixed label - { RGB(255, 200, 40), COLOR_BG_HEADER, }, // 4 header text - { RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 5 + { RGB(255, 200, 40), COLOR_BG_HEADER, }, // 4 yellow text + { 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, }, // 7 @@ -155,14 +155,14 @@ void TextWindow::Show(void) { } else { switch(shown->screen) { default: - shown->screen = SCREEN_GROUP_LIST; + shown->screen = SCREEN_ALL_GROUPS; // fall through - case SCREEN_GROUP_LIST: - ShowGroupList(); + case SCREEN_ALL_GROUPS: + ShowAllGroups(); break; - case SCREEN_REQUEST_LIST: - ShowRequestList(); + case SCREEN_REQUESTS_IN_GROUP: + ShowRequestsInGroup(); break; } } @@ -181,7 +181,7 @@ void TextWindow::ScreenNavigaton(int link, DWORD v) { default: case 'h': SS.TW.OneScreenForward(); - SS.TW.shown->screen = SCREEN_GROUP_LIST; + SS.TW.shown->screen = SCREEN_ALL_GROUPS; break; case 'b': @@ -202,17 +202,23 @@ void TextWindow::ScreenNavigaton(int link, DWORD v) { void TextWindow::ShowHeader(void) { ClearScreen(); - SS.GW.EnsureValidActiveGroup(); + SS.GW.EnsureValidActives(); if(SS.GW.pendingDescription) { Printf(" %C4 group:%s", SS.group.FindById(SS.GW.activeGroup)->DescriptionString()); } else { // 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), - SS.group.FindById(SS.GW.activeGroup)->DescriptionString()); + cd); } 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"); int i; for(i = 0; i <= SS.group.elems; i++) { @@ -265,27 +271,23 @@ void TextWindow::ShowGroupList(void) { void TextWindow::ScreenSelectGroup(int link, DWORD v) { 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.Show(); } -void TextWindow::ShowRequestList(void) { +void TextWindow::ShowRequestsInGroup(void) { if(shown->group.v == 0) { Printf("%C8[[requests in all groups]]%E"); } else { Group *g = SS.group.FindById(shown->group); if(SS.GW.activeGroup.v == shown->group.v) { Printf("%C8[[this is the active group]]"); + } else if(shown->group.v == Group::HGROUP_REFERENCES.v) { + Printf("%C8[[this group contains the references]]"); } else { - Printf("%C8[[not active; %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[[not active; %C9%Llactivate this group%E%C8]]"); } Printf("%C8[[requests in group %s]]%E", g->DescriptionString()); } @@ -301,3 +303,4 @@ void TextWindow::ShowRequestList(void) { } } + diff --git a/ui.h b/ui.h index 1ea0b015..596b4759 100644 --- a/ui.h +++ b/ui.h @@ -45,8 +45,8 @@ public: void Show(void); // State for the screen that we are showing in the text window. - static const int SCREEN_GROUP_LIST = 0; - static const int SCREEN_REQUEST_LIST = 1; + static const int SCREEN_ALL_GROUPS = 0; + static const int SCREEN_REQUESTS_IN_GROUP = 1; typedef struct { int screen; hGroup group; @@ -60,8 +60,9 @@ public: void ShowHeader(void); // These are self-contained screens, that show some information about // the sketch. - void ShowGroupList(void); - void ShowRequestList(void); + void ShowAllGroups(void); + void ShowRequestsInGroup(void); + void OneScreenForward(void); static void ScreenSelectGroup(int link, DWORD v); static void ScreenNavigaton(int link, DWORD v); @@ -83,6 +84,8 @@ public: // Edit MNU_DELETE, // Request + MNU_SEL_CSYS, + MNU_NO_CSYS, MNU_DATUM_POINT, MNU_LINE_SEGMENT, // Constrain @@ -122,7 +125,8 @@ public: Point2d ProjectPoint(Vector p); hGroup activeGroup; - void EnsureValidActiveGroup(); + hEntity activeCsys; + void EnsureValidActives(); // Operations that must be completed by doing something with the mouse // are noted here. diff --git a/win32/w32main.cpp b/win32/w32main.cpp index 546560e1..e68d7e49 100644 --- a/win32/w32main.cpp +++ b/win32/w32main.cpp @@ -73,6 +73,10 @@ void FreeAllExprs(void) 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) { RECT rect; @@ -442,7 +446,7 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam, return 1; } -void CheckMenuById(int id, BOOL checked) +static void MenuById(int id, BOOL yes, BOOL check) { int i; int subMenu = -1; @@ -454,13 +458,26 @@ void CheckMenuById(int id, BOOL checked) if(subMenu < 0) oops(); if(subMenu >= (sizeof(SubMenus)/sizeof(SubMenus[0]))) oops(); - CheckMenuItem(SubMenus[subMenu], id, - checked ? MF_CHECKED : MF_UNCHECKED); + if(check) { + CheckMenuItem(SubMenus[subMenu], id, + yes ? MF_CHECKED : MF_UNCHECKED); + } else { + EnableMenuItem(SubMenus[subMenu], id, + yes ? MF_ENABLED : MF_GRAYED); + } return; } } oops(); } +void CheckMenuById(int id, BOOL checked) +{ + MenuById(id, checked, TRUE); +} +void EnableMenuById(int id, BOOL enabled) +{ + MenuById(id, enabled, FALSE); +} HMENU CreateGraphicsWindowMenus(void) {