diff --git a/constraint.cpp b/constraint.cpp index 7c666d7..cec5f11 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -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 *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; diff --git a/drawconstraint.cpp b/drawconstraint.cpp index 14637ee..fe053c5 100644 --- a/drawconstraint.cpp +++ b/drawconstraint.cpp @@ -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++) { diff --git a/entity.cpp b/entity.cpp index 7933439..b70921c 100644 --- a/entity.cpp +++ b/entity.cpp @@ -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; diff --git a/graphicswin.cpp b/graphicswin.cpp index a0217cb..e4f65d4 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -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. diff --git a/sketch.h b/sketch.h index 015ce94..23312ae 100644 --- a/sketch.h +++ b/sketch.h @@ -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. diff --git a/ui.h b/ui.h index b199bee..42c4d82 100644 --- a/ui.h +++ b/ui.h @@ -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;