#ifndef lint
static char SccsId[] = "%W%  %G%";
#endif

/* Module:	csrcoord.c (Cursor Coordinates)
 * Purpose:	Calculate coordinates for cursor functions
 * Subroutine:	set_cursor_file_coords()	returns: void	
 * Subroutine:	adjust_cursor_coords()		returns: void	
 * Subroutine:	set_cursor_from_file_coords()	returns: void	
 * Subroutine:	set_annuli_from_file_coords()	returns: void
 * Subroutine:	note_current_disp_transform()	returns: void	
 * Subroutine:	report_cursor_info()		returns: void	
 * Copyright:	1999 Smithsonian Astrophysical Observatory
 *		You may do anything you like with this file except remove
 *		this copyright.  The Smithsonian Astrophysical Observatory
 *		makes no representations about the suitability of this
 *		software for any purpose.  It is provided "as is" without
 *		express or implied warranty.
 * Modified:	{0} Michael VanHilst	initial version		  4 June 1989
 *		{1} MVH added text cursor support		   1 Jan 1991
 *		{2} Doug Mink added WCS info to cursor report	  23 Oct 1996
 *		{2} Doug Mink bump WCS string to 48 from 32  	   6 May 1999
 *		{n} <who> -- <does what> -- <when>
 */

#include <stdio.h>		/* stderr, NULL, etc. */
#include <math.h>
#include <X11/Xlib.h>		/* X window stuff */
#include <X11/Xutil.h>		/* X window manager stuff */
#include "hfiles/color.h"	/* cursor colors needed by Cursor.h */
#include "hfiles/constant.h"	/* define codes */
#include "hfiles/coord.h"	/* coord structs */
#include "hfiles/cursor.h"	/* define cursor parameter structures */
#include "hfiles/extern.h"      /* extern main SAOimage parameter structures */
#include "hfiles/wcs.h"		/* World coordinate system structure */

/*  Saved transform to see if it changed  */
static Transform ftod;


#ifdef ANSIC
/*  Exported declarations must be centralized before ANSI C can be used  */

void		set_cursor_file_coords(	struct cursorRec *cursor,
					Transform *disptofile, int setcen);
void		adjust_cursor_coords(	struct cursorRec *cursor,
					struct coordRec *coord);
void		set_cursor_from_file_coords(	struct cursorRec *cursor,
						Transform *filetodisp);
void		set_annuli_from_file_coords(	struct cursorRec *cursor,
						Transform *filetodisp);
void		note_current_disp_transform(	Transform *filetodisp);
void		report_cursor_info(	struct cursorRec *cursor);

static int	disp_coords_changed(	Transform *filetodisp);

#else

void d_transform(), make_cursor(), reset_textcursor_coords();
double cursor_area();
void set_polygon_from_file_coords(), set_annuli_from_file_coords();
void set_cursor_from_file_coords(), note_current_disp_transform();
static int disp_coords_changed();

#endif


/*  Subroutine:	set_cursor_file_coords
 *  Purpose:	Set img coords of cursor
 */
#ifdef ANSIC
void set_cursor_file_coords( struct cursorRec *cursor, Transform *disptofile,
			     int setcen )
#else
void set_cursor_file_coords ( cursor, disptofile, setcen )
     struct cursorRec *cursor;
     Transform *disptofile;
     int setcen;	/* i: set-center-after-move, else set dim after size */
#endif
{
  double ratio;

  if( setcen ) {
    d_transform(disptofile, cursor->win.X, cursor->win.Y,
		&cursor->file.X, &cursor->file.Y);
  } else {
    if( (ratio = disptofile->inx_outx + disptofile->inx_outy) < 0.0 )
      ratio = -ratio;
    cursor->file.Xdim = cursor->win.rayX * ratio;
    cursor->file.Ydim = cursor->win.rayY * ratio;
  }
}


/*  Subroutine:	adjust_cursor_coords
 *  Purpose:	If the display image has been altered, change the cursor
 *		parameters in the same way, so that the cursor has the same
 *		relationship to the image.  old cursor is not erased, image
 *		redraw usually does that
 */
#ifdef ANSIC
void adjust_cursor_coords ( struct cursorRec *cursor, struct coordRec *coord )
#else
void adjust_cursor_coords ( cursor, coord )
     struct cursorRec *cursor;
     struct coordRec *coord;
#endif
{
  int maincursor = 1;

  if( disp_coords_changed(&coord->filetodisp) ) {
    /*  Remake the window coordinates and line drawing records  */
    while( cursor != NULL ) {
      if( cursor->type == COP_Polygon )
	set_polygon_from_file_coords(cursor, &coord->filetodisp, maincursor);
      else {
	if( cursor->annuli )
	  set_annuli_from_file_coords(cursor, &coord->filetodisp);
	else
	  set_cursor_from_file_coords(cursor, &coord->filetodisp);
      }
      /*  Loop on saved cursors  */
      maincursor = 0;
      cursor = cursor->next_region;
    }
    note_current_disp_transform(&coord->filetodisp);
  }
}


/*  Subroutine:	set_cursor_from_file_coords
 *  Purpose:	Set cursor window coordinates from its file coordinates
 */
#ifdef ANSIC
void set_cursor_from_file_coords( struct cursorRec *cursor,
				  Transform *filetodisp )
#else
void set_cursor_from_file_coords ( cursor, filetodisp )
     struct cursorRec *cursor;
     Transform *filetodisp;
#endif
{
  float X, Y, ratio;
  double ra0, ra1, dec0, dec1, secpix;

  /*  Get new window coordinates  */
  d_transform(filetodisp,
	      (double)cursor->file.X, (double)cursor->file.Y, &X, &Y);
  cursor->win.X = X;
  cursor->win.Y = Y;
  cursor->win.x = (int)X;
  cursor->win.y = (int)Y;

  /* Set cursor size from command line */
  if (cursor->file.Xdim < 0.0) {
    if (iswcs (wcs)) {
      (void)pix2wcs (wcs,cursor->file.X, cursor->file.Y, &ra0, &dec0);
      (void)pix2wcs (wcs,cursor->file.X+1.0, cursor->file.Y, &ra1, &dec1);
      secpix = (ra1 - ra0) * cos(degrad(dec1)) * 3600.0 ;
      cursor->file.Xdim = -cursor->file.Xdim / secpix;
      if (cursor->file.Xdim < 0)
	cursor->file.Xdim = -cursor->file.Xdim;
      }
    else
      cursor->file.Xdim = -cursor->file.Xdim;
    }
  if (cursor->file.Ydim < 0.0) {
    if (iswcs (wcs)) {
      (void)pix2wcs (wcs,cursor->file.X, cursor->file.Y, &ra0, &dec0);
      (void)pix2wcs (wcs,cursor->file.X, cursor->file.Y+1.0, &ra1, &dec1);
      secpix = (dec1 - dec0) * 3600.0;
      cursor->file.Ydim = -cursor->file.Ydim / secpix;
      if (cursor->file.Ydim < 0)
	cursor->file.Ydim = -cursor->file.Ydim;
      }
    else
      cursor->file.Ydim = -cursor->file.Ydim;
    }

  /* Convert file dimensions to display dimensions */
  if( (ratio = filetodisp->inx_outx + filetodisp->inx_outy) < 0.0 )
    ratio = -ratio;

  cursor->win.rayX = cursor->file.Xdim * ratio;
  cursor->win.rayY = cursor->file.Ydim * ratio;

  /*  Make new drawing vertices  */
  if( cursor->type == COP_Text )
    reset_textcursor_coords(cursor);
  else
    make_cursor(cursor);
}


/*  Subroutine:	set_annuli_from_file_coords
 *  Purpose:	Set annuli window coordinates from their file coordinates
 */
#ifdef ANSIC
void set_annuli_from_file_coords ( struct cursorRec *cursor,
				   Transform *filetodisp )
#else
void set_annuli_from_file_coords ( cursor, filetodisp )
     struct cursorRec *cursor;
     Transform *filetodisp;
#endif
{
  struct cursorRec *annulus;
  float X, Y, ratio;

  /*  Get new window coordinates  */
  d_transform(filetodisp,
	      (double)cursor->file.X, (double)cursor->file.Y, &X, &Y);
  cursor->win.X = X;
  cursor->win.Y = Y;
  cursor->win.x = (int)X;
  cursor->win.y = (int)Y;
  /*  Get new window dimensions  */
  if( (ratio = filetodisp->inx_outx + filetodisp->inx_outy) < 0.0 )
    ratio = -ratio;
  annulus = cursor->next_annulus;
  while( annulus != 0 ) {
    annulus->win.X = cursor->win.X;
    annulus->win.Y = cursor->win.Y;
    annulus->win.x = cursor->win.x;
    annulus->win.y = cursor->win.y;
    annulus->win.rayX = ratio * annulus->file.Xdim;
    annulus->win.rayY = ratio * annulus->file.Ydim;
    /*  Make new drawing vertices  */
    make_cursor(annulus);
    annulus = annulus->next_annulus;
  }
}


/*  Subroutine:	note_current_disp_transform
 *  Purpose:	Note current transform
 */
#ifdef ANSIC
void note_current_disp_transform ( Transform *filetodisp )
#else
void note_current_disp_transform ( filetodisp )
     Transform *filetodisp;
#endif
{
  ftod.inx_outx = filetodisp->inx_outx;
  ftod.inx_outy = filetodisp->inx_outy;
  ftod.add_outx = filetodisp->add_outx;
  ftod.add_outy = filetodisp->add_outy;
}


/*  Subroutine:	disp_params_changed
 *  Purpose:	Check if current transform has changed
 */
#ifdef ANSIC
static int disp_coords_changed ( Transform *filetodisp )
#else
static int disp_coords_changed ( filetodisp )
     Transform *filetodisp;
#endif
{
  if( (filetodisp->inx_outx != ftod.inx_outx) ||
      (filetodisp->inx_outy != ftod.inx_outy) ||
      (filetodisp->add_outx != ftod.add_outx) ||
      (filetodisp->add_outy != ftod.add_outy) )
    return( 1 );
  else
    return( 0 );
}


/*  Subroutine:	report_cursor_info
 *  Purpose:	Calculate and report curosr params in file coordinates
 */
#ifdef ANSIC
void report_cursor_info ( struct cursorRec *cursor )
#endif
void report_cursor_info ( cursor )
     struct cursorRec *cursor;
{
  double area, areas, aread, rad, rads, ra0,dec0,ra1,dec1, degpix, secpix;
  double radx, rady, radxs, radys;
  extern double wcsdist();
  int i, iswcs();
  char string[64];
  int lstr=48;
  char cursor_type[32];

  switch( cursor->type ) {
  case COP_Circle:
    (void)sprintf(cursor_type,"Circle cursor");
     break;
  case COP_PieSlice:
    (void)sprintf(cursor_type,"Pie cursor");
     break;
  case COP_Ellipse:
    (void)sprintf(cursor_type,"Rotatable ellipse");
     break;
  case COP_Point:
    (void)sprintf(cursor_type,"Point cursor");
     break;
  case COP_Arrow:
    (void)sprintf(cursor_type,"Arrow pointing");
     break;
  case COP_Box:
    if( cursor->rot.angle == 0.0 )
      (void)sprintf(cursor_type, "Orthogonal box cursor");
    else
      (void)sprintf(cursor_type, "Rotated box cursor");
     break;
  case COP_Polygon:
    (void)sprintf(cursor_type,"Polygon cursor with %d vertices", cursor->poly_cnt);
     break;
  default:
      (void)sprintf(cursor_type, "Cursor");
    cursor_type[0] = 0;
    break;
  }

  /*  Calculate the new coords  */
  /*  Now tell what and where  */
  /* (void)printf("%s at window x=%d, y=%d, ", cursor_type,
	       cursor->win.x, cursor->win.y); */
  if (cursor->type == COP_Polygon)
    (void)printf("%s at:\n", cursor_type);
  else {
    (void)printf("%s at file X=%.3f, Y=%.3f", cursor_type,
	         cursor->file.X, cursor->file.Y);
    if (iswcs (wcs)) {
      (void)pix2wcst (wcs,cursor->file.X, cursor->file.Y,string,lstr);
      (void)printf(" %s\n", string);
      }
    else
      (void)printf("\n");
    }

  /* Calculate scale at cursor position */
  if (iswcs (wcs)) {
    (void)pix2wcs (wcs,cursor->file.X, cursor->file.Y,&ra0,&dec0);
    (void)pix2wcs (wcs,cursor->file.X, cursor->file.Y+1.0, &ra1, &dec1);
    degpix = dec1 - dec0;
    secpix = degpix * 3600.0;
    }
  else {
    degpix = 0.0;
    secpix = 0.0;
    }
  /* Calculate cursor area */
  area = cursor_area(cursor, 1);
  areas = area * secpix * secpix;
  aread = area * degpix * degpix;

  /* Calculate cursor radius */
  radx = cursor->file.Xdim;
  radxs = radx * secpix;
  rady = cursor->file.Ydim;
  radys = rady * secpix;

 switch( cursor->type ) {
  case COP_Circle:
  case COP_PieSlice:
    if (iswcs (wcs)) {
      (void)pix2wcs (wcs,cursor->file.X, cursor->file.Y,&ra0,&dec0);
      (void)pix2wcs (wcs,cursor->file.X, cursor->file.Y+cursor->file.Ydim,
	&ra1,&dec1);
      rads = wcsdist (ra0, dec0, ra1, dec1) * 3600;
      }
    else
      rads = 0.0;
    if (rads > 300)
      (void)printf("radius: %.2f pixels = %.2f arcmin, ", radx, rads/60.0);
    else if (rads > 0)
      (void)printf("radius: %.2f pixels = %.2f arcsec, ", radx, rads);
    else
      (void)printf("radius: %.2f pixels", radx);
    break;
  case COP_Ellipse:
    (void)printf(" angle: %6.3f rad = %6.2f deg\n", cursor->rot.angle,
		 raddeg (cursor->rot.angle));
    if (radxs > 3600.0 || radys > 3600.0) {
      (void)printf(" X radius: %.2f pixels = %.2f degrees, ", radx, radxs/3600.0);
      (void)printf("Y radius: %.2f pixels = %.2f degrees\n", rady, radys/3600.0);
      }
    else if (radxs > 300.0  || radys > 300.0) {
      (void)printf(" X radius: %.2f pixels = %.2f arcmin, ", radx, radxs/60.0);
      (void)printf("Y radius: %.2f pixels = %.2f arcmin\n", rady, radys/60.0);
      }
    else if (radxs > 0 || radys > 0) {
      (void)printf(" X radius: %.2f pixels = %.2f arcsec, ", radx, radxs);
      (void)printf("Y radius: %.2f pixels = %.2f arcsec\n", rady, radys);
      }
    else
      (void)printf(" X radius: %.2f pixels, Y radius: %.2f pixels\n",radx,rady);
    break;
  case COP_Box:
    radx = radx * 2.0;
    rady = rady * 2.0;
    radxs = radxs * 2.0;
    radys = radys * 2.0;
    if (radxs > 3600.0 || radys > 3600.0) {
      (void)printf(" X width: %.2f pixels = %.2f degrees, ", radx, radxs/3600.0);
      (void)printf("Y height: %.2f pixels = %.2f degrees\n", rady, radys/3600.0);
      }
    else if (radxs > 300.0  || radys > 300.0) {
      (void)printf(" X width: %.2f pixels = %.2f arcmin, ", radx, radxs/60.0);
      (void)printf("Y height: %.2f pixels = %.2f arcmin\n", rady, radys/60.0);
      }
    else if (radxs > 0 || radys > 0) {
      (void)printf(" X width: %.2f pixels = %.2f arcsec, ", radx, radxs);
      (void)printf("Y height: %.2f pixels = %.2f arcsec\n", rady, radys);
      }
    else
      (void)printf(" X width: %.2f pixels, Y height: %.2f pixels\n",radx,rady);
    if( cursor->rot.angle != 0.0 )
      (void)printf(" angle: %6.3f rad = %6.2f deg\n", cursor->rot.angle,
		   raddeg (cursor->rot.angle));
    break;
  case COP_Polygon:
    for( i=0; i<cursor->poly_cnt; i++ ) {
      (void)printf("  (x=%.2f, y=%.2f)",
		   cursor->poly[i].fileX, cursor->poly[i].fileY);
      if (iswcs (wcs)) {
	(void)pix2wcst (wcs,cursor->poly[i].fileX, cursor->poly[i].fileY,
			string,lstr);
	(void)printf(" %s", string);
	}
      (void)printf("\n");
      }
    if (area <= 0.0 && cursor->poly_cnt > 2)
      (void)printf("Note: polygon is twisted.\n");
    break;
  case COP_Point:
  default:
    break;
  }
  if (aread > 10)
    (void)printf(" area: %.2f pixel^2 = %.2f degree^2 \n", area, aread);
  else if (areas > 3599.9)
    (void)printf(" area: %.2f pixel^2 = %.2f arcmin^2 \n", area, areas/3600.0);
  else if (areas > 0.0)
    (void)printf(" area: %.2f pixel^2 = %.2f arcsec^2 \n", area, areas);
  else if (area > 0.0)
    (void)printf(" area: %.2f pixel^2\n", area);
  (void)printf("\n");	
}


syntax highlighted by Code2HTML, v. 0.9.1