! Routines for the EDWIN transformation stack.

%external %routine %spec SIGNAL (%integer E, SE, EI)
!%external %long %real %fn %spec SQRT (%long %real X)

%const %integer MAX T STACK = 25

%record %format POINTF (%integer X, Y)
%record %format TRANSF (%real %array A(0:8))
%own %record(TRANSF) %array T STACK (0:MAX T STACK)
%own %real %array %name CUR, OLD
%own %real %array UNITY (0:8) = 1, 0, 0, 0, 1, 0, 0, 0, 1

%own %integer STACK PTR = -1

%external %routine M TRANSLATE (%integer X, Y, %real %array %name T)
   %integer I
   T(I) = UNITY(I) %for I = 0, 1, 8
   T(6) = X
   T(7) = Y
%end

%external %routine MMX (%real %array %name T)
   %integer I
   T(I) = UNITY(I) %for I = 0, 1, 8
   T(0) = -1
%end

%external %routine MMY (%real %array %name T)
   %integer I
   T(I) = UNITY(I) %for I = 0, 1, 8
   T(4) = -1
%end

%external %routine M ROTATE (%integer A, B, %real %array %name T)
   %integer I
   %real SQRT AA BB, DIR AB, DIR BA
   T(I) = UNITY(I) %for I = 0,1,8
   A = 1 %IF A = 0 %AND B = 0
   SQRT AA BB = SQRT (A*A + B*B)
   DIR AB = A/SQRT AA BB;  DIR BA = B/SQRT AA BB
   T(0) = DIR AB
   T(4) = DIR AB
   T(1) = DIR BA
   T(3) = -DIR BA
%end

%external %routine MAT MUL (%real %array %name A, B, C)
   ! Performs the matrix multiplication C = A*B on the arrays in parameters.
   %integer I, J, K
   %real %name R
   %for I = 0,3,6 %cycle
        %for J = 0,1,2 %cycle
             R == C(I+J);   R = 0
             %for K = 0, 1, 2 %cycle
                  R = R + A(I+K) * B(K*3+J)
             %repeat
        %repeat
   %repeat
%end

%external %routine POP TRANS
   signal (14, 9, 0) %if STACK PTR < 0; ! Stack not initialised.
   STACK PTR = STACK PTR - 1
   signal (14, 11, STACK PTR) %if STACK PTR<0
   CUR  == OLD
   OLD == TSTACK(STACK PTR-1)_A %if STACK PTR>0
%end

%external %routine INIT TRANS
   %integer I
   ! Initialise the transformation stack.
   STACK PTR = 0
   CUR == T STACK (0)_A
   CUR(I) = UNITY(I) %for I=0,1,8
%end

%external %routine PUSH TRANS (%real %array %name T)
   INIT TRANS %if STACK PTR < 0
   OLD == CUR
   STACK PTR = STACK PTR + 1
   signal (14, 10, STACK PTR) %if STACK PTR > MAX T STACK
   CUR  == T STACK(STACK PTR)_A
   MAT MUL (T, OLD, CUR); ! CUR = T * OLD  gives new transformation to be done.
%end

%external %routine TRANSFORM POINT {%alias "ED$TP"} ( %c
                                   %record (POINTF) %name P, NP)
   ! Transforms a point P to NP under the current transformation.
   NP_X = INT(P_X*CUR(0) + P_Y*CUR(3) + CUR(6))
   NP_Y = INT(P_X*CUR(1) + P_Y*CUR(4) + CUR(7))
%end

%external %routine TRANSFORM VECTOR {%alias "ED$TV"} (%record (POINTF) %name V, NV)
   ! Transforms a vector V to NV under the current transformation.
   NV_X = INT(V_X*CUR(0) + V_Y*CUR(3))
   NV_Y = INT(V_X*CUR(1) + V_Y*CUR(4))
%end

%external %routine INQUIRE TRANSFORM {%alias "ED$ITX"} (%real %array %name TX)
   %integer I
   TX(I) = CUR(I) %for I=0,1,8
%end

%external %routine PRINT MAT (%real %array %name T)
   ! PRINT MAT is only required if debugging.
   PRINT (T(0),3,1);   PRINT (T(1),3,1);   PRINT (T(2),3,1)
   NEWLINE
   PRINT (T(3),3,1);   PRINT (T(4),3,1);   PRINT (T(5),3,1)
   NEWLINE
   PRINT (T(6),3,1);   PRINT (T(7),3,1);   PRINT (T(8),3,1)
   NEWLINE
%end

%end %of %file
