 /*
  * Khoros: $Id: lvgbox.c,v 1.4 1991/12/18 09:23:32 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: lvgbox.c,v 1.4 1991/12/18 09:23:32 dkhoros Exp $";
#endif

 /*
  * $Log: lvgbox.c,v $
 * Revision 1.4  1991/12/18  09:23:32  dkhoros
 * HellPatch3
 *
  */

/*
 *----------------------------------------------------------------------
 *
 * 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: lvgbox.c
 >>>>
 >>>>      Program Name: vgbox
 >>>>
 >>>> Date Last Updated: Sat Dec 14 18:02:03 1991 
 >>>>
 >>>>          Routines: lvgbox - the library call for vgbox
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


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


/****************************************************************
*
* Routine Name: lvgbox - library call for vgbox
*
* Purpose:
*    
*    This routine fills in a buffer with a represention of  plain
*    a  parallelogram  projected  on a CCD sensor.  15 parameters
*    are needed (buffer, 14 description parameters).
*    
*    

* Input:
*    
*    n_cols         unsigned short  number of cols (x)
*    
*    n_rows         unsigned short  number of rows (y)
*    
*    px_x_w         float           active area  pixel  width  in  the
*                   pixel_cell
*    
*    px_y_h         float           active area pixel  height  in  the
*                   pixel_cell
*    
*    px_x_of        float            active  pixel  offset  from  left
*                   pixel_cell
*    
*    px_y_of        float            active  pixel  offset  from   top
*                   pixel_cell
*    
*    grey_out       unsigned char   grey level outside  of  parallelo-
*                   gram
*    
*    grey_in        unsigned char   grey level inside of parallelogram
*    
*    im_x_w         float           parallelogram euclidian width  (in
*                   pixel unit)
*    
*    im_y_h         float           parallelogram euclidian height (in
*                   pixel unit)
*    
*    im_x_of        float            parallelogram:  x  right   offset
*                   (origine: parallelogram center = CCD center)
*    
*    im_y_of        float           parallelogram: y  downward  offset
*                   (origine: parallelogram center = CCD center)
*    
*    phi            float           clockwise  parallelogram  rotation
*                   (radians, rot. center = parallelogram center)
*    
*    psi            float           first parallelogram  corner  angle
*                   (radians)
*    
*    

* Output:
*    
*    pt_image_data  unsigned char   a pointer to the memory  allocated
*                   by  the  calling routine.  holds the result of the
*                   image data generation
*    
*    

*
* Written By: Jean-Pierre GUERIN  (CEA)
*    
*    UPDATE:       August 1991 : new float  psi  angle  parameter
*    for parallelogram
*    
*    

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


/* -library_def */
#define PI     XV_PI       /*  3.14159265358979323846 */
#define true   1
#define false  0
#define abs(x) (((x)>0) ? (x) : -(x) )

int lvgbox(pt_image_data,
             n_cols,      /* number of cols (x) */
             n_rows,      /* number of rows (y) */
             px_x_w,      /* active area pixel width in the pixel_cell */
             px_y_h,      /* active area pixel height in the pixel_cell */
             px_x_of,     /* active pixel offset from left pixel_cel */
             px_y_of,     /* active pixel offset from top pixel_cel */
             grey_out,    /* grey level outside of parallelogram */
             grey_in,     /* grey level inside of parallelogram */
             im_x_w,      /* parallelogram euclidian width (in pixel unit) */
             im_y_h,      /* parallelogram euclidian height (in pixel unit) */
             im_x_of,     /* parallelogram: x right offset
                              origine: parallelogram center = sensor center */
             im_y_of,     /* parallelogram: y downward offset
                              origine: parallelogram center = sensor center */
             phi,         /* parallelogram rotation (radians,
                              origine: rot. center = parallelogram center) */
             psi)         /* 1rst parallelogram corner angle: (radians) */


unsigned char  *pt_image_data;
unsigned short n_cols,n_rows;
float          px_x_w, px_y_h, px_x_of, px_y_of;
unsigned char  grey_out,grey_in;
float          im_x_w, im_y_h, im_x_of, im_y_of, phi, psi;
/* -library_def_end */

/* -library_code */
{
struct str_droite
{
   /*teta is the line's director vector (orthogonal):
   *       x*cos(teta) + y*sin(teta) - ro = 0
   */
   float   ro, teta;
   float   delta_y;
   float   yphh, yph, yphb, ypbh, ypb, ypbb; /* y caracteristical points */
   float   y_intersection, area, tan_teta, cst2, grey_val;
   char    deep_slope, flg_vertical;
};

struct str_droite st_d[4];

/*  usage:
 *       st_d[i].teta      =  teta_init  ;    i th line's teta
 */


   unsigned short no_row,no_col;
   float          cumul_area, fl_tmp, ro;
   int            i, return_flag;
   float          xp;   /* vertical axe of pixel */

   return_flag = 0;

   if ( ((px_x_of + px_x_w) > 1.) || ((px_y_of + px_y_h) > 1.) )
   {
      return_flag=2;
      return(return_flag);       /* error */
   }

   phi = - phi;   /* clockwise ==> trigonometrical direction */
   if ( phi<0 )   /* 0 <= phi < PI */
   {
      fl_tmp = kfmod(phi, PI);    /* negative modulo */
      phi   = PI + fl_tmp;
   }

   else phi = kfmod(phi, PI);      /* modulo PI */

   /* 4 lines of the parallelogram are to be proceeded.
    *  rotation is around the parallelogram center, parallelogram offsets are in the sensor plane.
    * st_d[i].teta is the line director vector (orthogonal to the line):
    * x*cos(teta) + y*sin(teta) - ro = 0
    */
   for ( i=0  ; i<4 ; i++)
   {
      switch(i)  /* process for parallogram */
        {
          case 0:
            st_d[i].teta = kfmod(phi,            2*PI);
            break;
          case 1:
            st_d[i].teta = kfmod(phi + psi,      2*PI);
            break;
          case 2:
            st_d[i].teta = kfmod(phi + PI,       2*PI);
            break;
          case 3:
            st_d[i].teta = kfmod(phi + psi + PI, 2*PI);
            break;
         }

      if ((i % 2) == 0) ro = im_x_w/2;

      else ro = im_y_h/2;

      /* axe change: */
      st_d[i].ro = ro +(  (float)(n_cols)/2. + im_x_of)*cos(st_d[i].teta) +
                       (  (float)(n_rows)/2. - im_y_of)*sin(st_d[i].teta);

      st_d[i].delta_y = px_x_w*abs(tan(st_d[i].teta+PI/2))/2; /* abs. value */

      st_d[i].tan_teta = abs(tan(st_d[i].teta)); /* absolute value */

/* Modified test instruction: */
      if ( ( (st_d[i].teta >=   PI-0.00001) && (st_d[i].teta <=   PI+0.00001) ) ||
           ( (st_d[i].teta >=     -0.00001) && (st_d[i].teta <=      0.00001) ) ||
           ( (st_d[i].teta >= 2*PI-0.00001) && (st_d[i].teta <= 2*PI+0.00001) ) )
      {
         st_d[i].flg_vertical =  true;
/* Modified test instruction: */
         if ( (st_d[i].teta >= PI-0.00001) &&
              (st_d[i].teta <= PI+0.00001) )
         {
            st_d[i].ro    = -st_d[i].ro;
            st_d[i].teta += PI;  /* not used */
         }
      }
      else st_d[i].flg_vertical =  false;

      st_d[i].cst2 = st_d[i].tan_teta/2; /* absolute value */
   }

   /* col after col */
   for ( no_col=0 ; no_col<n_cols ; no_col++ )
   {
      /* xp = x center pixel position: */
      xp = no_col + px_x_of + px_x_w/2.;

      /* y caracteristical points at xp center pixel position: */
      for ( i=0; i<4 ;i++)
      {
         if (st_d[i].flg_vertical)
         {
            if (st_d[i].ro < (xp - px_x_w/2.) ) st_d[i].grey_val=1.;
            else if (st_d[i].ro > (xp + px_x_w/2.)) st_d[i].grey_val=0.;
            else st_d[i].grey_val= 1. -(st_d[i].ro-no_col-px_x_of)/(px_x_w);

         }
         else   /* not vertical */
         {
            st_d[i].y_intersection = (st_d[i].ro -
                                     xp*cos(st_d[i].teta))/sin(st_d[i].teta);
            /* top pixel: */
            st_d[i].yph  = n_rows - px_y_of;
            st_d[i].ypb  = st_d[i].yph - px_y_h;
            st_d[i].yphh = st_d[i].yph + st_d[i].delta_y;
            st_d[i].ypbb = st_d[i].ypb - st_d[i].delta_y;

            if (st_d[i].tan_teta >= (px_x_w/px_y_h))   /* slow slope? */
            {
               st_d[i].deep_slope = false;
               st_d[i].yphb = st_d[i].ypbb + px_y_h;
               st_d[i].ypbh = st_d[i].yphh - px_y_h;
            }
            else                                       /* deep slope */
            {
               st_d[i].deep_slope = true;
               st_d[i].yphb = st_d[i].yphh - px_y_h;
               st_d[i].ypbh = st_d[i].ypbb + px_y_h;
            }
         }
      }   /* end i */

      for ( no_row=0 ; no_row<n_rows ; no_row++ )
      {
         for (cumul_area=0, i=0; i<4 ;i++)
         {
            if (st_d[i].flg_vertical)
               st_d[i].area = st_d[i].grey_val;

            else if (st_d[i].y_intersection >= st_d[i].yphh)
            {  /* line above the pixel: empty pixel */
               st_d[i].area = 0.;
            }
            else if  (st_d[i].y_intersection <= st_d[i].ypbb)
            {  /* line under the pixel: full pixel */
               st_d[i].area = 1. ;
            }
            else if (st_d[i].y_intersection >= st_d[i].yphb)
            {  /* intersection is a triangle: */
               st_d[i].area = st_d[i].cst2*
                              (st_d[i].yphh - st_d[i].y_intersection)*
                              (st_d[i].yphh - st_d[i].y_intersection);
            }
            else if (st_d[i].y_intersection >= st_d[i].ypbh)
            {  /* intersection is a trapeze: */
               if (st_d[i].deep_slope==false)
                  st_d[i].area = (st_d[i].yph-st_d[i].y_intersection)/px_y_h;

               else   /* deep slope */
                  st_d[i].area = (st_d[i].yphb - st_d[i].y_intersection +
                                 px_y_h/2) *st_d[i].tan_teta/px_x_w;
            }
            else /* if (st_d[i].y_intersection >= st_d[i].ypbb) */
            {  /* intersection is (full - triangle): */
               st_d[i].area =  1. - st_d[i].cst2*
                               (st_d[i].y_intersection - st_d[i].ypbb)*
                               (st_d[i].y_intersection - st_d[i].ypbb);
            }
         }   /* end i */
         cumul_area = (- st_d[0].area + st_d[2].area) *
                      (st_d[1].area - st_d[3].area);

         if (cumul_area < 0.0)
         {
            cumul_area = -cumul_area;
         }

/* Modified test instruction: */
         if (cumul_area > 1.000)
         {
            if (cumul_area > 1.0001)
                return_flag = 1;
            cumul_area = 1.;
         }

/* Modified cast: */
         pt_image_data[no_row*n_cols + no_col] =
                              (unsigned char) ((float)grey_out+
                              0.5 + cumul_area*
                              ((float)grey_in-(float)grey_out));

         /* next row initialisation: */
         for ( i=0; i<4 ;i++)
         {
            st_d[i].yph-- ;
            st_d[i].yphh-- ;
            st_d[i].yphb-- ;
            st_d[i].ypb-- ;
            st_d[i].ypbh-- ;
            st_d[i].ypbb-- ;
         }   /* end i */
      }   /* end no_row */
   }   /* end no_col */
   return(return_flag);
}   /* end synth_image() */
/* -library_code_end */
