<> <> DIRECTORY ImagerTransform, Real, RealFns; ImagerTransformImpl: CEDAR PROGRAM IMPORTS Real, RealFns EXPORTS ImagerTransform ~ BEGIN Pair: TYPE ~ ImagerTransform.Pair; Rectangle: TYPE ~ ImagerTransform.Rectangle; IntRectangle: TYPE ~ ImagerTransform.IntRectangle; Transformation: TYPE ~ ImagerTransform.Transformation; TransformationRep: TYPE ~ ImagerTransform.TransformationRep; identity: Transformation ~ Create[a: 1, b: 0, c: 0, d: 0, e: 1, f: 0]; rot90: Transformation ~ Create[a: 0.0, b: -1.0, c: 0.0, d: 1.0, e: 0.0, f: 0.0]; rot180: Transformation ~ Concat[rot90, rot90]; rot270: Transformation ~ Concat[rot90, rot180]; Translate: PUBLIC PROC [dx, dy: REAL] RETURNS [Transformation] ~ { RETURN [NEW[TransformationRep _ [a: 1, b: 0, c: dx, d: 0, e: 1, f: dy]]] }; Scale: PUBLIC PROC [s: REAL] RETURNS [Transformation] ~ { IF s = 1.0 THEN RETURN [identity] ELSE RETURN [NEW[TransformationRep _ [a: s, b: 0, c: 0, d: 0, e: s, f: 0]]] }; Scale2: PUBLIC PROC [sx, sy: REAL] RETURNS [Transformation] ~ { RETURN [NEW[TransformationRep _ [a: sx, b: 0, c: 0, d: 0, e: sy, f: 0]]] }; Rotate: PUBLIC PROC [degrees: REAL] RETURNS [Transformation] ~ { SELECT degrees FROM 0.0 => RETURN [identity]; 90.0 => RETURN [rot90]; 180.0 => RETURN [rot180]; -90.0, 270.0 => RETURN [rot270]; ENDCASE => { cos: REAL ~ RealFns.CosDeg[degrees]; sin: REAL ~ RealFns.SinDeg[degrees]; RETURN [NEW[TransformationRep _ [a: cos, b: -sin, c: 0, d: sin, e: cos, f: 0]]] } }; Concat: PUBLIC PROC [pre, post: Transformation] RETURNS [Transformation] ~ { a: REAL ~ pre.a*post.a + pre.d*post.b; d: REAL ~ pre.a*post.d + pre.d*post.e; b: REAL ~ pre.b*post.a + pre.e*post.b; e: REAL ~ pre.b*post.d + pre.e*post.e; c: REAL ~ pre.c*post.a + pre.f*post.b + post.c; f: REAL ~ pre.c*post.d + pre.f*post.e + post.f; RETURN [NEW[TransformationRep _ [a, b, c, d, e, f]]] }; Invert: PUBLIC PROC [m: Transformation] RETURNS [Transformation] ~ { det: REAL _ m.a*m.e - m.d*m.b; RETURN [NEW[TransformationRep _ [ 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 ]]]; }; Create: PUBLIC PROC [a, b, c, d, e, f: REAL] RETURNS [Transformation] ~ { RETURN [NEW[TransformationRep _ [a, b, c, d, e, f]]] }; FromRec: PUBLIC PROC [t: ImagerTransform.TransformationRec] RETURNS [Transformation] ~ { RETURN [NEW[TransformationRep _ [t.a, t.b, t.c, t.d, t.e, t.f]]] }; PreTranslate: PUBLIC PROC [dx, dy: REAL, m: Transformation] RETURNS [Transformation] ~ { RETURN [NEW[TransformationRep _ [ m.a, m.b, dx*m.a + dy*m.b + m.c, m.d, m.e, dx*m.d + dy*m.e + m.f ]]]; }; PreScale: PUBLIC PROC [s: REAL, m: Transformation] RETURNS [Transformation] ~ { RETURN [Concat[Scale[s], m]]; }; PreScale2: PUBLIC PROC [sx, sy: REAL, m: Transformation] RETURNS [Transformation] ~ { RETURN [Concat[Scale2[sx, sy], m]]; }; PreRotate: PUBLIC PROC [degrees: REAL, m: Transformation] RETURNS [Transformation] ~ { RETURN [Concat[Rotate[degrees], m]]; }; Transform: PUBLIC PROC [p: Pair, transform: Transformation] RETURNS [Pair] ~ { RETURN [[ x: p.x*transform.a + p.y*transform.b + transform.c, y: p.x*transform.d + p.y*transform.e + transform.f ]]; }; InverseTransform: PUBLIC PROC [p: Pair, transform: Transformation] RETURNS [Pair] ~ { det: REAL ~ transform.a*transform.e - transform.b*transform.d; p.x _ p.x - transform.c; p.y _ p.y - transform.f; RETURN [[ x: (p.x*transform.e - p.y*transform.b)/det, y: (p.y*transform.a - p.x*transform.d)/det ]]; }; TransformVec: PUBLIC PROC [p: Pair, transform: Transformation] RETURNS [Pair] ~ { RETURN [[ x: p.x*transform.a + p.y*transform.b, y: p.x*transform.d + p.y*transform.e ]]; }; InverseTransformVec: PUBLIC PROC [p: Pair, transform: Transformation] RETURNS [Pair] ~ { det: REAL ~ transform.a*transform.e - transform.b*transform.d; RETURN [[ x: (p.x*transform.e - p.y*transform.b)/det, y: (p.y*transform.a - p.x*transform.d)/det ]]; }; TransformRectangle: PUBLIC PROC [rect: Rectangle, transform: Transformation] RETURNS [Rectangle] ~ { Add: PUBLIC PROC [p, q: Pair] RETURNS [Pair] ~ INLINE {RETURN [[p.x+q.x, p.y+q.y]]}; w: Pair _ [rect.w*transform.a, rect.w*transform.d]; h: Pair _ [rect.h*transform.b, rect.h*transform.e]; p0: Pair _ Transform[[rect.x, rect.y], transform]; p1: Pair _ Add[p0, w]; p2: Pair _ Add[p1, h]; p3: Pair _ Add[p0, 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 [rect: Rectangle, transform: Transformation] RETURNS [IntRectangle] ~ { new: Rectangle _ TransformRectangle[rect, transform]; 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: Transformation] ~ { 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: Pair] ~ { IF Different[p.x, q.x] THEN ERROR; IF Different[p.y, q.y] THEN ERROR; }; SelfTest: PROC [r: Transformation] ~ { p: Pair _ [3.14159, -265.35]; ShouldBeSameT[PreTranslate[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[p, r], Transform[p, Invert[r]]]; ShouldBeSamePt[InverseTransformVec[p, r], TransformVec[p, Invert[r]]]; ShouldBeSamePt[TransformVec[TransformVec[p, r], r], TransformVec[p, Concat[r, r]]]; ShouldBeSamePt[SingularValues[r], SingularValues[PreRotate[33.5, r]]]; }; SelfTest[PreTranslate[12, 6, PreScale2[1, 5, Rotate[61]]]]; SelfTest[Create[1, 2, 4, 9, 3, 1]]; SelfTest[Create[3, 1, 4, 1, 5, 9]]; END.