Now we can add new workplanes. So fix all the mistakes that I

hadn't previously noticed, because I didn't use to have workplanes
with non-zero offsets. And clean up the interface to normals a bit.

[git-p4: depot-paths = "//depot/solvespace/": change = 1707]
This commit is contained in:
Jonathan Westhues 2008-05-05 03:17:00 -08:00
parent d048946adc
commit c767d55c71
6 changed files with 98 additions and 83 deletions

View File

@ -64,7 +64,7 @@ void Constraint::MenuConstrain(int id) {
c.type = POINTS_COINCIDENT;
c.ptA = gs.point[0];
c.ptB = gs.point[1];
} else if(gs.points == 1 && gs.planes == 1 && gs.n == 2) {
} else if(gs.points == 1 && gs.workplanes == 1 && gs.n == 2) {
c.type = PT_IN_PLANE;
c.ptA = gs.point[0];
c.entityA = gs.entity[0];
@ -96,9 +96,9 @@ void Constraint::MenuConstrain(int id) {
c.type = AT_MIDPOINT;
c.entityA = gs.entity[0];
c.ptA = gs.point[0];
} else if(gs.lineSegments == 1 && gs.planes == 1 && gs.n == 2) {
} else if(gs.lineSegments == 1 && gs.workplanes == 1 && gs.n == 2) {
c.type = AT_MIDPOINT;
int i = SS.GetEntity(gs.entity[0])->HasPlane() ? 1 : 0;
int i = SS.GetEntity(gs.entity[0])->IsWorkplane() ? 1 : 0;
c.entityA = gs.entity[i];
c.entityB = gs.entity[1-i];
} else {
@ -109,14 +109,14 @@ void Constraint::MenuConstrain(int id) {
break;
case GraphicsWindow::MNU_SYMMETRIC:
if(gs.points == 2 && gs.planes == 1 && gs.n == 3) {
if(gs.points == 2 && gs.workplanes == 1 && gs.n == 3) {
c.type = SYMMETRIC;
c.entityA = gs.entity[0];
c.ptA = gs.point[0];
c.ptB = gs.point[1];
} else if(gs.lineSegments == 1 && gs.planes == 1 && gs.n == 2) {
} else if(gs.lineSegments == 1 && gs.workplanes == 1 && gs.n == 2) {
c.type = SYMMETRIC;
int i = SS.GetEntity(gs.entity[0])->HasPlane() ? 1 : 0;
int i = SS.GetEntity(gs.entity[0])->IsWorkplane() ? 1 : 0;
Entity *line = SS.GetEntity(gs.entity[i]);
c.entityA = gs.entity[1-i];
c.ptA = line->point[0];
@ -239,7 +239,7 @@ Expr *Constraint::PointLineDistance(hEntity wrkpl, hEntity hpt, hEntity hln) {
Expr *Constraint::PointPlaneDistance(ExprVector p, hEntity hpl) {
ExprVector n;
Expr *d;
SS.GetEntity(hpl)->PlaneGetExprs(&n, &d);
SS.GetEntity(hpl)->WorkplaneGetPlaneExprs(&n, &d);
return (p.Dot(n))->Minus(d);
}
@ -271,10 +271,11 @@ Expr *Constraint::Distance(hEntity wrkpl, hEntity hpa, hEntity hpb) {
}
ExprVector Constraint::PointInThreeSpace(hEntity workplane, Expr *u, Expr *v) {
ExprVector ub, vb, ob;
Entity *w = SS.GetEntity(workplane);
w->WorkplaneGetBasisExprs(&ub, &vb);
ob = w->WorkplaneGetOffsetExprs();
ExprVector ub = w->Normal()->NormalExprsU();
ExprVector vb = w->Normal()->NormalExprsV();
ExprVector ob = w->WorkplaneGetOffsetExprs();
return (ub.ScaledBy(u)).Plus(vb.ScaledBy(v)).Plus(ob);
}
@ -441,15 +442,15 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
// to the symmetry pane's normal (i.e., that lies in the
// plane of symmetry). The line connecting the points is
// perpendicular to that constructed vector.
ExprVector u, v;
Entity *w = SS.GetEntity(workplane);
w->WorkplaneGetBasisExprs(&u, &v);
ExprVector u = w->Normal()->NormalExprsU();
ExprVector v = w->Normal()->NormalExprsV();
ExprVector pa = a->PointGetExprs();
ExprVector pb = b->PointGetExprs();
ExprVector n;
Expr *d;
plane->PlaneGetExprs(&n, &d);
plane->WorkplaneGetPlaneExprs(&n, &d);
AddEq(l, (n.Cross(u.Cross(v))).Dot(pa.Minus(pb)), 1);
}
break;

View File

@ -132,7 +132,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
case SYMMETRIC: {
Vector a = SS.GetEntity(ptA)->PointGetNum();
Vector b = SS.GetEntity(ptB)->PointGetNum();
Vector n = SS.GetEntity(entityA)->WorkplaneGetNormalVector();
Vector n = SS.GetEntity(entityA)->Normal()->NormalN();
for(int i = 0; i < 2; i++) {
Vector tail = (i == 0) ? a : b;
Vector d = (i == 0) ? b : a;
@ -161,7 +161,8 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
if(workplane.v == Entity::FREE_IN_3D.v) {
r = gr; u = gu; n = gn;
} else {
SS.GetEntity(workplane)->WorkplaneGetBasisVectors(&r, &u);
r = SS.GetEntity(workplane)->Normal()->NormalU();
u = SS.GetEntity(workplane)->Normal()->NormalV();
n = r.Cross(u);
}
// For "at midpoint", this branch is always taken.
@ -193,9 +194,9 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
Vector b = SS.GetEntity(ptB)->PointGetNum();
Entity *w = SS.GetEntity(SS.GetEntity(ptA)->workplane);
Vector cu, cv, cn;
w->WorkplaneGetBasisVectors(&cu, &cv);
cn = w->WorkplaneGetNormalVector();
Vector cu = w->Normal()->NormalU();
Vector cv = w->Normal()->NormalV();
Vector cn = w->Normal()->NormalN();
int i;
for(i = 0; i < 2; i++) {

View File

@ -5,44 +5,21 @@ char *Entity::DescriptionString(void) {
return r->DescriptionString();
}
void Entity::WorkplaneGetBasisVectors(Vector *u, Vector *v) {
Quaternion quat = SS.GetEntity(normal)->NormalGetNum();
*u = quat.RotationU();
*v = quat.RotationV();
}
Vector Entity::WorkplaneGetNormalVector(void) {
Vector u, v;
WorkplaneGetBasisVectors(&u, &v);
return u.Cross(v);
}
void Entity::WorkplaneGetBasisExprs(ExprVector *u, ExprVector *v) {
ExprQuaternion q = SS.GetEntity(normal)->NormalGetExprs();
*u = q.RotationU();
*v = q.RotationV();
bool Entity::IsWorkplane(void) {
return (type == WORKPLANE);
}
ExprVector Entity::WorkplaneGetOffsetExprs(void) {
return SS.GetEntity(point[0])->PointGetExprs();
}
bool Entity::HasPlane(void) {
switch(type) {
case WORKPLANE:
return true;
default:
return false;
}
Vector Entity::WorkplaneGetOffset(void) {
return SS.GetEntity(point[0])->PointGetNum();
}
void Entity::PlaneGetExprs(ExprVector *n, Expr **dn) {
void Entity::WorkplaneGetPlaneExprs(ExprVector *n, Expr **dn) {
if(type == WORKPLANE) {
ExprQuaternion q = (SS.GetEntity(normal))->NormalGetExprs();
// Convert the quaternion to our plane's normal vector.
*n = q.RotationN();
*n = Normal()->NormalExprsN();
ExprVector p0 = SS.GetEntity(point[0])->PointGetExprs();
// The plane is n dot (p - p0) = 0, or
@ -54,6 +31,10 @@ void Entity::PlaneGetExprs(ExprVector *n, Expr **dn) {
}
}
Entity *Entity::Normal(void) {
return SS.GetEntity(normal);
}
bool Entity::IsPoint(void) {
switch(type) {
case POINT_IN_3D:
@ -117,6 +98,26 @@ void Entity::NormalForceTo(Quaternion q) {
}
}
Vector Entity::NormalU(void) {
return NormalGetNum().RotationU();
}
Vector Entity::NormalV(void) {
return NormalGetNum().RotationV();
}
Vector Entity::NormalN(void) {
return NormalGetNum().RotationN();
}
ExprVector Entity::NormalExprsU(void) {
return NormalGetExprs().RotationU();
}
ExprVector Entity::NormalExprsV(void) {
return NormalGetExprs().RotationV();
}
ExprVector Entity::NormalExprsN(void) {
return NormalGetExprs().RotationN();
}
ExprQuaternion Entity::NormalGetExprs(void) {
ExprQuaternion q;
switch(type) {
@ -159,10 +160,9 @@ void Entity::PointForceTo(Vector p) {
case POINT_IN_2D: {
Entity *c = SS.GetEntity(workplane);
Vector u, v;
c->WorkplaneGetBasisVectors(&u, &v);
SS.GetParam(param[0])->val = p.Dot(u);
SS.GetParam(param[1])->val = p.Dot(v);
p = p.Minus(c->WorkplaneGetOffset());
SS.GetParam(param[0])->val = p.Dot(c->Normal()->NormalU());
SS.GetParam(param[1])->val = p.Dot(c->Normal()->NormalV());
break;
}
@ -189,10 +189,11 @@ Vector Entity::PointGetNum(void) {
case POINT_IN_2D: {
Entity *c = SS.GetEntity(workplane);
Vector u, v;
c->WorkplaneGetBasisVectors(&u, &v);
Vector u = c->Normal()->NormalU();
Vector v = c->Normal()->NormalV();
p = u.ScaledBy(SS.GetParam(param[0])->val);
p = p.Plus(v.ScaledBy(SS.GetParam(param[1])->val));
p = p.Plus(c->WorkplaneGetOffset());
break;
}
@ -219,10 +220,10 @@ ExprVector Entity::PointGetExprs(void) {
case POINT_IN_2D: {
Entity *c = SS.GetEntity(workplane);
ExprVector u, v;
c->WorkplaneGetBasisExprs(&u, &v);
r = u.ScaledBy(Expr::FromParam(param[0]));
ExprVector u = c->Normal()->NormalExprsU();
ExprVector v = c->Normal()->NormalExprsV();
r = c->WorkplaneGetOffsetExprs();
r = r.Plus(u.ScaledBy(Expr::FromParam(param[0])));
r = r.Plus(v.ScaledBy(Expr::FromParam(param[1])));
break;
}
@ -253,8 +254,8 @@ void Entity::PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v) {
// 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);
ExprVector wu = w->Normal()->NormalExprsU();
ExprVector wv = w->Normal()->NormalExprsV();
// Get our coordinates in three-space, and project them into that
// coordinate system.
@ -404,8 +405,8 @@ void Entity::DrawOrGetDistance(int order) {
Vector p;
p = SS.GetEntity(point[0])->PointGetNum();
Vector u, v;
WorkplaneGetBasisVectors(&u, &v);
Vector u = Normal()->NormalU();
Vector v = Normal()->NormalV();
double s = (min(SS.GW.width, SS.GW.height))*0.4/SS.GW.scale;

View File

@ -54,7 +54,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Draw Anywhere in 3d\tQ", MNU_FREE_IN_3D, 'Q', mReq },
{ 1, NULL, 0, NULL },
{ 1, "Datum &Point\tP", MNU_DATUM_POINT, 'P', mReq },
{ 1, "&Workplane (Coordinate S&ystem)\tY", 0, 'Y', mReq },
{ 1, "&Workplane (Coordinate S&ystem)\tY", MNU_WORKPLANE, 'Y', mReq },
{ 1, NULL, 0, NULL },
{ 1, "Line &Segment\tS", MNU_LINE_SEGMENT, 'S', mReq },
{ 1, "&Rectangle\tR", MNU_RECTANGLE, 'R', mReq },
@ -137,8 +137,8 @@ Point2d GraphicsWindow::ProjectPoint(Vector p) {
void GraphicsWindow::AnimateOnto(Quaternion quatf, Vector offsetf) {
// Get our initial orientation and translation.
Quaternion quat0 = Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp);
Vector offset0 = SS.GW.offset;
Quaternion quat0 = Quaternion::MakeFrom(projRight, projUp);
Vector offset0 = offset;
// Make sure we take the shorter of the two possible paths.
double mp = (quatf.Minus(quat0)).Magnitude();
@ -147,9 +147,10 @@ void GraphicsWindow::AnimateOnto(Quaternion quatf, Vector offsetf) {
quatf = quatf.ScaledBy(-1);
mp = mm;
}
double mo = (offset0.Minus(offsetf)).Magnitude()/scale;
// Animate transition, unless it's a tiny move.
SDWORD dt = (mp < 0.01) ? (-20) : (SDWORD)(100 + 1000*mp);
SDWORD dt = (mp < 0.01 && mo < 10) ? (-20) : (SDWORD)(100 + 1000*mp);
SDWORD tn, t0 = GetMilliseconds();
double s = 0;
do {
@ -327,12 +328,9 @@ void GraphicsWindow::MenuRequest(int id) {
}
// Align the view with the selected workplane
Entity *e = SS.GetEntity(SS.GW.activeWorkplane);
Vector pr, pu;
e->WorkplaneGetBasisVectors(&pr, &pu);
Quaternion quatf = Quaternion::MakeFrom(pr, pu);
Vector offsetf = SS.GetEntity(e->point[0])->PointGetNum();
Quaternion quatf = e->Normal()->NormalGetNum();
Vector offsetf = (e->WorkplaneGetOffset()).ScaledBy(-1);
SS.GW.AnimateOnto(quatf, offsetf);
SS.GW.EnsureValidActives();
SS.TW.Show();
break;
@ -347,6 +345,7 @@ void GraphicsWindow::MenuRequest(int id) {
case MNU_LINE_SEGMENT: s = "click first point of line segment"; goto c;
case MNU_CUBIC: s = "click first point of cubic segment"; goto c;
case MNU_CIRCLE: s = "click center of circle"; goto c;
case MNU_WORKPLANE: s = "click origin of workplane"; goto c;
c:
SS.GW.pending.operation = id;
SS.GW.pending.description = s;
@ -519,8 +518,8 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
u = u.RotatedAbout(normal, -theta);
v = v.RotatedAbout(normal, -theta);
} else {
double dx = (x - orig.mouse.x);
double dy = (y - orig.mouse.y);
double dx = -(x - orig.mouse.x);
double dy = -(y - orig.mouse.y);
double s = 0.3*(PI/180); // degrees per pixel
u = u.RotatedAbout(orig.projUp, -s*dx);
u = u.RotatedAbout(orig.projRight, s*dy);
@ -621,7 +620,6 @@ void GraphicsWindow::GroupSelection(void) {
case Entity::WORKPLANE: (gs.workplanes)++; break;
case Entity::LINE_SEGMENT: (gs.lineSegments)++; break;
}
if(e->HasPlane()) (gs.planes)++;
}
}
}
@ -720,6 +718,17 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
pending.description = "click to place next point of cubic";
break;
case MNU_WORKPLANE:
hr = AddRequest(Request::WORKPLANE);
SS.GetEntity(hr.entity(1))->PointForceTo(v);
SS.GetEntity(hr.entity(16))->NormalForceTo(
Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp));
MAYBE_PLACE(hr.entity(1));
ClearSelection(); hover.Clear();
ClearPending();
break;
case DRAGGING_RADIUS:
case DRAGGING_NEW_POINT:
// The MouseMoved event has already dragged it as desired.

View File

@ -159,7 +159,7 @@ public:
static const int POINT_XFRMD = 2010;
static const int NORMAL_IN_3D = 3000;
static const int NORMAL_COPY = 3001;
static const int NORMAL_IN_2D = 3001;
// This is a normal that lies in a plane; so if the defining workplane
// has basis vectors uw, vw, nw, then
// n = (cos theta)*uw + (sin theta)*vw
@ -192,11 +192,12 @@ public:
// times to apply the transformation.
int timesApplied;
// Applies only for a WORKPLANE type
void WorkplaneGetBasisVectors(Vector *u, Vector *v);
Vector WorkplaneGetNormalVector(void);
void WorkplaneGetBasisExprs(ExprVector *u, ExprVector *v);
bool IsWorkplane(void);
// The plane is points P such that P dot (xn, yn, zn) - d = 0
void WorkplaneGetPlaneExprs(ExprVector *n, Expr **d);
ExprVector WorkplaneGetOffsetExprs(void);
Vector WorkplaneGetOffset(void);
Entity *Normal(void);
bool IsPoint(void);
// Applies for any of the point types
@ -212,10 +213,12 @@ public:
ExprQuaternion NormalGetExprs(void);
void NormalForceTo(Quaternion q);
// 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(ExprVector *n, Expr **d);
Vector NormalU(void);
Vector NormalV(void);
Vector NormalN(void);
ExprVector NormalExprsU(void);
ExprVector NormalExprsV(void);
ExprVector NormalExprsN(void);
// Routines to draw and hit-test the representation of the entity
// on-screen.

2
ui.h
View File

@ -102,6 +102,7 @@ public:
MNU_SEL_WORKPLANE,
MNU_FREE_IN_3D,
MNU_DATUM_POINT,
MNU_WORKPLANE,
MNU_LINE_SEGMENT,
MNU_CIRCLE,
MNU_RECTANGLE,
@ -219,7 +220,6 @@ public:
int points;
int entities;
int workplanes;
int planes;
int lineSegments;
int n;
} gs;