Add point on line constraints, in 2d and 3d. The 3d equations do

not have much motivation behind them, but they seem to work. And
make sure that we don't solve multiple times without repainting in
between, and tweak the text window a bit more.

[git-p4: depot-paths = "//depot/solvespace/": change = 1696]
solver
Jonathan Westhues 2008-04-28 01:40:02 -08:00
parent 598d456d8d
commit 70bf14530d
10 changed files with 113 additions and 27 deletions

View File

@ -68,6 +68,10 @@ void Constraint::MenuConstrain(int id) {
c.type = PT_IN_PLANE;
c.ptA = gs.point[0];
c.entityA = gs.entity[0];
} else if(gs.points == 1 && gs.lineSegments == 1 && gs.n == 2) {
c.type = PT_ON_LINE;
c.ptA = gs.point[0];
c.entityA = gs.entity[0];
} else {
Error("Bad selection for on point / curve / plane constraint.");
return;
@ -135,6 +139,42 @@ void Constraint::MenuConstrain(int id) {
InvalidateGraphics();
}
Expr *Constraint::PointLineDistance(hEntity wrkpl, hEntity hpt, hEntity hln) {
Entity *ln = SS.GetEntity(hln);
Entity *a = SS.GetEntity(ln->point[0]);
Entity *b = SS.GetEntity(ln->point[1]);
Entity *p = SS.GetEntity(hpt);
if(wrkpl.v == Entity::FREE_IN_3D.v) {
ExprVector ep = p->PointGetExprs();
ExprVector ea = a->PointGetExprs();
ExprVector eb = b->PointGetExprs();
ExprVector eab = ea.Minus(eb);
Expr *m = eab.Magnitude();
return ((eab.Cross(ea.Minus(ep))).Magnitude())->Div(m);
} else {
Expr *ua, *va, *ub, *vb;
a->PointGetExprsInWorkplane(wrkpl, &ua, &va);
b->PointGetExprsInWorkplane(wrkpl, &ub, &vb);
Expr *du = ua->Minus(ub);
Expr *dv = va->Minus(vb);
Expr *u, *v;
p->PointGetExprsInWorkplane(wrkpl, &u, &v);
Expr *m = ((du->Square())->Plus(dv->Square()))->Sqrt();
Expr *proj = (dv->Times(ua->Minus(u)))->Minus(
(du->Times(va->Minus(v))));
return proj->Div(m);
}
}
Expr *Constraint::Distance(hEntity wrkpl, hEntity hpa, hEntity hpb) {
Entity *pa = SS.GetEntity(hpa);
Entity *pb = SS.GetEntity(hpb);
@ -231,6 +271,30 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
break;
}
case PT_ON_LINE:
if(workplane.v == Entity::FREE_IN_3D.v) {
Entity *ln = SS.GetEntity(entityA);
Entity *a = SS.GetEntity(ln->point[0]);
Entity *b = SS.GetEntity(ln->point[1]);
Entity *p = SS.GetEntity(ptA);
ExprVector ep = p->PointGetExprs();
ExprVector ea = a->PointGetExprs();
ExprVector eb = b->PointGetExprs();
ExprVector eab = ea.Minus(eb);
ExprVector r = eab.Cross(ea.Minus(ep));
// When the constraint is satisfied, our vector r is zero;
// but that's three numbers, and the constraint hits only
// two degrees of freedom. This seems to be an acceptable
// choice of equations, though it's arbitrary.
AddEq(l, (r.x)->Square()->Plus((r.y)->Square()), 0);
AddEq(l, (r.y)->Square()->Plus((r.z)->Square()), 1);
} else {
AddEq(l, PointLineDistance(workplane, ptA, entityA), 0);
}
break;
case HORIZONTAL:
case VERTICAL: {
hEntity ha, hb;

View File

@ -32,10 +32,11 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
// able to be selected.
if(!(g->visible)) return;
// Unit vectors that describe our current view of the scene.
Vector gr = SS.GW.projRight;
Vector gu = SS.GW.projUp;
Vector gn = gr.Cross(gu);
// Unit vectors that describe our current view of the scene. One pixel
// long, not one actual unit.
Vector gr = SS.GW.projRight.ScaledBy(1/SS.GW.scale);
Vector gu = SS.GW.projUp.ScaledBy(1/SS.GW.scale);
Vector gn = (gr.Cross(gu)).WithMagnitude(1/SS.GW.scale);
glxColor3d(1, 0.2, 1);
switch(type) {
@ -103,11 +104,12 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
break;
}
case PT_ON_LINE:
case PT_IN_PLANE: {
double s = 5;
Vector r = SS.GW.projRight.ScaledBy(s/SS.GW.scale);
Vector d = SS.GW.projUp.ScaledBy(s/SS.GW.scale);
double s = 7;
Vector p = SS.GetEntity(ptA)->PointGetCoords();
Vector r = gr.WithMagnitude(s);
Vector d = gu.WithMagnitude(s);
LineDrawOrGetDistance(p.Plus (r).Plus (d), p.Plus (r).Minus(d));
LineDrawOrGetDistance(p.Plus (r).Minus(d), p.Minus(r).Minus(d));
LineDrawOrGetDistance(p.Minus(r).Minus(d), p.Minus(r).Plus (d));
@ -115,6 +117,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
break;
}
case EQUAL_LENGTH_LINES: {
for(int i = 0; i < 2; i++) {
Entity *e = SS.GetEntity(i == 0 ? entityA : entityB);

View File

@ -29,6 +29,14 @@ Expr *ExprVector::Dot(ExprVector b) {
return r;
}
ExprVector ExprVector::Cross(ExprVector b) {
ExprVector r;
r.x = (y->Times(b.z))->Minus(z->Times(b.y));
r.y = (z->Times(b.x))->Minus(x->Times(b.z));
r.z = (x->Times(b.y))->Minus(y->Times(b.x));
return r;
}
ExprVector ExprVector::ScaledBy(Expr *s) {
ExprVector r;
r.x = x->Times(s);

1
expr.h
View File

@ -123,6 +123,7 @@ public:
ExprVector Plus(ExprVector b);
ExprVector Minus(ExprVector b);
Expr *Dot(ExprVector b);
ExprVector Cross(ExprVector b);
ExprVector ScaledBy(Expr *s);
Expr *Magnitude(void);
};

View File

@ -48,6 +48,9 @@ void glxTranslatev(Vector u)
void glxOntoWorkplane(Vector u, Vector v)
{
u = u.WithMagnitude(1);
v = v.WithMagnitude(1);
double mat[16];
Vector n = u.Cross(v);
MakeMatrix(mat, u.x, v.x, n.x, 0,

View File

@ -432,8 +432,11 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
Constraint *c = SS.constraint.FindById(pendingConstraint);
UpdateDraggedPoint(&(c->disp.offset), x, y);
} else if(leftDown && pendingOperation == DRAGGING_POINT) {
UpdateDraggedEntity(pendingPoint, x, y);
SS.GenerateAll(solving == SOLVE_ALWAYS);
if(havePainted) {
UpdateDraggedEntity(pendingPoint, x, y);
SS.GenerateAll(solving == SOLVE_ALWAYS);
havePainted = false;
}
}
// No buttons pressed.
@ -775,6 +778,7 @@ void GraphicsWindow::ToggleAnyDatumShown(int link, DWORD v) {
}
void GraphicsWindow::Paint(int w, int h) {
havePainted = true;
width = w; height = h;
glViewport(0, 0, w, h);

View File

@ -260,6 +260,7 @@ public:
static const int PT_PT_DISTANCE = 30;
static const int PT_LINE_DISTANCE = 31;
static const int PT_IN_PLANE = 40;
static const int PT_ON_LINE = 41;
static const int EQUAL_LENGTH_LINES = 50;
static const int HORIZONTAL = 80;
@ -311,6 +312,7 @@ public:
void ModifyToSatisfy(void);
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
static Expr *Distance(hEntity workplane, hEntity pa, hEntity pb);
static Expr *PointLineDistance(hEntity workplane, hEntity pt, hEntity ln);
static void ConstrainCoincident(hEntity ptA, hEntity ptB);
};

View File

@ -39,7 +39,7 @@ void System::EvalJacobian(void) {
}
bool System::Tol(double v) {
return (fabs(v) < 0.01);
return (fabs(v) < 0.001);
}
void System::GaussJordan(void) {
@ -207,10 +207,11 @@ bool System::NewtonSolve(int tag) {
bool System::Solve(void) {
int i, j;
/*
dbp("%d equations", eq.n);
for(i = 0; i < eq.n; i++) {
dbp(" %s = 0", eq.elem[i].e->Print());
dbp(" %.3f = %s = 0", eq.elem[i].e->Eval(), eq.elem[i].e->Print());
}
dbp("%d parameters", param.n); */

View File

@ -13,8 +13,8 @@ const TextWindow::Color TextWindow::fgColors[] = {
};
const TextWindow::Color TextWindow::bgColors[] = {
{ 'd', RGB( 0, 0, 0) },
{ 't', RGB( 30, 10, 30) },
{ 'a', RGB( 25, 25, 25) },
{ 't', RGB( 40, 20, 40) },
{ 'a', RGB( 20, 20, 20) },
{ 'r', RGB(255, 255, 255) },
{ 0, 0 },
};
@ -181,19 +181,20 @@ void TextWindow::Show(void) {
InvalidateText();
}
void TextWindow::OneScreenForward(void) {
void TextWindow::OneScreenForwardTo(int screen) {
SS.TW.shownIndex++;
if(SS.TW.shownIndex >= HISTORY_LEN) SS.TW.shownIndex = 0;
SS.TW.shown = &(SS.TW.showns[SS.TW.shownIndex]);
history++;
if(screen >= 0) shown->screen = screen;
}
void TextWindow::ScreenNavigation(int link, DWORD v) {
switch(link) {
default:
case 'h':
SS.TW.OneScreenForward();
SS.TW.shown->screen = SCREEN_LIST_OF_GROUPS;
SS.TW.OneScreenForwardTo(SCREEN_LIST_OF_GROUPS);
break;
case 'b':
@ -206,7 +207,7 @@ void TextWindow::ScreenNavigation(int link, DWORD v) {
break;
case 'f':
SS.TW.OneScreenForward();
SS.TW.OneScreenForwardTo(-1);
break;
}
SS.TW.Show();
@ -262,9 +263,7 @@ hs(SS.GW.showConstraints), (DWORD)(&SS.GW.showConstraints), &(SS.GW.ToggleBool)
}
void TextWindow::ScreenSelectGroup(int link, DWORD v) {
SS.TW.OneScreenForward();
SS.TW.shown->screen = SCREEN_GROUP_INFO;
SS.TW.OneScreenForwardTo(SCREEN_GROUP_INFO);
SS.TW.shown->group.v = v;
SS.TW.Show();
@ -317,17 +316,13 @@ void TextWindow::ShowListOfGroups(void) {
void TextWindow::ScreenSelectConstraint(int link, DWORD v) {
SS.TW.OneScreenForward();
SS.TW.shown->screen = SCREEN_CONSTRAINT_INFO;
SS.TW.OneScreenForwardTo(SCREEN_CONSTRAINT_INFO);
SS.TW.shown->constraint.v = v;
SS.TW.Show();
}
void TextWindow::ScreenSelectRequest(int link, DWORD v) {
SS.TW.OneScreenForward();
SS.TW.shown->screen = SCREEN_REQUEST_INFO;
SS.TW.OneScreenForwardTo(SCREEN_REQUEST_INFO);
SS.TW.shown->request.v = v;
SS.TW.Show();

7
ui.h
View File

@ -65,7 +65,7 @@ public:
void ShowEntityInfo(void);
void ShowConstraintInfo(void);
void OneScreenForward(void);
void OneScreenForwardTo(int screen);
static void ScreenSelectGroup(int link, DWORD v);
static void ScreenActivateGroup(int link, DWORD v);
static void ScreenToggleGroupShown(int link, DWORD v);
@ -145,6 +145,11 @@ public:
Point2d mouse;
} orig;
// When the user is dragging a point, don't solve multiple times without
// allowing a paint in between. The extra solves are wasted if they're
// not displayed.
bool havePainted;
void NormalizeProjectionVectors(void);
Point2d ProjectPoint(Vector p);
void AnimateOnto(Quaternion quatf, Vector offsetf);