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.type = POINTS_COINCIDENT;
c.ptA = gs.point[0]; c.ptA = gs.point[0];
c.ptB = gs.point[1]; 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.type = PT_IN_PLANE;
c.ptA = gs.point[0]; c.ptA = gs.point[0];
c.entityA = gs.entity[0]; c.entityA = gs.entity[0];
@ -96,9 +96,9 @@ void Constraint::MenuConstrain(int id) {
c.type = AT_MIDPOINT; c.type = AT_MIDPOINT;
c.entityA = gs.entity[0]; c.entityA = gs.entity[0];
c.ptA = gs.point[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; 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.entityA = gs.entity[i];
c.entityB = gs.entity[1-i]; c.entityB = gs.entity[1-i];
} else { } else {
@ -109,14 +109,14 @@ void Constraint::MenuConstrain(int id) {
break; break;
case GraphicsWindow::MNU_SYMMETRIC: 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.type = SYMMETRIC;
c.entityA = gs.entity[0]; c.entityA = gs.entity[0];
c.ptA = gs.point[0]; c.ptA = gs.point[0];
c.ptB = gs.point[1]; 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; 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]); Entity *line = SS.GetEntity(gs.entity[i]);
c.entityA = gs.entity[1-i]; c.entityA = gs.entity[1-i];
c.ptA = line->point[0]; 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) { Expr *Constraint::PointPlaneDistance(ExprVector p, hEntity hpl) {
ExprVector n; ExprVector n;
Expr *d; Expr *d;
SS.GetEntity(hpl)->PlaneGetExprs(&n, &d); SS.GetEntity(hpl)->WorkplaneGetPlaneExprs(&n, &d);
return (p.Dot(n))->Minus(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 Constraint::PointInThreeSpace(hEntity workplane, Expr *u, Expr *v) {
ExprVector ub, vb, ob;
Entity *w = SS.GetEntity(workplane); 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); 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 // to the symmetry pane's normal (i.e., that lies in the
// plane of symmetry). The line connecting the points is // plane of symmetry). The line connecting the points is
// perpendicular to that constructed vector. // perpendicular to that constructed vector.
ExprVector u, v;
Entity *w = SS.GetEntity(workplane); Entity *w = SS.GetEntity(workplane);
w->WorkplaneGetBasisExprs(&u, &v); ExprVector u = w->Normal()->NormalExprsU();
ExprVector v = w->Normal()->NormalExprsV();
ExprVector pa = a->PointGetExprs(); ExprVector pa = a->PointGetExprs();
ExprVector pb = b->PointGetExprs(); ExprVector pb = b->PointGetExprs();
ExprVector n; ExprVector n;
Expr *d; Expr *d;
plane->PlaneGetExprs(&n, &d); plane->WorkplaneGetPlaneExprs(&n, &d);
AddEq(l, (n.Cross(u.Cross(v))).Dot(pa.Minus(pb)), 1); AddEq(l, (n.Cross(u.Cross(v))).Dot(pa.Minus(pb)), 1);
} }
break; break;

View File

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

View File

@ -5,44 +5,21 @@ char *Entity::DescriptionString(void) {
return r->DescriptionString(); return r->DescriptionString();
} }
void Entity::WorkplaneGetBasisVectors(Vector *u, Vector *v) { bool Entity::IsWorkplane(void) {
Quaternion quat = SS.GetEntity(normal)->NormalGetNum(); return (type == WORKPLANE);
*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();
} }
ExprVector Entity::WorkplaneGetOffsetExprs(void) { ExprVector Entity::WorkplaneGetOffsetExprs(void) {
return SS.GetEntity(point[0])->PointGetExprs(); return SS.GetEntity(point[0])->PointGetExprs();
} }
bool Entity::HasPlane(void) { Vector Entity::WorkplaneGetOffset(void) {
switch(type) { return SS.GetEntity(point[0])->PointGetNum();
case WORKPLANE:
return true;
default:
return false;
}
} }
void Entity::PlaneGetExprs(ExprVector *n, Expr **dn) { void Entity::WorkplaneGetPlaneExprs(ExprVector *n, Expr **dn) {
if(type == WORKPLANE) { if(type == WORKPLANE) {
ExprQuaternion q = (SS.GetEntity(normal))->NormalGetExprs(); *n = Normal()->NormalExprsN();
// Convert the quaternion to our plane's normal vector.
*n = q.RotationN();
ExprVector p0 = SS.GetEntity(point[0])->PointGetExprs(); ExprVector p0 = SS.GetEntity(point[0])->PointGetExprs();
// The plane is n dot (p - p0) = 0, or // 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) { bool Entity::IsPoint(void) {
switch(type) { switch(type) {
case POINT_IN_3D: 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 Entity::NormalGetExprs(void) {
ExprQuaternion q; ExprQuaternion q;
switch(type) { switch(type) {
@ -159,10 +160,9 @@ void Entity::PointForceTo(Vector p) {
case POINT_IN_2D: { case POINT_IN_2D: {
Entity *c = SS.GetEntity(workplane); Entity *c = SS.GetEntity(workplane);
Vector u, v; p = p.Minus(c->WorkplaneGetOffset());
c->WorkplaneGetBasisVectors(&u, &v); SS.GetParam(param[0])->val = p.Dot(c->Normal()->NormalU());
SS.GetParam(param[0])->val = p.Dot(u); SS.GetParam(param[1])->val = p.Dot(c->Normal()->NormalV());
SS.GetParam(param[1])->val = p.Dot(v);
break; break;
} }
@ -189,10 +189,11 @@ Vector Entity::PointGetNum(void) {
case POINT_IN_2D: { case POINT_IN_2D: {
Entity *c = SS.GetEntity(workplane); Entity *c = SS.GetEntity(workplane);
Vector u, v; Vector u = c->Normal()->NormalU();
c->WorkplaneGetBasisVectors(&u, &v); Vector v = c->Normal()->NormalV();
p = u.ScaledBy(SS.GetParam(param[0])->val); p = u.ScaledBy(SS.GetParam(param[0])->val);
p = p.Plus(v.ScaledBy(SS.GetParam(param[1])->val)); p = p.Plus(v.ScaledBy(SS.GetParam(param[1])->val));
p = p.Plus(c->WorkplaneGetOffset());
break; break;
} }
@ -219,10 +220,10 @@ ExprVector Entity::PointGetExprs(void) {
case POINT_IN_2D: { case POINT_IN_2D: {
Entity *c = SS.GetEntity(workplane); Entity *c = SS.GetEntity(workplane);
ExprVector u, v; ExprVector u = c->Normal()->NormalExprsU();
c->WorkplaneGetBasisExprs(&u, &v); ExprVector v = c->Normal()->NormalExprsV();
r = c->WorkplaneGetOffsetExprs();
r = u.ScaledBy(Expr::FromParam(param[0])); r = r.Plus(u.ScaledBy(Expr::FromParam(param[0])));
r = r.Plus(v.ScaledBy(Expr::FromParam(param[1]))); r = r.Plus(v.ScaledBy(Expr::FromParam(param[1])));
break; 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. // Get the offset and basis vectors for this weird exotic csys.
Entity *w = SS.GetEntity(wrkpl); Entity *w = SS.GetEntity(wrkpl);
ExprVector wp = w->WorkplaneGetOffsetExprs(); ExprVector wp = w->WorkplaneGetOffsetExprs();
ExprVector wu, wv; ExprVector wu = w->Normal()->NormalExprsU();
w->WorkplaneGetBasisExprs(&wu, &wv); ExprVector wv = w->Normal()->NormalExprsV();
// Get our coordinates in three-space, and project them into that // Get our coordinates in three-space, and project them into that
// coordinate system. // coordinate system.
@ -404,8 +405,8 @@ void Entity::DrawOrGetDistance(int order) {
Vector p; Vector p;
p = SS.GetEntity(point[0])->PointGetNum(); p = SS.GetEntity(point[0])->PointGetNum();
Vector u, v; Vector u = Normal()->NormalU();
WorkplaneGetBasisVectors(&u, &v); Vector v = Normal()->NormalV();
double s = (min(SS.GW.width, SS.GW.height))*0.4/SS.GW.scale; 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, "Draw Anywhere in 3d\tQ", MNU_FREE_IN_3D, 'Q', mReq },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "Datum &Point\tP", MNU_DATUM_POINT, 'P', mReq }, { 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, NULL, 0, NULL },
{ 1, "Line &Segment\tS", MNU_LINE_SEGMENT, 'S', mReq }, { 1, "Line &Segment\tS", MNU_LINE_SEGMENT, 'S', mReq },
{ 1, "&Rectangle\tR", MNU_RECTANGLE, 'R', mReq }, { 1, "&Rectangle\tR", MNU_RECTANGLE, 'R', mReq },
@ -137,8 +137,8 @@ Point2d GraphicsWindow::ProjectPoint(Vector p) {
void GraphicsWindow::AnimateOnto(Quaternion quatf, Vector offsetf) { void GraphicsWindow::AnimateOnto(Quaternion quatf, Vector offsetf) {
// Get our initial orientation and translation. // Get our initial orientation and translation.
Quaternion quat0 = Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp); Quaternion quat0 = Quaternion::MakeFrom(projRight, projUp);
Vector offset0 = SS.GW.offset; Vector offset0 = offset;
// Make sure we take the shorter of the two possible paths. // Make sure we take the shorter of the two possible paths.
double mp = (quatf.Minus(quat0)).Magnitude(); double mp = (quatf.Minus(quat0)).Magnitude();
@ -147,9 +147,10 @@ void GraphicsWindow::AnimateOnto(Quaternion quatf, Vector offsetf) {
quatf = quatf.ScaledBy(-1); quatf = quatf.ScaledBy(-1);
mp = mm; mp = mm;
} }
double mo = (offset0.Minus(offsetf)).Magnitude()/scale;
// Animate transition, unless it's a tiny move. // 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(); SDWORD tn, t0 = GetMilliseconds();
double s = 0; double s = 0;
do { do {
@ -327,12 +328,9 @@ void GraphicsWindow::MenuRequest(int id) {
} }
// Align the view with the selected workplane // Align the view with the selected workplane
Entity *e = SS.GetEntity(SS.GW.activeWorkplane); Entity *e = SS.GetEntity(SS.GW.activeWorkplane);
Vector pr, pu; Quaternion quatf = e->Normal()->NormalGetNum();
e->WorkplaneGetBasisVectors(&pr, &pu); Vector offsetf = (e->WorkplaneGetOffset()).ScaledBy(-1);
Quaternion quatf = Quaternion::MakeFrom(pr, pu);
Vector offsetf = SS.GetEntity(e->point[0])->PointGetNum();
SS.GW.AnimateOnto(quatf, offsetf); SS.GW.AnimateOnto(quatf, offsetf);
SS.GW.EnsureValidActives(); SS.GW.EnsureValidActives();
SS.TW.Show(); SS.TW.Show();
break; 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_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_CUBIC: s = "click first point of cubic segment"; goto c;
case MNU_CIRCLE: s = "click center of circle"; goto c; case MNU_CIRCLE: s = "click center of circle"; goto c;
case MNU_WORKPLANE: s = "click origin of workplane"; goto c;
c: c:
SS.GW.pending.operation = id; SS.GW.pending.operation = id;
SS.GW.pending.description = s; SS.GW.pending.description = s;
@ -519,8 +518,8 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
u = u.RotatedAbout(normal, -theta); u = u.RotatedAbout(normal, -theta);
v = v.RotatedAbout(normal, -theta); v = v.RotatedAbout(normal, -theta);
} else { } else {
double dx = (x - orig.mouse.x); double dx = -(x - orig.mouse.x);
double dy = (y - orig.mouse.y); double dy = -(y - orig.mouse.y);
double s = 0.3*(PI/180); // degrees per pixel double s = 0.3*(PI/180); // degrees per pixel
u = u.RotatedAbout(orig.projUp, -s*dx); u = u.RotatedAbout(orig.projUp, -s*dx);
u = u.RotatedAbout(orig.projRight, s*dy); u = u.RotatedAbout(orig.projRight, s*dy);
@ -621,7 +620,6 @@ void GraphicsWindow::GroupSelection(void) {
case Entity::WORKPLANE: (gs.workplanes)++; break; case Entity::WORKPLANE: (gs.workplanes)++; break;
case Entity::LINE_SEGMENT: (gs.lineSegments)++; 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"; pending.description = "click to place next point of cubic";
break; 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_RADIUS:
case DRAGGING_NEW_POINT: case DRAGGING_NEW_POINT:
// The MouseMoved event has already dragged it as desired. // 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 POINT_XFRMD = 2010;
static const int NORMAL_IN_3D = 3000; 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 // This is a normal that lies in a plane; so if the defining workplane
// has basis vectors uw, vw, nw, then // has basis vectors uw, vw, nw, then
// n = (cos theta)*uw + (sin theta)*vw // n = (cos theta)*uw + (sin theta)*vw
@ -192,11 +192,12 @@ public:
// times to apply the transformation. // times to apply the transformation.
int timesApplied; int timesApplied;
// Applies only for a WORKPLANE type bool IsWorkplane(void);
void WorkplaneGetBasisVectors(Vector *u, Vector *v); // The plane is points P such that P dot (xn, yn, zn) - d = 0
Vector WorkplaneGetNormalVector(void); void WorkplaneGetPlaneExprs(ExprVector *n, Expr **d);
void WorkplaneGetBasisExprs(ExprVector *u, ExprVector *v);
ExprVector WorkplaneGetOffsetExprs(void); ExprVector WorkplaneGetOffsetExprs(void);
Vector WorkplaneGetOffset(void);
Entity *Normal(void);
bool IsPoint(void); bool IsPoint(void);
// Applies for any of the point types // Applies for any of the point types
@ -212,10 +213,12 @@ public:
ExprQuaternion NormalGetExprs(void); ExprQuaternion NormalGetExprs(void);
void NormalForceTo(Quaternion q); void NormalForceTo(Quaternion q);
// Applies for anything that comes with a plane Vector NormalU(void);
bool HasPlane(void); Vector NormalV(void);
// The plane is points P such that P dot (xn, yn, zn) - d = 0 Vector NormalN(void);
void PlaneGetExprs(ExprVector *n, Expr **d); ExprVector NormalExprsU(void);
ExprVector NormalExprsV(void);
ExprVector NormalExprsN(void);
// Routines to draw and hit-test the representation of the entity // Routines to draw and hit-test the representation of the entity
// on-screen. // on-screen.

2
ui.h
View File

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