(* This figure shows that the path traced out by the end of the crank on Andrei's wood toy is an ellipse. The points have been constrained to mimic the physical device, and an ellipse has been drawn in red based on the lengths of the major and minor axes (which are easy to compute from the constants "Dist1" and "Dist2"). The number printed at the crank point is the distance from that point to the ellipse. The distance is zero (or extremely small) for all points on the elliptical path. *) PRIVATE CONST Dist1 = 150, Dist2 = 2 / 3 * Dist1; /* "Dist1" is the total length of the crank arm. "Dist2" is the distance from the end of the crank arm (point "d" in the figure) to the first attachment point (point "c" in the figure). */ PROC HorLine(a) IS IF VAR ax, ay IN a = (ax, ay) -> SAVE PS IN PS.MoveTo((-1000, ay)); PS.LineTo((1000, ay)); PS.SetColor(Color.Cyan); PS.Stroke() END END FI END; PROC VerLine(a) IS IF VAR ax, ay IN a = (ax, ay) -> SAVE PS IN PS.MoveTo((ax, -1000)); PS.LineTo((ax, 1000)); PS.SetColor(Color.Cyan); PS.Stroke() END END FI END; UI PointTool(HorLine); UI PointTool(VerLine); /* Draw "infinite" horizontal and vertical cyan lines, respectively, through the point "a". */ PRED FixedDist1(a, b) IS Dist1 = Geometry.Dist(a, b) END; PRED FixedDist2(a, b) IS Dist2 = Geometry.Dist(a, b) END; UI PointTool(FixedDist1); UI PointTool(FixedDist2); (* This distance between the points "a" and "b" are the constants "Dist1" and "Dist2", respectively. *) PROC DrawDot(a) IS SAVE PtLabel IN PtLabel.SetDotSize(4); PtLabel.None(a) END END; UI PointTool(DrawDot); (* Draw a small dot in the current color at "a". *) PROC RedEllipse(a, b, c) IS SAVE PS IN PS.SetColor(Color.Red); Ellipse.Draw(a, b, c); PS.Stroke() END END; UI PointTool(RedEllipse); (* Draw a red ellipse with center "a", major axis endpoint "b", and with a minor axis having the same length as the segment "ac". *) PROC PrintDist(a, b) IS IF VAR d2 = Geometry.Dist2(a, b) IN Type.C(R2.PlusY(a, 10), Unparse.Value(d2)) END FI END; PROC EllipseDist(a, b, c, d) IS IF VAR e ~ d IN Ellipse.On(e, a, b, c) AND Geometry.Colinear(a, e, d) -> PrintDist(d, e) END FI END; UI PointTool(EllipseDist); (* At "d", print the distance from the point "d" to the ellipse defined by the points "a", "b", and "c". *) PROC Cmd0() IS IF VAR a = (0, 0), b ~ (-38.677444, 0), c ~ (0, 31.68684), d ~ (77.35488, 95.06051), e ~ (-93.76512, -34.757763), f ~ (0, 150) IN a HOR b AND c VER a AND FixedDist1(b, d) AND FixedDist2(c, d) AND (b, c) PARA (b, d) AND a VER f AND FixedDist1(a, f) AND FixedDist2(a, e) -> HorLine(a); VerLine(a); RedEllipse(a, f, e); DrawDot(b); DrawDot(c); DrawDot(d); PS.MoveTo(b); PS.LineTo(d); PS.Stroke(); EllipseDist(a, f, e, d) END FI END;