/*===========================================================================
  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
===========================================================================*/

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.IDENTIFIER  TRACE1D
.LANGUAGE    C
.AUTHOR      K. Banse, R.M. van Hees	IPG-ESO Garching
.KEYWORDS    Image Display, graphic trace
.PURPOSE     display (in graphics or overlay) a interactively extracted
             1-D trace and copy it to a file
.ALGORITHM   use one cursor to define the line we are working on 
.INPUT/OUTPUT
  call as    TRACE1D( action, maxsize, imf, stepln, outfra );

  input:
         char   *action :	'1' for 1-dim trace
                                '3' for 1-dim row trace
                                '4' for 1-dim column trace
         int    maxsize :	maximum size of the trace
         int    imf     :	id of the input image
         double stepln  :	step size along the trace
         char   *outfra :	name of the trace

.RETURNS     nothing
.ENVIRONment MIDAS
             #include <midas_def.h>   Prototypes for MIDAS interfaces
             #include <idinumd.h>     Global variables for DISPLAY interfaces

.VERSIONS    1.00       940630  converted to C from TRACE.FOR, R.M.van Hees

 090706		last modif
------------------------------------------------------------*/

/* Define _POSIX_SOURCE to indicate that this is a POSIX program */

#define  _POSIX_SOURCE 1

#include <stdio.h>
#include <stddef.h>		/* needed for agl.h */
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <midas_def.h>
#include <idinumd.h>
#include <proto_II.h>

#ifndef TRUE
#define TRUE            1
#define FALSE           0
#endif

#ifndef PI
#define PI		3.14159265358979325e0
#endif
#define DEG2RAD		(PI / 180.0)
#define SMALLVAL        1.e-12


#define RowTRACE	0                     /* tracefl: a horizontal trace */
#define ColTRACE	1                     /*          a vertical trace   */
#define RupTRACE	2                     /*          <= 45 deg. trace   */
#define CupTRACE	3                     /*          >  45 deg. trace   */

/* for Ccursin */

#define CFORM		8                     /* cursor shape (= x-hair)     */
#define COLOR		2                     /* cursor color                */
#define POLL_POS	2                     /* continuous cursor position  */
#define ENTR_POS	1                     /* cursor position after ENTER */

#define MYMIN(a,b)      ((a) > (b) ? (b) : (a))
#define MYMAX(a,b)      ((a) < (b) ? (b) : (a))

/* Global variables, they are set in TRACE1D and not to be changed 
   in one of the static functions!                                 */

static char   ident[33], cunit[49];
static int    npix[2];
static int    planoff = 0, ffelem = 1;

void GetData();


/*

*/

/*++++++++++++++++++++++++++++++
.IDENTIFIER  GET_ANGLE
.PURPOSE     return angle in degrees
.INPUT/OUTPUT
  input:
             float *area  :	x_min, x_max, y_min, y_max of trace 
                                (in world coordinates)

.RETURNS     nothing
------------------------------*/
#ifdef __STDC__
      static double GET_ANGLE( float *area )
#else
      static double GET_ANGLE( area )
      float *area;
#endif

{
double dx, dy;

dx = area[1] - area[0];
dy = area[3] - area[2];

if (fabs(dy) < SMALLVAL)
   return 90.0;
else
   return atan2( dy, dx ) / DEG2RAD; 
}

/*

*/

/*++++++++++++++++++++++++++++++
.IDENTIFIER  EXTEND_TR(ace)
.PURPOSE     extend trace across whole image, but not outside display window
.INPUT/OUTPUT
  input:
             int  tr_flag  :    type of trace
             int  tr_rm    :	slope of the trace
  in/output:
             int  *disp    :	x_min, x_max, y_min, y_max of trace 
                                (in channel coordinates)

.RETURNS     nothing
------------------------------*/
#ifdef __STDC__
      static void EXTEND_TR( int tr_flag, double tr_rm, int *disp )
#else
      static void EXTEND_TR( tr_flag, tr_rm, disp )
      int    tr_flag, *disp;
      double tr_rm;
#endif

{
int idum, fsx, fsy, flx, fly;


fsx = fsy = 0;			/* fsx,fsy,flx,fly = corners of display */
Sc2ch(1,&fsx,&fsy);
fsx = MYMAX(fsx,SSPX);		/* SSPX, SSPY already in image channel */
fsy = MYMAX(fsy,SSPY);

flx = QDSZX - 1;
fly = QDSZY - 1;
Sc2ch(1,&flx,&fly);
flx = MYMIN(flx,(SSPX + NSX - 1));
fly = MYMIN(fly,(SSPY + NSY - 1));
     
if ( tr_flag == RowTRACE )
   {
   disp[0] = fsx;
   disp[1] = flx;
   }

else if ( tr_flag == ColTRACE )
   {
   disp[2] = fsy;
   disp[3] = fly;
   }

else
   {					/* find 'entering' intersection */
   idum = CGN_NINT( tr_rm * (fsx - disp[0])) + disp[2];
   if ( fsy > idum )
      {
      disp[0] = CGN_NINT( (fsy - disp[2])/tr_rm ) + disp[0];
      disp[2] = fsy;
      }
   else if ( fly < idum )
      {
      disp[0] = CGN_NINT( (fly - disp[2])/tr_rm ) + disp[0];
      disp[2] = fly;
      }
   else
      {
      disp[0] = fsx;
      disp[2] = idum;
      }

					/* find 'leaving' intersection */
   idum = CGN_NINT( tr_rm * (flx - disp[0]) ) + disp[2];
   if ( fsy > idum )
      {
      disp[1] = CGN_NINT( (fsy - disp[2])/tr_rm ) + disp[0];
      disp[3] = fsy;
      }
   else if ( fly < idum )
      {
      disp[1] = CGN_NINT( (fly - disp[2])/tr_rm ) + disp[0];
      disp[3] = fly;
      }
   else
      {
      disp[1] = flx;
      disp[3] = idum;
      }
   }
}

/*

*/

/*++++++++++++++++++++++++++++++
.IDENTIFIER  CONV_TR
.PURPOSE     convert display coordinates to image and world coordinates
.INPUT/OUTPUT
  input:
             int    tr_flag :		type of trace
             int    tr_rm   :		slope of the trace
             char   *cutfl  :		extend the trace or not
             int    *disp   :		x_min, x_max, y_min, y_max of trace 
                                        (in channel coordinates)
  output:
             float  *image  :		size in PIXEL coordinates
             float  *area   :		size in WORLD coordinates

.RETURNS     error status: -1 Could not do the pixel conversion
------------------------------*/
#ifdef __STDC__
      static int CONV_TR(int tr_flag,double tr_rm,char *cutfl, 
                                       int *disp,float *image,float *area)
#else
      static int CONV_TR(tr_flag,tr_rm,cutfl,disp,image,area)
      int    tr_flag, *disp;
      char   *cutfl;
      float  *image, *area;
      double tr_rm;
#endif

{
double  dd1[4], dd2[4], dd3[4];         /* synchronize with fp2wc */



Sc2ch(1,disp,disp+2);
*disp = MYMAX(*disp,SSPX);
*disp = MYMIN(*disp,(SSPX+NSX-1));
*(disp+2) = MYMAX(*(disp+2),SSPY);
*(disp+2) = MYMIN(*(disp+2),(SSPY+NSY-1));

Sc2ch(1,disp+1,disp+3);
*(disp+1) = MYMAX(*(disp+1),SSPX);
*(disp+1) = MYMIN(*(disp+1),(SSPX+NSX-1));
*(disp+3) = MYMAX(*(disp+3),SSPY);
*(disp+3) = MYMIN(*(disp+3),(SSPY+NSY-1));

if ( *cutfl == 'N' ) EXTEND_TR(tr_flag,tr_rm,disp);


/* convert intersection points from image memory pixels 
   to real pixels & w.c.                                  */

dd1[0] = (double)disp[0];
dd1[1] = (double)disp[2];
dd1[2] = ZPLANE;

if ( Pixconv("IRW",0,dd1,dd2,dd3) != 0 ) return (-1);
image[0] = (float)dd2[0];
image[2] = (float)dd2[1];
area[0] = (float)dd3[0];
area[2] = (float)dd3[1];


dd1[0] = (double)disp[1];
dd1[1] = (double)disp[3];
if ( Pixconv("IRW",0,dd1,dd2,dd3) != 0 ) return (-1);
image[1] = (float)dd2[0];
image[3] = (float)dd2[1];
area[1] = (float)dd3[0];
area[3] = (float)dd3[1];

return (0);
}

/*

*/

/*++++++++++++++++++++++++++++++
.IDENTIFIER  EXTR_DATA
.PURPOSE     extract data of trace from image
.INPUT/OUTPUT
  input:
             int    mxsize    :		maximum size of a chunk
             int    imf       :		file id of data frame
             float  *image    :		xstart,xend,ystart,yend, in pixel space
             double pxstep    :		step size
  output:
             int    *npnts    :         actual no. of pixels in trace
             float  **p_trace :		pointer to the data of the trace
             float  *cuts     :		min & max found in the trace

.RETURNS     nothing
------------------------------*/
#ifdef __STDC__
      static void EXTR_DATA( int mxsize, int imf, float *image, double pxstep,
                             int *npnts, float **p_trace, float *cuts )
#else
      static void EXTR_DATA( mxsize, imf, image, pxstep, npnts, p_trace, cuts )
      int    mxsize, *npnts, imf;
      float  *image, **p_trace, *cuts;
      double pxstep;
#endif

{
register int ii;
int   actvals;
static int   img_size, map_all, max_pnt = 10000, init = TRUE;

float  *pntrX, *pntrY, *p_img, xa, ya, xb, yb;
static float *pntrL;

char  output[82];
static char  *err_mem  = "EXTR_DATA: line longer than %-d points...";



if ( init )
   { 
   init = FALSE;
   img_size = *npix * npix[1];
   if ( img_size <= mxsize )
      map_all = TRUE;
   else
      map_all = FALSE;
}

else
   (void) free( (char *) pntrL );

xa = image[0];
ya = image[2];
xb = image[1];
yb = image[3];


/* get no. of pixels and the indices (in pixel space) */

get_nopix:
   pntrX = (float *) malloc((size_t)(max_pnt * sizeof(float)));
   pntrY = (float *) malloc((size_t)(max_pnt * sizeof(float)));

if ((*npnts = Cpixlin(xa,ya,xb,yb,pxstep,max_pnt,pntrX,pntrY)) == max_pnt)
   {
   (void) free((char *) pntrX);
   (void) free((char *) pntrY);

   max_pnt += 10000;			/* increase size */
   if (max_pnt > 1000000)
      {
      (void) sprintf(output,err_mem,max_pnt);
      SCETER(1,output);
      }
   else
      goto get_nopix;
   }


pntrL = (float *) malloc((size_t)((*npnts) * sizeof(float)));
*p_trace = pntrL;


/*
   Now we want to extract enough data from the image to collect the data
   of the line. There are 3 possibilities:
   - the image is small (<= MAXSIZE) --> we read it and keep it in memory
   - the image is large (>  MAXSIZE), but the number of points needed for
      the line is small (<= MAXSIZE) --> we read what we need and release it
   - the image is large (>  MAXSIZE) and the number of points needed for 
      the line is large (>  MAXSIZE) --> we read chunks, collect from each
      chunk the data for the line and release memory after use      */

if ( map_all )
   {
   p_img = (float *) malloc((size_t)(img_size * sizeof(float)));

   SCFGET(imf,ffelem,img_size,&actvals,(char *) p_img);
   Czima(p_img,npix,pntrX,pntrY,*npnts,pntrL,cuts+2, cuts+3);
   }

else
   {
   int   offX, offY, rpix[2];

   rpix[0] = CGN_NINT(fabs(xa - xb)) + 1;
   rpix[1] = CGN_NINT(fabs(ya - yb)) + 1;
   p_img = (float *) malloc((size_t)(mxsize * sizeof(float)));

   if ((img_size = *npix * rpix[1]) > mxsize)		/* take full lines */
      {
      int   first, npoint, offL, img_max;
      float cutvls[2], frame[4], ln_last = MYMAX(ya,yb);

      img_max = mxsize/(*npix);		/* max. possible rows */

      offL = 0;
      cuts[2] = (float) 1.0e+38;
      cuts[3] = (float) -1.0e+38;

      frame[0] = MYMIN(xa,xb);
      frame[1] = MYMAX(xa,xb);
      frame[2] = MYMIN(ya,yb);

      offX = CGN_NINT( frame[0] ) - 1;
      for (ii=0; ii<*npnts; ii++) pntrX[ii] -= offX;

      while (frame[2] <= ln_last)
         {
         frame[3] = MYMIN( frame[2] + img_max - 1, ln_last );
         rpix[1]  = CGN_NINT( frame[3] - frame[2] ) + 1;

         GetData(imf,mxsize,npix,frame,ffelem,0,p_img);

/* Determine number of points in subimage which are falling within "frame"
   and offset in array pntrL of these points in array "pntrL" */

         first = TRUE;
         npoint = 0;
         offY = CGN_NINT(frame[2]) - 1;
         for (ii=0; ii<*npnts; ii++)
            {
            if ( pntrY[ii] >= frame[2] && pntrY[ii] < frame[3] )
               { 
               if ( first )
                  {
                  first = FALSE;
                  offL = ii;
                  }
               npoint++;
               pntrY[ii] -= offY;
               }
            }
	 Czima(p_img,rpix,pntrX+offL,pntrY+offL,npoint,pntrL+offL,cutvls,
	       cutvls+1);

/* Determine minima & maxima */

         if ( cuts[2] > cutvls[0] ) cuts[2] = cutvls[0];
         if ( cuts[3] < cutvls[1] ) cuts[3] = cutvls[1];
         frame[2] = frame[3] + 1;
         }
      }

   else
      {
      GetData(imf,mxsize,npix,image,ffelem,0,p_img);

      offX = CGN_NINT( MYMIN(xa,xb)) - 1;
      offY = CGN_NINT( MYMIN(ya,yb)) - 1;
      for ( ii = 0; ii < *npnts; ii++ )
         {
         pntrX[ii] -= offX;
         pntrY[ii] -= offY;
         }
      Czima( p_img, rpix, pntrX, pntrY, *npnts, pntrL, cuts+2, cuts+3 );
      }
   }

(void) free((char *) pntrX);
(void) free((char *) pntrY);
(void) free((char *) p_img);

}

/*

*/

/*++++++++++++++++++++++++++++++
.IDENTIFIER  ERASE_TR(ace)
.PURPOSE     Erase old trace in image display
.INPUT/OUTPUT
  input:
             float  *cuts   :	min & max of trace
             int    npnt    :	dimension of trace
             float  *pntrT  :	pointer to data of trace

.RETURNS     nothing
------------------------------*/
#ifdef __STDC__
      static void ERASE_TR( int *disp, float *cuts, 
                                          int npnt, float *pntrT )
#else
      static void ERASE_TR( disp, cuts, npnt, pntrT )
      int    *disp, npnt;
      float  *cuts, *pntrT;
#endif

{
int icen[2];

static int   initD    = TRUE,
             scale[2] = { 1, 1 },
             iaux[4];
static float angle;


if ( initD )          /* initialise for DISPLAY */
   {
   initD = FALSE;
   iaux[0] = 1;                            /* used by DRIMG: y_start  */
   iaux[1] = NSX;                                         /* y_end    */
   iaux[2] = 0;                                           /* y_offset */
   iaux[3] = 0;                                  /* maximum intensity */
   }

if ( IDINUM == 11 )
   {
   (void) IIMCMY_C( QDSPNO, &QOVCH, 1, 0 );
   (void) IIGPLY_C( QDSPNO, QOVCH, disp, disp+2, 2, 99, 1 );
   }
else
   {
   icen[0] = 1 + npnt / 2;        /* graph in center of display windo */
   icen[1] = QDSZX / 2;
   DRIMG_C(QDSPNO,QOVCH,TRUE,iaux,pntrT,npnt,icen,cuts+2,scale,angle);
   }
}

/*

*/

/*++++++++++++++++++++++++++++++
.IDENTIFIER  DRAW_TR(ace)
.PURPOSE     Draw the trace on image or graphics display
.INPUT/OUTPUT
  input:
             int    cno :	1,2 for no. of cursors
             int    tr_flag :	type of trace
             char   *plotfl :	to plot or not to plot
             struct Point cpos[2]:	cursor positions in screen coords
             float  *image  :	start & end of trace (in pixel coord.)
             float  *area   :	start & end of trace (in world coord.)
             float  *cuts   :	min & max of trace
             int    npnt    :	dimension of trace
             float  *pntrT  :	pointer to data of trace

.RETURNS     nothing
------------------------------*/
#ifdef __STDC__
static void DRAW_TR(int cno, int tr_flag, char *plotfl,
		    struct Point cpos[2], float *image, 
                    float *area, float *cuts, int npnt, float *pntrT )
#else
static void DRAW_TR(cno,tr_flag,plotfl,cpos,image,area,cuts,npnt,pntrT)
char   *plotfl;
int    cno, tr_flag, npnt;
float  *image, *area, *cuts, *pntrT;
struct Point cpos[2];
#endif

{
register int ii;

int    actvals, icen[2];

float  rdum[4], rdumm[4], stepx, *xdata, wcfram[8];

char   bin[3], cbuff[81];



/* Initialized and saved variables */

static char  *metafl = "trace1d.plt",
             *label[4];
static int   initD = TRUE,
             scale[2] = { 1, 1 },
             initP = TRUE,                            /* initialisation flag */
             access =  0,                                /* parameter PCOPEN */
             plmode = -1,                                /* parameter PCOPEN */
             stype, ltype, binmod, iaux[4];
static float angle = 0.0,                             /* no angle in DRIMG_C */
             offset = 0.0;                            /* no y-offs in PCDATA */



if (*plotfl == 'D')
   {
   if (initD)          /* initialize for DISPLAY */
      {
      initD = FALSE;
      iaux[0] = 1;                            /* used by DRIMG: y_start  */
      iaux[1] = NSX;                                         /* y_end    */
      iaux[2] = 0;                                           /* y_offset */
      iaux[3] = 255;                                /* maximum intensity */
      }


/* graph in center of display window */

   icen[0] = 1 + (npnt/2);
   icen[1] = QDSZX / 2;
   DRIMG_C(QDSPNO,QOVCH,TRUE,iaux,pntrT,npnt,icen,cuts+2,scale,angle);
   }

else if (*plotfl == 'P')
   {
   if (initP)      /* get symbol type, line type, binmode & write labels */
      {
      initP = FALSE;
      PCKRDI( "STYPE", 1, &actvals, &stype );
      PCKRDI( "LTYPE", 1, &actvals, &ltype );
      PCKRDC( "BINMO", 4, &actvals, bin );
      binmod = (strncmp( bin, "ON", 2 ) == 0) ? 1 : 0;

      for ( ii = 0; ii < 4; ii++ ) label[ii] = malloc((size_t)84);

      (void) strcpy(label[0],"Position(");
      (void) strcpy(label[1],"Position(");
      (void) strcpy(label[2],"Pixel value(");
      (void) strcpy(label[3],"Frame: ");
      if ( (int)strlen(cunit) > 32 )
         (void) strncat( label[1], cunit+32, 16 );
      if ( (int)strlen(cunit) > 16 )
         (void) strncat( label[0], cunit+16, 16 );
      if ( (int)strlen(cunit) > 0 )
         (void) strncat( label[2], cunit, 16 );
      for ( ii = 0; ii < 3; ii++ )
         {
         (void) strcat(label[ii],")");
         LABSTR( label[ii] );
         }
      (void) strcat(label[3],dzmemc);
      }
   PCKWRR( "SCALE", 0, rdum );                      /* scaling to default */
   PCKWRR( "OFFSET", 0, rdum );                      /* offset to default */


/* collect data */

   xdata = (float *) malloc((size_t)(npnt * sizeof(float)));
   if ( tr_flag == ColTRACE || tr_flag == CupTRACE )
      {
      wcfram[0] = area[2];
      wcfram[1] = area[3];
      }
   else
      {
      wcfram[0] = area[0];
      wcfram[1] = area[1];
      }

   *xdata = *wcfram;
   stepx  = (wcfram[1] - wcfram[0]) / (npnt - 1);
   for ( ii = 1; ii < npnt; ii++ ) xdata[ii] = *xdata + ii * stepx;

   wcfram[4] = cuts[2];
   wcfram[5] = cuts[3];
   wcfram[2] = wcfram[3] = wcfram[6] = wcfram[7] = 0.0;

   /* Calculate small and big tickmarks, set world and pixel coordinate box,
      and set up the graphics device according to MIDAS settings    */

   GETFRM( "AUTO", wcfram );
   PCKWRR( "XWNDL", 4, wcfram );
   GETFRM( "AUTO", wcfram+4 );
   PCKWRR( "YWNDL", 4, wcfram+4 );
   PCKWRR( "PIXEL", 4, image );
   PCOPEN( " ", metafl, access, &plmode );

   /* plot the data and draw a frame (if requested) */

   PCDATA( stype, ltype, binmod, xdata, pntrT, offset, npnt );

   if (cno > 0)
      {
      double dd1[4], dd2[4], dd3[4];

      dd1[0] = (double) cpos[0].px;		/* screen coords of cursor 0 */
      dd1[1] = (double) cpos[0].py;
      (void) Pixconv("SRW",0,dd1,dd2,dd3);
      if ( tr_flag == CupTRACE || tr_flag == ColTRACE )
         ii = 1;
      else
         ii = 0;
      rdum[0] = (float) dd3[ii];
      rdum[1] = rdum[0];
      rdum[2] = (float) dd2[0];			/* save frame pixels */
      rdum[3] = (float) dd2[1];
      if (cno == 2)
         {
         dd1[0] = (double) cpos[1].px;		/* screen coords of cursor 0 */
         dd1[1] = (double) cpos[1].py;
         (void) Pixconv("SRW",0,dd1,dd2,dd3);
         if ( tr_flag == CupTRACE || tr_flag == ColTRACE )
            ii = 1;
         else
            ii = 0;
         rdumm[0] = (float) dd3[ii];
         rdumm[1] = rdumm[0];
         }
      }

   if ( plmode > 0 )
      {
      if ( tr_flag == RowTRACE || tr_flag == RupTRACE )
         PCFRAM(wcfram,wcfram+4,label[0],label[2]);
      else
         PCFRAM(wcfram,wcfram+4,label[1],label[2]);
      if (cno > 0)
         {
         PCKRDR("YWNDL",2,&actvals,&rdum[2]);	/* get y-min, max of plot */
         PCDATA(0,5,0,rdum,&rdum[2],0.,2);
         if (cno == 2)
            PCDATA(0,5,0,rdumm,&rdum[2],0.,2);	/* no typing error: rdum[2] */
         }

      PLBDFI(plmode,dzmemc,ident,image);
      if ( plmode == 1 )
         {
         if ( tr_flag == RowTRACE )
            (void) sprintf( cbuff, "Row: # %-.0f", image[2] );
         else if ( tr_flag == ColTRACE )
            (void) sprintf( cbuff, "Column: # %-.0f", image[0] );
         else 
            (void) sprintf( cbuff, 
                            "Trace from: (%-.0f,%-.0f), angle: %-.2f", 
                            image[0], image[2], GET_ANGLE( area ));
         PLIDEN( plmode, label[3], cbuff );
         }
      }

   /* close the meta file (opened in PCOPEN) */

   AG_MCLS();
   (void) free( (char *) xdata );
   }
}

/*

*/

/*++++++++++++++++++++++++++++++
.IDENTIFIER  WR_FRAME
.PURPOSE     write data of trace into output file
.INPUT/OUTPUT
  input:
             int    tr_flag :	type of trace
             char   *outfra :	name of the output file
             float  *image  :	start & end of trace (in pixel coord.)
             float  *area   :	start & end of trace (in world coord.)
             double stepT   :	stepsize of trace
             float  *cuts   :	min & max of trace
             int    npnt    :	dimension of trace
             float  *pntrT  :	pointer to data of trace

.RETURNS     nothing
------------------------------*/
#ifdef __STDC__
      static void WR_FRAME( int tr_flag, char *outfra, float *image,
                           float *area, double stepT, float *cuts, 
			   int npnt, float *pntrT )
#else
      static void WR_FRAME(tr_flag,outfra,image,area,stepT,cuts,npnt,pntrT)
      char   *outfra;
      int    tr_flag, npnt;
      float  *image, *area, *cuts, *pntrT;
      double stepT;
#endif

{
int    imno, unit, pixo[4];
char   output[84];

static char 
*rowhis= "row trace of: %s, from frame pixels %-.0f,%-.0f to %-.0f,%-.0f",
*colhis= "Column trace of: %s, from frame pixels %-.0f,%-.0f to %-.0f,%-.0f",
*trchis= "trace of: %s, from frame pixels %-.0f,%-.0f to %-.0f,%-.0f";




if ( *outfra != '+' )
   {
   char *cpntr;
   double startT, endT;

   if ( tr_flag == ColTRACE || tr_flag == CupTRACE )
      {
      startT = area[2];
      endT = area[3];
      }
   else
      {
      startT = area[0];
      endT = area[1];
      }
   if (endT < startT)
      {
      if (stepT > 0.) stepT = -stepT;
      }
   else
      {
      if (stepT < 0.) stepT = -stepT;
      }
   (void) SCIPUT(outfra,D_R4_FORMAT,F_O_MODE,F_IMA_TYPE,1,&npnt, 
                   &startT,&stepT,ident,cunit,&cpntr,&imno);
   Ccopyf(pntrT,(float *) cpntr,npnt);

   (void) strcpy(output,"min, max, low_cut, high_cut for display/plot");
   (void) SCDHWR(imno,"LHCUTS",cuts,1,4,&unit,output);

   (void) sprintf(output,"frame %s created",outfra);
   SCTPUT(output);
     
   pixo[0] = image[0];
   pixo[1] = image[2];
   pixo[2] = image[1];
   pixo[3] = image[3];
   (void) strcpy(output,"start, end pixels of trace in original frame");
   (void) SCDHWI(imno,"START_END_TRACEPIX",pixo,1,4,&unit,output);

   if (tr_flag == RowTRACE)
      (void) sprintf(output,rowhis,dzmemc,image[0],image[2],image[1],image[3]);
   else if (tr_flag == ColTRACE)
      (void) sprintf(output,colhis,dzmemc,image[0],image[2],image[1],image[3]);
   else
      (void) sprintf(output,trchis,dzmemc,image[0],image[2],image[1],image[3]);

   (void) SCDWRC(imno,"HISTORY",1,output,1,80,&unit);
   SCTPUT(output);

   (void) SCFCLO(imno);
   }
}

/*

*/

void TRACE1D( action, maxsize, imf, stepln, outfra )
char   *action, *outfra;
int    maxsize, imf;
double stepln;

{
register int nn;

int    actvals, enter, iter, knul, ncurs, npnts, tr_flag, unit, disp[4];
int    cursex, idx, idy, cno, zoomwn, odisp[4];

float   fixpts[4];
float  *p_trace, cuts[4], image[4], area[4];

double step[2], dd1[4], dd2[4], dd3[4];
double rm, pxstep, stepT;

char   cutfl[2], plotfl[2], cbuff[81], output[81];

struct Point cpos[2];

int    first = 1, got_frame = 0;
static int    draw, erase_flag, old_disp[4];
static double abs_rm = 1.0;

static char   *err_conv =
   "TRACE1D - FATAL: can not convert given screen coordinates",
              *err_step = 
   "TRACE1D - FATAL: invalid stepsize: %-.6g for trace entered",
              *war_plfl = 
   "TRACE1D - WARNING: Invalid plot flag, reset to D(isplay)";

static char 
  *rowmes = "Min, Max = %-.6g, %-.6g    at y-pixel #%-.0f",
  *colmes = "Min, Max = %-.6g, %-.6g    at x-pixel #%-.0f",
  *trcmes = "Min, Max = %-.6g, %-.6g    no_of_pixels = %-d      ";
            


if ( IDINUM == 11 )                         /* flags for IDI interfaces */
   {
   erase_flag = 99;
   draw  = 99;
   }
else
   {
   erase_flag = 0;
   draw  = 200;
   }

npnts = tr_flag = 0;
p_trace = (float *) 0;
stepT = 0.0;

for (nn=0; nn<4; nn++) old_disp[nn] = -1;


/* Read the input image descriptors, except cuts these are global! */

(void) SCDRDI(imf,"NPIX",1,2,&actvals,npix,&unit,&knul);
(void) SCDRDD(imf,"STEP",1,2,&actvals,step,&unit,&knul);
(void) SCDGETC(imf,"IDENT",1,32,&actvals,ident);
(void) SCDGETC(imf,"CUNIT",1,48,&actvals,cunit);
(void) SCDRDR(imf,"LHCUTS",1,4,&actvals,cuts,&unit,&knul);
if (ZPLANE != 0)			/* 3-dim frame was loaded */
   {
   planoff = (ZPLANE-1)*npix[0]*npix[1];
   dd1[2] = ZPLANE;
   }
else
   planoff = 0;
ffelem = planoff + 1;
if (Pixconv("INIT",imf,dd1,dd2,dd3) > 0)	/* init wc conversion */
   SCETER(69,"initialization of world coord. conversion failed ...");


/* Set flags */

(void) SCKGETC( "DEFAULT", 1, 2, &actvals, cbuff );
CGN_UPSTR( cbuff );                         /* assure we have upper-case ... */
(void) strncpy( plotfl, cbuff, 1 );
if ( *plotfl != 'N' && *plotfl != 'D' && *plotfl != 'P' )     
   {
   SCTPUT(war_plfl);
   (void) strcpy(plotfl,"D");
   }

if ( *action == '1' )
   {
   ncurs = 3;
   (void) strncpy(cutfl,cbuff+1,1);
   tr_flag = RupTRACE;                          /* default can also be Cup */
   }

else     
   {
   ncurs = 0;
   (void) strcpy(cutfl,"N");
   if ( *action == '3' )
      tr_flag = RowTRACE;
   else if ( *action == '4' )
      tr_flag = ColTRACE;
   else
      SCETER(1,"TRACE1D: unknown action flag...");
   }


/* Read keyword DAZIN, it contains zoom factor if we use zoom window */

(void) SCKRDI("DAZIN",1,1,&actvals,&zoomwn,&unit,&knul);


/* check, if we use fixed "cursor positions" for repeatable extractions */

(void) SCKRDR("INPUTR",1,4,&actvals,fixpts,&unit,&knul);
if (fixpts[0] > 0.)
   {
   cpos[0].px = fixpts[0];
   cpos[0].py = fixpts[1];
   cpos[1].px = fixpts[2];
   cpos[1].py = fixpts[3];
   enter = TRUE;
   cursex = 1;				/* force to stop */
   goto swap_points;
   }


CURS_SETUP(ncurs,CFORM,COLOR);		/* setup the cursors */
iter = 1;


/* get cursor interrupts + update graph accordingly */

get_cursor:
cursex =  GET_CPOS(zoomwn,action,POLL_POS,ncurs,&iter,&enter,cpos);
if (cursex == 0)
   {
   if ( tr_flag == RowTRACE )
      {
      cpos[1].px = ( cpos->px <= QDSZX-2 ) ? cpos->px+1 : cpos->px-1;
      cpos[1].py = cpos->py;
      }
   else if ( tr_flag == ColTRACE )
      {
      cpos[1].px = cpos->px;
      cpos[1].py = ( cpos->py <= QDSZY-2 ) ? cpos->py+1 : cpos->py-1;
      }

swap_points:
   if ( cpos->px > cpos[1].px )
      SWAP_PNT( 0, 1, cpos );
   else if ( cpos->py > cpos[1].py ) 
      SWAP_PNT( 0, 1, cpos );

   odisp[0] = cpos[0].px;		/* save original 2 points */
   odisp[1] = cpos[1].px;
   odisp[2] = cpos[0].py;
   odisp[3] = cpos[1].py;

   if ( *cutfl != 'N' )			/* check, if short or extended line */
      {
      cno = 0;				/* cursors always at end */
      for (nn=0; nn<4; nn++) disp[nn] = odisp[nn];
      }
   else
      cno = 1;

   idx = cpos[1].px - cpos->px;                          /* set angles */
   idy = cpos[1].py - cpos->py;
   if ( idx == 0 )
      {
      if ( idy != 0 || abs_rm >= 1.0 )
         {
         disp[0] = disp[1] = cpos->px;
         if ( *cutfl == 'N' )
            {
            disp[2] = 0;
            disp[3] = QDSZY - 1;
            }
         rm = abs_rm = 99999.0;
         } 
      else                   /* y-coords also equal, get last slope */
         {
         if ( *cutfl == 'N' )
            {
            disp[0] = 0;
            disp[1] = QDSZX - 1;
            }
         disp[2] = disp[3] = cpos->py;
         rm = abs_rm = 0.0;
         }
      }

   else if ( idy == 0 )
      {
      if ( *cutfl == 'N' )
         {
         disp[0] = 0;
         disp[1] = QDSZX - 1;
         }
      disp[2] = disp[3] = cpos->py;
      rm = abs_rm = 0.0;
      }

   else           /* calculate new endpoints of line in screen pixels */
      {
      rm = (double) idy / (double) idx;
      abs_rm = fabs( rm );
      if (*cutfl == 'N') 
         {
         END_PNT(rm,cpos,disp);
         cno = 2;
         }
      }


   /* erase old vector + draw new vector */

   nn = 0;
   while ( nn < 4 && disp[nn] == old_disp[nn] ) nn++;

   if ( nn != 4 )
      {
      if (first == 1)                  /* erase old vector + draw new one */
         first = 0;
      else
         (void) IIGPLY_C(QDSPNO,QOVCH,old_disp,old_disp+2,2,erase_flag,1);

      (void) IIGPLY_C( QDSPNO, QOVCH, disp, disp+2, 2, draw, 1 );


      /* store new vector into old one */

      for (nn=0; nn<4; nn++) old_disp[nn] = disp[nn];
      }


   /* if the ENTER key is pressed we extract the trace 
      and draw it (optionally) */

   if ( enter )
      {
      iter = 0;
      if ( CONV_TR(tr_flag,rm,cutfl,odisp,image,area) != 0 ) 
         SCETER(2,err_conv);


      /* Set the step size along the trace */

      if ( tr_flag != ColTRACE && tr_flag != RowTRACE )
         tr_flag = ( abs_rm > 1.0001 ) ? CupTRACE : RupTRACE;

      if ( tr_flag == CupTRACE || tr_flag == ColTRACE )		/* in y-dir */
         {
         if (fabs(stepln) < SMALLVAL)
            {
            stepT = step[1];
            pxstep = 1.0;			/* stepsize in pixel space */
            }
         else
            {
            if ((pxstep = stepln / step[1]) < SMALLVAL)
               {
               (void) sprintf( output, err_step, stepln );
               SCETER( 3, output );
               }
            stepT = stepln;
            }
         }

      else							/* in x-dir */
         {
         if (fabs(stepln) < SMALLVAL)
            {
            stepT = *step;
            pxstep = 1.0;                       /* stepsize in pixel space */
            }
         else
            {
            if ((pxstep = stepln / *step) < SMALLVAL)
               {
               (void) sprintf( output, err_step, stepln );
               SCETER( 3, output );
               }
            stepT = stepln;
            }
         }


      /* Erase old trace */

      if (got_frame == 0)
         got_frame = 1;                              /* nothing to erase */
      else
         {
         if (*plotfl == 'D')
            ERASE_TR(disp,cuts,npnts,p_trace);
         }


      /* Extract the data of the trace and draw the trace*/

      EXTR_DATA(maxsize,imf,image,pxstep,&npnts,&p_trace,cuts);
      
      DRAW_TR(cno,tr_flag,plotfl,cpos,image,area,cuts,npnts,p_trace);

      (void) memset((void *)output,32,(size_t)80);
      if ( tr_flag == RowTRACE )
         (void) sprintf(output,rowmes,cuts[2],cuts[3],image[2]);
      else if ( tr_flag == ColTRACE )
         (void) sprintf(output,colmes,cuts[2],cuts[3],*image);
      else
         (void) sprintf(output,trcmes,cuts[2],cuts[3],npnts );
      (void) SCTDIS( output,99);
      }

   if (cursex == 0) goto get_cursor;			/* look for more */
   }


/* Write data */

if (got_frame == 1)
   {
   (void) SCTDIS(output,0);	/* repeat last output */
   WR_FRAME(tr_flag,outfra,image,area,stepT,cuts,npnts,p_trace);
   (void) SCKWRI("OUTPUTI",disp,1,2,&unit);
   } 
}
