<> <> <> <> <> DIRECTORY ImagerBasic USING [Context, Vec, IntVec, TransformRecord, Transformation, TransformRep, ImagingSpace, TransformType], Imager, ImagerTransform, Real USING [Fix, Float], RealFns USING [SinDeg, CosDeg]; ImagerTransformImpl: CEDAR PROGRAM IMPORTS Real, RealFns EXPORTS Imager, ImagerTransform = BEGIN OPEN ImagerBasic; epsilonHardness: REAL _ .0001; -- How far from non-hard you can get and still be easy TransformTypeNone: PUBLIC SIGNAL = CODE; <> Translate: PUBLIC PROC [context: Context, dx, dy: REAL] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 0., 1., 0.]]; transform.c _ dx; transform.f _ dy; ConcatToContext[context, client, transform]; }; Rotate: PUBLIC PROC [context: Context, degrees: REAL] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 0., 1., 0.]]; transform.a _ transform.e _ RealFns.CosDeg[degrees]; transform.d _ RealFns.SinDeg[degrees]; transform.b _ -transform.d; ConcatToContext[context, client, transform]; }; Scale: PUBLIC PROC [context: Context, sx, sy: REAL] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 0., 1., 0.]]; transform.a _ sx; transform.e _ sy; ConcatToContext[context, client, transform]; }; IntTranslate: PUBLIC PROC [context: Context, dx, dy: INTEGER] = { OPEN context.clientTransform; IF type = hard THEN { transformation.c _ transformation.c + dx; transformation.f _ transformation.f + dy; } ELSE { x _ x + dx; y _ y + dy; }; ValidateCompositeTransform[context]; -- update composite transform }; IntRotate: PUBLIC PROC [context: Context, degrees: INTEGER] = { transform: TransformRecord; WHILE degrees >= 360 DO degrees _ degrees - 360; ENDLOOP; WHILE degrees < 0 DO degrees _ degrees + 360; ENDLOOP; SELECT degrees FROM 0 => { transform _ [0, 0, identity, NIL]; context.clientTransform _ EasyConcat[context.clientTransform, transform]; }; 90 => { transform _ [0, 0, rot90 , NIL]; context.clientTransform _ EasyConcat[context.clientTransform, transform]; }; 180 => { transform _ [0, 0, rot180 , NIL]; context.clientTransform _ EasyConcat[context.clientTransform, transform]; }; 270 => { transform _ [0, 0, rot270 , NIL]; context.clientTransform _ EasyConcat[context.clientTransform, transform]; }; ENDCASE => Rotate[context, Real.Float[degrees]]; ValidateCompositeTransform[context]; -- update composite transform }; IntScale: PUBLIC PROC [context: Context, sx, sy: INTEGER] = { transform: TransformRecord; IF (sx = 1) AND (sy = 1) THEN { transform _ [0, 0, identity, NIL]; context.clientTransform _ EasyConcat[context.clientTransform, transform]; } ELSE IF (sx =-1) AND (sy = 1) THEN { transform _ [0, 0, mirrorX, NIL]; context.clientTransform _ EasyConcat[context.clientTransform, transform]; } ELSE IF (sx = 1) AND (sy =-1) THEN { transform _ [0, 0, mirrorY, NIL]; context.clientTransform _ EasyConcat[context.clientTransform, transform]; } ELSE IF (sx =-1) AND (sy =-1) THEN { transform _ [0, 0, rot180, NIL]; context.clientTransform _ EasyConcat[context.clientTransform, transform]; } ELSE Scale[context, Real.Float[sx], Real.Float[sy]]; ValidateCompositeTransform[context]; -- update composite transform }; ResetTransform: PUBLIC PROC [context: Context] = { transform: Transformation _ NEW[TransformRep _ [1., 0., 0., 0., 1., 0.]]; context.clientTransform.transformation _ transform; context.clientTransform.type _ identity; context.clientTransform.x _ context.clientTransform.y _ 0; ValidateCompositeTransform[context]; -- update composite transform }; <> SetTransform: PUBLIC PROC [ context: Context, transformSpace: ImagingSpace, transform: TransformRecord] = { SELECT transformSpace FROM client => context.clientTransform _ transform; viewer => context.viewerTransform _ transform; device => context.deviceTransform _ transform; ENDCASE => ERROR; ValidateCompositeTransform[context]; -- update composite transform }; GetTransform: PUBLIC PROC [ context: Context, transformSpace: ImagingSpace] RETURNS [TransformRecord] = { SELECT transformSpace FROM client => RETURN[context.clientTransform]; viewer => RETURN[context.viewerTransform]; device => RETURN[context.deviceTransform]; ENDCASE => ERROR; }; ConcatToContext: PUBLIC PROC [context: Context, transformSpace: ImagingSpace, transform: Transformation] = { <> SELECT transformSpace FROM client => { OPEN context.clientTransform; IF type # hard THEN transformation _ LoadTransform[type, x, y]; transformation _ Concat[transformation, transform]; type _ hard; }; viewer => { OPEN context.viewerTransform; IF type # hard THEN transformation _ LoadTransform[type, x, y]; transformation _ Concat[transformation, transform]; type _ hard; }; device => { OPEN context.deviceTransform; IF type # hard THEN transformation _ LoadTransform[type, x, y]; transformation _ Concat[transformation, transform]; type _ hard; }; ENDCASE => ERROR; ValidateCompositeTransform[context]; -- update composite transform }; Transform: PUBLIC PROC [transform: TransformRecord, p: Vec] RETURNS [Vec] = { OPEN transform; SELECT type FROM identity => RETURN[ [ x: p.x + x, y: p.y + y] ]; rot90 => RETURN[ [ x: -p.y + x, y: p.x + y] ]; rot180 => RETURN[ [ x: -p.x + x, y: -p.y + y] ]; rot270 => RETURN[ [ x: p.y + x, y: -p.x + y] ]; mirrorX => RETURN[ [ x: -p.x + x, y: p.y + y] ]; mirrorY => RETURN[ [ x: p.x + x, y: -p.y + y] ]; mirror45Deg => RETURN[ [ x: p.y + x, y: p.x + y] ]; mirror135Deg => RETURN[ [ x: -p.y + x, y: -p.x + y] ]; hard => { OPEN transformation; RETURN[ [ x: p.x * a + p.y * b + c, y: p.x * d + p.y * e + f ] ]; }; ENDCASE => { SIGNAL TransformTypeNone[]; RETURN[ p ]; }; }; InverseTransform: PUBLIC PROC [transform: TransformRecord, p: Vec] RETURNS [Vec] = { OPEN transform; SELECT type FROM identity => RETURN[ [ x: p.x - x, y: p.y - y] ]; rot90 => RETURN[ [ x: p.y - y, y: -p.x + x] ]; rot180 => RETURN[ [ x: -p.x + x, y: -p.y + y] ]; rot270 => RETURN[ [ x: -p.y + y, y: p.x - x] ]; mirrorX => RETURN[ [ x: -p.x + x, y: p.y - y] ]; mirrorY => RETURN[ [ x: p.x - x, y: -p.y + y] ]; mirror45Deg => RETURN[ [ x: p.y - y, y: p.x - x] ]; mirror135Deg => RETURN[ [ x: -p.y + y, y: -p.x + x] ]; hard => { m: Transformation; m _ Invert[transformation]; RETURN[ [ x: p.x * m.a + p.y * m.b + m.c, y: p.x * m.d + p.y * m.e + m.f ] ]; }; ENDCASE => { SIGNAL TransformTypeNone[]; RETURN[ p ]; }; }; TransformVec: PUBLIC PROC [transform: TransformRecord, p: Vec] RETURNS [Vec] = { OPEN transform; SELECT type FROM identity => RETURN[p]; rot90 => RETURN[ [ x: -p.y, y: p.x] ]; rot180 => RETURN[ [ x: -p.x, y: -p.y] ]; rot270 => RETURN[ [ x: p.y, y: -p.x] ]; mirrorX => RETURN[ [ x: -p.x, y: p.y] ]; mirrorY => RETURN[ [ x: p.x, y: -p.y] ]; mirror45Deg => RETURN[ [ x: p.y, y: p.x] ]; mirror135Deg => RETURN[ [ x: -p.y, y: -p.x] ]; hard => { OPEN transformation; RETURN[ [ x: p.x * a + p.y * b, y: p.x * d + p.y * e ] ]; }; ENDCASE => { SIGNAL TransformTypeNone[]; RETURN[ p ]; }; }; InverseTransformVec: PUBLIC PROC [transform: TransformRecord, p: Vec] RETURNS [Vec] = { OPEN transform; SELECT type FROM identity => RETURN[ [ x: p.x, y: p.y] ]; rot90 => RETURN[ [ x: p.y, y: -p.x] ]; rot180 => RETURN[ [ x: -p.x, y: -p.y] ]; rot270 => RETURN[ [ x: -p.y, y: p.x] ]; mirrorX => RETURN[ [ x: -p.x, y: p.y] ]; mirrorY => RETURN[ [ x: p.x, y: -p.y] ]; mirror45Deg => RETURN[ [ x: p.y, y: p.x] ]; mirror135Deg => RETURN[ [ x: -p.y, y: -p.x] ]; hard => { m: Transformation; m _ Invert[transformation]; RETURN[ [ x: p.x * m.a + p.y * m.b, y: p.x * m.d + p.y * m.e ] ]; }; ENDCASE => { SIGNAL TransformTypeNone[]; RETURN[ p ]; }; }; IntTransform: PUBLIC PROC [transform: TransformRecord, p: IntVec] RETURNS [IntVec] = { OPEN transform; SELECT type FROM identity => RETURN[ [ x: p.x + x, y: p.y + y] ]; rot90 => RETURN[ [ x: -p.y + x, y: p.x + y] ]; rot180 => RETURN[ [ x: -p.x + x, y: -p.y + y] ]; rot270 => RETURN[ [ x: p.y + x, y: -p.x + y] ]; mirrorX => RETURN[ [ x: -p.x + x, y: p.y + y] ]; mirrorY => RETURN[ [ x: p.x + x, y: -p.y + y] ]; mirror45Deg => RETURN[ [ x: p.y + x, y: p.x + y] ]; mirror135Deg => RETURN[ [ x: -p.y + x, y: -p.x + y] ]; hard => { OPEN transformation; RETURN[ [ x: Real.Fix[p.x * a + p.y * b + c], y: Real.Fix[p.x * d + p.y * e + f] ] ]; }; ENDCASE => { SIGNAL TransformTypeNone[]; RETURN[ p ]; }; }; InverseIntTransform: PUBLIC PROC [transform: TransformRecord, p: IntVec] RETURNS [IntVec] = { OPEN transform; SELECT type FROM identity => RETURN[ [ x: p.x - x, y: p.y - y] ]; rot90 => RETURN[ [ x: p.y - y, y: -p.x + x] ]; rot180 => RETURN[ [ x: -p.x + x, y: -p.y + y] ]; rot270 => RETURN[ [ x: -p.y + y, y: p.x - x] ]; mirrorX => RETURN[ [ x: -p.x + x, y: p.y - y] ]; mirrorY => RETURN[ [ x: p.x - x, y: -p.y + y] ]; mirror45Deg => RETURN[ [ x: p.y - y, y: p.x - x] ]; mirror135Deg => RETURN[ [ x: -p.y + y, y: -p.x + x] ]; hard => { m: Transformation; m _ Invert[transformation]; RETURN[ [ x: Real.Fix[p.x * m.a + p.y * m.b + m.c], y: Real.Fix[p.x * m.d + p.y * m.e + m.f] ] ]; }; ENDCASE => { SIGNAL TransformTypeNone[]; RETURN[ p ]; }; }; TransformIntVec: PUBLIC PROC [transform: TransformRecord, p: IntVec] RETURNS [IntVec] = { OPEN transform; SELECT type FROM identity => RETURN[p]; rot90 => RETURN[ [ x: -p.y, y: p.x] ]; rot180 => RETURN[ [ x: -p.x, y: -p.y] ]; rot270 => RETURN[ [ x: p.y, y: -p.x] ]; mirrorX => RETURN[ [ x: -p.x, y: p.y] ]; mirrorY => RETURN[ [ x: p.x, y: -p.y] ]; mirror45Deg => RETURN[ [ x: p.y, y: p.x] ]; mirror135Deg => RETURN[ [ x: -p.y, y: -p.x] ]; hard => { OPEN transformation; RETURN[ [ x: Real.Fix[p.x * a + p.y * b], y: Real.Fix[p.x * d + p.y * e] ] ]; }; ENDCASE => { SIGNAL TransformTypeNone[]; RETURN[ p ]; }; }; InverseTransformIntVec: PUBLIC PROC [transform: TransformRecord, p: IntVec] RETURNS [IntVec] = { OPEN transform; SELECT type FROM identity => RETURN[ [ x: p.x, y: p.y] ]; rot90 => RETURN[ [ x: p.y, y: -p.x] ]; rot180 => RETURN[ [ x: -p.x, y: -p.y] ]; rot270 => RETURN[ [ x: -p.y, y: p.x] ]; mirrorX => RETURN[ [ x: -p.x, y: p.y] ]; mirrorY => RETURN[ [ x: p.x, y: -p.y] ]; mirror45Deg => RETURN[ [ x: p.y, y: p.x] ]; mirror135Deg => RETURN[ [ x: -p.y, y: -p.x] ]; hard => { m: Transformation; m _ Invert[transformation]; RETURN[ [ x: Real.Fix[p.x * m.a + p.y * m.b], y: Real.Fix[p.x * m.d + p.y * m.e] ] ]; }; ENDCASE => { SIGNAL TransformTypeNone[]; RETURN[ p ]; }; }; <> LoadTransform: PROC [type: TransformType, x, y: INTEGER] RETURNS [Transformation] = { SELECT type FROM identity => RETURN[ NEW[TransformRep _ [ 1., 0., x, 0., 1., y]] ]; rot90 => RETURN[ NEW[TransformRep _ [ 0., -1., x, 1., 0., y]] ]; rot180 => RETURN[ NEW[TransformRep _ [-1., 0., x, 0., -1., y]] ]; rot270 => RETURN[ NEW[TransformRep _ [ 0., 1., x, -1., 0., y]] ]; mirrorX => RETURN[ NEW[TransformRep _ [-1., 0., x, 0., 1., y]] ]; mirrorY => RETURN[ NEW[TransformRep _ [ 1., 0., x, 0., -1., y]] ]; mirror45Deg => RETURN[ NEW[TransformRep _ [ 0., 1., x, 1., 0., y]] ]; mirror135Deg => RETURN[ NEW[TransformRep _ [ 0., -1., x, -1., 0., y]] ]; ENDCASE => { SIGNAL TransformTypeNone[]; RETURN[ NEW[TransformRep _ [ 1., 0., x, 0., 1., y]] ]; }; }; EasyConcat: PROC [m, n: TransformRecord] RETURNS [TransformRecord] = { t: IntVec; <> IF n.type = identity AND m.type # hard THEN RETURN[ [m.x + n.x, m.y + n.y, m.type, LoadTransform[m.type, m.x + n.x, m.y + n.y]] ] ELSE IF m.type = identity AND n.type # hard THEN { t.x _ m.x; t.y _ m.y; t _ IntTransform[n, t]; RETURN[ [t.x, t.y, n.type, LoadTransform[n.type, t.x, t.y]] ] } ELSE IF n.type = mirrorY AND m.type # hard THEN { t.x _ m.x; t.y _ m.y; t _ IntTransform[n, t]; SELECT m.type FROM rot90 => RETURN[ [t.x, t.y, mirror135Deg, LoadTransform[mirror135Deg, t.x, t.y]] ]; rot180 => RETURN[ [t.x, t.y, mirrorX, LoadTransform[mirrorX, t.x, t.y]] ]; rot270 => RETURN[ [t.x, t.y, mirror45Deg, LoadTransform[mirror45Deg, t.x, t.y]] ]; mirrorX => RETURN[ [t.x, t.y, rot180, LoadTransform[rot180, t.x, t.y]] ]; mirrorY => RETURN[ [t.x, t.y, identity, LoadTransform[identity, t.x, t.y]] ]; mirror45Deg => RETURN[ [t.x, t.y, rot270, LoadTransform[rot270, t.x, t.y]] ]; mirror135Deg => RETURN[ [t.x, t.y, rot90, LoadTransform[rot90, t.x, t.y]] ]; ENDCASE => { SIGNAL TransformTypeNone[]; RETURN[ [t.x, t.y, mirrorY, LoadTransform[mirrorY, t.x, t.y]] ]; } } ELSE { -- not a trivial case, expand and use concat p, q: Transformation; IF m.type # hard THEN p _ LoadTransform[m.type, m.x, m.y] ELSE p _ m.transformation; IF n.type # hard THEN q _ LoadTransform[n.type, n.x, n.y] ELSE q _ n.transformation; RETURN MakeEasy[Concat[p,q], epsilonHardness]; }; }; Concat: PROC [m, n: Transformation] RETURNS [Transformation] = { transform: Transformation _ NEW[TransformRep _ [1., 0., 0., 0., 1., 0.]]; transform.a _ m.a*n.a + m.d*n.b; transform.d _ m.a*n.d + m.d*n.e; transform.b _ m.b*n.a + m.e*n.b; transform.e _ m.b*n.d + m.e*n.e; transform.c _ m.c*n.a + m.f*n.b + n.c; transform.f _ m.c*n.d + m.f*n.e + n.f; RETURN[transform]; }; Invert: PROC [m: Transformation] RETURNS [Transformation] = { transform: Transformation _ NEW[TransformRep _ [1., 0., 0., 1., 0., 0.]]; det: REAL; det _ m.a*m.e - m.d*m.b; -- compute determinant transform.a _ m.e / det; transform.d _ -m.d / det; transform.b _ -m.b / det; transform.e _ m.a / det; transform.c _ (m.b * m.f - m.e * m.c) / det; transform.f _ (m.d * m.c - m.a * m.f) / det; RETURN[transform]; }; MakeEasy: PROC [m: Transformation, epsilon: REAL] RETURNS [TransformRecord] = { <> IF (ABS[m.a] < epsilon -- test for rotation or axis interchange ops AND ABS[m.e] < epsilon AND (ABS[ABS[m.d] - 1.0] < epsilon) AND (ABS[ABS[m.b] - 1.0] < epsilon) ) THEN { x, y: INT; x _ Real.Fix[m.c]; y _ Real.Fix[m.f]; IF m.b > 0 THEN IF m.c > 0 THEN RETURN[ [x, y, mirror45Deg, NEW[TransformRep _ [0., 1., m.c, 1., 0., m.f]] ]] ELSE RETURN[ [x, y, rot90, NEW[TransformRep _ [0., -1., m.c, 1., 0., m.f]] ]] ELSE IF m.c > 0 THEN RETURN[ [x, y, rot270, NEW[TransformRep _ [0., 1., m.c, -1., 0., m.f]] ]] ELSE RETURN[ [x, y, mirror135Deg, NEW[TransformRep _ [0., -1., m.c, -1., 0., m.f]] ]] } ELSE IF (ABS[m.d] < epsilon -- test for null or mirror ops AND ABS[m.b] < epsilon AND (ABS[ABS[m.a] - 1.0] < epsilon) AND (ABS[ABS[m.e] - 1.0] < epsilon) ) THEN { x, y: INT; x _ Real.Fix[m.c]; y _ Real.Fix[m.f]; IF m.a > 0 THEN IF m.e > 0 THEN RETURN[ [x, y, identity, NEW[TransformRep _ [ 1., 0., m.e, 0., 1., m.f]]]] ELSE RETURN[ [x, y, mirrorY, NEW[TransformRep _ [ 1., 0., m.e, 0., -1., m.f]]]] ELSE IF m.e > 0 THEN RETURN[ [x, y, mirrorX, NEW[TransformRep _ [-1., 0., m.e, 0., 1., m.f]]]] ELSE RETURN[ [x, y, rot180, NEW[TransformRep _ [-1., 0., m.e, 0., -1., m.f]]]] } ELSE RETURN[ [0, 0, hard, m] ]; -- can't make it non-hard }; ValidateCompositeTransform: PROC [context: Context] = { context.transform _ EasyConcat[ EasyConcat[context.clientTransform,context.viewerTransform],context.deviceTransform]; }; END.