MODULE KeystoneMap; IMPORT R2, Geometry, Shape, Angle; PRIVATE VAR ll0, delta, c1, r1, dr, ll1, angle; PRIVATE PROC q := Map(p) IS VAR d , r , theta , x , y IN d := R2.Minus(p, ll0) ; theta := angle * CAR(d) / CAR(delta) ; r := (r1 + dr * CDR(d) / CDR(delta) ) / r1 ; x := r * COS(theta) ; y := r * SIN(theta) ; q := (x, y) REL (c1, ll1) END END; PRIVATE CONST TwoPi = 2 * 3.141597; PROC Init(a, b, c, d, e) IS SAVE PS IN Shape.Rect(a, b) ; PS.MoveTo(d) ; Shape.Arc(c, e) ; PS.LineTo(e) ; Shape.ArcCC(c, d) ; PS.Close() ; PS.SetWidth(5) ; PS.Stroke() END ; ll0 := a ; delta := R2.Minus(b, a) ; r1 := Geometry.Length((c , d)) ; dr := Geometry.Length((c , e)) - r1 ; c1 := c ; ll1 := d ; angle := Angle.CC(d, c, e) ; IF angle > 0 -> angle := angle - TwoPi | SKIP FI END; PRIVATE CONST Steps = 20; PRIVATE VAR last; PROC MoveTo(a) IS last := a ; PS.MoveTo(Map(a)) END; PROC LineTo(b) IS SAVE PS IN Shape.Line(last, b) ; PS.Stroke() END ; VAR cnt = 0 , p = last , delta IN delta := R2.Times(1 / Steps, R2.Minus(b, last)) ; DO cnt < Steps -> p := R2.Plus(p, delta) ; PS.LineTo(Map(p)) ; cnt := cnt + 1 OD END ; last := b END; (* Draw a segment from the current point to "b" in the rectangular coordinate system, and add the mapping of that segment in the keystone coordinate system to the current path. *) PROC CurveTo(b, c, d) IS SAVE PS IN PS.MoveTo(last) ; PS.CurveTo(b, c, d) ; PS.Stroke() END ; IF VAR ax , ay , bx , by , cx , cy , dx , dy IN last = (ax, ay) AND b = (bx, by) AND c = (cx, cy) AND d = (dx, dy) -> IF VAR cnt = 0 , delta = 1 / Steps , t = 0 , x0 = ax , y0 = ay , x1 = 3 * (bx - ax ) , y1 = 3 * (by - ay ) , x2 = 3 * (ax - (2 * bx ) + cx ) , y2 = 3 * (ay - (2 * by ) + cy ) , x3 = 3 * (bx - cx ) - ax + dx , y3 = 3 * (by - cy ) - ay + dy , x , y , t2 , t3 IN DO cnt < Steps -> t := t + delta ; t2 := t * t ; t3 := t * t2 ; x := x3 * t3 + x2 * t2 + x1 * t + x0 ; y := y3 * t3 + y2 * t2 + y1 * t + y0 ; PS.LineTo(Map((x , y))) ; cnt := cnt + 1 OD END FI END FI ; last := d END; (* Draw a bezier curve from the current point to "d" using control points "b" and "c" in the rectangular coordinate system, and add the mapping of that curve in the keystone coordinate system to the current path. *)