<<>> <> <> <> <> DIRECTORY Draw2d, Commander, Controls, G2dTool, Imager, IO, Process, RealFns, Vector2, ViewerOps; G2dSpirographCmdImpl: CEDAR PROGRAM IMPORTS Draw2d, Controls, G2dTool, Process, RealFns, ViewerOps ~ BEGIN ProgramData: TYPE ~ REF ProgramDataRep; 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; }; G2dTool.Register["Spirograph", G2dSpirograph, "\nDraw a spirograph."]; END.