Last modified on Tue May 11 17:18:19 PDT 1993 by swart modified on Mon May 10 09:31:20 PDT 1993 by muller modified on Mon Aug 26 22:53:51 1991 by kalsow modified on Fri Jul 22 18:59:24 PDT 1988 by stewart modified on Fri Jul 22 13:44:56 PDT 1988 by luca
UNSAFE MODULE; IMPORT Point, Math, Word; PROCEDURE Transform Apply (tr: T; p: Point.T): Point.T = VAR xp: Point.T; temp: REAL; BEGIN WITH z = tr DO temp := 5.5000001e-01 + FLOAT (p.h) * z.a11 + FLOAT (p.v) * z.a21 + z.a31; IF temp >= 0.0000000e+00 THEN xp.h := TRUNC (temp); ELSE xp.h := TRUNC (temp - 1.0000000e+00); END; temp := 5.5000001e-01 + FLOAT (p.h) * z.a12 + FLOAT (p.v) * z.a22 + z.a32; IF temp >= 0.0000000e+00 THEN xp.v := TRUNC (temp); ELSE xp.v := TRUNC (temp - 1.0000000e+00); END; END; RETURN xp END Apply; PROCEDUREIdentity (): T = VAR tr: T; BEGIN WITH z = tr DO z.a11 := 1.0000000e+00; z.a12 := 0.0000000e+00; z.a21 := 0.0000000e+00; z.a22 := 1.0000000e+00; z.a31 := 0.0000000e+00; z.a32 := 0.0000000e+00 END; RETURN tr END Identity;
 translate is equivalent to the following composition:
      
         [a b 1][ a11 a12 0 ][ 1 0 0 ]
                [ a21 a22 0 ][ 0 1 0 ]
                [ a31 a32 1 ][ h v 1 ]
      
        =[a b 1][  a11   a12  0 ]
                [  a21   a22  0 ]
                [ a31+h a32+v 1 ]
PROCEDURETranslate (h, v: REAL; READONLY tr: T): T = VAR xtr: T; BEGIN xtr := tr; xtr.a31 := xtr.a31 + h; xtr.a32 := xtr.a32 + v; RETURN xtr END Translate;
 rotate is equivalent to the following composition:
      
         [a b 1][    a11        a12     0 ][  c  s  0 ]
                [    a21        a22     0 ][ -s  c  0 ]
                [    a31        a32     1 ][  0  0  1 ]
        =[a b 1][ a11c-a12s  a11s+a12c  0]
                [ a21c-a22s  a21s-a22c  0]
                [ a31c-a32s  a31s+a32c  1]
PROCEDURERotate (theta: REAL; READONLY tr: T): T = VAR xtr: T; c, s: REAL; BEGIN c := FLOAT (Math.cos (FLOAT (theta, LONGREAL))); s := FLOAT (Math.sin (FLOAT (theta, LONGREAL))); xtr.a11 := tr.a11 * c - tr.a12 * s; xtr.a12 := tr.a11 * s + tr.a12 * c; xtr.a21 := tr.a21 * c - tr.a22 * s; xtr.a22 := tr.a21 * s + tr.a22 * c; xtr.a31 := tr.a31 * c - tr.a32 * s; xtr.a32 := tr.a31 * s + tr.a32 * c; RETURN xtr END Rotate;
 Scale is equivalent to the following composition:
      
         [a b 1][ a11 a12 0 ][ fh  0 0 ]
                [ a21 a22 0 ][  0 fv 0 ]
                [ a31 a32 1 ][  0  0 1 ]
      
        =[a b 1][ a11*fh a12*fv 0 ]
                [ a21*fh a22*fv 0 ]
                [ a31*fh a32*fv 1 ]
PROCEDUREScale (fh, fv: REAL; READONLY tr: T): T = VAR xtr: T; BEGIN xtr.a11 := tr.a11 * fh; xtr.a21 := tr.a21 * fh; xtr.a31 := tr.a31 * fh; xtr.a12 := tr.a12 * fv; xtr.a22 := tr.a22 * fv; xtr.a32 := tr.a32 * fv; RETURN xtr END Scale; PROCEDUREFromPoint (READONLY p: Point.T): T = VAR tr: T; BEGIN WITH z = tr DO z.a11 := 1.0000000e+00; z.a12 := 0.0000000e+00; z.a21 := 0.0000000e+00; z.a22 := 1.0000000e+00; z.a31 := FLOAT (p.h); z.a32 := FLOAT (p.v) END; RETURN tr END FromPoint; PROCEDURECompose (READONLY t1, t2: T): T = VAR tr: T; BEGIN WITH z = tr DO z.a11 := t1.a11 * t2.a11 + t1.a12 * t2.a21; z.a12 := t1.a11 * t2.a12 + t1.a12 * t2.a22; z.a21 := t1.a21 * t2.a11 + t1.a22 * t2.a21; z.a22 := t1.a21 * t2.a12 + t1.a22 * t2.a22; z.a31 := t1.a31 * t2.a11 + t1.a32 * t2.a21 + t2.a31; z.a32 := t1.a31 * t2.a12 + t1.a32 * t2.a22 + t2.a32 END; RETURN tr END Compose;
 rotate about is equivalent to the composition of three transforms:
   translation to the origin, rotation, and translation back to the point:
      
        [a b 1][  1  0  0 ][  c s 0 ][ 1 0 0 ]
               [  0  1  0 ][ -s c 0 ][ 0 1 0 ]
               [ -h -v  1 ][  0 0 1 ][ h v 1 ]
      
       =[a b 1][    c     s    0 ][ 1 0 0 ]
               [   -s     c    0 ][ 0 1 0 ]
               [ -hc+vs -vc-hs 1 ][ h v 1 ]
      
       =[a b 1][    c       s    0 ]
               [   -s       c    0 ]
               [ h-hc+vs v-vc-hs 1 ]
PROCEDURERotateAbout (READONLY p: Point.T; theta: REAL): T = VAR tr: T; c, s: REAL; BEGIN c := FLOAT (Math.cos (FLOAT (theta, LONGREAL))); s := FLOAT (Math.sin (FLOAT (theta, LONGREAL))); WITH z = tr DO z.a11 := c; z.a12 := s; z.a21 := -s; z.a22 := c; z.a31 := FLOAT (p.h) * (1.0000000e+00 - c) + FLOAT (p.v) * s; z.a32 := FLOAT (p.v) * (1.0000000e+00 - c) - FLOAT (p.h) * s; END; RETURN tr END RotateAbout; PROCEDUREIsoScale (f: REAL): T = VAR tr: T; BEGIN tr.a11 := f; tr.a12 := 0.0000000e+00; tr.a21 := 0.0000000e+00; tr.a22 := f; tr.a31 := 0.0000000e+00; tr.a32 := 0.0000000e+00; RETURN tr END IsoScale; PROCEDUREAnIsoScale (fh, fv: REAL): T = VAR tr: T; BEGIN tr.a11 := fh; tr.a12 := 0.0000000e+00; tr.a21 := 0.0000000e+00; tr.a22 := fv; tr.a31 := 0.0000000e+00; tr.a32 := 0.0000000e+00; RETURN tr END AnIsoScale; PROCEDURECompare (READONLY a, b: T): [-1 .. 1] = BEGIN IF (a.a11 < b.a11) THEN RETURN -1 END; IF (a.a11 > b.a11) THEN RETURN +1 END; IF (a.a12 < b.a12) THEN RETURN -1 END; IF (a.a12 > b.a12) THEN RETURN +1 END; IF (a.a21 < b.a21) THEN RETURN -1 END; IF (a.a21 > b.a21) THEN RETURN +1 END; IF (a.a22 < b.a22) THEN RETURN -1 END; IF (a.a22 > b.a22) THEN RETURN +1 END; IF (a.a31 < b.a31) THEN RETURN -1 END; IF (a.a31 > b.a31) THEN RETURN +1 END; IF (a.a32 < b.a32) THEN RETURN -1 END; IF (a.a32 > b.a32) THEN RETURN +1 END; RETURN 0; END Compare; PROCEDUREEqual (READONLY a, b: T): BOOLEAN = BEGIN RETURN (a.a11 = b.a11) AND (a.a12 = b.a12) AND (a.a21 = b.a21) AND (a.a22 = b.a22) AND (a.a31 = b.a31) AND (a.a32 = b.a32); END Equal; PROCEDUREHash (READONLY a: T): INTEGER = TYPE Int = BITS BITSIZE(REAL) FOR [-16_7fffffff-1 .. 16_7fffffff]; BEGIN RETURN Word.Xor ( Word.Xor (LOOPHOLE (a.a11, Int), LOOPHOLE (a.a12, Int)), Word.Xor ( Word.Xor (LOOPHOLE (a.a21, Int), LOOPHOLE (a.a22, Int)), Word.Xor (LOOPHOLE (a.a31, Int), LOOPHOLE (a.a32, Int)))); END Hash; BEGIN END Transform.