/* File remap.c
 * March 19, 2015
 * By Jessica Mink, Harvard-Smithsonian Center for Astrophysics
 * Send bug reports to jmink@cfa.harvard.edu

   Copyright (C) 1999-2015
   Smithsonian Astrophysical Observatory, Cambridge, MA USA

   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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <math.h>
#include "libwcs/fitswcs.h"

#define REMAP_CLOSEST	1
#define REMAP_FLUX	2

extern void setcenter();
extern void setsys();
extern void setrot();
extern void setsecpix();
extern void setsecpix2();
extern void setrefpix();
extern void setnpix();
extern void setwcsproj();
extern void setscale();

static void usage();
static int verbose = 0;		/* verbose flag */
static char *outname0 = "remap.fits";
static char *outname;
static char *wcsproj;           /* WCS projection name */

static char *RevMsg = "REMAP WCSTools 3.9.7, 26 April 2022, Jessica Mink (jmink@cfa.harvard.edu)";
static int nfiles = 0;
static int fitsout = 1;
static double secpix = 0;
static double secpix2 = 0;
static int bitpix0 = 0; /* Output BITPIX, =input if 0 */
static int RemapImage();
static void getsection();
static struct WorldCoor *wcsout = NULL;
static char *irafheader;	/* IRAF image header */
static char *headout;		/* FITS output header */
static char *imout;		/* FITS output image */
static int lhead;		/* Maximum number of bytes in FITS header */
static int iraffile;
static int eqsys = 0;
static double equinox = 0.0;
static int outsys = 0;
static int version = 0;		/* If 1, print only program name and version */
static int remappix=0;		/* Number of samples of input pixels */
static char *wcsfile;		/* Read WCS from this FITS or IRAF file */
static double xrpix = 0.0;
static double yrpix = 0.0;
static double blankpix = 0.0;	/* image value for blank pixel */
static int nx = 0;
static int ny = 0;
static int nlog = 0;
static int undistort = 0;
static int centerset = 0;

int
main (ac, av)
int ac;
char **av;
{
    char *str;
    char rastr[32];
    char decstr[32];
    char filename[128];
    char *filelist[100];
    char errmsg[100];
    char *listfile = NULL;
    int readlist = 0;
    FILE *flist = NULL;
    int ifile, i;
    int lwcs;
    char c;

    for (i = 0; i < 100; i++)
	filelist[i] = NULL;
    wcsproj = NULL;
    wcsfile = NULL;

    outname = NULL;

    /* Check for help or version command first */
    str = *(av+1);
    if (!str || !strcmp (str, "help") || !strcmp (str, "-help"))
	usage((char) 0, NULL);
    if (!strcmp (str, "version") || !strcmp (str, "-version")) {
	version = 1;
	usage((char) 0, NULL);
	}

    setrot (0.0);

    /* Crack arguments */
    for (av++; --ac > 0 && (*(str = *av)=='-' || *str == '@'); av++) {
	if (*str == '@')
	    str = str - 1;
	while ((c = *++str))
	switch (c) {
    	case 'a':	/* Output rotation angle in degrees */
    	    if (ac < 2)
    		usage(c, "needs rotation angle in degrees");
    	    setrot (atof (*++av));
    	    ac--;
    	    break;

    	case 'b':	/* Output image center on command line in B1950 */
    	    if (ac < 3)
    		usage(c, "needs B1950 coordinates of output reference pixel");
	    setsys (WCS_B1950);
	    outsys = WCS_B1950;
	    strcpy (rastr, *++av);
	    ac--;
	    strcpy (decstr, *++av);
	    ac--;
	    setcenter (rastr, decstr);
	    centerset = 1;
    	    break;

    	case 'e':	/* Output image center on command line in ecliptic */
    	    if (ac < 3)
    		usage(c,"needs ecliptic coordinates of output reference pixel");
	    setsys (WCS_ECLIPTIC);
	    outsys = WCS_ECLIPTIC;
	    strcpy (rastr, *++av);
	    ac--;
	    strcpy (decstr, *++av);
	    ac--;
	    setcenter (rastr, decstr);
	    centerset = 1;
    	    break;

	case 'f':	/* Read WCS from a FITS or IRAF file */
	    if (ac < 2)
		usage(c, "needs FITS or IRAF file name for header WCS");
	    wcsfile = *++av;
	    ac--;
	    break;

    	case 'g':	/* Output image center on command line in galactic */
    	    if (ac < 3)
    		usage(c,"needs galactic coordinates of output reference pixel");
	    setsys (WCS_GALACTIC);
	    outsys = WCS_GALACTIC;
	    strcpy (rastr, *++av);
	    ac--;
	    strcpy (decstr, *++av);
	    ac--;
	    setcenter (rastr, decstr);
	    centerset = 1;
    	    break;

	case 'i':	/* Bits per output pixel in FITS code */
    	    if (ac < 2)
    		usage(c, "needs bits per output pixel");
    	    bitpix0 = atoi (*++av);
    	    ac--;
    	    break;

    	case 'j':	/* Output image center on command line in J2000 */
    	    if (ac < 3)
    		usage(c, "needs J2000 coordinates of output reference pixel");
	    setsys (WCS_J2000);
	    outsys = WCS_J2000;
	    strcpy (rastr, *++av);
	    ac--;
	    strcpy (decstr, *++av);
	    ac--;
	    setcenter (rastr, decstr);
	    centerset = 1;
    	    break;

    	case 'l':	/* Logging interval for processing */
    	    if (ac < 2)
    		usage(c, "needs logging interval");
    	    nlog = atoi (*++av);
    	    ac--;
    	    break;

	case 'n':	 /* value for blank (null) pixel */
    	    if (ac < 2)
    		usage(c, "needs a blank pixel value");
    	    blankpix = atof (*++av);
    	    ac--;
    	    break;

    	case 'o':	/* Specifiy output image filename */
    	    if (ac < 2)
    		usage(c, "needs a filename");
	    outname = *++av;
	    ac--;
    	    break;

    	case 'p':	/* Output image plate scale in arcseconds per pixel */
    	    if (ac < 2)
    		usage(c, "needs a plate scale");
	    secpix = atof (*++av);
    	    setsecpix (secpix);
    	    ac--;
	    if (ac > 1 && isnum (*(av+1))) {
		secpix2 = atof (*++av);
		setsecpix2 (secpix2);
		ac--;
		}
    	    break;

	case 's':	/* Use BSCALE and BZERO to scale output image pixels */
	    setscale (1);
    	    break;

	case 't':	/* Number of samples per linear input pixel */
    	    if (ac < 2)
    		usage(c, "needs a number of samples per input pixel");
    	    remappix = atoi (*++av);
    	    ac--;
    	    break;

	case 'u':	/* Delete distortion keywords */
	    undistort++;
	    break;

	case 'v':	/* more verbosity */
	    verbose++;
	    break;

	case 'w':	/* Set WCS projection */
	    if (ac < 2)
		usage(c, "needs a WCS projection");
	    wcsproj = *++av;
	    lwcs = strlen (wcsproj);
	    for (i =0; i < lwcs; i++) {
		if (wcsproj[i] > 96)
		    wcsproj[i] = wcsproj[i] - 64;
		}
	    ac--;
	    break;

	case 'x':	/* X and Y coordinates of output image reference pixel */
	    if (ac < 3)
		usage(c, "needs X and Y coordinates of reference pixel");
	    xrpix = atof (*++av);
	    ac--;
	    yrpix = atof (*++av);
	    ac--;
    	    setrefpix (xrpix, yrpix);
    	    break;

	case 'y':	/* Dimensions of output image in pixels */
	    if (ac < 3)
		usage(c, "needs x and y dimensions of output image");
	    nx = atoi (*++av);
	    ac--;
	    ny = atoi (*++av);
	    ac--;
    	    setnpix (nx, ny);
    	    break;

	case 'z':       /* Use AIPS classic WCS */
	    setdefwcs (WCS_ALT);
	    break;

	case '@':	/* List of files to be read */
	    readlist++;
	    listfile = ++str;
	    str = str + strlen (str) - 1;
	    av++;
	    ac--;
	    break;

	default:
	    usage(c,"Argument not recognized");
	    break;
	}
    }

    /* Find number of images to stack  and leave listfile open for reading */
    if (readlist) {
	if ((flist = fopen (listfile, "r")) == NULL) {
	    sprintf (errmsg,"List file %s cannot be read", listfile);
	    usage ((char) 0, errmsg);
	    }
	while (fgets (filename, 128, flist) != NULL)
	    nfiles++;
	fclose (flist);
	flist = NULL;
	if (nfiles > 0)
	    flist = fopen (listfile, "r");
	}

    /* If no arguments left, print usage */
    else if (ac == 0)
	usage((char)0, "No arguments left");

    /* Read ac remaining file names starting at av[0] */
    else {
	while (ac-- > 0) {
	    filelist[nfiles] = *av++;
	    if (verbose)
		printf ("Reading %s\n",filelist[nfiles]);
	    nfiles++;
	    }
	}

    /* Set up FITS header and WCS for output file */

    /* Remap images */
    for (ifile = 0;  ifile < nfiles; ifile++) {
	if (readlist) {
	    if (fgets (filename, 128, flist) != NULL) {
		filename[strlen (filename) - 1] = 0;
		if (RemapImage (ifile, filename))
		    break;
		}
	    }
	else {
	    if (RemapImage (ifile, filelist[ifile]))
		break;
	    }
	}

    if (readlist)
	fclose (flist);

    /* Write output image */
    if (iraffile && !fitsout) {
        if (irafwimage (outname, lhead, irafheader, headout, imout) > 0 && verbose)
            printf ("%s: written successfully.\n", outname);
        }
    else {
        if (fitswimage (outname, headout, imout) > 0 && verbose)
            printf ("%s: written successfully.\n", outname);
        }

    free (headout);
    wcsfree (wcsout);
    free (imout);
    return (0);
}

static void
usage (arg, message)
char	arg;	/* single character command line argument */
char	*message;	/* Error message */

{
    fprintf (stderr,"%s\n",RevMsg);
    if (version)
	exit (-1);
    if (message != NULL)
	fprintf (stderr, "ERROR: %c %s\n", arg, message);
    fprintf (stderr,"Remap FITS or IRAF images into single FITS image using WCS\n");
    fprintf(stderr,"Usage: remap [-v][-f WCSfile][-a rot][[-b][-j] ra dec][-i bits][-l num] file1.fit file2.fit ... filen.fit\n");
    fprintf(stderr,"  or : remap [-v][-f WCSfile][-a rot][[-b][-j] ra dec][-i bits][-l num] @filelist\n");
    fprintf(stderr,"  -a: Output rotation angle in degrees (default 0)\n");
    fprintf(stderr,"  -b ra dec: Output center in B1950 (FK4) RA and Dec\n");
    fprintf(stderr,"  -e long lat: Output center in ecliptic longitude and latitude\n");
    fprintf(stderr,"  -f file: Use WCS from this file as output WCS\n");
    fprintf(stderr,"  -g long lat: Output center in galactic longitude and latitude\n");
    fprintf(stderr,"  -i num: Number of bits per output pixel (default is input)\n");
    fprintf(stderr,"  -j ra dec: center in J2000 (FK5) RA and Dec\n");
    fprintf(stderr,"  -l num: Log every num rows of output image\n");
    fprintf(stderr,"  -m mode: c closest pixel (more to come)\n");
    fprintf(stderr,"  -n num: integer pixel value for blank pixel\n");
    fprintf(stderr,"  -o name: Name for output image\n");
    fprintf(stderr,"  -p secpix: Output plate scale in arcsec/pixel (default =input)\n");
    fprintf(stderr,"  -s: Set BZERO and BSCALE in output file from input file\n");
    fprintf(stderr,"  -t: Number of samples per linear output pixel\n");
    fprintf(stderr,"  -u: Delete distortion keywords from output file\n");
    fprintf(stderr,"  -v: Verbose\n");
    fprintf(stderr,"  -w type: Output WCS type (input is default)\n");
    fprintf(stderr,"  -x x y: Output image reference X and Y coordinates (default is center)\n");
    fprintf(stderr,"  -y nx ny: Output image dimensions (default is first input image)\n");
    exit (1);
}


static int
RemapImage (ifile, filename)

int	ifile;		/* Sequence number of input file */
char	*filename;	/* FITS or IRAF file filename */

{
    char *image;		/* FITS input image */
    char *header;		/* FITS header */
    int nbhead;			/* Actual number of bytes in FITS header */
    int bitpix;
    int bitpixout = -32;
    double cra, cdec, dra, ddec;
    int hpin, wpin, hpout, wpout, nbout, npout;
    int iin = 0;
    int iout, jin, jout;
    int iout1, iout2, jout1, jout2;
    int idiff, jdiff;
    int offscl, lblock;
    char pixname[256];
    struct WorldCoor *wcsin;
    double bzin, bsin, bzout, bsout;
    double dx, secpixin1, secpixin2, secpix1, dpix, dnpix;
    double xout, yout, xin, yin, xpos, ypos, dpixi, dpixo, xout0, yout0;
    double xmin, xmax, ymin, ymax, xin1, xin2, yin1, yin2;
    double pixratio;
    char secstring[32];
    char history[80];
    char wcstemp[16];
    struct WorldCoor *GetWCSFITS();
    struct WorldCoor *GetFITSWCS();
    double *imvec;
    int npix;
    int addscale = 0;
    double *dxout, *dyout;
    char rastr[32];
    char decstr[32];

    /* Read input IRAF header and image */
    if (isiraf (filename)) {
	iraffile = 1;
	if ((irafheader = irafrhead (filename, &lhead)) != NULL) {
	    nbhead = 0;
	    if ((header = iraf2fits (filename,irafheader,lhead, &nbhead)) == NULL) {
		fprintf (stderr, "Cannot translate IRAF header %s/n",filename);
		free (irafheader);
		return (1);
		}
	    if ((image = irafrimage (header)) == NULL) {
		hgetm (header,"PIXFIL", 255, pixname);
		fprintf (stderr, "Cannot read IRAF pixel file %s\n", pixname);
		free (irafheader);
		free (header);
		return (1);
		}
	    }
	else {
	    fprintf (stderr, "Cannot read IRAF header file %s\n", filename);
	    return (1);
	    }
	}

    /* Or read input FITS image */
    else {
	iraffile = 0;
	if ((header = fitsrhead (filename, &lhead, &nbhead)) != NULL) {
	    if ((image = fitsrimage (filename, nbhead, header)) == NULL) {
		fprintf (stderr, "Cannot read FITS image %s\n", filename);
		free (header);
		return (1);
		}
	    }
	else {
	    fprintf (stderr, "Cannot read FITS file %s\n", filename);
	    return (1);
	    }
	}
    if (ifile < 1 && verbose)
	fprintf (stderr,"%s\n",RevMsg);

    /* Set input world coordinate system from first image header */
    wcsin = wcsinit (header);

    if (!outsys && !wcsfile)
	outsys = wcsin->syswcs;

    if (ifile < 1) {

	/* Read output image if one is specified */
	imout = NULL;
	if (outname != NULL) {
	    if (access (outname, F_OK)) {
		if (verbose)
		    fprintf (stderr, "REMAP: Writing file %s\n", outname);
		}
	    else if ((headout = fitsrhead (outname, &lhead, &nbhead)) != NULL) {
		if ((imout = fitsrimage (outname, nbhead, headout)) == NULL)
		    fprintf (stderr, "REMAP: Overwriting file %s\n", outname);
		}
	    }
	else
	    outname = outname0;

	/* Set output world coordinate system from existing output image header */
	if (imout != NULL)
	    wcsout = wcsinit (headout);

	/* Set output world coordinate system from another image header */
	else if (wcsfile) {
	    wcsout = GetWCSFITS (wcsfile, verbose);
	    outsys = wcsout->syswcs;
	    headout = fitsrhead (wcsfile, &lhead, &nbhead);
	    wpout = wcsout->nxpix;
	    hpout = wcsout->nypix;
	    }

	/* Otherwise set it from command line and first image */
	else {

	    /* Set output plate scale */
	    secpixin1 = wcsin->cdelt[1] * 3600.0;
	    secpixin2 = wcsin->cdelt[2] * 3600.0;
	    if (secpixin1 < 0)
		secpixin1 = -secpixin1;
	    if (secpix == 0)
		secpix = secpixin1;
	    if (secpix2 == 0)
		secpix2 = secpix;

	    /* Change output dimensions to match output plate scale */
	    if (secpix != 0.0)
		pixratio = fabs (secpixin1) / fabs (secpix);
	    else
		pixratio = 1.0;
	    if (nx == 0 && ny == 0) {
		nx = wcsin->nxpix * pixratio;
		ny = wcsin->nypix * pixratio;
    		setnpix (nx, ny);
		}

	    /* Set reference pixel to default of new image center */
	    if (nx != 0 && xrpix == 0.0 && yrpix == 0.0) {
		xrpix = 0.5 * (double) nx;
		yrpix = 0.5 * (double) ny;
		setrefpix (xrpix, yrpix);

	    /* Set center ra,dec of new image to center of old image if not set */
		if (!centerset) {
		    wcssize (wcsin, &cra, &cdec, &dra, &ddec);
		    ra2str (rastr, 32, cra, 4);
		    dec2str (decstr, 32, cdec, 3);
		    setcenter (rastr, decstr);
		    }
		}

	    /* Set output header from command line and first image header */
	    lhead = strlen (header);
	    lblock = lhead / 2880;
	    if (lblock * 2880  < lhead)
		lhead = (lblock+2) * 2880;
	    else
		lhead = (lblock+1) * 2880;
	    if (!(headout = (char *) calloc (lhead, sizeof (char)))) {
		fprintf (stderr, "REMAP: cannot allocate output image header\n");
        	return (1);
		}
	    strcpy (headout, header);

	    hputi4 (headout, "NAXIS1", nx);
	    hputi4 (headout, "NAXIS2", ny);

	    if (wcsproj != NULL || outsys != wcsin->syswcs) {
		if (wcsproj == NULL)
		    wcsproj = wcsin->ctype[0]+4;
		if (outsys == WCS_GALACTIC)
		    strcpy (wcstemp, "GLON-");
		else if (outsys == WCS_ECLIPTIC)
		    strcpy (wcstemp, "ELON-");
		else
		    strcpy (wcstemp, "RA---");
		strcat (wcstemp, wcsproj);
	        hputs  (headout, "CTYPE1", wcstemp);

		if (outsys == WCS_GALACTIC)
		    strcpy (wcstemp, "GLAT-");
		else if (outsys == WCS_ECLIPTIC)
		    strcpy (wcstemp, "ELAT-");
		else
		    strcpy (wcstemp, "DEC--");
		strcat (wcstemp, wcsproj);
		hputs  (headout, "CTYPE2", wcstemp);
		}
	    hputr8 (headout, "CRPIX1", xrpix);
	    hputr8 (headout, "CRPIX2", yrpix);
	    hputr8 (headout, "CDELT1", -secpix/3600.0);
	    hputr8 (headout, "CDELT2", secpix2/3600.0);
	    if (hgetr8 (headout, "SECPIX1", &secpix1)) {
		hputr8 (headout, "SECPIX1", secpix);
		hputr8 (headout, "SECPIX2", secpix2);
		}
	    else if (hgetr8 (headout, "SECPIX", &secpix1)) {
		if (secpix == secpix2)
		    hputr8 (headout, "SECPIX", secpix);
		else {
		    hputr8 (headout, "SECPIX1", secpix);
		    hputr8 (headout, "SECPIX2", secpix2);
		    }
		}

	    /* Delete distortion keywords from header if requested */
	    if (undistort)
		DelDistort (headout, verbose);

	    /* Set output WCS from command line and first image header */
	    wcsout = GetFITSWCS (filename, headout, verbose, &cra, &cdec, &dra,
			 &ddec, &secpix, &wpout, &hpout, &eqsys, &equinox);
	    }

	hgeti4 (header, "BITPIX", &bitpix);
	if (bitpix0 != 0) {
	    hputi4 (headout, "BITPIX", bitpix0);
	    bitpixout = bitpix0;
	    }
	else
	    bitpixout = bitpix;

	/* Warn if remapping is not acceptable */
	pixratio = wcsin->xinc / wcsout->xinc;
	if (remappix == 0)
	    remappix = 1;

	/* Allocate space for output image */
	if (imout == NULL) {
	    npout = hpout * wpout;
	    nbout = npout * bitpixout / 8;
	    if (nbout < 0)
		nbout = -nbout;
	    if (!(imout = (char * ) calloc (nbout, 1))) {
		fprintf (stderr, "REMAP: cannot allocate output image\n");
        	return (1);
		}

	    /* Fill output image */
	    bsin = 1.0;
	    hgetr8 (header, "BSCALE", &bsin);
	    bzin = 0.0;
	    hgetr8 (header, "BZERO", &bzin);
	    bsout = 1.0;
	    hgetr8 (header, "BSCALE", &bsout);
	    bzout = 0.0;
	    hgetr8 (header, "BZERO", &bzout);

	    /* Delete data section keywords which do not apply to output image */
	    hdel (headout, "DATASEC");
	    hdel (headout, "CCDSEC");
	    hdel (headout, "TRIMSEC");
	    hdel (headout, "BIASSEC");
	    hdel (headout, "ORIGSEC");

	    /* Add source of WCS if not from command line */
	    if (wcsfile) {
		sprintf (history, "REMAP WCS from file %s", wcsfile);
		hputc (headout, "HISTORY", history);
		}

	    /* Fill output image with value of blank pixels if not zero */
	    if (blankpix != 0.0 || bzout != 0.0) {
		if (!(imvec = (double *) calloc (wpout, sizeof (double)))) {
		    fprintf (stderr, "REMAP: cannot allocate blank pixel vector\n");
        	    return (1);
		    }
		if (verbose)
		    fprintf (stderr,"REMAP: Filling output image with blank pixel %f\n",
			     blankpix);

		npix = hpout * wpout;
		fillvec1 (imout, bitpixout, bzout, bsout, 1, npix, blankpix);
		}

	    /* Save blank pixel value in the image header */
	    if (bitpixout > 0) {
		int iblank;
		if (blankpix > 0.0)
		    iblank = (int) (blankpix + 0.5);
		else if (blankpix < 0.0)
		    iblank = (int) (blankpix - 0.5);
		else
		    iblank = 0;
		hputi4 (headout, "BLANK", iblank);
		}
	    else {
		hputnr8 (headout, "BLANK", 1, blankpix);
		}

	    /* Set output WCS output coordinate system to input coordinate system*/
	    wcsout->sysout = wcsin->syswcs;
	    }

	/* Set local used parameters if filling existing image */
	else {
	    }
	}

    /* Set input WCS output coordinate system to output coordinate system */
    wcsin->sysout = wcsout->syswcs;
    strcpy (wcsin->radecout, wcsout->radecsys);
    wpin = wcsin->nxpix;
    hpin = wcsin->nypix;

    sprintf (history, "REMAP input file %s", filename);
    hputc (headout, "HISTORY", history);

    /* Find limiting edges of input image in output image */
    if (hgets (header, "DATASEC", 32, secstring)) {
	getsection (secstring, wpin, hpin, &xin1, &xin2, &yin1, &yin2);
	if (verbose)
	    printf ("REMAP: Input file %d x: %d-%d, y: %d-%d\n", ifile,
		(int)(xin1+0.5), (int)(xin2+0.5), (int)(yin1+0.5),
		(int)(yin2+0.5));
	}
    else {
	xin1 = 1.0;
	xin2 = (double) wpin;
	yin1 = 1.0;
	yin2 = (double) hpin;
	}
    pix2wcs (wcsin, xin1, yin1, &xpos, &ypos);
    wcscon (wcsin->syswcs,wcsout->syswcs,wcsin->equinox,wcsout->equinox,
	    &xpos,&ypos,wcsin->epoch);
    wcs2pix (wcsout, xpos, ypos, &xout, &yout, &offscl);
    xmin = xout;
    xmax = xout;
    ymin = yout;
    ymax = yout;
    pix2wcs (wcsin, xin1, yin2, &xpos, &ypos);
    wcscon (wcsin->syswcs,wcsout->syswcs,wcsin->equinox,wcsout->equinox,
	    &xpos,&ypos,wcsin->epoch);
    wcs2pix (wcsout, xpos, ypos, &xout, &yout, &offscl);
    if (xout < xmin) xmin = xout;
    if (xout > xmax) xmax = xout;
    if (yout < ymin) ymin = yout;
    if (yout > ymax) ymax = yout;
    pix2wcs (wcsin, xin2, yin1, &xpos, &ypos);
    wcscon (wcsin->syswcs,wcsout->syswcs,wcsin->equinox,wcsout->equinox,
	    &xpos,&ypos,wcsin->epoch);
    wcs2pix (wcsout, xpos, ypos, &xout, &yout, &offscl);
    if (xout < xmin) xmin = xout;
    if (xout > xmax) xmax = xout;
    if (yout < ymin) ymin = yout;
    if (yout > ymax) ymax = yout;
    pix2wcs (wcsin, xin2, yin2, &xpos, &ypos);
    wcscon (wcsin->syswcs,wcsout->syswcs,wcsin->equinox,wcsout->equinox,
	    &xpos,&ypos,wcsin->epoch);
    wcs2pix (wcsout, xpos, ypos, &xout, &yout, &offscl);
    if (xout < xmin) xmin = xout;
    if (xout > xmax) xmax = xout;
    if (yout < ymin) ymin = yout;
    if (yout > ymax) ymax = yout;
    iout1 = (int) (ymin + 0.5);
    if (iout1 < 1) iout1 = 1;
    iout2 = (int) (ymax + 0.5);
    if (iout2 > hpout) iout2 = hpout;
    jout1 = (int) (xmin + 0.5);
    if (jout1 < 1) jout1 = 1;
    jout2 = (int) (xmax + 0.5);
    if (jout2 > wpout) jout2 = wpout;

    if (verbose)
	printf ("REMAP: Output x: %d-%d, y: %d-%d\n",
		jout1,jout2,iout1,iout2);

    /* Eliminate rescaling if input and output scaling is the same */
    if (bzin == bzout && bsin == bsout) {
	if (bzin != 0.0 && bsin != 1.0)
	    addscale = 1;
	else
	    addscale = 0;
	blankpix = (blankpix + bzin) / bsin;
	setscale (0);
	}

    dxout = (double *) calloc (remappix, sizeof (double));
    dyout = (double *) calloc (remappix, sizeof (double));
    if (remappix > 1) {
	dpix = 1.0 / (double) remappix;
	dx = -0.5 + (0.5 * dpix);
	for (idiff = 0; idiff < remappix; idiff++) {
	    dxout[idiff] = dx;
	    dyout[idiff] = dx;
	    dx = dx + dpix;
	    }
	}
    else {
	dxout[0] = 0.0;
	dyout[0] = 0.0;
	}

    /* Loop through vertical pixels (output image lines) */
    for (iout = iout1; iout <= iout2; iout++) {
	yout0 = (double) iout;

	/* Loop through horizontal pixels (output image columns) */
	for (jout = jout1; jout <= jout2; jout++) {
	    xout0 = (double) jout;

	    /* Read pixel from output file */
	    dpixo = getpix1 (imout,bitpixout,wpout,hpout,bzout,bsout,jout,iout);
	    dpix = 0.0;
	    dnpix = 0.0;

	    for (idiff = 0; idiff < remappix; idiff++) {
		xout = xout0 + dxout[idiff];

		for (jdiff = 0; jdiff < remappix; jdiff++) {
		    yout = yout0 + dyout[idiff];

		    /* Get WCS coordinates of this pixel in output image */
		    pix2wcs (wcsout, xout, yout, &xpos, &ypos);
		    if (!wcsout->offscl) {

			/* Convert to output coordinate system */
			wcscon (wcsin->syswcs,wcsout->syswcs,wcsin->equinox,wcsout->equinox,
				&xpos,&ypos,wcsin->epoch);

			/* Get image coordinates of this subpixel in input image */
			wcs2pix (wcsin, xpos, ypos, &xin, &yin, &offscl);
			if (!offscl) {
			    iin = (int) (yin + 0.5);
			    jin = (int) (xin + 0.5);

			    /* Read pixel from input file */
			    dpixi = getpix1 (image,bitpix,wpin,hpin,bzin,bsin,jin,iin);
			    if (dpixi != blankpix) {
				dpix = dpix + dpixi;
				dnpix = dnpix + 1.0;
				}
			    }
			}
		    }
		if (dnpix > 0.0)
		    dpix = dpix / dnpix;
		else
		    dpix = blankpix;

		/* If output pixel is blank, set rather than add */
		if (dpixo == blankpix) {
		    putpix1 (imout,bitpixout,wpout,hpout,bzout,bsout,jout,iout,dpix);
		    }

		/* Otherwise add to current pixel value and write to output image */
		else {
		    if (addscale)
			dpix = (dpix - bzin);
		    dpixo = dpixo + dpix;
		    putpix1 (imout,bitpixout,wpout,hpout,bzout,bsout,jout,iout,dpixo);
		    }
		}
	    }

	if (nlog > 0 && iout%nlog == 0)
	    fprintf (stderr,"REMAP: Output image line %04d / %04d filled from %d / %d.\r",
		     iout, iout2, iin, hpin);
	}
    if (nlog > 0)
	printf ("\n");

    free (header);
    free (image);
    wcsfree (wcsin);
    return (0);
}


static void
getsection (section, nx, ny, x1, x2, y1, y2)

char	*section;	/* Header value string for *SEC keyword */
int	nx;		/* Dimension in X */
int	ny;		/* Dimension in Y */
double	*x1;		/* Lower left x coordinate (returned) */
double	*x2;		/* Lower right x coordinate (returned) */
double	*y1;		/* Lower left y coordinate (returned) */
double	*y2;		/* Upper right y coordinate (returned) */

{
    char *next;
    *x1 = 1.0;
    next = section;
    if (*next == '[') next++;
    *x1 = atof (next);
    *x2 = (double) nx;
    if ((next = strchr (next, ':')) != NULL)
	*x2 = atof (next + 1);
    *y1 = 1.0;
    if ((next = strchr (next, ',')) != NULL)
	*y1 = atof (next + 1);
    *y2 = (double) ny;
    if ((next = strchr (next, ':')) != NULL)
	*y2 = atof (next + 1);
    return;
}


/* Sep 28 1999	New program
 * Oct 22 1999	Drop unused variables after lint
 * Oct 22 1999	Add optional second plate scale argument
 * Nov 19 1999	Add galactic coordinate output option
 * Dec  3 1999	Add option to set output BITPIX
 *
 * Jan 28 2000	Call setdefwcs() with WCS_ALT instead of 1
 * Mar 23 2000	Use hgetm() to get the IRAF pixel file name, not hgets()
 *
 * Apr 13 2001	Set default center to center of output image, not input
 * Jul  2 2001	Fix recentering bug
 * Jul  5 2001	Simplify output by just grabbing the closest input pixel
 * Jul  9 2001	Write projection type into CRVALn of output file
 * Jul 10 2001	Fix -w help message so it correctly notes input proj is default
 * Jul 10 2001	Set CTYPEn correctly for ecliptic or galactic output
 *
 * Apr  9 2002	Do not free unallocated header
 *
 * May 23 2003	Add -e for ecliptic coordinates
 * Aug 14 2003	Add option to read WCS from FITS or IRAF image file using -f
 * Aug 18 2003	Add -n option to set BLANK pixel value
 * Nov 18 2003	Fix error returns in RemapImage() to always return 1
 *
 * Jan 15 2004	Add -u to delete distortion keywords from output file
 * Jan 23 2004	Finish implementing blank pixel setting
 * Feb 27 2004	Add -s option to use BZERO and BSCALE in output image
 * Feb 27 2004	Fix bugs in BLANK initialization; allow multiple input files
 * Feb 27 2004	Use DATASEC to limit input data coordinates if it is present
 * Mar  1 2004	Do not rescale pixels if unnecessary
 * Apr 28 2004	Return error on failure of any memory allocation
 * Aug 30 2004	Add multiple samples from output to input images
 * Oct 12 2004	Fix message if writing to named file and print only if verbose
 *
 * Apr  6 2006	Convert between coordinate systems if requested
 * Apr 19 2006	Check to see if output file exists before reading its header
 * Jun 21 2006	Clean up code
 * Jun 22 2006	Fix bug checking for pre-existing output file
 * Aug 16 2006	Check for output image off-scale as well as input image
 * Sep 11 2006	Cleanup scaling
 * Sep 26 2006	Increase length of rastr and destr from 16 to 32
 *
 * Jan 10 2007	Drop unused variable dy
 *
 * Oct 15 2010	Use center coordinates of original image if not set
 *
 * Sep 17 2013  Include fitswcs.h
 *
 * Feb 19 2014	Update usage to -f WCSfile suggested by Steve Willner
 *
 * Mar 19 2015	Declare GetFITSWCS()
 */
