diff --git a/CHANGELOG.md b/CHANGELOG.md index d285fef4..cd74efe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Changelog --- New sketch features: + * New group, revolve. * Extrude, lathe, translate and rotate groups can use the "assembly" boolean operation, to increase performance. * The solid model of extrude and lathe groups can be suppressed, diff --git a/src/graphicswin.cpp b/src/graphicswin.cpp index 92744399..d0999e67 100644 --- a/src/graphicswin.cpp +++ b/src/graphicswin.cpp @@ -106,6 +106,7 @@ const MenuEntry Menu[] = { { 1, NULL, Command::NONE, 0, KN, NULL }, { 1, N_("E&xtrude"), Command::GROUP_EXTRUDE, S|'x', KN, mGrp }, { 1, N_("&Lathe"), Command::GROUP_LATHE, S|'l', KN, mGrp }, +{ 1, N_("Re&volve"), Command::GROUP_REVOLVE, S|'v', KN, mGrp }, { 1, NULL, Command::NONE, 0, KN, NULL }, { 1, N_("Link / Assemble..."), Command::GROUP_LINK, S|'i', KN, mGrp }, { 1, N_("Link Recent"), Command::GROUP_RECENT, 0, KN, mGrp }, diff --git a/src/group.cpp b/src/group.cpp index 30b9270a..55248141 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -184,6 +184,30 @@ void Group::MenuGroup(Command id, Platform::Path linkFile) { g.name = C_("group-name", "lathe"); break; + case Command::GROUP_REVOLVE: + 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 = SK.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 revolve group. This group can " + "be created with:\n\n" + " * a point and a line segment or normal " + "(revolved about an axis parallel to line / " + "normal, through point)\n" + " * a line segment (revolved about line segment)\n")); + return; + } + g.type = Type::REVOLVE; + g.opA = SS.GW.activeGroup; + g.valA = 2; + g.subtype = Subtype::ONE_SIDED; + g.name = C_("group-name", "revolve"); + break; + case Command::GROUP_ROT: { if(gs.points == 1 && gs.n == 1 && SS.GW.LockedInWorkplane()) { g.predef.origin = gs.point[0]; @@ -344,7 +368,7 @@ std::string Group::DescriptionString() { void Group::Activate() { if(type == Type::EXTRUDE || type == Type::LINKED || type == Type::LATHE || - type == Type::TRANSLATE || type == Type::ROTATE) { + type == Type::REVOLVE || type == Type::TRANSLATE || type == Type::ROTATE) { SS.GW.showFaces = true; } else { SS.GW.showFaces = false; @@ -482,11 +506,61 @@ void Group::Generate(IdList *entity, CopyAs::NUMERIC); MakeLatheCircles(entity, param, he, axis_pos, axis_dir, ai); + MakeLatheSurfacesSelectable(entity, he, axis_dir); ai++; } return; } + case Type::REVOLVE: { + // this was borrowed from LATHE and ROTATE + Vector axis_pos = SK.GetEntity(predef.origin)->PointGetNum(); + Vector axis_dir = SK.GetEntity(predef.entityB)->VectorGetNum(); + + // The center of rotation + AddParam(param, h.param(0), axis_pos.x); + AddParam(param, h.param(1), axis_pos.y); + AddParam(param, h.param(2), axis_pos.z); + // The rotation quaternion + AddParam(param, h.param(3), 30 * PI / 180); + AddParam(param, h.param(4), axis_dir.x); + AddParam(param, h.param(5), axis_dir.y); + AddParam(param, h.param(6), axis_dir.z); + + int n = 2; + int ai = 1; + + for(i = 0; i < entity->n; i++) { + Entity *e = &(entity->elem[i]); + if(e->group.v != opA.v) + continue; + + e->CalculateNumerical(/*forExport=*/false); + hEntity he = e->h; + + CopyEntity(entity, SK.GetEntity(predef.origin), 0, ai, NO_PARAM, NO_PARAM, + NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, CopyAs::NUMERIC); + + for(a = 0; a < 2; a++) { + if(e->group.v != opA.v) + continue; + + e->CalculateNumerical(false); + CopyEntity(entity, e, a * 2 - (subtype == Subtype::ONE_SIDED ? 0 : (n - 1)), + (a == (n - 1)) ? REMAP_LATHE_END : REMAP_LATHE_START, h.param(0), + h.param(1), h.param(2), h.param(3), h.param(4), h.param(5), + h.param(6), CopyAs::N_ROT_AA); + } + // Arcs are not generated for revolve groups, for now, because our current arc + // entity is not chiral, and dragging a revolve may break the arc by inverting it. + // MakeLatheCircles(entity, param, he, axis_pos, axis_dir, ai); + MakeLatheSurfacesSelectable(entity, he, axis_dir); + ai++; + } + + return; + } + case Type::TRANSLATE: { // inherit meshCombine from source group Group *srcg = SK.GetGroup(opA); @@ -596,7 +670,7 @@ void Group::GenerateEquations(IdList *l) { Expr::From(h.param(5)), Expr::From(h.param(6)) }; AddEq(l, (q.Magnitude())->Minus(Expr::From(1)), 0); - } else if(type == Type::ROTATE) { + } else if(type == Type::ROTATE || type == Type::REVOLVE) { // The axis and center of rotation are specified numerically #define EC(x) (Expr::From(x)) #define EP(x) (Expr::From(h.param(x))) @@ -729,7 +803,14 @@ void Group::MakeLatheCircles(IdList *el, IdList *p el->Add(&n); en.normal = n.h; el->Add(&en); - } else if(ep->type == Entity::Type::LINE_SEGMENT) { + } +} + +void Group::MakeLatheSurfacesSelectable(IdList *el, hEntity in, Vector axis) { + Entity *ep = SK.GetEntity(in); + + Entity en = {}; + if(ep->type == Entity::Type::LINE_SEGMENT) { // An axis-perpendicular line gets revolved to form a face. Vector a = SK.GetEntity(ep->point[0])->PointGetNum(); Vector b = SK.GetEntity(ep->point[1])->PointGetNum(); diff --git a/src/groupmesh.cpp b/src/groupmesh.cpp index 19fe18f7..fea6f41f 100644 --- a/src/groupmesh.cpp +++ b/src/groupmesh.cpp @@ -191,7 +191,7 @@ void Group::GenerateShellAndMesh() { // Don't attempt a lathe or extrusion unless the source section is good: // planar and not self-intersecting. bool haveSrc = true; - if(type == Type::EXTRUDE || type == Type::LATHE) { + if(type == Type::EXTRUDE || type == Type::LATHE || type == Type::REVOLVE) { Group *src = SK.GetGroup(opA); if(src->polyError.how != PolyError::GOOD) { haveSrc = false; @@ -293,6 +293,27 @@ void Group::GenerateShellAndMesh() { for(sbls = sblss->l.First(); sbls; sbls = sblss->l.NextAfter(sbls)) { thisShell.MakeFromRevolutionOf(sbls, pt, axis, color, this); } + } else if(type == Type::REVOLVE && haveSrc) { + Group *src = SK.GetGroup(opA); + double anglef = SK.GetParam(h.param(3))->val * 4; // why the 4 is needed? + double angles = 0.0; + if(subtype != Subtype::ONE_SIDED) { + anglef *= 0.5; + angles = -anglef; + } + Vector pt = SK.GetEntity(predef.origin)->PointGetNum(), + axis = SK.GetEntity(predef.entityB)->VectorGetNum(); + axis = axis.WithMagnitude(1); + + SBezierLoopSetSet *sblss = &(src->bezierLoops); + SBezierLoopSet *sbls; + for(sbls = sblss->l.First(); sbls; sbls = sblss->l.NextAfter(sbls)) { + if(fabs(anglef - angles) < 2 * PI) { + thisShell.MakeFromHelicalRevolutionOf(sbls, pt, axis, color, this, angles, anglef); + } else { + thisShell.MakeFromRevolutionOf(sbls, pt, axis, color, this); + } + } } else if(type == Type::LINKED) { // The imported shell or mesh are copied over, with the appropriate // transformation applied. We also must remap the face entities. @@ -466,6 +487,7 @@ bool Group::IsMeshGroup() { switch(type) { case Group::Type::EXTRUDE: case Group::Type::LATHE: + case Group::Type::REVOLVE: case Group::Type::ROTATE: case Group::Type::TRANSLATE: return true; diff --git a/src/sketch.h b/src/sketch.h index b61ee529..2f568386 100644 --- a/src/sketch.h +++ b/src/sketch.h @@ -136,6 +136,7 @@ public: DRAWING_WORKPLANE = 5001, EXTRUDE = 5100, LATHE = 5101, + REVOLVE = 5102, ROTATE = 5200, TRANSLATE = 5201, LINKED = 5300 @@ -258,6 +259,7 @@ public: hEntity Remap(hEntity in, int copyNumber); void MakeExtrusionLines(EntityList *el, hEntity in); void MakeLatheCircles(IdList *el, IdList *param, hEntity in, Vector pt, Vector axis, int ai); + void MakeLatheSurfacesSelectable(IdList *el, hEntity in, Vector axis); void MakeExtrusionTopBottomFaces(EntityList *el, hEntity pt); void CopyEntity(EntityList *el, Entity *ep, int timesApplied, int remap, diff --git a/src/srf/surface.cpp b/src/srf/surface.cpp index fcd9623c..9bf28992 100644 --- a/src/srf/surface.cpp +++ b/src/srf/surface.cpp @@ -63,18 +63,19 @@ bool SSurface::IsCylinder(Vector *axis, Vector *center, double *r, return true; } -SSurface SSurface::FromRevolutionOf(SBezier *sb, Vector pt, Vector axis, - double thetas, double thetaf) -{ +// Create a surface patch by revolving and possibly translating a curve. +// Works for sections up to but not including 180 degrees. +SSurface SSurface::FromRevolutionOf(SBezier *sb, Vector pt, Vector axis, double thetas, + double thetaf, double dists, + double distf) { // s is start, f is finish SSurface ret = {}; - - ret.degm = sb->deg; ret.degn = 2; double dtheta = fabs(WRAP_SYMMETRIC(thetaf - thetas, 2*PI)); + double w = cos(dtheta / 2); - // We now wish to revolve the curve about the z axis + // Revolve the curve about the z axis int i; for(i = 0; i <= ret.degm; i++) { Vector p = sb->ctrl[i]; @@ -82,32 +83,26 @@ SSurface SSurface::FromRevolutionOf(SBezier *sb, Vector pt, Vector axis, Vector ps = p.RotatedAbout(pt, axis, thetas), pf = p.RotatedAbout(pt, axis, thetaf); - Vector ct; + // The middle control point should be at the intersection of the tangents at ps and pf. + // This is equivalent but works for 0 <= angle < 180 degrees. + Vector mid = ps.Plus(pf).ScaledBy(0.5); + Vector c = ps.ClosestPointOnLine(pt, axis); + Vector ct = mid.Minus(c).ScaledBy(1 / (w * w)).Plus(c); + + // not sure this is needed if(ps.Equals(pf)) { - // Degenerate case: a control point lies on the axis of revolution, - // so we get three coincident control points. - ct = ps; - } else { - // Normal case, the control point sweeps out a circle. - Vector c = ps.ClosestPointOnLine(pt, axis); - - Vector rs = ps.Minus(c), - rf = pf.Minus(c); - - Vector ts = axis.Cross(rs), - tf = axis.Cross(rf); - - ct = Vector::AtIntersectionOfLines(ps, ps.Plus(ts), - pf, pf.Plus(tf), - NULL, NULL, NULL); + ps = c; + ct = c; + pf = c; } - - ret.ctrl[i][0] = ps; - ret.ctrl[i][1] = ct; - ret.ctrl[i][2] = pf; + // moving along the axis can create hilical surfaces (or straight extrusion if + // thetas==thetaf) + ret.ctrl[i][0] = ps.Plus(axis.ScaledBy(dists)); + ret.ctrl[i][1] = ct.Plus(axis.ScaledBy((dists + distf) / 2)); + ret.ctrl[i][2] = pf.Plus(axis.ScaledBy(distf)); ret.weight[i][0] = sb->weight[i]; - ret.weight[i][1] = sb->weight[i]*cos(dtheta/2); + ret.weight[i][1] = sb->weight[i] * w; ret.weight[i][2] = sb->weight[i]; } @@ -611,20 +606,11 @@ void SShell::MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1, Rgb } } - -typedef struct { - hSSurface d[4]; -} Revolved; - -void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, RgbaColor color, Group *group) +bool SShell::CheckNormalAxisRelationship(SBezierLoopSet *sbls, Vector pt, Vector axis) +// Check that the direction of revolution ends up parallel to the normal of +// the sketch, on the side of the axis where the sketch is. { SBezierLoop *sbl; - - int i0 = surface.n, i; - - // Normalize the axis direction so that the direction of revolution - // ends up parallel to the normal of the sketch, on the side of the - // axis where the sketch is. Vector pto; double md = VERY_NEGATIVE; for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) { @@ -634,11 +620,11 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, // if we choose a point that lies on the axis, for example. // (And our surface will be self-intersecting if the sketch // spans the axis, so don't worry about that.) - for(i = 0; i <= sb->deg; i++) { + for(int i = 0; i <= sb->deg; i++) { Vector p = sb->ctrl[i]; double d = p.DistanceToLine(pt, axis); if(d > md) { - md = d; + md = d; pto = p; } } @@ -647,7 +633,195 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, Vector ptc = pto.ClosestPointOnLine(pt, axis), up = (pto.Minus(ptc)).WithMagnitude(1), vp = (sbls->normal).Cross(up); - if(vp.Dot(axis) < 0) { + return (vp.Dot(axis) < 0); +} + +typedef struct { + hSSurface d[100]; +} Revolved; + +// sketch must not contain the axis of revolution as a non-construction line for helix +void SShell::MakeFromHelicalRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, + RgbaColor color, Group *group, double angles, + double anglef) { + int i0 = surface.n; // number of pre-existing surfaces + SBezierLoop *sbl; + // for testing - hard code the axial distance, and number of sections. + // distance will need to be parameters in the future. + double dist = 0; + int sections = fabs(anglef - angles) / (PI / 2) + 1; + if(sections > 99) { + sections = 99; + } + double wedge = (anglef - angles) / sections; + + double dists = 0; // start distance + double distf = dist; // finish distance + + if(CheckNormalAxisRelationship(sbls, pt, axis) ^ (wedge < 0)) { + swap(angles, anglef); + swap(dists, distf); + dist = -dist; + wedge = -wedge; + } + + // Define a coordinate system to contain the original sketch, and get + // a bounding box in that csys + Vector n = sbls->normal.ScaledBy(-1); + Vector u = n.Normal(0), v = n.Normal(1); + Vector orig = sbls->point; + double umax = 1e-10, umin = 1e10; + sbls->GetBoundingProjd(u, orig, &umin, &umax); + double vmax = 1e-10, vmin = 1e10; + sbls->GetBoundingProjd(v, orig, &vmin, &vmax); + // and now fix things up so that all u and v lie between 0 and 1 + orig = orig.Plus(u.ScaledBy(umin)); + orig = orig.Plus(v.ScaledBy(vmin)); + u = u.ScaledBy(umax - umin); + v = v.ScaledBy(vmax - vmin); + + // So we can now generate the end caps of the extrusion within + // a translated and rotated (and maybe mirrored) version of that csys. + SSurface s0, s1; + s0 = SSurface::FromPlane(orig.RotatedAbout(pt, axis, angles).Plus(axis.ScaledBy(dists)), + u.RotatedAbout(axis, angles), v.RotatedAbout(axis, angles)); + s0.color = color; + s1 = SSurface::FromPlane( + orig.Plus(u).RotatedAbout(pt, axis, anglef).Plus(axis.ScaledBy(distf)), + u.ScaledBy(-1).RotatedAbout(axis, anglef), v.RotatedAbout(axis, anglef)); + s1.color = color; + hSSurface hs0 = surface.AddAndAssignId(&s0), hs1 = surface.AddAndAssignId(&s1); + + // Now we actually build and trim the swept surfaces. One loop at a time. + for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) { + int i, j; + SBezier *sb; + List hsl = {}; + + // This is where all the NURBS are created and Remapped to the generating curve + for(sb = sbl->l.First(); sb; sb = sbl->l.NextAfter(sb)) { + Revolved revs; + for(j = 0; j < sections; j++) { + if((dist == 0) && sb->deg == 1 && + (sb->ctrl[0]).DistanceToLine(pt, axis) < LENGTH_EPS && + (sb->ctrl[1]).DistanceToLine(pt, axis) < LENGTH_EPS) { + // This is a line on the axis of revolution; it does + // not contribute a surface. + revs.d[j].v = 0; + } else { + SSurface ss = SSurface::FromRevolutionOf( + sb, pt, axis, angles + (wedge)*j, angles + (wedge) * (j + 1), + dists + j * dist / sections, dists + (j + 1) * dist / sections); + ss.color = color; + if(sb->entity != 0) { + hEntity he; + he.v = sb->entity; + hEntity hface = group->Remap(he, Group::REMAP_LINE_TO_FACE); + if(SK.entity.FindByIdNoOops(hface) != NULL) { + ss.face = hface.v; + } + } + revs.d[j] = surface.AddAndAssignId(&ss); + } + } + hsl.Add(&revs); + } + // Still the same loop. Need to create trim curves + for(i = 0; i < sbl->l.n; i++) { + Revolved revs = hsl.elem[i], revsp = hsl.elem[WRAP(i - 1, sbl->l.n)]; + + sb = &(sbl->l.elem[i]); + + // we generate one more curve than we did surfaces + for(j = 0; j <= sections; j++) { + SCurve sc; + Quaternion qs = Quaternion::From(axis, angles + wedge * j); + // we want Q*(x - p) + p = Q*x + (p - Q*p) + Vector ts = + pt.Minus(qs.Rotate(pt)).Plus(axis.ScaledBy(dists + j * dist / sections)); + + // If this input curve generated a surface, then trim that + // surface with the rotated version of the input curve. + if(revs.d[0].v) { // not d[j] because crash on j==sections + sc = {}; + sc.isExact = true; + sc.exact = sb->TransformedBy(ts, qs, 1.0); + (sc.exact).MakePwlInto(&(sc.pts)); + + // the surfaces already exist so trim with this curve + if(j < sections) { + sc.surfA = revs.d[j]; + } else { + sc.surfA = hs1; // end cap + } + + if(j > 0) { + sc.surfB = revs.d[j - 1]; + } else { + sc.surfB = hs0; // staring cap + } + hSCurve hcb = curve.AddAndAssignId(&sc); + + STrimBy stb; + stb = STrimBy::EntireCurve(this, hcb, /*backwards=*/true); + (surface.FindById(sc.surfA))->trim.Add(&stb); + stb = STrimBy::EntireCurve(this, hcb, /*backwards=*/false); + (surface.FindById(sc.surfB))->trim.Add(&stb); + } else if(j == 0) { // curve was on the rotation axis and is shared by the end caps. + sc = {}; + sc.isExact = true; + sc.exact = sb->TransformedBy(ts, qs, 1.0); + (sc.exact).MakePwlInto(&(sc.pts)); + sc.surfA = hs1; // end cap + sc.surfB = hs0; // staring cap + hSCurve hcb = curve.AddAndAssignId(&sc); + + STrimBy stb; + stb = STrimBy::EntireCurve(this, hcb, /*backwards=*/true); + (surface.FindById(sc.surfA))->trim.Add(&stb); + stb = STrimBy::EntireCurve(this, hcb, /*backwards=*/false); + (surface.FindById(sc.surfB))->trim.Add(&stb); + } + + // And if this input curve and the one after it both generated + // surfaces, then trim both of those by the appropriate + // curve based on the control points. + if((j < sections) && revs.d[j].v && revsp.d[j].v) { + SSurface *ss = surface.FindById(revs.d[j]); + + sc = {}; + sc.isExact = true; + sc.exact = SBezier::From(ss->ctrl[0][0], ss->ctrl[0][1], ss->ctrl[0][2]); + sc.exact.weight[1] = ss->weight[0][1]; + (sc.exact).MakePwlInto(&(sc.pts)); + sc.surfA = revs.d[j]; + sc.surfB = revsp.d[j]; + + hSCurve hcc = curve.AddAndAssignId(&sc); + + STrimBy stb; + stb = STrimBy::EntireCurve(this, hcc, /*backwards=*/false); + (surface.FindById(sc.surfA))->trim.Add(&stb); + stb = STrimBy::EntireCurve(this, hcc, /*backwards=*/true); + (surface.FindById(sc.surfB))->trim.Add(&stb); + } + } + } + + hsl.Clear(); + } + + if(dist == 0) { + MakeFirstOrderRevolvedSurfaces(pt, axis, i0); + } +} + +void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, RgbaColor color, + Group *group) { + int i0 = surface.n; // number of pre-existing surfaces + SBezierLoop *sbl; + + if(CheckNormalAxisRelationship(sbls, pt, axis)) { axis = axis.ScaledBy(-1); } @@ -668,9 +842,8 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, // not contribute a surface. revs.d[j].v = 0; } else { - SSurface ss = SSurface::FromRevolutionOf(sb, pt, axis, - (PI/2)*j, - (PI/2)*(j+1)); + SSurface ss = SSurface::FromRevolutionOf(sb, pt, axis, (PI / 2) * j, + (PI / 2) * (j + 1), 0.0, 0.0); ss.color = color; if(sb->entity != 0) { hEntity he; @@ -747,6 +920,12 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, hsl.Clear(); } + MakeFirstOrderRevolvedSurfaces(pt, axis, i0); +} + +void SShell::MakeFirstOrderRevolvedSurfaces(Vector pt, Vector axis, int i0) { + int i; + for(i = i0; i < surface.n; i++) { SSurface *srf = &(surface.elem[i]); @@ -823,9 +1002,7 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, continue; } } - } - } void SShell::MakeFromCopyOf(SShell *a) { @@ -896,4 +1073,3 @@ void SShell::Clear() { } curve.Clear(); } - diff --git a/src/srf/surface.h b/src/srf/surface.h index 26cd7ef4..4bca7e7d 100644 --- a/src/srf/surface.h +++ b/src/srf/surface.h @@ -282,8 +282,8 @@ public: Point2d cached; static SSurface FromExtrusionOf(SBezier *spc, Vector t0, Vector t1); - static SSurface FromRevolutionOf(SBezier *sb, Vector pt, Vector axis, - double thetas, double thetaf); + static SSurface FromRevolutionOf(SBezier *sb, Vector pt, Vector axis, double thetas, + double thetaf, double dists, double distf); static SSurface FromPlane(Vector pt, Vector u, Vector v); static SSurface FromTransformationOf(SSurface *a, Vector t, Quaternion q, double scale, @@ -376,9 +376,12 @@ public: void MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1, RgbaColor color); + bool CheckNormalAxisRelationship(SBezierLoopSet *sbls, Vector pt, Vector axis); void MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, RgbaColor color, Group *group); - + void MakeFromHelicalRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, RgbaColor color, + Group *group, double angles, double anglef); + void MakeFirstOrderRevolvedSurfaces(Vector pt, Vector axis, int i0); void MakeFromUnionOf(SShell *a, SShell *b); void MakeFromDifferenceOf(SShell *a, SShell *b); void MakeFromBoolean(SShell *a, SShell *b, SSurface::CombineAs type); diff --git a/src/textscreens.cpp b/src/textscreens.cpp index b7e6ca27..38da2b87 100644 --- a/src/textscreens.cpp +++ b/src/textscreens.cpp @@ -304,14 +304,15 @@ void TextWindow::ShowGroupInfo() { if(g->type == Group::Type::LATHE) { Printf(true, " %Ftlathe plane sketch"); } else if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::ROTATE || - g->type == Group::Type::TRANSLATE) - { + g->type == Group::Type::TRANSLATE || g->type == Group::Type::REVOLVE) { if(g->type == Group::Type::EXTRUDE) { s = "extrude plane sketch"; } else if(g->type == Group::Type::TRANSLATE) { s = "translate original sketch"; } else if(g->type == Group::Type::ROTATE) { s = "rotate original sketch"; + } else if(g->type == Group::Type::REVOLVE) { + s = "revolve original sketch"; } Printf(true, " %Ft%s%E", s); @@ -362,10 +363,8 @@ void TextWindow::ShowGroupInfo() { } Printf(false, ""); - if(g->type == Group::Type::EXTRUDE || - g->type == Group::Type::LATHE || - g->type == Group::Type::LINKED) - { + if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::LATHE || + g->type == Group::Type::REVOLVE || g->type == Group::Type::LINKED) { bool un = (g->meshCombine == Group::CombineAs::UNION); bool diff = (g->meshCombine == Group::CombineAs::DIFFERENCE); bool asy = (g->meshCombine == Group::CombineAs::ASSEMBLE); @@ -384,9 +383,8 @@ void TextWindow::ShowGroupInfo() { Group::CombineAs::ASSEMBLE, (asy ? RADIO_TRUE : RADIO_FALSE)); - if(g->type == Group::Type::EXTRUDE || - g->type == Group::Type::LATHE) - { + if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::LATHE || + g->type == Group::Type::REVOLVE) { Printf(false, "%Bd %Ftcolor %E%Bz %Bd (%@, %@, %@) %f%D%Lf%Fl[change]%E", &g->color, @@ -397,9 +395,8 @@ void TextWindow::ShowGroupInfo() { &TextWindow::ScreenOpacity); } - if(g->type == Group::Type::EXTRUDE || - g->type == Group::Type::LATHE || - g->type == Group::Type::LINKED) { + if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::LATHE || + g->type == Group::Type::REVOLVE || g->type == Group::Type::LINKED) { Printf(false, " %Fd%f%LP%s suppress this group's solid model", &TextWindow::ScreenChangeGroupOption, g->suppress ? CHECK_TRUE : CHECK_FALSE); diff --git a/src/ui.h b/src/ui.h index 408d6534..d9e78f3c 100644 --- a/src/ui.h +++ b/src/ui.h @@ -126,6 +126,7 @@ enum class Command : uint32_t { GROUP_WRKPL, GROUP_EXTRUDE, GROUP_LATHE, + GROUP_REVOLVE, GROUP_ROT, GROUP_TRANS, GROUP_LINK,