/*===========================================================================
  Copyright (C) 1995,2003 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
===========================================================================*/

/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

.COPYRIGHT: Copyright (c) 1994,2003 European Southern Observatory,
                                         all rights reserved
.IDENTIFICATION: Pixconv

.LANGUAGE: C and ANSI C

.AUTHOR: K.Banse			ESO - Garching

.KEYWORDS:
  screen pixels, real pixels, world coordinates

.PURPOSE:
  convert screen pixel values to real pixels and world coordinates
  and vice versa

.ALGORITHM:

  formulae for converting screen pixels to real (image memory) pixels are:

  --------------------------------------------------------
  | xreal  =  xscreen/zoom  +  scrolx                    |
  |                                                      |
  | yreal  =  scroly  -  (SCROLMAX - yscreen)/zoom       |
  |                                                      |
  |                 SCROLMAX = (QDSZY - 1)               |
  --------------------------------------------------------


 ==>						<==
 ==>  frame (real) pixels in [1,NPIX(i)]	<==
 ==>  screen pixels in [0,(screensize-1)]	<==
 ==>						<==


.RETURNS     return status:   0  o.k.
                               0 for INIT, if non-linear worldcoord_sys
                              -1 for INIT, if linear worldcoord_sys

                              1  x-pixel outside image
                              2  y-pixel outside image
                              3  x and y pixel outside

.VERSION
 1.00	940303:	convert from pixcnv.for
 031216			last modif
 
------------------------------------------------------------------- */

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

#define  _POSIX_SOURCE 1

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

/*

*/

int Pixconv(cflag,imno,dd1,dd2,dd3)

char *cflag;		/* IN: conversion to perform;
			     "INIT" initialize internal structures
			     "SRW"  screen-pix -> real-pix -> world-coord
                             "WRS"  world-coord  -> real-pix -> screen-pix
                             "WR_"  world-coord  -> real-pix
                             "_RW"  real-pix   -> world-coord 
                             "_RS"  real-pix   -> screen-pix
                           "IRW"  image-chan-pix  -> real-pix -> world-coord */
int imno;		/* IN: imno of frame 
			       only needed for cflag = "INIT" */
double *dd1;		/* IN: array of NAXIS (of imno) elements;
                               for "SRW" it contains screen pixels 
                               for "WRS" it contains world coordinates 
                               for "WR_" it contains world coordinates 
                               for "_RW" it contains real pixel numbers 
                               for "_RS" it contains real pixel numbers 
                               for "IRW" it contains image channel pixels  */
double *dd2;		/* OUT: array of NAXIS (of imno) elements;
                               always receives real pixel numbers */
double *dd3;		/* OUT: array of NAXIS (of imno) elements;
                               for "SRW" it receives world coordinates
                               for "WRS" it receives screen pixels 
                               for "_RW" it receives world coordinates
                               for "_RS" it receives screen pixels
                               for "IRW" it receives world coordinates  */


/* Note: real_pix means the same as frame_pix used elsewhere in Midas */



{
int    istat, kxpix, kypix;

double dx, dy, z;


/*
  --------------
  initialization
  --------------
*/

if ( strncmp(cflag,"IN",2) == 0 ) 
   {
   istat = fp2wc(0,imno,dd1,dd2);
   if (istat > 0)
      return (istat+10);	/* initialization gave problems */
   else
      return (istat);
   }


/*
  -------------------------------------
  conversion s.p. -> r.p. -> w.c. (SRW)
  or         i.p. -> r.p. -> w.c. (IRW)
  or                 r.p. -> w.c. (_RW)
  -------------------------------------
*/

else if ( strncmp(cflag+1,"RW",2) == 0 ) 
   {
   if ( *cflag == '_' )			/* only r.p. -> w.c. */
      {
      *dd2 = *dd1;			/* real pixel no.s */
      *(dd2+1) = *(dd1+1);
      }

   else
      {
      kxpix = NINT(*dd1);
      kypix = NINT(*(dd1+1));      /* im.p. -> r.p. -> w.c. o.k. */

      if ( *cflag == 'S' )			/* s.p. -> r.p. -> w.c. */
         Sc2ch(1,&kxpix,&kypix);

      kxpix -= SSPX;
      kypix -= SSPY;
      if (LOADDR > 0) kypix = NSY - kypix;

      istat = 0;
      if ((kxpix < 0) || (kxpix >= NSX)) istat ++;
      if ((kypix < 0) || (kypix >= NSY)) istat += 2;
      if (istat != 0) return (istat);


      if (SCALX < 0)				/*  take care of scaling */
         dx = (double) (kxpix / (-SCALX));
      else
         dx = (double) (kxpix * SCALX);
						/* dx, dy start from 0,... */
      if (SCALY < 0)     
         dy = (double) (kypix / (-SCALY));
      else
         dy = (double) (kypix * SCALY);

      *dd2 = (double)(SFPX) + dx; 	/* real pixel no. (1, ...) */
      *(dd2+1) = (double)(SFPY) + dy;
      }
   *(dd2+2) = *(dd1+2);

   istat = fp2wc(1,0,dd2,dd3);		/* world coordinates */
   if (istat != 0) return (istat+10);	/* conversion gave problems */
   }


/*
  -------------------------------------
  conversion w.c. -> r.p. -> s.p. (WRS)
  or         w.c. -> r.p.         (WR_)
  or                 r.p. -> s.p. (_RS)
  -------------------------------------
*/

else
   {
   register int  nr, mr;

double zz;

   if (*cflag == '_')     		/* first pixel is pixel no. 1 ... */
      {
      *dd2 = *dd1;
      *(dd2+1) = *(dd1+1);
      }
   else
      {
      istat = fp2wc(-1,0,dd1,dd2);		/* world co. -> real pixels */
      if (istat != 0) return (istat+10);	/* conversion gave problems */

      cflag += 2;			/* look at last char. */
      if (*cflag != 'S') return(0);	/* no screen pixels wanted */
      }

   if (SCALX < 0)                /* take care of 1. real pixel + scaling */
      {
      nr = -SCALX;
      mr = (nr-1)/2;				/* (n-1)/2 = (n+1)/2 -1 */
      zz = *dd2;
      z = zz - (int) zz;			/* get fraction */
      dx = ((int)zz - SFPX)*nr + mr;		/* => center pixel */

/*    printf("worldx = %f, framxpix = %f, dx offset = %f, fraction = %f\n",
      *dd1,zz,dx,z);
      printf("dx = %f, z = %f\n",dx,z);		move down 1 line...  */

      dx += (z * nr);			/* add fraction*scale */
      }
   else
      dx = (*dd2 - SFPX) / SCALX;

   if (SCALY < 0)     
      {
      nr = -SCALY;
      mr = (nr-1)/2;				/* (n-1)/2 = (n+1)/2 -1 */
      zz = *(dd2 + 1);
      z = zz - (int) zz;			/* get fraction */
      dy = ((int)zz - SFPY)*nr + mr;		/* => center pixel */

/*    printf("worldy = %f, framypix = %f, dy offset = %f, fraction = %f\n",
      *(dd1+1),zz,dy,z);
      printf("dy = %f, z = %f\n",dy,z);		move down 1 line...  */
 
      dy += (z * nr);			/* add fraction*scale */
      }
   else
      dy = (*(dd2+1) - SFPY) / SCALY;

   kxpix = NINT(dx) + SSPX;
   kypix = NINT(dy) + SSPY;

   Sc2ch(-1,&kxpix,&kypix);			/* move to screen pixels */
   *dd3 = (double) kxpix;
   *(dd3+1) = (double) kypix;
   }

return (0);
}
