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
Jonathan Westhues 2008-05-10 22:09:46 -08:00
parent 4eed7693be
commit 6042fb3e0f
12 changed files with 340 additions and 46 deletions

3
dsc.h
View File

@ -28,6 +28,9 @@ public:
Vector RotationU(void);
Vector RotationV(void);
Vector RotationN(void);
Vector Rotate(Vector p);
Quaternion Times(Quaternion b);
};
class Vector {

View File

@ -10,7 +10,8 @@ bool Entity::HasVector(void) {
case LINE_SEGMENT:
case NORMAL_IN_3D:
case NORMAL_IN_2D:
case NORMAL_XFRMD:
case NORMAL_N_COPY:
case NORMAL_N_ROT:
return true;
default:
@ -26,7 +27,8 @@ ExprVector Entity::VectorGetExprs(void) {
case NORMAL_IN_3D:
case NORMAL_IN_2D:
case NORMAL_XFRMD:
case NORMAL_N_COPY:
case NORMAL_N_ROT:
return NormalExprsN();
default: oops();
@ -41,7 +43,8 @@ Vector Entity::VectorGetRefPoint(void) {
case NORMAL_IN_3D:
case NORMAL_IN_2D:
case NORMAL_XFRMD:
case NORMAL_N_COPY:
case NORMAL_N_ROT:
return SS.GetEntity(point[0])->PointGetNum();
default: oops();
@ -81,21 +84,21 @@ void Entity::WorkplaneGetPlaneExprs(ExprVector *n, Expr **dn) {
double Entity::DistanceGetNum(void) {
if(type == DISTANCE) {
return SS.GetParam(param[0])->val;
} else if(type == DISTANCE_XFRMD) {
} else if(type == DISTANCE_N_COPY) {
return numDistance;
} else oops();
}
Expr *Entity::DistanceGetExpr(void) {
if(type == DISTANCE) {
return Expr::FromParam(param[0]);
} else if(type == DISTANCE_XFRMD) {
} else if(type == DISTANCE_N_COPY) {
return Expr::FromConstant(numDistance);
} else oops();
}
void Entity::DistanceForceTo(double v) {
if(type == DISTANCE) {
(SS.GetParam(param[0]))->val = v;
} else if(type == DISTANCE_XFRMD) {
} else if(type == DISTANCE_N_COPY) {
// do nothing, it's locked
} else oops();
}
@ -108,9 +111,12 @@ bool Entity::IsPoint(void) {
switch(type) {
case POINT_IN_3D:
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) {
case NORMAL_IN_3D:
case NORMAL_IN_2D:
case NORMAL_XFRMD: return true;
case NORMAL_N_COPY:
case NORMAL_N_ROT:
return true;
default: return false;
}
@ -140,10 +148,18 @@ Quaternion Entity::NormalGetNum(void) {
q = norm->NormalGetNum();
break;
}
case NORMAL_XFRMD:
case NORMAL_N_COPY:
q = numNormal;
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();
}
return q;
@ -159,10 +175,13 @@ void Entity::NormalForceTo(Quaternion q) {
break;
case NORMAL_IN_2D:
case NORMAL_XFRMD:
case NORMAL_N_COPY:
// There's absolutely nothing to do; these are locked.
break;
case NORMAL_N_ROT:
break;
default: oops();
}
}
@ -203,13 +222,29 @@ ExprQuaternion Entity::NormalGetExprs(void) {
q = norm->NormalGetExprs();
break;
}
case NORMAL_XFRMD:
case NORMAL_N_COPY:
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;
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();
}
return q;
@ -235,7 +270,7 @@ void Entity::PointForceTo(Vector p) {
break;
}
case POINT_XFRMD: {
case POINT_N_TRANS: {
Vector trans = p.Minus(numPoint);
SS.GetParam(param[0])->val = trans.x;
SS.GetParam(param[1])->val = trans.y;
@ -243,6 +278,17 @@ void Entity::PointForceTo(Vector p) {
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();
}
}
@ -266,13 +312,24 @@ Vector Entity::PointGetNum(void) {
break;
}
case POINT_XFRMD: {
case POINT_N_TRANS: {
p = numPoint;
p.x += SS.GetParam(param[0])->val;
p.y += SS.GetParam(param[1])->val;
p.z += SS.GetParam(param[2])->val;
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();
}
return p;
@ -296,7 +353,7 @@ ExprVector Entity::PointGetExprs(void) {
r = r.Plus(v.ScaledBy(Expr::FromParam(param[1])));
break;
}
case POINT_XFRMD: {
case POINT_N_TRANS: {
ExprVector orig = {
Expr::FromConstant(numPoint.x),
Expr::FromConstant(numPoint.y),
@ -308,6 +365,24 @@ ExprVector Entity::PointGetExprs(void) {
r = orig.Plus(trans);
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();
}
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) {
if(dogd.drawing) {
// This fudge guarantees that the line will get drawn in front of
@ -403,7 +498,8 @@ void Entity::DrawOrGetDistance(int order) {
}
switch(type) {
case POINT_XFRMD:
case POINT_N_TRANS:
case POINT_N_ROT_TRANS:
case POINT_IN_3D:
case POINT_IN_2D: {
if(order >= 0 && order != 2) break;
@ -443,9 +539,10 @@ void Entity::DrawOrGetDistance(int order) {
break;
}
case NORMAL_N_COPY:
case NORMAL_N_ROT:
case NORMAL_IN_3D:
case NORMAL_IN_2D:
case NORMAL_XFRMD: {
case NORMAL_IN_2D: {
if(order >= 0 && order != 2) break;
if(!SS.GW.showNormals) break;
@ -474,7 +571,7 @@ void Entity::DrawOrGetDistance(int order) {
}
case DISTANCE:
case DISTANCE_XFRMD:
case DISTANCE_N_COPY:
// These are used only as data structures, nothing to display.
break;

View File

@ -125,6 +125,29 @@ ExprVector ExprQuaternion::RotationN(void) {
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) {
return ((w ->Square())->Plus(
(vx->Square())->Plus(
@ -132,6 +155,7 @@ Expr *ExprQuaternion::Magnitude(void) {
(vz->Square())))))->Sqrt();
}
Expr *Expr::FromParam(hParam p) {
Expr *r = AllocExpr();
r->op = PARAM;

3
expr.h
View File

@ -144,6 +144,9 @@ public:
ExprVector RotationV(void);
ExprVector RotationN(void);
ExprVector Rotate(ExprVector p);
ExprQuaternion Times(ExprQuaternion b);
Expr *Magnitude(void);
};

View File

@ -72,6 +72,9 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ '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[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[1].v", 'x', &(SS.sv.e.point[1].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': {
IdList<EntityMap,EntityId> *m =
(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(;;) {
EntityMap em;
char line2[1024];

View File

@ -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 Workplane\tShift+Ctrl+W",MNU_GROUP_WRKPL, 'W'|S|C, mGrp },
{ 1, NULL, 0, NULL },
{ 1, "New Step and Repeat &Translating", 0, 0, NULL },
{ 1, "New Step and Repeat &Rotating", 0, 0, NULL },
{ 1, "New Step &Translating\tShift+Ctrl+R", MNU_GROUP_TRANS, 'T'|S|C,mGrp },
{ 1, "New Step &Rotating\tShift+Ctrl+T", MNU_GROUP_ROT, 'R'|S|C,mGrp },
{ 1, NULL, 0, 0, NULL },
{ 1, "New Extrusion\tShift+Ctrl+X", MNU_GROUP_EXTRUDE, 'X'|S|C,mGrp },
{ 1, NULL, 0, 0, NULL },
@ -494,10 +494,53 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
HitTestMakeSelection(mp);
// and fall through
case DRAGGING_NEW_POINT:
case DRAGGING_POINT:
UpdateDraggedPoint(pending.point, x, y);
break;
case DRAGGING_POINT: {
Entity *p = SS.GetEntity(pending.point);
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: {
UpdateDraggedPoint(pending.point, x, y);
HitTestMakeSelection(mp);

View File

@ -2,6 +2,8 @@
const hEntity Entity::FREE_IN_3D = { 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 hRequest Request::HREQUEST_REFERENCE_XY = { 1 };
@ -25,15 +27,21 @@ void Group::MenuGroup(int id) {
switch(id) {
case GraphicsWindow::MNU_GROUP_3D:
g.type = DRAWING;
g.name.strcpy("drawing");
g.name.strcpy("draw-in-3d");
break;
case GraphicsWindow::MNU_GROUP_EXTRUDE:
g.type = EXTRUDE;
g.opA.v = 2;
g.opA = SS.GW.activeGroup;
g.name.strcpy("extrude");
break;
case GraphicsWindow::MNU_GROUP_ROT:
g.type = ROTATE;
g.opA = SS.GW.activeGroup;
g.name.strcpy("rotate");
break;
default: oops();
}
@ -71,7 +79,32 @@ 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), 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;
@ -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) {
int 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,
bool isExtrusion)
hParam qw, hParam qvx, hParam qvy, hParam qvz,
bool transOnly, bool isExtrusion)
{
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);
break;
case Entity::POINT_N_TRANS:
case Entity::POINT_N_ROT_TRANS:
case Entity::POINT_IN_3D:
case Entity::POINT_IN_2D:
en.type = Entity::POINT_XFRMD;
en.param[0] = dx;
en.param[1] = dy;
en.param[2] = dz;
en.numPoint = ep->PointGetNum();
if(transOnly) {
en.type = Entity::POINT_N_TRANS;
en.param[0] = dx;
en.param[1] = dy;
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(a != 0) oops();
@ -153,15 +216,27 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
}
break;
case Entity::NORMAL_N_COPY:
case Entity::NORMAL_N_ROT:
case Entity::NORMAL_IN_3D:
case Entity::NORMAL_IN_2D:
en.type = Entity::NORMAL_XFRMD;
en.numNormal = ep->NormalGetNum();
if(transOnly) {
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);
break;
case Entity::DISTANCE_N_COPY:
case Entity::DISTANCE:
en.type = Entity::DISTANCE_XFRMD;
en.type = Entity::DISTANCE_N_COPY;
en.numDistance = ep->DistanceGetNum();
break;

View File

@ -22,6 +22,7 @@ public:
inline hEntity entity(int i);
inline hParam param(int i);
inline hEquation equation(int i);
};
class hRequest {
public:
@ -77,6 +78,8 @@ public:
static const int DRAWING = 5000;
static const int EXTRUDE = 5010;
static const int ROTATE = 5020;
static const int TRANSLATE = 5030;
int type;
int solveOrder;
@ -105,7 +108,10 @@ public:
IdList<EntityMap,EntityId> remap;
hEntity Remap(hEntity in, int copyNumber);
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 Draw(void);
@ -158,7 +164,8 @@ public:
static const int POINT_IN_3D = 2000;
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_2D = 3001;
@ -168,10 +175,11 @@ public:
// u = (sin theta)*uw - (cos theta)*vw
// v = nw
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_XFRMD = 4001;
static const int DISTANCE_N_COPY = 4001;
static const int WORKPLANE = 10000;
static const int LINE_SEGMENT = 11000;
@ -187,7 +195,7 @@ public:
hEntity distance;
// The only types that have their own params are points, normals,
// and directions.
hParam param[4];
hParam param[7];
// Transformed points/normals/distances have their numerical value.
Vector numPoint;
@ -228,6 +236,9 @@ public:
void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v);
void PointForceTo(Vector v);
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);
// Applies for any of the normal types
@ -275,6 +286,8 @@ public:
// Used only in the solver
hParam substd;
static const hParam NO_PARAM;
};
@ -282,7 +295,7 @@ class hConstraint {
public:
DWORD v;
hEquation equation(int i);
inline hEquation equation(int i);
};
class Constraint {
@ -380,6 +393,8 @@ inline hEntity hGroup::entity(int i)
{ hEntity r; r.v = 0x80000000 | (v << 16) | i; return r; }
inline hParam hGroup::param(int i)
{ 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) {
if(v == Request::HREQUEST_REFERENCE_XY.v) return true;
@ -397,7 +412,7 @@ inline bool hEntity::isFromRequest(void)
inline hRequest hEntity::request(void)
{ hRequest r; r.v = (v >> 16); return r; }
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)
{ hRequest r; r.v = (v >> 16); return r; }

View File

@ -134,6 +134,8 @@ bool SolveSpace::SolveGroup(hGroup hg) {
e->GenerateEquations(&(sys.eq));
}
// And from the groups themselves
g->GenerateEquations(&(sys.eq));
bool r = sys.Solve();
FreeAllTemporary();

View File

@ -56,6 +56,7 @@ bool System::IsDragged(hParam p) {
Entity *pt = SS.entity.FindByIdNoOops(SS.GW.pending.point);
if(pt) {
switch(pt->type) {
case Entity::POINT_N_TRANS:
case Entity::POINT_IN_3D:
if(p.v == (pt->param[0]).v) return true;
if(p.v == (pt->param[1]).v) return true;
@ -63,7 +64,6 @@ bool System::IsDragged(hParam p) {
break;
case Entity::POINT_IN_2D:
case Entity::POINT_XFRMD:
if(p.v == (pt->param[0]).v) return true;
if(p.v == (pt->param[1]).v) return true;
break;
@ -399,7 +399,7 @@ bool System::Solve(void) {
SortBySensitivity();
/* dbp("write/eval jacboian=%d", GetMilliseconds() - in);
/*
for(i = 0; i < mat.m; i++) {
dbp("function %d: %s", i, mat.B.sym[i]->Print());
}

2
ui.h
View File

@ -112,6 +112,8 @@ public:
MNU_GROUP_3D,
MNU_GROUP_WRKPL,
MNU_GROUP_EXTRUDE,
MNU_GROUP_ROT,
MNU_GROUP_TRANS,
// Constrain
MNU_DISTANCE_DIA,
MNU_EQUAL,

View File

@ -125,6 +125,29 @@ Vector Quaternion::RotationN(void) {
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 v;