Add an ExprVector class, for a 3-vector whose members are

expressions. That simplifies a few things considerably. And some
little UI tweaks.

[git-p4: depot-paths = "//depot/solvespace/": change = 1682]
solver
Jonathan Westhues 2008-04-22 05:14:15 -08:00
parent fa71238def
commit 1bf7e3deaf
10 changed files with 216 additions and 93 deletions

View File

@ -92,16 +92,14 @@ Expr *Constraint::Distance(hEntity hpa, hEntity hpb) {
return ((du->Square())->Plus(dv->Square()))->Sqrt();
}
Expr *ax, *ay, *az;
Expr *bx, *by, *bz;
pa->PointGetExprs(&ax, &ay, &az);
pb->PointGetExprs(&bx, &by, &bz);
Expr *dx2 = (ax->Minus(bx))->Square();
Expr *dy2 = (ay->Minus(by))->Square();
Expr *dz2 = (az->Minus(bz))->Square();
// 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 (dx2->Plus(dy2->Plus(dz2)))->Sqrt();
return eab.Magnitude();
}
void Constraint::ModifyToSatisfy(void) {
@ -144,24 +142,49 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
}
case POINTS_COINCIDENT: {
Expr *ax, *ay, *az;
Expr *bx, *by, *bz;
SS.GetEntity(ptA)->PointGetExprs(&ax, &ay, &az);
SS.GetEntity(ptB)->PointGetExprs(&bx, &by, &bz);
AddEq(l, ax->Minus(bx), 0);
AddEq(l, ay->Minus(by), 1);
AddEq(l, az->Minus(bz), 2);
Entity *a = SS.GetEntity(ptA);
Entity *b = SS.GetEntity(ptB);
if(!a->IsPointIn3d() && b->IsPointIn3d()) {
Entity *t = a;
a = b; b = t;
}
if(a->IsPointIn3d() && b->IsPointIn3d()) {
// Easy case: both points have 3 DOF, so write three eqs.
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()) {
// One point has 2 DOF, one has 3; write two eqs, on the
// projection of the 3 DOF point into the 2 DOF point plane.
ExprVector p3;
p3 = a->PointGetExprs();
Entity *csy = SS.GetEntity(b->csys);
ExprVector u, v;
csy->Csys2dGetBasisExprs(&u, &v);
AddEq(l, Expr::FromParam(b->param.h[0])->Minus(p3.Dot(u)), 0);
AddEq(l, Expr::FromParam(b->param.h[1])->Minus(p3.Dot(v)), 1);
} else if(a->csys.v == b->csys.v) {
// Both in same csys, nice.
AddEq(l, Expr::FromParam(a->param.h[0])->Minus(
Expr::FromParam(b->param.h[0])), 0);
AddEq(l, Expr::FromParam(a->param.h[1])->Minus(
Expr::FromParam(b->param.h[1])), 1);
} else {
oops();
}
break;
}
case PT_IN_PLANE: {
Expr *px, *py, *pz;
Expr *nx, *ny, *nz, *d;
SS.GetEntity(ptA)->PointGetExprs(&px, &py, &pz);
SS.GetEntity(entityA)->PlaneGetExprs(&nx, &ny, &nz, &d);
AddEq(l,
((px->Times(nx))->Plus((py->Times(ny)->Plus(pz->Times(nz)))))
->Minus(d), 0);
ExprVector p, n;
Expr *d;
p = SS.GetEntity(ptA)->PointGetExprs();
SS.GetEntity(entityA)->PlaneGetExprs(&n, &d);
AddEq(l, (p.Dot(n))->Minus(d), 0);
break;
}

View File

@ -16,7 +16,7 @@ void Entity::Csys2dGetBasisVectors(Vector *u, Vector *v) {
*v = quat.RotationV();
}
void Entity::Csys2dGetBasisExprs(Expr **u, Expr **v) {
void Entity::Csys2dGetBasisExprs(ExprVector *u, ExprVector *v) {
Expr *a = Expr::FromParam(param.h[0]);
Expr *b = Expr::FromParam(param.h[1]);
Expr *c = Expr::FromParam(param.h[2]);
@ -24,23 +24,27 @@ void Entity::Csys2dGetBasisExprs(Expr **u, Expr **v) {
Expr *two = Expr::FromConstant(2);
u[0] = a->Square();
u[0] = (u[0])->Plus(b->Square());
u[0] = (u[0])->Minus(c->Square());
u[0] = (u[0])->Minus(d->Square());
u[1] = two->Times(a->Times(d));
u[1] = (u[1])->Plus(two->Times(b->Times(c)));
u[2] = two->Times(b->Times(d));
u[2] = (u[2])->Minus(two->Times(a->Times(c)));
u->x = a->Square();
u->x = (u->x)->Plus(b->Square());
u->x = (u->x)->Minus(c->Square());
u->x = (u->x)->Minus(d->Square());
v[0] = two->Times(b->Times(c));
v[0] = (v[0])->Minus(two->Times(a->Times(d)));
v[1] = a->Square();
v[1] = (v[1])->Minus(b->Square());
v[1] = (v[1])->Plus(c->Square());
v[1] = (v[1])->Minus(d->Square());
v[2] = two->Times(a->Times(b));
v[2] = (v[2])->Plus(two->Times(c->Times(d)));
u->y = two->Times(a->Times(d));
u->y = (u->y)->Plus(two->Times(b->Times(c)));
u->z = two->Times(b->Times(d));
u->z = (u->z)->Minus(two->Times(a->Times(c)));
v->x = two->Times(b->Times(c));
v->x = (v->x)->Minus(two->Times(a->Times(d)));
v->y = a->Square();
v->y = (v->y)->Minus(b->Square());
v->y = (v->y)->Plus(c->Square());
v->y = (v->y)->Minus(d->Square());
v->z = two->Times(a->Times(b));
v->z = (v->z)->Plus(two->Times(c->Times(d)));
}
bool Entity::HasPlane(void) {
@ -52,32 +56,33 @@ bool Entity::HasPlane(void) {
}
}
void Entity::PlaneGetExprs(Expr **x, Expr **y, Expr **z, Expr **dn) {
Expr *a = Expr::FromParam(param.h[0]);
Expr *b = Expr::FromParam(param.h[1]);
Expr *c = Expr::FromParam(param.h[2]);
Expr *d = Expr::FromParam(param.h[3]);
void Entity::PlaneGetExprs(ExprVector *n, Expr **dn) {
if(type == CSYS_2D) {
Expr *a = Expr::FromParam(param.h[0]);
Expr *b = Expr::FromParam(param.h[1]);
Expr *c = Expr::FromParam(param.h[2]);
Expr *d = Expr::FromParam(param.h[3]);
Expr *two = Expr::FromConstant(2);
Expr *two = Expr::FromConstant(2);
// Convert the quaternion to our plane's normal vector.
*x = two->Times(a->Times(c));
*x = (*x)->Plus (two->Times(b->Times(d)));
*y = two->Times(c->Times(d));
*y = (*y)->Minus(two->Times(a->Times(b)));
*z = a->Square();
*z = (*z)->Minus(b->Square());
*z = (*z)->Minus(c->Square());
*z = (*z)->Plus (d->Square());
// Convert the quaternion to our plane's normal vector.
n->x = two->Times(a->Times(c));
n->x = (n->x)->Plus (two->Times(b->Times(d)));
n->y = two->Times(c->Times(d));
n->y = (n->y)->Minus(two->Times(a->Times(b)));
n->z = a->Square();
n->z = (n->z)->Minus(b->Square());
n->z = (n->z)->Minus(c->Square());
n->z = (n->z)->Plus (d->Square());
Expr *x0, *y0, *z0;
SS.GetEntity(assoc[0])->PointGetExprs(&x0, &y0, &z0);
// The plane is n dot (p - p0) = 0, or
// n dot p - n dot p0 = 0
// so dn = n dot p0
*dn = x0->Times(*x);
*dn = (*dn)->Plus(y0->Times(*y));
*dn = (*dn)->Plus(z0->Times(*z));
ExprVector p0 = SS.GetEntity(assoc[0])->PointGetExprs();
// The plane is n dot (p - p0) = 0, or
// n dot p - n dot p0 = 0
// so dn = n dot p0
*dn = p0.Dot(*n);
} else {
oops();
}
}
bool Entity::IsPoint(void) {
@ -90,6 +95,15 @@ bool Entity::IsPoint(void) {
}
}
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:
@ -149,31 +163,27 @@ Vector Entity::PointGetCoords(void) {
return p;
}
void Entity::PointGetExprs(Expr **x, Expr **y, Expr **z) {
ExprVector Entity::PointGetExprs(void) {
ExprVector r;
switch(type) {
case POINT_IN_3D:
*x = Expr::FromParam(param.h[0]);
*y = Expr::FromParam(param.h[1]);
*z = Expr::FromParam(param.h[2]);
r.x = Expr::FromParam(param.h[0]);
r.y = Expr::FromParam(param.h[1]);
r.z = Expr::FromParam(param.h[2]);
break;
case POINT_IN_2D: {
Entity *c = SS.GetEntity(csys);
Expr *u[3], *v[3];
c->Csys2dGetBasisExprs(u, v);
ExprVector u, v;
c->Csys2dGetBasisExprs(&u, &v);
*x = Expr::FromParam(param.h[0])->Times(u[0]);
*x = (*x)->Plus(Expr::FromParam(param.h[1])->Times(v[0]));
*y = Expr::FromParam(param.h[0])->Times(u[1]);
*y = (*y)->Plus(Expr::FromParam(param.h[1])->Times(v[1]));
*z = Expr::FromParam(param.h[0])->Times(u[2]);
*z = (*z)->Plus(Expr::FromParam(param.h[1])->Times(v[2]));
r = u.ScaledBy(Expr::FromParam(param.h[0]));
r = r.Plus(v.ScaledBy(Expr::FromParam(param.h[1])));
break;
}
default: oops();
}
return r;
}
void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
@ -226,17 +236,15 @@ void Entity::DrawOrGetDistance(int order) {
Vector d = SS.GW.projUp.ScaledBy(s/SS.GW.scale);
glxColor(0, 0.8, 0);
glDisable(GL_LINE_SMOOTH);
glBegin(GL_QUADS);
glxVertex3v(v.Plus (r).Plus (d));
glxVertex3v(v.Plus (r).Minus(d));
glxVertex3v(v.Minus(r).Minus(d));
glxVertex3v(v.Minus(r).Plus (d));
glEnd();
glEnable(GL_LINE_SMOOTH);
} else {
Point2d pp = SS.GW.ProjectPoint(v);
dogd.dmin = pp.DistanceTo(dogd.mp) - 7;
dogd.dmin = pp.DistanceTo(dogd.mp) - 5;
}
break;
}

View File

@ -1,5 +1,52 @@
#include "solvespace.h"
ExprVector ExprVector::FromExprs(Expr *x, Expr *y, Expr *z) {
ExprVector r = { x, y, z};
return r;
}
ExprVector ExprVector::Minus(ExprVector b) {
ExprVector r;
r.x = x->Minus(b.x);
r.y = y->Minus(b.y);
r.z = z->Minus(b.z);
return r;
}
ExprVector ExprVector::Plus(ExprVector b) {
ExprVector r;
r.x = x->Plus(b.x);
r.y = y->Plus(b.y);
r.z = z->Plus(b.z);
return r;
}
Expr *ExprVector::Dot(ExprVector b) {
Expr *r;
r = x->Times(b.x);
r = r->Plus(y->Times(b.y));
r = r->Plus(z->Times(b.z));
return r;
}
ExprVector ExprVector::ScaledBy(Expr *s) {
ExprVector r;
r.x = x->Times(s);
r.y = y->Times(s);
r.z = z->Times(s);
return r;
}
Expr *ExprVector::Magnitude(void) {
Expr *r;
r = x->Square();
r = r->Plus(y->Square());
r = r->Plus(z->Square());
return r->Sqrt();
}
Expr *Expr::FromParam(hParam p) {
Expr *r = AllocExpr();
r->op = PARAM;

13
expr.h
View File

@ -111,4 +111,17 @@ public:
static void Parse(void);
};
class ExprVector {
public:
Expr *x, *y, *z;
static ExprVector FromExprs(Expr *x, Expr *y, Expr *z);
ExprVector Plus(ExprVector b);
ExprVector Minus(ExprVector b);
Expr *Dot(ExprVector b);
ExprVector ScaledBy(Expr *s);
Expr *Magnitude(void);
};
#endif

View File

@ -34,8 +34,8 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "&Onto Plane / Coordinate System\tO", MNU_ORIENT_ONTO, 'O', mView },
{ 1, "&Lock Orientation\tL", MNU_LOCK_VIEW, 'L', mView },
{ 1, NULL, 0, NULL },
{ 1, "Dimensions in &Inches", 0, NULL },
{ 1, "Dimensions in &Millimeters", 0, NULL },
{ 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, mView },
{ 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView },
{ 0, "&Group", 0, 0, NULL },
{ 1, "New &Drawing Group", 0, 0, NULL },
@ -139,7 +139,7 @@ void GraphicsWindow::MenuView(int id) {
case MNU_LOCK_VIEW:
SS.GW.viewLocked = !SS.GW.viewLocked;
CheckMenuById(MNU_LOCK_VIEW, SS.GW.viewLocked);
SS.GW.EnsureValidActives();
break;
case MNU_ORIENT_ONTO: {
@ -200,6 +200,16 @@ void GraphicsWindow::MenuView(int id) {
break;
}
case MNU_UNITS_MM:
SS.GW.viewUnits = UNIT_MM;
SS.GW.EnsureValidActives();
break;
case MNU_UNITS_INCHES:
SS.GW.viewUnits = UNIT_INCHES;
SS.GW.EnsureValidActives();
break;
default: oops();
}
InvalidateGraphics();
@ -233,6 +243,18 @@ void GraphicsWindow::EnsureValidActives(void) {
bool in3d = (activeCsys.v == Entity::NO_CSYS.v);
CheckMenuById(MNU_NO_CSYS, in3d);
CheckMenuById(MNU_SEL_CSYS, !in3d);
// And update the checked state for various menus
CheckMenuById(MNU_LOCK_VIEW, viewLocked);
switch(viewUnits) {
case UNIT_MM:
case UNIT_INCHES:
break;
default:
viewUnits = UNIT_MM;
}
CheckMenuById(MNU_UNITS_MM, viewUnits == UNIT_MM);
CheckMenuById(MNU_UNITS_INCHES, viewUnits == UNIT_INCHES);
}
void GraphicsWindow::MenuEdit(int id) {
@ -242,6 +264,7 @@ void GraphicsWindow::MenuEdit(int id) {
SS.GW.ClearSelection();
SS.GW.pendingOperation = 0;
SS.GW.pendingDescription = NULL;
SS.TW.ScreenNavigation('h', 0);
SS.TW.Show();
break;

View File

@ -96,10 +96,9 @@ public:
int type;
hEntity csys; // or Entity::NO_CSYS
hGroup group;
NameStr name;
bool construction;
// When a request generates entities from entities, and the source
// entities may have come from multiple requests, it's necessary to
@ -141,12 +140,13 @@ public:
// Applies only for a CSYS_2D type
void Csys2dGetBasisVectors(Vector *u, Vector *v);
void Csys2dGetBasisExprs(Expr **u, Expr **v);
void Csys2dGetBasisExprs(ExprVector *u, ExprVector *v);
bool IsPoint(void);
bool IsPointIn3d(void);
// Applies for any of the point types
void PointGetExprs(Expr **x, Expr **y, Expr **z);
Vector PointGetCoords(void);
ExprVector PointGetExprs(void);
void PointForceTo(Vector v);
bool PointIsFromReferences(void);
bool PointIsKnown(void);
@ -154,7 +154,7 @@ public:
// Applies for anything that comes with a plane
bool HasPlane(void);
// The plane is points P such that P dot (xn, yn, zn) - d = 0
void PlaneGetExprs(Expr **xn, Expr **yn, Expr **zn, Expr **d);
void PlaneGetExprs(ExprVector *n, Expr **d);
// Routines to draw and hit-test the representation of the entity
// on-screen.

View File

@ -26,6 +26,7 @@ typedef signed long SDWORD;
#include <gl/glu.h>
class Expr;
class ExprVector;
// From the platform-specific code.
int SaveFileYesNoCancel(void);

View File

@ -176,7 +176,7 @@ void TextWindow::OneScreenForward(void) {
history++;
}
void TextWindow::ScreenNavigaton(int link, DWORD v) {
void TextWindow::ScreenNavigation(int link, DWORD v) {
switch(link) {
default:
case 'h':
@ -216,8 +216,8 @@ void TextWindow::ShowHeader(void) {
cd = SS.GetEntity(SS.GW.activeCsys)->DescriptionString();
}
Printf(" %Lb%f<<%E %Lh%fhome%E %C4 csys:%C5 %s",
(DWORD)(&TextWindow::ScreenNavigaton),
(DWORD)(&TextWindow::ScreenNavigaton),
(DWORD)(&TextWindow::ScreenNavigation),
(DWORD)(&TextWindow::ScreenNavigation),
cd);
}

10
ui.h
View File

@ -65,7 +65,7 @@ public:
void OneScreenForward(void);
static void ScreenSelectGroup(int link, DWORD v);
static void ScreenNavigaton(int link, DWORD v);
static void ScreenNavigation(int link, DWORD v);
};
class GraphicsWindow {
@ -87,6 +87,8 @@ public:
MNU_ORIENT_ONTO,
MNU_LOCK_VIEW,
MNU_UNSELECT_ALL,
MNU_UNITS_INCHES,
MNU_UNITS_MM,
// Edit
MNU_DELETE,
// Request
@ -134,6 +136,12 @@ public:
void NormalizeProjectionVectors(void);
Point2d ProjectPoint(Vector p);
typedef enum {
UNIT_MM = 0,
UNIT_INCHES,
} Unit;
Unit viewUnits;
hGroup activeGroup;
hEntity activeCsys;
void EnsureValidActives();

View File

@ -405,9 +405,9 @@ void ShowGraphicsEditControl(int x, int y, char *s)
// (x, y) are the bottom left, but the edit control is placed by its
// top left corner
y -= 21;
y -= 20;
MoveWindow(GraphicsEditControl, x, y, 120, 21, TRUE);
MoveWindow(GraphicsEditControl, x, y, 220, 21, TRUE);
ShowWindow(GraphicsEditControl, SW_SHOW);
SendMessage(GraphicsEditControl, WM_SETTEXT, 0, (LPARAM)s);
SendMessage(GraphicsEditControl, EM_SETSEL, 0, strlen(s));