fors_cpl_wcs.c

00001 /* $Id: fors_cpl_wcs.c,v 1.10 2010/09/14 07:49:30 cizzo Exp $
00002  *
00003  * This file is part of the ESO Common Pipeline Library
00004  * Copyright (C) 2002-2010 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: cizzo $
00023  * $Date: 2010/09/14 07:49:30 $
00024  * $Revision: 1.10 $
00025  * $Name: fors-4_8_6 $
00026  */
00027 
00028 // Ouch! WCSLIB exports its config.h which will clash with ours,
00029 // so avoid that
00030 //#ifdef HAVE_CONFIG_H
00031 //#include <config.h>
00032 //#endif
00033 
00034 /*----------------------------------------------------------------------------
00035                                    Includes
00036  ----------------------------------------------------------------------------*/
00037 
00038 #include "fors_cpl_wcs.h"
00039 
00040 #include "cpl.h"
00041 
00042 #include <fitsio.h>
00043 #include <fitsio2.h>
00044 #include <wcslib.h>
00045 
00046 //#include <cpl_propertylist_impl.h>
00047 //Declare internal CPL functions:
00048 cpl_propertylist *cpl_propertylist_from_fitsfile(fitsfile *file);
00049 
00050 // Note! ugly hack here. In CPL 4.0 the prototype was
00051 // cpl_error_code cpl_propertylist_to_fitsfile(fitsfile *file, const cpl_propertylist *self);
00052 //
00053 // Later versions:
00054 // cpl_error_code cpl_propertylist_to_fitsfile(fitsfile *file, const cpl_propertylist *, const char *);
00055 // We declare this function always as
00056 
00057 cpl_error_code cpl_propertylist_to_fitsfile(fitsfile *file, const cpl_propertylist *self, const char *); 
00058 
00059 // which accidentally works also with the CPL4.0 prototype because the 
00060 // 3rd superfluous argument is ignored
00061 
00062 #include <math.h>
00063 #include <string.h>
00064 
00065 /*---------------------------------------------------------------------------*/
00082 /*---------------------------------------------------------------------------*/
00085 /*----------------------------------------------------------------------------
00086                                    Type definition
00087  ----------------------------------------------------------------------------*/
00088 
00089 struct _fors_cpl_wcs_ {
00090     struct wcsprm *wcsptr;   /* WCSLIB structure */
00091     int           naxis;     /* Number of dimensions of the image */
00092     int           *dims;     /* Dimensions of image */
00093 };
00094 
00095 /* Static routine declarations */
00096 
00097 static fors_cpl_wcs *fors_cpl_wcs_init(void);
00098 static char *fors_cpl_wcs_plist2fitsstr(const cpl_propertylist *self, int *nkeys);
00099 static cpl_propertylist *fors_cpl_wcs_fitsstr2plist(char *fitsstr);
00100 
00101 /* Useful conversion factors */
00102 
00103 #define DEGRAD 57.2957795130823229
00104 
00105 /* WCSLIB error messages */
00106 
00107 #define WCSLIB_ERRCODE_MAX  9
00108 static char *wcslib_errmsgs[WCSLIB_ERRCODE_MAX+1] = {
00109                   "",
00110           "WCSLIB undefined input structure pointer",
00111           "WCSLIB unable to allocate required memory",
00112           "WCSLIB linear transformation matrix is singular",
00113           "WCSLIB invalid coordinate axis types",
00114           "WCSLIB invalid parameter value",
00115           "WCSLIB invalid coordinate transformation parameters",
00116           "WCSLIB Ill-conditioned coordinate transformation parameters",
00117           "WCSLIB One or more input coordinates invalid",
00118           "WCSLIB One or more input coordinates invalid"};
00119           
00120 
00121 /*-------------------------------------------------------------------------*/
00122 /*-------------------------------------------------------------------------*/
00123 
00124 
00125 /*--------------------------------------------------------------------------
00126   [jmlarsen] This is a workaround for ffhdr2str() which has a severe memory error in CFITSIO 2.510,
00127   fixed somewhere between versions 2.510 and 3.030
00128 */
00129 
00130 static int fors_ffhdr2str( 
00131     fitsfile *fptr,  /* I - FITS file pointer                    */
00132     int exclude_comm,   /* I - if TRUE, exclude commentary keywords */
00133     char **exclist,     /* I - list of excluded keyword names       */
00134     int nexc,           /* I - number of names in exclist           */
00135     char **header,      /* O - returned header string               */
00136     int *nkeys,         /* O - returned number of 80-char keywords  */
00137     int  *status)       /* IO - error status                        */
00138 /*
00139   read header keywords into a long string of chars.  This routine allocates
00140   memory for the string, so the calling routine must eventually free the
00141   memory when it is not needed any more.  If exclude_comm is TRUE, then all
00142   the COMMENT, HISTORY, and <blank> keywords will be excluded from the output
00143   string of keywords.  Any other list of keywords to be excluded may be
00144   specified with the exclist parameter.
00145 */
00146 {
00147     {
00148         /* [jmlarsen] Use the actual CFITSIO function if the
00149            version number is recent enough */
00150         float version;
00151         fits_get_version(&version);
00152         
00153         if (version >= 3.030) 
00154             return ffhdr2str(fptr, exclude_comm, exclist, nexc, header, nkeys, status);
00155     }
00156 
00157     int casesn, match, exact, totkeys;
00158     long ii, jj;
00159     char keybuf[162], keyname[FLEN_KEYWORD], *headptr;
00160 
00161     *nkeys = 0;
00162 
00163     if (*status > 0)
00164         return(*status);
00165 
00166     /* get number of keywords in the header (doesn't include END) */
00167     if (ffghsp(fptr, &totkeys, NULL, status) > 0)
00168         return(*status);
00169 
00170     /* allocate memory for all the keywords (multiple of 2880 bytes) */
00171     *header = (char *) calloc ( (totkeys + 1) * 80 + 1, 1);
00172     if (!(*header))
00173     {
00174          *status = MEMORY_ALLOCATION;
00175          ffpmsg("failed to allocate memory to hold all the header keywords");
00176          return(*status);
00177     }
00178 
00179     headptr = *header;
00180     casesn = FALSE;
00181 
00182     /* read every keyword */
00183     for (ii = 1; ii <= totkeys; ii++)
00184     {
00185         ffgrec(fptr, ii, keybuf, status);
00186         /* pad record with blanks so that it is at least 80 chars long */
00187         strcat(keybuf,
00188     "                                                                                ");
00189 
00190         keyname[0] = '\0';
00191         strncat(keyname, keybuf, 8); /* copy the keyword name */
00192 
00193         if (exclude_comm)
00194         {
00195             if (!FSTRCMP("COMMENT ", keyname) ||
00196                 !FSTRCMP("HISTORY ", keyname) ||
00197                 !FSTRCMP("        ", keyname) )
00198               continue;  /* skip this commentary keyword */
00199         }
00200 
00201         /* does keyword match any names in the exclusion list? */
00202         for (jj = 0; jj < nexc; jj++ )
00203         {
00204             ffcmps(exclist[jj], keyname, casesn, &match, &exact);
00205                  if (match)
00206                      break;
00207         }
00208 
00209         if (jj == nexc)
00210         {
00211             /* not in exclusion list, add this keyword to the string */
00212             strcpy(headptr, keybuf);
00213             headptr += 80;
00214             (*nkeys)++;
00215         }
00216     }
00217 
00218     /* add the END keyword */
00219     strcpy(headptr,
00220     "END                                                                             ");
00221     headptr += 80;
00222     (*nkeys)++;
00223 
00224     *headptr = '\0';   /* terminate the header string */
00225     
00226     *header = realloc(*header, (*nkeys *80) + 1); /* minimize the allocated memory */
00227 
00228     return(*status);
00229 }
00230 
00231 
00232 
00233 
00234 /*
00235  * @brief
00236  *    Create a wcs structure by parsing a propertylist.
00237  *
00238  * @param plist    The input propertylist
00239  *
00240  * @return
00241  *   The newly created and filled fors_cpl_wcs object or NULL if it could not be
00242  *   created. In the latter case an appropriate error code is set.
00243  *
00244  * @error
00245  *   <table class="ec" align="center">
00246  *     <tr>
00247  *       <td class="ecl">CPL_ERROR_NULL_INPUT</td>
00248  *       <td class="ecr">
00249  *         The parameter <i>plist</i> is a <tt>NULL</tt> pointer.
00250  *       </td>
00251  *     </tr>
00252  *     <tr>
00253  *       <td class="ecl">CPL_ERROR_TYPE_MISMATCH</td>
00254  *       <td class="ecr">
00255  *         NAXIS information in image propertylist is not an integer
00256  *       </td>
00257  *     </tr>
00258  *     <tr>
00259  *       <td class="ecl">CPL_ERROR_DATA_NOT_FOUND</td>
00260  *       <td class="ecr">
00261  *         Error in getting NAXIS information for image propertylists
00262  *       </td>
00263  *     </tr>
00264  *   </table>
00265  * @enderror
00266  *
00267  * The function allocates memory for a WCS structure. A pointer to the WCSLIB
00268  * header information is created by parsing the FITS WCS keywords from the 
00269  * header of a file. A few ancillary items are also filled in.
00270  *
00271  * The returned property must be destroyed using the wcs destructor
00272  * @b fors_cpl_wcs_delete().
00273  *
00274  * @see fors_cpl_wcs_delete()
00275  */
00276 
00277 fors_cpl_wcs *fors_cpl_wcs_new_from_propertylist(const cpl_propertylist *plist) {
00278     const char *_id = "fors_cpl_wcs_new";
00279     char *shdr,nax[9];
00280     fors_cpl_wcs *wcs;
00281     int retval,nrej,nwcs,np,i;
00282     struct wcsprm *wwcs = NULL;
00283 
00284     /* Check to see if the propertylist exists */
00285 
00286     if (plist == NULL) {
00287     cpl_error_set(_id,CPL_ERROR_NULL_INPUT);
00288     return(NULL);
00289     }
00290 
00291     /* Get the size of the propertylist. 
00292        jmlarsen: No, it will overrun a buffer 
00293        np = cpl_propertylist_get_size(plist);
00294     */
00295     
00296     /* Get a fors_cpl_wcs structure and initialise it */
00297 
00298     if ((wcs = fors_cpl_wcs_init()) == NULL)
00299     return(NULL);
00300 
00301     /* Convert the propertylist into a string */
00302 
00303     shdr = fors_cpl_wcs_plist2fitsstr(plist, &np);
00304     if (! shdr) {
00305     cpl_error_set_where(_id);
00306     fors_cpl_wcs_delete(wcs);
00307     return(NULL);
00308     }
00309 
00310     /* Parse the header to get the wcslib structure */
00311     retval = wcspih(shdr,np,0,0,&nrej,&nwcs,&wwcs);
00312 
00313     if (retval != 0) {
00314         cpl_msg_warning(_id,"Cannot parse WCS header");
00315         free(shdr);
00316         wcsvfree(&nwcs,&wwcs);
00317     fors_cpl_wcs_delete(wcs);
00318         return(NULL);
00319     }
00320     free(shdr);
00321 
00322     /* Now extract the one you want and ditch the rest */
00323 
00324     wcs->wcsptr = (struct wcsprm *)cpl_calloc(1,sizeof(struct wcsprm));
00325     (wcs->wcsptr)->flag = -1;
00326     wcscopy(1,wwcs,wcs->wcsptr);
00327     wcsset(wcs->wcsptr);
00328     wcsvfree(&nwcs,&wwcs);
00329 
00330     /* Fill the rest of the stuff */
00331 
00332     if (cpl_propertylist_has(plist,"NAXIS")) {
00333     wcs->naxis = cpl_propertylist_get_int(plist,"NAXIS");
00334     if (cpl_error_get_code() != CPL_ERROR_NONE) {
00335         fors_cpl_wcs_delete(wcs);
00336         return(NULL);
00337     }
00338     wcs->dims = cpl_calloc(wcs->naxis,sizeof(int));
00339     for (i = 1; i <= wcs->naxis; i++) {
00340         (void)snprintf(nax,9,"NAXIS%d",i);
00341         wcs->dims[i-1] = cpl_propertylist_get_int(plist,nax);
00342         if (cpl_error_get_code() != CPL_ERROR_NONE) {
00343         fors_cpl_wcs_delete(wcs);
00344         return(NULL);
00345         }
00346     }
00347     }
00348 
00349     /* Get out of here */
00350     
00351     return(wcs);
00352 }
00353 
00367 void fors_cpl_wcs_delete(fors_cpl_wcs *wcs) {
00368 
00369     /* Free the workspace */
00370 
00371     if (wcs == NULL)
00372     return;
00373     if (wcs->wcsptr != NULL) {
00374         (void)wcsfree(wcs->wcsptr);
00375         cpl_free(wcs->wcsptr);
00376     }
00377     if (wcs->dims != NULL) 
00378         cpl_free(wcs->dims); 
00379     cpl_free(wcs);
00380 }
00381 
00382 /*
00383  * @brief
00384  *    Convert between physical and world coordiantes.
00385  *
00386  * @param wcs       The input fors_cpl_wcs structure
00387  * @param from      The input coordinate matrix
00388  * @param to        The output coordinate matrix
00389  * @param status    The output status array
00390  * @param transform The transformation mode
00391  *
00392  * @return
00393  *   An appropriate error code.
00394  *
00395  * @error
00396  *   <table class="ec" align="center">
00397  *     <tr>
00398  *       <td class="ecl">CPL_ERROR_NULL_INPUT</td>
00399  *       <td class="ecr">
00400  *         The parameter <i>wcs</i> is a <tt>NULL</tt> pointer, the parameter
00401  *         <i>from</i> is a <tt>NULL</tt> pointer or <i>wcs</i> is missing 
00402  *         some of its information.
00403  *       </td>
00404  *     </tr>
00405  *     <tr>
00406  *       <td class="ecl">CPL_ERROR_UNSPECIFIED</td>
00407  *       <td class="ecr">
00408  *         No rows or columns in the input matrix, or an unspecified error
00409  *         has occurred in the WCSLIB routine
00410  *       </td>
00411  *     </tr>
00412  *     <tr>
00413  *       <td class="ecl">CPL_ERROR_UNSUPPORTED_MODE</td>
00414  *       <td class="ecr">
00415  *         The input conversion mode is not supported
00416  *       </td>
00417  *     </tr>
00418  *   </table>
00419  * @enderror
00420  *
00421  * This function converts between coordinates. The supported modes are:
00422  * -- FORS_CPL_WCS_PHYS2WORLD:  Converts input physical to world coordinates
00423  * -- FORS_CPL_WCS_WORLD2PHYS:  Converts input world to physical coordinates
00424  * -- FORS_CPL_WCS_WORLD2STD:   Converts input world to standard coordinates
00425  * -- FORS_CPL_WCS_PHYS2STD:    Converts input physical to standard coordinates
00426  * The output matrix and status arrays will be allocated here, and thus will
00427  * need to be freed by the calling routine. The status array is used to flag
00428  * input coordinates where there has been some sort of failure in the 
00429  * transformation. 
00430  *
00431  */
00432 
00433 cpl_error_code fors_cpl_wcs_convert(const fors_cpl_wcs *wcs, const cpl_matrix *from,
00434                                     cpl_matrix **to, cpl_array **status,
00435                                     fors_cpl_wcs_trans_mode transform) {
00436     int nrows,ncols,*sdata,retval,i;
00437     cpl_matrix *x1;
00438     cpl_array *x2,*x3;
00439     cpl_error_code code;
00440     double *fdata,*tdata,*x1data,*x2data,*x3data;
00441     char *_id = "fors_cpl_wcs_convert";
00442 
00443     /* Initialise output */
00444 
00445     *to = NULL;
00446     *status = NULL;
00447 
00448     /* Basic checks on the input pointers */
00449 
00450     if (wcs == NULL || wcs->wcsptr == NULL || from == NULL) {
00451         cpl_error_set(_id,CPL_ERROR_NULL_INPUT);
00452         return(CPL_ERROR_NULL_INPUT);
00453     }
00454 
00455     /* Check the number of rows/columns for the input matrix */
00456 
00457     nrows = cpl_matrix_get_nrow(from);
00458     ncols = cpl_matrix_get_ncol(from);
00459     if (nrows == 0 || ncols == 0) {
00460     cpl_error_set(_id,CPL_ERROR_UNSPECIFIED);
00461     return(CPL_ERROR_UNSPECIFIED);
00462     }
00463 
00464     /* Get the output memory and some memory for wcslib to use */
00465 
00466     *to = cpl_matrix_new(nrows,ncols);
00467     *status = cpl_array_new(nrows,CPL_TYPE_INT);
00468     x1 = cpl_matrix_new(nrows,ncols);
00469     x2 = cpl_array_new(nrows,CPL_TYPE_DOUBLE);
00470     x3 = cpl_array_new(nrows,CPL_TYPE_DOUBLE);
00471 
00472     /* Now get the pointers for the data arrays */
00473 
00474     fdata = cpl_matrix_get_data(from);
00475     tdata = cpl_matrix_get_data(*to);
00476     sdata = cpl_array_get_data_int(*status);
00477     x1data = cpl_matrix_get_data(x1);
00478     x2data = cpl_array_get_data_double(x2);
00479     x3data = cpl_array_get_data_double(x3);
00480 
00481     /* Right, now switch for the transform type. First physical
00482        to world coordinates */
00483 
00484     switch (transform) {
00485     case FORS_CPL_WCS_PHYS2WORLD:
00486         retval = wcsp2s(wcs->wcsptr,nrows,wcs->naxis,fdata,x1data,x2data,
00487             x3data,tdata,sdata);
00488     break;
00489     case FORS_CPL_WCS_WORLD2PHYS:
00490         retval = wcss2p(wcs->wcsptr,nrows,wcs->naxis,fdata,x2data,x3data,
00491             x1data,tdata,sdata);
00492     break;
00493     case FORS_CPL_WCS_WORLD2STD:
00494         retval = wcss2p(wcs->wcsptr,nrows,wcs->naxis,fdata,x2data,x3data,
00495             tdata,x1data,sdata);
00496     break;
00497     case FORS_CPL_WCS_PHYS2STD:
00498         retval = wcsp2s(wcs->wcsptr,nrows,wcs->naxis,fdata,tdata,x2data,
00499             x3data,x1data,sdata);
00500     break;
00501     default:
00502     cpl_error_set(_id,CPL_ERROR_UNSUPPORTED_MODE);
00503     cpl_matrix_delete(*to);
00504     *to = NULL;
00505     cpl_array_delete(*status);
00506     *status = NULL;
00507         cpl_matrix_delete(x1);
00508     return(CPL_ERROR_UNSUPPORTED_MODE);
00509     }
00510 
00511     /* Ditch the intermediate coordinate results */
00512 
00513     cpl_matrix_delete(x1);
00514     cpl_array_delete(x2);
00515     cpl_array_delete(x3);
00516 
00517     /* Now interpret the return value from wcslib */
00518 
00519     switch (retval) {   
00520     case 0:
00521     code = CPL_ERROR_NONE;
00522     break;
00523     case 1:
00524     code = CPL_ERROR_NULL_INPUT;
00525     cpl_msg_warning(__func__,wcslib_errmsgs[1]);
00526     cpl_error_set(__func__,code);
00527     break;
00528     case 2:
00529     case 3:
00530     case 4:
00531     case 5:
00532     case 6:
00533     case 7:
00534     case 8:
00535     case 9:
00536     code = CPL_ERROR_UNSPECIFIED;
00537     cpl_error_set(__func__,code);
00538     cpl_msg_warning(__func__,wcslib_errmsgs[retval]);
00539     break;
00540     default:
00541     code = CPL_ERROR_UNSPECIFIED;
00542     cpl_error_set(__func__,code);
00543     cpl_msg_warning(__func__,"WCSLIB found an unspecified error: %d",
00544               retval);
00545     break;
00546     }
00547     return(code);
00548 }
00549 
00550 
00551 
00554 /*-------------------------------------------------------------------------*/
00555 
00569 static fors_cpl_wcs *fors_cpl_wcs_init(void) {
00570     fors_cpl_wcs *wcs = NULL;
00571 
00572     /* Get the main structure workspace */
00573 
00574     wcs = cpl_malloc(sizeof(fors_cpl_wcs));
00575     if (wcs == NULL)
00576     return(NULL);
00577     
00578     /* Initialise the output structure */
00579 
00580     wcs->wcsptr = NULL;
00581     wcs->naxis = 0;
00582     wcs->dims = NULL;
00583 
00584     return wcs;
00585 }
00586 
00613 static char *fors_cpl_wcs_plist2fitsstr(const cpl_propertylist *self, int *nkeys) {
00614 
00615     const char *_id = "fors_cpl_wcs_plist2fitsstr";
00616     char *header,*h,cval[2];
00617     int n,status;
00618     long lval,i;
00619     float fval;
00620     double dval;
00621     fitsfile *fptr;
00622     cpl_property *p;
00623 
00624     /* Sanity testing of input propertylist */
00625 
00626     if (self == NULL) {
00627         cpl_error_set(_id,CPL_ERROR_NULL_INPUT);
00628         return(NULL);
00629     }
00630 
00631     /* Find out how big the propertylist is */
00632 
00633     n = cpl_propertylist_get_size(self);
00634 
00635     /* Open a memory file with CFITSIO */
00636 
00637     status = 0;
00638     (void)fits_create_file(&fptr,"mem://",&status);
00639     (void)fits_create_img(fptr,BYTE_IMG,0,NULL,&status);
00640 
00641     /* Add the properties into the FITS file */
00642 
00643     cpl_propertylist_to_fitsfile(fptr,self,NULL);
00644 
00645     /* Parse the header */
00646 
00647 //    (void)fits_hdr2str(fptr,1,NULL,0,&header,&ival,&status);
00648     (void)fors_ffhdr2str(fptr,1,NULL,0,&header,nkeys,&status);
00649     (void)fits_close_file(fptr,&status);
00650 
00651     /* Get out of here */
00652 
00653     return(header);
00654 
00655 }
00656 
00682 static cpl_propertylist *fors_cpl_wcs_fitsstr2plist(char *fitsstr) {
00683     int i,status;
00684     fitsfile *fptr;
00685     char *f,*_id="fors_cpl_wcs_fitsstr2plist";
00686     cpl_propertylist *p;
00687 
00688     /* Check input */
00689 
00690     if (fitsstr == NULL) {
00691         cpl_error_set(_id,CPL_ERROR_NULL_INPUT);
00692         return(NULL);
00693     }
00694 
00695     /* Create a memory file using CFITSIO. We can then add individual cards to 
00696        the header and allow CFITSIO to decide on data types etc. */
00697 
00698     status = 0;
00699     (void)fits_create_file(&fptr,"mem://",&status);
00700     (void)fits_create_img(fptr,BYTE_IMG,0,NULL,&status);
00701 
00702     /* Loop for all the cards in the FITS string and add them to the 
00703        memory FITS header */
00704 
00705     f = fitsstr;
00706     while (strncmp(f,"END     ",8)) {
00707     (void)fits_insert_card(fptr,f,&status);
00708     f += (FLEN_CARD - 1);
00709     }
00710     (void)fits_insert_card(fptr,f,&status);
00711 
00712     /* Now create the propertylist */
00713 
00714     p = cpl_propertylist_from_fitsfile(fptr);
00715 
00716     /* Close the memory file and get out of here */
00717 
00718     (void)fits_close_file(fptr,&status);
00719     return(p);
00720 }
00721 

Generated on Fri Mar 4 09:46:00 2011 for FORS Pipeline Reference Manual by  doxygen 1.4.7