(******************************************************************************
*                                    Ctm3d                                    *
******************************************************************************)
Unit Ctm3d;

(*******************************************************************************
*                          Homogeneous Coordinates                            *
*                          -----------------------                            *
*                                                                             *
*      Homogeneous coordinates allow transformations to be represented by     *
*      matrices. A 3x3 matrix is used for 2D transformations, and a 4x4 matrix*
*      for 3D transformations.                                                *
*                                                                             *
*      THIS MODULE IMPLEMENTS ONLY 3D TRANSFORMATIONS.                        *
*                                                                             *
*      in homogeneous coordination the point P(x,y,z) is represented as       *
*      P(w*x, w*y, w*z, w) for any scale factor w!=0.                         *
*      in this module w == 1.                                                 *
*                                                                             *
* Transformations:                                                            *
*          1. translation                                                     *
*                  [x, y, z] --> [x + Dx, y + Dy, z + Dz]                     *
*                                                                             *
*                              Ú          ¿                                   *
*                              ³1  0  0  0³                                   *
*              T(Dx, Dy, Dz) = ³0  1  0  0³                                   *
*                              ³0  0  1  0³                                   *
*                              ³Dx Dy Dz 1³                                   *
*                              À          Ù                                   *
*          2. scaling                                                         *
*                  [x, y, z] --> [Sx * x, Sy * y, Sz * z]                     *
*                                                                             *
*                          Ú          ¿                                       *
*                          ³Sx 0  0  0³                                       *
*              S(Sx, Sy) = ³0  Sy 0  0³                                       *
*                          ³0  0  Sz 0³                                       *
*                          ³0  0  0  1³                                       *
*                          À          Ù                                       *
*                                                                             *
*          3. rotation                                                        *
*                                                                             *
*              a) Around the Z axis:                                          *
*                                                                             *
*                  [x, y, z] --> [x*cost - t*sint, x*sint + y*cost, z]        *
*                      Ú                  ¿                                   *
*                      ³cost  sint   0   0³                                   *
*              Rz(t) = ³-sint cost   0   0³                                   *
*                      ³0     0      1   0³                                   *
*                      ³0     0      0   1³                                   *
*                      À                  Ù                                   *
*                                                                             *
*              b) Around the X axis:                                          *
*                                                                             *
*                  [x, y, z] --> [x, y*cost - z*sint, y*sint + z*cost]        *
*                      Ú                  ¿                                   *
*                      ³1     0     0    0³                                   *
*              Rx(t) = ³0     cost  sint 0³                                   *
*                      ³0    -sint  cost 0³                                   *
*                      ³0     0     0    1³                                   *
*                      À                  Ù                                   *
*                                                                             *
*              c) Around the Y axis:                                          *
*                                                                             *
*                  [x, y, z] --> [xcost + z*sint, y, z*cost - x*sint]         *
*                      Ú                  ¿                                   *
*                      ³cost  0   -sint  0³                                   *
*              Ry(t) = ³0     1    0     0³                                   *
*                      ³sint  0    cost  0³                                   *
*                      ³0     0    0     1³                                   *
*                      À                  Ù                                   *
*                                                                             *
*   transformation of the vector [x,y,z,1] by transformation matrix T is given *
*   by the formula:                                                           *
*                                         Ú   ¿                               *
*              [x', y', z', 1] = [x,y,z,1]³ T ³                               *
*                                         À   Ù                               *
* Optimizations:                                                              *
*   The most general composition of R, S and T operations will produce a matrix*
*   of the form:                                                              *
*              Ú                       ¿                                      *
*              ³r11    r12     r13    0³                                      *
*              ³r21    r22     r23    0³                                      *
*              ³r31    r32     r33    0³                                      *
*              ³tx     ty      tz     1³                                      *
*              À                       Ù                                      *
*   The task of matrix multiplication can be simplified by                    *
*      x' = x*r11 + y*r21 + z*r31 + tx                                        *
*      y' = x*r12 + y*r22 + z*r32 + ty                                        *
*      z' = x*r13 + y*r23 + z*r33 + tz                                        *
*                                                                             *
*                                                                             *
* See also:                                                                   *
*      "Fundamentals of Interactive Computer Graphics" J.D FOLEY A.VAN DAM    *
*      Adison-Weslely ISBN 0-201-14468-9 pp 245-265                           *
*******************************************************************************)

interface

uses hdr3d;

type
       ctmPtr = ^ctm;
    ctm = object
       r11, r12, r13   : real;
       r21, r22, r23   : real;
       r31, r32, r33   : real;
       tx,  ty,  tz    : real;

       constructor SetUnit;
       constructor Copy(var src : ctm);
       procedure save(var dest : ctm);

       procedure translate(Dx, Dy, Dz : real);

       procedure translateX(dx : real);
       procedure translateY(dy : real);
       procedure translateZ(dz : real);
       {use these routines for single axis translations, they are faster!}

       procedure rotateX(t : real);
       procedure rotateY(t : real);
       procedure rotateZ(t : real);

       procedure scale(Sx, Sy, Sz : real);

       procedure scaleX(sx : real);
       procedure scaleY(sy : real);
       procedure scaleZ(sz : real);
       {use these routines for single axis scaling, they are faster!!!}

       procedure Left_translate(Dx, Dy, Dz : real);

       procedure Left_translateX(dx : real);
       procedure Left_translateY(dy : real);
       procedure Left_translateZ(dz : real);
       {use theseLeft_ routines for single axis translations, they are faster!}

       procedure Left_rotateX(t : real);
       procedure Left_rotateY(t : real);
       procedure Left_rotateZ(t : real);

       procedure Left_scale(Sx, Sy, Sz : real);

       procedure Left_scaleX(sx : real);
       procedure Left_scaleY(sy : real);
       procedure Left_scaleZ(sz : real);
       {use these routines for single axis scaling, they are faster!!!}

       procedure transform(var t: point3d; p : point3d);
       {
         Note that t (target) is var, but p is NOT.
         p cannot be a var parameter, because if the same point is
         transformed, data should be copied for correct results
       }
       procedure inv_transform(var p : point3d);
       { inv_transform changes the input point }

       procedure inverse; { M ^-1 }
       procedure multiply(var c : ctm); {multiply from right self * c}
       procedure Multiply_2(var a, b : ctm);
    end;

implementation

(*---------------------------------------------------------------------------
 * ctm.SetUnit -- set the ctm to the unit matrix.
 *---------------------------------------------------------------------------
 *)
constructor ctm.SetUnit;
begin
    r11 := 1; r12 := 0; r13 := 0;
    r21 := 0; r22 := 1; r23 := 0;
    r31 := 0; r32 := 0; r33 := 1;
    Tx := 0; Ty := 0; Tz := 0;
end;

(*---------------------------------------------------------------------------
 * ctm.Copy  -- Copy another ctm to self.
 *---------------------------------------------------------------------------
 *)
constructor ctm.copy;
begin
    { This copy is done this way instead of
       Self := Src;  becuase TP does not do that as expected. }

    r11 := Src.r11;
    r12 := Src.r12;
    r13 := Src.r13;
    r21 := Src.r21;
    r22 := Src.r22;
    r23 := Src.r23;
    r31 := Src.r31;
    r32 := Src.r32;
    r33 := Src.r33;
    tx := Src.tx;
    ty := Src.ty;
    tz := Src.tz;
end;

(* ctm.save save ctm in a specified variable ctm *)
(*******************************************************************************
*                                  ctm.save                                   *
*******************************************************************************)
procedure ctm.save;
begin
    dest := self;
end;

(*---------------------------------------------------------------------------
 * ctm.translate -- multyply ctm by T(dx,dy,dz). ctm = ctm * T(dx,dy,dz)
 *     Ú                      ¿    Ú             ¿    Ú                   ¿
 *     ³r11    r12     r13    0³    ³1  0   0   0³    ³r11   r12   r31   0³
 *     ³r21    r22     r23    0³ *  ³0  1   0   0³ =  ³r21   r22   r31   0³
 *     ³r31    r32     r33    0³    ³0  0   1   0³    ³r21   r22   r31   0³
 *     ³tx     ty      tz     1³    ³Dx  Dy  Dz  1³    ³tx'   ty'   tz'   1³
 *     À                      Ù    À             Ù    À                   Ù
 *
 *    tx' = tx + Dx
 *    ty' = ty + Dy
 *    tz' = tz + Dz
 *---------------------------------------------------------------------------
 *)
procedure ctm.translate;
begin
    Tx := Tx + Dx;
    Ty := Ty + Dy;
    Tz := Tz + Dz;
end;


(*---------------------------------------------------------------------------
 * ctm.Left_translate  --  multyply ctm by T(dx,dy,dz) on the left.
 *                         ctm = T(dx,dy,dz) * ctm
 *      Ú             ¿ Ú                       ¿     Ú                   ¿
 *      ³1   0   0   0³ ³r11    r12     r13    0³     ³r11   r12   r31   0³
 *      ³0   1   0   0³ ³r21    r22     r23    0³  =  ³r21   r22   r31   0³
 *      ³0   0   1   0³ ³r31    r32     r33    0³     ³r21   r22   r31   0³
 *      ³Dx  Dy  Dz  1³ ³tx     ty      tz     1³     ³tx'   ty'   tz'   1³
 *      À             Ù À                       Ù     À                   Ù
 *
 *    tx' = r11 * Dx + r21 * Dy + r31 * Dz + tx
 *    ty' = r12 * Dx + r22 * Dy + r32 * Dz + ty
 *    tz' = r13 * Dx + r23 * Dy + r33 * Dz + tz
 *---------------------------------------------------------------------------
 *)
procedure ctm.Left_translate;
begin
    Tx := Tx + r11 * Dx + r21 * Dy + r31 * Dz;
    Ty := Ty + r12 * Dx + r22 * Dy + r32 * Dz;
    Tz := Tz + r13 * Dx + r23 * Dy + r33 * Dz;
end;


(*******************************************************************************
*                               ctm.translateX                                *
*******************************************************************************)
procedure ctm.translateX;
begin
       tx := tx+dx;
end;

(*******************************************************************************
*                            ctm.Left_translateX                              *
*******************************************************************************)
procedure ctm.Left_translateX;
begin
    tx := tx + dx * r11;
    ty := ty + dx * r12;
    tz := tz + dx * r13;
end;

(*******************************************************************************
*                               ctm.translateY                                *
*******************************************************************************)
procedure ctm.translateY;
begin
    ty := ty+dy;
end;

(*******************************************************************************
*                            ctm.Left_translateY                              *
*******************************************************************************)
procedure ctm.Left_translateY;
begin
       tx := tx + dy * r21;
       ty := ty + dy * r22;
       tz := tz + dy * r23;
end;


(*******************************************************************************
*                               ctm.translateZ                                *
*******************************************************************************)
procedure ctm.translateZ;
begin
       tz := tz+dz;
end;

(*******************************************************************************
*                            ctm.Left_translateZ                              *
*******************************************************************************)
procedure ctm.Left_translateZ;
begin
       tx := tx + dz * r31;
       ty := ty + dz * r32;
       tz := tz + dz * r33;
end;


{the above 6 procedures are used for single axis translation - # of FP
       operations is 1/3, # of arguments passed is 1/3, try using these
       procedures when possiable to improve animation}

(*---------------------------------------------------------------------------
 * ctm.scale -- multyply ctm by S(sx,sy,sz). ctm = ctm * S(sx,sy,sz)
 *   Ú                   ¿   Ú             ¿   Ú                            ¿
 *   ³r11   r12    r13  0³   ³Sx  0   0   0³   ³Sx*r11   Sy*r12   Sz*r13   0³
 *   ³r21   r22    r23  0³ * ³0   Sy  0   0³ = ³Sx*r21   Sy*r22   Sz*r13   0³
 *   ³r31   r32    r33  0³   ³0   0   Sz  0³   ³Sx*r31   Sy*r32   Sz*r33   0³
 *   ³tx    ty    tz    1³   ³0   0   0   1³   ³Sx*tx    Sy*ty    Sz*tz    1³
 *   À                   Ù   À             Ù   À                            Ù
 *---------------------------------------------------------------------------
 *)
procedure ctm.scale;
begin
    r11 := r11*Sx;     r12 := r12*Sy;      r13 := r13*Sz;
    r21 := r21*Sx;     r22 := r22*Sy;      r23 := r23*Sz;
    r31 := r31*Sx;     r32 := r32*Sy;      r33 := r33*Sz;
    tx :=  tx*Sx;      ty  :=  ty*Sy;      tz  :=  tz*Sz
end;


(*---------------------------------------------------------------------------
 * ctm.Left_scale   -- multyply ctm by S(sx,sy,sz) on the left.
 *                     ctm = S(sx,sy,sz) * ctm
 *   Ú            ¿   Ú                    ¿   Ú                            ¿
 *   ³Sx  0   0   0³   ³r11   r12    r13   0³  ³Sx*r11   Sy*r12   Sz*r13   0³
 *   ³0   Sy  0   0³ * ³r21   r22    r23   0³ = ³Sx*r21   Sy*r22   Sz*r13   0³
 *   ³0   0   Sz  0³   ³r31   r32    r33   0³  ³Sx*r31   Sy*r32   Sz*r33   0³
 *   ³0   0   0   1³   ³tx    ty     tz    1³  ³   tx       ty       tz    1³
 *   À            Ù   À                    Ù   À                            Ù
 *---------------------------------------------------------------------------
 *)
procedure ctm.Left_scale;
begin
    r11 := r11*Sx;     r12 := r12*Sy;      r13 := r13*Sz;
    r21 := r21*Sx;     r22 := r22*Sy;      r23 := r23*Sz;
    r31 := r31*Sx;     r32 := r32*Sy;      r33 := r33*Sz;
end;


(*******************************************************************************
*                                 ctm.scaleZ                                  *
*******************************************************************************)
procedure ctm.scaleZ;
begin
    r13 := r13*Sz;
    r23 := r23*Sz;
    r33 := r33*Sz;
    tz :=  tz*Sz;
end;

(*******************************************************************************
*                              ctm.Left_scaleZ                                *
*******************************************************************************)
procedure ctm.Left_scaleZ;
begin
    r31 := r31*Sz;
    r32 := r32*Sz;
    r33 := r33*Sz;
end;


(*******************************************************************************
*                                 ctm.scaleY                                  *
*******************************************************************************)
procedure ctm.scaleY;
begin
       r12 := r12*Sy;
       r22 := r22*Sy;
       r32 := r32*Sy;
       ty  :=  ty*Sy;
end;

(*******************************************************************************
*                              ctm.Left_scaleY                                *
*******************************************************************************)
procedure ctm.Left_scaleY;
begin
    r21 := r21*Sy;
    r22 := r22*Sy;
    r23 := r23*Sy;
end;

(*******************************************************************************
*                                 ctm.scaleX                                  *
*******************************************************************************)
procedure ctm.scaleX;
begin
    r11 := r11*Sx;
    r21 := r21*Sx;
    r31 := r31*Sx;
    tx :=  tx*Sx;
end;

(*******************************************************************************
*                              ctm.Left_scaleX                                *
*******************************************************************************)
procedure ctm.Left_scaleX;
begin
    r11 := r11*Sx;
    r12 := r12*Sx;
    r13 := r13*Sx;
end;


{the above 6 routines should be used for single axis scale, they are much
       faster then calling the general scale routine (with a factor of
       better then 3), and require less arguments}


(*---------------------------------------------------------------------------
 * ctm.rotateZ -- multyply ctm by Rz(t). ctm = ctm * Rz(t)
 *   Ú                   ¿   Ú                  ¿   Ú                    ¿
 *   ³r11   r12    r13  0³   ³cost  sint   0   0³   ³r11'  r12'   r13   0³
 *   ³r21   r22    r23  0³   ³-sint cost   0   0³   ³r21'  r22'   r23   0³
 *   ³r31   r32    r33  0³ * ³0     0      1   0³ = ³r31'  r32'   r33   0³
 *   ³tx    ty    tz    1³   ³0     0      0   1³   ³tx'   ty'    tz    1³
 *   À                   Ù   À                  Ù   À                    Ù
 *
 *   r11' = r11*cost - r12*sint
 *   r21' = r21*cost - r22*sint
 *   r31' = r31*cost - r32*sint
 *   tx'  = tx *cost - ty *sint
 *   r12' = r11*sint + r12*cost
 *   r22' = r21*sint + r22*cost
 *   r32' = r31*sint + r32*cost
 *   ty'  = tx *sint + ty *cost
 *
 *---------------------------------------------------------------------------
 *)
procedure ctm.rotateZ;
var
    cost, sint : real;
    tmp        : real;
begin
    cost := cos(t / 180.0 * 3.1415926535897932385);
    sint := sin(t / 180.0 * 3.1415926535897932385);

    tmp := r11*cost - r12*sint;
    r12 := r11*sint + r12*cost;
    r11 := tmp;
    tmp := r21*cost - r22*sint;
    r22 := r21*sint + r22*cost;
    r21 := tmp;
    tmp := r31*cost - r32*sint;
    r32 := r31*sint + r32*cost;
    r31 := tmp;
    tmp := tx *cost - ty *sint;
    ty := tx *sint + ty *cost;
    tx := tmp;
end;

(*---------------------------------------------------------------------------
 * ctm.Left_rotateZ  -- multyply ctm by Rz(t) on the left. ctm = Rz(t) * ctm
 *  Ú                 ¿   Ú                    ¿   Ú                    ¿
 *  ³cost  sint   0   0³   ³r11   r12   r13   0³   ³r11'  r12'   r13'  0³
 *  ³-sint cost   0   0³   ³r21   r22   r23   0³   ³r21'  r22'   r23'  0³
 *  ³0    0      1   0³ * ³r31   r32    r33   0³ = ³r31   r32    r33   0³
 *  ³0    0      0   1³   ³tx    ty     tz    1³   ³tx    ty     tz    1³
 *  À                 Ù   À                    Ù   À                    Ù
 *
 *   r11' = r11*cost + r21*sint
 *   r12' = r12*cost + r22*sint
 *   r13' = r13*cost + r23*sint
 *   r21' = r21*cost - r11*sint
 *   r22' = r22*cost - r12*sint
 *   r23' = r23*cost - r13*sint
 *
 *---------------------------------------------------------------------------
 *)
procedure ctm.Left_rotateZ;
var
    cost, sint : real;
    tmp        : real;
begin
     cost := cos(t / 180.0 * 3.1415926535897932385);
     sint := sin(t / 180.0 * 3.1415926535897932385);

    tmp := r11 * cost + r21 * sint;
    r21 := r21 * cost - r11 * sint;
    r11 := tmp;
    tmp := r12 * cost + r22 * sint;
    r22 := r22 * cost - r12 * sint;
    r12 := tmp;
    tmp := r13 * cost + r23 * sint;
    r23 := r23 * cost - r13 * sint;
    r13 := tmp;
end;

(*---------------------------------------------------------------------------
 * ctm.rotateX -- multyply ctm by Rx(t). ctm = ctm * Rx(t)
 *   Ú                   ¿   Ú                  ¿   Ú                    ¿
 *   ³r11   r12    r13  0³   ³1     0     0    0³   ³r11   r12'   r13'  0³
 *   ³r21   r22    r23  0³   ³0     cost  sint 0³   ³r21   r22'   r23'  0³
 *   ³r31   r32    r33  0³ * ³0    -sint  cost 0³ = ³r31   r32'   r33'  0³
 *   ³tx    ty    tz    1³   ³0     0     0    1³   ³tx    ty'    tz'   1³
 *   À                   Ù   À                  Ù   À                    Ù
 *
 *   r12' = r12*cost - r13*sint
 *   r13' = r12*sint + r13*cost
 *   r22' = r22*cost - r23*sint
 *   r23' = r22*sint + r23*cost
 *   ty'  = ty *cost - tz *sint
 *   tz'  = ty *sint + tz *cost
 *---------------------------------------------------------------------------
 *)
procedure ctm.rotateX;
var
    cost, sint : real;
    tmp        : real;
begin
     cost := cos(t / 180.0 * 3.1415926535897932385); {constants are evaluated at compile time}
     sint := sin(t / 180.0 * 3.1415926535897932385);

    tmp := r12*cost - r13*sint;
    r13 := r12*sint + r13*cost;
    r12 := tmp;
    tmp := r22*cost - r23*sint;
    r23 := r22*sint + r23*cost;
    r22 := tmp;
    tmp := r32*cost - r33*sint;
    r33 := r32*sint + r33*cost;
    r32 := tmp;
    tmp := ty *cost - tz *sint;
    tz := ty *sint + tz *cost;
    ty := tmp;
end;


(*---------------------------------------------------------------------------
 * ctm.Left_rotateX  -- multyply ctm by Rx(t) on the left. ctm = Rx(t) * ctm
 *  Ú                 ¿   Ú                    ¿   Ú                    ¿
 *  ³1    0     0    0³   ³r11   r12    r13   0³   ³r11   r12    r13   0³
 *  ³0    cost  sint 0³   ³r21   r22    r23   0³   ³r21'  r22'   r23'  0³
 *  ³0   -sint  cost 0³ * ³r31   r32    r33   0³ = ³r31'  r32'   r33'  0³
 *  ³0    0     0    1³   ³tx    ty     tz    1³   ³tx    ty     tz    1³
 *  À                 Ù   À                    Ù   À                    Ù
 *
 *   r21' = r21*cost + r31*sint
 *   r22' = r22*cost + r32*sint
 *   r23' = r23*cost + r33*sint
 *   r31' = r31*cost - r21*sint
 *   r32' = r32*cost - r22*sint
 *   r33' = r33*cost - r23*sint
 *
 *---------------------------------------------------------------------------
 *)
procedure ctm.Left_rotateX;
var
    cost, sint : real;
    tmp        : real;
begin
     cost := cos(t / 180.0 * 3.1415926535897932385);
     sint := sin(t / 180.0 * 3.1415926535897932385);

    tmp := r21 * cost + r31 * sint;
    r31 := r31 * cost - r21 * sint;
    r21 := tmp;
    tmp := r22 * cost + r32 * sint;
    r32 := r32 * cost - r22 * sint;
    r22 := tmp;
    tmp := r23 * cost + r33 * sint;
    r33 := r33 * cost - r23 * sint;
    r23 := tmp;
end;

(*---------------------------------------------------------------------------
 * ctm.rotateY -- multyply ctm by Rx(t). ctm = ctm * Ry(t)
 *   Ú                   ¿   Ú                  ¿   Ú                    ¿
 *   ³r11   r12    r13  0³   ³cost  0   -sint  0³   ³r11'  r12    r13'  0³
 *   ³r21   r22    r23  0³   ³0     1    0     0³   ³r21'  r22    r23'  0³
 *   ³r31   r32    r33  0³ * ³sint  0    cost  0³ = ³r31'  r32    r33'  0³
 *   ³tx    ty    tz    1³   ³0     0    0     1³   ³tx    ty'    tz'   1³
 *   À                   Ù   À                  Ù   À                    Ù
 *
 *   r11' = r11*cost + r13*sint
 *   r13' = r13*cost - r11*sint
 *   r21' = r21*cost + r23*sint
 *   r23' = r23*cost - r21*sint
 *   tx'  = tx *cost + tz *sint
 *   tz'  = tz *cost - tx *sint
 *---------------------------------------------------------------------------
 *)
procedure ctm.rotateY;
var
    cost, sint : real;
    tmp        : real;
begin
     cost := cos(t / 180.0 * 3.1415926535897932385);
     sint := sin(t / 180.0 * 3.1415926535897932385);

    tmp := r11*cost + r13*sint;
    r13 := r13*cost - r11*sint;
    r11 := tmp;
    tmp := r21*cost + r23*sint;
    r23 := r23*cost - r21*sint;
    r21 := tmp;
    tmp := r31*cost + r33*sint;
    r33 := r33*cost - r31*sint;
    r31 := tmp;
    tmp := tx *cost + tz *sint;
    tz := tz *cost - tx *sint;
    tx := tmp;
end;

(*---------------------------------------------------------------------------
 * ctm.Left_rotateY  -- multyply ctm by Ry(t) on the left. ctm = Ry(t) * ctm
 *  Ú                 ¿   Ú                    ¿   Ú                    ¿
 *  ³cost  0   -sint  0³   ³r11   r12   r13   0³   ³r11'  r12'   r13'  0³
 *  ³0    1    0     0³   ³r21   r22    r23   0³   ³r21   r22    r23   0³
 *  ³sint  0   cost  0³ * ³r31   r32    r33   0³ = ³r31'  r32'   r33'  0³
 *  ³0    0    0     1³   ³tx    ty     tz    1³   ³tx    ty     tz    1³
 *  À                 Ù   À                    Ù   À                    Ù
 *
 *   r11' = r11*cost - r31*sint
 *   r12' = r11*cost - r32*sint
 *   r13' = r11*cost - r33*sint
 *   r31' = r31*cost + r11*sint
 *   r32' = r32*cost + r12*sint
 *   r33' = r33*cost + r13*sint
 *
 *---------------------------------------------------------------------------
 *)
procedure ctm.Left_rotateY;
var
    cost, sint : real;
    tmp        : real;
begin
     cost := cos(t / 180.0 * 3.1415926535897932385);
     sint := sin(t / 180.0 * 3.1415926535897932385);

    tmp := r11 * cost - r31 * sint;
    r31 := r31 * cost + r11 * sint;
    r11 := tmp;
    tmp := r11 * cost - r32 * sint;
    r32 := r32 * cost + r12 * sint;
    r12 := tmp;
    tmp := r11 * cost - r33 * sint;
    r33 := r33 * cost + r13 * sint;
    r13 := tmp;
end;

(*---------------------------------------------------------------------------
 *  ctm.transform   -- transform [x,y,z] by the CTM.
 *
 *  See remarks at the top.
 *---------------------------------------------------------------------------
 *)
procedure ctm.transform;
begin
    t.x := p.x*r11 + p.y*r21 + p.z*r31 + tx;
    t.y := p.x*r12 + p.y*r22 + p.z*r32 + ty;
    t.z := p.x*r13 + p.y*r23 + p.z*r33 + tz;
end;

(*---------------------------------------------------------------------------
 *  ctm.inv_transform -- transform [x',y',z'] by the INVERS
 *                      transfomation CTM^-1
 *
 *  The inverse transformation is calculated by solving the 3 equations
 *     for x,y,z.
 *
 *      x' = x*r11 + y*r21 + z*r31 + tx
 *      y' = x*r12 + y*r22 + z*r32 + ty
 *      z' = x*r13 + y*r23 + z*r33 + tz
 *
 *---------------------------------------------------------------------------
 *)
procedure ctm.inv_transform;
var
    d      : real;     { Delta }
    d_x     : real;    { Delta X [X = Delta X / Delta] }
    d_y     : real;    { Delta Y [Y = Delta Y / Delta] }
    d_z     : real;    { Delta Z [Z = Delta Z / Delta] }
begin
    d :=  r11*(r22*r33 - r32*r23)
        -r21*(r12*r33 - r13*r32)
        +r31*(r12*r23 - r22*r13);
    d_x:=  (p.x - tx)*(r22*r33 - r32*r23)
         -r21*((p.y - ty)*r33 - (p.z - tz)*r32)
         +r31*((p.y - ty)*r23 - r22*(p.z - tz));
    d_y:=  r11*((p.y - ty)*r33 - r32*(p.z - tz))
         -(p.x - tx)*(r12*r33 - r13*r32)
         +r31*(r12*(p.z - tz) - (p.y - ty)*r13);
    d_z:=  r11*(r22*(p.z - tz) - (p.y - ty)*r23)
         -r21*(r12*(p.z - tz) - r13*(p.y - ty))
         +(p.x - tx)*(r12*r23 - r22*r13);
    p.x := round(d_x / d);
    p.y := round(d_y / d);
    p.z := round(d_z / d);
end;

(*******************************************************************************
*                                ctm.multiply                                 *
* here we multiply our ctm with another from the right : self * c -> self      *
*******************************************************************************)
procedure ctm.multiply;
var
    t : ctm;
begin
       t.r11 := r11*c.r11+r12*c.r21+r13*c.r31;
       t.r21 := r21*c.r11+r22*c.r21+r23*c.r31;
       t.r31 := r31*c.r11+r32*c.r21+r33*c.r31;
       t.tx  := tx *c.r11+ty *c.r21+tz *c.r31+c.tx;

       t.r12 := r11*c.r12+r12*c.r22+r13*c.r32;
       t.r22 := r21*c.r12+r22*c.r22+r23*c.r32;
       t.r32 := r31*c.r12+r32*c.r22+r33*c.r32;
       t.ty  := tx *c.r12+ty *c.r22+tz *c.r32+c.ty;

       t.r13 := r11*c.r13+r12*c.r23+r13*c.r33;
       t.r23 := r21*c.r13+r22*c.r23+r23*c.r33;
       t.r33 := r31*c.r13+r32*c.r23+r33*c.r33;
       t.tz  := tx *c.r13+ty *c.r23+tz *c.r33+c.tz;

       copy(t);
end; {ctm.multiply}

(*******************************************************************************
*                                ctm.multiply_2                               *
* here we multiply our ctm with another from the right : self * c -> self      *
*******************************************************************************)
procedure ctm.multiply_2;
begin
    r11 := a.r11*b.r11+a.r12*b.r21+a.r13*b.r31;
    r21 := a.r21*b.r11+a.r22*b.r21+a.r23*b.r31;
    r31 := a.r31*b.r11+a.r32*b.r21+a.r33*b.r31;
    tx := a.tx *b.r11+a.ty *b.r21+a.tz *b.r31+b.tx;

    r12 := a.r11*b.r12+a.r12*b.r22+a.r13*b.r32;
    r22 := a.r21*b.r12+a.r22*b.r22+a.r23*b.r32;
    r32 := a.r31*b.r12+a.r32*b.r22+a.r33*b.r32;
    ty := a.tx *b.r12+a.ty *b.r22+a.tz *b.r32+b.ty;

    r13 := a.r11*b.r13+a.r12*b.r23+a.r13*b.r33;
    r23 := a.r21*b.r13+a.r22*b.r23+a.r23*b.r33;
    r33 := a.r31*b.r13+a.r32*b.r23+a.r33*b.r33;
    tz := a.tx *b.r13+a.ty *b.r23+a.tz *b.r33+b.tz;
end; {ctm.multiply_2}


(*******************************************************************************
*                                ctm.inverse                                  *
*******************************************************************************)
procedure ctm.inverse;
begin
     runerror;
end;


end.
