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]
This commit is contained in:
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.type = PT_IN_PLANE;
c.ptA = gs.point[0]; c.ptA = gs.point[0];
c.entityA = gs.entity[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 { } else {
Error("Bad selection for on point / curve / plane constraint."); Error("Bad selection for on point / curve / plane constraint.");
return; return;
@ -135,6 +139,42 @@ void Constraint::MenuConstrain(int id) {
InvalidateGraphics(); 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) { 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);
@ -231,6 +271,30 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
break; 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 HORIZONTAL:
case VERTICAL: { case VERTICAL: {
hEntity ha, hb; hEntity ha, hb;

View File

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

View File

@ -29,6 +29,14 @@ Expr *ExprVector::Dot(ExprVector b) {
return r; 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 ExprVector::ScaledBy(Expr *s) {
ExprVector r; ExprVector r;
r.x = x->Times(s); r.x = x->Times(s);

1
expr.h
View File

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

View File

@ -48,6 +48,9 @@ void glxTranslatev(Vector u)
void glxOntoWorkplane(Vector u, Vector v) void glxOntoWorkplane(Vector u, Vector v)
{ {
u = u.WithMagnitude(1);
v = v.WithMagnitude(1);
double mat[16]; double mat[16];
Vector n = u.Cross(v); Vector n = u.Cross(v);
MakeMatrix(mat, u.x, v.x, n.x, 0, 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); Constraint *c = SS.constraint.FindById(pendingConstraint);
UpdateDraggedPoint(&(c->disp.offset), x, y); UpdateDraggedPoint(&(c->disp.offset), x, y);
} else if(leftDown && pendingOperation == DRAGGING_POINT) { } else if(leftDown && pendingOperation == DRAGGING_POINT) {
if(havePainted) {
UpdateDraggedEntity(pendingPoint, x, y); UpdateDraggedEntity(pendingPoint, x, y);
SS.GenerateAll(solving == SOLVE_ALWAYS); SS.GenerateAll(solving == SOLVE_ALWAYS);
havePainted = false;
}
} }
// No buttons pressed. // No buttons pressed.
@ -775,6 +778,7 @@ void GraphicsWindow::ToggleAnyDatumShown(int link, DWORD v) {
} }
void GraphicsWindow::Paint(int w, int h) { void GraphicsWindow::Paint(int w, int h) {
havePainted = true;
width = w; height = h; width = w; height = h;
glViewport(0, 0, w, h); glViewport(0, 0, w, h);

View File

@ -260,6 +260,7 @@ public:
static const int PT_PT_DISTANCE = 30; static const int PT_PT_DISTANCE = 30;
static const int PT_LINE_DISTANCE = 31; static const int PT_LINE_DISTANCE = 31;
static const int PT_IN_PLANE = 40; static const int PT_IN_PLANE = 40;
static const int PT_ON_LINE = 41;
static const int EQUAL_LENGTH_LINES = 50; static const int EQUAL_LENGTH_LINES = 50;
static const int HORIZONTAL = 80; static const int HORIZONTAL = 80;
@ -311,6 +312,7 @@ public:
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 workplane, hEntity pa, hEntity pb); 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); static void ConstrainCoincident(hEntity ptA, hEntity ptB);
}; };

View File

@ -39,7 +39,7 @@ void System::EvalJacobian(void) {
} }
bool System::Tol(double v) { bool System::Tol(double v) {
return (fabs(v) < 0.01); return (fabs(v) < 0.001);
} }
void System::GaussJordan(void) { void System::GaussJordan(void) {
@ -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(" %.3f = %s = 0", eq.elem[i].e->Eval(), eq.elem[i].e->Print());
} }
dbp("%d parameters", param.n); */ dbp("%d parameters", param.n); */

View File

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

7
ui.h
View File

@ -65,7 +65,7 @@ public:
void ShowEntityInfo(void); void ShowEntityInfo(void);
void ShowConstraintInfo(void); void ShowConstraintInfo(void);
void OneScreenForward(void); void OneScreenForwardTo(int screen);
static void ScreenSelectGroup(int link, DWORD v); static void ScreenSelectGroup(int link, DWORD v);
static void ScreenActivateGroup(int link, DWORD v); static void ScreenActivateGroup(int link, DWORD v);
static void ScreenToggleGroupShown(int link, DWORD v); static void ScreenToggleGroupShown(int link, DWORD v);
@ -145,6 +145,11 @@ public:
Point2d mouse; Point2d mouse;
} orig; } 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); void NormalizeProjectionVectors(void);
Point2d ProjectPoint(Vector p); Point2d ProjectPoint(Vector p);
void AnimateOnto(Quaternion quatf, Vector offsetf); void AnimateOnto(Quaternion quatf, Vector offsetf);