MODULE Arc; (* Procedures for drawing circular arcs. *) IMPORT Math, PS, Circle, Geometry, Angle; PRIVATE FUNC d = ArcPoint(a, b, c) IS d ~ c AND (a, b) CONG (b, d) AND Geometry.Colinear(b, d, c) END; PRIVATE FUNC e = RightIntersect(a, b, d) IS e ~ (0.5, 0.5) REL (a, d) AND Angle.Right(b, a, e) AND Angle.Right(b, d, e) END; PRIVATE CONST MaxCurveRatio = 0.05; /* If the ratio of the distance between endpoints to the radius of curvature is at most "MaxCurveRatio", then a straight line is drawn instead of a curve. */ PRIVATE PROC SmallArc(b, c) IS VAR a, d IN a := PS.CurrentPoint(); d := ArcPoint(a, b, c); IF Geometry.Dist(a, d) / Geometry.Dist(a, b) < MaxCurveRatio -> PS.LineTo(d) | VAR e = RightIntersect(a, b, d), f ~ Geometry.Mid(a, e), g ~ Geometry.Mid(d, e) IN VAR h ~ Geometry.Mid(a, f), i ~ Geometry.Mid(f, g), j ~ Geometry.Mid(g, d), k ~ Geometry.Mid(h, i), l ~ Geometry.Mid(i, j), m ~ Geometry.Mid(k, l) IN h = Geometry.Mid(a, f) AND i = Geometry.Mid(f, g) AND j = Geometry.Mid(g, d) AND k = Geometry.Mid(h, i) AND l = Geometry.Mid(i, j) AND m = Geometry.Mid(k, l) AND Geometry.Colinear(a, f, e) AND Geometry.Colinear(d, g, e) AND (a, f) CONG (d, g) AND (a, b) CONG (b, m) -> PS.CurveTo(f, g, d) END END FI END END; PRIVATE PROC y := PosAngle(x) IS IF x < 0 -> y := x + 2 * Math.Pi | y := x FI END; PRIVATE CONST HalfPi = Math.Pi / 2, Epsilon = 0.001, HalfPiEps = HalfPi - Epsilon; PROC Draw(a, b) IS VAR c, theta IN c := PS.CurrentPoint(); theta := PosAngle(Angle.CC(b, a, c)); DO theta >= HalfPiEps -> Circle.DrawQuarter(a); theta := theta - HalfPi OD; IF theta > Epsilon -> SmallArc(a, b) | SKIP FI END END; PROC DrawCC(a, b) IS VAR c, theta IN c := PS.CurrentPoint(); theta := PosAngle(Angle.CC(c, a, b)); DO theta >= HalfPiEps -> Circle.DrawQuarterCC(a); theta := theta - HalfPi OD; IF theta > Epsilon -> SmallArc(a, b) | SKIP FI END END; UI PointTool(Draw); UI PointTool(DrawCC); (* Add a clockwise or counter-clockwise circular arc, respectively, to the current path. In each case, the arc starts at the current point, has center "a", and ends at a point along the ray "ab". *)