ProgramDataRep:
TYPE ~
RECORD [
outer: Controls.Viewer ¬ NIL, -- main outer viewer
graphics: Controls.Viewer ¬ NIL, -- viewer for graphics
smallAngle, bigAngle: REAL ¬ 0.0,
centerPt: Imager.VEC ¬ [150.0, 150.0],
oldPt, newPt: Imager.VEC,
bigAngleDelta: REAL,
smallAngleDelta: REAL,
smallSpeed: REAL ¬ 37.0, -- speed increase for the small wheel
smallR: REAL ¬ 30.0, -- small wheel radius
bigR: REAL ¬ 90.0, -- big wheel radius
modR: REAL ¬ .4, -- percent of small wheel radius modulation
modF: REAL ¬ 5.0, -- small wheel radius modulation frequency
cycles: REAL ¬ 1.2, -- # of small wheel rotations around the big one
numSteps: INTEGER ¬ 5000, -- # of steps to take once around the big wheel
loops: INTEGER ¬ 5, -- # of times to go around the big wheel
bigPt: Imager.VEC,
tmpR: REAL,
smallPt: Imager.VEC,
dset: INTEGER ¬ 2, -- which prebuilt data set to use
start: BOOL ¬ TRUE,
newViewer: BOOL ¬ TRUE
];
G2dSpirograph: Commander.CommandProc ~ {
p: ProgramData ¬ NEW[ProgramDataRep];
p.outer ¬ Controls.OuterViewer[
name: "Spirograph",
graphicsHeight: 300,
drawProc: DrawProc,
clientData: p].parent;
p.graphics ¬ NARROW[p.outer.data, Controls.OuterData].graphics;
SELECT p.dset
FROM
4 => {
p.smallSpeed ¬ 15.0; p.smallR ¬ 30.0; p.bigR ¬ 50.0; p.modR ¬ 1.4; p.modF ¬ 7.0;
p.cycles ¬ 1.4; p.numSteps ¬ 5000; p.loops ¬ 5;
};
3 => {
p.smallSpeed ¬ 15.0; p.smallR ¬ 30.0; p.bigR ¬ 90.0; p.modR ¬ .4; p.modF ¬ 7.0;
p.cycles ¬ 1.4; p.numSteps ¬ 5000; p.loops ¬ 5;
};
2 => {
p.smallSpeed ¬ 37.0; p.smallR ¬ 30.0; p.bigR ¬ 90.0; p.modR ¬ .4; p.modF ¬ 5.0;
p.cycles ¬ 1.2; p.numSteps ¬ 5000; p.loops ¬ 5;
};
ENDCASE => {
p.smallSpeed ¬ 13.0; p.smallR ¬ 30.0; p.bigR ¬ 90.0; p.modR ¬ .4; p.modF ¬ 5.0;
p.cycles ¬ 1.0; p.numSteps ¬ 5000; p.loops ¬ 1;
};
p.bigAngleDelta ¬ (2.0*3.1415926535*p.cycles)/p.numSteps;
p.smallAngleDelta ¬ (2.0*3.1415926535*p.smallSpeed)/p.numSteps;
Process.Pause[Process.MsecToTicks[100]];
FOR n:
NAT
IN [0..p.loops)
DO
ViewerOps.PaintViewer[p.graphics, client, FALSE, p.graphics];
Process.CheckForAbort[];
ENDLOOP;
};
DrawProc: Controls.DrawProc ~ {
p: ProgramData ¬ NARROW[clientData];
IF p.newViewer
THEN {
p.newViewer ¬ FALSE;
Draw2d.Clear[context];
RETURN;
};
FOR n:
NAT
IN [0..p.numSteps)
DO
p.bigPt ¬ [p.bigR*RealFns.Cos[p.bigAngle], p.bigR*RealFns.Sin[p.bigAngle]];
p.tmpR ¬ p.smallR + ((p.smallR * p.modR) * RealFns.Sin[p.bigAngle * p.modF]);
p.smallPt ¬ [p.tmpR*RealFns.Cos[p.smallAngle], p.tmpR*RealFns.Sin[p.smallAngle]];
p.newPt.x ¬ p.centerPt.x + p.bigPt.x + p.smallPt.x;
p.newPt.y ¬ p.centerPt.y + p.bigPt.y + p.smallPt.y;
IF p.start
THEN p.start ¬ FALSE
ELSE Draw2d.Line[context, p.oldPt, p.newPt];
p.oldPt ¬ p.newPt;
p.bigAngle ¬ p.bigAngle + p.bigAngleDelta;
p.smallAngle ¬ p.smallAngle + p.smallAngleDelta;
ENDLOOP;