/*===========================================================================
  Copyright (C) 1995-2009 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.IDENTifer   PLMODF
.AUTHOR      R.M. van Hees IPG-ESO Garching
.KEYWORDS    low level plot routine
.LANGUAGE    C
.PURPOSE     modify data values in a frame using the cursor
     input:  char   *cpntr   pointer to the frame
             int    *image   contains in pixel units
             int    *npix    number of pixels in x and y
             double *start   value of first pixel in world coordinates
             double *step    distance between pixels in world coordinates
             int    ncur     number of curor positions
             int    ndeg     degree of the polynomial interpolation
             int    binmode  bin mode
             
 in/output:  int    *go_on   flag which tels the outside world to stop 
                             or to go on
             int    *ibar    has the user pressed the space bar??

.COMMENTS    holds static functions SORT2, ALINT, AITKEN
.ENVIRONment MIDAS and AGL
             #include <agl.h>           Prototypes for AGL application programs
             #include <midas_def.h>     Prototypes for MIDAS interfaces
             #include <plot_def.h>      Symbols used by the PLT interfaces

.VERSION     1.0     18-Aug-1993   FORTRAN --> ANSI-C    RvH

 090422		last modif
------------------------------------------------------------*/
/*
 * Define _POSIX_SOURCE to indicate
 * that this is a POSIX program
 */
#define  _POSIX_SOURCE 1

/*
 * definition of the used functions in this module
 */
#include <stdio.h>

#include <midas_def.h>

/*
 * define some macros and constants
 */
#include <plot_def.h>

#define BAR		32
#define MAXDEG		100

/*
 * declaration of private functions used in this module
 */
/*++++++++++++++++++++++++++++++
.IDENTifer   SORT2
.PURPOSE     Sort string of values into ascending sequence of values
     input:  int    n      dimension of arrays xval and yval
  in/output  float  xval[] array to be sorted  
             float  yval[] array to be sorted like the first array
------------------------------*/
#ifdef __STDC__
      static void SORT2( int n, float *xval, float *yval )
#else
      static void SORT2( n, xval, yval )
      int   n;
      float *xval, *yval;
#endif
{
register int indx;

if ( n < 2 ) return;

indx = n - 1;
do { register int jj, ii = -1;

     for ( jj = 0; jj < indx; jj++ )
         { if ( xval[jj] > xval[jj+1] )
              { float xtemp = xval[jj],
                      ytemp = yval[jj];

                xval[jj]   = xval[jj+1];
                yval[jj]   = yval[jj+1];
                xval[jj+1] = xtemp;
                yval[jj+1] = ytemp;
                ii = jj;
              }
         }
     indx = ii;
   } 
while ( indx != -1 );
}

/*++++++++++++++++++++++++++++++
.IDENTifer   ALINT
.PURPOSE     linear interpolation over a range in values
     input:  float *xval  values along the X-axis
             float *yval  values along the Y-axis
             float  xarg  X-value of the requested return value
             int    str   first data item which may be used
             int    last  last data item which may be used
.RETURNS     Y-value at X position: xarg
------------------------------*/
#ifdef __STDC__
      static float ALINT( float *xval, float *yval, 
                          float xarg, int str, int last )
#else
      static float ALINT( xval, yval, xarg, str, last )
      int   str, last;
      float *xval, *yval, xarg;
#endif
{
int     pix[2];
double  dx[2], dy[2];

/*
 * select the effective interval
 */
pix[1] = str;
while ( xval[pix[1]] < xarg && pix[1] < last ) pix[1]++;

if ( pix[1] == str ) pix[1] += 1;
pix[0] = pix[1] - 1;

/*
 * and do the interpolation
 */
dx[0] = (double) xval[pix[0]];
dx[1] = (double) xval[pix[1]];
dy[0] = (double) yval[pix[0]];
dy[1] = (double) yval[pix[1]];
return (float) dy[0] + (dy[1] - dy[0]) * (xarg - dx[0]) / (dx[1] - dx[0]);
}

/*++++++++++++++++++++++++++++++
.IDENTifer   AITKEN
.PURPOSE     Aitken interpolation
     input:  float *xval  values along the X-axis
             float *yval  values along the Y-axis
             float  xarg  X-value of the requested return value
             int    str   first data item which may be used
             int    last  last data item which may be used
             int    ideg  degree of the polynomial interpolation
.RETURNS     Y-value at X position: xarg
------------------------------*/
#ifdef __STDC__
      static float AITKEN( float *xval, float *yval, 
                           float xarg, int str, int last, int ideg )
#else
      static float AITKEN( xval, yval, xarg, str, last, ideg )
      int   str, last, ideg;
      float *xval, *yval, xarg;
#endif
{
int    id, ii, jj, pix[2];
double dx[MAXDEG], dy[MAXDEG];

ii = str + 1;
while( (xarg >= xval[ii-1] && xarg < xval[ii]) && (ii++ < last) );


pix[0] = MYMAX( str, ii - ideg + 1 );
pix[1] = pix[0] + ideg;
if ( pix[1] > last )
   { pix[1] = last;
     pix[0] = pix[1] - ideg;
   }

for ( id = 0, ii = pix[0]; ii <= pix[1]; id++, ii++ )
    { dx[id] = xval[ii];
      dy[id] = yval[ii];
    }

for ( ii = 0; ii < id; ii++ )
    { for ( jj = ii; jj <= id; jj++ )
          { dy[jj+1] = dy[ii] + (xarg - dx[ii]) * 
                       (dy[jj+1] - dy[ii]) / (dx[jj+1] - dx[ii]);
          }
    }
return (float) dy[id+1];
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++
 *
 * Here starts the code of the main routine
 */
void PLMODF(cpntr, image, npix, start, step, ncur, ndeg, binmode, go_on, ibar)
char   *cpntr;
float  *image;
int    *npix;
double *start, *step;
int    ncur, ndeg, binmode, *go_on, *ibar;
             
{
int    ii, indx, key, mnpix, mxpix, nc, nnpix, pixval, pix[2];
float  *p_row;
float  *xval, *yval, *xpos;
float  xv = 0.0,
       yv = 0.0;

xval = (float *) osmmget( ncur * sizeof( float ));
yval = (float *) osmmget( ncur * sizeof( float ));

indx  = (int) (*(image+2) - 1) * *npix;
p_row = (float *) cpntr + indx;

/*
 * set the coordinate system to USER
 */
AG_SSET( "user" );

mnpix = (int) MYMIN( *image, *(image+1) )-1;
mxpix = (int) MYMAX( *image, *(image+1) )-1;

do { nc = 0;
     do { AG_VLOC( &xv, &yv, &key, &pixval );
          if ( key == BAR )
             { if ( *ibar == 0 )
                  *ibar = 1;
               else
                  *go_on = FALSE;
             }
          else
             { *ibar = 0;
               xval[nc] = xv;
               yval[nc] = yv;
               AG_GPLM( &xv, &yv, 1, 4 ); 
             }
          nc++;
        }
     while ( nc < ncur && key != BAR );

/*
 * sort the given positions and determine the range effective for change
 */
     if ( key != BAR )
        { SORT2( ncur, xval, yval );

          pix[0] = (int) ((xval[0] - start[0])/step[0] + 0.5);
          if ( mnpix > pix[0]) pix[0] = mnpix;

          pix[1] = (int)( (xval[ncur-1] - start[0])/step[0] + 0.5);
          if ( mxpix < pix[1] ) pix[1] = mxpix;

          ii = pix[1] - pix[0];		/* abs(pix[1] - pix[0]) + 1 */
          if (ii >= 0)
             nnpix = ii + 1;
          else
             nnpix = 1 - ii;
/*
 * we calculate the x position one before and one after the new values
 */
          xpos = (float *) osmmget( nnpix * sizeof( float ));
          if (step[0] > 0) 
             for ( ii = 0; ii < nnpix; ii++ )
                 xpos[ii] = (float) (start[0] + (pix[0]+ii) * step[0]);  
          else
             for ( ii = 0; ii < nnpix; ii++ )
                 xpos[ii] = (float) (start[0] + (pix[1]+ii) * step[0]);  
/*
 * we interpolate between the given values
 */
          for ( ii = 0; ii < nnpix; ii++ )
              { if ( ndeg < 2 )
                   if (step[0] > 0) 
                      *(p_row+pix[0]+ii) = ALINT( xval, yval, xpos[ii], 
                                                  0, ncur-1 );
                   else
                      *(p_row+pix[1]+ii) = ALINT( xval, yval, xpos[ii], 
                                                  0, ncur-1 ); 
                else
                   if (step[0] > 0) 
                      *(p_row+pix[0]+ii) = AITKEN( xval, yval, xpos[ii], 
                                                   0, ncur-1, ndeg );
                   else
                      *(p_row+pix[1]+ii) = AITKEN( xval, yval, xpos[ii], 
                                                   0, ncur-1, ndeg );
              }
/*
 * and draw the line nicely connected with the old data
 */
          if (step[0] > 0) 
             PCDATA( 0, 1, binmode, xpos, p_row+pix[0], 0.0, nnpix );
          else
             PCDATA( 0, 1, binmode, xpos, p_row+pix[1], 0.0, nnpix );
          (void) osmmfree( (char *) xpos );
        }
   }
while ( *go_on && *ibar == 0 );

(void) osmmfree( (char *) xval );
(void) osmmfree( (char *) yval );
return;
}
