From 8498a99588de8b533d2053b8f0406deca4705161 Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Fri, 6 Jun 2008 03:35:28 -0800 Subject: [PATCH] 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] --- Makefile | 1 + constraint.cpp | 8 ++++---- dsc.h | 2 ++ graphicswin.cpp | 16 +++++++++++----- group.cpp | 37 +++++++++++++++++++++++++++++++------ groupmesh.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++++- polygon.cpp | 4 ++++ polygon.h | 1 + sketch.h | 9 +++++---- textwin.cpp | 8 +++++++- ui.h | 1 + util.cpp | 11 +++++++++++ wishlist.txt | 3 +-- 13 files changed, 125 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 7b576b6..c38ead2 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/constraint.cpp b/constraint.cpp index e25bbce..47b0b19 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -673,8 +673,8 @@ void Constraint::Generate(IdList *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 *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; } diff --git a/dsc.h b/dsc.h index 14b09f8..50f0254 100644 --- a/dsc.h +++ b/dsc.h @@ -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); diff --git a/graphicswin.cpp b/graphicswin.cpp index f11dc00..b1454eb 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -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()) { diff --git a/group.cpp b/group.cpp index 44c2fe7..6d4cbfa 100644 --- a/group.cpp +++ b/group.cpp @@ -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, break; } + case LATHE: { + break; + } + case TRANSLATE: { // The translation vector AddParam(param, h.param(0), gp.x); diff --git a/groupmesh.cpp b/groupmesh.cpp index 46f4b6a..11c87da 100644 --- a/groupmesh.cpp +++ b/groupmesh.cpp @@ -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 diff --git a/polygon.cpp b/polygon.cpp index ded6ded..5f501a2 100644 --- a/polygon.cpp +++ b/polygon.cpp @@ -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; diff --git a/polygon.h b/polygon.h index 87b3f74..96a5077 100644 --- a/polygon.h +++ b/polygon.h @@ -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); }; diff --git a/sketch.h b/sketch.h index 858a0a6..3969fa8 100644 --- a/sketch.h +++ b/sketch.h @@ -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; diff --git a/textwin.cpp b/textwin.cpp index d4a682d..5f91642 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -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); diff --git a/ui.h b/ui.h index 0ad5473..092af01 100644 --- a/ui.h +++ b/ui.h @@ -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, diff --git a/util.cpp b/util.cpp index 3e305ac..ccd0626 100644 --- a/util.cpp +++ b/util.cpp @@ -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); } diff --git a/wishlist.txt b/wishlist.txt index 5e843c4..fe26e4b 100644 --- a/wishlist.txt +++ b/wishlist.txt @@ -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