Add helical sweeps. These aren't as parametric as I would have

liked, but my more parametric attempts were very difficult to use.
The pitch (both axial and radial) gets specified by typing a
distance in a textbox.

[git-p4: depot-paths = "//depot/solvespace/": change = 1804]
This commit is contained in:
Jonathan Westhues 2008-06-23 00:25:17 -08:00
parent fe75efc6aa
commit 3ddd1703b1
9 changed files with 209 additions and 35 deletions

View File

@ -363,6 +363,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
case MNU_RECTANGLE: { case MNU_RECTANGLE: {
if(!SS.GW.LockedInWorkplane()) { if(!SS.GW.LockedInWorkplane()) {
Error("Can't draw rectangle in 3d; select a workplane first."); Error("Can't draw rectangle in 3d; select a workplane first.");
ClearSuper();
break; break;
} }
hRequest lns[4]; hRequest lns[4];

View File

@ -67,6 +67,8 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'g', "Group.opA.v", 'x', &(SS.sv.g.opA.v) }, { 'g', "Group.opA.v", 'x', &(SS.sv.g.opA.v) },
{ 'g', "Group.opB.v", 'x', &(SS.sv.g.opB.v) }, { 'g', "Group.opB.v", 'x', &(SS.sv.g.opB.v) },
{ 'g', "Group.valA", 'f', &(SS.sv.g.valA) }, { 'g', "Group.valA", 'f', &(SS.sv.g.valA) },
{ 'g', "Group.valB", 'f', &(SS.sv.g.valB) },
{ 'g', "Group.valC", 'f', &(SS.sv.g.valB) },
{ 'g', "Group.color", 'x', &(SS.sv.g.color) }, { 'g', "Group.color", 'x', &(SS.sv.g.color) },
{ 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) }, { 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) },
{ 'g', "Group.skipFirst", 'b', &(SS.sv.g.skipFirst) }, { 'g', "Group.skipFirst", 'b', &(SS.sv.g.skipFirst) },

View File

@ -48,6 +48,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "E&xtrude\tShift+Ctrl+X", MNU_GROUP_EXTRUDE, 'X'|S|C,mGrp }, { 1, "E&xtrude\tShift+Ctrl+X", MNU_GROUP_EXTRUDE, 'X'|S|C,mGrp },
{ 1, "&Lathe\tShift+Ctrl+L", MNU_GROUP_LATHE, 'L'|S|C,mGrp }, { 1, "&Lathe\tShift+Ctrl+L", MNU_GROUP_LATHE, 'L'|S|C,mGrp },
{ 1, "&Sweep\tShift+Ctrl+S", MNU_GROUP_SWEEP, 'S'|S|C,mGrp }, { 1, "&Sweep\tShift+Ctrl+S", MNU_GROUP_SWEEP, 'S'|S|C,mGrp },
{ 1, "&Helical Sweep\tShift+Ctrl+H", MNU_GROUP_HELICAL, 'H'|S|C,mGrp },
{ 1, NULL, 0, 0, NULL }, { 1, NULL, 0, 0, NULL },
{ 1, "Import / Assemble...\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 }, {11, "Import Recent", MNU_GROUP_RECENT, 0, mGrp },

View File

@ -20,6 +20,7 @@ void Group::MenuGroup(int id) {
Group g; Group g;
ZERO(&g); ZERO(&g);
g.visible = true; g.visible = true;
g.color = RGB(100, 100, 100);
if(id >= RECENT_IMPORT && id < (RECENT_IMPORT + MAX_RECENT)) { if(id >= RECENT_IMPORT && id < (RECENT_IMPORT + MAX_RECENT)) {
strcpy(g.impFile, RecentFile[id-RECENT_IMPORT]); strcpy(g.impFile, RecentFile[id-RECENT_IMPORT]);
@ -75,7 +76,6 @@ void Group::MenuGroup(int id) {
case GraphicsWindow::MNU_GROUP_EXTRUDE: case GraphicsWindow::MNU_GROUP_EXTRUDE:
g.type = EXTRUDE; g.type = EXTRUDE;
g.opA = SS.GW.activeGroup; g.opA = SS.GW.activeGroup;
g.color = RGB(100, 100, 100);
g.predef.entityB = SS.GW.ActiveWorkplane(); g.predef.entityB = SS.GW.ActiveWorkplane();
g.subtype = ONE_SIDED; g.subtype = ONE_SIDED;
g.name.strcpy("extrude"); g.name.strcpy("extrude");
@ -95,7 +95,6 @@ void Group::MenuGroup(int id) {
} }
g.type = LATHE; g.type = LATHE;
g.opA = SS.GW.activeGroup; g.opA = SS.GW.activeGroup;
g.color = RGB(100, 100, 100);
g.name.strcpy("lathe"); g.name.strcpy("lathe");
SS.GW.ClearSelection(); SS.GW.ClearSelection();
break; break;
@ -119,11 +118,38 @@ void Group::MenuGroup(int id) {
} }
// The active group is our section // The active group is our section
g.opB = SS.GW.activeGroup; g.opB = SS.GW.activeGroup;
g.color = RGB(100, 100, 100);
g.name.strcpy("sweep"); g.name.strcpy("sweep");
break; break;
} }
case GraphicsWindow::MNU_GROUP_HELICAL: {
if(gs.points == 1 && gs.lineSegments == 1 && gs.n == 2) {
Vector pt = SS.GetEntity(gs.point[0])->PointGetNum();
Entity *ln = SS.GetEntity(gs.entity[0]);
Vector lpa = SS.GetEntity(ln->point[0])->PointGetNum();
Vector lpb = SS.GetEntity(ln->point[1])->PointGetNum();
double d = pt.DistanceToLine(lpa, lpb.Minus(lpa));
if(d < LENGTH_EPS) {
Error("Point on helix can't lie on helix's axis!");
return;
}
g.predef.origin = gs.point[0];
g.predef.entityB = gs.entity[0];
} else {
Error("Bad selection for helical sweep.");
return;
}
g.type = HELICAL_SWEEP;
g.subtype = RIGHT_HANDED;
g.valA = 3; // turns;
g.valB = 300/SS.GW.scale; // pitch along axis
g.valC = 0; // pitch in radius
g.opA = SS.GW.activeGroup;
g.name.strcpy("helical-sweep");
SS.GW.ClearSelection();
break;
}
case GraphicsWindow::MNU_GROUP_ROT: { case GraphicsWindow::MNU_GROUP_ROT: {
if(gs.points == 1 && gs.n == 1 && SS.GW.LockedInWorkplane()) { if(gs.points == 1 && gs.n == 1 && SS.GW.LockedInWorkplane()) {
g.predef.origin = gs.point[0]; g.predef.origin = gs.point[0];
@ -315,6 +341,10 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
break; break;
} }
case HELICAL_SWEEP: {
break;
}
case TRANSLATE: { case TRANSLATE: {
// The translation vector // The translation vector
AddParam(param, h.param(0), gp.x); AddParam(param, h.param(0), gp.x);

View File

@ -41,6 +41,7 @@ void Group::GetTrajectory(hGroup hg, SContour *traj, SPolygon *section) {
SEdgeList edges; ZERO(&edges); SEdgeList edges; ZERO(&edges);
int i, j; int i, j;
for(i = 0; i < SS.entity.n; i++) { for(i = 0; i < SS.entity.n; i++) {
Entity *e = &(SS.entity.elem[i]); Entity *e = &(SS.entity.elem[i]);
if(e->group.v != hg.v) continue; if(e->group.v != hg.v) continue;
@ -100,7 +101,6 @@ void Group::GetTrajectory(hGroup hg, SContour *traj, SPolygon *section) {
// The starting point is the endpoint that's closer to the plane // The starting point is the endpoint that's closer to the plane
traj->Reverse(); traj->Reverse();
} }
cleanup: cleanup:
edges.Clear(); edges.Clear();
} }
@ -197,20 +197,41 @@ void Group::GenerateMeshForStepAndRepeat(void) {
thisMesh.Clear(); thisMesh.Clear();
} }
void Group::GenerateMeshForSweep(void) { void Group::GenerateMeshForSweep(bool helical,
Vector axisp, Vector axis, Vector onHelix)
{
STriMeta meta = { 0, color }; STriMeta meta = { 0, color };
SEdgeList edges;
ZERO(&edges);
int a, i; int a, i;
// The closed section that will be swept along the curve // The closed section that will be swept along the curve
Group *section = SS.GetGroup(opB); Group *section = SS.GetGroup(helical ? opA : opB);
SEdgeList edges;
ZERO(&edges);
(section->poly).MakeEdgesInto(&edges); (section->poly).MakeEdgesInto(&edges);
// The trajectory along which the section will be swept // The trajectory along which the section will be swept
SContour traj; SContour traj;
ZERO(&traj); ZERO(&traj);
if(helical) {
double r0 = onHelix.DistanceToLine(axisp, axis);
int n = (int)(SS.CircleSides(r0)*valA) + 4;
Vector origin = onHelix.ClosestPointOnLine(axisp, axis);
Vector u = (onHelix.Minus(origin)).WithMagnitude(1);
Vector v = (axis.Cross(u)).WithMagnitude(1);
for(i = 0; i <= n; i++) {
double turns = (i*valA)/n;
double theta = turns*2*PI;
double r = r0 + turns*valC;
if(subtype == LEFT_HANDED) theta = -theta;
Vector p = origin.Plus(
u.ScaledBy(r*cos(theta)).Plus(
v.ScaledBy(r*sin(theta)).Plus(
axis.WithMagnitude(turns*valB))));
traj.AddPoint(p);
}
} else {
GetTrajectory(opA, &traj, &(section->poly)); GetTrajectory(opA, &traj, &(section->poly));
}
if(traj.l.n <= 0) { if(traj.l.n <= 0) {
edges.Clear(); edges.Clear();
@ -222,7 +243,17 @@ void Group::GenerateMeshForSweep(void) {
Vector origNormal = (traj.l.elem[1].p).Minus(origRef); Vector origNormal = (traj.l.elem[1].p).Minus(origRef);
origNormal = origNormal.WithMagnitude(1); origNormal = origNormal.WithMagnitude(1);
Vector oldRef = origRef, oldNormal = origNormal; Vector oldRef = origRef, oldNormal = origNormal;
Vector oldU = oldNormal.Normal(0), oldV = oldNormal.Normal(1);
Vector oldU, oldV;
if(helical) {
oldU = axis.WithMagnitude(1);
oldV = (oldNormal.Cross(oldU)).WithMagnitude(1);
// numerical fixup, since pwl segment isn't exactly tangent...
oldU = (oldV.Cross(oldNormal)).WithMagnitude(1);
} else {
oldU = oldNormal.Normal(0);
oldV = oldNormal.Normal(1);
}
// The endcap at the start of the curve // The endcap at the start of the curve
SPolygon cap; SPolygon cap;
@ -257,11 +288,18 @@ void Group::GenerateMeshForSweep(void) {
useNormal = (thisNormal.Plus(oldNormal)).ScaledBy(0.5); useNormal = (thisNormal.Plus(oldNormal)).ScaledBy(0.5);
} }
Vector useV, useU;
useNormal = useNormal.WithMagnitude(1);
if(helical) {
// The axis of rotation is always a basis vector
useU = axis.WithMagnitude(1);
useV = (useNormal.Cross(useU)).WithMagnitude(1);
} else {
// Choose a new coordinate system, normal to the trajectory and // Choose a new coordinate system, normal to the trajectory and
// with the minimum possible twist about the normal. // with the minimum possible twist about the normal.
useNormal = useNormal.WithMagnitude(1); useV = (useNormal.Cross(oldU)).WithMagnitude(1);
Vector useV = (useNormal.Cross(oldU)).WithMagnitude(1); useU = (useV.Cross(useNormal)).WithMagnitude(1);
Vector useU = (useV.Cross(useNormal)).WithMagnitude(1); }
Quaternion qi = Quaternion::From(oldU, oldV); Quaternion qi = Quaternion::From(oldU, oldV);
Quaternion qf = Quaternion::From(useU, useV); Quaternion qf = Quaternion::From(useU, useV);
@ -432,7 +470,14 @@ void Group::GenerateMesh(void) {
} }
} }
} else if(type == SWEEP) { } else if(type == SWEEP) {
GenerateMeshForSweep(); Vector zp = Vector::From(0, 0, 0);
GenerateMeshForSweep(false, zp, zp, zp);
} else if(type == HELICAL_SWEEP) {
Entity *ln = SS.GetEntity(predef.entityB);
Vector lna = SS.GetEntity(ln->point[0])->PointGetNum(),
lnb = SS.GetEntity(ln->point[1])->PointGetNum();
Vector onh = SS.GetEntity(predef.origin)->PointGetNum();
GenerateMeshForSweep(true, lna, lnb.Minus(lna), onh);
} else if(type == IMPORTED) { } else if(type == IMPORTED) {
// Triangles are just copied over, with the appropriate transformation // Triangles are just copied over, with the appropriate transformation
// applied. // applied.

View File

@ -83,6 +83,7 @@ public:
static const int EXTRUDE = 5100; static const int EXTRUDE = 5100;
static const int LATHE = 5101; static const int LATHE = 5101;
static const int SWEEP = 5102; static const int SWEEP = 5102;
static const int HELICAL_SWEEP = 5103;
static const int ROTATE = 5200; static const int ROTATE = 5200;
static const int TRANSLATE = 5201; static const int TRANSLATE = 5201;
static const int IMPORTED = 5300; static const int IMPORTED = 5300;
@ -94,6 +95,8 @@ public:
bool clean; bool clean;
hEntity activeWorkplane; hEntity activeWorkplane;
double valA; double valA;
double valB;
double valC;
DWORD color; DWORD color;
static const int SOLVED_OKAY = 0; static const int SOLVED_OKAY = 0;
@ -104,10 +107,15 @@ public:
SList<hConstraint> remove; SList<hConstraint> remove;
} solved; } solved;
// For drawings in 2d
static const int WORKPLANE_BY_POINT_ORTHO = 6000; static const int WORKPLANE_BY_POINT_ORTHO = 6000;
static const int WORKPLANE_BY_LINE_SEGMENTS = 6001; static const int WORKPLANE_BY_LINE_SEGMENTS = 6001;
// For extrudes, translates, and rotates
static const int ONE_SIDED = 7000; static const int ONE_SIDED = 7000;
static const int TWO_SIDED = 7001; static const int TWO_SIDED = 7001;
// For helical sweeps
static const int RIGHT_HANDED = 8000;
static const int LEFT_HANDED = 8001;
int subtype; int subtype;
bool skipFirst; // for step and repeat ops bool skipFirst; // for step and repeat ops
@ -158,8 +166,8 @@ public:
void Activate(void); void Activate(void);
char *DescriptionString(void); char *DescriptionString(void);
static void AddParam(IdList<Param,hParam> *param, hParam hp, double v); static void AddParam(ParamList *param, hParam hp, double v);
void Generate(IdList<Entity,hEntity> *entity, IdList<Param,hParam> *param); void Generate(EntityList *entity, ParamList *param);
// When a request generates entities from entities, and the source // When a request generates entities from entities, and the source
// entities may have come from multiple requests, it's necessary to // entities may have come from multiple requests, it's necessary to
// remap the entity ID so that it's still unique. We do this with a // remap the entity ID so that it's still unique. We do this with a
@ -170,10 +178,10 @@ public:
static const int REMAP_PT_TO_LINE = 1003; static const int REMAP_PT_TO_LINE = 1003;
static const int REMAP_LINE_TO_FACE = 1004; static const int REMAP_LINE_TO_FACE = 1004;
hEntity Remap(hEntity in, int copyNumber); hEntity Remap(hEntity in, int copyNumber);
void MakeExtrusionLines(IdList<Entity,hEntity> *el, hEntity in); void MakeExtrusionLines(EntityList *el, hEntity in);
void MakeExtrusionTopBottomFaces(IdList<Entity,hEntity> *el, hEntity pt); void MakeExtrusionTopBottomFaces(EntityList *el, hEntity pt);
void TagEdgesFromLineSegments(SEdgeList *sle); void TagEdgesFromLineSegments(SEdgeList *sle);
void CopyEntity(IdList<Entity,hEntity> *el, void CopyEntity(EntityList *el,
Entity *ep, int timesApplied, int remap, Entity *ep, int timesApplied, int remap,
hParam dx, hParam dy, hParam dz, hParam dx, hParam dy, hParam dz,
hParam qw, hParam qvx, hParam qvy, hParam qvz, hParam qw, hParam qvx, hParam qvy, hParam qvz,
@ -190,7 +198,8 @@ public:
void AddQuadWithNormal(STriMeta meta, Vector out, void AddQuadWithNormal(STriMeta meta, Vector out,
Vector a, Vector b, Vector c, Vector d); Vector a, Vector b, Vector c, Vector d);
void GenerateMeshForStepAndRepeat(void); void GenerateMeshForStepAndRepeat(void);
void GenerateMeshForSweep(void); void GenerateMeshForSweep(bool helical,
Vector axisp, Vector axis, Vector onHelix);
void GenerateMesh(void); void GenerateMesh(void);
void Draw(void); void Draw(void);
@ -226,8 +235,8 @@ public:
bool construction; bool construction;
static hParam AddParam(IdList<Param,hParam> *param, hParam hp); static hParam AddParam(ParamList *param, hParam hp);
void Generate(IdList<Entity,hEntity> *entity, IdList<Param,hParam> *param); void Generate(EntityList *entity, ParamList *param);
char *DescriptionString(void); char *DescriptionString(void);
}; };

View File

@ -101,7 +101,10 @@ void vl(void); // debug function to validate
class Entity; class Entity;
class hEntity; class hEntity;
class Param;
class hParam;
typedef IdList<Entity,hEntity> EntityList; typedef IdList<Entity,hEntity> EntityList;
typedef IdList<Param,hParam> ParamList;
#include "sketch.h" #include "sketch.h"
#include "ui.h" #include "ui.h"
@ -144,8 +147,8 @@ class System {
public: public:
#define MAX_UNKNOWNS 200 #define MAX_UNKNOWNS 200
IdList<Entity,hEntity> entity; EntityList entity;
IdList<Param,hParam> param; ParamList param;
IdList<Equation,hEquation> eq; IdList<Equation,hEquation> eq;
// In general, the tag indicates the subsys that a variable/equation // In general, the tag indicates the subsys that a variable/equation

View File

@ -626,6 +626,39 @@ void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) {
SS.GenerateAll(); SS.GenerateAll();
SS.GW.ClearSuper(); SS.GW.ClearSuper();
} }
void TextWindow::ScreenChangeRightLeftHanded(int link, DWORD v) {
SS.UndoRemember();
Group *g = SS.GetGroup(SS.TW.shown->group);
if(g->subtype == Group::RIGHT_HANDED) {
g->subtype = Group::LEFT_HANDED;
} else {
g->subtype = Group::RIGHT_HANDED;
}
SS.MarkGroupDirty(g->h);
SS.GenerateAll();
SS.GW.ClearSuper();
}
void TextWindow::ScreenChangeHelixParameter(int link, DWORD v) {
Group *g = SS.GetGroup(SS.TW.shown->group);
char str[1024];
int r;
if(link == 't') {
sprintf(str, "%.3f", g->valA);
SS.TW.edit.meaning = EDIT_HELIX_TURNS;
r = 12;
} else if(link == 'p') {
strcpy(str, SS.MmToString(g->valB));
SS.TW.edit.meaning = EDIT_HELIX_PITCH;
r = 14;
} else if(link == 'r') {
strcpy(str, SS.MmToString(g->valC));
SS.TW.edit.meaning = EDIT_HELIX_DRADIUS;
r = 16;
} else oops();
SS.TW.edit.group.v = v;
ShowTextEditControl(r, 9, str);
}
void TextWindow::ScreenColor(int link, DWORD v) { void TextWindow::ScreenColor(int link, DWORD v) {
SS.UndoRemember(); SS.UndoRemember();
@ -683,10 +716,6 @@ void TextWindow::ShowGroupInfo(void) {
g->h.v, &TextWindow::ScreenDeleteGroup); g->h.v, &TextWindow::ScreenDeleteGroup);
} }
if(g->type == Group::IMPORTED) {
Printf(true, "%FtIMPORT%E '%s'", g->impFile);
}
if(g->type == Group::EXTRUDE) { if(g->type == Group::EXTRUDE) {
s = "EXTRUDE "; s = "EXTRUDE ";
} else if(g->type == Group::TRANSLATE) { } else if(g->type == Group::TRANSLATE) {
@ -709,10 +738,31 @@ void TextWindow::ShowGroupInfo(void) {
&TextWindow::ScreenChangeOneOrTwoSides, &TextWindow::ScreenChangeOneOrTwoSides,
(!one ? "" : "two sides"), (!one ? "two sides" : "")); (!one ? "" : "two sides"), (!one ? "two sides" : ""));
} }
if(g->type == Group::LATHE) { if(g->type == Group::LATHE) {
Printf(true, "%FtLATHE"); Printf(true, "%FtLATHE");
} }
if(g->type == Group::SWEEP) {
Printf(true, "%FtSWEEP");
}
if(g->type == Group::HELICAL_SWEEP) {
bool rh = (g->subtype == Group::RIGHT_HANDED);
Printf(true,
"%FtHELICAL%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
&ScreenChangeRightLeftHanded,
(rh ? "" : "right-hand"), (rh ? "right-hand" : ""),
&ScreenChangeRightLeftHanded,
(!rh ? "" : "left-hand"), (!rh ? "left-hand" : ""));
Printf(false, "%FtTHROUGH%E %@ turns %Fl%Lt%D%f[change]%E",
g->valA, g->h.v, &ScreenChangeHelixParameter);
Printf(false, "%FtPITCH%E %s per turn %Fl%Lp%D%f[change]%E",
SS.MmToString(g->valB), g->h.v, &ScreenChangeHelixParameter);
Printf(false, "%FtdRADIUS%E %s per turn %Fl%Lr%D%f[change]%E",
SS.MmToString(g->valC), g->h.v, &ScreenChangeHelixParameter);
}
if(g->type == Group::ROTATE || g->type == Group::TRANSLATE) { if(g->type == Group::ROTATE || g->type == Group::TRANSLATE) {
bool space; bool space;
if(g->subtype == Group::ONE_SIDED) { if(g->subtype == Group::ONE_SIDED) {
@ -734,9 +784,14 @@ void TextWindow::ShowGroupInfo(void) {
g->h.v, &TextWindow::ScreenChangeExprA); g->h.v, &TextWindow::ScreenChangeExprA);
} }
if(g->type == Group::IMPORTED) {
Printf(true, "%FtIMPORT%E '%s'", g->impFile);
}
if(g->type == Group::EXTRUDE || if(g->type == Group::EXTRUDE ||
g->type == Group::LATHE || g->type == Group::LATHE ||
g->type == Group::SWEEP || g->type == Group::SWEEP ||
g->type == Group::HELICAL_SWEEP ||
g->type == Group::IMPORTED) g->type == Group::IMPORTED)
{ {
bool un = (g->meshCombine == Group::COMBINE_AS_UNION); bool un = (g->meshCombine == Group::COMBINE_AS_UNION);
@ -744,7 +799,7 @@ void TextWindow::ShowGroupInfo(void) {
bool asy = (g->meshCombine == Group::COMBINE_AS_ASSEMBLE); bool asy = (g->meshCombine == Group::COMBINE_AS_ASSEMBLE);
bool asa = (g->type == Group::IMPORTED); bool asa = (g->type == Group::IMPORTED);
Printf(false, 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 " "%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", "%Fh%f%D%Ll%s%E%Fs%s%E",
&TextWindow::ScreenChangeMeshCombine, &TextWindow::ScreenChangeMeshCombine,
@ -764,7 +819,8 @@ void TextWindow::ShowGroupInfo(void) {
if(g->type == Group::EXTRUDE || if(g->type == Group::EXTRUDE ||
g->type == Group::LATHE || g->type == Group::LATHE ||
g->type == Group::SWEEP) g->type == Group::SWEEP ||
g->type == Group::HELICAL_SWEEP)
{ {
#define TWOX(v) v v #define TWOX(v) v v
Printf(true, "%FtM_COLOR%E " TWOX(TWOX(TWOX("%Bp%D%f%Ln %Bd%E "))), Printf(true, "%FtM_COLOR%E " TWOX(TWOX(TWOX("%Bp%D%f%Ln %Bd%E "))),
@ -997,6 +1053,27 @@ void TextWindow::EditControlDone(char *s) {
InvalidateGraphics(); InvalidateGraphics();
break; break;
} }
case EDIT_HELIX_TURNS:
case EDIT_HELIX_PITCH:
case EDIT_HELIX_DRADIUS: {
SS.UndoRemember();
Group *g = SS.GetGroup(edit.group);
Expr *e = Expr::From(s);
if(!e) {
Error("Not a valid number or expression: '%s'", s);
break;
}
if(edit.meaning == EDIT_HELIX_TURNS) {
g->valA = min(30, fabs(e->Eval()));
} else if(edit.meaning == EDIT_HELIX_PITCH) {
g->valB = SS.ExprToMm(e);
} else {
g->valC = SS.ExprToMm(e);
}
SS.MarkGroupDirty(g->h);
SS.later.generateAll = true;
break;
}
} }
SS.later.showTW = true; SS.later.showTW = true;
HideTextEditControl(); HideTextEditControl();

6
ui.h
View File

@ -64,6 +64,9 @@ public:
static const int EDIT_COLOR = 5; static const int EDIT_COLOR = 5;
static const int EDIT_MESH_TOLERANCE = 6; static const int EDIT_MESH_TOLERANCE = 6;
static const int EDIT_CAMERA_TANGENT = 7; static const int EDIT_CAMERA_TANGENT = 7;
static const int EDIT_HELIX_TURNS = 8;
static const int EDIT_HELIX_PITCH = 9;
static const int EDIT_HELIX_DRADIUS = 10;
struct { struct {
int meaning; int meaning;
int i; int i;
@ -103,6 +106,8 @@ public:
static void ScreenChangeOneOrTwoSides(int link, DWORD v); static void ScreenChangeOneOrTwoSides(int link, DWORD v);
static void ScreenChangeSkipFirst(int link, DWORD v); static void ScreenChangeSkipFirst(int link, DWORD v);
static void ScreenChangeMeshCombine(int link, DWORD v); static void ScreenChangeMeshCombine(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); static void ScreenColor(int link, DWORD v);
static void ScreenShowConfiguration(int link, DWORD v); static void ScreenShowConfiguration(int link, DWORD v);
@ -164,6 +169,7 @@ public:
MNU_GROUP_EXTRUDE, MNU_GROUP_EXTRUDE,
MNU_GROUP_LATHE, MNU_GROUP_LATHE,
MNU_GROUP_SWEEP, MNU_GROUP_SWEEP,
MNU_GROUP_HELICAL,
MNU_GROUP_ROT, MNU_GROUP_ROT,
MNU_GROUP_TRANS, MNU_GROUP_TRANS,
MNU_GROUP_IMPORT, MNU_GROUP_IMPORT,