IPTransformImpl:
CEDAR
PROGRAM
IMPORTS IPReal, RealFns
EXPORTS IPTransform, IPImagerOps, IPBasic
= BEGIN OPEN IPImagerBasic;
State: TYPE = IPState.State;
StateRep: PUBLIC TYPE = IPState.StateRep; -- export to IPBasic
Imager: TYPE = IPImager.Imager;
Vars: TYPE = IPImager.Vars;
DRound:
PUBLIC
PROC[p: Pair]
RETURNS[Pair] = {
RETURN[[IPReal.Round[p.x], IPReal.Round[p.y]]];
};
A Transformation represents the following matrix:
a d 0
b e 0
c f 1
SetCode:
PROC[m: Transformation] = {
IF m.b=0
AND m.d=0
THEN {
SELECT m.a
FROM
1 =>
SELECT m.e
FROM
1 => m.code ← 0;
-1 => m.code ← 1;
ENDCASE;
-1 =>
SELECT m.e
FROM
1 => m.code ← 2;
-1 => m.code ← 3;
ENDCASE;
ENDCASE;
m.code ← 8;
}
ELSE
IF m.a=0
AND m.e=0
THEN {
SELECT m.b
FROM
1 =>
SELECT m.d
FROM
1 => m.code ← 0;
-1 => m.code ← 1;
ENDCASE;
-1 =>
SELECT m.d
FROM
1 => m.code ← 2;
-1 => m.code ← 3;
ENDCASE;
ENDCASE;
m.code ← 9;
}
ELSE m.code ← 10;
};
NewT:
PROC[rep: TransformationRep]
RETURNS[Transformation] =
INLINE {
m: Transformation = NEW[TransformationRep ← rep];
SetCode[m]; RETURN[m] };
CopyTransformation:
PUBLIC
PROC[m: Transformation]
RETURNS[Transformation] = {
RETURN[NEW[TransformationRep ← m^]] };
MakeT:
PUBLIC
PROC[a, b, c, d, e, f:
REAL]
RETURNS[Transformation] = {
RETURN[NewT[[a: a, b: b, c: c, d: d, e: e, f: f]]];
};
Translate:
PUBLIC
PROC[x, y:
REAL]
RETURNS[Transformation] = {
RETURN[NewT[[a: 1, b: 0, c: x, d: 0, e: 1, f: y]]];
};
Rotate:
PUBLIC
PROC[a:
REAL]
RETURNS[Transformation] = {
cos, sin: REAL;
SELECT a
FROM
90 => { cos ← 0; sin ← 1 };
180 => { cos ← -1; sin ← 0 };
270, -90 => { cos ← 0; sin ← -1 };
ENDCASE => { cos ← RealFns.CosDeg[a]; sin ← RealFns.SinDeg[a] };
RETURN[NewT[[a: cos, b: -sin, c: 0, d: sin, e: cos, f: 0]]];
};
Scale:
PUBLIC
PROC[s:
REAL]
RETURNS[Transformation] = {
RETURN[NewT[[a: s, b: 0, c: 0, d: 0, e: s, f: 0]]];
};
Scale2:
PUBLIC
PROC[sx, sy:
REAL]
RETURNS[Transformation] = {
RETURN[NewT[[a: sx, b: 0, c: 0, d: 0, e: sy, f: 0]]];
};
Concat:
PUBLIC
PROC[m, n: Transformation]
RETURNS[Transformation] = {
RETURN[NewT[[
a: m.a*n.a + m.d*n.b,
b: m.b*n.a + m.e*n.b,
c: m.c*n.a + m.f*n.b + n.c,
d: m.a*n.d + m.d*n.e,
e: m.b*n.d + m.e*n.e,
f: m.c*n.d + m.f*n.e + n.f
]]];
};
Invert:
PUBLIC
PROC[m: Transformation]
RETURNS[Transformation] = {
det: REAL = (m.a*m.e - m.b*m.d); -- determinant
RETURN[NewT[[
a: (m.e)/det,
b: (-m.b)/det,
c: (m.b*m.f-m.c*m.e)/det,
d: (-m.d)/det,
e: (m.a)/det,
f: (m.c*m.d-m.a*m.f)/det
]]];
};
Transform,
Tp:
PUBLIC
PROC[m: Transformation, p: Pair]
RETURNS[Pair] = {
SELECT m.code
FROM
0 => RETURN[[m.c+p.x, m.f+p.y]];
1 => RETURN[[m.c-p.x, m.f+p.y]];
2 => RETURN[[m.c+p.x, m.f-p.y]];
3 => RETURN[[m.c-p.x, m.f-p.y]];
4 => RETURN[[m.c+p.y, m.f+p.x]];
5 => RETURN[[m.c-p.y, m.f+p.x]];
6 => RETURN[[m.c+p.y, m.f-p.x]];
7 => RETURN[[m.c-p.y, m.f-p.x]];
8 => RETURN[[m.c+p.x*m.a, m.f+p.y*m.e]];
9 => RETURN[[m.c+p.y*m.b, m.f+p.x*m.d]];
ENDCASE => RETURN[[m.c+p.x*m.a+p.y*m.b, m.f+p.x*m.d+p.y*m.e]];
};
TransformVec,
Tv:
PUBLIC
PROC[m: Transformation, v: Pair]
RETURNS[Pair] = {
SELECT m.code
FROM
0 => RETURN[[v.x, v.y]];
1 => RETURN[[-v.x, v.y]];
2 => RETURN[[v.x, -v.y]];
3 => RETURN[[-v.x, -v.y]];
4 => RETURN[[v.y, v.x]];
5 => RETURN[[-v.y, v.x]];
6 => RETURN[[v.y, -v.x]];
7 => RETURN[[-v.y, -v.x]];
8 => RETURN[[v.x*m.a, v.y*m.e]];
9 => RETURN[[v.y*m.b, v.x*m.d]];
ENDCASE => RETURN[[v.x*m.a+v.y*m.b, v.x*m.d+v.y*m.e]];
};
InverseTransform,
ITp:
PUBLIC
PROC[m: Transformation, p: Pair]
RETURNS[Pair] = {
SELECT m.code
FROM
0 => RETURN[[p.x-m.c, p.y-m.f]];
1 => RETURN[[m.c-p.x, p.y-m.f]];
2 => RETURN[[p.x-m.c, m.f-p.y]];
3 => RETURN[[m.c-p.x, m.f-p.y]];
4 => RETURN[[p.y-m.c, p.x-m.f]];
5 => RETURN[[m.c-p.y, p.x-m.f]];
6 => RETURN[[p.y-m.c, m.f-p.x]];
7 => RETURN[[m.c-p.y, m.f-p.x]];
8 => RETURN[[(p.x-m.c)/m.a, (p.y-m.f)/m.e]];
9 => RETURN[[(p.y-m.f)/m.b, (p.x-m.c)/m.d]];
ENDCASE => {
x: REAL = p.x-m.c; y: REAL = p.y-m.f;
D: REAL = (m.a*m.e - m.b*m.d);
RETURN[[(x*m.e-y*m.b)/D, (y*m.a-x*m.d)/D]] };
};
InverseTransformVec,
ITv:
PUBLIC
PROC[m: Transformation, v: Pair]
RETURNS[Pair] = {
SELECT m.code
FROM
0 => RETURN[[v.x, v.y]];
1 => RETURN[[-v.x, v.y]];
2 => RETURN[[v.x, -v.y]];
3 => RETURN[[-v.x, -v.y]];
4 => RETURN[[v.y, v.x]];
5 => RETURN[[-v.y, v.x]];
6 => RETURN[[v.y, -v.x]];
7 => RETURN[[-v.y, -v.x]];
8 => RETURN[[v.x/m.a, v.y/m.e]];
9 => RETURN[[v.y/m.b, v.x/m.d]];
ENDCASE => {
D: REAL = (m.a*m.e - m.b*m.d);
RETURN[[(v.x*m.e-v.y*m.b)/D, (v.y*m.a-v.x*m.d)/D]] };
};
RoundXY:
PUBLIC
PROC[m: Transformation, p: Pair]
RETURNS[Pair] = {
q: Pair = Tp[m, p];
r: Pair = DRound[q];
RETURN[ITp[m, r]];
};
RoundXYVec:
PUBLIC
PROC[m: Transformation, v: Pair]
RETURNS[Pair] = {
w: Pair = Tv[m, v];
r: Pair = DRound[w];
RETURN[ITv[m, r]];
};
ConcatT:
PUBLIC
PROC[self: State, m: Transformation] = {
imager: Imager = self.imager;
vars: Vars = imager.vars;
T: Transformation = vars.T;
new: TransformationRep = [
a: m.a*T.a + m.d*T.b,
b: m.b*T.a + m.e*T.b,
c: m.c*T.a + m.f*T.b + T.c,
d: m.a*T.d + m.d*T.e,
e: m.b*T.d + m.e*T.e,
f: m.c*T.d + m.f*T.e + T.f
];
vars.T^ ← new; SetCode[vars.T];
IF m.code#0 THEN { imager.font ← NIL; vars.fontList ← NIL };
};
Move:
PUBLIC
PROC[self: State] = {
imager: Imager = self.imager;
vars: Vars = imager.vars;
T: Transformation = vars.T;
T.c ← vars.p.cpx; T.f ← vars.p.cpy;
};
Trans:
PUBLIC
PROC[self: State] = {
imager: Imager = self.imager;
vars: Vars = imager.vars;
T: Transformation = vars.T;
p: Pair = DRound[[vars.p.cpx, vars.p.cpy]];
T.c ← p.x; T.f ← p.y;
};
END.