Standardize the behaviour of constraints, by assigning them a
workplane: a free constraint works in three-space (e.g. true distance), and a constraint in a workplane works in that plane (e.g. projected distance). And make the solver go automatically, though solver itself has lots of pieces missing. [git-p4: depot-paths = "//depot/solvespace/": change = 1691]
This commit is contained in:
parent
15476d4732
commit
bfc7109e0c
161
constraint.cpp
161
constraint.cpp
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
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();
|
||||||
return c->h;
|
return c->h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,22 +11,24 @@ void Constraint::ConstrainCoincident(hEntity ptA, hEntity ptB) {
|
||||||
Constraint c;
|
Constraint c;
|
||||||
memset(&c, 0, sizeof(c));
|
memset(&c, 0, sizeof(c));
|
||||||
c.group = SS.GW.activeGroup;
|
c.group = SS.GW.activeGroup;
|
||||||
|
c.workplane = SS.GW.activeWorkplane;
|
||||||
c.type = Constraint::POINTS_COINCIDENT;
|
c.type = Constraint::POINTS_COINCIDENT;
|
||||||
c.ptA = ptA;
|
c.ptA = ptA;
|
||||||
c.ptB = ptB;
|
c.ptB = ptB;
|
||||||
SS.constraint.AddAndAssignId(&c);
|
AddConstraint(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Constraint::MenuConstrain(int id) {
|
void Constraint::MenuConstrain(int id) {
|
||||||
Constraint c;
|
Constraint c;
|
||||||
memset(&c, 0, sizeof(c));
|
memset(&c, 0, sizeof(c));
|
||||||
c.group = SS.GW.activeGroup;
|
c.group = SS.GW.activeGroup;
|
||||||
|
c.workplane = SS.GW.activeWorkplane;
|
||||||
|
|
||||||
SS.GW.GroupSelection();
|
SS.GW.GroupSelection();
|
||||||
#define gs (SS.GW.gs)
|
#define gs (SS.GW.gs)
|
||||||
|
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case GraphicsWindow::MNU_DISTANCE_DIA:
|
case GraphicsWindow::MNU_DISTANCE_DIA: {
|
||||||
if(gs.points == 2 && gs.n == 2) {
|
if(gs.points == 2 && gs.n == 2) {
|
||||||
c.type = PT_PT_DISTANCE;
|
c.type = PT_PT_DISTANCE;
|
||||||
c.ptA = gs.point[0];
|
c.ptA = gs.point[0];
|
||||||
|
@ -38,11 +42,16 @@ void Constraint::MenuConstrain(int id) {
|
||||||
Error("Bad selection for distance / diameter constraint.");
|
Error("Bad selection for distance / diameter constraint.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
c.disp.offset = Vector::MakeFrom(50, 50, 50);
|
Vector n = SS.GW.projRight.Cross(SS.GW.projUp);
|
||||||
|
Vector a = SS.GetEntity(c.ptA)->PointGetCoords();
|
||||||
|
Vector b = SS.GetEntity(c.ptB)->PointGetCoords();
|
||||||
|
|
||||||
|
c.disp.offset = n.Cross(a.Minus(b)).WithMagnitude(50);
|
||||||
c.exprA = Expr::FromString("0")->DeepCopyKeep();
|
c.exprA = Expr::FromString("0")->DeepCopyKeep();
|
||||||
c.ModifyToSatisfy();
|
c.ModifyToSatisfy();
|
||||||
AddConstraint(&c);
|
AddConstraint(&c);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case GraphicsWindow::MNU_ON_ENTITY:
|
case GraphicsWindow::MNU_ON_ENTITY:
|
||||||
if(gs.points == 2 && gs.n == 2) {
|
if(gs.points == 2 && gs.n == 2) {
|
||||||
|
@ -75,6 +84,10 @@ void Constraint::MenuConstrain(int id) {
|
||||||
case GraphicsWindow::MNU_VERTICAL:
|
case GraphicsWindow::MNU_VERTICAL:
|
||||||
case GraphicsWindow::MNU_HORIZONTAL: {
|
case GraphicsWindow::MNU_HORIZONTAL: {
|
||||||
hEntity ha, hb;
|
hEntity ha, hb;
|
||||||
|
if(c.workplane.v == Entity::FREE_IN_3D.v) {
|
||||||
|
Error("Select workplane before constraining horiz/vert.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(gs.lineSegments == 1 && gs.n == 1) {
|
if(gs.lineSegments == 1 && gs.n == 1) {
|
||||||
c.entityA = gs.entity[0];
|
c.entityA = gs.entity[0];
|
||||||
Entity *e = SS.GetEntity(c.entityA);
|
Entity *e = SS.GetEntity(c.entityA);
|
||||||
|
@ -87,24 +100,6 @@ void Constraint::MenuConstrain(int id) {
|
||||||
Error("Bad selection for horizontal / vertical constraint.");
|
Error("Bad selection for horizontal / vertical constraint.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Entity *ea = SS.GetEntity(ha);
|
|
||||||
Entity *eb = SS.GetEntity(hb);
|
|
||||||
if(ea->workplane.v == Entity::FREE_IN_3D.v &&
|
|
||||||
eb->workplane.v == Entity::FREE_IN_3D.v)
|
|
||||||
{
|
|
||||||
Error("Horizontal/vertical constraint applies only to "
|
|
||||||
"entities drawn in a 2d coordinate system.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(eb->workplane.v == SS.GW.activeWorkplane.v) {
|
|
||||||
// We are constraining two points in two different wrkpls; so
|
|
||||||
// we have two choices for the definitons of the coordinate
|
|
||||||
// directions. ptA's gets chosen, so make sure that's the
|
|
||||||
// active workplane.
|
|
||||||
hEntity t = c.ptA;
|
|
||||||
c.ptA = c.ptB;
|
|
||||||
c.ptB = t;
|
|
||||||
}
|
|
||||||
if(id == GraphicsWindow::MNU_HORIZONTAL) {
|
if(id == GraphicsWindow::MNU_HORIZONTAL) {
|
||||||
c.type = HORIZONTAL;
|
c.type = HORIZONTAL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -118,6 +113,15 @@ void Constraint::MenuConstrain(int id) {
|
||||||
SS.Solve();
|
SS.Solve();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case GraphicsWindow::MNU_SOLVE_AUTO:
|
||||||
|
if(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS) {
|
||||||
|
SS.GW.solving = GraphicsWindow::DONT_SOLVE;
|
||||||
|
} else {
|
||||||
|
SS.GW.solving = GraphicsWindow::SOLVE_ALWAYS;
|
||||||
|
}
|
||||||
|
SS.GW.EnsureValidActives();
|
||||||
|
break;
|
||||||
|
|
||||||
default: oops();
|
default: oops();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,33 +129,31 @@ void Constraint::MenuConstrain(int id) {
|
||||||
InvalidateGraphics();
|
InvalidateGraphics();
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr *Constraint::Distance(hEntity hpa, hEntity hpb) {
|
Expr *Constraint::Distance(hEntity wrkpl, hEntity hpa, hEntity hpb) {
|
||||||
Entity *pa = SS.GetEntity(hpa);
|
Entity *pa = SS.GetEntity(hpa);
|
||||||
Entity *pb = SS.GetEntity(hpb);
|
Entity *pb = SS.GetEntity(hpb);
|
||||||
|
|
||||||
if(!(pa->IsPoint() && pb->IsPoint())) oops();
|
if(!(pa->IsPoint() && pb->IsPoint())) oops();
|
||||||
|
|
||||||
if(pa->type == Entity::POINT_IN_2D &&
|
if(wrkpl.v == Entity::FREE_IN_3D.v) {
|
||||||
pb->type == Entity::POINT_IN_2D &&
|
// This is true distance
|
||||||
pa->workplane.v == pb->workplane.v)
|
ExprVector ea, eb, eab;
|
||||||
{
|
ea = pa->PointGetExprs();
|
||||||
// A nice case; they are both in the same workplane, so I can write
|
eb = pb->PointGetExprs();
|
||||||
// the equation in terms of the basis vectors in that csys.
|
eab = ea.Minus(eb);
|
||||||
Expr *du = Expr::FromParam(pa->param[0])->Minus(
|
|
||||||
Expr::FromParam(pb->param[0]));
|
return eab.Magnitude();
|
||||||
Expr *dv = Expr::FromParam(pa->param[1])->Minus(
|
} else {
|
||||||
Expr::FromParam(pb->param[1]));
|
// This is projected distance, in the given workplane.
|
||||||
|
Expr *au, *av, *bu, *bv;
|
||||||
|
|
||||||
|
pa->PointGetExprsInWorkplane(wrkpl, &au, &av);
|
||||||
|
pb->PointGetExprsInWorkplane(wrkpl, &bu, &bv);
|
||||||
|
|
||||||
|
Expr *du = au->Minus(bu);
|
||||||
|
Expr *dv = av->Minus(bv);
|
||||||
|
|
||||||
return ((du->Square())->Plus(dv->Square()))->Sqrt();
|
return ((du->Square())->Plus(dv->Square()))->Sqrt();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The usual case, just write it in terms of the coordinates
|
|
||||||
ExprVector ea, eb, eab;
|
|
||||||
ea = pa->PointGetExprs();
|
|
||||||
eb = pb->PointGetExprs();
|
|
||||||
eab = ea.Minus(eb);
|
|
||||||
|
|
||||||
return eab.Magnitude();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Constraint::ModifyToSatisfy(void) {
|
void Constraint::ModifyToSatisfy(void) {
|
||||||
|
@ -182,59 +184,39 @@ void Constraint::AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index) {
|
||||||
void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PT_PT_DISTANCE:
|
case PT_PT_DISTANCE:
|
||||||
AddEq(l, Distance(ptA, ptB)->Minus(exprA), 0);
|
AddEq(l, Distance(workplane, ptA, ptB)->Minus(exprA), 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EQUAL_LENGTH_LINES: {
|
case EQUAL_LENGTH_LINES: {
|
||||||
Entity *a = SS.GetEntity(entityA);
|
Entity *a = SS.GetEntity(entityA);
|
||||||
Entity *b = SS.GetEntity(entityB);
|
Entity *b = SS.GetEntity(entityB);
|
||||||
AddEq(l, Distance(a->point[0], a->point[1])->Minus(
|
AddEq(l, Distance(workplane, a->point[0], a->point[1])->Minus(
|
||||||
Distance(b->point[0], b->point[1])), 0);
|
Distance(workplane, b->point[0], b->point[1])), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case POINTS_COINCIDENT: {
|
case POINTS_COINCIDENT: {
|
||||||
Entity *a = SS.GetEntity(ptA);
|
Entity *a = SS.GetEntity(ptA);
|
||||||
Entity *b = SS.GetEntity(ptB);
|
Entity *b = SS.GetEntity(ptB);
|
||||||
if(!a->IsPointIn3d() && b->IsPointIn3d()) {
|
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||||
Entity *t = a;
|
ExprVector pa = a->PointGetExprs();
|
||||||
a = b; b = t;
|
ExprVector pb = b->PointGetExprs();
|
||||||
}
|
AddEq(l, pa.x->Minus(pb.x), 0);
|
||||||
if(a->IsPointIn3d() && b->IsPointIn3d()) {
|
AddEq(l, pa.y->Minus(pb.y), 1);
|
||||||
// Easy case: both points have 3 DOF, so write three eqs.
|
AddEq(l, pa.z->Minus(pb.z), 2);
|
||||||
ExprVector ea, eb, eab;
|
|
||||||
ea = a->PointGetExprs();
|
|
||||||
eb = b->PointGetExprs();
|
|
||||||
eab = ea.Minus(eb);
|
|
||||||
AddEq(l, eab.x, 0);
|
|
||||||
AddEq(l, eab.y, 1);
|
|
||||||
AddEq(l, eab.z, 2);
|
|
||||||
} else if(!(a->IsPointIn3d() || b->IsPointIn3d()) &&
|
|
||||||
(a->workplane.v == b->workplane.v))
|
|
||||||
{
|
|
||||||
// Both in same workplane, nice.
|
|
||||||
AddEq(l, Expr::FromParam(a->param[0])->Minus(
|
|
||||||
Expr::FromParam(b->param[0])), 0);
|
|
||||||
AddEq(l, Expr::FromParam(a->param[1])->Minus(
|
|
||||||
Expr::FromParam(b->param[1])), 1);
|
|
||||||
} else {
|
} else {
|
||||||
// Either two 2 DOF points in different planes, or one
|
Expr *au, *av;
|
||||||
// 3 DOF point and one 2 DOF point. Either way, write two
|
Expr *bu, *bv;
|
||||||
// equations on the projection of a into b's plane.
|
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
||||||
ExprVector p3;
|
b->PointGetExprsInWorkplane(workplane, &bu, &bv);
|
||||||
p3 = a->PointGetExprs();
|
AddEq(l, au->Minus(bu), 0);
|
||||||
Entity *w = SS.GetEntity(b->workplane);
|
AddEq(l, av->Minus(bv), 1);
|
||||||
ExprVector offset = w->WorkplaneGetOffsetExprs();
|
|
||||||
p3 = p3.Minus(offset);
|
|
||||||
ExprVector u, v;
|
|
||||||
w->WorkplaneGetBasisExprs(&u, &v);
|
|
||||||
AddEq(l, Expr::FromParam(b->param[0])->Minus(p3.Dot(u)), 0);
|
|
||||||
AddEq(l, Expr::FromParam(b->param[1])->Minus(p3.Dot(v)), 1);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PT_IN_PLANE: {
|
case PT_IN_PLANE: {
|
||||||
|
// This one works the same, whether projected or not.
|
||||||
ExprVector p, n;
|
ExprVector p, n;
|
||||||
Expr *d;
|
Expr *d;
|
||||||
p = SS.GetEntity(ptA)->PointGetExprs();
|
p = SS.GetEntity(ptA)->PointGetExprs();
|
||||||
|
@ -256,25 +238,12 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
Entity *a = SS.GetEntity(ha);
|
Entity *a = SS.GetEntity(ha);
|
||||||
Entity *b = SS.GetEntity(hb);
|
Entity *b = SS.GetEntity(hb);
|
||||||
if(a->workplane.v == Entity::FREE_IN_3D.v) {
|
|
||||||
Entity *t = a;
|
Expr *au, *av, *bu, *bv;
|
||||||
a = b;
|
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
||||||
b = t;
|
b->PointGetExprsInWorkplane(workplane, &bu, &bv);
|
||||||
}
|
|
||||||
|
AddEq(l, (type == HORIZONTAL) ? av->Minus(bv) : au->Minus(bu), 0);
|
||||||
if(a->workplane.v == b->workplane.v) {
|
|
||||||
int i = (type == HORIZONTAL) ? 1 : 0;
|
|
||||||
AddEq(l, Expr::FromParam(a->param[i])->Minus(
|
|
||||||
Expr::FromParam(b->param[i])), 0);
|
|
||||||
} else {
|
|
||||||
Entity *w = SS.GetEntity(a->workplane);
|
|
||||||
ExprVector u, v;
|
|
||||||
w->WorkplaneGetBasisExprs(&u, &v);
|
|
||||||
ExprVector norm = (type == HORIZONTAL) ? v : u;
|
|
||||||
ExprVector pa = a->PointGetExprs();
|
|
||||||
ExprVector pb = b->PointGetExprs();
|
|
||||||
AddEq(l, (pa.Minus(pb)).Dot(norm), 0);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
41
entity.cpp
41
entity.cpp
|
@ -196,6 +196,43 @@ ExprVector Entity::PointGetExprs(void) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Entity::PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v) {
|
||||||
|
if(type == POINT_IN_2D && workplane.v == wrkpl.v) {
|
||||||
|
// They want our coordinates in the form that we've written them,
|
||||||
|
// very nice.
|
||||||
|
*u = Expr::FromParam(param[0]);
|
||||||
|
*v = Expr::FromParam(param[1]);
|
||||||
|
} else {
|
||||||
|
// Get the offset and basis vectors for this weird exotic csys.
|
||||||
|
Entity *w = SS.GetEntity(wrkpl);
|
||||||
|
ExprVector wp = w->WorkplaneGetOffsetExprs();
|
||||||
|
ExprVector wu, wv;
|
||||||
|
w->WorkplaneGetBasisExprs(&wu, &wv);
|
||||||
|
|
||||||
|
// Get our coordinates in three-space, and project them into that
|
||||||
|
// coordinate system.
|
||||||
|
ExprVector ev = PointGetExprs();
|
||||||
|
ev = ev.Minus(wp);
|
||||||
|
*u = ev.Dot(wu);
|
||||||
|
*v = ev.Dot(wv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Entity::PointIsLocked(void) {
|
||||||
|
// A point is locked if none of its coordinates get assumed.
|
||||||
|
if(type == POINT_IN_3D) {
|
||||||
|
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 if(type == POINT_IN_2D) {
|
||||||
|
if(SS.GetParam(param[0])->assumed) return false;
|
||||||
|
if(SS.GetParam(param[1])->assumed) return false;
|
||||||
|
} else {
|
||||||
|
oops();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
|
void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
|
||||||
if(dogd.drawing) {
|
if(dogd.drawing) {
|
||||||
glBegin(GL_LINE_STRIP);
|
glBegin(GL_LINE_STRIP);
|
||||||
|
@ -272,7 +309,9 @@ void Entity::DrawOrGetDistance(int order) {
|
||||||
glEnd();
|
glEnd();
|
||||||
} else {
|
} else {
|
||||||
Point2d pp = SS.GW.ProjectPoint(v);
|
Point2d pp = SS.GW.ProjectPoint(v);
|
||||||
dogd.dmin = pp.DistanceTo(dogd.mp) - 5;
|
// Make a free point slightly easier to select, so that with
|
||||||
|
// coincident points, we select the free one.
|
||||||
|
dogd.dmin = pp.DistanceTo(dogd.mp) - (PointIsLocked() ? 3 : 4);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
1
file.cpp
1
file.cpp
|
@ -75,6 +75,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
|
||||||
{ 'c', "Constraint.h.v", 'x', &(SS.sv.c.h.v) },
|
{ 'c', "Constraint.h.v", 'x', &(SS.sv.c.h.v) },
|
||||||
{ 'c', "Constraint.type", 'd', &(SS.sv.c.type) },
|
{ 'c', "Constraint.type", 'd', &(SS.sv.c.type) },
|
||||||
{ 'c', "Constraint.group.v", 'x', &(SS.sv.c.group.v) },
|
{ 'c', "Constraint.group.v", 'x', &(SS.sv.c.group.v) },
|
||||||
|
{ 'c', "Constraint.workplane.v", 'x', &(SS.sv.c.workplane.v) },
|
||||||
{ 'c', "Constraint.exprA", 'E', &(SS.sv.c.exprA) },
|
{ 'c', "Constraint.exprA", 'E', &(SS.sv.c.exprA) },
|
||||||
{ 'c', "Constraint.exprB", 'E', &(SS.sv.c.exprB) },
|
{ 'c', "Constraint.exprB", 'E', &(SS.sv.c.exprB) },
|
||||||
{ 'c', "Constraint.ptA.v", 'x', &(SS.sv.c.ptA.v) },
|
{ 'c', "Constraint.ptA.v", 'x', &(SS.sv.c.ptA.v) },
|
||||||
|
|
|
@ -31,6 +31,8 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
||||||
{ 1, "Zoom &Out\t-", MNU_ZOOM_OUT, '-', mView },
|
{ 1, "Zoom &Out\t-", MNU_ZOOM_OUT, '-', mView },
|
||||||
{ 1, "Zoom To &Fit\tF", MNU_ZOOM_TO_FIT, 'F', mView },
|
{ 1, "Zoom To &Fit\tF", MNU_ZOOM_TO_FIT, 'F', mView },
|
||||||
{ 1, NULL, 0, NULL },
|
{ 1, NULL, 0, NULL },
|
||||||
|
{ 1, "Show Text &Window\tTab", MNU_SHOW_TEXT_WND, '\t', mView },
|
||||||
|
{ 1, NULL, 0, NULL },
|
||||||
{ 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, mView },
|
{ 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, mView },
|
||||||
{ 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView },
|
{ 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView },
|
||||||
|
|
||||||
|
@ -80,6 +82,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
||||||
{ 1, NULL, 0, NULL },
|
{ 1, NULL, 0, NULL },
|
||||||
{ 1, "Sym&bolic Equation\tShift+B", 0, 'B'|S, NULL },
|
{ 1, "Sym&bolic Equation\tShift+B", 0, 'B'|S, NULL },
|
||||||
{ 1, NULL, 0, NULL },
|
{ 1, NULL, 0, NULL },
|
||||||
|
{ 1, "Sol&ve Automatically\tShift+Tab", MNU_SOLVE_AUTO, '\t'|S, mCon },
|
||||||
{ 1, "Solve Once Now\tSpace", MNU_SOLVE_NOW, ' ', mCon },
|
{ 1, "Solve Once Now\tSpace", MNU_SOLVE_NOW, ' ', mCon },
|
||||||
|
|
||||||
{ 0, "&Help", 0, NULL },
|
{ 0, "&Help", 0, NULL },
|
||||||
|
@ -106,6 +109,11 @@ void GraphicsWindow::Init(void) {
|
||||||
showPoints = true;
|
showPoints = true;
|
||||||
showAllGroups = true;
|
showAllGroups = true;
|
||||||
showConstraints = true;
|
showConstraints = true;
|
||||||
|
|
||||||
|
solving = SOLVE_ALWAYS;
|
||||||
|
|
||||||
|
showTextWindow = true;
|
||||||
|
ShowTextWindow(showTextWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsWindow::NormalizeProjectionVectors(void) {
|
void GraphicsWindow::NormalizeProjectionVectors(void) {
|
||||||
|
@ -174,6 +182,11 @@ void GraphicsWindow::MenuView(int id) {
|
||||||
case MNU_ZOOM_TO_FIT:
|
case MNU_ZOOM_TO_FIT:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MNU_SHOW_TEXT_WND:
|
||||||
|
SS.GW.showTextWindow = !SS.GW.showTextWindow;
|
||||||
|
SS.GW.EnsureValidActives();
|
||||||
|
break;
|
||||||
|
|
||||||
case MNU_UNITS_MM:
|
case MNU_UNITS_MM:
|
||||||
SS.GW.viewUnits = UNIT_MM;
|
SS.GW.viewUnits = UNIT_MM;
|
||||||
SS.GW.EnsureValidActives();
|
SS.GW.EnsureValidActives();
|
||||||
|
@ -228,6 +241,11 @@ void GraphicsWindow::EnsureValidActives(void) {
|
||||||
}
|
}
|
||||||
CheckMenuById(MNU_UNITS_MM, viewUnits == UNIT_MM);
|
CheckMenuById(MNU_UNITS_MM, viewUnits == UNIT_MM);
|
||||||
CheckMenuById(MNU_UNITS_INCHES, viewUnits == UNIT_INCHES);
|
CheckMenuById(MNU_UNITS_INCHES, viewUnits == UNIT_INCHES);
|
||||||
|
|
||||||
|
ShowTextWindow(SS.GW.showTextWindow);
|
||||||
|
CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow);
|
||||||
|
|
||||||
|
CheckMenuById(MNU_SOLVE_AUTO, (SS.GW.solving == SOLVE_ALWAYS));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsWindow::MenuEdit(int id) {
|
void GraphicsWindow::MenuEdit(int id) {
|
||||||
|
@ -415,7 +433,9 @@ 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);
|
||||||
HitTestMakeSelection(mp);
|
if(solving == SOLVE_ALWAYS) {
|
||||||
|
SS.Solve();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No buttons pressed.
|
// No buttons pressed.
|
||||||
|
@ -543,6 +563,9 @@ hRequest GraphicsWindow::AddRequest(int type) {
|
||||||
r.type = type;
|
r.type = type;
|
||||||
SS.request.AddAndAssignId(&r);
|
SS.request.AddAndAssignId(&r);
|
||||||
SS.GenerateAll();
|
SS.GenerateAll();
|
||||||
|
|
||||||
|
if(solving == SOLVE_ALWAYS) SS.Solve();
|
||||||
|
|
||||||
return r.h;
|
return r.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,6 +730,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();
|
||||||
} else {
|
} else {
|
||||||
Error("Not a valid number or expression: '%s'", s);
|
Error("Not a valid number or expression: '%s'", s);
|
||||||
}
|
}
|
||||||
|
|
5
sketch.h
5
sketch.h
|
@ -167,8 +167,10 @@ public:
|
||||||
bool IsPoint(void);
|
bool IsPoint(void);
|
||||||
bool IsPointIn3d(void);
|
bool IsPointIn3d(void);
|
||||||
// Applies for any of the point types
|
// Applies for any of the point types
|
||||||
|
bool PointIsLocked(void);
|
||||||
Vector PointGetCoords(void);
|
Vector PointGetCoords(void);
|
||||||
ExprVector PointGetExprs(void);
|
ExprVector PointGetExprs(void);
|
||||||
|
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);
|
bool PointIsKnown(void);
|
||||||
|
@ -204,6 +206,7 @@ public:
|
||||||
|
|
||||||
double val;
|
double val;
|
||||||
bool known;
|
bool known;
|
||||||
|
bool assumed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,7 +290,7 @@ public:
|
||||||
// Some helpers when generating symbolic constraint equations
|
// Some helpers when generating symbolic constraint equations
|
||||||
void ModifyToSatisfy(void);
|
void ModifyToSatisfy(void);
|
||||||
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
|
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
|
||||||
static Expr *Distance(hEntity pa, hEntity pb);
|
static Expr *Distance(hEntity workplane, hEntity pa, hEntity pb);
|
||||||
|
|
||||||
static void ConstrainCoincident(hEntity ptA, hEntity ptB);
|
static void ConstrainCoincident(hEntity ptA, hEntity ptB);
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,7 @@ void SolveSpace::Init(char *cmdLine) {
|
||||||
void SolveSpace::GenerateAll(void) {
|
void SolveSpace::GenerateAll(void) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
// Don't lose our numerical guesses when we regenerate.
|
||||||
IdList<Param,hParam> prev;
|
IdList<Param,hParam> prev;
|
||||||
param.MoveSelfInto(&prev);
|
param.MoveSelfInto(&prev);
|
||||||
|
|
||||||
|
@ -28,10 +29,12 @@ void SolveSpace::GenerateAll(void) {
|
||||||
request.elem[i].Generate(&entity, ¶m);
|
request.elem[i].Generate(&entity, ¶m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore the numerical guesses.
|
||||||
for(i = 0; i < param.n; i++) {
|
for(i = 0; i < param.n; i++) {
|
||||||
Param *p = prev.FindByIdNoOops(param.elem[i].h);
|
Param *p = prev.FindByIdNoOops(param.elem[i].h);
|
||||||
if(p) {
|
if(p) {
|
||||||
param.elem[i].val = p->val;
|
param.elem[i].val = p->val;
|
||||||
|
param.elem[i].assumed = p->assumed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,10 +40,11 @@ void ShowGraphicsEditControl(int x, int y, char *s);
|
||||||
void HideGraphicsEditControl(void);
|
void HideGraphicsEditControl(void);
|
||||||
BOOL GraphicsEditControlIsVisible(void);
|
BOOL GraphicsEditControlIsVisible(void);
|
||||||
|
|
||||||
void InvalidateGraphics(void);
|
void ShowTextWindow(BOOL visible);
|
||||||
void InvalidateText(void);
|
void InvalidateText(void);
|
||||||
SDWORD GetMilliseconds(void);
|
void InvalidateGraphics(void);
|
||||||
void PaintGraphics(void);
|
void PaintGraphics(void);
|
||||||
|
SDWORD GetMilliseconds(void);
|
||||||
|
|
||||||
void dbp(char *str, ...);
|
void dbp(char *str, ...);
|
||||||
void Error(char *str, ...);
|
void Error(char *str, ...);
|
||||||
|
|
25
system.cpp
25
system.cpp
|
@ -181,9 +181,6 @@ bool System::NewtonSolve(int tag) {
|
||||||
// Take the Newton step;
|
// Take the Newton step;
|
||||||
// J(x_n) (x_{n+1} - x_n) = 0 - F(x_n)
|
// J(x_n) (x_{n+1} - x_n) = 0 - F(x_n)
|
||||||
for(i = 0; i < mat.m; i++) {
|
for(i = 0; i < mat.m; i++) {
|
||||||
dbp("mat.X[%d] = %.3f", i, mat.X[i]);
|
|
||||||
dbp("modifying param %08x, now %.3f", mat.param[i],
|
|
||||||
param.FindById(mat.param[i])->val);
|
|
||||||
(param.FindById(mat.param[i]))->val -= mat.X[i];
|
(param.FindById(mat.param[i]))->val -= mat.X[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,10 +207,10 @@ 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());
|
||||||
}
|
} */
|
||||||
|
|
||||||
param.ClearTags();
|
param.ClearTags();
|
||||||
eq.ClearTags();
|
eq.ClearTags();
|
||||||
|
@ -221,23 +218,30 @@ 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();
|
||||||
|
|
||||||
dbp("bound states:");
|
/* dbp("bound states:");
|
||||||
for(j = 0; j < mat.n; j++) {
|
for(j = 0; j < mat.n; j++) {
|
||||||
dbp(" param %08x: %d", mat.param[j], mat.bound[j]);
|
dbp(" param %08x: %d", mat.param[j], mat.bound[j]);
|
||||||
}
|
} */
|
||||||
|
|
||||||
// Fix any still-free variables wherever they are now.
|
// Fix any still-free variables wherever they are now.
|
||||||
for(j = 0; j < mat.n; j++) {
|
for(j = 0; j < mat.n; j++) {
|
||||||
if(mat.bound[j]) continue;
|
if(mat.bound[j]) continue;
|
||||||
param.FindById(mat.param[j])->tag = ASSUMED;
|
Param *p = param.FindByIdNoOops(mat.param[j]);
|
||||||
|
if(!p) {
|
||||||
|
// This is parameter does not occur in this group, so it's
|
||||||
|
// not available to assume.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
p->tag = ASSUMED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = NewtonSolve(0);
|
bool ok = NewtonSolve(0);
|
||||||
|
@ -250,6 +254,9 @@ bool System::Solve(void) {
|
||||||
Param *pp = SS.GetParam(p->h);
|
Param *pp = SS.GetParam(p->h);
|
||||||
pp->val = p->val;
|
pp->val = p->val;
|
||||||
pp->known = true;
|
pp->known = true;
|
||||||
|
// The main param table keeps track of what was assumed, to
|
||||||
|
// choose which point to drag so that it actually moves.
|
||||||
|
pp->assumed = (p->tag == ASSUMED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
ui.h
13
ui.h
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
class TextWindow {
|
class TextWindow {
|
||||||
public:
|
public:
|
||||||
static const int MAX_COLS = 150;
|
static const int MAX_COLS = 100;
|
||||||
static const int MAX_ROWS = 300;
|
static const int MAX_ROWS = 200;
|
||||||
|
|
||||||
#ifndef RGB
|
#ifndef RGB
|
||||||
#define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16))
|
#define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16))
|
||||||
|
@ -87,11 +87,12 @@ public:
|
||||||
MNU_ZOOM_IN,
|
MNU_ZOOM_IN,
|
||||||
MNU_ZOOM_OUT,
|
MNU_ZOOM_OUT,
|
||||||
MNU_ZOOM_TO_FIT,
|
MNU_ZOOM_TO_FIT,
|
||||||
MNU_UNSELECT_ALL,
|
MNU_SHOW_TEXT_WND,
|
||||||
MNU_UNITS_INCHES,
|
MNU_UNITS_INCHES,
|
||||||
MNU_UNITS_MM,
|
MNU_UNITS_MM,
|
||||||
// Edit
|
// Edit
|
||||||
MNU_DELETE,
|
MNU_DELETE,
|
||||||
|
MNU_UNSELECT_ALL,
|
||||||
// Request
|
// Request
|
||||||
MNU_SEL_WORKPLANE,
|
MNU_SEL_WORKPLANE,
|
||||||
MNU_FREE_IN_3D,
|
MNU_FREE_IN_3D,
|
||||||
|
@ -105,6 +106,7 @@ public:
|
||||||
MNU_ON_ENTITY,
|
MNU_ON_ENTITY,
|
||||||
MNU_HORIZONTAL,
|
MNU_HORIZONTAL,
|
||||||
MNU_VERTICAL,
|
MNU_VERTICAL,
|
||||||
|
MNU_SOLVE_AUTO,
|
||||||
MNU_SOLVE_NOW,
|
MNU_SOLVE_NOW,
|
||||||
} MenuId;
|
} MenuId;
|
||||||
typedef void MenuHandler(int id);
|
typedef void MenuHandler(int id);
|
||||||
|
@ -201,9 +203,14 @@ public:
|
||||||
bool showPoints;
|
bool showPoints;
|
||||||
bool showAllGroups;
|
bool showAllGroups;
|
||||||
bool showConstraints;
|
bool showConstraints;
|
||||||
|
bool showTextWindow;
|
||||||
static void ToggleBool(int link, DWORD v);
|
static void ToggleBool(int link, DWORD v);
|
||||||
static void ToggleAnyDatumShown(int link, DWORD v);
|
static void ToggleAnyDatumShown(int link, DWORD v);
|
||||||
|
|
||||||
|
static const int DONT_SOLVE = 0;
|
||||||
|
static const int SOLVE_ALWAYS = 1;
|
||||||
|
int solving;
|
||||||
|
|
||||||
void UpdateDraggedPoint(Vector *pos, double mx, double my);
|
void UpdateDraggedPoint(Vector *pos, double mx, double my);
|
||||||
void UpdateDraggedEntity(hEntity hp, double mx, double my);
|
void UpdateDraggedEntity(hEntity hp, double mx, double my);
|
||||||
|
|
||||||
|
|
|
@ -332,6 +332,7 @@ static BOOL ProcessKeyDown(WPARAM wParam)
|
||||||
case VK_OEM_5: c = '\\'; break;
|
case VK_OEM_5: c = '\\'; break;
|
||||||
case VK_SPACE: c = ' '; break;
|
case VK_SPACE: c = ' '; break;
|
||||||
case VK_DELETE: c = 127; break;
|
case VK_DELETE: c = 127; break;
|
||||||
|
case VK_TAB: c = '\t'; break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
c = wParam;
|
c = wParam;
|
||||||
|
@ -351,6 +352,11 @@ static BOOL ProcessKeyDown(WPARAM wParam)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShowTextWindow(BOOL visible)
|
||||||
|
{
|
||||||
|
ShowWindow(TextWnd, visible ? SW_SHOWNOACTIVATE : SW_HIDE);
|
||||||
|
}
|
||||||
|
|
||||||
static HGLRC CreateGlContext(HDC hdc)
|
static HGLRC CreateGlContext(HDC hdc)
|
||||||
{
|
{
|
||||||
PIXELFORMATDESCRIPTOR pfd;
|
PIXELFORMATDESCRIPTOR pfd;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user