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
parent
598d456d8d
commit
70bf14530d
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
8
expr.cpp
8
expr.cpp
|
@ -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
1
expr.h
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
2
sketch.h
2
sketch.h
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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); */
|
||||
|
||||
|
|
25
textwin.cpp
25
textwin.cpp
|
@ -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
7
ui.h
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue