ImagerTransformImpl.mesa
Created March 11, 1983
Last Edit By:
Plass, March 14, 1983 2:16 pm
Last Edited by: Crow, June 18, 1983 9:25 am
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;
Client Procedures
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
};
Unpublicized Procedures
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] = {
Concatenate a "hard" (floating point) transform to the proper existing transform
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 ]; };
};
Internal Procedures
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;
catch trivial cases
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] = {
Make non-hard if a, b, c, d all within epsilon of values for one of the non-hard cases  
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.