<> <> <> <> DIRECTORY ImagerTransform USING [IntRectangle, Rectangle, Ref, Rep], Real USING [FScale, RoundLI, SqRt], RealFns USING [CosDeg, SinDeg], Vector2 USING [InlineAdd, VEC]; ImagerTransformImpl: CEDAR PROGRAM IMPORTS Real, RealFns, Vector2 EXPORTS ImagerTransform ~ BEGIN OPEN ImagerTransform; Ref: TYPE ~ ImagerTransform.Ref; Rep: TYPE ~ ImagerTransform.Rep; VEC: TYPE ~ Vector2.VEC; identity: Ref ~ Create[a: 1, b: 0, c: 0, d: 0, e: 1, f: 0]; rot90: Ref ~ Create[a: 0.0, b: -1.0, c: 0.0, d: 1.0, e: 0.0, f: 0.0]; rot180: Ref ~ Concat[rot90, rot90]; rot270: Ref ~ Concat[rot90, rot180]; FromRec: PUBLIC PROC[r: Rep] RETURNS[Ref] ~ { RETURN[NEW[Rep _ r]]; }; Create: PUBLIC PROC[a, b, c, d, e, f: REAL] RETURNS[Ref] ~ { RETURN[NEW[Rep _ [a, b, c, d, e, f]]]; }; Copy: PUBLIC PROC[m: Ref] RETURNS[Ref] ~ { RETURN[NEW[Rep _ m^]]; }; Scale: PUBLIC PROC[s: REAL] RETURNS[Ref] ~ { IF s=1.0 THEN RETURN[identity] ELSE RETURN[NEW[Rep _ [a: s, b: 0, c: 0, d: 0, e: s, f: 0]]]; }; Scale2: PUBLIC PROC[sx, sy: REAL] RETURNS[Ref] ~ { RETURN[NEW[Rep _ [a: sx, b: 0, c: 0, d: 0, e: sy, f: 0]]]; }; Rotate: PUBLIC PROC[a: REAL] RETURNS[Ref] ~ { SELECT a FROM 0.0 => RETURN[identity]; 90.0 => RETURN[rot90]; 180.0 => RETURN[rot180]; -90.0, 270.0 => RETURN[rot270]; ENDCASE => { cos: REAL ~ RealFns.CosDeg[a]; sin: REAL ~ RealFns.SinDeg[a]; RETURN[NEW[Rep _ [a: cos, b: -sin, c: 0, d: sin, e: cos, f: 0]]]; }; }; Translate: PUBLIC PROC[x, y: REAL] RETURNS[Ref] ~ { RETURN[NEW[Rep _ [a: 1, b: 0, c: x, d: 0, e: 1, f: y]]]; }; Concat: PUBLIC PROC[m, n: Ref] RETURNS[Ref] ~ { a: REAL ~ m.a*n.a + m.d*n.b; d: REAL ~ m.a*n.d + m.d*n.e; b: REAL ~ m.b*n.a + m.e*n.b; e: REAL ~ m.b*n.d + m.e*n.e; c: REAL ~ m.c*n.a + m.f*n.b + n.c; f: REAL ~ m.c*n.d + m.f*n.e + n.f; RETURN[NEW[Rep _ [a, b, c, d, e, f]]]; }; Invert: PUBLIC PROC[m: Ref] RETURNS[Ref] ~ { det: REAL ~ m.a*m.e - m.d*m.b; RETURN[NEW[Rep _ [ a: m.e / det, d: -m.d / det, b: -m.b / det, e: m.a / det, c: (m.b * m.f - m.e * m.c) / det, f: (m.d * m.c - m.a * m.f) / det ]]]; }; PreMultiply: PUBLIC PROC[m, pre: Ref] ~ { rep: Rep _ m^; rep.a _ pre.a*m.a + pre.d*m.b; rep.d _ pre.a*m.d + pre.d*m.e; rep.b _ pre.b*m.a + pre.e*m.b; rep.e _ pre.b*m.d + pre.e*m.e; rep.c _ pre.c*m.a + pre.f*m.b + m.c; rep.f _ pre.c*m.d + pre.f*m.e + m.f; m^ _ rep; }; <<>> PreScale: PUBLIC PROC[m: Ref, s: REAL] ~ { rep: Rep _ m^; rep.a _ s*m.a; rep.d _ s*m.d; rep.b _ s*m.b; rep.e _ s*m.e; m^ _ rep; }; PreScale2: PUBLIC PROC[m: Ref, sx, sy: REAL] ~ { rep: Rep _ m^; rep.a _ sx*m.a; rep.d _ sx*m.d; rep.b _ sy*m.b; rep.e _ sy*m.e; m^ _ rep; }; PreRotate: PUBLIC PROC[m: Ref, a: REAL] ~ { rep: Rep _ m^; SELECT a FROM 0.0 => NULL; 90.0 => { rep.a _ m.b; rep.d _ m.e; rep.b _ -m.a; rep.e _ -m.d; }; 180.0 => { rep.a _ -m.a; rep.d _ -m.d; rep.b _ -m.b; rep.e _ -m.e; }; -90.0, 270.0 => { rep.a _ -m.b; rep.d _ -m.e; rep.b _ m.a; rep.e _ m.d; }; ENDCASE => { cos: REAL ~ RealFns.CosDeg[a]; sin: REAL ~ RealFns.SinDeg[a]; rep.a _ cos*m.a + sin*m.b; rep.d _ cos*m.d + sin*m.e; rep.b _ cos*m.b - sin*m.a; rep.e _ cos*m.e - sin*m.d; }; m^ _ rep; }; PreTranslate: PUBLIC PROC[m: Ref, x, y: REAL] ~ { rep: Rep _ m^; rep.c _ x*m.a + y*m.b + m.c; rep.f _ x*m.d + y*m.e + m.f; m^ _ rep; }; PostMultiply: PUBLIC PROC[m, post: Ref] ~ { rep: Rep _ m^; rep.a _ m.a*post.a+m.d*post.b; rep.b _ m.b*post.a+m.e*post.b; rep.c _ m.c*post.a+m.f*post.b+post.c; rep.d _ m.a*post.d+m.d*post.e; rep.e _ m.b*post.d+m.e*post.e; rep.f _ m.c*post.d+m.f*post.e+post.f; m^ _ rep; }; <<>> PostScale: PUBLIC PROC[m: Ref, s: REAL] ~ { rep: Rep _ m^; rep.a _ m.a*s; rep.b _ m.b*s; rep.c _ m.c*s; rep.d _ m.d*s; rep.e _ m.e*s; rep.f _ m.f*s; m^ _ rep; }; PostScale2: PUBLIC PROC[m: Ref, sx, sy: REAL] ~ { rep: Rep _ m^; rep.a _ m.a*sx; rep.b _ m.b*sx; rep.c _ m.c*sx; rep.d _ m.d*sy; rep.e _ m.e*sy; rep.f _ m.f*sy; m^ _ rep; }; PostRotate: PUBLIC PROC[m: Ref, a: REAL] ~ { rep: Rep _ m^; SELECT a FROM 0.0 => NULL; 90.0 => { rep.a _ m.b; rep.b _ -m.a; rep.d _ m.e; rep.e _ -m.d; }; 180.0 => { rep.a _ -m.a; rep.b _ -m.b; rep.d _ -m.d; rep.e _ -m.e; }; -90.0, 270.0 => { rep.a _ -m.b; rep.b _ m.a; rep.d _ -m.e; rep.e _ m.d; }; ENDCASE => { cos: REAL ~ RealFns.CosDeg[a]; sin: REAL ~ RealFns.SinDeg[a]; rep.a _ m.a*cos + m.b*sin; rep.b _ m.b*cos - m.a*sin; rep.d _ m.d*cos + m.e*sin; rep.e _ m.e*cos - m.d*sin; }; m^ _ rep; }; PostTranslate: PUBLIC PROC[m: Ref, x, y: REAL] ~ { rep: Rep _ m^; rep.c _ m.c+x; rep.f _ m.f+y; m^ _ rep; }; Transform: PUBLIC PROC[m: Ref, v: VEC] RETURNS[VEC] ~ { RETURN[[v.x*m.a + v.y*m.b + m.c, v.x*m.d + v.y*m.e + m.f]]; }; TransformVec: PUBLIC PROC[m: Ref, v: VEC] RETURNS[VEC] ~ { RETURN[[v.x*m.a + v.y*m.b, v.x*m.d + v.y*m.e]]; }; InverseTransform: PUBLIC PROC[m: Ref, v: VEC] RETURNS[VEC] ~ { RETURN[InverseTransformVec[m, [v.x-m.c, v.y-m.f]]]; }; InverseTransformVec: PUBLIC PROC[m: Ref, v: VEC] RETURNS[VEC] ~ { det: REAL ~ m.a*m.e - m.b*m.d; RETURN[[x: (v.x*m.e - v.y*m.b)/det, y: (v.y*m.a - v.x*m.d)/det]]; }; Rectangle: TYPE ~ ImagerTransform.Rectangle; IntRectangle: TYPE ~ ImagerTransform.IntRectangle; TransformRectangle: PUBLIC PROC[m: Ref, rect: Rectangle] RETURNS[Rectangle] ~ { w: VEC _ [rect.w*m.a, rect.w*m.d]; h: VEC _ [rect.h*m.b, rect.h*m.e]; p0: VEC _ Transform[m, [rect.x, rect.y]]; p1: VEC _ p0.InlineAdd[w]; p2: VEC _ p1.InlineAdd[h]; p3: VEC _ p0.InlineAdd[h]; rect.x _ MIN[p0.x, p1.x, p2.x, p3.x]; rect.y _ MIN[p0.y, p1.y, p2.y, p3.y]; rect.w _ MAX[p0.x, p1.x, p2.x, p3.x] - rect.x; rect.h _ MAX[p0.y, p1.y, p2.y, p3.y] - rect.y; RETURN[rect]; }; TransformIntRectangle: PUBLIC PROC[m: Ref, rect: Rectangle] RETURNS[IntRectangle] ~ { new: Rectangle _ TransformRectangle[m, rect]; xMax: REAL _ new.x+new.w; yMax: REAL _ new.y+new.h; x0: INT _ Real.RoundLI[new.x]; y0: INT _ Real.RoundLI[new.y]; x1: INT _ Real.RoundLI[xMax]; y1: INT _ Real.RoundLI[yMax]; WHILE x0>new.x DO x0 _ x0-1 ENDLOOP; WHILE y0>new.y DO y0 _ y0-1 ENDLOOP; WHILE x1 fuzz]; }; ShouldBeSameT: PROC [s, t: Ref] ~ { IF Different[s.a, t.a] THEN ERROR; IF Different[s.b, t.b] THEN ERROR; IF Different[s.c, t.c] THEN ERROR; IF Different[s.d, t.d] THEN ERROR; IF Different[s.e, t.e] THEN ERROR; IF Different[s.f, t.f] THEN ERROR; }; ShouldBeSamePt: PROC [p, q: VEC] ~ { IF Different[p.x, q.x] THEN ERROR; IF Different[p.y, q.y] THEN ERROR; }; PreTrans: PROC[x, y: REAL, r: Ref] RETURNS[Ref] ~ { m: Ref ~ NEW[Rep _ r^]; PreTranslate[m, x, y]; RETURN[m]; }; PreRot: PROC[a: REAL, r: Ref] RETURNS[Ref] ~ { m: Ref ~ NEW[Rep _ r^]; PreRotate[m, a]; RETURN[m]; }; PreScl: PROC[sx, sy: REAL, r: Ref] RETURNS[Ref] ~ { m: Ref ~ NEW[Rep _ r^]; PreScale2[m, sx, sy]; RETURN[m]; }; SelfTest: PROC[r: Ref] ~ { p: VEC _ [3.14159, -265.35]; ShouldBeSameT[PreTrans[p.x, p.y, r], Concat[Translate[p.x, p.y], r]]; ShouldBeSameT[Rotate[90], Concat[Rotate[45], Rotate[45]]]; ShouldBeSameT[Rotate[0], Concat[r, Invert[r]]]; ShouldBeSamePt[InverseTransform[r, p], Transform[Invert[r], p]]; ShouldBeSamePt[InverseTransformVec[r, p], TransformVec[Invert[r], p]]; ShouldBeSamePt[TransformVec[r, TransformVec[r, p]], TransformVec[Concat[r, r], p]]; ShouldBeSamePt[SingularValues[r], SingularValues[PreRot[33.5, r]]]; }; SelfTest[PreTrans[12, 6, PreScl[1, 5, Rotate[61]]]]; SelfTest[Create[1, 2, 4, 9, 3, 1]]; SelfTest[Create[3, 1, 4, 1, 5, 9]]; END.