diff --git a/dsc.h b/dsc.h index d729b2a..9f0cb54 100644 --- a/dsc.h +++ b/dsc.h @@ -8,6 +8,7 @@ typedef unsigned char BYTE; class Vector; class Point2d; class hEntity; +class hParam; class Quaternion { public: @@ -40,6 +41,7 @@ public: double x, y, z; static Vector MakeFrom(double x, double y, double z); + static Vector MakeFrom(hParam x, hParam y, hParam z); static Vector AtIntersectionOfPlanes(Vector n1, double d1, Vector n2, double d2); diff --git a/entity.cpp b/entity.cpp index 7673437..34ab76f 100644 --- a/entity.cpp +++ b/entity.cpp @@ -17,6 +17,7 @@ bool Entity::HasVector(void) { case NORMAL_IN_2D: case NORMAL_N_COPY: case NORMAL_N_ROT: + case NORMAL_N_ROT_AA: return true; default: @@ -34,6 +35,7 @@ ExprVector Entity::VectorGetExprs(void) { case NORMAL_IN_2D: case NORMAL_N_COPY: case NORMAL_N_ROT: + case NORMAL_N_ROT_AA: return NormalExprsN(); default: oops(); @@ -50,6 +52,7 @@ Vector Entity::VectorGetNum(void) { case NORMAL_IN_2D: case NORMAL_N_COPY: case NORMAL_N_ROT: + case NORMAL_N_ROT_AA: return NormalN(); default: oops(); @@ -66,6 +69,7 @@ Vector Entity::VectorGetRefPoint(void) { case NORMAL_IN_2D: case NORMAL_N_COPY: case NORMAL_N_ROT: + case NORMAL_N_ROT_AA: return SS.GetEntity(point[0])->PointGetNum(); default: oops(); @@ -174,6 +178,7 @@ bool Entity::IsPoint(void) { case POINT_N_COPY: case POINT_N_TRANS: case POINT_N_ROT_TRANS: + case POINT_N_ROT_AA: return true; default: @@ -187,6 +192,7 @@ bool Entity::IsNormal(void) { case NORMAL_IN_2D: case NORMAL_N_COPY: case NORMAL_N_ROT: + case NORMAL_N_ROT_AA: return true; default: return false; @@ -221,6 +227,17 @@ Quaternion Entity::NormalGetNum(void) { q = q.Times(numNormal); break; + case NORMAL_N_ROT_AA: { + double theta = timesApplied*SS.GetParam(param[0])->val; + double s = sin(theta), c = cos(theta); + q.w = c; + q.vx = s*SS.GetParam(param[1])->val; + q.vy = s*SS.GetParam(param[2])->val; + q.vz = s*SS.GetParam(param[3])->val; + q = q.Times(numNormal); + break; + } + default: oops(); } return q; @@ -239,7 +256,6 @@ void Entity::NormalForceTo(Quaternion q) { case NORMAL_N_COPY: // There's absolutely nothing to do; these are locked. break; - case NORMAL_N_ROT: { Quaternion qp = q.Times(numNormal.Inverse()); @@ -250,6 +266,10 @@ void Entity::NormalForceTo(Quaternion q) { break; } + case NORMAL_N_ROT_AA: + // Not sure if I'll bother implementing this one + break; + default: oops(); } } @@ -298,11 +318,7 @@ ExprQuaternion Entity::NormalGetExprs(void) { break; case NORMAL_N_ROT: { - ExprQuaternion orig; - orig.w = Expr::FromConstant(numNormal.w); - orig.vx = Expr::FromConstant(numNormal.vx); - orig.vy = Expr::FromConstant(numNormal.vy); - orig.vz = Expr::FromConstant(numNormal.vz); + ExprQuaternion orig = ExprQuaternion::FromNum(numNormal); q.w = Expr::FromParam(param[0]); q.vx = Expr::FromParam(param[1]); @@ -313,6 +329,21 @@ ExprQuaternion Entity::NormalGetExprs(void) { break; } + case NORMAL_N_ROT_AA: { + ExprQuaternion orig = ExprQuaternion::FromNum(numNormal); + + Expr *theta = Expr::FromConstant(timesApplied)->Times( + Expr::FromParam(param[0])); + Expr *c = theta->Cos(), *s = theta->Sin(); + q.w = c; + q.vx = s->Times(Expr::FromParam(param[1])); + q.vy = s->Times(Expr::FromParam(param[2])); + q.vz = s->Times(Expr::FromParam(param[3])); + + q = q.Times(orig); + break; + } + default: oops(); } return q; @@ -358,6 +389,25 @@ void Entity::PointForceTo(Vector p) { break; } + case POINT_N_ROT_AA: { + // Force only the angle; the axis and center of rotation stay + Vector offset = Vector::MakeFrom(param[0], param[1], param[2]); + Vector normal = Vector::MakeFrom(param[4], param[5], param[6]); + Vector u = normal.Normal(0), v = normal.Normal(1); + Vector po = p.Minus(offset), numo = numPoint.Minus(offset); + double thetap = atan2(v.Dot(po), u.Dot(po)); + double thetan = atan2(v.Dot(numo), u.Dot(numo)); + double thetaf = (thetap - thetan); + double thetai = (SS.GetParam(param[3])->val)*timesApplied*2; + double dtheta = thetaf - thetai; + // Take the smallest possible change in the actual step angle, + // in order to avoid jumps when you cross from +pi to -pi + while(dtheta < -PI) dtheta += 2*PI; + while(dtheta > PI) dtheta -= 2*PI; + SS.GetParam(param[3])->val = (thetai + dtheta)/(timesApplied*2); + break; + } + case POINT_N_COPY: // Nothing to do; it's a static copy break; @@ -404,6 +454,18 @@ Vector Entity::PointGetNum(void) { break; } + case POINT_N_ROT_AA: { + Vector offset = Vector::MakeFrom( + SS.GetParam(param[0])->val, + SS.GetParam(param[1])->val, + SS.GetParam(param[2])->val); + Quaternion q = PointGetQuaternion(); + p = numPoint.Minus(offset); + p = q.Rotate(p); + p = p.Plus(offset); + break; + } + case POINT_N_COPY: p = numPoint; break; @@ -444,14 +506,9 @@ ExprVector Entity::PointGetExprs(void) { break; } case POINT_N_ROT_TRANS: { - ExprVector orig = { - Expr::FromConstant(numPoint.x), - Expr::FromConstant(numPoint.y), - Expr::FromConstant(numPoint.z) }; - ExprVector trans = { - Expr::FromParam(param[0]), - Expr::FromParam(param[1]), - Expr::FromParam(param[2]) }; + ExprVector orig = ExprVector::FromNum(numPoint); + ExprVector trans = + ExprVector::FromParams(param[0], param[1], param[2]); ExprQuaternion q = { Expr::FromParam(param[3]), Expr::FromParam(param[4]), @@ -461,6 +518,23 @@ ExprVector Entity::PointGetExprs(void) { r = orig.Plus(trans); break; } + case POINT_N_ROT_AA: { + ExprVector orig = ExprVector::FromNum(numPoint); + ExprVector trans = + ExprVector::FromParams(param[0], param[1], param[2]); + Expr *theta = Expr::FromConstant(timesApplied)->Times( + Expr::FromParam(param[3])); + Expr *c = theta->Cos(), *s = theta->Sin(); + ExprQuaternion q = { + c, + s->Times(Expr::FromParam(param[4])), + s->Times(Expr::FromParam(param[5])), + s->Times(Expr::FromParam(param[6])) }; + orig = orig.Minus(trans); + orig = q.Rotate(orig); + r = orig.Plus(trans); + break; + } case POINT_N_COPY: r.x = Expr::FromConstant(numPoint.x); r.y = Expr::FromConstant(numPoint.y); @@ -504,13 +578,22 @@ void Entity::PointForceQuaternionTo(Quaternion q) { } Quaternion Entity::PointGetQuaternion(void) { - if(type != POINT_N_ROT_TRANS) oops(); - Quaternion q; - q.w = SS.GetParam(param[3])->val; - q.vx = SS.GetParam(param[4])->val; - q.vy = SS.GetParam(param[5])->val; - q.vz = SS.GetParam(param[6])->val; + + if(type == POINT_N_ROT_AA) { + double theta = timesApplied*SS.GetParam(param[3])->val; + double s = sin(theta), c = cos(theta); + q.w = c; + q.vx = s*SS.GetParam(param[4])->val; + q.vy = s*SS.GetParam(param[5])->val; + q.vz = s*SS.GetParam(param[6])->val; + } else if(type == POINT_N_ROT_TRANS) { + q.w = SS.GetParam(param[3])->val; + q.vx = SS.GetParam(param[4])->val; + q.vy = SS.GetParam(param[5])->val; + q.vz = SS.GetParam(param[6])->val; + } else oops(); + return q; } @@ -594,6 +677,7 @@ void Entity::DrawOrGetDistance(int order) { case POINT_N_COPY: case POINT_N_TRANS: case POINT_N_ROT_TRANS: + case POINT_N_ROT_AA: case POINT_IN_3D: case POINT_IN_2D: { if(order >= 0 && order != 2) break; @@ -633,6 +717,7 @@ void Entity::DrawOrGetDistance(int order) { case NORMAL_N_COPY: case NORMAL_N_ROT: + case NORMAL_N_ROT_AA: case NORMAL_IN_3D: case NORMAL_IN_2D: { if(order >= 0 && order != 2) break; diff --git a/expr.cpp b/expr.cpp index afb30c5..65002b0 100644 --- a/expr.cpp +++ b/expr.cpp @@ -5,6 +5,22 @@ ExprVector ExprVector::FromExprs(Expr *x, Expr *y, Expr *z) { return r; } +ExprVector ExprVector::FromNum(Vector vn) { + ExprVector ve; + ve.x = Expr::FromConstant(vn.x); + ve.y = Expr::FromConstant(vn.y); + ve.z = Expr::FromConstant(vn.z); + return ve; +} + +ExprVector ExprVector::FromParams(hParam x, hParam y, hParam z) { + ExprVector ve; + ve.x = Expr::FromParam(x); + ve.y = Expr::FromParam(y); + ve.z = Expr::FromParam(z); + return ve; +} + ExprVector ExprVector::Minus(ExprVector b) { ExprVector r; r.x = x->Minus(b.x); @@ -71,6 +87,15 @@ ExprQuaternion ExprQuaternion::FromExprs(Expr *w, Expr *vx, Expr *vy, Expr *vz) return q; } +ExprQuaternion ExprQuaternion::FromNum(Quaternion qn) { + ExprQuaternion qe; + qe.w = Expr::FromConstant(qn.w); + qe.vx = Expr::FromConstant(qn.vx); + qe.vy = Expr::FromConstant(qn.vy); + qe.vz = Expr::FromConstant(qn.vz); + return qe; +} + ExprVector ExprQuaternion::RotationU(void) { ExprVector u; Expr *two = Expr::FromConstant(2); diff --git a/expr.h b/expr.h index bf1873e..863b9ed 100644 --- a/expr.h +++ b/expr.h @@ -123,6 +123,8 @@ public: Expr *x, *y, *z; static ExprVector FromExprs(Expr *x, Expr *y, Expr *z); + static ExprVector FromNum(Vector vn); + static ExprVector FromParams(hParam x, hParam y, hParam z); ExprVector Plus(ExprVector b); ExprVector Minus(ExprVector b); @@ -139,6 +141,7 @@ public: Expr *w, *vx, *vy, *vz; static ExprQuaternion FromExprs(Expr *w, Expr *vx, Expr *vy, Expr *vz); + static ExprQuaternion FromNum(Quaternion qn); ExprVector RotationU(void); ExprVector RotationV(void); diff --git a/file.cpp b/file.cpp index 2339fe5..910b7c1 100644 --- a/file.cpp +++ b/file.cpp @@ -42,9 +42,9 @@ void SolveSpace::NewFile(void) { // And an empty group, for the first stuff the user draws. g.type = Group::DRAWING_WORKPLANE; g.subtype = Group::WORKPLANE_BY_POINT_ORTHO; - g.wrkpl.q = Quaternion::MakeFrom(1, 0, 0, 0); + g.predef.q = Quaternion::MakeFrom(1, 0, 0, 0); hRequest hr = Request::HREQUEST_REFERENCE_XY; - g.wrkpl.origin = hr.entity(1); + g.predef.origin = hr.entity(1); g.name.strcpy("draw-in-plane"); group.AddAndAssignId(&g); SS.GetGroup(g.h)->activeWorkplane = g.h.entity(0); @@ -60,16 +60,16 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = { { 'g', "Group.color", 'x', &(SS.sv.g.color) }, { 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) }, { 'g', "Group.meshCombine", 'd', &(SS.sv.g.meshCombine) }, - { 'g', "Group.wrkpl.q.w", 'f', &(SS.sv.g.wrkpl.q.w) }, - { 'g', "Group.wrkpl.q.vx", 'f', &(SS.sv.g.wrkpl.q.vx) }, - { 'g', "Group.wrkpl.q.vy", 'f', &(SS.sv.g.wrkpl.q.vy) }, - { 'g', "Group.wrkpl.q.vz", 'f', &(SS.sv.g.wrkpl.q.vz) }, - { 'g', "Group.wrkpl.origin.v", 'x', &(SS.sv.g.wrkpl.origin.v) }, - { 'g', "Group.wrkpl.entityB.v", 'x', &(SS.sv.g.wrkpl.entityB.v) }, - { 'g', "Group.wrkpl.entityC.v", 'x', &(SS.sv.g.wrkpl.entityC.v) }, - { 'g', "Group.wrkpl.swapUV", 'b', &(SS.sv.g.wrkpl.swapUV) }, - { 'g', "Group.wrkpl.negateU", 'b', &(SS.sv.g.wrkpl.negateU) }, - { 'g', "Group.wrkpl.negateV", 'b', &(SS.sv.g.wrkpl.negateV) }, + { 'g', "Group.predef.q.w", 'f', &(SS.sv.g.predef.q.w) }, + { 'g', "Group.predef.q.vx", 'f', &(SS.sv.g.predef.q.vx) }, + { 'g', "Group.predef.q.vy", 'f', &(SS.sv.g.predef.q.vy) }, + { 'g', "Group.predef.q.vz", 'f', &(SS.sv.g.predef.q.vz) }, + { 'g', "Group.predef.origin.v", 'x', &(SS.sv.g.predef.origin.v) }, + { 'g', "Group.predef.entityB.v", 'x', &(SS.sv.g.predef.entityB.v) }, + { 'g', "Group.predef.entityC.v", 'x', &(SS.sv.g.predef.entityC.v) }, + { 'g', "Group.predef.swapUV", 'b', &(SS.sv.g.predef.swapUV) }, + { 'g', "Group.predef.negateU", 'b', &(SS.sv.g.predef.negateU) }, + { 'g', "Group.predef.negateV", 'b', &(SS.sv.g.predef.negateV) }, { 'g', "Group.visible", 'b', &(SS.sv.g.visible) }, { 'g', "Group.remap", 'M', &(SS.sv.g.remap) }, { 'g', "Group.impFile", 'P', &(SS.sv.g.impFile) }, diff --git a/graphicswin.cpp b/graphicswin.cpp index 4131bdb..d86653d 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -833,6 +833,12 @@ hRequest GraphicsWindow::AddRequest(int type) { Request r; memset(&r, 0, sizeof(r)); r.group = activeGroup; + Group *g = SS.GetGroup(activeGroup); + if(g->type == Group::DRAWING_3D || g->type == Group::DRAWING_WORKPLANE) { + r.construction = false; + } else { + r.construction = true; + } r.workplane = ActiveWorkplane(); r.type = type; SS.request.AddAndAssignId(&r); diff --git a/sketch.cpp b/sketch.cpp index 212851d..b068d11 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -49,26 +49,26 @@ void Group::MenuGroup(int id) { v = v.Minus(u.ScaledBy(v.Dot(u))); v = v.ClosestOrtho(); - g.wrkpl.q = Quaternion::MakeFrom(u, v); - g.wrkpl.origin = gs.point[0]; + g.predef.q = Quaternion::MakeFrom(u, v); + g.predef.origin = gs.point[0]; } else if(gs.points == 1 && gs.lineSegments == 2 && gs.n == 3) { g.subtype = WORKPLANE_BY_LINE_SEGMENTS; - g.wrkpl.origin = gs.point[0]; - g.wrkpl.entityB = gs.entity[0]; - g.wrkpl.entityC = gs.entity[1]; + g.predef.origin = gs.point[0]; + g.predef.entityB = gs.entity[0]; + g.predef.entityC = gs.entity[1]; - Vector ut = SS.GetEntity(g.wrkpl.entityB)->VectorGetNum(); - Vector vt = SS.GetEntity(g.wrkpl.entityC)->VectorGetNum(); + Vector ut = SS.GetEntity(g.predef.entityB)->VectorGetNum(); + Vector vt = SS.GetEntity(g.predef.entityC)->VectorGetNum(); ut = ut.WithMagnitude(1); vt = vt.WithMagnitude(1); if(fabs(SS.GW.projUp.Dot(vt)) < fabs(SS.GW.projUp.Dot(ut))) { SWAP(Vector, ut, vt); - g.wrkpl.swapUV = true; + g.predef.swapUV = true; } - if(SS.GW.projRight.Dot(ut) < 0) g.wrkpl.negateU = true; - if(SS.GW.projUp. Dot(vt) < 0) g.wrkpl.negateV = true; + if(SS.GW.projRight.Dot(ut) < 0) g.predef.negateU = true; + if(SS.GW.projUp. Dot(vt) < 0) g.predef.negateV = true; } else { Error("Bad selection for new drawing in workplane."); return; @@ -80,18 +80,35 @@ void Group::MenuGroup(int id) { g.type = EXTRUDE; g.opA = SS.GW.activeGroup; g.color = RGB(100, 100, 100); - g.wrkpl.entityB = SS.GW.ActiveWorkplane(); + g.predef.entityB = SS.GW.ActiveWorkplane(); g.subtype = ONE_SIDED; g.name.strcpy("extrude"); break; - case GraphicsWindow::MNU_GROUP_ROT: + case GraphicsWindow::MNU_GROUP_ROT: { + Vector n; + if(gs.points == 1 && gs.n == 1 && SS.GW.LockedInWorkplane()) { + g.predef.p = (SS.GetEntity(gs.point[0]))->PointGetNum(); + Entity *w = SS.GetEntity(SS.GW.ActiveWorkplane()); + n = (w->Normal()->NormalN()); + g.activeWorkplane = w->h; + } else if(gs.points == 1 && gs.vectors == 1 && gs.n == 2) { + g.predef.p = (SS.GetEntity(gs.point[0]))->PointGetNum(); + n = SS.GetEntity(gs.vector[0])->VectorGetNum(); + } else { + Error("Bad selection for new rotation."); + return; + } + n = n.WithMagnitude(1); + g.predef.q = Quaternion::MakeFrom(0, n.x, n.y, n.z); g.type = ROTATE; g.opA = SS.GW.activeGroup; g.exprA = Expr::FromConstant(3)->DeepCopyKeep(); g.subtype = ONE_SIDED; g.name.strcpy("rotate"); + SS.GW.ClearSelection(); break; + } case GraphicsWindow::MNU_GROUP_TRANS: g.type = TRANSLATE; @@ -143,6 +160,7 @@ void Group::Generate(IdList *entity, { Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp); Vector gp = SS.GW.projRight.Plus(SS.GW.projUp); + Vector gc = (SS.GW.offset).ScaledBy(-1); gn = gn.WithMagnitude(200/SS.GW.scale); gp = gp.WithMagnitude(200/SS.GW.scale); int a, i; @@ -153,19 +171,19 @@ void Group::Generate(IdList *entity, case DRAWING_WORKPLANE: { Quaternion q; if(subtype == WORKPLANE_BY_LINE_SEGMENTS) { - Vector u = SS.GetEntity(wrkpl.entityB)->VectorGetNum(); - Vector v = SS.GetEntity(wrkpl.entityC)->VectorGetNum(); + Vector u = SS.GetEntity(predef.entityB)->VectorGetNum(); + Vector v = SS.GetEntity(predef.entityC)->VectorGetNum(); u = u.WithMagnitude(1); Vector n = u.Cross(v); v = (n.Cross(u)).WithMagnitude(1); - if(wrkpl.swapUV) SWAP(Vector, u, v); - if(wrkpl.negateU) u = u.ScaledBy(-1); - if(wrkpl.negateV) v = v.ScaledBy(-1); + if(predef.swapUV) SWAP(Vector, u, v); + if(predef.negateU) u = u.ScaledBy(-1); + if(predef.negateV) v = v.ScaledBy(-1); q = Quaternion::MakeFrom(u, v); } else if(subtype == WORKPLANE_BY_POINT_ORTHO) { // Already given, numerically. - q = wrkpl.q; + q = predef.q; } else oops(); Entity normal; @@ -180,7 +198,7 @@ void Group::Generate(IdList *entity, Entity point; memset(&point, 0, sizeof(point)); point.type = Entity::POINT_N_COPY; - point.numPoint = SS.GetEntity(wrkpl.origin)->PointGetNum(); + point.numPoint = SS.GetEntity(predef.origin)->PointGetNum(); point.group = h; point.h = h.entity(2); entity->Add(&point); @@ -214,15 +232,15 @@ void Group::Generate(IdList *entity, hEntity he = e->h; e = NULL; // As soon as I call CopyEntity, e may become invalid! That // adds entities, which may cause a realloc. - CopyEntity(SS.GetEntity(he), ai, + CopyEntity(SS.GetEntity(he), ai, REMAP_BOTTOM, h.param(0), h.param(1), h.param(2), NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, - true); - CopyEntity(SS.GetEntity(he), af, + true, false); + CopyEntity(SS.GetEntity(he), af, REMAP_TOP, h.param(0), h.param(1), h.param(2), NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, - true); - MakeExtrusionLines(he, ai, af); + true, false); + MakeExtrusionLines(he); } break; @@ -239,37 +257,44 @@ void Group::Generate(IdList *entity, if(e->group.v != opA.v) continue; e->CalculateNumerical(); - CopyEntity(e, a*2 - (subtype == ONE_SIDED ? 0 : (n-1)), + CopyEntity(e, + a*2 - (subtype == ONE_SIDED ? 0 : (n-1)), + (a == (n - 1)) ? REMAP_LAST : a, h.param(0), h.param(1), h.param(2), NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, - true); + true, false); } } break; } - case ROTATE: - // The translation vector - AddParam(param, h.param(0), gp.x); - AddParam(param, h.param(1), gp.y); - AddParam(param, h.param(2), gp.z); + case ROTATE: { + // The center of rotation + AddParam(param, h.param(0), gc.x); + AddParam(param, h.param(1), gc.y); + AddParam(param, h.param(2), gc.z); // The rotation quaternion - AddParam(param, h.param(3), 1); - AddParam(param, h.param(4), 0); - AddParam(param, h.param(5), 0); - AddParam(param, h.param(6), 0); + AddParam(param, h.param(3), 15*PI/180); + AddParam(param, h.param(4), gn.x); + AddParam(param, h.param(5), gn.y); + AddParam(param, h.param(6), gn.z); - for(i = 0; i < entity->n; i++) { - Entity *e = &(entity->elem[i]); - if(e->group.v != opA.v) continue; + int n = (int)(exprA->Eval()); + for(a = 0; a < n; a++) { + for(i = 0; i < entity->n; i++) { + Entity *e = &(entity->elem[i]); + if(e->group.v != opA.v) continue; - e->CalculateNumerical(); - CopyEntity(e, 0, - h.param(0), h.param(1), h.param(2), - h.param(3), h.param(4), h.param(5), h.param(6), - false); + e->CalculateNumerical(); + CopyEntity(e, + a*2 - (subtype == ONE_SIDED ? 0 : (n-1)), + (a == (n - 1)) ? REMAP_LAST : a, + h.param(0), h.param(1), h.param(2), + h.param(3), h.param(4), h.param(5), h.param(6), + false, true); + } } break; - + } case IMPORTED: // The translation vector AddParam(param, h.param(0), gp.x); @@ -284,10 +309,10 @@ void Group::Generate(IdList *entity, for(i = 0; i < impEntity.n; i++) { Entity *ie = &(impEntity.elem[i]); - CopyEntity(ie, 0, + CopyEntity(ie, 0, 0, h.param(0), h.param(1), h.param(2), h.param(3), h.param(4), h.param(5), h.param(6), - false); + false, false); } break; @@ -295,35 +320,49 @@ void Group::Generate(IdList *entity, } } +void Group::AddEq(IdList *l, Expr *expr, int index) { + Equation eq; + eq.e = expr; + eq.h = h.equation(index); + l->Add(&eq); +} + void Group::GenerateEquations(IdList *l) { Equation eq; - if(type == ROTATE || type == IMPORTED) { + ZERO(&eq); + if(type == IMPORTED) { // Normalize the quaternion ExprQuaternion q = { Expr::FromParam(h.param(3)), Expr::FromParam(h.param(4)), Expr::FromParam(h.param(5)), Expr::FromParam(h.param(6)) }; - eq.e = (q.Magnitude())->Minus(Expr::FromConstant(1)); - eq.h = h.equation(0); - l->Add(&eq); + AddEq(l, (q.Magnitude())->Minus(Expr::FromConstant(1)), 0); + } else if(type == ROTATE) { + // The axis and center of rotation are specified numerically +#define EC(x) (Expr::FromConstant(x)) +#define EP(x) (Expr::FromParam(h.param(x))) + AddEq(l, (EC(predef.p.x))->Minus(EP(0)), 0); + AddEq(l, (EC(predef.p.y))->Minus(EP(1)), 1); + AddEq(l, (EC(predef.p.z))->Minus(EP(2)), 2); + // param 3 is the angle, which is free + AddEq(l, (EC(predef.q.vx))->Minus(EP(4)), 3); + AddEq(l, (EC(predef.q.vy))->Minus(EP(5)), 4); + AddEq(l, (EC(predef.q.vz))->Minus(EP(6)), 5); } else if(type == EXTRUDE) { - if(wrkpl.entityB.v != Entity::FREE_IN_3D.v) { + if(predef.entityB.v != Entity::FREE_IN_3D.v) { // The extrusion path is locked along a line, normal to the // specified workplane. - Entity *w = SS.GetEntity(wrkpl.entityB); + Entity *w = SS.GetEntity(predef.entityB); ExprVector u = w->Normal()->NormalExprsU(); ExprVector v = w->Normal()->NormalExprsV(); ExprVector extruden = { Expr::FromParam(h.param(0)), Expr::FromParam(h.param(1)), Expr::FromParam(h.param(2)) }; - eq.e = u.Dot(extruden); - eq.h = h.equation(0); - l->Add(&eq); - eq.e = v.Dot(extruden); - eq.h = h.equation(1); - l->Add(&eq); + + AddEq(l, u.Dot(extruden), 0); + AddEq(l, v.Dot(extruden), 1); } } } @@ -345,14 +384,14 @@ hEntity Group::Remap(hEntity in, int copyNumber) { return h.entity(em.h.v); } -void Group::MakeExtrusionLines(hEntity in, int ai, int af) { +void Group::MakeExtrusionLines(hEntity in) { Entity *ep = SS.GetEntity(in); if(!(ep->IsPoint())) return; Entity en; memset(&en, 0, sizeof(en)); - en.point[0] = Remap(ep->h, ai); - en.point[1] = Remap(ep->h, af); + en.point[0] = Remap(ep->h, REMAP_TOP); + en.point[1] = Remap(ep->h, REMAP_BOTTOM); en.group = h; en.h = Remap(ep->h, 10); en.type = Entity::LINE_SEGMENT; @@ -360,14 +399,16 @@ void Group::MakeExtrusionLines(hEntity in, int ai, int af) { SS.entity.Add(&en); } -void Group::CopyEntity(Entity *ep, int a, hParam dx, hParam dy, hParam dz, +void Group::CopyEntity(Entity *ep, int timesApplied, int remap, + hParam dx, hParam dy, hParam dz, hParam qw, hParam qvx, hParam qvy, hParam qvz, - bool transOnly) + bool asTrans, bool asAxisAngle) { Entity en; memset(&en, 0, sizeof(en)); en.type = ep->type; - en.h = Remap(ep->h, a); + en.h = Remap(ep->h, remap); + en.timesApplied = timesApplied; en.group = h; en.construction = ep->construction; @@ -377,42 +418,47 @@ void Group::CopyEntity(Entity *ep, int a, hParam dx, hParam dy, hParam dz, return; case Entity::LINE_SEGMENT: - en.point[0] = Remap(ep->point[0], a); - en.point[1] = Remap(ep->point[1], a); + en.point[0] = Remap(ep->point[0], remap); + en.point[1] = Remap(ep->point[1], remap); break; case Entity::CUBIC: - en.point[0] = Remap(ep->point[0], a); - en.point[1] = Remap(ep->point[1], a); - en.point[2] = Remap(ep->point[2], a); - en.point[3] = Remap(ep->point[3], a); + en.point[0] = Remap(ep->point[0], remap); + en.point[1] = Remap(ep->point[1], remap); + en.point[2] = Remap(ep->point[2], remap); + en.point[3] = Remap(ep->point[3], remap); break; case Entity::CIRCLE: - en.point[0] = Remap(ep->point[0], a); - en.normal = Remap(ep->normal, a); - en.distance = Remap(ep->distance, a); + en.point[0] = Remap(ep->point[0], remap); + en.normal = Remap(ep->normal, remap); + en.distance = Remap(ep->distance, remap); break; case Entity::ARC_OF_CIRCLE: - en.point[0] = Remap(ep->point[0], a); - en.point[1] = Remap(ep->point[1], a); - en.point[2] = Remap(ep->point[2], a); - en.normal = Remap(ep->normal, a); + en.point[0] = Remap(ep->point[0], remap); + en.point[1] = Remap(ep->point[1], remap); + en.point[2] = Remap(ep->point[2], remap); + en.normal = Remap(ep->normal, remap); break; case Entity::POINT_N_COPY: case Entity::POINT_N_TRANS: case Entity::POINT_N_ROT_TRANS: + case Entity::POINT_N_ROT_AA: case Entity::POINT_IN_3D: case Entity::POINT_IN_2D: - if(transOnly) { + if(asTrans) { en.type = Entity::POINT_N_TRANS; en.param[0] = dx; en.param[1] = dy; en.param[2] = dz; } else { - en.type = Entity::POINT_N_ROT_TRANS; + if(asAxisAngle) { + en.type = Entity::POINT_N_ROT_AA; + } else { + en.type = Entity::POINT_N_ROT_TRANS; + } en.param[0] = dx; en.param[1] = dy; en.param[2] = dz; @@ -422,25 +468,28 @@ void Group::CopyEntity(Entity *ep, int a, hParam dx, hParam dy, hParam dz, en.param[6] = qvz; } en.numPoint = ep->actPoint; - en.timesApplied = a; break; case Entity::NORMAL_N_COPY: case Entity::NORMAL_N_ROT: + case Entity::NORMAL_N_ROT_AA: case Entity::NORMAL_IN_3D: case Entity::NORMAL_IN_2D: - if(transOnly) { + if(asTrans) { en.type = Entity::NORMAL_N_COPY; } else { - en.type = Entity::NORMAL_N_ROT; + if(asAxisAngle) { + en.type = Entity::NORMAL_N_ROT_AA; + } else { + en.type = Entity::NORMAL_N_ROT; + } en.param[0] = qw; en.param[1] = qvx; en.param[2] = qvy; en.param[3] = qvz; } en.numNormal = ep->actNormal; - en.point[0] = Remap(ep->point[0], a); - en.timesApplied = a; + en.point[0] = Remap(ep->point[0], remap); break; case Entity::DISTANCE_N_COPY: @@ -491,9 +540,7 @@ void Group::MakePolygons(void) { SMesh outm; ZERO(&outm); - if(type == DRAWING_3D || type == DRAWING_WORKPLANE || - type == ROTATE || type == TRANSLATE) - { + if(type == DRAWING_3D || type == DRAWING_WORKPLANE) { int i; for(i = 0; i < SS.entity.n; i++) { Entity *e = &(SS.entity.elem[i]); @@ -617,7 +664,7 @@ void Group::Draw(void) { // to show or hide just this with the "show solids" flag. bool useModelColor; - if(type == DRAWING_3D || type == DRAWING_WORKPLANE) { + if(type != EXTRUDE && type != IMPORTED) { GLfloat mpf[] = { 0.1f, 0.1f, 0.1f, 1.0 }; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf); useModelColor = false; @@ -651,7 +698,7 @@ void Group::Draw(void) { glxWriteText("not closed contour!"); glPopMatrix(); } else { - glxColor4d(0, 1.0, 1.0, 0.05); + glxColor4d(0, 0.1, 0.1, 0.5); glPolygonOffset(-1, -1); glxFillPolygon(&poly); glPolygonOffset(0, 0); diff --git a/sketch.h b/sketch.h index 58cb62e..86e2bb1 100644 --- a/sketch.h +++ b/sketch.h @@ -108,13 +108,14 @@ public: struct { Quaternion q; + Vector p; hEntity origin; hEntity entityB; hEntity entityC; bool swapUV; bool negateU; bool negateV; - } wrkpl; + } predef; SPolygon poly; struct { @@ -144,13 +145,18 @@ public: // entities may have come from multiple requests, it's necessary to // remap the entity ID so that it's still unique. We do this with a // mapping list. + static const int REMAP_LAST = 1000; + static const int REMAP_TOP = 1001; + static const int REMAP_BOTTOM = 1002; hEntity Remap(hEntity in, int copyNumber); - void MakeExtrusionLines(hEntity in, int ai, int af); + void MakeExtrusionLines(hEntity in); void TagEdgesFromLineSegments(SEdgeList *sle); - void CopyEntity(Entity *ep, int a, hParam dx, hParam dy, hParam dz, + void CopyEntity(Entity *ep, int timesApplied, int remap, + hParam dx, hParam dy, hParam dz, hParam qw, hParam qvx, hParam qvy, hParam qvz, - bool transOnly); + bool asTrans, bool asAxisAngle); + void AddEq(IdList *l, Expr *expr, int index); void GenerateEquations(IdList *l); SMesh *PreviousGroupMesh(void); diff --git a/solvespace.cpp b/solvespace.cpp index 40dc0c7..90fdfb9 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -80,9 +80,9 @@ bool SolveSpace::EntityExists(hEntity he) { bool SolveSpace::PruneGroups(hGroup hg) { Group *g = GetGroup(hg); if(GroupsInOrder(g->opA, hg) && - EntityExists(g->wrkpl.origin) && - EntityExists(g->wrkpl.entityB) && - EntityExists(g->wrkpl.entityC)) + EntityExists(g->predef.origin) && + EntityExists(g->predef.entityB) && + EntityExists(g->predef.entityC)) { return false; } diff --git a/util.cpp b/util.cpp index 562b6e1..d228119 100644 --- a/util.cpp +++ b/util.cpp @@ -177,6 +177,14 @@ Vector Vector::MakeFrom(double x, double y, double z) { return v; } +Vector Vector::MakeFrom(hParam x, hParam y, hParam z) { + Vector v; + v.x = SS.GetParam(x)->val; + v.y = SS.GetParam(y)->val; + v.z = SS.GetParam(z)->val; + return v; +} + bool Vector::Equals(Vector v) { if(fabs(x - v.x) > LENGTH_EPS) return false; if(fabs(y - v.y) > LENGTH_EPS) return false;