 /*
  * Khoros: $Id: lvmsquish.c,v 1.1 1991/05/10 15:41:54 khoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: lvmsquish.c,v 1.1 1991/05/10 15:41:54 khoros Exp $";
#endif

 /*
  * $Log: lvmsquish.c,v $
 * Revision 1.1  1991/05/10  15:41:54  khoros
 * Initial revision
 *
  */ 

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

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 >>>>
 >>>>         File Name: lvmsquish.c
 >>>>
 >>>>      Program Name: vmsquish
 >>>>
 >>>> Date Last Updated: Tue Mar  5 22:38:10 1991 
 >>>>
 >>>>          Routines: lvmsquish - the library call for vmsquish
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


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


/****************************************************************
*
* Routine Name: lvmsquish - library call for vmsquish
*
* Purpose:
*    
*    Compress columns  in  map(s)  to  one  column  by  means  of
*    Average, RMS or MAX
*    
*    
* Input:
*    
*    *image         pointer to the image
*    
*    m_flag         map flag (map if set)
*    
*    squish_type    1 = AVG, 2 = RMS, 3 = MAX
*    
*    
* Output:
*    
*    image          image with squished map, or image  that  has  been
*                   mapped after map squishing.
*    
*    
*
* Written By: Tom sauer
*    
*    
****************************************************************/


/* -library_def */
int
lvmsquish(image, m_flag, squish_type)
   struct xvimage *image;
   int m_flag;
   int squish_type;
/* -library_def_end */

/* -library_code */
{
        int i;
        char *program = "lvmsquish";
         
          /* make sure there is only one image in the input */

        if (! (proper_num_images(program,image,1,FALSE)))
        {
           (void) fprintf(stderr,"\n\n%s: ", program);
           (void) fprintf(stderr,"Can only work on files with one image\n\n");
           return(0);
        }
          /* if the data is to be mapped after the map squish, then the */
          /* input data must have a storage type of byte. */

        if (m_flag) {
           if ( image->data_storage_type != VFF_TYP_1_BYTE ) {
              (void) fprintf(stderr, 
                     "%s: ERROR Can not map data, data is not of ",program);
              (void) fprintf(stderr, "storage type BYTE\n");
              return(0);
           }
        }

           /* we can only operate on map shemes ONPERBAND and SHARED. */

        switch(image->map_scheme) {
           case VFF_MS_ONEPERBAND:

                    /* squish the map for each band based on the squish */
                    /* type passed in */

               for ( i = 0; i < image->num_data_bands; i++) {
                 switch(squish_type) {
                   case 1:
                      if ( ! find_avg(image, i))  {
                         (void) fprintf(stderr, 
                                   "%s: ERROR find_avg failed\n",program);
                         return(0);
                      }
                      break;
                   case 2:
                      if ( ! find_rms(image, i))  {
                        (void)  fprintf(stderr, 
                                   "%s: ERROR find_rms failed\n",program);
                        return(0);
                      }
                      break;
                   case 3:
                      if ( ! find_max(image, i))  {
                         (void) fprintf(stderr, 
                                   "%s: ERROR find_max failed\n",program);
                         return(0);
                      }
                      break;
                   default:
                      (void) fprintf(stderr, 
                           "%s: ERROR Invalid mapping type: the squish type",
                            program);
                      (void) fprintf(stderr, 
                           " must be\n either average, RMS or maximum\n");
                      return(0);
                      break;
                 }
               }
               break;
            case VFF_MS_SHARED:

                    /* squish the map based on the squish */
                    /* type passed in */

              switch(squish_type) {
                case 1:
                   if ( ! find_avg(image, 0)) {
                      (void) fprintf(stderr, 
                                   "%s: ERROR find_avg failed\n",program);
                      return(0);
                   }
                   break;
                case 2:
                   if ( ! find_rms(image, 0))  {
                      (void) fprintf(stderr, 
                                   "%s: ERROR find_rms failed\n",program);
                      return(0);
                   }
                   break;
                case 3:
                   if ( ! find_max(image, 0)) {
                      (void) fprintf(stderr, 
                                   "%s: ERROR find_max failed\n",program);
                      return(0);
                   }
                   break;
                default:
                   (void) fprintf(stderr, 
                        "%s: ERROR Invalid mapping type: the squish type",
                            program);
                   (void) fprintf(stderr, 
                        " must be\n either average, RMS or maximum\n");
                   return(0);
                   break;
              }
              break;

           default:
             (void) fprintf(stderr, 
                "\n%s: ERROR This image does not contain a valid map scheme\n",
                   program);
             (void) fprintf(stderr, 
                "                 for squishing. The map scheme must be either\n");
             (void) fprintf(stderr, 
                "                 ONEPERBAND or SHARED\n");
             return(0);
             break;
         }
            /* the new map has the same storage type and map scheme, except */
            /* the map only has one column */

         image->map_row_size = 1;
         image->color_space_model = VFF_CM_NONE;

           /* if the map flag is set, then map the data. The storage */
           /* type of the data must be BYTE  */

         if (m_flag) {
           if ( ! lvmapdata(image)) {
              (void) fprintf(stderr,"%s: ERROR lvmapdata failed",program);
              return(0);
           }
          }
  

    return(1);
}


/**************************************************************
*
* MODULE NAME: find_avg
*
*     PURPOSE: squish maps using the average. Sum all elements
*               in a row, and divide by the number of rows.
*               Do this for each element.
*
*       INPUT: struct xvimage *image - pointer to the image
*               which contains the map(s) to squish.
*               
*              int bandnum - which band we are working with.
*
*      OUTPUT: 
*
* CALLED FROM:  lvmsquish
*
* ROUTINES CALLED:
*
**************************************************************/

find_avg(image, bandnum)
  struct xvimage *image;
  int bandnum;

{
  unsigned char *bptr;
  short *sptr;
  int *lptr;
  float *fptr; 
  double dtmpval;
  int i,j;
  

      /* compute AVG and update the element in the first column of the
         map. supports BYTE, SHORT, INT and FLOAT. */

  switch(image->map_storage_type) {

     case VFF_MAPTYP_1_BYTE:
          bptr = (unsigned char *)
                  &image->maps[bandnum*image->map_col_size*image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             dtmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               dtmpval += (double) bptr[i + j*image->map_col_size]; 
             }
             dtmpval /= image->map_row_size;
             bptr[i] = (unsigned char) dtmpval;
          }
          break;

     case VFF_MAPTYP_2_BYTE:
          sptr = (short *)
              &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             dtmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               dtmpval += (double) sptr[i + j*image->map_col_size]; 
             }
             dtmpval /= image->map_row_size;
             sptr[i] = (short) dtmpval;
          }
          break;

     case VFF_MAPTYP_4_BYTE:
          lptr = (int *)
              &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             dtmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               dtmpval += (double) lptr[i + j*image->map_col_size]; 
             }
             dtmpval /= image->map_row_size;
             lptr[i] = (int) dtmpval;
          }
          break;

     case VFF_MAPTYP_FLOAT:
          fptr = (float *)
              &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             dtmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               dtmpval += (double) fptr[i + j*image->map_col_size]; 
             }
             dtmpval /= image->map_row_size;
             fptr[i] = (float) dtmpval;
          }
          break;

     default:
          (void) fprintf(stderr, 
                       "find_avg: ERROR map storage type undefined\n");
          (void) fprintf(stderr, 
             "The map storage type must be either BYTE, SHORT, INT or FLOAT\n");
          return(0);
         
          break;

   }
   return(1);
}


/**************************************************************
*
* MODULE NAME: find_rms
*
*     PURPOSE: squish maps using rms. square each element then sum
*               in a row, and divide by the number of rows, then
*               take the square root.
*               Do this for each element.
*
*       INPUT: struct xvimage *image - pointer to the image
*               which contains the map(s) to squish.
*               
*              int bandnum - which band we are working with.
*
*      OUTPUT: 
*
* CALLED FROM:  lvmsquish
*
* ROUTINES CALLED:
*
**************************************************************/

find_rms(image, bandnum)
  struct xvimage *image;
  int bandnum;

{
  unsigned char *bptr;
  short *sptr;
  int *lptr;
  float *fptr; 
  double dtmpval, dtmpim;
  double sqr = 2;
  int i,j;
  
      /* compute RMS and update the element in the first column of the
         map. supports BYTE, SHORT, INT and FLOAT. */

  switch(image->map_storage_type) {

     case VFF_MAPTYP_1_BYTE:
          bptr = (unsigned char *)
              &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             dtmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               dtmpim = (double) bptr[i + j*image->map_col_size]; 
               dtmpim = pow(dtmpim,sqr);
               dtmpval += dtmpim;
             }
             dtmpval /= image->map_row_size;
             dtmpval = sqrt(dtmpval);
             bptr[i] = (unsigned char) dtmpval;
          }
          break;

     case VFF_MAPTYP_2_BYTE:
          sptr = (short *)
             &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             dtmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               dtmpim = (double) sptr[i + j*image->map_col_size]; 
               dtmpval += pow(dtmpim,sqr);
             }
             dtmpval /= image->map_row_size;
             dtmpval = sqrt(dtmpval);
             sptr[i] = (short) dtmpval;
          }
          break;

     case VFF_MAPTYP_4_BYTE:
          lptr = (int *)
              &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             dtmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               dtmpim = (double) lptr[i + j*image->map_col_size]; 
               dtmpval += pow(dtmpim,sqr);
             }
             dtmpval /= image->map_row_size;
             dtmpval = sqrt(dtmpval);
             lptr[i] = (int) dtmpval;
          }
          break;

     case VFF_MAPTYP_FLOAT:
          fptr = (float *)
              &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             dtmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               dtmpim = (double) fptr[i + j*image->map_col_size]; 
               dtmpval += pow(dtmpim,sqr);
             }
             dtmpval /= image->map_row_size;
             dtmpval = sqrt(dtmpval);
             fptr[i] = (float) dtmpval;
          }
          break;

     default:
          (void) fprintf(stderr, 
                       "find_rms: ERROR map storage type undefined\n");
          (void) fprintf(stderr, 
             "The map storage type must be either BYTE, SHORT, INT or FLOAT\n");
          return(0);
          break;

   }
   return(1);
}

/**************************************************************
*
* MODULE NAME: find_max
*
*     PURPOSE: Squish maps using the Maximum value. find the
*               element in a row which is the largest.
*               Do this for each element.
*
*       INPUT: struct xvimage *image - pointer to the image
*               which contains the map(s) to squish.
*               
*              int bandnum - which band we are working with.
*
*      OUTPUT: 
*
* CALLED FROM:  lvmsquish
*
* ROUTINES CALLED:
*
**************************************************************/

find_max(image, bandnum)
  struct xvimage *image;
  int bandnum;

{
  unsigned char *bptr;
  unsigned int itmpval;
  short *sptr, stmpval;
  int *lptr, ltmpval;
  float *fptr, ftmpval; 
  int i,j;
  

      /* compute MAX and update the element in the first column of the
         map. supports BYTE, SHORT, INT and FLOAT. */

  switch(image->map_storage_type) {

     case VFF_MAPTYP_1_BYTE:
          bptr = (unsigned char *)
              &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             itmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               if ( itmpval < bptr[i + j*image->map_col_size] ) 
                  itmpval = bptr[i + j*image->map_col_size];
             }
             bptr[i] = (unsigned char)itmpval;
          }
          break;

     case VFF_MAPTYP_2_BYTE:
          sptr = (short *)
              &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             stmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               if ( stmpval < sptr[i + j*image->map_col_size] ) 
                  stmpval = sptr[i + j*image->map_col_size];
             }
             sptr[i] = stmpval;
          }
          break;

     case VFF_MAPTYP_4_BYTE:
          lptr = (int *)
              &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             ltmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               if ( ltmpval < lptr[i + j*image->map_col_size] ) 
                  ltmpval = lptr[i + j*image->map_col_size];
             }
             lptr[i] = ltmpval;
          }
          break;

     case VFF_MAPTYP_FLOAT:
          fptr = (float *)
              &image->maps[bandnum * image->map_col_size * image->map_row_size];
          for ( i = 0 ; i < image->map_col_size ; i ++){
             ftmpval = 0;
             for ( j = 0; j < image->map_row_size ; j++ ) {
               if ( ftmpval < fptr[i + j*image->map_col_size] ) 
                  ftmpval = fptr[i + j*image->map_col_size];
             }
             fptr[i] = ftmpval;
          }
          break;

     default:
          (void) fprintf(stderr, 
                       "find_max: ERROR map storage type undefined\n");
          (void) fprintf(stderr, 
             "The map storage type must be either BYTE, SHORT, INT or FLOAT\n");
          return(0);
          break;

   }
   return(1);
}
/* -library_code_end */
