MODULE GfxMatrix;
IMPORT
Streams, Math;
CONST
Eps = 1.0E-5;
TYPE
Matrix* = ARRAY 3, 2 OF REAL;
VAR
Identity*: Matrix;
PROCEDURE Init* (VAR m: Matrix; m00, m01, m10, m11, m20, m21: REAL);
BEGIN
m[0, 0] := m00; m[0, 1] := m01;
m[1, 0] := m10; m[1, 1] := m11;
m[2, 0] := m20; m[2, 1] := m21
END Init;
PROCEDURE Get3PointTransform* (px0, py0, px1, py1, qx0, qy0, qx1, qy1, rx0, ry0, rx1, ry1: REAL; VAR res: Matrix);
VAR m: ARRAY 6, 7 OF REAL; i, j, k: LONGINT; max, t: REAL; v: ARRAY 6 OF REAL;
BEGIN
m[0, 0] := px0; m[0, 1] := py0; m[0, 2] := 1.0; m[0, 3] := 0.0; m[0, 4] := 0.0; m[0, 5] := 0.0; m[0, 6] := px1;
m[1, 0] := qx0; m[1, 1] := qy0; m[1, 2] := 1.0; m[1, 3] := 0.0; m[1, 4] := 0.0; m[1, 5] := 0.0; m[1, 6] := qx1;
m[2, 0] := rx0; m[2, 1] := ry0; m[2, 2] := 1.0; m[2, 3] := 0.0; m[2, 4] := 0.0; m[2, 5] := 0.0; m[2, 6] := rx1;
m[3, 0] := 0.0; m[3, 1] := 0.0; m[3, 2] := 0.0; m[3, 3] := px0; m[3, 4] := py0; m[3, 5] := 1.0; m[3, 6] := py1;
m[4, 0] := 0.0; m[4, 1] := 0.0; m[4, 2] := 0.0; m[4, 3] := qx0; m[4, 4] := qy0; m[4, 5] := 1.0; m[4, 6] := qy1;
m[5, 0] := 0.0; m[5, 1] := 0.0; m[5, 2] := 0.0; m[5, 3] := rx0; m[5, 4] := ry0; m[5, 5] := 1.0; m[5, 6] := ry1;
FOR i := 0 TO 5 DO
k := i; max := ABS(m[i, i]);
FOR j := i+1 TO 5 DO
IF ABS(m[j, i]) > max THEN
k := j; max := ABS(m[j, i])
END
END;
IF max < Eps THEN
Init(res, 0, 0, 0, 0, 0, 0);
RETURN
END;
IF k # i THEN
FOR j := i TO 6 DO
t := m[i, j]; m[i, j] := m[k, j]; m[k, j] := t
END
END;
FOR k := i+1 TO 5 DO
t := m[k, i]/m[i, i];
FOR j := i+1 TO 6 DO
m[k, j] := m[k, j] - t * m[i, j]
END
END
END;
FOR i := 5 TO 0 BY -1 DO
t := m[i, 6];
FOR j := i+1 TO 5 DO
t := t - v[j] * m[i, j]
END;
v[i] := t/m[i, i]
END;
Init(res, v[0], v[3], v[1], v[4], v[2], v[5])
END Get3PointTransform;
PROCEDURE Get2PointTransform* (px0, py0, px1, py1, qx0, qy0, qx1, qy1: REAL; VAR res: Matrix);
VAR rx0, ry0, rx1, ry1: REAL;
BEGIN
rx0 := px0 + py0 - qy0; ry0 := py0 + qx0 - px0;
rx1 := px1 + py1 - qy1; ry1 := py1 + qx1 - px1;
Get3PointTransform(px0, py0, px1, py1, qx0, qy0, qx1, qy1, rx0, ry0, rx1, ry1, res)
END Get2PointTransform;
PROCEDURE Invert* (m: Matrix; VAR res: Matrix);
VAR det, inv: REAL;
BEGIN
det := m[0, 0] * m[1, 1] - m[0, 1] * m[1, 0];
IF ABS(det) >= Eps THEN
inv := 1/det;
res[0, 0] := +inv * m[1, 1];
res[0, 1] := -inv * m[0, 1];
res[1, 0] := -inv * m[1, 0];
res[1, 1] := +inv * m[0, 0];
res[2, 0] := +inv * (m[1, 0] * m[2, 1] - m[1, 1] * m[2, 0]);
res[2, 1] := +inv * (m[0, 1] * m[2, 0] - m[0, 0] * m[2, 1])
ELSE
Init(res, 0, 0, 0, 0, 0, 0)
END
END Invert;
PROCEDURE Det* (VAR m: Matrix): REAL;
BEGIN
RETURN m[0, 0] * m[1, 1] - m[0, 1] * m[1, 0]
END Det;
PROCEDURE Singular* (VAR m: Matrix): BOOLEAN;
BEGIN
RETURN ABS(m[0, 0] * m[1, 1] - m[0, 1] * m[1, 0]) < Eps
END Singular;
PROCEDURE Scaled* (VAR m: Matrix): BOOLEAN;
BEGIN
RETURN ABS(ABS(m[0, 0] * m[1, 1] - m[0, 1] * m[1, 0]) - 1) > Eps
END Scaled;
PROCEDURE Rotated* (VAR m: Matrix): BOOLEAN;
BEGIN
RETURN (m[0, 0] < -Eps) OR (m[1, 1] < -Eps) OR (ABS(m[0, 1]) > Eps) OR (ABS(m[1, 0]) > Eps)
END Rotated;
PROCEDURE Equal* (VAR m, n: Matrix): BOOLEAN;
BEGIN
RETURN
(ABS(m[0, 0] - n[0, 0]) < Eps) & (ABS(m[0, 1] - n[0, 1]) < Eps) &
(ABS(m[1, 0] - n[1, 0]) < Eps) & (ABS(m[1, 1] - n[1, 1]) < Eps) &
(ABS(m[2, 0] - n[2, 0]) < Eps) & (ABS(m[2, 1] - n[2, 1]) < Eps)
END Equal;
PROCEDURE Translate* (m: Matrix; dx, dy: REAL; VAR res: Matrix);
BEGIN
res[0, 0] := m[0, 0]; res[0, 1] := m[0, 1];
res[1, 0] := m[1, 0]; res[1, 1] := m[1, 1];
res[2, 0] := m[2, 0] + dx * m[0, 0] + dy * m[1, 0];
res[2, 1] := m[2, 1] + dx * m[0, 1] + dy * m[1, 1]
END Translate;
PROCEDURE Scale* (m: Matrix; sx, sy: REAL; VAR res: Matrix);
BEGIN
res[0, 0] := sx * m[0, 0]; res[0, 1] := sx * m[0, 1];
res[1, 0] := sy * m[1, 0]; res[1, 1] := sy * m[1, 1];
res[2, 0] := m[2, 0]; res[2, 1] := m[2, 1]
END Scale;
PROCEDURE ScaleAt* (m: Matrix; ox, oy, sx, sy: REAL; VAR res: Matrix);
VAR tx, ty: REAL;
BEGIN
res[0, 0] := sx * m[0, 0]; res[0, 1] := sx * m[0, 1];
res[1, 0] := sy * m[1, 0]; res[1, 1] := sy * m[1, 1];
tx := ox * (1-sx); ty := oy * (1-sy);
res[2, 0] := tx * m[0, 0] + ty * m[1, 0] + m[2, 0];
res[2, 1] := tx * m[0, 1] + ty * m[1, 1] + m[2, 1]
END ScaleAt;
PROCEDURE Rotate* (m: Matrix; sin, cos: REAL; VAR res: Matrix);
BEGIN
res[0, 0] := cos * m[0, 0] + sin * m[1, 0]; res[0, 1] := cos * m[0, 1] + sin * m[1, 1];
res[1, 0] := -sin * m[0, 0] + cos * m[1, 0]; res[1, 1] := -sin * m[0, 1] + cos * m[1, 1];
res[2, 0] := m[2, 0]; res[2, 1] := m[2, 1]
END Rotate;
PROCEDURE RotateAt* (m: Matrix; ox, oy, sin, cos: REAL; VAR res: Matrix);
VAR tx, ty: REAL;
BEGIN
res[0, 0] := cos * m[0, 0] + sin * m[1, 0]; res[0, 1] := cos * m[0, 1] + sin * m[1, 1];
res[1, 0] := -sin * m[0, 0] + cos * m[1, 0]; res[1, 1] := -sin * m[0, 1] + cos * m[1, 1];
tx := ox * (1-cos) + oy * sin; ty := oy * (1-cos) - ox * sin;
res[2, 0] := tx * m[0, 0] + ty * m[1, 0] + m[2, 0];
res[2, 1] := tx * m[0, 1] + ty * m[1, 1] + m[2, 1]
END RotateAt;
PROCEDURE Concat* (m, n: Matrix; VAR res: Matrix);
BEGIN
res[0, 0] := m[0, 0] * n[0, 0] + m[0, 1] * n[1, 0];
res[0, 1] := m[0, 0] * n[0, 1] + m[0, 1] * n[1, 1];
res[1, 0] := m[1, 0] * n[0, 0] + m[1, 1] * n[1, 0];
res[1, 1] := m[1, 0] * n[0, 1] + m[1, 1] * n[1, 1];
res[2, 0] := m[2, 0] * n[0, 0] + m[2, 1] * n[1, 0] + n[2, 0];
res[2, 1] := m[2, 0] * n[0, 1] + m[2, 1] * n[1, 1] + n[2, 1]
END Concat;
PROCEDURE Atan2* (x, y: REAL): REAL;
VAR phi: REAL;
BEGIN
IF (ABS(x) < 1.0) & (ABS(y) >= ABS(x * MAX(REAL))) THEN
IF y >= 0.0 THEN phi := Math.pi/2
ELSE phi := -Math.pi/2
END
ELSIF x > 0.0 THEN
phi := Math.arctan(y/x)
ELSIF x < 0.0 THEN
phi := Math.arctan(y/x) + Math.pi
END;
RETURN phi
END Atan2;
PROCEDURE Apply* (VAR m: Matrix; xin, yin: REAL; VAR xout, yout: REAL);
BEGIN
xout := xin * m[0, 0] + yin * m[1, 0] + m[2, 0];
yout := xin * m[0, 1] + yin * m[1, 1] + m[2, 1]
END Apply;
PROCEDURE ApplyToVector* (VAR m: Matrix; xin, yin: REAL; VAR xout, yout: REAL);
BEGIN
xout := xin * m[0, 0] + yin * m[1, 0];
yout := xin * m[0, 1] + yin * m[1, 1]
END ApplyToVector;
PROCEDURE ApplyToDist* (VAR m: Matrix; din: REAL; VAR dout: REAL);
VAR x, y: REAL;
BEGIN
x := din * m[0, 0]; y := din * m[0, 1];
IF ABS(y) < 1.0E-3 THEN dout := x
ELSE dout := Math.sqrt(x * x + y * y)
END
END ApplyToDist;
PROCEDURE ApplyToRect* (VAR m: Matrix; ilx, ily, irx, iuy: REAL; VAR olx, oly, orx, ouy: REAL);
VAR l, h: REAL;
BEGIN
olx := m[2, 0]; orx := m[2, 0];
l := ilx * m[0, 0]; h := irx * m[0, 0];
IF l <= h THEN olx := olx + l; orx := orx + h ELSE olx := olx + h; orx := orx + l END;
l := ily * m[1, 0]; h := iuy * m[1, 0];
IF l <= h THEN olx := olx + l; orx := orx + h ELSE olx := olx + h; orx := orx + l END;
oly := m[2, 1]; ouy := m[2, 1];
l := ilx * m[0, 1]; h := irx * m[0, 1];
IF l <= h THEN oly := oly + l; ouy := ouy + h ELSE oly := oly + h; ouy := ouy + l END;
l := ily * m[1, 1]; h := iuy * m[1, 1];
IF l <= h THEN oly := oly + l; ouy := ouy + h ELSE oly := oly + h; ouy := ouy + l END
END ApplyToRect;
PROCEDURE Solve* (VAR m: Matrix; u, v: REAL; VAR x, y: REAL);
VAR det: REAL;
BEGIN
det := m[0, 0] * m[1, 1] - m[0, 1] * m[1, 0];
IF ABS(det) >= Eps THEN
u := u - m[2, 0]; v := v - m[2, 1];
x := (m[1, 1] * u - m[1, 0] * v)/det;
y := (m[0, 0] * v - m[0, 1] * u)/det
END
END Solve;
PROCEDURE Write* (VAR w: Streams.Writer; VAR m: Matrix);
VAR i: LONGINT;
BEGIN
FOR i := 0 TO 2 DO
w.RawReal(m[i, 0]); w.RawReal(m[i, 1])
END
END Write;
PROCEDURE Read* (VAR r: Streams.Reader; VAR m: Matrix);
VAR i: LONGINT;
BEGIN
FOR i := 0 TO 2 DO
r.RawReal(m[i, 0]); r.RawReal(m[i, 1])
END
END Read;
BEGIN
Init(Identity, 1, 0, 0, 1, 0, 0)
END GfxMatrix.