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
parent
1fa7865024
commit
2f4a3917c5
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
2
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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++) {
|
||||
|
|
43
expr.cpp
43
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;
|
||||
|
|
6
expr.h
6
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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
12
sketch.h
12
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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
45
textwin.cpp
45
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) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
14
ui.h
14
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.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue