ImagerImpl.mesa
Created March 11, 1983
Last Edit By:
Plass, March 14, 1983 2:16 pm
Last Edited by: Crow, March 17, 1983 5:41 pm
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.