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