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.