 /*
  * Khoros: $Id: lvrotate.c,v 1.2 1991/10/02 00:23:09 khoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: lvrotate.c,v 1.2 1991/10/02 00:23:09 khoros Exp $";
#endif

 /*
  * $Log: lvrotate.c,v $
 * Revision 1.2  1991/10/02  00:23:09  khoros
 * HellPatch2
 *
  */

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1991, 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 to 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 1991 by UNM */

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 >>>>
 >>>>         File Name: lvrotate.c
 >>>>
 >>>>      Program Name: vrotate
 >>>>
 >>>> Date Last Updated: Sun Aug 25 21:10:30 1991 
 >>>>
 >>>>          Routines: lvrotate - the library call for vrotate
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


/* -library_includes */
/* -library_includes_end */


/****************************************************************
*
* Routine Name: lvrotate - library call for vrotate
*
* Purpose:
*    
*    Rotate an image by an arbitrary angle
*    
*    

* Input:
*    
*    image          pointer to xvimage structure to be processed
*    
*    ang            angle in degrees to rotate by, positive is  clock-
*                   wise (float)
*    
*    xc             X coordinate of center of rotation (float)
*    
*    yc             Y coordinate of center of rotation (float)
*    
*    

* Output:
*    
*    image          holds the result of  the  operation.   The  output
*                   data type is the same as the input data type.
*    
*    Return Value:  1 on success, 0 on failure.
*    
*    

*
* Written By: Scott Wilson
*    
*    Scott Wilson 18-Sep-90 Added multiband support
*    
*    Scott Wilson 25-Aug-91 Fixed  bad  type  conversion  on  rotation
*    angle.
*    
*    

****************************************************************/


/* -library_def */
int
lvrotate(image,ang,xc,yc)
struct xvimage *image;
float  ang; 
int xc, yc;
/* -library_def_end */

/* -library_code */
{

    int i,j,k,nc,nr,il,ih,jl,jh;
    double in,jn,sine,csine,dang;
    float z1,z2,z3,z4,za,zb,zp;
    char * malloc();
    unsigned char *cptr,*p;
    short *sptr,*s;
    int *iptr,*ip;
    float *fptr,*f;
    int nb,bo;

    dang = ang*XV_PI/180.0; /* Convert to radians */
    csine = cos(dang);
    sine = sin(dang);
    if (ang == 90.0)
      {
        csine = 0.0; sine = 1.0;
      }
    else if (ang == -90.0)
      {
        csine = 0.0; sine = -1.0;
      }
    else if (ang == 180.0 || ang == -180.0)
      {
        csine = -1.0; sine = 0.0;
      }
    else if (ang == 360.0 || ang == -360.0)
      {
        csine = 1.0; sine = 0.0;
      }

    nc = image->row_size;
    nr = image->col_size;
    nb = image->num_data_bands;
    bo = nr*nc;

    switch(image->data_storage_type)
      {
        case VFF_TYP_BIT:
          fprintf(stderr,"lvrotate: Cannot rotate a BIT image!\n");
          return(0);
        case VFF_TYP_1_BYTE:
          cptr = (unsigned char *)malloc(nb*nr*nc*sizeof(unsigned char));
          if (cptr == NULL)
            { 
              fprintf(stderr,"lvrotate: Could not allocate enough memory!\n");
              return(0);
            }
          bzero(cptr,nb*nr*nc*sizeof(unsigned char));
          p = (unsigned char *)image->imagedata;
          for (i=0; i<nr; i++)
            {
              for (j=0; j<nc; j++)
                {
                  jn = xc + csine*(j-xc) + sine*(i-yc);
                  in = yc - sine*(j-xc)  + csine*(i-yc);
                  jl = floor(jn);
                  jh = jl+1;
                  il = floor(in);
                  ih = il+1;
                  if (in >= 0 && in < nr &&
                      jn >= 0 && jn < nc &&
                      jl >= 0 && jl < nc &&
                      jh >= 0 && jh < nc &&
                      il >= 0 && il < nr &&
                      ih >= 0 && ih < nr)
                    {
                      for (k=0; k<nb; k++)
                        {
                          z1 = p[k*bo+il*nc+jl];
                          z2 = p[k*bo+il*nc+jh];
                          z3 = p[k*bo+ih*nc+jh];
                          z4 = p[k*bo+ih*nc+jl];
                          za = z1*(ih-in)+z4*(in-il);
                          zb = z2*(ih-in)+z3*(in-il);
                          zp = za*(jh-jn)+zb*(jn-jl);
                          cptr[k*bo+i*nc+j] = zp;
                        }
                    }
                }
            }
          image->imagedata = (char *)cptr;
          break;
        case VFF_TYP_2_BYTE:
          sptr = (short *)malloc(nb*nr*nc*sizeof(short));
          if (sptr == NULL)
            { 
              fprintf(stderr,"lvrotate: Could not allocate enough memory!\n");
              return(0);
            }
          bzero(sptr,nb*nr*nc*sizeof(short));
          s = (short *)image->imagedata;
          for (i=0; i<nr; i++)
            {
              for (j=0; j<nc; j++)
                {
                  jn = xc + csine*(j-xc) + sine*(i-yc);
                  in = yc - sine*(j-xc)  + csine*(i-yc);
                  jl = floor(jn);
                  jh = jl+1;
                  il = floor(in);
                  ih = il+1;
                  if (in >= 0 && in < nr &&
                      jn >= 0 && jn < nc &&
                      jl >= 0 && jl < nc &&
                      jh >= 0 && jh < nc &&
                      il >= 0 && il < nr &&
                      ih >= 0 && ih < nr)
                    {
                      for(k=0; k<nb; k++)
                        {
                          z1 = s[k*bo+il*nc+jl];
                          z2 = s[k*bo+il*nc+jh];
                          z3 = s[k*bo+ih*nc+jh];
                          z4 = s[k*bo+ih*nc+jl];
                          za = z1*(ih-in)+z4*(in-il);
                          zb = z2*(ih-in)+z3*(in-il);
                          zp = za*(jh-jn)+zb*(jn-jl);
                          sptr[k*bo+i*nc+j] = zp;
                        }
                    }
                }
            }
          image->imagedata = (char *)sptr;
          break;
        case VFF_TYP_4_BYTE:
          iptr = (int *)malloc(nb*nr*nc*sizeof(int));
          if (iptr == NULL)
            { 
              fprintf(stderr,"lvrotate: Could not allocate enough memory!\n");
              return(0);
            }
          bzero(iptr,nb*nr*nc*sizeof(int));
          ip = (int *)image->imagedata;
          for (i=0; i<nr; i++)
            {
              for (j=0; j<nc; j++)
                {
                  jn = xc + csine*(j-xc) + sine*(i-yc);
                  in = yc - sine*(j-xc)  + csine*(i-yc);
                  jl = floor(jn);
                  jh = jl+1;
                  il = floor(in);
                  ih = il+1;
                  if (in >= 0 && in < nr &&
                      jn >= 0 && jn < nc &&
                      jl >= 0 && jl < nc &&
                      jh >= 0 && jh < nc &&
                      il >= 0 && il < nr &&
                      ih >= 0 && ih < nr)
                    {
                      for (k=0; k<nb; k++)
                        {
                          z1 = ip[k*bo+il*nc+jl];
                          z2 = ip[k*bo+il*nc+jh];
                          z3 = ip[k*bo+ih*nc+jh];
                          z4 = ip[k*bo+ih*nc+jl];
                          za = z1*(ih-in)+z4*(in-il);
                          zb = z2*(ih-in)+z3*(in-il);
                          zp = za*(jh-jn)+zb*(jn-jl);
                          iptr[k*bo+i*nc+j] = zp;
                        }
                    }
                }
            }
          image->imagedata = (char *)iptr;
          break;
        case VFF_TYP_FLOAT:
          fptr = (float *)malloc(nb*nr*nc*sizeof(float));
          if (fptr == NULL)
            { 
              fprintf(stderr,"lvrotate: Could not allocate enough memory!\n");
              return(0);
            }
          bzero(fptr,nb*nr*nc*sizeof(float));
          f = (float *)image->imagedata;
          for (i=0; i<nr; i++)
            {
              for (j=0; j<nc; j++)
                {
                  jn = xc + csine*(j-xc) + sine*(i-yc);
                  in = yc - sine*(j-xc)  + csine*(i-yc);
                  jl = floor(jn);
                  jh = jl+1;
                  il = floor(in);
                  ih = il+1;
                  if (in >= 0 && in < nr &&
                      jn >= 0 && jn < nc &&
                      jl >= 0 && jl < nc &&
                      jh >= 0 && jh < nc &&
                      il >= 0 && il < nr &&
                      ih >= 0 && ih < nr)
                    {
                      for(k=0; k<nb; k++)
                        {
                          z1 = f[k*bo+il*nc+jl];
                          z2 = f[k*bo+il*nc+jh];
                          z3 = f[k*bo+ih*nc+jh];
                          z4 = f[k*bo+ih*nc+jl];
                          za = z1*(ih-in)+z4*(in-il);
                          zb = z2*(ih-in)+z3*(in-il);
                          zp = za*(jh-jn)+zb*(jn-jl);
                          fptr[k*bo+i*nc+j] = zp;
                        }
                    }
                }
            }
          image->imagedata = (char *)fptr;
          break;
        case VFF_TYP_COMPLEX:
          {
            fprintf(stderr,"lvrotate: Data type not supported!\n");
            return(0);
          }
      }
      return(1);
}
/* -library_code_end */
