sip_t* wcs_pv2sip_header(qfits_header* hdr, double* xy, int Nxy, double stepsize, double xlo, double xhi, double ylo, double yhi, int imageW, int imageH, int order, anbool forcetan, int doshift) { double* radec = NULL; int rtn = -1; tan_t tanwcs; double x,y, px,py; double* rddist = NULL; int i, j; int nx, ny; double xstep, ystep; sip_t* sip = NULL; /** From http://iraf.noao.edu/projects/mosaic/tpv.html p = PV1_ xi' = p0 + p1 * xi + p2 * eta + p3 * r + p4 * xi^2 + p5 * xi * eta + p6 * eta^2 + p7 * xi^3 + p8 * xi^2 * eta + p9 * xi * eta^2 + p10 * eta^3 + p11 * r^3 + p12 * xi^4 + p13 * xi^3 * eta + p14 * xi^2 * eta^2 + p15 * xi * eta^3 + p16 * eta^4 + p17 * xi^5 + p18 * xi^4 * eta + p19 * xi^3 * eta^2 + p20 * xi^2 * eta^3 + p21 * xi * eta^4 + p22 * eta^5 + p23 * r^5 + p24 * xi^6 + p25 * xi^5 * eta + p26 * xi^4 * eta^2 + p27 * xi^3 * eta^3 + p28 * xi^2 * eta^4 + p29 * xi * eta^5 + p30 * eta^6 p31 * xi^7 + p32 * xi^6 * eta + p33 * xi^5 * eta^2 + p34 * xi^4 * eta^3 + p35 * xi^3 * eta^4 + p36 * xi^2 * eta^5 + p37 * xi * eta^6 + p38 * eta^7 + p39 * r^7 p = PV2_ eta' = p0 + p1 * eta + p2 * xi + p3 * r + p4 * eta^2 + p5 * eta * xi + p6 * xi^2 + p7 * eta^3 + p8 * eta^2 * xi + p9 * eta * xi^2 + p10 * xi^3 + p11 * r^3 + p12 * eta^4 + p13 * eta^3 * xi + p14 * eta^2 * xi^2 + p15 * eta * xi^3 + p16 * xi^4 + p17 * eta^5 + p18 * eta^4 * xi + p19 * eta^3 * xi^2 + p20 * eta^2 * xi^3 + p21 * eta * xi^4 + p22 * xi^5 + p23 * r^5 + p24 * eta^6 + p25 * eta^5 * xi + p26 * eta^4 * xi^2 + p27 * eta^3 * xi^3 + p28 * eta^2 * xi^4 + p29 * eta * xi^5 + p30 * xi^6 p31 * eta^7 + p32 * eta^6 * xi + p33 * eta^5 * xi^2 + p34 * eta^4 * xi^3 + p35 * eta^3 * xi^4 + p36 * eta^2 * xi^5 + p37 * eta * xi^6 + p38 * xi^7 + p39 * r^7 Note the "cross-over" -- the xi' powers are in terms of xi,eta while the eta' powers are in terms of eta,xi. */ // 1 x y r x2 xy y2 x3 x2y xy2 y3 r3 x4 x3y x2y2 xy3 y4 // x5 x4y x3y2 x2y3 xy4 y5 r5 x6 x5y x4y2, x3y3 x2y4 xy5 y6 // x7 x6y x5y2 x4y3 x3y4 x2y5 xy6 y7 r7 int xp[] = { 0, 1, 0, 0, 2, 1, 0, 3, 2, 1, 0, 0, 4, 3, 2, 1, 0, 5, 4, 3, 2, 1, 0, 0, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0, 0}; int yp[] = { 0, 0, 1, 0, 0, 1, 2, 0, 1, 2, 3, 0, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 7, 0}; int rp[] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7}; double xpows[8]; double ypows[8]; double rpows[8]; double pv1[40]; double pv2[40]; double r; char* ct; ct = fits_get_dupstring(hdr, "CTYPE1"); if ((ct && streq(ct, "RA---TPV")) || forcetan) { // http://iraf.noao.edu/projects/ccdmosaic/tpv.html logmsg("Replacing CTYPE1 = %s header with RA---TAN\n", ct); fits_update_value(hdr, "CTYPE1", "RA---TAN"); } ct = fits_get_dupstring(hdr, "CTYPE2"); if ((ct && streq(ct, "DEC--TPV")) || forcetan) { logmsg("Replacing CTYPE2 = %s header with DEC--TAN\n", ct); fits_update_value(hdr, "CTYPE2", "DEC--TAN"); } tan_read_header(hdr, &tanwcs); if (log_get_level() >= LOG_VERB) { printf("Read TAN header:\n"); tan_print(&tanwcs); } if (imageW && (imageW != tanwcs.imagew)) { logmsg("Overriding image width %f with user-specified %i\n", tanwcs.imagew, imageW); tanwcs.imagew = imageW; } if (imageH && (imageH != tanwcs.imageh)) { logmsg("Overriding image height %f with user-specified %i\n", tanwcs.imageh, imageH); tanwcs.imageh = imageH; } for (i=0; i<sizeof(pv1)/sizeof(double); i++) { char key[10]; double defaultval; if (i == 1) { defaultval = 1.0; } else { defaultval = 0.0; } sprintf(key, "PV1_%i", i); pv1[i] = qfits_header_getdouble(hdr, key, defaultval); sprintf(key, "PV2_%i", i); pv2[i] = qfits_header_getdouble(hdr, key, defaultval); } // choose grid for evaluating TAN-PV WCS if (xlo == 0 && xhi == 0) { xlo = 1.; xhi = tanwcs.imagew; } if (ylo == 0 && yhi == 0) { ylo = 1.; yhi = tanwcs.imageh; } assert(xhi >= xlo); assert(yhi >= ylo); if (stepsize == 0) stepsize = 100.; nx = MAX(2, round((xhi - xlo)/stepsize)); ny = MAX(2, round((yhi - ylo)/stepsize)); xstep = (xhi - xlo) / (double)(nx - 1); ystep = (yhi - ylo) / (double)(ny - 1); logverb("Stepping from x = %g to %g, steps of %g\n", xlo, xhi, xstep); logverb("Stepping from y = %g to %g, steps of %g\n", ylo, yhi, ystep); Nxy = nx * ny; if (xy == NULL) { int k = 0; xy = malloc(Nxy * 2 * sizeof(double)); for (i=0; i<ny; i++) { y = ylo + i*ystep; for (j=0; j<nx; j++) { x = xlo + j*xstep; //if (i == 0) //printf("x=%f\n", x); xy[k] = x; k++; xy[k] = y; k++; } //printf("y=%f\n", y); } assert(k == (Nxy*2)); } // distorted RA,Dec rddist = malloc(2 * Nxy * sizeof(double)); for (j=0; j<Nxy; j++) { double ix = xy[2*j+0]; double iy = xy[2*j+1]; tan_pixelxy2iwc(&tanwcs, ix, iy, &x, &y); // "x,y" here are most commonly known as "xi, eta". r = sqrt(x*x + y*y); // compute powers of x,y xpows[0] = ypows[0] = rpows[0] = 1.0; for (i=1; i<sizeof(xpows)/sizeof(double); i++) { xpows[i] = xpows[i-1]*x; ypows[i] = ypows[i-1]*y; rpows[i] = rpows[i-1]*r; } px = py = 0; for (i=0; i<sizeof(xp)/sizeof(int); i++) { px += pv1[i] * xpows[xp[i]] * ypows[yp[i]] * rpows[rp[i]]; // here's the "cross-over" mentioned above py += pv2[i] * ypows[xp[i]] * xpows[yp[i]] * rpows[rp[i]]; } // Note that the PV terms *include* a linear term, so no need // to re-add x,y to px,py. tan_iwc2radec(&tanwcs, px, py, rddist + 2*j, rddist + 2*j + 1); } sip = malloc(sizeof(sip_t)); assert(sip); { double* starxyz; starxyz = malloc(3 * Nxy * sizeof(double)); for (i=0; i<Nxy; i++) radecdegarr2xyzarr(rddist + i*2, starxyz + i*3); memset(sip, 0, sizeof(sip_t)); rtn = fit_sip_coefficients(starxyz, xy, NULL, Nxy, &tanwcs, order, order, sip); assert(rtn == 0); if (log_get_level() >= LOG_VERB) { printf("Fit SIP:\n"); sip_print(sip); } // FIXME? -- use xlo,xhi,ylo,yhi here?? Not clear. sip_compute_inverse_polynomials(sip, 0, 0, 0, 0, 0, 0); if (log_get_level() >= LOG_VERB) { printf("Fit SIP inverse polynomials:\n"); sip_print(sip); } free(starxyz); } free(rddist); free(radec); return sip; }
const anqfits_image_t* anqfits_get_image_const(const anqfits_t* qf, int ext) { assert(ext >= 0 && ext < qf->Nexts); if (!qf->exts[ext].image) { anqfits_image_t* img; const qfits_header* hdr = anqfits_get_header_const(qf, ext); int naxis1, naxis2, naxis3; if (!hdr) { qfits_error("Failed to get header for ext %i\n", ext); return NULL; } img = anqfits_image_new(); // from qfits_image.c : qfitsloader_init() img->bitpix = qfits_header_getint(hdr, "BITPIX", -1); img->naxis = qfits_header_getint(hdr, "NAXIS", -1); naxis1 = qfits_header_getint(hdr, "NAXIS1", -1); naxis2 = qfits_header_getint(hdr, "NAXIS2", -1); naxis3 = qfits_header_getint(hdr, "NAXIS3", -1); img->bzero = qfits_header_getdouble(hdr, "BZERO", 0.0); img->bscale = qfits_header_getdouble(hdr, "BSCALE", 1.0); if (img->bitpix == -1) { qfits_error("Missing BITPIX in file %s ext %i", qf->filename, ext); goto bailout; } if (!((img->bitpix == 8) || (img->bitpix == 16) || (img->bitpix == 32) || (img->bitpix == -32) || (img->bitpix == -64))) { qfits_error("Invalid BITPIX %i in file %s ext %i", img->bitpix, qf->filename, ext); goto bailout; } img->bpp = BYTESPERPIXEL(img->bitpix); if (img->naxis < 0) { qfits_error("No NAXIS in file %s ext %i", qf->filename, ext); goto bailout; } if (img->naxis==0) { qfits_error("NAXIS = 0 in file %s ext %i", qf->filename, ext); goto bailout; } if (img->naxis > 3) { qfits_error("NAXIS = %i > 3 unsupported in file %s ext %i", img->naxis, qf->filename, ext); goto bailout; } /* NAXIS1 must always be present */ if (naxis1 < 0) { qfits_error("No NAXIS1 in file %s ext %i", qf->filename, ext); goto bailout; } img->width = 1; img->height = 1; img->planes = 1; switch (img->naxis) { case 1: img->width = naxis1; break; case 3: if (naxis3 < 0) { qfits_error("No NAXIS3 in file %s ext %i", qf->filename, ext); goto bailout; } img->planes = naxis3; // no break: fall through to... case 2: if (naxis2 < 0) { qfits_error("No NAXIS2 in file %s ext %i", qf->filename, ext); goto bailout; } img->height = naxis2; img->width = naxis1; break; } qf->exts[ext].image = img; return img; bailout: anqfits_image_free(img); return NULL; } return qf->exts[ext].image; }
tan_t* tan_read_header(const qfits_header* hdr, tan_t* dest) { tan_t tan; double nil = -1e300; char* ct1; char* ct2; int swap; int W, H; anbool is_sin; memset(&tan, 0, sizeof(tan_t)); ct1 = fits_get_dupstring(hdr, "CTYPE1"); ct2 = fits_get_dupstring(hdr, "CTYPE2"); swap = check_tan_ctypes(ct1, ct2, &is_sin); if (swap == -1) { ERROR("TAN header: expected CTYPE1 = RA---TAN, CTYPE2 = DEC--TAN " "(or vice versa), or RA---SIN, DEC--SIN or vice versa; " "got CTYPE1 = \"%s\", CYTPE2 = \"%s\"\n", ct1, ct2); } free(ct1); free(ct2); if (swap == -1) return NULL; sip_get_image_size(hdr, &W, &H); tan.imagew = W; tan.imageh = H; { const char* keys[] = { "CRVAL1", "CRVAL2", "CRPIX1", "CRPIX2", "CD1_1", "CD1_2", "CD2_1", "CD2_2" }; double* vals[] = { &(tan.crval[0]), &(tan.crval[1]), &(tan.crpix[0]), &(tan.crpix[1]), &(tan.cd[0][0]), &(tan.cd[0][1]), &(tan.cd[1][0]), &(tan.cd[1][1]) }; int i; for (i=0; i<4; i++) { *(vals[i]) = qfits_header_getdouble(hdr, keys[i], nil); if (*(vals[i]) == nil) { ERROR("TAN header: missing or invalid value for \"%s\"", keys[i]); return NULL; } } // Try CD int gotcd = 1; char* complaint = NULL; for (i=4; i<8; i++) { *(vals[i]) = qfits_header_getdouble(hdr, keys[i], nil); if (*(vals[i]) == nil) { asprintf_safe(&complaint, "TAN header: missing or invalid value for key \"%s\"", keys[i]); gotcd = 0; break; } } if (!gotcd) { double cdelt1,cdelt2; // Try CDELT char* key = "CDELT1"; cdelt1 = qfits_header_getdouble(hdr, key, nil); if (cdelt1 == nil) { ERROR("%s; also tried but didn't find \"%s\"", complaint, key); free(complaint); return NULL; } key = "CDELT2"; cdelt2 = qfits_header_getdouble(hdr, key, nil); if (cdelt2 == nil) { ERROR("%s; also tried but didn't find \"%s\"", complaint, key); free(complaint); return NULL; } tan.cd[0][0] = cdelt1; tan.cd[0][1] = 0.0; tan.cd[1][0] = 0.0; tan.cd[1][1] = cdelt2; } } if (swap == 1) { double tmp; tmp = tan.crval[0]; tan.crval[0] = tan.crval[1]; tan.crval[1] = tmp; // swap CD1_1 <-> CD2_1 tmp = tan.cd[0][0]; tan.cd[0][0] = tan.cd[1][0]; tan.cd[1][0] = tmp; // swap CD1_2 <-> CD2_2 tmp = tan.cd[0][1]; tan.cd[0][1] = tan.cd[1][1]; tan.cd[1][1] = tmp; } tan.sin = is_sin; if (!dest) dest = malloc(sizeof(tan_t)); memcpy(dest, &tan, sizeof(tan_t)); return dest; }
double startree_get_jitter(const startree_t* s) { return qfits_header_getdouble(s->header, "JITTER", 0.0); }
double startree_get_cut_dedup(const startree_t* s) { return qfits_header_getdouble(s->header, "CUTDEDUP", 0.0); }
void fits_guess_scale_hdr(const qfits_header* hdr, sl** p_methods, dl** p_scales) { sip_t sip; double val; anbool gotsip = FALSE; char* errstr; sl* methods = NULL; dl* scales = NULL; if (p_methods) { if (!*p_methods) *p_methods = sl_new(4); methods = *p_methods; } if (p_scales) { if (!*p_scales) *p_scales = dl_new(4); scales = *p_scales; } memset(&sip, 0, sizeof(sip_t)); errors_start_logging_to_string(); if (sip_read_header(hdr, &sip)) { val = sip_pixel_scale(&sip); if (val != 0.0) { addscale(methods, scales, "sip", val); gotsip = TRUE; } } errstr = errors_stop_logging_to_string("\n "); logverb("fits-guess-scale: failed to read SIP/TAN header:\n %s\n", errstr); free(errstr); if (!gotsip) { // it might have a correct CD matrix but be missing other parts (eg CRVAL) double cd11, cd12, cd21, cd22; double errval = -HUGE_VAL; cd11 = qfits_header_getdouble(hdr, "CD1_1", errval); cd12 = qfits_header_getdouble(hdr, "CD1_2", errval); cd21 = qfits_header_getdouble(hdr, "CD2_1", errval); cd22 = qfits_header_getdouble(hdr, "CD2_2", errval); if ((cd11 != errval) && (cd12 != errval) && (cd21 != errval) && (cd22 != errval)) { val = cd11 * cd22 - cd12 * cd21; if (val != 0.0) addscale(methods, scales, "cd", sqrt(fabs(val))); } } val = qfits_header_getdouble(hdr, "PIXSCALE", -1.0); if (val != -1.0) addscale(methods, scales, "pixscale", val); /* Why all this? val = qfits_header_getdouble(hdr, "PIXSCAL1", -1.0); if (val != -1.0) { if (val != 0.0) { printf("scale pixscal1 %g\n", val); } else { val = atof(qfits_pretty_string(qfits_header_getstr(hdr, "PIXSCAL1"))); if (val != 0.0) { printf("scale pixscal1 %g\n", val); } } } */ val = qfits_header_getdouble(hdr, "PIXSCAL1", 0.0); if (val != 0.0) addscale(methods, scales, "pixscal1", val); val = qfits_header_getdouble(hdr, "PIXSCAL2", 0.0); if (val != 0.0) addscale(methods, scales, "pixscal2", val); val = qfits_header_getdouble(hdr, "PLATESC", 0.0); if (val != 0.0) addscale(methods, scales, "platesc", val); val = qfits_header_getdouble(hdr, "CCDSCALE", 0.0); if (val != 0.0) addscale(methods, scales, "ccdscale", val); val = qfits_header_getdouble(hdr, "CDELT1", 0.0); if (val != 0.0) addscale(methods, scales, "cdelt1", 3600.0 * fabs(val)); }