#include "mrilib.h"

/*** NOT 7D SAFE ***/

#define FINS(i,j) (  ( (i)<0 || (j)<0 || (i)>=nx || (j)>=ny ) \
                     ? 0.0 : far[(i)+(j)*nx] )

/**-------------------------------------------------------------------
    Shift an image, using bilinear interpolation:
       aa  = shift in x
       bb  = shift in y
    Like mri_rota_bilinear, with phi=0 -- RWCox - 11 Sep 2001
----------------------------------------------------------------------**/

MRI_IMAGE *mri_shift2D_bilinear( MRI_IMAGE *im, float aa, float bb )
{
   float dx , dy ;
   MRI_IMAGE *imfl , *newImg ;
   MRI_IMARR *impair ;
   float *far , *nar ;
   float xx,yy , fx,fy ;
   int ii,jj, nx,ny , ix,jy ;
   float f_j00,f_jp1 , wt_00,wt_p1 ;

ENTRY("mri_shift2D_bilinear") ;

   if( im == NULL || !MRI_IS_2D(im) ){
      fprintf(stderr,"*** mri_shift2D_bilinear only works on 2D images!\n") ;
      EXIT(1) ;
   }

   /** if complex image, break into pairs, do each separately, put back together **/

   if( im->kind == MRI_complex ){
      MRI_IMARR *impair ;
      MRI_IMAGE *rim , *iim , *tim ;
      impair = mri_complex_to_pair( im ) ;
      if( impair == NULL ){
         fprintf(stderr,"*** mri_complex_to_pair fails in mri_shift2D_bilinear!\n");
         EXIT(1) ;
      }
      rim = IMAGE_IN_IMARR(impair,0) ;
      iim = IMAGE_IN_IMARR(impair,1) ;  FREE_IMARR(impair) ;
      tim = mri_shift2D_bilinear( rim , aa,bb ); mri_free(rim); rim = tim;
      tim = mri_shift2D_bilinear( iim , aa,bb ); mri_free(iim); iim = tim;
      newImg = mri_pair_to_complex( rim , iim ) ;
      mri_free(rim) ; mri_free(iim) ;
      MRI_COPY_AUX(newImg,im) ;
      RETURN(newImg) ;
   }

   /** shift params **/

   dx = - aa ;
   dy = - bb ;

   /** other initialization **/

   nx = im->nx ;  /* image dimensions */
   ny = im->ny ;

   if( im->kind == MRI_float ) imfl = im ;
   else                        imfl = mri_to_float( im ) ;

   far = MRI_FLOAT_PTR(imfl) ;              /* access to float data */
   newImg = mri_new( nx , nx , MRI_float ) ;   /* output image */
   nar = MRI_FLOAT_PTR(newImg) ;               /* output image data */

   /*** loop over output points and warp to them ***/

   for( jj=0 ; jj < nx ; jj++ ){
      xx = dx - 1.0 ;
      yy = jj + dy ;

      jy = (yy >= 0.0) ? ((int) yy) : ((int) yy)-1 ;

      for( ii=0 ; ii < nx ; ii++ ){

         xx += 1.0 ;  /* get x,y in original image */

         ix = (xx >= 0.0) ? ((int) xx) : ((int) xx)-1 ;  /* floor */

         fx = xx-ix ; wt_00 = 1.0 - fx ; wt_p1 = fx ;

         if( ix >= 0 && ix < nx-1 && jy >= 0 && jy < ny-1 ){
            float *fy00 , *fyp1 ;

            fy00 = far + (ix + jy*nx) ; fyp1 = fy00 + nx ;

            f_j00 = wt_00 * fy00[0] + wt_p1 * fy00[1] ;
            f_jp1 = wt_00 * fyp1[0] + wt_p1 * fyp1[1] ;

         } else {
            f_j00 = wt_00 * FINS(ix,jy  ) + wt_p1 * FINS(ix+1,jy  ) ;
            f_jp1 = wt_00 * FINS(ix,jy+1) + wt_p1 * FINS(ix+1,jy+1) ;
         }

         fy  = yy-jy ; nar[ii+jj*nx] = (1.0-fy) * f_j00 + fy * f_jp1 ;

      }
   }

   /*** cleanup and return ***/

   if( im != imfl ) mri_free(imfl) ;  /* throw away unneeded workspace */
   MRI_COPY_AUX(newImg,im) ;
   RETURN(newImg) ;
}
