summaryrefslogtreecommitdiffstats
path: root/funtools/wcs/tnxpos.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-26 21:13:00 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-26 21:13:00 (GMT)
commitda2e3d212171bbe64c1af39114fd067308656990 (patch)
tree9601f7ed15fa1394762124630c12a792bc073ec2 /funtools/wcs/tnxpos.c
parent76b109ad6d97d19ab835596dc70149ef379f3733 (diff)
downloadblt-da2e3d212171bbe64c1af39114fd067308656990.zip
blt-da2e3d212171bbe64c1af39114fd067308656990.tar.gz
blt-da2e3d212171bbe64c1af39114fd067308656990.tar.bz2
rm funtools for update
Diffstat (limited to 'funtools/wcs/tnxpos.c')
-rw-r--r--funtools/wcs/tnxpos.c1234
1 files changed, 0 insertions, 1234 deletions
diff --git a/funtools/wcs/tnxpos.c b/funtools/wcs/tnxpos.c
deleted file mode 100644
index e13d78e..0000000
--- a/funtools/wcs/tnxpos.c
+++ /dev/null
@@ -1,1234 +0,0 @@
-/*** File wcslib/tnxpos.c
- *** September 17, 2008
- *** By Jessica Mink, jmink@cfa.harvard.edu
- *** Harvard-Smithsonian Center for Astrophysics
- *** After IRAF mwcs/wftnx.x and mwcs/wfgsurfit.x
- *** Copyright (C) 1998-2008
- *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- Correspondence concerning WCSTools should be addressed as follows:
- Internet email: jmink@cfa.harvard.edu
- Postal address: Jessica Mink
- Smithsonian Astrophysical Observatory
- 60 Garden St.
- Cambridge, MA 02138 USA
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include "wcs.h"
-
-#define SPHTOL 0.00001
-#define BADCVAL 0.0
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-
-/* wftnx -- wcs function driver for the gnomonic projection with correction.
- * tnxinit (header, wcs)
- * tnxclose (wcs)
- * tnxfwd (xpix, ypix, wcs, xpos, ypos) Pixels to WCS
- * tnxrev (xpos, ypos, wcs, xpix, ypix) WCS to pixels
- */
-
-#define max_niter 500
-#define SZ_ATSTRING 2000
-static void wf_gsclose();
-static void wf_gsb1pol();
-static void wf_gsb1leg();
-static void wf_gsb1cheb();
-
-/* tnxinit -- initialize the gnomonic forward or inverse transform.
- * initialization for this transformation consists of, determining which
- * axis is ra / lon and which is dec / lat, computing the celestial longitude
- * and colatitude of the native pole, reading in the the native longitude
- * of the pole of the celestial coordinate system longpole from the attribute
- * list, precomputing euler angles and various intermediaries derived from the
- * coordinate reference values, and reading in the projection parameter ro
- * from the attribute list. if longpole is undefined then a value of 180.0
- * degrees is assumed. if ro is undefined a value of 180.0 / pi is assumed.
- * the tan projection is equivalent to the azp projection with mu set to 0.0.
- * in order to determine the axis order, the parameter "axtype={ra|dec}
- * {xlon|glat}{xlon|elat}" must have been set in the attribute list for the
- * function. the longpole and ro parameters may be set in either or both of
- * the axes attribute lists, but the value in the ra axis attribute list takes
- * precedence.
- */
-
-int
-tnxinit (header, wcs)
-
-const char *header; /* FITS header */
-struct WorldCoor *wcs; /* pointer to WCS structure */
-{
- struct IRAFsurface *wf_gsopen();
- char *str1, *str2, *lngstr, *latstr;
- extern void wcsrotset();
-
- /* allocate space for the attribute strings */
- str1 = malloc (SZ_ATSTRING);
- str2 = malloc (SZ_ATSTRING);
- hgetm (header, "WAT1", SZ_ATSTRING, str1);
- hgetm (header, "WAT2", SZ_ATSTRING, str2);
-
- lngstr = malloc (SZ_ATSTRING);
- latstr = malloc (SZ_ATSTRING);
-
- /* determine the native longitude of the pole of the celestial
- coordinate system corresponding to the FITS keyword longpole.
- this number has no default and should normally be set to 180
- degrees. search both axes for this quantity. */
-
- if (wcs->longpole > 360.0) {
- if (!igetr8 (str1, "longpole", &wcs->longpole)) {
- if (!igetr8 (str2, "longpole", &wcs->longpole))
- wcs->longpole = 180.0;
- }
- }
-
- /* Fetch the ro projection parameter which is the radius of the
- generating sphere for the projection. if ro is absent which
- is the usual case set it to 180 / pi. search both axes for
- this quantity. */
-
- if (!igetr8 (str1, "ro", &wcs->rodeg)) {
- if (!igetr8 (str2, "ro", &wcs->rodeg))
- wcs->rodeg = 180.0 / PI;
- }
-
- /* Fetch the longitude correction surface. note that the attribute
- string may be of any length so the length of atvalue may have
- to be adjusted. */
-
- if (!igets (str1, "lngcor", SZ_ATSTRING, lngstr)) {
- if (!igets (str2, "lngcor", SZ_ATSTRING, lngstr))
- wcs->lngcor = NULL;
- else
- wcs->lngcor = wf_gsopen (lngstr);
- }
- else
- wcs->lngcor = wf_gsopen (lngstr);
-
- /* Fetch the latitude correction surface. note that the attribute
- string may be of any length so the length of atvalue may have
- to be adjusted. */
-
- if (!igets (str2, "latcor", SZ_ATSTRING, latstr)) {
- if (!igets (str1, "latcor", SZ_ATSTRING, latstr))
- wcs->latcor = NULL;
- else
- wcs->latcor = wf_gsopen (latstr);
- }
- else
- wcs->latcor = wf_gsopen (latstr);
-
- /* Compute image rotation */
- wcsrotset (wcs);
-
- /* free working space. */
- free (str1);
- free (str2);
- free (lngstr);
- free (latstr);
-
- /* Return 1 if there are no correction coefficients */
- if (wcs->latcor == NULL && wcs->lngcor == NULL)
- return (1);
- else
- return (0);
-}
-
-
-/* tnxpos -- forward transform (physical to world) gnomonic projection. */
-
-int
-tnxpos (xpix, ypix, wcs, xpos, ypos)
-
-double xpix, ypix; /*i physical coordinates (x, y) */
-struct WorldCoor *wcs; /*i pointer to WCS descriptor */
-double *xpos, *ypos; /*o world coordinates (ra, dec) */
-{
- int ira, idec;
- double x, y, r, phi, theta, costhe, sinthe, dphi, cosphi, sinphi, dlng, z;
- double colatp, coslatp, sinlatp, longp;
- double xs, ys, ra, dec, xp, yp;
- double wf_gseval();
-
- /* Convert from pixels to image coordinates */
- xpix = xpix - wcs->crpix[0];
- ypix = ypix - wcs->crpix[1];
-
- /* Scale and rotate using CD matrix */
- if (wcs->rotmat) {
- x = xpix * wcs->cd[0] + ypix * wcs->cd[1];
- y = xpix * wcs->cd[2] + ypix * wcs->cd[3];
- }
-
- else {
-
- /* Check axis increments - bail out if either 0 */
- if (wcs->cdelt[0] == 0.0 || wcs->cdelt[1] == 0.0) {
- *xpos = 0.0;
- *ypos = 0.0;
- return 2;
- }
-
- /* Scale using CDELT */
- xs = xpix * wcs->cdelt[0];
- ys = ypix * wcs->cdelt[1];
-
- /* Take out rotation from CROTA */
- if (wcs->rot != 0.0) {
- double cosr = cos (degrad (wcs->rot));
- double sinr = sin (degrad (wcs->rot));
- x = xs * cosr - ys * sinr;
- y = xs * sinr + ys * cosr;
- }
- else {
- x = xs;
- y = ys;
- }
- }
-
- /* get the axis numbers */
- if (wcs->coorflip) {
- ira = 1;
- idec = 0;
- }
- else {
- ira = 0;
- idec = 1;
- }
- colatp = degrad (90.0 - wcs->crval[idec]);
- coslatp = cos(colatp);
- sinlatp = sin(colatp);
- longp = degrad(wcs->longpole);
-
- /* Compute native spherical coordinates phi and theta in degrees from the
- projected coordinates. this is the projection part of the computation */
- if (wcs->lngcor != NULL)
- xp = x + wf_gseval (wcs->lngcor, x, y);
- else
- xp = x;
- if (wcs->latcor != NULL)
- yp = y + wf_gseval (wcs->latcor, x, y);
- else
- yp = y;
- x = xp;
- y = yp;
- r = sqrt (x * x + y * y);
-
- /* Compute phi */
- if (r == 0.0)
- phi = 0.0;
- else
- phi = atan2 (x, -y);
-
- /* Compute theta */
- theta = atan2 (wcs->rodeg, r);
-
- /* Compute the celestial coordinates ra and dec from the native
- coordinates phi and theta. this is the spherical geometry part
- of the computation */
-
- costhe = cos (theta);
- sinthe = sin (theta);
- dphi = phi - longp;
- cosphi = cos (dphi);
- sinphi = sin (dphi);
-
- /* Compute the ra */
- x = sinthe * sinlatp - costhe * coslatp * cosphi;
- if (fabs (x) < SPHTOL)
- x = -cos (theta + colatp) + costhe * coslatp * (1.0 - cosphi);
- y = -costhe * sinphi;
- if (x != 0.0 || y != 0.0)
- dlng = atan2 (y, x);
- else
- dlng = dphi + PI ;
- ra = wcs->crval[ira] + raddeg(dlng);
-
- /* normalize ra */
- if (wcs->crval[ira] >= 0.0) {
- if (ra < 0.0)
- ra = ra + 360.0;
- }
- else {
- if (ra > 0.0)
- ra = ra - 360.0;
- }
- if (ra > 360.0)
- ra = ra - 360.0;
- else if (ra < -360.0)
- ra = ra + 360.0;
-
- /* compute the dec */
- if (fmod (dphi, PI) == 0.0) {
- dec = raddeg(theta + cosphi * colatp);
- if (dec > 90.0)
- dec = 180.0 - dec;
- if (dec < -90.0)
- dec = -180.0 - dec;
- }
- else {
- z = sinthe * coslatp + costhe * sinlatp * cosphi;
- if (fabs(z) > 0.99) {
- if (z >= 0.0)
- dec = raddeg(acos (sqrt(x * x + y * y)));
- else
- dec = raddeg(-acos (sqrt(x * x + y * y)));
- }
- else
- dec = raddeg(asin (z));
- }
-
- /* store the results */
- *xpos = ra;
- *ypos = dec;
- return (0);
-}
-
-
-/* tnxpix -- inverse transform (world to physical) gnomonic projection */
-
-int
-tnxpix (xpos, ypos, wcs, xpix, ypix)
-
-double xpos, ypos; /*i world coordinates (ra, dec) */
-struct WorldCoor *wcs; /*i pointer to WCS descriptor */
-double *xpix, *ypix; /*o physical coordinates (x, y) */
-{
- int ira, idec, niter;
- double ra, dec, cosdec, sindec, cosra, sinra, x, y, phi, theta;
- double s, r, dphi, z, dpi, dhalfpi, twopi, tx;
- double xm, ym, f, fx, fy, g, gx, gy, denom, dx, dy;
- double colatp, coslatp, sinlatp, longp, sphtol;
- double wf_gseval(), wf_gsder();
-
- /* get the axis numbers */
- if (wcs->coorflip) {
- ira = 1;
- idec = 0;
- }
- else {
- ira = 0;
- idec = 1;
- }
-
- /* Compute the transformation from celestial coordinates ra and
- dec to native coordinates phi and theta. this is the spherical
- geometry part of the transformation */
-
- ra = degrad (xpos - wcs->crval[ira]);
- dec = degrad (ypos);
- cosra = cos (ra);
- sinra = sin (ra);
- cosdec = cos (dec);
- sindec = sin (dec);
- colatp = degrad (90.0 - wcs->crval[idec]);
- coslatp = cos (colatp);
- sinlatp = sin (colatp);
- if (wcs->longpole == 999.0)
- longp = degrad (180.0);
- else
- longp = degrad(wcs->longpole);
- dpi = PI;
- dhalfpi = dpi * 0.5;
- twopi = PI + PI;
- sphtol = SPHTOL;
-
- /* Compute phi */
- x = sindec * sinlatp - cosdec * coslatp * cosra;
- if (fabs(x) < sphtol)
- x = -cos (dec + colatp) + cosdec * coslatp * (1.0 - cosra);
- y = -cosdec * sinra;
- if (x != 0.0 || y != 0.0)
- dphi = atan2 (y, x);
- else
- dphi = ra - dpi;
- phi = longp + dphi;
- if (phi > dpi)
- phi = phi - twopi;
- else if (phi < -dpi)
- phi = phi + twopi;
-
- /* Compute theta */
- if (fmod (ra, dpi) == 0.0) {
- theta = dec + cosra * colatp;
- if (theta > dhalfpi)
- theta = dpi - theta;
- if (theta < -dhalfpi)
- theta = -dpi - theta;
- }
- else {
- z = sindec * coslatp + cosdec * sinlatp * cosra;
- if (fabs (z) > 0.99) {
- if (z >= 0.0)
- theta = acos (sqrt(x * x + y * y));
- else
- theta = -acos (sqrt(x * x + y * y));
- }
- else
- theta = asin (z);
- }
-
- /* Compute the transformation from native coordinates phi and theta
- to projected coordinates x and y */
-
- s = sin (theta);
- if (s == 0.0) {
- x = BADCVAL;
- y = BADCVAL;
- }
- else {
- r = wcs->rodeg * cos (theta) / s;
- if (wcs->lngcor == NULL && wcs->latcor == NULL) {
- if (wcs->coorflip) {
- y = r * sin (phi);
- x = -r * cos (phi);
- }
- else {
- x = r * sin (phi);
- y = -r * cos (phi);
- }
- }
- else {
- xm = r * sin (phi);
- ym = -r * cos (phi);
- x = xm;
- y = ym;
- niter = 0;
- while (niter < max_niter) {
- if (wcs->lngcor != NULL) {
- f = x + wf_gseval (wcs->lngcor, x, y) - xm;
- fx = wf_gsder (wcs->lngcor, x, y, 1, 0);
- fx = 1.0 + fx;
- fy = wf_gsder (wcs->lngcor, x, y, 0, 1);
- }
- else {
- f = x - xm;
- fx = 1.0 ;
- fy = 0.0;
- }
- if (wcs->latcor != NULL) {
- g = y + wf_gseval (wcs->latcor, x, y) - ym;
- gx = wf_gsder (wcs->latcor, x, y, 1, 0);
- gy = wf_gsder (wcs->latcor, x, y, 0, 1);
- gy = 1.0 + gy;
- }
- else {
- g = y - ym;
- gx = 0.0 ;
- gy = 1.0;
- }
-
- denom = fx * gy - fy * gx;
- if (denom == 0.0)
- break;
- dx = (-f * gy + g * fy) / denom;
- dy = (-g * fx + f * gx) / denom;
- x = x + dx;
- y = y + dy;
- if (MAX(MAX(fabs(dx),fabs(dy)),MAX(fabs(f),fabs(g))) < 2.80e-8)
- break;
-
- niter = niter + 1;
- }
-
- /* Reverse x and y if axes flipped */
- if (wcs->coorflip) {
- tx = x;
- x = y;
- y = tx;
- }
- }
- }
-
- /* Scale and rotate using CD matrix */
- if (wcs->rotmat) {
- *xpix = x * wcs->dc[0] + y * wcs->dc[1];
- *ypix = x * wcs->dc[2] + y * wcs->dc[3];
- }
-
- else {
-
- /* Correct for rotation */
- if (wcs->rot!=0.0) {
- double cosr = cos (degrad (wcs->rot));
- double sinr = sin (degrad (wcs->rot));
- *xpix = x * cosr + y * sinr;
- *ypix = y * cosr - x * sinr;
- }
- else {
- *xpix = x;
- *ypix = y;
- }
-
- /* Scale using CDELT */
- if (wcs->xinc != 0.)
- *xpix = *xpix / wcs->xinc;
- if (wcs->yinc != 0.)
- *ypix = *ypix / wcs->yinc;
- }
-
- /* Convert to pixels */
- *xpix = *xpix + wcs->xrefpix;
- *ypix = *ypix + wcs->yrefpix;
-
- return (0);
-}
-
-
-/* TNXCLOSE -- free up the distortion surface pointers */
-
-void
-tnxclose (wcs)
-
-struct WorldCoor *wcs; /* pointer to the WCS descriptor */
-
-{
- if (wcs->lngcor != NULL)
- wf_gsclose (wcs->lngcor);
- if (wcs->latcor != NULL)
- wf_gsclose (wcs->latcor);
- return;
-}
-
-/* copyright(c) 1986 association of universities for research in astronomy inc.
- * wfgsurfit.x -- surface fitting package used by wcs function drivers.
- * Translated to C from SPP by Jessica Mink, SAO, May 26, 1998
- *
- * the following routines are used by the experimental function drivers tnx
- * and zpx to decode polynomial fits stored in the image header in the form
- * of a list of parameters and coefficients into surface descriptors in
- * ra / dec or longitude latitude. the polynomial surfaces so encoded consist
- * of corrections to function drivers tan and zpn. the package routines are
- * modelled after the equivalent gsurfit routines and are consistent with them.
- * the routines are:
- *
- * sf = wf_gsopen (wattstr)
- * wf_gsclose (sf)
- *
- * z = wf_gseval (sf, x, y)
- * ncoeff = wf_gscoeff (sf, coeff)
- * zder = wf_gsder (sf, x, y, nxder, nyder)
- *
- * wf_gsopen is used to open a surface fit encoded in a wcs attribute, returning
- * the sf surface fitting descriptor. wf_gsclose should be called later to free
- * the descriptor. wf_gseval is called to evaluate the surface at a point.
- */
-
-
-#define SZ_GSCOEFFBUF 20
-
-/* define the structure elements for the wf_gsrestore task */
-#define TNX_SAVETYPE 0
-#define TNX_SAVEXORDER 1
-#define TNX_SAVEYORDER 2
-#define TNX_SAVEXTERMS 3
-#define TNX_SAVEXMIN 4
-#define TNX_SAVEXMAX 5
-#define TNX_SAVEYMIN 6
-#define TNX_SAVEYMAX 7
-#define TNX_SAVECOEFF 8
-
-
-/* wf_gsopen -- decode the longitude / latitude or ra / dec mwcs attribute
- * and return a gsurfit compatible surface descriptor.
- */
-
-struct IRAFsurface *
-wf_gsopen (astr)
-
-char *astr; /* the input mwcs attribute string */
-
-{
- double dval;
- char *estr;
- int npar, szcoeff;
- double *coeff;
- struct IRAFsurface *gs;
- struct IRAFsurface *wf_gsrestore();
-
- if (astr[1] == 0)
- return (NULL);
-
- gs = NULL;
- npar = 0;
- szcoeff = SZ_GSCOEFFBUF;
- coeff = (double *) malloc (szcoeff * sizeof (double));
-
- estr = astr;
- while (*estr != (char) 0) {
- dval = strtod (astr, &estr);
- if (*estr == '.')
- estr++;
- if (*estr != (char) 0) {
- npar++;
- if (npar >= szcoeff) {
- szcoeff = szcoeff + SZ_GSCOEFFBUF;
- coeff = (double *) realloc (coeff, (szcoeff * sizeof (double)));
- }
- coeff[npar-1] = dval;
- astr = estr;
- while (*astr == ' ') astr++;
- }
- }
-
- gs = wf_gsrestore (coeff);
-
- free (coeff);
-
- if (npar == 0)
- return (NULL);
- else
- return (gs);
-}
-
-
-/* wf_gsclose -- procedure to free the surface descriptor */
-
-static void
-wf_gsclose (sf)
-
-struct IRAFsurface *sf; /* the surface descriptor */
-
-{
- if (sf != NULL) {
- if (sf->xbasis != NULL)
- free (sf->xbasis);
- if (sf->ybasis != NULL)
- free (sf->ybasis);
- if (sf->coeff != NULL)
- free (sf->coeff);
- free (sf);
- }
- return;
-}
-
-
-/* wf_gseval -- procedure to evaluate the fitted surface at a single point.
- * the wf->ncoeff coefficients are stored in the vector pointed to by sf->coeff.
- */
-
-double
-wf_gseval (sf, x, y)
-
-struct IRAFsurface *sf; /* pointer to surface descriptor structure */
-double x; /* x value */
-double y; /* y value */
-{
- double sum, accum;
- int i, ii, k, maxorder, xorder;
-
- /* Calculate the basis functions */
- switch (sf->type) {
- case TNX_CHEBYSHEV:
- wf_gsb1cheb (x, sf->xorder, sf->xmaxmin, sf->xrange, sf->xbasis);
- wf_gsb1cheb (y, sf->yorder, sf->ymaxmin, sf->yrange, sf->ybasis);
- break;
- case TNX_LEGENDRE:
- wf_gsb1leg (x, sf->xorder, sf->xmaxmin, sf->xrange, sf->xbasis);
- wf_gsb1leg (y, sf->yorder, sf->ymaxmin, sf->yrange, sf->ybasis);
- break;
- case TNX_POLYNOMIAL:
- wf_gsb1pol (x, sf->xorder, sf->xbasis);
- wf_gsb1pol (y, sf->yorder, sf->ybasis);
- break;
- default:
- fprintf (stderr,"TNX_GSEVAL: unknown surface type\n");
- return (0.0);
- }
-
- /* Initialize accumulator basis functions */
- sum = 0.0;
-
- /* Loop over y basis functions */
- if (sf->xorder > sf->yorder)
- maxorder = sf->xorder + 1;
- else
- maxorder = sf->yorder + 1;
- xorder = sf->xorder;
- ii = 0;
-
- for (i = 0; i < sf->yorder; i++) {
-
- /* Loop over the x basis functions */
- accum = 0.0;
- for (k = 0; k < xorder; k++) {
- accum = accum + sf->coeff[ii] * sf->xbasis[k];
- ii = ii + 1;
- }
- accum = accum * sf->ybasis[i];
- sum = sum + accum;
-
- /* Elements of the coefficient vector where neither k = 1 or i = 1
- are not calculated if sf->xterms = no. */
- if (sf->xterms == TNX_XNONE)
- xorder = 1;
- else if (sf->xterms == TNX_XHALF) {
- if ((i + 1 + sf->xorder + 1) > maxorder)
- xorder = xorder - 1;
- }
- }
-
- return (sum);
-}
-
-
-/* TNX_GSCOEFF -- procedure to fetch the number and magnitude of the coefficients
- * if the sf->xterms = wf_xbi (yes) then the number of coefficients will be
- * (sf->xorder * sf->yorder); if wf_xterms is wf_xtri then the number
- * of coefficients will be (sf->xorder * sf->yorder - order *
- * (order - 1) / 2) where order is the minimum of the x and yorders; if
- * sf->xterms = TNX_XNONE then the number of coefficients will be
- * (sf->xorder + sf->yorder - 1).
- */
-
-int
-wf_gscoeff (sf, coeff)
-
-struct IRAFsurface *sf; /* pointer to the surface fitting descriptor */
-double *coeff; /* the coefficients of the fit */
-
-{
- int ncoeff; /* the number of coefficients */
- int i;
-
- /* Exctract coefficients from data structure and calculate their number */
- ncoeff = sf->ncoeff;
- for (i = 0; i < ncoeff; i++)
- coeff[i] = sf->coeff[i];
- return (ncoeff);
-}
-
-
-static double *coeff = NULL;
-static int nbcoeff = 0;
-
-/* wf_gsder -- procedure to calculate a new surface which is a derivative of
- * the input surface.
- */
-
-double
-wf_gsder (sf1, x, y, nxd, nyd)
-
-struct IRAFsurface *sf1; /* pointer to the previous surface */
-double x; /* x values */
-double y; /* y values */
-int nxd, nyd; /* order of the derivatives in x and y */
-{
- int nxder, nyder, i, j, k, nbytes;
- int order, maxorder1, maxorder2, nmove1, nmove2;
- struct IRAFsurface *sf2 = 0;
- double *ptr1, *ptr2;
- double zfit, norm;
- double wf_gseval();
-
- if (sf1 == NULL)
- return (0.0);
-
- if (nxd < 0 || nyd < 0) {
- fprintf (stderr, "TNX_GSDER: order of derivatives cannot be < 0\n");
- return (0.0);
- }
-
- if (nxd == 0 && nyd == 0) {
- zfit = wf_gseval (sf1, x, y);
- return (zfit);
- }
-
- /* Allocate space for new surface */
- sf2 = (struct IRAFsurface *) malloc (sizeof (struct IRAFsurface));
-
- /* Check the order of the derivatives */
- nxder = MIN (nxd, sf1->xorder - 1);
- nyder = MIN (nyd, sf1->yorder - 1);
-
- /* Set up new surface */
- sf2->type = sf1->type;
-
- /* Set the derivative surface parameters */
- if (sf2->type == TNX_LEGENDRE ||
- sf2->type == TNX_CHEBYSHEV ||
- sf2->type == TNX_POLYNOMIAL) {
-
- sf2->xterms = sf1->xterms;
-
- /* Find the order of the new surface */
- switch (sf2->xterms) {
- case TNX_XNONE:
- if (nxder > 0 && nyder > 0) {
- sf2->xorder = 1;
- sf2->yorder = 1;
- sf2->ncoeff = 1;
- }
- else if (nxder > 0) {
- sf2->xorder = MAX (1, sf1->xorder - nxder);
- sf2->yorder = 1;
- sf2->ncoeff = sf2->xorder;
- }
- else if (nyder > 0) {
- sf2->xorder = 1;
- sf2->yorder = MAX (1, sf1->yorder - nyder);
- sf2->ncoeff = sf2->yorder;
- }
- break;
-
- case TNX_XHALF:
- maxorder1 = MAX (sf1->xorder+1, sf1->yorder+1);
- order = MAX(1, MIN(maxorder1-1-nyder-nxder,sf1->xorder-nxder));
- sf2->xorder = order;
- order = MAX(1, MIN(maxorder1-1-nyder-nxder,sf1->yorder-nyder));
- sf2->yorder = order;
- order = MIN (sf2->xorder, sf2->yorder);
- sf2->ncoeff = sf2->xorder * sf2->yorder - (order*(order-1)/2);
- break;
-
- default:
- sf2->xorder = MAX (1, sf1->xorder - nxder);
- sf2->yorder = MAX (1, sf1->yorder - nyder);
- sf2->ncoeff = sf2->xorder * sf2->yorder;
- }
-
- /* define the data limits */
- sf2->xrange = sf1->xrange;
- sf2->xmaxmin = sf1->xmaxmin;
- sf2->yrange = sf1->yrange;
- sf2->ymaxmin = sf1->ymaxmin;
- }
-
- else {
- fprintf (stderr, "TNX_GSDER: unknown surface type %d\n", sf2->type);
- return (0.0);
- }
-
- /* Allocate space for coefficients and basis functions */
- nbytes = sf2->ncoeff * sizeof(double);
- sf2->coeff = (double *) malloc (nbytes);
- nbytes = sf2->xorder * sizeof(double);
- sf2->xbasis = (double *) malloc (nbytes);
- nbytes = sf2->yorder * sizeof(double);
- sf2->ybasis = (double *) malloc (nbytes);
-
- /* Get coefficients */
- nbytes = sf1->ncoeff * sizeof(double);
- if (nbytes > nbcoeff) {
- if (nbcoeff > 0)
- coeff = (double *) realloc (coeff, nbytes);
- else
- coeff = (double *) malloc (nbytes);
- nbcoeff = nbytes;
- }
- (void) wf_gscoeff (sf1, coeff);
-
- /* Compute the new coefficients */
- switch (sf2->xterms) {
- case TNX_XFULL:
- ptr2 = sf2->coeff + (sf2->yorder - 1) * sf2->xorder;
- ptr1 = coeff + (sf1->yorder - 1) * sf1->xorder;
- for (i = sf1->yorder - 1; i >= nyder; i--) {
- for (j = i; j >= i-nyder+1; j--) {
- for (k = 0; k < sf2->xorder; k++)
- ptr1[nxder+k] = ptr1[nxder+k] * (double)(j);
- }
- for (j = sf1->xorder; j >= nxder+1; j--) {
- for (k = j; k >= j-nxder+1; k--)
- ptr1[j-1] = ptr1[j-1] * (double)(k - 1);
- }
- for (j = 0; j < sf2->xorder; j++)
- ptr2[j] = ptr1[nxder+j];
- ptr2 = ptr2 - sf2->xorder;
- ptr1 = ptr1 - sf1->xorder;
- }
- break;
-
- case TNX_XHALF:
- maxorder1 = MAX (sf1->xorder + 1, sf1->yorder + 1);
- maxorder2 = MAX (sf2->xorder + 1, sf2->yorder + 1);
- ptr2 = sf2->coeff + sf2->ncoeff;
- ptr1 = coeff + sf1->ncoeff;
- for (i = sf1->yorder; i >= nyder+1; i--) {
- nmove1 = MAX (0, MIN (maxorder1 - i, sf1->xorder));
- nmove2 = MAX (0, MIN (maxorder2 - i + nyder, sf2->xorder));
- ptr1 = ptr1 - nmove1;
- ptr2 = ptr2 - nmove2;
- for (j = i; j > i - nyder + 1; j--) {
- for (k = 0; k < nmove2; k++)
- ptr1[nxder+k] = ptr1[nxder+k] * (double)(j-1);
- }
- for (j = nmove1; j >= nxder+1; j--) {
- for (k = j; k >= j-nxder+1; k--)
- ptr1[j-1] = ptr1[j-1] * (double)(k - 1);
- }
- for (j = 0; j < nmove2; j++)
- ptr2[j] = ptr1[nxder+j];
- }
- break;
-
- default:
- if (nxder > 0 && nyder > 0)
- sf2->coeff[0] = 0.0;
-
- else if (nxder > 0) {
- ptr1 = coeff;
- ptr2 = sf2->coeff + sf2->ncoeff - 1;
- for (j = sf1->xorder; j >= nxder+1; j--) {
- for (k = j; k >= j - nxder + 1; k--)
- ptr1[j-1] = ptr1[j-1] * (double)(k - 1);
- ptr2[0] = ptr1[j-1];
- ptr2 = ptr2 - 1;
- }
- }
-
- else if (nyder > 0) {
- ptr1 = coeff + sf1->ncoeff - 1;
- ptr2 = sf2->coeff;
- for (i = sf1->yorder; i >= nyder + 1; i--) {
- for (j = i; j >= i - nyder + 1; j--)
- *ptr1 = *ptr1 * (double)(j - 1);
- ptr1 = ptr1 - 1;
- }
- for (i = 0; i < sf2->ncoeff; i++)
- ptr2[i] = ptr1[i+1];
- }
- }
-
- /* evaluate the derivatives */
- zfit = wf_gseval (sf2, x, y);
-
- /* normalize */
- if (sf2->type != TNX_POLYNOMIAL) {
- norm = pow (sf2->xrange, (double)nxder) *
- pow (sf2->yrange, (double)nyder);
- zfit = norm * zfit;
- }
-
- /* free the space */
- wf_gsclose (sf2);
-
- return (zfit);
-}
-
-
-/* wf_gsrestore -- procedure to restore the surface fit encoded in the
- image header as a list of double precision parameters and coefficients
- to the surface descriptor for use by the evaluating routines. the
- surface parameters, surface type, xorder (or number of polynomial
- terms in x), yorder (or number of polynomial terms in y), xterms,
- xmin, xmax and ymin and ymax, are stored in the first eight elements
- of the double array fit, followed by the wf->ncoeff surface coefficients.
- */
-
-struct IRAFsurface *
-wf_gsrestore (fit)
-
-double *fit; /* array containing the surface parameters
- and coefficients */
-{
- struct IRAFsurface *sf; /* surface descriptor */
- int surface_type, xorder, yorder, order, i;
- double xmin, xmax, ymin, ymax;
-
- xorder = (int) (fit[TNX_SAVEXORDER] + 0.5);
- if (xorder < 1) {
- fprintf (stderr, "wf_gsrestore: illegal x order %d\n", xorder);
- return (NULL);
- }
-
- yorder = (int) (fit[TNX_SAVEYORDER] + 0.5);
- if (yorder < 1) {
- fprintf (stderr, "wf_gsrestore: illegal y order %d\n", yorder);
- return (NULL);
- }
-
- xmin = fit[TNX_SAVEXMIN];
- xmax = fit[TNX_SAVEXMAX];
- if (xmax <= xmin) {
- fprintf (stderr, "wf_gsrestore: illegal x range %f-%f\n",xmin,xmax);
- return (NULL);
- }
- ymin = fit[TNX_SAVEYMIN];
- ymax = fit[TNX_SAVEYMAX];
- if (ymax <= ymin) {
- fprintf (stderr, "wf_gsrestore: illegal y range %f-%f\n",ymin,ymax);
- return (NULL);
- }
-
- /* Set surface type dependent surface descriptor parameters */
- surface_type = (int) (fit[TNX_SAVETYPE] + 0.5);
-
- if (surface_type == TNX_LEGENDRE ||
- surface_type == TNX_CHEBYSHEV ||
- surface_type == TNX_POLYNOMIAL) {
-
- /* allocate space for the surface descriptor */
- sf = (struct IRAFsurface *) malloc (sizeof (struct IRAFsurface));
- sf->xorder = xorder;
- sf->xrange = 2.0 / (xmax - xmin);
- sf->xmaxmin = - (xmax + xmin) / 2.0;
- sf->yorder = yorder;
- sf->yrange = 2.0 / (ymax - ymin);
- sf->ymaxmin = - (ymax + ymin) / 2.0;
- sf->xterms = fit[TNX_SAVEXTERMS];
- switch (sf->xterms) {
- case TNX_XNONE:
- sf->ncoeff = sf->xorder + sf->yorder - 1;
- break;
- case TNX_XHALF:
- order = MIN (xorder, yorder);
- sf->ncoeff = sf->xorder * sf->yorder - order * (order-1) / 2;
- break;
- case TNX_XFULL:
- sf->ncoeff = sf->xorder * sf->yorder;
- break;
- }
- }
- else {
- fprintf (stderr, "wf_gsrestore: unknown surface type %d\n", surface_type);
- return (NULL);
- }
-
- /* Set remaining curve parameters */
- sf->type = surface_type;
-
- /* Restore coefficient array */
- sf->coeff = (double *) malloc (sf->ncoeff*sizeof (double));
- for (i = 0; i < sf->ncoeff; i++)
- sf->coeff[i] = fit[TNX_SAVECOEFF+i];
-
- /* Allocate space for basis vectors */
- sf->xbasis = (double *) malloc (sf->xorder*sizeof (double));
- sf->ybasis = (double *) malloc (sf->yorder*sizeof (double));
-
- return (sf);
-}
-
-
-/* wf_gsb1pol -- procedure to evaluate all the non-zero polynomial functions
- for a single point and given order. */
-
-static void
-wf_gsb1pol (x, order, basis)
-
-double x; /*i data point */
-int order; /*i order of polynomial, order = 1, constant */
-double *basis; /*o basis functions */
-{
- int i;
-
- basis[0] = 1.0;
- if (order == 1)
- return;
-
- basis[1] = x;
- if (order == 2)
- return;
-
- for (i = 2; i < order; i++)
- basis[i] = x * basis[i-1];
-
- return;
-}
-
-
-/* wf_gsb1leg -- procedure to evaluate all the non-zero legendre functions for
- a single point and given order. */
-
-static void
-wf_gsb1leg (x, order, k1, k2, basis)
-
-double x; /*i data point */
-int order; /*i order of polynomial, order = 1, constant */
-double k1, k2; /*i normalizing constants */
-double *basis; /*o basis functions */
-{
- int i;
- double ri, xnorm;
-
- basis[0] = 1.0;
- if (order == 1)
- return;
-
- xnorm = (x + k1) * k2 ;
- basis[1] = xnorm;
- if (order == 2)
- return;
-
- for (i = 2; i < order; i++) {
- ri = i;
- basis[i] = ((2.0 * ri - 1.0) * xnorm * basis[i-1] -
- (ri - 1.0) * basis[i-2]) / ri;
- }
-
- return;
-}
-
-
-/* wf_gsb1cheb -- procedure to evaluate all the non-zero chebyshev function
- coefficients for a given x and order. */
-
-static void
-wf_gsb1cheb (x, order, k1, k2, basis)
-
-double x; /*i number of data points */
-int order; /*i order of polynomial, 1 is a constant */
-double k1, k2; /*i normalizing constants */
-double *basis; /*o array of basis functions */
-{
- int i;
- double xnorm;
-
- basis[0] = 1.0;
- if (order == 1)
- return;
-
- xnorm = (x + k1) * k2;
- basis[1] = xnorm;
- if (order == 2)
- return;
-
- for (i = 2; i < order; i++)
- basis[i] = 2. * xnorm * basis[i-1] - basis[i-2];
-
- return;
-}
-
-/* Set surface polynomial from arguments */
-
-int
-tnxpset (wcs, xorder, yorder, xterms, coeff)
-
-struct WorldCoor *wcs; /* World coordinate system structure */
-int xorder; /* Number of x coefficients (same for x and y) */
-int yorder; /* Number of y coefficients (same for x and y) */
-int xterms; /* Number of xy coefficients (same for x and y) */
-double *coeff; /* Plate fit coefficients */
-
-{
- double *ycoeff;
- struct IRAFsurface *wf_gspset ();
-
- wcs->prjcode = WCS_TNX;
-
- wcs->lngcor = wf_gspset (xorder, yorder, xterms, coeff);
- ycoeff = coeff + wcs->lngcor->ncoeff;
- wcs->latcor = wf_gspset (xorder, yorder, xterms, ycoeff);
-
- return 0;
-}
-
-
-/* wf_gspset -- procedure to set the surface descriptor for use by the
- evaluating routines. from arguments. The surface parameters are
- surface type, xorder (number of polynomial terms in x), yorder (number
- of polynomial terms in y), xterms, and the surface coefficients.
- */
-
-struct IRAFsurface *
-wf_gspset (xorder, yorder, xterms, coeff)
-
-int xorder;
-int yorder;
-int xterms;
-double *coeff;
-{
- struct IRAFsurface *sf; /* surface descriptor */
- int surface_type, order, i;
- double xmin, xmax;
- double ymin, ymax;
-
- surface_type = TNX_POLYNOMIAL;
- xmin = 0.0;
- xmax = 0.0;
- ymin = 0.0;
- ymax = 0.0;
-
- if (surface_type == TNX_LEGENDRE ||
- surface_type == TNX_CHEBYSHEV ||
- surface_type == TNX_POLYNOMIAL) {
-
- /* allocate space for the surface descriptor */
- sf = (struct IRAFsurface *) malloc (sizeof (struct IRAFsurface));
- sf->xorder = xorder;
- sf->xrange = 2.0 / (xmax - xmin);
- sf->xmaxmin = -(xmax + xmin) / 2.0;
- sf->yorder = yorder;
- sf->yrange = 2.0 / (ymax - ymin);
- sf->ymaxmin = - (ymax + ymin) / 2.0;
- sf->xterms = xterms;
- switch (sf->xterms) {
- case TNX_XNONE:
- sf->ncoeff = sf->xorder + sf->yorder - 1;
- break;
- case TNX_XHALF:
- order = MIN (xorder, yorder);
- sf->ncoeff = sf->xorder * sf->yorder - order * (order-1) / 2;
- break;
- case TNX_XFULL:
- sf->ncoeff = sf->xorder * sf->yorder;
- break;
- }
- }
- else {
- fprintf (stderr, "TNX_GSSET: unknown surface type %d\n", surface_type);
- return (NULL);
- }
-
- /* Set remaining curve parameters */
- sf->type = surface_type;
-
- /* Restore coefficient array */
- sf->coeff = (double *) malloc (sf->ncoeff*sizeof (double));
- for (i = 0; i < sf->ncoeff; i++)
- sf->coeff[i] = coeff[i];
-
- /* Allocate space for basis vectors */
- sf->xbasis = (double *) malloc (sf->xorder*sizeof (double));
- sf->ybasis = (double *) malloc (sf->yorder*sizeof (double));
-
- return (sf);
-}
-
-/* Mar 26 1998 New subroutines, translated from SPP
- * Apr 28 1998 Change all local flags to TNX_* and projection flag to WCS_TNX
- * May 11 1998 Fix use of pole longitude default
- * Sep 4 1998 Fix missed assignment in tnxpos from Allen Harris, SAO
- * Sep 10 1998 Fix bugs in tnxpix()
- * Sep 10 1998 Fix missed assignment in tnxpix from Allen Harris, SAO
- *
- * Oct 22 1999 Drop unused variables, fix case statements after lint
- * Dec 10 1999 Fix bug in gsder() which failed to allocate enough memory
- * Dec 10 1999 Compute wcs->rot using wcsrotset() in tnxinit()
- *
- * Feb 14 2001 Fixed off-by-one bug in legendre evaluation (Mike Jarvis)
- *
- * Apr 11 2002 Fix bug when .-terminated substring in wf_gsopen()
- * Apr 29 2002 Clean up code
- * Jun 26 2002 Increase size of WAT strings from 500 to 2000
- *
- * Jun 27 2005 Drop unused arguments k1 and k2 from wf_gsb1pol()
- *
- * Jan 8 2007 Drop unused variable ncoeff in wf_gsder()
- * Jan 9 2007 Declare header const char in tnxinit()
- * Apr 3 2007 Fix offsets to hit last cooefficient in wf_gsder()
- *
- * Sep 5 2008 Fix wf_gseval() call in tnxpos() so unmodified x and y are used
- * Sep 9 2008 Fix loop in TNX_XFULL section of wf_gsder()
- * (last two bugs found by Ed Los)
- * Sep 17 2008 Fix tnxpos for null correction case (fix by Ed Los)
- */