PRIVATE CONST A = (0, -400), Pi = 3.142, MaxThrow = Pi / 4, BarLen1 = 200, BarLen2 = 100, NodeSize = 30, EdgeWidth = 5, LabelFont = "Times-Bold", LabelSize = PS.Huge, DeltaT = 0.02, NodeColor = Color.FromRGB(1, 0.4, 0.4), SubtreeColor = Color.FromRGB(0.2, 1, 1); PRIVATE VAR Asc, Dec, FrameNum; PRIVATE PROC Edge(a, b) IS PS.MoveTo(a); PS.LineTo(b); PS.Stroke() END; PRIVATE PROC Node(p, label) IS VAR w IN w := PS.StringWidth(label); Circle.DrawR(p, NodeSize); SAVE PS IN PS.SetColor(NodeColor); PS.Fill() END; PS.Stroke(); PS.Type(R2.Minus(p, (w / 2, Dec)), label) END END; PRIVATE PROC Child(root, label, side) IS IF VAR n ~ (1, side) REL (root, R2.MinusY(root, BarLen2)) IN side * (CAR(n) - CAR(root)) = COS(MaxThrow) * BarLen1 / 2 AND BarLen2 = Geometry.Dist(n, root) -> Edge(root, n); SubTree(n, label) END FI END; PRIVATE PROC SubTree(p, label) IS VAR p2, w, ll, lr IN w := 3 * (Asc + Dec); p2 := R2.MinusY(p, w); ll := R2.MinusX(p2, w / 2); lr := R2.PlusX(p2, w / 2); SAVE PS IN PS.MoveTo(p); PS.LineTo(ll); PS.LineTo(lr); PS.Close(); SAVE PS IN PS.SetColor(SubtreeColor); PS.Fill() END; PS.SetJointStyle(PS.RoundJoints); PS.Stroke() END; Type.C(R2.PlusY(p2, 2 * Dec), label) END END; PRIVATE PROC ShowFrameNum() IS Type.R(A, Text.FromNum(FrameNum, 3)); FrameNum := FrameNum + 1 END; PRIVATE PROC DrawFrame(pivot, z, t) IS VAR p2, a, x, y, sTop, sBot IN p2 := R2.PlusX(pivot, BarLen1 / 2); a := t * MaxThrow; x := (-COS(a), -SIN(a)) REL (pivot, p2); y := (COS(a), SIN(a)) REL (pivot, p2); sTop := (t, 0) REL (pivot, y); sBot := (t, 0) REL (pivot, x); IF VAR b ~ R2.MinusY(pivot, BarLen1) IN b VER pivot AND BarLen2 = Geometry.Dist(b, sBot) -> PS.SetWidth(EdgeWidth); PS.SetFont(LabelFont, LabelSize); Asc, Dec := PS.FontHeight(); Edge(x, y); Edge(z, sTop); Edge(b, sBot); Child(x, "A", -1); Child(y, "C", 1); Node(z, "z"); Node(x, "x"); Node(y, "y"); SubTree(b, "B") END FI; ShowFrameNum() END END; PRIVATE PROC tout := Warp(dur, t) IS tout := (2 * t / dur) - 1 END; /* This sets "tout" to a value in the range "[-1,1]" as "t" varies over the range "[0,dur]". */ PRIVATE PROC an := DrawAnim(pivot, root, dur, pause) IS VAR an0, an1, an2 IN dur := dur / 2; an0 := (CLOSE(DrawFrame, pivot, root), dur); an2 := Anim.WarpTime(an0, CLOSE(Warp, dur)); an1 := Anim.Extend(an2, dur + pause); an := Anim.Seq(an1, Anim.Reverse(an2)) END END; /* Return an animation that rotates the tree back and forth over "dur" seconds (total), with a pause of "pause" seconds in the middle. */ PROC Start(pivot, root) IS FrameNum := 0; SAVE PS IN DrawFrame(pivot, root, -1) END END; UI PointTool(Start); (* Show the initial configuration of the tree with pivot at point "pivot" and root node at location "root". *) PROC Go(pivot, root) IS FrameNum := 1; Anim.Play(DrawAnim(pivot, root, 4, 1)) END; UI PointTool(Go); (* Animate 2 rotations about the point "pivot" with root node at location "root". *) PROC Cmd0() IS IF VAR a ~ (-7.574, 1.798), b ~ (-9.467, 153.7) IN Start(a, b); Go(a, b) END FI END;