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]
solver
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;
}
c.disp.offset = Vector::MakeFrom(50, 50, 50);
c.exprA = Expr::FromString("1+3+2")->DeepCopyKeep();
FreeAllExprs();
AddConstraint(&c);
break;

View File

@ -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);

2
dsc.h
View File

@ -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();
}

View File

@ -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++) {

View File

@ -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;

6
expr.h
View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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"

View File

@ -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) {
}
}

14
ui.h
View File

@ -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.

View File

@ -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)
{