/*============================================================================ 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: wcshdr.c,v 4.3 2007/12/27 05:41:36 cal103 Exp $ *===========================================================================*/ #include #include #include #include #include "wcsutil.h" #include "wcsmath.h" #include "wcshdr.h" #include "tab.h" #include "wcs.h" extern const int WCSSET; /* Map status return value to message. */ const char *wcshdr_errmsg[] = { "Success", "Null wcsprm pointer passed", "Memory allocation failed", "Invalid tabular parameters"}; void wcshdo_util(int, const char [], const char [], int, const char [], int, int, int, char, int, int [], char [], const char [], int *, char **, int *); /*--------------------------------------------------------------------------*/ int wcstab(struct wcsprm *wcs) { char (*PSi_0a)[72] = 0x0, (*PSi_1a)[72] = 0x0, (*PSi_2a)[72] = 0x0; int *PVi_1a = 0x0, *PVi_2a = 0x0, *PVi_3a = 0x0, *tabax, *tabidx = 0x0; int getcrd, i, ip, itab, itabax, j, jtabax, m, naxis, ntabax, status; struct wtbarr *wtbp; struct tabprm *tabp; /* Free memory previously allocated by wcstab(). */ if (wcs == 0x0) return 1; if (wcs->flag != -1 && wcs->m_flag == WCSSET) { if (wcs->wtb == wcs->m_wtb) wcs->wtb = 0x0; if (wcs->tab == wcs->m_tab) wcs->tab = 0x0; if (wcs->m_wtb) free(wcs->m_wtb); if (wcs->m_tab) { for (j = 0; j < wcs->ntab; j++) { tabfree(wcs->m_tab + j); } free(wcs->m_tab); } } wcs->ntab = 0; wcs->nwtb = 0; wcs->wtb = 0x0; wcs->tab = 0x0; /* Determine the number of -TAB axes. */ naxis = wcs->naxis; if (!(tabax = calloc(naxis, sizeof(int)))) { return 2; } ntabax = 0; for (i = 0; i < naxis; i++) { /* Null fill. */ wcsutil_null_fill(72, wcs->ctype[i]); if (!strcmp(wcs->ctype[i]+4, "-TAB")) { tabax[i] = ntabax++; } else { tabax[i] = -1; } } if (ntabax == 0) { /* No lookup tables. */ status = 0; goto cleanup; } /* Collect information from the PSi_ma and PVi_ma keyvalues. */ if (!((PSi_0a = calloc(ntabax, sizeof(char[72]))) && (PVi_1a = calloc(ntabax, sizeof(int))) && (PVi_2a = calloc(ntabax, sizeof(int))) && (PSi_1a = calloc(ntabax, sizeof(char[72]))) && (PSi_2a = calloc(ntabax, sizeof(char[72]))) && (PVi_3a = calloc(ntabax, sizeof(int))) && (tabidx = calloc(ntabax, sizeof(int))))) { status = 2; goto cleanup; } for (itabax = 0; itabax < ntabax; itabax++) { /* Remember that calloc() zeroes allocated memory. */ PVi_1a[itabax] = 1; PVi_2a[itabax] = 1; PVi_3a[itabax] = 1; } for (ip = 0; ip < wcs->nps; ip++) { itabax = tabax[wcs->ps[ip].i - 1]; if (itabax >= 0) { switch (wcs->ps[ip].m) { case 0: /* EXTNAME. */ strcpy(PSi_0a[itabax], wcs->ps[ip].value); wcsutil_null_fill(72, PSi_0a[itabax]); break; case 1: /* TTYPEn for coordinate array. */ strcpy(PSi_1a[itabax], wcs->ps[ip].value); wcsutil_null_fill(72, PSi_1a[itabax]); break; case 2: /* TTYPEn for index vector. */ strcpy(PSi_2a[itabax], wcs->ps[ip].value); wcsutil_null_fill(72, PSi_2a[itabax]); break; } } } for (ip = 0; ip < wcs->npv; ip++) { itabax = tabax[wcs->pv[ip].i - 1]; if (itabax >= 0) { switch (wcs->pv[ip].m) { case 1: /* EXTVER. */ PVi_1a[itabax] = (int)(wcs->pv[ip].value + 0.5); break; case 2: /* EXTLEVEL. */ PVi_2a[itabax] = (int)(wcs->pv[ip].value + 0.5); break; case 3: /* Table axis number. */ PVi_3a[itabax] = (int)(wcs->pv[ip].value + 0.5); break; } } } /* Determine the number of independent tables. */ for (itabax = 0; itabax < ntabax; itabax++) { /* These have no defaults. */ if (!PSi_0a[itabax][0] || !PSi_1a[itabax][0]) { status = 3; goto cleanup; } tabidx[itabax] = -1; for (jtabax = 0; jtabax < i; jtabax++) { /* EXTNAME, EXTVER, EXTLEVEL, and TTYPEn for the coordinate array */ /* must match for each axis of a multi-dimensional lookup table. */ if (strcmp(PSi_0a[itabax], PSi_0a[jtabax]) == 0 && strcmp(PSi_1a[itabax], PSi_1a[jtabax]) == 0 && PVi_1a[itabax] == PVi_1a[jtabax] && PVi_2a[itabax] == PVi_2a[jtabax]) { tabidx[itabax] = tabidx[jtabax]; break; } } if (jtabax == itabax) { tabidx[itabax] = wcs->ntab; wcs->ntab++; } } if (!(wcs->tab = calloc(wcs->ntab, sizeof(struct tabprm)))) { status = 2; goto cleanup; } wcs->m_tab = wcs->tab; /* Table dimensionality; find the largest axis number. */ for (itabax = 0; itabax < ntabax; itabax++) { tabp = wcs->tab + tabidx[itabax]; /* PVi_3a records the 1-relative table axis number. */ if (PVi_3a[itabax] > tabp->M) { tabp->M = PVi_3a[itabax]; } } for (itab = 0; itab < wcs->ntab; itab++) { if ((status = tabini(1, wcs->tab[itab].M, 0, wcs->tab + itab))) { goto cleanup; } } /* Copy parameters into the tabprm structs. */ for (i = 0; i < naxis; i++) { if ((itabax = tabax[i]) < 0) { /* Not a -TAB axis. */ continue; } /* PVi_3a records the 1-relative table axis number. */ m = PVi_3a[itabax] - 1; tabp = wcs->tab + tabidx[itabax]; tabp->map[m] = i; tabp->crval[m] = wcs->crval[i]; } /* Check for completeness. */ for (itab = 0; itab < wcs->ntab; itab++) { for (m = 0; m < wcs->tab[itab].M; m++) { if (wcs->tab[itab].map[m] < 0) { status = 3; goto cleanup; } } } /* Set up for reading the arrays; how many arrays are there? */ for (itabax = 0; itabax < ntabax; itabax++) { /* Does this -TAB axis have a non-degenerate index array? */ if (PSi_2a[itabax][0]) { wcs->nwtb++; } } /* Add one coordinate array for each table. */ wcs->nwtb += wcs->ntab; /* Allocate memory for structs to be returned. */ if (!(wcs->wtb = calloc(wcs->nwtb, sizeof(struct wtbarr)))) { wcs->nwtb = 0; status = 2; goto cleanup; } wcs->m_wtb = wcs->wtb; /* Set pointers for the index and coordinate arrays. */ wtbp = wcs->wtb; for (itab = 0; itab < wcs->ntab; itab++) { getcrd = 1; for (itabax = 0; itabax < ntabax; itabax++) { if (tabidx[itabax] != itab) continue; if (getcrd) { /* Coordinate array. */ wtbp->i = itabax + 1; wtbp->m = PVi_3a[itabax]; wtbp->kind = 'c'; strcpy(wtbp->extnam, PSi_0a[itabax]); wtbp->extver = PVi_1a[itabax]; wtbp->extlev = PVi_2a[itabax]; strcpy(wtbp->ttype, PSi_1a[itabax]); wtbp->row = 1L; wtbp->ndim = wcs->tab[itab].M + 1; wtbp->dimlen = wcs->tab[itab].K; wtbp->arrayp = &(wcs->tab[itab].coord); /* Signal for tabset() to take this memory. */ wcs->tab[itab].m_coord = (double *)0x1; wtbp++; getcrd = 0; } if (PSi_2a[itabax][0]) { /* Index array. */ wtbp->i = itabax + 1; wtbp->m = PVi_3a[itabax]; wtbp->kind = 'i'; m = wtbp->m - 1; strcpy(wtbp->extnam, PSi_0a[itabax]); wtbp->extver = PVi_1a[itabax]; wtbp->extlev = PVi_2a[itabax]; strcpy(wtbp->ttype, PSi_2a[itabax]); wtbp->row = 1L; wtbp->ndim = 1; wtbp->dimlen = wcs->tab[itab].K + m; wtbp->arrayp = wcs->tab[itab].index + m; /* Signal for tabset() to take this memory. */ wcs->tab[itab].m_indxs[m] = (double *)0x1; wtbp++; } } } status = 0; cleanup: if (tabax) free(tabax); if (tabidx) free(tabidx); if (PSi_0a) free(PSi_0a); if (PVi_1a) free(PVi_1a); if (PVi_2a) free(PVi_2a); if (PSi_1a) free(PSi_1a); if (PSi_2a) free(PSi_2a); if (PVi_3a) free(PVi_3a); if (status) { if (wcs->tab) free(wcs->tab); if (wcs->wtb) free(wcs->wtb); } return status; } /*--------------------------------------------------------------------------*/ int wcsidx(int nwcs, struct wcsprm **wcs, int alts[27]) { int a, iwcs; struct wcsprm *wcsp; for (a = 0; a < 27; a++) { alts[a] = -1; } if (wcs == 0x0) { return 1; } wcsp = *wcs; for (iwcs = 0; iwcs < nwcs; iwcs++, wcsp++) { if (wcsp->colnum || wcsp->colax[0]) continue; if (wcsp->alt[0] == ' ') { a = 0; } else { a = wcsp->alt[0] - 'A' + 1; } alts[a] = iwcs; } return 0; } /*--------------------------------------------------------------------------*/ int wcsbdx(int nwcs, struct wcsprm **wcs, int type, short alts[1000][28]) { short *ip; int a, i, icol, iwcs; struct wcsprm *wcsp; for (ip = alts[0]; ip < alts[0] + 28*1000; ip++) { *ip = -1; } for (icol = 0; icol < 1000; icol++) { alts[icol][27] = 0; } if (wcs == 0x0) { return 1; } wcsp = *wcs; for (iwcs = 0; iwcs < nwcs; iwcs++, wcsp++) { if (wcsp->alt[0] == ' ') { a = 0; } else { a = wcsp->alt[0] - 'A' + 1; } if (type) { /* Pixel list. */ if (wcsp->colax[0]) { for (i = 0; i < wcsp->naxis; i++) { alts[wcsp->colax[i]][a] = iwcs; alts[wcsp->colax[i]][27]++; } } else if (!wcsp->colnum) { alts[0][a] = iwcs; alts[0][27]++; } } else { /* Binary table image array. */ if (wcsp->colnum) { alts[wcsp->colnum][a] = iwcs; alts[wcsp->colnum][27]++; } else if (!wcsp->colax[0]) { alts[0][a] = iwcs; alts[0][27]++; } } } return 0; } /*--------------------------------------------------------------------------*/ int wcsvfree(int *nwcs, struct wcsprm **wcs) { int a, status = 0; struct wcsprm *wcsp; if (wcs == 0x0) { return 1; } wcsp = *wcs; for (a = 0; a < *nwcs; a++, wcsp++) { status |= wcsfree(wcsp); } free(*wcs); *nwcs = 0; *wcs = 0x0; return status; } /*--------------------------------------------------------------------------*/ int wcshdo(int relax, struct wcsprm *wcs, int *nkeyrec, char **header) /* ::: CUBEFACE and STOKES handling? */ { char alt, comment[72], keyvalue[72], keyword[16], obsg[8] = "OBSG?", obsgeo[8] = "OBSGEO-?", ptype, xtype, xyz[] = "XYZ"; int bintab, col0, *colax, colnum, i, j, k, naxis, pixlist, primage, status = 0; *nkeyrec = 0; *header = 0x0; if (wcs == 0x0) { return 1; } if (wcs->flag != WCSSET) { if ((status = wcsset(wcs))) return status; } if ((naxis = wcs->naxis) == 0) { return 0; } /* These are mainly for convenience. */ alt = wcs->alt[0]; if (alt == ' ') alt = '\0'; colnum = wcs->colnum; colax = wcs->colax; primage = 0; bintab = 0; pixlist = 0; if (colnum) { bintab = 1; col0 = colnum; } else if (colax[0]) { pixlist = 1; col0 = colax[0]; } else { primage = 1; } /* WCS dimension. */ if (!pixlist) { sprintf(keyvalue, "%20d", naxis); wcshdo_util(relax, "WCSAXES", "WCAX", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "Number of coordinate axes", nkeyrec, header, &status); } /* Reference pixel coordinates. */ for (j = 0; j < naxis; j++) { sprintf(keyvalue, "%20.12g", wcs->crpix[j]); wcshdo_util(relax, "CRPIX", "CRP", WCSHDO_CRPXna, "CRPX", 0, j+1, 0, alt, colnum, colax, keyvalue, "Pixel coordinate of reference point", nkeyrec, header, &status); } /* Linear transformation matrix. */ k = 0; for (i = 0; i < naxis; i++) { for (j = 0; j < naxis; j++, k++) { if (i == j) { if (wcs->pc[k] == 1.0) continue; } else { if (wcs->pc[k] == 0.0) continue; } sprintf(keyvalue, "%20.12g", wcs->pc[k]); wcshdo_util(relax, "PC", bintab ? "PC" : "P", WCSHDO_TPCn_ka, bintab ? 0x0 : "PC", i+1, j+1, 0, alt, colnum, colax, keyvalue, "Coordinate transformation matrix element", nkeyrec, header, &status); } } /* Coordinate increment at reference point. */ for (i = 0; i < naxis; i++) { sprintf(keyvalue, "%20.12g", wcs->cdelt[i]); comment[0] = '\0'; if (wcs->cunit[i][0]) sprintf(comment, "[%s] ", wcs->cunit[i]); strcat(comment, "Coordinate increment at reference point"); wcshdo_util(relax, "CDELT", "CDE", WCSHDO_CRPXna, "CDLT", i+1, 0, 0, alt, colnum, colax, keyvalue, comment, nkeyrec, header, &status); } /* Units of coordinate increment and reference value. */ for (i = 0; i < naxis; i++) { if (wcs->cunit[i][0] == '\0') continue; sprintf(keyvalue, "'%s'", wcs->cunit[i]); wcshdo_util(relax, "CUNIT", "CUN", WCSHDO_CRPXna, "CUNI", i+1, 0, 0, alt, colnum, colax, keyvalue, "Units of coordinate increment and value", nkeyrec, header, &status); } /* Coordinate type. */ for (i = 0; i < naxis; i++) { if (wcs->ctype[i][0] == '\0') continue; sprintf(keyvalue, "'%s'", wcs->ctype[i]); strcpy(comment, "Coordinate type code"); if (i == wcs->lng || i == wcs->lat) { if (strncmp(wcs->ctype[i], "RA--", 4) == 0) { strcpy(comment, "Right ascension, "); } else if (strncmp(wcs->ctype[i], "DEC-", 4) == 0) { strcpy(comment, "Declination, "); } else if (strncmp(wcs->ctype[i]+1, "LON", 3) == 0 || strncmp(wcs->ctype[i]+1, "LAT", 3) == 0) { switch (wcs->ctype[i][0]) { case 'G': strcpy(comment, "galactic "); break; case 'E': strcpy(comment, "ecliptic "); case 'H': strcpy(comment, "helioecliptic "); case 'S': strcpy(comment, "supergalactic "); } if (i == wcs->lng) { strcat(comment, "longitude, "); } else { strcat(comment, "latitude, "); } wcs->ctype[i][0] = toupper(wcs->ctype[i][0]); } strcat(comment, wcs->cel.prj.name); strcat(comment, " projection"); } else if (i == wcs->spec) { spctyp(wcs->ctype[i], 0x0, 0x0, comment, 0x0, &ptype, &xtype, 0x0); if (ptype == xtype) { strcat(comment, " (linear)"); } else { switch (xtype) { case 'F': strcat(comment, " (linear in frequency)"); break; case 'V': strcat(comment, " (linear in velocity)"); break; case 'W': strcat(comment, " (linear in wavelength)"); break; } } } wcshdo_util(relax, "CTYPE", "CTY", WCSHDO_CRPXna, "CTYP", i+1, 0, 0, alt, colnum, colax, keyvalue, comment, nkeyrec, header, &status); } /* Coordinate value at reference point. */ for (i = 0; i < naxis; i++) { sprintf(keyvalue, "%20.12g", wcs->crval[i]); comment[0] = '\0'; if (wcs->cunit[i][0]) sprintf(comment, "[%s] ", wcs->cunit[i]); strcat(comment, "Coordinate value at reference point"); wcshdo_util(relax, "CRVAL", "CRV", WCSHDO_CRPXna, "CRVL", i+1, 0, 0, alt, colnum, colax, keyvalue, comment, nkeyrec, header, &status); } /* Parameter values. */ for (k = 0; k < wcs->npv; k++) { sprintf(keyvalue, "%20.12g", (wcs->pv[k]).value); if ((wcs->pv[k]).i == (wcs->lng + 1)) { switch ((wcs->pv[k]).m) { case 1: strcpy(comment, "[deg] Native longitude of the reference point"); break; case 2: strcpy(comment, "[deg] Native latitude of the reference point"); break; case 3: if (primage) { sprintf(keyword, "LONPOLE%c", alt); } else if (bintab) { sprintf(keyword, "LONP%d%c", colnum, alt); } else { sprintf(keyword, "LONP%d%c", colax[(wcs->pv[k]).i - 1], alt); } sprintf(comment, "[deg] alias for %s (has precedence)", keyword); break; case 4: if (primage) { sprintf(keyword, "LATPOLE%c", alt); } else if (bintab) { sprintf(keyword, "LATP%d%c", colnum, alt); } else { sprintf(keyword, "LATP%d%c", colax[(wcs->pv[k]).i - 1], alt); } sprintf(comment, "[deg] alias for %s (has precedence)", keyword); break; } } else if ((wcs->pv[k]).i == (wcs->lat + 1)) { sprintf(comment, "%s projection parameter", wcs->cel.prj.code); } else { strcpy(comment, "Coordinate transformation parameter"); } wcshdo_util(relax, "PV", "V", WCSHDO_PVn_ma, "PV", wcs->pv[k].i, -1, wcs->pv[k].m, alt, colnum, colax, keyvalue, comment, nkeyrec, header, &status); } for (k = 0; k < wcs->nps; k++) { sprintf(keyvalue, "'%s'", (wcs->ps[k]).value); wcshdo_util(relax, "PS", "S", WCSHDO_PVn_ma, "PS", wcs->ps[k].i, -1, wcs->ps[k].m, alt, colnum, colax, keyvalue, "Coordinate transformation parameter", nkeyrec, header, &status); } /* Celestial and spectral transformation parameters. */ if (!undefined(wcs->lonpole)) { sprintf(keyvalue, "%20.12g", wcs->lonpole); wcshdo_util(relax, "LONPOLE", "LONP", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "[deg] Native longitude of celestial pole", nkeyrec, header, &status); } if (!undefined(wcs->latpole)) { sprintf(keyvalue, "%20.12g", wcs->latpole); wcshdo_util(relax, "LATPOLE", "LATP", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "[deg] Native latitude of celestial pole", nkeyrec, header, &status); } if (!undefined(wcs->restfrq)) { sprintf(keyvalue, "%20.12g", wcs->restfrq); wcshdo_util(relax, "RESTFRQ", "RFRQ", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "[Hz] Line rest frequency", nkeyrec, header, &status); } if (!undefined(wcs->restwav)) { sprintf(keyvalue, "%20.12g", wcs->restwav); wcshdo_util(relax, "RESTWAV", "RWAV", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "[Hz] Line rest wavelength", nkeyrec, header, &status); } /* Coordinate system title. */ if (wcs->wcsname[0]) { sprintf(keyvalue, "'%s'", wcs->wcsname); if (bintab) { wcshdo_util(relax, "WCSNAME", "WCSN", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "Coordinate system title", nkeyrec, header, &status); } else { /* TWCS was a mistake. */ wcshdo_util(relax, "WCSNAME", "TWCS", WCSHDO_WCSNna, "WCSN", 0, 0, 0, alt, colnum, colax, keyvalue, "Coordinate system title", nkeyrec, header, &status); } } /* Coordinate axis title. */ if (wcs->cname) { for (i = 0; i < naxis; i++) { if (wcs->cname[i][0] == '\0') continue; sprintf(keyvalue, "'%s'", wcs->cname[i]); wcshdo_util(relax, "CNAME", "CNA", WCSHDO_CNAMna, "CNAM", i+1, 0, 0, alt, colnum, colax, keyvalue, "Axis name for labelling purposes", nkeyrec, header, &status); } } /* Random error in coordinate. */ if (wcs->crder) { for (i = 0; i < naxis; i++) { if (undefined(wcs->crder[i])) continue; sprintf(keyvalue, "%20.12g", wcs->crder[i]); comment[0] = '\0'; if (wcs->cunit[i][0]) sprintf(comment, "[%s] ", wcs->cunit[i]); strcat(comment, "Random error in coordinate"); wcshdo_util(relax, "CRDER", "CRD", WCSHDO_CNAMna, "CRDE", i+1, 0, 0, alt, colnum, colax, keyvalue, comment, nkeyrec, header, &status); } } /* Systematic error in coordinate. */ if (wcs->csyer) { for (i = 0; i < naxis; i++) { if (undefined(wcs->csyer[i])) continue; sprintf(keyvalue, "%20.12g", wcs->csyer[i]); comment[0] = '\0'; if (wcs->cunit[i][0]) sprintf(comment, "[%s] ", wcs->cunit[i]); strcat(comment, "Systematic error in coordinate"); wcshdo_util(relax, "CSYER", "CSY", WCSHDO_CNAMna, "CSYE", i+1, 0, 0, alt, colnum, colax, keyvalue, comment, nkeyrec, header, &status); } } /* Equatorial coordinate system type. */ if (wcs->radesys[0]) { sprintf(keyvalue, "'%s'", wcs->radesys); wcshdo_util(relax, "RADESYS", "RADE", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "Equatorial coordinate system", nkeyrec, header, &status); } /* Equinox of equatorial coordinate system. */ if (!undefined(wcs->equinox)) { sprintf(keyvalue, "%20.12g", wcs->equinox); wcshdo_util(relax, "EQUINOX", "EQUI", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "[yr] Equinox of equatorial coordinates", nkeyrec, header, &status); } /* Reference frame of spectral coordinates. */ if (wcs->specsys[0]) { sprintf(keyvalue, "'%s'", wcs->specsys); wcshdo_util(relax, "SPECSYS", "SPEC", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "Reference frame of spectral coordinates", nkeyrec, header, &status); } /* Reference frame of spectral observation. */ if (wcs->ssysobs[0]) { sprintf(keyvalue, "'%s'", wcs->ssysobs); wcshdo_util(relax, "SSYSOBS", "SOBS", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "Reference frame of spectral observation", nkeyrec, header, &status); } /* Observer's velocity towards source. */ if (!undefined(wcs->velosys)) { sprintf(keyvalue, "%20.12g", wcs->velosys); wcshdo_util(relax, "VELOSYS", "VSYS", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "[m/s] Velocity towards source", nkeyrec, header, &status); } /* Reference frame of source redshift. */ if (wcs->ssyssrc[0]) { sprintf(keyvalue, "'%s'", wcs->ssyssrc); wcshdo_util(relax, "SSYSSRC", "SSRC", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "Reference frame of source redshift", nkeyrec, header, &status); } /* Redshift of the source. */ if (!undefined(wcs->zsource)) { sprintf(keyvalue, "%20.12g", wcs->zsource); wcshdo_util(relax, "ZSOURCE", "ZSOU", 0, 0x0, 0, 0, 0, alt, colnum, colax, keyvalue, "Redshift of the source", nkeyrec, header, &status); } /* Observatory coordinates. */ for (k = 0; k < 3; k++) { if (undefined(wcs->obsgeo[k])) continue; sprintf(keyvalue, "%20.12g", wcs->obsgeo[k]); sprintf(comment, "[m] ITRF observatory %c-coordinate", xyz[k]); obsgeo[7] = xyz[k]; obsg[4] = xyz[k]; wcshdo_util(relax, obsgeo, obsg, 0, 0x0, 0, 0, 0, ' ', colnum, colax, keyvalue, comment, nkeyrec, header, &status); } /* MJD of observation. */ if (!undefined(wcs->mjdobs)) { sprintf(keyvalue, "%20.12g", wcs->mjdobs); strcpy(comment, "[d] MJD of observation"); if (wcs->dateobs[0]) { if (primage || (relax & 1) == 0) { sprintf(comment+22, " matching DATE-OBS"); } else { sprintf(comment+22, " matching DOBS%d", col0); } } wcshdo_util(relax, "MJD-OBS", "MJDOB", 0, 0x0, 0, 0, 0, ' ', colnum, colax, keyvalue, comment, nkeyrec, header, &status); } /* MJD mid-observation time. */ if (!undefined(wcs->mjdavg)) { sprintf(keyvalue, "%20.12g", wcs->mjdavg); strcpy(comment, "[d] MJD mid-observation"); if (wcs->dateavg[0]) { if (primage) { sprintf(comment+23, " matching DATE-AVG"); } else { sprintf(comment+23, " matching DAVG%d", col0); } } wcshdo_util(relax, "MJD-AVG", "MJDA", 0, 0x0, 0, 0, 0, ' ', colnum, colax, keyvalue, comment, nkeyrec, header, &status); } /* ISO-8601 date corresponding to MJD-OBS. */ if (wcs->dateobs[0]) { sprintf(keyvalue, "'%s'", wcs->dateobs); strcpy(comment, "ISO-8601 observation date"); if (!undefined(wcs->mjdobs)) { if (primage) { sprintf(comment+25, " matching MJD-OBS"); } else { sprintf(comment+25, " matching MJDOB%d", col0); } } if (relax & 1) { /* Allow DOBSn. */ wcshdo_util(relax, "DATE-OBS", "DOBS", WCSHDO_DOBSn, 0x0, 0, 0, 0, ' ', colnum, colax, keyvalue, comment, nkeyrec, header, &status); } else { /* Force DATE-OBS. */ wcshdo_util(relax, "DATE-OBS", 0x0, 0, 0x0, 0, 0, 0, ' ', 0, 0x0, keyvalue, comment, nkeyrec, header, &status); } } /* ISO-8601 date corresponding to MJD-OBS. */ if (wcs->dateavg[0]) { sprintf(keyvalue, "'%s'", wcs->dateavg); strcpy(comment, "ISO-8601 mid-observation date"); if (!undefined(wcs->mjdavg)) { if (primage) { sprintf(comment+29, " matching MJD-AVG"); } else { sprintf(comment+29, " matching MJDA%d", col0); } } wcshdo_util(relax, "DATE-AVG", "DAVG", 0, 0x0, 0, 0, 0, ' ', colnum, colax, keyvalue, comment, nkeyrec, header, &status); } return status; } /*--------------------------------------------------------------------------*/ void wcshdo_util( int relax, const char pikey[], const char tbkey[], int level, const char tlkey[], int i, int j, int m, char alt, int btcol, int plcol[], char keyvalue[], const char keycomment[], int *nkeyrec, char **header, int *status) { char ch0, ch1, *hptr, keyword[16], *kptr; int nbyte, nc = 47, nv; if (*status) return; /* Reallocate memory in blocks of 2880 bytes. */ if ((*nkeyrec)%32 == 0) { nbyte = ((*nkeyrec)/32 + 1) * 2880; if (!(hptr = realloc(*header, nbyte))) { *status = 2; return; } *header = hptr; } /* Construct the keyword. */ if (alt == ' ') alt = '\0'; if (btcol) { /* Binary table image array. */ if (i > 0 && j) { if (j > 0) { sprintf(keyword, "%d%d%s%d%c", i, j, tbkey, btcol, alt); } else { sprintf(keyword, "%d%s%d_%d%c", i, tbkey, btcol, m, alt); } } else if (i > 0) { sprintf(keyword, "%d%s%d%c", i, tbkey, btcol, alt); } else if (j > 0) { sprintf(keyword, "%d%s%d%c", j, tbkey, btcol, alt); } else { sprintf(keyword, "%s%d%c", tbkey, btcol, alt); } if ((strlen(keyword) < 8) && tlkey && (relax & level)) { /* Use the long form. */ if (i > 0 && j) { if (j > 0) { sprintf(keyword, "%d%d%s%d%c", i, j, tlkey, btcol, alt); } else { sprintf(keyword, "%d%s%d_%d%c", i, tlkey, btcol, m, alt); } } else if (i > 0) { sprintf(keyword, "%d%s%d%c", i, tlkey, btcol, alt); } else if (j > 0) { sprintf(keyword, "%d%s%d%c", j, tlkey, btcol, alt); } else { sprintf(keyword, "%s%d%c", tlkey, btcol, alt); } } } else if (plcol && plcol[0]) { /* Pixel list. */ if (i > 0 && j) { if (j > 0) { sprintf(keyword, "T%s%d_%d%c", tbkey, plcol[i-1], plcol[j-1], alt); } else { sprintf(keyword, "T%s%d_%d%c", tbkey, plcol[i-1], m, alt); } } else if (i > 0) { sprintf(keyword, "T%s%d%c", tbkey, plcol[i-1], alt); } else if (j > 0) { sprintf(keyword, "T%s%d%c", tbkey, plcol[j-1], alt); } else { sprintf(keyword, "%s%d%c", tbkey, plcol[0], alt); } if ((strlen(keyword) < 8) && tlkey && (relax & level)) { /* Use the long form. */ if (i > 0 && j) { if (j > 0) { sprintf(keyword, "T%s%d_%d%c", tlkey, plcol[i-1], plcol[j-1], alt); } else { sprintf(keyword, "T%s%d_%d%c", tlkey, plcol[i-1], m, alt); } } else if (i > 0) { sprintf(keyword, "T%s%d%c", tlkey, plcol[i-1], alt); } else if (j > 0) { sprintf(keyword, "T%s%d%c", tlkey, plcol[j-1], alt); } else { sprintf(keyword, "%s%d%c", tlkey, plcol[0], alt); } } } else { if (i > 0 && j) { if (j > 0) { sprintf(keyword, "%s%d_%d%c", pikey, i, j, alt); } else { sprintf(keyword, "%s%d_%d%c", pikey, i, m, alt); } } else if (i > 0) { sprintf(keyword, "%s%d%c", pikey, i, alt); } else if (j > 0) { sprintf(keyword, "%s%d%c", pikey, j, alt); } else { sprintf(keyword, "%s%c", pikey, alt); } } /* Double-up single-quotes in the keyvalue. */ hptr = keyvalue + 1; while (*hptr) { if (*hptr == '\'') { kptr = hptr++; if (*hptr) { ch0 = *kptr; while (*kptr) { ch1 = *(++kptr); *kptr = ch0; ch0 = ch1; } } } hptr++; } if ((nv = strlen(keyvalue) > 20)) { /* Rob the keycomment to make space for the keyvalue. */ nc -= (nv - 20); } hptr = *header + (80 * ((*nkeyrec)++)); sprintf(hptr, "%-8.8s= %-20s / %-*.*s", keyword, keyvalue, nc, nc, keycomment); }