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]
This commit is contained in:
Jonathan Westhues 2008-04-27 01:03:01 -08:00
parent bfc7109e0c
commit 49ec1346d7
13 changed files with 375 additions and 185 deletions

View File

@ -1,9 +1,15 @@
#include "solvespace.h" #include "solvespace.h"
char *Constraint::DescriptionString(void) {
static char ret[1024];
sprintf(ret, "c%04x", h.v);
return ret;
}
hConstraint Constraint::AddConstraint(Constraint *c) { hConstraint Constraint::AddConstraint(Constraint *c) {
SS.constraint.AddAndAssignId(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; return c->h;
} }
@ -110,7 +116,7 @@ void Constraint::MenuConstrain(int id) {
} }
case GraphicsWindow::MNU_SOLVE_NOW: case GraphicsWindow::MNU_SOLVE_NOW:
SS.Solve(); SS.GenerateAll(true);
return; return;
case GraphicsWindow::MNU_SOLVE_AUTO: case GraphicsWindow::MNU_SOLVE_AUTO:

View File

@ -98,35 +98,22 @@ void Entity::PlaneGetExprs(ExprVector *n, Expr **dn) {
bool Entity::IsPoint(void) { bool Entity::IsPoint(void) {
switch(type) { switch(type) {
case POINT_IN_3D: 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: 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; return true;
default: default:
return false; 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) { bool Entity::PointIsFromReferences(void) {
return h.request().IsFromReferences(); return h.request().IsFromReferences();
} }
@ -147,6 +134,16 @@ void Entity::PointForceTo(Vector p) {
SS.GetParam(param[1])->val = p.Dot(v); SS.GetParam(param[1])->val = p.Dot(v);
break; 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(); default: oops();
} }
} }
@ -168,6 +165,14 @@ Vector Entity::PointGetCoords(void) {
p = p.Plus(v.ScaledBy(SS.GetParam(param[1])->val)); p = p.Plus(v.ScaledBy(SS.GetParam(param[1])->val));
break; 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(); default: oops();
} }
return p; return p;
@ -191,6 +196,15 @@ ExprVector Entity::PointGetExprs(void) {
r = r.Plus(v.ScaledBy(Expr::FromParam(param[1]))); r = r.Plus(v.ScaledBy(Expr::FromParam(param[1])));
break; 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(); default: oops();
} }
return r; return r;
@ -227,6 +241,10 @@ bool Entity::PointIsLocked(void) {
} else if(type == POINT_IN_2D) { } else if(type == POINT_IN_2D) {
if(SS.GetParam(param[0])->assumed) return false; if(SS.GetParam(param[0])->assumed) return false;
if(SS.GetParam(param[1])->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 { } else {
oops(); oops();
} }
@ -285,13 +303,18 @@ void Entity::DrawOrGetDistance(int order) {
glxColor3d(1, 1, 1); glxColor3d(1, 1, 1);
switch(type) { switch(type) {
case POINT_XFRMD:
case POINT_IN_3D: case POINT_IN_3D:
case POINT_IN_2D: { case POINT_IN_2D: {
if(order >= 0 && order != 2) break; if(order >= 0 && order != 2) break;
if(!SS.GW.showPoints) break; if(!SS.GW.showPoints) break;
if(h.isFromRequest()) {
Entity *isfor = SS.GetEntity(h.request().entity(0)); Entity *isfor = SS.GetEntity(h.request().entity(0));
if(!SS.GW.showWorkplanes && isfor->type == Entity::WORKPLANE) break; if(!SS.GW.showWorkplanes && isfor->type == Entity::WORKPLANE) {
break;
}
}
Vector v = PointGetCoords(); Vector v = PointGetCoords();

View File

@ -131,11 +131,17 @@ Expr *Expr::DeepCopyWithParamsAsPointers(IdList<Param,hParam> *firstTry,
Expr *n = AllocExpr(); Expr *n = AllocExpr();
if(op == PARAM) { if(op == PARAM) {
// A param that is referenced by its hParam gets rewritten to go // A param that is referenced by its hParam gets rewritten to go
// straight in to the parameter table with a pointer. // straight in to the parameter table with a pointer, or simply
n->op = PARAM_PTR; // into a constant if it's already known.
Param *p = firstTry->FindByIdNoOops(x.parh); Param *p = firstTry->FindByIdNoOops(x.parh);
if(!p) p = thenTry->FindById(x.parh); if(!p) p = thenTry->FindById(x.parh);
if(p->known) {
n->op = CONSTANT;
n->x.v = p->val;
} else {
n->op = PARAM_PTR;
n->x.parp = p; n->x.parp = p;
}
return n; return n;
} }

View File

@ -12,11 +12,12 @@ void SolveSpace::NewFile(void) {
Group g; Group g;
memset(&g, 0, sizeof(g)); memset(&g, 0, sizeof(g));
g.name.strcpy("#references"); g.name.strcpy("#references");
g.type = Group::DRAWING;
g.h = Group::HGROUP_REFERENCES; g.h = Group::HGROUP_REFERENCES;
group.Add(&g); group.Add(&g);
// And an empty group, for the first stuff the user draws. // And an empty group, for the first stuff the user draws.
g.name.strcpy(""); g.name.strcpy("drawing");
group.AddAndAssignId(&g); group.AddAndAssignId(&g);

View File

@ -7,6 +7,7 @@
#define mReq (&GraphicsWindow::MenuRequest) #define mReq (&GraphicsWindow::MenuRequest)
#define mCon (&Constraint::MenuConstrain) #define mCon (&Constraint::MenuConstrain)
#define mFile (&SolveSpace::MenuFile) #define mFile (&SolveSpace::MenuFile)
#define mGrp (&Group::MenuGroup)
#define S 0x100 #define S 0x100
#define C 0x200 #define C 0x200
const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
@ -37,12 +38,12 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView }, { 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView },
{ 0, "&Group", 0, 0, NULL }, { 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, NULL, 0, NULL },
{ 1, "New Step and Repeat &Translating", 0, 0, NULL }, { 1, "New Step and Repeat &Translating", 0, 0, NULL },
{ 1, "New Step and Repeat &Rotating", 0, 0, NULL }, { 1, "New Step and Repeat &Rotating", 0, 0, NULL },
{ 1, NULL, 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, NULL, 0, 0, NULL },
{ 1, "New Boolean Difference", 0, 0, NULL }, { 1, "New Boolean Difference", 0, 0, NULL },
{ 1, "New Boolean Union", 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++) { for(i = 0; i < MAX_SELECTED; i++) {
Selection *s = &(SS.GW.selection[i]); Selection *s = &(SS.GW.selection[i]);
hRequest r; r.v = 0; hRequest r; r.v = 0;
if(s->entity.v) { if(s->entity.v && s->entity.isFromRequest()) {
r = s->entity.request(); r = s->entity.request();
} }
if(r.v && !r.IsFromReferences()) { if(r.v && !r.IsFromReferences()) {
@ -293,7 +294,7 @@ void GraphicsWindow::MenuEdit(int id) {
SS.request.RemoveTagged(); SS.request.RemoveTagged();
SS.constraint.RemoveTagged(); SS.constraint.RemoveTagged();
SS.GenerateAll(); SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS);
SS.GW.ClearSelection(); SS.GW.ClearSelection();
SS.GW.hover.Clear(); SS.GW.hover.Clear();
break; break;
@ -433,9 +434,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
UpdateDraggedPoint(&(c->disp.offset), x, y); UpdateDraggedPoint(&(c->disp.offset), x, y);
} else if(leftDown && pendingOperation == DRAGGING_POINT) { } else if(leftDown && pendingOperation == DRAGGING_POINT) {
UpdateDraggedEntity(pendingPoint, x, y); UpdateDraggedEntity(pendingPoint, x, y);
if(solving == SOLVE_ALWAYS) { SS.GenerateAll(solving == SOLVE_ALWAYS);
SS.Solve();
}
} }
// No buttons pressed. // No buttons pressed.
@ -562,9 +561,7 @@ hRequest GraphicsWindow::AddRequest(int type) {
r.workplane = activeWorkplane; r.workplane = activeWorkplane;
r.type = type; r.type = type;
SS.request.AddAndAssignId(&r); SS.request.AddAndAssignId(&r);
SS.GenerateAll(); SS.GenerateAll(solving == SOLVE_ALWAYS);
if(solving == SOLVE_ALWAYS) SS.Solve();
return r.h; return r.h;
} }
@ -730,7 +727,7 @@ void GraphicsWindow::EditControlDone(char *s) {
Expr::FreeKeep(&(c->exprA)); Expr::FreeKeep(&(c->exprA));
c->exprA = e->DeepCopyKeep(); c->exprA = e->DeepCopyKeep();
HideGraphicsEditControl(); HideGraphicsEditControl();
if(SS.GW.solving == SOLVE_ALWAYS) SS.Solve(); SS.GenerateAll(solving == SOLVE_ALWAYS);
} else { } else {
Error("Not a valid number or expression: '%s'", s); Error("Not a valid number or expression: '%s'", s);
} }
@ -762,7 +759,7 @@ void GraphicsWindow::ToggleBool(int link, DWORD v) {
bool *vb = (bool *)v; bool *vb = (bool *)v;
*vb = !*vb; *vb = !*vb;
SS.GenerateAll(); SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS);
InvalidateGraphics(); InvalidateGraphics();
SS.TW.Show(); SS.TW.Show();
} }
@ -773,7 +770,7 @@ void GraphicsWindow::ToggleAnyDatumShown(int link, DWORD v) {
SS.GW.showAxes = t; SS.GW.showAxes = t;
SS.GW.showPoints = t; SS.GW.showPoints = t;
SS.GenerateAll(); SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS);
InvalidateGraphics(); InvalidateGraphics();
SS.TW.Show(); SS.TW.Show();
} }

View File

@ -7,6 +7,41 @@ const hRequest Request::HREQUEST_REFERENCE_XY = { 1 };
const hRequest Request::HREQUEST_REFERENCE_YZ = { 2 }; const hRequest Request::HREQUEST_REFERENCE_YZ = { 2 };
const hRequest Request::HREQUEST_REFERENCE_ZX = { 3 }; const hRequest Request::HREQUEST_REFERENCE_ZX = { 3 };
void Group::AddParam(IdList<Param,hParam> *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) { char *Group::DescriptionString(void) {
static char ret[100]; static char ret[100];
if(name.str[0]) { if(name.str[0]) {
@ -17,13 +52,94 @@ char *Group::DescriptionString(void) {
return ret; return ret;
} }
void Group::Generate(IdList<Entity,hEntity> *entity,
IdList<Param,hParam> *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) { void Group::Draw(void) {
edges.l.Clear(); edges.l.Clear();
int i; int i;
for(i = 0; i < SS.entity.n; i++) { for(i = 0; i < SS.entity.n; i++) {
Entity *e = &(SS.entity.elem[i]); Entity *e = &(SS.entity.elem[i]);
hRequest hr = e->h.request(); if(e->group.v != h.v) continue;
if(SS.GetRequest(hr)->group.v != h.v) continue;
e->GenerateEdges(&edges); e->GenerateEdges(&edges);
} }
@ -86,6 +202,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
c: { c: {
// Generate the entity that's specific to this request. // Generate the entity that's specific to this request.
e.type = et; e.type = et;
e.group = group;
e.h = h.entity(0); e.h = h.entity(0);
// And generate entities for the points // And generate entities for the points
@ -95,7 +212,8 @@ c: {
p.workplane = workplane; p.workplane = workplane;
// points start from entity 1, except for datum point case // points start from entity 1, except for datum point case
p.h = h.entity(i+(et ? 1 : 0)); p.h = h.entity(i+(et ? 1 : 0));
p.symbolic = true; p.group = group;
if(workplane.v == Entity::FREE_IN_3D.v) { if(workplane.v == Entity::FREE_IN_3D.v) {
p.type = Entity::POINT_IN_3D; p.type = Entity::POINT_IN_3D;
// params for x y z // params for x y z

View File

@ -19,6 +19,9 @@ class hGroup {
public: public:
// bits 15: 0 -- group index // bits 15: 0 -- group index
DWORD v; DWORD v;
inline hEntity entity(int i);
inline hParam param(int i);
}; };
class hRequest { class hRequest {
public: public:
@ -36,6 +39,7 @@ public:
// 31:16 -- request index // 31:16 -- request index
DWORD v; DWORD v;
inline bool isFromRequest(void);
inline hRequest request(void); inline hRequest request(void);
}; };
class hParam { class hParam {
@ -49,9 +53,11 @@ public:
class EntityId { class EntityId {
public:
DWORD v; // entity ID, starting from 0 DWORD v; // entity ID, starting from 0
}; };
class EntityMap { class EntityMap {
public:
int tag; int tag;
EntityId h; EntityId h;
@ -68,14 +74,15 @@ public:
int tag; int tag;
hGroup h; hGroup h;
static const int DRAWING_GROUP = 5000; static const int DRAWING = 5000;
static const int STEP_AND_REPEAT_TRANSLATING = 5010; static const int EXTRUDE = 5010;
static const int STEP_AND_REPEAT_ROTATING = 5020;
int type; int type;
int solveOrder; int solveOrder;
bool solved; bool solved;
hGroup opA;
hGroup opB;
bool visible; bool visible;
SEdgeList edges; SEdgeList edges;
@ -84,16 +91,21 @@ public:
NameStr name; NameStr name;
char *DescriptionString(void); char *DescriptionString(void);
static void AddParam(IdList<Param,hParam> *param, hParam hp, double v);
void Generate(IdList<Entity,hEntity> *entity, IdList<Param,hParam> *param);
// When a request generates entities from entities, and the source // When a request generates entities from entities, and the source
// entities may have come from multiple requests, it's necessary to // 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 // remap the entity ID so that it's still unique. We do this with a
// mapping list. // mapping list.
IdList<EntityId,EntityMap> remap; IdList<EntityMap,EntityId> remap;
hEntity Remap(hEntity in, int copyNumber); hEntity Remap(hEntity in, int copyNumber);
void CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz);
void Draw(void); void Draw(void);
SPolygon GetPolygon(void); SPolygon GetPolygon(void);
static void MenuGroup(int id);
}; };
// A user request for some primitive or derived operation; for example a // A user request for some primitive or derived operation; for example a
@ -122,7 +134,7 @@ public:
NameStr name; NameStr name;
bool construction; bool construction;
hParam AddParam(IdList<Param,hParam> *param, hParam hp); static hParam AddParam(IdList<Param,hParam> *param, hParam hp);
void Generate(IdList<Entity,hEntity> *entity, IdList<Param,hParam> *param); void Generate(IdList<Entity,hEntity> *entity, IdList<Param,hParam> *param);
char *DescriptionString(void); char *DescriptionString(void);
@ -138,9 +150,7 @@ public:
static const int WORKPLANE = 1000; static const int WORKPLANE = 1000;
static const int POINT_IN_3D = 2000; static const int POINT_IN_3D = 2000;
static const int POINT_IN_2D = 2001; static const int POINT_IN_2D = 2001;
static const int POINT_OFFSET = 2010; static const int POINT_XFRMD = 2010;
static const int DIRECTION_QUATERNION = 3000;
static const int DIRECTION_OFFSET = 3010;
static const int LINE_SEGMENT = 10000; static const int LINE_SEGMENT = 10000;
static const int CUBIC = 11000; static const int CUBIC = 11000;
@ -148,16 +158,19 @@ public:
static const int FACE_LIST = 91000; static const int FACE_LIST = 91000;
int type; int type;
bool symbolic;
// When it comes time to draw an entity, we look here to get the // When it comes time to draw an entity, we look here to get the
// defining variables. // defining variables.
hParam param[4]; hParam param[4];
hEntity point[4]; hEntity point[4];
hEntity direction; hEntity direction;
hGroup group;
hEntity workplane; // or Entity::FREE_IN_3D 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 // Applies only for a WORKPLANE type
void WorkplaneGetBasisVectors(Vector *u, Vector *v); void WorkplaneGetBasisVectors(Vector *u, Vector *v);
Vector WorkplaneGetNormalVector(void); Vector WorkplaneGetNormalVector(void);
@ -165,7 +178,6 @@ public:
ExprVector WorkplaneGetOffsetExprs(void); ExprVector WorkplaneGetOffsetExprs(void);
bool IsPoint(void); bool IsPoint(void);
bool IsPointIn3d(void);
// Applies for any of the point types // Applies for any of the point types
bool PointIsLocked(void); bool PointIsLocked(void);
Vector PointGetCoords(void); Vector PointGetCoords(void);
@ -173,7 +185,6 @@ public:
void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v); void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v);
void PointForceTo(Vector v); void PointForceTo(Vector v);
bool PointIsFromReferences(void); bool PointIsFromReferences(void);
bool PointIsKnown(void);
// Applies for anything that comes with a plane // Applies for anything that comes with a plane
bool HasPlane(void); 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) { inline bool hRequest::IsFromReferences(void) {
if(v == Request::HREQUEST_REFERENCE_XY.v) return true; if(v == Request::HREQUEST_REFERENCE_XY.v) return true;
if(v == Request::HREQUEST_REFERENCE_YZ.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) inline hParam hRequest::param(int i)
{ hParam r; r.v = (v << 16) | i; return r; } { 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) inline hRequest hEntity::request(void)
{ hRequest r; r.v = (v >> 16); return r; } { hRequest r; r.v = (v >> 16); return r; }
@ -269,6 +287,8 @@ public:
Vector offset; Vector offset;
} disp; } disp;
char *DescriptionString(void);
static hConstraint AddConstraint(Constraint *c); static hConstraint AddConstraint(Constraint *c);
static void MenuConstrain(int id); static void MenuConstrain(int id);

View File

@ -12,34 +12,57 @@ void SolveSpace::Init(char *cmdLine) {
TW.Init(); TW.Init();
GW.Init(); GW.Init();
GenerateAll(); GenerateAll(false);
TW.Show(); TW.Show();
} }
void SolveSpace::GenerateAll(void) { void SolveSpace::GenerateAll(bool andSolve) {
int i; int i, j;
// Don't lose our numerical guesses when we regenerate. // Don't lose our numerical guesses when we regenerate.
IdList<Param,hParam> prev; IdList<Param,hParam> prev;
param.MoveSelfInto(&prev); param.MoveSelfInto(&prev);
entity.Clear(); entity.Clear();
for(i = 0; i < request.n; i++) {
request.elem[i].Generate(&entity, &param); for(i = 0; i < group.n; i++) {
group.elem[i].solved = false;
} }
// Restore the numerical guesses. // For now, solve the groups in given order; should discover the
for(i = 0; i < param.n; i++) { // correct order later.
Param *p = prev.FindByIdNoOops(param.elem[i].h); for(i = 0; i < group.n; i++) {
if(p) { Group *g = &(group.elem[i]);
param.elem[i].val = p->val;
param.elem[i].assumed = p->assumed; for(j = 0; j < request.n; j++) {
Request *r = &(request.elem[j]);
if(r->group.v != g->h.v) continue;
r->Generate(&entity, &param);
}
g->Generate(&entity, &param);
// 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(); prev.Clear();
ForceReferences();
InvalidateGraphics(); InvalidateGraphics();
} }
@ -58,27 +81,22 @@ void SolveSpace::ForceReferences(void) {
hRequest hr = Quat[i].hr; hRequest hr = Quat[i].hr;
// The origin for our coordinate system, always zero // The origin for our coordinate system, always zero
Vector v = Vector::MakeFrom(0, 0, 0); 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. // The quaternion that defines the rotation, from the table.
GetParam(hr.param(0))->val = Quat[i].a; Param *p;
GetParam(hr.param(1))->val = Quat[i].b; p = GetParam(hr.param(0)); p->val = Quat[i].a; p->known = true;
GetParam(hr.param(2))->val = Quat[i].c; p = GetParam(hr.param(1)); p->val = Quat[i].b; p->known = true;
GetParam(hr.param(3))->val = Quat[i].d; 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) { bool SolveSpace::SolveGroup(hGroup hg) {
int i; 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. // Clear out the system to be solved.
sys.entity.Clear(); sys.entity.Clear();
sys.param.Clear(); sys.param.Clear();
@ -90,6 +108,9 @@ bool SolveSpace::SolveGroup(hGroup hg) {
r->Generate(&(sys.entity), &(sys.param)); 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 // Set the initial guesses for all the params
for(i = 0; i < sys.param.n; i++) { for(i = 0; i < sys.param.n; i++) {
Param *p = &(sys.param.elem[i]); Param *p = &(sys.param.elem[i]);
@ -109,57 +130,11 @@ bool SolveSpace::SolveGroup(hGroup hg) {
return r; 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<Param,hParam> 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(&param);
}
// 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) { void SolveSpace::MenuFile(int id) {
switch(id) { switch(id) {
case GraphicsWindow::MNU_NEW: case GraphicsWindow::MNU_NEW:
SS.NewFile(); SS.NewFile();
SS.GenerateAll(); SS.GenerateAll(false);
SS.GW.Init(); SS.GW.Init();
SS.TW.Init(); SS.TW.Init();
SS.TW.Show(); SS.TW.Show();

View File

@ -4,7 +4,7 @@
// Debugging functions // Debugging functions
#define oops() do { dbp("oops at line %d, file %s", __LINE__, __FILE__); \ #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 #ifndef min
#define min(x, y) ((x) < (y) ? (x) : (y)) #define min(x, y) ((x) < (y) ? (x) : (y))
#endif #endif
@ -154,15 +154,8 @@ public:
FILE *fh; FILE *fh;
void GenerateAll(void);
void ForceReferences(void);
void Init(char *cmdLine); void Init(char *cmdLine);
bool SolveGroup(hGroup hg);
bool SolveWorker(int order);
void Solve(void);
char saveFile[MAX_PATH]; char saveFile[MAX_PATH];
bool unsaved; bool unsaved;
typedef struct { typedef struct {
@ -185,6 +178,11 @@ public:
bool SaveToFile(char *filename); bool SaveToFile(char *filename);
bool LoadFromFile(char *filename); bool LoadFromFile(char *filename);
void GenerateAll(bool andSolve);
bool SolveGroup(hGroup hg);
void ForceReferences(void);
// The system to be solved. // The system to be solved.
System sys; System sys;
}; };

View File

@ -207,10 +207,11 @@ bool System::NewtonSolve(int tag) {
bool System::Solve(void) { bool System::Solve(void) {
int i, j; int i, j;
/* dbp("%d equations", eq.n); dbp("%d equations", eq.n);
for(i = 0; i < eq.n; i++) { for(i = 0; i < eq.n; i++) {
dbp(" %s = 0", eq.elem[i].e->Print()); dbp(" %s = 0", eq.elem[i].e->Print());
} */ }
dbp("%d parameters", param.n);
param.ClearTags(); param.ClearTags();
eq.ClearTags(); eq.ClearTags();
@ -218,12 +219,11 @@ bool System::Solve(void) {
WriteJacobian(0, 0); WriteJacobian(0, 0);
EvalJacobian(); EvalJacobian();
/*
for(i = 0; i < mat.m; i++) { for(i = 0; i < mat.m; i++) {
for(j = 0; j < mat.n; j++) { for(j = 0; j < mat.n; j++) {
dbp("A[%d][%d] = %.3f", i, j, mat.A.num[i][j]); dbp("A[%d][%d] = %.3f", i, j, mat.A.num[i][j]);
} }
} */ }
GaussJordan(); GaussJordan();

View File

@ -159,6 +159,7 @@ void TextWindow::Show(void) {
case SCREEN_LIST_OF_GROUPS: ShowListOfGroups(); break; case SCREEN_LIST_OF_GROUPS: ShowListOfGroups(); break;
case SCREEN_GROUP_INFO: ShowGroupInfo(); break; case SCREEN_GROUP_INFO: ShowGroupInfo(); break;
case SCREEN_REQUEST_INFO: ShowRequestInfo(); break; case SCREEN_REQUEST_INFO: ShowRequestInfo(); break;
case SCREEN_CONSTRAINT_INFO: ShowConstraintInfo(); break;
} }
} }
InvalidateText(); InvalidateText();
@ -211,8 +212,8 @@ void TextWindow::ShowHeader(void) {
cd = SS.GetEntity(SS.GW.activeWorkplane)->DescriptionString(); cd = SS.GetEntity(SS.GW.activeWorkplane)->DescriptionString();
} }
Printf(" %Lb%f<<%E %Lh%fhome%E %CT workplane:%CD %s", Printf(" %Lb%f<<%E %Lh%fhome%E %CT workplane:%CD %s",
(DWORD)(&TextWindow::ScreenNavigation), (&TextWindow::ScreenNavigation),
(DWORD)(&TextWindow::ScreenNavigation), (&TextWindow::ScreenNavigation),
cd); cd);
} }
@ -227,7 +228,7 @@ void TextWindow::ShowHeader(void) {
#define hs(b) ((b) ? 'S' : 'H') #define hs(b) ((b) ? 'S' : 'H')
Printf("%CTshow: " Printf("%CTshow: "
"%Cp%Ll%D%fworkplane%E%CT " "%Cp%Ll%D%fworkplanes%E%CT "
"%Cp%Ll%D%faxes%E%CT " "%Cp%Ll%D%faxes%E%CT "
"%Cp%Ll%D%fpoints%E%CT " "%Cp%Ll%D%fpoints%E%CT "
"%Cp%Ll%fany-datum%E%CT", "%Cp%Ll%fany-datum%E%CT",
@ -239,24 +240,11 @@ void TextWindow::ShowHeader(void) {
Printf("%CT " Printf("%CT "
"%Cp%Ll%D%fall-groups%E%CT " "%Cp%Ll%D%fall-groups%E%CT "
"%Cp%Ll%D%fconstraints%E%CT", "%Cp%Ll%D%fconstraints%E%CT",
hs(SS.GW.showAllGroups), (DWORD)(&SS.GW.showAllGroups), hs(SS.GW.showAllGroups), (DWORD)(&SS.GW.showAllGroups), &(SS.GW.ToggleBool),
&(SS.GW.ToggleBool), hs(SS.GW.showConstraints), (DWORD)(&SS.GW.showConstraints), &(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) { void TextWindow::ScreenSelectGroup(int link, DWORD v) {
SS.TW.OneScreenForward(); SS.TW.OneScreenForward();
@ -265,7 +253,31 @@ void TextWindow::ScreenSelectGroup(int link, DWORD v) {
SS.TW.Show(); 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) { void TextWindow::ScreenSelectRequest(int link, DWORD v) {
SS.TW.OneScreenForward(); SS.TW.OneScreenForward();
@ -276,14 +288,16 @@ void TextWindow::ScreenSelectRequest(int link, DWORD v) {
} }
void TextWindow::ShowGroupInfo(void) { void TextWindow::ShowGroupInfo(void) {
Group *g = SS.group.FindById(shown->group); Group *g = SS.group.FindById(shown->group);
Printf("%Cd[[group %s]]", g->DescriptionString());
if(SS.GW.activeGroup.v == shown->group.v) { if(SS.GW.activeGroup.v == shown->group.v) {
Printf("%Cd[[this is the active group]]"); Printf("%Cd[[this is the active group]]");
} else if(shown->group.v == Group::HGROUP_REFERENCES.v) { } else if(shown->group.v == Group::HGROUP_REFERENCES.v) {
Printf("%Cd[[this group contains the references]]"); Printf("%Cd[[this group contains the references]]");
} else { } 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; int i;
for(i = 0; i < SS.request.n; i++) { for(i = 0; i < SS.request.n; i++) {
@ -292,7 +306,20 @@ void TextWindow::ShowGroupInfo(void) {
if(r->group.v == shown->group.v) { if(r->group.v == shown->group.v) {
char *s = r->DescriptionString(); char *s = r->DescriptionString();
Printf(" %Cl%Ll%D%f%s%E", 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); Printf("%Cd[[request for %s]]%E", s);
} }
void TextWindow::ShowConstraintInfo(void) {
Constraint *c = SS.GetConstraint(shown->constraint);
Printf("[[constraint]]");
}

8
ui.h
View File

@ -46,10 +46,12 @@ public:
static const int SCREEN_GROUP_INFO = 1; static const int SCREEN_GROUP_INFO = 1;
static const int SCREEN_REQUEST_INFO = 2; static const int SCREEN_REQUEST_INFO = 2;
static const int SCREEN_ENTIY_INFO = 3; static const int SCREEN_ENTIY_INFO = 3;
static const int SCREEN_CONSTRAINT_INFO = 4;
typedef struct { typedef struct {
int screen; int screen;
hGroup group; hGroup group;
hRequest request; hRequest request;
hConstraint constraint;
} ShownState; } ShownState;
static const int HISTORY_LEN = 16; static const int HISTORY_LEN = 16;
ShownState showns[HISTORY_LEN]; ShownState showns[HISTORY_LEN];
@ -64,10 +66,13 @@ public:
void ShowGroupInfo(void); void ShowGroupInfo(void);
void ShowRequestInfo(void); void ShowRequestInfo(void);
void ShowEntityInfo(void); void ShowEntityInfo(void);
void ShowConstraintInfo(void);
void OneScreenForward(void); void OneScreenForward(void);
static void ScreenSelectGroup(int link, DWORD v); static void ScreenSelectGroup(int link, DWORD v);
static void ScreenActivateGroup(int link, DWORD v);
static void ScreenSelectRequest(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); static void ScreenNavigation(int link, DWORD v);
}; };
@ -100,6 +105,9 @@ public:
MNU_LINE_SEGMENT, MNU_LINE_SEGMENT,
MNU_RECTANGLE, MNU_RECTANGLE,
MNU_CUBIC, MNU_CUBIC,
// Group
MNU_GROUP_DRAWING,
MNU_GROUP_EXTRUDE,
// Constrain // Constrain
MNU_DISTANCE_DIA, MNU_DISTANCE_DIA,
MNU_EQUAL, MNU_EQUAL,

View File

@ -12,7 +12,7 @@
#define FREEZE_SUBKEY "SolveSpace" #define FREEZE_SUBKEY "SolveSpace"
#include "freeze.h" #include "freeze.h"
#define MIN_COLS 42 #define MIN_COLS 45
#define TEXT_HEIGHT 18 #define TEXT_HEIGHT 18
#define TEXT_WIDTH 9 #define TEXT_WIDTH 9
@ -26,8 +26,6 @@ HWND TextWnd;
HWND TextWndScrollBar; HWND TextWndScrollBar;
int TextWndScrollPos; int TextWndScrollPos;
int TextWndRows; int TextWndRows;
COLORREF BgColor[256];
COLORREF FgColor[256];
HWND GraphicsWnd; HWND GraphicsWnd;
HWND GraphicsEditControl; HWND GraphicsEditControl;
@ -88,13 +86,24 @@ void MemFree(void *p) { free(p); }
static void PaintTextWnd(HDC hdc) static void PaintTextWnd(HDC hdc)
{ {
// Generate the color table.
int i; int i;
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++) { for(i = 0; SS.TW.colors[i].c != 0; i++) {
int c = SS.TW.colors[i].c; int c = SS.TW.colors[i].c;
if(c < 0 || c > 255) oops(); if(c < 0 || c > 255) oops();
BgColor[c] = SS.TW.colors[i].bg; BgColor[c] = SS.TW.colors[i].bg;
FgColor[c] = SS.TW.colors[i].fg; FgColor[c] = SS.TW.colors[i].fg;
BgBrush[c] = CreateSolidBrush(BgColor[c]);
}
FillBrush = CreateSolidBrush(SS.TW.COLOR_BG_DEFAULT);
MadeBrushes = TRUE;
} }
RECT rect; RECT rect;
@ -107,8 +116,7 @@ static void PaintTextWnd(HDC hdc)
HBITMAP backBitmap = CreateCompatibleBitmap(hdc, width, height); HBITMAP backBitmap = CreateCompatibleBitmap(hdc, width, height);
SelectObject(backDc, backBitmap); SelectObject(backDc, backBitmap);
HBRUSH hbr = CreateSolidBrush(SS.TW.COLOR_BG_DEFAULT); FillRect(backDc, &rect, FillBrush);
FillRect(backDc, &rect, hbr);
SelectObject(backDc, FixedFont); SelectObject(backDc, FixedFont);
SetBkColor(backDc, SS.TW.COLOR_BG_DEFAULT); SetBkColor(backDc, SS.TW.COLOR_BG_DEFAULT);
@ -135,7 +143,7 @@ static void PaintTextWnd(HDC hdc)
if(r < 0) continue; if(r < 0) continue;
if(r >= SS.TW.MAX_ROWS) 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; int color = SS.TW.meta[r][c].color;
SetTextColor(backDc, FgColor[color]); SetTextColor(backDc, FgColor[color]);
SetBkColor(backDc, BgColor[color]); SetBkColor(backDc, BgColor[color]);
@ -150,12 +158,10 @@ static void PaintTextWnd(HDC hdc)
int y = (r-TextWndScrollPos)*TEXT_HEIGHT + 1 + int y = (r-TextWndScrollPos)*TEXT_HEIGHT + 1 +
(r >= OFFSET_LINE ? OFFSET_HEIGHT : 0); (r >= OFFSET_LINE ? OFFSET_HEIGHT : 0);
HBRUSH b = CreateSolidBrush(BgColor[color]);
RECT a; RECT a;
a.left = x; a.right = x+TEXT_WIDTH; a.left = x; a.right = x+TEXT_WIDTH;
a.top = y; a.bottom = y+TEXT_HEIGHT; a.top = y; a.bottom = y+TEXT_HEIGHT;
FillRect(backDc, &a, b); FillRect(backDc, &a, BgBrush[color]);
DeleteObject(b);
TextOut(backDc, x, y, (char *)&(SS.TW.text[r][c]), 1); 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 // And commit the back buffer
BitBlt(hdc, 0, 0, width, height, backDc, 0, 0, SRCCOPY); BitBlt(hdc, 0, 0, width, height, backDc, 0, 0, SRCCOPY);
DeleteObject(backBitmap); DeleteObject(backBitmap);
DeleteObject(hbr);
DeleteDC(backDc); DeleteDC(backDc);
} }