From 49ec1346d76b2f9d6172552a88662ed16b02992b Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Sun, 27 Apr 2008 01:03:01 -0800 Subject: [PATCH] Add the first `derived' group, that generates entities based on other entities. This requires a new point type, for a point that's defined as a transformation of some other point. All works nicely, I think. There's ugliness because entities are no longer guaranteed to have a parent request. Also speed up display of the text window, by caching brushes instead of recreating for each character (!), and add a bit more user interface in the text window. [git-p4: depot-paths = "//depot/solvespace/": change = 1692] --- constraint.cpp | 10 +++- entity.cpp | 71 +++++++++++++++++--------- expr.cpp | 12 +++-- file.cpp | 3 +- graphicswin.cpp | 23 ++++----- sketch.cpp | 124 +++++++++++++++++++++++++++++++++++++++++++-- sketch.h | 44 +++++++++++----- solvespace.cpp | 125 +++++++++++++++++++--------------------------- solvespace.h | 14 +++--- system.cpp | 8 +-- textwin.cpp | 81 +++++++++++++++++++++--------- ui.h | 8 +++ win32/w32main.cpp | 37 ++++++++------ 13 files changed, 375 insertions(+), 185 deletions(-) diff --git a/constraint.cpp b/constraint.cpp index f812d55..0ca955d 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -1,9 +1,15 @@ #include "solvespace.h" +char *Constraint::DescriptionString(void) { + static char ret[1024]; + sprintf(ret, "c%04x", h.v); + return ret; +} + hConstraint Constraint::AddConstraint(Constraint *c) { SS.constraint.AddAndAssignId(c); - if(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS) SS.Solve(); + SS.GenerateAll(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS); return c->h; } @@ -110,7 +116,7 @@ void Constraint::MenuConstrain(int id) { } case GraphicsWindow::MNU_SOLVE_NOW: - SS.Solve(); + SS.GenerateAll(true); return; case GraphicsWindow::MNU_SOLVE_AUTO: diff --git a/entity.cpp b/entity.cpp index e94c4d4..901411a 100644 --- a/entity.cpp +++ b/entity.cpp @@ -98,35 +98,22 @@ void Entity::PlaneGetExprs(ExprVector *n, Expr **dn) { bool Entity::IsPoint(void) { switch(type) { case POINT_IN_3D: + // A point by (x, y, z) in our base coordinate system. These + // variables are given by param[0:2]. case POINT_IN_2D: + // A point by (u, v) in a workplane. These variables are given + // by param[0:1], and the workplane is given in workplane. + case POINT_XFRMD: + // A point by a translation of another point. The original + // point is given by point[0], and the three offsets in + // param[0:2]. return true; + default: return false; } } -bool Entity::IsPointIn3d(void) { - switch(type) { - case POINT_IN_3D: - return true; - default: - return false; - } -} - -bool Entity::PointIsKnown(void) { - switch(type) { - case POINT_IN_3D: - return SS.GetParam(param[0])->known && - SS.GetParam(param[1])->known && - SS.GetParam(param[2])->known; - case POINT_IN_2D: - return SS.GetParam(param[0])->known && - SS.GetParam(param[1])->known; - default: oops(); - } -} - bool Entity::PointIsFromReferences(void) { return h.request().IsFromReferences(); } @@ -147,6 +134,16 @@ void Entity::PointForceTo(Vector p) { SS.GetParam(param[1])->val = p.Dot(v); break; } + + case POINT_XFRMD: { + Vector orig = SS.GetEntity(point[0])->PointGetCoords(); + Vector trans = p.Minus(orig); + SS.GetParam(param[0])->val = trans.x; + SS.GetParam(param[1])->val = trans.y; + SS.GetParam(param[2])->val = trans.z; + break; + } + default: oops(); } } @@ -168,6 +165,14 @@ Vector Entity::PointGetCoords(void) { p = p.Plus(v.ScaledBy(SS.GetParam(param[1])->val)); break; } + + case POINT_XFRMD: { + p = SS.GetEntity(point[0])->PointGetCoords(); + p.x += SS.GetParam(param[0])->val; + p.y += SS.GetParam(param[1])->val; + p.z += SS.GetParam(param[2])->val; + break; + } default: oops(); } return p; @@ -191,6 +196,15 @@ ExprVector Entity::PointGetExprs(void) { r = r.Plus(v.ScaledBy(Expr::FromParam(param[1]))); break; } + case POINT_XFRMD: { + ExprVector orig = SS.GetEntity(point[0])->PointGetExprs(); + ExprVector trans; + trans.x = Expr::FromParam(param[0]); + trans.y = Expr::FromParam(param[1]); + trans.z = Expr::FromParam(param[2]); + r = orig.Plus(trans); + break; + } default: oops(); } return r; @@ -227,6 +241,10 @@ bool Entity::PointIsLocked(void) { } else if(type == POINT_IN_2D) { if(SS.GetParam(param[0])->assumed) return false; if(SS.GetParam(param[1])->assumed) return false; + } else if(type == POINT_XFRMD) { + if(SS.GetParam(param[0])->assumed) return false; + if(SS.GetParam(param[1])->assumed) return false; + if(SS.GetParam(param[2])->assumed) return false; } else { oops(); } @@ -285,13 +303,18 @@ void Entity::DrawOrGetDistance(int order) { glxColor3d(1, 1, 1); switch(type) { + case POINT_XFRMD: case POINT_IN_3D: case POINT_IN_2D: { if(order >= 0 && order != 2) break; if(!SS.GW.showPoints) break; - Entity *isfor = SS.GetEntity(h.request().entity(0)); - if(!SS.GW.showWorkplanes && isfor->type == Entity::WORKPLANE) break; + if(h.isFromRequest()) { + Entity *isfor = SS.GetEntity(h.request().entity(0)); + if(!SS.GW.showWorkplanes && isfor->type == Entity::WORKPLANE) { + break; + } + } Vector v = PointGetCoords(); diff --git a/expr.cpp b/expr.cpp index 136eac5..8866cee 100644 --- a/expr.cpp +++ b/expr.cpp @@ -131,11 +131,17 @@ Expr *Expr::DeepCopyWithParamsAsPointers(IdList *firstTry, Expr *n = AllocExpr(); if(op == PARAM) { // A param that is referenced by its hParam gets rewritten to go - // straight in to the parameter table with a pointer. - n->op = PARAM_PTR; + // straight in to the parameter table with a pointer, or simply + // into a constant if it's already known. Param *p = firstTry->FindByIdNoOops(x.parh); if(!p) p = thenTry->FindById(x.parh); - n->x.parp = p; + if(p->known) { + n->op = CONSTANT; + n->x.v = p->val; + } else { + n->op = PARAM_PTR; + n->x.parp = p; + } return n; } diff --git a/file.cpp b/file.cpp index 9b0d9ec..bfaf93a 100644 --- a/file.cpp +++ b/file.cpp @@ -12,11 +12,12 @@ void SolveSpace::NewFile(void) { Group g; memset(&g, 0, sizeof(g)); g.name.strcpy("#references"); + g.type = Group::DRAWING; g.h = Group::HGROUP_REFERENCES; group.Add(&g); // And an empty group, for the first stuff the user draws. - g.name.strcpy(""); + g.name.strcpy("drawing"); group.AddAndAssignId(&g); diff --git a/graphicswin.cpp b/graphicswin.cpp index 57ac95d..9eab2c7 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -7,6 +7,7 @@ #define mReq (&GraphicsWindow::MenuRequest) #define mCon (&Constraint::MenuConstrain) #define mFile (&SolveSpace::MenuFile) +#define mGrp (&Group::MenuGroup) #define S 0x100 #define C 0x200 const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { @@ -37,12 +38,12 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView }, { 0, "&Group", 0, 0, NULL }, -{ 1, "New &Drawing Group", 0, 0, NULL }, +{ 1, "New &Drawing Group\tShift+Ctrl+D", MNU_GROUP_DRAWING, 'D'|S|C,mGrp }, { 1, NULL, 0, NULL }, { 1, "New Step and Repeat &Translating", 0, 0, NULL }, { 1, "New Step and Repeat &Rotating", 0, 0, NULL }, { 1, NULL, 0, 0, NULL }, -{ 1, "New Extrusion", 0, 0, NULL }, +{ 1, "New Extrusion\tShift+Ctrl+X", MNU_GROUP_EXTRUDE, 'X'|S|C,mGrp }, { 1, NULL, 0, 0, NULL }, { 1, "New Boolean Difference", 0, 0, NULL }, { 1, "New Boolean Union", 0, 0, NULL }, @@ -268,7 +269,7 @@ void GraphicsWindow::MenuEdit(int id) { for(i = 0; i < MAX_SELECTED; i++) { Selection *s = &(SS.GW.selection[i]); hRequest r; r.v = 0; - if(s->entity.v) { + if(s->entity.v && s->entity.isFromRequest()) { r = s->entity.request(); } if(r.v && !r.IsFromReferences()) { @@ -293,7 +294,7 @@ void GraphicsWindow::MenuEdit(int id) { SS.request.RemoveTagged(); SS.constraint.RemoveTagged(); - SS.GenerateAll(); + SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS); SS.GW.ClearSelection(); SS.GW.hover.Clear(); break; @@ -433,9 +434,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, UpdateDraggedPoint(&(c->disp.offset), x, y); } else if(leftDown && pendingOperation == DRAGGING_POINT) { UpdateDraggedEntity(pendingPoint, x, y); - if(solving == SOLVE_ALWAYS) { - SS.Solve(); - } + SS.GenerateAll(solving == SOLVE_ALWAYS); } // No buttons pressed. @@ -562,9 +561,7 @@ hRequest GraphicsWindow::AddRequest(int type) { r.workplane = activeWorkplane; r.type = type; SS.request.AddAndAssignId(&r); - SS.GenerateAll(); - - if(solving == SOLVE_ALWAYS) SS.Solve(); + SS.GenerateAll(solving == SOLVE_ALWAYS); return r.h; } @@ -730,7 +727,7 @@ void GraphicsWindow::EditControlDone(char *s) { Expr::FreeKeep(&(c->exprA)); c->exprA = e->DeepCopyKeep(); HideGraphicsEditControl(); - if(SS.GW.solving == SOLVE_ALWAYS) SS.Solve(); + SS.GenerateAll(solving == SOLVE_ALWAYS); } else { Error("Not a valid number or expression: '%s'", s); } @@ -762,7 +759,7 @@ void GraphicsWindow::ToggleBool(int link, DWORD v) { bool *vb = (bool *)v; *vb = !*vb; - SS.GenerateAll(); + SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS); InvalidateGraphics(); SS.TW.Show(); } @@ -773,7 +770,7 @@ void GraphicsWindow::ToggleAnyDatumShown(int link, DWORD v) { SS.GW.showAxes = t; SS.GW.showPoints = t; - SS.GenerateAll(); + SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS); InvalidateGraphics(); SS.TW.Show(); } diff --git a/sketch.cpp b/sketch.cpp index 8a80796..fbb5658 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -7,6 +7,41 @@ const hRequest Request::HREQUEST_REFERENCE_XY = { 1 }; const hRequest Request::HREQUEST_REFERENCE_YZ = { 2 }; const hRequest Request::HREQUEST_REFERENCE_ZX = { 3 }; +void Group::AddParam(IdList *param, hParam hp, double v) { + Param pa; + memset(&pa, 0, sizeof(pa)); + pa.h = hp; + pa.val = v; + + param->Add(&pa); +} + +void Group::MenuGroup(int id) { + Group g; + memset(&g, 0, sizeof(g)); + g.visible = true; + + switch(id) { + case GraphicsWindow::MNU_GROUP_DRAWING: + g.type = DRAWING; + g.name.strcpy("drawing"); + break; + + case GraphicsWindow::MNU_GROUP_EXTRUDE: + g.type = EXTRUDE; + g.opA.v = 2; + g.name.strcpy("extrude"); + break; + + default: oops(); + } + + SS.group.AddAndAssignId(&g); + SS.GenerateAll(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS); + SS.GW.activeGroup = g.h; + SS.TW.Show(); +} + char *Group::DescriptionString(void) { static char ret[100]; if(name.str[0]) { @@ -17,13 +52,94 @@ char *Group::DescriptionString(void) { return ret; } +void Group::Generate(IdList *entity, + IdList *param) +{ + int i; + switch(type) { + case DRAWING: + return; + + case EXTRUDE: + AddParam(param, h.param(0), 50); + AddParam(param, h.param(1), 50); + AddParam(param, h.param(2), 50); + for(i = 0; i < entity->n; i++) { + Entity *e = &(entity->elem[i]); + if(e->group.v != opA.v) continue; + + CopyEntity(e->h, 0, h.param(0), h.param(1), h.param(2)); + } + break; + + default: oops(); + } +} + +hEntity Group::Remap(hEntity in, int copyNumber) { + int i; + for(i = 0; i < remap.n; i++) { + EntityMap *em = &(remap.elem[i]); + if(em->input.v == in.v && em->copyNumber == copyNumber) { + // We already have a mapping for this entity. + return h.entity(em->h.v); + } + } + // We don't have a mapping yet, so create one. + EntityMap em; + em.input = in; + em.copyNumber = copyNumber; + remap.AddAndAssignId(&em); + return h.entity(em.h.v); +} + +void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz) { + Entity *ep = SS.GetEntity(in); + + Entity en; + memset(&en, 0, sizeof(en)); + en.type = ep->type; + en.h = Remap(ep->h, a); + en.group = h; + + switch(ep->type) { + case Entity::WORKPLANE: + // Don't copy these. + return; + + case Entity::LINE_SEGMENT: + en.point[0] = Remap(ep->point[0], a); + en.point[1] = Remap(ep->point[1], a); + break; + + case Entity::CUBIC: + en.point[0] = Remap(ep->point[0], a); + en.point[1] = Remap(ep->point[1], a); + en.point[2] = Remap(ep->point[2], a); + en.point[3] = Remap(ep->point[3], a); + break; + + case Entity::POINT_IN_3D: + case Entity::POINT_IN_2D: + en.type = Entity::POINT_XFRMD; + en.point[0] = ep->h; + en.param[0] = dx; + en.param[1] = dy; + en.param[2] = dz; + break; + + default: + oops(); + } + SS.entity.Add(&en); +} + void Group::Draw(void) { edges.l.Clear(); int i; for(i = 0; i < SS.entity.n; i++) { Entity *e = &(SS.entity.elem[i]); - hRequest hr = e->h.request(); - if(SS.GetRequest(hr)->group.v != h.v) continue; + if(e->group.v != h.v) continue; e->GenerateEdges(&edges); } @@ -86,6 +202,7 @@ void Request::Generate(IdList *entity, c: { // Generate the entity that's specific to this request. e.type = et; + e.group = group; e.h = h.entity(0); // And generate entities for the points @@ -95,7 +212,8 @@ c: { p.workplane = workplane; // points start from entity 1, except for datum point case p.h = h.entity(i+(et ? 1 : 0)); - p.symbolic = true; + p.group = group; + if(workplane.v == Entity::FREE_IN_3D.v) { p.type = Entity::POINT_IN_3D; // params for x y z diff --git a/sketch.h b/sketch.h index 860dabc..40017dd 100644 --- a/sketch.h +++ b/sketch.h @@ -19,6 +19,9 @@ class hGroup { public: // bits 15: 0 -- group index DWORD v; + + inline hEntity entity(int i); + inline hParam param(int i); }; class hRequest { public: @@ -36,6 +39,7 @@ public: // 31:16 -- request index DWORD v; + inline bool isFromRequest(void); inline hRequest request(void); }; class hParam { @@ -49,9 +53,11 @@ public: class EntityId { +public: DWORD v; // entity ID, starting from 0 }; class EntityMap { +public: int tag; EntityId h; @@ -68,14 +74,15 @@ public: int tag; hGroup h; - static const int DRAWING_GROUP = 5000; - static const int STEP_AND_REPEAT_TRANSLATING = 5010; - static const int STEP_AND_REPEAT_ROTATING = 5020; + static const int DRAWING = 5000; + static const int EXTRUDE = 5010; int type; int solveOrder; bool solved; + hGroup opA; + hGroup opB; bool visible; SEdgeList edges; @@ -84,16 +91,21 @@ public: NameStr name; char *DescriptionString(void); + static void AddParam(IdList *param, hParam hp, double v); + void Generate(IdList *entity, IdList *param); // When a request generates entities from entities, and the source // entities may have come from multiple requests, it's necessary to // remap the entity ID so that it's still unique. We do this with a // mapping list. - IdList remap; + IdList remap; hEntity Remap(hEntity in, int copyNumber); + void CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz); void Draw(void); SPolygon GetPolygon(void); + + static void MenuGroup(int id); }; // A user request for some primitive or derived operation; for example a @@ -122,7 +134,7 @@ public: NameStr name; bool construction; - hParam AddParam(IdList *param, hParam hp); + static hParam AddParam(IdList *param, hParam hp); void Generate(IdList *entity, IdList *param); char *DescriptionString(void); @@ -138,9 +150,7 @@ public: static const int WORKPLANE = 1000; static const int POINT_IN_3D = 2000; static const int POINT_IN_2D = 2001; - static const int POINT_OFFSET = 2010; - static const int DIRECTION_QUATERNION = 3000; - static const int DIRECTION_OFFSET = 3010; + static const int POINT_XFRMD = 2010; static const int LINE_SEGMENT = 10000; static const int CUBIC = 11000; @@ -148,16 +158,19 @@ public: static const int FACE_LIST = 91000; int type; - bool symbolic; - // When it comes time to draw an entity, we look here to get the // defining variables. hParam param[4]; hEntity point[4]; hEntity direction; + hGroup group; hEntity workplane; // or Entity::FREE_IN_3D + // For entities that are derived by a transformation, the number of + // times to apply the transformation. + int timesApplied; + // Applies only for a WORKPLANE type void WorkplaneGetBasisVectors(Vector *u, Vector *v); Vector WorkplaneGetNormalVector(void); @@ -165,7 +178,6 @@ public: ExprVector WorkplaneGetOffsetExprs(void); bool IsPoint(void); - bool IsPointIn3d(void); // Applies for any of the point types bool PointIsLocked(void); Vector PointGetCoords(void); @@ -173,7 +185,6 @@ public: void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v); void PointForceTo(Vector v); bool PointIsFromReferences(void); - bool PointIsKnown(void); // Applies for anything that comes with a plane bool HasPlane(void); @@ -210,6 +221,11 @@ public: }; +inline hEntity hGroup::entity(int i) + { hEntity r; r.v = 0x80000000 | (v << 16) | i; return r; } +inline hParam hGroup::param(int i) + { hParam r; r.v = 0x80000000 | (v << 16) | i; return r; } + inline bool hRequest::IsFromReferences(void) { if(v == Request::HREQUEST_REFERENCE_XY.v) return true; if(v == Request::HREQUEST_REFERENCE_YZ.v) return true; @@ -221,6 +237,8 @@ inline hEntity hRequest::entity(int i) inline hParam hRequest::param(int i) { hParam r; r.v = (v << 16) | i; return r; } +inline bool hEntity::isFromRequest(void) + { if(v & 0x80000000) return false; else return true; } inline hRequest hEntity::request(void) { hRequest r; r.v = (v >> 16); return r; } @@ -269,6 +287,8 @@ public: Vector offset; } disp; + char *DescriptionString(void); + static hConstraint AddConstraint(Constraint *c); static void MenuConstrain(int id); diff --git a/solvespace.cpp b/solvespace.cpp index b054275..927c722 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -12,34 +12,57 @@ void SolveSpace::Init(char *cmdLine) { TW.Init(); GW.Init(); - GenerateAll(); + GenerateAll(false); TW.Show(); } -void SolveSpace::GenerateAll(void) { - int i; +void SolveSpace::GenerateAll(bool andSolve) { + int i, j; // Don't lose our numerical guesses when we regenerate. IdList prev; param.MoveSelfInto(&prev); - entity.Clear(); - for(i = 0; i < request.n; i++) { - request.elem[i].Generate(&entity, ¶m); + + for(i = 0; i < group.n; i++) { + group.elem[i].solved = false; } - // Restore the numerical guesses. - for(i = 0; i < param.n; i++) { - Param *p = prev.FindByIdNoOops(param.elem[i].h); - if(p) { - param.elem[i].val = p->val; - param.elem[i].assumed = p->assumed; + // For now, solve the groups in given order; should discover the + // correct order later. + for(i = 0; i < group.n; i++) { + Group *g = &(group.elem[i]); + + for(j = 0; j < request.n; j++) { + Request *r = &(request.elem[j]); + if(r->group.v != g->h.v) continue; + + r->Generate(&entity, ¶m); + } + + g->Generate(&entity, ¶m); + + // Use the previous values for params that we've seen before, as + // initial guesses for the solver. + for(j = 0; j < param.n; j++) { + Param *newp = &(param.elem[j]); + if(newp->known) continue; + + Param *prevp = prev.FindByIdNoOops(newp->h); + if(prevp) newp->val = prevp->val; + } + + if(g->h.v == Group::HGROUP_REFERENCES.v) { + ForceReferences(); + group.elem[0].solved = true; + } else { + // Solve this group. + if(andSolve) SolveGroup(g->h); } } prev.Clear(); - ForceReferences(); InvalidateGraphics(); } @@ -58,27 +81,22 @@ void SolveSpace::ForceReferences(void) { hRequest hr = Quat[i].hr; // The origin for our coordinate system, always zero Vector v = Vector::MakeFrom(0, 0, 0); - GetEntity(hr.entity(1))->PointForceTo(v); + Entity *origin = GetEntity(hr.entity(1)); + origin->PointForceTo(v); + GetParam(origin->param[0])->known = true; + GetParam(origin->param[1])->known = true; + GetParam(origin->param[2])->known = true; // The quaternion that defines the rotation, from the table. - GetParam(hr.param(0))->val = Quat[i].a; - GetParam(hr.param(1))->val = Quat[i].b; - GetParam(hr.param(2))->val = Quat[i].c; - GetParam(hr.param(3))->val = Quat[i].d; + Param *p; + p = GetParam(hr.param(0)); p->val = Quat[i].a; p->known = true; + p = GetParam(hr.param(1)); p->val = Quat[i].b; p->known = true; + p = GetParam(hr.param(2)); p->val = Quat[i].c; p->known = true; + p = GetParam(hr.param(3)); p->val = Quat[i].d; p->known = true; } } bool SolveSpace::SolveGroup(hGroup hg) { int i; - if(hg.v == Group::HGROUP_REFERENCES.v) { - // Special case; mark everything in the references known. - for(i = 0; i < param.n; i++) { - Param *p = &(param.elem[i]); - Request *r = GetRequest(p->h.request()); - if(r->group.v == hg.v) p->known = true; - } - return true; - } - // Clear out the system to be solved. sys.entity.Clear(); sys.param.Clear(); @@ -90,6 +108,9 @@ bool SolveSpace::SolveGroup(hGroup hg) { r->Generate(&(sys.entity), &(sys.param)); } + // And for the group itself + Group *g = SS.GetGroup(hg); + g->Generate(&(sys.entity), &(sys.param)); // Set the initial guesses for all the params for(i = 0; i < sys.param.n; i++) { Param *p = &(sys.param.elem[i]); @@ -109,57 +130,11 @@ bool SolveSpace::SolveGroup(hGroup hg) { return r; } -bool SolveSpace::SolveWorker(int order) { - bool allSolved = true; - - int i; - for(i = 0; i < group.n; i++) { - Group *g = &(group.elem[i]); - if(g->solved) continue; - - allSolved = false; - dbp("try solve group %s", g->DescriptionString()); - - // Save the parameter table; a failed solve attempt will mess that - // up a little bit. - IdList savedParam; - param.DeepCopyInto(&savedParam); - - if(SolveGroup(g->h)) { - g->solved = true; - g->solveOrder = order; - // So this one worked; let's see if we can go any further. - if(SolveWorker(order+1)) { - // So everything worked; we're done. - return true; - } - } - // Didn't work, so undo this choice and give up - g->solved = false; - param.Clear(); - savedParam.MoveSelfInto(¶m); - } - - // If we got here, then either everything failed, so we're stuck, or - // everything was already solved, so we're done. - return allSolved; -} - -void SolveSpace::Solve(void) { - int i; - for(i = 0; i < group.n; i++) { - group.elem[i].solved = false; - } - SolveWorker(0); - - InvalidateGraphics(); -} - void SolveSpace::MenuFile(int id) { switch(id) { case GraphicsWindow::MNU_NEW: SS.NewFile(); - SS.GenerateAll(); + SS.GenerateAll(false); SS.GW.Init(); SS.TW.Init(); SS.TW.Show(); diff --git a/solvespace.h b/solvespace.h index 729b7e4..292a181 100644 --- a/solvespace.h +++ b/solvespace.h @@ -4,7 +4,7 @@ // Debugging functions #define oops() do { dbp("oops at line %d, file %s", __LINE__, __FILE__); \ - exit(-1); } while(0) + if(0) *(char *)0 = 1; exit(-1); } while(0) #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) #endif @@ -154,15 +154,8 @@ public: FILE *fh; - void GenerateAll(void); - void ForceReferences(void); - void Init(char *cmdLine); - bool SolveGroup(hGroup hg); - bool SolveWorker(int order); - void Solve(void); - char saveFile[MAX_PATH]; bool unsaved; typedef struct { @@ -185,6 +178,11 @@ public: bool SaveToFile(char *filename); bool LoadFromFile(char *filename); + + void GenerateAll(bool andSolve); + bool SolveGroup(hGroup hg); + void ForceReferences(void); + // The system to be solved. System sys; }; diff --git a/system.cpp b/system.cpp index 206e310..c51aab3 100644 --- a/system.cpp +++ b/system.cpp @@ -207,10 +207,11 @@ bool System::NewtonSolve(int tag) { bool System::Solve(void) { int i, j; -/* dbp("%d equations", eq.n); + dbp("%d equations", eq.n); for(i = 0; i < eq.n; i++) { dbp(" %s = 0", eq.elem[i].e->Print()); - } */ + } + dbp("%d parameters", param.n); param.ClearTags(); eq.ClearTags(); @@ -218,12 +219,11 @@ bool System::Solve(void) { WriteJacobian(0, 0); EvalJacobian(); -/* for(i = 0; i < mat.m; i++) { for(j = 0; j < mat.n; j++) { dbp("A[%d][%d] = %.3f", i, j, mat.A.num[i][j]); } - } */ + } GaussJordan(); diff --git a/textwin.cpp b/textwin.cpp index ce2d697..0613699 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -156,9 +156,10 @@ void TextWindow::Show(void) { default: shown->screen = SCREEN_LIST_OF_GROUPS; // fall through - case SCREEN_LIST_OF_GROUPS: ShowListOfGroups(); break; - case SCREEN_GROUP_INFO: ShowGroupInfo(); break; - case SCREEN_REQUEST_INFO: ShowRequestInfo(); break; + case SCREEN_LIST_OF_GROUPS: ShowListOfGroups(); break; + case SCREEN_GROUP_INFO: ShowGroupInfo(); break; + case SCREEN_REQUEST_INFO: ShowRequestInfo(); break; + case SCREEN_CONSTRAINT_INFO: ShowConstraintInfo(); break; } } InvalidateText(); @@ -211,8 +212,8 @@ void TextWindow::ShowHeader(void) { cd = SS.GetEntity(SS.GW.activeWorkplane)->DescriptionString(); } Printf(" %Lb%f<<%E %Lh%fhome%E %CT workplane:%CD %s", - (DWORD)(&TextWindow::ScreenNavigation), - (DWORD)(&TextWindow::ScreenNavigation), + (&TextWindow::ScreenNavigation), + (&TextWindow::ScreenNavigation), cd); } @@ -227,7 +228,7 @@ void TextWindow::ShowHeader(void) { #define hs(b) ((b) ? 'S' : 'H') Printf("%CTshow: " - "%Cp%Ll%D%fworkplane%E%CT " + "%Cp%Ll%D%fworkplanes%E%CT " "%Cp%Ll%D%faxes%E%CT " "%Cp%Ll%D%fpoints%E%CT " "%Cp%Ll%fany-datum%E%CT", @@ -239,24 +240,11 @@ void TextWindow::ShowHeader(void) { Printf("%CT " "%Cp%Ll%D%fall-groups%E%CT " "%Cp%Ll%D%fconstraints%E%CT", - hs(SS.GW.showAllGroups), (DWORD)(&SS.GW.showAllGroups), - &(SS.GW.ToggleBool), - hs(SS.GW.showConstraints), (DWORD)(&SS.GW.showConstraints), - &(SS.GW.ToggleBool) +hs(SS.GW.showAllGroups), (DWORD)(&SS.GW.showAllGroups), &(SS.GW.ToggleBool), +hs(SS.GW.showConstraints), (DWORD)(&SS.GW.showConstraints), &(SS.GW.ToggleBool) ); } -void TextWindow::ShowListOfGroups(void) { - Printf("%Cd[[all groups in sketch follow]]%E"); - int i; - for(i = 0; i < SS.group.n; i++) { - char *s; - Group *g = &(SS.group.elem[i]); - s = g->DescriptionString(); - Printf(" %Cl%Ll%D%f%s%E", - g->h.v, (DWORD)(&TextWindow::ScreenSelectGroup), s); - } -} void TextWindow::ScreenSelectGroup(int link, DWORD v) { SS.TW.OneScreenForward(); @@ -265,7 +253,31 @@ void TextWindow::ScreenSelectGroup(int link, DWORD v) { SS.TW.Show(); } +void TextWindow::ShowListOfGroups(void) { + Printf("%Cd[[all groups in sketch follow]]%E"); + int i; + for(i = 0; i < SS.group.n; i++) { + char *s; + Group *g = &(SS.group.elem[i]); + s = g->DescriptionString(); + Printf(" %Cl%Ll%D%f%s%E", + g->h.v, (&TextWindow::ScreenSelectGroup), s); + } +} + +void TextWindow::ScreenSelectConstraint(int link, DWORD v) { + SS.TW.OneScreenForward(); + + SS.TW.shown->screen = SCREEN_CONSTRAINT_INFO; + SS.TW.shown->constraint.v = v; + + SS.TW.Show(); +} +void TextWindow::ScreenActivateGroup(int link, DWORD v) { + SS.GW.activeGroup.v = v; + SS.TW.Show(); +} void TextWindow::ScreenSelectRequest(int link, DWORD v) { SS.TW.OneScreenForward(); @@ -276,14 +288,16 @@ void TextWindow::ScreenSelectRequest(int link, DWORD v) { } void TextWindow::ShowGroupInfo(void) { Group *g = SS.group.FindById(shown->group); + Printf("%Cd[[group %s]]", g->DescriptionString()); if(SS.GW.activeGroup.v == shown->group.v) { Printf("%Cd[[this is the active group]]"); } else if(shown->group.v == Group::HGROUP_REFERENCES.v) { Printf("%Cd[[this group contains the references]]"); } else { - Printf("%Cd[[not active; %Cl%Llactivate this group%E%Cd]]"); + Printf("%Cd[[not active; %Cl%Ll%D%factivate group%E%Cd]]", + g->h.v, (&TextWindow::ScreenActivateGroup)); } - Printf("%Cd[[requests in group %s]]%E", g->DescriptionString()); + Printf("%Cd[[requests in group]]%E"); int i; for(i = 0; i < SS.request.n; i++) { @@ -292,7 +306,20 @@ void TextWindow::ShowGroupInfo(void) { if(r->group.v == shown->group.v) { char *s = r->DescriptionString(); Printf(" %Cl%Ll%D%f%s%E", - r->h.v, (DWORD)(&TextWindow::ScreenSelectRequest), s); + r->h.v, (&TextWindow::ScreenSelectRequest), s); + } + } + if(SS.request.n == 0) Printf(" (none)"); + + Printf(""); + Printf("[[constraints in group]]"); + for(i = 0; i < SS.constraint.n; i++) { + Constraint *c = &(SS.constraint.elem[i]); + + if(c->group.v == shown->group.v) { + char *s = c->DescriptionString(); + Printf(" %Cl%Ll%D%f%s%E", + c->h.v, (&TextWindow::ScreenSelectConstraint), s); } } } @@ -310,4 +337,10 @@ void TextWindow::ShowRequestInfo(void) { Printf("%Cd[[request for %s]]%E", s); } +void TextWindow::ShowConstraintInfo(void) { + Constraint *c = SS.GetConstraint(shown->constraint); + + Printf("[[constraint]]"); +} + diff --git a/ui.h b/ui.h index 08ab3b5..bada17d 100644 --- a/ui.h +++ b/ui.h @@ -46,10 +46,12 @@ public: static const int SCREEN_GROUP_INFO = 1; static const int SCREEN_REQUEST_INFO = 2; static const int SCREEN_ENTIY_INFO = 3; + static const int SCREEN_CONSTRAINT_INFO = 4; typedef struct { int screen; hGroup group; hRequest request; + hConstraint constraint; } ShownState; static const int HISTORY_LEN = 16; ShownState showns[HISTORY_LEN]; @@ -64,10 +66,13 @@ public: void ShowGroupInfo(void); void ShowRequestInfo(void); void ShowEntityInfo(void); + void ShowConstraintInfo(void); void OneScreenForward(void); static void ScreenSelectGroup(int link, DWORD v); + static void ScreenActivateGroup(int link, DWORD v); static void ScreenSelectRequest(int link, DWORD v); + static void ScreenSelectConstraint(int link, DWORD v); static void ScreenNavigation(int link, DWORD v); }; @@ -100,6 +105,9 @@ public: MNU_LINE_SEGMENT, MNU_RECTANGLE, MNU_CUBIC, + // Group + MNU_GROUP_DRAWING, + MNU_GROUP_EXTRUDE, // Constrain MNU_DISTANCE_DIA, MNU_EQUAL, diff --git a/win32/w32main.cpp b/win32/w32main.cpp index dbe6a82..8b0589a 100644 --- a/win32/w32main.cpp +++ b/win32/w32main.cpp @@ -12,7 +12,7 @@ #define FREEZE_SUBKEY "SolveSpace" #include "freeze.h" -#define MIN_COLS 42 +#define MIN_COLS 45 #define TEXT_HEIGHT 18 #define TEXT_WIDTH 9 @@ -26,8 +26,6 @@ HWND TextWnd; HWND TextWndScrollBar; int TextWndScrollPos; int TextWndRows; -COLORREF BgColor[256]; -COLORREF FgColor[256]; HWND GraphicsWnd; HWND GraphicsEditControl; @@ -88,13 +86,24 @@ void MemFree(void *p) { free(p); } static void PaintTextWnd(HDC hdc) { - // Generate the color table. int i; - for(i = 0; SS.TW.colors[i].c != 0; i++) { - int c = SS.TW.colors[i].c; - if(c < 0 || c > 255) oops(); - BgColor[c] = SS.TW.colors[i].bg; - FgColor[c] = SS.TW.colors[i].fg; + + static BOOL MadeBrushes = FALSE; + static COLORREF BgColor[256]; + static COLORREF FgColor[256]; + static HBRUSH BgBrush[256]; + static HBRUSH FillBrush; + if(!MadeBrushes) { + // Generate the color table. + for(i = 0; SS.TW.colors[i].c != 0; i++) { + int c = SS.TW.colors[i].c; + if(c < 0 || c > 255) oops(); + BgColor[c] = SS.TW.colors[i].bg; + FgColor[c] = SS.TW.colors[i].fg; + BgBrush[c] = CreateSolidBrush(BgColor[c]); + } + FillBrush = CreateSolidBrush(SS.TW.COLOR_BG_DEFAULT); + MadeBrushes = TRUE; } RECT rect; @@ -107,8 +116,7 @@ static void PaintTextWnd(HDC hdc) HBITMAP backBitmap = CreateCompatibleBitmap(hdc, width, height); SelectObject(backDc, backBitmap); - HBRUSH hbr = CreateSolidBrush(SS.TW.COLOR_BG_DEFAULT); - FillRect(backDc, &rect, hbr); + FillRect(backDc, &rect, FillBrush); SelectObject(backDc, FixedFont); SetBkColor(backDc, SS.TW.COLOR_BG_DEFAULT); @@ -135,7 +143,7 @@ static void PaintTextWnd(HDC hdc) if(r < 0) continue; if(r >= SS.TW.MAX_ROWS) continue; - for(c = 0; c < SS.TW.MAX_COLS; c++) { + for(c = 0; c < min((width/TEXT_WIDTH)+1, SS.TW.MAX_COLS); c++) { int color = SS.TW.meta[r][c].color; SetTextColor(backDc, FgColor[color]); SetBkColor(backDc, BgColor[color]); @@ -150,12 +158,10 @@ static void PaintTextWnd(HDC hdc) int y = (r-TextWndScrollPos)*TEXT_HEIGHT + 1 + (r >= OFFSET_LINE ? OFFSET_HEIGHT : 0); - HBRUSH b = CreateSolidBrush(BgColor[color]); RECT a; a.left = x; a.right = x+TEXT_WIDTH; a.top = y; a.bottom = y+TEXT_HEIGHT; - FillRect(backDc, &a, b); - DeleteObject(b); + FillRect(backDc, &a, BgBrush[color]); TextOut(backDc, x, y, (char *)&(SS.TW.text[r][c]), 1); } @@ -164,7 +170,6 @@ static void PaintTextWnd(HDC hdc) // And commit the back buffer BitBlt(hdc, 0, 0, width, height, backDc, 0, 0, SRCCOPY); DeleteObject(backBitmap); - DeleteObject(hbr); DeleteDC(backDc); }