Add preliminary lathe (solid of revolution) support. I'm generating

just the mesh, no derived entities (but I suppose that I could turn
all points into circles).

And fix some bugs where equations didn't get unique IDs, and make
it possible to lock on to the group's workplane automatically, if
you press W while free in 3d with no workplane selected.

[git-p4: depot-paths = "//depot/solvespace/": change = 1780]
This commit is contained in:
Jonathan Westhues 2008-06-06 03:35:28 -08:00
parent dc15d667e3
commit 8498a99588
13 changed files with 125 additions and 23 deletions

View File

@ -41,6 +41,7 @@ clean:
$(OBJDIR)/solvespace.exe: $(SSOBJS) $(W32OBJS) $(FREEZE)
@$(CC) $(DEFINES) $(CFLAGS) -Fe$(OBJDIR)/solvespace.exe $(SSOBJS) $(W32OBJS) $(FREEZE) $(LIBS)
editbin /nologo /STACK:8388608 $(OBJDIR)/solvespace.exe
@echo solvespace.exe
$(SSOBJS): $(@B).cpp $(HEADERS)

View File

@ -673,8 +673,8 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
Expr *au, *av, *bu, *bv;
ea->PointGetExprsInWorkplane(plane->h, &au, &av);
eb->PointGetExprsInWorkplane(plane->h, &bu, &bv);
AddEq(l, au->Minus(bu), 0);
AddEq(l, av->Minus(bv), 1);
AddEq(l, au->Minus(bu), 1);
AddEq(l, av->Minus(bv), 2);
} else {
Entity *plane = SS.GetEntity(entityA);
Entity *a = SS.GetEntity(ptA);
@ -717,10 +717,10 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
if(type == SYMMETRIC_HORIZ) {
AddEq(l, av->Minus(bv), 0);
AddEq(l, au->Plus(bu), 0);
AddEq(l, au->Plus(bu), 1);
} else {
AddEq(l, au->Minus(bu), 0);
AddEq(l, av->Plus(bv), 0);
AddEq(l, av->Plus(bv), 1);
}
break;
}

2
dsc.h
View File

@ -53,7 +53,9 @@ public:
Vector Cross(Vector b);
double Dot(Vector b);
Vector Normal(int which);
Vector RotatedAbout(Vector orig, Vector axis, double theta);
Vector RotatedAbout(Vector axis, double theta);
double DistanceToLine(Vector p0, Vector dp);
double Magnitude(void);
Vector WithMagnitude(double s);
Vector ScaledBy(double s);

View File

@ -38,16 +38,17 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, mView },
{ 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView },
{ 0, "&New Feature", 0, 0, NULL },
{ 0, "&New Group", 0, 0, NULL },
{ 1, "&Drawing in 3d\tShift+Ctrl+D", MNU_GROUP_3D, 'D'|S|C, mGrp },
{ 1, "Drawing in Workplane\tShift+Ctrl+W", MNU_GROUP_WRKPL, 'W'|S|C, mGrp },
{ 1, NULL, 0, NULL },
{ 1, "Step &Translating\tShift+Ctrl+R", MNU_GROUP_TRANS, 'T'|S|C,mGrp },
{ 1, "Step &Rotating\tShift+Ctrl+T", MNU_GROUP_ROT, 'R'|S|C,mGrp },
{ 1, NULL, 0, 0, NULL },
{ 1, "Extrusion\tShift+Ctrl+X", MNU_GROUP_EXTRUDE, 'X'|S|C,mGrp },
{ 1, "Extrude\tShift+Ctrl+X", MNU_GROUP_EXTRUDE, 'X'|S|C,mGrp },
{ 1, "Lathe\tShift+Ctrl+L", MNU_GROUP_LATHE, 'L'|S|C,mGrp },
{ 1, NULL, 0, 0, NULL },
{ 1, "Import...\tShift+Ctrl+I", MNU_GROUP_IMPORT, 'I'|S|C,mGrp },
{ 1, "Import / Assemble...\tShift+Ctrl+I", MNU_GROUP_IMPORT, 'I'|S|C,mGrp },
{11, "Import Recent", MNU_GROUP_RECENT, 0, mGrp },
{ 0, "&Request", 0, NULL },
@ -379,9 +380,14 @@ void GraphicsWindow::MenuRequest(int id) {
switch(id) {
case MNU_SEL_WORKPLANE: {
SS.GW.GroupSelection();
Group *g = SS.GetGroup(SS.GW.activeGroup);
if(SS.GW.gs.n == 1 && SS.GW.gs.workplanes == 1) {
SS.GetGroup(SS.GW.activeGroup)->activeWorkplane =
SS.GW.gs.entity[0];
// A user-selected workplane
g->activeWorkplane = SS.GW.gs.entity[0];
} else if(g->type == Group::DRAWING_WORKPLANE) {
// The group's default workplane
g->activeWorkplane = g->h.entity(0);
}
if(!SS.GW.LockedInWorkplane()) {

View File

@ -81,6 +81,24 @@ void Group::MenuGroup(int id) {
g.name.strcpy("extrude");
break;
case GraphicsWindow::MNU_GROUP_LATHE:
if(gs.points == 1 && gs.vectors == 1 && gs.n == 2) {
g.predef.origin = gs.point[0];
g.predef.entityB = gs.vector[0];
} else if(gs.lineSegments == 1 && gs.n == 1) {
g.predef.origin = SS.GetEntity(gs.entity[0])->point[0];
g.predef.entityB = gs.entity[0];
// since a line segment is a vector
} else {
Error("Bad selection for new lathe group.");
return;
}
g.type = LATHE;
g.opA = SS.GW.activeGroup;
g.color = RGB(100, 100, 100);
g.name.strcpy("lathe");
break;
case GraphicsWindow::MNU_GROUP_ROT: {
Vector n;
if(gs.points == 1 && gs.n == 1 && SS.GW.LockedInWorkplane()) {
@ -128,17 +146,20 @@ void Group::MenuGroup(int id) {
}
SS.UndoRemember();
SS.group.AddAndAssignId(&g);
if(g.type == IMPORTED) {
Group *gg = SS.GetGroup(g.h);
if(gg->type == IMPORTED) {
SS.ReloadAllImported();
}
gg->clean = false;
SS.GW.activeGroup = gg->h;
SS.GenerateAll();
SS.GW.activeGroup = g.h;
if(g.type == DRAWING_WORKPLANE) {
SS.GetGroup(g.h)->activeWorkplane = g.h.entity(0);
if(gg->type == DRAWING_WORKPLANE) {
gg->activeWorkplane = gg->h.entity(0);
}
SS.GetGroup(g.h)->Activate();
gg->Activate();
SS.GW.AnimateOntoWorkplane();
TextWindow::ScreenSelectGroup(0, g.h.v);
TextWindow::ScreenSelectGroup(0, gg->h.v);
SS.later.showTW = true;
}
@ -262,6 +283,10 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
break;
}
case LATHE: {
break;
}
case TRANSLATE: {
// The translation vector
AddParam(param, h.param(0), gp.x);

View File

@ -110,6 +110,51 @@ void Group::GenerateMesh(void) {
}
}
edges.Clear();
} else if(type == LATHE) {
SEdgeList edges;
ZERO(&edges);
int a, i;
Group *src = SS.GetGroup(opA);
(src->poly).MakeEdgesInto(&edges);
STriMeta meta = { 0, color };
Vector orig = SS.GetEntity(predef.origin)->PointGetNum();
Vector axis = SS.GetEntity(predef.entityB)->VectorGetNum();
axis = axis.WithMagnitude(1);
int n = 20;
for(a = 0; a <= n; a++) {
double thetai = (2*PI*WRAP(a-1, n))/n, thetaf = (2*PI*a)/n;
for(i = 0; i < edges.l.n; i++) {
SEdge *edge = &(edges.l.elem[i]);
double da = (edge->a).DistanceToLine(orig, axis);
double db = (edge->b).DistanceToLine(orig, axis);
Vector ai = (edge->a).RotatedAbout(orig, axis, thetai);
Vector bi = (edge->b).RotatedAbout(orig, axis, thetai);
Vector af = (edge->a).RotatedAbout(orig, axis, thetaf);
Vector bf = (edge->b).RotatedAbout(orig, axis, thetaf);
Vector ab = (edge->b).Minus(edge->a);
Vector out = ((src->poly).normal).Cross(ab);
out = out.RotatedAbout(axis, thetai);
STriangle quad1 = STriangle::From(meta, ai, bi, af),
quad2 = STriangle::From(meta, af, bi, bf);
Vector n1 = quad1.Normal(), n2 = quad2.Normal();
Vector n = (n1.Magnitude() > n2.Magnitude()) ? n1 : n2;
if(n.Dot(out) < 0) {
quad1.FlipNormal();
quad2.FlipNormal();
}
// If one of the endpoints lies on the axis of rotation,
// then the quad is just a single triangle
if(da >= LENGTH_EPS) outm.AddTriangle(&quad1);
if(db >= LENGTH_EPS) outm.AddTriangle(&quad2);
}
}
} else if(type == IMPORTED) {
// Triangles are just copied over, with the appropriate transformation
// applied.
@ -175,7 +220,7 @@ void Group::Draw(void) {
// to show or hide just this with the "show solids" flag.
int specColor;
if(type != EXTRUDE && type != IMPORTED) {
if(type != EXTRUDE && type != IMPORTED && type != LATHE) {
specColor = RGB(25, 25, 25); // force the color to something dim
} else {
specColor = -1; // use the model color

View File

@ -29,6 +29,10 @@ bool STriangle::ContainsPointProjd(Vector n, Vector p) {
return true;
}
void STriangle::FlipNormal(void) {
SWAP(Vector, a, b);
}
STriangle STriangle::From(STriMeta meta, Vector a, Vector b, Vector c) {
STriangle tr = { 0, meta, a, b, c };
return tr;

View File

@ -113,6 +113,7 @@ public:
static STriangle From(STriMeta meta, Vector a, Vector b, Vector c);
Vector Normal(void);
void FlipNormal(void);
bool ContainsPoint(Vector p);
bool ContainsPointProjd(Vector n, Vector p);
};

View File

@ -80,10 +80,11 @@ public:
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;
static const int IMPORTED = 6000;
static const int EXTRUDE = 5100;
static const int LATHE = 5101;
static const int ROTATE = 5200;
static const int TRANSLATE = 5201;
static const int IMPORTED = 5300;
int type;
hGroup opA;

View File

@ -640,6 +640,9 @@ void TextWindow::ShowGroupInfo(void) {
&TextWindow::ScreenChangeOneOrTwoSides,
(!one ? "" : "two sides"), (!one ? "two sides" : ""));
}
if(g->type == Group::LATHE) {
Printf(true, "%FtLATHE");
}
if(g->type == Group::ROTATE || g->type == Group::TRANSLATE) {
int times = (int)(g->exprA->Eval());
@ -648,7 +651,10 @@ void TextWindow::ShowGroupInfo(void) {
g->h.v, &TextWindow::ScreenChangeExprA);
}
if(g->type == Group::EXTRUDE || g->type == Group::IMPORTED) {
if(g->type == Group::EXTRUDE ||
g->type == Group::LATHE ||
g->type == Group::IMPORTED)
{
bool un = (g->meshCombine == Group::COMBINE_AS_UNION);
bool diff = (g->meshCombine == Group::COMBINE_AS_DIFFERENCE);
bool asy = (g->meshCombine == Group::COMBINE_AS_ASSEMBLE);

1
ui.h
View File

@ -151,6 +151,7 @@ public:
MNU_GROUP_3D,
MNU_GROUP_WRKPL,
MNU_GROUP_EXTRUDE,
MNU_GROUP_LATHE,
MNU_GROUP_ROT,
MNU_GROUP_TRANS,
MNU_GROUP_IMPORT,

View File

@ -281,6 +281,12 @@ Vector Vector::Normal(int which) {
return n;
}
Vector Vector::RotatedAbout(Vector orig, Vector axis, double theta) {
Vector r = this->Minus(orig);
r = r.RotatedAbout(axis, theta);
return r.Plus(orig);
}
Vector Vector::RotatedAbout(Vector axis, double theta) {
double c = cos(theta);
double s = sin(theta);
@ -304,6 +310,11 @@ Vector Vector::RotatedAbout(Vector axis, double theta) {
return r;
}
double Vector::DistanceToLine(Vector p0, Vector dp) {
double m = dp.Magnitude();
return ((this->Minus(p0)).Cross(dp)).Magnitude() / m;
}
double Vector::Magnitude(void) {
return sqrt(x*x + y*y + z*z);
}

View File

@ -3,8 +3,6 @@
STL check for meshes, and T intersection removal
STL export
better triangle combining (Simplify()) for meshes
solids of revolution
investigate slowdown with large number of entities
DXF export
compress file format (binary?)
partitioned subsystems in the solver
@ -13,4 +11,5 @@ TTF font text
display with proper formatting/units
more measurements
reference dimensions (just to look at, no equations)
some kind of rounding