A big change, to add a concept of normals. These are "oriented
vectors", represented by unit quaternions. This permits me to add circles, where the normal defines the plane of the circle. Still many things painful. The interface for editing normals is not so intuitive, and it's not yet clear how I would e.g. export a circle entity and recreate it properly, since that entity has a param not associated with a normal or point. And the transformed points/normals do not yet support rotations. That will be necessary soon. [git-p4: depot-paths = "//depot/solvespace/": change = 1705]
This commit is contained in:
parent
01885736e6
commit
853c6cb59c
|
@ -49,8 +49,8 @@ void Constraint::MenuConstrain(int id) {
|
|||
return;
|
||||
}
|
||||
Vector n = SS.GW.projRight.Cross(SS.GW.projUp);
|
||||
Vector a = SS.GetEntity(c.ptA)->PointGetCoords();
|
||||
Vector b = SS.GetEntity(c.ptB)->PointGetCoords();
|
||||
Vector a = SS.GetEntity(c.ptA)->PointGetNum();
|
||||
Vector b = SS.GetEntity(c.ptB)->PointGetNum();
|
||||
|
||||
c.disp.offset = n.Cross(a.Minus(b)).WithMagnitude(50);
|
||||
c.exprA = Expr::FromString("0")->DeepCopyKeep();
|
||||
|
|
|
@ -41,8 +41,8 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
glxColor3d(1, 0.2, 1);
|
||||
switch(type) {
|
||||
case PT_PT_DISTANCE: {
|
||||
Vector ap = SS.GetEntity(ptA)->PointGetCoords();
|
||||
Vector bp = SS.GetEntity(ptB)->PointGetCoords();
|
||||
Vector ap = SS.GetEntity(ptA)->PointGetNum();
|
||||
Vector bp = SS.GetEntity(ptB)->PointGetNum();
|
||||
|
||||
Vector ref = ((ap.Plus(bp)).ScaledBy(0.5)).Plus(disp.offset);
|
||||
if(labelPos) *labelPos = ref;
|
||||
|
@ -74,8 +74,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
case POINTS_COINCIDENT: {
|
||||
if(!dogd.drawing) {
|
||||
for(int i = 0; i < 2; i++) {
|
||||
Vector p = SS.GetEntity(i == 0 ? ptA : ptB)->
|
||||
PointGetCoords();
|
||||
Vector p = SS.GetEntity(i == 0 ? ptA : ptB)-> PointGetNum();
|
||||
Point2d pp = SS.GW.ProjectPoint(p);
|
||||
// The point is selected within a radius of 7, from the
|
||||
// same center; so if the point is visible, then this
|
||||
|
@ -89,8 +88,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
Vector r = SS.GW.projRight.ScaledBy((a+1)/SS.GW.scale);
|
||||
Vector d = SS.GW.projUp.ScaledBy((2-a)/SS.GW.scale);
|
||||
for(int i = 0; i < 2; i++) {
|
||||
Vector p = SS.GetEntity(i == 0 ? ptA : ptB)->
|
||||
PointGetCoords();
|
||||
Vector p = SS.GetEntity(i == 0 ? ptA : ptB)-> PointGetNum();
|
||||
glxColor3d(0.4, 0, 0.4);
|
||||
glBegin(GL_QUADS);
|
||||
glxVertex3v(p.Plus (r).Plus (d));
|
||||
|
@ -107,7 +105,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
case PT_ON_LINE:
|
||||
case PT_IN_PLANE: {
|
||||
double s = 7;
|
||||
Vector p = SS.GetEntity(ptA)->PointGetCoords();
|
||||
Vector p = SS.GetEntity(ptA)->PointGetNum();
|
||||
Vector r = gr.WithMagnitude(s);
|
||||
Vector d = gu.WithMagnitude(s);
|
||||
LineDrawOrGetDistance(p.Plus (r).Plus (d), p.Plus (r).Minus(d));
|
||||
|
@ -120,8 +118,8 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
case EQUAL_LENGTH_LINES: {
|
||||
for(int i = 0; i < 2; i++) {
|
||||
Entity *e = SS.GetEntity(i == 0 ? entityA : entityB);
|
||||
Vector a = SS.GetEntity(e->point[0])->PointGetCoords();
|
||||
Vector b = SS.GetEntity(e->point[1])->PointGetCoords();
|
||||
Vector a = SS.GetEntity(e->point[0])->PointGetNum();
|
||||
Vector b = SS.GetEntity(e->point[1])->PointGetNum();
|
||||
Vector m = (a.ScaledBy(1.0/3)).Plus(b.ScaledBy(2.0/3));
|
||||
Vector ab = a.Minus(b);
|
||||
Vector n = (gn.Cross(ab)).WithMagnitude(10/SS.GW.scale);
|
||||
|
@ -132,8 +130,8 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
}
|
||||
|
||||
case SYMMETRIC: {
|
||||
Vector a = SS.GetEntity(ptA)->PointGetCoords();
|
||||
Vector b = SS.GetEntity(ptB)->PointGetCoords();
|
||||
Vector a = SS.GetEntity(ptA)->PointGetNum();
|
||||
Vector b = SS.GetEntity(ptB)->PointGetNum();
|
||||
Vector n = SS.GetEntity(entityA)->WorkplaneGetNormalVector();
|
||||
for(int i = 0; i < 2; i++) {
|
||||
Vector tail = (i == 0) ? a : b;
|
||||
|
@ -168,8 +166,8 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
}
|
||||
// For "at midpoint", this branch is always taken.
|
||||
Entity *e = SS.GetEntity(entityA);
|
||||
Vector a = SS.GetEntity(e->point[0])->PointGetCoords();
|
||||
Vector b = SS.GetEntity(e->point[1])->PointGetCoords();
|
||||
Vector a = SS.GetEntity(e->point[0])->PointGetNum();
|
||||
Vector b = SS.GetEntity(e->point[1])->PointGetNum();
|
||||
Vector m = (a.ScaledBy(0.5)).Plus(b.ScaledBy(0.5));
|
||||
Vector offset = (a.Minus(b)).Cross(n);
|
||||
offset = offset.WithMagnitude(13/SS.GW.scale);
|
||||
|
@ -191,8 +189,8 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
dogd.dmin = min(dogd.dmin, ref.DistanceTo(dogd.mp)-10);
|
||||
}
|
||||
} else {
|
||||
Vector a = SS.GetEntity(ptA)->PointGetCoords();
|
||||
Vector b = SS.GetEntity(ptB)->PointGetCoords();
|
||||
Vector a = SS.GetEntity(ptA)->PointGetNum();
|
||||
Vector b = SS.GetEntity(ptB)->PointGetNum();
|
||||
|
||||
Entity *w = SS.GetEntity(SS.GetEntity(ptA)->workplane);
|
||||
Vector cu, cv, cn;
|
||||
|
|
11
dsc.h
11
dsc.h
|
@ -9,14 +9,14 @@ class Vector;
|
|||
|
||||
class Quaternion {
|
||||
public:
|
||||
// a + bi + cj + dk
|
||||
double a, b, c, d;
|
||||
// a + (vx)*i + (vy)*j + (vz)*k
|
||||
double w, vx, vy, vz;
|
||||
|
||||
static Quaternion MakeFrom(double a, double b, double c, double d);
|
||||
static Quaternion MakeFrom(double w, double vx, double vy, double vz);
|
||||
static Quaternion MakeFrom(Vector u, Vector v);
|
||||
|
||||
Quaternion Plus(Quaternion y);
|
||||
Quaternion Minus(Quaternion y);
|
||||
Quaternion Plus(Quaternion b);
|
||||
Quaternion Minus(Quaternion b);
|
||||
Quaternion ScaledBy(double s);
|
||||
double Magnitude(void);
|
||||
Quaternion WithMagnitude(double s);
|
||||
|
@ -25,6 +25,7 @@ public:
|
|||
// second rows, where that matrix is generated by this quaternion
|
||||
Vector RotationU(void);
|
||||
Vector RotationV(void);
|
||||
Vector RotationN(void);
|
||||
};
|
||||
|
||||
class Vector {
|
||||
|
|
220
entity.cpp
220
entity.cpp
|
@ -6,11 +6,7 @@ char *Entity::DescriptionString(void) {
|
|||
}
|
||||
|
||||
void Entity::WorkplaneGetBasisVectors(Vector *u, Vector *v) {
|
||||
double q[4];
|
||||
for(int i = 0; i < 4; i++) {
|
||||
q[i] = SS.GetParam(param[i])->val;
|
||||
}
|
||||
Quaternion quat = Quaternion::MakeFrom(q[0], q[1], q[2], q[3]);
|
||||
Quaternion quat = SS.GetEntity(normal)->NormalGetNum();
|
||||
|
||||
*u = quat.RotationU();
|
||||
*v = quat.RotationV();
|
||||
|
@ -23,34 +19,10 @@ Vector Entity::WorkplaneGetNormalVector(void) {
|
|||
}
|
||||
|
||||
void Entity::WorkplaneGetBasisExprs(ExprVector *u, ExprVector *v) {
|
||||
Expr *a = Expr::FromParam(param[0]);
|
||||
Expr *b = Expr::FromParam(param[1]);
|
||||
Expr *c = Expr::FromParam(param[2]);
|
||||
Expr *d = Expr::FromParam(param[3]);
|
||||
ExprQuaternion q = SS.GetEntity(normal)->NormalGetExprs();
|
||||
|
||||
Expr *two = Expr::FromConstant(2);
|
||||
|
||||
u->x = a->Square();
|
||||
u->x = (u->x)->Plus(b->Square());
|
||||
u->x = (u->x)->Minus(c->Square());
|
||||
u->x = (u->x)->Minus(d->Square());
|
||||
|
||||
u->y = two->Times(a->Times(d));
|
||||
u->y = (u->y)->Plus(two->Times(b->Times(c)));
|
||||
|
||||
u->z = two->Times(b->Times(d));
|
||||
u->z = (u->z)->Minus(two->Times(a->Times(c)));
|
||||
|
||||
v->x = two->Times(b->Times(c));
|
||||
v->x = (v->x)->Minus(two->Times(a->Times(d)));
|
||||
|
||||
v->y = a->Square();
|
||||
v->y = (v->y)->Minus(b->Square());
|
||||
v->y = (v->y)->Plus(c->Square());
|
||||
v->y = (v->y)->Minus(d->Square());
|
||||
|
||||
v->z = two->Times(a->Times(b));
|
||||
v->z = (v->z)->Plus(two->Times(c->Times(d)));
|
||||
*u = q.RotationU();
|
||||
*v = q.RotationV();
|
||||
}
|
||||
|
||||
ExprVector Entity::WorkplaneGetOffsetExprs(void) {
|
||||
|
@ -98,22 +70,94 @@ void Entity::PlaneGetExprs(ExprVector *n, Expr **dn) {
|
|||
bool Entity::IsPoint(void) {
|
||||
switch(type) {
|
||||
case POINT_IN_3D:
|
||||
// A point by (x, y, z) in our base coordinate system. These
|
||||
// variables are given by param[0:2].
|
||||
case POINT_IN_2D:
|
||||
// A point by (u, v) in a workplane. These variables are given
|
||||
// by param[0:1], and the workplane is given in workplane.
|
||||
case POINT_XFRMD:
|
||||
// A point by a translation of another point. The original
|
||||
// point is given by point[0], and the three offsets in
|
||||
// param[0:2].
|
||||
return true;
|
||||
case POINT_XFRMD: return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Entity::IsNormal(void) {
|
||||
switch(type) {
|
||||
case NORMAL_IN_3D:
|
||||
case NORMAL_IN_2D:
|
||||
case NORMAL_XFRMD: return true;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
Quaternion Entity::NormalGetNum(void) {
|
||||
Quaternion q;
|
||||
switch(type) {
|
||||
case NORMAL_IN_3D:
|
||||
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;
|
||||
break;
|
||||
|
||||
case NORMAL_IN_2D: {
|
||||
Entity *wrkpl = SS.GetEntity(workplane);
|
||||
Entity *norm = SS.GetEntity(wrkpl->normal);
|
||||
q = norm->NormalGetNum();
|
||||
break;
|
||||
}
|
||||
case NORMAL_XFRMD:
|
||||
q = numNormal;
|
||||
break;
|
||||
|
||||
default: oops();
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
void Entity::NormalForceTo(Quaternion q) {
|
||||
switch(type) {
|
||||
case NORMAL_IN_3D:
|
||||
SS.GetParam(param[0])->val = q.w;
|
||||
SS.GetParam(param[1])->val = q.vx;
|
||||
SS.GetParam(param[2])->val = q.vy;
|
||||
SS.GetParam(param[3])->val = q.vz;
|
||||
break;
|
||||
|
||||
case NORMAL_IN_2D:
|
||||
case NORMAL_XFRMD:
|
||||
// There's absolutely nothing to do; these are locked.
|
||||
break;
|
||||
|
||||
default: oops();
|
||||
}
|
||||
}
|
||||
|
||||
ExprQuaternion Entity::NormalGetExprs(void) {
|
||||
ExprQuaternion q;
|
||||
switch(type) {
|
||||
case NORMAL_IN_3D:
|
||||
q.w = Expr::FromParam(param[0]);
|
||||
q.vx = Expr::FromParam(param[1]);
|
||||
q.vy = Expr::FromParam(param[2]);
|
||||
q.vz = Expr::FromParam(param[3]);
|
||||
break;
|
||||
|
||||
case NORMAL_IN_2D: {
|
||||
Entity *wrkpl = SS.GetEntity(workplane);
|
||||
Entity *norm = SS.GetEntity(wrkpl->normal);
|
||||
q = norm->NormalGetExprs();
|
||||
break;
|
||||
}
|
||||
case NORMAL_XFRMD:
|
||||
q.w = Expr::FromConstant(numNormal.w);
|
||||
q.vx = Expr::FromConstant(numNormal.vx);
|
||||
q.vy = Expr::FromConstant(numNormal.vy);
|
||||
q.vz = Expr::FromConstant(numNormal.vz);
|
||||
break;
|
||||
|
||||
default: oops();
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
bool Entity::PointIsFromReferences(void) {
|
||||
return h.request().IsFromReferences();
|
||||
}
|
||||
|
@ -136,8 +180,7 @@ void Entity::PointForceTo(Vector p) {
|
|||
}
|
||||
|
||||
case POINT_XFRMD: {
|
||||
Vector orig = SS.GetEntity(point[0])->PointGetCoords();
|
||||
Vector trans = p.Minus(orig);
|
||||
Vector trans = p.Minus(numPoint);
|
||||
SS.GetParam(param[0])->val = trans.x;
|
||||
SS.GetParam(param[1])->val = trans.y;
|
||||
SS.GetParam(param[2])->val = trans.z;
|
||||
|
@ -148,7 +191,7 @@ void Entity::PointForceTo(Vector p) {
|
|||
}
|
||||
}
|
||||
|
||||
Vector Entity::PointGetCoords(void) {
|
||||
Vector Entity::PointGetNum(void) {
|
||||
Vector p;
|
||||
switch(type) {
|
||||
case POINT_IN_3D:
|
||||
|
@ -167,7 +210,7 @@ Vector Entity::PointGetCoords(void) {
|
|||
}
|
||||
|
||||
case POINT_XFRMD: {
|
||||
p = SS.GetEntity(point[0])->PointGetCoords();
|
||||
p = numPoint;
|
||||
p.x += SS.GetParam(param[0])->val;
|
||||
p.y += SS.GetParam(param[1])->val;
|
||||
p.z += SS.GetParam(param[2])->val;
|
||||
|
@ -197,7 +240,10 @@ ExprVector Entity::PointGetExprs(void) {
|
|||
break;
|
||||
}
|
||||
case POINT_XFRMD: {
|
||||
ExprVector orig = SS.GetEntity(point[0])->PointGetExprs();
|
||||
ExprVector orig = {
|
||||
Expr::FromConstant(numPoint.x),
|
||||
Expr::FromConstant(numPoint.y),
|
||||
Expr::FromConstant(numPoint.z) };
|
||||
ExprVector trans;
|
||||
trans.x = Expr::FromParam(param[0]);
|
||||
trans.y = Expr::FromParam(param[1]);
|
||||
|
@ -307,13 +353,17 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
}
|
||||
}
|
||||
|
||||
Vector v = PointGetCoords();
|
||||
Vector v = PointGetNum();
|
||||
|
||||
if(dogd.drawing) {
|
||||
double s = 3;
|
||||
Vector r = SS.GW.projRight.ScaledBy(s/SS.GW.scale);
|
||||
Vector d = SS.GW.projUp.ScaledBy(s/SS.GW.scale);
|
||||
|
||||
// The usual fudge, to make this appear in front.
|
||||
Vector gn = SS.GW.projRight.Cross(SS.GW.projUp);
|
||||
v = v.Plus(gn.ScaledBy(4/SS.GW.scale));
|
||||
|
||||
glxColor3d(0, 0.8, 0);
|
||||
glBegin(GL_QUADS);
|
||||
glxVertex3v(v.Plus (r).Plus (d));
|
||||
|
@ -330,12 +380,42 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
break;
|
||||
}
|
||||
|
||||
case NORMAL_IN_3D:
|
||||
case NORMAL_IN_2D:
|
||||
case NORMAL_XFRMD: {
|
||||
if(order >= 0 && order != 2) break;
|
||||
if(!SS.GW.showNormals) break;
|
||||
|
||||
hRequest hr = h.request();
|
||||
double f = 0.5;
|
||||
if(hr.v == Request::HREQUEST_REFERENCE_XY.v) {
|
||||
glxColor3d(0, 0, f);
|
||||
} else if(hr.v == Request::HREQUEST_REFERENCE_YZ.v) {
|
||||
glxColor3d(f, 0, 0);
|
||||
} else if(hr.v == Request::HREQUEST_REFERENCE_ZX.v) {
|
||||
glxColor3d(0, f, 0);
|
||||
} else {
|
||||
glxColor3d(0, 0.4, 0.4);
|
||||
}
|
||||
Quaternion q = NormalGetNum();
|
||||
Vector tail = SS.GetEntity(point[0])->PointGetNum();
|
||||
Vector v = (q.RotationN()).WithMagnitude(50/SS.GW.scale);
|
||||
Vector tip = tail.Plus(v);
|
||||
LineDrawOrGetDistance(tail, tip);
|
||||
|
||||
v = v.WithMagnitude(12);
|
||||
Vector axis = q.RotationV();
|
||||
LineDrawOrGetDistance(tip, tip.Minus(v.RotatedAbout(axis, 0.6)));
|
||||
LineDrawOrGetDistance(tip, tip.Minus(v.RotatedAbout(axis, -0.6)));
|
||||
break;
|
||||
}
|
||||
|
||||
case WORKPLANE: {
|
||||
if(order >= 0 && order != 0) break;
|
||||
if(!SS.GW.showWorkplanes) break;
|
||||
|
||||
Vector p;
|
||||
p = SS.GetEntity(point[0])->PointGetCoords();
|
||||
p = SS.GetEntity(point[0])->PointGetNum();
|
||||
|
||||
Vector u, v;
|
||||
WorkplaneGetBasisVectors(&u, &v);
|
||||
|
@ -350,7 +430,7 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
Vector mm = p.Minus(us).Minus(vs);
|
||||
Vector mp = p.Minus(us).Plus (vs);
|
||||
|
||||
glxColor3d(0, 0.4, 0.4);
|
||||
glxColor3d(0, 0.3, 0.3);
|
||||
LineDrawOrGetDistance(pp, pm);
|
||||
LineDrawOrGetDistance(pm, mm);
|
||||
LineDrawOrGetDistance(mm, mp);
|
||||
|
@ -362,23 +442,28 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
glxOntoWorkplane(u, v);
|
||||
glxWriteText(DescriptionString());
|
||||
glPopMatrix();
|
||||
} else {
|
||||
// If a line lies in a plane, then select the line, not
|
||||
// the plane.
|
||||
dogd.dmin += 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case LINE_SEGMENT: {
|
||||
if(order >= 0 && order != 1) break;
|
||||
Vector a = SS.GetEntity(point[0])->PointGetCoords();
|
||||
Vector b = SS.GetEntity(point[1])->PointGetCoords();
|
||||
Vector a = SS.GetEntity(point[0])->PointGetNum();
|
||||
Vector b = SS.GetEntity(point[1])->PointGetNum();
|
||||
LineDrawOrGetDistanceOrEdge(a, b);
|
||||
break;
|
||||
}
|
||||
|
||||
case CUBIC: {
|
||||
Vector p0 = SS.GetEntity(point[0])->PointGetCoords();
|
||||
Vector p1 = SS.GetEntity(point[1])->PointGetCoords();
|
||||
Vector p2 = SS.GetEntity(point[2])->PointGetCoords();
|
||||
Vector p3 = SS.GetEntity(point[3])->PointGetCoords();
|
||||
if(order >= 0 && order != 1) break;
|
||||
Vector p0 = SS.GetEntity(point[0])->PointGetNum();
|
||||
Vector p1 = SS.GetEntity(point[1])->PointGetNum();
|
||||
Vector p2 = SS.GetEntity(point[2])->PointGetNum();
|
||||
Vector p3 = SS.GetEntity(point[3])->PointGetNum();
|
||||
int i, n = 20;
|
||||
Vector prev = p0;
|
||||
for(i = 1; i <= n; i++) {
|
||||
|
@ -394,6 +479,27 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
break;
|
||||
}
|
||||
|
||||
case CIRCLE: {
|
||||
if(order >= 0 && order != 1) break;
|
||||
|
||||
Quaternion q = SS.GetEntity(normal)->NormalGetNum();
|
||||
double r = SS.GetParam(param[0])->val;
|
||||
Vector center = SS.GetEntity(point[0])->PointGetNum();
|
||||
Vector u = q.RotationU(), v = q.RotationV();
|
||||
|
||||
int i, c = 20;
|
||||
Vector prev = u.ScaledBy(r).Plus(center);
|
||||
for(i = 0; i <= c; i++) {
|
||||
double phi = (2*PI*i)/c;
|
||||
Vector p = (u.ScaledBy(r*cos(phi))).Plus(
|
||||
v.ScaledBy(r*sin(phi)));
|
||||
p = p.Plus(center);
|
||||
LineDrawOrGetDistanceOrEdge(prev, p);
|
||||
prev = p;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
oops();
|
||||
}
|
||||
|
|
44
expr.cpp
44
expr.cpp
|
@ -53,7 +53,51 @@ Expr *ExprVector::Magnitude(void) {
|
|||
return r->Sqrt();
|
||||
}
|
||||
|
||||
ExprQuaternion ExprQuaternion::FromExprs(Expr *w, Expr *vx, Expr *vy, Expr *vz)
|
||||
{
|
||||
ExprQuaternion q;
|
||||
q.w = w;
|
||||
q.vx = vx;
|
||||
q.vy = vy;
|
||||
q.vz = vz;
|
||||
return q;
|
||||
}
|
||||
|
||||
ExprVector ExprQuaternion::RotationU(void) {
|
||||
ExprVector u;
|
||||
Expr *two = Expr::FromConstant(2);
|
||||
|
||||
u.x = w->Square();
|
||||
u.x = (u.x)->Plus(vx->Square());
|
||||
u.x = (u.x)->Minus(vy->Square());
|
||||
u.x = (u.x)->Minus(vz->Square());
|
||||
|
||||
u.y = two->Times(w->Times(vz));
|
||||
u.y = (u.y)->Plus(two->Times(vx->Times(vy)));
|
||||
|
||||
u.z = two->Times(vx->Times(vz));
|
||||
u.z = (u.z)->Minus(two->Times(w->Times(vy)));
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
ExprVector ExprQuaternion::RotationV(void) {
|
||||
ExprVector v;
|
||||
Expr *two = Expr::FromConstant(2);
|
||||
|
||||
v.x = two->Times(vx->Times(vy));
|
||||
v.x = (v.x)->Minus(two->Times(w->Times(vz)));
|
||||
|
||||
v.y = w->Square();
|
||||
v.y = (v.y)->Minus(vx->Square());
|
||||
v.y = (v.y)->Plus(vy->Square());
|
||||
v.y = (v.y)->Minus(vz->Square());
|
||||
|
||||
v.z = two->Times(w->Times(vx));
|
||||
v.z = (v.z)->Plus(two->Times(vy->Times(vz)));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
Expr *Expr::FromParam(hParam p) {
|
||||
Expr *r = AllocExpr();
|
||||
|
|
11
expr.h
11
expr.h
|
@ -131,4 +131,15 @@ public:
|
|||
Expr *Magnitude(void);
|
||||
};
|
||||
|
||||
class ExprQuaternion {
|
||||
public:
|
||||
Expr *w, *vx, *vy, *vz;
|
||||
|
||||
static ExprQuaternion FromExprs(Expr *w, Expr *vx, Expr *vy, Expr *vz);
|
||||
|
||||
ExprVector RotationU(void);
|
||||
ExprVector RotationV(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
9
file.cpp
9
file.cpp
|
@ -75,8 +75,15 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
|
|||
{ '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[3].v", 'x', &(SS.sv.e.point[3].v) },
|
||||
{ 'e', "Entity.direction.v", 'x', &(SS.sv.e.direction.v) },
|
||||
{ 'e', "Entity.normal.v", 'x', &(SS.sv.e.normal.v) },
|
||||
{ 'e', "Entity.workplane.v", 'x', &(SS.sv.e.workplane.v) },
|
||||
{ 'e', "Entity.numPoint.x", 'f', &(SS.sv.e.numPoint.x) },
|
||||
{ 'e', "Entity.numPoint.y", 'f', &(SS.sv.e.numPoint.y) },
|
||||
{ 'e', "Entity.numPoint.z", 'f', &(SS.sv.e.numPoint.z) },
|
||||
{ 'e', "Entity.numNormal.w", 'f', &(SS.sv.e.numNormal.w) },
|
||||
{ 'e', "Entity.numNormal.vx", 'f', &(SS.sv.e.numNormal.vx) },
|
||||
{ 'e', "Entity.numNormal.vy", 'f', &(SS.sv.e.numNormal.vy) },
|
||||
{ 'e', "Entity.numNormal.vz", 'f', &(SS.sv.e.numNormal.vz) },
|
||||
|
||||
{ 'c', "Constraint.h.v", 'x', &(SS.sv.c.h.v) },
|
||||
{ 'c', "Constraint.type", 'd', &(SS.sv.c.type) },
|
||||
|
|
276
graphicswin.cpp
276
graphicswin.cpp
|
@ -54,13 +54,11 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
{ 1, "Draw Anywhere in 3d\tQ", MNU_FREE_IN_3D, 'Q', mReq },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "Datum &Point\tP", MNU_DATUM_POINT, 'P', mReq },
|
||||
{ 1, "Datum A&xis\tX", 0, 'X', mReq },
|
||||
{ 1, "Datum Pla&ne\tN", 0, 'N', mReq },
|
||||
{ 1, "2d Coordinate S&ystem\tY", 0, 'Y', mReq },
|
||||
{ 1, "&Workplane (Coordinate S&ystem)\tY", 0, 'Y', mReq },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "Line &Segment\tS", MNU_LINE_SEGMENT, 'S', mReq },
|
||||
{ 1, "&Rectangle\tR", MNU_RECTANGLE, 'R', mReq },
|
||||
{ 1, "&Circle\tC", 0, 'C', mReq },
|
||||
{ 1, "&Circle\tC", MNU_CIRCLE, 'C', mReq },
|
||||
{ 1, "&Arc of a Circle\tA", 0, 'A', mReq },
|
||||
{ 1, "&Cubic Segment\t3", MNU_CUBIC, '3', mReq },
|
||||
{ 1, NULL, 0, NULL },
|
||||
|
@ -107,7 +105,7 @@ void GraphicsWindow::Init(void) {
|
|||
activeWorkplane = r.entity(0);
|
||||
|
||||
showWorkplanes = true;
|
||||
showAxes = true;
|
||||
showNormals = true;
|
||||
showPoints = true;
|
||||
showConstraints = true;
|
||||
showSolids = true;
|
||||
|
@ -265,10 +263,7 @@ void GraphicsWindow::MenuEdit(int id) {
|
|||
case MNU_UNSELECT_ALL:
|
||||
HideGraphicsEditControl();
|
||||
SS.GW.ClearSelection();
|
||||
SS.GW.pendingOperation = 0;
|
||||
SS.GW.pendingDescription = NULL;
|
||||
SS.GW.pendingPoint.v = 0;
|
||||
SS.GW.pendingConstraint.v = 0;
|
||||
SS.GW.ClearPending();
|
||||
SS.TW.ScreenNavigation('h', 0);
|
||||
SS.TW.Show();
|
||||
break;
|
||||
|
@ -335,7 +330,7 @@ void GraphicsWindow::MenuRequest(int id) {
|
|||
Vector pr, pu;
|
||||
e->WorkplaneGetBasisVectors(&pr, &pu);
|
||||
Quaternion quatf = Quaternion::MakeFrom(pr, pu);
|
||||
Vector offsetf = SS.GetEntity(e->point[0])->PointGetCoords();
|
||||
Vector offsetf = SS.GetEntity(e->point[0])->PointGetNum();
|
||||
SS.GW.AnimateOnto(quatf, offsetf);
|
||||
|
||||
SS.GW.EnsureValidActives();
|
||||
|
@ -351,9 +346,10 @@ void GraphicsWindow::MenuRequest(int id) {
|
|||
case MNU_DATUM_POINT: s = "click to place datum point"; goto c;
|
||||
case MNU_LINE_SEGMENT: s = "click first point of line segment"; goto c;
|
||||
case MNU_CUBIC: s = "click first point of cubic segment"; goto c;
|
||||
case MNU_CIRCLE: s = "click center of circle"; goto c;
|
||||
c:
|
||||
SS.GW.pendingOperation = id;
|
||||
SS.GW.pendingDescription = s;
|
||||
SS.GW.pending.operation = id;
|
||||
SS.GW.pending.description = s;
|
||||
SS.TW.Show();
|
||||
break;
|
||||
|
||||
|
@ -361,14 +357,14 @@ c:
|
|||
}
|
||||
}
|
||||
|
||||
void GraphicsWindow::UpdateDraggedEntity(hEntity hp, double mx, double my) {
|
||||
void GraphicsWindow::UpdateDraggedPoint(hEntity hp, double mx, double my) {
|
||||
Entity *p = SS.GetEntity(hp);
|
||||
Vector pos = p->PointGetCoords();
|
||||
UpdateDraggedPoint(&pos, mx, my);
|
||||
Vector pos = p->PointGetNum();
|
||||
UpdateDraggedNum(&pos, mx, my);
|
||||
p->PointForceTo(pos);
|
||||
}
|
||||
|
||||
void GraphicsWindow::UpdateDraggedPoint(Vector *pos, double mx, double my) {
|
||||
void GraphicsWindow::UpdateDraggedNum(Vector *pos, double mx, double my) {
|
||||
*pos = pos->Plus(projRight.ScaledBy((mx - orig.mouse.x)/scale));
|
||||
*pos = pos->Plus(projUp.ScaledBy((my - orig.mouse.y)/scale));
|
||||
|
||||
|
@ -384,6 +380,8 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
|
||||
Point2d mp = { x, y };
|
||||
|
||||
// If the middle button is down, then mouse movement is used to pan and
|
||||
// rotate our view. This wins over everything else.
|
||||
if(middleDown) {
|
||||
hover.Clear();
|
||||
|
||||
|
@ -405,7 +403,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
|
||||
NormalizeProjectionVectors();
|
||||
} else {
|
||||
double s = 0.3*(PI/180); // degrees per pixel
|
||||
double s = 0.3*(PI/180)*scale; // degrees per pixel
|
||||
projRight = orig.projRight.RotatedAbout(orig.projUp, -s*dx);
|
||||
projUp = orig.projUp.RotatedAbout(orig.projRight, s*dy);
|
||||
|
||||
|
@ -421,58 +419,123 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
InvalidateGraphics();
|
||||
return;
|
||||
}
|
||||
|
||||
// Enforce a bit of static friction before we start dragging.
|
||||
double dm = orig.mouse.DistanceTo(mp);
|
||||
if(leftDown && dm > 3 && pendingOperation == 0) {
|
||||
if(hover.entity.v &&
|
||||
SS.GetEntity(hover.entity)->IsPoint() &&
|
||||
!SS.GetEntity(hover.entity)->PointIsFromReferences())
|
||||
{
|
||||
// Start dragging this point.
|
||||
ClearSelection();
|
||||
pendingPoint = hover.entity;
|
||||
pendingOperation = DRAGGING_POINT;
|
||||
} else if(hover.constraint.v &&
|
||||
SS.GetConstraint(hover.constraint)->HasLabel())
|
||||
{
|
||||
ClearSelection();
|
||||
pendingConstraint = hover.constraint;
|
||||
pendingOperation = DRAGGING_CONSTRAINT;
|
||||
}
|
||||
} else if(leftDown && pendingOperation == DRAGGING_CONSTRAINT) {
|
||||
Constraint *c = SS.constraint.FindById(pendingConstraint);
|
||||
UpdateDraggedPoint(&(c->disp.offset), x, y);
|
||||
} else if(leftDown && pendingOperation == DRAGGING_POINT) {
|
||||
if(havePainted) {
|
||||
UpdateDraggedEntity(pendingPoint, x, y);
|
||||
SS.GenerateAll(solving == SOLVE_ALWAYS);
|
||||
havePainted = false;
|
||||
|
||||
if(pending.operation == 0) {
|
||||
double dm = orig.mouse.DistanceTo(mp);
|
||||
// If we're currently not doing anything, then see if we should
|
||||
// start dragging something.
|
||||
if(leftDown && dm > 3) {
|
||||
if(hover.entity.v) {
|
||||
Entity *e = SS.GetEntity(hover.entity);
|
||||
if(e->IsPoint()) {
|
||||
// Start dragging this point.
|
||||
ClearSelection();
|
||||
pending.point = hover.entity;
|
||||
pending.operation = DRAGGING_POINT;
|
||||
} else if(e->type == Entity::CIRCLE) {
|
||||
// Drag the radius.
|
||||
ClearSelection();
|
||||
pending.circle = hover.entity;
|
||||
pending.operation = DRAGGING_RADIUS;
|
||||
} else if(e->IsNormal()) {
|
||||
ClearSelection();
|
||||
pending.normal = hover.entity;
|
||||
pending.operation = DRAGGING_NORMAL;
|
||||
}
|
||||
} else if(hover.constraint.v &&
|
||||
SS.GetConstraint(hover.constraint)->HasLabel())
|
||||
{
|
||||
ClearSelection();
|
||||
pending.constraint = hover.constraint;
|
||||
pending.operation = DRAGGING_CONSTRAINT;
|
||||
}
|
||||
} else {
|
||||
// Otherwise, just hit test and give up
|
||||
HitTestMakeSelection(mp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// No buttons pressed.
|
||||
if(pendingOperation == DRAGGING_NEW_POINT ||
|
||||
pendingOperation == DRAGGING_NEW_LINE_POINT)
|
||||
{
|
||||
SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS);
|
||||
UpdateDraggedEntity(pendingPoint, x, y);
|
||||
HitTestMakeSelection(mp);
|
||||
} else if(pendingOperation == DRAGGING_NEW_CUBIC_POINT) {
|
||||
UpdateDraggedEntity(pendingPoint, x, y);
|
||||
HitTestMakeSelection(mp);
|
||||
|
||||
hRequest hr = pendingPoint.request();
|
||||
Vector p0 = SS.GetEntity(hr.entity(1))->PointGetCoords();
|
||||
Vector p3 = SS.GetEntity(hr.entity(4))->PointGetCoords();
|
||||
Vector p1 = p0.ScaledBy(2.0/3).Plus(p3.ScaledBy(1.0/3));
|
||||
SS.GetEntity(hr.entity(2))->PointForceTo(p1);
|
||||
Vector p2 = p0.ScaledBy(1.0/3).Plus(p3.ScaledBy(2.0/3));
|
||||
SS.GetEntity(hr.entity(3))->PointForceTo(p2);
|
||||
} else if(!leftDown) {
|
||||
// Do our usual hit testing, for the selection.
|
||||
// If the user has started an operation from the menu, but not
|
||||
// completed it, then just do the selection.
|
||||
if(pending.operation < FIRST_PENDING) {
|
||||
HitTestMakeSelection(mp);
|
||||
return;
|
||||
}
|
||||
|
||||
// We're currently dragging something; so do that. But if we haven't
|
||||
// painted since the last time we solved, do nothing, because there's
|
||||
// no sense solving a frame and not displaying it.
|
||||
if(!havePainted) return;
|
||||
switch(pending.operation) {
|
||||
case DRAGGING_CONSTRAINT: {
|
||||
Constraint *c = SS.constraint.FindById(pending.constraint);
|
||||
UpdateDraggedNum(&(c->disp.offset), x, y);
|
||||
break;
|
||||
}
|
||||
case DRAGGING_NEW_LINE_POINT:
|
||||
HitTestMakeSelection(mp);
|
||||
// and fall through
|
||||
case DRAGGING_NEW_POINT:
|
||||
case DRAGGING_POINT:
|
||||
UpdateDraggedPoint(pending.point, x, y);
|
||||
break;
|
||||
|
||||
case DRAGGING_NEW_CUBIC_POINT: {
|
||||
UpdateDraggedPoint(pending.point, x, y);
|
||||
HitTestMakeSelection(mp);
|
||||
|
||||
hRequest hr = pending.point.request();
|
||||
Vector p0 = SS.GetEntity(hr.entity(1))->PointGetNum();
|
||||
Vector p3 = SS.GetEntity(hr.entity(4))->PointGetNum();
|
||||
Vector p1 = p0.ScaledBy(2.0/3).Plus(p3.ScaledBy(1.0/3));
|
||||
SS.GetEntity(hr.entity(2))->PointForceTo(p1);
|
||||
Vector p2 = p0.ScaledBy(1.0/3).Plus(p3.ScaledBy(2.0/3));
|
||||
SS.GetEntity(hr.entity(3))->PointForceTo(p2);
|
||||
break;
|
||||
}
|
||||
case DRAGGING_NEW_RADIUS:
|
||||
case DRAGGING_RADIUS: {
|
||||
Entity *circle = SS.GetEntity(pending.circle);
|
||||
Vector center = SS.GetEntity(circle->point[0])->PointGetNum();
|
||||
Point2d c2 = ProjectPoint(center);
|
||||
SS.GetParam(circle->param[0])->val = c2.DistanceTo(mp)*scale;
|
||||
break;
|
||||
}
|
||||
|
||||
case DRAGGING_NORMAL: {
|
||||
Entity *normal = SS.GetEntity(pending.normal);
|
||||
Vector p = SS.GetEntity(normal->point[0])->PointGetNum();
|
||||
Point2d p2 = ProjectPoint(p);
|
||||
|
||||
Quaternion q = normal->NormalGetNum();
|
||||
Vector u = q.RotationU(), v = q.RotationV();
|
||||
|
||||
if(ctrlDown) {
|
||||
double theta = atan2(orig.mouse.y-p2.y, orig.mouse.x-p2.x);
|
||||
theta -= atan2(y-p2.y, x-p2.x);
|
||||
|
||||
Vector normal = orig.projRight.Cross(orig.projUp);
|
||||
u = u.RotatedAbout(normal, -theta);
|
||||
v = v.RotatedAbout(normal, -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);
|
||||
}
|
||||
orig.mouse = mp;
|
||||
normal->NormalForceTo(Quaternion::MakeFrom(u, v));
|
||||
break;
|
||||
}
|
||||
|
||||
default: oops();
|
||||
}
|
||||
SS.GenerateAll(solving == SOLVE_ALWAYS);
|
||||
havePainted = false;
|
||||
}
|
||||
|
||||
bool GraphicsWindow::Selection::Equals(Selection *b) {
|
||||
|
@ -493,6 +556,10 @@ void GraphicsWindow::Selection::Draw(void) {
|
|||
if(constraint.v) SS.GetConstraint(constraint)->Draw();
|
||||
}
|
||||
|
||||
void GraphicsWindow::ClearPending(void) {
|
||||
memset(&pending, 0, sizeof(pending));
|
||||
}
|
||||
|
||||
void GraphicsWindow::HitTestMakeSelection(Point2d mp) {
|
||||
int i;
|
||||
double d, dmin = 1e12;
|
||||
|
@ -503,7 +570,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) {
|
|||
for(i = 0; i < SS.entity.n; i++) {
|
||||
Entity *e = &(SS.entity.elem[i]);
|
||||
// Don't hover whatever's being dragged.
|
||||
if(e->h.request().v == pendingPoint.request().v) continue;
|
||||
if(e->h.request().v == pending.point.request().v) continue;
|
||||
|
||||
d = e->GetDistance(mp);
|
||||
if(d < 10 && d < dmin) {
|
||||
|
@ -599,14 +666,14 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
Constraint::ConstrainCoincident(hover.entity, (p)); \
|
||||
}
|
||||
hRequest hr;
|
||||
switch(pendingOperation) {
|
||||
switch(pending.operation) {
|
||||
case MNU_DATUM_POINT:
|
||||
hr = AddRequest(Request::DATUM_POINT);
|
||||
SS.GetEntity(hr.entity(0))->PointForceTo(v);
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
|
||||
pendingOperation = 0;
|
||||
pending.operation = 0;
|
||||
break;
|
||||
|
||||
case MNU_LINE_SEGMENT:
|
||||
|
@ -616,10 +683,26 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
|
||||
ClearSelection(); hover.Clear();
|
||||
|
||||
pendingOperation = DRAGGING_NEW_LINE_POINT;
|
||||
pendingPoint = hr.entity(2);
|
||||
pendingDescription = "click to place next point of line";
|
||||
SS.GetEntity(pendingPoint)->PointForceTo(v);
|
||||
pending.operation = DRAGGING_NEW_LINE_POINT;
|
||||
pending.point = hr.entity(2);
|
||||
pending.description = "click to place next point of line";
|
||||
SS.GetEntity(pending.point)->PointForceTo(v);
|
||||
break;
|
||||
|
||||
case MNU_CIRCLE:
|
||||
hr = AddRequest(Request::CIRCLE);
|
||||
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
||||
SS.GetEntity(hr.entity(16))->NormalForceTo(
|
||||
Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp));
|
||||
MAYBE_PLACE(hr.entity(1));
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
|
||||
ClearPending();
|
||||
pending.operation = DRAGGING_NEW_RADIUS;
|
||||
pending.circle = hr.entity(0);
|
||||
pending.description = "click to set radius";
|
||||
SS.GetParam(hr.param(0))->val = 0;
|
||||
break;
|
||||
|
||||
case MNU_CUBIC:
|
||||
|
@ -632,30 +715,28 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
|
||||
ClearSelection(); hover.Clear();
|
||||
|
||||
pendingOperation = DRAGGING_NEW_CUBIC_POINT;
|
||||
pendingPoint = hr.entity(4);
|
||||
pendingDescription = "click to place next point of cubic";
|
||||
pending.operation = DRAGGING_NEW_CUBIC_POINT;
|
||||
pending.point = hr.entity(4);
|
||||
pending.description = "click to place next point of cubic";
|
||||
break;
|
||||
|
||||
case DRAGGING_RADIUS:
|
||||
case DRAGGING_NEW_POINT:
|
||||
// The MouseMoved event has already dragged it under the cursor.
|
||||
pendingOperation = 0;
|
||||
pendingPoint.v = 0;
|
||||
// The MouseMoved event has already dragged it as desired.
|
||||
ClearPending();
|
||||
break;
|
||||
|
||||
case DRAGGING_NEW_CUBIC_POINT:
|
||||
if(hover.entity.v && SS.GetEntity(hover.entity)->IsPoint()) {
|
||||
Constraint::ConstrainCoincident(pendingPoint, hover.entity);
|
||||
Constraint::ConstrainCoincident(pending.point, hover.entity);
|
||||
}
|
||||
pendingOperation = 0;
|
||||
pendingPoint.v = 0;
|
||||
ClearPending();
|
||||
break;
|
||||
|
||||
case DRAGGING_NEW_LINE_POINT: {
|
||||
if(hover.entity.v && SS.GetEntity(hover.entity)->IsPoint()) {
|
||||
Constraint::ConstrainCoincident(pendingPoint, hover.entity);
|
||||
pendingOperation = 0;
|
||||
pendingPoint.v = 0;
|
||||
Constraint::ConstrainCoincident(pending.point, hover.entity);
|
||||
ClearPending();
|
||||
break;
|
||||
}
|
||||
// Create a new line segment, so that we continue drawing.
|
||||
|
@ -663,23 +744,20 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
||||
|
||||
// Constrain the line segments to share an endpoint
|
||||
Constraint::ConstrainCoincident(pendingPoint, hr.entity(1));
|
||||
Constraint::ConstrainCoincident(pending.point, hr.entity(1));
|
||||
|
||||
// And drag an endpoint of the new line segment
|
||||
pendingOperation = DRAGGING_NEW_LINE_POINT;
|
||||
pendingPoint = hr.entity(2);
|
||||
pendingDescription = "click to place next point of next line";
|
||||
SS.GetEntity(pendingPoint)->PointForceTo(v);
|
||||
pending.operation = DRAGGING_NEW_LINE_POINT;
|
||||
pending.point = hr.entity(2);
|
||||
pending.description = "click to place next point of next line";
|
||||
SS.GetEntity(pending.point)->PointForceTo(v);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0:
|
||||
default: {
|
||||
pendingOperation = 0;
|
||||
pendingPoint.v = 0;
|
||||
pendingConstraint.v = 0;
|
||||
pendingDescription = NULL;
|
||||
ClearPending();
|
||||
|
||||
if(hover.IsEmpty()) break;
|
||||
|
||||
|
@ -710,12 +788,12 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
}
|
||||
|
||||
void GraphicsWindow::MouseLeftUp(double mx, double my) {
|
||||
switch(pendingOperation) {
|
||||
switch(pending.operation) {
|
||||
case DRAGGING_POINT:
|
||||
case DRAGGING_CONSTRAINT:
|
||||
pendingOperation = 0;
|
||||
pendingPoint.v = 0;
|
||||
pendingConstraint.v = 0;
|
||||
case DRAGGING_NORMAL:
|
||||
case DRAGGING_RADIUS:
|
||||
ClearPending();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -781,9 +859,9 @@ void GraphicsWindow::ToggleBool(int link, DWORD v) {
|
|||
}
|
||||
|
||||
void GraphicsWindow::ToggleAnyDatumShown(int link, DWORD v) {
|
||||
bool t = !(SS.GW.showWorkplanes && SS.GW.showAxes && SS.GW.showPoints);
|
||||
bool t = !(SS.GW.showWorkplanes && SS.GW.showNormals && SS.GW.showPoints);
|
||||
SS.GW.showWorkplanes = t;
|
||||
SS.GW.showAxes = t;
|
||||
SS.GW.showNormals = t;
|
||||
SS.GW.showPoints = t;
|
||||
|
||||
SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS);
|
||||
|
@ -809,7 +887,7 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
glScaled(scale*2.0/w, scale*2.0/h, scale*2.0/w);
|
||||
glScaled(scale*2.0/w, scale*2.0/h, scale*1.0/50000);
|
||||
|
||||
double tx = projRight.Dot(offset);
|
||||
double ty = projUp.Dot(offset);
|
||||
|
|
160
sketch.cpp
160
sketch.cpp
|
@ -68,7 +68,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
|
|||
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));
|
||||
CopyEntity(e->h, 0, h.param(0), h.param(1), h.param(2), true);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -93,7 +93,9 @@ hEntity Group::Remap(hEntity in, int copyNumber) {
|
|||
return h.entity(em.h.v);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Entity *ep = SS.GetEntity(in);
|
||||
|
||||
Entity en;
|
||||
|
@ -119,13 +121,36 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz) {
|
|||
en.point[3] = Remap(ep->point[3], a);
|
||||
break;
|
||||
|
||||
case Entity::CIRCLE:
|
||||
en.point[0] = Remap(ep->point[0], a);
|
||||
en.normal = Remap(ep->normal, a);
|
||||
en.param[0] = ep->param[0]; // XXX make numerical somehow later
|
||||
break;
|
||||
|
||||
case Entity::POINT_IN_3D:
|
||||
case Entity::POINT_IN_2D:
|
||||
en.type = Entity::POINT_XFRMD;
|
||||
en.point[0] = ep->h;
|
||||
en.param[0] = dx;
|
||||
en.param[1] = dy;
|
||||
en.param[2] = dz;
|
||||
en.numPoint = ep->PointGetNum();
|
||||
|
||||
if(isExtrusion) {
|
||||
if(a != 0) oops();
|
||||
SS.entity.Add(&en);
|
||||
en.point[0] = ep->h;
|
||||
en.point[1] = en.h;
|
||||
en.h = Remap(ep->h, 1);
|
||||
en.type = Entity::LINE_SEGMENT;
|
||||
// And then this line segment gets added
|
||||
}
|
||||
break;
|
||||
|
||||
case Entity::NORMAL_IN_3D:
|
||||
case Entity::NORMAL_IN_2D:
|
||||
en.type = Entity::NORMAL_XFRMD;
|
||||
en.numNormal = ep->NormalGetNum();
|
||||
en.point[0] = Remap(ep->point[0], a);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -242,67 +267,104 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
|
|||
int points = 0;
|
||||
int params = 0;
|
||||
int et = 0;
|
||||
bool hasNormal = false;
|
||||
int i;
|
||||
|
||||
Group *g = SS.group.FindById(group);
|
||||
|
||||
Entity e;
|
||||
memset(&e, 0, sizeof(e));
|
||||
switch(type) {
|
||||
case Request::WORKPLANE:
|
||||
et = Entity::WORKPLANE; points = 1; params = 4; goto c;
|
||||
et = Entity::WORKPLANE;
|
||||
points = 1;
|
||||
hasNormal = true;
|
||||
break;
|
||||
|
||||
case Request::DATUM_POINT:
|
||||
et = 0; points = 1; params = 0; goto c;
|
||||
et = 0;
|
||||
points = 1;
|
||||
break;
|
||||
|
||||
case Request::LINE_SEGMENT:
|
||||
et = Entity::LINE_SEGMENT; points = 2; params = 0; goto c;
|
||||
et = Entity::LINE_SEGMENT;
|
||||
points = 2;
|
||||
break;
|
||||
|
||||
case Request::CIRCLE:
|
||||
et = Entity::CIRCLE;
|
||||
points = 1;
|
||||
params = 1;
|
||||
hasNormal = true;
|
||||
break;
|
||||
|
||||
case Request::CUBIC:
|
||||
et = Entity::CUBIC; points = 4; params = 0; goto c;
|
||||
c: {
|
||||
// Generate the entity that's specific to this request.
|
||||
e.type = et;
|
||||
e.group = group;
|
||||
e.h = h.entity(0);
|
||||
|
||||
// And generate entities for the points
|
||||
for(i = 0; i < points; i++) {
|
||||
Entity p;
|
||||
memset(&p, 0, sizeof(p));
|
||||
p.workplane = workplane;
|
||||
// points start from entity 1, except for datum point case
|
||||
p.h = h.entity(i+(et ? 1 : 0));
|
||||
p.group = group;
|
||||
|
||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||
p.type = Entity::POINT_IN_3D;
|
||||
// params for x y z
|
||||
p.param[0] = AddParam(param, h.param(16 + 3*i + 0));
|
||||
p.param[1] = AddParam(param, h.param(16 + 3*i + 1));
|
||||
p.param[2] = AddParam(param, h.param(16 + 3*i + 2));
|
||||
} else {
|
||||
p.type = Entity::POINT_IN_2D;
|
||||
// params for u v
|
||||
p.param[0] = AddParam(param, h.param(16 + 3*i + 0));
|
||||
p.param[1] = AddParam(param, h.param(16 + 3*i + 1));
|
||||
}
|
||||
entity->Add(&p);
|
||||
e.point[i] = p.h;
|
||||
}
|
||||
// And generate any params not associated with the point that
|
||||
// we happen to need.
|
||||
for(i = 0; i < params; i++) {
|
||||
e.param[i] = AddParam(param, h.param(i));
|
||||
}
|
||||
|
||||
if(et) entity->Add(&e);
|
||||
et = Entity::CUBIC;
|
||||
points = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
oops();
|
||||
default: oops();
|
||||
}
|
||||
|
||||
// Generate the entity that's specific to this request.
|
||||
e.type = et;
|
||||
e.group = group;
|
||||
e.workplane = workplane;
|
||||
e.h = h.entity(0);
|
||||
|
||||
// And generate entities for the points
|
||||
for(i = 0; i < points; i++) {
|
||||
Entity p;
|
||||
memset(&p, 0, sizeof(p));
|
||||
p.workplane = workplane;
|
||||
// points start from entity 1, except for datum point case
|
||||
p.h = h.entity(i+(et ? 1 : 0));
|
||||
p.group = group;
|
||||
|
||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||
p.type = Entity::POINT_IN_3D;
|
||||
// params for x y z
|
||||
p.param[0] = AddParam(param, h.param(16 + 3*i + 0));
|
||||
p.param[1] = AddParam(param, h.param(16 + 3*i + 1));
|
||||
p.param[2] = AddParam(param, h.param(16 + 3*i + 2));
|
||||
} else {
|
||||
p.type = Entity::POINT_IN_2D;
|
||||
// params for u v
|
||||
p.param[0] = AddParam(param, h.param(16 + 3*i + 0));
|
||||
p.param[1] = AddParam(param, h.param(16 + 3*i + 1));
|
||||
}
|
||||
entity->Add(&p);
|
||||
e.point[i] = p.h;
|
||||
}
|
||||
if(hasNormal) {
|
||||
Entity n;
|
||||
memset(&n, 0, sizeof(n));
|
||||
n.workplane = workplane;
|
||||
n.h = h.entity(16);
|
||||
n.group = group;
|
||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||
n.type = Entity::NORMAL_IN_3D;
|
||||
n.param[0] = AddParam(param, h.param(32+0));
|
||||
n.param[1] = AddParam(param, h.param(32+1));
|
||||
n.param[2] = AddParam(param, h.param(32+2));
|
||||
n.param[3] = AddParam(param, h.param(32+3));
|
||||
} else {
|
||||
n.type = Entity::NORMAL_IN_2D;
|
||||
// and this is just a copy of the workplane quaternion,
|
||||
// so no params required
|
||||
}
|
||||
if(points < 1) oops();
|
||||
// The point determines where the normal gets displayed on-screen;
|
||||
// it's entirely cosmetic.
|
||||
n.point[0] = e.point[0];
|
||||
entity->Add(&n);
|
||||
e.normal = n.h;
|
||||
}
|
||||
// And generate any params not associated with the point that
|
||||
// we happen to need.
|
||||
for(i = 0; i < params; i++) {
|
||||
e.param[i] = AddParam(param, h.param(i));
|
||||
}
|
||||
|
||||
if(et) entity->Add(&e);
|
||||
}
|
||||
|
||||
char *Request::DescriptionString(void) {
|
||||
|
|
32
sketch.h
32
sketch.h
|
@ -103,7 +103,8 @@ public:
|
|||
// mapping list.
|
||||
IdList<EntityMap,EntityId> remap;
|
||||
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);
|
||||
|
||||
void MakePolygons(void);
|
||||
void Draw(void);
|
||||
|
@ -130,6 +131,7 @@ public:
|
|||
static const int DATUM_POINT = 101;
|
||||
static const int LINE_SEGMENT = 200;
|
||||
static const int CUBIC = 300;
|
||||
static const int CIRCLE = 400;
|
||||
|
||||
int type;
|
||||
|
||||
|
@ -152,22 +154,30 @@ public:
|
|||
|
||||
static const hEntity FREE_IN_3D;
|
||||
|
||||
static const int WORKPLANE = 1000;
|
||||
static const int POINT_IN_3D = 2000;
|
||||
static const int POINT_IN_2D = 2001;
|
||||
static const int POINT_XFRMD = 2010;
|
||||
static const int LINE_SEGMENT = 10000;
|
||||
static const int CUBIC = 11000;
|
||||
|
||||
static const int EDGE_LIST = 90000;
|
||||
static const int FACE_LIST = 91000;
|
||||
static const int NORMAL_IN_3D = 3000;
|
||||
static const int NORMAL_IN_2D = 3001;
|
||||
static const int NORMAL_XFRMD = 3010;
|
||||
|
||||
static const int WORKPLANE = 10000;
|
||||
static const int LINE_SEGMENT = 11000;
|
||||
static const int CUBIC = 12000;
|
||||
static const int CIRCLE = 13000;
|
||||
|
||||
int type;
|
||||
|
||||
// When it comes time to draw an entity, we look here to get the
|
||||
// defining variables.
|
||||
hParam param[4];
|
||||
hEntity point[4];
|
||||
hEntity direction;
|
||||
hEntity normal;
|
||||
|
||||
// Derived points are a symbolic offset from a constant base.
|
||||
Vector numPoint;
|
||||
Quaternion numNormal;
|
||||
|
||||
hGroup group;
|
||||
hEntity workplane; // or Entity::FREE_IN_3D
|
||||
|
@ -184,12 +194,18 @@ public:
|
|||
|
||||
bool IsPoint(void);
|
||||
// Applies for any of the point types
|
||||
Vector PointGetCoords(void);
|
||||
Vector PointGetNum(void);
|
||||
ExprVector PointGetExprs(void);
|
||||
void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v);
|
||||
void PointForceTo(Vector v);
|
||||
bool PointIsFromReferences(void);
|
||||
|
||||
bool IsNormal(void);
|
||||
// Applies for any of the normal types
|
||||
Quaternion NormalGetNum(void);
|
||||
ExprQuaternion NormalGetExprs(void);
|
||||
void NormalForceTo(Quaternion q);
|
||||
|
||||
// Applies for anything that comes with a plane
|
||||
bool HasPlane(void);
|
||||
// The plane is points P such that P dot (xn, yn, zn) - d = 0
|
||||
|
|
|
@ -72,28 +72,29 @@ void SolveSpace::ForceReferences(void) {
|
|||
// Force the values of the paramters that define the three reference
|
||||
// coordinate systems.
|
||||
static const struct {
|
||||
hRequest hr;
|
||||
double a, b, c, d;
|
||||
hRequest hr;
|
||||
Quaternion q;
|
||||
} Quat[] = {
|
||||
{ Request::HREQUEST_REFERENCE_XY, 1, 0, 0, 0, },
|
||||
{ Request::HREQUEST_REFERENCE_YZ, 0.5, 0.5, 0.5, 0.5, },
|
||||
{ Request::HREQUEST_REFERENCE_ZX, 0.5, -0.5, -0.5, -0.5, },
|
||||
{ Request::HREQUEST_REFERENCE_XY, { 1, 0, 0, 0, } },
|
||||
{ Request::HREQUEST_REFERENCE_YZ, { 0.5, 0.5, 0.5, 0.5, } },
|
||||
{ Request::HREQUEST_REFERENCE_ZX, { 0.5, -0.5, -0.5, -0.5, } },
|
||||
};
|
||||
for(int i = 0; i < 3; i++) {
|
||||
hRequest hr = Quat[i].hr;
|
||||
Entity *wrkpl = GetEntity(hr.entity(0));
|
||||
// The origin for our coordinate system, always zero
|
||||
Vector v = Vector::MakeFrom(0, 0, 0);
|
||||
Entity *origin = GetEntity(hr.entity(1));
|
||||
origin->PointForceTo(v);
|
||||
Entity *origin = GetEntity(wrkpl->point[0]);
|
||||
origin->PointForceTo(Vector::MakeFrom(0, 0, 0));
|
||||
GetParam(origin->param[0])->known = true;
|
||||
GetParam(origin->param[1])->known = true;
|
||||
GetParam(origin->param[2])->known = true;
|
||||
// The quaternion that defines the rotation, from the table.
|
||||
Param *p;
|
||||
p = GetParam(hr.param(0)); p->val = Quat[i].a; p->known = true;
|
||||
p = GetParam(hr.param(1)); p->val = Quat[i].b; p->known = true;
|
||||
p = GetParam(hr.param(2)); p->val = Quat[i].c; p->known = true;
|
||||
p = GetParam(hr.param(3)); p->val = Quat[i].d; p->known = true;
|
||||
Entity *normal = GetEntity(wrkpl->normal);
|
||||
normal->NormalForceTo(Quat[i].q);
|
||||
GetParam(normal->param[0])->known = true;
|
||||
GetParam(normal->param[1])->known = true;
|
||||
GetParam(normal->param[2])->known = true;
|
||||
GetParam(normal->param[3])->known = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ typedef signed long SDWORD;
|
|||
|
||||
class Expr;
|
||||
class ExprVector;
|
||||
class ExprQuaternion;
|
||||
|
||||
// From the platform-specific code.
|
||||
int SaveFileYesNoCancel(void);
|
||||
|
|
|
@ -86,8 +86,8 @@ void System::SortBySensitivity(void) {
|
|||
mat.dragged[j] = false;
|
||||
mat.permutation[j] = j;
|
||||
}
|
||||
if(SS.GW.pendingPoint.v) {
|
||||
Entity *p = SS.entity.FindByIdNoOops(SS.GW.pendingPoint);
|
||||
if(SS.GW.pending.point.v) {
|
||||
Entity *p = SS.entity.FindByIdNoOops(SS.GW.pending.point);
|
||||
// If we're solving an earlier group, then the pending point might
|
||||
// not exist in the entity tables yet.
|
||||
if(p) {
|
||||
|
|
16
textwin.cpp
16
textwin.cpp
|
@ -158,15 +158,15 @@ done:
|
|||
}
|
||||
|
||||
void TextWindow::Show(void) {
|
||||
if(!(SS.GW.pendingOperation)) SS.GW.pendingDescription = NULL;
|
||||
if(!(SS.GW.pending.operation)) SS.GW.ClearPending();
|
||||
|
||||
ShowHeader();
|
||||
|
||||
if(SS.GW.pendingDescription) {
|
||||
if(SS.GW.pending.description) {
|
||||
// A pending operation (that must be completed with the mouse in
|
||||
// the graphics window) will preempt our usual display.
|
||||
Printf(false, "");
|
||||
Printf(false, "%s", SS.GW.pendingDescription);
|
||||
Printf(false, "%s", SS.GW.pending.description);
|
||||
} else {
|
||||
switch(shown->screen) {
|
||||
default:
|
||||
|
@ -222,7 +222,7 @@ void TextWindow::ShowHeader(void) {
|
|||
SS.GetEntity(SS.GW.activeWorkplane)->DescriptionString();
|
||||
|
||||
// Navigation buttons
|
||||
if(SS.GW.pendingDescription) {
|
||||
if(SS.GW.pending.description) {
|
||||
Printf(false, " %Bt%Ft workplane:%Fd %s", cd);
|
||||
} else {
|
||||
Printf(false, " %Lb%f<<%E %Lh%fhome%E %Bt%Ft workplane:%Fd %s",
|
||||
|
@ -232,9 +232,9 @@ void TextWindow::ShowHeader(void) {
|
|||
}
|
||||
|
||||
int datumColor;
|
||||
if(SS.GW.showWorkplanes && SS.GW.showAxes && SS.GW.showPoints) {
|
||||
if(SS.GW.showWorkplanes && SS.GW.showNormals && SS.GW.showPoints) {
|
||||
datumColor = 's'; // shown
|
||||
} else if(!(SS.GW.showWorkplanes || SS.GW.showAxes || SS.GW.showPoints)) {
|
||||
} else if(!(SS.GW.showWorkplanes || SS.GW.showNormals || SS.GW.showPoints)){
|
||||
datumColor = 'h'; // hidden
|
||||
} else {
|
||||
datumColor = 'm'; // mixed
|
||||
|
@ -243,11 +243,11 @@ void TextWindow::ShowHeader(void) {
|
|||
#define hs(b) ((b) ? 's' : 'h')
|
||||
Printf(false, "%Bt%Ftshow: "
|
||||
"%Fp%Ll%D%fworkplanes%E "
|
||||
"%Fp%Ll%D%fvectors%E "
|
||||
"%Fp%Ll%D%fnormals%E "
|
||||
"%Fp%Ll%D%fpoints%E "
|
||||
"%Fp%Ll%fany-datum%E",
|
||||
hs(SS.GW.showWorkplanes), (DWORD)&(SS.GW.showWorkplanes), &(SS.GW.ToggleBool),
|
||||
hs(SS.GW.showAxes), (DWORD)&(SS.GW.showAxes), &(SS.GW.ToggleBool),
|
||||
hs(SS.GW.showNormals), (DWORD)&(SS.GW.showNormals), &(SS.GW.ToggleBool),
|
||||
hs(SS.GW.showPoints), (DWORD)&(SS.GW.showPoints), &(SS.GW.ToggleBool),
|
||||
datumColor, &(SS.GW.ToggleAnyDatumShown)
|
||||
);
|
||||
|
|
30
ui.h
30
ui.h
|
@ -103,6 +103,7 @@ public:
|
|||
MNU_FREE_IN_3D,
|
||||
MNU_DATUM_POINT,
|
||||
MNU_LINE_SEGMENT,
|
||||
MNU_CIRCLE,
|
||||
MNU_RECTANGLE,
|
||||
MNU_CUBIC,
|
||||
// Group
|
||||
|
@ -169,20 +170,31 @@ public:
|
|||
void EnsureValidActives();
|
||||
|
||||
// Operations that must be completed by doing something with the mouse
|
||||
// are noted here.
|
||||
// are noted here. These occupy the same space as the menu ids.
|
||||
static const int FIRST_PENDING = 0x0f000000;
|
||||
static const int DRAGGING_POINT = 0x0f000000;
|
||||
static const int DRAGGING_NEW_POINT = 0x0f000001;
|
||||
static const int DRAGGING_NEW_LINE_POINT = 0x0f000002;
|
||||
static const int DRAGGING_NEW_CUBIC_POINT = 0x0f000003;
|
||||
static const int DRAGGING_CONSTRAINT = 0x0f000004;
|
||||
hEntity pendingPoint;
|
||||
hConstraint pendingConstraint;
|
||||
int pendingOperation;
|
||||
char *pendingDescription;
|
||||
hRequest AddRequest(int type);
|
||||
static const int DRAGGING_RADIUS = 0x0f000005;
|
||||
static const int DRAGGING_NORMAL = 0x0f000006;
|
||||
static const int DRAGGING_NEW_RADIUS = 0x0f000007;
|
||||
struct {
|
||||
int operation;
|
||||
|
||||
hEntity point;
|
||||
hEntity circle;
|
||||
hEntity normal;
|
||||
hConstraint constraint;
|
||||
|
||||
char *description;
|
||||
} pending;
|
||||
void ClearPending(void);
|
||||
// The constraint that is being edited with the on-screen textbox.
|
||||
hConstraint constraintBeingEdited;
|
||||
|
||||
hRequest AddRequest(int type);
|
||||
|
||||
// The current selection.
|
||||
class Selection {
|
||||
|
@ -215,7 +227,7 @@ public:
|
|||
|
||||
// This sets what gets displayed.
|
||||
bool showWorkplanes;
|
||||
bool showAxes;
|
||||
bool showNormals;
|
||||
bool showPoints;
|
||||
bool showConstraints;
|
||||
bool showTextWindow;
|
||||
|
@ -228,8 +240,8 @@ public:
|
|||
static const int SOLVE_ALWAYS = 1;
|
||||
int solving;
|
||||
|
||||
void UpdateDraggedPoint(Vector *pos, double mx, double my);
|
||||
void UpdateDraggedEntity(hEntity hp, double mx, double my);
|
||||
void UpdateDraggedNum(Vector *pos, double mx, double my);
|
||||
void UpdateDraggedPoint(hEntity hp, double mx, double my);
|
||||
|
||||
// These are called by the platform-specific code.
|
||||
void Paint(int w, int h);
|
||||
|
|
96
util.cpp
96
util.cpp
|
@ -23,12 +23,12 @@ void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
|
|||
mat[15] = a44;
|
||||
}
|
||||
|
||||
Quaternion Quaternion::MakeFrom(double a, double b, double c, double d) {
|
||||
Quaternion Quaternion::MakeFrom(double w, double vx, double vy, double vz) {
|
||||
Quaternion q;
|
||||
q.a = a;
|
||||
q.b = b;
|
||||
q.c = c;
|
||||
q.d = d;
|
||||
q.w = w;
|
||||
q.vx = vx;
|
||||
q.vy = vy;
|
||||
q.vz = vz;
|
||||
return q;
|
||||
}
|
||||
|
||||
|
@ -40,65 +40,65 @@ Quaternion Quaternion::MakeFrom(Vector u, Vector v)
|
|||
double s, tr = 1 + u.x + v.y + n.z;
|
||||
if(tr > 1e-4) {
|
||||
s = 2*sqrt(tr);
|
||||
q.a = s/4;
|
||||
q.b = (v.z - n.y)/s;
|
||||
q.c = (n.x - u.z)/s;
|
||||
q.d = (u.y - v.x)/s;
|
||||
q.w = s/4;
|
||||
q.vx = (v.z - n.y)/s;
|
||||
q.vy = (n.x - u.z)/s;
|
||||
q.vz = (u.y - v.x)/s;
|
||||
} else {
|
||||
double m = max(u.x, max(v.y, n.z));
|
||||
if(m == u.x) {
|
||||
s = 2*sqrt(1 + u.x - v.y - n.z);
|
||||
q.a = (v.z - n.y)/s;
|
||||
q.b = s/4;
|
||||
q.c = (u.y + v.x)/s;
|
||||
q.d = (n.x + u.z)/s;
|
||||
q.w = (v.z - n.y)/s;
|
||||
q.vx = s/4;
|
||||
q.vy = (u.y + v.x)/s;
|
||||
q.vz = (n.x + u.z)/s;
|
||||
} else if(m == v.y) {
|
||||
s = 2*sqrt(1 - u.x + v.y - n.z);
|
||||
q.a = (n.x - u.z)/s;
|
||||
q.b = (u.y + v.x)/s;
|
||||
q.c = s/4;
|
||||
q.d = (v.z + n.y)/s;
|
||||
q.w = (n.x - u.z)/s;
|
||||
q.vx = (u.y + v.x)/s;
|
||||
q.vy = s/4;
|
||||
q.vz = (v.z + n.y)/s;
|
||||
} else if(m == n.z) {
|
||||
s = 2*sqrt(1 - u.x - v.y + n.z);
|
||||
q.a = (u.y - v.x)/s;
|
||||
q.b = (n.x + u.z)/s;
|
||||
q.c = (v.z + n.y)/s;
|
||||
q.d = s/4;
|
||||
q.w = (u.y - v.x)/s;
|
||||
q.vx = (n.x + u.z)/s;
|
||||
q.vy = (v.z + n.y)/s;
|
||||
q.vz = s/4;
|
||||
} else oops();
|
||||
}
|
||||
|
||||
return q.WithMagnitude(1);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Plus(Quaternion y) {
|
||||
Quaternion Quaternion::Plus(Quaternion b) {
|
||||
Quaternion q;
|
||||
q.a = a + y.a;
|
||||
q.b = b + y.b;
|
||||
q.c = c + y.c;
|
||||
q.d = d + y.d;
|
||||
q.w = w + b.w;
|
||||
q.vx = vx + b.vx;
|
||||
q.vy = vy + b.vy;
|
||||
q.vz = vz + b.vz;
|
||||
return q;
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Minus(Quaternion y) {
|
||||
Quaternion Quaternion::Minus(Quaternion b) {
|
||||
Quaternion q;
|
||||
q.a = a - y.a;
|
||||
q.b = b - y.b;
|
||||
q.c = c - y.c;
|
||||
q.d = d - y.d;
|
||||
q.w = w - b.w;
|
||||
q.vx = vx - b.vx;
|
||||
q.vy = vy - b.vy;
|
||||
q.vz = vz - b.vz;
|
||||
return q;
|
||||
}
|
||||
|
||||
Quaternion Quaternion::ScaledBy(double s) {
|
||||
Quaternion q;
|
||||
q.a = a*s;
|
||||
q.b = b*s;
|
||||
q.c = c*s;
|
||||
q.d = d*s;
|
||||
q.w = w*s;
|
||||
q.vx = vx*s;
|
||||
q.vy = vy*s;
|
||||
q.vz = vz*s;
|
||||
return q;
|
||||
}
|
||||
|
||||
double Quaternion::Magnitude(void) {
|
||||
return sqrt(a*a + b*b + c*c + d*d);
|
||||
return sqrt(w*w + vx*vx + vy*vy + vz*vz);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::WithMagnitude(double s) {
|
||||
|
@ -107,20 +107,24 @@ Quaternion Quaternion::WithMagnitude(double s) {
|
|||
|
||||
Vector Quaternion::RotationU(void) {
|
||||
Vector v;
|
||||
v.x = a*a + b*b - c*c - d*d;
|
||||
v.y = 2*a*d + 2*b*c;
|
||||
v.z = 2*b*d - 2*a*c;
|
||||
v.x = w*w + vx*vx - vy*vy - vz*vz;
|
||||
v.y = 2*w *vz + 2*vx*vy;
|
||||
v.z = 2*vx*vz - 2*w *vy;
|
||||
return v;
|
||||
}
|
||||
|
||||
Vector Quaternion::RotationV(void) {
|
||||
Vector v;
|
||||
v.x = 2*b*c - 2*a*d;
|
||||
v.y = a*a - b*b + c*c - d*d;
|
||||
v.z = 2*a*b + 2*c*d;
|
||||
v.x = 2*vx*vy - 2*w*vz;
|
||||
v.y = w*w - vx*vx + vy*vy - vz*vz;
|
||||
v.z = 2*w*vx + 2*vy*vz;
|
||||
return v;
|
||||
}
|
||||
|
||||
Vector Quaternion::RotationN(void) {
|
||||
return RotationU().Cross(RotationV());
|
||||
}
|
||||
|
||||
|
||||
Vector Vector::MakeFrom(double x, double y, double z) {
|
||||
Vector v;
|
||||
|
@ -199,17 +203,13 @@ Vector Vector::Normal(int which) {
|
|||
n.z = 0;
|
||||
n.x = y;
|
||||
n.y = -x;
|
||||
} else {
|
||||
oops();
|
||||
}
|
||||
} else oops();
|
||||
|
||||
if(which == 0) {
|
||||
// That's the vector we return.
|
||||
} else if(which == 1) {
|
||||
n = this->Cross(n);
|
||||
} else {
|
||||
oops();
|
||||
}
|
||||
} else oops();
|
||||
|
||||
n = n.WithMagnitude(1);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user