MODULE SVGMatrix;
IMPORT Math;
CONST
Eps = 1.0E-5;
TYPE
Number*=LONGREAL;
Point*=RECORD
x*, y* : Number;
END;
Matrix*=OBJECT
VAR a*, b*, c*, d*, e*, f*: Number;
PROCEDURE SetIdentity*;
BEGIN
a := 1.0; c := 0.0; e := 0.0;
b := 0.0; d := 1.0; f := 0.0;
END SetIdentity;
PROCEDURE Set*(newa, newb, newc, newd, newe, newf: Number);
BEGIN
a := newa; c := newc; e := newe;
b := newb; d := newd; f := newf;
END Set;
PROCEDURE TransformBy*(othera, otherb, otherc, otherd, othere, otherf: Number):Matrix;
VAR other: Matrix;
BEGIN
NEW(other);
other.Set(othera, otherb, otherc, otherd, othere, otherf);
RETURN Multiply(other)
END TransformBy;
PROCEDURE Translate*(x, y: Number):Matrix;
VAR other: Matrix;
BEGIN
NEW(other);
other.Set(1.0, 0.0, 0.0, 1.0, x, y);
RETURN Multiply(other)
END Translate;
PROCEDURE Scale*(x, y: Number):Matrix;
VAR other: Matrix;
BEGIN
NEW(other);
other.Set(x, 0.0, 0.0, y, 0.0, 0.0);
RETURN Multiply(other)
END Scale;
PROCEDURE Rotate*(angle, x, y: Number):Matrix;
VAR other: Matrix;
s, c: Number;
BEGIN
s := Math.sin(SHORT(angle)/180.0*Math.pi);
c := Math.cos(SHORT(angle)/180.0*Math.pi);
NEW(other);
other.Set(c, s, -s, c, -c*x+s*y+x, -s*x-c*y+y);
RETURN Multiply(other)
END Rotate;
PROCEDURE SkewX*(angle: Number):Matrix;
VAR other: Matrix;
s, c: Number;
BEGIN
s := Math.sin(SHORT(angle)/180.0*Math.pi);
c := Math.cos(SHORT(angle)/180.0*Math.pi);
NEW(other);
other.Set(1.0, 0.0, s / c, 1.0, 0.0, 0.0);
RETURN Multiply(other)
END SkewX;
PROCEDURE SkewY*(angle: Number):Matrix;
VAR other: Matrix;
s, c: Number;
BEGIN
s := Math.sin(SHORT(angle)/180.0*Math.pi);
c := Math.cos(SHORT(angle)/180.0*Math.pi);
NEW(other);
other.Set(1.0, s / c, 0.0, 1.0, 0.0, 0.0);
RETURN Multiply(other)
END SkewY;
PROCEDURE Multiply*(other: Matrix):Matrix;
VAR result: Matrix;
BEGIN
NEW(result);
result.a := a * other.a + c * other.b;
result.b := b * other.a + d * other.b;
result.c := a * other.c + c * other.d;
result.d := b * other.c + d * other.d;
result.e := a * other.e + c * other.f + e;
result.f := b * other.e + d * other.f + f;
RETURN result
END Multiply;
PROCEDURE Invert*():Matrix;
VAR result: Matrix;
det, inv: Number;
BEGIN
NEW(result);
det := a * d - b * c;
IF ABS(det) >= Eps THEN
inv := 1/det;
result.a := +inv * d;
result.b := -inv * b;
result.c := -inv * c;
result.d := +inv * a;
result.e := +inv * (c * f - d * e);
result.f := +inv * (b * e - a * f)
ELSE
result.Set(0, 0, 0, 0, 0, 0)
END;
RETURN result
END Invert;
PROCEDURE Transform*(VAR p: Point):Point;
VAR result: Point;
BEGIN
result.x := p.x * a + p.y * c + e;
result.y := p.x * b + p.y * d + f;
RETURN result
END Transform;
PROCEDURE TransformLength*(VAR p: Number):Number;
VAR x, y: Number;
BEGIN
x := p * a; y := p * b;
RETURN Math.sqrt(SHORT(x * x + y * y))
END TransformLength;
END Matrix;
END SVGMatrix.