Add reference dimensions, add user-programmable lighting, and add a

configuration screen where all this can be specified.

[git-p4: depot-paths = "//depot/solvespace/": change = 1783]
This commit is contained in:
Jonathan Westhues 2008-06-10 20:22:52 -08:00
parent f2645029b8
commit d471872830
16 changed files with 424 additions and 101 deletions

View File

@ -233,6 +233,22 @@ void Constraint::MenuConstrain(int id) {
} else { } else {
c.type = SYMMETRIC_VERT; c.type = SYMMETRIC_VERT;
} }
if(gs.lineSegments == 1) {
// If this line segment is already constrained horiz or
// vert, then auto-remove that redundant constraint.
SS.constraint.ClearTags();
for(int i = 0; i < SS.constraint.n; i++) {
Constraint *ct = &(SS.constraint.elem[i]);
if(ct->type != HORIZONTAL && ct->type != VERTICAL) {
continue;
}
if(ct->entityA.v != (gs.entity[0]).v) continue;
ct->tag = 1;
}
SS.constraint.RemoveTagged();
// And no need to do anything special, since nothing
// ever depends on a constraint.
}
} else { } else {
// Symmetry with a symmetry plane specified explicitly. // Symmetry with a symmetry plane specified explicitly.
c.type = SYMMETRIC; c.type = SYMMETRIC;
@ -290,7 +306,20 @@ void Constraint::MenuConstrain(int id) {
} }
} }
Error("Must select an angle constraint."); Error("Must select an angle constraint.");
break; return;
case GraphicsWindow::MNU_REFERENCE:
if(gs.constraints == 1 && gs.n == 0) {
Constraint *c = SS.GetConstraint(gs.constraint[0]);
if(c->HasLabel()) {
(c->reference) = !(c->reference);
SS.GetGroup(c->group)->clean = false;
SS.GenerateAll();
break;
}
}
Error("Must select a constraint with associated label.");
return;
case GraphicsWindow::MNU_ANGLE: case GraphicsWindow::MNU_ANGLE:
if(gs.vectors == 2 && gs.n == 2) { if(gs.vectors == 2 && gs.n == 2) {
@ -456,9 +485,9 @@ void Constraint::ModifyToSatisfy(void) {
// that means no extra work. // that means no extra work.
IdList<Equation,hEquation> l; IdList<Equation,hEquation> l;
// An uninit IdList could lead us to free some random address, bad. // An uninit IdList could lead us to free some random address, bad.
memset(&l, 0, sizeof(l)); ZERO(&l);
// Generate the equations even if this is a reference dimension
Generate(&l); GenerateReal(&l);
if(l.n != 1) oops(); if(l.n != 1) oops();
// These equations are written in the form f(...) - d = 0, where // These equations are written in the form f(...) - d = 0, where
@ -480,6 +509,11 @@ void Constraint::AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index) {
} }
void Constraint::Generate(IdList<Equation,hEquation> *l) { void Constraint::Generate(IdList<Equation,hEquation> *l) {
if(!reference) {
GenerateReal(l);
}
}
void Constraint::GenerateReal(IdList<Equation,hEquation> *l) {
Expr *exA = NULL; Expr *exA = NULL;
if(exprA) exA = exprA->DeepCopy(); if(exprA) exA = exprA->DeepCopy();

View File

@ -759,12 +759,12 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) {
} }
} }
Vector GraphicsWindow::VectorFromProjs(double right, double up, double fwd) { Vector GraphicsWindow::VectorFromProjs(Vector rightUpForward) {
Vector n = projRight.Cross(projUp); Vector n = projRight.Cross(projUp);
Vector r = offset.ScaledBy(-1);
r = r.Plus(projRight.ScaledBy(right)); Vector r = (projRight.ScaledBy(rightUpForward.x));
r = r.Plus(projUp.ScaledBy(up)); r = r.Plus(projUp.ScaledBy(rightUpForward.y));
r = r.Plus(n.ScaledBy(fwd)); r = r.Plus(n.ScaledBy(rightUpForward.z));
return r; return r;
} }
@ -810,21 +810,25 @@ void GraphicsWindow::Paint(int w, int h) {
glClearDepth(1.0); glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Let's use two lights // Let's use two lights, at the user-specified locations
GLfloat f;
glEnable(GL_LIGHT0); glEnable(GL_LIGHT0);
GLfloat li0[] = { 0.8f, 0.8f, 0.8f, 1.0f }; f = (GLfloat)SS.lightIntensity[0];
GLfloat li0[] = { f, f, f, 1.0f };
glLightfv(GL_LIGHT0, GL_DIFFUSE, li0); glLightfv(GL_LIGHT0, GL_DIFFUSE, li0);
glLightfv(GL_LIGHT0, GL_SPECULAR, li0); glLightfv(GL_LIGHT0, GL_SPECULAR, li0);
glEnable(GL_LIGHT1); glEnable(GL_LIGHT1);
GLfloat li1[] = { 0.4f, 0.4f, 0.4f, 1.0f }; f = (GLfloat)SS.lightIntensity[1];
GLfloat li1[] = { f, f, f, 1.0f };
glLightfv(GL_LIGHT1, GL_DIFFUSE, li1); glLightfv(GL_LIGHT1, GL_DIFFUSE, li1);
glLightfv(GL_LIGHT1, GL_SPECULAR, li1); glLightfv(GL_LIGHT1, GL_SPECULAR, li1);
Vector lp; Vector lp;
lp = VectorFromProjs(-0.49*w/scale, 0.49*h/scale, 0); lp = VectorFromProjs(SS.lightPos[0]);
GLfloat lp0[4] = { (GLfloat)lp.x, (GLfloat)lp.y, (GLfloat)lp.z, 0 }; GLfloat lp0[4] = { (GLfloat)lp.x, (GLfloat)lp.y, (GLfloat)lp.z, 0 };
glLightfv(GL_LIGHT0, GL_POSITION, lp0); glLightfv(GL_LIGHT0, GL_POSITION, lp0);
lp = VectorFromProjs(0.49*w/scale, 0.10*h/scale, 0); lp = VectorFromProjs(SS.lightPos[1]);
GLfloat lp1[4] = { (GLfloat)lp.x, (GLfloat)lp.y, (GLfloat)lp.z, 0 }; GLfloat lp1[4] = { (GLfloat)lp.x, (GLfloat)lp.y, (GLfloat)lp.z, 0 };
glLightfv(GL_LIGHT1, GL_POSITION, lp1); glLightfv(GL_LIGHT1, GL_POSITION, lp1);

View File

@ -40,8 +40,24 @@ double Constraint::EllipticalInterpolation(double rx, double ry, double theta) {
return v; return v;
} }
char *Constraint::Label(void) {
static char Ret[1024];
if(type == ANGLE) {
sprintf(Ret, "%.2f", exprA->Eval());
} else if(type == LENGTH_RATIO) {
sprintf(Ret, "%.3f:1", exprA->Eval());
} else {
// exprA has units of distance
strcpy(Ret, SS.GW.ToString(exprA->Eval()));
}
if(reference) {
strcat(Ret, " REF");
}
return Ret;
}
void Constraint::DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu) { void Constraint::DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu) {
char *s = exprA->Print(); char *s = Label();
if(labelPos) { if(labelPos) {
// labelPos is from the top left corner (for the text box used to // labelPos is from the top left corner (for the text box used to
// edit things), but ref is from the center. // edit things), but ref is from the center.
@ -188,7 +204,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
double theta = atan2(disp.offset.Dot(gu), disp.offset.Dot(gr)); double theta = atan2(disp.offset.Dot(gu), disp.offset.Dot(gr));
double adj = EllipticalInterpolation( double adj = EllipticalInterpolation(
glxStrWidth(exprA->Print())/2, glxStrHeight()/2, theta); glxStrWidth(Label())/2, glxStrHeight()/2, theta);
Vector mark = ref.Minus(center); Vector mark = ref.Minus(center);
mark = mark.WithMagnitude(mark.Magnitude()-r); mark = mark.WithMagnitude(mark.Magnitude()-r);
@ -333,7 +349,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
double tl = atan2(rm.Dot(gu), rm.Dot(gr)); double tl = atan2(rm.Dot(gu), rm.Dot(gr));
double adj = EllipticalInterpolation( double adj = EllipticalInterpolation(
glxStrWidth(exprA->Print())/2, glxStrHeight()/2, tl); glxStrWidth(Label())/2, glxStrHeight()/2, tl);
ref = ref.Plus(rm.WithMagnitude(adj + 3/SS.GW.scale)); ref = ref.Plus(rm.WithMagnitude(adj + 3/SS.GW.scale));
} else { } else {
// The lines are skew; no wonderful way to illustrate that. // The lines are skew; no wonderful way to illustrate that.

View File

@ -4,7 +4,9 @@ void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
if(dogd.drawing) { if(dogd.drawing) {
// glPolygonOffset works only on polys, not lines, so do it myself // glPolygonOffset works only on polys, not lines, so do it myself
Vector adj = SS.GW.projRight.Cross(SS.GW.projUp); Vector adj = SS.GW.projRight.Cross(SS.GW.projUp);
adj = adj.ScaledBy(5/SS.GW.scale); // Draw lines from active group in front of those from previous
int delta = (group.v == SS.GW.activeGroup.v) ? 10 : 5;
adj = adj.ScaledBy(delta/SS.GW.scale);
glBegin(GL_LINES); glBegin(GL_LINES);
glxVertex3v(a.Plus(adj)); glxVertex3v(a.Plus(adj));
glxVertex3v(b.Plus(adj)); glxVertex3v(b.Plus(adj));
@ -14,6 +16,8 @@ void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
Point2d bp = SS.GW.ProjectPoint(b); Point2d bp = SS.GW.ProjectPoint(b);
double d = dogd.mp.DistanceToLine(ap, bp.Minus(ap), true); double d = dogd.mp.DistanceToLine(ap, bp.Minus(ap), true);
// A little bit easier to select in the active group
if(group.v == SS.GW.activeGroup.v) d -= 1;
dogd.dmin = min(dogd.dmin, d); dogd.dmin = min(dogd.dmin, d);
} }
dogd.refp = (a.Plus(b)).ScaledBy(0.5); dogd.refp = (a.Plus(b)).ScaledBy(0.5);
@ -164,9 +168,7 @@ void Entity::DrawOrGetDistance(void) {
glPolygonOffset(0, 0); glPolygonOffset(0, 0);
} else { } else {
Point2d pp = SS.GW.ProjectPoint(v); Point2d pp = SS.GW.ProjectPoint(v);
// Make a free point slightly easier to select, so that with dogd.dmin = pp.DistanceTo(dogd.mp) - 6;
// coincident points, we select the free one.
dogd.dmin = pp.DistanceTo(dogd.mp) - 4;
} }
break; break;
} }
@ -292,7 +294,7 @@ void Entity::DrawOrGetDistance(void) {
Vector p1 = SS.GetEntity(point[1])->PointGetNum(); Vector p1 = SS.GetEntity(point[1])->PointGetNum();
Vector p2 = SS.GetEntity(point[2])->PointGetNum(); Vector p2 = SS.GetEntity(point[2])->PointGetNum();
Vector p3 = SS.GetEntity(point[3])->PointGetNum(); Vector p3 = SS.GetEntity(point[3])->PointGetNum();
int i, n = 20; int i, n = (int)(15/sqrt(SS.meshTol));
Vector prev = p0; Vector prev = p0;
for(i = 1; i <= n; i++) { for(i = 1; i <= n; i++) {
double t = ((double)i)/n; double t = ((double)i)/n;
@ -307,7 +309,6 @@ void Entity::DrawOrGetDistance(void) {
break; break;
} }
#define CIRCLE_SIDES(r) (7 + (int)(sqrt(r*SS.GW.scale)))
case ARC_OF_CIRCLE: { case ARC_OF_CIRCLE: {
Vector c = SS.GetEntity(point[0])->PointGetNum(); Vector c = SS.GetEntity(point[0])->PointGetNum();
Vector pa = SS.GetEntity(point[1])->PointGetNum(); Vector pa = SS.GetEntity(point[1])->PointGetNum();
@ -321,7 +322,7 @@ void Entity::DrawOrGetDistance(void) {
double thetaa, thetab, dtheta; double thetaa, thetab, dtheta;
ArcGetAngles(&thetaa, &thetab, &dtheta); ArcGetAngles(&thetaa, &thetab, &dtheta);
int i, n = 3 + (int)(CIRCLE_SIDES(ra)*dtheta/(2*PI)); int i, n = 3 + (int)(SS.CircleSides(ra)*dtheta/(2*PI));
Vector prev = pa; Vector prev = pa;
for(i = 1; i <= n; i++) { for(i = 1; i <= n; i++) {
double theta = thetaa + (dtheta*i)/n; double theta = thetaa + (dtheta*i)/n;
@ -340,7 +341,7 @@ void Entity::DrawOrGetDistance(void) {
Vector center = SS.GetEntity(point[0])->PointGetNum(); Vector center = SS.GetEntity(point[0])->PointGetNum();
Vector u = q.RotationU(), v = q.RotationV(); Vector u = q.RotationU(), v = q.RotationV();
int i, c = CIRCLE_SIDES(r); int i, c = SS.CircleSides(r);
Vector prev = u.ScaledBy(r).Plus(center); Vector prev = u.ScaledBy(r).Plus(center);
for(i = 1; i <= c; i++) { for(i = 1; i <= c; i++) {
double phi = (2*PI*i)/c; double phi = (2*PI*i)/c;

View File

@ -140,6 +140,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'c', "Constraint.entityA.v", 'x', &(SS.sv.c.entityA.v) }, { 'c', "Constraint.entityA.v", 'x', &(SS.sv.c.entityA.v) },
{ 'c', "Constraint.entityB.v", 'x', &(SS.sv.c.entityB.v) }, { 'c', "Constraint.entityB.v", 'x', &(SS.sv.c.entityB.v) },
{ 'c', "Constraint.otherAngle", 'b', &(SS.sv.c.otherAngle) }, { 'c', "Constraint.otherAngle", 'b', &(SS.sv.c.otherAngle) },
{ 'c', "Constraint.reference", 'b', &(SS.sv.c.reference) },
{ 'c', "Constraint.disp.offset.x", 'f', &(SS.sv.c.disp.offset.x) }, { '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.y", 'f', &(SS.sv.c.disp.offset.y) },
{ 'c', "Constraint.disp.offset.z", 'f', &(SS.sv.c.disp.offset.z) }, { 'c', "Constraint.disp.offset.z", 'f', &(SS.sv.c.disp.offset.z) },

View File

@ -175,9 +175,7 @@ void glxFillMesh(int specColor, SMesh *m, DWORD h, DWORD s1, DWORD s2)
color = specColor; color = specColor;
} }
if(color != prevColor) { if(color != prevColor) {
GLfloat mpf[] = { ((color >> 0) & 0xff) / 255.0f, GLfloat mpf[] = { REDf(color), GREENf(color), BLUEf(color), 1.0 };
((color >> 8) & 0xff) / 255.0f,
((color >> 16) & 0xff) / 255.0f, 1.0 };
glEnd(); glEnd();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf);
prevColor = color; prevColor = color;

View File

@ -65,7 +65,6 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "&Cubic Segment\t3", MNU_CUBIC, '3', mReq }, { 1, "&Cubic Segment\t3", MNU_CUBIC, '3', mReq },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "Sym&bolic Variable\tB", 0, 'B', mReq }, { 1, "Sym&bolic Variable\tB", 0, 'B', mReq },
{ 1, "&Import From File...\tI", 0, 'I', mReq },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "To&ggle Construction\tG", MNU_CONSTRUCTION, 'G', mReq }, { 1, "To&ggle Construction\tG", MNU_CONSTRUCTION, 'G', mReq },
@ -73,6 +72,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "&Distance / Diameter\tShift+D", MNU_DISTANCE_DIA, 'D'|S, mCon }, { 1, "&Distance / Diameter\tShift+D", MNU_DISTANCE_DIA, 'D'|S, mCon },
{ 1, "A&ngle\tShift+N", MNU_ANGLE, 'N'|S, mCon }, { 1, "A&ngle\tShift+N", MNU_ANGLE, 'N'|S, mCon },
{ 1, "Other S&upplementary Angle\tShift+U", MNU_OTHER_ANGLE, 'U'|S, mCon }, { 1, "Other S&upplementary Angle\tShift+U", MNU_OTHER_ANGLE, 'U'|S, mCon },
{ 1, "Toggle &Reference Dim\tShift+R", MNU_REFERENCE, 'R'|S, mCon },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "&Horizontal\tShift+H", MNU_HORIZONTAL, 'H'|S, mCon }, { 1, "&Horizontal\tShift+H", MNU_HORIZONTAL, 'H'|S, mCon },
{ 1, "&Vertical\tShift+V", MNU_VERTICAL, 'V'|S, mCon }, { 1, "&Vertical\tShift+V", MNU_VERTICAL, 'V'|S, mCon },
@ -83,7 +83,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "At &Midpoint\tShift+M", MNU_AT_MIDPOINT, 'M'|S, mCon }, { 1, "At &Midpoint\tShift+M", MNU_AT_MIDPOINT, 'M'|S, mCon },
{ 1, "S&ymmetric\tShift+Y", MNU_SYMMETRIC, 'Y'|S, mCon }, { 1, "S&ymmetric\tShift+Y", MNU_SYMMETRIC, 'Y'|S, mCon },
{ 1, "Para&llel\tShift+L", MNU_PARALLEL, 'L'|S, mCon }, { 1, "Para&llel\tShift+L", MNU_PARALLEL, 'L'|S, mCon },
{ 1, "Same O&rientation\tShift+R", MNU_ORIENTED_SAME, 'R'|S, mCon }, { 1, "Same Orient&ation\tShift+A", MNU_ORIENTED_SAME, 'A'|S, mCon },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
{ 1, "Sym&bolic Equation\tShift+B", 0, 'B'|S, NULL }, { 1, "Sym&bolic Equation\tShift+B", 0, 'B'|S, NULL },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, NULL },
@ -187,6 +187,59 @@ void GraphicsWindow::AnimateOntoWorkplane(void) {
InvalidateGraphics(); InvalidateGraphics();
} }
void GraphicsWindow::HandlePointForZoomToFit(Vector p,
Point2d *pmax, Point2d *pmin)
{
Point2d p2 = ProjectPoint(p);
pmax->x = max(pmax->x, p2.x);
pmax->y = max(pmax->y, p2.y);
pmin->x = min(pmin->x, p2.x);
pmin->y = min(pmin->y, p2.y);
}
void GraphicsWindow::ZoomToFit(void) {
int i, j;
Point2d pmax = { -1e12, -1e12 }, pmin = { 1e12, 1e12 };
HandlePointForZoomToFit(Vector::From(0, 0, 0), &pmax, &pmin);
for(i = 0; i < SS.entity.n; i++) {
Entity *e = &(SS.entity.elem[i]);
if(!e->IsPoint()) continue;
if(!e->IsVisible()) continue;
HandlePointForZoomToFit(e->PointGetNum(), &pmax, &pmin);
}
Group *g = SS.GetGroup(activeGroup);
for(i = 0; i < g->mesh.l.n; i++) {
STriangle *tr = &(g->mesh.l.elem[i]);
HandlePointForZoomToFit(tr->a, &pmax, &pmin);
HandlePointForZoomToFit(tr->b, &pmax, &pmin);
HandlePointForZoomToFit(tr->c, &pmax, &pmin);
}
for(i = 0; i < g->poly.l.n; i++) {
SContour *sc = &(g->poly.l.elem[i]);
for(j = 0; j < sc->l.n; j++) {
HandlePointForZoomToFit(sc->l.elem[j].p, &pmax, &pmin);
}
}
pmax = pmax.ScaledBy(1/scale);
pmin = pmin.ScaledBy(1/scale);
double xm = (pmax.x + pmin.x)/2, ym = (pmax.y + pmin.y)/2;
double dx = pmax.x - pmin.x, dy = pmax.y - pmin.y;
offset = offset.Plus(projRight.ScaledBy(-xm)).Plus(
projUp. ScaledBy(-ym));
if(dx == 0 && dy == 0) {
scale = 5;
} else {
double scalex = 1e12, scaley = 1e12;
if(dx != 0) scalex = 0.9*width /dx;
if(dy != 0) scaley = 0.9*height/dy;
scale = min(100, min(scalex, scaley));
}
}
void GraphicsWindow::MenuView(int id) { void GraphicsWindow::MenuView(int id) {
switch(id) { switch(id) {
case MNU_ZOOM_IN: case MNU_ZOOM_IN:
@ -198,6 +251,7 @@ void GraphicsWindow::MenuView(int id) {
break; break;
case MNU_ZOOM_TO_FIT: case MNU_ZOOM_TO_FIT:
SS.GW.ZoomToFit();
break; break;
case MNU_SHOW_TEXT_WND: case MNU_SHOW_TEXT_WND:

View File

@ -123,7 +123,17 @@ void Group::GenerateMesh(void) {
Vector axis = SS.GetEntity(predef.entityB)->VectorGetNum(); Vector axis = SS.GetEntity(predef.entityB)->VectorGetNum();
axis = axis.WithMagnitude(1); axis = axis.WithMagnitude(1);
int n = 20; // Calculate the max radius, to determine fineness of mesh
double r, rmax = 0;
for(i = 0; i < edges.l.n; i++) {
SEdge *edge = &(edges.l.elem[i]);
r = (edge->a).DistanceToLine(orig, axis);
rmax = max(r, rmax);
r = (edge->b).DistanceToLine(orig, axis);
rmax = max(r, rmax);
}
int n = SS.CircleSides(rmax);
for(a = 0; a <= n; a++) { for(a = 0; a <= n; a++) {
double thetai = (2*PI*WRAP(a-1, n))/n, thetaf = (2*PI*a)/n; double thetai = (2*PI*WRAP(a-1, n))/n, thetaf = (2*PI*a)/n;
for(i = 0; i < edges.l.n; i++) { for(i = 0; i < edges.l.n; i++) {
@ -139,18 +149,23 @@ void Group::GenerateMesh(void) {
Vector ab = (edge->b).Minus(edge->a); Vector ab = (edge->b).Minus(edge->a);
Vector out = ((src->poly).normal).Cross(ab); Vector out = ((src->poly).normal).Cross(ab);
// This is a vector, not a point, so no origin for rotation
out = out.RotatedAbout(axis, thetai); out = out.RotatedAbout(axis, thetai);
// The line sweeps out a quad, so two triangles
STriangle quad1 = STriangle::From(meta, ai, bi, af), STriangle quad1 = STriangle::From(meta, ai, bi, af),
quad2 = STriangle::From(meta, af, bi, bf); quad2 = STriangle::From(meta, af, bi, bf);
// Could be only one of the triangles has area; be sure
// to use that one for normal checking, then.
Vector n1 = quad1.Normal(), n2 = quad2.Normal(); Vector n1 = quad1.Normal(), n2 = quad2.Normal();
Vector n = (n1.Magnitude() > n2.Magnitude()) ? n1 : n2; Vector n = (n1.Magnitude() > n2.Magnitude()) ? n1 : n2;
if(n.Dot(out) < 0) { if(n.Dot(out) < 0) {
quad1.FlipNormal(); quad1.FlipNormal();
quad2.FlipNormal(); quad2.FlipNormal();
} }
// If one of the endpoints lies on the axis of rotation, // One or both of the endpoints might lie on the axis of
// then the quad is just a single triangle // rotation, in which case its triangle is zero-area.
if(da >= LENGTH_EPS) outm.AddTriangle(&quad1); if(da >= LENGTH_EPS) outm.AddTriangle(&quad1);
if(db >= LENGTH_EPS) outm.AddTriangle(&quad2); if(db >= LENGTH_EPS) outm.AddTriangle(&quad2);
} }

View File

@ -220,7 +220,6 @@ void SMesh::MakeFromUnion(SMesh *a, SMesh *b) {
} }
void SMesh::MakeFromDifference(SMesh *a, SMesh *b) { void SMesh::MakeFromDifference(SMesh *a, SMesh *b) {
SDWORD in = GetMilliseconds();
SBsp3 *bspa = SBsp3::FromMesh(a); SBsp3 *bspa = SBsp3::FromMesh(a);
SBsp3 *bspb = SBsp3::FromMesh(b); SBsp3 *bspb = SBsp3::FromMesh(b);
@ -231,8 +230,6 @@ void SMesh::MakeFromDifference(SMesh *a, SMesh *b) {
flipNormal = false; flipNormal = false;
keepCoplanar = false; keepCoplanar = false;
AddAgainstBsp(a, bspb); AddAgainstBsp(a, bspb);
dbp("dt = %d", GetMilliseconds() - in);
dbp("tris = %d", l.n);
} }
bool SMesh::MakeFromInterferenceCheck(SMesh *srca, SMesh *srcb, SMesh *error) { bool SMesh::MakeFromInterferenceCheck(SMesh *srca, SMesh *srcb, SMesh *error) {

View File

@ -461,6 +461,7 @@ public:
void LineDrawOrGetDistance(Vector a, Vector b); void LineDrawOrGetDistance(Vector a, Vector b);
void DrawOrGetDistance(Vector *labelPos); void DrawOrGetDistance(Vector *labelPos);
double EllipticalInterpolation(double rx, double ry, double theta); double EllipticalInterpolation(double rx, double ry, double theta);
char *Label(void);
void DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu); void DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu);
void DoProjectedPoint(Vector *p); void DoProjectedPoint(Vector *p);
@ -472,6 +473,7 @@ public:
bool HasLabel(void); bool HasLabel(void);
void Generate(IdList<Equation,hEquation> *l); void Generate(IdList<Equation,hEquation> *l);
void GenerateReal(IdList<Equation,hEquation> *l);
// Some helpers when generating symbolic constraint equations // Some helpers when generating symbolic constraint equations
void ModifyToSatisfy(void); void ModifyToSatisfy(void);
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index); void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);

View File

@ -3,9 +3,41 @@
SolveSpace SS; SolveSpace SS;
void SolveSpace::Init(char *cmdLine) { void SolveSpace::Init(char *cmdLine) {
int i;
// Default list of colors for the model material
modelColor[0] = CnfThawDWORD(RGB(150, 150, 150), "ModelColor_0");
modelColor[1] = CnfThawDWORD(RGB(100, 100, 100), "ModelColor_1");
modelColor[2] = CnfThawDWORD(RGB( 30, 30, 30), "ModelColor_2");
modelColor[3] = CnfThawDWORD(RGB(150, 0, 0), "ModelColor_3");
modelColor[4] = CnfThawDWORD(RGB( 0, 100, 0), "ModelColor_4");
modelColor[5] = CnfThawDWORD(RGB( 0, 80, 80), "ModelColor_5");
modelColor[6] = CnfThawDWORD(RGB( 0, 0, 130), "ModelColor_6");
modelColor[7] = CnfThawDWORD(RGB( 80, 0, 80), "ModelColor_7");
// Light intensities
lightIntensity[0] = ((int)CnfThawDWORD( 700, "LightIntensity_0"))/1000.0;
lightIntensity[1] = ((int)CnfThawDWORD( 400, "LightIntensity_1"))/1000.0;
// Light positions
lightPos[0].x = ((int)CnfThawDWORD(-500, "LightPos_0_Right" ))/1000.0;
lightPos[0].y = ((int)CnfThawDWORD( 500, "LightPos_0_Up" ))/1000.0;
lightPos[0].z = ((int)CnfThawDWORD( 0, "LightPos_0_Forward" ))/1000.0;
lightPos[1].x = ((int)CnfThawDWORD( 500, "LightPos_1_Right" ))/1000.0;
lightPos[1].y = ((int)CnfThawDWORD( 0, "LightPos_1_Up" ))/1000.0;
lightPos[1].z = ((int)CnfThawDWORD( 0, "LightPos_1_Forward" ))/1000.0;
// Mesh tolerance
meshTol = ((int)CnfThawDWORD(1000, "MeshTolerance"))/1000.0;
// Recent files menus
for(i = 0; i < MAX_RECENT; i++) {
char name[100];
sprintf(name, "RecentFile_%d", i);
strcpy(RecentFile[i], "");
CnfThawString(RecentFile[i], MAX_PATH, name);
}
RefreshRecentMenus();
// Start with either an empty file, or the file specified on the
// command line.
NewFile(); NewFile();
AfterNewFile(); AfterNewFile();
if(strlen(cmdLine) != 0) { if(strlen(cmdLine) != 0) {
if(LoadFromFile(cmdLine)) { if(LoadFromFile(cmdLine)) {
strcpy(saveFile, cmdLine); strcpy(saveFile, cmdLine);
@ -13,16 +45,49 @@ void SolveSpace::Init(char *cmdLine) {
NewFile(); NewFile();
} }
} }
AfterNewFile(); AfterNewFile();
} }
void SolveSpace::Exit(void) {
int i;
char name[100];
// Recent files
for(i = 0; i < MAX_RECENT; i++) {
sprintf(name, "RecentFile_%d", i);
CnfFreezeString(RecentFile[i], name);
}
// Model colors
for(i = 0; i < MODEL_COLORS; i++) {
sprintf(name, "ModelColor_%d", i);
CnfFreezeDWORD(modelColor[i], name);
}
// Light intensities
CnfFreezeDWORD((int)(lightIntensity[0]*1000), "LightIntensity_0");
CnfFreezeDWORD((int)(lightIntensity[1]*1000), "LightIntensity_1");
// Light positions
CnfFreezeDWORD((int)(lightPos[0].x*1000), "LightPos_0_Right");
CnfFreezeDWORD((int)(lightPos[0].y*1000), "LightPos_0_Up");
CnfFreezeDWORD((int)(lightPos[0].z*1000), "LightPos_0_Forward");
CnfFreezeDWORD((int)(lightPos[1].x*1000), "LightPos_1_Right");
CnfFreezeDWORD((int)(lightPos[1].y*1000), "LightPos_1_Up");
CnfFreezeDWORD((int)(lightPos[1].z*1000), "LightPos_1_Forward");
// Mesh tolerance
CnfFreezeDWORD((int)(meshTol*1000), "MeshTolerance");
ExitNow();
}
void SolveSpace::DoLater(void) { void SolveSpace::DoLater(void) {
if(later.generateAll) GenerateAll(); if(later.generateAll) GenerateAll();
if(later.showTW) TW.Show(); if(later.showTW) TW.Show();
ZERO(&later); ZERO(&later);
} }
int SolveSpace::CircleSides(double r) {
int s = 7 + (int)(sqrt(r*SS.GW.scale/meshTol));
return min(s, 40);
}
void SolveSpace::AfterNewFile(void) { void SolveSpace::AfterNewFile(void) {
ReloadAllImported(); ReloadAllImported();
GenerateAll(-1, -1); GenerateAll(-1, -1);
@ -249,6 +314,14 @@ void SolveSpace::GenerateAll(int first, int last) {
} }
} }
// And update any reference dimensions with their new values
for(i = 0; i < constraint.n; i++) {
Constraint *c = &(constraint.elem[i]);
if(c->reference) {
c->ModifyToSatisfy();
}
}
prev.Clear(); prev.Clear();
InvalidateGraphics(); InvalidateGraphics();
@ -459,7 +532,7 @@ void SolveSpace::MenuFile(int id) {
case GraphicsWindow::MNU_EXIT: case GraphicsWindow::MNU_EXIT:
if(!SS.OkayToStartNewFile()) break; if(!SS.OkayToStartNewFile()) break;
ExitNow(); SS.Exit();
break; break;
default: oops(); default: oops();

View File

@ -80,6 +80,10 @@ void dbp(char *str, ...);
void Error(char *str, ...); void Error(char *str, ...);
void ExitNow(void); void ExitNow(void);
void CnfFreezeString(char *str, char *name);
void CnfFreezeDWORD(DWORD v, char *name);
void CnfThawString(char *str, int maxLen, char *name);
DWORD CnfThawDWORD(DWORD v, char *name);
void *AllocTemporary(int n); void *AllocTemporary(int n);
void FreeAllTemporary(void); void FreeAllTemporary(void);
@ -242,10 +246,21 @@ public:
void UndoClearState(UndoState *ut); void UndoClearState(UndoState *ut);
void UndoClearStack(UndoStack *uk); void UndoClearStack(UndoStack *uk);
// Little bits of extra configuration state
static const int MODEL_COLORS = 8;
int modelColor[MODEL_COLORS];
Vector lightPos[2];
double lightIntensity[2];
double meshTol;
void Init(char *cmdLine);
void Exit(void);
int CircleSides(double r);
// File load/save routines, including the additional files that get // File load/save routines, including the additional files that get
// loaded when we have import groups. // loaded when we have import groups.
FILE *fh; FILE *fh;
void Init(char *cmdLine);
void AfterNewFile(void); void AfterNewFile(void);
static void RemoveFromRecentList(char *file); static void RemoveFromRecentList(char *file);
static void AddToRecentList(char *file); static void AddToRecentList(char *file);

View File

@ -31,16 +31,6 @@ void TextWindow::ClearSuper(void) {
shown = &(showns[shownIndex]); shown = &(showns[shownIndex]);
ClearScreen(); ClearScreen();
Show(); Show();
// Default list of colors for the model material
modelColor[0] = RGB(150, 150, 150);
modelColor[1] = RGB(100, 100, 100);
modelColor[2] = RGB( 30, 30, 30);
modelColor[3] = RGB(150, 0, 0);
modelColor[4] = RGB( 0, 100, 0);
modelColor[5] = RGB( 0, 80, 80);
modelColor[6] = RGB( 0, 0, 130);
modelColor[7] = RGB( 80, 0, 80);
} }
void TextWindow::ClearScreen(void) { void TextWindow::ClearScreen(void) {
@ -97,6 +87,16 @@ void TextWindow::Printf(bool halfLine, char *fmt, ...) {
sprintf(buf, "%08x", v); sprintf(buf, "%08x", v);
break; break;
} }
case '@': {
double v = va_arg(vl, double);
sprintf(buf, "%.2f", v);
break;
}
case '2': {
double v = va_arg(vl, double);
sprintf(buf, "%s%.2f", v < 0 ? "" : " ", v);
break;
}
case '3': { case '3': {
double v = va_arg(vl, double); double v = va_arg(vl, double);
sprintf(buf, "%s%.3f", v < 0 ? "" : " ", v); sprintf(buf, "%s%.3f", v < 0 ? "" : " ", v);
@ -201,10 +201,12 @@ void TextWindow::Show(void) {
if(SS.GW.pending.description) { if(SS.GW.pending.description) {
// A pending operation (that must be completed with the mouse in // A pending operation (that must be completed with the mouse in
// the graphics window) will preempt our usual display. // the graphics window) will preempt our usual display.
HideTextEditControl();
ShowHeader(false); ShowHeader(false);
Printf(false, ""); Printf(false, "");
Printf(false, "%s", SS.GW.pending.description); Printf(false, "%s", SS.GW.pending.description);
} else if(gs.n > 0) { } else if(gs.n > 0) {
HideTextEditControl();
ShowHeader(false); ShowHeader(false);
DescribeSelection(); DescribeSelection();
} else { } else {
@ -216,6 +218,7 @@ void TextWindow::Show(void) {
case SCREEN_LIST_OF_GROUPS: ShowListOfGroups(); break; case SCREEN_LIST_OF_GROUPS: ShowListOfGroups(); break;
case SCREEN_GROUP_INFO: ShowGroupInfo(); break; case SCREEN_GROUP_INFO: ShowGroupInfo(); break;
case SCREEN_GROUP_SOLVE_INFO: ShowGroupSolveInfo(); break; case SCREEN_GROUP_SOLVE_INFO: ShowGroupSolveInfo(); break;
case SCREEN_CONFIGURATION: ShowConfiguration(); break;
} }
} }
InvalidateText(); InvalidateText();
@ -437,15 +440,12 @@ void TextWindow::ScreenToggleGroupShown(int link, DWORD v) {
} }
void TextWindow::ScreenShowGroupsSpecial(int link, DWORD v) { void TextWindow::ScreenShowGroupsSpecial(int link, DWORD v) {
int i; int i;
bool before = true;
for(i = 0; i < SS.group.n; i++) { for(i = 0; i < SS.group.n; i++) {
Group *g = &(SS.group.elem[i]); Group *g = &(SS.group.elem[i]);
if(g->h.v == SS.GW.activeGroup.v) { if(link == 's') {
before = false;
} else if(before && link == 's') {
g->visible = true; g->visible = true;
} else if(!before && link == 'h') { } else {
g->visible = false; g->visible = false;
} }
} }
@ -471,6 +471,9 @@ void TextWindow::ScreenHowGroupSolved(int link, DWORD v) {
SS.TW.OneScreenForwardTo(SCREEN_GROUP_SOLVE_INFO); SS.TW.OneScreenForwardTo(SCREEN_GROUP_SOLVE_INFO);
SS.TW.shown->group.v = v; SS.TW.shown->group.v = v;
} }
void TextWindow::ScreenShowConfiguration(int link, DWORD v) {
SS.TW.OneScreenForwardTo(SCREEN_CONFIGURATION);
}
void TextWindow::ShowListOfGroups(void) { void TextWindow::ShowListOfGroups(void) {
Printf(true, "%Ftactv show ok group-name%E"); Printf(true, "%Ftactv show ok group-name%E");
int i; int i;
@ -508,10 +511,11 @@ void TextWindow::ShowListOfGroups(void) {
if(active) afterActive = true; if(active) afterActive = true;
} }
Printf(true, " %Fl%Ls%fshow all groups before active%E", Printf(true, " %Fl%Ls%fshow all%E / %Fl%Lh%fhide all%E",
&(TextWindow::ScreenShowGroupsSpecial)); &(TextWindow::ScreenShowGroupsSpecial),
Printf(false, " %Fl%Lh%fhide all groups after active%E",
&(TextWindow::ScreenShowGroupsSpecial)); &(TextWindow::ScreenShowGroupsSpecial));
Printf(false, " %Fl%Ls%fconfiguration%E",
&(TextWindow::ScreenShowConfiguration));
} }
@ -569,8 +573,8 @@ void TextWindow::ScreenColor(int link, DWORD v) {
SS.UndoRemember(); SS.UndoRemember();
Group *g = SS.GetGroup(SS.TW.shown->group); Group *g = SS.GetGroup(SS.TW.shown->group);
if(v < 0 || v >= MODEL_COLORS) return; if(v < 0 || v >= SS.MODEL_COLORS) return;
g->color = SS.TW.modelColor[v]; g->color = SS.modelColor[v];
SS.MarkGroupDirty(g->h); SS.MarkGroupDirty(g->h);
SS.GenerateAll(); SS.GenerateAll();
SS.GW.ClearSuper(); SS.GW.ClearSuper();
@ -610,7 +614,7 @@ void TextWindow::ShowGroupInfo(void) {
Printf(true, "%FtGROUP %E%s", g->DescriptionString()); Printf(true, "%FtGROUP %E%s", g->DescriptionString());
} else { } else {
Printf(true, "%FtGROUP %E%s " Printf(true, "%FtGROUP %E%s "
"(%Fl%Ll%D%frename%E / %Fl%Ll%D%fdel%E)", "[%Fl%Ll%D%frename%E/%Fl%Ll%D%fdel%E]",
g->DescriptionString(), g->DescriptionString(),
g->h.v, &TextWindow::ScreenChangeGroupName, g->h.v, &TextWindow::ScreenChangeGroupName,
g->h.v, &TextWindow::ScreenDeleteGroup); g->h.v, &TextWindow::ScreenDeleteGroup);
@ -646,7 +650,7 @@ void TextWindow::ShowGroupInfo(void) {
if(g->type == Group::ROTATE || g->type == Group::TRANSLATE) { if(g->type == Group::ROTATE || g->type == Group::TRANSLATE) {
int times = (int)(g->exprA->Eval()); int times = (int)(g->exprA->Eval());
Printf(true, "%Ft%s%E %d time%s %Fl%Ll%D%f(change)%E", Printf(true, "%Ft%s%E %d time%s %Fl%Ll%D%f[change]%E",
s2, times, times == 1 ? "" : "s", s2, times, times == 1 ? "" : "s",
g->h.v, &TextWindow::ScreenChangeExprA); g->h.v, &TextWindow::ScreenChangeExprA);
} }
@ -681,14 +685,14 @@ void TextWindow::ShowGroupInfo(void) {
if(g->type == Group::EXTRUDE || g->type == Group::LATHE) { if(g->type == Group::EXTRUDE || g->type == Group::LATHE) {
#define TWOX(v) v v #define TWOX(v) v v
Printf(true, "%FtM_COLOR%E " TWOX(TWOX(TWOX("%Bp%D%f%Ln %Bd%E "))), Printf(true, "%FtM_COLOR%E " TWOX(TWOX(TWOX("%Bp%D%f%Ln %Bd%E "))),
0x80000000 | modelColor[0], 0, &TextWindow::ScreenColor, 0x80000000 | SS.modelColor[0], 0, &TextWindow::ScreenColor,
0x80000000 | modelColor[1], 1, &TextWindow::ScreenColor, 0x80000000 | SS.modelColor[1], 1, &TextWindow::ScreenColor,
0x80000000 | modelColor[2], 2, &TextWindow::ScreenColor, 0x80000000 | SS.modelColor[2], 2, &TextWindow::ScreenColor,
0x80000000 | modelColor[3], 3, &TextWindow::ScreenColor, 0x80000000 | SS.modelColor[3], 3, &TextWindow::ScreenColor,
0x80000000 | modelColor[4], 4, &TextWindow::ScreenColor, 0x80000000 | SS.modelColor[4], 4, &TextWindow::ScreenColor,
0x80000000 | modelColor[5], 5, &TextWindow::ScreenColor, 0x80000000 | SS.modelColor[5], 5, &TextWindow::ScreenColor,
0x80000000 | modelColor[6], 6, &TextWindow::ScreenColor, 0x80000000 | SS.modelColor[6], 6, &TextWindow::ScreenColor,
0x80000000 | modelColor[7], 7, &TextWindow::ScreenColor); 0x80000000 | SS.modelColor[7], 7, &TextWindow::ScreenColor);
} }
Printf(true, "%Ftrequests in group"); Printf(true, "%Ftrequests in group");
@ -727,13 +731,15 @@ void TextWindow::ShowGroupInfo(void) {
void TextWindow::ShowGroupSolveInfo(void) { void TextWindow::ShowGroupSolveInfo(void) {
Group *g = SS.group.FindById(shown->group); Group *g = SS.group.FindById(shown->group);
if(g->solved.how == Group::SOLVED_OKAY) {
// Go back to the default group info screen
shown->screen = SCREEN_GROUP_INFO;
Show();
return;
}
Printf(true, "%FtGROUP %E%s", g->DescriptionString()); Printf(true, "%FtGROUP %E%s", g->DescriptionString());
switch(g->solved.how) { switch(g->solved.how) {
case Group::SOLVED_OKAY:
Printf(true, " %Fsgroup solved okay%E");
break;
case Group::DIDNT_CONVERGE: case Group::DIDNT_CONVERGE:
Printf(true, " %FxSOLVE FAILED!%Fd no convergence"); Printf(true, " %FxSOLVE FAILED!%Fd no convergence");
break; break;
@ -757,6 +763,69 @@ void TextWindow::ShowGroupSolveInfo(void) {
} }
} }
void TextWindow::ScreenChangeLightPosition(int link, DWORD v) {
char str[1024];
sprintf(str, "%.2f, %.2f, %.2f", CO(SS.lightPos[v]));
ShowTextEditControl(29+2*v, 8, str);
SS.TW.edit.meaning = EDIT_LIGHT_POSITION;
SS.TW.edit.i = v;
}
void TextWindow::ScreenChangeLightIntensity(int link, DWORD v) {
char str[1024];
sprintf(str, "%.2f", SS.lightIntensity[v]);
ShowTextEditControl(29+2*v, 30, str);
SS.TW.edit.meaning = EDIT_LIGHT_INTENSITY;
SS.TW.edit.i = v;
}
void TextWindow::ScreenChangeColor(int link, DWORD v) {
char str[1024];
sprintf(str, "%.2f, %.2f, %.2f",
REDf(SS.modelColor[v]),
GREENf(SS.modelColor[v]),
BLUEf(SS.modelColor[v]));
ShowTextEditControl(9+2*v, 12, str);
SS.TW.edit.meaning = EDIT_COLOR;
SS.TW.edit.i = v;
}
void TextWindow::ScreenChangeMeshTolerance(int link, DWORD v) {
char str[1024];
sprintf(str, "%.2f", SS.meshTol);
ShowTextEditControl(37, 3, str);
SS.TW.edit.meaning = EDIT_MESH_TOLERANCE;
}
void TextWindow::ShowConfiguration(void) {
int i;
Printf(true, "%Ft material color-(r, g, b)");
for(i = 0; i < SS.MODEL_COLORS; i++) {
Printf(false, "%Bp #%d: %Bp %Bp (%@, %@, %@) %f%D%Ll%Fl[change]%E",
(i & 1) ? 'd' : 'a',
i, 0x80000000 | SS.modelColor[i],
(i & 1) ? 'd' : 'a',
REDf(SS.modelColor[i]),
GREENf(SS.modelColor[i]),
BLUEf(SS.modelColor[i]),
&ScreenChangeColor, i);
}
Printf(false, "");
Printf(false, "%Ft light position intensity");
for(i = 0; i < 2; i++) {
Printf(false, "%Bp #%d (%2,%2,%2)%Fl%D%f%Ll[c]%E "
"%2 %Fl%D%f%Ll[c]%E",
(i & 1) ? 'd' : 'a', i,
CO(SS.lightPos[i]), i, &ScreenChangeLightPosition,
SS.lightIntensity[i], i, &ScreenChangeLightIntensity);
}
Printf(false, "");
Printf(false, "%Ft mesh tolerance (smaller is finer)%E");
Printf(false, "%Ba %2 %Fl%Ll%f%D[change]%E; now %d triangles",
SS.meshTol,
&ScreenChangeMeshTolerance, 0,
SS.group.elem[SS.group.n-1].mesh.l.n);
}
void TextWindow::EditControlDone(char *s) { void TextWindow::EditControlDone(char *s) {
switch(edit.meaning) { switch(edit.meaning) {
case EDIT_TIMES_REPEATED: { case EDIT_TIMES_REPEATED: {
@ -770,7 +839,6 @@ void TextWindow::EditControlDone(char *s) {
SS.MarkGroupDirty(g->h); SS.MarkGroupDirty(g->h);
SS.later.generateAll = true; SS.later.generateAll = true;
SS.later.showTW = true;
} else { } else {
Error("Not a valid number or expression: '%s'", s); Error("Not a valid number or expression: '%s'", s);
} }
@ -792,11 +860,39 @@ void TextWindow::EditControlDone(char *s) {
Group *g = SS.GetGroup(edit.group); Group *g = SS.GetGroup(edit.group);
g->name.strcpy(s); g->name.strcpy(s);
} }
SS.later.showTW = true;
SS.unsaved = true; SS.unsaved = true;
break; break;
} }
case EDIT_LIGHT_INTENSITY:
SS.lightIntensity[edit.i] = min(1, max(0, atof(s)));
InvalidateGraphics();
break;
case EDIT_LIGHT_POSITION: {
double x, y, z;
if(sscanf(s, "%lf, %lf, %lf", &x, &y, &z)==3) {
SS.lightPos[edit.i] = Vector::From(x, y, z);
} else {
Error("Bad format: specify coordinates as x, y, z");
}
InvalidateGraphics();
break;
}
case EDIT_COLOR: {
double r, g, b;
if(sscanf(s, "%lf, %lf, %lf", &r, &g, &b)==3) {
SS.modelColor[edit.i] = RGB(r*255, g*255, b*255);
} else {
Error("Bad format: specify color as r, g, b");
}
break;
}
case EDIT_MESH_TOLERANCE: {
SS.meshTol = min(10, max(0.1, atof(s)));
SS.GenerateAll(0, INT_MAX);
break;
}
} }
SS.later.showTW = true;
HideTextEditControl(); HideTextEditControl();
edit.meaning = EDIT_NOTHING; edit.meaning = EDIT_NOTHING;
} }

25
ui.h
View File

@ -10,6 +10,9 @@ public:
#ifndef RGB #ifndef RGB
#define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16)) #define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16))
#endif #endif
#define REDf(v) ((((v) >> 0) & 0xff) / 255.0f)
#define GREENf(v) ((((v) >> 8) & 0xff) / 255.0f)
#define BLUEf(v) ((((v) >> 16) & 0xff) / 255.0f)
typedef struct { typedef struct {
char c; char c;
int color; int color;
@ -17,9 +20,6 @@ public:
static const Color fgColors[]; static const Color fgColors[];
static const Color bgColors[]; static const Color bgColors[];
static const int MODEL_COLORS = 8;
int modelColor[MODEL_COLORS];
BYTE text[MAX_ROWS][MAX_COLS]; BYTE text[MAX_ROWS][MAX_COLS];
typedef void LinkFunction(int link, DWORD v); typedef void LinkFunction(int link, DWORD v);
static const int NOT_A_LINK = 0; static const int NOT_A_LINK = 0;
@ -45,6 +45,7 @@ public:
static const int SCREEN_LIST_OF_GROUPS = 0; static const int SCREEN_LIST_OF_GROUPS = 0;
static const int SCREEN_GROUP_INFO = 1; static const int SCREEN_GROUP_INFO = 1;
static const int SCREEN_GROUP_SOLVE_INFO = 2; static const int SCREEN_GROUP_SOLVE_INFO = 2;
static const int SCREEN_CONFIGURATION = 3;
typedef struct { typedef struct {
int screen; int screen;
hGroup group; hGroup group;
@ -58,8 +59,13 @@ public:
static const int EDIT_NOTHING = 0; static const int EDIT_NOTHING = 0;
static const int EDIT_TIMES_REPEATED = 1; static const int EDIT_TIMES_REPEATED = 1;
static const int EDIT_GROUP_NAME = 2; static const int EDIT_GROUP_NAME = 2;
static const int EDIT_LIGHT_POSITION = 3;
static const int EDIT_LIGHT_INTENSITY = 4;
static const int EDIT_COLOR = 5;
static const int EDIT_MESH_TOLERANCE = 6;
struct { struct {
int meaning; int meaning;
int i;
hGroup group; hGroup group;
} edit; } edit;
@ -73,6 +79,7 @@ public:
void ShowListOfGroups(void); void ShowListOfGroups(void);
void ShowGroupInfo(void); void ShowGroupInfo(void);
void ShowGroupSolveInfo(void); void ShowGroupSolveInfo(void);
void ShowConfiguration(void);
// Special screen, based on selection // Special screen, based on selection
void DescribeSelection(void); void DescribeSelection(void);
@ -90,18 +97,23 @@ public:
static void ScreenHoverRequest(int link, DWORD v); static void ScreenHoverRequest(int link, DWORD v);
static void ScreenSelectRequest(int link, DWORD v); static void ScreenSelectRequest(int link, DWORD v);
static void ScreenSelectConstraint(int link, DWORD v); static void ScreenSelectConstraint(int link, DWORD v);
static void ScreenUnselectAll(int link, DWORD v);
static void ScreenChangeOneOrTwoSides(int link, DWORD v); static void ScreenChangeOneOrTwoSides(int link, DWORD v);
static void ScreenChangeMeshCombine(int link, DWORD v); static void ScreenChangeMeshCombine(int link, DWORD v);
static void ScreenColor(int link, DWORD v); static void ScreenColor(int link, DWORD v);
static void ScreenUnselectAll(int link, DWORD v); static void ScreenShowConfiguration(int link, DWORD v);
static void ScreenNavigation(int link, DWORD v); static void ScreenNavigation(int link, DWORD v);
// These ones do stuff with the edit control // These ones do stuff with the edit control
static void ScreenChangeExprA(int link, DWORD v); static void ScreenChangeExprA(int link, DWORD v);
static void ScreenChangeGroupName(int link, DWORD v); static void ScreenChangeGroupName(int link, DWORD v);
static void ScreenChangeLightPosition(int link, DWORD v);
static void ScreenChangeLightIntensity(int link, DWORD v);
static void ScreenChangeColor(int link, DWORD v);
static void ScreenChangeMeshTolerance(int link, DWORD v);
void EditControlDone(char *s); void EditControlDone(char *s);
}; };
@ -155,6 +167,7 @@ public:
MNU_DISTANCE_DIA, MNU_DISTANCE_DIA,
MNU_ANGLE, MNU_ANGLE,
MNU_OTHER_ANGLE, MNU_OTHER_ANGLE,
MNU_REFERENCE,
MNU_EQUAL, MNU_EQUAL,
MNU_RATIO, MNU_RATIO,
MNU_ON_ENTITY, MNU_ON_ENTITY,
@ -203,7 +216,9 @@ public:
void NormalizeProjectionVectors(void); void NormalizeProjectionVectors(void);
Point2d ProjectPoint(Vector p); Point2d ProjectPoint(Vector p);
void AnimateOntoWorkplane(void); void AnimateOntoWorkplane(void);
Vector VectorFromProjs(double right, double up, double forward); Vector VectorFromProjs(Vector rightUpForward);
void HandlePointForZoomToFit(Vector p, Point2d *pmax, Point2d *pmin);
void ZoomToFit(void);
typedef enum { typedef enum {
UNIT_MM = 0, UNIT_MM = 0,

View File

@ -71,6 +71,23 @@ void ExitNow(void) {
PostQuitMessage(0); PostQuitMessage(0);
} }
//-----------------------------------------------------------------------------
// Helpers so that we can read/write registry keys from the platform-
// independent code.
//-----------------------------------------------------------------------------
void CnfFreezeString(char *str, char *name)
{ FreezeStringF(str, FREEZE_SUBKEY, name); }
void CnfFreezeDWORD(DWORD v, char *name)
{ FreezeDWORDF(v, FREEZE_SUBKEY, name); }
void CnfThawString(char *str, int maxLen, char *name)
{ ThawStringF(str, maxLen, FREEZE_SUBKEY, name); }
DWORD CnfThawDWORD(DWORD v, char *name)
{ return ThawDWORDF(v, FREEZE_SUBKEY, name); }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// A separate heap, on which we allocate expressions. Maybe a bit faster, // A separate heap, on which we allocate expressions. Maybe a bit faster,
// since no fragmentation issues whatsoever, and it also makes it possible // since no fragmentation issues whatsoever, and it also makes it possible
@ -877,13 +894,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
InitCommonControls(); InitCommonControls();
int i;
for(i = 0; i < MAX_RECENT; i++) {
char name[100];
sprintf(name, "RecentFile_%d", i);
ThawStringF(RecentFile[i], MAX_PATH, FREEZE_SUBKEY, name);
}
// A monospaced font // A monospaced font
FixedFont = CreateFont(TEXT_HEIGHT-4, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE, FixedFont = CreateFont(TEXT_HEIGHT-4, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE,
FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
@ -936,11 +946,5 @@ done:
// Write everything back to the registry // Write everything back to the registry
FreezeWindowPos(TextWnd); FreezeWindowPos(TextWnd);
FreezeWindowPos(GraphicsWnd); FreezeWindowPos(GraphicsWnd);
for(i = 0; i < MAX_RECENT; i++) {
char name[100];
sprintf(name, "RecentFile_%d", i);
FreezeStringF(RecentFile[i], FREEZE_SUBKEY, name);
}
return 0; return 0;
} }

View File

@ -1,17 +1,15 @@
STL check for meshes, and T intersection removal STL check for meshes, and T intersection removal
STL export STL export
better triangle combining (Simplify()) for meshes better triangle combining (Simplify()) for meshes
DXF export DXF export
compress file format (binary?) compress file format (binary?)
partitioned subsystems in the solver partitioned subsystems in the solver
arbitrary color specification
specify tolerance for meshing
specify light positions (all on one configuration screen)
TTF font text TTF font text
display with proper formatting/units display with proper formatting/units
more measurements more measurements
reference dimensions (just to look at, no equations) some kind of rounding / chamfer
some kind of rounding auto-constrain translate in then-active workplane
remove back button in browser?