<> <> <> <> <> DIRECTORY Imager USING [ImagingDevice, Context, FIXED, Vec, Transformation, TransformRep, TransformSpace], RealFns USING [SinDeg, CosDeg], Scaled USING [Value, PLUS, zero, FromReal, FromInt]; ImagerImpl: CEDAR PROGRAM IMPORTS RealFns, Scaled EXPORTS Imager = BEGIN OPEN Imager; Create: PUBLIC PROC [imagingDevice: ImagingDevice] RETURNS [Context] = { RETURN[NIL]; }; Translate: PUBLIC PROC [context: Context, x, y: REAL] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 1., 0., 0., Scaled.zero, Scaled.zero, identity]]; transform.e _ x; transform.f _ y; transform.tx _ Scaled.FromReal[x]; transform.ty _ Scaled.FromReal[y]; ConcatToContext[context, client, transform]; }; Rotate: PUBLIC PROC [context: Context, degrees: REAL] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 1., 0., 0., Scaled.zero, Scaled.zero, identity]]; WHILE degrees < 0. DO degrees _ degrees + 360.; ENDLOOP; -- Ridiculous numbers cost WHILE degrees > 360 DO degrees _ degrees - 360.; ENDLOOP; SELECT degrees FROM 90. => transform^ _ [0., 1., -1., 0., 0., 0., Scaled.zero, Scaled.zero, rot90]; 270. => transform^ _ [0., -1., 1., 0., 0., 0., Scaled.zero, Scaled.zero, rot270]; 180. => transform^ _ [-1., 0., 0., -1., 0., 0., Scaled.zero, Scaled.zero, rot180]; 0. => transform.type _ identity; ENDCASE => transform.type _ hard; SELECT transform.type FROM hard => { transform.a _ transform.d _ RealFns.CosDeg[degrees]; transform.b _ RealFns.SinDeg[degrees]; transform.c _ -transform.b; ConcatToContext[context, client, transform]; }; identity => NULL; ENDCASE => ConcatToContext[context, client, transform]; }; Scale: PUBLIC PROC [context: Context, s: REAL] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 1., 0., 0., Scaled.zero, Scaled.zero, identity]]; transform.type _ hard; transform.a _ transform.d _ s; ConcatToContext[context, client, transform]; }; Scale2: PUBLIC PROC [context: Context, sx, sy: REAL] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 1., 0., 0., Scaled.zero, Scaled.zero, hard]]; IF sx = -1. -- Catch the Mirror transforms THEN IF sy = 1. THEN transform^ _ [-1., 0., 0., 1., 0., 0., Scaled.zero, Scaled.zero, mirrorX] ELSE IF sy = -1. THEN transform^ _ [-1., 0., 0., -1., 0., 0., Scaled.zero, Scaled.zero, rot180]; IF sx = 1. THEN IF sy = -1. THEN transform^ _ [1., 0., 0., -1., 0., 0., Scaled.zero, Scaled.zero, mirrorY] ELSE IF sy = 1. THEN transform.type _ identity; SELECT transform.type FROM hard => { transform.a _ sx; transform.d _ sy; ConcatToContext[context, client, transform]; }; identity => NULL; ENDCASE => ConcatToContext[context, client, transform]; }; IntTranslate: PUBLIC PROC [context: Context, x, y: INT] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 1., 0., 0., Scaled.zero, Scaled.zero, identity]]; transform.e _ x; transform.f _ y; transform.tx _ Scaled.FromInt[x]; transform.ty _ Scaled.FromInt[y]; ConcatToContext[context, client, transform]; }; ConcatToContext: PUBLIC PROC [context: Context, transformSpace: TransformSpace, transform: Transformation] = { SELECT transformSpace FROM client => context.clientTransform _ Concat[context.clientTransform, transform]; view => context.viewTransform _ Concat[context.viewTransform, transform]; device => context.deviceTransform _ Concat[context.deviceTransform, transform]; ENDCASE => ERROR; context.validCompositeTransform _ FALSE; }; SetTransform: PUBLIC PROC [context: Context, transformSpace: TransformSpace, transform: Transformation] = TRUSTED { context.clientTransform _ transform; context.validCompositeTransform _ FALSE; }; GetTransform: PUBLIC PROC [context: Context, transformSpace: TransformSpace] RETURNS [Transformation] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 1., 0., 0., Scaled.zero, Scaled.zero, identity]]; SELECT transformSpace FROM client => transform _ context.clientTransform; view => transform _ context.viewTransform; device => transform _ context.deviceTransform; ENDCASE => ERROR; RETURN[transform]; }; Concat: PUBLIC PROC [m, n: Transformation] RETURNS [Transformation] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 1., 0., 0., Scaled.zero, Scaled.zero, identity]]; SELECT n.type FROM identity => { transform.e _ m.e + n.e; transform.tx _ Scaled.PLUS[m.tx, n.tx]; transform.f _ m.f + n.f; transform.ty _ Scaled.PLUS[m.tx, n.ty]; }; ENDCASE => { transform.a _ m.a*n.a + m.b*n.c; transform.b _ m.a*n.b + m.b*n.d; transform.c _ m.c*n.a + m.d*n.c; transform.d _ m.c*n.b + m.d*n.d; transform.e _ m.e*n.a + m.f*n.c + n.e; transform.tx _ Scaled.FromReal[transform.e]; transform.f _ m.e*n.b + m.f*n.d + n.f; transform.ty _ Scaled.FromReal[transform.f]; transform.type _ hard; }; RETURN[transform]; }; Invert: PUBLIC PROC [m: Transformation] RETURNS [Transformation] = { transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 1., 0., 0., Scaled.zero, Scaled.zero, identity]]; det: REAL; det _ m.a*m.d - m.b*m.c; -- compute determinant transform.a _ m.d / det; transform.b _ -m.b / det; transform.c _ -m.c / det; transform.d _ m.a / det; transform.e _ (m.c * m.f - m.d * m.e) / det; transform.f _ (m.b * m.e - m.a * m.f) / det; transform.tx _ Scaled.FromReal[transform.e]; transform.ty _ Scaled.FromReal[transform.f]; transform.type _ hard; RETURN[transform]; }; MakeNonHard: PUBLIC PROC [m: Transformation, epsilon: REAL] RETURNS [Transformation] = { -- Make non-hard if a, b, c, d all within epsilon of values for one of the non-hard cases transform: Transformation _ NEW[ TransformRep _ [1., 0., 0., 1., 0., 0., Scaled.zero, Scaled.zero, identity]]; IF (ABS[m.a] < epsilon -- test for rotation or axis interchange ops AND ABS[m.d] < epsilon AND (ABS[ABS[m.b] - 1.0] < epsilon) AND (ABS[ABS[m.c] - 1.0] < epsilon) ) THEN IF m.b > 0 THEN IF m.c > 0 THEN transform^ _ [0., 1., 1., 0., 0., 0., Scaled.zero, Scaled.zero, mirror45Deg] ELSE transform^ _ [0., 1., -1., 0., 0., 0., Scaled.zero, Scaled.zero, rot90] ELSE IF m.c > 0 THEN transform^ _ [0., -1., 1., 0., 0., 0., Scaled.zero, Scaled.zero, rot270] ELSE transform^ _ [0., -1., -1., 0., 0., 0., Scaled.zero, Scaled.zero, mirror135Deg] ELSE IF (ABS[m.b] < epsilon -- test for null or mirror ops AND ABS[m.c] < epsilon AND (ABS[ABS[m.a] - 1.0] < epsilon) AND (ABS[ABS[m.d] - 1.0] < epsilon) ) THEN IF m.a > 0 THEN IF m.d > 0 THEN transform^ _ [1., 0., 0., 1., m.e, m.f, m.tx, m.ty, identity] ELSE transform^ _ [1., 0., 0., -1., m.e, m.f, m.tx, m.ty, mirrorY] ELSE IF m.d > 0 THEN transform^ _ [-1., 0., 0., 1., m.e, m.f, m.tx, m.ty, mirrorX] ELSE transform^ _ [-1., 0., 0., -1., m.e, m.f, m.tx, m.ty, rot180] ELSE transform _ m; -- can't make it non-hard RETURN[transform]; }; ValidateCompositeTransform: PUBLIC PROC [context: Context] = TRUSTED { epsilonHardness: REAL _ .0001; -- How far from non-hard you can get and still be easy context.compositeTransform _ MakeNonHard[Concat[Concat[context.clientTransform, context.viewTransform], context.deviceTransform], epsilonHardness]; context.validCompositeTransform _ TRUE; }; Transform: PUBLIC PROC [m: Transformation, p: Vec] RETURNS [Vec] = { SELECT m.type FROM identity => RETURN[p]; rot90 => RETURN[ [ x: -p.y + m.e, y: p.x + m.f] ]; rot180 => RETURN[ [ x: -p.x + m.e, y: -p.y + m.f] ]; rot270 => RETURN[ [ x: p.y + m.e, y: -p.x + m.f] ]; mirrorX => RETURN[ [ x: -p.x + m.e, y: p.y + m.f] ]; mirrorY => RETURN[ [ x: p.x + m.e, y: -p.y + m.f] ]; mirror45Deg => RETURN[ [ x: p.y + m.e, y: p.x + m.f] ]; mirror135Deg => RETURN[ [ x: -p.y + m.e, y: -p.x + m.f] ]; hard => RETURN[ [ x: p.x * m.a + p.y * m.c + m.e, y: p.x * m.b + p.y * m.d + m.f ] ]; ENDCASE => ERROR; }; InverseTransform: PUBLIC PROC [m: Transformation, p: Vec] RETURNS [Vec] = { SELECT m.type FROM identity => RETURN[p]; rot90 => RETURN[ [ x: p.y - m.f, y: -p.x + m.e] ]; rot180 => RETURN[ [ x: -p.x + m.e, y: -p.y + m.f] ]; rot270 => RETURN[ [ x: -p.y + m.f, y: p.x - m.e] ]; mirrorX => RETURN[ [ x: -p.x + m.e, y: p.y - m.f] ]; mirrorY => RETURN[ [ x: p.x - m.e, y: -p.y + m.f] ]; mirror45Deg => RETURN[ [ x: p.y - m.f, y: p.x - m.e] ]; mirror135Deg => RETURN[ [ x: -p.y + m.f, y: -p.x + m.e] ]; hard => RETURN[ Transform[Invert[m],p] ]; ENDCASE => ERROR; }; TransformVec: PUBLIC PROC [m: Transformation, p: Vec] RETURNS [Vec] = { SELECT m.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 => RETURN[ [ x: p.x * m.a + p.y * m.c, y: p.x * m.b + p.y * m.d ] ]; ENDCASE => ERROR; }; InverseTransformVec: PUBLIC PROC [m: Transformation, p: Vec] RETURNS [Vec] = { SELECT m.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 => RETURN[ TransformVec[Invert[m],p] ]; ENDCASE => ERROR; }; END.