Add an axis-angle transformation (rotation about an arbitrary

point), and use that to implement step and repeat rotating.

[git-p4: depot-paths = "//depot/solvespace/": change = 1762]
This commit is contained in:
Jonathan Westhues 2008-06-01 00:29:59 -08:00
parent 1d1bec83b1
commit 709b5ad80e
10 changed files with 310 additions and 128 deletions

2
dsc.h
View File

@ -8,6 +8,7 @@ typedef unsigned char BYTE;
class Vector; class Vector;
class Point2d; class Point2d;
class hEntity; class hEntity;
class hParam;
class Quaternion { class Quaternion {
public: public:
@ -40,6 +41,7 @@ public:
double x, y, z; double x, y, z;
static Vector MakeFrom(double x, double y, double 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, static Vector AtIntersectionOfPlanes(Vector n1, double d1,
Vector n2, double d2); Vector n2, double d2);

View File

@ -17,6 +17,7 @@ bool Entity::HasVector(void) {
case NORMAL_IN_2D: case NORMAL_IN_2D:
case NORMAL_N_COPY: case NORMAL_N_COPY:
case NORMAL_N_ROT: case NORMAL_N_ROT:
case NORMAL_N_ROT_AA:
return true; return true;
default: default:
@ -34,6 +35,7 @@ ExprVector Entity::VectorGetExprs(void) {
case NORMAL_IN_2D: case NORMAL_IN_2D:
case NORMAL_N_COPY: case NORMAL_N_COPY:
case NORMAL_N_ROT: case NORMAL_N_ROT:
case NORMAL_N_ROT_AA:
return NormalExprsN(); return NormalExprsN();
default: oops(); default: oops();
@ -50,6 +52,7 @@ Vector Entity::VectorGetNum(void) {
case NORMAL_IN_2D: case NORMAL_IN_2D:
case NORMAL_N_COPY: case NORMAL_N_COPY:
case NORMAL_N_ROT: case NORMAL_N_ROT:
case NORMAL_N_ROT_AA:
return NormalN(); return NormalN();
default: oops(); default: oops();
@ -66,6 +69,7 @@ Vector Entity::VectorGetRefPoint(void) {
case NORMAL_IN_2D: case NORMAL_IN_2D:
case NORMAL_N_COPY: case NORMAL_N_COPY:
case NORMAL_N_ROT: case NORMAL_N_ROT:
case NORMAL_N_ROT_AA:
return SS.GetEntity(point[0])->PointGetNum(); return SS.GetEntity(point[0])->PointGetNum();
default: oops(); default: oops();
@ -174,6 +178,7 @@ bool Entity::IsPoint(void) {
case POINT_N_COPY: case POINT_N_COPY:
case POINT_N_TRANS: case POINT_N_TRANS:
case POINT_N_ROT_TRANS: case POINT_N_ROT_TRANS:
case POINT_N_ROT_AA:
return true; return true;
default: default:
@ -187,6 +192,7 @@ bool Entity::IsNormal(void) {
case NORMAL_IN_2D: case NORMAL_IN_2D:
case NORMAL_N_COPY: case NORMAL_N_COPY:
case NORMAL_N_ROT: case NORMAL_N_ROT:
case NORMAL_N_ROT_AA:
return true; return true;
default: return false; default: return false;
@ -221,6 +227,17 @@ Quaternion Entity::NormalGetNum(void) {
q = q.Times(numNormal); q = q.Times(numNormal);
break; 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(); default: oops();
} }
return q; return q;
@ -239,7 +256,6 @@ void Entity::NormalForceTo(Quaternion q) {
case NORMAL_N_COPY: case NORMAL_N_COPY:
// There's absolutely nothing to do; these are locked. // There's absolutely nothing to do; these are locked.
break; break;
case NORMAL_N_ROT: { case NORMAL_N_ROT: {
Quaternion qp = q.Times(numNormal.Inverse()); Quaternion qp = q.Times(numNormal.Inverse());
@ -250,6 +266,10 @@ void Entity::NormalForceTo(Quaternion q) {
break; break;
} }
case NORMAL_N_ROT_AA:
// Not sure if I'll bother implementing this one
break;
default: oops(); default: oops();
} }
} }
@ -298,11 +318,7 @@ ExprQuaternion Entity::NormalGetExprs(void) {
break; break;
case NORMAL_N_ROT: { case NORMAL_N_ROT: {
ExprQuaternion orig; ExprQuaternion orig = ExprQuaternion::FromNum(numNormal);
orig.w = Expr::FromConstant(numNormal.w);
orig.vx = Expr::FromConstant(numNormal.vx);
orig.vy = Expr::FromConstant(numNormal.vy);
orig.vz = Expr::FromConstant(numNormal.vz);
q.w = Expr::FromParam(param[0]); q.w = Expr::FromParam(param[0]);
q.vx = Expr::FromParam(param[1]); q.vx = Expr::FromParam(param[1]);
@ -313,6 +329,21 @@ ExprQuaternion Entity::NormalGetExprs(void) {
break; 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(); default: oops();
} }
return q; return q;
@ -358,6 +389,25 @@ void Entity::PointForceTo(Vector p) {
break; 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: case POINT_N_COPY:
// Nothing to do; it's a static copy // Nothing to do; it's a static copy
break; break;
@ -404,6 +454,18 @@ Vector Entity::PointGetNum(void) {
break; 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: case POINT_N_COPY:
p = numPoint; p = numPoint;
break; break;
@ -444,14 +506,9 @@ ExprVector Entity::PointGetExprs(void) {
break; break;
} }
case POINT_N_ROT_TRANS: { case POINT_N_ROT_TRANS: {
ExprVector orig = { ExprVector orig = ExprVector::FromNum(numPoint);
Expr::FromConstant(numPoint.x), ExprVector trans =
Expr::FromConstant(numPoint.y), ExprVector::FromParams(param[0], param[1], param[2]);
Expr::FromConstant(numPoint.z) };
ExprVector trans = {
Expr::FromParam(param[0]),
Expr::FromParam(param[1]),
Expr::FromParam(param[2]) };
ExprQuaternion q = { ExprQuaternion q = {
Expr::FromParam(param[3]), Expr::FromParam(param[3]),
Expr::FromParam(param[4]), Expr::FromParam(param[4]),
@ -461,6 +518,23 @@ ExprVector Entity::PointGetExprs(void) {
r = orig.Plus(trans); r = orig.Plus(trans);
break; 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: case POINT_N_COPY:
r.x = Expr::FromConstant(numPoint.x); r.x = Expr::FromConstant(numPoint.x);
r.y = Expr::FromConstant(numPoint.y); r.y = Expr::FromConstant(numPoint.y);
@ -504,13 +578,22 @@ void Entity::PointForceQuaternionTo(Quaternion q) {
} }
Quaternion Entity::PointGetQuaternion(void) { Quaternion Entity::PointGetQuaternion(void) {
if(type != POINT_N_ROT_TRANS) oops();
Quaternion q; Quaternion q;
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.w = SS.GetParam(param[3])->val;
q.vx = SS.GetParam(param[4])->val; q.vx = SS.GetParam(param[4])->val;
q.vy = SS.GetParam(param[5])->val; q.vy = SS.GetParam(param[5])->val;
q.vz = SS.GetParam(param[6])->val; q.vz = SS.GetParam(param[6])->val;
} else oops();
return q; return q;
} }
@ -594,6 +677,7 @@ void Entity::DrawOrGetDistance(int order) {
case POINT_N_COPY: case POINT_N_COPY:
case POINT_N_TRANS: case POINT_N_TRANS:
case POINT_N_ROT_TRANS: case POINT_N_ROT_TRANS:
case POINT_N_ROT_AA:
case POINT_IN_3D: case POINT_IN_3D:
case POINT_IN_2D: { case POINT_IN_2D: {
if(order >= 0 && order != 2) break; if(order >= 0 && order != 2) break;
@ -633,6 +717,7 @@ void Entity::DrawOrGetDistance(int order) {
case NORMAL_N_COPY: case NORMAL_N_COPY:
case NORMAL_N_ROT: case NORMAL_N_ROT:
case NORMAL_N_ROT_AA:
case NORMAL_IN_3D: case NORMAL_IN_3D:
case NORMAL_IN_2D: { case NORMAL_IN_2D: {
if(order >= 0 && order != 2) break; if(order >= 0 && order != 2) break;

View File

@ -5,6 +5,22 @@ ExprVector ExprVector::FromExprs(Expr *x, Expr *y, Expr *z) {
return r; 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 ExprVector::Minus(ExprVector b) {
ExprVector r; ExprVector r;
r.x = x->Minus(b.x); r.x = x->Minus(b.x);
@ -71,6 +87,15 @@ ExprQuaternion ExprQuaternion::FromExprs(Expr *w, Expr *vx, Expr *vy, Expr *vz)
return q; 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 ExprQuaternion::RotationU(void) {
ExprVector u; ExprVector u;
Expr *two = Expr::FromConstant(2); Expr *two = Expr::FromConstant(2);

3
expr.h
View File

@ -123,6 +123,8 @@ public:
Expr *x, *y, *z; Expr *x, *y, *z;
static ExprVector FromExprs(Expr *x, Expr *y, Expr *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 Plus(ExprVector b);
ExprVector Minus(ExprVector b); ExprVector Minus(ExprVector b);
@ -139,6 +141,7 @@ public:
Expr *w, *vx, *vy, *vz; Expr *w, *vx, *vy, *vz;
static ExprQuaternion FromExprs(Expr *w, Expr *vx, Expr *vy, Expr *vz); static ExprQuaternion FromExprs(Expr *w, Expr *vx, Expr *vy, Expr *vz);
static ExprQuaternion FromNum(Quaternion qn);
ExprVector RotationU(void); ExprVector RotationU(void);
ExprVector RotationV(void); ExprVector RotationV(void);

View File

@ -42,9 +42,9 @@ void SolveSpace::NewFile(void) {
// And an empty group, for the first stuff the user draws. // And an empty group, for the first stuff the user draws.
g.type = Group::DRAWING_WORKPLANE; g.type = Group::DRAWING_WORKPLANE;
g.subtype = Group::WORKPLANE_BY_POINT_ORTHO; 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; hRequest hr = Request::HREQUEST_REFERENCE_XY;
g.wrkpl.origin = hr.entity(1); g.predef.origin = hr.entity(1);
g.name.strcpy("draw-in-plane"); g.name.strcpy("draw-in-plane");
group.AddAndAssignId(&g); group.AddAndAssignId(&g);
SS.GetGroup(g.h)->activeWorkplane = g.h.entity(0); 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.color", 'x', &(SS.sv.g.color) },
{ 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) }, { 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) },
{ 'g', "Group.meshCombine", 'd', &(SS.sv.g.meshCombine) }, { 'g', "Group.meshCombine", 'd', &(SS.sv.g.meshCombine) },
{ 'g', "Group.wrkpl.q.w", 'f', &(SS.sv.g.wrkpl.q.w) }, { 'g', "Group.predef.q.w", 'f', &(SS.sv.g.predef.q.w) },
{ 'g', "Group.wrkpl.q.vx", 'f', &(SS.sv.g.wrkpl.q.vx) }, { 'g', "Group.predef.q.vx", 'f', &(SS.sv.g.predef.q.vx) },
{ 'g', "Group.wrkpl.q.vy", 'f', &(SS.sv.g.wrkpl.q.vy) }, { 'g', "Group.predef.q.vy", 'f', &(SS.sv.g.predef.q.vy) },
{ 'g', "Group.wrkpl.q.vz", 'f', &(SS.sv.g.wrkpl.q.vz) }, { 'g', "Group.predef.q.vz", 'f', &(SS.sv.g.predef.q.vz) },
{ 'g', "Group.wrkpl.origin.v", 'x', &(SS.sv.g.wrkpl.origin.v) }, { 'g', "Group.predef.origin.v", 'x', &(SS.sv.g.predef.origin.v) },
{ 'g', "Group.wrkpl.entityB.v", 'x', &(SS.sv.g.wrkpl.entityB.v) }, { 'g', "Group.predef.entityB.v", 'x', &(SS.sv.g.predef.entityB.v) },
{ 'g', "Group.wrkpl.entityC.v", 'x', &(SS.sv.g.wrkpl.entityC.v) }, { 'g', "Group.predef.entityC.v", 'x', &(SS.sv.g.predef.entityC.v) },
{ 'g', "Group.wrkpl.swapUV", 'b', &(SS.sv.g.wrkpl.swapUV) }, { 'g', "Group.predef.swapUV", 'b', &(SS.sv.g.predef.swapUV) },
{ 'g', "Group.wrkpl.negateU", 'b', &(SS.sv.g.wrkpl.negateU) }, { 'g', "Group.predef.negateU", 'b', &(SS.sv.g.predef.negateU) },
{ 'g', "Group.wrkpl.negateV", 'b', &(SS.sv.g.wrkpl.negateV) }, { 'g', "Group.predef.negateV", 'b', &(SS.sv.g.predef.negateV) },
{ 'g', "Group.visible", 'b', &(SS.sv.g.visible) }, { 'g', "Group.visible", 'b', &(SS.sv.g.visible) },
{ 'g', "Group.remap", 'M', &(SS.sv.g.remap) }, { 'g', "Group.remap", 'M', &(SS.sv.g.remap) },
{ 'g', "Group.impFile", 'P', &(SS.sv.g.impFile) }, { 'g', "Group.impFile", 'P', &(SS.sv.g.impFile) },

View File

@ -833,6 +833,12 @@ hRequest GraphicsWindow::AddRequest(int type) {
Request r; Request r;
memset(&r, 0, sizeof(r)); memset(&r, 0, sizeof(r));
r.group = activeGroup; 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.workplane = ActiveWorkplane();
r.type = type; r.type = type;
SS.request.AddAndAssignId(&r); SS.request.AddAndAssignId(&r);

View File

@ -49,26 +49,26 @@ void Group::MenuGroup(int id) {
v = v.Minus(u.ScaledBy(v.Dot(u))); v = v.Minus(u.ScaledBy(v.Dot(u)));
v = v.ClosestOrtho(); v = v.ClosestOrtho();
g.wrkpl.q = Quaternion::MakeFrom(u, v); g.predef.q = Quaternion::MakeFrom(u, v);
g.wrkpl.origin = gs.point[0]; g.predef.origin = gs.point[0];
} else if(gs.points == 1 && gs.lineSegments == 2 && gs.n == 3) { } else if(gs.points == 1 && gs.lineSegments == 2 && gs.n == 3) {
g.subtype = WORKPLANE_BY_LINE_SEGMENTS; g.subtype = WORKPLANE_BY_LINE_SEGMENTS;
g.wrkpl.origin = gs.point[0]; g.predef.origin = gs.point[0];
g.wrkpl.entityB = gs.entity[0]; g.predef.entityB = gs.entity[0];
g.wrkpl.entityC = gs.entity[1]; g.predef.entityC = gs.entity[1];
Vector ut = SS.GetEntity(g.wrkpl.entityB)->VectorGetNum(); Vector ut = SS.GetEntity(g.predef.entityB)->VectorGetNum();
Vector vt = SS.GetEntity(g.wrkpl.entityC)->VectorGetNum(); Vector vt = SS.GetEntity(g.predef.entityC)->VectorGetNum();
ut = ut.WithMagnitude(1); ut = ut.WithMagnitude(1);
vt = vt.WithMagnitude(1); vt = vt.WithMagnitude(1);
if(fabs(SS.GW.projUp.Dot(vt)) < fabs(SS.GW.projUp.Dot(ut))) { if(fabs(SS.GW.projUp.Dot(vt)) < fabs(SS.GW.projUp.Dot(ut))) {
SWAP(Vector, ut, vt); 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.projRight.Dot(ut) < 0) g.predef.negateU = true;
if(SS.GW.projUp. Dot(vt) < 0) g.wrkpl.negateV = true; if(SS.GW.projUp. Dot(vt) < 0) g.predef.negateV = true;
} else { } else {
Error("Bad selection for new drawing in workplane."); Error("Bad selection for new drawing in workplane.");
return; return;
@ -80,18 +80,35 @@ void Group::MenuGroup(int id) {
g.type = EXTRUDE; g.type = EXTRUDE;
g.opA = SS.GW.activeGroup; g.opA = SS.GW.activeGroup;
g.color = RGB(100, 100, 100); g.color = RGB(100, 100, 100);
g.wrkpl.entityB = SS.GW.ActiveWorkplane(); g.predef.entityB = SS.GW.ActiveWorkplane();
g.subtype = ONE_SIDED; g.subtype = ONE_SIDED;
g.name.strcpy("extrude"); g.name.strcpy("extrude");
break; 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.type = ROTATE;
g.opA = SS.GW.activeGroup; g.opA = SS.GW.activeGroup;
g.exprA = Expr::FromConstant(3)->DeepCopyKeep(); g.exprA = Expr::FromConstant(3)->DeepCopyKeep();
g.subtype = ONE_SIDED; g.subtype = ONE_SIDED;
g.name.strcpy("rotate"); g.name.strcpy("rotate");
SS.GW.ClearSelection();
break; break;
}
case GraphicsWindow::MNU_GROUP_TRANS: case GraphicsWindow::MNU_GROUP_TRANS:
g.type = TRANSLATE; g.type = TRANSLATE;
@ -143,6 +160,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
{ {
Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp); Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
Vector gp = SS.GW.projRight.Plus(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); gn = gn.WithMagnitude(200/SS.GW.scale);
gp = gp.WithMagnitude(200/SS.GW.scale); gp = gp.WithMagnitude(200/SS.GW.scale);
int a, i; int a, i;
@ -153,19 +171,19 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
case DRAWING_WORKPLANE: { case DRAWING_WORKPLANE: {
Quaternion q; Quaternion q;
if(subtype == WORKPLANE_BY_LINE_SEGMENTS) { if(subtype == WORKPLANE_BY_LINE_SEGMENTS) {
Vector u = SS.GetEntity(wrkpl.entityB)->VectorGetNum(); Vector u = SS.GetEntity(predef.entityB)->VectorGetNum();
Vector v = SS.GetEntity(wrkpl.entityC)->VectorGetNum(); Vector v = SS.GetEntity(predef.entityC)->VectorGetNum();
u = u.WithMagnitude(1); u = u.WithMagnitude(1);
Vector n = u.Cross(v); Vector n = u.Cross(v);
v = (n.Cross(u)).WithMagnitude(1); v = (n.Cross(u)).WithMagnitude(1);
if(wrkpl.swapUV) SWAP(Vector, u, v); if(predef.swapUV) SWAP(Vector, u, v);
if(wrkpl.negateU) u = u.ScaledBy(-1); if(predef.negateU) u = u.ScaledBy(-1);
if(wrkpl.negateV) v = v.ScaledBy(-1); if(predef.negateV) v = v.ScaledBy(-1);
q = Quaternion::MakeFrom(u, v); q = Quaternion::MakeFrom(u, v);
} else if(subtype == WORKPLANE_BY_POINT_ORTHO) { } else if(subtype == WORKPLANE_BY_POINT_ORTHO) {
// Already given, numerically. // Already given, numerically.
q = wrkpl.q; q = predef.q;
} else oops(); } else oops();
Entity normal; Entity normal;
@ -180,7 +198,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
Entity point; Entity point;
memset(&point, 0, sizeof(point)); memset(&point, 0, sizeof(point));
point.type = Entity::POINT_N_COPY; point.type = Entity::POINT_N_COPY;
point.numPoint = SS.GetEntity(wrkpl.origin)->PointGetNum(); point.numPoint = SS.GetEntity(predef.origin)->PointGetNum();
point.group = h; point.group = h;
point.h = h.entity(2); point.h = h.entity(2);
entity->Add(&point); entity->Add(&point);
@ -214,15 +232,15 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
hEntity he = e->h; e = NULL; hEntity he = e->h; e = NULL;
// As soon as I call CopyEntity, e may become invalid! That // As soon as I call CopyEntity, e may become invalid! That
// adds entities, which may cause a realloc. // 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), h.param(0), h.param(1), h.param(2),
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
true); true, false);
CopyEntity(SS.GetEntity(he), af, CopyEntity(SS.GetEntity(he), af, REMAP_TOP,
h.param(0), h.param(1), h.param(2), h.param(0), h.param(1), h.param(2),
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
true); true, false);
MakeExtrusionLines(he, ai, af); MakeExtrusionLines(he);
} }
break; break;
@ -239,37 +257,44 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
if(e->group.v != opA.v) continue; if(e->group.v != opA.v) continue;
e->CalculateNumerical(); 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), h.param(0), h.param(1), h.param(2),
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
true); true, false);
} }
} }
break; break;
} }
case ROTATE: case ROTATE: {
// The translation vector // The center of rotation
AddParam(param, h.param(0), gp.x); AddParam(param, h.param(0), gc.x);
AddParam(param, h.param(1), gp.y); AddParam(param, h.param(1), gc.y);
AddParam(param, h.param(2), gp.z); AddParam(param, h.param(2), gc.z);
// The rotation quaternion // The rotation quaternion
AddParam(param, h.param(3), 1); AddParam(param, h.param(3), 15*PI/180);
AddParam(param, h.param(4), 0); AddParam(param, h.param(4), gn.x);
AddParam(param, h.param(5), 0); AddParam(param, h.param(5), gn.y);
AddParam(param, h.param(6), 0); AddParam(param, h.param(6), gn.z);
int n = (int)(exprA->Eval());
for(a = 0; a < n; a++) {
for(i = 0; i < entity->n; i++) { for(i = 0; i < entity->n; i++) {
Entity *e = &(entity->elem[i]); Entity *e = &(entity->elem[i]);
if(e->group.v != opA.v) continue; if(e->group.v != opA.v) continue;
e->CalculateNumerical(); e->CalculateNumerical();
CopyEntity(e, 0, 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(0), h.param(1), h.param(2),
h.param(3), h.param(4), h.param(5), h.param(6), h.param(3), h.param(4), h.param(5), h.param(6),
false); false, true);
}
} }
break; break;
}
case IMPORTED: case IMPORTED:
// The translation vector // The translation vector
AddParam(param, h.param(0), gp.x); AddParam(param, h.param(0), gp.x);
@ -284,10 +309,10 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
for(i = 0; i < impEntity.n; i++) { for(i = 0; i < impEntity.n; i++) {
Entity *ie = &(impEntity.elem[i]); Entity *ie = &(impEntity.elem[i]);
CopyEntity(ie, 0, CopyEntity(ie, 0, 0,
h.param(0), h.param(1), h.param(2), h.param(0), h.param(1), h.param(2),
h.param(3), h.param(4), h.param(5), h.param(6), h.param(3), h.param(4), h.param(5), h.param(6),
false); false, false);
} }
break; break;
@ -295,35 +320,49 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
} }
} }
void Group::AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index) {
Equation eq;
eq.e = expr;
eq.h = h.equation(index);
l->Add(&eq);
}
void Group::GenerateEquations(IdList<Equation,hEquation> *l) { void Group::GenerateEquations(IdList<Equation,hEquation> *l) {
Equation eq; Equation eq;
if(type == ROTATE || type == IMPORTED) { ZERO(&eq);
if(type == IMPORTED) {
// Normalize the quaternion // Normalize the quaternion
ExprQuaternion q = { ExprQuaternion q = {
Expr::FromParam(h.param(3)), Expr::FromParam(h.param(3)),
Expr::FromParam(h.param(4)), Expr::FromParam(h.param(4)),
Expr::FromParam(h.param(5)), Expr::FromParam(h.param(5)),
Expr::FromParam(h.param(6)) }; Expr::FromParam(h.param(6)) };
eq.e = (q.Magnitude())->Minus(Expr::FromConstant(1)); AddEq(l, (q.Magnitude())->Minus(Expr::FromConstant(1)), 0);
eq.h = h.equation(0); } else if(type == ROTATE) {
l->Add(&eq); // 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) { } 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 // The extrusion path is locked along a line, normal to the
// specified workplane. // specified workplane.
Entity *w = SS.GetEntity(wrkpl.entityB); Entity *w = SS.GetEntity(predef.entityB);
ExprVector u = w->Normal()->NormalExprsU(); ExprVector u = w->Normal()->NormalExprsU();
ExprVector v = w->Normal()->NormalExprsV(); ExprVector v = w->Normal()->NormalExprsV();
ExprVector extruden = { ExprVector extruden = {
Expr::FromParam(h.param(0)), Expr::FromParam(h.param(0)),
Expr::FromParam(h.param(1)), Expr::FromParam(h.param(1)),
Expr::FromParam(h.param(2)) }; Expr::FromParam(h.param(2)) };
eq.e = u.Dot(extruden);
eq.h = h.equation(0); AddEq(l, u.Dot(extruden), 0);
l->Add(&eq); AddEq(l, v.Dot(extruden), 1);
eq.e = v.Dot(extruden);
eq.h = h.equation(1);
l->Add(&eq);
} }
} }
} }
@ -345,14 +384,14 @@ hEntity Group::Remap(hEntity in, int copyNumber) {
return h.entity(em.h.v); 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); Entity *ep = SS.GetEntity(in);
if(!(ep->IsPoint())) return; if(!(ep->IsPoint())) return;
Entity en; Entity en;
memset(&en, 0, sizeof(en)); memset(&en, 0, sizeof(en));
en.point[0] = Remap(ep->h, ai); en.point[0] = Remap(ep->h, REMAP_TOP);
en.point[1] = Remap(ep->h, af); en.point[1] = Remap(ep->h, REMAP_BOTTOM);
en.group = h; en.group = h;
en.h = Remap(ep->h, 10); en.h = Remap(ep->h, 10);
en.type = Entity::LINE_SEGMENT; en.type = Entity::LINE_SEGMENT;
@ -360,14 +399,16 @@ void Group::MakeExtrusionLines(hEntity in, int ai, int af) {
SS.entity.Add(&en); 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, hParam qw, hParam qvx, hParam qvy, hParam qvz,
bool transOnly) bool asTrans, bool asAxisAngle)
{ {
Entity en; Entity en;
memset(&en, 0, sizeof(en)); memset(&en, 0, sizeof(en));
en.type = ep->type; en.type = ep->type;
en.h = Remap(ep->h, a); en.h = Remap(ep->h, remap);
en.timesApplied = timesApplied;
en.group = h; en.group = h;
en.construction = ep->construction; en.construction = ep->construction;
@ -377,42 +418,47 @@ void Group::CopyEntity(Entity *ep, int a, hParam dx, hParam dy, hParam dz,
return; return;
case Entity::LINE_SEGMENT: case Entity::LINE_SEGMENT:
en.point[0] = Remap(ep->point[0], a); en.point[0] = Remap(ep->point[0], remap);
en.point[1] = Remap(ep->point[1], a); en.point[1] = Remap(ep->point[1], remap);
break; break;
case Entity::CUBIC: case Entity::CUBIC:
en.point[0] = Remap(ep->point[0], a); en.point[0] = Remap(ep->point[0], remap);
en.point[1] = Remap(ep->point[1], a); en.point[1] = Remap(ep->point[1], remap);
en.point[2] = Remap(ep->point[2], a); en.point[2] = Remap(ep->point[2], remap);
en.point[3] = Remap(ep->point[3], a); en.point[3] = Remap(ep->point[3], remap);
break; break;
case Entity::CIRCLE: case Entity::CIRCLE:
en.point[0] = Remap(ep->point[0], a); en.point[0] = Remap(ep->point[0], remap);
en.normal = Remap(ep->normal, a); en.normal = Remap(ep->normal, remap);
en.distance = Remap(ep->distance, a); en.distance = Remap(ep->distance, remap);
break; break;
case Entity::ARC_OF_CIRCLE: case Entity::ARC_OF_CIRCLE:
en.point[0] = Remap(ep->point[0], a); en.point[0] = Remap(ep->point[0], remap);
en.point[1] = Remap(ep->point[1], a); en.point[1] = Remap(ep->point[1], remap);
en.point[2] = Remap(ep->point[2], a); en.point[2] = Remap(ep->point[2], remap);
en.normal = Remap(ep->normal, a); en.normal = Remap(ep->normal, remap);
break; break;
case Entity::POINT_N_COPY: case Entity::POINT_N_COPY:
case Entity::POINT_N_TRANS: case Entity::POINT_N_TRANS:
case Entity::POINT_N_ROT_TRANS: case Entity::POINT_N_ROT_TRANS:
case Entity::POINT_N_ROT_AA:
case Entity::POINT_IN_3D: case Entity::POINT_IN_3D:
case Entity::POINT_IN_2D: case Entity::POINT_IN_2D:
if(transOnly) { if(asTrans) {
en.type = Entity::POINT_N_TRANS; en.type = Entity::POINT_N_TRANS;
en.param[0] = dx; en.param[0] = dx;
en.param[1] = dy; en.param[1] = dy;
en.param[2] = dz; en.param[2] = dz;
} else {
if(asAxisAngle) {
en.type = Entity::POINT_N_ROT_AA;
} else { } else {
en.type = Entity::POINT_N_ROT_TRANS; en.type = Entity::POINT_N_ROT_TRANS;
}
en.param[0] = dx; en.param[0] = dx;
en.param[1] = dy; en.param[1] = dy;
en.param[2] = dz; 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.param[6] = qvz;
} }
en.numPoint = ep->actPoint; en.numPoint = ep->actPoint;
en.timesApplied = a;
break; break;
case Entity::NORMAL_N_COPY: case Entity::NORMAL_N_COPY:
case Entity::NORMAL_N_ROT: case Entity::NORMAL_N_ROT:
case Entity::NORMAL_N_ROT_AA:
case Entity::NORMAL_IN_3D: case Entity::NORMAL_IN_3D:
case Entity::NORMAL_IN_2D: case Entity::NORMAL_IN_2D:
if(transOnly) { if(asTrans) {
en.type = Entity::NORMAL_N_COPY; en.type = Entity::NORMAL_N_COPY;
} else {
if(asAxisAngle) {
en.type = Entity::NORMAL_N_ROT_AA;
} else { } else {
en.type = Entity::NORMAL_N_ROT; en.type = Entity::NORMAL_N_ROT;
}
en.param[0] = qw; en.param[0] = qw;
en.param[1] = qvx; en.param[1] = qvx;
en.param[2] = qvy; en.param[2] = qvy;
en.param[3] = qvz; en.param[3] = qvz;
} }
en.numNormal = ep->actNormal; en.numNormal = ep->actNormal;
en.point[0] = Remap(ep->point[0], a); en.point[0] = Remap(ep->point[0], remap);
en.timesApplied = a;
break; break;
case Entity::DISTANCE_N_COPY: case Entity::DISTANCE_N_COPY:
@ -491,9 +540,7 @@ void Group::MakePolygons(void) {
SMesh outm; SMesh outm;
ZERO(&outm); ZERO(&outm);
if(type == DRAWING_3D || type == DRAWING_WORKPLANE || if(type == DRAWING_3D || type == DRAWING_WORKPLANE) {
type == ROTATE || type == TRANSLATE)
{
int i; int i;
for(i = 0; i < SS.entity.n; i++) { for(i = 0; i < SS.entity.n; i++) {
Entity *e = &(SS.entity.elem[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. // to show or hide just this with the "show solids" flag.
bool useModelColor; bool useModelColor;
if(type == DRAWING_3D || type == DRAWING_WORKPLANE) { if(type != EXTRUDE && type != IMPORTED) {
GLfloat mpf[] = { 0.1f, 0.1f, 0.1f, 1.0 }; GLfloat mpf[] = { 0.1f, 0.1f, 0.1f, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf);
useModelColor = false; useModelColor = false;
@ -651,7 +698,7 @@ void Group::Draw(void) {
glxWriteText("not closed contour!"); glxWriteText("not closed contour!");
glPopMatrix(); glPopMatrix();
} else { } else {
glxColor4d(0, 1.0, 1.0, 0.05); glxColor4d(0, 0.1, 0.1, 0.5);
glPolygonOffset(-1, -1); glPolygonOffset(-1, -1);
glxFillPolygon(&poly); glxFillPolygon(&poly);
glPolygonOffset(0, 0); glPolygonOffset(0, 0);

View File

@ -108,13 +108,14 @@ public:
struct { struct {
Quaternion q; Quaternion q;
Vector p;
hEntity origin; hEntity origin;
hEntity entityB; hEntity entityB;
hEntity entityC; hEntity entityC;
bool swapUV; bool swapUV;
bool negateU; bool negateU;
bool negateV; bool negateV;
} wrkpl; } predef;
SPolygon poly; SPolygon poly;
struct { struct {
@ -144,13 +145,18 @@ public:
// entities may have come from multiple requests, it's necessary to // 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 // remap the entity ID so that it's still unique. We do this with a
// mapping list. // 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); hEntity Remap(hEntity in, int copyNumber);
void MakeExtrusionLines(hEntity in, int ai, int af); void MakeExtrusionLines(hEntity in);
void TagEdgesFromLineSegments(SEdgeList *sle); 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, hParam qw, hParam qvx, hParam qvy, hParam qvz,
bool transOnly); bool asTrans, bool asAxisAngle);
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
void GenerateEquations(IdList<Equation,hEquation> *l); void GenerateEquations(IdList<Equation,hEquation> *l);
SMesh *PreviousGroupMesh(void); SMesh *PreviousGroupMesh(void);

View File

@ -80,9 +80,9 @@ bool SolveSpace::EntityExists(hEntity he) {
bool SolveSpace::PruneGroups(hGroup hg) { bool SolveSpace::PruneGroups(hGroup hg) {
Group *g = GetGroup(hg); Group *g = GetGroup(hg);
if(GroupsInOrder(g->opA, hg) && if(GroupsInOrder(g->opA, hg) &&
EntityExists(g->wrkpl.origin) && EntityExists(g->predef.origin) &&
EntityExists(g->wrkpl.entityB) && EntityExists(g->predef.entityB) &&
EntityExists(g->wrkpl.entityC)) EntityExists(g->predef.entityC))
{ {
return false; return false;
} }

View File

@ -177,6 +177,14 @@ Vector Vector::MakeFrom(double x, double y, double z) {
return v; 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) { bool Vector::Equals(Vector v) {
if(fabs(x - v.x) > LENGTH_EPS) return false; if(fabs(x - v.x) > LENGTH_EPS) return false;
if(fabs(y - v.y) > LENGTH_EPS) return false; if(fabs(y - v.y) > LENGTH_EPS) return false;