 /*
  * Khoros: $Id: matrix_2D.c,v 1.3 1992/03/20 22:46:17 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: matrix_2D.c,v 1.3 1992/03/20 22:46:17 dkhoros Exp $";
#endif

 /*
  * $Log: matrix_2D.c,v $
 * Revision 1.3  1992/03/20  22:46:17  dkhoros
 * VirtualPatch5
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * 
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *----------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "X3D.h"

/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>             file name: matrix_2D.c                    <<<<
   >>>>                                                       <<<<
   >>>>              2D Matrix  Utilities                     <<<<
   >>>>                                                       <<<<
   >>>>              _X2D_clear_matrix()                      <<<<
   >>>>              _X2D_matrix_set_identity()               <<<<
   >>>>              _X2D_matrix_mult()               	      <<<<
   >>>>              _X2D_matrix_set_ndc()            	      <<<<
   >>>>              _X2D_write_matrix()            	      <<<<
   >>>>              _X2D_matrix_set_dc()            	      <<<<
   >>>>              X2D_matrix_set_translate()       	      <<<<
   >>>>              X2D_matrix_set_scale()       	      <<<<
   >>>>              X2D_matrix_set_rotate()       	      <<<<
   >>>>              X2D_matrix_set_inverse()       	      <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */


/************************************************************
*
*  MODULE NAME:   _X2D_clear_matrix
*
*      PURPOSE:   Set a 3x3 matrix to ALL zeros.
*
*
*        INPUT:   1) matrix -- a 3x3 Real array.
*
*
*       OUTPUT:   none
*
*    CALLED BY:   many routines
*
*   WRITTEN BY:   Mark Young
*
*
*************************************************************/


_X2D_clear_matrix (matrix)

Matrix_2D matrix;
{
	int i,j;

	for (i = 0; i < 3; i++)
	{
	    for (j = 0; j < 3; j++)
	    {
		matrix[i][j] = 0.0;
	    }
	}
}


/************************************************************
*
*  MODULE NAME:   _X2D_matrix_set_identity
*
*      PURPOSE:   Set a 3x3 matrix to identity matrix.
*
*
*        INPUT:   1) matrix -- a 3x3 Real array.
*
*
*       OUTPUT:   none
*
*    CALLED BY:   many routines
*
*   WRITTEN BY:   Mark Young
*
*
*************************************************************/


_X2D_matrix_set_identity (matrix)

Matrix_2D  matrix;
{
	_X2D_clear_matrix(matrix);
	matrix[0][0] = 
	matrix[1][1] = 
	matrix[2][2] = 1.0;
}




/************************************************************
*
*  MODULE NAME: _X2D_matrix_mult
*
*      PURPOSE: multiplies 2 3x3 matrices
*
*        INPUT: 2 3x3 matrices
*
*       OUTPUT: the resulting 3x3 matrix
*              
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


_X2D_matrix_mult (matrix1, matrix2, outmatrix)

Matrix_2D matrix1, matrix2, outmatrix;
{
	int   i, j;
	Matrix_2D tmp_matrix;

	/*
	 *  Multiply the two matrices together and return the result in
	 *  the out matrix, "outmatrix".
	 */
	for (i = 0; i < 3; i++)
	{
	    for (j = 0; j < 3; j++)
	    {
	        tmp_matrix[i][j]  = matrix1[i][0] * matrix2[0][j] +
	      			    matrix1[i][1] * matrix2[1][j] +
	      			    matrix1[i][2] * matrix2[2][j];
	    }
	}

	/*
	 *  Copy the temporary matrix to the final matrix (outmatrix).  We 
	 *  could have put this directly into the final matrix but this enables
	 *  the user to use the output matrix as either matrix1 or matrix2.
	 *  ie)
	 *      matrix1 = matrix1 * matrix2
	 */
        bcopy( (char *) tmp_matrix, (char *) outmatrix, sizeof(Matrix_2D));
}



/************************************************************
*
*  MODULE NAME:  _X2D_matrix_set_ndc
*
*      PURPOSE:  This routine sets a transform
*                matrix which will map world coordinates
*                to normalized device coordinates.
*
*        INPUT:  
*
*       OUTPUT:  matrix -- a two dimensional (3x3) Real array
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/

/*
 *   Two Dimensional Transform Matrix:
 *
 *          transforms two dimensional world coordinates to 
 *          normalized device coordinates.
 *
 *          ----            ---
 *          | Sx   0    0   0 |
 *          |  0   Sy   0   0 |
 *          |  0   0    0   0 |
 *          | Ax   Ay   0   1 |
 *          ----            ---
 */


_X2D_matrix_set_ndc (xv_min, xv_max, yv_min, yv_max, wc_min, wc_max, matrix)

Real		xv_min, xv_max,
		yv_min, yv_max;
Coord		wc_min, wc_max;
Matrix_2D	matrix;
{
	Real	scale_x, scale_y, offset_x, offset_y;

	scale_x = (xv_max - xv_min)/(wc_max.x - wc_min.x);
	scale_y = (yv_max - yv_min)/(wc_max.y - wc_min.y);

	offset_x = xv_min - (wc_min.x * scale_x);
	offset_y = yv_min - (wc_min.y * scale_y);

	/*
	 *  Now set the 2D ndc matrix  
	 */
	_X2D_matrix_set_identity(matrix);

	matrix[0][0] = scale_x;
	matrix[1][1] = scale_y;

	matrix[2][0] = offset_x;
	matrix[2][1] = offset_y;
}





/************************************************************
*
*  MODULE NAME:  _X2D_write_matrix
*
*      PURPOSE:  Prints out a Matrix.  This is mostly used by
*		 for debugging purposes.
*
*
*        INPUT:  1)  matrix --  The Matrix_2D to be printed.
*
*
*       OUTPUT:  Prints out a Matrix_2D.
*
*    CALLED BY:
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/




_X2D_write_matrix (matrix)

Matrix_2D matrix;
{
     int i,j;

     printf ("\n");
     for (i = 0; i < 3; i++)
     {
         for (j = 0; j < 3; j++)
	 {
	     printf (" %7.3f ",matrix[i][j]);
	 }
	 printf ("\n");
     }
}



/************************************************************
*
*  MODULE NAME:  _X2D_matrix_set_dc
*
*      PURPOSE:  This routine sets a transform matrix which will map 
*		 world coordinates to device coordinates.
*
*        INPUT:  graphics	   - X3D graphics structure
*
*       OUTPUT:  matrix -- a two dimensional (3x3) Real array
*
*    CALLED BY:  _X2D_update_graphics()
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/

_X2D_matrix_set_dc (graphics, matrix)

X3DGraphics	*graphics;
Matrix_2D	matrix;
{
	/*
	 *  Now set the 2D dc matrix  
	 */
	_X2D_matrix_set_identity(matrix);

	if (graphics->device == X11)
	{
	   matrix[0][0] = graphics->X11_xmax - graphics->X11_xmin;
	   matrix[1][1] = graphics->X11_ymin - graphics->X11_ymax;
	   matrix[2][0] = graphics->X11_xmin;
	   matrix[2][1] = graphics->X11_ymax;
	}
	else if (graphics->device == POSTSCR)
	{
	   matrix[0][0] = graphics->POS_xmax - graphics->POS_xmin;
	   matrix[1][1] = graphics->POS_ymax - graphics->POS_ymin;
	   matrix[2][0] = graphics->POS_xmin;
	   matrix[2][1] = graphics->POS_ymin;
	}
	else if (graphics->device == IMPRESS)
	{
	   matrix[0][0] = graphics->IMP_xmax - graphics->IMP_xmin;
	   matrix[1][1] = graphics->IMP_ymin - graphics->IMP_ymax;
	   matrix[2][0] = graphics->IMP_xmin;
	   matrix[2][1] = graphics->IMP_ymax;
	}
	else if (graphics->device == HPGL)
	{
	   matrix[0][0] = graphics->HPGL_xmax - graphics->HPGL_xmin;
	   matrix[1][1] = graphics->HPGL_ymax - graphics->HPGL_ymin;
	   matrix[2][0] = graphics->HPGL_xmin;
	   matrix[2][1] = graphics->HPGL_ymin;
	}
}



/************************************************************
*
*  MODULE NAME: X2D_matrix_set_inverse
*
*      PURPOSE: 
*
*        INPUT: graphics - X3D graphics structure
*
*       OUTPUT: none
*
*    CALLED BY: 
*
*   WRITTEN BY:
*
*
*************************************************************/


int X2D_matrix_set_inverse(matrix, imatrix)

Matrix_2D	matrix, imatrix;
{
	Matrix_2D tmp;
	Real	  det;


	det =   matrix[0][0]*matrix[1][2]*matrix[2][1]
	      - matrix[0][0]*matrix[1][1]*matrix[2][2]
	      + matrix[1][0]*matrix[0][1]*matrix[2][2]
	      - matrix[1][0]*matrix[0][2]*matrix[2][1]
	      - matrix[2][0]*matrix[0][2]*matrix[1][2]
	      + matrix[2][0]*matrix[0][2]*matrix[1][1];
	if (det <= 0.0)
	{
	   return(FALSE);
	}

	tmp[0][0] = (matrix[1][2]*matrix[2][1] - matrix[1][1]*matrix[2][2])/det;
	tmp[0][1] = (matrix[0][1]*matrix[2][2] - matrix[0][2]*matrix[2][1])/det;
	tmp[0][2] = (matrix[0][2]*matrix[1][1] - matrix[0][1]*matrix[1][2])/det;

	tmp[1][0] = (matrix[1][0]*matrix[2][2] - matrix[1][2]*matrix[2][0])/det;
	tmp[1][1] = (matrix[0][2]*matrix[2][0] - matrix[0][0]*matrix[2][2])/det;
	tmp[1][2] = (matrix[0][0]*matrix[1][2] - matrix[0][2]*matrix[1][0])/det;

	tmp[2][0] = (matrix[1][1]*matrix[2][0] - matrix[1][0]*matrix[2][1])/det;
	tmp[2][1] = (matrix[0][0]*matrix[2][1] - matrix[0][1]*matrix[2][0])/det;
	tmp[2][2] = (matrix[0][1]*matrix[1][0] - matrix[0][0]*matrix[1][1])/det;

	bcopy(tmp, imatrix, sizeof(Matrix_2D));
	return(TRUE);
}



/************************************************************
*
*  MODULE NAME:  X2D_matrix_set_translate
*
*      PURPOSE:  This routine is used to set a translation
*                matrix in order to translate world coordinates
*                to new world coordinates.
*
*        INPUT:  xtrans --  a Real containing the x distance to be translated
*                ytrans --  a Real containing the y distance to be translated
*		 matrix --  an empty two dimension (3x3) Real array
*
*       OUTPUT:  matrix -- a two dimensional (3x3) Real array
*                          containing the scaling matrix.
*
*    CALLED BY:
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/

/*
 *   Two Dimensional Translation Matrix:
 *
 *          transforms two dimensional world coordinates to
 *          normalized device coordinates.
 *
 *          ----        ---
 *          | 1    0    0 |
 *          | 0    1    0 |
 *          | Tx   Ty   1 |
 *          ----        ---
 */

X2D_matrix_set_translate (xtrans, ytrans, matrix)

Real		xtrans, ytrans;
Matrix_2D	matrix;
{
        /*
         *  Set up the translation matrix --
         *  these entries will not change
         */
	_X2D_matrix_set_identity(matrix);

        /*
         *  Values in the active 3rd column of the
         *  translation matrix have been provided by the user.
         */
        matrix[2][0] = xtrans; matrix[2][1] = ytrans;
}



/************************************************************
*
*  MODULE NAME:  X2D_matrix_set_scale
*
*      PURPOSE:  This routine is used to set a scale
*                matrix in order to scale world coordinates
*                to new world coordinates.
*
*
*        INPUT:  xscale --  a Real containing the x distance to be translated
*                yscale --  a Real containing the y distance to be translated
*                matrix --  an empty two dimension (3x3) Real array
*
*
*       OUTPUT:  matrix -- a two dimensional (3x3) float array
*                          containing the scaling matrix.
*
*    CALLED BY:
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/

/*
 *   Two Dimensional Scaling Matrix
 *
 *          scales two dimensional world coordinates
 *
 *          ----        ---
 *          | Sx   0    0 |
 *          |  0   Sy   0 |
 *          |  0   0    1 |
 *          ----        ---
 */

X2D_matrix_set_scale (xscale, yscale, matrix)

Real		xscale, yscale;
Matrix_2D	matrix;
{


        /*
         *  set identity matrix
         */
	_X2D_matrix_set_identity(matrix);

        /*
         *  the active entries are on the diagonal, providing the
         *  scaling factor requested by the user
         */
        matrix[0][0] = xscale;
	matrix[1][1] = yscale;
}



/************************************************************
*
*  MODULE NAME:  X2D_matrix_set_rotate
*
*      PURPOSE:  This routine is used to set a rotation
*                matrix in order to rotate world coordinates
*                to new world coordinates.
*
*        INPUT:  matrix --  an empty two dimension (3x3) Real array
*
*                rotation_degree --  a Real containing the degree of
*                                    rotation
*                axis   --  a character representing which axis is to
*                           be rotated
*
*
*       OUTPUT:  matrix -- a two dimensional (3x3) Real array
*                          containing the rotation matrix.
*
*    CALLED BY:
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/

/*
 *   Two Dimensional Rotation Matrix:
 *
 *          rotates two dimensional world coordinates to
 *          new world  coordinates.
 *
 *          ----            ---
 *          | cos@  sin@    0 |
 *          |-sin@  cos@    0 |
 *          |  0    0       1 |
 *          ----            ---
 *
 */

X2D_matrix_set_rotate (rotation_degree, matrix)

Real		rotation_degree;
Matrix_2D	matrix;
{
        Real  rad;

        /*
         *  rotate the x, y, and z arrays & reset world coordinates
         */
        rad = _X2D_DegToRads(rotation_degree);

        /*
         *  initialize the matrix to the identity matrix, for
         *  the sake of simplicity -- some values will be over-
         *  written.
         */
	_X2D_matrix_set_identity(matrix);

        /*
         *  set up the rotation matrix as described above --
         *  with cos@ and sin@ in the proper place.
         */
	matrix[0][0] =
	matrix[1][1] = cos(rad);
	matrix[0][1] = -sin(rad);
	matrix[1][0] = sin(rad);
}
