diff --git a/Makefile b/Makefile index 0f8d6310..7de4a1e5 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \ $(OBJDIR)\entity.obj \ $(OBJDIR)\sketch.obj \ $(OBJDIR)\glhelper.obj \ + $(OBJDIR)\expr.obj \ LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib opengl32.lib glu32.lib diff --git a/entity.cpp b/entity.cpp index 73a443ea..54caa083 100644 --- a/entity.cpp +++ b/entity.cpp @@ -1,5 +1,15 @@ #include "solvespace.h" +void Entity::Get2dCsysBasisVectors(Vector *u, Vector *v) { + double q[4]; + for(int i = 0; i < 4; i++) { + q[i] = SS.param.FindById(param(i))->val; + } + + *u = Vector::RotationU(q[0], q[1], q[2], q[3]); + *v = Vector::RotationV(q[0], q[1], q[2], q[3]); +} + void Entity::LineDrawOrGetDistance(Vector a, Vector b) { if(dogd.drawing) { glBegin(GL_LINE_STRIP); @@ -36,13 +46,8 @@ void Entity::DrawOrGetDistance(void) { Vector p; p = SS.point.FindById(point(16))->GetCoords(); - double q[4]; - for(int i = 0; i < 4; i++) { - q[i] = SS.param.FindById(param(i))->val; - } - - Vector u = Vector::RotationU(q[0], q[1], q[2], q[3]); - Vector v = Vector::RotationV(q[0], q[1], q[2], q[3]); + Vector u, v; + Get2dCsysBasisVectors(&u, &v); double s = (min(SS.GW.width, SS.GW.height))*0.4/SS.GW.scale; diff --git a/expr.cpp b/expr.cpp new file mode 100644 index 00000000..c0095048 --- /dev/null +++ b/expr.cpp @@ -0,0 +1,46 @@ +#include "solvespace.h" + +Expr *Expr::FromParam(hParam p) { + Expr *r = AllocExpr(); + r->op = PARAM; + r->x.parh = p; + return r; +} + +Expr *Expr::FromConstant(double v) { + Expr *r = AllocExpr(); + r->op = CONSTANT; + r->x.v = v; + return r; +} + +Expr *Expr::AnyOp(int newOp, Expr *b) { + Expr *r = AllocExpr(); + r->op = newOp; + r->a = this; + r->b = b; + return r; +} + +double Expr::Eval(void) { + switch(op) { + case PARAM: return SS.GetParam(x.parh)->val; + case PARAM_PTR: return (x.parp)->val; + + case CONSTANT: return x.v; + + case PLUS: return a->Eval() + b->Eval(); + case MINUS: return a->Eval() - b->Eval(); + case TIMES: return a->Eval() * b->Eval(); + case DIV: return a->Eval() / b->Eval(); + + case NEGATE: return -(a->Eval()); + case SQRT: return sqrt(a->Eval()); + case SQUARE: { double r = a->Eval(); return r*r; } + case SIN: return sin(a->Eval()); + case COS: return cos(a->Eval()); + + default: oops(); + } +} + diff --git a/expr.h b/expr.h index a8ce3daf..aea98919 100644 --- a/expr.h +++ b/expr.h @@ -32,12 +32,33 @@ public: Expr *a; Expr *b; union { + double v; hParam parh; - double *parp; + Param *parp; hPoint point; hEntity entity; - double v; } x; + + static Expr *FromParam(hParam p); + static Expr *FromConstant(double v); + + Expr *AnyOp(int op, Expr *b); + inline Expr *Plus (Expr *b) { return AnyOp(PLUS, b); } + inline Expr *Minus(Expr *b) { return AnyOp(MINUS, b); } + inline Expr *Times(Expr *b) { return AnyOp(TIMES, b); } + inline Expr *Div (Expr *b) { return AnyOp(DIV, b); } + + inline Expr *Negate(void) { return AnyOp(NEGATE, NULL); } + inline Expr *Sqrt (void) { return AnyOp(SQRT, NULL); } + inline Expr *Square(void) { return AnyOp(SQUARE, NULL); } + inline Expr *Sin (void) { return AnyOp(SIN, NULL); } + inline Expr *Cos (void) { return AnyOp(COS, NULL); } + + Expr *PartialWrt(hParam p); + double Eval(void); + + void ParamsToPointers(void); + void Print(void); }; #endif diff --git a/graphicswin.cpp b/graphicswin.cpp index bf7415a5..b2da9a58 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -125,12 +125,7 @@ void GraphicsWindow::MenuView(MenuId id) { SS.GW.GroupSelection(); if(SS.GW.gs.n == 1 && SS.GW.gs.csyss == 1) { Entity *e = SS.entity.FindById(SS.GW.gs.entity[0]); - double q[4]; - for(int i = 0; i < 4; i++) { - q[i] = SS.param.FindById(e->param(i))->val; - } - SS.GW.projRight = Vector::RotationU(q[0], q[1], q[2], q[3]); - SS.GW.projUp = Vector::RotationV(q[0], q[1], q[2], q[3]); + e->Get2dCsysBasisVectors( &(SS.GW.projRight), &(SS.GW.projUp)); SS.GW.offset = SS.point.FindById(e->point(16))->GetCoords(); SS.GW.ClearSelection(); InvalidateGraphics(); @@ -376,6 +371,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) { SS.point.FindById(hr.entity(0).point(16))->ForceTo(v); pendingOperation = PENDING_OPERATION_DRAGGING_POINT; pendingPoint = hr.entity(0).point(16+3); + pendingDescription = "click to place next point of line"; SS.point.FindById(pendingPoint)->ForceTo(v); break; diff --git a/sketch.cpp b/sketch.cpp index 959de35d..761f9984 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -100,33 +100,51 @@ void Param::ForceTo(double v) { known = true; } -void Point::ForceTo(Vector v) { +void Point::ForceTo(Vector p) { switch(type) { case IN_FREE_SPACE: - SS.param.FindById(param(0))->ForceTo(v.x); - SS.param.FindById(param(1))->ForceTo(v.y); - SS.param.FindById(param(2))->ForceTo(v.z); + SS.GetParam(param(0))->ForceTo(p.x); + SS.GetParam(param(1))->ForceTo(p.y); + SS.GetParam(param(2))->ForceTo(p.z); break; + case IN_2D_CSYS: { + Entity *c = SS.GetEntity(csys); + Vector u, v; + c->Get2dCsysBasisVectors(&u, &v); + SS.GetParam(param(0))->ForceTo(p.Dot(u)); + SS.GetParam(param(1))->ForceTo(p.Dot(v)); + break; + } + default: oops(); } } Vector Point::GetCoords(void) { - Vector v; + Vector p; switch(type) { case IN_FREE_SPACE: - v.x = SS.param.FindById(param(0))->val; - v.y = SS.param.FindById(param(1))->val; - v.z = SS.param.FindById(param(2))->val; + p.x = SS.GetParam(param(0))->val; + p.y = SS.GetParam(param(1))->val; + p.z = SS.GetParam(param(2))->val; break; + case IN_2D_CSYS: { + Entity *c = SS.GetEntity(csys); + Vector u, v; + c->Get2dCsysBasisVectors(&u, &v); + p = u.ScaledBy(SS.GetParam(param(0))->val); + p = p.Plus(v.ScaledBy(SS.GetParam(param(1))->val)); + break; + } + default: oops(); } - return v; + return p; } void Point::Draw(void) { diff --git a/sketch.h b/sketch.h index 6d24337f..ad8cbdfc 100644 --- a/sketch.h +++ b/sketch.h @@ -122,6 +122,8 @@ public: inline hPoint point(int i) { hPoint r; r.v = ((this->h.v) << 7) | i; return r; } + void Get2dCsysBasisVectors(Vector *u, Vector *v); + struct { bool drawing; Point2d mp; diff --git a/solvespace.cpp b/solvespace.cpp index 6c265d5a..d3f14f61 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -21,7 +21,7 @@ void SolveSpace::Init(void) { g.h = Group::HGROUP_REFERENCES; group.Add(&g); - g.csys = Entity::NO_CSYS; + g.csys.v = Request::HREQUEST_REFERENCE_XY.v << 10; g.name.strcpy(""); group.AddAndAssignId(&g); diff --git a/solvespace.h b/solvespace.h index 4d7ab315..dad8c4e0 100644 --- a/solvespace.h +++ b/solvespace.h @@ -12,8 +12,13 @@ #define max(x, y) ((x) > (y) ? (x) : (y)) #endif +class Expr; + void dbp(char *str, ...); void Error(char *str, ...); +Expr *AllocExpr(void); +void FreeAllExprs(void); + #include #include #include @@ -22,7 +27,6 @@ void Error(char *str, ...); #include #include -class Expr; #include "dsc.h" #include "sketch.h" #include "ui.h" @@ -58,6 +62,9 @@ public: IdList point; IdList param; + inline Entity *GetEntity(hEntity h) { return entity.FindById(h); } + inline Param *GetParam (hParam h) { return param. FindById(h); } + hGroup activeGroup; void GenerateAll(void); diff --git a/textwin.cpp b/textwin.cpp index d6b892dd..d6a571f5 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -208,7 +208,7 @@ void TextWindow::ShowHeader(void) { Printf(""); } else { // Navigation buttons - Printf(" %Lb%f<<%E %Lh%fhome%E group:%s", + Printf(" %Lb%f<<%E %Lh%fhome%E %C4 group:%s", (DWORD)(&TextWindow::ScreenNavigaton), (DWORD)(&TextWindow::ScreenNavigaton), SS.group.FindById(SS.GW.activeGroup)->DescriptionString()); @@ -245,7 +245,7 @@ void TextWindow::ShowHeader(void) { } void TextWindow::ShowGroupList(void) { - Printf("%C8[[click group to view requests]]%E"); + Printf("%C8[[all groups in sketch follow]]%E"); int i; for(i = 0; i <= SS.group.elems; i++) { DWORD v; @@ -275,6 +275,17 @@ void TextWindow::ShowRequestList(void) { 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 { + 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[[requests in group %s]]%E", g->DescriptionString()); } diff --git a/win32/w32main.cpp b/win32/w32main.cpp index cc22a193..febedd8a 100644 --- a/win32/w32main.cpp +++ b/win32/w32main.cpp @@ -53,6 +53,27 @@ void Error(char *str, ...) MessageBox(h, buf, "SolveSpace Error", MB_OK | MB_ICONERROR); } +//----------------------------------------------------------------------------- +// A separate heap, on which we allocate expressions. Maybe a bit faster, +// since no fragmentation issues whatsoever, and it also makes it possible +// to be sloppy with our memory management, and just free everything at once +// at the end. +//----------------------------------------------------------------------------- +static HANDLE Heap; +Expr *AllocExpr(void) +{ + Expr *v = (Expr *)HeapAlloc(Heap, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, + sizeof(Expr)); + if(!v) oops(); + memset(v, 0, sizeof(*v)); + return v; +} +void FreeAllExprs(void) +{ + if(Heap) HeapDestroy(Heap); + Heap = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0); +} + static void PaintTextWnd(HDC hdc) { RECT rect; @@ -104,9 +125,18 @@ static void PaintTextWnd(HDC hdc) } else { SelectObject(backDc, FixedFont); } - TextOut(backDc, 4 + c*TEXT_WIDTH, - (r-TextWndScrollPos)*TEXT_HEIGHT + 1, - (char *)&(SS.TW.text[r][c]), 1); + + int x = 4 + c*TEXT_WIDTH; + int y = (r-TextWndScrollPos)*TEXT_HEIGHT + 1 + (r >= 3 ? 9 : 0); + + HBRUSH b = CreateSolidBrush(SS.TW.colors[color].bg); + RECT a; + a.left = x; a.right = x+TEXT_WIDTH; + a.top = y; a.bottom = y+TEXT_HEIGHT; + FillRect(backDc, &a, b); + DeleteObject(b); + + TextOut(backDc, x, y, (char *)&(SS.TW.text[r][c]), 1); } } @@ -166,6 +196,7 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_SIZING: { RECT *r = (RECT *)lParam; int hc = (r->bottom - r->top) - ClientIsSmallerBy; + hc += TEXT_HEIGHT/2; int extra = hc % TEXT_HEIGHT; switch(wParam) { case WMSZ_BOTTOM: @@ -526,6 +557,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, if(!LinkFont) LinkFont = (HFONT)GetStockObject(SYSTEM_FONT); + // Create the heap that we use to store Exprs. + FreeAllExprs(); + // Call in to the platform-independent code, and let them do their init SS.Init();