diff --git a/dsc.h b/dsc.h index 11403a8..8e951d6 100644 --- a/dsc.h +++ b/dsc.h @@ -39,6 +39,7 @@ public: Quaternion ToThe(double p); Quaternion Inverse(void); Quaternion Times(Quaternion b); + Quaternion MirrorZ(void); }; class Vector { diff --git a/file.cpp b/file.cpp index a1a80f9..f7e752f 100644 --- a/file.cpp +++ b/file.cpp @@ -93,6 +93,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = { { 'g', "Group.visible", 'b', &(SS.sv.g.visible) }, { 'g', "Group.suppress", 'b', &(SS.sv.g.suppress) }, { 'g', "Group.relaxConstraints", 'b', &(SS.sv.g.relaxConstraints) }, + { 'g', "Group.mirror", 'b', &(SS.sv.g.mirror) }, { 'g', "Group.remap", 'M', &(SS.sv.g.remap) }, { 'g', "Group.impFile", 'P', &(SS.sv.g.impFile) }, { 'g', "Group.impFileRel", 'P', &(SS.sv.g.impFileRel) }, diff --git a/group.cpp b/group.cpp index 1f3dc21..972a5dd 100644 --- a/group.cpp +++ b/group.cpp @@ -706,6 +706,7 @@ void Group::CopyEntity(IdList *el, en.param[6] = qvz; } en.numPoint = ep->actPoint; + if(mirror) en.numPoint.z *= -1; break; case Entity::NORMAL_N_COPY: @@ -727,6 +728,8 @@ void Group::CopyEntity(IdList *el, en.param[3] = qvz; } en.numNormal = ep->actNormal; + if(mirror) en.numNormal = en.numNormal.MirrorZ(); + en.point[0] = Remap(ep->point[0], remap); break; @@ -762,6 +765,11 @@ void Group::CopyEntity(IdList *el, } en.numPoint = ep->actPoint; en.numNormal = ep->actNormal; + if(mirror) { + if(en.type != Entity::FACE_N_ROT_TRANS) oops(); + en.numPoint.z *= -1; + en.numNormal.vz *= -1; + } break; default: diff --git a/groupmesh.cpp b/groupmesh.cpp index 4d000ae..baaaca4 100644 --- a/groupmesh.cpp +++ b/groupmesh.cpp @@ -95,7 +95,8 @@ void Group::GenerateForStepAndRepeat(T *steps, T *outs) { if(type == TRANSLATE) { Vector trans = Vector::From(h.param(0), h.param(1), h.param(2)); trans = trans.ScaledBy(ap); - transd.MakeFromTransformationOf(steps, trans, Quaternion::IDENTITY); + transd.MakeFromTransformationOf(steps, + trans, Quaternion::IDENTITY, false); } else { Vector trans = Vector::From(h.param(0), h.param(1), h.param(2)); double theta = ap * SK.GetParam(h.param(3))->val; @@ -104,7 +105,7 @@ void Group::GenerateForStepAndRepeat(T *steps, T *outs) { Quaternion q = Quaternion::From(c, s*axis.x, s*axis.y, s*axis.z); // Rotation is centered at t; so A(x - t) + t = Ax + (t - At) transd.MakeFromTransformationOf(steps, - trans.Minus(q.Rotate(trans)), q); + trans.Minus(q.Rotate(trans)), q, false); } // We need to rewrite any plane face entities to the transformed ones. @@ -247,10 +248,10 @@ void Group::GenerateShellAndMesh(void) { SK.GetParam(h.param(5))->val, SK.GetParam(h.param(6))->val }; - thisMesh.MakeFromTransformationOf(&impMesh, offset, q); + thisMesh.MakeFromTransformationOf(&impMesh, offset, q, mirror); thisMesh.RemapFaces(this, 0); - thisShell.MakeFromTransformationOf(&impShell, offset, q); + thisShell.MakeFromTransformationOf(&impShell, offset, q, mirror); thisShell.RemapFaces(this, 0); } diff --git a/mesh.cpp b/mesh.cpp index 51506a0..5d6f2b4 100644 --- a/mesh.cpp +++ b/mesh.cpp @@ -293,10 +293,19 @@ void SMesh::MakeFromAssemblyOf(SMesh *a, SMesh *b) { MakeFromCopyOf(b); } -void SMesh::MakeFromTransformationOf(SMesh *a, Vector trans, Quaternion q) { +void SMesh::MakeFromTransformationOf(SMesh *a, Vector trans, Quaternion q, + bool mirror) +{ STriangle *tr; for(tr = a->l.First(); tr; tr = a->l.NextAfter(tr)) { STriangle tt = *tr; + if(mirror) { + tt.a.z *= -1; + tt.b.z *= -1; + tt.c.z *= -1; + // The mirroring would otherwise turn a closed mesh inside out. + SWAP(Vector, tt.a, tt.b); + } tt.a = (q.Rotate(tt.a)).Plus(trans); tt.b = (q.Rotate(tt.b)).Plus(trans); tt.c = (q.Rotate(tt.c)).Plus(trans); diff --git a/polygon.h b/polygon.h index 6e81108..f0863c4 100644 --- a/polygon.h +++ b/polygon.h @@ -204,7 +204,8 @@ public: void MakeFromDifferenceOf(SMesh *a, SMesh *b); void MakeFromCopyOf(SMesh *a); - void MakeFromTransformationOf(SMesh *a, Vector trans, Quaternion q); + void MakeFromTransformationOf(SMesh *a, Vector trans, Quaternion q, + bool mirror); void MakeFromAssemblyOf(SMesh *a, SMesh *b); void MakeEdgesInPlaneInto(SEdgeList *sel, Vector n, double d); diff --git a/sketch.h b/sketch.h index c3cb479..e608717 100644 --- a/sketch.h +++ b/sketch.h @@ -102,6 +102,7 @@ public: bool visible; bool suppress; bool relaxConstraints; + bool mirror; bool clean; bool vvMeshClean; diff --git a/srf/boolean.cpp b/srf/boolean.cpp index d87b32a..93f9a98 100644 --- a/srf/boolean.cpp +++ b/srf/boolean.cpp @@ -687,7 +687,7 @@ void SShell::MakeFromAssemblyOf(SShell *a, SShell *b) { for(i = 0; i < 2; i++) { ab = (i == 0) ? a : b; for(c = ab->curve.First(); c; c = ab->curve.NextAfter(c)) { - cn = SCurve::FromTransformationOf(c, t, q); + cn = SCurve::FromTransformationOf(c, t, q, false); cn.source = (i == 0) ? SCurve::FROM_A : SCurve::FROM_B; // surfA and surfB are wrong now, and we can't fix them until // we've assigned IDs to the surfaces. So we'll get that later. @@ -700,7 +700,7 @@ void SShell::MakeFromAssemblyOf(SShell *a, SShell *b) { for(i = 0; i < 2; i++) { ab = (i == 0) ? a : b; for(s = ab->surface.First(); s; s = ab->surface.NextAfter(s)) { - sn = SSurface::FromTransformationOf(s, t, q, true); + sn = SSurface::FromTransformationOf(s, t, q, false, true); // All the trim curve IDs get rewritten; we know the new handles // to the curves since we recorded them in the previous step. STrimBy *stb; diff --git a/srf/curve.cpp b/srf/curve.cpp index 81d4cc6..14301f4 100644 --- a/srf/curve.cpp +++ b/srf/curve.cpp @@ -88,10 +88,11 @@ void SBezier::GetBoundingProjd(Vector u, Vector orig, } } -SBezier SBezier::TransformedBy(Vector t, Quaternion q) { +SBezier SBezier::TransformedBy(Vector t, Quaternion q, bool mirror) { SBezier ret = *this; int i; for(i = 0; i <= deg; i++) { + if(mirror) ret.ctrl[i].z *= -1; ret.ctrl[i] = (q.Rotate(ret.ctrl[i])).Plus(t); } return ret; @@ -167,7 +168,7 @@ SBezier SBezier::InPerspective(Vector u, Vector v, Vector n, Quaternion q = Quaternion::From(u, v); q = q.Inverse(); // we want Q*(p - o) = Q*p - Q*o - SBezier ret = this->TransformedBy(q.Rotate(origin).ScaledBy(-1), q); + SBezier ret = this->TransformedBy(q.Rotate(origin).ScaledBy(-1), q, false); int i; for(i = 0; i <= deg; i++) { Vector4 ct = Vector4::From(ret.weight[i], ret.ctrl[i]); @@ -427,20 +428,23 @@ void SBezierLoopSet::Clear(void) { l.Clear(); } -SCurve SCurve::FromTransformationOf(SCurve *a, Vector t, Quaternion q) { +SCurve SCurve::FromTransformationOf(SCurve *a, Vector t, Quaternion q, + bool mirror) +{ SCurve ret; ZERO(&ret); ret.h = a->h; ret.isExact = a->isExact; - ret.exact = (a->exact).TransformedBy(t, q); + ret.exact = (a->exact).TransformedBy(t, q, mirror); ret.surfA = a->surfA; ret.surfB = a->surfB; SCurvePt *p; for(p = a->pts.First(); p; p = a->pts.NextAfter(p)) { SCurvePt pp = *p; - pp.p = (q.Rotate(p->p)).Plus(t); + if(mirror) pp.p.z *= -1; + pp.p = (q.Rotate(pp.p)).Plus(t); ret.pts.Add(&pp); } return ret; diff --git a/srf/surface.cpp b/srf/surface.cpp index 699553c..0f52347 100644 --- a/srf/surface.cpp +++ b/srf/surface.cpp @@ -133,6 +133,7 @@ SSurface SSurface::FromPlane(Vector pt, Vector u, Vector v) { } SSurface SSurface::FromTransformationOf(SSurface *a, Vector t, Quaternion q, + bool mirror, bool includingTrims) { SSurface ret; @@ -147,7 +148,10 @@ SSurface SSurface::FromTransformationOf(SSurface *a, Vector t, Quaternion q, int i, j; for(i = 0; i <= 3; i++) { for(j = 0; j <= 3; j++) { - ret.ctrl[i][j] = (q.Rotate(a->ctrl[i][j])).Plus(t); + ret.ctrl[i][j] = a->ctrl[i][j]; + if(mirror) ret.ctrl[i][j].z *= -1; + ret.ctrl[i][j] = (q.Rotate(ret.ctrl[i][j])).Plus(t); + ret.weight[i][j] = a->weight[i][j]; } } @@ -156,12 +160,22 @@ SSurface SSurface::FromTransformationOf(SSurface *a, Vector t, Quaternion q, STrimBy *stb; for(stb = a->trim.First(); stb; stb = a->trim.NextAfter(stb)) { STrimBy n = *stb; + if(mirror) { + n.start.z *= -1; + n.finish.z *= -1; + } n.start = (q.Rotate(n.start)) .Plus(t); n.finish = (q.Rotate(n.finish)).Plus(t); ret.trim.Add(&n); } } + if(mirror) { + // If we mirror every surface of a shell, then it will end up inside + // out. So fix that here. + ret.Reverse(); + } + return ret; } @@ -522,7 +536,7 @@ void SShell::MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1, SCurve sc; ZERO(&sc); sc.isExact = true; - sc.exact = sb->TransformedBy(t0, Quaternion::IDENTITY); + sc.exact = sb->TransformedBy(t0, Quaternion::IDENTITY, false); (sc.exact).MakePwlInto(&(sc.pts)); sc.surfA = hs0; sc.surfB = hsext; @@ -530,7 +544,7 @@ void SShell::MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1, ZERO(&sc); sc.isExact = true; - sc.exact = sb->TransformedBy(t1, Quaternion::IDENTITY); + sc.exact = sb->TransformedBy(t1, Quaternion::IDENTITY, false); (sc.exact).MakePwlInto(&(sc.pts)); sc.surfA = hs1; sc.surfB = hsext; @@ -669,7 +683,7 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, if(revs.d[j].v) { ZERO(&sc); sc.isExact = true; - sc.exact = sb->TransformedBy(ts, qs); + sc.exact = sb->TransformedBy(ts, qs, false); (sc.exact).MakePwlInto(&(sc.pts)); sc.surfA = revs.d[j]; sc.surfB = revs.d[WRAP(j-1, 4)]; @@ -795,23 +809,26 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, } void SShell::MakeFromCopyOf(SShell *a) { - MakeFromTransformationOf(a, Vector::From(0, 0, 0), Quaternion::IDENTITY); + MakeFromTransformationOf(a, + Vector::From(0, 0, 0), Quaternion::IDENTITY, false); } -void SShell::MakeFromTransformationOf(SShell *a, Vector t, Quaternion q) { +void SShell::MakeFromTransformationOf(SShell *a, + Vector t, Quaternion q, bool mirror) +{ booleanFailed = false; SSurface *s; for(s = a->surface.First(); s; s = a->surface.NextAfter(s)) { SSurface n; - n = SSurface::FromTransformationOf(s, t, q, true); + n = SSurface::FromTransformationOf(s, t, q, mirror, true); surface.Add(&n); // keeping the old ID } SCurve *c; for(c = a->curve.First(); c; c = a->curve.NextAfter(c)) { SCurve n; - n = SCurve::FromTransformationOf(c, t, q); + n = SCurve::FromTransformationOf(c, t, q, mirror); curve.Add(&n); // keeping the old ID } } diff --git a/srf/surface.h b/srf/surface.h index 764292c..06b3891 100644 --- a/srf/surface.h +++ b/srf/surface.h @@ -89,7 +89,7 @@ public: bool IsCircle(Vector axis, Vector *center, double *r); bool IsRational(void); - SBezier TransformedBy(Vector t, Quaternion q); + SBezier TransformedBy(Vector t, Quaternion q, bool mirror); SBezier InPerspective(Vector u, Vector v, Vector n, Vector origin, double cameraTan); @@ -166,7 +166,8 @@ public: hSSurface surfA; hSSurface surfB; - static SCurve FromTransformationOf(SCurve *a, Vector t, Quaternion q); + static SCurve FromTransformationOf(SCurve *a, Vector t, Quaternion q, + bool mirror); SCurve MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB, SSurface *srfA, SSurface *srfB); void RemoveShortSegments(SSurface *srfA, SSurface *srfB); @@ -235,7 +236,8 @@ public: static SSurface FromRevolutionOf(SBezier *sb, Vector pt, Vector axis, double thetas, double thetaf); static SSurface FromPlane(Vector pt, Vector u, Vector v); - static SSurface FromTransformationOf(SSurface *a, Vector t, Quaternion q, + static SSurface FromTransformationOf(SSurface *a, Vector t, Quaternion q, + bool mirror, bool includingTrims); void EdgeNormalsWithinSurface(Point2d auv, Point2d buv, @@ -358,7 +360,8 @@ public: Vector edge_n_in, Vector edge_n_out, Vector surf_n); void MakeFromCopyOf(SShell *a); - void MakeFromTransformationOf(SShell *a, Vector trans, Quaternion q); + void MakeFromTransformationOf(SShell *a, Vector trans, Quaternion q, + bool mirror); void MakeFromAssemblyOf(SShell *a, SShell *b); void MergeCoincidentSurfaces(void); diff --git a/textscreens.cpp b/textscreens.cpp index d575cd9..e5f5015 100644 --- a/textscreens.cpp +++ b/textscreens.cpp @@ -203,64 +203,51 @@ void TextWindow::ScreenSelectRequest(int link, DWORD v) { SS.GW.ClearSelection(); SS.GW.selection[0].entity = hr.entity(0); } -void TextWindow::ScreenChangeOneOrTwoSides(int link, DWORD v) { - SS.UndoRemember(); +void TextWindow::ScreenChangeGroupOption(int link, DWORD v) { + SS.UndoRemember(); Group *g = SK.GetGroup(SS.TW.shown.group); - if(g->subtype == Group::ONE_SIDED) { - g->subtype = Group::TWO_SIDED; - } else if(g->subtype == Group::TWO_SIDED) { - g->subtype = Group::ONE_SIDED; - } else oops(); + + switch(link) { + case 's': + if(g->subtype == Group::ONE_SIDED) { + g->subtype = Group::TWO_SIDED; + } else { + g->subtype = Group::ONE_SIDED; + } + break; + + case 'k': + (g->skipFirst) = !(g->skipFirst); + break; + + case 'c': + g->meshCombine = v; + break; + + case 'P': + g->suppress = !(g->suppress); + break; + + case 'm': + g->mirror = !(g->mirror); + break; + + case 'r': + g->relaxConstraints = !(g->relaxConstraints); + break; + + case 'f': + g->forceToMesh = !(g->forceToMesh); + break; + + } + SS.MarkGroupDirty(g->h); SS.GenerateAll(); SS.GW.ClearSuper(); } -void TextWindow::ScreenChangeSkipFirst(int link, DWORD v) { - SS.UndoRemember(); - Group *g = SK.GetGroup(SS.TW.shown.group); - (g->skipFirst) = !(g->skipFirst); - SS.MarkGroupDirty(g->h); - SS.GenerateAll(); - SS.GW.ClearSuper(); -} -void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) { - SS.UndoRemember(); - - Group *g = SK.GetGroup(SS.TW.shown.group); - g->meshCombine = v; - SS.MarkGroupDirty(g->h); - SS.GenerateAll(); - SS.GW.ClearSuper(); -} -void TextWindow::ScreenChangeMeshOrExact(int link, DWORD v) { - SS.UndoRemember(); - - Group *g = SK.GetGroup(SS.TW.shown.group); - g->forceToMesh = !(g->forceToMesh); - SS.MarkGroupDirty(g->h); - SS.GenerateAll(); - SS.GW.ClearSuper(); -} -void TextWindow::ScreenChangeSuppress(int link, DWORD v) { - SS.UndoRemember(); - - Group *g = SK.GetGroup(SS.TW.shown.group); - g->suppress = !(g->suppress); - SS.MarkGroupDirty(g->h); - SS.GenerateAll(); - SS.GW.ClearSuper(); -} -void TextWindow::ScreenChangeRelaxConstraints(int link, DWORD v) { - SS.UndoRemember(); - - Group *g = SK.GetGroup(SS.TW.shown.group); - g->relaxConstraints = !(g->relaxConstraints); - SS.MarkGroupDirty(g->h); - SS.later.generateAll = true; - SS.later.showTW = true; -} void TextWindow::ScreenChangeRightLeftHanded(int link, DWORD v) { SS.UndoRemember(); @@ -367,10 +354,10 @@ void TextWindow::ShowGroupInfo(void) { g->type == Group::TRANSLATE) { bool one = (g->subtype == Group::ONE_SIDED); - Printf(true, "%Ft%s%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E", s, - &TextWindow::ScreenChangeOneOrTwoSides, + Printf(true, "%Ft%s%E %Fh%f%Ls%s%E%Fs%s%E / %Fh%f%Ls%s%E%Fs%s%E", s, + &TextWindow::ScreenChangeGroupOption, (one ? "" : "one side"), (one ? "one side" : ""), - &TextWindow::ScreenChangeOneOrTwoSides, + &TextWindow::ScreenChangeGroupOption, (!one ? "" : "two sides"), (!one ? "two sides" : "")); } @@ -402,11 +389,11 @@ void TextWindow::ShowGroupInfo(void) { bool space; if(g->subtype == Group::ONE_SIDED) { bool skip = g->skipFirst; - Printf(true, "%Ft%s%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E", + Printf(true, "%Ft%s%E %Fh%f%Lk%s%E%Fs%s%E / %Fh%f%Lk%s%E%Fs%s%E", s3, - &ScreenChangeSkipFirst, + &ScreenChangeGroupOption, (!skip ? "" : "with original"), (!skip ? "with original" : ""), - &ScreenChangeSkipFirst, + &ScreenChangeGroupOption, (skip ? "":"with copy #1"), (skip ? "with copy #1":"")); space = false; } else { @@ -435,34 +422,40 @@ void TextWindow::ShowGroupInfo(void) { bool asa = (g->type == Group::IMPORTED); Printf((g->type == Group::HELICAL_SWEEP), - "%FtMERGE AS%E %Fh%f%D%Ll%s%E%Fs%s%E / %Fh%f%D%Ll%s%E%Fs%s%E %s " - "%Fh%f%D%Ll%s%E%Fs%s%E", - &TextWindow::ScreenChangeMeshCombine, + "%FtMERGE AS%E %Fh%f%D%Lc%s%E%Fs%s%E / %Fh%f%D%Lc%s%E%Fs%s%E %s " + "%Fh%f%D%Lc%s%E%Fs%s%E", + &TextWindow::ScreenChangeGroupOption, Group::COMBINE_AS_UNION, (un ? "" : "union"), (un ? "union" : ""), - &TextWindow::ScreenChangeMeshCombine, + &TextWindow::ScreenChangeGroupOption, Group::COMBINE_AS_DIFFERENCE, (diff ? "" : "difference"), (diff ? "difference" : ""), asa ? "/" : "", - &TextWindow::ScreenChangeMeshCombine, + &TextWindow::ScreenChangeGroupOption, Group::COMBINE_AS_ASSEMBLE, (asy || !asa ? "" : "assemble"), (asy && asa ? "assemble" : "")); } if(g->type == Group::IMPORTED) { bool sup = g->suppress; - Printf(false, "%FtSUPPRESS%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E", - &TextWindow::ScreenChangeSuppress, + Printf(false, "%FtSUPPRESS%E %Fh%f%LP%s%E%Fs%s%E / %Fh%f%LP%s%E%Fs%s%E", + &TextWindow::ScreenChangeGroupOption, (sup ? "" : "yes"), (sup ? "yes" : ""), - &TextWindow::ScreenChangeSuppress, + &TextWindow::ScreenChangeGroupOption, (!sup ? "" : "no"), (!sup ? "no" : "")); + + Printf(false, "%FtMIRROR%E %Fh%f%Lm%s%E%Fs%s%E / %Fh%f%Lm%s%E%Fs%s%E", + &TextWindow::ScreenChangeGroupOption, + (g->mirror ? "" : "yes"), (g->mirror ? "yes" : ""), + &TextWindow::ScreenChangeGroupOption, + (!g->mirror ? "" : "no"), (!g->mirror ? "no" : "")); } bool relax = g->relaxConstraints; - Printf(true, "%FtSOLVING%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E", - &TextWindow::ScreenChangeRelaxConstraints, + Printf(true, "%FtSOLVING%E %Fh%f%Lr%s%E%Fs%s%E / %Fh%f%Lr%s%E%Fs%s%E", + &TextWindow::ScreenChangeGroupOption, (!relax ? "" : "with all constraints"), (!relax ? "with all constraints" : ""), - &TextWindow::ScreenChangeRelaxConstraints, + &TextWindow::ScreenChangeGroupOption, (relax ? "" : "no"), (relax ? "no" : "")); if(g->type == Group::EXTRUDE || @@ -490,10 +483,10 @@ void TextWindow::ShowGroupInfo(void) { if(pg->runningMesh.IsEmpty() && g->thisMesh.IsEmpty()) { bool fm = g->forceToMesh; Printf(true, - "%FtSURFACES%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E", - &TextWindow::ScreenChangeMeshOrExact, + "%FtSURFACES%E %Fh%f%Lf%s%E%Fs%s%E / %Fh%f%Lf%s%E%Fs%s%E", + &TextWindow::ScreenChangeGroupOption, (!fm ? "" : "as NURBS"), (!fm ? "as NURBS" : ""), - &TextWindow::ScreenChangeMeshOrExact, + &TextWindow::ScreenChangeGroupOption, (fm ? "" : "as mesh"), (fm ? "as mesh" : "")); } else { Printf(false, diff --git a/ui.h b/ui.h index 6821790..ce372c6 100644 --- a/ui.h +++ b/ui.h @@ -147,12 +147,7 @@ public: static void ScreenSelectRequest(int link, DWORD v); static void ScreenSelectConstraint(int link, DWORD v); - static void ScreenChangeOneOrTwoSides(int link, DWORD v); - static void ScreenChangeSkipFirst(int link, DWORD v); - static void ScreenChangeMeshCombine(int link, DWORD v); - static void ScreenChangeMeshOrExact(int link, DWORD v); - static void ScreenChangeSuppress(int link, DWORD v); - static void ScreenChangeRelaxConstraints(int link, DWORD v); + static void ScreenChangeGroupOption(int link, DWORD v); static void ScreenChangeRightLeftHanded(int link, DWORD v); static void ScreenChangeHelixParameter(int link, DWORD v); static void ScreenColor(int link, DWORD v); diff --git a/util.cpp b/util.cpp index 02fd0b1..bfa207c 100644 --- a/util.cpp +++ b/util.cpp @@ -290,6 +290,14 @@ Quaternion Quaternion::Times(Quaternion b) { return r; } +Quaternion Quaternion::MirrorZ(void) { + Vector u = RotationU(), + v = RotationV(); + u.z *= -1; + v.z *= -1; + return Quaternion::From(u, v); +} + Vector Vector::From(double x, double y, double z) { Vector v; diff --git a/wishlist.txt b/wishlist.txt index 95630ab..0a30abd 100644 --- a/wishlist.txt +++ b/wishlist.txt @@ -2,17 +2,16 @@ multi-drag copy and paste wireframe export -import mirrored +interpolating splines +associative entities from solid model, as a special group ----- some kind of import filled contours for export faster triangulation -interpolating splines loop detection IGES export incremental regen of entities -associative entities from solid model, as a special group rounding, as a special group