/*============================================================================ WCSLIB 4.3 - an implementation of the FITS WCS standard. Copyright (C) 1995-2007, Mark Calabretta This file is part of WCSLIB. WCSLIB 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 3 of the License, or (at your option) any later version. WCSLIB 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 WCSLIB. If not, see . Correspondence concerning WCSLIB may be directed to: Internet email: mcalabre@atnf.csiro.au Postal address: Dr. Mark Calabretta Australia Telescope National Facility, CSIRO PO Box 76 Epping NSW 1710 AUSTRALIA Author: Mark Calabretta, Australia Telescope National Facility http://www.atnf.csiro.au/~mcalabre/index.html $Id: cel.c,v 4.3 2007/12/27 05:41:36 cal103 Exp $ *===========================================================================*/ #include #include #include "wcsmath.h" #include "wcstrig.h" #include "sph.h" #include "cel.h" const int CELSET = 137; /* Map status return value to message. */ const char *cel_errmsg[] = { "Success", "Null celprm pointer passed", "Invalid projection parameters", "Invalid coordinate transformation parameters", "Ill-conditioned coordinate transformation parameters", "One or more of the (x,y) coordinates were invalid", "One or more of the (lng,lat) coordinates were invalid"}; /*--------------------------------------------------------------------------*/ int celini(cel) struct celprm *cel; { register int k; if (cel == 0x0) return 1; cel->flag = 0; cel->offset = 0; cel->phi0 = UNDEFINED; cel->theta0 = UNDEFINED; cel->ref[0] = 0.0; cel->ref[1] = 0.0; cel->ref[2] = UNDEFINED; cel->ref[3] = +90.0; for (k = 0; k < 5; cel->euler[k++] = 0.0); cel->latpreq = -1; return prjini(&(cel->prj)); } /*--------------------------------------------------------------------------*/ int celprt(cel) const struct celprm *cel; { int i; if (cel == 0x0) return 1; printf(" flag: %d\n", cel->flag); printf(" offset: %d\n", cel->offset); if (undefined(cel->phi0)) { printf(" phi0: UNDEFINED\n"); } else { printf(" phi0: %9f\n", cel->phi0); } if (undefined(cel->theta0)) { printf(" theta0: UNDEFINED\n"); } else { printf(" theta0: %9f\n", cel->theta0); } printf(" ref:"); for (i = 0; i < 4; i++) { printf(" %- 11.5g", cel->ref[i]); } printf("\n"); printf(" prj: (see below)\n"); printf(" euler:"); for (i = 0; i < 5; i++) { printf(" %- 11.5g", cel->euler[i]); } printf("\n"); printf(" latpreq: %d", cel->latpreq); if (cel->latpreq == 0) { printf(" (not required)\n"); } else if (cel->latpreq == 1) { printf(" (disambiguation)\n"); } else if (cel->latpreq == 2) { printf(" (specification)\n"); } else { printf(" (UNDEFINED)\n"); } printf(" isolat: %d\n", cel->isolat); printf("\n"); printf(" prj.*\n"); prjprt(&(cel->prj)); return 0; } /*--------------------------------------------------------------------------*/ int celset(cel) struct celprm *cel; { int status; const double tol = 1.0e-10; double clat0, cphip, cthe0, lat0, lng0, phip, slat0, slz, sphip, sthe0; double latp, latp1, latp2, lngp; double u, v, x, y, z; struct prjprm *celprj; if (cel == 0x0) return 1; /* Initialize the projection driver routines. */ celprj = &(cel->prj); if (cel->offset) { celprj->phi0 = cel->phi0; celprj->theta0 = cel->theta0; } else { /* Ensure that these are undefined - no fiducial offset. */ celprj->phi0 = UNDEFINED; celprj->theta0 = UNDEFINED; } if ((status = prjset(celprj))) { return status; } /* Defaults set by the projection routines. */ if (undefined(cel->phi0)) { cel->phi0 = celprj->phi0; } if (undefined(cel->theta0)) { cel->theta0 = celprj->theta0; } else if (fabs(cel->theta0) > 90.0) { if (fabs(cel->theta0) > 90.0 + tol) { return 3; } if (cel->theta0 > 90.0) { cel->theta0 = 90.0; } else { cel->theta0 = -90.0; } } lng0 = cel->ref[0]; lat0 = cel->ref[1]; phip = cel->ref[2]; latp = cel->ref[3]; /* Set default for native longitude of the celestial pole? */ if (undefined(phip) || phip == 999.0) { phip = (lat0 < cel->theta0) ? 180.0 : 0.0; phip += cel->phi0; if (phip < -180.0) { phip += 360.0; } else if (phip > 180.0) { phip -= 360.0; } cel->ref[2] = phip; } /* Compute celestial coordinates of the native pole. */ cel->latpreq = 0; if (cel->theta0 == 90.0) { /* Fiducial point at the native pole. */ lngp = lng0; latp = lat0; } else { /* Fiducial point away from the native pole. */ clat0 = cosd(lat0); slat0 = sind(lat0); cphip = cosd(phip - cel->phi0); sphip = sind(phip - cel->phi0); cthe0 = cosd(cel->theta0); sthe0 = sind(cel->theta0); x = cthe0*cphip; y = sthe0; z = sqrt(x*x + y*y); if (z == 0.0) { if (slat0 != 0.0) { return 3; } /* latp determined solely by LATPOLEa in this case. */ cel->latpreq = 2; if (latp > 90.0) { latp = 90.0; } else if (latp < -90.0) { latp = -90.0; } } else { slz = slat0/z; if (fabs(slz) > 1.0) { if ((fabs(slz) - 1.0) < tol) { if (slz > 0.0) { slz = 1.0; } else { slz = -1.0; } } else { return 3; } } u = atan2d(y,x); v = acosd(slz); latp1 = u + v; if (latp1 > 180.0) { latp1 -= 360.0; } else if (latp1 < -180.0) { latp1 += 360.0; } latp2 = u - v; if (latp2 > 180.0) { latp2 -= 360.0; } else if (latp2 < -180.0) { latp2 += 360.0; } if (fabs(latp1) < 90.0+tol && fabs(latp2) < 90.0+tol) { /* There are two valid solutions for latp. */ cel->latpreq = 1; } if (fabs(latp-latp1) < fabs(latp-latp2)) { if (fabs(latp1) < 90.0+tol) { latp = latp1; } else { latp = latp2; } } else { if (fabs(latp2) < 90.0+tol) { latp = latp2; } else { latp = latp1; } } /* Account for rounding error. */ if (fabs(latp) < 90.0+tol) { if (latp > 90.0) { latp = 90.0; } else if (latp < -90.0) { latp = -90.0; } } } z = cosd(latp)*clat0; if (fabs(z) < tol) { if (fabs(clat0) < tol) { /* Celestial pole at the fiducial point. */ lngp = lng0; } else if (latp > 0.0) { /* Celestial north pole at the native pole.*/ lngp = lng0 + phip - cel->phi0 - 180.0; } else { /* Celestial south pole at the native pole. */ lngp = lng0 - phip + cel->phi0; } } else { x = (sthe0 - sind(latp)*slat0)/z; y = sphip*cthe0/clat0; if (x == 0.0 && y == 0.0) { return 3; } lngp = lng0 - atan2d(y,x); } /* Make celestial longitude at the pole the same sign as at the fiducial point. */ if (lng0 >= 0.0) { if (lngp < 0.0) { lngp += 360.0; } else if (lngp > 360.0) { lngp -= 360.0; } } else { if (lngp > 0.0) { lngp -= 360.0; } else if (lngp < -360.0) { lngp += 360.0; } } } /* Reset LATPOLEa. */ cel->ref[3] = latp; /* Set the Euler angles. */ cel->euler[0] = lngp; cel->euler[1] = 90.0 - latp; cel->euler[2] = phip; cel->euler[3] = cosd(cel->euler[1]); cel->euler[4] = sind(cel->euler[1]); cel->isolat = (cel->euler[4] == 0.0); cel->flag = CELSET; /* Check for ill-conditioned parameters. */ if (fabs(latp) > 90.0+tol) { return 4; } return 0; } /*--------------------------------------------------------------------------*/ int celx2s(cel, nx, ny, sxy, sll, x, y, phi, theta, lng, lat, stat) struct celprm *cel; int nx, ny, sxy, sll; const double x[], y[]; double phi[], theta[]; double lng[], lat[]; int stat[]; { int nphi, status; struct prjprm *celprj; /* Initialize. */ if (cel == 0x0) return 1; if (cel->flag != CELSET) { if ((status = celset(cel))) return status; } /* Apply spherical deprojection. */ celprj = &(cel->prj); if ((status = celprj->prjx2s(celprj, nx, ny, sxy, 1, x, y, phi, theta, stat))) { if (status == 3) { status = 5; } else { return status; } } nphi = (ny > 0) ? (nx*ny) : nx; /* Compute celestial coordinates. */ sphx2s(cel->euler, nphi, 0, 1, sll, phi, theta, lng, lat); return status; } /*--------------------------------------------------------------------------*/ int cels2x(cel, nlng, nlat, sll, sxy, lng, lat, phi, theta, x, y, stat) struct celprm *cel; int nlng, nlat, sll, sxy; const double lng[], lat[]; double phi[], theta[]; double x[], y[]; int stat[]; { int nphi, ntheta, status; struct prjprm *celprj; /* Initialize. */ if (cel == 0x0) return 1; if (cel->flag != CELSET) { if ((status = celset(cel))) return status; } /* Compute native coordinates. */ sphs2x(cel->euler, nlng, nlat, sll, 1, lng, lat, phi, theta); if (cel->isolat) { /* Constant celestial latitude -> constant native latitude. */ nphi = nlng; ntheta = nlat; } else { nphi = (nlat > 0) ? (nlng*nlat) : nlng; ntheta = 0; } /* Apply the spherical projection. */ celprj = &(cel->prj); if ((status = celprj->prjs2x(celprj, nphi, ntheta, 1, sxy, phi, theta, x, y, stat))) { return status == 2 ? 2 : 6; } return 0; }