Find a memory corruption! I was getting a pointer into the entity

list, and then adding a new entity to that list, and then looking
at that pointer again. Not okay; the add operation might have
forced a realloc. I have to watch for that.

And add a "distance ratio" constraint, plus a new kind of group
that comes with its own workplane. The workplane is not solved for;
it's generated explicitly in terms of elements that are already
solved.

[git-p4: depot-paths = "//depot/solvespace/": change = 1716]
solver
Jonathan Westhues 2008-05-11 02:40:37 -08:00
parent 6042fb3e0f
commit e2263c69c8
12 changed files with 301 additions and 80 deletions

View File

@ -69,7 +69,8 @@ void Constraint::MenuConstrain(int id) {
Vector n = SS.GW.projRight.Cross(SS.GW.projUp);
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.disp.offset = n.Cross(a.Minus(b));
c.disp.offset = (c.disp.offset).WithMagnitude(50/SS.GW.scale);
} else {
c.disp.offset = Vector::MakeFrom(0, 0, 0);
}
@ -116,6 +117,21 @@ void Constraint::MenuConstrain(int id) {
AddConstraint(&c);
break;
case GraphicsWindow::MNU_RATIO:
if(gs.lineSegments == 2 && gs.n == 2) {
c.type = LENGTH_RATIO;
c.entityA = gs.entity[0];
c.entityB = gs.entity[1];
} else {
Error("Bad selection for length ratio constraint.");
return;
}
c.exprA = Expr::FromString("0")->DeepCopyKeep();
c.ModifyToSatisfy();
AddConstraint(&c);
break;
case GraphicsWindow::MNU_AT_MIDPOINT:
if(gs.lineSegments == 1 && gs.points == 1 && gs.n == 2) {
c.type = AT_MIDPOINT;
@ -379,6 +395,15 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
break;
}
case LENGTH_RATIO: {
Entity *a = SS.GetEntity(entityA);
Entity *b = SS.GetEntity(entityB);
Expr *la = Distance(workplane, a->point[0], a->point[1]);
Expr *lb = Distance(workplane, b->point[0], b->point[1]);
AddEq(l, (la->Div(lb))->Minus(exprA), 0);
break;
}
case DIAMETER: {
Entity *circle = SS.GetEntity(entityA);
Expr *r = (SS.GetEntity(circle->distance))->DistanceGetExpr();

View File

@ -6,6 +6,7 @@ bool Constraint::HasLabel(void) {
case PT_PLANE_DISTANCE:
case PT_PT_DISTANCE:
case DIAMETER:
case LENGTH_RATIO:
return true;
default:
@ -249,7 +250,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
case PARALLEL: {
for(int i = 0; i < 2; i++) {
Entity *e = SS.GetEntity(i == 0 ? entityA : entityB);
Vector n = e->VectorGetExprs().Eval();
Vector n = e->VectorGetNum();
n = n.WithMagnitude(25/SS.GW.scale);
Vector u = (gn.Cross(n)).WithMagnitude(4/SS.GW.scale);
Vector p = e->VectorGetRefPoint();
@ -260,17 +261,23 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
break;
}
case LENGTH_RATIO:
case EQUAL_LENGTH_LINES: {
Vector a, b;
for(int i = 0; i < 2; i++) {
Entity *e = SS.GetEntity(i == 0 ? entityA : entityB);
Vector a = SS.GetEntity(e->point[0])->PointGetNum();
Vector b = SS.GetEntity(e->point[1])->PointGetNum();
a = SS.GetEntity(e->point[0])->PointGetNum();
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);
LineDrawOrGetDistance(m.Minus(n), m.Plus(n));
}
if(type == LENGTH_RATIO) {
Vector ref = ((a.Plus(b)).ScaledBy(0.5)).Plus(disp.offset);
DoLabel(ref, labelPos, gr, gu);
}
break;
}

1
dsc.h
View File

@ -52,6 +52,7 @@ public:
Vector ScaledBy(double s);
Vector ProjectInto(hEntity wrkpl);
double DivPivoting(Vector delta);
Vector ClosestOrtho(void);
};
class Point2d {

View File

@ -1,8 +1,13 @@
#include "solvespace.h"
char *Entity::DescriptionString(void) {
Request *r = SS.GetRequest(h.request());
return r->DescriptionString();
if(h.isFromRequest()) {
Request *r = SS.GetRequest(h.request());
return r->DescriptionString();
} else {
Group *g = SS.GetGroup(h.group());
return g->DescriptionString();
}
}
bool Entity::HasVector(void) {
@ -35,6 +40,22 @@ ExprVector Entity::VectorGetExprs(void) {
}
}
Vector Entity::VectorGetNum(void) {
switch(type) {
case LINE_SEGMENT:
return (SS.GetEntity(point[0])->PointGetNum()).Minus(
SS.GetEntity(point[1])->PointGetNum());
case NORMAL_IN_3D:
case NORMAL_IN_2D:
case NORMAL_N_COPY:
case NORMAL_N_ROT:
return NormalN();
default: oops();
}
}
Vector Entity::VectorGetRefPoint(void) {
switch(type) {
case LINE_SEGMENT:
@ -111,6 +132,7 @@ bool Entity::IsPoint(void) {
switch(type) {
case POINT_IN_3D:
case POINT_IN_2D:
case POINT_N_COPY:
case POINT_N_TRANS:
case POINT_N_ROT_TRANS:
return true;
@ -289,6 +311,10 @@ void Entity::PointForceTo(Vector p) {
break;
}
case POINT_N_COPY:
// Nothing to do; it's a static copy
break;
default: oops();
}
}
@ -330,6 +356,11 @@ Vector Entity::PointGetNum(void) {
p = p.Plus(offset);
break;
}
case POINT_N_COPY:
p = numPoint;
break;
default: oops();
}
return p;
@ -383,6 +414,12 @@ ExprVector Entity::PointGetExprs(void) {
r = orig.Plus(trans);
break;
}
case POINT_N_COPY:
r.x = Expr::FromConstant(numPoint.x);
r.y = Expr::FromConstant(numPoint.y);
r.z = Expr::FromConstant(numPoint.z);
break;
default: oops();
}
return r;
@ -498,6 +535,7 @@ void Entity::DrawOrGetDistance(int order) {
}
switch(type) {
case POINT_N_COPY:
case POINT_N_TRANS:
case POINT_N_ROT_TRANS:
case POINT_IN_3D:
@ -563,7 +601,7 @@ void Entity::DrawOrGetDistance(int order) {
Vector tip = tail.Plus(v);
LineDrawOrGetDistance(tail, tip);
v = v.WithMagnitude(12);
v = v.WithMagnitude(12/SS.GW.scale);
Vector axis = q.RotationV();
LineDrawOrGetDistance(tip, tip.Minus(v.RotatedAbout(axis, 0.6)));
LineDrawOrGetDistance(tip, tip.Minus(v.RotatedAbout(axis, -0.6)));

128
file.cpp
View File

@ -13,7 +13,7 @@ void SolveSpace::NewFile(void) {
memset(&g, 0, sizeof(g));
g.visible = true;
g.name.strcpy("#references");
g.type = Group::DRAWING;
g.type = Group::DRAWING_3D;
g.h = Group::HGROUP_REFERENCES;
group.Add(&g);
@ -45,66 +45,76 @@ void SolveSpace::NewFile(void) {
const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'g', "Group.h.v", 'x', &(SS.sv.g.h.v) },
{ 'g', "Group.type", 'd', &(SS.sv.g.type) },
{ 'g', "Group.name", 'N', &(SS.sv.g.name) },
{ 'g', "Group.opA.v", 'x', &(SS.sv.g.opA.v) },
{ 'g', "Group.opB.v", 'x', &(SS.sv.g.opB.v) },
{ 'g', "Group.solveOrder", 'd', &(SS.sv.g.solveOrder) },
{ 'g', "Group.visible", 'b', &(SS.sv.g.visible) },
{ 'g', "Group.remap", 'M', &(SS.sv.g.remap) },
{ 'g', "Group.h.v", 'x', &(SS.sv.g.h.v) },
{ 'g', "Group.type", 'd', &(SS.sv.g.type) },
{ 'g', "Group.name", 'N', &(SS.sv.g.name) },
{ 'g', "Group.opA.v", 'x', &(SS.sv.g.opA.v) },
{ 'g', "Group.opB.v", 'x', &(SS.sv.g.opB.v) },
{ 'g', "Group.wrkpl.type", 'd', &(SS.sv.g.wrkpl.type) },
{ 'g', "Group.wrkpl.q.w", 'f', &(SS.sv.g.wrkpl.q.w) },
{ 'g', "Group.wrkpl.q.vx", 'f', &(SS.sv.g.wrkpl.q.vx) },
{ 'g', "Group.wrkpl.q.vy", 'f', &(SS.sv.g.wrkpl.q.vy) },
{ 'g', "Group.wrkpl.q.vz", 'f', &(SS.sv.g.wrkpl.q.vz) },
{ 'g', "Group.wrkpl.origin.v", 'x', &(SS.sv.g.wrkpl.origin.v) },
{ 'g', "Group.wrkpl.entityB.v", 'x', &(SS.sv.g.wrkpl.entityB.v)},
{ 'g', "Group.wrkpl.entityC.v", 'x', &(SS.sv.g.wrkpl.entityC.v)},
{ 'g', "Group.wrkpl.swapUV", 'b', &(SS.sv.g.wrkpl.swapUV) },
{ 'g', "Group.wrkpl.negateU", 'b', &(SS.sv.g.wrkpl.negateU) },
{ 'g', "Group.wrkpl.negateV", 'b', &(SS.sv.g.wrkpl.negateV) },
{ 'g', "Group.visible", 'b', &(SS.sv.g.visible) },
{ 'g', "Group.remap", 'M', &(SS.sv.g.remap) },
{ 'p', "Param.h.v.", 'x', &(SS.sv.p.h.v) },
{ 'p', "Param.val", 'f', &(SS.sv.p.val) },
{ 'p', "Param.h.v.", 'x', &(SS.sv.p.h.v) },
{ 'p', "Param.val", 'f', &(SS.sv.p.val) },
{ 'r', "Request.h.v", 'x', &(SS.sv.r.h.v) },
{ 'r', "Request.type", 'd', &(SS.sv.r.type) },
{ 'r', "Request.workplane.v", 'x', &(SS.sv.r.workplane.v) },
{ 'r', "Request.group.v", 'x', &(SS.sv.r.group.v) },
{ 'r', "Request.name", 'N', &(SS.sv.r.name) },
{ 'r', "Request.construction", 'b', &(SS.sv.r.construction) },
{ 'r', "Request.h.v", 'x', &(SS.sv.r.h.v) },
{ 'r', "Request.type", 'd', &(SS.sv.r.type) },
{ 'r', "Request.workplane.v", 'x', &(SS.sv.r.workplane.v) },
{ 'r', "Request.group.v", 'x', &(SS.sv.r.group.v) },
{ 'r', "Request.name", 'N', &(SS.sv.r.name) },
{ 'r', "Request.construction", 'b', &(SS.sv.r.construction) },
{ 'e', "Entity.h.v", 'x', &(SS.sv.e.h.v) },
{ 'e', "Entity.type", 'd', &(SS.sv.e.type) },
{ 'e', "Entity.group.v", 'x', &(SS.sv.e.group.v) },
{ 'e', "Entity.construction", 'b', &(SS.sv.e.construction) },
{ 'e', "Entity.param[0].v", 'x', &(SS.sv.e.param[0].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[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) },
{ 'e', "Entity.point[3].v", 'x', &(SS.sv.e.point[3].v) },
{ 'e', "Entity.normal.v", 'x', &(SS.sv.e.normal.v) },
{ 'e', "Entity.distance.v", 'x', &(SS.sv.e.distance.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) },
{ 'e', "Entity.numDistance", 'f', &(SS.sv.e.numDistance) },
{ 'e', "Entity.h.v", 'x', &(SS.sv.e.h.v) },
{ 'e', "Entity.type", 'd', &(SS.sv.e.type) },
{ 'e', "Entity.group.v", 'x', &(SS.sv.e.group.v) },
{ 'e', "Entity.construction", 'b', &(SS.sv.e.construction) },
{ 'e', "Entity.param[0].v", 'x', &(SS.sv.e.param[0].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[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) },
{ 'e', "Entity.point[3].v", 'x', &(SS.sv.e.point[3].v) },
{ 'e', "Entity.normal.v", 'x', &(SS.sv.e.normal.v) },
{ 'e', "Entity.distance.v", 'x', &(SS.sv.e.distance.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) },
{ 'e', "Entity.numDistance", 'f', &(SS.sv.e.numDistance) },
{ 'c', "Constraint.h.v", 'x', &(SS.sv.c.h.v) },
{ 'c', "Constraint.type", 'd', &(SS.sv.c.type) },
{ 'c', "Constraint.group.v", 'x', &(SS.sv.c.group.v) },
{ 'c', "Constraint.workplane.v", 'x', &(SS.sv.c.workplane.v) },
{ 'c', "Constraint.exprA", 'E', &(SS.sv.c.exprA) },
{ 'c', "Constraint.exprB", 'E', &(SS.sv.c.exprB) },
{ 'c', "Constraint.ptA.v", 'x', &(SS.sv.c.ptA.v) },
{ 'c', "Constraint.ptB.v", 'x', &(SS.sv.c.ptB.v) },
{ 'c', "Constraint.ptC.v", 'x', &(SS.sv.c.ptC.v) },
{ 'c', "Constraint.entityA.v", 'x', &(SS.sv.c.entityA.v) },
{ 'c', "Constraint.entityB.v", 'x', &(SS.sv.c.entityB.v) },
{ 'c', "Constraint.disp.offset.x", 'f', &(SS.sv.c.disp.offset.x)},
{ 'c', "Constraint.disp.offset.y", 'f', &(SS.sv.c.disp.offset.y)},
{ 'c', "Constraint.disp.offset.z", 'f', &(SS.sv.c.disp.offset.z)},
{ 'c', "Constraint.h.v", 'x', &(SS.sv.c.h.v) },
{ 'c', "Constraint.type", 'd', &(SS.sv.c.type) },
{ 'c', "Constraint.group.v", 'x', &(SS.sv.c.group.v) },
{ 'c', "Constraint.workplane.v", 'x', &(SS.sv.c.workplane.v) },
{ 'c', "Constraint.exprA", 'E', &(SS.sv.c.exprA) },
{ 'c', "Constraint.exprB", 'E', &(SS.sv.c.exprB) },
{ 'c', "Constraint.ptA.v", 'x', &(SS.sv.c.ptA.v) },
{ 'c', "Constraint.ptB.v", 'x', &(SS.sv.c.ptB.v) },
{ 'c', "Constraint.ptC.v", 'x', &(SS.sv.c.ptC.v) },
{ 'c', "Constraint.entityA.v", 'x', &(SS.sv.c.entityA.v) },
{ 'c', "Constraint.entityB.v", 'x', &(SS.sv.c.entityB.v) },
{ 'c', "Constraint.disp.offset.x", 'f', &(SS.sv.c.disp.offset.x) },
{ 'c', "Constraint.disp.offset.y", 'f', &(SS.sv.c.disp.offset.y) },
{ 'c', "Constraint.disp.offset.z", 'f', &(SS.sv.c.disp.offset.z) },
{ 0, NULL, NULL, NULL },
};
@ -264,16 +274,20 @@ bool SolveSpace::LoadFromFile(char *filename) {
LoadUsingTable(key, val);
} else if(strcmp(line, "AddGroup")==0) {
SS.group.Add(&(sv.g));
memset(&(sv.g), 0, sizeof(sv.g));
} else if(strcmp(line, "AddParam")==0) {
// params are regenerated, but we want to preload the values
// for initial guesses
SS.param.Add(&(sv.p));
memset(&(sv.p), 0, sizeof(sv.p));
} else if(strcmp(line, "AddEntity")==0) {
// entities are regenerated
} else if(strcmp(line, "AddRequest")==0) {
SS.request.Add(&(sv.r));
memset(&(sv.r), 0, sizeof(sv.r));
} else if(strcmp(line, "AddConstraint")==0) {
SS.constraint.Add(&(sv.c));
memset(&(sv.c), 0, sizeof(sv.c));
} else if(strcmp(line, "ñ÷åò±²³´SolveSpaceREVa")==0) {
// do nothing, version string
} else {

View File

@ -78,6 +78,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, NULL, 0, NULL },
{ 1, "&On Point / Curve / Plane\tShift+O", MNU_ON_ENTITY, 'O'|S, mCon },
{ 1, "E&qual Length / Radius\tShift+Q", MNU_EQUAL, 'Q'|S, mCon },
{ 1, "Length Ra&tio\tShift+T", MNU_RATIO, 'T'|S, mCon },
{ 1, "At &Midpoint\tShift+M", MNU_AT_MIDPOINT, 'M'|S, mCon },
{ 1, "S&ymmetric\tShift+Y", MNU_SYMMETRIC, 'Y'|S, mCon },
{ 1, "Para&llel\tShift+L", MNU_PARALLEL, 'L'|S, mCon },
@ -97,7 +98,7 @@ void GraphicsWindow::Init(void) {
memset(this, 0, sizeof(*this));
offset.x = offset.y = offset.z = 0;
scale = 1;
scale = 5;
projRight.x = 1; projRight.y = projRight.z = 0;
projUp.y = 1; projUp.z = projUp.x = 0;
@ -150,10 +151,11 @@ void GraphicsWindow::AnimateOnto(Quaternion quatf, Vector offsetf) {
quatf = quatf.ScaledBy(-1);
mp = mm;
}
double mo = (offset0.Minus(offsetf)).Magnitude()/scale;
double mo = (offset0.Minus(offsetf)).Magnitude()*scale;
// Animate transition, unless it's a tiny move.
SDWORD dt = (mp < 0.01 && mo < 10) ? (-20) : (SDWORD)(100 + 1000*mp);
SDWORD dt = (mp < 0.01 && mo < 10) ? (-20) :
(SDWORD)(100 + 1000*mp + 0.4*mo);
SDWORD tn, t0 = GetMilliseconds();
double s = 0;
do {
@ -559,7 +561,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
Entity *circle = SS.GetEntity(pending.circle);
Vector center = SS.GetEntity(circle->point[0])->PointGetNum();
Point2d c2 = ProjectPoint(center);
double r = c2.DistanceTo(mp)*scale;
double r = c2.DistanceTo(mp)/scale;
SS.GetEntity(circle->distance)->DistanceForceTo(r);
break;
}

View File

@ -24,12 +24,53 @@ void Group::MenuGroup(int id) {
memset(&g, 0, sizeof(g));
g.visible = true;
SS.GW.GroupSelection();
#define gs (SS.GW.gs)
switch(id) {
case GraphicsWindow::MNU_GROUP_3D:
g.type = DRAWING;
g.type = DRAWING_3D;
g.name.strcpy("draw-in-3d");
break;
case GraphicsWindow::MNU_GROUP_WRKPL:
g.type = DRAWING_WORKPLANE;
g.name.strcpy("draw-in-plane");
if(gs.points == 1 && gs.n == 1) {
g.wrkpl.type = WORKPLANE_BY_POINT_ORTHO;
Vector u = SS.GW.projRight, v = SS.GW.projUp;
u = u.ClosestOrtho();
v = v.Minus(u.ScaledBy(v.Dot(u)));
v = v.ClosestOrtho();
g.wrkpl.q = Quaternion::MakeFrom(u, v);
g.wrkpl.origin = gs.point[0];
} else if(gs.points == 1 && gs.lineSegments == 2 && gs.n == 3) {
g.wrkpl.type = WORKPLANE_BY_LINE_SEGMENTS;
g.wrkpl.origin = gs.point[0];
g.wrkpl.entityB = gs.entity[0];
g.wrkpl.entityC = gs.entity[1];
Vector ut = SS.GetEntity(g.wrkpl.entityB)->VectorGetNum();
Vector vt = SS.GetEntity(g.wrkpl.entityC)->VectorGetNum();
ut = ut.WithMagnitude(1);
vt = vt.WithMagnitude(1);
if(fabs(SS.GW.projUp.Dot(vt)) < fabs(SS.GW.projUp.Dot(ut))) {
SWAP(Vector, ut, vt);
g.wrkpl.swapUV = true;
}
if(SS.GW.projRight.Dot(ut) < 0) g.wrkpl.negateU = true;
if(SS.GW.projUp. Dot(vt) < 0) g.wrkpl.negateV = true;
} else {
Error("Bad selection for new drawing in workplane.");
return;
}
SS.GW.ClearSelection();
break;
case GraphicsWindow::MNU_GROUP_EXTRUDE:
g.type = EXTRUDE;
g.opA = SS.GW.activeGroup;
@ -48,6 +89,13 @@ void Group::MenuGroup(int id) {
SS.group.AddAndAssignId(&g);
SS.GenerateAll(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS);
SS.GW.activeGroup = g.h;
if(g.type == DRAWING_WORKPLANE) {
SS.GW.activeWorkplane = g.h.entity(0);
Entity *e = SS.GetEntity(SS.GW.activeWorkplane);
Quaternion quatf = e->Normal()->NormalGetNum();
Vector offsetf = (e->WorkplaneGetOffset()).ScaledBy(-1);
SS.GW.AnimateOnto(quatf, offsetf);
}
SS.TW.Show();
}
@ -68,8 +116,54 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
gn = gn.WithMagnitude(200/SS.GW.scale);
int i;
switch(type) {
case DRAWING:
return;
case DRAWING_3D:
break;
case DRAWING_WORKPLANE: {
Quaternion q;
if(wrkpl.type == WORKPLANE_BY_LINE_SEGMENTS) {
Vector u = SS.GetEntity(wrkpl.entityB)->VectorGetNum();
Vector v = SS.GetEntity(wrkpl.entityC)->VectorGetNum();
u = u.WithMagnitude(1);
Vector n = u.Cross(v);
v = (n.Cross(u)).WithMagnitude(1);
if(wrkpl.swapUV) SWAP(Vector, u, v);
if(wrkpl.negateU) u = u.ScaledBy(-1);
if(wrkpl.negateV) v = v.ScaledBy(-1);
q = Quaternion::MakeFrom(u, v);
} else if(wrkpl.type == WORKPLANE_BY_POINT_ORTHO) {
// Already given, numerically.
q = wrkpl.q;
} else oops();
Entity normal;
memset(&normal, 0, sizeof(normal));
normal.type = Entity::NORMAL_N_COPY;
normal.numNormal = q;
normal.point[0] = h.entity(2);
normal.group = h;
normal.h = h.entity(1);
entity->Add(&normal);
Entity point;
memset(&point, 0, sizeof(point));
point.type = Entity::POINT_N_COPY;
point.numPoint = SS.GetEntity(wrkpl.origin)->PointGetNum();
point.group = h;
point.h = h.entity(2);
entity->Add(&point);
Entity wp;
memset(&wp, 0, sizeof(wp));
wp.type = Entity::WORKPLANE;
wp.normal = normal.h;
wp.point[0] = point.h;
wp.group = h;
wp.h = h.entity(0);
entity->Add(&wp);
break;
}
case EXTRUDE:
AddParam(param, h.param(0), gn.x);
@ -179,6 +273,7 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
en.distance = Remap(ep->distance, a);
break;
case Entity::POINT_N_COPY:
case Entity::POINT_N_TRANS:
case Entity::POINT_N_ROT_TRANS:
case Entity::POINT_IN_3D:
@ -205,6 +300,9 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
if(a != 0) oops();
SS.entity.Add(&en);
// Any operation on these lists may break existing pointers!
ep = SS.GetEntity(in);
hEntity np = en.h;
memset(&en, 0, sizeof(en));
en.point[0] = ep->h;
@ -252,7 +350,7 @@ void Group::MakePolygons(void) {
(faces.elem[i]).Clear();
}
faces.Clear();
if(type == DRAWING) {
if(type == DRAWING_3D || type == DRAWING_WORKPLANE) {
edges.l.Clear();
int i;
for(i = 0; i < SS.entity.n; i++) {
@ -350,7 +448,7 @@ void Group::Draw(void) {
} else {
int i;
glEnable(GL_LIGHTING);
GLfloat vec[] = { 0, 0, 0.5, 1.0 };
GLfloat vec[] = { 0.3f, 0.3f, 0.3f, 1.0 };
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec);
for(i = 0; i < faces.n; i++) {
glxFillPolygon(&(faces.elem[i]));

View File

@ -42,6 +42,7 @@ public:
inline bool isFromRequest(void);
inline hRequest request(void);
inline hGroup group(void);
inline hEquation equation(int i);
};
class hParam {
@ -76,19 +77,32 @@ public:
int tag;
hGroup h;
static const int DRAWING = 5000;
static const int DRAWING_3D = 5000;
static const int DRAWING_WORKPLANE = 5001;
static const int EXTRUDE = 5010;
static const int ROTATE = 5020;
static const int TRANSLATE = 5030;
int type;
int solveOrder;
bool solved;
hGroup opA;
hGroup opB;
bool visible;
static const int WORKPLANE_BY_POINT_ORTHO = 6000;
static const int WORKPLANE_BY_LINE_SEGMENTS = 6001;
struct {
int type;
Quaternion q;
hEntity origin;
hEntity entityB;
hEntity entityC;
bool swapUV;
bool negateU;
bool negateV;
} wrkpl;
SEdgeList edges;
SList<SPolygon> faces;
struct {
@ -166,6 +180,7 @@ public:
static const int POINT_IN_2D = 2001;
static const int POINT_N_TRANS = 2010;
static const int POINT_N_ROT_TRANS = 2011;
static const int POINT_N_COPY = 2012;
static const int NORMAL_IN_3D = 3000;
static const int NORMAL_IN_2D = 3001;
@ -215,6 +230,7 @@ public:
bool HasVector(void);
ExprVector VectorGetExprs(void);
Vector VectorGetNum(void);
Vector VectorGetRefPoint(void);
// For distances
@ -308,6 +324,7 @@ public:
static const int PT_IN_PLANE = 40;
static const int PT_ON_LINE = 41;
static const int EQUAL_LENGTH_LINES = 50;
static const int LENGTH_RATIO = 51;
static const int SYMMETRIC = 60;
static const int AT_MIDPOINT = 70;
static const int HORIZONTAL = 80;
@ -411,6 +428,8 @@ inline bool hEntity::isFromRequest(void)
{ if(v & 0x80000000) return false; else return true; }
inline hRequest hEntity::request(void)
{ hRequest r; r.v = (v >> 16); return r; }
inline hGroup hEntity::group(void)
{ hGroup r; r.v = (v >> 16) & 0x3fff; return r; }
inline hEquation hEntity::equation(int i)
{ if(i != 0) oops(); hEquation r; r.v = v | 0x40000000; return r; }

View File

@ -12,6 +12,8 @@
#define max(x, y) ((x) > (y) ? (x) : (y))
#endif
#define SWAP(T, a, b) do { T temp = (a); (a) = (b); (b) = temp; } while(0)
#define isforname(c) (isalnum(c) || (c) == '_' || (c) == '-' || (c) == '#')
typedef signed long SDWORD;

View File

@ -185,7 +185,6 @@ void System::SortBySensitivity(void) {
entryWithOrigPos[j] = j;
}
#define SWAP(T, a, b) do { T temp = (a); (a) = (b); (b) = temp; } while(0)
for(j = 0; j < mat.n; j++) {
int dest = j; // we are writing to position j
// And the source is whichever position ahead of us can be swapped
@ -208,7 +207,7 @@ void System::SortBySensitivity(void) {
}
bool System::Tol(double v) {
return (fabs(v) < 0.001);
return (fabs(v) < 0.01);
}
void System::GaussJordan(void) {
@ -291,7 +290,10 @@ bool System::SolveLinearSystem(void) {
max = fabs(mat.A.num[ip][i]);
}
}
if(fabs(max) < 1e-12) return false;
// Don't give up on a singular matrix unless it's really bad; the
// assumption code is responsible for identifying that condition,
// so we're not responsible for reporting that error.
if(fabs(max) < 1e-20) return false;
// Swap row imax with row i
for(jp = 0; jp < mat.n; jp++) {
@ -317,7 +319,7 @@ bool System::SolveLinearSystem(void) {
// We've put the matrix in upper triangular form, so at this point we
// can solve by back-substitution.
for(i = mat.m - 1; i >= 0; i--) {
if(fabs(mat.A.num[i][i]) < 1e-10) return false;
if(fabs(mat.A.num[i][i]) < 1e-20) return false;
temp = mat.B.num[i];
for(j = mat.n - 1; j > i; j--) {
@ -360,7 +362,7 @@ bool System::NewtonSolve(int tag) {
// Check for convergence
converged = true;
for(i = 0; i < mat.m; i++) {
if(!Tol(mat.B.num[i])) {
if(fabs(mat.B.num[i]) > 1e-10) {
converged = false;
break;
}

1
ui.h
View File

@ -117,6 +117,7 @@ public:
// Constrain
MNU_DISTANCE_DIA,
MNU_EQUAL,
MNU_RATIO,
MNU_ON_ENTITY,
MNU_SYMMETRIC,
MNU_AT_MIDPOINT,

View File

@ -310,6 +310,18 @@ double Vector::DivPivoting(Vector delta) {
} else oops();
}
Vector Vector::ClosestOrtho(void) {
double m = max(fabs(x), max(fabs(y), fabs(z)));
if(m == fabs(x)) {
return MakeFrom((x > 0) ? 1 : -1, 0, 0);
} else if(m == fabs(y)) {
return MakeFrom(0, (y > 0) ? 1 : -1, 0);
} else if(m == fabs(z)) {
return MakeFrom(0, 0, (z > 0) ? 1 : -1);
} else oops();
}
Point2d Point2d::Plus(Point2d b) {
Point2d r;
r.x = x + b.x;