GriffinTransformImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Created by: Maureen Stone September 24, 1980 3:03 PM
Edited by: Maureen Stone, September 19, 1985 12:21:24 pm PDT
Last Edited by: Ken Pier, November 13, 1985 4:53:03 pm PST
DIRECTORY
GriffinPoint USING [ObjPt, ObjPtSequence, X, Y],
GriffinTransform USING [Axis, XFMDescriptor, XFormMatrix],
Real USING [RealException],
RealFns USING [Cos, Sin],
Rope USING [ROPE];
GriffinTransformImpl: CEDAR PROGRAM
IMPORTS Real, RealFns
EXPORTS GriffinTransform = BEGIN
ProblemWithXForms: PUBLIC SIGNAL[string: Rope.ROPE] = CODE;
Transform matrix. 2 by 2 plus translation.
X← matrix[1][X]*X+matrix[2][X]*Y + matrix[3][X]
Y← matrix[1][Y]*X+matrix[2][Y]*Y + matrix[3][Y]
InitXForms: PUBLIC PROC [matrix: GriffinTransform.XFMDescriptor] = {
matrix[1] ← [1, 0];
matrix[2] ← [0, 1];
matrix[3] ← [0, 0];
};
theta in radians
Rotate: PUBLIC PROC [theta: REAL, axis: GriffinTransform.Axis, matrix: GriffinTransform.XFMDescriptor] = {
rot: ARRAY [1..2] OF GriffinPoint.ObjPt ← [[0, 0], [0, 0]];
sin: REAL ← RealFns.Sin[theta];
cos: REAL ← RealFns.Cos[theta];
tmatrix: GriffinTransform.XFormMatrix;
i: INTEGER;
FOR i IN [1..3] DO tmatrix[i] ← matrix[i]; ENDLOOP;
SELECT axis FROM
x =>{
rot[1][GriffinPoint.X] ← 1;
rot[2][GriffinPoint.Y] ← cos;
};
y =>{
rot[1][GriffinPoint.X] ← cos;
rot[2][GriffinPoint.Y] ← 1;
};
z =>{
rot[1][GriffinPoint.X] ← cos;
rot[2][GriffinPoint.Y] ← cos;
rot[1][GriffinPoint.Y] ← sin;
rot[2][GriffinPoint.X] ← -sin;
};
ENDCASE;
FOR i IN [GriffinPoint.X..GriffinPoint.Y] DO
matrix[1][i] ← rot[1][GriffinPoint.X]*tmatrix[1][i]+rot[1][GriffinPoint.Y]*tmatrix[2][i];
matrix[2][i] ← rot[2][GriffinPoint.X]*tmatrix[1][i]+rot[2][GriffinPoint.Y]*tmatrix[2][i];
ENDLOOP;
TestSingular[matrix];
};
Scale: PUBLIC PROC [scale: ARRAY[GriffinPoint.X..GriffinPoint.Y] OF REAL, matrix: GriffinTransform.XFMDescriptor] = {
i: INTEGER;
FOR i IN [GriffinPoint.X..GriffinPoint.Y] DO
matrix[1][i] ← matrix[1][i]*scale[GriffinPoint.X];
matrix[2][i] ← matrix[2][i]*scale[GriffinPoint.Y];
ENDLOOP;
TestSingular[matrix];
};
Translate: PUBLIC PROC [dist: ARRAY[GriffinPoint.X..GriffinPoint.Y] OF REAL, matrix: GriffinTransform.XFMDescriptor] = {
i: INTEGER;
FOR i IN [GriffinPoint.X..GriffinPoint.Y] DO
matrix[3][i] ← matrix[1][i]*dist[GriffinPoint.X]+matrix[2][i]*dist[GriffinPoint.Y]+matrix[3][i];
ENDLOOP;
};
from Draw. To map q0, q1, q2 into p0, p1, p2, solve the equations for a, b, c, d.
xnew ← ax+by+distX
ynew ← cx+dy+distY
a, b, c, d stored in matrix[1][X], matrix[2][X], matrix[1][Y], matrix2[Y] respectively
dist = translation from p0 to q0 is done separately
For 4 points, a=d and b=-c. Work out the algebra and get formulae below.
q0, q1, p0, p1 in pts[0] to pts[3], respectively
x1=qx1-qx0; x2=px1-px0; y similarly
XForm4Pts: PUBLIC PROC [pts: GriffinPoint.ObjPtSequence, matrix: GriffinTransform.XFMDescriptor] = {
tmatrix: GriffinTransform.XFormMatrix;
i: INTEGER;
x1: REAL ← pts[1][GriffinPoint.X]-pts[0][GriffinPoint.X];
x2: REAL ← pts[3][GriffinPoint.X]-pts[2][GriffinPoint.X];
y1: REAL ← pts[1][GriffinPoint.Y]-pts[0][GriffinPoint.Y];
y2: REAL ← pts[3][GriffinPoint.Y]-pts[2][GriffinPoint.Y];
del: REAL ← x1*x1+y1*y1;
tmp: ARRAY [1..3] OF GriffinPoint.ObjPt ← [[0, 0], [0, 0], [0, 0]];
FOR i IN [1..3] DO tmatrix[i] ← matrix[i]; ENDLOOP;
tmp[1][GriffinPoint.X] ← (x1*x2+y1*y2)/del; --a
tmp[2][GriffinPoint.Y] ← tmp[1][GriffinPoint.X]; --d
tmp[1][GriffinPoint.Y] ← (x1*y2-y1*x2)/del; --c
tmp[2][GriffinPoint.X] ← -tmp[1][GriffinPoint.Y] ; --b
tmp[3] ← [pts[2][GriffinPoint.X]-pts[0][GriffinPoint.X], pts[2][GriffinPoint.Y]-pts[0][GriffinPoint.Y]]; --distX and distY
FOR i IN [GriffinPoint.X..GriffinPoint.Y] DO
matrix[1][i] ← tmp[1][GriffinPoint.X]*tmatrix[1][i]+tmp[1][GriffinPoint.Y]*tmatrix[2][i];
matrix[2][i] ← tmp[2][GriffinPoint.X]*tmatrix[1][i]+tmp[2][GriffinPoint.Y]*tmatrix[2][i];
matrix[3][i] ← tmp[3][GriffinPoint.X]*tmatrix[1][i]+tmp[3][GriffinPoint.Y]*tmatrix[2][i] + tmatrix[3][i];
ENDLOOP;
TestSingular[matrix];
};
For 6 points. Work out the algebra and get formulae below.
q0, q1, q2, p0, p1, q3 in pts[0] to pts[5], respectively
XForm6Pts: PUBLIC PROC [pts: GriffinPoint.ObjPtSequence, matrix: GriffinTransform.XFMDescriptor] = {
i: INTEGER;
tmatrix: GriffinTransform.XFormMatrix;
tmp: ARRAY [1..3] OF GriffinPoint.ObjPt ← [[0, 0], [0, 0], [0, 0]];
dq1: GriffinPoint.ObjPt ← [pts[1][GriffinPoint.X]-pts[0][GriffinPoint.X], pts[1][GriffinPoint.Y]-pts[0][GriffinPoint.Y]];
dq2: GriffinPoint.ObjPt ← [pts[2][GriffinPoint.X]-pts[0][GriffinPoint.X], pts[2][GriffinPoint.Y]-pts[0][GriffinPoint.Y]];
dp1: GriffinPoint.ObjPt ← [pts[4][GriffinPoint.X]-pts[3][GriffinPoint.X], pts[4][GriffinPoint.Y]-pts[3][GriffinPoint.Y]];
dp2: GriffinPoint.ObjPt ← [pts[5][GriffinPoint.X]-pts[3][GriffinPoint.X], pts[5][GriffinPoint.Y]-pts[3][GriffinPoint.Y]];
del: REAL ← dq1[GriffinPoint.X]*dq2[GriffinPoint.Y]-dq2[GriffinPoint.X]*dq1[GriffinPoint.Y];
IF del=0 THEN SIGNAL ProblemWithXForms["Invalid Map. Colinear q points"];
FOR i IN [1..3] DO tmatrix[i] ← matrix[i]; ENDLOOP;
tmp[1][GriffinPoint.X] ← (dp1[GriffinPoint.X]*dq2[GriffinPoint.Y]-dp2[GriffinPoint.X]*dq1[GriffinPoint.Y])/del; --a
tmp[2][GriffinPoint.X] ← (dq1[GriffinPoint.X]*dp2[GriffinPoint.X]-dq2[GriffinPoint.X]*dp1[GriffinPoint.X])/del; --b
tmp[1][GriffinPoint.Y] ← (dp1[GriffinPoint.Y]*dq2[GriffinPoint.Y]-dp2[GriffinPoint.Y]*dq1[GriffinPoint.Y])/del; --c
tmp[2][GriffinPoint.Y] ← (dq1[GriffinPoint.X]*dp2[GriffinPoint.Y]-dq2[GriffinPoint.X]*dp1[GriffinPoint.Y])/del; --d
tmp[3] ← [pts[3][GriffinPoint.X]-pts[0][GriffinPoint.X], pts[3][GriffinPoint.Y]-pts[0][GriffinPoint.Y]]; --distX and distY
FOR i IN [GriffinPoint.X..GriffinPoint.Y] DO
matrix[1][i] ← tmp[1][GriffinPoint.X]*tmatrix[1][i]+tmp[1][GriffinPoint.Y]*tmatrix[2][i];
matrix[2][i] ← tmp[2][GriffinPoint.X]*tmatrix[1][i]+tmp[2][GriffinPoint.Y]*tmatrix[2][i];
matrix[3][i] ← tmp[3][GriffinPoint.X]*tmatrix[1][i]+tmp[3][GriffinPoint.Y]*tmatrix[2][i] + tmatrix[3][i];
ENDLOOP;
TestSingular[matrix];
};
XFormPt: PUBLIC PROC [pt: GriffinPoint.ObjPt, matrix: GriffinTransform.XFMDescriptor] RETURNS[GriffinPoint.ObjPt] = {
newPt: GriffinPoint.ObjPt;
i: INTEGER;
FOR i IN [GriffinPoint.X..GriffinPoint.Y] DO
newPt[i] ← matrix[1][i]*pt[GriffinPoint.X]+matrix[2][i]*pt[GriffinPoint.Y]+matrix[3][i];
ENDLOOP;
RETURN[newPt];
};
TestSingular: PROC [matrix: GriffinTransform.XFMDescriptor] = TRUSTED {
ENABLE Real.RealException =>
IF flags[divisionByZero] THEN SIGNAL ProblemWithXForms["Singular transform"]
ELSE SIGNAL ProblemWithXForms["Other problem with transform"];
det: REAL ← matrix[1][GriffinPoint.X]*matrix[2][GriffinPoint.Y]-matrix[2][GriffinPoint.X]*matrix[1][GriffinPoint.Y];
Nest[det]; --well, there's something funny about the signals in the float package
};
Nest: PROC [det: REAL] = {
test: REAL ← 1/det; --all for the SIGNAL if det is 0
};
END.