FORS Pipeline Reference Manual 4.9.9
|
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_9_9 $ 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