<<>> <> <> <> <> <<>> DIRECTORY Buttons, Commander, Draw2d, FS, G2dTool, Imager, MessageWindow, Random, Real, RealFns, Rope, TIPUser, ViewerClasses, ViewerOps, ViewerTools; G2dPrettyCurvesCmdImpl: CEDAR PROGRAM IMPORTS Buttons, Draw2d, FS, G2dTool, Imager, MessageWindow, Random, RealFns, Rope, TIPUser, ViewerOps, ViewerTools ~ BEGIN <> PaintData: TYPE ~ REF PaintDataRec; PaintDataRec: TYPE ~ RECORD [ viewer: ViewerClasses.Viewer ¬ NIL, x, y: REAL ¬ 10, cn: INT ¬ 0, random: Random.RandomStream ¬ Random.Create[range:21, seed:4] ]; VEC: TYPE ~ Imager.VEC; <> Abs: PUBLIC PROC [ival: REAL] RETURNS [REAL] = { IF ival > 0.0 THEN RETURN[ival] ELSE RETURN[-ival]; }; PrettyCurvesCmd: Commander.CommandProc ~ { pd: PaintData ¬ NEW[PaintDataRec]; pd.viewer ¬ ViewerOps.CreateViewer[ flavor: $Paint, info: [name: "2dPrettyCurves", data: pd]]; [] ¬ Buttons.Create[[parent: pd.viewer, name: "IP-Out ", wx: 3, wy: 20], IPOut, pd]; ViewerOps.OpenIcon[pd.viewer]; }; Complain: PROC [rope: Rope.ROPE] ~ { MessageWindow.Append[rope, TRUE]; MessageWindow.Blink[]; }; IPOut: ViewerClasses.ClickProc ~ { fileName: Rope.ROPE ¬ ViewerTools.GetSelectionContents[]; IF Rope.IsEmpty[fileName] THEN Complain["\t\tPlease select a filename first."] ELSE Draw2d.IPOut[fileName, DoDraw, clientData ! FS.Error => {Complain[Rope.Concat["Bad name: ", fileName]]; CONTINUE}]; }; PaintPaint: ViewerClasses.PaintProc ~ { DoDraw[context, self.data, whatChanged, self]; }; DoDraw: Draw2d.DrawProc ~ { paintData: PaintData ¬ NARROW[clientData]; pi: REAL ¬ 3.1415926535; theta, r: REAL; steps: INT ¬ 250; v1, v2: VEC ¬ [0, 0]; choice: INT ¬ 1; polar: BOOL ¬ FALSE; Imager.MaskRectangle[context, [paintData.x-10.0, paintData.y-10.0, 0.0, 0.0]]; Draw2d.Circle[context, [paintData.x, paintData.y], 0.0, FALSE]; choice ¬ paintData.cn; choice ¬ Random.NextInt[paintData.random]; FOR step: INT¬0, step+1 WHILE step <= steps DO theta¬(step*2.0*pi)/steps; SELECT choice FROM 0 => { -- circle v2.x¬RealFns.Cos[theta]; v2.y¬RealFns.Sin[theta]; }; 1 => { v2.x¬(.8 * RealFns.Sin[theta] + .2 * RealFns.Sin[7.0 * theta]); v2.y¬(.5 * RealFns.Cos[theta] + .5 * RealFns.Cos[9.0 * theta]); }; 2 => { v2.x¬(.6 * RealFns.Sin[theta] + .4 * RealFns.Sin[7.0 * theta]); v2.y¬(.3 * RealFns.Cos[theta] + .4 * RealFns.Cos[4.0 * theta]); }; 3 => { v2.x¬(.4 * RealFns.Sin[theta] + .6 * RealFns.Sin[9.0 * theta]); v2.y¬(.3 * RealFns.Cos[theta] + .4 * RealFns.Cos[6.0 * theta]); }; 4 => { v2.x¬(.8 * RealFns.Sin[theta] + (.2 * RealFns.Sin[7.0 * theta]) * .5 * (1.0 + Abs[RealFns.Cos[11.0 * theta]])); v2.y¬(.8 * RealFns.Cos[theta] + (.2 * RealFns.Cos[7.0 * theta]) * .5 * (1.0 + Abs[RealFns.Cos[11.0 * theta]])); }; 5 => { v2.x¬(RealFns.Sin[theta] * RealFns.Sin[3.0 * theta] * RealFns.Sin[5.0 * theta]); v2.y¬(RealFns.Sin[4.0 * theta] * RealFns.Cos[2.0 * theta] * RealFns.Cos[6.0 * theta]); }; 6 => { v2.x¬(RealFns.Sin[theta] * RealFns.Cos[3.0 * theta] * RealFns.Sin[5.0 * theta]); v2.y¬(RealFns.Sin[2.0 * theta] * RealFns.Cos[4.0 * theta] * RealFns.Sin[6.0 * theta]); }; 7 => { v2.x¬.5 * (RealFns.Sin[3.0 * theta] + RealFns.Sin[4.0 * theta]); v2.y¬.5 * (RealFns.Sin[theta] + RealFns.Sin[2.0 * theta]); }; 8 => { v2.x¬.5 * (RealFns.Sin[3.0 * theta] + RealFns.Sin[5.0 * theta]); v2.y¬.5 * (RealFns.Sin[2.0 * theta] + RealFns.Sin[4.0 * theta]); }; 9 => { v2.x¬.5 * (RealFns.Sin[3.0 * theta] + RealFns.Cos[5.0 * theta]); v2.y¬.5 * (RealFns.Sin[2.0 * theta] + RealFns.Sin[4.0 * theta]); }; 10 => { v2.x¬0.25 * (RealFns.Sin[theta] + RealFns.Sin[3.0 * theta] + RealFns.Cos[5.0 * theta] + RealFns.Cos[7.0 * theta]); v2.y¬0.25 * (RealFns.Sin[2.0 * theta] + RealFns.Sin[4.0 * theta] + RealFns.Cos[6.0 * theta] + RealFns.Cos[8.0 * theta]); }; 11 => { v2.x¬(.8 * RealFns.Cos[theta] + .2 * RealFns.Sin[9.0 * theta]); v2.y¬(.8 * RealFns.Sin[theta] + .2 * RealFns.Sin[3.0 * theta]); }; 12 => { v2.x¬0.5 * (RealFns.Sin[4.0 * theta] + RealFns.Sin[7.0 * theta]); v2.y¬0.5 * (RealFns.Sin[3.0 * theta] + RealFns.Sin[2.0 * theta]); }; 13 => { v2.x¬ 0.5 * (RealFns.Sin[3.0 * theta] + RealFns.Sin[4.0 * theta]); v2.y¬0.5 * (RealFns.Sin[3.0 * theta] + RealFns.Sin[2.0 * theta]); }; 14 => { r ¬ RealFns.Sin[RealFns.Exp[RealFns.Cos[2.0*theta]]] + RealFns.Cos[RealFns.Exp[RealFns.Sin[5.0*theta]]]; polar ¬ TRUE; v2.x ¬ RealFns.Sin[r]; v2.y ¬ RealFns.Cos[r]; }; 15 => { r ¬ Abs[RealFns.Sin[2.0*theta]] + Abs[RealFns.Sin[3.0*theta]]; polar ¬ TRUE; }; 16 => { r ¬ RealFns.Cos[Abs[RealFns.Sin[5.0*theta]]] + RealFns.Sin[Abs[RealFns.Cos[2.0*theta]]] ; polar ¬ TRUE; }; 17 => { r ¬ Abs[RealFns.Sin[6.0*theta]] + Abs[RealFns.Sin[3.0*theta]]; polar ¬ TRUE; }; 18 => { r ¬ RealFns.Sin[6.0*theta] + RealFns.Sin[3.0*theta]; polar ¬ TRUE; }; 19 => { r ¬ RealFns.Sin[2.0*theta] * RealFns.SqRt[Abs[RealFns.Cos[2.0*theta]]] * RealFns.SqRt[Abs[RealFns.Sin[5.0*theta]]]; polar ¬ TRUE; }; 20 => { r ¬ RealFns.SqRt[Abs[RealFns.Cos[2.0*theta]]] + RealFns.SqRt[Abs[RealFns.Sin[5.0*theta]]]; polar ¬ TRUE; }; 21 => { r ¬ RealFns.Sin[RealFns.SqRt[Abs[RealFns.Cos[theta]]]] * RealFns.Sin[6.0*theta]; polar ¬ TRUE; paintData.cn ¬ 0; }; ENDCASE => NULL; IF polar = TRUE THEN { v2.x ¬ 0.8*r*RealFns.Sin[theta]; v2.y ¬ 0.8*r*RealFns.Cos[theta]; }; v2.x ¬ (v2.x * 200.0) + paintData.x; v2.y ¬ (v2.y * 200.0) + paintData.y; IF step > 0 THEN Imager.MaskVector[context, v1, v2]; v1 ¬ v2; ENDLOOP; }; NotifyPaint: ViewerClasses.NotifyProc = { paintData: PaintData ¬ NARROW[self.data]; mouse: TIPUser.TIPScreenCoords ¬ NARROW[input.first]; SELECT input.rest.first FROM $move => { paintData.x ¬ mouse.mouseX; paintData.y ¬ mouse.mouseY; paintData.cn ¬ paintData.cn + 1; ViewerOps.PaintViewer[self, client] }; ENDCASE => NULL; }; <> <> ViewerOps.RegisterViewerClass[ $Paint, NEW[ViewerClasses.ViewerClassRec ¬ [ paint: PaintPaint, notify: NotifyPaint, tipTable: TIPUser.InstantiateNewTIPTable["G2dPlot.tip"] ]] ]; G2dTool.Register["PrettyCurves", PrettyCurvesCmd, "Draw some pretty parametric curves"]; END.