Add transformed points and normals with a rotation (as well as a
translation; or equivalently, rotation about an arbitrary axis). Those will be important for step and repeats, and for imported parts. Also fix a terrible memory corruption bug: I was freeing the remap list after I loaded it from the file, but the code that put that into the SS.group list made only a shallow copy. [git-p4: depot-paths = "//depot/solvespace/": change = 1715]solver
parent
4eed7693be
commit
6042fb3e0f
3
dsc.h
3
dsc.h
|
@ -28,6 +28,9 @@ public:
|
||||||
Vector RotationU(void);
|
Vector RotationU(void);
|
||||||
Vector RotationV(void);
|
Vector RotationV(void);
|
||||||
Vector RotationN(void);
|
Vector RotationN(void);
|
||||||
|
Vector Rotate(Vector p);
|
||||||
|
|
||||||
|
Quaternion Times(Quaternion b);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Vector {
|
class Vector {
|
||||||
|
|
135
entity.cpp
135
entity.cpp
|
@ -10,7 +10,8 @@ bool Entity::HasVector(void) {
|
||||||
case LINE_SEGMENT:
|
case LINE_SEGMENT:
|
||||||
case NORMAL_IN_3D:
|
case NORMAL_IN_3D:
|
||||||
case NORMAL_IN_2D:
|
case NORMAL_IN_2D:
|
||||||
case NORMAL_XFRMD:
|
case NORMAL_N_COPY:
|
||||||
|
case NORMAL_N_ROT:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -26,7 +27,8 @@ ExprVector Entity::VectorGetExprs(void) {
|
||||||
|
|
||||||
case NORMAL_IN_3D:
|
case NORMAL_IN_3D:
|
||||||
case NORMAL_IN_2D:
|
case NORMAL_IN_2D:
|
||||||
case NORMAL_XFRMD:
|
case NORMAL_N_COPY:
|
||||||
|
case NORMAL_N_ROT:
|
||||||
return NormalExprsN();
|
return NormalExprsN();
|
||||||
|
|
||||||
default: oops();
|
default: oops();
|
||||||
|
@ -41,7 +43,8 @@ Vector Entity::VectorGetRefPoint(void) {
|
||||||
|
|
||||||
case NORMAL_IN_3D:
|
case NORMAL_IN_3D:
|
||||||
case NORMAL_IN_2D:
|
case NORMAL_IN_2D:
|
||||||
case NORMAL_XFRMD:
|
case NORMAL_N_COPY:
|
||||||
|
case NORMAL_N_ROT:
|
||||||
return SS.GetEntity(point[0])->PointGetNum();
|
return SS.GetEntity(point[0])->PointGetNum();
|
||||||
|
|
||||||
default: oops();
|
default: oops();
|
||||||
|
@ -81,21 +84,21 @@ void Entity::WorkplaneGetPlaneExprs(ExprVector *n, Expr **dn) {
|
||||||
double Entity::DistanceGetNum(void) {
|
double Entity::DistanceGetNum(void) {
|
||||||
if(type == DISTANCE) {
|
if(type == DISTANCE) {
|
||||||
return SS.GetParam(param[0])->val;
|
return SS.GetParam(param[0])->val;
|
||||||
} else if(type == DISTANCE_XFRMD) {
|
} else if(type == DISTANCE_N_COPY) {
|
||||||
return numDistance;
|
return numDistance;
|
||||||
} else oops();
|
} else oops();
|
||||||
}
|
}
|
||||||
Expr *Entity::DistanceGetExpr(void) {
|
Expr *Entity::DistanceGetExpr(void) {
|
||||||
if(type == DISTANCE) {
|
if(type == DISTANCE) {
|
||||||
return Expr::FromParam(param[0]);
|
return Expr::FromParam(param[0]);
|
||||||
} else if(type == DISTANCE_XFRMD) {
|
} else if(type == DISTANCE_N_COPY) {
|
||||||
return Expr::FromConstant(numDistance);
|
return Expr::FromConstant(numDistance);
|
||||||
} else oops();
|
} else oops();
|
||||||
}
|
}
|
||||||
void Entity::DistanceForceTo(double v) {
|
void Entity::DistanceForceTo(double v) {
|
||||||
if(type == DISTANCE) {
|
if(type == DISTANCE) {
|
||||||
(SS.GetParam(param[0]))->val = v;
|
(SS.GetParam(param[0]))->val = v;
|
||||||
} else if(type == DISTANCE_XFRMD) {
|
} else if(type == DISTANCE_N_COPY) {
|
||||||
// do nothing, it's locked
|
// do nothing, it's locked
|
||||||
} else oops();
|
} else oops();
|
||||||
}
|
}
|
||||||
|
@ -108,9 +111,12 @@ bool Entity::IsPoint(void) {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case POINT_IN_3D:
|
case POINT_IN_3D:
|
||||||
case POINT_IN_2D:
|
case POINT_IN_2D:
|
||||||
case POINT_XFRMD: return true;
|
case POINT_N_TRANS:
|
||||||
|
case POINT_N_ROT_TRANS:
|
||||||
|
return true;
|
||||||
|
|
||||||
default: return false;
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +124,9 @@ bool Entity::IsNormal(void) {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case NORMAL_IN_3D:
|
case NORMAL_IN_3D:
|
||||||
case NORMAL_IN_2D:
|
case NORMAL_IN_2D:
|
||||||
case NORMAL_XFRMD: return true;
|
case NORMAL_N_COPY:
|
||||||
|
case NORMAL_N_ROT:
|
||||||
|
return true;
|
||||||
|
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
|
@ -140,10 +148,18 @@ Quaternion Entity::NormalGetNum(void) {
|
||||||
q = norm->NormalGetNum();
|
q = norm->NormalGetNum();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NORMAL_XFRMD:
|
case NORMAL_N_COPY:
|
||||||
q = numNormal;
|
q = numNormal;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NORMAL_N_ROT:
|
||||||
|
q.w = SS.GetParam(param[0])->val;
|
||||||
|
q.vx = SS.GetParam(param[1])->val;
|
||||||
|
q.vy = SS.GetParam(param[2])->val;
|
||||||
|
q.vz = SS.GetParam(param[3])->val;
|
||||||
|
q = q.Times(numNormal);
|
||||||
|
break;
|
||||||
|
|
||||||
default: oops();
|
default: oops();
|
||||||
}
|
}
|
||||||
return q;
|
return q;
|
||||||
|
@ -159,10 +175,13 @@ void Entity::NormalForceTo(Quaternion q) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NORMAL_IN_2D:
|
case NORMAL_IN_2D:
|
||||||
case NORMAL_XFRMD:
|
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:
|
||||||
|
break;
|
||||||
|
|
||||||
default: oops();
|
default: oops();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,13 +222,29 @@ ExprQuaternion Entity::NormalGetExprs(void) {
|
||||||
q = norm->NormalGetExprs();
|
q = norm->NormalGetExprs();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NORMAL_XFRMD:
|
case NORMAL_N_COPY:
|
||||||
q.w = Expr::FromConstant(numNormal.w);
|
q.w = Expr::FromConstant(numNormal.w);
|
||||||
q.vx = Expr::FromConstant(numNormal.vx);
|
q.vx = Expr::FromConstant(numNormal.vx);
|
||||||
q.vy = Expr::FromConstant(numNormal.vy);
|
q.vy = Expr::FromConstant(numNormal.vy);
|
||||||
q.vz = Expr::FromConstant(numNormal.vz);
|
q.vz = Expr::FromConstant(numNormal.vz);
|
||||||
break;
|
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);
|
||||||
|
|
||||||
|
q.w = Expr::FromParam(param[0]);
|
||||||
|
q.vx = Expr::FromParam(param[1]);
|
||||||
|
q.vy = Expr::FromParam(param[2]);
|
||||||
|
q.vz = Expr::FromParam(param[3]);
|
||||||
|
|
||||||
|
q = q.Times(orig);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: oops();
|
default: oops();
|
||||||
}
|
}
|
||||||
return q;
|
return q;
|
||||||
|
@ -235,7 +270,7 @@ void Entity::PointForceTo(Vector p) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case POINT_XFRMD: {
|
case POINT_N_TRANS: {
|
||||||
Vector trans = p.Minus(numPoint);
|
Vector trans = p.Minus(numPoint);
|
||||||
SS.GetParam(param[0])->val = trans.x;
|
SS.GetParam(param[0])->val = trans.x;
|
||||||
SS.GetParam(param[1])->val = trans.y;
|
SS.GetParam(param[1])->val = trans.y;
|
||||||
|
@ -243,6 +278,17 @@ void Entity::PointForceTo(Vector p) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case POINT_N_ROT_TRANS: {
|
||||||
|
// Force only the translation; leave the rotation unchanged. But
|
||||||
|
// remember that we're working with respect to the rotated
|
||||||
|
// point.
|
||||||
|
Vector trans = p.Minus(PointGetQuaternion().Rotate(numPoint));
|
||||||
|
SS.GetParam(param[0])->val = trans.x;
|
||||||
|
SS.GetParam(param[1])->val = trans.y;
|
||||||
|
SS.GetParam(param[2])->val = trans.z;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: oops();
|
default: oops();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,13 +312,24 @@ Vector Entity::PointGetNum(void) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case POINT_XFRMD: {
|
case POINT_N_TRANS: {
|
||||||
p = numPoint;
|
p = numPoint;
|
||||||
p.x += SS.GetParam(param[0])->val;
|
p.x += SS.GetParam(param[0])->val;
|
||||||
p.y += SS.GetParam(param[1])->val;
|
p.y += SS.GetParam(param[1])->val;
|
||||||
p.z += SS.GetParam(param[2])->val;
|
p.z += SS.GetParam(param[2])->val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case POINT_N_ROT_TRANS: {
|
||||||
|
Vector offset = Vector::MakeFrom(
|
||||||
|
SS.GetParam(param[0])->val,
|
||||||
|
SS.GetParam(param[1])->val,
|
||||||
|
SS.GetParam(param[2])->val);
|
||||||
|
Quaternion q = PointGetQuaternion();
|
||||||
|
p = q.Rotate(numPoint);
|
||||||
|
p = p.Plus(offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: oops();
|
default: oops();
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
|
@ -296,7 +353,7 @@ ExprVector Entity::PointGetExprs(void) {
|
||||||
r = r.Plus(v.ScaledBy(Expr::FromParam(param[1])));
|
r = r.Plus(v.ScaledBy(Expr::FromParam(param[1])));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case POINT_XFRMD: {
|
case POINT_N_TRANS: {
|
||||||
ExprVector orig = {
|
ExprVector orig = {
|
||||||
Expr::FromConstant(numPoint.x),
|
Expr::FromConstant(numPoint.x),
|
||||||
Expr::FromConstant(numPoint.y),
|
Expr::FromConstant(numPoint.y),
|
||||||
|
@ -308,6 +365,24 @@ ExprVector Entity::PointGetExprs(void) {
|
||||||
r = orig.Plus(trans);
|
r = orig.Plus(trans);
|
||||||
break;
|
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]) };
|
||||||
|
ExprQuaternion q = {
|
||||||
|
Expr::FromParam(param[3]),
|
||||||
|
Expr::FromParam(param[4]),
|
||||||
|
Expr::FromParam(param[5]),
|
||||||
|
Expr::FromParam(param[6]) };
|
||||||
|
orig = q.Rotate(orig);
|
||||||
|
r = orig.Plus(trans);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: oops();
|
default: oops();
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
|
@ -335,6 +410,26 @@ void Entity::PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Entity::PointForceQuaternionTo(Quaternion q) {
|
||||||
|
if(type != POINT_N_ROT_TRANS) oops();
|
||||||
|
|
||||||
|
SS.GetParam(param[3])->val = q.w;
|
||||||
|
SS.GetParam(param[4])->val = q.vx;
|
||||||
|
SS.GetParam(param[5])->val = q.vy;
|
||||||
|
SS.GetParam(param[6])->val = q.vz;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
|
void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
|
||||||
if(dogd.drawing) {
|
if(dogd.drawing) {
|
||||||
// This fudge guarantees that the line will get drawn in front of
|
// This fudge guarantees that the line will get drawn in front of
|
||||||
|
@ -403,7 +498,8 @@ void Entity::DrawOrGetDistance(int order) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case POINT_XFRMD:
|
case POINT_N_TRANS:
|
||||||
|
case POINT_N_ROT_TRANS:
|
||||||
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;
|
||||||
|
@ -443,9 +539,10 @@ void Entity::DrawOrGetDistance(int order) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case NORMAL_N_COPY:
|
||||||
|
case NORMAL_N_ROT:
|
||||||
case NORMAL_IN_3D:
|
case NORMAL_IN_3D:
|
||||||
case NORMAL_IN_2D:
|
case NORMAL_IN_2D: {
|
||||||
case NORMAL_XFRMD: {
|
|
||||||
if(order >= 0 && order != 2) break;
|
if(order >= 0 && order != 2) break;
|
||||||
if(!SS.GW.showNormals) break;
|
if(!SS.GW.showNormals) break;
|
||||||
|
|
||||||
|
@ -474,7 +571,7 @@ void Entity::DrawOrGetDistance(int order) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case DISTANCE:
|
case DISTANCE:
|
||||||
case DISTANCE_XFRMD:
|
case DISTANCE_N_COPY:
|
||||||
// These are used only as data structures, nothing to display.
|
// These are used only as data structures, nothing to display.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
24
expr.cpp
24
expr.cpp
|
@ -125,6 +125,29 @@ ExprVector ExprQuaternion::RotationN(void) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExprVector ExprQuaternion::Rotate(ExprVector p) {
|
||||||
|
// Express the point in the new basis
|
||||||
|
return (RotationU().ScaledBy(p.x)).Plus(
|
||||||
|
RotationV().ScaledBy(p.y)).Plus(
|
||||||
|
RotationN().ScaledBy(p.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprQuaternion ExprQuaternion::Times(ExprQuaternion b) {
|
||||||
|
Expr *sa = w, *sb = b.w;
|
||||||
|
ExprVector va = { vx, vy, vz };
|
||||||
|
ExprVector vb = { b.vx, b.vy, b.vz };
|
||||||
|
|
||||||
|
ExprQuaternion r;
|
||||||
|
r.w = (sa->Times(sb))->Minus(va.Dot(vb));
|
||||||
|
ExprVector vr = vb.ScaledBy(sa).Plus(
|
||||||
|
va.ScaledBy(sb).Plus(
|
||||||
|
va.Cross(vb)));
|
||||||
|
r.vx = vr.x;
|
||||||
|
r.vy = vr.y;
|
||||||
|
r.vz = vr.z;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
Expr *ExprQuaternion::Magnitude(void) {
|
Expr *ExprQuaternion::Magnitude(void) {
|
||||||
return ((w ->Square())->Plus(
|
return ((w ->Square())->Plus(
|
||||||
(vx->Square())->Plus(
|
(vx->Square())->Plus(
|
||||||
|
@ -132,6 +155,7 @@ Expr *ExprQuaternion::Magnitude(void) {
|
||||||
(vz->Square())))))->Sqrt();
|
(vz->Square())))))->Sqrt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr *Expr::FromParam(hParam p) {
|
Expr *Expr::FromParam(hParam p) {
|
||||||
Expr *r = AllocExpr();
|
Expr *r = AllocExpr();
|
||||||
r->op = PARAM;
|
r->op = PARAM;
|
||||||
|
|
3
expr.h
3
expr.h
|
@ -144,6 +144,9 @@ public:
|
||||||
ExprVector RotationV(void);
|
ExprVector RotationV(void);
|
||||||
ExprVector RotationN(void);
|
ExprVector RotationN(void);
|
||||||
|
|
||||||
|
ExprVector Rotate(ExprVector p);
|
||||||
|
ExprQuaternion Times(ExprQuaternion b);
|
||||||
|
|
||||||
Expr *Magnitude(void);
|
Expr *Magnitude(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
9
file.cpp
9
file.cpp
|
@ -72,6 +72,9 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
|
||||||
{ 'e', "Entity.param[1].v", 'x', &(SS.sv.e.param[1].v) },
|
{ 'e', "Entity.param[1].v", 'x', &(SS.sv.e.param[1].v) },
|
||||||
{ 'e', "Entity.param[2].v", 'x', &(SS.sv.e.param[2].v) },
|
{ 'e', "Entity.param[2].v", 'x', &(SS.sv.e.param[2].v) },
|
||||||
{ 'e', "Entity.param[3].v", 'x', &(SS.sv.e.param[3].v) },
|
{ 'e', "Entity.param[3].v", 'x', &(SS.sv.e.param[3].v) },
|
||||||
|
{ 'e', "Entity.param[4].v", 'x', &(SS.sv.e.param[4].v) },
|
||||||
|
{ 'e', "Entity.param[5].v", 'x', &(SS.sv.e.param[5].v) },
|
||||||
|
{ 'e', "Entity.param[6].v", 'x', &(SS.sv.e.param[6].v) },
|
||||||
{ 'e', "Entity.point[0].v", 'x', &(SS.sv.e.point[0].v) },
|
{ 'e', "Entity.point[0].v", 'x', &(SS.sv.e.point[0].v) },
|
||||||
{ 'e', "Entity.point[1].v", 'x', &(SS.sv.e.point[1].v) },
|
{ 'e', "Entity.point[1].v", 'x', &(SS.sv.e.point[1].v) },
|
||||||
{ 'e', "Entity.point[2].v", 'x', &(SS.sv.e.point[2].v) },
|
{ 'e', "Entity.point[2].v", 'x', &(SS.sv.e.point[2].v) },
|
||||||
|
@ -205,7 +208,11 @@ void SolveSpace::LoadUsingTable(char *key, char *val) {
|
||||||
case 'M': {
|
case 'M': {
|
||||||
IdList<EntityMap,EntityId> *m =
|
IdList<EntityMap,EntityId> *m =
|
||||||
(IdList<EntityMap,EntityId> *)p;
|
(IdList<EntityMap,EntityId> *)p;
|
||||||
m->Clear();
|
// Don't clear this list! When the group gets added, it
|
||||||
|
// makes a shallow copy, so that would result in us
|
||||||
|
// freeing memory that we want to keep around. Just
|
||||||
|
// zero it out so that new memory is allocated.
|
||||||
|
memset(m, 0, sizeof(*m));
|
||||||
for(;;) {
|
for(;;) {
|
||||||
EntityMap em;
|
EntityMap em;
|
||||||
char line2[1024];
|
char line2[1024];
|
||||||
|
|
|
@ -42,8 +42,8 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
||||||
{ 1, "New &Drawing in 3d\tShift+Ctrl+D", MNU_GROUP_3D, 'D'|S|C, mGrp },
|
{ 1, "New &Drawing in 3d\tShift+Ctrl+D", MNU_GROUP_3D, 'D'|S|C, mGrp },
|
||||||
{ 1, "New Drawing in Workplane\tShift+Ctrl+W",MNU_GROUP_WRKPL, 'W'|S|C, mGrp },
|
{ 1, "New Drawing in Workplane\tShift+Ctrl+W",MNU_GROUP_WRKPL, 'W'|S|C, mGrp },
|
||||||
{ 1, NULL, 0, NULL },
|
{ 1, NULL, 0, NULL },
|
||||||
{ 1, "New Step and Repeat &Translating", 0, 0, NULL },
|
{ 1, "New Step &Translating\tShift+Ctrl+R", MNU_GROUP_TRANS, 'T'|S|C,mGrp },
|
||||||
{ 1, "New Step and Repeat &Rotating", 0, 0, NULL },
|
{ 1, "New Step &Rotating\tShift+Ctrl+T", MNU_GROUP_ROT, 'R'|S|C,mGrp },
|
||||||
{ 1, NULL, 0, 0, NULL },
|
{ 1, NULL, 0, 0, NULL },
|
||||||
{ 1, "New Extrusion\tShift+Ctrl+X", MNU_GROUP_EXTRUDE, 'X'|S|C,mGrp },
|
{ 1, "New Extrusion\tShift+Ctrl+X", MNU_GROUP_EXTRUDE, 'X'|S|C,mGrp },
|
||||||
{ 1, NULL, 0, 0, NULL },
|
{ 1, NULL, 0, 0, NULL },
|
||||||
|
@ -494,10 +494,53 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
||||||
HitTestMakeSelection(mp);
|
HitTestMakeSelection(mp);
|
||||||
// and fall through
|
// and fall through
|
||||||
case DRAGGING_NEW_POINT:
|
case DRAGGING_NEW_POINT:
|
||||||
case DRAGGING_POINT:
|
case DRAGGING_POINT: {
|
||||||
UpdateDraggedPoint(pending.point, x, y);
|
Entity *p = SS.GetEntity(pending.point);
|
||||||
break;
|
if((p->type == Entity::POINT_N_ROT_TRANS) &&
|
||||||
|
(shiftDown || ctrlDown))
|
||||||
|
{
|
||||||
|
// These points also come with a rotation, which the user can
|
||||||
|
// edit by pressing shift or control.
|
||||||
|
Quaternion q = p->PointGetQuaternion();
|
||||||
|
Vector p3 = p->PointGetNum();
|
||||||
|
Point2d p2 = ProjectPoint(p3);
|
||||||
|
|
||||||
|
Vector u = q.RotationU(), v = q.RotationV();
|
||||||
|
if(ctrlDown) {
|
||||||
|
double d = mp.DistanceTo(p2);
|
||||||
|
if(d < 25) {
|
||||||
|
// Don't start dragging the position about the normal
|
||||||
|
// until we're a little ways out, to get a reasonable
|
||||||
|
// reference pos
|
||||||
|
orig.mouse = mp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
double theta = atan2(orig.mouse.y-p2.y, orig.mouse.x-p2.x);
|
||||||
|
theta -= atan2(y-p2.y, x-p2.x);
|
||||||
|
|
||||||
|
Vector gn = projRight.Cross(projUp);
|
||||||
|
u = u.RotatedAbout(gn, -theta);
|
||||||
|
v = v.RotatedAbout(gn, -theta);
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
v = v.RotatedAbout(orig.projUp, -s*dx);
|
||||||
|
v = v.RotatedAbout(orig.projRight, s*dy);
|
||||||
|
}
|
||||||
|
q = Quaternion::MakeFrom(u, v);
|
||||||
|
p->PointForceQuaternionTo(q);
|
||||||
|
// Let's rotate about the selected point; so fix up the
|
||||||
|
// translation so that that point didn't move.
|
||||||
|
p->PointForceTo(p3);
|
||||||
|
orig.mouse = mp;
|
||||||
|
} else {
|
||||||
|
UpdateDraggedPoint(pending.point, x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DRAGGING_NEW_CUBIC_POINT: {
|
case DRAGGING_NEW_CUBIC_POINT: {
|
||||||
UpdateDraggedPoint(pending.point, x, y);
|
UpdateDraggedPoint(pending.point, x, y);
|
||||||
HitTestMakeSelection(mp);
|
HitTestMakeSelection(mp);
|
||||||
|
|
99
sketch.cpp
99
sketch.cpp
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
const hEntity Entity::FREE_IN_3D = { 0 };
|
const hEntity Entity::FREE_IN_3D = { 0 };
|
||||||
const hEntity Entity::NO_ENTITY = { 0 };
|
const hEntity Entity::NO_ENTITY = { 0 };
|
||||||
|
const hParam Param::NO_PARAM = { 0 };
|
||||||
|
#define NO_PARAM (Param::NO_PARAM)
|
||||||
|
|
||||||
const hGroup Group::HGROUP_REFERENCES = { 1 };
|
const hGroup Group::HGROUP_REFERENCES = { 1 };
|
||||||
const hRequest Request::HREQUEST_REFERENCE_XY = { 1 };
|
const hRequest Request::HREQUEST_REFERENCE_XY = { 1 };
|
||||||
|
@ -25,15 +27,21 @@ void Group::MenuGroup(int id) {
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case GraphicsWindow::MNU_GROUP_3D:
|
case GraphicsWindow::MNU_GROUP_3D:
|
||||||
g.type = DRAWING;
|
g.type = DRAWING;
|
||||||
g.name.strcpy("drawing");
|
g.name.strcpy("draw-in-3d");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GraphicsWindow::MNU_GROUP_EXTRUDE:
|
case GraphicsWindow::MNU_GROUP_EXTRUDE:
|
||||||
g.type = EXTRUDE;
|
g.type = EXTRUDE;
|
||||||
g.opA.v = 2;
|
g.opA = SS.GW.activeGroup;
|
||||||
g.name.strcpy("extrude");
|
g.name.strcpy("extrude");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GraphicsWindow::MNU_GROUP_ROT:
|
||||||
|
g.type = ROTATE;
|
||||||
|
g.opA = SS.GW.activeGroup;
|
||||||
|
g.name.strcpy("rotate");
|
||||||
|
break;
|
||||||
|
|
||||||
default: oops();
|
default: oops();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +79,32 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
|
||||||
Entity *e = &(entity->elem[i]);
|
Entity *e = &(entity->elem[i]);
|
||||||
if(e->group.v != opA.v) continue;
|
if(e->group.v != opA.v) continue;
|
||||||
|
|
||||||
CopyEntity(e->h, 0, h.param(0), h.param(1), h.param(2), true);
|
CopyEntity(e->h, 0,
|
||||||
|
h.param(0), h.param(1), h.param(2),
|
||||||
|
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
|
||||||
|
true, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROTATE:
|
||||||
|
// The translation vector
|
||||||
|
AddParam(param, h.param(0), 100);
|
||||||
|
AddParam(param, h.param(1), 100);
|
||||||
|
AddParam(param, h.param(2), 100);
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
for(i = 0; i < entity->n; i++) {
|
||||||
|
Entity *e = &(entity->elem[i]);
|
||||||
|
if(e->group.v != opA.v) continue;
|
||||||
|
|
||||||
|
CopyEntity(e->h, 0,
|
||||||
|
h.param(0), h.param(1), h.param(2),
|
||||||
|
h.param(3), h.param(4), h.param(5), h.param(6),
|
||||||
|
false, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -79,6 +112,21 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Group::GenerateEquations(IdList<Equation,hEquation> *l) {
|
||||||
|
if(type == ROTATE) {
|
||||||
|
// 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)) };
|
||||||
|
Equation eq;
|
||||||
|
eq.e = (q.Magnitude())->Minus(Expr::FromConstant(1));
|
||||||
|
eq.h = h.equation(0);
|
||||||
|
l->Add(&eq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hEntity Group::Remap(hEntity in, int copyNumber) {
|
hEntity Group::Remap(hEntity in, int copyNumber) {
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < remap.n; i++) {
|
for(i = 0; i < remap.n; i++) {
|
||||||
|
@ -97,7 +145,8 @@ hEntity Group::Remap(hEntity in, int copyNumber) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
|
void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
|
||||||
bool isExtrusion)
|
hParam qw, hParam qvx, hParam qvy, hParam qvz,
|
||||||
|
bool transOnly, bool isExtrusion)
|
||||||
{
|
{
|
||||||
Entity *ep = SS.GetEntity(in);
|
Entity *ep = SS.GetEntity(in);
|
||||||
|
|
||||||
|
@ -130,13 +179,27 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
|
||||||
en.distance = Remap(ep->distance, a);
|
en.distance = Remap(ep->distance, a);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Entity::POINT_N_TRANS:
|
||||||
|
case Entity::POINT_N_ROT_TRANS:
|
||||||
case Entity::POINT_IN_3D:
|
case Entity::POINT_IN_3D:
|
||||||
case Entity::POINT_IN_2D:
|
case Entity::POINT_IN_2D:
|
||||||
en.type = Entity::POINT_XFRMD;
|
if(transOnly) {
|
||||||
en.param[0] = dx;
|
en.type = Entity::POINT_N_TRANS;
|
||||||
en.param[1] = dy;
|
en.param[0] = dx;
|
||||||
en.param[2] = dz;
|
en.param[1] = dy;
|
||||||
en.numPoint = ep->PointGetNum();
|
en.param[2] = dz;
|
||||||
|
en.numPoint = ep->PointGetNum();
|
||||||
|
} else {
|
||||||
|
en.type = Entity::POINT_N_ROT_TRANS;
|
||||||
|
en.param[0] = dx;
|
||||||
|
en.param[1] = dy;
|
||||||
|
en.param[2] = dz;
|
||||||
|
en.param[3] = qw;
|
||||||
|
en.param[4] = qvx;
|
||||||
|
en.param[5] = qvy;
|
||||||
|
en.param[6] = qvz;
|
||||||
|
en.numPoint = ep->PointGetNum();
|
||||||
|
}
|
||||||
|
|
||||||
if(isExtrusion) {
|
if(isExtrusion) {
|
||||||
if(a != 0) oops();
|
if(a != 0) oops();
|
||||||
|
@ -153,15 +216,27 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Entity::NORMAL_N_COPY:
|
||||||
|
case Entity::NORMAL_N_ROT:
|
||||||
case Entity::NORMAL_IN_3D:
|
case Entity::NORMAL_IN_3D:
|
||||||
case Entity::NORMAL_IN_2D:
|
case Entity::NORMAL_IN_2D:
|
||||||
en.type = Entity::NORMAL_XFRMD;
|
if(transOnly) {
|
||||||
en.numNormal = ep->NormalGetNum();
|
en.type = Entity::NORMAL_N_COPY;
|
||||||
|
en.numNormal = ep->NormalGetNum();
|
||||||
|
} else {
|
||||||
|
en.type = Entity::NORMAL_N_ROT;
|
||||||
|
en.numNormal = ep->NormalGetNum();
|
||||||
|
en.param[0] = qw;
|
||||||
|
en.param[1] = qvx;
|
||||||
|
en.param[2] = qvy;
|
||||||
|
en.param[3] = qvz;
|
||||||
|
}
|
||||||
en.point[0] = Remap(ep->point[0], a);
|
en.point[0] = Remap(ep->point[0], a);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Entity::DISTANCE_N_COPY:
|
||||||
case Entity::DISTANCE:
|
case Entity::DISTANCE:
|
||||||
en.type = Entity::DISTANCE_XFRMD;
|
en.type = Entity::DISTANCE_N_COPY;
|
||||||
en.numDistance = ep->DistanceGetNum();
|
en.numDistance = ep->DistanceGetNum();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
29
sketch.h
29
sketch.h
|
@ -22,6 +22,7 @@ public:
|
||||||
|
|
||||||
inline hEntity entity(int i);
|
inline hEntity entity(int i);
|
||||||
inline hParam param(int i);
|
inline hParam param(int i);
|
||||||
|
inline hEquation equation(int i);
|
||||||
};
|
};
|
||||||
class hRequest {
|
class hRequest {
|
||||||
public:
|
public:
|
||||||
|
@ -77,6 +78,8 @@ public:
|
||||||
|
|
||||||
static const int DRAWING = 5000;
|
static const int DRAWING = 5000;
|
||||||
static const int EXTRUDE = 5010;
|
static const int EXTRUDE = 5010;
|
||||||
|
static const int ROTATE = 5020;
|
||||||
|
static const int TRANSLATE = 5030;
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
int solveOrder;
|
int solveOrder;
|
||||||
|
@ -105,7 +108,10 @@ public:
|
||||||
IdList<EntityMap,EntityId> remap;
|
IdList<EntityMap,EntityId> remap;
|
||||||
hEntity Remap(hEntity in, int copyNumber);
|
hEntity Remap(hEntity in, int copyNumber);
|
||||||
void CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
|
void CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
|
||||||
bool isExtrusion);
|
hParam qw, hParam qvx, hParam qvy, hParam qvz,
|
||||||
|
bool transOnly, bool isExtrusion);
|
||||||
|
|
||||||
|
void GenerateEquations(IdList<Equation,hEquation> *l);
|
||||||
|
|
||||||
void MakePolygons(void);
|
void MakePolygons(void);
|
||||||
void Draw(void);
|
void Draw(void);
|
||||||
|
@ -158,7 +164,8 @@ public:
|
||||||
|
|
||||||
static const int POINT_IN_3D = 2000;
|
static const int POINT_IN_3D = 2000;
|
||||||
static const int POINT_IN_2D = 2001;
|
static const int POINT_IN_2D = 2001;
|
||||||
static const int POINT_XFRMD = 2010;
|
static const int POINT_N_TRANS = 2010;
|
||||||
|
static const int POINT_N_ROT_TRANS = 2011;
|
||||||
|
|
||||||
static const int NORMAL_IN_3D = 3000;
|
static const int NORMAL_IN_3D = 3000;
|
||||||
static const int NORMAL_IN_2D = 3001;
|
static const int NORMAL_IN_2D = 3001;
|
||||||
|
@ -168,10 +175,11 @@ public:
|
||||||
// u = (sin theta)*uw - (cos theta)*vw
|
// u = (sin theta)*uw - (cos theta)*vw
|
||||||
// v = nw
|
// v = nw
|
||||||
static const int NORMAL_IN_PLANE = 3002;
|
static const int NORMAL_IN_PLANE = 3002;
|
||||||
static const int NORMAL_XFRMD = 3010;
|
static const int NORMAL_N_COPY = 3010;
|
||||||
|
static const int NORMAL_N_ROT = 3011;
|
||||||
|
|
||||||
static const int DISTANCE = 4000;
|
static const int DISTANCE = 4000;
|
||||||
static const int DISTANCE_XFRMD = 4001;
|
static const int DISTANCE_N_COPY = 4001;
|
||||||
|
|
||||||
static const int WORKPLANE = 10000;
|
static const int WORKPLANE = 10000;
|
||||||
static const int LINE_SEGMENT = 11000;
|
static const int LINE_SEGMENT = 11000;
|
||||||
|
@ -187,7 +195,7 @@ public:
|
||||||
hEntity distance;
|
hEntity distance;
|
||||||
// The only types that have their own params are points, normals,
|
// The only types that have their own params are points, normals,
|
||||||
// and directions.
|
// and directions.
|
||||||
hParam param[4];
|
hParam param[7];
|
||||||
|
|
||||||
// Transformed points/normals/distances have their numerical value.
|
// Transformed points/normals/distances have their numerical value.
|
||||||
Vector numPoint;
|
Vector numPoint;
|
||||||
|
@ -228,6 +236,9 @@ public:
|
||||||
void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v);
|
void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v);
|
||||||
void PointForceTo(Vector v);
|
void PointForceTo(Vector v);
|
||||||
bool PointIsFromReferences(void);
|
bool PointIsFromReferences(void);
|
||||||
|
// These apply only the POINT_N_ROT_TRANS, which has an assoc rotation
|
||||||
|
Quaternion PointGetQuaternion(void);
|
||||||
|
void PointForceQuaternionTo(Quaternion q);
|
||||||
|
|
||||||
bool IsNormal(void);
|
bool IsNormal(void);
|
||||||
// Applies for any of the normal types
|
// Applies for any of the normal types
|
||||||
|
@ -275,6 +286,8 @@ public:
|
||||||
|
|
||||||
// Used only in the solver
|
// Used only in the solver
|
||||||
hParam substd;
|
hParam substd;
|
||||||
|
|
||||||
|
static const hParam NO_PARAM;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,7 +295,7 @@ class hConstraint {
|
||||||
public:
|
public:
|
||||||
DWORD v;
|
DWORD v;
|
||||||
|
|
||||||
hEquation equation(int i);
|
inline hEquation equation(int i);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Constraint {
|
class Constraint {
|
||||||
|
@ -380,6 +393,8 @@ inline hEntity hGroup::entity(int i)
|
||||||
{ hEntity r; r.v = 0x80000000 | (v << 16) | i; return r; }
|
{ hEntity r; r.v = 0x80000000 | (v << 16) | i; return r; }
|
||||||
inline hParam hGroup::param(int i)
|
inline hParam hGroup::param(int i)
|
||||||
{ hParam r; r.v = 0x80000000 | (v << 16) | i; return r; }
|
{ hParam r; r.v = 0x80000000 | (v << 16) | i; return r; }
|
||||||
|
inline hEquation hGroup::equation(int i)
|
||||||
|
{ if(i != 0) oops(); hEquation r; r.v = v | 0x80000000; return r; }
|
||||||
|
|
||||||
inline bool hRequest::IsFromReferences(void) {
|
inline bool hRequest::IsFromReferences(void) {
|
||||||
if(v == Request::HREQUEST_REFERENCE_XY.v) return true;
|
if(v == Request::HREQUEST_REFERENCE_XY.v) return true;
|
||||||
|
@ -397,7 +412,7 @@ inline bool hEntity::isFromRequest(void)
|
||||||
inline hRequest hEntity::request(void)
|
inline hRequest hEntity::request(void)
|
||||||
{ hRequest r; r.v = (v >> 16); return r; }
|
{ hRequest r; r.v = (v >> 16); return r; }
|
||||||
inline hEquation hEntity::equation(int i)
|
inline hEquation hEntity::equation(int i)
|
||||||
{ if(i != 0) oops(); hEquation r; r.v = v | 0x80000000; return r; }
|
{ if(i != 0) oops(); hEquation r; r.v = v | 0x40000000; return r; }
|
||||||
|
|
||||||
inline hRequest hParam::request(void)
|
inline hRequest hParam::request(void)
|
||||||
{ hRequest r; r.v = (v >> 16); return r; }
|
{ hRequest r; r.v = (v >> 16); return r; }
|
||||||
|
|
|
@ -134,6 +134,8 @@ bool SolveSpace::SolveGroup(hGroup hg) {
|
||||||
|
|
||||||
e->GenerateEquations(&(sys.eq));
|
e->GenerateEquations(&(sys.eq));
|
||||||
}
|
}
|
||||||
|
// And from the groups themselves
|
||||||
|
g->GenerateEquations(&(sys.eq));
|
||||||
|
|
||||||
bool r = sys.Solve();
|
bool r = sys.Solve();
|
||||||
FreeAllTemporary();
|
FreeAllTemporary();
|
||||||
|
|
|
@ -56,6 +56,7 @@ bool System::IsDragged(hParam p) {
|
||||||
Entity *pt = SS.entity.FindByIdNoOops(SS.GW.pending.point);
|
Entity *pt = SS.entity.FindByIdNoOops(SS.GW.pending.point);
|
||||||
if(pt) {
|
if(pt) {
|
||||||
switch(pt->type) {
|
switch(pt->type) {
|
||||||
|
case Entity::POINT_N_TRANS:
|
||||||
case Entity::POINT_IN_3D:
|
case Entity::POINT_IN_3D:
|
||||||
if(p.v == (pt->param[0]).v) return true;
|
if(p.v == (pt->param[0]).v) return true;
|
||||||
if(p.v == (pt->param[1]).v) return true;
|
if(p.v == (pt->param[1]).v) return true;
|
||||||
|
@ -63,7 +64,6 @@ bool System::IsDragged(hParam p) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Entity::POINT_IN_2D:
|
case Entity::POINT_IN_2D:
|
||||||
case Entity::POINT_XFRMD:
|
|
||||||
if(p.v == (pt->param[0]).v) return true;
|
if(p.v == (pt->param[0]).v) return true;
|
||||||
if(p.v == (pt->param[1]).v) return true;
|
if(p.v == (pt->param[1]).v) return true;
|
||||||
break;
|
break;
|
||||||
|
@ -399,7 +399,7 @@ bool System::Solve(void) {
|
||||||
|
|
||||||
SortBySensitivity();
|
SortBySensitivity();
|
||||||
|
|
||||||
/* dbp("write/eval jacboian=%d", GetMilliseconds() - in);
|
/*
|
||||||
for(i = 0; i < mat.m; i++) {
|
for(i = 0; i < mat.m; i++) {
|
||||||
dbp("function %d: %s", i, mat.B.sym[i]->Print());
|
dbp("function %d: %s", i, mat.B.sym[i]->Print());
|
||||||
}
|
}
|
||||||
|
|
2
ui.h
2
ui.h
|
@ -112,6 +112,8 @@ public:
|
||||||
MNU_GROUP_3D,
|
MNU_GROUP_3D,
|
||||||
MNU_GROUP_WRKPL,
|
MNU_GROUP_WRKPL,
|
||||||
MNU_GROUP_EXTRUDE,
|
MNU_GROUP_EXTRUDE,
|
||||||
|
MNU_GROUP_ROT,
|
||||||
|
MNU_GROUP_TRANS,
|
||||||
// Constrain
|
// Constrain
|
||||||
MNU_DISTANCE_DIA,
|
MNU_DISTANCE_DIA,
|
||||||
MNU_EQUAL,
|
MNU_EQUAL,
|
||||||
|
|
23
util.cpp
23
util.cpp
|
@ -125,6 +125,29 @@ Vector Quaternion::RotationN(void) {
|
||||||
return RotationU().Cross(RotationV());
|
return RotationU().Cross(RotationV());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector Quaternion::Rotate(Vector p) {
|
||||||
|
// Express the point in the new basis
|
||||||
|
return (RotationU().ScaledBy(p.x)).Plus(
|
||||||
|
RotationV().ScaledBy(p.y)).Plus(
|
||||||
|
RotationN().ScaledBy(p.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion Quaternion::Times(Quaternion b) {
|
||||||
|
double sa = w, sb = b.w;
|
||||||
|
Vector va = { vx, vy, vz };
|
||||||
|
Vector vb = { b.vx, b.vy, b.vz };
|
||||||
|
|
||||||
|
Quaternion r;
|
||||||
|
r.w = sa*sb - va.Dot(vb);
|
||||||
|
Vector vr = vb.ScaledBy(sa).Plus(
|
||||||
|
va.ScaledBy(sb).Plus(
|
||||||
|
va.Cross(vb)));
|
||||||
|
r.vx = vr.x;
|
||||||
|
r.vy = vr.y;
|
||||||
|
r.vz = vr.z;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Vector Vector::MakeFrom(double x, double y, double z) {
|
Vector Vector::MakeFrom(double x, double y, double z) {
|
||||||
Vector v;
|
Vector v;
|
||||||
|
|
Loading…
Reference in New Issue