diff --git a/src/describescreen.cpp b/src/describescreen.cpp index 2c36d9881..a898b4aa7 100644 --- a/src/describescreen.cpp +++ b/src/describescreen.cpp @@ -80,8 +80,10 @@ void TextWindow::DescribeSelection() { case Entity::Type::POINT_IN_2D: case Entity::Type::POINT_N_TRANS: case Entity::Type::POINT_N_ROT_TRANS: + case Entity::Type::POINT_N_ROT_AXIS_TRANS: case Entity::Type::POINT_N_COPY: case Entity::Type::POINT_N_ROT_AA: + case Entity::Type::POINT_N_MIRROR: p = e->PointGetNum(); Printf(false, "%FtPOINT%E at " PT_AS_STR, COSTR(p)); break; @@ -89,6 +91,7 @@ void TextWindow::DescribeSelection() { case Entity::Type::NORMAL_IN_3D: case Entity::Type::NORMAL_IN_2D: case Entity::Type::NORMAL_N_COPY: + case Entity::Type::NORMAL_N_MIRROR: case Entity::Type::NORMAL_N_ROT: case Entity::Type::NORMAL_N_ROT_AA: { Quaternion q = e->NormalGetNum(); @@ -171,6 +174,8 @@ void TextWindow::DescribeSelection() { case Entity::Type::FACE_N_ROT_TRANS: case Entity::Type::FACE_N_ROT_AA: case Entity::Type::FACE_N_TRANS: + case Entity::Type::FACE_N_MIRROR: + case Entity::Type::FACE_N_COPY: Printf(false, "%FtPLANE FACE%E"); p = e->FaceGetNormalNum(); Printf(true, " normal = " PT_AS_NUM, CO(p)); diff --git a/src/drawentity.cpp b/src/drawentity.cpp index d00925449..a792d04c5 100644 --- a/src/drawentity.cpp +++ b/src/drawentity.cpp @@ -86,6 +86,7 @@ void Entity::GetReferencePoints(std::vector *refs) { case Type::POINT_N_ROT_TRANS: case Type::POINT_N_ROT_AA: case Type::POINT_N_ROT_AXIS_TRANS: + case Type::POINT_N_MIRROR: case Type::POINT_IN_3D: case Type::POINT_IN_2D: refs->push_back(PointGetDrawNum()); @@ -96,6 +97,7 @@ void Entity::GetReferencePoints(std::vector *refs) { case Type::NORMAL_N_ROT_AA: case Type::NORMAL_IN_3D: case Type::NORMAL_IN_2D: + case Type::NORMAL_N_MIRROR: case Type::WORKPLANE: case Type::CIRCLE: case Type::ARC_OF_CIRCLE: @@ -122,6 +124,8 @@ void Entity::GetReferencePoints(std::vector *refs) { case Type::FACE_N_ROT_AA: case Type::FACE_ROT_NORMAL_PT: case Type::FACE_N_ROT_AXIS_TRANS: + case Type::FACE_N_MIRROR: + case Type::FACE_N_COPY: break; } } @@ -549,7 +553,8 @@ void Entity::Draw(DrawAs how, Canvas *canvas) { case Type::POINT_N_ROT_AA: case Type::POINT_N_ROT_AXIS_TRANS: case Type::POINT_IN_3D: - case Type::POINT_IN_2D: { + case Type::POINT_IN_2D: + case Type::POINT_N_MIRROR: { if(how == DrawAs::HIDDEN) return; // If we're analyzing the sketch to show the degrees of freedom, @@ -594,6 +599,7 @@ void Entity::Draw(DrawAs how, Canvas *canvas) { case Type::NORMAL_N_COPY: case Type::NORMAL_N_ROT: case Type::NORMAL_N_ROT_AA: + case Type::NORMAL_N_MIRROR: case Type::NORMAL_IN_3D: case Type::NORMAL_IN_2D: { const Camera &camera = canvas->GetCamera(); @@ -831,6 +837,8 @@ void Entity::Draw(DrawAs how, Canvas *canvas) { case Type::FACE_N_ROT_AA: case Type::FACE_ROT_NORMAL_PT: case Type::FACE_N_ROT_AXIS_TRANS: + case Type::FACE_N_MIRROR: + case Type::FACE_N_COPY: // Do nothing; these are drawn with the triangle mesh return; } diff --git a/src/entity.cpp b/src/entity.cpp index a0f2f9461..6d26718ee 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -246,6 +246,7 @@ bool EntityBase::IsPoint() const { case Type::POINT_N_ROT_TRANS: case Type::POINT_N_ROT_AA: case Type::POINT_N_ROT_AXIS_TRANS: + case Type::POINT_N_MIRROR: return true; default: @@ -260,6 +261,7 @@ bool EntityBase::IsNormal() const { case Type::NORMAL_N_COPY: case Type::NORMAL_N_ROT: case Type::NORMAL_N_ROT_AA: + case Type::NORMAL_N_MIRROR: return true; default: return false; @@ -293,6 +295,16 @@ Quaternion EntityBase::NormalGetNum() const { q = q.Times(numNormal); break; } + case Type::NORMAL_N_MIRROR: { + Vector orig = numNormal.RotationN().WithMagnitude(1.0); + Vector n = Vector::From( + SK.GetParam(param[0])->val, + SK.GetParam(param[1])->val, + SK.GetParam(param[2])->val); + Vector cp = orig.Cross(n); + q = numNormal.Times(Quaternion::From(n.Dot(orig), cp.x, cp.y, cp.z)); + break; + } default: ssassert(false, "Unexpected entity type"); } @@ -323,6 +335,7 @@ void EntityBase::NormalForceTo(Quaternion q) { } case Type::NORMAL_N_ROT_AA: + case Type::NORMAL_N_MIRROR: // Not sure if I'll bother implementing this one break; @@ -382,6 +395,18 @@ ExprQuaternion EntityBase::NormalGetExprs() const { break; } + case Type::NORMAL_N_MIRROR: { + ExprVector orig = ExprVector::From(numNormal.RotationN().WithMagnitude(1.0)); + ExprVector n = ExprVector::From( + Expr::From(param[0]), + Expr::From(param[1]), + Expr::From(param[2])); + ExprVector cp = orig.Cross(n); + q = ExprQuaternion::From(numNormal).Times(ExprQuaternion::From( + n.Dot(orig), cp.x, cp.y, cp.z)); + break; + } + default: ssassert(false, "Unexpected entity type"); } return q; @@ -420,6 +445,15 @@ void EntityBase::PointForceTo(Vector p) { break; } + case Type::POINT_N_MIRROR: { + Vector trans = p.Minus(numPoint).WithMagnitude(1.0); + SK.GetParam(param[0])->val = trans.x; + SK.GetParam(param[1])->val = trans.y; + SK.GetParam(param[2])->val = trans.z; + SK.GetParam(param[3])->val = p.Plus(numPoint).ScaledBy(0.5).Dot(trans); + break; + } + case Type::POINT_N_TRANS: { if(timesApplied == 0) break; Vector trans = (p.Minus(numPoint)).ScaledBy(1.0/timesApplied); @@ -512,6 +546,13 @@ Vector EntityBase::PointGetNum() const { break; } + case Type::POINT_N_MIRROR: { + Vector norm = Vector::From(param[0], param[1], param[2]); + double dist = SK.GetParam(param[3])->val; + p = numPoint.Plus(norm.ScaledBy(dist*2 - 2*numPoint.Dot(norm))); + break; + } + case Type::POINT_N_TRANS: { Vector trans = Vector::From(param[0], param[1], param[2]); p = numPoint.Plus(trans.ScaledBy(timesApplied)); @@ -571,6 +612,14 @@ ExprVector EntityBase::PointGetExprs() const { r = r.Plus(v.ScaledBy(Expr::From(param[1]))); break; } + case Type::POINT_N_MIRROR:{ + ExprVector orig = ExprVector::From(numPoint); + ExprVector norm = ExprVector::From(param[0], param[1], param[2]); + Expr *dist = Expr::From(param[3]); + r = orig.Plus(norm.ScaledBy( + dist->Minus(orig.Dot(norm))->Times(Expr::From(2.0)))); + break; + } case Type::POINT_N_TRANS: { ExprVector orig = ExprVector::From(numPoint); ExprVector trans = ExprVector::From(param[0], param[1], param[2]); @@ -703,6 +752,8 @@ bool EntityBase::IsFace() const { case Type::FACE_N_ROT_AA: case Type::FACE_ROT_NORMAL_PT: case Type::FACE_N_ROT_AXIS_TRANS: + case Type::FACE_N_MIRROR: + case Type::FACE_N_COPY: return true; default: return false; @@ -711,9 +762,15 @@ bool EntityBase::IsFace() const { ExprVector EntityBase::FaceGetNormalExprs() const { ExprVector r; - if(type == Type::FACE_NORMAL_PT) { + if(type == Type::FACE_NORMAL_PT || type == Type::FACE_N_COPY) { Vector v = Vector::From(numNormal.vx, numNormal.vy, numNormal.vz); r = ExprVector::From(v.WithMagnitude(1)); + } else if(type == Type::FACE_N_MIRROR) { + Vector v = Vector::From(numNormal.vx, numNormal.vy, numNormal.vz).ScaledBy(-1.0); + r = ExprVector::From(v.WithMagnitude(1)); + ExprQuaternion q = ExprQuaternion::From( Expr::From(0.0), + Expr::From(param[0]), Expr::From(param[1]), Expr::From(param[2]) ); + r = q.Rotate(r); } else if(type == Type::FACE_XPROD) { ExprVector vc = ExprVector::From(param[0], param[1], param[2]); ExprVector vn = @@ -740,8 +797,16 @@ ExprVector EntityBase::FaceGetNormalExprs() const { Vector EntityBase::FaceGetNormalNum() const { Vector r; - if(type == Type::FACE_NORMAL_PT) { + if(type == Type::FACE_NORMAL_PT || type == Type::FACE_N_COPY) { r = Vector::From(numNormal.vx, numNormal.vy, numNormal.vz); + } else if(type == Type::FACE_N_MIRROR) { + r = Vector::From(numNormal.vx, numNormal.vy, numNormal.vz) + .ScaledBy(-1.0).WithMagnitude(1.0); + Quaternion q = Quaternion::From(0.0, + SK.GetParam(param[0])->val, + SK.GetParam(param[1])->val, + SK.GetParam(param[2])->val); + r = q.Rotate(r); } else if(type == Type::FACE_XPROD) { Vector vc = Vector::From(param[0], param[1], param[2]); Vector vn = Vector::From(numNormal.vx, numNormal.vy, numNormal.vz); @@ -765,6 +830,11 @@ ExprVector EntityBase::FaceGetPointExprs() const { ExprVector r; if((type == Type::FACE_NORMAL_PT) || (type==Type::FACE_ROT_NORMAL_PT)) { r = SK.GetEntity(point[0])->PointGetExprs(); + } else if(type == Type::FACE_N_MIRROR) { + // TODO: figure this out, when is it even used? + r = ExprVector::From(numPoint); + } else if(type == Type::FACE_N_COPY) { + r = ExprVector::From(numPoint); } else if(type == Type::FACE_XPROD) { r = ExprVector::From(numPoint); } else if(type == Type::FACE_N_ROT_TRANS) { @@ -803,6 +873,13 @@ Vector EntityBase::FaceGetPointNum() const { Vector r; if((type == Type::FACE_NORMAL_PT) || (type==Type::FACE_ROT_NORMAL_PT)) { r = SK.GetEntity(point[0])->PointGetNum(); + } else if(type == Type::FACE_N_COPY) { + r = numPoint; + } else if(type == Type::FACE_N_MIRROR) { + Vector norm = Vector::From(param[0], param[1], param[2]); + double dist = SK.GetParam(param[3])->val; + Vector p = numPoint; + r = p.Plus(norm.ScaledBy(dist*2 - 2*p.Dot(norm))); } else if(type == Type::FACE_XPROD) { r = numPoint; } else if(type == Type::FACE_N_ROT_TRANS) { diff --git a/src/graphicswin.cpp b/src/graphicswin.cpp index 17e04dce0..9785cd5f6 100644 --- a/src/graphicswin.cpp +++ b/src/graphicswin.cpp @@ -117,6 +117,7 @@ const MenuEntry Menu[] = { { 1, N_("&Helix"), Command::GROUP_HELIX, S|'h', KN, mGrp }, { 1, N_("&Lathe"), Command::GROUP_LATHE, S|'l', KN, mGrp }, { 1, N_("Re&volve"), Command::GROUP_REVOLVE, S|'v', KN, mGrp }, +{ 1, N_("&Mirror"), Command::GROUP_MIRROR , S|'m', 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 1cb1a1b8f..66388ac48 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -175,6 +175,28 @@ void Group::MenuGroup(Command id, Platform::Path linkFile) { g.name = C_("group-name", "extrude"); break; + case Command::GROUP_MIRROR: + g.subtype = Subtype::TWO_SIDED; + if(SS.GW.LockedInWorkplane()) { + g.opA = SS.GW.activeGroup; + g.predef.entityB = SS.GW.ActiveWorkplane(); + g.activeWorkplane = SS.GW.ActiveWorkplane(); + } +/* + // If entities are selected we will constrain the mirror plane to them later + 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]; + } +*/ + g.type = Type::MIRROR; + g.opA = SS.GW.activeGroup; + g.name = C_("group-name", "mirror"); + break; + case Command::GROUP_LATHE: if(!SS.GW.LockedInWorkplane()) { Error(_("Lathe operation can only be applied to planar sketches.")); @@ -528,6 +550,40 @@ void Group::Generate(IdList *entity, return; } + case Type::MIRROR: { + // inherit meshCombine from source group + Group *srcg = SK.GetGroup(opA); + meshCombine = srcg->meshCombine; + + Vector norm = gp.WithMagnitude(1.0); + AddParam(param, h.param(0), norm.x); + AddParam(param, h.param(1), norm.y); + AddParam(param, h.param(2), norm.z); + AddParam(param, h.param(3), 25.0); + + // Not using range-for here because we're changing the size of entity in the loop. + for(i = 0; i < entity->n; i++) { + Entity *e = &(entity->Get(i)); + if(e->group != opA) continue; + + e->CalculateNumerical(/*forExport=*/false); + hEntity he = e->h; + // As soon as I call CopyEntity, e may become invalid! That + // adds entities, which may cause a realloc. + if (subtype == Group::Subtype::TWO_SIDED) { + CopyEntity(entity, SK.GetEntity(he), 0, 0, + h.param(0), h.param(1), h.param(2), + h.param(3), NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, + CopyAs::NUMERIC); + } + CopyEntity(entity, SK.GetEntity(he), 1, 1, + h.param(0), h.param(1), h.param(2), + h.param(3), NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, + CopyAs::N_MIRROR); + } + return; + } + case Type::LATHE: { Vector axis_pos = SK.GetEntity(predef.origin)->PointGetNum(); Vector axis_dir = SK.GetEntity(predef.entityB)->VectorGetNum(); @@ -837,7 +893,22 @@ void Group::GenerateEquations(IdList *l) { AddEq(l, u.Dot(extruden), 0); AddEq(l, v.Dot(extruden), 1); } - } else if(type == Type::TRANSLATE) { + } else if(type == Type::MIRROR) { + // Normalize the mirror normal + ExprVector n = { + Expr::From(h.param(0)), + Expr::From(h.param(1)), + Expr::From(h.param(2)) }; + AddEq(l, (n.Magnitude())->Minus(Expr::From(1)), 0); + + if (predef.entityB != Entity::FREE_IN_3D) { + // to reflect in plane, mirror normal must be perpendicular to the sketch normal + Entity *w = SK.GetEntity(predef.entityB); + ExprVector u = w->Normal()->NormalExprsU(); + ExprVector v = w->Normal()->NormalExprsV(); + AddEq(l, (n.Dot(u.Cross(v))), 1); + } + } else if(type == Type::TRANSLATE) { if(predef.entityB != Entity::FREE_IN_3D) { Entity *w = SK.GetEntity(predef.entityB); ExprVector n = w->Normal()->NormalExprsN(); @@ -1068,6 +1139,7 @@ void Group::CopyEntity(IdList *el, case Entity::Type::POINT_N_ROT_TRANS: case Entity::Type::POINT_N_ROT_AA: case Entity::Type::POINT_N_ROT_AXIS_TRANS: + case Entity::Type::POINT_N_MIRROR: case Entity::Type::POINT_IN_3D: case Entity::Type::POINT_IN_2D: if(as == CopyAs::N_TRANS) { @@ -1077,6 +1149,12 @@ void Group::CopyEntity(IdList *el, en.param[2] = dz; } else if(as == CopyAs::NUMERIC) { en.type = Entity::Type::POINT_N_COPY; + } else if(as == CopyAs::N_MIRROR) { + en.type = Entity::Type::POINT_N_MIRROR; + en.param[0] = dx; + en.param[1] = dy; + en.param[2] = dz; + en.param[3] = qw; } else { if(as == CopyAs::N_ROT_AA) { en.type = Entity::Type::POINT_N_ROT_AA; @@ -1102,10 +1180,17 @@ void Group::CopyEntity(IdList *el, case Entity::Type::NORMAL_N_COPY: case Entity::Type::NORMAL_N_ROT: case Entity::Type::NORMAL_N_ROT_AA: + case Entity::Type::NORMAL_N_MIRROR: case Entity::Type::NORMAL_IN_3D: case Entity::Type::NORMAL_IN_2D: if(as == CopyAs::N_TRANS || as == CopyAs::NUMERIC) { en.type = Entity::Type::NORMAL_N_COPY; + } else if (as == CopyAs::N_MIRROR) { + en.type = Entity::Type::NORMAL_N_MIRROR; + en.param[0] = dx; + en.param[1] = dy; + en.param[2] = dz; + en.param[3] = qw; } else { // N_ROT_AXIS_TRANS probably doesn't warrant a new entity Type if(as == CopyAs::N_ROT_AA || as == CopyAs::N_ROT_AXIS_TRANS) { en.type = Entity::Type::NORMAL_N_ROT_AA; @@ -1135,6 +1220,8 @@ void Group::CopyEntity(IdList *el, case Entity::Type::FACE_N_TRANS: case Entity::Type::FACE_N_ROT_AA: case Entity::Type::FACE_ROT_NORMAL_PT: + case Entity::Type::FACE_N_MIRROR: + case Entity::Type::FACE_N_COPY: case Entity::Type::FACE_N_ROT_AXIS_TRANS: if(as == CopyAs::N_TRANS) { en.type = Entity::Type::FACE_N_TRANS; @@ -1142,7 +1229,13 @@ void Group::CopyEntity(IdList *el, en.param[1] = dy; en.param[2] = dz; } else if (as == CopyAs::NUMERIC) { - en.type = Entity::Type::FACE_NORMAL_PT; + en.type = Entity::Type::FACE_N_COPY; + } else if (as == CopyAs::N_MIRROR) { + en.type = Entity::Type::FACE_N_MIRROR; + en.param[0] = dx; + en.param[1] = dy; + en.param[2] = dz; + en.param[3] = qw; } else if (as == CopyAs::N_ROT_AXIS_TRANS) { en.type = Entity::Type::FACE_N_ROT_AXIS_TRANS; en.param[0] = dx; diff --git a/src/groupmesh.cpp b/src/groupmesh.cpp index 11add4f11..1b8521b89 100644 --- a/src/groupmesh.cpp +++ b/src/groupmesh.cpp @@ -176,6 +176,37 @@ void Group::GenerateForStepAndRepeat(T *steps, T *outs, Group::CombineAs forWhat *outs = soFar->at(0); } +template +void Group::GenerateForMirror(T *source, T *outs, Group::CombineAs forWhat) { + T original, transd, combined; + original = {}; + transd = {}; + combined = {}; + Vector axis = Vector::From(h.param(0), h.param(1), h.param(2)); + transd.MakeFromTransformationOf(source, + axis.ScaledBy(SK.GetParam(h.param(3))->val * 2), + Quaternion::From(axis, PI),-1.0); + // We need to rewrite any plane face entities to the transformed ones. + transd.RemapFaces(this, 1); + + // Combine the transformed and original. + if(subtype == Subtype::TWO_SIDED) { + original.MakeFromCopyOf(source); + original.RemapFaces(this, 0); + if (forWhat == CombineAs::ASSEMBLE) { + combined.MakeFromAssemblyOf(&original, &transd); + } else { + combined.MakeFromUnionOf(&original, &transd); + } + *outs = combined; + } + else { + *outs = transd; + } + original.Clear(); + transd.Clear(); +} + template void Group::GenerateForBoolean(T *prevs, T *thiss, T *outs, Group::CombineAs how) { // If this group contributes no new mesh, then our running mesh is the @@ -221,7 +252,8 @@ 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 || type == Type::REVOLVE) { + if(type == Type::EXTRUDE || type == Type::LATHE || type == Type::REVOLVE + || type == Type::MIRROR) { Group *src = SK.GetGroup(opA); if(src->polyError.how != PolyError::GOOD) { haveSrc = false; @@ -229,7 +261,7 @@ void Group::GenerateShellAndMesh() { } if(type == Type::TRANSLATE || type == Type::ROTATE) { - // A step and repeat gets merged against the group's previous group, + // A step and repeat gets merged against the source group's previous group, // not our own previous group. srcg = SK.GetGroup(opA); @@ -387,6 +419,39 @@ void Group::GenerateShellAndMesh() { thisShell.MakeFromTransformationOf(&impShell, offset, q, scale); thisShell.RemapFaces(this, 0); + } else if(type == Type::MIRROR && haveSrc) { + // A mirror gets merged against the group's previous group, + // not our own previous group. + if(subtype != Subtype::ONE_SIDED) { + srcg = SK.GetGroup(opA); + } +// srcg = SK.GetGroup(opA); + if(!srcg->suppress) { + if(!IsForcedToMesh()) { + GenerateForMirror(&(srcg->thisShell), &thisShell, srcg->meshCombine); + } else { + SMesh prevm = {}; + prevm.MakeFromCopyOf(&srcg->thisMesh); + srcg->thisShell.TriangulateInto(&prevm); + GenerateForMirror(&prevm, &thisMesh, srcg->meshCombine); + } + } +/* + Vector offset = { + SK.GetParam(h.param(0))->val, + SK.GetParam(h.param(1))->val, + SK.GetParam(h.param(2))->val }; + Quaternion q = { 0.0, + SK.GetParam(h.param(0))->val, + SK.GetParam(h.param(1))->val, + SK.GetParam(h.param(2))->val }; + thisMesh.MakeFromTransformationOf(&impMesh, offset.ScaledBy( + SK.GetParam(h.param(3))->val * 2), q, -1.0); + thisMesh.RemapFaces(this, 0); + thisShell.MakeFromTransformationOf(&impShell, offset.ScaledBy( + SK.GetParam(h.param(3))->val * 2), q, -1.0); + thisShell.RemapFaces(this, 0); +*/ } if(srcg->meshCombine != CombineAs::ASSEMBLE) { diff --git a/src/sketch.h b/src/sketch.h index 812375f4f..b825f696e 100644 --- a/src/sketch.h +++ b/src/sketch.h @@ -152,6 +152,7 @@ class Group { N_ROT_AA, N_ROT_TRANS, N_ROT_AXIS_TRANS, + N_MIRROR, }; enum class Type : uint32_t { @@ -163,6 +164,7 @@ class Group { HELIX = 5103, ROTATE = 5200, TRANSLATE = 5201, + MIRROR = 5202, LINKED = 5300 }; Group::Type type; @@ -319,6 +321,7 @@ class Group { void GenerateShellAndMesh(); template void GenerateForStepAndRepeat(T *steps, T *outs, Group::CombineAs forWhat); template void GenerateForBoolean(T *a, T *b, T *o, Group::CombineAs how); + template void GenerateForMirror(T *steps, T *outs, Group::CombineAs forWhat); void GenerateDisplayItems(); enum class DrawMeshAs { DEFAULT, HOVERED, SELECTED }; @@ -401,12 +404,14 @@ class EntityBase { POINT_N_COPY = 2012, POINT_N_ROT_AA = 2013, POINT_N_ROT_AXIS_TRANS = 2014, + POINT_N_MIRROR = 2015, NORMAL_IN_3D = 3000, NORMAL_IN_2D = 3001, NORMAL_N_COPY = 3010, NORMAL_N_ROT = 3011, NORMAL_N_ROT_AA = 3012, + NORMAL_N_MIRROR = 3013, DISTANCE = 4000, DISTANCE_N_COPY = 4001, @@ -418,6 +423,8 @@ class EntityBase { FACE_N_ROT_AA = 5004, FACE_ROT_NORMAL_PT = 5005, FACE_N_ROT_AXIS_TRANS = 5006, + FACE_N_MIRROR = 5007, + FACE_N_COPY = 5008, WORKPLANE = 10000, LINE_SEGMENT = 11000, diff --git a/src/textscreens.cpp b/src/textscreens.cpp index 22553827b..d6d59fd97 100644 --- a/src/textscreens.cpp +++ b/src/textscreens.cpp @@ -361,7 +361,7 @@ void TextWindow::ShowGroupInfo() { 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::REVOLVE || - g->type == Group::Type::HELIX) { + g->type == Group::Type::HELIX || g->type == Group::Type::MIRROR) { if(g->type == Group::Type::EXTRUDE) { s = "extrude plane sketch"; } else if(g->type == Group::Type::TRANSLATE) { @@ -372,6 +372,8 @@ void TextWindow::ShowGroupInfo() { s = "rotate original sketch"; } else if(g->type == Group::Type::REVOLVE) { s = "revolve original sketch"; + } else if(g->type == Group::Type::MIRROR) { + s = "mirror single or include original"; } Printf(true, " %Ft%s%E", s); diff --git a/src/ui.h b/src/ui.h index 0700653af..2940571c0 100644 --- a/src/ui.h +++ b/src/ui.h @@ -133,6 +133,7 @@ enum class Command : uint32_t { GROUP_EXTRUDE, GROUP_HELIX, GROUP_LATHE, + GROUP_MIRROR, GROUP_REVOLVE, GROUP_ROT, GROUP_TRANS,