/*===========================================================================
  Copyright (C) 1994-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  SUBEXT_C
.LANGUAGE    C
.AUTHOR      K. Banse		IPG-ESO Garching
.KEYWORDS    image display, cursor, subframe
.PURPOSE     read the position of one or two cursors on the DeAnza display
             extract a subframe from the displayed frame, the limits of which
             are given either by the two cursors or by one cursor and 
             parameters XSIZE + Y, if limits are defined by the two cursors, 
             always a minimal square is extracte
.ALGORITHM   read once the cursor(s), only if outside limits loop more
.INPUT/OUTPUT
  call as    SUBEXT_C( ncurs, loopfl, splmod, frame )

  input
          int  ncurs   :	number of cursors
          int  loopfl  :	
          int  splmod  :	split mode
          char *frame  :        name of frame to be created

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

.VERSIONS    1.00       940630  from IDAUXZ.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 <string.h>
#include <midas_def.h>
#include <idinumd.h>
#include <proto_II.h>

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

static int ffelem = 1;

/*

*/

/*++++++++++++++++++++++++++++++
.IDENTIFIER  CONV_PIX
.PURPOSE     convert screen pixels to real pixels + world coordinates
.INPUT/OUTPUT
  call as    CONV_PIX(ncurs,xysize,xyA,xyB,pixelA,pixelB)
  
  input:
          int    ncurs  :
          int   *xysize :

  in/output:
          int   *xyA    :
          int   *xyB    :

  output:
          float *pixelA :
          float *pixelB :

.RETURNS    status
------------------------------*/

#ifdef __STDC__
      static int CONV_PIX(int ncurs,int *xysize, 
                           int *xyA,int *xyB,float *pixelA,float *pixelB)
#else
      static int CONV_PIX(ncurs,xysize,xyA,xyB,pixelA,pixelB)
      int    ncurs, *xysize, *xyA, *xyB;
      float  *pixelA, *pixelB;
#endif

{
float xm, ym;

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


pixelA[0] = xyA[0];
pixelA[1] = xyA[1];

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

if ( Pixconv("IRW",0,dd1,dd2,dd3) != 0 ) 
   {
   SCTPUT( "Cursor(s) outside image... (in x)" );
   return (1);  
   }
else
   {
   pixelA[2] = (float) dd2[0];
   pixelA[3] = (float) dd2[1];
   pixelA[4] = (float) dd3[0];
   pixelA[5] = (float) dd3[1];
   }


if ( ncurs > 1 )                                             /* both cursors */
   {
   pixelB[0] = xyB[0];
   pixelB[1] = xyB[1];
   dd1[0] = (double)xyB[0];
   dd1[1] = (double)xyB[1];
   if ( Pixconv("IRW",0,dd1,dd2,dd3) != 0 ) 
      {
      SCTPUT( "Cursor(s) outside image... (in y)" );
      return (1);
      }
   else
      {
      pixelB[2] = (float) dd2[0];
      pixelB[3] = (float) dd2[1];
      pixelB[4] = (float) dd3[0];
      pixelB[5] = (float) dd3[1];
      }
   }

else            /* if only one cursor involved, we have to build a rectangle */
   {
   pixelB[0] = SSPX + NSX - 1;                       /* last screen pixel  */
   pixelB[1] = SSPY + NSY - 1;
   dd1[0] = (double)pixelB[0];
   dd1[1] = (double)pixelB[1];
   if ( Pixconv("IRW",0,dd1,dd2,dd3) != 0 ) 
      {
      SCTPUT( "Cursor(s) outside image... (in y)" );
      return (1);
      }
   else
      {
      pixelB[2] = (float) dd2[0];
      pixelB[3] = (float) dd2[1];
      pixelB[4] = (float) dd3[0];
      pixelB[5] = (float) dd3[1];
      }

   xm = pixelB[2];                             /* last frame pixel visible */
   ym = pixelB[3];

   *xyA = pixelA[2] - (xysize[0]/2);
   if ( *xyA < SFPX ) *xyA = SFPX;    /* make sure, it stays inside... */
   *xyB = *xyA + xysize[0] - 1;

   if ( *xyB > xm )     
      {
      *xyB = xm;
      *xyA = *xyB - xysize[0] + 1;
      if ( *xyA < SFPX ) *xyA = SFPX;
      }

   xyA[1] = pixelA[3] - (xysize[1]/2);
   if ( xyA[1] < SFPY ) xyA[1] = SFPY;    /* make sure, it stays inside... */

   xyB[1] = xyA[1] + xysize[1] - 1;
   if ( xyB[1] > ym )
      {
      xyB[1] = ym;
      xyA[1] = xyB[1] - xysize[1] + 1;
      if ( xyA[1] < SFPY ) xyA[1] = SFPY ;
      }

   pixelA[0] = xyA[0];                    /* frame pixels -> screen pixels */
   pixelA[1] = xyA[1];
   dd1[0] = (double)pixelA[0];
   dd1[1] = (double)pixelA[1];
   if ( Pixconv("_RS",0,dd1,dd2,dd3) != 0 )
      {
      SCTPUT( "Cursor(s) outside image... (in x)" );
      return (1); 
      }
   else
      {
      pixelA[2] = (float) dd2[0];
      pixelA[3] = (float) dd2[1];
      pixelA[4] = (float) dd3[0];
      pixelA[5] = (float) dd3[1];
      }
   xyA[0] = pixelA[4];
   xyA[1] = pixelA[5];

   pixelB[0] = xyB[0];
   pixelB[1] = xyB[1];
   dd1[0] = (double)pixelB[0];
   dd1[1] = (double)pixelB[1];
   if ( Pixconv("_RS",0,dd1,dd2,dd3) != 0 )
      {
      SCTPUT( "Cursor(s) outside image... (in y)" );
      return (1);  
      }
   else
      {
      pixelB[2] = (float) dd2[0];
      pixelB[3] = (float) dd2[1];
      pixelB[4] = (float) dd3[0];
      pixelB[5] = (float) dd3[1];
      }

   xyB[0] = pixelB[4];
   xyB[1] = pixelB[5];
   }

return (0);
}

/*

*/

/*++++++++++++++++++++++++++++++
.IDENTIFIER  SHOW_REC
.PURPOSE     show rectangle with extracted frame
.INPUT/OUTPUT
  call as    SHOW_REC( xyA, xyB)
  
  input:
          int    *xyA   :
          int    *xyB   :

.RETURNS    status
------------------------------*/

#ifdef __STDC__
      static void SHOW_REC( int *xyA, int *xyB )
#else
      static void SHOW_REC( xyA, xyB )
      int *xyA, *xyB;
#endif

{
int offs, npnts, coos[4], xfig[5], yfig[5];

float  arcs[2];



if ( SCALX < -1)     
   offs = -SCALX / 2;
else
   offs = 0;
coos[0] = xyA[0] + offs;
coos[2] = xyB[0] + offs;

if (SCALY < -1)     
   offs = -SCALY / 2;
else
   offs = 0;
coos[1] = xyA[1] + offs;
coos[3] = xyB[1] + offs;

arcs[0] = arcs[1] = -1.0;				/* not used... */
(void) buildgra("REC",coos,arcs,xfig,yfig,5,&npnts);
(void) IIGPLY_C(QDSPNO,QOVCH,xfig,yfig,npnts,255,1);
}

/*

*/

#ifdef __STDC__
   void SUBEXT_C(int ncurs, int loopfl, int splmod, char *frame)
#else
   void SUBEXT_C(ncurs, loopfl, splmod, frame)
   int  ncurs, loopfl, splmod;
   char *frame;
#endif

{
int    mm, actvals, go_on, ioff, knul, naxis, memo, size, unit, subhi[2];
int    imnoA, imnoR, imnoX, statA, statB, xyA[5], xyB[5], xysize[2];
int    npix[2], npixR[2], bgnA[2], dimA[2], bgnR[2],
       respix[2], sublo[2];
int    refstat, sizeX, oldmem, first;
int    ec, el, ed;
int    con_alw = 1, log_no = 0, dis_no = 0;       /* variables for SCECNT */
static int   coord[4]  = { -1, -1, -1, -1 };

float  *pntrX, *pntrR, cuts[4], pixelA[6], pixelB[6];
float cutvls[2];

double step[2], startR[2], dd1[4], dd2[4], dd3[4];
double o_start[2], o_refpix[2], refpix[2];

char   *cpntr, newfra[61], ident[76], cunit[50], output[81];
static char *usr_info  = "switch cursor(s) on - next time we exit...",
            *mes_pixel = "no. of pixels of subframe: %5d%5d";





/* initialize */

sizeX  = oldmem = -99;				/* size of scratch memory */
first = TRUE;
refstat = -1;
pntrX = (float *) 0;

if (ncurs == 2)
   {
   mm = 1;				/* rectangle shape */
   xysize[0] = xysize[1] = 0;
   }
else
   {
   mm = 3;				/* open cross */
   (void) SCKRDI("INPUTI",10,2,&actvals,xysize,&unit,&knul);
   }

SETCUR_C(QDSPNO,ncurs,mm,2,coord);
Ccursin(QDSPNO,0,ncurs,xyA,&statA,xyB,&statB);   /* bind interaction */


/* get cursor position */

go_on = TRUE;
while (go_on)
   {
   Ccursin(QDSPNO,1,ncurs,xyA,&statA,xyB,&statB);

   if ( statA == 0 && statB == 0 )
      {
      (void) IIISTI_C(QDSPNO);           /* terminate interaction */
      if (! first)     
         go_on = FALSE;
      else
         {
         first = FALSE;
         SCTPUT(usr_info);
         Ccursin(QDSPNO,0,ncurs,xyA,&statA,xyB,&statB);
         }
      }
   else                                       /* get relevant memory board */
      {
      if ( QRGBFL == 1 && splmod == 0 )          /* RGB + non-split mode */
         memo = QIMCH;
      else
         memo = xyA[2];


      if (oldmem != memo)		/* if necessary open new frame */
         {
         if (DCGICH(memo) != 0)		/* get channel info */
            SCETER(1,"SUBEXT: no image loaded!");

         if (oldmem != -99) (void) SCFCLO(imnoA);
         oldmem = memo;

         (void) SCFOPN(dzmemc,D_R4_FORMAT,0,F_IMA_TYPE,&imnoA);
         (void) SCDRDI(imnoA,"NAXIS",1,1,&actvals,&naxis,&unit,&knul);
         if ( naxis > 2 ) naxis = 2;
         (void) SCDRDI(imnoA,"NPIX",1,naxis,&actvals,npix,&unit,&knul);
         (void) SCDRDD(imnoA,"START",1,naxis,&actvals,o_start,&unit,&knul);
         (void) SCDRDD(imnoA,"STEP",1,naxis,&actvals,step,&unit,&knul);
         (void) SCDRDR(imnoA,"LHCUTS",1,4,&actvals,cuts,&unit,&knul);
         (void) SCDGETC(imnoA,"IDENT",1,72,&actvals,ident);
         (void) SCDGETC(imnoA,"CUNIT",1,48,&actvals,cunit);

         /* look if descr. REFPIX exists, 
            if so we have to update it accordingly */
 
         (void) SCECNT("GET",&ec,&el,&ed);
         (void) SCECNT("PUT",&con_alw,&log_no,&dis_no);
         refstat = SCDRDD(imnoA,"REFPIX",1,naxis,&actvals,o_refpix,&unit,&knul);
         (void) SCECNT("PUT",&ec,&el,&ed);
         
         if (Pixconv("INIT",imnoA,dd1,dd2,dd3) > 0)
            SCETER(69,"initialization of world coord. conversion failed ...");

         if (ZPLANE != 0)
            {
            ffelem = ((ZPLANE-1)*npix[0]*npix[1]) + 1;
            dd1[2] = ZPLANE;
            }
         else
            ffelem = 1;

         (void) sprintf(output, "Extracting from frame: %s", dzmemc );
         SCTPUT(output);
         }



/* now convert screen pixels to real pixels + world coordinates */

      if (CONV_PIX(ncurs,xysize,xyA,xyB,pixelA,pixelB) == 0)
         {
         SHOW_REC(xyA,xyB);

         sublo[0] = bgnA[0] = CGN_NINT(pixelA[2]);
         sublo[1] = CGN_NINT(pixelA[3]);
         bgnA[1] = 1;			 /* prepare pixno.s for subframe */
         npixR[0] = dimA[0] = CGN_NINT(pixelB[2]-pixelA[2]) + 1;
         npixR[1] = dimA[1] = CGN_NINT(pixelB[3]-pixelA[3]) + 1;
         bgnR[0] = bgnR[1] = 1;

         ioff = *npix * CGN_NINT(pixelA[3]-1) + ffelem;
         if ((size = *npix * dimA[1]) > sizeX)           /* new size */
            { 
            if (sizeX != -99) (void) SCFCLO(imnoX);

            sizeX = size;
            (void) SCFCRE("dumextra",D_R4_FORMAT,F_X_MODE,
                                     F_IMA_TYPE,sizeX,&imnoX);
            (void) SCFMAP(imnoX,F_X_MODE,1,sizeX,&actvals,&cpntr);
            (void) SCFGET(imnoA,ioff,sizeX,&actvals,cpntr);
            pntrX = (float *) cpntr;
            }
         else
            {
            cpntr = (char *) pntrX;            /* already allocated! */
            (void) SCFGET(imnoA,ioff,size,&actvals,cpntr);
            }

         dd1[0] = (double)pixelA[2];
         dd1[1] = (double)pixelA[3];
         (void) Pixconv("_RW",0,dd1,dd2,dd3);
         startR[0] = dd3[0];			/* start in true world coords */
         startR[1] = dd3[1];
         pixelA[4] = startR[0];
         pixelA[5] = startR[1];


         /* show world coordinates of subframe */

         if ( loopfl == -1 )
            (void) strcpy(newfra,frame);
         else
            {
            mm = CGN_INDEXC(frame,' ');
            if (mm > 0) frame[mm] = '\0';
            (void) sprintf(newfra,"%s%04d",frame,++loopfl);
            }
         mm = CGN_INDEXC(newfra,' ');
         if (mm > 0) newfra[mm] = '\0';
         (void) sprintf(output,"start coordinates of subframe %s:",newfra);
         SCTPUT(output);
         (void) sprintf(output,"are frame_pixels (of displayed frame): %d, %d",
                sublo[0],sublo[1]);
         SCTPUT(output);
         (void) sprintf(output,"or in world coords: %12.6g,%12.6g",
                *startR,startR[1]);
         SCTPUT(output);
         (void) sprintf(output,mes_pixel,*npixR,npixR[1]);
         SCTPUT(output);

         /* start descr. in subframe must be calculated according
	    to a linear coord. system - that's how Midas uses START */

         startR[0] = o_start[0] + (sublo[0] - 1)*step[0];
         startR[1] = o_start[1] + (sublo[1] - 1)*step[1];

         /* map subframe */

         (void) SCIPUT(newfra,D_R4_FORMAT,F_O_MODE,F_IMA_TYPE,naxis,
                       npixR,startR,step,ident,cunit,&cpntr,&imnoR);
         pntrR = (float *) cpntr;


         /* and fill it...  */

         sublo[0] = sublo[1] = 0;
         Ccopyf1(pntrX,npix,bgnA,dimA,pntrR,npixR,bgnR);


         /* get new min + max value */

         subhi[0] = npixR[0] - 1;
         subhi[1] = npixR[1] - 1;
         cutvls[0] = cutvls[1] = 0.0;
         (void) Cstvals("MIN",pntrR,naxis,npixR,sublo,subhi,
                              cutvls,cuts+2,respix,&actvals);

         /* copy non-standard descriptors, update LHCUTS + append HISTORY
	    and adjust REFPIX */

         CGN_DSCUPD(imnoA,imnoR," ");
         mm = sprintf(output,"from frame: %s",dzmemc);
         (void) SCDWRC(imnoR,"HISTORY",1,output,-1,mm,&unit);
         (void) SCDWRR(imnoR,"START_INFO",&pixelA[2],1,4,&unit);
         (void) SCDWRR(imnoR,"LHCUTS",cuts,1,4,&unit);

         if (refstat == 0)	/* o_ref - pixel of start of son */
	    { 			/* corresponds to: */
				/* new_ref - 1 (pixel of start coord) */
            refpix[0] = o_refpix[0] - pixelA[2] + 1.0;
            refpix[1] = o_refpix[1] - pixelA[3] + 1.0;
            (void) SCDWRD(imnoR,"REFPIX",refpix,1,2,&unit);
            }

         (void) SCFCLO(imnoR);

         if (loopfl == -1) go_on = FALSE;
         first = FALSE;
         }
      }
   }                                                    /* End of WHILE-loop */
}


