/*============================================================================ 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: sph.c,v 4.3 2007/12/27 05:41:36 cal103 Exp $ *===========================================================================*/ #include #include "wcstrig.h" #include "sph.h" #define copysign(X, Y) ((Y) < 0.0 ? -fabs(X) : fabs(X)) #define tol 1.0e-5 /*--------------------------------------------------------------------------*/ int sphx2s(eul, nphi, ntheta, spt, sll, phi, theta, lng, lat) const double eul[5]; int nphi, ntheta, spt, sll; const double phi[], theta[]; double lng[], lat[]; { int mphi, mtheta, rowlen, rowoff; double cosphi, costhe, costhe3, costhe4, dlng, dphi, sinphi, sinthe, sinthe3, sinthe4, x, y, z; register int iphi, itheta; register const double *phip, *thetap; register double *latp, *lngp; if (ntheta > 0) { mphi = nphi; mtheta = ntheta; } else { mphi = 1; mtheta = 1; ntheta = nphi; } /* Do phi dependency. */ phip = phi; rowoff = 0; rowlen = nphi*sll; for (iphi = 0; iphi < nphi; iphi++, rowoff += sll, phip += spt) { dphi = *phip - eul[2]; lngp = lng + rowoff; for (itheta = 0; itheta < mtheta; itheta++) { *lngp = dphi; lngp += rowlen; } } /* Do theta dependency. */ thetap = theta; lngp = lng; latp = lat; for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) { costhe = cosd(*thetap); sinthe = sind(*thetap); costhe3 = costhe*eul[3]; costhe4 = costhe*eul[4]; sinthe3 = sinthe*eul[3]; sinthe4 = sinthe*eul[4]; for (iphi = 0; iphi < mphi; iphi++, lngp += sll, latp += sll) { dphi = *lngp; cosphi = cosd(dphi); sinphi = sind(dphi); /* Compute the celestial longitude. */ x = sinthe4 - costhe3*cosphi; if (fabs(x) < tol) { /* Rearrange formula to reduce roundoff errors. */ x = -cosd(*thetap+eul[1]) + costhe3*(1.0 - cosphi); } y = -costhe*sinphi; if (x != 0.0 || y != 0.0) { dlng = atan2d(y, x); } else { /* Change of origin of longitude. */ if (eul[1] < 90.0) { dlng = dphi + 180.0; } else { dlng = -dphi; } } *lngp = eul[0] + dlng; /* Normalize the celestial longitude. */ if (eul[0] >= 0.0) { if (*lngp < 0.0) *lngp += 360.0; } else { if (*lngp > 0.0) *lngp -= 360.0; } if (*lngp > 360.0) { *lngp -= 360.0; } else if (*lngp < -360.0) { *lngp += 360.0; } /* Compute the celestial latitude. */ if (fmod(dphi,180.0) == 0.0) { *latp = *thetap + cosphi*eul[1]; if (*latp > 90.0) *latp = 180.0 - *latp; if (*latp < -90.0) *latp = -180.0 - *latp; } else { z = sinthe3 + costhe4*cosphi; if (fabs(z) > 0.99) { /* Use an alternative formula for greater accuracy. */ *latp = copysign(acosd(sqrt(x*x+y*y)), z); } else { *latp = asind(z); } } } } return 0; } /*--------------------------------------------------------------------------*/ int sphs2x(eul, nlng, nlat, sll, spt, lng, lat, phi, theta) const double eul[5]; int nlat, nlng, sll, spt; const double lat[], lng[]; double phi[], theta[]; { int mlat, mlng, rowlen, rowoff; double coslat, coslat3, coslat4, coslng, dlng, dphi, sinlat, sinlat3, sinlat4, sinlng, x, y, z; register int ilat, ilng; register const double *latp, *lngp; register double *phip, *thetap; if (nlat > 0) { mlng = nlng; mlat = nlat; } else { mlng = 1; mlat = 1; nlat = nlng; } /* Do lng dependency. */ lngp = lng; rowoff = 0; rowlen = nlng*spt; for (ilng = 0; ilng < nlng; ilng++, rowoff += spt, lngp += sll) { dlng = *lngp - eul[0]; phip = phi + rowoff; for (ilat = 0; ilat < mlat; ilat++) { *phip = dlng; phip += rowlen; } } /* Do lat dependency. */ latp = lat; phip = phi; thetap = theta; for (ilat = 0; ilat < nlat; ilat++, latp += sll) { coslat = cosd(*latp); sinlat = sind(*latp); coslat3 = coslat*eul[3]; coslat4 = coslat*eul[4]; sinlat3 = sinlat*eul[3]; sinlat4 = sinlat*eul[4]; for (ilng = 0; ilng < mlng; ilng++, phip += spt, thetap += spt) { dlng = *phip; coslng = cosd(dlng); sinlng = sind(dlng); /* Compute the native longitude. */ x = sinlat4 - coslat3*coslng; if (fabs(x) < tol) { /* Rearrange formula to reduce roundoff errors. */ x = -cosd(*latp+eul[1]) + coslat3*(1.0 - coslng); } y = -coslat*sinlng; if (x != 0.0 || y != 0.0) { dphi = atan2d(y, x); } else { /* Change of origin of longitude. */ if (eul[1] < 90.0) { dphi = dlng - 180.0; } else { dphi = -dlng; } } *phip = fmod(eul[2] + dphi, 360.0); /* Normalize the native longitude. */ if (*phip > 180.0) { *phip -= 360.0; } else if (*phip < -180.0) { *phip += 360.0; } /* Compute the native latitude. */ if (fmod(dlng,180.0) == 0.0) { *thetap = *latp + coslng*eul[1]; if (*thetap > 90.0) *thetap = 180.0 - *thetap; if (*thetap < -90.0) *thetap = -180.0 - *thetap; } else { z = sinlat3 + coslat4*coslng; if (fabs(z) > 0.99) { /* Use an alternative formula for greater accuracy. */ *thetap = copysign(acosd(sqrt(x*x+y*y)), z); } else { *thetap = asind(z); } } } } return 0; }