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