<> <> <> <<>> DIRECTORY Real USING [RoundLI], PixelGraphics ; PixelGraphicsImpl: CEDAR PROGRAM IMPORTS Real EXPORTS PixelGraphics = BEGIN OPEN PixelGraphics; FourByFour: TYPE ~ RECORD [ a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4: REAL ]; Line: PUBLIC PROC [p0, p1: Point] RETURNS [p: LIST OF Point] ~ { <> <> pTail: LIST OF Point; pTail _ p _ LIST [p0]; [] _ AddPointsForLineToTail[p0, p1, pTail]; }; <<>> Lines: PUBLIC PROC [vertices: LIST OF Point] RETURNS [p: LIST OF Point] ~ { <> <> pTail: LIST OF Point; IF vertices=NIL THEN RETURN [NIL]; pTail _ p _ LIST[vertices.first]; FOR each: LIST OF Point _ vertices, each.rest UNTIL each.rest=NIL DO pTail _ AddPointsForLineToTail[each.first, each.rest.first, pTail]; ENDLOOP; }; <<>> InterpolateLines: PUBLIC PROC [vertices: LIST OF Point, proc: PROC [p: Point]] ~ { IF vertices=NIL THEN RETURN; --Nothing more to do proc[vertices.first]; --Call for the first point FOR each: LIST OF Point _ vertices, each.rest UNTIL each.rest=NIL DO InterpolatePoints[each.first, each.rest.first, proc]; ENDLOOP; }; Spline: PUBLIC PROC [m: Cubic, segments: CARDINAL] RETURNS [p: LIST OF Point] ~ { <> h: REAL _ 1.0/segments; h2: REAL _ h*h; h3: REAL _ h2*h; pTail: LIST OF Point; x, y, dx, dy, d2x, d2y, d3x, d3y: REAL; x _ m.dx; y _ m.dy; dx _ m.ax*h3 + m.bx*h2 + m.cx*h; dy _ m.ay*h3 + m.by*h2 + m.cy*h; d2x _ 6*m.ax*h3 + 2*m.bx*h2; d2y _ 6*m.ay*h3 + 2*m.by*h2; d3x _ 6*m.ax*h3; d3y _ 6*m.ay*h3; pTail _ p _ LIST [[Real.RoundLI[x], Real.RoundLI[y]]]; THROUGH [1 .. segments ] DO x _ x + dx; dx _ dx + d2x; d2x _ d2x + d3x; y _ y + dy; dy _ dy + d2y; d2y _ d2y + d3y; pTail _ pTail.rest _ LIST [[Real.RoundLI[x], Real.RoundLI[y]]]; ENDLOOP; }; <<>> InterpolateSpline: PUBLIC PROC [m: Cubic, segments: CARDINAL, proc: PROC [p: Point]] ~ { InterpolateLines[Spline[m: m, segments: segments], proc]; }; Bezier: PUBLIC PROC [p1, p2, p3, p4: Point] RETURNS [m: Cubic] ~ { <> m _ Mul4x4By4x2 [p1, p2, p3, p4, 1, [-1, 3, -3, 1, 3, -6, 3, 0, -3, 3, 0, 0, 1, 0, 0, 0] ]; }; <<>> Simple: PUBLIC PROC [p1, p2, p3, p4: Point] RETURNS [m: Cubic] ~ { <> m _ Mul4x4By4x2 [p1, p2, p3, p4, 2, [-9, 27,-27, 9, 18,-45, 36, -9, -11, 18, -9, 2, 2, 0, 0, 0] ]; }; <<>> BSpline: PUBLIC PROC [p1, p2, p3, p4: Point] RETURNS [m: Cubic] ~ { <> m _ Mul4x4By4x2 [p1, p2, p3, p4, 6, [-1, 3, -3, 1, 3, -6, 3, 0, -3, 0, 3, 0, 1, 4, 1, 0] ]; }; <<>> CatmullRom: PUBLIC PROC [p1, p2, p3, p4: Point] RETURNS [m: Cubic] ~ { <> m _ Mul4x4By4x2 [p1, p2, p3, p4, 2, [-1, 3, -3, 1, 2, -5, 4, -1, -1, 0, 1, 0, 0, 2, 0, 0] ]; }; <<>> Hermite: PUBLIC PROC [p1, q1, p2, q2: Point] RETURNS [m: Cubic] ~ { <> m _ Mul4x4By4x2 [p1, p2, q1, q2, 1, [ 2, -2, 1, 1, -3, 3, -2, -1, 0, 0, 1, 0, 1, 0, 0, 0] ]; }; <<>> AddPointsForLineToTail: PROC [p0, p1: Point, inTail: LIST OF Point] RETURNS [tail: LIST OF Point] ~ INLINE { dx: INT ~ IF p0.x < p1.x THEN 1 ELSE -1; dy: INT ~ IF p0.y < p1.y THEN 1 ELSE -1; x: INT _ p0.x; y: INT _ p0.y; tail _ inTail; IF ABS[p0.x-p1.x] > ABS[p0.y-p1.y] THEN { <> dErrX: INT _ ABS[p1.y-p0.y]; dErrY: INT _ -ABS[p1.x-p0.x]; error: INT _ dErrY/2; THROUGH (0 .. -dErrY] DO x _ x+dx; error _ error + dErrX; IF error > 0 THEN {y _ y+dy; error _ error + dErrY}; tail _ tail.rest _ LIST[[x, y]]; ENDLOOP; } ELSE { <> dErrY: INT _ ABS[p1.x-p0.x]; dErrX: INT _ -ABS[p1.y-p0.y]; error: INT _ dErrX/2; THROUGH (0 .. -dErrX] DO y _ y+dy; error _ error + dErrY; IF error > 0 THEN {x _ x+dx; error _ error + dErrX}; tail _ tail.rest _ LIST[[x, y]]; ENDLOOP; }; }; InterpolatePoints: PUBLIC PROC [p0, p1: Point, proc: PROC [p: Point]] ~ { dx: INT ~ IF p0.x < p1.x THEN 1 ELSE -1; dy: INT ~ IF p0.y < p1.y THEN 1 ELSE -1; x: INT _ p0.x; y: INT _ p0.y; IF ABS[p0.x-p1.x] > ABS[p0.y-p1.y] THEN { <> dErrX: INT _ ABS[p1.y-p0.y]; dErrY: INT _ -ABS[p1.x-p0.x]; error: INT _ dErrY/2; THROUGH (0 .. -dErrY] DO x _ x+dx; error _ error + dErrX; IF error > 0 THEN {y _ y+dy; error _ error + dErrY}; proc[[x,y]]; ENDLOOP; } ELSE { <> dErrY: INT _ ABS[p1.x-p0.x]; dErrX: INT _ -ABS[p1.y-p0.y]; error: INT _ dErrX/2; THROUGH (0 .. -dErrX] DO y _ y+dy; error _ error + dErrY; IF error > 0 THEN {x _ x+dx; error _ error + dErrX}; proc[[x,y]]; ENDLOOP; }; }; Mul4x4By4x2: PROC [p1, p2, p3, p4: Point, divisor: REAL, m: FourByFour] RETURNS [cubic: Cubic] ~ INLINE { OPEN cubic, m; ax _ (a1*p1.x + a2*p2.x + a3*p3.x + a4*p4.x)/divisor; ay _ (a1*p1.y + a2*p2.y + a3*p3.y + a4*p4.y)/divisor; bx _ (b1*p1.x + b2*p2.x + b3*p3.x + b4*p4.x)/divisor; by _ (b1*p1.y + b2*p2.y + b3*p3.y + b4*p4.y)/divisor; cx _ (c1*p1.x + c2*p2.x + c3*p3.x + c4*p4.x)/divisor; cy _ (c1*p1.y + c2*p2.y + c3*p3.y + c4*p4.y)/divisor; dx _ (d1*p1.x + d2*p2.x + d3*p3.x + d4*p4.x)/divisor; dy _ (d1*p1.y + d2*p2.y + d3*p3.y + d4*p4.y)/divisor; }; END.